@dloizides/auth-web 1.3.0 → 1.4.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/dist/index.js CHANGED
@@ -69,6 +69,77 @@ var DEFAULT_PIN_LABELS = {
69
69
  missingPin: "Enter your event PIN.",
70
70
  invalidPin: "That PIN is incorrect, has expired, or is locked out."
71
71
  };
72
+ var DEFAULT_DEVICE_PIN_UNLOCK_LABELS = {
73
+ title: "Welcome back, {name}",
74
+ titleNoName: "Welcome back",
75
+ description: "Enter your {count}-digit PIN to sign in on this device.",
76
+ pinLabel: "PIN",
77
+ pinPlaceholder: "Enter your PIN",
78
+ submit: "Unlock",
79
+ submitting: "Signing in...",
80
+ usePasswordInstead: "Sign in with password instead",
81
+ usePasswordHint: "Switch to signing in with your username and password",
82
+ errorIncomplete: "Enter all {count} digits of your PIN.",
83
+ errorInvalid: "That PIN is incorrect. Try again.",
84
+ errorLockedOut: "Too many attempts. Try again later.",
85
+ errorLockedOutRetry: "Too many attempts. Try again in {count} seconds.",
86
+ errorRateLimited: "Too many requests. Try again later.",
87
+ errorRateLimitedRetry: "Too many requests. Try again in {count} seconds.",
88
+ errorGeneric: "Something went wrong. Try again, or sign in with your password.",
89
+ digitFilledHint: "PIN digit entered",
90
+ digitEmptyHint: "PIN digit not yet entered"
91
+ };
92
+ var DEFAULT_DEVICE_PIN_ENROLL_LABELS = {
93
+ offerTitle: "Set a PIN for faster sign-in?",
94
+ offerDescription: "Next time, sign in on this device with a short PIN instead of your full password.",
95
+ offerAccept: "Set up a PIN",
96
+ offerAcceptHint: "Open the form to choose a quick sign-in PIN",
97
+ offerSkip: "Not now",
98
+ offerSkipHint: "Dismiss the PIN setup offer",
99
+ formTitle: "Choose your PIN",
100
+ formDescription: "Pick a {count}-digit PIN you will remember. You will use it to sign in on this device.",
101
+ lengthLabel: "PIN length",
102
+ lengthOptionHint: "Use a {count}-digit PIN",
103
+ pinLabel: "New PIN",
104
+ pinPlaceholder: "Enter a new PIN",
105
+ confirmLabel: "Confirm PIN",
106
+ confirmPlaceholder: "Re-enter your PIN",
107
+ submit: "Save PIN",
108
+ submitting: "Saving...",
109
+ cancel: "Cancel",
110
+ cancelHint: "Close the PIN setup form without saving",
111
+ errorMismatch: "The PINs must match and be exactly {count} digits.",
112
+ errorUnauthorized: "Your session has expired. Sign in again to set a PIN.",
113
+ errorForbidden: "A PIN is already set for this session.",
114
+ errorInvalidPin: "That PIN is not allowed. Choose a different one.",
115
+ errorFailed: "Could not set your PIN. Try again later."
116
+ };
117
+ var DEFAULT_DEVICE_PIN_SETTINGS_LABELS = {
118
+ title: "Quick PIN sign-in",
119
+ description: "Sign in on this device with a short PIN instead of your full password.",
120
+ statusEnabled: "Quick PIN sign-in is enabled on this device.",
121
+ statusDisabled: "Quick PIN sign-in is off.",
122
+ enable: "Enable quick PIN sign-in",
123
+ enableHint: "Set a PIN so you can sign in faster on this device",
124
+ disable: "Disable",
125
+ disableHint: "Remove the PIN sign-in from this device",
126
+ disabling: "Disabling...",
127
+ disableFailed: "Could not disable PIN sign-in. Try again later."
128
+ };
129
+ var DEFAULT_PASSKEY_LOGIN_LABELS = {
130
+ signInButton: "Sign in with a passkey",
131
+ signInHint: "Use your fingerprint, face, or security key to sign in",
132
+ errorCancelled: "Passkey sign-in was cancelled. You can try again or sign in another way.",
133
+ errorFailed: "Passkey sign-in didn't work. Try again, or sign in another way."
134
+ };
135
+ var DEFAULT_PASSKEY_SETTINGS_LABELS = {
136
+ title: "Passkeys",
137
+ description: "Add a passkey to sign in with your fingerprint, face, or a security key instead of a password.",
138
+ reauthHint: "You'll be asked to confirm your password before adding a passkey.",
139
+ addButton: "Add a passkey",
140
+ addHint: "Start setting up a passkey for this account",
141
+ registeredSuccess: "Your passkey was added. You can now use it to sign in."
142
+ };
72
143
  var DEFAULT_RESET_PASSWORD_LABELS = {
73
144
  title: "Reset password",
74
145
  description: "Choose a new password for your account.",
@@ -117,7 +188,39 @@ var AuthTestIds = {
117
188
  pinForm: "auth-pin-form",
118
189
  pinInput: "auth-pin-input",
119
190
  pinSubmitButton: "auth-pin-submit",
120
- pinError: "auth-pin-error"
191
+ pinError: "auth-pin-error",
192
+ // Device-PIN unlock gate
193
+ devicePinUnlock: "auth-device-pin-unlock",
194
+ devicePinUnlockInput: "auth-device-pin-unlock-input",
195
+ devicePinUnlockSubmit: "auth-device-pin-unlock-submit",
196
+ devicePinUnlockUsePassword: "auth-device-pin-unlock-use-password",
197
+ devicePinUnlockError: "auth-device-pin-unlock-error",
198
+ // Device-PIN enrol form + length picker
199
+ devicePinEnrollForm: "auth-device-pin-enroll-form",
200
+ devicePinEnrollLength: "auth-device-pin-enroll-length",
201
+ devicePinEnrollPin: "auth-device-pin-enroll-pin",
202
+ devicePinEnrollConfirm: "auth-device-pin-enroll-confirm",
203
+ devicePinEnrollSubmit: "auth-device-pin-enroll-submit",
204
+ devicePinEnrollCancel: "auth-device-pin-enroll-cancel",
205
+ devicePinEnrollError: "auth-device-pin-enroll-error",
206
+ // Device-PIN offer (post-login)
207
+ devicePinOffer: "auth-device-pin-offer",
208
+ devicePinOfferAccept: "auth-device-pin-offer-accept",
209
+ devicePinOfferSkip: "auth-device-pin-offer-skip",
210
+ // Device-PIN settings card
211
+ devicePinSettings: "auth-device-pin-settings",
212
+ devicePinSettingsStatus: "auth-device-pin-settings-status",
213
+ devicePinSettingsEnable: "auth-device-pin-settings-enable",
214
+ devicePinSettingsDisable: "auth-device-pin-settings-disable",
215
+ devicePinSettingsError: "auth-device-pin-settings-error",
216
+ // Passkey login button
217
+ passkeyLogin: "auth-passkey-login",
218
+ passkeyLoginButton: "auth-passkey-login-button",
219
+ passkeyLoginError: "auth-passkey-login-error",
220
+ // Passkey settings card
221
+ passkeySettings: "auth-passkey-settings",
222
+ passkeySettingsAdd: "auth-passkey-settings-add",
223
+ passkeySettingsSuccess: "auth-passkey-settings-success"
121
224
  };
122
225
  function withTestIdPrefix(baseId, prefix) {
123
226
  return prefix === void 0 || prefix === "" ? baseId : `${prefix}-${baseId}`;
@@ -211,6 +314,32 @@ function useAuthStyles(theme) {
211
314
  helperText: {
212
315
  fontSize: typography.caption,
213
316
  color: colors.textSecondary
317
+ },
318
+ escapeLink: {
319
+ alignSelf: "center",
320
+ marginTop: spacing.md,
321
+ paddingVertical: spacing.xs / 2
322
+ },
323
+ secondaryButton: {
324
+ borderRadius: radii.input,
325
+ borderWidth: 1,
326
+ borderColor: colors.primary,
327
+ paddingVertical: BUTTON_VERTICAL_PADDING,
328
+ alignItems: "center",
329
+ justifyContent: "center",
330
+ marginTop: spacing.sm,
331
+ backgroundColor: colors.surface
332
+ },
333
+ secondaryButtonText: {
334
+ fontSize: typography.body,
335
+ fontWeight: "600",
336
+ color: colors.primary
337
+ },
338
+ statusText: {
339
+ fontSize: typography.label,
340
+ fontWeight: "600",
341
+ marginTop: spacing.sm,
342
+ color: colors.text
214
343
  }
215
344
  });
216
345
  }, [theme]);
@@ -372,7 +501,7 @@ function LoginForm({
372
501
  testIdPrefix
373
502
  }) {
374
503
  const theme = useAuthTheme(themeProp);
375
- const styles = useAuthStyles(theme);
504
+ const styles3 = useAuthStyles(theme);
376
505
  const labels = react.useMemo(
377
506
  () => ({ ...DEFAULT_LOGIN_LABELS, ...labelsProp }),
378
507
  [labelsProp]
@@ -399,12 +528,12 @@ function LoginForm({
399
528
  const handleSubmit = react.useCallback(() => {
400
529
  void runLogin();
401
530
  }, [runLogin]);
402
- const submitButtonStyle = isSubmitting ? [styles.primaryButton, styles.primaryButtonDisabled] : styles.primaryButton;
403
- return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles.screen, children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles.card, testID: withTestIdPrefix(AuthTestIds.loginForm, testIdPrefix), children: [
404
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles.title, children: labels.title }),
405
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles.subtitle, children: labels.subtitle }),
406
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles.fieldGroup, children: [
407
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles.label, children: labels.usernameLabel }),
531
+ const submitButtonStyle = isSubmitting ? [styles3.primaryButton, styles3.primaryButtonDisabled] : styles3.primaryButton;
532
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles3.screen, children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles3.card, testID: withTestIdPrefix(AuthTestIds.loginForm, testIdPrefix), children: [
533
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.title, children: labels.title }),
534
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.subtitle, children: labels.subtitle }),
535
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles3.fieldGroup, children: [
536
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.label, children: labels.usernameLabel }),
408
537
  /* @__PURE__ */ jsxRuntime.jsx(
409
538
  reactNative.TextInput,
410
539
  {
@@ -415,15 +544,15 @@ function LoginForm({
415
544
  editable: !isSubmitting,
416
545
  placeholder: labels.usernamePlaceholder,
417
546
  placeholderTextColor: theme.colors.textSecondary,
418
- style: styles.input,
547
+ style: styles3.input,
419
548
  testID: withTestIdPrefix(AuthTestIds.loginUsernameInput, testIdPrefix),
420
549
  value: username,
421
550
  onChangeText: setUsername
422
551
  }
423
552
  )
424
553
  ] }),
425
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles.fieldGroup, children: [
426
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles.label, children: labels.passwordLabel }),
554
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles3.fieldGroup, children: [
555
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.label, children: labels.passwordLabel }),
427
556
  /* @__PURE__ */ jsxRuntime.jsx(
428
557
  reactNative.TextInput,
429
558
  {
@@ -435,7 +564,7 @@ function LoginForm({
435
564
  editable: !isSubmitting,
436
565
  placeholder: labels.passwordPlaceholder,
437
566
  placeholderTextColor: theme.colors.textSecondary,
438
- style: styles.input,
567
+ style: styles3.input,
439
568
  testID: withTestIdPrefix(AuthTestIds.loginPasswordInput, testIdPrefix),
440
569
  value: password,
441
570
  onChangeText: setPassword
@@ -445,7 +574,7 @@ function LoginForm({
445
574
  errorText !== null ? /* @__PURE__ */ jsxRuntime.jsx(
446
575
  reactNative.Text,
447
576
  {
448
- style: styles.errorText,
577
+ style: styles3.errorText,
449
578
  testID: withTestIdPrefix(AuthTestIds.loginError, testIdPrefix),
450
579
  children: errorText
451
580
  }
@@ -457,10 +586,10 @@ function LoginForm({
457
586
  accessibilityLabel: labels.forgotPassword,
458
587
  accessibilityRole: "link",
459
588
  disabled: isSubmitting,
460
- style: styles.fieldGroup,
589
+ style: styles3.fieldGroup,
461
590
  testID: withTestIdPrefix(AuthTestIds.loginForgotLink, testIdPrefix),
462
591
  onPress: onForgotPassword,
463
- children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles.linkText, children: labels.forgotPassword })
592
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.linkText, children: labels.forgotPassword })
464
593
  }
465
594
  ) : null,
466
595
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -473,7 +602,7 @@ function LoginForm({
473
602
  style: submitButtonStyle,
474
603
  testID: withTestIdPrefix(AuthTestIds.loginSubmitButton, testIdPrefix),
475
604
  onPress: handleSubmit,
476
- children: isSubmitting ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles.primaryButtonText, children: labels.submit })
605
+ children: isSubmitting ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.primaryButtonText, children: labels.submit })
477
606
  }
478
607
  ),
479
608
  onSignUp !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(
@@ -483,10 +612,10 @@ function LoginForm({
483
612
  accessibilityLabel: labels.signUp,
484
613
  accessibilityRole: "link",
485
614
  disabled: isSubmitting,
486
- style: styles.fieldGroup,
615
+ style: styles3.fieldGroup,
487
616
  testID: withTestIdPrefix(AuthTestIds.loginSignUpLink, testIdPrefix),
488
617
  onPress: onSignUp,
489
- children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles.linkText, children: labels.signUp })
618
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.linkText, children: labels.signUp })
490
619
  }
491
620
  ) : null
492
621
  ] }) });
@@ -524,7 +653,7 @@ function ForgotPasswordForm({
524
653
  testIdPrefix
525
654
  }) {
526
655
  const theme = useAuthTheme(themeProp);
527
- const styles = useAuthStyles(theme);
656
+ const styles3 = useAuthStyles(theme);
528
657
  const labels = react.useMemo(
529
658
  () => ({ ...DEFAULT_FORGOT_PASSWORD_LABELS, ...labelsProp }),
530
659
  [labelsProp]
@@ -556,25 +685,25 @@ function ForgotPasswordForm({
556
685
  }
557
686
  mutation.mutate({ email: trimmedEmail, resetUrlTemplate });
558
687
  }, [email, mutation, resetUrlTemplate, labels.invalidEmail]);
559
- const submitButtonStyle = isPending ? [styles.primaryButton, styles.primaryButtonDisabled] : styles.primaryButton;
560
- return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles.screen, children: /* @__PURE__ */ jsxRuntime.jsxs(
688
+ const submitButtonStyle = isPending ? [styles3.primaryButton, styles3.primaryButtonDisabled] : styles3.primaryButton;
689
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles3.screen, children: /* @__PURE__ */ jsxRuntime.jsxs(
561
690
  reactNative.View,
562
691
  {
563
- style: styles.card,
692
+ style: styles3.card,
564
693
  testID: withTestIdPrefix(AuthTestIds.forgotPasswordForm, testIdPrefix),
565
694
  children: [
566
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles.title, children: labels.title }),
695
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.title, children: labels.title }),
567
696
  submitted ? /* @__PURE__ */ jsxRuntime.jsx(
568
697
  reactNative.Text,
569
698
  {
570
- style: styles.successText,
699
+ style: styles3.successText,
571
700
  testID: withTestIdPrefix(AuthTestIds.forgotPasswordSuccess, testIdPrefix),
572
701
  children: labels.successMessage
573
702
  }
574
703
  ) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
575
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles.subtitle, children: labels.description }),
576
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles.fieldGroup, children: [
577
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles.label, children: labels.emailLabel }),
704
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.subtitle, children: labels.description }),
705
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles3.fieldGroup, children: [
706
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.label, children: labels.emailLabel }),
578
707
  /* @__PURE__ */ jsxRuntime.jsx(
579
708
  reactNative.TextInput,
580
709
  {
@@ -586,7 +715,7 @@ function ForgotPasswordForm({
586
715
  keyboardType: "email-address",
587
716
  placeholder: labels.emailPlaceholder,
588
717
  placeholderTextColor: theme.colors.textSecondary,
589
- style: styles.input,
718
+ style: styles3.input,
590
719
  testID: withTestIdPrefix(AuthTestIds.forgotPasswordEmailInput, testIdPrefix),
591
720
  value: email,
592
721
  onChangeText: setEmail
@@ -596,7 +725,7 @@ function ForgotPasswordForm({
596
725
  errorText !== null ? /* @__PURE__ */ jsxRuntime.jsx(
597
726
  reactNative.Text,
598
727
  {
599
- style: styles.errorText,
728
+ style: styles3.errorText,
600
729
  testID: withTestIdPrefix(AuthTestIds.forgotPasswordError, testIdPrefix),
601
730
  children: errorText
602
731
  }
@@ -611,7 +740,7 @@ function ForgotPasswordForm({
611
740
  style: submitButtonStyle,
612
741
  testID: withTestIdPrefix(AuthTestIds.forgotPasswordSubmitButton, testIdPrefix),
613
742
  onPress: handleSubmit,
614
- children: isPending ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles.primaryButtonText, children: labels.submit })
743
+ children: isPending ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.primaryButtonText, children: labels.submit })
615
744
  }
616
745
  )
617
746
  ] })
@@ -703,7 +832,7 @@ function ForgotPasswordFields({
703
832
  testIdPrefix
704
833
  }) {
705
834
  const theme = useAuthTheme(themeProp);
706
- const styles = useAuthStyles(theme);
835
+ const styles3 = useAuthStyles(theme);
707
836
  const modalStyles = useModalStyles(theme);
708
837
  const labels = react.useMemo(
709
838
  () => ({ ...DEFAULT_FORGOT_PASSWORD_FIELDS_LABELS, ...labelsProp }),
@@ -716,7 +845,7 @@ function ForgotPasswordFields({
716
845
  reset();
717
846
  }
718
847
  }, [visible, reset]);
719
- const submitButtonStyle = form.canSubmit ? styles.primaryButton : [styles.primaryButton, styles.primaryButtonDisabled];
848
+ const submitButtonStyle = form.canSubmit ? styles3.primaryButton : [styles3.primaryButton, styles3.primaryButtonDisabled];
720
849
  const handleCancel = () => {
721
850
  form.reset();
722
851
  onCancel?.();
@@ -727,25 +856,25 @@ function ForgotPasswordFields({
727
856
  };
728
857
  if (form.submitted) {
729
858
  return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: modalStyles.body, testID: withTestIdPrefix(AuthTestIds.forgotPasswordForm, testIdPrefix), children: [
730
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles.successText, testID: withTestIdPrefix(AuthTestIds.forgotPasswordSuccess, testIdPrefix), children: labels.successMessage }),
859
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.successText, testID: withTestIdPrefix(AuthTestIds.forgotPasswordSuccess, testIdPrefix), children: labels.successMessage }),
731
860
  onClose !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: modalStyles.actions, children: /* @__PURE__ */ jsxRuntime.jsx(
732
861
  reactNative.TouchableOpacity,
733
862
  {
734
863
  accessibilityHint: labels.close,
735
864
  accessibilityLabel: labels.close,
736
865
  accessibilityRole: "button",
737
- style: styles.primaryButton,
866
+ style: styles3.primaryButton,
738
867
  testID: withTestIdPrefix(AuthTestIds.forgotPasswordCloseButton, testIdPrefix),
739
868
  onPress: handleClose,
740
- children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles.primaryButtonText, children: labels.close })
869
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.primaryButtonText, children: labels.close })
741
870
  }
742
871
  ) }) : null
743
872
  ] });
744
873
  }
745
874
  return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: modalStyles.body, testID: withTestIdPrefix(AuthTestIds.forgotPasswordForm, testIdPrefix), children: [
746
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles.subtitle, children: labels.description }),
747
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles.fieldGroup, children: [
748
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles.label, children: labels.emailLabel }),
875
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.subtitle, children: labels.description }),
876
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles3.fieldGroup, children: [
877
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.label, children: labels.emailLabel }),
749
878
  /* @__PURE__ */ jsxRuntime.jsx(
750
879
  reactNative.TextInput,
751
880
  {
@@ -757,14 +886,14 @@ function ForgotPasswordFields({
757
886
  keyboardType: "email-address",
758
887
  placeholder: labels.emailPlaceholder,
759
888
  placeholderTextColor: theme.colors.textSecondary,
760
- style: styles.input,
889
+ style: styles3.input,
761
890
  testID: withTestIdPrefix(AuthTestIds.forgotPasswordEmailInput, testIdPrefix),
762
891
  value: form.email,
763
892
  onChangeText: form.setEmail
764
893
  }
765
894
  )
766
895
  ] }),
767
- form.hasNetworkError ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles.errorText, testID: withTestIdPrefix(AuthTestIds.forgotPasswordError, testIdPrefix), children: labels.networkError }) : null,
896
+ form.hasNetworkError ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.errorText, testID: withTestIdPrefix(AuthTestIds.forgotPasswordError, testIdPrefix), children: labels.networkError }) : null,
768
897
  /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: modalStyles.actions, children: [
769
898
  onCancel !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(
770
899
  reactNative.TouchableOpacity,
@@ -789,7 +918,7 @@ function ForgotPasswordFields({
789
918
  style: submitButtonStyle,
790
919
  testID: withTestIdPrefix(AuthTestIds.forgotPasswordSubmitButton, testIdPrefix),
791
920
  onPress: form.submit,
792
- children: form.isSubmitting ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles.primaryButtonText, children: labels.submit })
921
+ children: form.isSubmitting ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.primaryButtonText, children: labels.submit })
793
922
  }
794
923
  )
795
924
  ] })
@@ -968,24 +1097,24 @@ function ResetPasswordForm({
968
1097
  testIdPrefix
969
1098
  }) {
970
1099
  const theme = useAuthTheme(themeProp);
971
- const styles = useAuthStyles(theme);
1100
+ const styles3 = useAuthStyles(theme);
972
1101
  const labels = react.useMemo(
973
1102
  () => ({ ...DEFAULT_RESET_PASSWORD_LABELS, ...labelsProp }),
974
1103
  [labelsProp]
975
1104
  );
976
1105
  const form = useResetPasswordForm({ client, token, onSuccess });
977
1106
  const message = errorMessage(form.errorKey, labels);
978
- const submitButtonStyle = form.isSubmitting ? [styles.primaryButton, styles.primaryButtonDisabled] : styles.primaryButton;
979
- return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles.screen, children: /* @__PURE__ */ jsxRuntime.jsxs(
1107
+ const submitButtonStyle = form.isSubmitting ? [styles3.primaryButton, styles3.primaryButtonDisabled] : styles3.primaryButton;
1108
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles3.screen, children: /* @__PURE__ */ jsxRuntime.jsxs(
980
1109
  reactNative.View,
981
1110
  {
982
- style: styles.card,
1111
+ style: styles3.card,
983
1112
  testID: withTestIdPrefix(AuthTestIds.resetPasswordForm, testIdPrefix),
984
1113
  children: [
985
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles.title, children: labels.title }),
986
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles.subtitle, children: labels.description }),
987
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles.fieldGroup, children: [
988
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles.label, children: labels.newPasswordLabel }),
1114
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.title, children: labels.title }),
1115
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.subtitle, children: labels.description }),
1116
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles3.fieldGroup, children: [
1117
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.label, children: labels.newPasswordLabel }),
989
1118
  /* @__PURE__ */ jsxRuntime.jsx(
990
1119
  reactNative.TextInput,
991
1120
  {
@@ -997,15 +1126,15 @@ function ResetPasswordForm({
997
1126
  editable: !form.isSubmitting,
998
1127
  placeholder: labels.newPasswordPlaceholder,
999
1128
  placeholderTextColor: theme.colors.textSecondary,
1000
- style: styles.input,
1129
+ style: styles3.input,
1001
1130
  testID: withTestIdPrefix(AuthTestIds.resetPasswordNewInput, testIdPrefix),
1002
1131
  value: form.newPassword,
1003
1132
  onChangeText: form.setNewPassword
1004
1133
  }
1005
1134
  )
1006
1135
  ] }),
1007
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles.fieldGroup, children: [
1008
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles.label, children: labels.confirmPasswordLabel }),
1136
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles3.fieldGroup, children: [
1137
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.label, children: labels.confirmPasswordLabel }),
1009
1138
  /* @__PURE__ */ jsxRuntime.jsx(
1010
1139
  reactNative.TextInput,
1011
1140
  {
@@ -1017,7 +1146,7 @@ function ResetPasswordForm({
1017
1146
  editable: !form.isSubmitting,
1018
1147
  placeholder: labels.confirmPasswordPlaceholder,
1019
1148
  placeholderTextColor: theme.colors.textSecondary,
1020
- style: styles.input,
1149
+ style: styles3.input,
1021
1150
  testID: withTestIdPrefix(AuthTestIds.resetPasswordConfirmInput, testIdPrefix),
1022
1151
  value: form.confirmPassword,
1023
1152
  onChangeText: form.setConfirmPassword
@@ -1027,7 +1156,7 @@ function ResetPasswordForm({
1027
1156
  message !== null ? /* @__PURE__ */ jsxRuntime.jsx(
1028
1157
  reactNative.Text,
1029
1158
  {
1030
- style: styles.errorText,
1159
+ style: styles3.errorText,
1031
1160
  testID: withTestIdPrefix(AuthTestIds.resetPasswordError, testIdPrefix),
1032
1161
  children: message
1033
1162
  }
@@ -1042,7 +1171,7 @@ function ResetPasswordForm({
1042
1171
  style: submitButtonStyle,
1043
1172
  testID: withTestIdPrefix(AuthTestIds.resetPasswordSubmitButton, testIdPrefix),
1044
1173
  onPress: form.submit,
1045
- children: form.isSubmitting ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles.primaryButtonText, children: labels.submit })
1174
+ children: form.isSubmitting ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.primaryButtonText, children: labels.submit })
1046
1175
  }
1047
1176
  )
1048
1177
  ]
@@ -1050,7 +1179,7 @@ function ResetPasswordForm({
1050
1179
  ) });
1051
1180
  }
1052
1181
  function OtpRequestStep({
1053
- styles,
1182
+ styles: styles3,
1054
1183
  theme,
1055
1184
  labels,
1056
1185
  testIdPrefix,
@@ -1059,12 +1188,12 @@ function OtpRequestStep({
1059
1188
  onSubmit
1060
1189
  }) {
1061
1190
  const [email, setEmail] = react.useState("");
1062
- const buttonStyle = isSubmitting ? [styles.primaryButton, styles.primaryButtonDisabled] : styles.primaryButton;
1191
+ const buttonStyle = isSubmitting ? [styles3.primaryButton, styles3.primaryButtonDisabled] : styles3.primaryButton;
1063
1192
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1064
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles.title, children: labels.requestTitle }),
1065
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles.subtitle, children: labels.requestDescription }),
1066
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles.fieldGroup, children: [
1067
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles.label, children: labels.emailLabel }),
1193
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.title, children: labels.requestTitle }),
1194
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.subtitle, children: labels.requestDescription }),
1195
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles3.fieldGroup, children: [
1196
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.label, children: labels.emailLabel }),
1068
1197
  /* @__PURE__ */ jsxRuntime.jsx(
1069
1198
  reactNative.TextInput,
1070
1199
  {
@@ -1076,14 +1205,14 @@ function OtpRequestStep({
1076
1205
  keyboardType: "email-address",
1077
1206
  placeholder: labels.emailPlaceholder,
1078
1207
  placeholderTextColor: theme.colors.textSecondary,
1079
- style: styles.input,
1208
+ style: styles3.input,
1080
1209
  testID: withTestIdPrefix(AuthTestIds.otpEmailInput, testIdPrefix),
1081
1210
  value: email,
1082
1211
  onChangeText: setEmail
1083
1212
  }
1084
1213
  )
1085
1214
  ] }),
1086
- errorText !== null ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles.errorText, testID: withTestIdPrefix(AuthTestIds.otpError, testIdPrefix), children: errorText }) : null,
1215
+ errorText !== null ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.errorText, testID: withTestIdPrefix(AuthTestIds.otpError, testIdPrefix), children: errorText }) : null,
1087
1216
  /* @__PURE__ */ jsxRuntime.jsx(
1088
1217
  reactNative.TouchableOpacity,
1089
1218
  {
@@ -1094,13 +1223,13 @@ function OtpRequestStep({
1094
1223
  style: buttonStyle,
1095
1224
  testID: withTestIdPrefix(AuthTestIds.otpRequestButton, testIdPrefix),
1096
1225
  onPress: () => onSubmit(email.trim()),
1097
- children: isSubmitting ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles.primaryButtonText, children: labels.requestSubmit })
1226
+ children: isSubmitting ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.primaryButtonText, children: labels.requestSubmit })
1098
1227
  }
1099
1228
  )
1100
1229
  ] });
1101
1230
  }
1102
1231
  function OtpVerifyStep({
1103
- styles,
1232
+ styles: styles3,
1104
1233
  theme,
1105
1234
  labels,
1106
1235
  testIdPrefix,
@@ -1112,13 +1241,13 @@ function OtpVerifyStep({
1112
1241
  onChangeEmail
1113
1242
  }) {
1114
1243
  const [code, setCode] = react.useState("");
1115
- const buttonStyle = isSubmitting ? [styles.primaryButton, styles.primaryButtonDisabled] : styles.primaryButton;
1244
+ const buttonStyle = isSubmitting ? [styles3.primaryButton, styles3.primaryButtonDisabled] : styles3.primaryButton;
1116
1245
  const description = labels.verifyDescription.replace("{identifier}", identifier);
1117
1246
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1118
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles.title, children: labels.verifyTitle }),
1119
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles.subtitle, children: description }),
1120
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles.fieldGroup, children: [
1121
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles.label, children: labels.codeLabel }),
1247
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.title, children: labels.verifyTitle }),
1248
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.subtitle, children: description }),
1249
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles3.fieldGroup, children: [
1250
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.label, children: labels.codeLabel }),
1122
1251
  /* @__PURE__ */ jsxRuntime.jsx(
1123
1252
  reactNative.TextInput,
1124
1253
  {
@@ -1130,14 +1259,14 @@ function OtpVerifyStep({
1130
1259
  keyboardType: "number-pad",
1131
1260
  placeholder: labels.codePlaceholder,
1132
1261
  placeholderTextColor: theme.colors.textSecondary,
1133
- style: styles.input,
1262
+ style: styles3.input,
1134
1263
  testID: withTestIdPrefix(AuthTestIds.otpCodeInput, testIdPrefix),
1135
1264
  value: code,
1136
1265
  onChangeText: setCode
1137
1266
  }
1138
1267
  )
1139
1268
  ] }),
1140
- errorText !== null ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles.errorText, testID: withTestIdPrefix(AuthTestIds.otpError, testIdPrefix), children: errorText }) : null,
1269
+ errorText !== null ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.errorText, testID: withTestIdPrefix(AuthTestIds.otpError, testIdPrefix), children: errorText }) : null,
1141
1270
  /* @__PURE__ */ jsxRuntime.jsx(
1142
1271
  reactNative.TouchableOpacity,
1143
1272
  {
@@ -1148,7 +1277,7 @@ function OtpVerifyStep({
1148
1277
  style: buttonStyle,
1149
1278
  testID: withTestIdPrefix(AuthTestIds.otpVerifyButton, testIdPrefix),
1150
1279
  onPress: () => onSubmit(code.trim()),
1151
- children: isSubmitting ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles.primaryButtonText, children: labels.verifySubmit })
1280
+ children: isSubmitting ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.primaryButtonText, children: labels.verifySubmit })
1152
1281
  }
1153
1282
  ),
1154
1283
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -1158,10 +1287,10 @@ function OtpVerifyStep({
1158
1287
  accessibilityLabel: isSubmitting ? labels.resending : labels.resend,
1159
1288
  accessibilityRole: "link",
1160
1289
  disabled: isSubmitting,
1161
- style: styles.fieldGroup,
1290
+ style: styles3.fieldGroup,
1162
1291
  testID: withTestIdPrefix(AuthTestIds.otpResendButton, testIdPrefix),
1163
1292
  onPress: onResend,
1164
- children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles.linkText, children: isSubmitting ? labels.resending : labels.resend })
1293
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.linkText, children: isSubmitting ? labels.resending : labels.resend })
1165
1294
  }
1166
1295
  ),
1167
1296
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -1173,7 +1302,7 @@ function OtpVerifyStep({
1173
1302
  disabled: isSubmitting,
1174
1303
  testID: withTestIdPrefix(AuthTestIds.otpChangeEmailButton, testIdPrefix),
1175
1304
  onPress: onChangeEmail,
1176
- children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles.linkText, children: labels.changeEmail })
1305
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.linkText, children: labels.changeEmail })
1177
1306
  }
1178
1307
  )
1179
1308
  ] });
@@ -1342,7 +1471,7 @@ function OtpForm({
1342
1471
  testIdPrefix
1343
1472
  }) {
1344
1473
  const theme = useAuthTheme(themeProp);
1345
- const styles = useAuthStyles(theme);
1474
+ const styles3 = useAuthStyles(theme);
1346
1475
  const labels = react.useMemo(
1347
1476
  () => ({ ...DEFAULT_OTP_LABELS, ...labelsProp }),
1348
1477
  [labelsProp]
@@ -1360,13 +1489,13 @@ function OtpForm({
1360
1489
  otp.reset();
1361
1490
  }, [otp]);
1362
1491
  const errorText = localError ?? transportErrorFor(otp.step, otp.error, labels);
1363
- return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles.screen, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles.card, testID: withTestIdPrefix(AuthTestIds.otpForm, testIdPrefix), children: otp.step === "requestCode" /* RequestCode */ ? /* @__PURE__ */ jsxRuntime.jsx(
1492
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles3.screen, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles3.card, testID: withTestIdPrefix(AuthTestIds.otpForm, testIdPrefix), children: otp.step === "requestCode" /* RequestCode */ ? /* @__PURE__ */ jsxRuntime.jsx(
1364
1493
  OtpRequestStep,
1365
1494
  {
1366
1495
  errorText,
1367
1496
  isSubmitting: otp.isSubmitting,
1368
1497
  labels,
1369
- styles,
1498
+ styles: styles3,
1370
1499
  testIdPrefix,
1371
1500
  theme,
1372
1501
  onSubmit: handleRequest
@@ -1378,7 +1507,7 @@ function OtpForm({
1378
1507
  identifier: otp.identifier,
1379
1508
  isSubmitting: otp.isSubmitting,
1380
1509
  labels,
1381
- styles,
1510
+ styles: styles3,
1382
1511
  testIdPrefix,
1383
1512
  theme,
1384
1513
  onChangeEmail: handleChangeEmail,
@@ -1467,7 +1596,7 @@ function PinForm({
1467
1596
  testIdPrefix
1468
1597
  }) {
1469
1598
  const theme = useAuthTheme(themeProp);
1470
- const styles = useAuthStyles(theme);
1599
+ const styles3 = useAuthStyles(theme);
1471
1600
  const labels = react.useMemo(
1472
1601
  () => ({ ...DEFAULT_PIN_LABELS, ...labelsProp }),
1473
1602
  [labelsProp]
@@ -1477,12 +1606,12 @@ function PinForm({
1477
1606
  const [pinValue, setPinValue] = react.useState("");
1478
1607
  const handleSubmit = useSubmitHandler(pin, labels, setLocalError, onSuccess);
1479
1608
  const errorText = localError ?? transportErrorFor2(pin.error, labels);
1480
- const buttonStyle = pin.isSubmitting ? [styles.primaryButton, styles.primaryButtonDisabled] : styles.primaryButton;
1481
- return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles.screen, children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles.card, testID: withTestIdPrefix(AuthTestIds.pinForm, testIdPrefix), children: [
1482
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles.title, children: labels.title }),
1483
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles.subtitle, children: labels.description }),
1484
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles.fieldGroup, children: [
1485
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles.label, children: labels.pinLabel }),
1609
+ const buttonStyle = pin.isSubmitting ? [styles3.primaryButton, styles3.primaryButtonDisabled] : styles3.primaryButton;
1610
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles3.screen, children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles3.card, testID: withTestIdPrefix(AuthTestIds.pinForm, testIdPrefix), children: [
1611
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.title, children: labels.title }),
1612
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.subtitle, children: labels.description }),
1613
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles3.fieldGroup, children: [
1614
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.label, children: labels.pinLabel }),
1486
1615
  /* @__PURE__ */ jsxRuntime.jsx(
1487
1616
  reactNative.TextInput,
1488
1617
  {
@@ -1495,7 +1624,7 @@ function PinForm({
1495
1624
  placeholder: labels.pinPlaceholder,
1496
1625
  placeholderTextColor: theme.colors.textSecondary,
1497
1626
  secureTextEntry: true,
1498
- style: styles.input,
1627
+ style: styles3.input,
1499
1628
  testID: withTestIdPrefix(AuthTestIds.pinInput, testIdPrefix),
1500
1629
  value: pinValue,
1501
1630
  onChangeText: setPinValue
@@ -1505,7 +1634,7 @@ function PinForm({
1505
1634
  errorText !== null ? /* @__PURE__ */ jsxRuntime.jsx(
1506
1635
  reactNative.Text,
1507
1636
  {
1508
- style: styles.errorText,
1637
+ style: styles3.errorText,
1509
1638
  testID: withTestIdPrefix(AuthTestIds.pinError, testIdPrefix),
1510
1639
  children: errorText
1511
1640
  }
@@ -1520,11 +1649,918 @@ function PinForm({
1520
1649
  style: buttonStyle,
1521
1650
  testID: withTestIdPrefix(AuthTestIds.pinSubmitButton, testIdPrefix),
1522
1651
  onPress: () => handleSubmit(pinValue.trim()),
1523
- children: pin.isSubmitting ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles.primaryButtonText, children: labels.submit })
1652
+ children: pin.isSubmitting ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.primaryButtonText, children: labels.submit })
1524
1653
  }
1525
1654
  )
1526
1655
  ] }) });
1527
1656
  }
1657
+ var DOT_SIZE = 18;
1658
+ var DOT_BORDER_WIDTH = 2;
1659
+ var DOT_RADIUS = 9;
1660
+ var ROW_GAP = 12;
1661
+ var ROW_MIN_HEIGHT = 44;
1662
+ var ROW_VERTICAL_MARGIN = 16;
1663
+ var HIDDEN_SIZE = 1;
1664
+ function sanitise(raw, length) {
1665
+ return raw.replace(/\D/g, "").slice(0, length);
1666
+ }
1667
+ function useDotStyles(theme) {
1668
+ return react.useMemo(
1669
+ () => ({
1670
+ filled: { backgroundColor: theme.colors.primary, borderColor: theme.colors.primary },
1671
+ empty: { backgroundColor: theme.colors.background, borderColor: theme.colors.border }
1672
+ }),
1673
+ [theme]
1674
+ );
1675
+ }
1676
+ function DevicePinInput({
1677
+ value,
1678
+ length,
1679
+ disabled,
1680
+ testID,
1681
+ testIdPrefix,
1682
+ accessibilityLabel,
1683
+ accessibilityHint,
1684
+ filledHint,
1685
+ emptyHint,
1686
+ theme: themeProp,
1687
+ onChange
1688
+ }) {
1689
+ const theme = useAuthTheme(themeProp);
1690
+ const inputRef = react.useRef(null);
1691
+ const dotStyles = useDotStyles(theme);
1692
+ const cells = Array.from({ length }, (_unused, index) => index);
1693
+ const baseId = withTestIdPrefix(testID, testIdPrefix);
1694
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1695
+ reactNative.Pressable,
1696
+ {
1697
+ accessibilityHint,
1698
+ accessibilityLabel,
1699
+ accessibilityRole: "button",
1700
+ disabled,
1701
+ style: styles.row,
1702
+ testID: `${baseId}-row`,
1703
+ onPress: () => inputRef.current?.focus(),
1704
+ children: [
1705
+ cells.map((index) => {
1706
+ const filled = index < value.length;
1707
+ return /* @__PURE__ */ jsxRuntime.jsx(
1708
+ reactNative.View,
1709
+ {
1710
+ accessibilityLabel: filled ? filledHint : emptyHint,
1711
+ style: [styles.dot, filled ? dotStyles.filled : dotStyles.empty],
1712
+ testID: `${baseId}-dot-${String(index)}`
1713
+ },
1714
+ index
1715
+ );
1716
+ }),
1717
+ /* @__PURE__ */ jsxRuntime.jsx(
1718
+ reactNative.TextInput,
1719
+ {
1720
+ ref: inputRef,
1721
+ accessibilityHint,
1722
+ accessibilityLabel,
1723
+ autoFocus: true,
1724
+ caretHidden: true,
1725
+ editable: !disabled,
1726
+ keyboardType: "number-pad",
1727
+ maxLength: length,
1728
+ secureTextEntry: true,
1729
+ style: styles.hiddenInput,
1730
+ testID: baseId,
1731
+ value,
1732
+ onChangeText: (raw) => onChange(sanitise(raw, length))
1733
+ }
1734
+ )
1735
+ ]
1736
+ }
1737
+ );
1738
+ }
1739
+ var styles = reactNative.StyleSheet.create({
1740
+ dot: {
1741
+ borderRadius: DOT_RADIUS,
1742
+ borderWidth: DOT_BORDER_WIDTH,
1743
+ height: DOT_SIZE,
1744
+ width: DOT_SIZE
1745
+ },
1746
+ hiddenInput: {
1747
+ height: HIDDEN_SIZE,
1748
+ opacity: 0,
1749
+ position: "absolute",
1750
+ width: HIDDEN_SIZE
1751
+ },
1752
+ row: {
1753
+ alignItems: "center",
1754
+ flexDirection: "row",
1755
+ gap: ROW_GAP,
1756
+ justifyContent: "center",
1757
+ marginVertical: ROW_VERTICAL_MARGIN,
1758
+ minHeight: ROW_MIN_HEIGHT
1759
+ }
1760
+ });
1761
+
1762
+ // src/components/interpolate.ts
1763
+ function interpolate(template, values) {
1764
+ return template.replace(/\{(\w+)\}/g, (match, key) => {
1765
+ const value = values[key];
1766
+ return value === void 0 ? match : String(value);
1767
+ });
1768
+ }
1769
+
1770
+ // src/devicePin/devicePinConstants.ts
1771
+ var DEVICE_PIN_ALLOWED_DIGITS = [4, 6, 8];
1772
+ var DEVICE_PIN_DEFAULT_DIGITS = 4;
1773
+ function isAllowedPinDigits(value) {
1774
+ return DEVICE_PIN_ALLOWED_DIGITS.includes(value);
1775
+ }
1776
+ var PILL_VERTICAL_PADDING = 10;
1777
+ var PILL_FONT_SIZE = 15;
1778
+ function usePickerStyles(theme) {
1779
+ return react.useMemo(
1780
+ () => ({
1781
+ pill: { borderColor: theme.colors.border },
1782
+ active: { backgroundColor: theme.colors.primary, borderColor: theme.colors.primary },
1783
+ text: { color: theme.colors.text },
1784
+ textActive: { color: theme.colors.onPrimary }
1785
+ }),
1786
+ [theme]
1787
+ );
1788
+ }
1789
+ function DevicePinLengthPicker({
1790
+ selected,
1791
+ disabled,
1792
+ optionHint,
1793
+ testIdPrefix,
1794
+ theme: themeProp,
1795
+ onSelect
1796
+ }) {
1797
+ const theme = useAuthTheme(themeProp);
1798
+ const dynamic = usePickerStyles(theme);
1799
+ const baseId = withTestIdPrefix(AuthTestIds.devicePinEnrollLength, testIdPrefix);
1800
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles2.row, children: DEVICE_PIN_ALLOWED_DIGITS.map((option) => {
1801
+ const active = option === selected;
1802
+ return /* @__PURE__ */ jsxRuntime.jsx(
1803
+ reactNative.Pressable,
1804
+ {
1805
+ accessibilityHint: interpolate(optionHint, { count: option }),
1806
+ accessibilityLabel: String(option),
1807
+ accessibilityRole: "button",
1808
+ accessibilityState: { selected: active },
1809
+ disabled,
1810
+ style: [styles2.pill, dynamic.pill, active ? dynamic.active : null],
1811
+ testID: `${baseId}-${String(option)}`,
1812
+ onPress: () => onSelect(option),
1813
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles2.text, dynamic.text, active ? dynamic.textActive : null], children: String(option) })
1814
+ },
1815
+ option
1816
+ );
1817
+ }) });
1818
+ }
1819
+ var styles2 = reactNative.StyleSheet.create({
1820
+ pill: {
1821
+ alignItems: "center",
1822
+ borderRadius: 8,
1823
+ borderWidth: 1,
1824
+ flex: 1,
1825
+ paddingVertical: PILL_VERTICAL_PADDING
1826
+ },
1827
+ row: {
1828
+ flexDirection: "row",
1829
+ gap: 8,
1830
+ marginBottom: 8
1831
+ },
1832
+ text: {
1833
+ fontSize: PILL_FONT_SIZE,
1834
+ fontWeight: "700"
1835
+ }
1836
+ });
1837
+
1838
+ // src/devicePin/DevicePinErrorKey.ts
1839
+ var DevicePinErrorKey = /* @__PURE__ */ ((DevicePinErrorKey2) => {
1840
+ DevicePinErrorKey2["Incomplete"] = "incomplete";
1841
+ DevicePinErrorKey2["Invalid"] = "invalid";
1842
+ DevicePinErrorKey2["LockedOut"] = "locked_out";
1843
+ DevicePinErrorKey2["RateLimited"] = "rate_limited";
1844
+ DevicePinErrorKey2["Generic"] = "generic";
1845
+ return DevicePinErrorKey2;
1846
+ })(DevicePinErrorKey || {});
1847
+ function useDevicePinUnlock({
1848
+ client,
1849
+ digits,
1850
+ onSignedIn
1851
+ }) {
1852
+ const [pin, setPinState] = react.useState("");
1853
+ const [submitting, setSubmitting] = react.useState(false);
1854
+ const [errorKey, setErrorKey] = react.useState(null);
1855
+ const [retryAfterSeconds, setRetryAfterSeconds] = react.useState(null);
1856
+ const setPin = react.useCallback((next) => {
1857
+ setPinState(next);
1858
+ setErrorKey(null);
1859
+ setRetryAfterSeconds(null);
1860
+ }, []);
1861
+ const submit = react.useCallback(() => {
1862
+ setErrorKey(null);
1863
+ setRetryAfterSeconds(null);
1864
+ if (pin.length < digits) {
1865
+ setErrorKey("incomplete" /* Incomplete */);
1866
+ return;
1867
+ }
1868
+ setSubmitting(true);
1869
+ client.unlockWithDevicePin({ pin }).then((result) => {
1870
+ if (result.status === "success") {
1871
+ onSignedIn(result.user);
1872
+ return;
1873
+ }
1874
+ if (result.status === "invalid") {
1875
+ setErrorKey("invalid" /* Invalid */);
1876
+ return;
1877
+ }
1878
+ if (result.status === "locked") {
1879
+ setRetryAfterSeconds(result.retryAfterSeconds);
1880
+ setErrorKey("locked_out" /* LockedOut */);
1881
+ return;
1882
+ }
1883
+ if (result.status === "rateLimited") {
1884
+ setRetryAfterSeconds(result.retryAfterSeconds);
1885
+ setErrorKey("rate_limited" /* RateLimited */);
1886
+ return;
1887
+ }
1888
+ setErrorKey("generic" /* Generic */);
1889
+ }).catch(() => {
1890
+ setErrorKey("generic" /* Generic */);
1891
+ }).finally(() => {
1892
+ setSubmitting(false);
1893
+ });
1894
+ }, [client, pin, digits, onSignedIn]);
1895
+ return { pin, submitting, errorKey, retryAfterSeconds, setPin, submit };
1896
+ }
1897
+ function resolveErrorText(errorKey, digits, retryAfter, labels) {
1898
+ if (errorKey === null) {
1899
+ return null;
1900
+ }
1901
+ if (errorKey === "incomplete" /* Incomplete */) {
1902
+ return interpolate(labels.errorIncomplete, { count: digits });
1903
+ }
1904
+ if (errorKey === "invalid" /* Invalid */) {
1905
+ return labels.errorInvalid;
1906
+ }
1907
+ if (errorKey === "locked_out" /* LockedOut */) {
1908
+ return retryAfter !== null ? interpolate(labels.errorLockedOutRetry, { count: retryAfter }) : labels.errorLockedOut;
1909
+ }
1910
+ if (errorKey === "rate_limited" /* RateLimited */) {
1911
+ return retryAfter !== null ? interpolate(labels.errorRateLimitedRetry, { count: retryAfter }) : labels.errorRateLimited;
1912
+ }
1913
+ return labels.errorGeneric;
1914
+ }
1915
+ function DevicePinUnlockScreen({
1916
+ client,
1917
+ digits,
1918
+ rememberedUsername,
1919
+ theme: themeProp,
1920
+ labels: labelsProp,
1921
+ testIdPrefix,
1922
+ onSignedIn,
1923
+ onUsePassword
1924
+ }) {
1925
+ const theme = useAuthTheme(themeProp);
1926
+ const styles3 = useAuthStyles(theme);
1927
+ const labels = react.useMemo(
1928
+ () => ({ ...DEFAULT_DEVICE_PIN_UNLOCK_LABELS, ...labelsProp }),
1929
+ [labelsProp]
1930
+ );
1931
+ const { pin, submitting, errorKey, retryAfterSeconds, setPin, submit } = useDevicePinUnlock({
1932
+ client,
1933
+ digits,
1934
+ onSignedIn
1935
+ });
1936
+ const hasName = rememberedUsername !== "";
1937
+ const title = hasName ? interpolate(labels.title, { name: rememberedUsername }) : labels.titleNoName;
1938
+ const error = resolveErrorText(errorKey, digits, retryAfterSeconds, labels);
1939
+ const buttonStyle = submitting ? [styles3.primaryButton, styles3.primaryButtonDisabled] : styles3.primaryButton;
1940
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles3.screen, children: /* @__PURE__ */ jsxRuntime.jsxs(
1941
+ reactNative.View,
1942
+ {
1943
+ style: styles3.card,
1944
+ testID: withTestIdPrefix(AuthTestIds.devicePinUnlock, testIdPrefix),
1945
+ children: [
1946
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.title, children: title }),
1947
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.subtitle, children: interpolate(labels.description, { count: digits }) }),
1948
+ /* @__PURE__ */ jsxRuntime.jsx(
1949
+ DevicePinInput,
1950
+ {
1951
+ accessibilityHint: labels.pinPlaceholder,
1952
+ accessibilityLabel: labels.pinLabel,
1953
+ disabled: submitting,
1954
+ emptyHint: labels.digitEmptyHint,
1955
+ filledHint: labels.digitFilledHint,
1956
+ length: digits,
1957
+ testID: AuthTestIds.devicePinUnlockInput,
1958
+ testIdPrefix,
1959
+ theme,
1960
+ value: pin,
1961
+ onChange: setPin
1962
+ }
1963
+ ),
1964
+ error !== null ? /* @__PURE__ */ jsxRuntime.jsx(
1965
+ reactNative.Text,
1966
+ {
1967
+ style: styles3.errorText,
1968
+ testID: withTestIdPrefix(AuthTestIds.devicePinUnlockError, testIdPrefix),
1969
+ children: error
1970
+ }
1971
+ ) : null,
1972
+ /* @__PURE__ */ jsxRuntime.jsx(
1973
+ reactNative.TouchableOpacity,
1974
+ {
1975
+ accessibilityHint: labels.submit,
1976
+ accessibilityLabel: submitting ? labels.submitting : labels.submit,
1977
+ accessibilityRole: "button",
1978
+ disabled: submitting,
1979
+ style: buttonStyle,
1980
+ testID: withTestIdPrefix(AuthTestIds.devicePinUnlockSubmit, testIdPrefix),
1981
+ onPress: submit,
1982
+ children: submitting ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.primaryButtonText, children: labels.submit })
1983
+ }
1984
+ ),
1985
+ /* @__PURE__ */ jsxRuntime.jsx(
1986
+ reactNative.TouchableOpacity,
1987
+ {
1988
+ accessibilityHint: labels.usePasswordHint,
1989
+ accessibilityLabel: labels.usePasswordInstead,
1990
+ accessibilityRole: "button",
1991
+ disabled: submitting,
1992
+ style: styles3.escapeLink,
1993
+ testID: withTestIdPrefix(AuthTestIds.devicePinUnlockUsePassword, testIdPrefix),
1994
+ onPress: onUsePassword,
1995
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.linkText, children: labels.usePasswordInstead })
1996
+ }
1997
+ )
1998
+ ]
1999
+ }
2000
+ ) });
2001
+ }
2002
+
2003
+ // src/devicePin/DevicePinEnrollErrorKey.ts
2004
+ var DevicePinEnrollErrorKey = /* @__PURE__ */ ((DevicePinEnrollErrorKey2) => {
2005
+ DevicePinEnrollErrorKey2["Mismatch"] = "mismatch";
2006
+ DevicePinEnrollErrorKey2["Unauthorized"] = "unauthorized";
2007
+ DevicePinEnrollErrorKey2["Forbidden"] = "forbidden";
2008
+ DevicePinEnrollErrorKey2["InvalidPin"] = "invalid_pin";
2009
+ DevicePinEnrollErrorKey2["Failed"] = "failed";
2010
+ return DevicePinEnrollErrorKey2;
2011
+ })(DevicePinEnrollErrorKey || {});
2012
+ function errorKeyFor(result) {
2013
+ if (result.status === "unauthorized") {
2014
+ return "unauthorized" /* Unauthorized */;
2015
+ }
2016
+ if (result.status === "forbidden") {
2017
+ return "forbidden" /* Forbidden */;
2018
+ }
2019
+ if (result.status === "invalidPin") {
2020
+ return "invalid_pin" /* InvalidPin */;
2021
+ }
2022
+ return "failed" /* Failed */;
2023
+ }
2024
+ function useDevicePinEnroll({
2025
+ client,
2026
+ digits,
2027
+ onEnrolled
2028
+ }) {
2029
+ const [pin, setPinState] = react.useState("");
2030
+ const [confirmPin, setConfirmState] = react.useState("");
2031
+ const [submitting, setSubmitting] = react.useState(false);
2032
+ const [errorKey, setErrorKey] = react.useState(null);
2033
+ const setPin = react.useCallback((next) => {
2034
+ setPinState(next);
2035
+ setErrorKey(null);
2036
+ }, []);
2037
+ const setConfirmPin = react.useCallback((next) => {
2038
+ setConfirmState(next);
2039
+ setErrorKey(null);
2040
+ }, []);
2041
+ const submit = react.useCallback(() => {
2042
+ setErrorKey(null);
2043
+ const wrongLength = pin.length !== digits;
2044
+ const mismatched = pin !== confirmPin;
2045
+ if (wrongLength || mismatched) {
2046
+ setErrorKey("mismatch" /* Mismatch */);
2047
+ return;
2048
+ }
2049
+ setSubmitting(true);
2050
+ client.enrollDevicePin({ pin, digits }).then((result) => {
2051
+ if (result.status === "success") {
2052
+ onEnrolled();
2053
+ return;
2054
+ }
2055
+ setErrorKey(errorKeyFor(result));
2056
+ }).catch(() => {
2057
+ setErrorKey("failed" /* Failed */);
2058
+ }).finally(() => {
2059
+ setSubmitting(false);
2060
+ });
2061
+ }, [client, pin, confirmPin, digits, onEnrolled]);
2062
+ return { pin, confirmPin, submitting, errorKey, setPin, setConfirmPin, submit };
2063
+ }
2064
+ function resolveErrorText2(errorKey, digits, labels) {
2065
+ if (errorKey === null) {
2066
+ return null;
2067
+ }
2068
+ if (errorKey === "mismatch" /* Mismatch */) {
2069
+ return interpolate(labels.errorMismatch, { count: digits });
2070
+ }
2071
+ if (errorKey === "unauthorized" /* Unauthorized */) {
2072
+ return labels.errorUnauthorized;
2073
+ }
2074
+ if (errorKey === "forbidden" /* Forbidden */) {
2075
+ return labels.errorForbidden;
2076
+ }
2077
+ if (errorKey === "invalid_pin" /* InvalidPin */) {
2078
+ return labels.errorInvalidPin;
2079
+ }
2080
+ return labels.errorFailed;
2081
+ }
2082
+ function DevicePinEnrollForm({
2083
+ client,
2084
+ initialDigits = DEVICE_PIN_DEFAULT_DIGITS,
2085
+ theme: themeProp,
2086
+ labels: labelsProp,
2087
+ testIdPrefix,
2088
+ onEnrolled,
2089
+ onCancel
2090
+ }) {
2091
+ const theme = useAuthTheme(themeProp);
2092
+ const styles3 = useAuthStyles(theme);
2093
+ const labels = react.useMemo(
2094
+ () => ({ ...DEFAULT_DEVICE_PIN_ENROLL_LABELS, ...labelsProp }),
2095
+ [labelsProp]
2096
+ );
2097
+ const [digits, setDigits] = react.useState(initialDigits);
2098
+ const { pin, confirmPin, submitting, errorKey, setPin, setConfirmPin, submit } = useDevicePinEnroll({ client, digits, onEnrolled });
2099
+ const error = resolveErrorText2(errorKey, digits, labels);
2100
+ const buttonStyle = submitting ? [styles3.primaryButton, styles3.primaryButtonDisabled] : styles3.primaryButton;
2101
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2102
+ reactNative.View,
2103
+ {
2104
+ style: styles3.card,
2105
+ testID: withTestIdPrefix(AuthTestIds.devicePinEnrollForm, testIdPrefix),
2106
+ children: [
2107
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.title, children: labels.formTitle }),
2108
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.subtitle, children: interpolate(labels.formDescription, { count: digits }) }),
2109
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.label, children: labels.lengthLabel }),
2110
+ /* @__PURE__ */ jsxRuntime.jsx(
2111
+ DevicePinLengthPicker,
2112
+ {
2113
+ disabled: submitting,
2114
+ optionHint: labels.lengthOptionHint,
2115
+ selected: digits,
2116
+ testIdPrefix,
2117
+ theme,
2118
+ onSelect: (option) => {
2119
+ setDigits(option);
2120
+ setPin("");
2121
+ setConfirmPin("");
2122
+ }
2123
+ }
2124
+ ),
2125
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.label, children: labels.pinLabel }),
2126
+ /* @__PURE__ */ jsxRuntime.jsx(
2127
+ DevicePinInput,
2128
+ {
2129
+ accessibilityHint: labels.pinPlaceholder,
2130
+ accessibilityLabel: labels.pinLabel,
2131
+ disabled: submitting,
2132
+ emptyHint: labels.pinPlaceholder,
2133
+ filledHint: labels.pinLabel,
2134
+ length: digits,
2135
+ testID: AuthTestIds.devicePinEnrollPin,
2136
+ testIdPrefix,
2137
+ theme,
2138
+ value: pin,
2139
+ onChange: setPin
2140
+ }
2141
+ ),
2142
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.label, children: labels.confirmLabel }),
2143
+ /* @__PURE__ */ jsxRuntime.jsx(
2144
+ DevicePinInput,
2145
+ {
2146
+ accessibilityHint: labels.confirmPlaceholder,
2147
+ accessibilityLabel: labels.confirmLabel,
2148
+ disabled: submitting,
2149
+ emptyHint: labels.confirmPlaceholder,
2150
+ filledHint: labels.confirmLabel,
2151
+ length: digits,
2152
+ testID: AuthTestIds.devicePinEnrollConfirm,
2153
+ testIdPrefix,
2154
+ theme,
2155
+ value: confirmPin,
2156
+ onChange: setConfirmPin
2157
+ }
2158
+ ),
2159
+ error !== null ? /* @__PURE__ */ jsxRuntime.jsx(
2160
+ reactNative.Text,
2161
+ {
2162
+ style: styles3.errorText,
2163
+ testID: withTestIdPrefix(AuthTestIds.devicePinEnrollError, testIdPrefix),
2164
+ children: error
2165
+ }
2166
+ ) : null,
2167
+ /* @__PURE__ */ jsxRuntime.jsx(
2168
+ reactNative.TouchableOpacity,
2169
+ {
2170
+ accessibilityHint: labels.submit,
2171
+ accessibilityLabel: submitting ? labels.submitting : labels.submit,
2172
+ accessibilityRole: "button",
2173
+ disabled: submitting,
2174
+ style: buttonStyle,
2175
+ testID: withTestIdPrefix(AuthTestIds.devicePinEnrollSubmit, testIdPrefix),
2176
+ onPress: submit,
2177
+ children: submitting ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.primaryButtonText, children: labels.submit })
2178
+ }
2179
+ ),
2180
+ /* @__PURE__ */ jsxRuntime.jsx(
2181
+ reactNative.TouchableOpacity,
2182
+ {
2183
+ accessibilityHint: labels.cancelHint,
2184
+ accessibilityLabel: labels.cancel,
2185
+ accessibilityRole: "button",
2186
+ disabled: submitting,
2187
+ style: styles3.escapeLink,
2188
+ testID: withTestIdPrefix(AuthTestIds.devicePinEnrollCancel, testIdPrefix),
2189
+ onPress: onCancel,
2190
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.linkText, children: labels.cancel })
2191
+ }
2192
+ )
2193
+ ]
2194
+ }
2195
+ );
2196
+ }
2197
+ function DevicePinOffer({
2198
+ client,
2199
+ initialDigits,
2200
+ theme: themeProp,
2201
+ labels: labelsProp,
2202
+ testIdPrefix,
2203
+ onDismiss
2204
+ }) {
2205
+ const theme = useAuthTheme(themeProp);
2206
+ const styles3 = useAuthStyles(theme);
2207
+ const labels = react.useMemo(
2208
+ () => ({ ...DEFAULT_DEVICE_PIN_ENROLL_LABELS, ...labelsProp }),
2209
+ [labelsProp]
2210
+ );
2211
+ const [expanded, setExpanded] = react.useState(false);
2212
+ const cardTestId = withTestIdPrefix(AuthTestIds.devicePinOffer, testIdPrefix);
2213
+ if (expanded) {
2214
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles3.card, testID: cardTestId, children: /* @__PURE__ */ jsxRuntime.jsx(
2215
+ DevicePinEnrollForm,
2216
+ {
2217
+ client,
2218
+ initialDigits,
2219
+ labels: labelsProp,
2220
+ testIdPrefix,
2221
+ theme,
2222
+ onCancel: onDismiss,
2223
+ onEnrolled: onDismiss
2224
+ }
2225
+ ) });
2226
+ }
2227
+ return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles3.card, testID: cardTestId, children: [
2228
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.title, children: labels.offerTitle }),
2229
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.subtitle, children: labels.offerDescription }),
2230
+ /* @__PURE__ */ jsxRuntime.jsx(
2231
+ reactNative.TouchableOpacity,
2232
+ {
2233
+ accessibilityHint: labels.offerAcceptHint,
2234
+ accessibilityLabel: labels.offerAccept,
2235
+ accessibilityRole: "button",
2236
+ style: styles3.primaryButton,
2237
+ testID: withTestIdPrefix(AuthTestIds.devicePinOfferAccept, testIdPrefix),
2238
+ onPress: () => setExpanded(true),
2239
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.primaryButtonText, children: labels.offerAccept })
2240
+ }
2241
+ ),
2242
+ /* @__PURE__ */ jsxRuntime.jsx(
2243
+ reactNative.TouchableOpacity,
2244
+ {
2245
+ accessibilityHint: labels.offerSkipHint,
2246
+ accessibilityLabel: labels.offerSkip,
2247
+ accessibilityRole: "button",
2248
+ style: styles3.secondaryButton,
2249
+ testID: withTestIdPrefix(AuthTestIds.devicePinOfferSkip, testIdPrefix),
2250
+ onPress: onDismiss,
2251
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.secondaryButtonText, children: labels.offerSkip })
2252
+ }
2253
+ )
2254
+ ] });
2255
+ }
2256
+ function useDevicePinDisable({
2257
+ client,
2258
+ initialHasPin,
2259
+ onChanged
2260
+ }) {
2261
+ const [hasPin, setHasPin] = react.useState(initialHasPin);
2262
+ const [disabling, setDisabling] = react.useState(false);
2263
+ const [failed, setFailed] = react.useState(false);
2264
+ const disable = react.useCallback(() => {
2265
+ setFailed(false);
2266
+ setDisabling(true);
2267
+ client.disableDevicePin().then((ok) => {
2268
+ if (ok) {
2269
+ setHasPin(false);
2270
+ onChanged?.(false);
2271
+ return;
2272
+ }
2273
+ setFailed(true);
2274
+ }).catch(() => {
2275
+ setFailed(true);
2276
+ }).finally(() => {
2277
+ setDisabling(false);
2278
+ });
2279
+ }, [client, onChanged]);
2280
+ const markEnabled = react.useCallback(() => {
2281
+ setHasPin(true);
2282
+ onChanged?.(true);
2283
+ }, [onChanged]);
2284
+ return { hasPin, disabling, failed, disable, markEnabled };
2285
+ }
2286
+ function DevicePinSettingsCard({
2287
+ client,
2288
+ initialHasPin,
2289
+ theme: themeProp,
2290
+ labels: labelsProp,
2291
+ enrollLabels,
2292
+ testIdPrefix,
2293
+ onChanged
2294
+ }) {
2295
+ const theme = useAuthTheme(themeProp);
2296
+ const styles3 = useAuthStyles(theme);
2297
+ const labels = react.useMemo(
2298
+ () => ({ ...DEFAULT_DEVICE_PIN_SETTINGS_LABELS, ...labelsProp }),
2299
+ [labelsProp]
2300
+ );
2301
+ const resolvedEnrollLabels = react.useMemo(
2302
+ () => ({ ...DEFAULT_DEVICE_PIN_ENROLL_LABELS, ...enrollLabels }),
2303
+ [enrollLabels]
2304
+ );
2305
+ const [enrolling, setEnrolling] = react.useState(false);
2306
+ const { hasPin, disabling, failed, disable, markEnabled } = useDevicePinDisable({
2307
+ client,
2308
+ initialHasPin,
2309
+ onChanged
2310
+ });
2311
+ const handleEnrolled = () => {
2312
+ setEnrolling(false);
2313
+ markEnabled();
2314
+ };
2315
+ const disableButtonStyle = disabling ? [styles3.secondaryButton, styles3.primaryButtonDisabled] : styles3.secondaryButton;
2316
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2317
+ reactNative.View,
2318
+ {
2319
+ style: styles3.card,
2320
+ testID: withTestIdPrefix(AuthTestIds.devicePinSettings, testIdPrefix),
2321
+ children: [
2322
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.title, children: labels.title }),
2323
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.subtitle, children: labels.description }),
2324
+ /* @__PURE__ */ jsxRuntime.jsx(
2325
+ reactNative.Text,
2326
+ {
2327
+ style: styles3.statusText,
2328
+ testID: withTestIdPrefix(AuthTestIds.devicePinSettingsStatus, testIdPrefix),
2329
+ children: hasPin ? labels.statusEnabled : labels.statusDisabled
2330
+ }
2331
+ ),
2332
+ failed ? /* @__PURE__ */ jsxRuntime.jsx(
2333
+ reactNative.Text,
2334
+ {
2335
+ style: styles3.errorText,
2336
+ testID: withTestIdPrefix(AuthTestIds.devicePinSettingsError, testIdPrefix),
2337
+ children: labels.disableFailed
2338
+ }
2339
+ ) : null,
2340
+ renderAction()
2341
+ ]
2342
+ }
2343
+ );
2344
+ function renderAction() {
2345
+ if (enrolling) {
2346
+ return /* @__PURE__ */ jsxRuntime.jsx(
2347
+ DevicePinEnrollForm,
2348
+ {
2349
+ client,
2350
+ labels: resolvedEnrollLabels,
2351
+ testIdPrefix,
2352
+ theme,
2353
+ onCancel: () => setEnrolling(false),
2354
+ onEnrolled: handleEnrolled
2355
+ }
2356
+ );
2357
+ }
2358
+ if (hasPin) {
2359
+ return /* @__PURE__ */ jsxRuntime.jsx(
2360
+ reactNative.TouchableOpacity,
2361
+ {
2362
+ accessibilityHint: labels.disableHint,
2363
+ accessibilityLabel: disabling ? labels.disabling : labels.disable,
2364
+ accessibilityRole: "button",
2365
+ disabled: disabling,
2366
+ style: disableButtonStyle,
2367
+ testID: withTestIdPrefix(AuthTestIds.devicePinSettingsDisable, testIdPrefix),
2368
+ onPress: disable,
2369
+ children: disabling ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { color: theme.colors.primary, size: "small" }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.secondaryButtonText, children: labels.disable })
2370
+ }
2371
+ );
2372
+ }
2373
+ return /* @__PURE__ */ jsxRuntime.jsx(
2374
+ reactNative.TouchableOpacity,
2375
+ {
2376
+ accessibilityHint: labels.enableHint,
2377
+ accessibilityLabel: labels.enable,
2378
+ accessibilityRole: "button",
2379
+ style: styles3.primaryButton,
2380
+ testID: withTestIdPrefix(AuthTestIds.devicePinSettingsEnable, testIdPrefix),
2381
+ onPress: () => setEnrolling(true),
2382
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.primaryButtonText, children: labels.enable })
2383
+ }
2384
+ );
2385
+ }
2386
+ }
2387
+
2388
+ // src/passkey/passkeyNavigation.ts
2389
+ var PASSKEY_LOGIN_ENDPOINT = "/bff/passkey/login";
2390
+ var PASSKEY_REGISTER_ENDPOINT = "/bff/passkey/register";
2391
+ var RETURN_URL_PARAM = "returnUrl";
2392
+ var PASSKEY_ERROR_PARAM = "passkeyError";
2393
+ var PASSKEY_PARAM = "passkey";
2394
+ var PASSKEY_REGISTERED_VALUE = "registered";
2395
+ var PASSKEY_ERROR_CANCELLED = "cancelled";
2396
+ var PASSKEY_ERROR_FAILED = "failed";
2397
+ function buildNavigationUrl(endpoint, returnUrl) {
2398
+ return `${endpoint}?${RETURN_URL_PARAM}=${encodeURIComponent(returnUrl)}`;
2399
+ }
2400
+ function readSearchParams() {
2401
+ if (typeof window === "undefined") {
2402
+ return null;
2403
+ }
2404
+ return new URLSearchParams(window.location.search);
2405
+ }
2406
+ function startPasskeyLogin(returnUrl) {
2407
+ if (typeof window === "undefined") {
2408
+ return;
2409
+ }
2410
+ window.location.assign(buildNavigationUrl(PASSKEY_LOGIN_ENDPOINT, returnUrl));
2411
+ }
2412
+ function startPasskeyRegistration(returnUrl) {
2413
+ if (typeof window === "undefined") {
2414
+ return;
2415
+ }
2416
+ window.location.assign(buildNavigationUrl(PASSKEY_REGISTER_ENDPOINT, returnUrl));
2417
+ }
2418
+ function readPasskeyError() {
2419
+ const params = readSearchParams();
2420
+ if (params === null) {
2421
+ return null;
2422
+ }
2423
+ const value = params.get(PASSKEY_ERROR_PARAM);
2424
+ if (value === PASSKEY_ERROR_CANCELLED) {
2425
+ return PASSKEY_ERROR_CANCELLED;
2426
+ }
2427
+ if (value === PASSKEY_ERROR_FAILED) {
2428
+ return PASSKEY_ERROR_FAILED;
2429
+ }
2430
+ return null;
2431
+ }
2432
+ function readPasskeyRegistered() {
2433
+ const params = readSearchParams();
2434
+ if (params === null) {
2435
+ return false;
2436
+ }
2437
+ return params.get(PASSKEY_PARAM) === PASSKEY_REGISTERED_VALUE;
2438
+ }
2439
+ var DEFAULT_RETURN_URL = "/";
2440
+ function PasskeyLoginButton({
2441
+ returnUrl = DEFAULT_RETURN_URL,
2442
+ theme: themeProp,
2443
+ labels: labelsProp,
2444
+ testIdPrefix
2445
+ }) {
2446
+ const theme = useAuthTheme(themeProp);
2447
+ const styles3 = useAuthStyles(theme);
2448
+ const labels = react.useMemo(
2449
+ () => ({ ...DEFAULT_PASSKEY_LOGIN_LABELS, ...labelsProp }),
2450
+ [labelsProp]
2451
+ );
2452
+ const error = readPasskeyError();
2453
+ return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { testID: withTestIdPrefix(AuthTestIds.passkeyLogin, testIdPrefix), children: [
2454
+ error !== null ? /* @__PURE__ */ jsxRuntime.jsx(
2455
+ reactNative.Text,
2456
+ {
2457
+ style: styles3.errorText,
2458
+ testID: withTestIdPrefix(AuthTestIds.passkeyLoginError, testIdPrefix),
2459
+ children: error === "cancelled" ? labels.errorCancelled : labels.errorFailed
2460
+ }
2461
+ ) : null,
2462
+ /* @__PURE__ */ jsxRuntime.jsx(
2463
+ reactNative.TouchableOpacity,
2464
+ {
2465
+ accessibilityHint: labels.signInHint,
2466
+ accessibilityLabel: labels.signInButton,
2467
+ accessibilityRole: "button",
2468
+ style: styles3.secondaryButton,
2469
+ testID: withTestIdPrefix(AuthTestIds.passkeyLoginButton, testIdPrefix),
2470
+ onPress: () => startPasskeyLogin(returnUrl),
2471
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.secondaryButtonText, children: labels.signInButton })
2472
+ }
2473
+ )
2474
+ ] });
2475
+ }
2476
+ var DEFAULT_RETURN_PATH = "/";
2477
+ function readCurrentPath() {
2478
+ if (typeof window === "undefined") {
2479
+ return DEFAULT_RETURN_PATH;
2480
+ }
2481
+ return window.location.pathname;
2482
+ }
2483
+ function PasskeySettingsCard({
2484
+ returnUrl,
2485
+ theme: themeProp,
2486
+ labels: labelsProp,
2487
+ testIdPrefix
2488
+ }) {
2489
+ const theme = useAuthTheme(themeProp);
2490
+ const styles3 = useAuthStyles(theme);
2491
+ const labels = react.useMemo(
2492
+ () => ({ ...DEFAULT_PASSKEY_SETTINGS_LABELS, ...labelsProp }),
2493
+ [labelsProp]
2494
+ );
2495
+ const justRegistered = readPasskeyRegistered();
2496
+ const target = returnUrl ?? readCurrentPath();
2497
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2498
+ reactNative.View,
2499
+ {
2500
+ style: styles3.card,
2501
+ testID: withTestIdPrefix(AuthTestIds.passkeySettings, testIdPrefix),
2502
+ children: [
2503
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.title, children: labels.title }),
2504
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.subtitle, children: labels.description }),
2505
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.helperText, children: labels.reauthHint }),
2506
+ justRegistered ? /* @__PURE__ */ jsxRuntime.jsx(
2507
+ reactNative.Text,
2508
+ {
2509
+ style: styles3.successText,
2510
+ testID: withTestIdPrefix(AuthTestIds.passkeySettingsSuccess, testIdPrefix),
2511
+ children: labels.registeredSuccess
2512
+ }
2513
+ ) : null,
2514
+ /* @__PURE__ */ jsxRuntime.jsx(
2515
+ reactNative.TouchableOpacity,
2516
+ {
2517
+ accessibilityHint: labels.addHint,
2518
+ accessibilityLabel: labels.addButton,
2519
+ accessibilityRole: "button",
2520
+ style: styles3.primaryButton,
2521
+ testID: withTestIdPrefix(AuthTestIds.passkeySettingsAdd, testIdPrefix),
2522
+ onPress: () => startPasskeyRegistration(target),
2523
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.primaryButtonText, children: labels.addButton })
2524
+ }
2525
+ )
2526
+ ]
2527
+ }
2528
+ );
2529
+ }
2530
+ var EMPTY_CONFIG = {
2531
+ methods: [],
2532
+ registrationEnabled: false,
2533
+ deviceState: {
2534
+ rememberedUsername: null,
2535
+ hasPin: false,
2536
+ pinDigits: null,
2537
+ preferredMethod: null
2538
+ }
2539
+ };
2540
+ function useBffLoginConfig(client) {
2541
+ const [config, setConfig] = react.useState(EMPTY_CONFIG);
2542
+ const [loading, setLoading] = react.useState(true);
2543
+ react.useEffect(() => {
2544
+ let active = true;
2545
+ client.getLoginConfig().then((next) => {
2546
+ if (active) {
2547
+ setConfig(next);
2548
+ }
2549
+ }).catch(() => {
2550
+ if (active) {
2551
+ setConfig(EMPTY_CONFIG);
2552
+ }
2553
+ }).finally(() => {
2554
+ if (active) {
2555
+ setLoading(false);
2556
+ }
2557
+ });
2558
+ return () => {
2559
+ active = false;
2560
+ };
2561
+ }, [client]);
2562
+ return { config, loading };
2563
+ }
1528
2564
  async function lazyFetchHttpClient(request) {
1529
2565
  const fetchImpl = typeof fetch === "function" ? fetch.bind(globalThis) : void 0;
1530
2566
  if (fetchImpl === void 0) {
@@ -1579,12 +2615,27 @@ Object.defineProperty(exports, "createFetchHttpClient", {
1579
2615
  exports.AuthTestIds = AuthTestIds;
1580
2616
  exports.AuthThemeProvider = AuthThemeProvider;
1581
2617
  exports.BffAuthStatus = BffAuthStatus;
2618
+ exports.DEFAULT_DEVICE_PIN_ENROLL_LABELS = DEFAULT_DEVICE_PIN_ENROLL_LABELS;
2619
+ exports.DEFAULT_DEVICE_PIN_SETTINGS_LABELS = DEFAULT_DEVICE_PIN_SETTINGS_LABELS;
2620
+ exports.DEFAULT_DEVICE_PIN_UNLOCK_LABELS = DEFAULT_DEVICE_PIN_UNLOCK_LABELS;
1582
2621
  exports.DEFAULT_FORGOT_PASSWORD_FIELDS_LABELS = DEFAULT_FORGOT_PASSWORD_FIELDS_LABELS;
1583
2622
  exports.DEFAULT_FORGOT_PASSWORD_LABELS = DEFAULT_FORGOT_PASSWORD_LABELS;
1584
2623
  exports.DEFAULT_LOGIN_LABELS = DEFAULT_LOGIN_LABELS;
1585
2624
  exports.DEFAULT_OTP_LABELS = DEFAULT_OTP_LABELS;
2625
+ exports.DEFAULT_PASSKEY_LOGIN_LABELS = DEFAULT_PASSKEY_LOGIN_LABELS;
2626
+ exports.DEFAULT_PASSKEY_SETTINGS_LABELS = DEFAULT_PASSKEY_SETTINGS_LABELS;
1586
2627
  exports.DEFAULT_PIN_LABELS = DEFAULT_PIN_LABELS;
1587
2628
  exports.DEFAULT_RESET_PASSWORD_LABELS = DEFAULT_RESET_PASSWORD_LABELS;
2629
+ exports.DEVICE_PIN_ALLOWED_DIGITS = DEVICE_PIN_ALLOWED_DIGITS;
2630
+ exports.DEVICE_PIN_DEFAULT_DIGITS = DEVICE_PIN_DEFAULT_DIGITS;
2631
+ exports.DevicePinEnrollErrorKey = DevicePinEnrollErrorKey;
2632
+ exports.DevicePinEnrollForm = DevicePinEnrollForm;
2633
+ exports.DevicePinErrorKey = DevicePinErrorKey;
2634
+ exports.DevicePinInput = DevicePinInput;
2635
+ exports.DevicePinLengthPicker = DevicePinLengthPicker;
2636
+ exports.DevicePinOffer = DevicePinOffer;
2637
+ exports.DevicePinSettingsCard = DevicePinSettingsCard;
2638
+ exports.DevicePinUnlockScreen = DevicePinUnlockScreen;
1588
2639
  exports.ForgotPasswordFields = ForgotPasswordFields;
1589
2640
  exports.ForgotPasswordForm = ForgotPasswordForm;
1590
2641
  exports.LoginForm = LoginForm;
@@ -1592,6 +2643,8 @@ exports.OtpForm = OtpForm;
1592
2643
  exports.OtpLoginStep = OtpLoginStep;
1593
2644
  exports.PASSWORD_MAX_LENGTH = PASSWORD_MAX_LENGTH;
1594
2645
  exports.PASSWORD_MIN_LENGTH = PASSWORD_MIN_LENGTH;
2646
+ exports.PasskeyLoginButton = PasskeyLoginButton;
2647
+ exports.PasskeySettingsCard = PasskeySettingsCard;
1595
2648
  exports.PasswordPolicyError = PasswordPolicyError;
1596
2649
  exports.PinForm = PinForm;
1597
2650
  exports.ResetPasswordError = ResetPasswordError;
@@ -1599,13 +2652,22 @@ exports.ResetPasswordForm = ResetPasswordForm;
1599
2652
  exports.collectUserRoles = collectUserRoles;
1600
2653
  exports.createBffAuthClient = createBffAuthClient;
1601
2654
  exports.defaultAuthTheme = defaultAuthTheme;
2655
+ exports.isAllowedPinDigits = isAllowedPinDigits;
1602
2656
  exports.isPasswordValid = isPasswordValid;
1603
2657
  exports.isValidForgotPasswordEmail = isValidForgotPasswordEmail;
2658
+ exports.readPasskeyError = readPasskeyError;
2659
+ exports.readPasskeyRegistered = readPasskeyRegistered;
1604
2660
  exports.resolvePostLoginRoute = resolvePostLoginRoute;
2661
+ exports.startPasskeyLogin = startPasskeyLogin;
2662
+ exports.startPasskeyRegistration = startPasskeyRegistration;
1605
2663
  exports.useAuthTheme = useAuthTheme;
1606
2664
  exports.useBffAuth = useBffAuth;
1607
2665
  exports.useBffForgotPassword = useBffForgotPassword;
2666
+ exports.useBffLoginConfig = useBffLoginConfig;
1608
2667
  exports.useBffResetPassword = useBffResetPassword;
2668
+ exports.useDevicePinDisable = useDevicePinDisable;
2669
+ exports.useDevicePinEnroll = useDevicePinEnroll;
2670
+ exports.useDevicePinUnlock = useDevicePinUnlock;
1609
2671
  exports.useForgotPasswordSubmit = useForgotPasswordSubmit;
1610
2672
  exports.useOtpLogin = useOtpLogin;
1611
2673
  exports.usePinLogin = usePinLogin;