@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,521 @@
1
+ import * as DropdownMenu from '@radix-ui/react-dropdown-menu';
2
+ import * as React from 'react';
3
+ import { GestureResponderEvent, Pressable, Text, View } from 'react-native';
4
+ import { useAugmentedRef } from '@rnr/hooks';
5
+ import * as Slot from '@rnr/slot';
6
+ import type {
7
+ ForceMountable,
8
+ PositionedContentProps,
9
+ PressableRef,
10
+ SlottablePressableProps,
11
+ SlottableTextProps,
12
+ SlottableViewProps,
13
+ TextRef,
14
+ ViewRef,
15
+ } from '@rnr/types';
16
+ import { EmptyGestureResponderEvent } from '@rnr/utils';
17
+ import type {
18
+ DropdownMenuCheckboxItemProps,
19
+ DropdownMenuItemProps,
20
+ DropdownMenuOverlayProps,
21
+ DropdownMenuPortalProps,
22
+ DropdownMenuRadioGroupProps,
23
+ DropdownMenuRadioItemProps,
24
+ DropdownMenuRootProps,
25
+ DropdownMenuSeparatorProps,
26
+ DropdownMenuSubProps,
27
+ DropdownMenuSubTriggerProps,
28
+ } from './types';
29
+
30
+ const DropdownMenuContext = React.createContext<DropdownMenuRootProps | null>(null);
31
+
32
+ const Root = React.forwardRef<ViewRef, SlottableViewProps & DropdownMenuRootProps>(
33
+ ({ asChild, open, onOpenChange, ...viewProps }, ref) => {
34
+ const Component = asChild ? Slot.View : View;
35
+ return (
36
+ <DropdownMenuContext.Provider value={{ open, onOpenChange }}>
37
+ <DropdownMenu.Root open={open} onOpenChange={onOpenChange}>
38
+ <Component ref={ref} {...viewProps} />
39
+ </DropdownMenu.Root>
40
+ </DropdownMenuContext.Provider>
41
+ );
42
+ }
43
+ );
44
+
45
+ Root.displayName = 'RootWebDropdownMenu';
46
+
47
+ function useRootContext() {
48
+ const context = React.useContext(DropdownMenuContext);
49
+ if (!context) {
50
+ throw new Error(
51
+ 'DropdownMenu compound components cannot be rendered outside the DropdownMenu component'
52
+ );
53
+ }
54
+ return context;
55
+ }
56
+
57
+ const Trigger = React.forwardRef<PressableRef, SlottablePressableProps>(
58
+ ({ asChild, disabled = false, ...props }, ref) => {
59
+ const augmentedRef = useAugmentedRef({ ref });
60
+ const { open } = useRootContext();
61
+
62
+ React.useLayoutEffect(() => {
63
+ if (augmentedRef.current) {
64
+ const augRef = augmentedRef.current as unknown as HTMLDivElement;
65
+ augRef.dataset.state = open ? 'open' : 'closed';
66
+ }
67
+ }, [open]);
68
+
69
+ React.useLayoutEffect(() => {
70
+ if (augmentedRef.current) {
71
+ const augRef = augmentedRef.current as unknown as HTMLDivElement;
72
+ if (disabled) {
73
+ augRef.dataset.disabled = 'true';
74
+ } else {
75
+ augRef.dataset.disabled = undefined;
76
+ }
77
+ }
78
+ }, [disabled]);
79
+
80
+ const Component = asChild ? Slot.Pressable : Pressable;
81
+ return (
82
+ <DropdownMenu.Trigger disabled={disabled ?? undefined} asChild>
83
+ <Component ref={augmentedRef} {...props} />
84
+ </DropdownMenu.Trigger>
85
+ );
86
+ }
87
+ );
88
+
89
+ Trigger.displayName = 'TriggerWebDropdownMenu';
90
+
91
+ function Portal({ forceMount, container, children }: DropdownMenuPortalProps) {
92
+ return <DropdownMenu.Portal forceMount={forceMount} container={container} children={children} />;
93
+ }
94
+
95
+ const Overlay = React.forwardRef<PressableRef, SlottablePressableProps & DropdownMenuOverlayProps>(
96
+ ({ asChild, ...props }, ref) => {
97
+ const Component = asChild ? Slot.Pressable : Pressable;
98
+ return <Component ref={ref} {...props} />;
99
+ }
100
+ );
101
+
102
+ Overlay.displayName = 'OverlayWebDropdownMenu';
103
+
104
+ const DropdownMenuContentContext = React.createContext<{
105
+ close: () => void;
106
+ } | null>(null);
107
+
108
+ const Content = React.forwardRef<PressableRef, SlottablePressableProps & PositionedContentProps>(
109
+ (
110
+ {
111
+ asChild = false,
112
+ forceMount,
113
+ align,
114
+ side,
115
+ sideOffset,
116
+ alignOffset = 0,
117
+ avoidCollisions = true,
118
+ insets,
119
+ loop = true,
120
+ onCloseAutoFocus,
121
+ onEscapeKeyDown,
122
+ onPointerDownOutside,
123
+ onFocusOutside,
124
+ onInteractOutside,
125
+ collisionBoundary,
126
+ sticky,
127
+ hideWhenDetached,
128
+ ...props
129
+ },
130
+ ref
131
+ ) => {
132
+ const itemRef = React.useRef<HTMLDivElement>(null);
133
+
134
+ function close() {
135
+ itemRef.current?.click();
136
+ }
137
+ const Component = asChild ? Slot.Pressable : Pressable;
138
+ return (
139
+ <DropdownMenuContentContext.Provider value={{ close }}>
140
+ <DropdownMenu.Content
141
+ forceMount={forceMount}
142
+ alignOffset={alignOffset}
143
+ avoidCollisions={avoidCollisions}
144
+ collisionPadding={insets}
145
+ loop={loop}
146
+ onCloseAutoFocus={onCloseAutoFocus}
147
+ onEscapeKeyDown={onEscapeKeyDown}
148
+ onPointerDownOutside={onPointerDownOutside}
149
+ onFocusOutside={onFocusOutside}
150
+ onInteractOutside={onInteractOutside}
151
+ collisionBoundary={collisionBoundary}
152
+ sticky={sticky}
153
+ hideWhenDetached={hideWhenDetached}
154
+ align={align}
155
+ side={side}
156
+ sideOffset={sideOffset}
157
+ >
158
+ <Component ref={ref} {...props} />
159
+ <DropdownMenu.Item
160
+ ref={itemRef}
161
+ aria-hidden
162
+ style={{ position: 'fixed', top: 0, left: 0, zIndex: -999999999 }}
163
+ aria-disabled
164
+ tabIndex={-1}
165
+ hidden
166
+ />
167
+ </DropdownMenu.Content>
168
+ </DropdownMenuContentContext.Provider>
169
+ );
170
+ }
171
+ );
172
+
173
+ Content.displayName = 'ContentWebDropdownMenu';
174
+
175
+ function useDropdownMenuContentContext() {
176
+ const context = React.useContext(DropdownMenuContentContext);
177
+ if (!context) {
178
+ throw new Error(
179
+ 'DropdownMenu compound components cannot be rendered outside the DropdownMenu component'
180
+ );
181
+ }
182
+ return context;
183
+ }
184
+
185
+ const Item = React.forwardRef<PressableRef, SlottablePressableProps & DropdownMenuItemProps>(
186
+ (
187
+ {
188
+ asChild,
189
+ textValue,
190
+ closeOnPress = true,
191
+ onPress: onPressProp,
192
+ onKeyDown: onKeyDownProp,
193
+ ...props
194
+ },
195
+ ref
196
+ ) => {
197
+ const { close } = useDropdownMenuContentContext();
198
+
199
+ function onKeyDown(ev: React.KeyboardEvent) {
200
+ onKeyDownProp?.(ev);
201
+ if (ev.key === 'Enter' || ev.key === ' ') {
202
+ onPressProp?.(EmptyGestureResponderEvent);
203
+ if (closeOnPress) {
204
+ close();
205
+ }
206
+ }
207
+ }
208
+
209
+ function onPress(ev: GestureResponderEvent) {
210
+ onPressProp?.(ev);
211
+ if (closeOnPress) {
212
+ close();
213
+ }
214
+ }
215
+
216
+ const Component = asChild ? Slot.Pressable : Pressable;
217
+ return (
218
+ <DropdownMenu.Item
219
+ textValue={textValue}
220
+ disabled={props.disabled ?? undefined}
221
+ onSelect={closeOnPress ? undefined : onSelected}
222
+ asChild
223
+ >
224
+ <Component
225
+ ref={ref}
226
+ // @ts-expect-error web only
227
+ onKeyDown={onKeyDown}
228
+ onPress={onPress}
229
+ {...props}
230
+ />
231
+ </DropdownMenu.Item>
232
+ );
233
+ }
234
+ );
235
+
236
+ Item.displayName = 'ItemWebDropdownMenu';
237
+
238
+ const Group = React.forwardRef<ViewRef, SlottableViewProps>(({ asChild, ...props }, ref) => {
239
+ const Component = asChild ? Slot.View : View;
240
+ return (
241
+ <DropdownMenu.Group asChild>
242
+ <Component ref={ref} {...props} />
243
+ </DropdownMenu.Group>
244
+ );
245
+ });
246
+
247
+ Group.displayName = 'GroupWebDropdownMenu';
248
+
249
+ const Label = React.forwardRef<TextRef, SlottableTextProps>(({ asChild, ...props }, ref) => {
250
+ const Component = asChild ? Slot.Text : Text;
251
+ return (
252
+ <DropdownMenu.Label asChild>
253
+ <Component ref={ref} {...props} />
254
+ </DropdownMenu.Label>
255
+ );
256
+ });
257
+
258
+ Label.displayName = 'LabelWebDropdownMenu';
259
+
260
+ const CheckboxItem = React.forwardRef<
261
+ PressableRef,
262
+ SlottablePressableProps & DropdownMenuCheckboxItemProps
263
+ >(
264
+ (
265
+ {
266
+ asChild,
267
+ checked,
268
+ onCheckedChange,
269
+ textValue,
270
+ disabled = false,
271
+ closeOnPress = true,
272
+ onPress: onPressProp,
273
+ onKeyDown: onKeyDownProp,
274
+ ...props
275
+ },
276
+ ref
277
+ ) => {
278
+ const { close } = useDropdownMenuContentContext();
279
+
280
+ function onKeyDown(ev: React.KeyboardEvent) {
281
+ onKeyDownProp?.(ev);
282
+ if (ev.key === 'Enter' || ev.key === ' ') {
283
+ onPressProp?.(EmptyGestureResponderEvent);
284
+ onCheckedChange?.(!checked);
285
+ if (closeOnPress) {
286
+ close();
287
+ }
288
+ }
289
+ }
290
+
291
+ function onPress(ev: GestureResponderEvent) {
292
+ onPressProp?.(ev);
293
+ onCheckedChange?.(!checked);
294
+ if (closeOnPress) {
295
+ close();
296
+ }
297
+ }
298
+ const Component = asChild ? Slot.Pressable : Pressable;
299
+ return (
300
+ <DropdownMenu.CheckboxItem
301
+ textValue={textValue}
302
+ checked={checked}
303
+ onCheckedChange={onCheckedChange}
304
+ onSelect={closeOnPress ? undefined : onSelected}
305
+ disabled={disabled ?? undefined}
306
+ asChild
307
+ >
308
+ <Component
309
+ ref={ref}
310
+ // @ts-expect-error web only
311
+ onKeyDown={onKeyDown}
312
+ onPress={onPress}
313
+ role='button'
314
+ {...props}
315
+ />
316
+ </DropdownMenu.CheckboxItem>
317
+ );
318
+ }
319
+ );
320
+
321
+ CheckboxItem.displayName = 'CheckboxItemWebDropdownMenu';
322
+
323
+ const DropdownMenuRadioGroupContext = React.createContext<{
324
+ value?: string;
325
+ onValueChange?: (value: string) => void;
326
+ } | null>(null);
327
+
328
+ const RadioGroup = React.forwardRef<ViewRef, SlottableViewProps & DropdownMenuRadioGroupProps>(
329
+ ({ asChild, value, onValueChange, ...props }, ref) => {
330
+ const Component = asChild ? Slot.View : View;
331
+ return (
332
+ <DropdownMenuRadioGroupContext.Provider value={{ value, onValueChange }}>
333
+ <DropdownMenu.RadioGroup value={value} onValueChange={onValueChange} asChild>
334
+ <Component ref={ref} {...props} />
335
+ </DropdownMenu.RadioGroup>
336
+ </DropdownMenuRadioGroupContext.Provider>
337
+ );
338
+ }
339
+ );
340
+
341
+ RadioGroup.displayName = 'RadioGroupWebDropdownMenu';
342
+
343
+ function useDropdownMenuRadioGroupContext() {
344
+ const context = React.useContext(DropdownMenuRadioGroupContext);
345
+ if (!context) {
346
+ throw new Error(
347
+ 'DropdownMenuRadioGroup compound components cannot be rendered outside the DropdownMenuRadioGroup component'
348
+ );
349
+ }
350
+ return context;
351
+ }
352
+
353
+ const RadioItem = React.forwardRef<
354
+ PressableRef,
355
+ SlottablePressableProps & DropdownMenuRadioItemProps
356
+ >(
357
+ (
358
+ {
359
+ asChild,
360
+ value,
361
+ textValue,
362
+ closeOnPress = true,
363
+ onPress: onPressProp,
364
+ onKeyDown: onKeyDownProp,
365
+ ...props
366
+ },
367
+ ref
368
+ ) => {
369
+ const { onValueChange } = useDropdownMenuRadioGroupContext();
370
+ const { close } = useDropdownMenuContentContext();
371
+
372
+ function onKeyDown(ev: React.KeyboardEvent) {
373
+ onKeyDownProp?.(ev);
374
+ if (ev.key === 'Enter' || ev.key === ' ') {
375
+ onValueChange?.(value);
376
+ onPressProp?.(EmptyGestureResponderEvent);
377
+ if (closeOnPress) {
378
+ close();
379
+ }
380
+ }
381
+ }
382
+
383
+ function onPress(ev: GestureResponderEvent) {
384
+ onValueChange?.(value);
385
+ onPressProp?.(ev);
386
+ if (closeOnPress) {
387
+ close();
388
+ }
389
+ }
390
+ const Component = asChild ? Slot.Pressable : Pressable;
391
+ return (
392
+ <DropdownMenu.RadioItem
393
+ value={value}
394
+ textValue={textValue}
395
+ disabled={props.disabled ?? undefined}
396
+ onSelect={closeOnPress ? undefined : onSelected}
397
+ asChild
398
+ >
399
+ <Component
400
+ ref={ref}
401
+ // @ts-expect-error web only
402
+ onKeyDown={onKeyDown}
403
+ onPress={onPress}
404
+ {...props}
405
+ />
406
+ </DropdownMenu.RadioItem>
407
+ );
408
+ }
409
+ );
410
+
411
+ RadioItem.displayName = 'RadioItemWebDropdownMenu';
412
+
413
+ const ItemIndicator = React.forwardRef<ViewRef, SlottableViewProps & ForceMountable>(
414
+ ({ asChild, forceMount, ...props }, ref) => {
415
+ const Component = asChild ? Slot.View : View;
416
+ return (
417
+ <DropdownMenu.ItemIndicator forceMount={forceMount} asChild>
418
+ <Component ref={ref} {...props} />
419
+ </DropdownMenu.ItemIndicator>
420
+ );
421
+ }
422
+ );
423
+
424
+ ItemIndicator.displayName = 'ItemIndicatorWebDropdownMenu';
425
+
426
+ const Separator = React.forwardRef<ViewRef, SlottableViewProps & DropdownMenuSeparatorProps>(
427
+ ({ asChild, decorative, ...props }, ref) => {
428
+ const Component = asChild ? Slot.View : View;
429
+ return (
430
+ <DropdownMenu.Separator asChild>
431
+ <Component ref={ref} {...props} />
432
+ </DropdownMenu.Separator>
433
+ );
434
+ }
435
+ );
436
+
437
+ Separator.displayName = 'SeparatorWebDropdownMenu';
438
+
439
+ const DropdownMenuSubContext = React.createContext<{
440
+ open: boolean;
441
+ onOpenChange: (open: boolean) => void;
442
+ } | null>(null);
443
+
444
+ const Sub = React.forwardRef<ViewRef, SlottableViewProps & DropdownMenuSubProps>(
445
+ ({ asChild, open, onOpenChange, ...props }, ref) => {
446
+ const Component = asChild ? Slot.View : View;
447
+ return (
448
+ <DropdownMenuSubContext.Provider value={{ open, onOpenChange }}>
449
+ <DropdownMenu.Sub open={open} onOpenChange={onOpenChange}>
450
+ <Component ref={ref} {...props} />
451
+ </DropdownMenu.Sub>
452
+ </DropdownMenuSubContext.Provider>
453
+ );
454
+ }
455
+ );
456
+
457
+ Sub.displayName = 'SubWebDropdownMenu';
458
+
459
+ function useSubContext() {
460
+ const context = React.useContext(DropdownMenuSubContext);
461
+ if (!context) {
462
+ throw new Error(
463
+ 'DropdownMenu compound components cannot be rendered outside the DropdownMenu component'
464
+ );
465
+ }
466
+ return context;
467
+ }
468
+
469
+ const SubTrigger = React.forwardRef<
470
+ PressableRef,
471
+ SlottablePressableProps & DropdownMenuSubTriggerProps
472
+ >(({ asChild, textValue, disabled = false, ...props }, ref) => {
473
+ const Component = asChild ? Slot.Pressable : Pressable;
474
+ return (
475
+ <DropdownMenu.SubTrigger disabled={disabled ?? undefined} textValue={textValue} asChild>
476
+ <Component ref={ref} {...props} />
477
+ </DropdownMenu.SubTrigger>
478
+ );
479
+ });
480
+
481
+ SubTrigger.displayName = 'SubTriggerWebDropdownMenu';
482
+
483
+ const SubContent = React.forwardRef<PressableRef, SlottablePressableProps & ForceMountable>(
484
+ ({ asChild = false, forceMount, ...props }, ref) => {
485
+ const Component = asChild ? Slot.Pressable : Pressable;
486
+ return (
487
+ <DropdownMenu.Portal>
488
+ <DropdownMenu.SubContent forceMount={forceMount}>
489
+ <Component ref={ref} {...props} />
490
+ </DropdownMenu.SubContent>
491
+ </DropdownMenu.Portal>
492
+ );
493
+ }
494
+ );
495
+
496
+ Content.displayName = 'ContentWebDropdownMenu';
497
+
498
+ export {
499
+ CheckboxItem,
500
+ Content,
501
+ Group,
502
+ Item,
503
+ ItemIndicator,
504
+ Label,
505
+ Overlay,
506
+ Portal,
507
+ RadioGroup,
508
+ RadioItem,
509
+ Root,
510
+ Separator,
511
+ Sub,
512
+ SubContent,
513
+ SubTrigger,
514
+ Trigger,
515
+ useRootContext,
516
+ useSubContext,
517
+ };
518
+
519
+ function onSelected(ev: Event) {
520
+ ev.preventDefault();
521
+ }
@@ -0,0 +1 @@
1
+ export * from './dropdown-menu';
@@ -0,0 +1,71 @@
1
+ import type { ForceMountable } from '@rnr/types';
2
+
3
+ interface DropdownMenuRootProps {
4
+ open: boolean;
5
+ onOpenChange: (value: boolean) => void;
6
+ }
7
+
8
+ interface DropdownMenuPortalProps extends ForceMountable {
9
+ children: React.ReactNode;
10
+ /**
11
+ * Platform: NATIVE ONLY
12
+ */
13
+ hostName?: string;
14
+ /**
15
+ * Platform: WEB ONLY
16
+ */
17
+ container?: HTMLElement | null | undefined;
18
+ }
19
+
20
+ interface DropdownMenuOverlayProps extends ForceMountable {
21
+ closeOnPress?: boolean;
22
+ }
23
+
24
+ interface DropdownMenuItemProps {
25
+ textValue?: string;
26
+ closeOnPress?: boolean;
27
+ }
28
+
29
+ interface DropdownMenuCheckboxItemProps {
30
+ checked: boolean;
31
+ onCheckedChange: (checked: boolean) => void;
32
+ closeOnPress?: boolean;
33
+ textValue?: string;
34
+ }
35
+
36
+ interface DropdownMenuRadioGroupProps {
37
+ value: string | undefined;
38
+ onValueChange: (value: string) => void;
39
+ }
40
+
41
+ interface DropdownMenuRadioItemProps {
42
+ value: string;
43
+ textValue?: string;
44
+ closeOnPress?: boolean;
45
+ }
46
+
47
+ interface DropdownMenuSeparatorProps {
48
+ decorative?: boolean;
49
+ }
50
+
51
+ interface DropdownMenuSubProps {
52
+ open: boolean;
53
+ onOpenChange: (value: boolean) => void;
54
+ }
55
+
56
+ interface DropdownMenuSubTriggerProps {
57
+ textValue?: string;
58
+ }
59
+
60
+ export type {
61
+ DropdownMenuCheckboxItemProps,
62
+ DropdownMenuItemProps,
63
+ DropdownMenuOverlayProps,
64
+ DropdownMenuPortalProps,
65
+ DropdownMenuRadioGroupProps,
66
+ DropdownMenuRadioItemProps,
67
+ DropdownMenuRootProps,
68
+ DropdownMenuSeparatorProps,
69
+ DropdownMenuSubProps,
70
+ DropdownMenuSubTriggerProps,
71
+ };
@@ -0,0 +1,3 @@
1
+ export { useAugmentedRef } from './useAugmentedRef';
2
+ export { useRelativePosition, type LayoutPosition } from './useRelativePosition';
3
+ export { useControllableState } from './useControllableState';
@@ -0,0 +1,29 @@
1
+ import * as React from 'react';
2
+
3
+ interface AugmentRefProps<T> {
4
+ ref: React.Ref<T>;
5
+ methods?: Record<string, (...args: any[]) => any>;
6
+ deps?: any[];
7
+ }
8
+
9
+ export function useAugmentedRef<T>({
10
+ ref,
11
+ methods,
12
+ deps = [],
13
+ }: AugmentRefProps<T>) {
14
+ const augmentedRef = React.useRef<T>(null);
15
+ React.useImperativeHandle(
16
+ ref,
17
+ () => {
18
+ if (typeof augmentedRef === 'function' || !augmentedRef?.current) {
19
+ return {} as T;
20
+ }
21
+ return {
22
+ ...augmentedRef.current,
23
+ ...methods,
24
+ };
25
+ },
26
+ deps
27
+ );
28
+ return augmentedRef;
29
+ }
@@ -0,0 +1,75 @@
1
+ // This project uses code from WorkOS/Radix Primitives.
2
+ // The code is licensed under the MIT License.
3
+ // https://github.com/radix-ui/primitives/tree/main
4
+
5
+ import * as React from 'react';
6
+
7
+ type UseControllableStateParams<T> = {
8
+ prop?: T | undefined;
9
+ defaultProp?: T | undefined;
10
+ onChange?: (state: T) => void;
11
+ };
12
+
13
+ type SetStateFn<T> = (prevState?: T) => T;
14
+
15
+ function useControllableState<T>({
16
+ prop,
17
+ defaultProp,
18
+ onChange = () => {},
19
+ }: UseControllableStateParams<T>) {
20
+ const [uncontrolledProp, setUncontrolledProp] = useUncontrolledState({ defaultProp, onChange });
21
+ const isControlled = prop !== undefined;
22
+ const value = isControlled ? prop : uncontrolledProp;
23
+ const handleChange = useCallbackRef(onChange);
24
+
25
+ const setValue: React.Dispatch<React.SetStateAction<T | undefined>> = React.useCallback(
26
+ (nextValue) => {
27
+ if (isControlled) {
28
+ const setter = nextValue as SetStateFn<T>;
29
+ const value = typeof nextValue === 'function' ? setter(prop) : nextValue;
30
+ if (value !== prop) handleChange(value as T);
31
+ } else {
32
+ setUncontrolledProp(nextValue);
33
+ }
34
+ },
35
+ [isControlled, prop, setUncontrolledProp, handleChange]
36
+ );
37
+
38
+ return [value, setValue] as const;
39
+ }
40
+
41
+ function useUncontrolledState<T>({
42
+ defaultProp,
43
+ onChange,
44
+ }: Omit<UseControllableStateParams<T>, 'prop'>) {
45
+ const uncontrolledState = React.useState<T | undefined>(defaultProp);
46
+ const [value] = uncontrolledState;
47
+ const prevValueRef = React.useRef(value);
48
+ const handleChange = useCallbackRef(onChange);
49
+
50
+ React.useEffect(() => {
51
+ if (prevValueRef.current !== value) {
52
+ handleChange(value as T);
53
+ prevValueRef.current = value;
54
+ }
55
+ }, [value, prevValueRef, handleChange]);
56
+
57
+ return uncontrolledState;
58
+ }
59
+
60
+ /**
61
+ * A custom hook that converts a callback to a ref to avoid triggering re-renders when passed as a
62
+ * prop or avoid re-executing effects when passed as a dependency
63
+ */
64
+ function useCallbackRef<T extends (...args: any[]) => any>(callback: T | undefined): T {
65
+ const callbackRef = React.useRef(callback);
66
+
67
+ React.useEffect(() => {
68
+ callbackRef.current = callback;
69
+ });
70
+
71
+ // https://github.com/facebook/react/issues/19240
72
+ return React.useMemo(() => ((...args) => callbackRef.current?.(...args)) as T, []);
73
+ }
74
+
75
+ export { useControllableState };