@mrmeg/expo-ui 0.1.0

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 (112) hide show
  1. package/README.md +96 -0
  2. package/dist/components/Accordion.d.ts +54 -0
  3. package/dist/components/Accordion.js +149 -0
  4. package/dist/components/Alert.d.ts +30 -0
  5. package/dist/components/Alert.js +25 -0
  6. package/dist/components/AnimatedView.d.ts +55 -0
  7. package/dist/components/AnimatedView.js +39 -0
  8. package/dist/components/Badge.d.ts +23 -0
  9. package/dist/components/Badge.js +74 -0
  10. package/dist/components/BottomSheet.d.ts +74 -0
  11. package/dist/components/BottomSheet.js +513 -0
  12. package/dist/components/Button.d.ts +129 -0
  13. package/dist/components/Button.js +216 -0
  14. package/dist/components/Card.d.ts +42 -0
  15. package/dist/components/Card.js +126 -0
  16. package/dist/components/Checkbox.d.ts +39 -0
  17. package/dist/components/Checkbox.js +96 -0
  18. package/dist/components/Collapsible.d.ts +67 -0
  19. package/dist/components/Collapsible.js +38 -0
  20. package/dist/components/Dialog.d.ts +140 -0
  21. package/dist/components/Dialog.js +167 -0
  22. package/dist/components/DismissKeyboard.d.ts +15 -0
  23. package/dist/components/DismissKeyboard.js +13 -0
  24. package/dist/components/Drawer.d.ts +74 -0
  25. package/dist/components/Drawer.js +423 -0
  26. package/dist/components/DropdownMenu.d.ts +120 -0
  27. package/dist/components/DropdownMenu.js +211 -0
  28. package/dist/components/EmptyState.d.ts +42 -0
  29. package/dist/components/EmptyState.js +58 -0
  30. package/dist/components/ErrorBoundary.d.ts +53 -0
  31. package/dist/components/ErrorBoundary.js +75 -0
  32. package/dist/components/Icon.d.ts +46 -0
  33. package/dist/components/Icon.js +40 -0
  34. package/dist/components/InputOTP.d.ts +72 -0
  35. package/dist/components/InputOTP.js +155 -0
  36. package/dist/components/Label.d.ts +61 -0
  37. package/dist/components/Label.js +72 -0
  38. package/dist/components/MaxWidthContainer.d.ts +58 -0
  39. package/dist/components/MaxWidthContainer.js +64 -0
  40. package/dist/components/Notification.d.ts +26 -0
  41. package/dist/components/Notification.js +230 -0
  42. package/dist/components/Popover.d.ts +79 -0
  43. package/dist/components/Popover.js +91 -0
  44. package/dist/components/Progress.d.ts +28 -0
  45. package/dist/components/Progress.js +107 -0
  46. package/dist/components/RadioGroup.d.ts +65 -0
  47. package/dist/components/RadioGroup.js +142 -0
  48. package/dist/components/Select.d.ts +88 -0
  49. package/dist/components/Select.js +172 -0
  50. package/dist/components/Separator.d.ts +83 -0
  51. package/dist/components/Separator.js +85 -0
  52. package/dist/components/Skeleton.d.ts +68 -0
  53. package/dist/components/Skeleton.js +99 -0
  54. package/dist/components/Slider.d.ts +24 -0
  55. package/dist/components/Slider.js +162 -0
  56. package/dist/components/StatusBar.d.ts +1 -0
  57. package/dist/components/StatusBar.js +19 -0
  58. package/dist/components/StyledText.d.ts +161 -0
  59. package/dist/components/StyledText.js +193 -0
  60. package/dist/components/Switch.d.ts +44 -0
  61. package/dist/components/Switch.js +129 -0
  62. package/dist/components/Tabs.d.ts +31 -0
  63. package/dist/components/Tabs.js +127 -0
  64. package/dist/components/TextInput.d.ts +120 -0
  65. package/dist/components/TextInput.js +263 -0
  66. package/dist/components/Toggle.d.ts +106 -0
  67. package/dist/components/Toggle.js +150 -0
  68. package/dist/components/ToggleGroup.d.ts +80 -0
  69. package/dist/components/ToggleGroup.js +189 -0
  70. package/dist/components/Tooltip.d.ts +121 -0
  71. package/dist/components/Tooltip.js +132 -0
  72. package/dist/components/index.d.ts +35 -0
  73. package/dist/components/index.js +35 -0
  74. package/dist/constants/colors.d.ts +82 -0
  75. package/dist/constants/colors.js +116 -0
  76. package/dist/constants/fonts.d.ts +32 -0
  77. package/dist/constants/fonts.js +91 -0
  78. package/dist/constants/index.d.ts +3 -0
  79. package/dist/constants/index.js +3 -0
  80. package/dist/constants/spacing.d.ts +40 -0
  81. package/dist/constants/spacing.js +48 -0
  82. package/dist/hooks/index.d.ts +6 -0
  83. package/dist/hooks/index.js +6 -0
  84. package/dist/hooks/useDimensions.d.ts +19 -0
  85. package/dist/hooks/useDimensions.js +55 -0
  86. package/dist/hooks/useReduceMotion.d.ts +5 -0
  87. package/dist/hooks/useReduceMotion.js +64 -0
  88. package/dist/hooks/useResources.d.ts +12 -0
  89. package/dist/hooks/useResources.js +56 -0
  90. package/dist/hooks/useScalePress.d.ts +57 -0
  91. package/dist/hooks/useScalePress.js +55 -0
  92. package/dist/hooks/useStaggeredEntrance.d.ts +67 -0
  93. package/dist/hooks/useStaggeredEntrance.js +74 -0
  94. package/dist/hooks/useTheme.d.ts +88 -0
  95. package/dist/hooks/useTheme.js +328 -0
  96. package/dist/index.d.ts +5 -0
  97. package/dist/index.js +5 -0
  98. package/dist/lib/animations.d.ts +1 -0
  99. package/dist/lib/animations.js +3 -0
  100. package/dist/lib/haptics.d.ts +3 -0
  101. package/dist/lib/haptics.js +29 -0
  102. package/dist/lib/index.d.ts +3 -0
  103. package/dist/lib/index.js +3 -0
  104. package/dist/lib/sentry.d.ts +16 -0
  105. package/dist/lib/sentry.js +55 -0
  106. package/dist/state/globalUIStore.d.ts +30 -0
  107. package/dist/state/globalUIStore.js +8 -0
  108. package/dist/state/index.d.ts +2 -0
  109. package/dist/state/index.js +2 -0
  110. package/dist/state/themeStore.d.ts +6 -0
  111. package/dist/state/themeStore.js +38 -0
  112. package/package.json +92 -0
@@ -0,0 +1,423 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import React, { createContext, useContext, useState, useReducer, useRef } from "react";
3
+ import { View, Pressable, Animated, StyleSheet, Platform, Dimensions, PanResponder, } from "react-native";
4
+ import { Portal } from "@rn-primitives/portal";
5
+ import { FullWindowOverlay as RNFullWindowOverlay } from "react-native-screens";
6
+ import { Pressable as SlotPressable } from "@rn-primitives/slot";
7
+ import { useTheme } from "../hooks/useTheme";
8
+ import { shouldUseNativeDriver } from "../lib/animations";
9
+ import { spacing } from "../constants/spacing";
10
+ import { TextColorContext, TextClassContext } from "./StyledText";
11
+ import { useSafeAreaInsets } from "react-native-safe-area-context";
12
+ /**
13
+ * Drawer Component with Sub-components
14
+ *
15
+ * A sliding drawer overlay that can appear from left or right side.
16
+ * Supports both controlled and uncontrolled modes.
17
+ * Supports swipe gestures on native platforms and backdrop press to close.
18
+ *
19
+ * @example
20
+ * ```tsx
21
+ * // Uncontrolled (internal state management)
22
+ * <Drawer side="left">
23
+ * <Drawer.Trigger asChild>
24
+ * <Button>Open Menu</Button>
25
+ * </Drawer.Trigger>
26
+ * <Drawer.Content>
27
+ * <Drawer.Header>
28
+ * <SansSerifBoldText>Menu</SansSerifBoldText>
29
+ * </Drawer.Header>
30
+ * <Drawer.Body>
31
+ * <SansSerifText>Content here</SansSerifText>
32
+ * </Drawer.Body>
33
+ * <Drawer.Footer>
34
+ * <DrawerCloseButton />
35
+ * </Drawer.Footer>
36
+ * </Drawer.Content>
37
+ * </Drawer>
38
+ *
39
+ * // Controlled (parent manages state)
40
+ * const [open, setOpen] = useState(false);
41
+ * <Drawer open={open} onOpenChange={setOpen} side="left">
42
+ * ...
43
+ * </Drawer>
44
+ * ```
45
+ */
46
+ // Platform-specific overlay wrapper
47
+ const FullWindowOverlay = Platform.OS === "ios" ? RNFullWindowOverlay : React.Fragment;
48
+ // ============================================================================
49
+ // Context
50
+ // ============================================================================
51
+ const DrawerContext = createContext(null);
52
+ function useDrawerContext() {
53
+ const context = useContext(DrawerContext);
54
+ if (!context) {
55
+ throw new Error("Drawer components must be used within a Drawer");
56
+ }
57
+ return context;
58
+ }
59
+ // ============================================================================
60
+ // Utility Functions
61
+ // ============================================================================
62
+ function parseWidth(width) {
63
+ if (typeof width === "number") {
64
+ return width;
65
+ }
66
+ // Parse percentage string
67
+ const percentage = parseFloat(width) / 100;
68
+ const screenWidth = Dimensions.get("window").width;
69
+ return screenWidth * percentage;
70
+ }
71
+ function drawerReducer(state, action) {
72
+ switch (action.type) {
73
+ case 'OPEN': return true;
74
+ case 'CLOSE': return false;
75
+ case 'TOGGLE': return !state; // Always uses current state!
76
+ }
77
+ }
78
+ // ============================================================================
79
+ // Drawer Root Component
80
+ // ============================================================================
81
+ function DrawerRoot({ open: controlledOpen, onOpenChange: controlledOnOpenChange, defaultOpen = false, side = "left", width = 300, closeOnBackdropPress = true, children, }) {
82
+ // Use reducer for stable state management - dispatch is stable and reducer always gets current state
83
+ const [internalOpen, dispatch] = useReducer(drawerReducer, defaultOpen);
84
+ const isControlled = controlledOpen !== undefined;
85
+ const open = isControlled ? controlledOpen : internalOpen;
86
+ // Stable toggle function - dispatch is stable across renders
87
+ const toggle = () => {
88
+ if (isControlled) {
89
+ // For controlled mode, we need to call the callback with the toggled value
90
+ // We use a functional update pattern via dispatch to ensure we get current state
91
+ controlledOnOpenChange?.(!controlledOpen);
92
+ }
93
+ else {
94
+ dispatch({ type: 'TOGGLE' });
95
+ }
96
+ };
97
+ // Handler for explicit open/close actions
98
+ const onOpenChange = (newOpen) => {
99
+ if (isControlled) {
100
+ controlledOnOpenChange?.(newOpen);
101
+ }
102
+ else {
103
+ dispatch({ type: newOpen ? 'OPEN' : 'CLOSE' });
104
+ }
105
+ };
106
+ const parsedWidth = parseWidth(width);
107
+ const contextValue = {
108
+ open,
109
+ onOpenChange,
110
+ toggle,
111
+ side,
112
+ width: parsedWidth,
113
+ closeOnBackdropPress,
114
+ };
115
+ return (_jsx(DrawerContext.Provider, { value: contextValue, children: children }));
116
+ }
117
+ // ============================================================================
118
+ // Drawer Trigger Component
119
+ // ============================================================================
120
+ function DrawerTrigger({ asChild, children, style: styleOverride }) {
121
+ const { toggle } = useDrawerContext();
122
+ // Use toggle directly - it reads current state from a ref, avoiding stale closures
123
+ const handlePress = () => {
124
+ toggle();
125
+ };
126
+ if (asChild && React.isValidElement(children)) {
127
+ // Clone child and inject onPress directly instead of using SlotPressable
128
+ return React.cloneElement(children, {
129
+ onPress: handlePress,
130
+ accessibilityRole: "button",
131
+ style: [
132
+ children.props.style,
133
+ Platform.OS === "web" && { cursor: "pointer" },
134
+ styleOverride,
135
+ ],
136
+ });
137
+ }
138
+ return (_jsx(Pressable, { onPress: handlePress, accessibilityRole: "button", style: [
139
+ Platform.OS === "web" && { cursor: "pointer" },
140
+ styleOverride,
141
+ ], children: children }));
142
+ }
143
+ // ============================================================================
144
+ // Drawer Content Component
145
+ // ============================================================================
146
+ function DrawerContent({ swipeEnabled = true, swipeThreshold = 0.3, velocityThreshold = 500, style: styleOverride, children, ...props }) {
147
+ const drawerContext = useDrawerContext();
148
+ const { open, onOpenChange, side, width, closeOnBackdropPress } = drawerContext;
149
+ const { theme, getShadowStyle } = useTheme();
150
+ const insets = useSafeAreaInsets();
151
+ // Animation values - initialize based on initial open state
152
+ const closedPosition = side === "left" ? -width : width;
153
+ const translateX = useRef(new Animated.Value(open ? 0 : closedPosition)).current;
154
+ const backdropOpacity = useRef(new Animated.Value(open ? 1 : 0)).current;
155
+ // Track if drawer is actually visible (for unmounting after close animation)
156
+ const [isVisible, setIsVisible] = useState(open);
157
+ // Track what we last animated to - persists across renders
158
+ const lastOpenRef = useRef(null);
159
+ // Track running animation to properly cancel it
160
+ const runningAnimationRef = useRef(null);
161
+ // Use semantic foreground color for text on background
162
+ const textColor = theme.colors.foreground;
163
+ // Trigger animation during render if open changed
164
+ if (open !== lastOpenRef.current) {
165
+ const previousOpen = lastOpenRef.current;
166
+ lastOpenRef.current = open;
167
+ // Stop any running animations immediately
168
+ if (runningAnimationRef.current) {
169
+ runningAnimationRef.current.stop();
170
+ runningAnimationRef.current = null;
171
+ }
172
+ if (open) {
173
+ // Opening - set visible immediately
174
+ if (!isVisible) {
175
+ setIsVisible(true);
176
+ }
177
+ // If this is first render (previousOpen is null), set initial position
178
+ // Otherwise animate from current position (handles mid-animation toggle)
179
+ if (previousOpen === null) {
180
+ translateX.setValue(closedPosition);
181
+ backdropOpacity.setValue(0);
182
+ }
183
+ // Animate to open position from wherever we are
184
+ const animation = Animated.parallel([
185
+ Animated.timing(translateX, {
186
+ toValue: 0,
187
+ duration: 200,
188
+ useNativeDriver: shouldUseNativeDriver,
189
+ }),
190
+ Animated.timing(backdropOpacity, {
191
+ toValue: 1,
192
+ duration: 200,
193
+ useNativeDriver: shouldUseNativeDriver,
194
+ }),
195
+ ]);
196
+ runningAnimationRef.current = animation;
197
+ animation.start(({ finished }) => {
198
+ if (finished) {
199
+ runningAnimationRef.current = null;
200
+ }
201
+ });
202
+ }
203
+ else if (previousOpen === true) {
204
+ // Closing - only animate if we were actually open (skip mount when drawer starts closed)
205
+ const animation = Animated.parallel([
206
+ Animated.timing(translateX, {
207
+ toValue: closedPosition,
208
+ duration: 200,
209
+ useNativeDriver: shouldUseNativeDriver,
210
+ }),
211
+ Animated.timing(backdropOpacity, {
212
+ toValue: 0,
213
+ duration: 200,
214
+ useNativeDriver: shouldUseNativeDriver,
215
+ }),
216
+ ]);
217
+ runningAnimationRef.current = animation;
218
+ animation.start(({ finished }) => {
219
+ runningAnimationRef.current = null;
220
+ // Only hide if animation completed (wasn't interrupted)
221
+ if (finished) {
222
+ setIsVisible(false);
223
+ }
224
+ });
225
+ }
226
+ }
227
+ // Create pan responder for swipe gestures (native only)
228
+ const panResponder = useRef(Platform.OS !== "web" && swipeEnabled
229
+ ? PanResponder.create({
230
+ onStartShouldSetPanResponder: () => false,
231
+ onMoveShouldSetPanResponder: (_evt, gestureState) => {
232
+ // Only respond to horizontal swipes
233
+ const isHorizontal = Math.abs(gestureState.dx) > Math.abs(gestureState.dy);
234
+ const isSignificant = Math.abs(gestureState.dx) > 10;
235
+ // For left drawer, only respond to leftward swipes (negative dx)
236
+ // For right drawer, only respond to rightward swipes (positive dx)
237
+ const isCorrectDirection = (side === "left" && gestureState.dx < 0) ||
238
+ (side === "right" && gestureState.dx > 0);
239
+ return isHorizontal && isSignificant && isCorrectDirection;
240
+ },
241
+ onPanResponderMove: (_evt, gestureState) => {
242
+ // Clamp the translation
243
+ let translation;
244
+ if (side === "left") {
245
+ // Left drawer: allow negative translation (closing)
246
+ translation = Math.min(0, Math.max(-width, gestureState.dx));
247
+ }
248
+ else {
249
+ // Right drawer: allow positive translation (closing)
250
+ translation = Math.max(0, Math.min(width, gestureState.dx));
251
+ }
252
+ translateX.setValue(translation);
253
+ // Update backdrop opacity based on drawer position
254
+ const progress = 1 - Math.abs(translation) / width;
255
+ backdropOpacity.setValue(progress);
256
+ },
257
+ onPanResponderRelease: (_evt, gestureState) => {
258
+ const velocity = side === "left" ? -gestureState.vx : gestureState.vx;
259
+ const translation = Math.abs(gestureState.dx);
260
+ // Determine if we should close
261
+ const shouldClose = translation > width * swipeThreshold || velocity > velocityThreshold / 1000;
262
+ if (shouldClose) {
263
+ // Animate to closed
264
+ const targetX = side === "left" ? -width : width;
265
+ Animated.parallel([
266
+ Animated.spring(translateX, {
267
+ toValue: targetX,
268
+ tension: 65,
269
+ friction: 11,
270
+ useNativeDriver: shouldUseNativeDriver,
271
+ }),
272
+ Animated.timing(backdropOpacity, {
273
+ toValue: 0,
274
+ duration: 200,
275
+ useNativeDriver: shouldUseNativeDriver,
276
+ }),
277
+ ]).start(() => {
278
+ onOpenChange(false);
279
+ setIsVisible(false);
280
+ });
281
+ }
282
+ else {
283
+ // Snap back to open
284
+ Animated.parallel([
285
+ Animated.spring(translateX, {
286
+ toValue: 0,
287
+ tension: 65,
288
+ friction: 11,
289
+ useNativeDriver: shouldUseNativeDriver,
290
+ }),
291
+ Animated.timing(backdropOpacity, {
292
+ toValue: 1,
293
+ duration: 150,
294
+ useNativeDriver: shouldUseNativeDriver,
295
+ }),
296
+ ]).start();
297
+ }
298
+ },
299
+ })
300
+ : null).current;
301
+ // Handle backdrop press
302
+ const handleBackdropPress = () => {
303
+ if (closeOnBackdropPress) {
304
+ onOpenChange(false);
305
+ }
306
+ };
307
+ // Don't render if not visible
308
+ if (!isVisible && !open) {
309
+ return null;
310
+ }
311
+ const shadowStyle = StyleSheet.flatten(getShadowStyle("soft"));
312
+ const drawerStyle = {
313
+ position: "absolute",
314
+ top: 0,
315
+ bottom: 0,
316
+ width,
317
+ [side]: 0,
318
+ backgroundColor: theme.colors.background,
319
+ borderColor: theme.colors.border,
320
+ ...(side === "left"
321
+ ? { borderRightWidth: 1 }
322
+ : { borderLeftWidth: 1 }),
323
+ ...shadowStyle,
324
+ paddingTop: insets.top,
325
+ paddingBottom: insets.bottom,
326
+ ...(Platform.OS === "web" && { zIndex: 51 }),
327
+ };
328
+ const contentElement = (_jsx(Portal, { name: "drawer-portal", children: _jsx(FullWindowOverlay, { children: _jsx(DrawerContext.Provider, { value: drawerContext, children: _jsxs(View, { style: StyleSheet.absoluteFill, children: [_jsx(Animated.View, { style: [
329
+ StyleSheet.absoluteFill,
330
+ {
331
+ backgroundColor: theme.colors.overlay,
332
+ opacity: backdropOpacity,
333
+ },
334
+ Platform.OS === "web" && { zIndex: 50 },
335
+ ], children: _jsx(Pressable, { style: StyleSheet.absoluteFill, onPress: handleBackdropPress, accessibilityRole: "button", accessibilityLabel: "Close drawer" }) }), _jsx(Animated.View, { style: [
336
+ drawerStyle,
337
+ {
338
+ transform: [{ translateX }],
339
+ },
340
+ styleOverride && typeof styleOverride !== "function"
341
+ ? StyleSheet.flatten(styleOverride)
342
+ : undefined,
343
+ ], accessibilityViewIsModal: true, ...(Platform.OS === "web" && {
344
+ role: "dialog",
345
+ "aria-modal": true,
346
+ }), ...(panResponder ? panResponder.panHandlers : {}), ...props, children: _jsx(TextColorContext.Provider, { value: textColor, children: _jsx(TextClassContext.Provider, { value: "", children: children }) }) })] }) }) }) }));
347
+ return contentElement;
348
+ }
349
+ // ============================================================================
350
+ // Drawer Header Component
351
+ // ============================================================================
352
+ function DrawerHeader({ children, style, ...props }) {
353
+ const { theme } = useTheme();
354
+ return (_jsx(View, { style: [
355
+ {
356
+ paddingHorizontal: spacing.md,
357
+ paddingVertical: spacing.md,
358
+ borderBottomWidth: 1,
359
+ borderBottomColor: theme.colors.border,
360
+ },
361
+ style,
362
+ ], ...props, children: children }));
363
+ }
364
+ // ============================================================================
365
+ // Drawer Body Component
366
+ // ============================================================================
367
+ function DrawerBody({ children, style, ...props }) {
368
+ return (_jsx(View, { style: [
369
+ {
370
+ flex: 1,
371
+ paddingHorizontal: spacing.md,
372
+ paddingVertical: spacing.md,
373
+ },
374
+ style,
375
+ ], ...props, children: children }));
376
+ }
377
+ // ============================================================================
378
+ // Drawer Footer Component
379
+ // ============================================================================
380
+ function DrawerFooter({ children, style, ...props }) {
381
+ const { theme } = useTheme();
382
+ return (_jsx(View, { style: [
383
+ {
384
+ paddingHorizontal: spacing.md,
385
+ paddingVertical: spacing.md,
386
+ borderTopWidth: 1,
387
+ borderTopColor: theme.colors.border,
388
+ },
389
+ style,
390
+ ], ...props, children: children }));
391
+ }
392
+ // ============================================================================
393
+ // Close Button Hook (for programmatic close from within drawer)
394
+ // ============================================================================
395
+ function useDrawerClose() {
396
+ const { onOpenChange } = useDrawerContext();
397
+ return () => onOpenChange(false);
398
+ }
399
+ function DrawerClose({ asChild, children, style: styleOverride }) {
400
+ const { onOpenChange } = useDrawerContext();
401
+ const handlePress = () => {
402
+ onOpenChange(false);
403
+ };
404
+ if (asChild) {
405
+ return (_jsx(SlotPressable, { onPress: handlePress, accessibilityRole: "button", accessibilityLabel: "Close", style: [
406
+ Platform.OS === "web" && { cursor: "pointer" },
407
+ styleOverride,
408
+ ], children: children }));
409
+ }
410
+ return (_jsx(Pressable, { onPress: handlePress, accessibilityRole: "button", accessibilityLabel: "Close", style: [
411
+ Platform.OS === "web" && { cursor: "pointer" },
412
+ styleOverride,
413
+ ], children: children }));
414
+ }
415
+ const Drawer = Object.assign(DrawerRoot, {
416
+ Trigger: DrawerTrigger,
417
+ Content: DrawerContent,
418
+ Header: DrawerHeader,
419
+ Body: DrawerBody,
420
+ Footer: DrawerFooter,
421
+ Close: DrawerClose,
422
+ });
423
+ export { Drawer, DrawerTrigger, DrawerContent, DrawerHeader, DrawerBody, DrawerFooter, DrawerClose, useDrawerClose, };
@@ -0,0 +1,120 @@
1
+ import * as React from "react";
2
+ import { type TextStyle, View } from "react-native";
3
+ import * as DropdownMenuPrimitive from "@rn-primitives/dropdown-menu";
4
+ declare const DropdownMenu: {
5
+ ({ asChild, onOpenChange: onOpenChangeProp, ref, ...viewProps }: import("react-native").ViewProps & {
6
+ asChild?: boolean;
7
+ } & {
8
+ onOpenChange?: (open: boolean) => void;
9
+ } & React.RefAttributes<View>): React.JSX.Element;
10
+ displayName: string;
11
+ };
12
+ declare const DropdownMenuTrigger: {
13
+ ({ asChild, onPress: onPressProp, disabled, ref, ...props }: Omit<import("react-native").PressableProps & React.RefAttributes<View>, "ref"> & {
14
+ asChild?: boolean;
15
+ } & {
16
+ onKeyDown?: (ev: React.KeyboardEvent) => void;
17
+ onKeyUp?: (ev: React.KeyboardEvent) => void;
18
+ } & React.RefAttributes<import("@rn-primitives/dropdown-menu").TriggerRef>): React.JSX.Element;
19
+ displayName: string;
20
+ };
21
+ declare const DropdownMenuGroup: {
22
+ ({ asChild, ref, ...props }: import("react-native").ViewProps & {
23
+ asChild?: boolean;
24
+ } & React.RefAttributes<View>): React.JSX.Element;
25
+ displayName: string;
26
+ };
27
+ declare const DropdownMenuPortal: typeof DropdownMenuPrimitive.Portal;
28
+ declare const DropdownMenuSub: {
29
+ ({ asChild, defaultOpen, open: openProp, onOpenChange: onOpenChangeProp, ref, ...props }: import("react-native").ViewProps & {
30
+ asChild?: boolean;
31
+ } & {
32
+ defaultOpen?: boolean;
33
+ open?: boolean;
34
+ onOpenChange?: (value: boolean) => void;
35
+ } & React.RefAttributes<View>): React.JSX.Element;
36
+ displayName: string;
37
+ };
38
+ declare const DropdownMenuRadioGroup: {
39
+ ({ asChild, value, onValueChange, ref, ...props }: import("react-native").ViewProps & {
40
+ asChild?: boolean;
41
+ } & {
42
+ value: string | undefined;
43
+ onValueChange: (value: string) => void;
44
+ } & React.RefAttributes<View>): React.JSX.Element;
45
+ displayName: string;
46
+ };
47
+ /**
48
+ * DropdownMenuSubTrigger Component
49
+ * Trigger for sub-menus with automatic chevron icon
50
+ * Shows ChevronRight on web, ChevronDown/ChevronUp on native based on open state
51
+ */
52
+ type DropdownMenuSubTriggerProps = DropdownMenuPrimitive.SubTriggerProps & {
53
+ inset?: boolean;
54
+ };
55
+ declare function DropdownMenuSubTrigger({ inset, children, style: styleOverride, ...props }: DropdownMenuSubTriggerProps): import("react/jsx-runtime").JSX.Element;
56
+ /**
57
+ * DropdownMenuSubContent Component
58
+ * Content container for sub-menus
59
+ */
60
+ type DropdownMenuSubContentProps = DropdownMenuPrimitive.SubContentProps;
61
+ declare function DropdownMenuSubContent({ style: styleOverride, ...props }: DropdownMenuSubContentProps): import("react/jsx-runtime").JSX.Element;
62
+ /**
63
+ * DropdownMenuContent Component
64
+ * Main dropdown content with portal, overlay, and animation
65
+ *
66
+ * Positioning props:
67
+ * - side: Which side of the trigger to position on ("top" | "bottom" | "left" | "right")
68
+ * - align: Alignment relative to the trigger ("start" | "center" | "end")
69
+ * - sideOffset: Distance from the trigger in pixels (default: 4)
70
+ */
71
+ type DropdownMenuContentProps = DropdownMenuPrimitive.ContentProps & {
72
+ portalHost?: string;
73
+ };
74
+ declare function DropdownMenuContent({ side, align, sideOffset, portalHost, style: styleOverride, ...props }: DropdownMenuContentProps): import("react/jsx-runtime").JSX.Element;
75
+ /**
76
+ * DropdownMenuItem Component
77
+ * Standard menu item with optional destructive variant
78
+ */
79
+ type DropdownMenuItemProps = DropdownMenuPrimitive.ItemProps & {
80
+ inset?: boolean;
81
+ variant?: "default" | "destructive";
82
+ };
83
+ declare function DropdownMenuItem({ inset, variant, style: styleOverride, ...props }: DropdownMenuItemProps): import("react/jsx-runtime").JSX.Element;
84
+ /**
85
+ * DropdownMenuCheckboxItem Component
86
+ * Menu item with checkbox indicator
87
+ */
88
+ type DropdownMenuCheckboxItemProps = DropdownMenuPrimitive.CheckboxItemProps;
89
+ declare function DropdownMenuCheckboxItem({ children, style: styleOverride, ...props }: DropdownMenuCheckboxItemProps): import("react/jsx-runtime").JSX.Element;
90
+ /**
91
+ * DropdownMenuRadioItem Component
92
+ * Menu item with radio button indicator
93
+ */
94
+ type DropdownMenuRadioItemProps = DropdownMenuPrimitive.RadioItemProps;
95
+ declare function DropdownMenuRadioItem({ children, style: styleOverride, ...props }: DropdownMenuRadioItemProps): import("react/jsx-runtime").JSX.Element;
96
+ /**
97
+ * DropdownMenuLabel Component
98
+ * Label for menu sections
99
+ */
100
+ type DropdownMenuLabelProps = DropdownMenuPrimitive.LabelProps & {
101
+ inset?: boolean;
102
+ };
103
+ declare function DropdownMenuLabel({ inset, style: styleOverride, ...props }: DropdownMenuLabelProps): import("react/jsx-runtime").JSX.Element;
104
+ /**
105
+ * DropdownMenuSeparator Component
106
+ * Visual divider between menu sections
107
+ */
108
+ type DropdownMenuSeparatorProps = DropdownMenuPrimitive.SeparatorProps;
109
+ declare function DropdownMenuSeparator({ style: styleOverride, ...props }: DropdownMenuSeparatorProps): import("react/jsx-runtime").JSX.Element;
110
+ /**
111
+ * DropdownMenuShortcut Component
112
+ * Text component for displaying keyboard shortcuts
113
+ */
114
+ interface DropdownMenuShortcutProps {
115
+ children: React.ReactNode;
116
+ style?: TextStyle;
117
+ }
118
+ declare function DropdownMenuShortcut({ style: styleOverride, ...props }: DropdownMenuShortcutProps): import("react/jsx-runtime").JSX.Element;
119
+ export { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, };
120
+ export type { DropdownMenuSubTriggerProps, DropdownMenuSubContentProps, DropdownMenuContentProps, DropdownMenuItemProps, DropdownMenuCheckboxItemProps, DropdownMenuRadioItemProps, DropdownMenuLabelProps, DropdownMenuSeparatorProps, DropdownMenuShortcutProps, };