@streamplace/components 0.8.8 → 0.8.9
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/components/mobile-player/ui/viewer-context-menu.js +7 -6
- package/dist/components/ui/dropdown.js +227 -20
- package/node-compile-cache/v22.15.0-x64-efe9a9df-0/37be0eec +0 -0
- package/package.json +2 -2
- package/src/components/mobile-player/ui/viewer-context-menu.tsx +49 -26
- package/src/components/ui/dropdown.tsx +391 -41
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -1,14 +1,23 @@
|
|
|
1
|
-
import BottomSheet, {
|
|
1
|
+
import BottomSheet, { BottomSheetScrollView } from "@gorhom/bottom-sheet";
|
|
2
2
|
import * as DropdownMenuPrimitive from "@rn-primitives/dropdown-menu";
|
|
3
3
|
import {
|
|
4
4
|
Check,
|
|
5
5
|
CheckCircle,
|
|
6
6
|
ChevronDown,
|
|
7
|
+
ChevronLeft,
|
|
7
8
|
ChevronRight,
|
|
8
9
|
ChevronUp,
|
|
9
10
|
Circle,
|
|
10
11
|
} from "lucide-react-native";
|
|
11
|
-
import React, {
|
|
12
|
+
import React, {
|
|
13
|
+
createContext,
|
|
14
|
+
forwardRef,
|
|
15
|
+
ReactNode,
|
|
16
|
+
startTransition,
|
|
17
|
+
useContext,
|
|
18
|
+
useRef,
|
|
19
|
+
useState,
|
|
20
|
+
} from "react";
|
|
12
21
|
import {
|
|
13
22
|
Platform,
|
|
14
23
|
Pressable,
|
|
@@ -17,7 +26,13 @@ import {
|
|
|
17
26
|
useWindowDimensions,
|
|
18
27
|
View,
|
|
19
28
|
} from "react-native";
|
|
20
|
-
import {
|
|
29
|
+
import Animated, {
|
|
30
|
+
runOnJS,
|
|
31
|
+
useAnimatedStyle,
|
|
32
|
+
useSharedValue,
|
|
33
|
+
withTiming,
|
|
34
|
+
} from "react-native-reanimated";
|
|
35
|
+
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
21
36
|
import {
|
|
22
37
|
a,
|
|
23
38
|
borderRadius,
|
|
@@ -42,12 +57,103 @@ import {
|
|
|
42
57
|
} from "./primitives/text";
|
|
43
58
|
import { Text } from "./text";
|
|
44
59
|
|
|
60
|
+
// Navigation stack context for bottom sheet menus
|
|
61
|
+
interface NavigationStackItem {
|
|
62
|
+
key: string;
|
|
63
|
+
title?: string;
|
|
64
|
+
content: ReactNode | ((state: { pressed: boolean }) => ReactNode);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
interface NavigationStackContextValue {
|
|
68
|
+
stack: NavigationStackItem[];
|
|
69
|
+
push: (item: NavigationStackItem) => void;
|
|
70
|
+
pop: () => void;
|
|
71
|
+
isNested: boolean;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const NavigationStackContext =
|
|
75
|
+
createContext<NavigationStackContextValue | null>(null);
|
|
76
|
+
|
|
77
|
+
const useNavigationStack = () => {
|
|
78
|
+
const context = useContext(NavigationStackContext);
|
|
79
|
+
return context;
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
// Context to capture submenu content for mobile navigation
|
|
83
|
+
interface SubMenuContextValue {
|
|
84
|
+
title?: string;
|
|
85
|
+
renderContent: () => ReactNode;
|
|
86
|
+
setRenderContent: (renderer: () => ReactNode) => void;
|
|
87
|
+
setTitle: (title: string) => void;
|
|
88
|
+
trigger: () => void;
|
|
89
|
+
key: string | null;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const SubMenuContext = createContext<SubMenuContextValue | null>(null);
|
|
93
|
+
|
|
45
94
|
export const DropdownMenu = DropdownMenuPrimitive.Root;
|
|
46
95
|
export const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
|
|
47
96
|
export const DropdownMenuPortal = DropdownMenuPrimitive.Portal;
|
|
48
|
-
export const DropdownMenuSub = DropdownMenuPrimitive.Sub;
|
|
49
97
|
export const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;
|
|
50
98
|
|
|
99
|
+
// Custom DropdownMenuSub that works with mobile navigation
|
|
100
|
+
export const DropdownMenuSub = forwardRef<any, any>(
|
|
101
|
+
({ children, ...props }, ref) => {
|
|
102
|
+
const navStack = useNavigationStack();
|
|
103
|
+
const [subMenuTitle, setSubMenuTitle] = useState<string | undefined>();
|
|
104
|
+
const renderContentRef = useRef<(() => ReactNode) | null>(null);
|
|
105
|
+
const [subMenuKey, setSubMenuKey] = useState<string | null>(null);
|
|
106
|
+
|
|
107
|
+
// If we're in a mobile navigation stack, use custom context
|
|
108
|
+
if (navStack) {
|
|
109
|
+
const trigger = () => {
|
|
110
|
+
if (renderContentRef.current) {
|
|
111
|
+
const key = `submenu-${Date.now()}`;
|
|
112
|
+
setSubMenuKey(key);
|
|
113
|
+
navStack.push({
|
|
114
|
+
key,
|
|
115
|
+
title: subMenuTitle,
|
|
116
|
+
// Store a function that always reads the latest content from the ref
|
|
117
|
+
content: (props: any) => {
|
|
118
|
+
const renderFn = renderContentRef.current;
|
|
119
|
+
return renderFn ? renderFn() : null;
|
|
120
|
+
},
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
const setRenderContent = (renderer: () => ReactNode) => {
|
|
126
|
+
renderContentRef.current = renderer;
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
const contextValue = React.useMemo(
|
|
130
|
+
() => ({
|
|
131
|
+
renderContent: () => renderContentRef.current?.(),
|
|
132
|
+
setRenderContent,
|
|
133
|
+
title: subMenuTitle,
|
|
134
|
+
setTitle: setSubMenuTitle,
|
|
135
|
+
trigger,
|
|
136
|
+
key: subMenuKey,
|
|
137
|
+
}),
|
|
138
|
+
[subMenuTitle, subMenuKey],
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
return (
|
|
142
|
+
<SubMenuContext.Provider value={contextValue}>
|
|
143
|
+
{children}
|
|
144
|
+
</SubMenuContext.Provider>
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Web - use primitive
|
|
149
|
+
return (
|
|
150
|
+
<DropdownMenuPrimitive.Sub ref={ref} {...props}>
|
|
151
|
+
{children}
|
|
152
|
+
</DropdownMenuPrimitive.Sub>
|
|
153
|
+
);
|
|
154
|
+
},
|
|
155
|
+
);
|
|
156
|
+
|
|
51
157
|
export const DropdownMenuBottomSheet = forwardRef<
|
|
52
158
|
any,
|
|
53
159
|
DropdownMenuPrimitive.ContentProps & {
|
|
@@ -59,53 +165,259 @@ export const DropdownMenuBottomSheet = forwardRef<
|
|
|
59
165
|
_ref,
|
|
60
166
|
) {
|
|
61
167
|
// Use the primitives' context to know if open
|
|
62
|
-
const {
|
|
63
|
-
const { zero: zt } = useTheme();
|
|
168
|
+
const { onOpenChange } = DropdownMenuPrimitive.useRootContext();
|
|
169
|
+
const { zero: zt, theme } = useTheme();
|
|
64
170
|
const sheetRef = useRef<BottomSheet>(null);
|
|
171
|
+
const { width } = useWindowDimensions();
|
|
172
|
+
const isWide = Platform.OS !== "web" && width >= 800;
|
|
173
|
+
const sheetWidth = isWide ? 450 : width;
|
|
174
|
+
const horizontalMargin = isWide ? (width - sheetWidth) / 2 : 0;
|
|
175
|
+
|
|
176
|
+
const insets = useSafeAreaInsets();
|
|
177
|
+
|
|
178
|
+
// Navigation stack state
|
|
179
|
+
const [stack, setStack] = useState<NavigationStackItem[]>([
|
|
180
|
+
{ key: "root", content: children },
|
|
181
|
+
]);
|
|
182
|
+
|
|
183
|
+
// Update root content when children changes
|
|
184
|
+
React.useEffect(() => {
|
|
185
|
+
setStack((prev) => {
|
|
186
|
+
if (!Array.isArray(prev) || prev.length === 0) {
|
|
187
|
+
return [{ key: "root", content: children }];
|
|
188
|
+
}
|
|
189
|
+
// Update the root item content
|
|
190
|
+
const newStack = [...prev];
|
|
191
|
+
newStack[0] = { ...newStack[0], content: children };
|
|
192
|
+
return newStack;
|
|
193
|
+
});
|
|
194
|
+
}, [children]);
|
|
195
|
+
|
|
196
|
+
const slideAnim = useSharedValue(0);
|
|
197
|
+
const fadeAnim = useSharedValue(1);
|
|
198
|
+
|
|
199
|
+
const push = (item: NavigationStackItem) => {
|
|
200
|
+
// First, update the stack
|
|
201
|
+
setStack((prev) => {
|
|
202
|
+
if (!Array.isArray(prev))
|
|
203
|
+
return [{ key: "root", content: children }, item];
|
|
204
|
+
return [...prev, item];
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
// Then animate from right to center with fade
|
|
208
|
+
slideAnim.value = 40;
|
|
209
|
+
fadeAnim.value = 0;
|
|
210
|
+
slideAnim.value = withTiming(0, { duration: 350 });
|
|
211
|
+
fadeAnim.value = withTiming(1, { duration: 350 });
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
const popStack = () => {
|
|
215
|
+
startTransition(() => {
|
|
216
|
+
setStack((prev) => {
|
|
217
|
+
if (!Array.isArray(prev) || prev.length <= 1) {
|
|
218
|
+
return [{ key: "root", content: children }];
|
|
219
|
+
}
|
|
220
|
+
return prev.slice(0, -1);
|
|
221
|
+
});
|
|
222
|
+
});
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
const resetAnimationValues = () => {
|
|
226
|
+
setTimeout(() => {
|
|
227
|
+
slideAnim.value = 0;
|
|
228
|
+
fadeAnim.value = 1;
|
|
229
|
+
}, 5);
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
const pop = () => {
|
|
233
|
+
if (stack.length <= 1) return;
|
|
234
|
+
|
|
235
|
+
// Animate out to the right with fade
|
|
236
|
+
slideAnim.value = withTiming(40, { duration: 150 });
|
|
237
|
+
fadeAnim.value = withTiming(0, { duration: 150 }, (finished) => {
|
|
238
|
+
if (finished) {
|
|
239
|
+
// Update stack first with startTransition for smoother render
|
|
240
|
+
runOnJS(popStack)();
|
|
241
|
+
|
|
242
|
+
// Then reset animation position after a brief delay to ensure component has unmounted
|
|
243
|
+
runOnJS(resetAnimationValues)();
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
const animatedStyle = useAnimatedStyle(() => ({
|
|
249
|
+
transform: [{ translateX: slideAnim.value }],
|
|
250
|
+
opacity: fadeAnim.value,
|
|
251
|
+
}));
|
|
252
|
+
|
|
253
|
+
const headerAnimatedStyle = useAnimatedStyle(() => ({
|
|
254
|
+
opacity: fadeAnim.value,
|
|
255
|
+
}));
|
|
256
|
+
|
|
257
|
+
const currentLevel = stack[stack.length - 1];
|
|
258
|
+
const isNested = stack.length > 1;
|
|
259
|
+
|
|
260
|
+
const onBackgroundTap = () => {
|
|
261
|
+
if (sheetRef.current) sheetRef.current?.close();
|
|
262
|
+
|
|
263
|
+
setTimeout(() => {
|
|
264
|
+
onOpenChange?.(false);
|
|
265
|
+
}, 300);
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
// Safety check - if no current level, don't render
|
|
269
|
+
if (!currentLevel) {
|
|
270
|
+
return null;
|
|
271
|
+
}
|
|
65
272
|
|
|
66
273
|
return (
|
|
67
274
|
<DropdownMenuPrimitive.Portal hostName={portalHost}>
|
|
68
|
-
<
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
275
|
+
<NavigationStackContext.Provider value={{ stack, push, pop, isNested }}>
|
|
276
|
+
<BottomSheet
|
|
277
|
+
ref={sheetRef}
|
|
278
|
+
enablePanDownToClose
|
|
279
|
+
enableDynamicSizing
|
|
280
|
+
detached={isWide}
|
|
281
|
+
bottomInset={isWide ? 0 : 0}
|
|
282
|
+
backdropComponent={({ style }) => (
|
|
283
|
+
<Pressable
|
|
284
|
+
style={[style, StyleSheet.absoluteFill]}
|
|
285
|
+
onPress={() => onBackgroundTap()}
|
|
286
|
+
/>
|
|
287
|
+
)}
|
|
288
|
+
onClose={() => onOpenChange?.(false)}
|
|
289
|
+
style={[
|
|
290
|
+
overlayStyle,
|
|
291
|
+
StyleSheet.flatten(rest.style),
|
|
292
|
+
isWide && { marginHorizontal: horizontalMargin },
|
|
293
|
+
]}
|
|
294
|
+
backgroundStyle={[zt.bg.popover, a.radius.all.md, a.shadows.md, p[1]]}
|
|
295
|
+
handleIndicatorStyle={[
|
|
296
|
+
a.sizes.width[12],
|
|
297
|
+
a.sizes.height[1],
|
|
298
|
+
zt.bg.mutedForeground,
|
|
299
|
+
]}
|
|
300
|
+
>
|
|
301
|
+
{isNested && (
|
|
302
|
+
<Animated.View
|
|
303
|
+
style={[
|
|
304
|
+
headerAnimatedStyle,
|
|
305
|
+
a.layout.flex.row,
|
|
306
|
+
a.layout.flex.alignCenter,
|
|
307
|
+
px[4],
|
|
308
|
+
pb[2],
|
|
309
|
+
{
|
|
310
|
+
borderBottomWidth: 1,
|
|
311
|
+
borderBottomColor: theme.colors.border,
|
|
312
|
+
},
|
|
313
|
+
]}
|
|
314
|
+
>
|
|
315
|
+
<Pressable
|
|
316
|
+
onPress={pop}
|
|
317
|
+
style={[
|
|
318
|
+
a.layout.flex.row,
|
|
319
|
+
a.layout.flex.alignCenter,
|
|
320
|
+
gap.all[2],
|
|
321
|
+
]}
|
|
322
|
+
hitSlop={80}
|
|
323
|
+
>
|
|
324
|
+
<ChevronLeft size={20} color={theme.colors.foreground} />
|
|
325
|
+
{currentLevel?.title ? (
|
|
326
|
+
<Text size="lg">{currentLevel.title}</Text>
|
|
327
|
+
) : null}
|
|
328
|
+
</Pressable>
|
|
329
|
+
</Animated.View>
|
|
330
|
+
)}
|
|
331
|
+
<Animated.View style={animatedStyle}>
|
|
332
|
+
<BottomSheetScrollView
|
|
333
|
+
style={[px[4]]}
|
|
334
|
+
contentContainerStyle={{
|
|
335
|
+
paddingBottom: insets.bottom + 50,
|
|
336
|
+
overflow: "hidden",
|
|
337
|
+
}}
|
|
338
|
+
>
|
|
339
|
+
{/* Render all stack levels to keep components mounted, but hide non-current ones */}
|
|
340
|
+
{stack.map((level, index) => {
|
|
341
|
+
const isCurrent = index === stack.length - 1;
|
|
342
|
+
return (
|
|
343
|
+
<View
|
|
344
|
+
key={level.key}
|
|
345
|
+
style={[{ display: isCurrent ? "flex" : "none" }]}
|
|
346
|
+
>
|
|
347
|
+
{typeof level.content === "function"
|
|
348
|
+
? level.content({ pressed: true })
|
|
349
|
+
: level.content}
|
|
350
|
+
</View>
|
|
351
|
+
);
|
|
352
|
+
})}
|
|
353
|
+
</BottomSheetScrollView>
|
|
354
|
+
</Animated.View>
|
|
355
|
+
</BottomSheet>
|
|
356
|
+
</NavigationStackContext.Provider>
|
|
94
357
|
</DropdownMenuPrimitive.Portal>
|
|
95
358
|
);
|
|
96
359
|
});
|
|
97
360
|
|
|
98
361
|
export const DropdownMenuSubTrigger = forwardRef<
|
|
99
362
|
any,
|
|
100
|
-
DropdownMenuPrimitive.SubTriggerProps & {
|
|
363
|
+
DropdownMenuPrimitive.SubTriggerProps & {
|
|
364
|
+
inset?: boolean;
|
|
365
|
+
subMenuTitle?: string;
|
|
366
|
+
} & {
|
|
101
367
|
ref?: React.RefObject<DropdownMenuPrimitive.SubTriggerRef>;
|
|
102
368
|
className?: string;
|
|
103
369
|
inset?: boolean;
|
|
104
370
|
children?: React.ReactNode;
|
|
105
371
|
}
|
|
106
|
-
>(({ inset, children, ...props }, ref) => {
|
|
372
|
+
>(({ inset, children, subMenuTitle, ...props }, ref) => {
|
|
373
|
+
const navStack = useNavigationStack();
|
|
374
|
+
const subMenuContext = useContext(SubMenuContext);
|
|
375
|
+
const { icons, theme } = useTheme();
|
|
376
|
+
|
|
377
|
+
// Set the title in the submenu context if provided
|
|
378
|
+
React.useEffect(() => {
|
|
379
|
+
if (subMenuContext && subMenuTitle) {
|
|
380
|
+
subMenuContext.setTitle(subMenuTitle);
|
|
381
|
+
}
|
|
382
|
+
}, [subMenuContext, subMenuTitle]);
|
|
383
|
+
|
|
384
|
+
// If we're in a navigation stack (mobile bottom sheet), handle differently
|
|
385
|
+
if (navStack && subMenuContext) {
|
|
386
|
+
return (
|
|
387
|
+
<Pressable
|
|
388
|
+
onPress={() => {
|
|
389
|
+
subMenuContext.trigger();
|
|
390
|
+
}}
|
|
391
|
+
{...props}
|
|
392
|
+
>
|
|
393
|
+
<View
|
|
394
|
+
style={[
|
|
395
|
+
inset && gap[2],
|
|
396
|
+
layout.flex.row,
|
|
397
|
+
layout.flex.alignCenter,
|
|
398
|
+
a.radius.all.sm,
|
|
399
|
+
py[1],
|
|
400
|
+
pl[2],
|
|
401
|
+
pr[2],
|
|
402
|
+
]}
|
|
403
|
+
>
|
|
404
|
+
{typeof children === "function" ? (
|
|
405
|
+
children({ pressed: true })
|
|
406
|
+
) : typeof children === "string" ? (
|
|
407
|
+
<Text>{children}</Text>
|
|
408
|
+
) : (
|
|
409
|
+
children
|
|
410
|
+
)}
|
|
411
|
+
<View style={[a.layout.position.absolute, a.position.right[1]]}>
|
|
412
|
+
<ChevronRight size={18} color={icons.color.muted} />
|
|
413
|
+
</View>
|
|
414
|
+
</View>
|
|
415
|
+
</Pressable>
|
|
416
|
+
);
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
// Web behavior - use primitive
|
|
107
420
|
const { open } = DropdownMenuPrimitive.useSubContext();
|
|
108
|
-
const { icons } = useTheme();
|
|
109
421
|
const Icon =
|
|
110
422
|
Platform.OS === "web" ? ChevronRight : open ? ChevronUp : ChevronDown;
|
|
111
423
|
return (
|
|
@@ -138,9 +450,42 @@ export const DropdownMenuSubTrigger = forwardRef<
|
|
|
138
450
|
|
|
139
451
|
export const DropdownMenuSubContent = forwardRef<
|
|
140
452
|
any,
|
|
141
|
-
DropdownMenuPrimitive.SubContentProps
|
|
142
|
-
>((props, ref) => {
|
|
453
|
+
DropdownMenuPrimitive.SubContentProps & { children?: ReactNode }
|
|
454
|
+
>(({ children, ...props }, ref) => {
|
|
143
455
|
const { zero: zt } = useTheme();
|
|
456
|
+
const subMenuContext = useContext(SubMenuContext);
|
|
457
|
+
const navStack = useNavigationStack();
|
|
458
|
+
const prevChildrenRef = useRef<ReactNode>(null);
|
|
459
|
+
|
|
460
|
+
// Register a render function that will be called fresh each time
|
|
461
|
+
React.useEffect(() => {
|
|
462
|
+
if (subMenuContext && navStack) {
|
|
463
|
+
// Only update if children reference actually changed
|
|
464
|
+
if (prevChildrenRef.current === children) {
|
|
465
|
+
return;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
prevChildrenRef.current = children;
|
|
469
|
+
|
|
470
|
+
// Pass a function that returns the current children
|
|
471
|
+
subMenuContext.setRenderContent(() => children);
|
|
472
|
+
|
|
473
|
+
// Force a stack update to trigger rerender with the actual children
|
|
474
|
+
if (subMenuContext.key) {
|
|
475
|
+
// Store the children directly so React can handle updates
|
|
476
|
+
//navStack.updateContent(subMenuContext.key, children);
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
}, [children, subMenuContext, navStack]);
|
|
480
|
+
|
|
481
|
+
// On mobile, don't render the subcontent here - it'll be rendered in the nav stack
|
|
482
|
+
// But keep the component mounted so effects run when children change
|
|
483
|
+
if (navStack && subMenuContext) {
|
|
484
|
+
// Component stays mounted to track prop changes, but renders nothing
|
|
485
|
+
return null;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
// Web - use primitive
|
|
144
489
|
return (
|
|
145
490
|
<DropdownMenuPrimitive.SubContent
|
|
146
491
|
ref={ref}
|
|
@@ -157,7 +502,9 @@ export const DropdownMenuSubContent = forwardRef<
|
|
|
157
502
|
a.shadows.md,
|
|
158
503
|
]}
|
|
159
504
|
{...props}
|
|
160
|
-
|
|
505
|
+
>
|
|
506
|
+
{children}
|
|
507
|
+
</DropdownMenuPrimitive.SubContent>
|
|
161
508
|
);
|
|
162
509
|
});
|
|
163
510
|
|
|
@@ -169,6 +516,9 @@ export const DropdownMenuContent = forwardRef<
|
|
|
169
516
|
}
|
|
170
517
|
>(({ overlayStyle, portalHost, style, children, ...props }, ref) => {
|
|
171
518
|
const { zero: zt } = useTheme();
|
|
519
|
+
const { height } = useWindowDimensions();
|
|
520
|
+
const maxHeight = height * 0.8;
|
|
521
|
+
|
|
172
522
|
return (
|
|
173
523
|
<DropdownMenuPrimitive.Portal hostName={portalHost}>
|
|
174
524
|
<DropdownMenuPrimitive.Overlay
|
|
@@ -196,7 +546,7 @@ export const DropdownMenuContent = forwardRef<
|
|
|
196
546
|
}
|
|
197
547
|
{...props}
|
|
198
548
|
>
|
|
199
|
-
<ScrollView showsVerticalScrollIndicator={true}>
|
|
549
|
+
<ScrollView style={{ maxHeight }} showsVerticalScrollIndicator={true}>
|
|
200
550
|
{typeof children === "function"
|
|
201
551
|
? children({ pressed: false })
|
|
202
552
|
: children}
|
|
@@ -265,12 +615,12 @@ export const ResponsiveDropdownMenuContent = forwardRef<any, any>(
|
|
|
265
615
|
const { width } = useWindowDimensions();
|
|
266
616
|
|
|
267
617
|
// On web, you might want to always use the normal dropdown
|
|
268
|
-
const isBottomSheet = Platform.OS !== "web"
|
|
618
|
+
const isBottomSheet = Platform.OS !== "web";
|
|
269
619
|
|
|
270
620
|
if (isBottomSheet) {
|
|
271
621
|
return (
|
|
272
622
|
<DropdownMenuBottomSheet ref={ref} {...props}>
|
|
273
|
-
|
|
623
|
+
{children}
|
|
274
624
|
</DropdownMenuBottomSheet>
|
|
275
625
|
);
|
|
276
626
|
}
|