@ramonclaudio/create-vexpo 0.1.0 → 0.1.1

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 +10 -10
  2. package/dist/index.js +8 -7
  3. package/dist/templates/default/.eas/workflows/asc-events.yml +9 -6
  4. package/dist/templates/default/.eas/workflows/deploy-production.yml +28 -15
  5. package/dist/templates/default/.eas/workflows/e2e-tests.yml +3 -2
  6. package/dist/templates/default/.eas/workflows/pr-preview.yml +12 -21
  7. package/dist/templates/default/.eas/workflows/release.yml +3 -7
  8. package/dist/templates/default/.eas/workflows/rollback.yml +54 -28
  9. package/dist/templates/default/.eas/workflows/rollout.yml +27 -33
  10. package/dist/templates/default/.eas/workflows/rotate-apple-jwt.yml +1 -5
  11. package/dist/templates/default/.eas/workflows/testflight.yml +3 -7
  12. package/dist/templates/default/.github/workflows/check.yml +20 -12
  13. package/dist/templates/default/.maestro/launch.yaml +19 -10
  14. package/dist/templates/default/AGENTS.md +25 -8
  15. package/dist/templates/default/DESIGN.md +14 -10
  16. package/dist/templates/default/README.md +83 -78
  17. package/dist/templates/default/SETUP.md +159 -152
  18. package/dist/templates/default/__tests__/convex/_auth-harness.test.ts +112 -0
  19. package/dist/templates/default/__tests__/convex/_harness.ts +132 -0
  20. package/dist/templates/default/__tests__/convex/appAttest.test.ts +172 -0
  21. package/dist/templates/default/__tests__/convex/appAttestStore.test.ts +48 -0
  22. package/dist/templates/default/__tests__/convex/pushTokens-remove.test.ts +106 -0
  23. package/dist/templates/default/__tests__/convex/pushTokens-upsert.test.ts +146 -0
  24. package/dist/templates/default/__tests__/convex/users-deleteAccount.test.ts +140 -0
  25. package/dist/templates/default/__tests__/convex/users-deleteAvatar.test.ts +104 -0
  26. package/dist/templates/default/__tests__/convex/users-getMe.test.ts +98 -0
  27. package/dist/templates/default/__tests__/convex/users-getUser.test.ts +120 -0
  28. package/dist/templates/default/__tests__/convex/users-hardDeleteExpired.test.ts +67 -0
  29. package/dist/templates/default/__tests__/convex/users-restoreAccount.test.ts +96 -0
  30. package/dist/templates/default/__tests__/convex/users-updateAvatar.test.ts +92 -0
  31. package/dist/templates/default/__tests__/convex/users-updateProfile.test.ts +126 -0
  32. package/dist/templates/default/__tests__/convex/webhook.test.ts +31 -0
  33. package/dist/templates/default/__tests__/lib/deep-link.test.ts +51 -6
  34. package/dist/templates/default/__tests__/lib/schemas.test.ts +205 -0
  35. package/dist/templates/default/__tests__/lib/text-style.test.ts +31 -0
  36. package/dist/templates/default/_env.example +7 -7
  37. package/dist/templates/default/_gitattributes +1 -1
  38. package/dist/templates/default/_gitignore +17 -2
  39. package/dist/templates/default/_npmrc +7 -0
  40. package/dist/templates/default/_oxlintrc.json +1 -1
  41. package/dist/templates/default/app-store/accessibility.config.json +20 -0
  42. package/dist/templates/default/app-store/privacy.config.json +27 -0
  43. package/dist/templates/default/app.config.ts +105 -33
  44. package/dist/templates/default/app.json +1 -9
  45. package/dist/templates/default/convex/_generated/api.d.ts +12 -0
  46. package/dist/templates/default/convex/admin.ts +0 -13
  47. package/dist/templates/default/convex/appAttest.ts +467 -0
  48. package/dist/templates/default/convex/appAttestStore.ts +141 -0
  49. package/dist/templates/default/convex/apple.ts +53 -0
  50. package/dist/templates/default/convex/auth.ts +6 -45
  51. package/dist/templates/default/convex/constants.ts +2 -7
  52. package/dist/templates/default/convex/crons.ts +12 -5
  53. package/dist/templates/default/convex/email.ts +4 -24
  54. package/dist/templates/default/convex/env.ts +0 -4
  55. package/dist/templates/default/convex/errors.ts +0 -7
  56. package/dist/templates/default/convex/functions.ts +0 -26
  57. package/dist/templates/default/convex/http.ts +3 -5
  58. package/dist/templates/default/convex/log.ts +2 -25
  59. package/dist/templates/default/convex/pushSender.ts +145 -0
  60. package/dist/templates/default/convex/pushTokens.ts +110 -13
  61. package/dist/templates/default/convex/rateLimit.ts +8 -39
  62. package/dist/templates/default/convex/schema.ts +48 -5
  63. package/dist/templates/default/convex/tsconfig.json +1 -0
  64. package/dist/templates/default/convex/users.ts +143 -61
  65. package/dist/templates/default/convex/validators.ts +1 -38
  66. package/dist/templates/default/convex/webhook.ts +1 -31
  67. package/dist/templates/default/convex.json +1 -2
  68. package/dist/templates/default/metro.config.js +9 -1
  69. package/dist/templates/default/package.json +67 -70
  70. package/dist/templates/default/plugins/README.md +5 -1
  71. package/dist/templates/default/scripts/README.md +9 -9
  72. package/dist/templates/default/scripts/_run.mjs +3 -20
  73. package/dist/templates/default/scripts/clean.ts +81 -69
  74. package/dist/templates/default/scripts/gen-update-cert.mjs +98 -0
  75. package/dist/templates/default/{app → src/app}/(app)/(tabs)/(home)/index.tsx +21 -6
  76. package/dist/templates/default/{app → src/app}/(app)/(tabs)/(home,search)/_layout.tsx +9 -8
  77. package/dist/templates/default/{app → src/app}/(app)/(tabs)/(search)/index.tsx +26 -24
  78. package/dist/templates/default/{app → src/app}/(app)/(tabs)/_layout.tsx +3 -4
  79. package/dist/templates/default/{app → src/app}/(app)/(tabs)/settings/_layout.tsx +10 -6
  80. package/dist/templates/default/{app → src/app}/(app)/(tabs)/settings/index.tsx +81 -51
  81. package/dist/templates/default/{app → src/app}/(app)/(tabs)/settings/preferences.tsx +72 -12
  82. package/dist/templates/default/src/app/(app)/_layout.tsx +147 -0
  83. package/dist/templates/default/{app/(auth) → src/app/(app)/auth}/_layout.tsx +4 -5
  84. package/dist/templates/default/{app/(auth) → src/app/(app)/auth}/forgot-password.tsx +15 -9
  85. package/dist/templates/default/{app/(auth) → src/app/(app)/auth}/reset-password.tsx +88 -14
  86. package/dist/templates/default/{app/(auth) → src/app/(app)/auth}/sign-in.tsx +65 -35
  87. package/dist/templates/default/{app/(auth) → src/app/(app)/auth}/sign-up.tsx +131 -196
  88. package/dist/templates/default/src/app/(app)/debug.tsx +479 -0
  89. package/dist/templates/default/{app → src/app}/(app)/help.tsx +76 -64
  90. package/dist/templates/default/{app → src/app}/(app)/linked.tsx +21 -27
  91. package/dist/templates/default/{app → src/app}/(app)/privacy.tsx +35 -8
  92. package/dist/templates/default/src/app/(app)/profile/change-password.tsx +264 -0
  93. package/dist/templates/default/{app/(app)/profile.tsx → src/app/(app)/profile/index.tsx} +179 -255
  94. package/dist/templates/default/src/app/(app)/restore-account.tsx +192 -0
  95. package/dist/templates/default/src/app/(app)/sessions.tsx +287 -0
  96. package/dist/templates/default/src/app/(app)/welcome.tsx +194 -0
  97. package/dist/templates/default/src/app/+native-intent.tsx +25 -0
  98. package/dist/templates/default/src/app/+not-found.tsx +43 -0
  99. package/dist/templates/default/{app → src/app}/_layout.tsx +28 -37
  100. package/dist/templates/default/src/components/auth/apple-button.tsx +51 -0
  101. package/dist/templates/default/{components → src/components}/auth/otp-verification.tsx +79 -58
  102. package/dist/templates/default/{components → src/components}/auth/password-field.tsx +74 -18
  103. package/dist/templates/default/src/components/auth/segmented-toggle.tsx +71 -0
  104. package/dist/templates/default/src/components/ui/content-unavailable.tsx +81 -0
  105. package/dist/templates/default/src/components/ui/convex-error.tsx +21 -0
  106. package/dist/templates/default/src/components/ui/error-boundary.tsx +89 -0
  107. package/dist/templates/default/{components → src/components}/ui/loading-screen.tsx +5 -4
  108. package/dist/templates/default/{components → src/components}/ui/material.tsx +50 -17
  109. package/dist/templates/default/src/components/ui/offline-banner.tsx +59 -0
  110. package/dist/templates/default/{components → src/components}/ui/prominent-button.tsx +8 -11
  111. package/dist/templates/default/{components → src/components}/ui/skeleton.tsx +31 -13
  112. package/dist/templates/default/src/components/ui/status-text.tsx +64 -0
  113. package/dist/templates/default/src/components/ui/update-banner.tsx +85 -0
  114. package/dist/templates/default/{constants → src/constants}/layout.ts +0 -6
  115. package/dist/templates/default/{constants → src/constants}/theme.ts +49 -64
  116. package/dist/templates/default/{constants → src/constants}/ui.ts +13 -4
  117. package/dist/templates/default/src/hooks/use-debounce.ts +12 -0
  118. package/dist/templates/default/src/hooks/use-deep-link.ts +51 -0
  119. package/dist/templates/default/src/hooks/use-delete-account.ts +35 -0
  120. package/dist/templates/default/src/hooks/use-motion-screen-options.ts +13 -0
  121. package/dist/templates/default/src/hooks/use-network.ts +34 -0
  122. package/dist/templates/default/{hooks → src/hooks}/use-notifications.ts +39 -30
  123. package/dist/templates/default/src/hooks/use-reduce-transparency.ts +30 -0
  124. package/dist/templates/default/{hooks → src/hooks}/use-theme.ts +0 -5
  125. package/dist/templates/default/src/lib/appAttest.ts +78 -0
  126. package/dist/templates/default/src/lib/assets.ts +9 -0
  127. package/dist/templates/default/src/lib/deep-link.ts +82 -0
  128. package/dist/templates/default/{lib → src/lib}/dev-menu.ts +0 -4
  129. package/dist/templates/default/{lib → src/lib}/device.ts +1 -13
  130. package/dist/templates/default/{lib → src/lib}/dynamic-font.ts +13 -10
  131. package/dist/templates/default/src/lib/dynamic-symbol-size.ts +33 -0
  132. package/dist/templates/default/src/lib/masks.ts +21 -0
  133. package/dist/templates/default/src/lib/native-state.ts +20 -0
  134. package/dist/templates/default/{lib → src/lib}/notifications.ts +7 -45
  135. package/dist/templates/default/{lib → src/lib}/preferences.ts +0 -2
  136. package/dist/templates/default/{lib → src/lib}/schemas.ts +19 -16
  137. package/dist/templates/default/src/lib/text-style.ts +20 -0
  138. package/dist/templates/default/{lib → src/lib}/updates.ts +0 -7
  139. package/dist/templates/default/store.config.json +1 -1
  140. package/dist/templates/default/tsconfig.json +3 -1
  141. package/dist/templates/default/vitest.config.ts +8 -1
  142. package/package.json +5 -5
  143. package/dist/templates/default/app/(app)/_layout.tsx +0 -73
  144. package/dist/templates/default/app/(app)/debug.tsx +0 -389
  145. package/dist/templates/default/app/(app)/sessions.tsx +0 -191
  146. package/dist/templates/default/app/(app)/welcome.tsx +0 -140
  147. package/dist/templates/default/app/+native-intent.tsx +0 -14
  148. package/dist/templates/default/app/+not-found.tsx +0 -51
  149. package/dist/templates/default/bun.lock +0 -1860
  150. package/dist/templates/default/components/auth/segmented-toggle.tsx +0 -47
  151. package/dist/templates/default/components/ui/convex-error.tsx +0 -32
  152. package/dist/templates/default/components/ui/error-boundary.tsx +0 -57
  153. package/dist/templates/default/components/ui/offline-banner.tsx +0 -58
  154. package/dist/templates/default/components/ui/status-text.tsx +0 -49
  155. package/dist/templates/default/components/ui/update-banner.tsx +0 -82
  156. package/dist/templates/default/fingerprint.config.js +0 -9
  157. package/dist/templates/default/hooks/use-debounce.ts +0 -20
  158. package/dist/templates/default/hooks/use-deep-link.ts +0 -43
  159. package/dist/templates/default/hooks/use-network.ts +0 -11
  160. package/dist/templates/default/lib/assets.ts +0 -17
  161. package/dist/templates/default/lib/deep-link.ts +0 -71
  162. package/dist/templates/default/patches/PR-368.patch +0 -91
  163. package/dist/templates/default/patches/convex-dev-better-auth-0.12.2.tgz +0 -0
  164. /package/dist/templates/default/{hooks → src/hooks}/use-navigation-tracking.ts +0 -0
  165. /package/dist/templates/default/{hooks → src/hooks}/use-onboarding.ts +0 -0
  166. /package/dist/templates/default/{hooks → src/hooks}/use-reduced-motion.ts +0 -0
  167. /package/dist/templates/default/{hooks → src/hooks}/use-updates.ts +0 -0
  168. /package/dist/templates/default/{lib → src/lib}/a11y.ts +0 -0
  169. /package/dist/templates/default/{lib → src/lib}/app.ts +0 -0
  170. /package/dist/templates/default/{lib → src/lib}/auth-client.ts +0 -0
  171. /package/dist/templates/default/{lib → src/lib}/convex-auth.tsx +0 -0
  172. /package/dist/templates/default/{lib → src/lib}/env.ts +0 -0
  173. /package/dist/templates/default/{lib → src/lib}/haptics.ts +0 -0
  174. /package/dist/templates/default/{lib → src/lib}/storage.ts +0 -0
@@ -0,0 +1,264 @@
1
+ import { startTransition, useActionState, useEffect, useState } from "react";
2
+ import { router, useNavigation } from "expo-router";
3
+ import { useQuery } from "convex/react";
4
+ import {
5
+ Host,
6
+ ScrollView,
7
+ VStack,
8
+ TextField,
9
+ Button,
10
+ Text,
11
+ Spacer,
12
+ ConfirmationDialog,
13
+ useNativeState,
14
+ } from "@expo/ui/swift-ui";
15
+ import {
16
+ accessibilityLabel,
17
+ background,
18
+ buttonStyle,
19
+ clipShape,
20
+ defaultScrollAnchorForRole,
21
+ disabled,
22
+ foregroundStyle,
23
+ frame,
24
+ padding,
25
+ scrollDismissesKeyboard,
26
+ textContentType,
27
+ textFieldStyle,
28
+ tint,
29
+ } from "@expo/ui/swift-ui/modifiers";
30
+
31
+ import { api } from "@/convex/_generated/api";
32
+ import { authClient } from "@/lib/auth-client";
33
+ import { announce } from "@/lib/a11y";
34
+ import { haptics } from "@/lib/haptics";
35
+ import { Button as ButtonTokens, TouchTarget } from "@/constants/layout";
36
+ import { PasswordField } from "@/components/auth/password-field";
37
+ import { ProminentButton } from "@/components/ui/prominent-button";
38
+ import { ErrorText } from "@/components/ui/status-text";
39
+ import { LoadingScreen } from "@/components/ui/loading-screen";
40
+ import { useColors } from "@/hooks/use-theme";
41
+ import { useDynamicFont } from "@/lib/dynamic-font";
42
+
43
+ type ChangePasswordState = { error?: string; ok?: boolean };
44
+ const initialState: ChangePasswordState = {};
45
+
46
+ export default function ChangePasswordScreen() {
47
+ const me = useQuery(api.users.getMe);
48
+ if (!me) return <LoadingScreen testID="change-password-loading" />;
49
+ return <ChangePasswordForm email={me.email} />;
50
+ }
51
+
52
+ function ChangePasswordForm({ email }: { email: string }) {
53
+ const dfont = useDynamicFont();
54
+ const colors = useColors();
55
+ const [current, setCurrent] = useState("");
56
+ const [next, setNext] = useState("");
57
+ const [confirm, setConfirm] = useState("");
58
+ // Hidden username carrier. iOS keychain pairs `username` + `newPassword` to
59
+ // save the credential and to associate Strong Password suggestions with this
60
+ // account. Without it the suggestion sheet may not fire and a saved password
61
+ // would land orphaned in iCloud Keychain.
62
+ const emailState = useNativeState(email);
63
+
64
+ const [state, submit, isPending] = useActionState<ChangePasswordState, void>(async () => {
65
+ haptics.light();
66
+ if (!current || !next || !confirm) {
67
+ haptics.error();
68
+ return { error: "Fill in every field" };
69
+ }
70
+ if (next.length < 10 || next.length > 128) {
71
+ haptics.error();
72
+ return { error: "Password must be 10-128 characters" };
73
+ }
74
+ if (next !== confirm) {
75
+ haptics.error();
76
+ return { error: "Passwords do not match" };
77
+ }
78
+ try {
79
+ const res = await authClient.changePassword({
80
+ currentPassword: current,
81
+ newPassword: next,
82
+ revokeOtherSessions: true,
83
+ });
84
+ if (res.error) {
85
+ haptics.error();
86
+ return { error: res.error.message ?? "Failed to change password" };
87
+ }
88
+ haptics.success();
89
+ announce("Password changed. Other sessions have been signed out.");
90
+ return { ok: true };
91
+ } catch {
92
+ haptics.error();
93
+ return { error: "An unexpected error occurred" };
94
+ }
95
+ }, initialState);
96
+
97
+ const navigation = useNavigation();
98
+ const hasInput = current.length > 0 || next.length > 0 || confirm.length > 0;
99
+ const [pendingNavAction, setPendingNavAction] = useState<
100
+ Parameters<typeof navigation.dispatch>[0] | null
101
+ >(null);
102
+ useEffect(() => {
103
+ if (!hasInput || state.ok) return;
104
+ return navigation.addListener("beforeRemove", (e) => {
105
+ e.preventDefault();
106
+ setPendingNavAction(e.data.action);
107
+ });
108
+ }, [navigation, hasInput, state.ok]);
109
+
110
+ useEffect(() => {
111
+ if (state.ok) router.back();
112
+ }, [state.ok]);
113
+
114
+ const labelModifiers = [dfont({ size: 17, weight: "semibold" })];
115
+ const helperModifiers = [dfont({ size: 13 }), foregroundStyle(colors.mutedForeground as string)];
116
+
117
+ return (
118
+ <Host testID="change-password-screen" style={{ flex: 1, backgroundColor: colors.background }}>
119
+ <ScrollView
120
+ modifiers={[
121
+ scrollDismissesKeyboard("interactively"),
122
+ tint(colors.primary as string),
123
+ // A wrong-current-password error appears below the confirm field and
124
+ // pushes the Update button down. Pin the visible center so the user
125
+ // does not lose the field they just submitted. No-op below iOS 18.
126
+ defaultScrollAnchorForRole("center", "sizeChanges"),
127
+ ]}
128
+ >
129
+ <VStack
130
+ spacing={20}
131
+ alignment="leading"
132
+ modifiers={[padding({ horizontal: 24, top: 24, bottom: 40 })]}
133
+ >
134
+ <VStack spacing={6} alignment="leading">
135
+ <Text testID="change-password-title" modifiers={[dfont({ size: 28, weight: "bold" })]}>
136
+ Change password
137
+ </Text>
138
+ <Text
139
+ modifiers={[dfont({ size: 14 }), foregroundStyle(colors.mutedForeground as string)]}
140
+ >
141
+ Other devices will be signed out.
142
+ </Text>
143
+ </VStack>
144
+
145
+ <VStack spacing={6} alignment="leading" modifiers={[frame({ maxWidth: Infinity })]}>
146
+ <Text modifiers={labelModifiers}>Account</Text>
147
+ <TextField
148
+ testID="change-password-account"
149
+ text={emailState}
150
+ modifiers={[
151
+ textFieldStyle("plain"),
152
+ padding({ horizontal: 16 }),
153
+ frame({ maxWidth: Infinity, minHeight: ButtonTokens.height }),
154
+ background(colors.muted as string),
155
+ clipShape("capsule"),
156
+ dfont({ size: 16 }),
157
+ foregroundStyle(colors.mutedForeground as string),
158
+ textContentType("username"),
159
+ disabled(true),
160
+ accessibilityLabel("Account email"),
161
+ ]}
162
+ />
163
+ </VStack>
164
+
165
+ <VStack spacing={6} alignment="leading" modifiers={[frame({ maxWidth: Infinity })]}>
166
+ <Text modifiers={labelModifiers}>Current password</Text>
167
+ <PasswordField
168
+ testID="change-password-current"
169
+ onTextChange={setCurrent}
170
+ disabled={isPending}
171
+ submitLabelType="next"
172
+ accessibilityLabel="Current password"
173
+ accessibilityHint="Enter your existing password"
174
+ />
175
+ </VStack>
176
+
177
+ <VStack spacing={6} alignment="leading" modifiers={[frame({ maxWidth: Infinity })]}>
178
+ <Text modifiers={labelModifiers}>New password</Text>
179
+ <PasswordField
180
+ testID="change-password-new"
181
+ onTextChange={setNext}
182
+ contentType="newPassword"
183
+ disabled={isPending}
184
+ submitLabelType="next"
185
+ accessibilityLabel="New password"
186
+ accessibilityHint="Choose a new password with at least 10 characters"
187
+ />
188
+ <Text modifiers={helperModifiers}>At least 10 characters.</Text>
189
+ </VStack>
190
+
191
+ <VStack spacing={6} alignment="leading" modifiers={[frame({ maxWidth: Infinity })]}>
192
+ <Text modifiers={labelModifiers}>Confirm new password</Text>
193
+ <PasswordField
194
+ testID="change-password-confirm"
195
+ onTextChange={setConfirm}
196
+ onSubmit={() => startTransition(() => submit())}
197
+ contentType="newPassword"
198
+ disabled={isPending}
199
+ accessibilityLabel="Confirm new password"
200
+ accessibilityHint="Re-enter the new password to confirm"
201
+ />
202
+ </VStack>
203
+
204
+ {state.error ? <ErrorText testID="change-password-error">{state.error}</ErrorText> : null}
205
+
206
+ <ProminentButton
207
+ testID="change-password-submit"
208
+ label={isPending ? "Updating..." : "Update password"}
209
+ onPress={() => startTransition(() => submit())}
210
+ disabled={isPending}
211
+ />
212
+
213
+ <VStack alignment="center" modifiers={[frame({ maxWidth: Infinity })]}>
214
+ <Button
215
+ testID="change-password-cancel"
216
+ label="Cancel"
217
+ modifiers={[
218
+ buttonStyle("plain"),
219
+ foregroundStyle(colors.mutedForeground as string),
220
+ dfont({ size: 14, weight: "semibold" }),
221
+ frame({ minHeight: TouchTarget.min }),
222
+ disabled(isPending),
223
+ ]}
224
+ onPress={() => {
225
+ haptics.light();
226
+ router.back();
227
+ }}
228
+ />
229
+ </VStack>
230
+ </VStack>
231
+ </ScrollView>
232
+
233
+ <ConfirmationDialog
234
+ title="Discard changes?"
235
+ isPresented={pendingNavAction !== null}
236
+ onIsPresentedChange={(v) => {
237
+ if (!v) setPendingNavAction(null);
238
+ }}
239
+ titleVisibility="visible"
240
+ >
241
+ <ConfirmationDialog.Trigger>
242
+ <Spacer modifiers={[frame({ width: 0, height: 0 })]} />
243
+ </ConfirmationDialog.Trigger>
244
+ <ConfirmationDialog.Actions>
245
+ <Button
246
+ testID="change-password-discard"
247
+ label="Discard"
248
+ role="destructive"
249
+ onPress={() => {
250
+ haptics.warning();
251
+ const action = pendingNavAction;
252
+ setPendingNavAction(null);
253
+ if (action) navigation.dispatch(action);
254
+ }}
255
+ />
256
+ <Button testID="change-password-keep-editing" label="Keep Editing" role="cancel" />
257
+ </ConfirmationDialog.Actions>
258
+ <ConfirmationDialog.Message>
259
+ <Text modifiers={[dfont({ size: 16 })]}>Your password entries will be lost.</Text>
260
+ </ConfirmationDialog.Message>
261
+ </ConfirmationDialog>
262
+ </Host>
263
+ );
264
+ }