@ramonclaudio/create-vexpo 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 (174) hide show
  1. package/README.md +50 -0
  2. package/dist/index.js +183 -0
  3. package/dist/templates/default/.eas/workflows/asc-events.yml +84 -0
  4. package/dist/templates/default/.eas/workflows/deploy-production.yml +129 -0
  5. package/dist/templates/default/.eas/workflows/development-builds.yml +19 -0
  6. package/dist/templates/default/.eas/workflows/e2e-tests.yml +42 -0
  7. package/dist/templates/default/.eas/workflows/pr-preview.yml +98 -0
  8. package/dist/templates/default/.eas/workflows/release.yml +44 -0
  9. package/dist/templates/default/.eas/workflows/rollback.yml +86 -0
  10. package/dist/templates/default/.eas/workflows/rollout.yml +84 -0
  11. package/dist/templates/default/.eas/workflows/rotate-apple-jwt.yml +42 -0
  12. package/dist/templates/default/.eas/workflows/testflight.yml +57 -0
  13. package/dist/templates/default/.github/workflows/check.yml +28 -0
  14. package/dist/templates/default/.maestro/launch.yaml +18 -0
  15. package/dist/templates/default/AGENTS.md +79 -0
  16. package/dist/templates/default/DESIGN.md +331 -0
  17. package/dist/templates/default/LICENSE +21 -0
  18. package/dist/templates/default/README.md +153 -0
  19. package/dist/templates/default/SETUP.md +618 -0
  20. package/dist/templates/default/__tests__/convex/constants.test.ts +49 -0
  21. package/dist/templates/default/__tests__/convex/validators.test.ts +23 -0
  22. package/dist/templates/default/__tests__/convex/webhook.test.ts +343 -0
  23. package/dist/templates/default/__tests__/lib/deep-link.test.ts +67 -0
  24. package/dist/templates/default/_easignore +22 -0
  25. package/dist/templates/default/_editorconfig +9 -0
  26. package/dist/templates/default/_env.example +34 -0
  27. package/dist/templates/default/_fingerprintignore +24 -0
  28. package/dist/templates/default/_gitattributes +7 -0
  29. package/dist/templates/default/_gitignore +69 -0
  30. package/dist/templates/default/_oxfmtrc.json +3 -0
  31. package/dist/templates/default/_oxlintrc.json +34 -0
  32. package/dist/templates/default/app/(app)/(tabs)/(home)/index.tsx +50 -0
  33. package/dist/templates/default/app/(app)/(tabs)/(home,search)/_layout.tsx +44 -0
  34. package/dist/templates/default/app/(app)/(tabs)/(search)/index.tsx +247 -0
  35. package/dist/templates/default/app/(app)/(tabs)/_layout.tsx +77 -0
  36. package/dist/templates/default/app/(app)/(tabs)/settings/_layout.tsx +37 -0
  37. package/dist/templates/default/app/(app)/(tabs)/settings/index.tsx +362 -0
  38. package/dist/templates/default/app/(app)/(tabs)/settings/preferences.tsx +184 -0
  39. package/dist/templates/default/app/(app)/_layout.tsx +73 -0
  40. package/dist/templates/default/app/(app)/debug.tsx +389 -0
  41. package/dist/templates/default/app/(app)/help.tsx +254 -0
  42. package/dist/templates/default/app/(app)/linked.tsx +116 -0
  43. package/dist/templates/default/app/(app)/privacy.tsx +159 -0
  44. package/dist/templates/default/app/(app)/profile.tsx +915 -0
  45. package/dist/templates/default/app/(app)/sessions.tsx +191 -0
  46. package/dist/templates/default/app/(app)/welcome.tsx +140 -0
  47. package/dist/templates/default/app/(auth)/_layout.tsx +31 -0
  48. package/dist/templates/default/app/(auth)/forgot-password.tsx +168 -0
  49. package/dist/templates/default/app/(auth)/reset-password.tsx +314 -0
  50. package/dist/templates/default/app/(auth)/sign-in.tsx +453 -0
  51. package/dist/templates/default/app/(auth)/sign-up.tsx +563 -0
  52. package/dist/templates/default/app/+native-intent.tsx +14 -0
  53. package/dist/templates/default/app/+not-found.tsx +51 -0
  54. package/dist/templates/default/app/_layout.tsx +102 -0
  55. package/dist/templates/default/app-store/screenshots/.gitkeep +0 -0
  56. package/dist/templates/default/app-store/screenshots/README.md +13 -0
  57. package/dist/templates/default/app.config.ts +201 -0
  58. package/dist/templates/default/app.json +11 -0
  59. package/dist/templates/default/assets/brand-icon-dark.png +0 -0
  60. package/dist/templates/default/assets/brand-icon-light.png +0 -0
  61. package/dist/templates/default/assets/fonts/Geist-Black.ttf +0 -0
  62. package/dist/templates/default/assets/fonts/Geist-BlackItalic.ttf +0 -0
  63. package/dist/templates/default/assets/fonts/Geist-Bold.ttf +0 -0
  64. package/dist/templates/default/assets/fonts/Geist-BoldItalic.ttf +0 -0
  65. package/dist/templates/default/assets/fonts/Geist-ExtraBold.ttf +0 -0
  66. package/dist/templates/default/assets/fonts/Geist-ExtraBoldItalic.ttf +0 -0
  67. package/dist/templates/default/assets/fonts/Geist-ExtraLight.ttf +0 -0
  68. package/dist/templates/default/assets/fonts/Geist-ExtraLightItalic.ttf +0 -0
  69. package/dist/templates/default/assets/fonts/Geist-Italic.ttf +0 -0
  70. package/dist/templates/default/assets/fonts/Geist-Light.ttf +0 -0
  71. package/dist/templates/default/assets/fonts/Geist-LightItalic.ttf +0 -0
  72. package/dist/templates/default/assets/fonts/Geist-Medium.ttf +0 -0
  73. package/dist/templates/default/assets/fonts/Geist-MediumItalic.ttf +0 -0
  74. package/dist/templates/default/assets/fonts/Geist-Regular.ttf +0 -0
  75. package/dist/templates/default/assets/fonts/Geist-SemiBold.ttf +0 -0
  76. package/dist/templates/default/assets/fonts/Geist-SemiBoldItalic.ttf +0 -0
  77. package/dist/templates/default/assets/fonts/Geist-Thin.ttf +0 -0
  78. package/dist/templates/default/assets/fonts/Geist-ThinItalic.ttf +0 -0
  79. package/dist/templates/default/assets/fonts/Geist-Variable-Italic.ttf +0 -0
  80. package/dist/templates/default/assets/fonts/Geist-Variable.ttf +0 -0
  81. package/dist/templates/default/assets/fonts/GeistMono-Bold.ttf +0 -0
  82. package/dist/templates/default/assets/fonts/GeistMono-BoldItalic.ttf +0 -0
  83. package/dist/templates/default/assets/fonts/GeistMono-Italic.ttf +0 -0
  84. package/dist/templates/default/assets/fonts/GeistMono-Medium.ttf +0 -0
  85. package/dist/templates/default/assets/fonts/GeistMono-MediumItalic.ttf +0 -0
  86. package/dist/templates/default/assets/fonts/GeistMono-Regular.ttf +0 -0
  87. package/dist/templates/default/assets/fonts/GeistPixel-Square.ttf +0 -0
  88. package/dist/templates/default/assets/icon.png +0 -0
  89. package/dist/templates/default/assets/sounds/notification.wav +0 -0
  90. package/dist/templates/default/assets/splash-image-dark.png +0 -0
  91. package/dist/templates/default/assets/splash-image-light.png +0 -0
  92. package/dist/templates/default/bun.lock +1860 -0
  93. package/dist/templates/default/components/auth/otp-verification.tsx +255 -0
  94. package/dist/templates/default/components/auth/password-field.tsx +121 -0
  95. package/dist/templates/default/components/auth/segmented-toggle.tsx +47 -0
  96. package/dist/templates/default/components/ui/convex-error.tsx +32 -0
  97. package/dist/templates/default/components/ui/error-boundary.tsx +57 -0
  98. package/dist/templates/default/components/ui/loading-screen.tsx +31 -0
  99. package/dist/templates/default/components/ui/material.tsx +94 -0
  100. package/dist/templates/default/components/ui/offline-banner.tsx +58 -0
  101. package/dist/templates/default/components/ui/prominent-button.tsx +71 -0
  102. package/dist/templates/default/components/ui/skeleton.tsx +107 -0
  103. package/dist/templates/default/components/ui/status-text.tsx +49 -0
  104. package/dist/templates/default/components/ui/update-banner.tsx +82 -0
  105. package/dist/templates/default/constants/layout.ts +102 -0
  106. package/dist/templates/default/constants/theme.ts +401 -0
  107. package/dist/templates/default/constants/ui.ts +77 -0
  108. package/dist/templates/default/convex/_generated/api.d.ts +77 -0
  109. package/dist/templates/default/convex/_generated/api.js +23 -0
  110. package/dist/templates/default/convex/_generated/dataModel.d.ts +60 -0
  111. package/dist/templates/default/convex/_generated/server.d.ts +143 -0
  112. package/dist/templates/default/convex/_generated/server.js +93 -0
  113. package/dist/templates/default/convex/admin.ts +102 -0
  114. package/dist/templates/default/convex/auth.config.ts +6 -0
  115. package/dist/templates/default/convex/auth.ts +335 -0
  116. package/dist/templates/default/convex/constants.ts +46 -0
  117. package/dist/templates/default/convex/convex.config.ts +11 -0
  118. package/dist/templates/default/convex/crons.ts +42 -0
  119. package/dist/templates/default/convex/email.ts +109 -0
  120. package/dist/templates/default/convex/env.ts +31 -0
  121. package/dist/templates/default/convex/errors.ts +33 -0
  122. package/dist/templates/default/convex/functions.ts +54 -0
  123. package/dist/templates/default/convex/http.ts +176 -0
  124. package/dist/templates/default/convex/log.ts +81 -0
  125. package/dist/templates/default/convex/pushTokens.ts +114 -0
  126. package/dist/templates/default/convex/rateLimit.ts +92 -0
  127. package/dist/templates/default/convex/schema.ts +28 -0
  128. package/dist/templates/default/convex/tsconfig.json +18 -0
  129. package/dist/templates/default/convex/users.ts +279 -0
  130. package/dist/templates/default/convex/validators.ts +74 -0
  131. package/dist/templates/default/convex/webhook.ts +193 -0
  132. package/dist/templates/default/convex.json +6 -0
  133. package/dist/templates/default/eas.json +56 -0
  134. package/dist/templates/default/fingerprint.config.js +9 -0
  135. package/dist/templates/default/hooks/use-debounce.ts +20 -0
  136. package/dist/templates/default/hooks/use-deep-link.ts +43 -0
  137. package/dist/templates/default/hooks/use-navigation-tracking.ts +15 -0
  138. package/dist/templates/default/hooks/use-network.ts +11 -0
  139. package/dist/templates/default/hooks/use-notifications.ts +107 -0
  140. package/dist/templates/default/hooks/use-onboarding.ts +15 -0
  141. package/dist/templates/default/hooks/use-reduced-motion.ts +11 -0
  142. package/dist/templates/default/hooks/use-theme.ts +53 -0
  143. package/dist/templates/default/hooks/use-updates.ts +86 -0
  144. package/dist/templates/default/lib/a11y.ts +5 -0
  145. package/dist/templates/default/lib/app.ts +14 -0
  146. package/dist/templates/default/lib/assets.ts +17 -0
  147. package/dist/templates/default/lib/auth-client.ts +21 -0
  148. package/dist/templates/default/lib/convex-auth.tsx +79 -0
  149. package/dist/templates/default/lib/deep-link.ts +71 -0
  150. package/dist/templates/default/lib/dev-menu.ts +119 -0
  151. package/dist/templates/default/lib/device.ts +40 -0
  152. package/dist/templates/default/lib/dynamic-font.ts +49 -0
  153. package/dist/templates/default/lib/env.ts +10 -0
  154. package/dist/templates/default/lib/haptics.ts +24 -0
  155. package/dist/templates/default/lib/notifications.ts +276 -0
  156. package/dist/templates/default/lib/preferences.ts +45 -0
  157. package/dist/templates/default/lib/schemas.ts +137 -0
  158. package/dist/templates/default/lib/storage.ts +47 -0
  159. package/dist/templates/default/lib/updates.ts +107 -0
  160. package/dist/templates/default/metro.config.js +14 -0
  161. package/dist/templates/default/package.json +129 -0
  162. package/dist/templates/default/patches/PR-368.patch +91 -0
  163. package/dist/templates/default/patches/convex-dev-better-auth-0.12.2.tgz +0 -0
  164. package/dist/templates/default/plugins/README.md +9 -0
  165. package/dist/templates/default/plugins/with-auto-signing.js +45 -0
  166. package/dist/templates/default/plugins/with-pod-deployment-target.js +35 -0
  167. package/dist/templates/default/scripts/README.md +36 -0
  168. package/dist/templates/default/scripts/_run.mjs +77 -0
  169. package/dist/templates/default/scripts/clean.ts +543 -0
  170. package/dist/templates/default/scripts/rotate-apple-jwt.mjs +80 -0
  171. package/dist/templates/default/store.config.json +58 -0
  172. package/dist/templates/default/tsconfig.json +13 -0
  173. package/dist/templates/default/vitest.config.ts +21 -0
  174. package/package.json +69 -0
@@ -0,0 +1,314 @@
1
+ import { startTransition, useActionState, useEffect, useState } from "react";
2
+ import { Image as ExpoImage } from "expo-image";
3
+ import { router, useLocalSearchParams, useNavigation } from "expo-router";
4
+ import {
5
+ Host,
6
+ ScrollView,
7
+ VStack,
8
+ TextField,
9
+ Button,
10
+ Text,
11
+ Image,
12
+ Spacer,
13
+ RNHostView,
14
+ ConfirmationDialog,
15
+ } from "@expo/ui/swift-ui";
16
+ import {
17
+ foregroundStyle,
18
+ buttonStyle,
19
+ background,
20
+ clipShape,
21
+ disabled,
22
+ keyboardType,
23
+ textFieldStyle,
24
+ padding,
25
+ frame,
26
+ scrollDismissesKeyboard,
27
+ multilineTextAlignment,
28
+ monospacedDigit,
29
+ kerning,
30
+ submitLabel,
31
+ accessibilityLabel,
32
+ accessibilityHint,
33
+ tint,
34
+ } from "@expo/ui/swift-ui/modifiers";
35
+ import { useDynamicFont } from "@/lib/dynamic-font";
36
+ import { Button as ButtonTokens } from "@/constants/layout";
37
+
38
+ import { authClient } from "@/lib/auth-client";
39
+ import { assets } from "@/lib/assets";
40
+ import { haptics } from "@/lib/haptics";
41
+ import { firstError, resetPasswordSchema } from "@/lib/schemas";
42
+ import { PasswordField } from "@/components/auth/password-field";
43
+ import { ProminentButton } from "@/components/ui/prominent-button";
44
+ import { ErrorText } from "@/components/ui/status-text";
45
+ import { announce } from "@/lib/a11y";
46
+ import { useColors, useThemedAsset } from "@/hooks/use-theme";
47
+ import { useQuery } from "convex/react";
48
+
49
+ import { api } from "@/convex/_generated/api";
50
+
51
+ type ResetState = { error?: string; ok?: boolean };
52
+ const initialState: ResetState = {};
53
+
54
+ export default function ResetPasswordScreen() {
55
+ const dfont = useDynamicFont();
56
+ const colors = useColors();
57
+ const brandIcon = useThemedAsset(assets.brandIconLight, assets.brandIconDark);
58
+ const { email = "" } = useLocalSearchParams<{ email: string }>();
59
+ const providers = useQuery(api.auth.getEnabledProviders);
60
+ // Reset requires the email-OTP flow which requires Resend. Redirect away
61
+ // in lite mode (`REQUIRE_EMAIL_VERIFICATION` unset).
62
+ useEffect(() => {
63
+ if (providers !== undefined && providers.emailFeatures === false) {
64
+ router.replace("/sign-in");
65
+ }
66
+ }, [providers]);
67
+
68
+ const [otp, setOtp] = useState("");
69
+ const [password, setPassword] = useState("");
70
+ const [confirmPassword, setConfirmPassword] = useState("");
71
+
72
+ const [state, submit, isPending] = useActionState<ResetState, void>(async () => {
73
+ haptics.light();
74
+
75
+ if (!email) {
76
+ haptics.error();
77
+ return { error: "Missing email. Start over from forgot password." };
78
+ }
79
+
80
+ const parsed = resetPasswordSchema.safeParse({ email, otp, password, confirmPassword });
81
+ if (!parsed.success) {
82
+ haptics.error();
83
+ return { error: firstError(parsed)! };
84
+ }
85
+
86
+ try {
87
+ const response = await authClient.emailOtp.resetPassword({
88
+ email: parsed.data.email,
89
+ otp: parsed.data.otp,
90
+ password: parsed.data.password,
91
+ });
92
+
93
+ if (response.error) {
94
+ haptics.error();
95
+ const message = response.error.message ?? "Failed to reset password";
96
+ const lower = message.toLowerCase();
97
+ if (lower.includes("expired") || lower.includes("invalid")) {
98
+ return { error: "This code has expired. Request a new one." };
99
+ }
100
+ return { error: message };
101
+ }
102
+ haptics.success();
103
+ announce("Password reset");
104
+ return { ok: true };
105
+ } catch {
106
+ haptics.error();
107
+ return { error: "An unexpected error occurred. Please try again." };
108
+ }
109
+ }, initialState);
110
+
111
+ const navigation = useNavigation();
112
+ const hasInput = otp.length > 0 || password.length > 0 || confirmPassword.length > 0;
113
+ const [pendingNavAction, setPendingNavAction] = useState<
114
+ Parameters<typeof navigation.dispatch>[0] | null
115
+ >(null);
116
+ useEffect(() => {
117
+ if (!hasInput || state.ok) return;
118
+ return navigation.addListener("beforeRemove", (e) => {
119
+ e.preventDefault();
120
+ setPendingNavAction(e.data.action);
121
+ });
122
+ }, [navigation, hasInput, state.ok]);
123
+
124
+ const error = state.error;
125
+ const isExpiredError = error && (error.includes("expired") || error.includes("Missing email"));
126
+ const inputModifiers = [
127
+ textFieldStyle("plain"),
128
+ padding({ horizontal: 16 }),
129
+ frame({ maxWidth: Infinity, height: ButtonTokens.height }),
130
+ background(colors.muted as string),
131
+ clipShape("capsule"),
132
+ dfont({ size: 16 }),
133
+ ];
134
+
135
+ if (state.ok) {
136
+ return (
137
+ <Host style={{ flex: 1, backgroundColor: colors.background }}>
138
+ <VStack
139
+ spacing={16}
140
+ alignment="center"
141
+ modifiers={[padding({ horizontal: 24 }), tint(colors.primary as string)]}
142
+ >
143
+ <Spacer />
144
+ <Image systemName="checkmark.circle.fill" size={56} color={colors.success} />
145
+ <Text modifiers={[dfont({ size: 28, weight: "bold" })]}>Password reset!</Text>
146
+ <Text
147
+ modifiers={[
148
+ dfont({ size: 15 }),
149
+ foregroundStyle(colors.mutedForeground as string),
150
+ multilineTextAlignment("center"),
151
+ ]}
152
+ >
153
+ Your password has been reset. You can now sign in with your new password.
154
+ </Text>
155
+ <ProminentButton
156
+ label="Sign in"
157
+ onPress={() => {
158
+ haptics.light();
159
+ router.replace("/sign-in");
160
+ }}
161
+ />
162
+ <Spacer />
163
+ </VStack>
164
+ </Host>
165
+ );
166
+ }
167
+
168
+ const labelModifiers = [dfont({ size: 17, weight: "semibold" })];
169
+
170
+ return (
171
+ <Host style={{ flex: 1, backgroundColor: colors.background }}>
172
+ <ScrollView
173
+ modifiers={[scrollDismissesKeyboard("interactively"), tint(colors.primary as string)]}
174
+ >
175
+ <VStack
176
+ spacing={20}
177
+ alignment="leading"
178
+ modifiers={[padding({ horizontal: 24, top: 60, bottom: 40 })]}
179
+ >
180
+ <RNHostView matchContents>
181
+ <ExpoImage
182
+ source={brandIcon}
183
+ style={{ width: 56, height: 56 } as never}
184
+ accessibilityLabel="App icon"
185
+ contentFit="contain"
186
+ />
187
+ </RNHostView>
188
+
189
+ <VStack spacing={6} alignment="leading">
190
+ <Text modifiers={[dfont({ size: 28, weight: "bold" })]}>Reset password</Text>
191
+ <Text
192
+ modifiers={[dfont({ size: 16 }), foregroundStyle(colors.mutedForeground as string)]}
193
+ >
194
+ Enter the 6-digit code sent to {email} and choose a new password.
195
+ </Text>
196
+ </VStack>
197
+
198
+ {error && (
199
+ <VStack spacing={8} alignment="leading">
200
+ <ErrorText>{error}</ErrorText>
201
+ {isExpiredError && (
202
+ <Button
203
+ label="Request a new code"
204
+ modifiers={[buttonStyle("plain"), dfont({ size: 14 })]}
205
+ onPress={() => {
206
+ haptics.light();
207
+ router.push("/forgot-password");
208
+ }}
209
+ />
210
+ )}
211
+ </VStack>
212
+ )}
213
+
214
+ <VStack spacing={6} alignment="leading" modifiers={[frame({ maxWidth: Infinity })]}>
215
+ <Text modifiers={labelModifiers}>Verification code</Text>
216
+ <TextField
217
+ placeholder="000000"
218
+ onTextChange={(text) => setOtp(text.replace(/\D/g, "").slice(0, 6))}
219
+ autoFocus
220
+ modifiers={[
221
+ ...inputModifiers,
222
+ keyboardType("numeric"),
223
+ dfont({ size: 24, design: "monospaced" }),
224
+ monospacedDigit(),
225
+ kerning(8),
226
+ multilineTextAlignment("center"),
227
+ submitLabel("next"),
228
+ disabled(isPending),
229
+ accessibilityLabel("Verification code"),
230
+ accessibilityHint("Enter the 6 digit code sent to your email"),
231
+ ]}
232
+ />
233
+ </VStack>
234
+
235
+ <VStack spacing={6} alignment="leading" modifiers={[frame({ maxWidth: Infinity })]}>
236
+ <Text modifiers={labelModifiers}>New password</Text>
237
+ <PasswordField
238
+ onTextChange={setPassword}
239
+ disabled={isPending}
240
+ submitLabelType="next"
241
+ accessibilityLabel="New password"
242
+ accessibilityHint="Choose a password with at least 10 characters"
243
+ />
244
+ <Text
245
+ modifiers={[dfont({ size: 13 }), foregroundStyle(colors.mutedForeground as string)]}
246
+ >
247
+ At least 10 characters.
248
+ </Text>
249
+ </VStack>
250
+
251
+ <VStack spacing={6} alignment="leading" modifiers={[frame({ maxWidth: Infinity })]}>
252
+ <Text modifiers={labelModifiers}>Confirm password</Text>
253
+ <PasswordField
254
+ onTextChange={setConfirmPassword}
255
+ onSubmit={() => startTransition(() => submit())}
256
+ disabled={isPending}
257
+ accessibilityLabel="Confirm new password"
258
+ accessibilityHint="Re-enter the new password to confirm"
259
+ />
260
+ </VStack>
261
+
262
+ <ProminentButton
263
+ label={isPending ? "Resetting..." : "Reset password"}
264
+ onPress={() => startTransition(() => submit())}
265
+ disabled={isPending}
266
+ />
267
+
268
+ <VStack alignment="center" modifiers={[frame({ maxWidth: Infinity })]}>
269
+ <Button
270
+ label="Back to sign in"
271
+ modifiers={[
272
+ buttonStyle("plain"),
273
+ foregroundStyle(colors.mutedForeground as string),
274
+ dfont({ size: 14, weight: "semibold" }),
275
+ ]}
276
+ onPress={() => {
277
+ haptics.light();
278
+ router.push("/sign-in");
279
+ }}
280
+ />
281
+ </VStack>
282
+ </VStack>
283
+ </ScrollView>
284
+
285
+ <ConfirmationDialog
286
+ title="Discard changes?"
287
+ isPresented={pendingNavAction !== null}
288
+ onIsPresentedChange={(v) => {
289
+ if (!v) setPendingNavAction(null);
290
+ }}
291
+ titleVisibility="visible"
292
+ >
293
+ <ConfirmationDialog.Trigger>
294
+ <Spacer modifiers={[frame({ width: 0, height: 0 })]} />
295
+ </ConfirmationDialog.Trigger>
296
+ <ConfirmationDialog.Actions>
297
+ <Button
298
+ label="Discard"
299
+ role="destructive"
300
+ onPress={() => {
301
+ const action = pendingNavAction;
302
+ setPendingNavAction(null);
303
+ if (action) navigation.dispatch(action);
304
+ }}
305
+ />
306
+ <Button label="Keep Editing" role="cancel" />
307
+ </ConfirmationDialog.Actions>
308
+ <ConfirmationDialog.Message>
309
+ <Text modifiers={[dfont({ size: 16 })]}>Your password entries will be lost.</Text>
310
+ </ConfirmationDialog.Message>
311
+ </ConfirmationDialog>
312
+ </Host>
313
+ );
314
+ }