@react-native-reusables/cli 0.0.9 → 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.
- package/dist/generated/components/primitives/accordion/accordion.tsx +216 -0
- package/dist/generated/components/primitives/accordion/accordion.web.tsx +295 -0
- package/dist/generated/components/primitives/accordion/index.ts +1 -0
- package/dist/generated/components/primitives/accordion/types.ts +45 -0
- package/dist/generated/components/primitives/alert-dialog/alert-dialog.tsx +237 -0
- package/dist/generated/components/primitives/alert-dialog/alert-dialog.web.tsx +256 -0
- package/dist/generated/components/primitives/alert-dialog/index.ts +1 -0
- package/dist/generated/components/primitives/alert-dialog/types.ts +48 -0
- package/dist/generated/components/primitives/aspect-ratio.tsx +23 -0
- package/dist/generated/components/primitives/avatar/ types.ts +10 -0
- package/dist/generated/components/primitives/avatar/index.tsx +95 -0
- package/dist/generated/components/primitives/checkbox/checkbox.tsx +101 -0
- package/dist/generated/components/primitives/checkbox/checkbox.web.tsx +114 -0
- package/dist/generated/components/primitives/checkbox/index.ts +1 -0
- package/dist/generated/components/primitives/checkbox/types.ts +11 -0
- package/dist/generated/components/primitives/collapsible/collapsible.tsx +119 -0
- package/dist/generated/components/primitives/collapsible/collapsible.web.tsx +157 -0
- package/dist/generated/components/primitives/collapsible/index.ts +1 -0
- package/dist/generated/components/primitives/collapsible/types.ts +18 -0
- package/dist/generated/components/primitives/context-menu/context-menu.tsx +626 -0
- package/dist/generated/components/primitives/context-menu/context-menu.web.tsx +504 -0
- package/dist/generated/components/primitives/context-menu/index.ts +1 -0
- package/dist/generated/components/primitives/context-menu/types.ts +82 -0
- package/dist/generated/components/primitives/dialog/dialog.tsx +211 -0
- package/dist/generated/components/primitives/dialog/dialog.web.tsx +197 -0
- package/dist/generated/components/primitives/dialog/index.ts +1 -0
- package/dist/generated/components/primitives/dialog/types.ts +60 -0
- package/dist/generated/components/primitives/dropdown-menu/dropdown-menu.tsx +584 -0
- package/dist/generated/components/primitives/dropdown-menu/dropdown-menu.web.tsx +521 -0
- package/dist/generated/components/primitives/dropdown-menu/index.ts +1 -0
- package/dist/generated/components/primitives/dropdown-menu/types.ts +71 -0
- package/dist/generated/components/primitives/hooks/index.ts +3 -0
- package/dist/generated/components/primitives/hooks/useAugmentedRef.tsx +29 -0
- package/dist/generated/components/primitives/hooks/useControllableState.tsx +75 -0
- package/dist/generated/components/primitives/hooks/useRelativePosition.tsx +227 -0
- package/dist/generated/components/primitives/hover-card/hover-card.tsx +271 -0
- package/dist/generated/components/primitives/hover-card/hover-card.web.tsx +145 -0
- package/dist/generated/components/primitives/hover-card/index.ts +1 -0
- package/dist/generated/components/primitives/hover-card/types.ts +42 -0
- package/dist/generated/components/primitives/label/index.ts +1 -0
- package/dist/generated/components/primitives/label/label.tsx +31 -0
- package/dist/generated/components/primitives/label/label.web.tsx +36 -0
- package/dist/generated/components/primitives/label/types.ts +15 -0
- package/dist/generated/components/primitives/menubar/index.ts +1 -0
- package/dist/generated/components/primitives/menubar/menubar.tsx +624 -0
- package/dist/generated/components/primitives/menubar/menubar.web.tsx +543 -0
- package/dist/generated/components/primitives/menubar/types.ts +76 -0
- package/dist/generated/components/primitives/navigation-menu/index.ts +1 -0
- package/dist/generated/components/primitives/navigation-menu/navigation-menu.tsx +315 -0
- package/dist/generated/components/primitives/navigation-menu/navigation-menu.web.tsx +264 -0
- package/dist/generated/components/primitives/navigation-menu/types.ts +49 -0
- package/dist/generated/components/primitives/popover/index.ts +1 -0
- package/dist/generated/components/primitives/popover/popover.tsx +286 -0
- package/dist/generated/components/primitives/popover/popover.web.tsx +179 -0
- package/dist/generated/components/primitives/popover/types.ts +30 -0
- package/dist/generated/components/primitives/portal.tsx +67 -0
- package/dist/generated/components/primitives/progress/index.ts +1 -0
- package/dist/generated/components/primitives/progress/progress.tsx +59 -0
- package/dist/generated/components/primitives/progress/progress.web.tsx +36 -0
- package/dist/generated/components/primitives/progress/types.ts +7 -0
- package/dist/generated/components/primitives/radio-group/index.ts +1 -0
- package/dist/generated/components/primitives/radio-group/radio-group.tsx +116 -0
- package/dist/generated/components/primitives/radio-group/radio-group.web.tsx +78 -0
- package/dist/generated/components/primitives/radio-group/types.ts +15 -0
- package/dist/generated/components/primitives/select/index.ts +1 -0
- package/dist/generated/components/primitives/select/select.tsx +455 -0
- package/dist/generated/components/primitives/select/select.web.tsx +319 -0
- package/dist/generated/components/primitives/select/types.ts +87 -0
- package/dist/generated/components/primitives/separator/ types.ts +6 -0
- package/dist/generated/components/primitives/separator/index.tsx +23 -0
- package/dist/generated/components/primitives/slider/index.ts +1 -0
- package/dist/generated/components/primitives/slider/slider.tsx +89 -0
- package/dist/generated/components/primitives/slider/slider.web.tsx +67 -0
- package/dist/generated/components/primitives/slider/types.ts +24 -0
- package/dist/generated/components/primitives/slot.tsx +187 -0
- package/dist/generated/components/primitives/switch/index.ts +1 -0
- package/dist/generated/components/primitives/switch/switch.tsx +65 -0
- package/dist/generated/components/primitives/switch/switch.web.tsx +67 -0
- package/dist/generated/components/primitives/switch/types.ts +11 -0
- package/dist/generated/components/primitives/table.tsx +55 -0
- package/dist/generated/components/primitives/tabs/index.ts +1 -0
- package/dist/generated/components/primitives/tabs/tabs.tsx +133 -0
- package/dist/generated/components/primitives/tabs/tabs.web.tsx +97 -0
- package/dist/generated/components/primitives/tabs/types.ts +24 -0
- package/dist/generated/components/primitives/toast/ types.ts +7 -0
- package/dist/generated/components/primitives/toast/index.tsx +128 -0
- package/dist/generated/components/primitives/toggle/index.ts +1 -0
- package/dist/generated/components/primitives/toggle/toggle.tsx +37 -0
- package/dist/generated/components/primitives/toggle/toggle.web.tsx +26 -0
- package/dist/generated/components/primitives/toggle/types.ts +7 -0
- package/dist/generated/components/primitives/toggle-group/index.ts +1 -0
- package/dist/generated/components/primitives/toggle-group/toggle-group.tsx +125 -0
- package/dist/generated/components/primitives/toggle-group/toggle-group.web.tsx +124 -0
- package/dist/generated/components/primitives/toggle-group/types.ts +37 -0
- package/dist/generated/components/primitives/toolbar/index.ts +1 -0
- package/dist/generated/components/primitives/toolbar/toolbar.tsx +125 -0
- package/dist/generated/components/primitives/toolbar/toolbar.web.tsx +129 -0
- package/dist/generated/components/primitives/toolbar/types.ts +39 -0
- package/dist/generated/components/primitives/tooltip/index.ts +1 -0
- package/dist/generated/components/primitives/tooltip/tooltip.tsx +271 -0
- package/dist/generated/components/primitives/tooltip/tooltip.web.tsx +167 -0
- package/dist/generated/components/primitives/tooltip/types.ts +44 -0
- package/dist/generated/components/primitives/types.ts +105 -0
- package/dist/generated/components/primitives/utils.ts +61 -0
- package/dist/generated/components/ui/accordion.tsx +127 -0
- package/dist/generated/components/ui/alert-dialog.tsx +167 -0
- package/dist/generated/components/ui/aspect-ratio.tsx +5 -0
- package/dist/generated/components/ui/avatar.tsx +44 -0
- package/dist/generated/components/ui/badge.tsx +51 -0
- package/dist/generated/components/ui/button.tsx +88 -0
- package/dist/generated/components/ui/card.tsx +67 -0
- package/dist/generated/components/ui/checkbox.tsx +34 -0
- package/dist/generated/components/ui/collapsible.tsx +9 -0
- package/dist/generated/components/ui/context-menu.tsx +244 -0
- package/dist/generated/components/ui/dialog.tsx +150 -0
- package/dist/generated/components/ui/dropdown-menu.tsx +244 -0
- package/dist/generated/components/ui/hover-card.tsx +45 -0
- package/dist/generated/components/ui/input.tsx +26 -0
- package/dist/generated/components/ui/label.tsx +28 -0
- package/dist/generated/components/ui/menubar.tsx +260 -0
- package/dist/generated/components/ui/navigation-menu.tsx +177 -0
- package/dist/generated/components/ui/popover.tsx +39 -0
- package/dist/generated/components/ui/radio-group.tsx +38 -0
- package/dist/generated/components/ui/select.tsx +181 -0
- package/dist/generated/components/ui/separator.tsx +23 -0
- package/dist/generated/components/ui/skeleton.tsx +39 -0
- package/dist/generated/components/ui/switch.tsx +97 -0
- package/dist/generated/components/ui/table.tsx +99 -0
- package/dist/generated/components/ui/tabs.tsx +65 -0
- package/dist/generated/components/ui/text.tsx +24 -0
- package/dist/generated/components/ui/textarea.tsx +28 -0
- package/dist/generated/components/ui/toggle-group.tsx +86 -0
- package/dist/generated/components/ui/toggle.tsx +85 -0
- package/dist/generated/components/ui/tooltip.tsx +36 -0
- package/dist/generated/components/ui/typography.tsx +204 -0
- 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,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 };
|