@mrmeg/expo-ui 0.13.0-rsd.0 → 0.13.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.
- package/CHANGELOG.md +31 -0
- package/LLM_USAGE.md +15 -0
- package/README.md +15 -1
- package/dist/components/Accordion.d.ts +18 -38
- package/dist/components/Accordion.js +121 -137
- package/dist/components/AnimatedView.d.ts +24 -13
- package/dist/components/AnimatedView.js +29 -70
- package/dist/components/Badge.d.ts +2 -2
- package/dist/components/Badge.js +47 -45
- package/dist/components/BottomSheet.d.ts +73 -30
- package/dist/components/BottomSheet.js +225 -191
- package/dist/components/Button.d.ts +56 -43
- package/dist/components/Button.js +203 -189
- package/dist/components/Card.d.ts +10 -7
- package/dist/components/Card.js +105 -90
- package/dist/components/Checkbox.d.ts +8 -20
- package/dist/components/Checkbox.js +80 -77
- package/dist/components/Collapsible.d.ts +47 -47
- package/dist/components/Collapsible.js +29 -108
- package/dist/components/Dialog.d.ts +121 -80
- package/dist/components/Dialog.js +132 -225
- package/dist/components/DismissKeyboard.js +2 -33
- package/dist/components/Drawer.d.ts +83 -37
- package/dist/components/Drawer.js +512 -252
- package/dist/components/DropdownMenu.d.ts +113 -106
- package/dist/components/DropdownMenu.js +204 -350
- package/dist/components/EmptyState.d.ts +2 -2
- package/dist/components/EmptyState.js +34 -41
- package/dist/components/InputOTP.d.ts +53 -19
- package/dist/components/InputOTP.js +102 -81
- package/dist/components/KeyboardAvoidingView.d.ts +3 -6
- package/dist/components/KeyboardAvoidingView.js +5 -18
- package/dist/components/Label.d.ts +17 -12
- package/dist/components/Label.js +51 -38
- package/dist/components/MaxWidthContainer.d.ts +16 -5
- package/dist/components/MaxWidthContainer.js +29 -28
- package/dist/components/Notification.d.ts +9 -5
- package/dist/components/Notification.js +187 -190
- package/dist/components/Popover.d.ts +66 -38
- package/dist/components/Popover.js +69 -158
- package/dist/components/Progress.d.ts +4 -5
- package/dist/components/Progress.js +77 -65
- package/dist/components/RadioGroup.d.ts +24 -30
- package/dist/components/RadioGroup.js +94 -90
- package/dist/components/Select.d.ts +74 -62
- package/dist/components/Select.js +154 -241
- package/dist/components/Separator.d.ts +23 -13
- package/dist/components/Separator.js +36 -29
- package/dist/components/Skeleton.d.ts +7 -8
- package/dist/components/Skeleton.js +61 -74
- package/dist/components/StyledText.context.d.ts +2 -6
- package/dist/components/StyledText.context.js +0 -3
- package/dist/components/StyledText.d.ts +7 -29
- package/dist/components/StyledText.js +29 -92
- package/dist/components/Switch.d.ts +6 -18
- package/dist/components/Switch.js +106 -112
- package/dist/components/Tabs.d.ts +16 -26
- package/dist/components/Tabs.js +91 -189
- package/dist/components/TextInput.d.ts +19 -6
- package/dist/components/TextInput.js +198 -226
- package/dist/components/Toggle.d.ts +41 -23
- package/dist/components/Toggle.js +98 -84
- package/dist/components/ToggleGroup.d.ts +29 -37
- package/dist/components/ToggleGroup.js +108 -113
- package/dist/components/Tooltip.d.ts +111 -41
- package/dist/components/Tooltip.js +118 -156
- package/dist/components/UIProvider.d.ts +1 -1
- package/dist/components/UIProvider.js +1 -1
- package/dist/components/keyboardFocusRegistry.d.ts +15 -1
- package/dist/components/keyboardFocusRegistry.js +39 -2
- package/dist/hooks/useTheme.d.ts +10 -34
- package/dist/hooks/useTheme.js +8 -20
- package/dist/lib/index.d.ts +0 -2
- package/dist/lib/index.js +0 -2
- package/package.json +29 -11
- package/dist/lib/portal.d.ts +0 -16
- package/dist/lib/portal.js +0 -84
- package/dist/lib/styles.d.ts +0 -32
- package/dist/lib/styles.js +0 -91
- package/dist/lib/useAnchoredPosition.d.ts +0 -57
- package/dist/lib/useAnchoredPosition.js +0 -120
|
@@ -1,232 +1,84 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import * as React from "react";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import {
|
|
3
|
+
import { Platform, StyleSheet, View } from "react-native";
|
|
4
|
+
import { FullWindowOverlay as RNFullWindowOverlay } from "react-native-screens";
|
|
5
|
+
import * as DialogPrimitive from "@rn-primitives/dialog";
|
|
6
|
+
import * as AlertDialogPrimitive from "@rn-primitives/alert-dialog";
|
|
7
|
+
import { AnimatedView } from "./AnimatedView.js";
|
|
8
8
|
import { TextClassContext, TextColorContext } from "./StyledText.context";
|
|
9
9
|
import { StyledText } from "./StyledText.js";
|
|
10
10
|
import { useTheme } from "../hooks/useTheme.js";
|
|
11
11
|
import { spacing } from "../constants/spacing.js";
|
|
12
12
|
import { palette } from "../constants/colors.js";
|
|
13
|
-
const
|
|
14
|
-
const DialogContext = createContext(null);
|
|
15
|
-
function useDialogContext(component) {
|
|
16
|
-
const ctx = use(DialogContext);
|
|
17
|
-
if (!ctx) {
|
|
18
|
-
throw new Error(`${component} must be used within a <Dialog> / <AlertDialog>`);
|
|
19
|
-
}
|
|
20
|
-
return ctx;
|
|
21
|
-
}
|
|
22
|
-
function createDialogRoot(variant) {
|
|
23
|
-
return function DialogRoot({ children, open: openProp, defaultOpen, onOpenChange, }) {
|
|
24
|
-
const [uncontrolledOpen, setUncontrolledOpen] = useState(defaultOpen ?? false);
|
|
25
|
-
const isControlled = openProp !== undefined;
|
|
26
|
-
const open = isControlled ? openProp : uncontrolledOpen;
|
|
27
|
-
const baseId = useId();
|
|
28
|
-
const setOpen = useCallback((next) => {
|
|
29
|
-
if (!isControlled)
|
|
30
|
-
setUncontrolledOpen(next);
|
|
31
|
-
onOpenChange?.(next);
|
|
32
|
-
}, [isControlled, onOpenChange]);
|
|
33
|
-
const value = useMemo(() => ({
|
|
34
|
-
open,
|
|
35
|
-
setOpen,
|
|
36
|
-
variant,
|
|
37
|
-
titleId: `${baseId}-title`,
|
|
38
|
-
descriptionId: `${baseId}-desc`,
|
|
39
|
-
dismissOnOverlay: variant === "dialog",
|
|
40
|
-
}), [open, setOpen, baseId]);
|
|
41
|
-
return _jsx(DialogContext.Provider, { value: value, children: children });
|
|
42
|
-
};
|
|
43
|
-
}
|
|
13
|
+
const FullWindowOverlay = Platform.OS === "ios" ? RNFullWindowOverlay : React.Fragment;
|
|
44
14
|
// ============================================================================
|
|
45
|
-
//
|
|
15
|
+
// Dialog
|
|
46
16
|
// ============================================================================
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
*/
|
|
52
|
-
function SlotPressable({ asChild, onActivate, children, }) {
|
|
53
|
-
if (asChild && React.isValidElement(children)) {
|
|
54
|
-
const child = children;
|
|
55
|
-
return React.cloneElement(child, {
|
|
56
|
-
onPress: () => {
|
|
57
|
-
child.props.onPress?.();
|
|
58
|
-
onActivate();
|
|
59
|
-
},
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
return (_jsx(html.button, { type: "button", onClick: onActivate, children: children }));
|
|
63
|
-
}
|
|
64
|
-
function DialogTrigger({ asChild, children, }) {
|
|
65
|
-
const { setOpen } = useDialogContext("DialogTrigger");
|
|
66
|
-
return (_jsx(SlotPressable, { asChild: asChild, onActivate: () => setOpen(true), children: children }));
|
|
67
|
-
}
|
|
68
|
-
function DialogClose({ asChild, children, }) {
|
|
69
|
-
const { setOpen } = useDialogContext("DialogClose");
|
|
70
|
-
return (_jsx(SlotPressable, { asChild: asChild, onActivate: () => setOpen(false), children: children }));
|
|
17
|
+
const DialogTrigger = DialogPrimitive.Trigger;
|
|
18
|
+
const DialogClose = DialogPrimitive.Close;
|
|
19
|
+
function DialogRoot({ children, ...props }) {
|
|
20
|
+
return _jsx(DialogPrimitive.Root, { ...props, children: children });
|
|
71
21
|
}
|
|
72
|
-
|
|
73
|
-
// Content (Portal + Overlay + centered card)
|
|
74
|
-
// ============================================================================
|
|
75
|
-
// css.keyframes() MUST be called inline and unconditionally, before the
|
|
76
|
-
// css.create() that references it: StyleX's babel plugin (web) only folds a
|
|
77
|
-
// keyframe name defined in the same file, and it cannot fold a runtime ternary
|
|
78
|
-
// condition (`Platform.OS === "web" ? ... : ""` throws "Referenced constant is
|
|
79
|
-
// not defined" in dev). On native css.keyframes is a no-op returning its arg,
|
|
80
|
-
// and the animationName has no visible effect (native animation fidelity gap).
|
|
81
|
-
const fadeIn = css.keyframes({
|
|
82
|
-
from: { opacity: 0 },
|
|
83
|
-
to: { opacity: 1 },
|
|
84
|
-
});
|
|
85
|
-
const scaleIn = css.keyframes({
|
|
86
|
-
from: { opacity: 0, transform: "scale(0.95)" },
|
|
87
|
-
to: { opacity: 1, transform: "scale(1)" },
|
|
88
|
-
});
|
|
89
|
-
const styles = css.create({
|
|
90
|
-
overlay: (backgroundColor, zIndex) => ({
|
|
91
|
-
position: "fixed",
|
|
92
|
-
top: 0,
|
|
93
|
-
left: 0,
|
|
94
|
-
right: 0,
|
|
95
|
-
bottom: 0,
|
|
96
|
-
backgroundColor,
|
|
97
|
-
display: "flex",
|
|
98
|
-
alignItems: "center",
|
|
99
|
-
justifyContent: "center",
|
|
100
|
-
zIndex,
|
|
101
|
-
// Fade-in on web; instant on native (animation props are no-ops there).
|
|
102
|
-
animationName: fadeIn,
|
|
103
|
-
animationDuration: "0.2s",
|
|
104
|
-
animationTimingFunction: "ease-out",
|
|
105
|
-
}),
|
|
106
|
-
// Native uses absolute fill rather than position:fixed (RSD maps fixed→
|
|
107
|
-
// absolute on native, but be explicit for the full-screen scrim).
|
|
108
|
-
overlayNative: {
|
|
109
|
-
position: "absolute",
|
|
110
|
-
},
|
|
111
|
-
// html.div defaults to display:block on web (not RN flexbox), so set flex
|
|
112
|
-
// explicitly on the wrapper + card to lay out their children predictably.
|
|
113
|
-
sizer: {
|
|
114
|
-
display: "flex",
|
|
115
|
-
flexDirection: "column",
|
|
116
|
-
width: "90%",
|
|
117
|
-
maxWidth: 450,
|
|
118
|
-
maxHeight: "85%",
|
|
119
|
-
animationName: scaleIn,
|
|
120
|
-
animationDuration: "0.25s",
|
|
121
|
-
animationTimingFunction: "ease-out",
|
|
122
|
-
},
|
|
123
|
-
card: (backgroundColor, borderColor, borderRadius, padding, boxShadow) => ({
|
|
124
|
-
display: "flex",
|
|
125
|
-
flexDirection: "column",
|
|
126
|
-
backgroundColor,
|
|
127
|
-
borderColor,
|
|
128
|
-
borderWidth: 1,
|
|
129
|
-
borderStyle: "solid",
|
|
130
|
-
borderRadius,
|
|
131
|
-
padding,
|
|
132
|
-
width: "100%",
|
|
133
|
-
boxShadow,
|
|
134
|
-
}),
|
|
135
|
-
header: (gap, marginBottom) => ({
|
|
136
|
-
display: "flex",
|
|
137
|
-
flexDirection: "column",
|
|
138
|
-
gap,
|
|
139
|
-
marginBottom,
|
|
140
|
-
}),
|
|
141
|
-
footer: (gap, marginTop) => ({
|
|
142
|
-
display: "flex",
|
|
143
|
-
flexDirection: "row",
|
|
144
|
-
justifyContent: "flex-end",
|
|
145
|
-
gap,
|
|
146
|
-
marginTop,
|
|
147
|
-
}),
|
|
148
|
-
});
|
|
149
|
-
function DialogContentImpl({ children, style, portalHost }) {
|
|
150
|
-
const ctx = useDialogContext("DialogContent");
|
|
151
|
-
const { open, setOpen, variant, titleId, descriptionId, dismissOnOverlay } = ctx;
|
|
22
|
+
function DialogContent({ portalHost, style, children, ...props }) {
|
|
152
23
|
const { theme, getShadowStyle, getContrastingColor } = useTheme();
|
|
153
|
-
const cardRef = useRef(null);
|
|
154
24
|
const textColor = getContrastingColor(theme.colors.popover, palette.white, palette.black);
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
cardRef.current?.focus?.();
|
|
172
|
-
}, [open]);
|
|
173
|
-
if (!open)
|
|
174
|
-
return null;
|
|
175
|
-
const handleOverlayClick = () => {
|
|
176
|
-
if (dismissOnOverlay)
|
|
177
|
-
setOpen(false);
|
|
178
|
-
};
|
|
179
|
-
// The Portal renders into a separate subtree (the PortalHost), so the
|
|
180
|
-
// DialogContext from the provider above is NOT visible there. Re-provide it
|
|
181
|
-
// inside the portal so Title/Description (which read titleId/descriptionId)
|
|
182
|
-
// and Close work from within the portaled content.
|
|
183
|
-
return (_jsx(Portal, { hostName: portalHost, children: _jsx(DialogContext.Provider, { value: ctx, children: _jsx(html.div, { style: [styles.overlay(theme.colors.overlay, zIndex), !isWeb ? styles.overlayNative : null], onClick: dismissOnOverlay ? handleOverlayClick : undefined, children: _jsx(html.div, { style: styles.sizer, children: _jsx(TextColorContext.Provider, { value: textColor, children: _jsx(TextClassContext.Provider, { value: "", children: _jsx(html.div, { ref: cardRef, role: variant === "alertdialog" ? "alertdialog" : "dialog", "aria-modal": true, "aria-labelledby": titleId, "aria-describedby": descriptionId, tabIndex: -1,
|
|
184
|
-
// Stop clicks inside the card from bubbling to the overlay scrim.
|
|
185
|
-
onClick: (e) => e.stopPropagation?.(), style: [
|
|
186
|
-
styles.card(theme.colors.popover, theme.colors.border, spacing.radiusLg, spacing.lg, getShadowStyle("soft").boxShadow ?? "none"),
|
|
187
|
-
style,
|
|
188
|
-
], children: children }) }) }) }) }) }) }));
|
|
189
|
-
}
|
|
190
|
-
// ============================================================================
|
|
191
|
-
// Header / Footer / Title / Description
|
|
192
|
-
// ============================================================================
|
|
193
|
-
function DialogHeader({ children, style }) {
|
|
194
|
-
return (_jsx(html.div, { style: [styles.header(spacing.xs, spacing.md), style], children: children }));
|
|
25
|
+
return (_jsx(DialogPrimitive.Portal, { hostName: portalHost, children: _jsx(FullWindowOverlay, { children: _jsx(DialogPrimitive.Overlay, { style: StyleSheet.flatten([
|
|
26
|
+
StyleSheet.absoluteFill,
|
|
27
|
+
{ backgroundColor: theme.colors.overlay },
|
|
28
|
+
Platform.OS === "web" && { zIndex: 50 },
|
|
29
|
+
]), children: _jsx(AnimatedView, { type: "fade", enterDuration: 200, style: StyleSheet.absoluteFill, children: _jsx(View, { style: overlayStyles.centeredContainer, children: _jsx(AnimatedView, { type: "scale", enterDuration: 250, style: overlayStyles.sizer, children: _jsx(TextColorContext.Provider, { value: textColor, children: _jsx(TextClassContext.Provider, { value: "", children: _jsx(DialogPrimitive.Content, { style: StyleSheet.flatten([
|
|
30
|
+
{
|
|
31
|
+
backgroundColor: theme.colors.popover,
|
|
32
|
+
borderColor: theme.colors.border,
|
|
33
|
+
borderWidth: 1,
|
|
34
|
+
borderRadius: spacing.radiusLg,
|
|
35
|
+
padding: spacing.lg,
|
|
36
|
+
width: "100%",
|
|
37
|
+
...getShadowStyle("soft"),
|
|
38
|
+
},
|
|
39
|
+
style,
|
|
40
|
+
]), ...props, children: children }) }) }) }) }) }) }) }) }));
|
|
195
41
|
}
|
|
196
|
-
function
|
|
197
|
-
return (_jsx(
|
|
42
|
+
function DialogHeader({ children, style, ...props }) {
|
|
43
|
+
return (_jsx(View, { style: StyleSheet.flatten([{ gap: spacing.xs, marginBottom: spacing.md }, style]), ...props, children: children }));
|
|
198
44
|
}
|
|
199
|
-
function
|
|
200
|
-
return
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
45
|
+
function DialogFooter({ children, style, ...props }) {
|
|
46
|
+
return (_jsx(View, { style: StyleSheet.flatten([
|
|
47
|
+
{
|
|
48
|
+
flexDirection: "row",
|
|
49
|
+
justifyContent: "flex-end",
|
|
50
|
+
gap: spacing.sm,
|
|
51
|
+
marginTop: spacing.lg,
|
|
52
|
+
},
|
|
205
53
|
style,
|
|
206
|
-
]);
|
|
207
|
-
return (_jsx(StyledText, { id: titleId, fontWeight: "semibold", style: merged, children: children }));
|
|
208
|
-
};
|
|
54
|
+
]), ...props, children: children }));
|
|
209
55
|
}
|
|
210
|
-
function
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
56
|
+
function DialogTitle({ children, style, ...props }) {
|
|
57
|
+
const { theme } = useTheme();
|
|
58
|
+
return (_jsx(DialogPrimitive.Title, { asChild: true, children: _jsx(StyledText, { fontWeight: "semibold", style: StyleSheet.flatten([
|
|
59
|
+
{
|
|
60
|
+
fontSize: 18,
|
|
61
|
+
lineHeight: 24,
|
|
62
|
+
letterSpacing: 0,
|
|
63
|
+
color: theme.colors.text,
|
|
64
|
+
},
|
|
65
|
+
style,
|
|
66
|
+
]), ...props, children: children }) }));
|
|
67
|
+
}
|
|
68
|
+
function DialogDescription({ children, style, ...props }) {
|
|
69
|
+
const { theme } = useTheme();
|
|
70
|
+
return (_jsx(DialogPrimitive.Description, { asChild: true, children: _jsx(StyledText, { style: StyleSheet.flatten([
|
|
71
|
+
{
|
|
72
|
+
fontSize: 14,
|
|
73
|
+
lineHeight: 20,
|
|
74
|
+
color: theme.colors.textDim,
|
|
75
|
+
},
|
|
76
|
+
style,
|
|
77
|
+
]), ...props, children: children }) }));
|
|
220
78
|
}
|
|
221
|
-
// ============================================================================
|
|
222
|
-
// Dialog assembly
|
|
223
|
-
// ============================================================================
|
|
224
|
-
const DialogRoot = createDialogRoot("dialog");
|
|
225
|
-
const DialogTitle = createTitle("dialog");
|
|
226
|
-
const DialogDescription = createDescription("dialog");
|
|
227
79
|
const Dialog = Object.assign(DialogRoot, {
|
|
228
80
|
Trigger: DialogTrigger,
|
|
229
|
-
Content:
|
|
81
|
+
Content: DialogContent,
|
|
230
82
|
Header: DialogHeader,
|
|
231
83
|
Footer: DialogFooter,
|
|
232
84
|
Title: DialogTitle,
|
|
@@ -234,25 +86,60 @@ const Dialog = Object.assign(DialogRoot, {
|
|
|
234
86
|
Close: DialogClose,
|
|
235
87
|
});
|
|
236
88
|
// ============================================================================
|
|
237
|
-
// AlertDialog
|
|
89
|
+
// AlertDialog
|
|
238
90
|
// ============================================================================
|
|
239
|
-
const
|
|
240
|
-
const
|
|
241
|
-
const
|
|
242
|
-
function
|
|
243
|
-
return _jsx(
|
|
91
|
+
const AlertDialogTrigger = AlertDialogPrimitive.Trigger;
|
|
92
|
+
const AlertDialogAction = AlertDialogPrimitive.Action;
|
|
93
|
+
const AlertDialogCancel = AlertDialogPrimitive.Cancel;
|
|
94
|
+
function AlertDialogRoot({ children, ...props }) {
|
|
95
|
+
return _jsx(AlertDialogPrimitive.Root, { ...props, children: children });
|
|
244
96
|
}
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
97
|
+
function AlertDialogContent({ portalHost, style, children, ...props }) {
|
|
98
|
+
const { theme, getShadowStyle, getContrastingColor } = useTheme();
|
|
99
|
+
const textColor = getContrastingColor(theme.colors.popover, palette.white, palette.black);
|
|
100
|
+
return (_jsx(AlertDialogPrimitive.Portal, { hostName: portalHost, children: _jsx(FullWindowOverlay, { children: _jsx(AlertDialogPrimitive.Overlay, { style: StyleSheet.flatten([
|
|
101
|
+
StyleSheet.absoluteFill,
|
|
102
|
+
{ backgroundColor: theme.colors.overlay },
|
|
103
|
+
Platform.OS === "web" && { zIndex: 52 },
|
|
104
|
+
]), children: _jsx(AnimatedView, { type: "fade", enterDuration: 200, style: StyleSheet.absoluteFill, children: _jsx(View, { style: overlayStyles.centeredContainer, children: _jsx(AnimatedView, { type: "scale", enterDuration: 250, style: overlayStyles.sizer, children: _jsx(TextColorContext.Provider, { value: textColor, children: _jsx(TextClassContext.Provider, { value: "", children: _jsx(AlertDialogPrimitive.Content, { style: StyleSheet.flatten([
|
|
105
|
+
{
|
|
106
|
+
backgroundColor: theme.colors.popover,
|
|
107
|
+
borderColor: theme.colors.border,
|
|
108
|
+
borderWidth: 1,
|
|
109
|
+
borderRadius: spacing.radiusLg,
|
|
110
|
+
padding: spacing.lg,
|
|
111
|
+
width: "100%",
|
|
112
|
+
...getShadowStyle("soft"),
|
|
113
|
+
},
|
|
114
|
+
style,
|
|
115
|
+
]), ...props, children: children }) }) }) }) }) }) }) }) }));
|
|
248
116
|
}
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
return _jsx(
|
|
117
|
+
function AlertDialogTitle({ children, style, ...props }) {
|
|
118
|
+
const { theme } = useTheme();
|
|
119
|
+
return (_jsx(AlertDialogPrimitive.Title, { asChild: true, children: _jsx(StyledText, { fontWeight: "semibold", style: StyleSheet.flatten([
|
|
120
|
+
{
|
|
121
|
+
fontSize: 18,
|
|
122
|
+
lineHeight: 24,
|
|
123
|
+
letterSpacing: 0,
|
|
124
|
+
color: theme.colors.text,
|
|
125
|
+
},
|
|
126
|
+
style,
|
|
127
|
+
]), ...props, children: children }) }));
|
|
128
|
+
}
|
|
129
|
+
function AlertDialogDescription({ children, style, ...props }) {
|
|
130
|
+
const { theme } = useTheme();
|
|
131
|
+
return (_jsx(AlertDialogPrimitive.Description, { asChild: true, children: _jsx(StyledText, { style: StyleSheet.flatten([
|
|
132
|
+
{
|
|
133
|
+
fontSize: 14,
|
|
134
|
+
lineHeight: 20,
|
|
135
|
+
color: theme.colors.textDim,
|
|
136
|
+
},
|
|
137
|
+
style,
|
|
138
|
+
]), ...props, children: children }) }));
|
|
252
139
|
}
|
|
253
140
|
const AlertDialog = Object.assign(AlertDialogRoot, {
|
|
254
141
|
Trigger: AlertDialogTrigger,
|
|
255
|
-
Content:
|
|
142
|
+
Content: AlertDialogContent,
|
|
256
143
|
Header: DialogHeader,
|
|
257
144
|
Footer: DialogFooter,
|
|
258
145
|
Title: AlertDialogTitle,
|
|
@@ -261,8 +148,28 @@ const AlertDialog = Object.assign(AlertDialogRoot, {
|
|
|
261
148
|
Cancel: AlertDialogCancel,
|
|
262
149
|
});
|
|
263
150
|
// ============================================================================
|
|
151
|
+
// Shared styles
|
|
152
|
+
// ============================================================================
|
|
153
|
+
const overlayStyles = StyleSheet.create({
|
|
154
|
+
centeredContainer: {
|
|
155
|
+
flex: 1,
|
|
156
|
+
justifyContent: "center",
|
|
157
|
+
alignItems: "center",
|
|
158
|
+
},
|
|
159
|
+
// Sizes the dialog relative to the full-screen centered container. Both the
|
|
160
|
+
// width AND maxHeight must live on this wrapper (the direct flex child of the
|
|
161
|
+
// full-screen container) rather than on Content: a percentage resolves
|
|
162
|
+
// against the parent's resolved box, and this wrapper's box is the screen.
|
|
163
|
+
// Putting `maxHeight: "85%"` on Content instead resolves it against this
|
|
164
|
+
// (content-sized) wrapper — clamping the card to 85% of its own content
|
|
165
|
+
// height, so the footer spills out the bottom.
|
|
166
|
+
sizer: {
|
|
167
|
+
width: "90%",
|
|
168
|
+
maxWidth: 450,
|
|
169
|
+
maxHeight: "85%",
|
|
170
|
+
},
|
|
171
|
+
});
|
|
172
|
+
// ============================================================================
|
|
264
173
|
// Exports
|
|
265
174
|
// ============================================================================
|
|
266
|
-
const DialogContent = DialogContentImpl;
|
|
267
|
-
const AlertDialogContent = DialogContentImpl;
|
|
268
175
|
export { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogFooter, DialogTitle, DialogDescription, DialogClose, AlertDialog, AlertDialogTrigger, AlertDialogContent, AlertDialogTitle, AlertDialogDescription, AlertDialogAction, AlertDialogCancel, };
|
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import React from "react";
|
|
3
3
|
import { Platform, ScrollView, View, } from "react-native";
|
|
4
|
-
import { css, html } from "react-strict-dom";
|
|
5
4
|
import { KeyboardController, useKeyboardContext, useKeyboardState, } from "react-native-keyboard-controller";
|
|
6
5
|
import { KeyboardAvoidingView, useKeyboardAvoidance } from "./KeyboardAvoidingView.js";
|
|
7
6
|
import { isTouchInsideKeyboardFocusedInput } from "./keyboardFocusRegistry.js";
|
|
8
|
-
import { sanitizeWebStyle } from "../lib/styles.js";
|
|
9
|
-
const IS_WEB = Platform.OS === "web";
|
|
10
7
|
/**
|
|
11
8
|
* Native tap-away keyboard dismissal.
|
|
12
9
|
*
|
|
@@ -35,35 +32,10 @@ function useDismissKeyboardOnOutsideTouch() {
|
|
|
35
32
|
return false;
|
|
36
33
|
}, [focusedInput, isVisible]);
|
|
37
34
|
}
|
|
38
|
-
const webStyles = css.create({
|
|
39
|
-
fill: { display: "flex", flexDirection: "column", flexGrow: 1, flexShrink: 1, flexBasis: "0%" },
|
|
40
|
-
scroller: {
|
|
41
|
-
display: "flex",
|
|
42
|
-
flexDirection: "column",
|
|
43
|
-
flexGrow: 1,
|
|
44
|
-
flexShrink: 1,
|
|
45
|
-
flexBasis: "0%",
|
|
46
|
-
justifyContent: "center",
|
|
47
|
-
overflowY: "auto",
|
|
48
|
-
},
|
|
49
|
-
});
|
|
50
35
|
/**
|
|
51
|
-
*
|
|
52
|
-
* tap-away + responder-capture logic is inert here — this is purely the layout
|
|
53
|
-
* wrapper, rebuilt on react-strict-dom (html.div) so web is RNW-free. A
|
|
54
|
-
* scrollable variant uses overflowY:auto; otherwise it's a flex fill.
|
|
55
|
-
*/
|
|
56
|
-
function WebDismissKeyboardLayout({ children, style, scrollable = true }) {
|
|
57
|
-
return (_jsx(html.div, { style: [
|
|
58
|
-
scrollable ? webStyles.scroller : webStyles.fill,
|
|
59
|
-
sanitizeWebStyle(style),
|
|
60
|
-
], children: children }));
|
|
61
|
-
}
|
|
62
|
-
/**
|
|
63
|
-
* Native layout — unchanged: RN ScrollView/View (no RSD scroll analog) plus the
|
|
64
|
-
* KeyboardAvoidingView path and the responder-capture tap-away dismissal.
|
|
36
|
+
* @returns Wrapper for a view that dismisses the keyboard when tapped outside of a text input
|
|
65
37
|
*/
|
|
66
|
-
function
|
|
38
|
+
function DismissKeyboardLayout({ children, style, avoidKeyboard = true, scrollable = true, dismissOnTouchStart, }) {
|
|
67
39
|
const hasKeyboardAvoidance = useKeyboardAvoidance();
|
|
68
40
|
const content = scrollable ? (_jsx(ScrollView, { style: { flex: 1 }, contentContainerStyle: { flexGrow: 1, justifyContent: "center" }, keyboardShouldPersistTaps: "handled", showsVerticalScrollIndicator: false, children: children })) : (children);
|
|
69
41
|
if (!avoidKeyboard || hasKeyboardAvoidance) {
|
|
@@ -71,9 +43,6 @@ function NativeDismissKeyboardLayout({ children, style, avoidKeyboard = true, sc
|
|
|
71
43
|
}
|
|
72
44
|
return (_jsx(KeyboardAvoidingView, { style: [{ flex: 1, width: "100%" }, style], keyboardVerticalOffset: Platform.OS === "ios" ? 0 : 0, onStartShouldSetResponderCapture: dismissOnTouchStart, children: content }));
|
|
73
45
|
}
|
|
74
|
-
function DismissKeyboardLayout(props) {
|
|
75
|
-
return IS_WEB ? _jsx(WebDismissKeyboardLayout, { ...props }) : _jsx(NativeDismissKeyboardLayout, { ...props });
|
|
76
|
-
}
|
|
77
46
|
function NativeDismissKeyboard(props) {
|
|
78
47
|
const dismissOnTouchStart = useDismissKeyboardOnOutsideTouch();
|
|
79
48
|
return (_jsx(DismissKeyboardLayout, { ...props, dismissOnTouchStart: dismissOnTouchStart }));
|
|
@@ -1,74 +1,120 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { ViewProps, StyleProp, ViewStyle } from "react-native";
|
|
3
|
+
type DrawerSide = "left" | "right";
|
|
3
4
|
/**
|
|
4
|
-
* Drawer
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* + backdrop fade) and a CSS width transition (rail). Native shows instantly —
|
|
9
|
-
* the package ships no Reanimated, and there's no RSD swipe-gesture analog, so
|
|
10
|
-
* the previous PanResponder swipe-to-close is a documented native gap.
|
|
5
|
+
* Drawer presentation mode.
|
|
6
|
+
* - `"overlay"` (default): modal drawer that slides in over content with a backdrop.
|
|
7
|
+
* - `"rail"`: docked, always-mounted collapsible sidebar (icon strip that expands to
|
|
8
|
+
* a labeled panel). It is in-flow and pushes sibling content as it grows.
|
|
11
9
|
*/
|
|
12
|
-
type DrawerSide = "left" | "right";
|
|
13
10
|
type DrawerVariant = "overlay" | "rail";
|
|
14
|
-
|
|
11
|
+
interface DrawerProps {
|
|
12
|
+
/** Controlled open state */
|
|
15
13
|
open?: boolean;
|
|
14
|
+
/** Callback when open state changes */
|
|
16
15
|
onOpenChange?: (open: boolean) => void;
|
|
16
|
+
/** Default open state for uncontrolled mode */
|
|
17
17
|
defaultOpen?: boolean;
|
|
18
|
+
/** Which side the drawer appears from */
|
|
18
19
|
side?: DrawerSide;
|
|
19
|
-
/** Drawer width in
|
|
20
|
+
/** Drawer width in pixels or percentage string (overlay mode only) */
|
|
20
21
|
width?: number | `${number}%`;
|
|
22
|
+
/** Whether to close when backdrop is pressed */
|
|
21
23
|
closeOnBackdropPress?: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Presentation mode. `"overlay"` (default) is the classic modal drawer;
|
|
26
|
+
* `"rail"` is a docked collapsible sidebar. See {@link DrawerVariant}.
|
|
27
|
+
*/
|
|
22
28
|
variant?: DrawerVariant;
|
|
23
|
-
/** Collapsed (icon-strip) width for rail mode. @default 72 */
|
|
29
|
+
/** Collapsed (icon-strip) width in pixels for rail mode. @default 72 */
|
|
24
30
|
collapsedWidth?: number;
|
|
25
|
-
/** Expanded (labeled-panel) width for rail mode. @default 240 */
|
|
31
|
+
/** Expanded (labeled-panel) width in pixels for rail mode. @default 240 */
|
|
26
32
|
expandedWidth?: number;
|
|
27
|
-
/**
|
|
33
|
+
/**
|
|
34
|
+
* Whether the rail expands on hover (web only — native has no hover).
|
|
35
|
+
* @default true on web, false on native
|
|
36
|
+
*/
|
|
28
37
|
expandOnHover?: boolean;
|
|
38
|
+
/** Default expanded state for uncontrolled rail mode. @default false */
|
|
29
39
|
defaultExpanded?: boolean;
|
|
40
|
+
/** Controlled expanded state for rail mode */
|
|
30
41
|
expanded?: boolean;
|
|
42
|
+
/** Callback when rail expanded state changes */
|
|
31
43
|
onExpandedChange?: (expanded: boolean) => void;
|
|
44
|
+
/** Children components */
|
|
32
45
|
children: React.ReactNode;
|
|
33
46
|
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
47
|
+
interface DrawerTriggerProps {
|
|
48
|
+
/** Use child component as trigger */
|
|
36
49
|
asChild?: boolean;
|
|
50
|
+
/** Children components */
|
|
37
51
|
children: React.ReactNode;
|
|
38
|
-
style
|
|
52
|
+
/** Optional style override */
|
|
53
|
+
style?: StyleProp<ViewStyle>;
|
|
39
54
|
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
55
|
+
interface DrawerContentProps extends ViewProps {
|
|
56
|
+
/** Whether to enable swipe gestures (native only) */
|
|
42
57
|
swipeEnabled?: boolean;
|
|
58
|
+
/** Swipe threshold to trigger close (0-1, percentage of width) */
|
|
43
59
|
swipeThreshold?: number;
|
|
60
|
+
/** Velocity threshold for quick swipe */
|
|
44
61
|
velocityThreshold?: number;
|
|
45
|
-
style
|
|
62
|
+
/** Optional style override */
|
|
63
|
+
style?: StyleProp<ViewStyle>;
|
|
64
|
+
/** Children components */
|
|
46
65
|
children: React.ReactNode;
|
|
47
|
-
testID?: string;
|
|
48
66
|
}
|
|
49
|
-
|
|
67
|
+
interface DrawerHeaderProps extends ViewProps {
|
|
68
|
+
/** Custom header content. Used when the structured slots are omitted. */
|
|
69
|
+
children?: React.ReactNode;
|
|
70
|
+
/** Brand or app icon shown before the title. */
|
|
71
|
+
icon?: React.ReactNode;
|
|
72
|
+
/** Header title. Strings receive the package's default drawer title style. */
|
|
73
|
+
title?: React.ReactNode;
|
|
74
|
+
/** Trailing control, such as a close or rail-collapse button. */
|
|
75
|
+
action?: React.ReactNode;
|
|
76
|
+
}
|
|
77
|
+
interface DrawerBodyProps extends ViewProps {
|
|
50
78
|
children: React.ReactNode;
|
|
51
|
-
style?: LooseStyle;
|
|
52
79
|
}
|
|
53
|
-
|
|
54
|
-
declare function DrawerTrigger({ asChild, children, style }: DrawerTriggerProps): React.JSX.Element;
|
|
55
|
-
export interface DrawerToggleCollapseProps {
|
|
56
|
-
asChild?: boolean;
|
|
80
|
+
interface DrawerFooterProps extends ViewProps {
|
|
57
81
|
children: React.ReactNode;
|
|
58
|
-
style?: LooseStyle;
|
|
59
82
|
}
|
|
60
|
-
declare function
|
|
61
|
-
|
|
83
|
+
declare function DrawerRoot({ open: controlledOpen, onOpenChange: controlledOnOpenChange, defaultOpen, side, width, closeOnBackdropPress, variant, collapsedWidth, expandedWidth, expandOnHover, defaultExpanded, expanded: controlledExpanded, onExpandedChange: controlledOnExpandedChange, children, }: DrawerProps): React.JSX.Element;
|
|
84
|
+
declare function DrawerTrigger({ asChild, children, style: styleOverride }: DrawerTriggerProps): React.JSX.Element;
|
|
85
|
+
interface DrawerToggleCollapseProps {
|
|
86
|
+
/** Use child component as the toggle */
|
|
62
87
|
asChild?: boolean;
|
|
88
|
+
/** Children components */
|
|
63
89
|
children: React.ReactNode;
|
|
64
|
-
style
|
|
90
|
+
/** Optional style override */
|
|
91
|
+
style?: StyleProp<ViewStyle>;
|
|
65
92
|
}
|
|
66
|
-
|
|
93
|
+
/**
|
|
94
|
+
* Toggles the rail's expanded state. Native has no hover, so a rail needs an
|
|
95
|
+
* explicit expand/collapse control; this provides it. On web it works too and
|
|
96
|
+
* coexists with `expandOnHover`.
|
|
97
|
+
*/
|
|
98
|
+
declare function DrawerToggleCollapse({ asChild, children, style: styleOverride }: DrawerToggleCollapseProps): React.JSX.Element;
|
|
99
|
+
/**
|
|
100
|
+
* DrawerContent dispatches to the overlay or rail implementation based on the
|
|
101
|
+
* `variant` set on the Drawer root. Both implementations are separate components
|
|
102
|
+
* so their hooks never run conditionally.
|
|
103
|
+
*/
|
|
67
104
|
declare function DrawerContent(props: DrawerContentProps): React.JSX.Element;
|
|
68
|
-
declare function DrawerHeader({ children, style }:
|
|
69
|
-
declare function DrawerBody({ children, style }:
|
|
70
|
-
declare function DrawerFooter({ children, style }:
|
|
105
|
+
declare function DrawerHeader({ children, icon, title, action, style, ...props }: DrawerHeaderProps): React.JSX.Element;
|
|
106
|
+
declare function DrawerBody({ children, style, ...props }: DrawerBodyProps): React.JSX.Element;
|
|
107
|
+
declare function DrawerFooter({ children, style, ...props }: DrawerFooterProps): React.JSX.Element;
|
|
71
108
|
declare function useDrawerClose(): () => void;
|
|
109
|
+
interface DrawerCloseProps {
|
|
110
|
+
/** Use child component as close button */
|
|
111
|
+
asChild?: boolean;
|
|
112
|
+
/** Children components */
|
|
113
|
+
children: React.ReactNode;
|
|
114
|
+
/** Optional style override */
|
|
115
|
+
style?: StyleProp<ViewStyle>;
|
|
116
|
+
}
|
|
117
|
+
declare function DrawerClose({ asChild, children, style: styleOverride }: DrawerCloseProps): React.JSX.Element;
|
|
72
118
|
declare const Drawer: typeof DrawerRoot & {
|
|
73
119
|
Trigger: typeof DrawerTrigger;
|
|
74
120
|
Content: typeof DrawerContent;
|
|
@@ -79,4 +125,4 @@ declare const Drawer: typeof DrawerRoot & {
|
|
|
79
125
|
ToggleCollapse: typeof DrawerToggleCollapse;
|
|
80
126
|
};
|
|
81
127
|
export { Drawer, DrawerTrigger, DrawerContent, DrawerHeader, DrawerBody, DrawerFooter, DrawerClose, DrawerToggleCollapse, useDrawerClose, };
|
|
82
|
-
export type { DrawerVariant,
|
|
128
|
+
export type { DrawerProps, DrawerVariant, DrawerTriggerProps, DrawerContentProps, DrawerHeaderProps, DrawerBodyProps, DrawerFooterProps, DrawerCloseProps, DrawerToggleCollapseProps, };
|