@oxy.so/services 8.3.0 → 9.0.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 (186) hide show
  1. package/lib/commonjs/ui/components/BenefitList.js +1 -2
  2. package/lib/commonjs/ui/components/BenefitList.js.map +1 -1
  3. package/lib/commonjs/ui/components/BloomLocaleBridge.js +37 -0
  4. package/lib/commonjs/ui/components/BloomLocaleBridge.js.map +1 -0
  5. package/lib/commonjs/ui/components/OxyProvider.js +11 -6
  6. package/lib/commonjs/ui/components/OxyProvider.js.map +1 -1
  7. package/lib/commonjs/ui/components/OxySignInRequestSurface.js +0 -1
  8. package/lib/commonjs/ui/components/OxySignInRequestSurface.js.map +1 -1
  9. package/lib/commonjs/ui/components/SurfaceScreen.js +4 -10
  10. package/lib/commonjs/ui/components/SurfaceScreen.js.map +1 -1
  11. package/lib/commonjs/ui/components/authChooser/TroubleDisclosure.js +0 -1
  12. package/lib/commonjs/ui/components/authChooser/TroubleDisclosure.js.map +1 -1
  13. package/lib/commonjs/ui/components/authChooser/primitives.js +9 -11
  14. package/lib/commonjs/ui/components/authChooser/primitives.js.map +1 -1
  15. package/lib/commonjs/ui/components/authChooser/requestSurfaces.js +13 -10
  16. package/lib/commonjs/ui/components/authChooser/requestSurfaces.js.map +1 -1
  17. package/lib/commonjs/ui/components/authChooser/styles.js +4 -1
  18. package/lib/commonjs/ui/components/authChooser/styles.js.map +1 -1
  19. package/lib/commonjs/ui/components/payment/PaymentDetailsStep.js +2 -2
  20. package/lib/commonjs/ui/components/payment/PaymentDetailsStep.js.map +1 -1
  21. package/lib/commonjs/ui/components/signIn/InlineCommonsQr.js +5 -2
  22. package/lib/commonjs/ui/components/signIn/InlineCommonsQr.js.map +1 -1
  23. package/lib/commonjs/ui/components/signIn/OxyAccountPicker.js +13 -17
  24. package/lib/commonjs/ui/components/signIn/OxyAccountPicker.js.map +1 -1
  25. package/lib/commonjs/ui/components/signIn/OxyAuthScreen.js +9 -8
  26. package/lib/commonjs/ui/components/signIn/OxyAuthScreen.js.map +1 -1
  27. package/lib/commonjs/ui/components/signIn/OxyAuthenticatorPanel.js +38 -42
  28. package/lib/commonjs/ui/components/signIn/OxyAuthenticatorPanel.js.map +1 -1
  29. package/lib/commonjs/ui/components/signIn/OxyDeleteAccountPanel.js +21 -6
  30. package/lib/commonjs/ui/components/signIn/OxyDeleteAccountPanel.js.map +1 -1
  31. package/lib/commonjs/ui/components/signIn/OxyLinkCommonsPanel.js +4 -2
  32. package/lib/commonjs/ui/components/signIn/OxyLinkCommonsPanel.js.map +1 -1
  33. package/lib/commonjs/ui/components/signIn/OxyPasswordPanel.js +5 -16
  34. package/lib/commonjs/ui/components/signIn/OxyPasswordPanel.js.map +1 -1
  35. package/lib/commonjs/ui/components/signIn/OxySignInPanel.js +19 -20
  36. package/lib/commonjs/ui/components/signIn/OxySignInPanel.js.map +1 -1
  37. package/lib/commonjs/ui/components/signIn/OxySignUpPanel.js +12 -8
  38. package/lib/commonjs/ui/components/signIn/OxySignUpPanel.js.map +1 -1
  39. package/lib/commonjs/ui/components/signIn/ReauthStep.js +2 -7
  40. package/lib/commonjs/ui/components/signIn/ReauthStep.js.map +1 -1
  41. package/lib/commonjs/ui/components/signIn/accountFlowParts.js +64 -13
  42. package/lib/commonjs/ui/components/signIn/accountFlowParts.js.map +1 -1
  43. package/lib/commonjs/ui/screens/AppInfoScreen.js +2 -1
  44. package/lib/commonjs/ui/screens/AppInfoScreen.js.map +1 -1
  45. package/lib/commonjs/ui/utils/clipboard.js +21 -0
  46. package/lib/commonjs/ui/utils/clipboard.js.map +1 -0
  47. package/lib/commonjs/ui/utils/clipboard.native.js +28 -0
  48. package/lib/commonjs/ui/utils/clipboard.native.js.map +1 -0
  49. package/lib/module/ui/components/BenefitList.js +1 -2
  50. package/lib/module/ui/components/BenefitList.js.map +1 -1
  51. package/lib/module/ui/components/BloomLocaleBridge.js +33 -0
  52. package/lib/module/ui/components/BloomLocaleBridge.js.map +1 -0
  53. package/lib/module/ui/components/OxyProvider.js +11 -6
  54. package/lib/module/ui/components/OxyProvider.js.map +1 -1
  55. package/lib/module/ui/components/OxySignInRequestSurface.js +0 -1
  56. package/lib/module/ui/components/OxySignInRequestSurface.js.map +1 -1
  57. package/lib/module/ui/components/SurfaceScreen.js +5 -11
  58. package/lib/module/ui/components/SurfaceScreen.js.map +1 -1
  59. package/lib/module/ui/components/authChooser/TroubleDisclosure.js +0 -1
  60. package/lib/module/ui/components/authChooser/TroubleDisclosure.js.map +1 -1
  61. package/lib/module/ui/components/authChooser/primitives.js +11 -12
  62. package/lib/module/ui/components/authChooser/primitives.js.map +1 -1
  63. package/lib/module/ui/components/authChooser/requestSurfaces.js +15 -10
  64. package/lib/module/ui/components/authChooser/requestSurfaces.js.map +1 -1
  65. package/lib/module/ui/components/authChooser/styles.js +4 -1
  66. package/lib/module/ui/components/authChooser/styles.js.map +1 -1
  67. package/lib/module/ui/components/payment/PaymentDetailsStep.js +3 -3
  68. package/lib/module/ui/components/payment/PaymentDetailsStep.js.map +1 -1
  69. package/lib/module/ui/components/signIn/InlineCommonsQr.js +6 -3
  70. package/lib/module/ui/components/signIn/InlineCommonsQr.js.map +1 -1
  71. package/lib/module/ui/components/signIn/OxyAccountPicker.js +13 -17
  72. package/lib/module/ui/components/signIn/OxyAccountPicker.js.map +1 -1
  73. package/lib/module/ui/components/signIn/OxyAuthScreen.js +10 -9
  74. package/lib/module/ui/components/signIn/OxyAuthScreen.js.map +1 -1
  75. package/lib/module/ui/components/signIn/OxyAuthenticatorPanel.js +40 -44
  76. package/lib/module/ui/components/signIn/OxyAuthenticatorPanel.js.map +1 -1
  77. package/lib/module/ui/components/signIn/OxyDeleteAccountPanel.js +22 -7
  78. package/lib/module/ui/components/signIn/OxyDeleteAccountPanel.js.map +1 -1
  79. package/lib/module/ui/components/signIn/OxyLinkCommonsPanel.js +5 -3
  80. package/lib/module/ui/components/signIn/OxyLinkCommonsPanel.js.map +1 -1
  81. package/lib/module/ui/components/signIn/OxyPasswordPanel.js +6 -17
  82. package/lib/module/ui/components/signIn/OxyPasswordPanel.js.map +1 -1
  83. package/lib/module/ui/components/signIn/OxySignInPanel.js +20 -21
  84. package/lib/module/ui/components/signIn/OxySignInPanel.js.map +1 -1
  85. package/lib/module/ui/components/signIn/OxySignUpPanel.js +13 -9
  86. package/lib/module/ui/components/signIn/OxySignUpPanel.js.map +1 -1
  87. package/lib/module/ui/components/signIn/ReauthStep.js +3 -8
  88. package/lib/module/ui/components/signIn/ReauthStep.js.map +1 -1
  89. package/lib/module/ui/components/signIn/accountFlowParts.js +60 -11
  90. package/lib/module/ui/components/signIn/accountFlowParts.js.map +1 -1
  91. package/lib/module/ui/screens/AppInfoScreen.js +3 -2
  92. package/lib/module/ui/screens/AppInfoScreen.js.map +1 -1
  93. package/lib/module/ui/utils/clipboard.js +17 -0
  94. package/lib/module/ui/utils/clipboard.js.map +1 -0
  95. package/lib/module/ui/utils/clipboard.native.js +23 -0
  96. package/lib/module/ui/utils/clipboard.native.js.map +1 -0
  97. package/lib/typescript/commonjs/ui/components/BloomLocaleBridge.d.ts +19 -0
  98. package/lib/typescript/commonjs/ui/components/BloomLocaleBridge.d.ts.map +1 -0
  99. package/lib/typescript/commonjs/ui/components/OxyProvider.d.ts.map +1 -1
  100. package/lib/typescript/commonjs/ui/components/OxySignInRequestSurface.d.ts.map +1 -1
  101. package/lib/typescript/commonjs/ui/components/SurfaceScreen.d.ts.map +1 -1
  102. package/lib/typescript/commonjs/ui/components/authChooser/TroubleDisclosure.d.ts.map +1 -1
  103. package/lib/typescript/commonjs/ui/components/authChooser/primitives.d.ts +4 -2
  104. package/lib/typescript/commonjs/ui/components/authChooser/primitives.d.ts.map +1 -1
  105. package/lib/typescript/commonjs/ui/components/authChooser/requestSurfaces.d.ts +4 -4
  106. package/lib/typescript/commonjs/ui/components/authChooser/requestSurfaces.d.ts.map +1 -1
  107. package/lib/typescript/commonjs/ui/components/authChooser/styles.d.ts +2 -1
  108. package/lib/typescript/commonjs/ui/components/authChooser/styles.d.ts.map +1 -1
  109. package/lib/typescript/commonjs/ui/components/payment/PaymentDetailsStep.d.ts.map +1 -1
  110. package/lib/typescript/commonjs/ui/components/signIn/InlineCommonsQr.d.ts.map +1 -1
  111. package/lib/typescript/commonjs/ui/components/signIn/OxyAccountPicker.d.ts.map +1 -1
  112. package/lib/typescript/commonjs/ui/components/signIn/OxyAuthScreen.d.ts +1 -5
  113. package/lib/typescript/commonjs/ui/components/signIn/OxyAuthScreen.d.ts.map +1 -1
  114. package/lib/typescript/commonjs/ui/components/signIn/OxyAuthenticatorPanel.d.ts.map +1 -1
  115. package/lib/typescript/commonjs/ui/components/signIn/OxyDeleteAccountPanel.d.ts.map +1 -1
  116. package/lib/typescript/commonjs/ui/components/signIn/OxyLinkCommonsPanel.d.ts.map +1 -1
  117. package/lib/typescript/commonjs/ui/components/signIn/OxyPasswordPanel.d.ts.map +1 -1
  118. package/lib/typescript/commonjs/ui/components/signIn/OxySignInPanel.d.ts.map +1 -1
  119. package/lib/typescript/commonjs/ui/components/signIn/OxySignUpPanel.d.ts.map +1 -1
  120. package/lib/typescript/commonjs/ui/components/signIn/ReauthStep.d.ts.map +1 -1
  121. package/lib/typescript/commonjs/ui/components/signIn/accountFlowParts.d.ts +29 -2
  122. package/lib/typescript/commonjs/ui/components/signIn/accountFlowParts.d.ts.map +1 -1
  123. package/lib/typescript/commonjs/ui/icons/MaterialCommunityIcons.d.ts +1 -1
  124. package/lib/typescript/commonjs/ui/screens/AppInfoScreen.d.ts.map +1 -1
  125. package/lib/typescript/commonjs/ui/utils/clipboard.d.ts +11 -0
  126. package/lib/typescript/commonjs/ui/utils/clipboard.d.ts.map +1 -0
  127. package/lib/typescript/commonjs/ui/utils/clipboard.native.d.ts +18 -0
  128. package/lib/typescript/commonjs/ui/utils/clipboard.native.d.ts.map +1 -0
  129. package/lib/typescript/module/ui/components/BloomLocaleBridge.d.ts +19 -0
  130. package/lib/typescript/module/ui/components/BloomLocaleBridge.d.ts.map +1 -0
  131. package/lib/typescript/module/ui/components/OxyProvider.d.ts.map +1 -1
  132. package/lib/typescript/module/ui/components/OxySignInRequestSurface.d.ts.map +1 -1
  133. package/lib/typescript/module/ui/components/SurfaceScreen.d.ts.map +1 -1
  134. package/lib/typescript/module/ui/components/authChooser/TroubleDisclosure.d.ts.map +1 -1
  135. package/lib/typescript/module/ui/components/authChooser/primitives.d.ts +4 -2
  136. package/lib/typescript/module/ui/components/authChooser/primitives.d.ts.map +1 -1
  137. package/lib/typescript/module/ui/components/authChooser/requestSurfaces.d.ts +4 -4
  138. package/lib/typescript/module/ui/components/authChooser/requestSurfaces.d.ts.map +1 -1
  139. package/lib/typescript/module/ui/components/authChooser/styles.d.ts +2 -1
  140. package/lib/typescript/module/ui/components/authChooser/styles.d.ts.map +1 -1
  141. package/lib/typescript/module/ui/components/payment/PaymentDetailsStep.d.ts.map +1 -1
  142. package/lib/typescript/module/ui/components/signIn/InlineCommonsQr.d.ts.map +1 -1
  143. package/lib/typescript/module/ui/components/signIn/OxyAccountPicker.d.ts.map +1 -1
  144. package/lib/typescript/module/ui/components/signIn/OxyAuthScreen.d.ts +1 -5
  145. package/lib/typescript/module/ui/components/signIn/OxyAuthScreen.d.ts.map +1 -1
  146. package/lib/typescript/module/ui/components/signIn/OxyAuthenticatorPanel.d.ts.map +1 -1
  147. package/lib/typescript/module/ui/components/signIn/OxyDeleteAccountPanel.d.ts.map +1 -1
  148. package/lib/typescript/module/ui/components/signIn/OxyLinkCommonsPanel.d.ts.map +1 -1
  149. package/lib/typescript/module/ui/components/signIn/OxyPasswordPanel.d.ts.map +1 -1
  150. package/lib/typescript/module/ui/components/signIn/OxySignInPanel.d.ts.map +1 -1
  151. package/lib/typescript/module/ui/components/signIn/OxySignUpPanel.d.ts.map +1 -1
  152. package/lib/typescript/module/ui/components/signIn/ReauthStep.d.ts.map +1 -1
  153. package/lib/typescript/module/ui/components/signIn/accountFlowParts.d.ts +29 -2
  154. package/lib/typescript/module/ui/components/signIn/accountFlowParts.d.ts.map +1 -1
  155. package/lib/typescript/module/ui/icons/MaterialCommunityIcons.d.ts +1 -1
  156. package/lib/typescript/module/ui/screens/AppInfoScreen.d.ts.map +1 -1
  157. package/lib/typescript/module/ui/utils/clipboard.d.ts +11 -0
  158. package/lib/typescript/module/ui/utils/clipboard.d.ts.map +1 -0
  159. package/lib/typescript/module/ui/utils/clipboard.native.d.ts +18 -0
  160. package/lib/typescript/module/ui/utils/clipboard.native.d.ts.map +1 -0
  161. package/package.json +11 -6
  162. package/src/ui/components/BenefitList.tsx +1 -1
  163. package/src/ui/components/BloomLocaleBridge.tsx +23 -0
  164. package/src/ui/components/OxyProvider.tsx +13 -8
  165. package/src/ui/components/OxySignInRequestSurface.tsx +0 -1
  166. package/src/ui/components/SurfaceScreen.tsx +3 -9
  167. package/src/ui/components/__tests__/BloomLocaleBridge.test.tsx +68 -0
  168. package/src/ui/components/authChooser/TroubleDisclosure.tsx +0 -1
  169. package/src/ui/components/authChooser/primitives.tsx +11 -9
  170. package/src/ui/components/authChooser/requestSurfaces.tsx +9 -8
  171. package/src/ui/components/authChooser/styles.ts +4 -1
  172. package/src/ui/components/payment/PaymentDetailsStep.tsx +5 -3
  173. package/src/ui/components/signIn/InlineCommonsQr.tsx +5 -2
  174. package/src/ui/components/signIn/OxyAccountPicker.tsx +14 -13
  175. package/src/ui/components/signIn/OxyAuthScreen.tsx +5 -8
  176. package/src/ui/components/signIn/OxyAuthenticatorPanel.tsx +33 -45
  177. package/src/ui/components/signIn/OxyDeleteAccountPanel.tsx +17 -3
  178. package/src/ui/components/signIn/OxyLinkCommonsPanel.tsx +3 -2
  179. package/src/ui/components/signIn/OxyPasswordPanel.tsx +6 -12
  180. package/src/ui/components/signIn/OxySignInPanel.tsx +18 -15
  181. package/src/ui/components/signIn/OxySignUpPanel.tsx +13 -5
  182. package/src/ui/components/signIn/ReauthStep.tsx +4 -7
  183. package/src/ui/components/signIn/accountFlowParts.tsx +61 -7
  184. package/src/ui/screens/AppInfoScreen.tsx +2 -2
  185. package/src/ui/utils/clipboard.native.ts +20 -0
  186. package/src/ui/utils/clipboard.ts +14 -0
@@ -8,7 +8,6 @@
8
8
 
9
9
  import type React from 'react';
10
10
  import { useState } from 'react';
11
- import { useTheme } from '@oxy.so/bloom/theme';
12
11
  import { EMAIL_CODE_LENGTH, TOTP_DIGITS, type ReauthAction, type ReauthProof } from '@oxy.so/contracts';
13
12
  import { useOxy } from '../../context/OxyContext';
14
13
  import { useI18n } from '../../hooks/useI18n';
@@ -20,6 +19,7 @@ import {
20
19
  AccountFlowErrorLine,
21
20
  AccountFlowField,
22
21
  AccountFlowNote,
22
+ AccountFlowNotice,
23
23
  BACKUP_CODE_LENGTH,
24
24
  describeSignInError,
25
25
  } from './accountFlowParts';
@@ -58,7 +58,6 @@ export const ReauthStep: React.FC<ReauthStepProps> = ({
58
58
  secondary,
59
59
  children,
60
60
  }) => {
61
- const theme = useTheme();
62
61
  const { t } = useI18n();
63
62
  const { oxyServices } = useOxy();
64
63
  const [mode, setMode] = useState<'email' | 'password'>(allowPassword ? 'password' : 'email');
@@ -140,7 +139,7 @@ export const ReauthStep: React.FC<ReauthStepProps> = ({
140
139
  />
141
140
  ) : verificationId ? (
142
141
  <>
143
- <AccountFlowNote>{t('reauth.codeSent')}</AccountFlowNote>
142
+ <AccountFlowNotice testID="reauth-code-sent">{t('reauth.codeSent')}</AccountFlowNotice>
144
143
  <AccountFlowCodeField
145
144
  label={t('reauth.codeLabel')}
146
145
  value={emailCode}
@@ -171,7 +170,6 @@ export const ReauthStep: React.FC<ReauthStepProps> = ({
171
170
  />
172
171
  <SubtleLink
173
172
  label={useBackupCode ? t('signin.secondFactor.useAuthenticator') : t('signin.secondFactor.useBackup')}
174
- theme={theme}
175
173
  onPress={() => {
176
174
  setUseBackupCode(!useBackupCode);
177
175
  setTotpCode('');
@@ -191,12 +189,11 @@ export const ReauthStep: React.FC<ReauthStepProps> = ({
191
189
  testID={needsCode ? 'reauth-send-code' : 'reauth-submit'}
192
190
  />
193
191
  {mode === 'email' && verificationId ? (
194
- <SubtleLink label={t('emailCode.resend')} theme={theme} onPress={sendCode} disabled={pending} testID="reauth-resend" />
192
+ <SubtleLink label={t('emailCode.resend')} onPress={sendCode} disabled={pending} testID="reauth-resend" />
195
193
  ) : null}
196
194
  {allowPassword ? (
197
195
  <SubtleLink
198
196
  label={mode === 'password' ? t('reauth.useEmail') : t('reauth.usePassword')}
199
- theme={theme}
200
197
  onPress={() => {
201
198
  setError(null);
202
199
  setMode(mode === 'password' ? 'email' : 'password');
@@ -206,7 +203,7 @@ export const ReauthStep: React.FC<ReauthStepProps> = ({
206
203
  />
207
204
  ) : null}
208
205
  {secondary ? (
209
- <SubtleLink label={secondary.label} theme={theme} onPress={secondary.onPress} disabled={pending} testID="reauth-cancel" />
206
+ <SubtleLink label={secondary.label} onPress={secondary.onPress} disabled={pending} testID="reauth-cancel" />
210
207
  ) : null}
211
208
  </OxyAuthScreen>
212
209
  );
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * The pieces every Oxy sign-in and account screen shares: the error vocabulary,
3
3
  * one labelled field, one one-time-code field, the one primary action, a note,
4
- * and the email-code step.
4
+ * a notice, and the email-code step.
5
5
  * Each screen is built from the same shell as `OxySignInPanel`
6
6
  * (`OxyAuthScreen`), so they read as one product in the account dialog, in an
7
7
  * app's settings and on auth.oxy.so.
@@ -10,12 +10,14 @@
10
10
  import type React from 'react';
11
11
  import { useState } from 'react';
12
12
  import { StyleSheet, View } from 'react-native';
13
+ import { Admonition } from '@oxy.so/bloom/admonition';
13
14
  import { Button } from '@oxy.so/bloom/button';
14
15
  import { Field } from '@oxy.so/bloom/field';
15
16
  import { InputOtp } from '@oxy.so/bloom/input-otp';
16
17
  import { useTheme } from '@oxy.so/bloom/theme';
17
18
  import { TextField, TextFieldHint, TextFieldInput, TextFieldLabel } from '@oxy.so/bloom/text-field';
18
19
  import { Text } from '@oxy.so/bloom/typography';
20
+ import { WizardProgress } from '@oxy.so/bloom/wizard';
19
21
  import {
20
22
  EMAIL_CODE_LENGTH,
21
23
  EMAIL_SIGNIN_LONG_CODE_ALPHABET,
@@ -119,7 +121,11 @@ export function isCompleteSignInCode(typed: string): boolean {
119
121
  /** Characters in a backup code (`xxxxx-xxxxx`, its dash not counted). */
120
122
  export const BACKUP_CODE_LENGTH = 10;
121
123
 
122
- /** One labelled input, the way the sign-in screen draws its fields. */
124
+ /**
125
+ * One labelled input, the way the sign-in screen draws its fields. A
126
+ * `secureTextEntry` field is always revealable: Bloom's eye button shows and
127
+ * hides the password, named in the locale Bloom speaks (`OxyProvider` sets it).
128
+ */
123
129
  export const AccountFlowField: React.FC<{
124
130
  label: string;
125
131
  value: string;
@@ -161,6 +167,7 @@ export const AccountFlowField: React.FC<{
161
167
  autoComplete={autoComplete}
162
168
  keyboardType={keyboardType}
163
169
  secureTextEntry={secureTextEntry}
170
+ revealable={secureTextEntry}
164
171
  autoCapitalize="none"
165
172
  autoCorrect={false}
166
173
  autoFocus={autoFocus}
@@ -257,6 +264,44 @@ export const AccountFlowNote: React.FC<{ children: React.ReactNode; testID?: str
257
264
  );
258
265
  };
259
266
 
267
+ /**
268
+ * Something the person should know before acting, above the action it is
269
+ * about: a wait before trying again, a code that was just sent, a warning. A
270
+ * Bloom `Admonition`, not a field's error hint — nothing they typed is wrong.
271
+ */
272
+ export const AccountFlowNotice: React.FC<{
273
+ children: React.ReactNode;
274
+ type?: 'info' | 'warning' | 'error';
275
+ testID?: string;
276
+ }> = ({ children, type = 'info', testID }) => (
277
+ <View testID={testID}>
278
+ <Admonition type={type}>{children}</Admonition>
279
+ </View>
280
+ );
281
+
282
+ /**
283
+ * Where a step sits in a flow of several (sign-up, turning on the
284
+ * authenticator): Bloom's segmented `WizardProgress` and "Step 2 of 3". The
285
+ * screen's own header names the step, so the progress draws no title; the
286
+ * titles still name the bar for assistive technology.
287
+ */
288
+ export const AccountFlowProgress: React.FC<{ steps: readonly string[]; current: number; testID?: string }> = ({
289
+ steps,
290
+ current,
291
+ testID,
292
+ }) => {
293
+ const { t } = useI18n();
294
+ return (
295
+ <WizardProgress
296
+ steps={steps.map((title, index) => ({ key: String(index), title }))}
297
+ current={current}
298
+ hideTitle
299
+ formatStepCount={(step, total) => t('common.stepOf', { step, total })}
300
+ testID={testID}
301
+ />
302
+ );
303
+ };
304
+
260
305
  /** Why a step failed, where it happened. */
261
306
  export const AccountFlowErrorLine: React.FC<{ message: string }> = ({ message }) => {
262
307
  const theme = useTheme();
@@ -277,11 +322,19 @@ export interface EmailCodeStepProps {
277
322
  onResend: () => Promise<void>;
278
323
  /** "Use another email" / "Back" — the step before. */
279
324
  back: { label: string; onPress: () => void };
325
+ /** Where this step sits in a longer flow (a `WizardProgress`), under the header. */
326
+ progress?: React.ReactNode;
280
327
  }
281
328
 
282
329
  /** "Check your email": the 6-digit code an email verification sent. Submits itself once complete. */
283
- export const EmailCodeStep: React.FC<EmailCodeStepProps> = ({ description, verificationId, onConfirmed, onResend, back }) => {
284
- const theme = useTheme();
330
+ export const EmailCodeStep: React.FC<EmailCodeStepProps> = ({
331
+ description,
332
+ verificationId,
333
+ onConfirmed,
334
+ onResend,
335
+ back,
336
+ progress,
337
+ }) => {
285
338
  const { t } = useI18n();
286
339
  const { oxyServices } = useOxy();
287
340
  const [code, setCode] = useState('');
@@ -317,6 +370,7 @@ export const EmailCodeStep: React.FC<EmailCodeStepProps> = ({ description, verif
317
370
  return (
318
371
  <OxyAuthScreen>
319
372
  <OxyAuthScreenHeader title={t('emailCode.title')} description={description} />
373
+ {progress}
320
374
  <AccountFlowCodeField
321
375
  label={t('emailCode.label')}
322
376
  value={code}
@@ -330,10 +384,10 @@ export const EmailCodeStep: React.FC<EmailCodeStepProps> = ({ description, verif
330
384
  length={EMAIL_CODE_LENGTH}
331
385
  testID="email-code"
332
386
  />
333
- {notice ? <Text style={[styles.note, { color: theme.colors.textSecondary }]}>{notice}</Text> : null}
387
+ {notice ? <AccountFlowNotice testID="email-code-notice">{notice}</AccountFlowNotice> : null}
334
388
  <AccountFlowAction label={t('signin.actions.continue')} onPress={() => confirm(code)} pending={pending} testID="email-code-continue" />
335
- <SubtleLink label={t('emailCode.resend')} theme={theme} onPress={resend} disabled={pending} testID="email-code-resend" />
336
- <SubtleLink label={back.label} theme={theme} onPress={back.onPress} disabled={pending} testID="email-code-back" />
389
+ <SubtleLink label={t('emailCode.resend')} onPress={resend} disabled={pending} testID="email-code-resend" />
390
+ <SubtleLink label={back.label} onPress={back.onPress} disabled={pending} testID="email-code-back" />
337
391
  </OxyAuthScreen>
338
392
  );
339
393
  };
@@ -4,12 +4,12 @@ import {
4
4
  View,
5
5
  Platform,
6
6
  Dimensions,
7
- Clipboard,
8
7
  ActivityIndicator,
9
8
  } from 'react-native';
10
9
  import type { BaseScreenProps } from '../types/navigation';
11
10
  import { packageInfo } from '@oxy.so/core';
12
11
  import { toast } from '@oxy.so/bloom/toast';
12
+ import { copyText } from '../utils/clipboard';
13
13
  import OxyServicesLogo from '../../assets/icons/OxyServices';
14
14
  import { SettingsIcon } from '../components/SettingsIcon';
15
15
  import { useTheme } from '@oxy.so/bloom/theme';
@@ -93,7 +93,7 @@ const AppInfoScreen: React.FC<BaseScreenProps> = ({
93
93
 
94
94
  const copyToClipboard = async (text: string, label: string) => {
95
95
  try {
96
- await Clipboard.setString(text);
96
+ await copyText(text);
97
97
  toast.success(t('appInfo.toasts.copiedToClipboard', { label }));
98
98
  } catch (error) {
99
99
  toast.error(t('appInfo.toasts.copyFailed'));
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Put text on the clipboard on iOS and Android, through `expo-clipboard`.
3
+ * React Native's own `Clipboard` is deprecated and gone from newer releases.
4
+ *
5
+ * `expo-clipboard` is an OPTIONAL peer, loaded with `import()` so an app
6
+ * without it (or with the JS but not the native module, before a rebuild)
7
+ * still bundles and boots: the copy rejects here and the caller says nothing
8
+ * was copied. A static import would instead fail the Metro build or throw
9
+ * while the root barrel evaluates.
10
+ *
11
+ * Only this NATIVE fork names the package; the default fork (`clipboard.ts`,
12
+ * which `tsc`, Vite and SSR resolve) names nothing, so a consumer's type graph
13
+ * reaches `expo-clipboard` only when it typechecks `.native` files
14
+ * (`moduleSuffixes`) — the case package-rules.md#package-boundaries warns
15
+ * about. `clipboardIsolation.test.ts` keeps it that way.
16
+ */
17
+ export async function copyText(text: string): Promise<void> {
18
+ const clipboard = await import('expo-clipboard');
19
+ await clipboard.setStringAsync(text);
20
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Put text on the clipboard: the browser's asynchronous Clipboard API. Rejects
3
+ * where there is none (an insecure origin, SSR, a denied permission), so the
4
+ * caller reports only a copy that happened.
5
+ *
6
+ * The native fork (`clipboard.native.ts`) uses `expo-clipboard`. React
7
+ * Native's own `Clipboard` is deprecated and gone from newer releases, so
8
+ * neither fork reaches for it.
9
+ */
10
+ export async function copyText(text: string): Promise<void> {
11
+ const clipboard = typeof navigator === 'undefined' ? undefined : navigator.clipboard;
12
+ if (!clipboard?.writeText) throw new Error('clipboard unavailable');
13
+ await clipboard.writeText(text);
14
+ }