@dloizides/auth-web 1.3.0 → 1.5.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,92 @@ 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
+ };
143
+ var DEFAULT_PREFERRED_METHOD_SETTINGS_LABELS = {
144
+ title: "Preferred sign-in method",
145
+ description: "Pick how you usually sign in. We will show this method first on your devices.",
146
+ noPreference: "No preference",
147
+ methodPassword: "Password",
148
+ methodPin: "Quick PIN",
149
+ methodPasskey: "Passkey",
150
+ saving: "Saving...",
151
+ saveFailed: "Could not save your preference. Try again later."
152
+ };
153
+ var DEFAULT_PREFERRED_METHOD_HINT_LABELS = {
154
+ password: "You usually sign in with your password.",
155
+ pin: "You usually sign in with your quick PIN on this account.",
156
+ passkey: "You usually sign in with a passkey."
157
+ };
72
158
  var DEFAULT_RESET_PASSWORD_LABELS = {
73
159
  title: "Reset password",
74
160
  description: "Choose a new password for your account.",
@@ -117,7 +203,46 @@ var AuthTestIds = {
117
203
  pinForm: "auth-pin-form",
118
204
  pinInput: "auth-pin-input",
119
205
  pinSubmitButton: "auth-pin-submit",
120
- pinError: "auth-pin-error"
206
+ pinError: "auth-pin-error",
207
+ // Device-PIN unlock gate
208
+ devicePinUnlock: "auth-device-pin-unlock",
209
+ devicePinUnlockInput: "auth-device-pin-unlock-input",
210
+ devicePinUnlockSubmit: "auth-device-pin-unlock-submit",
211
+ devicePinUnlockUsePassword: "auth-device-pin-unlock-use-password",
212
+ devicePinUnlockError: "auth-device-pin-unlock-error",
213
+ // Device-PIN enrol form + length picker
214
+ devicePinEnrollForm: "auth-device-pin-enroll-form",
215
+ devicePinEnrollLength: "auth-device-pin-enroll-length",
216
+ devicePinEnrollPin: "auth-device-pin-enroll-pin",
217
+ devicePinEnrollConfirm: "auth-device-pin-enroll-confirm",
218
+ devicePinEnrollSubmit: "auth-device-pin-enroll-submit",
219
+ devicePinEnrollCancel: "auth-device-pin-enroll-cancel",
220
+ devicePinEnrollError: "auth-device-pin-enroll-error",
221
+ // Device-PIN offer (post-login)
222
+ devicePinOffer: "auth-device-pin-offer",
223
+ devicePinOfferAccept: "auth-device-pin-offer-accept",
224
+ devicePinOfferSkip: "auth-device-pin-offer-skip",
225
+ // Device-PIN settings card
226
+ devicePinSettings: "auth-device-pin-settings",
227
+ devicePinSettingsStatus: "auth-device-pin-settings-status",
228
+ devicePinSettingsEnable: "auth-device-pin-settings-enable",
229
+ devicePinSettingsDisable: "auth-device-pin-settings-disable",
230
+ devicePinSettingsError: "auth-device-pin-settings-error",
231
+ // Passkey login button
232
+ passkeyLogin: "auth-passkey-login",
233
+ passkeyLoginButton: "auth-passkey-login-button",
234
+ passkeyLoginError: "auth-passkey-login-error",
235
+ // Passkey settings card
236
+ passkeySettings: "auth-passkey-settings",
237
+ passkeySettingsAdd: "auth-passkey-settings-add",
238
+ passkeySettingsSuccess: "auth-passkey-settings-success",
239
+ // Preferred-method settings card (cross-device default-method picker).
240
+ // Each option row appends `-${method}` to `preferredMethodSettingsOption`.
241
+ preferredMethodSettings: "auth-preferred-method-settings",
242
+ preferredMethodSettingsOption: "auth-preferred-method-settings-option",
243
+ preferredMethodSettingsError: "auth-preferred-method-settings-error",
244
+ // Preferred-method login-screen hint
245
+ preferredMethodHint: "auth-preferred-method-hint"
121
246
  };
122
247
  function withTestIdPrefix(baseId, prefix) {
123
248
  return prefix === void 0 || prefix === "" ? baseId : `${prefix}-${baseId}`;
@@ -211,6 +336,32 @@ function useAuthStyles(theme) {
211
336
  helperText: {
212
337
  fontSize: typography.caption,
213
338
  color: colors.textSecondary
339
+ },
340
+ escapeLink: {
341
+ alignSelf: "center",
342
+ marginTop: spacing.md,
343
+ paddingVertical: spacing.xs / 2
344
+ },
345
+ secondaryButton: {
346
+ borderRadius: radii.input,
347
+ borderWidth: 1,
348
+ borderColor: colors.primary,
349
+ paddingVertical: BUTTON_VERTICAL_PADDING,
350
+ alignItems: "center",
351
+ justifyContent: "center",
352
+ marginTop: spacing.sm,
353
+ backgroundColor: colors.surface
354
+ },
355
+ secondaryButtonText: {
356
+ fontSize: typography.body,
357
+ fontWeight: "600",
358
+ color: colors.primary
359
+ },
360
+ statusText: {
361
+ fontSize: typography.label,
362
+ fontWeight: "600",
363
+ marginTop: spacing.sm,
364
+ color: colors.text
214
365
  }
215
366
  });
216
367
  }, [theme]);
@@ -372,7 +523,7 @@ function LoginForm({
372
523
  testIdPrefix
373
524
  }) {
374
525
  const theme = useAuthTheme(themeProp);
375
- const styles = useAuthStyles(theme);
526
+ const styles3 = useAuthStyles(theme);
376
527
  const labels = react.useMemo(
377
528
  () => ({ ...DEFAULT_LOGIN_LABELS, ...labelsProp }),
378
529
  [labelsProp]
@@ -399,12 +550,12 @@ function LoginForm({
399
550
  const handleSubmit = react.useCallback(() => {
400
551
  void runLogin();
401
552
  }, [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 }),
553
+ const submitButtonStyle = isSubmitting ? [styles3.primaryButton, styles3.primaryButtonDisabled] : styles3.primaryButton;
554
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles3.screen, children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles3.card, testID: withTestIdPrefix(AuthTestIds.loginForm, testIdPrefix), children: [
555
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.title, children: labels.title }),
556
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.subtitle, children: labels.subtitle }),
557
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles3.fieldGroup, children: [
558
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.label, children: labels.usernameLabel }),
408
559
  /* @__PURE__ */ jsxRuntime.jsx(
409
560
  reactNative.TextInput,
410
561
  {
@@ -415,15 +566,15 @@ function LoginForm({
415
566
  editable: !isSubmitting,
416
567
  placeholder: labels.usernamePlaceholder,
417
568
  placeholderTextColor: theme.colors.textSecondary,
418
- style: styles.input,
569
+ style: styles3.input,
419
570
  testID: withTestIdPrefix(AuthTestIds.loginUsernameInput, testIdPrefix),
420
571
  value: username,
421
572
  onChangeText: setUsername
422
573
  }
423
574
  )
424
575
  ] }),
425
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles.fieldGroup, children: [
426
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles.label, children: labels.passwordLabel }),
576
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles3.fieldGroup, children: [
577
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.label, children: labels.passwordLabel }),
427
578
  /* @__PURE__ */ jsxRuntime.jsx(
428
579
  reactNative.TextInput,
429
580
  {
@@ -435,7 +586,7 @@ function LoginForm({
435
586
  editable: !isSubmitting,
436
587
  placeholder: labels.passwordPlaceholder,
437
588
  placeholderTextColor: theme.colors.textSecondary,
438
- style: styles.input,
589
+ style: styles3.input,
439
590
  testID: withTestIdPrefix(AuthTestIds.loginPasswordInput, testIdPrefix),
440
591
  value: password,
441
592
  onChangeText: setPassword
@@ -445,7 +596,7 @@ function LoginForm({
445
596
  errorText !== null ? /* @__PURE__ */ jsxRuntime.jsx(
446
597
  reactNative.Text,
447
598
  {
448
- style: styles.errorText,
599
+ style: styles3.errorText,
449
600
  testID: withTestIdPrefix(AuthTestIds.loginError, testIdPrefix),
450
601
  children: errorText
451
602
  }
@@ -457,10 +608,10 @@ function LoginForm({
457
608
  accessibilityLabel: labels.forgotPassword,
458
609
  accessibilityRole: "link",
459
610
  disabled: isSubmitting,
460
- style: styles.fieldGroup,
611
+ style: styles3.fieldGroup,
461
612
  testID: withTestIdPrefix(AuthTestIds.loginForgotLink, testIdPrefix),
462
613
  onPress: onForgotPassword,
463
- children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles.linkText, children: labels.forgotPassword })
614
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.linkText, children: labels.forgotPassword })
464
615
  }
465
616
  ) : null,
466
617
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -473,7 +624,7 @@ function LoginForm({
473
624
  style: submitButtonStyle,
474
625
  testID: withTestIdPrefix(AuthTestIds.loginSubmitButton, testIdPrefix),
475
626
  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 })
627
+ 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
628
  }
478
629
  ),
479
630
  onSignUp !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(
@@ -483,10 +634,10 @@ function LoginForm({
483
634
  accessibilityLabel: labels.signUp,
484
635
  accessibilityRole: "link",
485
636
  disabled: isSubmitting,
486
- style: styles.fieldGroup,
637
+ style: styles3.fieldGroup,
487
638
  testID: withTestIdPrefix(AuthTestIds.loginSignUpLink, testIdPrefix),
488
639
  onPress: onSignUp,
489
- children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles.linkText, children: labels.signUp })
640
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.linkText, children: labels.signUp })
490
641
  }
491
642
  ) : null
492
643
  ] }) });
@@ -524,7 +675,7 @@ function ForgotPasswordForm({
524
675
  testIdPrefix
525
676
  }) {
526
677
  const theme = useAuthTheme(themeProp);
527
- const styles = useAuthStyles(theme);
678
+ const styles3 = useAuthStyles(theme);
528
679
  const labels = react.useMemo(
529
680
  () => ({ ...DEFAULT_FORGOT_PASSWORD_LABELS, ...labelsProp }),
530
681
  [labelsProp]
@@ -556,25 +707,25 @@ function ForgotPasswordForm({
556
707
  }
557
708
  mutation.mutate({ email: trimmedEmail, resetUrlTemplate });
558
709
  }, [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(
710
+ const submitButtonStyle = isPending ? [styles3.primaryButton, styles3.primaryButtonDisabled] : styles3.primaryButton;
711
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles3.screen, children: /* @__PURE__ */ jsxRuntime.jsxs(
561
712
  reactNative.View,
562
713
  {
563
- style: styles.card,
714
+ style: styles3.card,
564
715
  testID: withTestIdPrefix(AuthTestIds.forgotPasswordForm, testIdPrefix),
565
716
  children: [
566
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles.title, children: labels.title }),
717
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.title, children: labels.title }),
567
718
  submitted ? /* @__PURE__ */ jsxRuntime.jsx(
568
719
  reactNative.Text,
569
720
  {
570
- style: styles.successText,
721
+ style: styles3.successText,
571
722
  testID: withTestIdPrefix(AuthTestIds.forgotPasswordSuccess, testIdPrefix),
572
723
  children: labels.successMessage
573
724
  }
574
725
  ) : /* @__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 }),
726
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.subtitle, children: labels.description }),
727
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles3.fieldGroup, children: [
728
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.label, children: labels.emailLabel }),
578
729
  /* @__PURE__ */ jsxRuntime.jsx(
579
730
  reactNative.TextInput,
580
731
  {
@@ -586,7 +737,7 @@ function ForgotPasswordForm({
586
737
  keyboardType: "email-address",
587
738
  placeholder: labels.emailPlaceholder,
588
739
  placeholderTextColor: theme.colors.textSecondary,
589
- style: styles.input,
740
+ style: styles3.input,
590
741
  testID: withTestIdPrefix(AuthTestIds.forgotPasswordEmailInput, testIdPrefix),
591
742
  value: email,
592
743
  onChangeText: setEmail
@@ -596,7 +747,7 @@ function ForgotPasswordForm({
596
747
  errorText !== null ? /* @__PURE__ */ jsxRuntime.jsx(
597
748
  reactNative.Text,
598
749
  {
599
- style: styles.errorText,
750
+ style: styles3.errorText,
600
751
  testID: withTestIdPrefix(AuthTestIds.forgotPasswordError, testIdPrefix),
601
752
  children: errorText
602
753
  }
@@ -611,7 +762,7 @@ function ForgotPasswordForm({
611
762
  style: submitButtonStyle,
612
763
  testID: withTestIdPrefix(AuthTestIds.forgotPasswordSubmitButton, testIdPrefix),
613
764
  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 })
765
+ 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
766
  }
616
767
  )
617
768
  ] })
@@ -703,7 +854,7 @@ function ForgotPasswordFields({
703
854
  testIdPrefix
704
855
  }) {
705
856
  const theme = useAuthTheme(themeProp);
706
- const styles = useAuthStyles(theme);
857
+ const styles3 = useAuthStyles(theme);
707
858
  const modalStyles = useModalStyles(theme);
708
859
  const labels = react.useMemo(
709
860
  () => ({ ...DEFAULT_FORGOT_PASSWORD_FIELDS_LABELS, ...labelsProp }),
@@ -716,7 +867,7 @@ function ForgotPasswordFields({
716
867
  reset();
717
868
  }
718
869
  }, [visible, reset]);
719
- const submitButtonStyle = form.canSubmit ? styles.primaryButton : [styles.primaryButton, styles.primaryButtonDisabled];
870
+ const submitButtonStyle = form.canSubmit ? styles3.primaryButton : [styles3.primaryButton, styles3.primaryButtonDisabled];
720
871
  const handleCancel = () => {
721
872
  form.reset();
722
873
  onCancel?.();
@@ -727,25 +878,25 @@ function ForgotPasswordFields({
727
878
  };
728
879
  if (form.submitted) {
729
880
  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 }),
881
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.successText, testID: withTestIdPrefix(AuthTestIds.forgotPasswordSuccess, testIdPrefix), children: labels.successMessage }),
731
882
  onClose !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: modalStyles.actions, children: /* @__PURE__ */ jsxRuntime.jsx(
732
883
  reactNative.TouchableOpacity,
733
884
  {
734
885
  accessibilityHint: labels.close,
735
886
  accessibilityLabel: labels.close,
736
887
  accessibilityRole: "button",
737
- style: styles.primaryButton,
888
+ style: styles3.primaryButton,
738
889
  testID: withTestIdPrefix(AuthTestIds.forgotPasswordCloseButton, testIdPrefix),
739
890
  onPress: handleClose,
740
- children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles.primaryButtonText, children: labels.close })
891
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.primaryButtonText, children: labels.close })
741
892
  }
742
893
  ) }) : null
743
894
  ] });
744
895
  }
745
896
  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 }),
897
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.subtitle, children: labels.description }),
898
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles3.fieldGroup, children: [
899
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.label, children: labels.emailLabel }),
749
900
  /* @__PURE__ */ jsxRuntime.jsx(
750
901
  reactNative.TextInput,
751
902
  {
@@ -757,14 +908,14 @@ function ForgotPasswordFields({
757
908
  keyboardType: "email-address",
758
909
  placeholder: labels.emailPlaceholder,
759
910
  placeholderTextColor: theme.colors.textSecondary,
760
- style: styles.input,
911
+ style: styles3.input,
761
912
  testID: withTestIdPrefix(AuthTestIds.forgotPasswordEmailInput, testIdPrefix),
762
913
  value: form.email,
763
914
  onChangeText: form.setEmail
764
915
  }
765
916
  )
766
917
  ] }),
767
- form.hasNetworkError ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles.errorText, testID: withTestIdPrefix(AuthTestIds.forgotPasswordError, testIdPrefix), children: labels.networkError }) : null,
918
+ form.hasNetworkError ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.errorText, testID: withTestIdPrefix(AuthTestIds.forgotPasswordError, testIdPrefix), children: labels.networkError }) : null,
768
919
  /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: modalStyles.actions, children: [
769
920
  onCancel !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(
770
921
  reactNative.TouchableOpacity,
@@ -789,7 +940,7 @@ function ForgotPasswordFields({
789
940
  style: submitButtonStyle,
790
941
  testID: withTestIdPrefix(AuthTestIds.forgotPasswordSubmitButton, testIdPrefix),
791
942
  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 })
943
+ 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
944
  }
794
945
  )
795
946
  ] })
@@ -968,24 +1119,24 @@ function ResetPasswordForm({
968
1119
  testIdPrefix
969
1120
  }) {
970
1121
  const theme = useAuthTheme(themeProp);
971
- const styles = useAuthStyles(theme);
1122
+ const styles3 = useAuthStyles(theme);
972
1123
  const labels = react.useMemo(
973
1124
  () => ({ ...DEFAULT_RESET_PASSWORD_LABELS, ...labelsProp }),
974
1125
  [labelsProp]
975
1126
  );
976
1127
  const form = useResetPasswordForm({ client, token, onSuccess });
977
1128
  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(
1129
+ const submitButtonStyle = form.isSubmitting ? [styles3.primaryButton, styles3.primaryButtonDisabled] : styles3.primaryButton;
1130
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles3.screen, children: /* @__PURE__ */ jsxRuntime.jsxs(
980
1131
  reactNative.View,
981
1132
  {
982
- style: styles.card,
1133
+ style: styles3.card,
983
1134
  testID: withTestIdPrefix(AuthTestIds.resetPasswordForm, testIdPrefix),
984
1135
  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 }),
1136
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.title, children: labels.title }),
1137
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.subtitle, children: labels.description }),
1138
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles3.fieldGroup, children: [
1139
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.label, children: labels.newPasswordLabel }),
989
1140
  /* @__PURE__ */ jsxRuntime.jsx(
990
1141
  reactNative.TextInput,
991
1142
  {
@@ -997,15 +1148,15 @@ function ResetPasswordForm({
997
1148
  editable: !form.isSubmitting,
998
1149
  placeholder: labels.newPasswordPlaceholder,
999
1150
  placeholderTextColor: theme.colors.textSecondary,
1000
- style: styles.input,
1151
+ style: styles3.input,
1001
1152
  testID: withTestIdPrefix(AuthTestIds.resetPasswordNewInput, testIdPrefix),
1002
1153
  value: form.newPassword,
1003
1154
  onChangeText: form.setNewPassword
1004
1155
  }
1005
1156
  )
1006
1157
  ] }),
1007
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles.fieldGroup, children: [
1008
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles.label, children: labels.confirmPasswordLabel }),
1158
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles3.fieldGroup, children: [
1159
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.label, children: labels.confirmPasswordLabel }),
1009
1160
  /* @__PURE__ */ jsxRuntime.jsx(
1010
1161
  reactNative.TextInput,
1011
1162
  {
@@ -1017,7 +1168,7 @@ function ResetPasswordForm({
1017
1168
  editable: !form.isSubmitting,
1018
1169
  placeholder: labels.confirmPasswordPlaceholder,
1019
1170
  placeholderTextColor: theme.colors.textSecondary,
1020
- style: styles.input,
1171
+ style: styles3.input,
1021
1172
  testID: withTestIdPrefix(AuthTestIds.resetPasswordConfirmInput, testIdPrefix),
1022
1173
  value: form.confirmPassword,
1023
1174
  onChangeText: form.setConfirmPassword
@@ -1027,7 +1178,7 @@ function ResetPasswordForm({
1027
1178
  message !== null ? /* @__PURE__ */ jsxRuntime.jsx(
1028
1179
  reactNative.Text,
1029
1180
  {
1030
- style: styles.errorText,
1181
+ style: styles3.errorText,
1031
1182
  testID: withTestIdPrefix(AuthTestIds.resetPasswordError, testIdPrefix),
1032
1183
  children: message
1033
1184
  }
@@ -1042,7 +1193,7 @@ function ResetPasswordForm({
1042
1193
  style: submitButtonStyle,
1043
1194
  testID: withTestIdPrefix(AuthTestIds.resetPasswordSubmitButton, testIdPrefix),
1044
1195
  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 })
1196
+ 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
1197
  }
1047
1198
  )
1048
1199
  ]
@@ -1050,7 +1201,7 @@ function ResetPasswordForm({
1050
1201
  ) });
1051
1202
  }
1052
1203
  function OtpRequestStep({
1053
- styles,
1204
+ styles: styles3,
1054
1205
  theme,
1055
1206
  labels,
1056
1207
  testIdPrefix,
@@ -1059,12 +1210,12 @@ function OtpRequestStep({
1059
1210
  onSubmit
1060
1211
  }) {
1061
1212
  const [email, setEmail] = react.useState("");
1062
- const buttonStyle = isSubmitting ? [styles.primaryButton, styles.primaryButtonDisabled] : styles.primaryButton;
1213
+ const buttonStyle = isSubmitting ? [styles3.primaryButton, styles3.primaryButtonDisabled] : styles3.primaryButton;
1063
1214
  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 }),
1215
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.title, children: labels.requestTitle }),
1216
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.subtitle, children: labels.requestDescription }),
1217
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles3.fieldGroup, children: [
1218
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.label, children: labels.emailLabel }),
1068
1219
  /* @__PURE__ */ jsxRuntime.jsx(
1069
1220
  reactNative.TextInput,
1070
1221
  {
@@ -1076,14 +1227,14 @@ function OtpRequestStep({
1076
1227
  keyboardType: "email-address",
1077
1228
  placeholder: labels.emailPlaceholder,
1078
1229
  placeholderTextColor: theme.colors.textSecondary,
1079
- style: styles.input,
1230
+ style: styles3.input,
1080
1231
  testID: withTestIdPrefix(AuthTestIds.otpEmailInput, testIdPrefix),
1081
1232
  value: email,
1082
1233
  onChangeText: setEmail
1083
1234
  }
1084
1235
  )
1085
1236
  ] }),
1086
- errorText !== null ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles.errorText, testID: withTestIdPrefix(AuthTestIds.otpError, testIdPrefix), children: errorText }) : null,
1237
+ errorText !== null ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.errorText, testID: withTestIdPrefix(AuthTestIds.otpError, testIdPrefix), children: errorText }) : null,
1087
1238
  /* @__PURE__ */ jsxRuntime.jsx(
1088
1239
  reactNative.TouchableOpacity,
1089
1240
  {
@@ -1094,13 +1245,13 @@ function OtpRequestStep({
1094
1245
  style: buttonStyle,
1095
1246
  testID: withTestIdPrefix(AuthTestIds.otpRequestButton, testIdPrefix),
1096
1247
  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 })
1248
+ 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
1249
  }
1099
1250
  )
1100
1251
  ] });
1101
1252
  }
1102
1253
  function OtpVerifyStep({
1103
- styles,
1254
+ styles: styles3,
1104
1255
  theme,
1105
1256
  labels,
1106
1257
  testIdPrefix,
@@ -1112,13 +1263,13 @@ function OtpVerifyStep({
1112
1263
  onChangeEmail
1113
1264
  }) {
1114
1265
  const [code, setCode] = react.useState("");
1115
- const buttonStyle = isSubmitting ? [styles.primaryButton, styles.primaryButtonDisabled] : styles.primaryButton;
1266
+ const buttonStyle = isSubmitting ? [styles3.primaryButton, styles3.primaryButtonDisabled] : styles3.primaryButton;
1116
1267
  const description = labels.verifyDescription.replace("{identifier}", identifier);
1117
1268
  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 }),
1269
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.title, children: labels.verifyTitle }),
1270
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.subtitle, children: description }),
1271
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles3.fieldGroup, children: [
1272
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.label, children: labels.codeLabel }),
1122
1273
  /* @__PURE__ */ jsxRuntime.jsx(
1123
1274
  reactNative.TextInput,
1124
1275
  {
@@ -1130,14 +1281,14 @@ function OtpVerifyStep({
1130
1281
  keyboardType: "number-pad",
1131
1282
  placeholder: labels.codePlaceholder,
1132
1283
  placeholderTextColor: theme.colors.textSecondary,
1133
- style: styles.input,
1284
+ style: styles3.input,
1134
1285
  testID: withTestIdPrefix(AuthTestIds.otpCodeInput, testIdPrefix),
1135
1286
  value: code,
1136
1287
  onChangeText: setCode
1137
1288
  }
1138
1289
  )
1139
1290
  ] }),
1140
- errorText !== null ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles.errorText, testID: withTestIdPrefix(AuthTestIds.otpError, testIdPrefix), children: errorText }) : null,
1291
+ errorText !== null ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.errorText, testID: withTestIdPrefix(AuthTestIds.otpError, testIdPrefix), children: errorText }) : null,
1141
1292
  /* @__PURE__ */ jsxRuntime.jsx(
1142
1293
  reactNative.TouchableOpacity,
1143
1294
  {
@@ -1148,7 +1299,7 @@ function OtpVerifyStep({
1148
1299
  style: buttonStyle,
1149
1300
  testID: withTestIdPrefix(AuthTestIds.otpVerifyButton, testIdPrefix),
1150
1301
  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 })
1302
+ 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
1303
  }
1153
1304
  ),
1154
1305
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -1158,10 +1309,10 @@ function OtpVerifyStep({
1158
1309
  accessibilityLabel: isSubmitting ? labels.resending : labels.resend,
1159
1310
  accessibilityRole: "link",
1160
1311
  disabled: isSubmitting,
1161
- style: styles.fieldGroup,
1312
+ style: styles3.fieldGroup,
1162
1313
  testID: withTestIdPrefix(AuthTestIds.otpResendButton, testIdPrefix),
1163
1314
  onPress: onResend,
1164
- children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles.linkText, children: isSubmitting ? labels.resending : labels.resend })
1315
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.linkText, children: isSubmitting ? labels.resending : labels.resend })
1165
1316
  }
1166
1317
  ),
1167
1318
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -1173,7 +1324,7 @@ function OtpVerifyStep({
1173
1324
  disabled: isSubmitting,
1174
1325
  testID: withTestIdPrefix(AuthTestIds.otpChangeEmailButton, testIdPrefix),
1175
1326
  onPress: onChangeEmail,
1176
- children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles.linkText, children: labels.changeEmail })
1327
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.linkText, children: labels.changeEmail })
1177
1328
  }
1178
1329
  )
1179
1330
  ] });
@@ -1342,7 +1493,7 @@ function OtpForm({
1342
1493
  testIdPrefix
1343
1494
  }) {
1344
1495
  const theme = useAuthTheme(themeProp);
1345
- const styles = useAuthStyles(theme);
1496
+ const styles3 = useAuthStyles(theme);
1346
1497
  const labels = react.useMemo(
1347
1498
  () => ({ ...DEFAULT_OTP_LABELS, ...labelsProp }),
1348
1499
  [labelsProp]
@@ -1360,13 +1511,13 @@ function OtpForm({
1360
1511
  otp.reset();
1361
1512
  }, [otp]);
1362
1513
  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(
1514
+ 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
1515
  OtpRequestStep,
1365
1516
  {
1366
1517
  errorText,
1367
1518
  isSubmitting: otp.isSubmitting,
1368
1519
  labels,
1369
- styles,
1520
+ styles: styles3,
1370
1521
  testIdPrefix,
1371
1522
  theme,
1372
1523
  onSubmit: handleRequest
@@ -1378,7 +1529,7 @@ function OtpForm({
1378
1529
  identifier: otp.identifier,
1379
1530
  isSubmitting: otp.isSubmitting,
1380
1531
  labels,
1381
- styles,
1532
+ styles: styles3,
1382
1533
  testIdPrefix,
1383
1534
  theme,
1384
1535
  onChangeEmail: handleChangeEmail,
@@ -1467,7 +1618,7 @@ function PinForm({
1467
1618
  testIdPrefix
1468
1619
  }) {
1469
1620
  const theme = useAuthTheme(themeProp);
1470
- const styles = useAuthStyles(theme);
1621
+ const styles3 = useAuthStyles(theme);
1471
1622
  const labels = react.useMemo(
1472
1623
  () => ({ ...DEFAULT_PIN_LABELS, ...labelsProp }),
1473
1624
  [labelsProp]
@@ -1477,12 +1628,12 @@ function PinForm({
1477
1628
  const [pinValue, setPinValue] = react.useState("");
1478
1629
  const handleSubmit = useSubmitHandler(pin, labels, setLocalError, onSuccess);
1479
1630
  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 }),
1631
+ const buttonStyle = pin.isSubmitting ? [styles3.primaryButton, styles3.primaryButtonDisabled] : styles3.primaryButton;
1632
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles3.screen, children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles3.card, testID: withTestIdPrefix(AuthTestIds.pinForm, testIdPrefix), children: [
1633
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.title, children: labels.title }),
1634
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.subtitle, children: labels.description }),
1635
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles3.fieldGroup, children: [
1636
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.label, children: labels.pinLabel }),
1486
1637
  /* @__PURE__ */ jsxRuntime.jsx(
1487
1638
  reactNative.TextInput,
1488
1639
  {
@@ -1495,7 +1646,7 @@ function PinForm({
1495
1646
  placeholder: labels.pinPlaceholder,
1496
1647
  placeholderTextColor: theme.colors.textSecondary,
1497
1648
  secureTextEntry: true,
1498
- style: styles.input,
1649
+ style: styles3.input,
1499
1650
  testID: withTestIdPrefix(AuthTestIds.pinInput, testIdPrefix),
1500
1651
  value: pinValue,
1501
1652
  onChangeText: setPinValue
@@ -1505,7 +1656,7 @@ function PinForm({
1505
1656
  errorText !== null ? /* @__PURE__ */ jsxRuntime.jsx(
1506
1657
  reactNative.Text,
1507
1658
  {
1508
- style: styles.errorText,
1659
+ style: styles3.errorText,
1509
1660
  testID: withTestIdPrefix(AuthTestIds.pinError, testIdPrefix),
1510
1661
  children: errorText
1511
1662
  }
@@ -1520,11 +1671,1200 @@ function PinForm({
1520
1671
  style: buttonStyle,
1521
1672
  testID: withTestIdPrefix(AuthTestIds.pinSubmitButton, testIdPrefix),
1522
1673
  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 })
1674
+ 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
1675
  }
1525
1676
  )
1526
1677
  ] }) });
1527
1678
  }
1679
+ var DOT_SIZE = 18;
1680
+ var DOT_BORDER_WIDTH = 2;
1681
+ var DOT_RADIUS = 9;
1682
+ var ROW_GAP = 12;
1683
+ var ROW_MIN_HEIGHT = 44;
1684
+ var ROW_VERTICAL_MARGIN = 16;
1685
+ var HIDDEN_SIZE = 1;
1686
+ function sanitise(raw, length) {
1687
+ return raw.replace(/\D/g, "").slice(0, length);
1688
+ }
1689
+ function useDotStyles(theme) {
1690
+ return react.useMemo(
1691
+ () => ({
1692
+ filled: { backgroundColor: theme.colors.primary, borderColor: theme.colors.primary },
1693
+ empty: { backgroundColor: theme.colors.background, borderColor: theme.colors.border }
1694
+ }),
1695
+ [theme]
1696
+ );
1697
+ }
1698
+ function DevicePinInput({
1699
+ value,
1700
+ length,
1701
+ disabled,
1702
+ testID,
1703
+ testIdPrefix,
1704
+ accessibilityLabel,
1705
+ accessibilityHint,
1706
+ filledHint,
1707
+ emptyHint,
1708
+ theme: themeProp,
1709
+ onChange
1710
+ }) {
1711
+ const theme = useAuthTheme(themeProp);
1712
+ const inputRef = react.useRef(null);
1713
+ const dotStyles = useDotStyles(theme);
1714
+ const cells = Array.from({ length }, (_unused, index) => index);
1715
+ const baseId = withTestIdPrefix(testID, testIdPrefix);
1716
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1717
+ reactNative.Pressable,
1718
+ {
1719
+ accessibilityHint,
1720
+ accessibilityLabel,
1721
+ accessibilityRole: "button",
1722
+ disabled,
1723
+ style: styles.row,
1724
+ testID: `${baseId}-row`,
1725
+ onPress: () => inputRef.current?.focus(),
1726
+ children: [
1727
+ cells.map((index) => {
1728
+ const filled = index < value.length;
1729
+ return /* @__PURE__ */ jsxRuntime.jsx(
1730
+ reactNative.View,
1731
+ {
1732
+ accessibilityLabel: filled ? filledHint : emptyHint,
1733
+ style: [styles.dot, filled ? dotStyles.filled : dotStyles.empty],
1734
+ testID: `${baseId}-dot-${String(index)}`
1735
+ },
1736
+ index
1737
+ );
1738
+ }),
1739
+ /* @__PURE__ */ jsxRuntime.jsx(
1740
+ reactNative.TextInput,
1741
+ {
1742
+ ref: inputRef,
1743
+ accessibilityHint,
1744
+ accessibilityLabel,
1745
+ autoFocus: true,
1746
+ caretHidden: true,
1747
+ editable: !disabled,
1748
+ keyboardType: "number-pad",
1749
+ maxLength: length,
1750
+ secureTextEntry: true,
1751
+ style: styles.hiddenInput,
1752
+ testID: baseId,
1753
+ value,
1754
+ onChangeText: (raw) => onChange(sanitise(raw, length))
1755
+ }
1756
+ )
1757
+ ]
1758
+ }
1759
+ );
1760
+ }
1761
+ var styles = reactNative.StyleSheet.create({
1762
+ dot: {
1763
+ borderRadius: DOT_RADIUS,
1764
+ borderWidth: DOT_BORDER_WIDTH,
1765
+ height: DOT_SIZE,
1766
+ width: DOT_SIZE
1767
+ },
1768
+ hiddenInput: {
1769
+ height: HIDDEN_SIZE,
1770
+ opacity: 0,
1771
+ position: "absolute",
1772
+ width: HIDDEN_SIZE
1773
+ },
1774
+ row: {
1775
+ alignItems: "center",
1776
+ flexDirection: "row",
1777
+ gap: ROW_GAP,
1778
+ justifyContent: "center",
1779
+ marginVertical: ROW_VERTICAL_MARGIN,
1780
+ minHeight: ROW_MIN_HEIGHT
1781
+ }
1782
+ });
1783
+
1784
+ // src/components/interpolate.ts
1785
+ function interpolate(template, values) {
1786
+ return template.replace(/\{(\w+)\}/g, (match, key) => {
1787
+ const value = values[key];
1788
+ return value === void 0 ? match : String(value);
1789
+ });
1790
+ }
1791
+
1792
+ // src/devicePin/devicePinConstants.ts
1793
+ var DEVICE_PIN_ALLOWED_DIGITS = [4, 6, 8];
1794
+ var DEVICE_PIN_DEFAULT_DIGITS = 4;
1795
+ function isAllowedPinDigits(value) {
1796
+ return DEVICE_PIN_ALLOWED_DIGITS.includes(value);
1797
+ }
1798
+ var PILL_VERTICAL_PADDING = 10;
1799
+ var PILL_FONT_SIZE = 15;
1800
+ function usePickerStyles(theme) {
1801
+ return react.useMemo(
1802
+ () => ({
1803
+ pill: { borderColor: theme.colors.border },
1804
+ active: { backgroundColor: theme.colors.primary, borderColor: theme.colors.primary },
1805
+ text: { color: theme.colors.text },
1806
+ textActive: { color: theme.colors.onPrimary }
1807
+ }),
1808
+ [theme]
1809
+ );
1810
+ }
1811
+ function DevicePinLengthPicker({
1812
+ selected,
1813
+ disabled,
1814
+ optionHint,
1815
+ testIdPrefix,
1816
+ theme: themeProp,
1817
+ onSelect
1818
+ }) {
1819
+ const theme = useAuthTheme(themeProp);
1820
+ const dynamic = usePickerStyles(theme);
1821
+ const baseId = withTestIdPrefix(AuthTestIds.devicePinEnrollLength, testIdPrefix);
1822
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles2.row, children: DEVICE_PIN_ALLOWED_DIGITS.map((option) => {
1823
+ const active = option === selected;
1824
+ return /* @__PURE__ */ jsxRuntime.jsx(
1825
+ reactNative.Pressable,
1826
+ {
1827
+ accessibilityHint: interpolate(optionHint, { count: option }),
1828
+ accessibilityLabel: String(option),
1829
+ accessibilityRole: "button",
1830
+ accessibilityState: { selected: active },
1831
+ disabled,
1832
+ style: [styles2.pill, dynamic.pill, active ? dynamic.active : null],
1833
+ testID: `${baseId}-${String(option)}`,
1834
+ onPress: () => onSelect(option),
1835
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles2.text, dynamic.text, active ? dynamic.textActive : null], children: String(option) })
1836
+ },
1837
+ option
1838
+ );
1839
+ }) });
1840
+ }
1841
+ var styles2 = reactNative.StyleSheet.create({
1842
+ pill: {
1843
+ alignItems: "center",
1844
+ borderRadius: 8,
1845
+ borderWidth: 1,
1846
+ flex: 1,
1847
+ paddingVertical: PILL_VERTICAL_PADDING
1848
+ },
1849
+ row: {
1850
+ flexDirection: "row",
1851
+ gap: 8,
1852
+ marginBottom: 8
1853
+ },
1854
+ text: {
1855
+ fontSize: PILL_FONT_SIZE,
1856
+ fontWeight: "700"
1857
+ }
1858
+ });
1859
+
1860
+ // src/devicePin/DevicePinErrorKey.ts
1861
+ var DevicePinErrorKey = /* @__PURE__ */ ((DevicePinErrorKey2) => {
1862
+ DevicePinErrorKey2["Incomplete"] = "incomplete";
1863
+ DevicePinErrorKey2["Invalid"] = "invalid";
1864
+ DevicePinErrorKey2["LockedOut"] = "locked_out";
1865
+ DevicePinErrorKey2["RateLimited"] = "rate_limited";
1866
+ DevicePinErrorKey2["Generic"] = "generic";
1867
+ return DevicePinErrorKey2;
1868
+ })(DevicePinErrorKey || {});
1869
+ function useDevicePinUnlock({
1870
+ client,
1871
+ digits,
1872
+ onSignedIn
1873
+ }) {
1874
+ const [pin, setPinState] = react.useState("");
1875
+ const [submitting, setSubmitting] = react.useState(false);
1876
+ const [errorKey, setErrorKey] = react.useState(null);
1877
+ const [retryAfterSeconds, setRetryAfterSeconds] = react.useState(null);
1878
+ const setPin = react.useCallback((next) => {
1879
+ setPinState(next);
1880
+ setErrorKey(null);
1881
+ setRetryAfterSeconds(null);
1882
+ }, []);
1883
+ const submit = react.useCallback(() => {
1884
+ setErrorKey(null);
1885
+ setRetryAfterSeconds(null);
1886
+ if (pin.length < digits) {
1887
+ setErrorKey("incomplete" /* Incomplete */);
1888
+ return;
1889
+ }
1890
+ setSubmitting(true);
1891
+ client.unlockWithDevicePin({ pin }).then((result) => {
1892
+ if (result.status === "success") {
1893
+ onSignedIn(result.user);
1894
+ return;
1895
+ }
1896
+ if (result.status === "invalid") {
1897
+ setErrorKey("invalid" /* Invalid */);
1898
+ return;
1899
+ }
1900
+ if (result.status === "locked") {
1901
+ setRetryAfterSeconds(result.retryAfterSeconds);
1902
+ setErrorKey("locked_out" /* LockedOut */);
1903
+ return;
1904
+ }
1905
+ if (result.status === "rateLimited") {
1906
+ setRetryAfterSeconds(result.retryAfterSeconds);
1907
+ setErrorKey("rate_limited" /* RateLimited */);
1908
+ return;
1909
+ }
1910
+ setErrorKey("generic" /* Generic */);
1911
+ }).catch(() => {
1912
+ setErrorKey("generic" /* Generic */);
1913
+ }).finally(() => {
1914
+ setSubmitting(false);
1915
+ });
1916
+ }, [client, pin, digits, onSignedIn]);
1917
+ return { pin, submitting, errorKey, retryAfterSeconds, setPin, submit };
1918
+ }
1919
+ function resolveErrorText(errorKey, digits, retryAfter, labels) {
1920
+ if (errorKey === null) {
1921
+ return null;
1922
+ }
1923
+ if (errorKey === "incomplete" /* Incomplete */) {
1924
+ return interpolate(labels.errorIncomplete, { count: digits });
1925
+ }
1926
+ if (errorKey === "invalid" /* Invalid */) {
1927
+ return labels.errorInvalid;
1928
+ }
1929
+ if (errorKey === "locked_out" /* LockedOut */) {
1930
+ return retryAfter !== null ? interpolate(labels.errorLockedOutRetry, { count: retryAfter }) : labels.errorLockedOut;
1931
+ }
1932
+ if (errorKey === "rate_limited" /* RateLimited */) {
1933
+ return retryAfter !== null ? interpolate(labels.errorRateLimitedRetry, { count: retryAfter }) : labels.errorRateLimited;
1934
+ }
1935
+ return labels.errorGeneric;
1936
+ }
1937
+ function DevicePinUnlockScreen({
1938
+ client,
1939
+ digits,
1940
+ rememberedUsername,
1941
+ theme: themeProp,
1942
+ labels: labelsProp,
1943
+ testIdPrefix,
1944
+ onSignedIn,
1945
+ onUsePassword
1946
+ }) {
1947
+ const theme = useAuthTheme(themeProp);
1948
+ const styles3 = useAuthStyles(theme);
1949
+ const labels = react.useMemo(
1950
+ () => ({ ...DEFAULT_DEVICE_PIN_UNLOCK_LABELS, ...labelsProp }),
1951
+ [labelsProp]
1952
+ );
1953
+ const { pin, submitting, errorKey, retryAfterSeconds, setPin, submit } = useDevicePinUnlock({
1954
+ client,
1955
+ digits,
1956
+ onSignedIn
1957
+ });
1958
+ const hasName = rememberedUsername !== "";
1959
+ const title = hasName ? interpolate(labels.title, { name: rememberedUsername }) : labels.titleNoName;
1960
+ const error = resolveErrorText(errorKey, digits, retryAfterSeconds, labels);
1961
+ const buttonStyle = submitting ? [styles3.primaryButton, styles3.primaryButtonDisabled] : styles3.primaryButton;
1962
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles3.screen, children: /* @__PURE__ */ jsxRuntime.jsxs(
1963
+ reactNative.View,
1964
+ {
1965
+ style: styles3.card,
1966
+ testID: withTestIdPrefix(AuthTestIds.devicePinUnlock, testIdPrefix),
1967
+ children: [
1968
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.title, children: title }),
1969
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.subtitle, children: interpolate(labels.description, { count: digits }) }),
1970
+ /* @__PURE__ */ jsxRuntime.jsx(
1971
+ DevicePinInput,
1972
+ {
1973
+ accessibilityHint: labels.pinPlaceholder,
1974
+ accessibilityLabel: labels.pinLabel,
1975
+ disabled: submitting,
1976
+ emptyHint: labels.digitEmptyHint,
1977
+ filledHint: labels.digitFilledHint,
1978
+ length: digits,
1979
+ testID: AuthTestIds.devicePinUnlockInput,
1980
+ testIdPrefix,
1981
+ theme,
1982
+ value: pin,
1983
+ onChange: setPin
1984
+ }
1985
+ ),
1986
+ error !== null ? /* @__PURE__ */ jsxRuntime.jsx(
1987
+ reactNative.Text,
1988
+ {
1989
+ style: styles3.errorText,
1990
+ testID: withTestIdPrefix(AuthTestIds.devicePinUnlockError, testIdPrefix),
1991
+ children: error
1992
+ }
1993
+ ) : null,
1994
+ /* @__PURE__ */ jsxRuntime.jsx(
1995
+ reactNative.TouchableOpacity,
1996
+ {
1997
+ accessibilityHint: labels.submit,
1998
+ accessibilityLabel: submitting ? labels.submitting : labels.submit,
1999
+ accessibilityRole: "button",
2000
+ disabled: submitting,
2001
+ style: buttonStyle,
2002
+ testID: withTestIdPrefix(AuthTestIds.devicePinUnlockSubmit, testIdPrefix),
2003
+ onPress: submit,
2004
+ children: submitting ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.primaryButtonText, children: labels.submit })
2005
+ }
2006
+ ),
2007
+ /* @__PURE__ */ jsxRuntime.jsx(
2008
+ reactNative.TouchableOpacity,
2009
+ {
2010
+ accessibilityHint: labels.usePasswordHint,
2011
+ accessibilityLabel: labels.usePasswordInstead,
2012
+ accessibilityRole: "button",
2013
+ disabled: submitting,
2014
+ style: styles3.escapeLink,
2015
+ testID: withTestIdPrefix(AuthTestIds.devicePinUnlockUsePassword, testIdPrefix),
2016
+ onPress: onUsePassword,
2017
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.linkText, children: labels.usePasswordInstead })
2018
+ }
2019
+ )
2020
+ ]
2021
+ }
2022
+ ) });
2023
+ }
2024
+
2025
+ // src/devicePin/DevicePinEnrollErrorKey.ts
2026
+ var DevicePinEnrollErrorKey = /* @__PURE__ */ ((DevicePinEnrollErrorKey2) => {
2027
+ DevicePinEnrollErrorKey2["Mismatch"] = "mismatch";
2028
+ DevicePinEnrollErrorKey2["Unauthorized"] = "unauthorized";
2029
+ DevicePinEnrollErrorKey2["Forbidden"] = "forbidden";
2030
+ DevicePinEnrollErrorKey2["InvalidPin"] = "invalid_pin";
2031
+ DevicePinEnrollErrorKey2["Failed"] = "failed";
2032
+ return DevicePinEnrollErrorKey2;
2033
+ })(DevicePinEnrollErrorKey || {});
2034
+ function errorKeyFor(result) {
2035
+ if (result.status === "unauthorized") {
2036
+ return "unauthorized" /* Unauthorized */;
2037
+ }
2038
+ if (result.status === "forbidden") {
2039
+ return "forbidden" /* Forbidden */;
2040
+ }
2041
+ if (result.status === "invalidPin") {
2042
+ return "invalid_pin" /* InvalidPin */;
2043
+ }
2044
+ return "failed" /* Failed */;
2045
+ }
2046
+ function useDevicePinEnroll({
2047
+ client,
2048
+ digits,
2049
+ onEnrolled
2050
+ }) {
2051
+ const [pin, setPinState] = react.useState("");
2052
+ const [confirmPin, setConfirmState] = react.useState("");
2053
+ const [submitting, setSubmitting] = react.useState(false);
2054
+ const [errorKey, setErrorKey] = react.useState(null);
2055
+ const setPin = react.useCallback((next) => {
2056
+ setPinState(next);
2057
+ setErrorKey(null);
2058
+ }, []);
2059
+ const setConfirmPin = react.useCallback((next) => {
2060
+ setConfirmState(next);
2061
+ setErrorKey(null);
2062
+ }, []);
2063
+ const submit = react.useCallback(() => {
2064
+ setErrorKey(null);
2065
+ const wrongLength = pin.length !== digits;
2066
+ const mismatched = pin !== confirmPin;
2067
+ if (wrongLength || mismatched) {
2068
+ setErrorKey("mismatch" /* Mismatch */);
2069
+ return;
2070
+ }
2071
+ setSubmitting(true);
2072
+ client.enrollDevicePin({ pin, digits }).then((result) => {
2073
+ if (result.status === "success") {
2074
+ onEnrolled();
2075
+ return;
2076
+ }
2077
+ setErrorKey(errorKeyFor(result));
2078
+ }).catch(() => {
2079
+ setErrorKey("failed" /* Failed */);
2080
+ }).finally(() => {
2081
+ setSubmitting(false);
2082
+ });
2083
+ }, [client, pin, confirmPin, digits, onEnrolled]);
2084
+ return { pin, confirmPin, submitting, errorKey, setPin, setConfirmPin, submit };
2085
+ }
2086
+ function resolveErrorText2(errorKey, digits, labels) {
2087
+ if (errorKey === null) {
2088
+ return null;
2089
+ }
2090
+ if (errorKey === "mismatch" /* Mismatch */) {
2091
+ return interpolate(labels.errorMismatch, { count: digits });
2092
+ }
2093
+ if (errorKey === "unauthorized" /* Unauthorized */) {
2094
+ return labels.errorUnauthorized;
2095
+ }
2096
+ if (errorKey === "forbidden" /* Forbidden */) {
2097
+ return labels.errorForbidden;
2098
+ }
2099
+ if (errorKey === "invalid_pin" /* InvalidPin */) {
2100
+ return labels.errorInvalidPin;
2101
+ }
2102
+ return labels.errorFailed;
2103
+ }
2104
+ function DevicePinEnrollForm({
2105
+ client,
2106
+ initialDigits = DEVICE_PIN_DEFAULT_DIGITS,
2107
+ theme: themeProp,
2108
+ labels: labelsProp,
2109
+ testIdPrefix,
2110
+ onEnrolled,
2111
+ onCancel
2112
+ }) {
2113
+ const theme = useAuthTheme(themeProp);
2114
+ const styles3 = useAuthStyles(theme);
2115
+ const labels = react.useMemo(
2116
+ () => ({ ...DEFAULT_DEVICE_PIN_ENROLL_LABELS, ...labelsProp }),
2117
+ [labelsProp]
2118
+ );
2119
+ const [digits, setDigits] = react.useState(initialDigits);
2120
+ const { pin, confirmPin, submitting, errorKey, setPin, setConfirmPin, submit } = useDevicePinEnroll({ client, digits, onEnrolled });
2121
+ const error = resolveErrorText2(errorKey, digits, labels);
2122
+ const buttonStyle = submitting ? [styles3.primaryButton, styles3.primaryButtonDisabled] : styles3.primaryButton;
2123
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2124
+ reactNative.View,
2125
+ {
2126
+ style: styles3.card,
2127
+ testID: withTestIdPrefix(AuthTestIds.devicePinEnrollForm, testIdPrefix),
2128
+ children: [
2129
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.title, children: labels.formTitle }),
2130
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.subtitle, children: interpolate(labels.formDescription, { count: digits }) }),
2131
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.label, children: labels.lengthLabel }),
2132
+ /* @__PURE__ */ jsxRuntime.jsx(
2133
+ DevicePinLengthPicker,
2134
+ {
2135
+ disabled: submitting,
2136
+ optionHint: labels.lengthOptionHint,
2137
+ selected: digits,
2138
+ testIdPrefix,
2139
+ theme,
2140
+ onSelect: (option) => {
2141
+ setDigits(option);
2142
+ setPin("");
2143
+ setConfirmPin("");
2144
+ }
2145
+ }
2146
+ ),
2147
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.label, children: labels.pinLabel }),
2148
+ /* @__PURE__ */ jsxRuntime.jsx(
2149
+ DevicePinInput,
2150
+ {
2151
+ accessibilityHint: labels.pinPlaceholder,
2152
+ accessibilityLabel: labels.pinLabel,
2153
+ disabled: submitting,
2154
+ emptyHint: labels.pinPlaceholder,
2155
+ filledHint: labels.pinLabel,
2156
+ length: digits,
2157
+ testID: AuthTestIds.devicePinEnrollPin,
2158
+ testIdPrefix,
2159
+ theme,
2160
+ value: pin,
2161
+ onChange: setPin
2162
+ }
2163
+ ),
2164
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.label, children: labels.confirmLabel }),
2165
+ /* @__PURE__ */ jsxRuntime.jsx(
2166
+ DevicePinInput,
2167
+ {
2168
+ accessibilityHint: labels.confirmPlaceholder,
2169
+ accessibilityLabel: labels.confirmLabel,
2170
+ disabled: submitting,
2171
+ emptyHint: labels.confirmPlaceholder,
2172
+ filledHint: labels.confirmLabel,
2173
+ length: digits,
2174
+ testID: AuthTestIds.devicePinEnrollConfirm,
2175
+ testIdPrefix,
2176
+ theme,
2177
+ value: confirmPin,
2178
+ onChange: setConfirmPin
2179
+ }
2180
+ ),
2181
+ error !== null ? /* @__PURE__ */ jsxRuntime.jsx(
2182
+ reactNative.Text,
2183
+ {
2184
+ style: styles3.errorText,
2185
+ testID: withTestIdPrefix(AuthTestIds.devicePinEnrollError, testIdPrefix),
2186
+ children: error
2187
+ }
2188
+ ) : null,
2189
+ /* @__PURE__ */ jsxRuntime.jsx(
2190
+ reactNative.TouchableOpacity,
2191
+ {
2192
+ accessibilityHint: labels.submit,
2193
+ accessibilityLabel: submitting ? labels.submitting : labels.submit,
2194
+ accessibilityRole: "button",
2195
+ disabled: submitting,
2196
+ style: buttonStyle,
2197
+ testID: withTestIdPrefix(AuthTestIds.devicePinEnrollSubmit, testIdPrefix),
2198
+ onPress: submit,
2199
+ children: submitting ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.primaryButtonText, children: labels.submit })
2200
+ }
2201
+ ),
2202
+ /* @__PURE__ */ jsxRuntime.jsx(
2203
+ reactNative.TouchableOpacity,
2204
+ {
2205
+ accessibilityHint: labels.cancelHint,
2206
+ accessibilityLabel: labels.cancel,
2207
+ accessibilityRole: "button",
2208
+ disabled: submitting,
2209
+ style: styles3.escapeLink,
2210
+ testID: withTestIdPrefix(AuthTestIds.devicePinEnrollCancel, testIdPrefix),
2211
+ onPress: onCancel,
2212
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.linkText, children: labels.cancel })
2213
+ }
2214
+ )
2215
+ ]
2216
+ }
2217
+ );
2218
+ }
2219
+ function DevicePinOffer({
2220
+ client,
2221
+ initialDigits,
2222
+ theme: themeProp,
2223
+ labels: labelsProp,
2224
+ testIdPrefix,
2225
+ onDismiss
2226
+ }) {
2227
+ const theme = useAuthTheme(themeProp);
2228
+ const styles3 = useAuthStyles(theme);
2229
+ const labels = react.useMemo(
2230
+ () => ({ ...DEFAULT_DEVICE_PIN_ENROLL_LABELS, ...labelsProp }),
2231
+ [labelsProp]
2232
+ );
2233
+ const [expanded, setExpanded] = react.useState(false);
2234
+ const cardTestId = withTestIdPrefix(AuthTestIds.devicePinOffer, testIdPrefix);
2235
+ if (expanded) {
2236
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles3.card, testID: cardTestId, children: /* @__PURE__ */ jsxRuntime.jsx(
2237
+ DevicePinEnrollForm,
2238
+ {
2239
+ client,
2240
+ initialDigits,
2241
+ labels: labelsProp,
2242
+ testIdPrefix,
2243
+ theme,
2244
+ onCancel: onDismiss,
2245
+ onEnrolled: onDismiss
2246
+ }
2247
+ ) });
2248
+ }
2249
+ return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles3.card, testID: cardTestId, children: [
2250
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.title, children: labels.offerTitle }),
2251
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.subtitle, children: labels.offerDescription }),
2252
+ /* @__PURE__ */ jsxRuntime.jsx(
2253
+ reactNative.TouchableOpacity,
2254
+ {
2255
+ accessibilityHint: labels.offerAcceptHint,
2256
+ accessibilityLabel: labels.offerAccept,
2257
+ accessibilityRole: "button",
2258
+ style: styles3.primaryButton,
2259
+ testID: withTestIdPrefix(AuthTestIds.devicePinOfferAccept, testIdPrefix),
2260
+ onPress: () => setExpanded(true),
2261
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.primaryButtonText, children: labels.offerAccept })
2262
+ }
2263
+ ),
2264
+ /* @__PURE__ */ jsxRuntime.jsx(
2265
+ reactNative.TouchableOpacity,
2266
+ {
2267
+ accessibilityHint: labels.offerSkipHint,
2268
+ accessibilityLabel: labels.offerSkip,
2269
+ accessibilityRole: "button",
2270
+ style: styles3.secondaryButton,
2271
+ testID: withTestIdPrefix(AuthTestIds.devicePinOfferSkip, testIdPrefix),
2272
+ onPress: onDismiss,
2273
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.secondaryButtonText, children: labels.offerSkip })
2274
+ }
2275
+ )
2276
+ ] });
2277
+ }
2278
+ function useDevicePinDisable({
2279
+ client,
2280
+ initialHasPin,
2281
+ onChanged
2282
+ }) {
2283
+ const [hasPin, setHasPin] = react.useState(initialHasPin);
2284
+ const [disabling, setDisabling] = react.useState(false);
2285
+ const [failed, setFailed] = react.useState(false);
2286
+ const disable = react.useCallback(() => {
2287
+ setFailed(false);
2288
+ setDisabling(true);
2289
+ client.disableDevicePin().then((ok) => {
2290
+ if (ok) {
2291
+ setHasPin(false);
2292
+ onChanged?.(false);
2293
+ return;
2294
+ }
2295
+ setFailed(true);
2296
+ }).catch(() => {
2297
+ setFailed(true);
2298
+ }).finally(() => {
2299
+ setDisabling(false);
2300
+ });
2301
+ }, [client, onChanged]);
2302
+ const markEnabled = react.useCallback(() => {
2303
+ setHasPin(true);
2304
+ onChanged?.(true);
2305
+ }, [onChanged]);
2306
+ return { hasPin, disabling, failed, disable, markEnabled };
2307
+ }
2308
+ function DevicePinSettingsCard({
2309
+ client,
2310
+ initialHasPin,
2311
+ theme: themeProp,
2312
+ labels: labelsProp,
2313
+ enrollLabels,
2314
+ testIdPrefix,
2315
+ onChanged
2316
+ }) {
2317
+ const theme = useAuthTheme(themeProp);
2318
+ const styles3 = useAuthStyles(theme);
2319
+ const labels = react.useMemo(
2320
+ () => ({ ...DEFAULT_DEVICE_PIN_SETTINGS_LABELS, ...labelsProp }),
2321
+ [labelsProp]
2322
+ );
2323
+ const resolvedEnrollLabels = react.useMemo(
2324
+ () => ({ ...DEFAULT_DEVICE_PIN_ENROLL_LABELS, ...enrollLabels }),
2325
+ [enrollLabels]
2326
+ );
2327
+ const [enrolling, setEnrolling] = react.useState(false);
2328
+ const { hasPin, disabling, failed, disable, markEnabled } = useDevicePinDisable({
2329
+ client,
2330
+ initialHasPin,
2331
+ onChanged
2332
+ });
2333
+ const handleEnrolled = () => {
2334
+ setEnrolling(false);
2335
+ markEnabled();
2336
+ };
2337
+ const disableButtonStyle = disabling ? [styles3.secondaryButton, styles3.primaryButtonDisabled] : styles3.secondaryButton;
2338
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2339
+ reactNative.View,
2340
+ {
2341
+ style: styles3.card,
2342
+ testID: withTestIdPrefix(AuthTestIds.devicePinSettings, testIdPrefix),
2343
+ children: [
2344
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.title, children: labels.title }),
2345
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.subtitle, children: labels.description }),
2346
+ /* @__PURE__ */ jsxRuntime.jsx(
2347
+ reactNative.Text,
2348
+ {
2349
+ style: styles3.statusText,
2350
+ testID: withTestIdPrefix(AuthTestIds.devicePinSettingsStatus, testIdPrefix),
2351
+ children: hasPin ? labels.statusEnabled : labels.statusDisabled
2352
+ }
2353
+ ),
2354
+ failed ? /* @__PURE__ */ jsxRuntime.jsx(
2355
+ reactNative.Text,
2356
+ {
2357
+ style: styles3.errorText,
2358
+ testID: withTestIdPrefix(AuthTestIds.devicePinSettingsError, testIdPrefix),
2359
+ children: labels.disableFailed
2360
+ }
2361
+ ) : null,
2362
+ renderAction()
2363
+ ]
2364
+ }
2365
+ );
2366
+ function renderAction() {
2367
+ if (enrolling) {
2368
+ return /* @__PURE__ */ jsxRuntime.jsx(
2369
+ DevicePinEnrollForm,
2370
+ {
2371
+ client,
2372
+ labels: resolvedEnrollLabels,
2373
+ testIdPrefix,
2374
+ theme,
2375
+ onCancel: () => setEnrolling(false),
2376
+ onEnrolled: handleEnrolled
2377
+ }
2378
+ );
2379
+ }
2380
+ if (hasPin) {
2381
+ return /* @__PURE__ */ jsxRuntime.jsx(
2382
+ reactNative.TouchableOpacity,
2383
+ {
2384
+ accessibilityHint: labels.disableHint,
2385
+ accessibilityLabel: disabling ? labels.disabling : labels.disable,
2386
+ accessibilityRole: "button",
2387
+ disabled: disabling,
2388
+ style: disableButtonStyle,
2389
+ testID: withTestIdPrefix(AuthTestIds.devicePinSettingsDisable, testIdPrefix),
2390
+ onPress: disable,
2391
+ children: disabling ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { color: theme.colors.primary, size: "small" }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.secondaryButtonText, children: labels.disable })
2392
+ }
2393
+ );
2394
+ }
2395
+ return /* @__PURE__ */ jsxRuntime.jsx(
2396
+ reactNative.TouchableOpacity,
2397
+ {
2398
+ accessibilityHint: labels.enableHint,
2399
+ accessibilityLabel: labels.enable,
2400
+ accessibilityRole: "button",
2401
+ style: styles3.primaryButton,
2402
+ testID: withTestIdPrefix(AuthTestIds.devicePinSettingsEnable, testIdPrefix),
2403
+ onPress: () => setEnrolling(true),
2404
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.primaryButtonText, children: labels.enable })
2405
+ }
2406
+ );
2407
+ }
2408
+ }
2409
+
2410
+ // src/passkey/passkeyNavigation.ts
2411
+ var PASSKEY_LOGIN_ENDPOINT = "/bff/passkey/login";
2412
+ var PASSKEY_REGISTER_ENDPOINT = "/bff/passkey/register";
2413
+ var RETURN_URL_PARAM = "returnUrl";
2414
+ var PASSKEY_ERROR_PARAM = "passkeyError";
2415
+ var PASSKEY_PARAM = "passkey";
2416
+ var PASSKEY_REGISTERED_VALUE = "registered";
2417
+ var PASSKEY_ERROR_CANCELLED = "cancelled";
2418
+ var PASSKEY_ERROR_FAILED = "failed";
2419
+ function buildNavigationUrl(endpoint, returnUrl) {
2420
+ return `${endpoint}?${RETURN_URL_PARAM}=${encodeURIComponent(returnUrl)}`;
2421
+ }
2422
+ function readSearchParams() {
2423
+ if (typeof window === "undefined") {
2424
+ return null;
2425
+ }
2426
+ return new URLSearchParams(window.location.search);
2427
+ }
2428
+ function startPasskeyLogin(returnUrl) {
2429
+ if (typeof window === "undefined") {
2430
+ return;
2431
+ }
2432
+ window.location.assign(buildNavigationUrl(PASSKEY_LOGIN_ENDPOINT, returnUrl));
2433
+ }
2434
+ function startPasskeyRegistration(returnUrl) {
2435
+ if (typeof window === "undefined") {
2436
+ return;
2437
+ }
2438
+ window.location.assign(buildNavigationUrl(PASSKEY_REGISTER_ENDPOINT, returnUrl));
2439
+ }
2440
+ function readPasskeyError() {
2441
+ const params = readSearchParams();
2442
+ if (params === null) {
2443
+ return null;
2444
+ }
2445
+ const value = params.get(PASSKEY_ERROR_PARAM);
2446
+ if (value === PASSKEY_ERROR_CANCELLED) {
2447
+ return PASSKEY_ERROR_CANCELLED;
2448
+ }
2449
+ if (value === PASSKEY_ERROR_FAILED) {
2450
+ return PASSKEY_ERROR_FAILED;
2451
+ }
2452
+ return null;
2453
+ }
2454
+ function readPasskeyRegistered() {
2455
+ const params = readSearchParams();
2456
+ if (params === null) {
2457
+ return false;
2458
+ }
2459
+ return params.get(PASSKEY_PARAM) === PASSKEY_REGISTERED_VALUE;
2460
+ }
2461
+ var DEFAULT_RETURN_URL = "/";
2462
+ function PasskeyLoginButton({
2463
+ returnUrl = DEFAULT_RETURN_URL,
2464
+ theme: themeProp,
2465
+ labels: labelsProp,
2466
+ testIdPrefix
2467
+ }) {
2468
+ const theme = useAuthTheme(themeProp);
2469
+ const styles3 = useAuthStyles(theme);
2470
+ const labels = react.useMemo(
2471
+ () => ({ ...DEFAULT_PASSKEY_LOGIN_LABELS, ...labelsProp }),
2472
+ [labelsProp]
2473
+ );
2474
+ const error = readPasskeyError();
2475
+ return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { testID: withTestIdPrefix(AuthTestIds.passkeyLogin, testIdPrefix), children: [
2476
+ error !== null ? /* @__PURE__ */ jsxRuntime.jsx(
2477
+ reactNative.Text,
2478
+ {
2479
+ style: styles3.errorText,
2480
+ testID: withTestIdPrefix(AuthTestIds.passkeyLoginError, testIdPrefix),
2481
+ children: error === "cancelled" ? labels.errorCancelled : labels.errorFailed
2482
+ }
2483
+ ) : null,
2484
+ /* @__PURE__ */ jsxRuntime.jsx(
2485
+ reactNative.TouchableOpacity,
2486
+ {
2487
+ accessibilityHint: labels.signInHint,
2488
+ accessibilityLabel: labels.signInButton,
2489
+ accessibilityRole: "button",
2490
+ style: styles3.secondaryButton,
2491
+ testID: withTestIdPrefix(AuthTestIds.passkeyLoginButton, testIdPrefix),
2492
+ onPress: () => startPasskeyLogin(returnUrl),
2493
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.secondaryButtonText, children: labels.signInButton })
2494
+ }
2495
+ )
2496
+ ] });
2497
+ }
2498
+ var DEFAULT_RETURN_PATH = "/";
2499
+ function readCurrentPath() {
2500
+ if (typeof window === "undefined") {
2501
+ return DEFAULT_RETURN_PATH;
2502
+ }
2503
+ return window.location.pathname;
2504
+ }
2505
+ function PasskeySettingsCard({
2506
+ returnUrl,
2507
+ theme: themeProp,
2508
+ labels: labelsProp,
2509
+ testIdPrefix
2510
+ }) {
2511
+ const theme = useAuthTheme(themeProp);
2512
+ const styles3 = useAuthStyles(theme);
2513
+ const labels = react.useMemo(
2514
+ () => ({ ...DEFAULT_PASSKEY_SETTINGS_LABELS, ...labelsProp }),
2515
+ [labelsProp]
2516
+ );
2517
+ const justRegistered = readPasskeyRegistered();
2518
+ const target = returnUrl ?? readCurrentPath();
2519
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2520
+ reactNative.View,
2521
+ {
2522
+ style: styles3.card,
2523
+ testID: withTestIdPrefix(AuthTestIds.passkeySettings, testIdPrefix),
2524
+ children: [
2525
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.title, children: labels.title }),
2526
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.subtitle, children: labels.description }),
2527
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.helperText, children: labels.reauthHint }),
2528
+ justRegistered ? /* @__PURE__ */ jsxRuntime.jsx(
2529
+ reactNative.Text,
2530
+ {
2531
+ style: styles3.successText,
2532
+ testID: withTestIdPrefix(AuthTestIds.passkeySettingsSuccess, testIdPrefix),
2533
+ children: labels.registeredSuccess
2534
+ }
2535
+ ) : null,
2536
+ /* @__PURE__ */ jsxRuntime.jsx(
2537
+ reactNative.TouchableOpacity,
2538
+ {
2539
+ accessibilityHint: labels.addHint,
2540
+ accessibilityLabel: labels.addButton,
2541
+ accessibilityRole: "button",
2542
+ style: styles3.primaryButton,
2543
+ testID: withTestIdPrefix(AuthTestIds.passkeySettingsAdd, testIdPrefix),
2544
+ onPress: () => startPasskeyRegistration(target),
2545
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.primaryButtonText, children: labels.addButton })
2546
+ }
2547
+ )
2548
+ ]
2549
+ }
2550
+ );
2551
+ }
2552
+
2553
+ // src/preferences/preferredMethodCache.ts
2554
+ var CACHE_KEY = "dloizides.auth.preferredLoginMethod";
2555
+ function safeStorage() {
2556
+ try {
2557
+ if (typeof localStorage === "undefined") {
2558
+ return null;
2559
+ }
2560
+ return localStorage;
2561
+ } catch {
2562
+ return null;
2563
+ }
2564
+ }
2565
+ function readCachedPreferredMethod() {
2566
+ const store = safeStorage();
2567
+ if (store === null) {
2568
+ return null;
2569
+ }
2570
+ try {
2571
+ const value = store.getItem(CACHE_KEY);
2572
+ return value === null || value === "" ? null : value;
2573
+ } catch {
2574
+ return null;
2575
+ }
2576
+ }
2577
+ function cachePreferredMethod(method) {
2578
+ const store = safeStorage();
2579
+ if (store === null) {
2580
+ return;
2581
+ }
2582
+ try {
2583
+ if (method === null || method === "") {
2584
+ store.removeItem(CACHE_KEY);
2585
+ return;
2586
+ }
2587
+ store.setItem(CACHE_KEY, method);
2588
+ } catch {
2589
+ }
2590
+ }
2591
+ function clearCachedPreferredMethod() {
2592
+ cachePreferredMethod(null);
2593
+ }
2594
+
2595
+ // src/preferences/usePreferredMethodSetting.ts
2596
+ function usePreferredMethodSetting({
2597
+ client,
2598
+ onChanged
2599
+ }) {
2600
+ const [loading, setLoading] = react.useState(true);
2601
+ const [saving, setSaving] = react.useState(false);
2602
+ const [failed, setFailed] = react.useState(false);
2603
+ const [selected, setSelected] = react.useState(null);
2604
+ react.useEffect(() => {
2605
+ let active = true;
2606
+ client.getPreferredLoginMethod().then((method) => {
2607
+ if (active) {
2608
+ setSelected(method);
2609
+ }
2610
+ }).catch(() => {
2611
+ }).finally(() => {
2612
+ if (active) {
2613
+ setLoading(false);
2614
+ }
2615
+ });
2616
+ return () => {
2617
+ active = false;
2618
+ };
2619
+ }, [client]);
2620
+ const select = react.useCallback(
2621
+ (method) => {
2622
+ const previous = selected;
2623
+ if (method === previous) {
2624
+ return;
2625
+ }
2626
+ setFailed(false);
2627
+ setSaving(true);
2628
+ setSelected(method);
2629
+ client.setPreferredLoginMethod(method).then((ok) => {
2630
+ if (ok) {
2631
+ cachePreferredMethod(method);
2632
+ onChanged?.(method);
2633
+ return;
2634
+ }
2635
+ setSelected(previous);
2636
+ setFailed(true);
2637
+ }).catch(() => {
2638
+ setSelected(previous);
2639
+ setFailed(true);
2640
+ }).finally(() => {
2641
+ setSaving(false);
2642
+ });
2643
+ },
2644
+ [client, selected, onChanged]
2645
+ );
2646
+ return { loading, saving, failed, selected, select };
2647
+ }
2648
+ var NO_PREFERENCE = "__none__";
2649
+ function methodDisplayName(method, labels) {
2650
+ if (method === "password") {
2651
+ return labels.methodPassword;
2652
+ }
2653
+ if (method === "pin") {
2654
+ return labels.methodPin;
2655
+ }
2656
+ if (method === "passkey") {
2657
+ return labels.methodPasskey;
2658
+ }
2659
+ return method;
2660
+ }
2661
+ function PreferredMethodSettingsCard({
2662
+ client,
2663
+ availableMethods,
2664
+ theme: themeProp,
2665
+ labels: labelsProp,
2666
+ testIdPrefix,
2667
+ onChanged
2668
+ }) {
2669
+ const theme = useAuthTheme(themeProp);
2670
+ const styles3 = useAuthStyles(theme);
2671
+ const labels = react.useMemo(
2672
+ () => ({ ...DEFAULT_PREFERRED_METHOD_SETTINGS_LABELS, ...labelsProp }),
2673
+ [labelsProp]
2674
+ );
2675
+ const { loading, saving, failed, selected, select } = usePreferredMethodSetting({
2676
+ client,
2677
+ onChanged
2678
+ });
2679
+ const options = react.useMemo(
2680
+ () => [
2681
+ { value: null, key: NO_PREFERENCE, label: labels.noPreference },
2682
+ ...availableMethods.map((method) => ({
2683
+ value: method,
2684
+ key: method,
2685
+ label: methodDisplayName(method, labels)
2686
+ }))
2687
+ ],
2688
+ [availableMethods, labels]
2689
+ );
2690
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2691
+ reactNative.View,
2692
+ {
2693
+ style: styles3.card,
2694
+ testID: withTestIdPrefix(AuthTestIds.preferredMethodSettings, testIdPrefix),
2695
+ children: [
2696
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.title, children: labels.title }),
2697
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.subtitle, children: labels.description }),
2698
+ loading ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { color: theme.colors.primary, size: "small" }) : options.map((option) => {
2699
+ const isSelected = option.value === selected;
2700
+ const optionTestId = `${withTestIdPrefix(
2701
+ AuthTestIds.preferredMethodSettingsOption,
2702
+ testIdPrefix
2703
+ )}-${option.key}`;
2704
+ return /* @__PURE__ */ jsxRuntime.jsx(
2705
+ reactNative.TouchableOpacity,
2706
+ {
2707
+ accessibilityHint: labels.description,
2708
+ accessibilityLabel: option.label,
2709
+ accessibilityRole: "radio",
2710
+ accessibilityState: { selected: isSelected },
2711
+ disabled: saving,
2712
+ style: isSelected ? styles3.secondaryButton : styles3.escapeLink,
2713
+ testID: optionTestId,
2714
+ onPress: () => select(option.value),
2715
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: isSelected ? styles3.secondaryButtonText : styles3.linkText, children: isSelected ? `\u2713 ${option.label}` : option.label })
2716
+ },
2717
+ option.key
2718
+ );
2719
+ }),
2720
+ saving ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.helperText, children: labels.saving }) : null,
2721
+ failed ? /* @__PURE__ */ jsxRuntime.jsx(
2722
+ reactNative.Text,
2723
+ {
2724
+ style: styles3.errorText,
2725
+ testID: withTestIdPrefix(AuthTestIds.preferredMethodSettingsError, testIdPrefix),
2726
+ children: labels.saveFailed
2727
+ }
2728
+ ) : null
2729
+ ]
2730
+ }
2731
+ );
2732
+ }
2733
+ function hintFor(method, labels) {
2734
+ if (method === "password") {
2735
+ return labels.password;
2736
+ }
2737
+ if (method === "pin") {
2738
+ return labels.pin;
2739
+ }
2740
+ if (method === "passkey") {
2741
+ return labels.passkey;
2742
+ }
2743
+ return null;
2744
+ }
2745
+ function PreferredMethodHint({
2746
+ method,
2747
+ theme: themeProp,
2748
+ labels: labelsProp,
2749
+ testIdPrefix
2750
+ }) {
2751
+ const theme = useAuthTheme(themeProp);
2752
+ const styles3 = useAuthStyles(theme);
2753
+ const labels = react.useMemo(
2754
+ () => ({ ...DEFAULT_PREFERRED_METHOD_HINT_LABELS, ...labelsProp }),
2755
+ [labelsProp]
2756
+ );
2757
+ const text = hintFor(method, labels);
2758
+ if (text === null) {
2759
+ return null;
2760
+ }
2761
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { testID: withTestIdPrefix(AuthTestIds.preferredMethodHint, testIdPrefix), children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.helperText, children: text }) });
2762
+ }
2763
+ var EMPTY_CONFIG = {
2764
+ methods: [],
2765
+ registrationEnabled: false,
2766
+ deviceState: {
2767
+ rememberedUsername: null,
2768
+ hasPin: false,
2769
+ pinDigits: null,
2770
+ preferredMethod: null
2771
+ }
2772
+ };
2773
+ function useBffLoginConfig(client) {
2774
+ const [config, setConfig] = react.useState(EMPTY_CONFIG);
2775
+ const [loading, setLoading] = react.useState(true);
2776
+ react.useEffect(() => {
2777
+ let active = true;
2778
+ client.getLoginConfig().then((next) => {
2779
+ if (active) {
2780
+ setConfig(next);
2781
+ }
2782
+ }).catch(() => {
2783
+ if (active) {
2784
+ setConfig(EMPTY_CONFIG);
2785
+ }
2786
+ }).finally(() => {
2787
+ if (active) {
2788
+ setLoading(false);
2789
+ }
2790
+ });
2791
+ return () => {
2792
+ active = false;
2793
+ };
2794
+ }, [client]);
2795
+ return { config, loading };
2796
+ }
2797
+
2798
+ // src/preferences/preferencesClient.ts
2799
+ var CSRF_HEADER = "X-BFF-Csrf";
2800
+ var CSRF_HEADER_VALUE = "1";
2801
+ var JSON_CONTENT_TYPE = "application/json";
2802
+ var DEFAULT_TENANTS_SEGMENT = "tenants";
2803
+ var PREFERENCES_PATH = "api/v1/me/preferences";
2804
+ var LOGIN_METHOD_PREFERENCE_PATH = "api/v1/me/login-method-preference";
2805
+ function isRecord(value) {
2806
+ return typeof value === "object" && value !== null;
2807
+ }
2808
+ function readOptionalString(record, key) {
2809
+ const value = record[key];
2810
+ if (typeof value !== "string" || value === "") {
2811
+ return null;
2812
+ }
2813
+ return value;
2814
+ }
2815
+ function createPreferencesClient(options) {
2816
+ const http = options.http;
2817
+ const baseUrl = (options.baseUrl ?? "").replace(/\/$/, "");
2818
+ const segment = options.tenantsSegment ?? DEFAULT_TENANTS_SEGMENT;
2819
+ const proxyBase = `${baseUrl}/bff/api/${segment}`;
2820
+ return {
2821
+ async getPreferredLoginMethod() {
2822
+ try {
2823
+ const response = await http({
2824
+ url: `${proxyBase}/${PREFERENCES_PATH}`,
2825
+ method: "GET",
2826
+ headers: { Accept: JSON_CONTENT_TYPE },
2827
+ credentials: "include"
2828
+ });
2829
+ if (!response.ok || !isRecord(response.data)) {
2830
+ return null;
2831
+ }
2832
+ return readOptionalString(response.data, "preferredLoginMethod");
2833
+ } catch {
2834
+ return null;
2835
+ }
2836
+ },
2837
+ async setPreferredLoginMethod(method) {
2838
+ try {
2839
+ const response = await http({
2840
+ url: `${proxyBase}/${LOGIN_METHOD_PREFERENCE_PATH}`,
2841
+ method: "PUT",
2842
+ headers: {
2843
+ "Content-Type": JSON_CONTENT_TYPE,
2844
+ Accept: JSON_CONTENT_TYPE,
2845
+ [CSRF_HEADER]: CSRF_HEADER_VALUE
2846
+ },
2847
+ body: JSON.stringify({ method }),
2848
+ credentials: "include"
2849
+ });
2850
+ return response.ok;
2851
+ } catch {
2852
+ return false;
2853
+ }
2854
+ }
2855
+ };
2856
+ }
2857
+
2858
+ // src/preferences/syncPreferredMethodCache.ts
2859
+ async function syncPreferredMethodFromServer(client) {
2860
+ try {
2861
+ const method = await client.getPreferredLoginMethod();
2862
+ cachePreferredMethod(method);
2863
+ return method;
2864
+ } catch {
2865
+ return null;
2866
+ }
2867
+ }
1528
2868
  async function lazyFetchHttpClient(request) {
1529
2869
  const fetchImpl = typeof fetch === "function" ? fetch.bind(globalThis) : void 0;
1530
2870
  if (fetchImpl === void 0) {
@@ -1540,11 +2880,11 @@ function createBffAuthClient(options = {}) {
1540
2880
  }
1541
2881
 
1542
2882
  // src/router/resolvePostLoginRoute.ts
1543
- function isRecord(value) {
2883
+ function isRecord2(value) {
1544
2884
  return typeof value === "object" && value !== null;
1545
2885
  }
1546
2886
  function readRealmAccessRoles(realmAccess) {
1547
- if (!isRecord(realmAccess)) {
2887
+ if (!isRecord2(realmAccess)) {
1548
2888
  return [];
1549
2889
  }
1550
2890
  const roles = realmAccess.roles;
@@ -1579,12 +2919,29 @@ Object.defineProperty(exports, "createFetchHttpClient", {
1579
2919
  exports.AuthTestIds = AuthTestIds;
1580
2920
  exports.AuthThemeProvider = AuthThemeProvider;
1581
2921
  exports.BffAuthStatus = BffAuthStatus;
2922
+ exports.DEFAULT_DEVICE_PIN_ENROLL_LABELS = DEFAULT_DEVICE_PIN_ENROLL_LABELS;
2923
+ exports.DEFAULT_DEVICE_PIN_SETTINGS_LABELS = DEFAULT_DEVICE_PIN_SETTINGS_LABELS;
2924
+ exports.DEFAULT_DEVICE_PIN_UNLOCK_LABELS = DEFAULT_DEVICE_PIN_UNLOCK_LABELS;
1582
2925
  exports.DEFAULT_FORGOT_PASSWORD_FIELDS_LABELS = DEFAULT_FORGOT_PASSWORD_FIELDS_LABELS;
1583
2926
  exports.DEFAULT_FORGOT_PASSWORD_LABELS = DEFAULT_FORGOT_PASSWORD_LABELS;
1584
2927
  exports.DEFAULT_LOGIN_LABELS = DEFAULT_LOGIN_LABELS;
1585
2928
  exports.DEFAULT_OTP_LABELS = DEFAULT_OTP_LABELS;
2929
+ exports.DEFAULT_PASSKEY_LOGIN_LABELS = DEFAULT_PASSKEY_LOGIN_LABELS;
2930
+ exports.DEFAULT_PASSKEY_SETTINGS_LABELS = DEFAULT_PASSKEY_SETTINGS_LABELS;
1586
2931
  exports.DEFAULT_PIN_LABELS = DEFAULT_PIN_LABELS;
2932
+ exports.DEFAULT_PREFERRED_METHOD_HINT_LABELS = DEFAULT_PREFERRED_METHOD_HINT_LABELS;
2933
+ exports.DEFAULT_PREFERRED_METHOD_SETTINGS_LABELS = DEFAULT_PREFERRED_METHOD_SETTINGS_LABELS;
1587
2934
  exports.DEFAULT_RESET_PASSWORD_LABELS = DEFAULT_RESET_PASSWORD_LABELS;
2935
+ exports.DEVICE_PIN_ALLOWED_DIGITS = DEVICE_PIN_ALLOWED_DIGITS;
2936
+ exports.DEVICE_PIN_DEFAULT_DIGITS = DEVICE_PIN_DEFAULT_DIGITS;
2937
+ exports.DevicePinEnrollErrorKey = DevicePinEnrollErrorKey;
2938
+ exports.DevicePinEnrollForm = DevicePinEnrollForm;
2939
+ exports.DevicePinErrorKey = DevicePinErrorKey;
2940
+ exports.DevicePinInput = DevicePinInput;
2941
+ exports.DevicePinLengthPicker = DevicePinLengthPicker;
2942
+ exports.DevicePinOffer = DevicePinOffer;
2943
+ exports.DevicePinSettingsCard = DevicePinSettingsCard;
2944
+ exports.DevicePinUnlockScreen = DevicePinUnlockScreen;
1588
2945
  exports.ForgotPasswordFields = ForgotPasswordFields;
1589
2946
  exports.ForgotPasswordForm = ForgotPasswordForm;
1590
2947
  exports.LoginForm = LoginForm;
@@ -1592,23 +2949,42 @@ exports.OtpForm = OtpForm;
1592
2949
  exports.OtpLoginStep = OtpLoginStep;
1593
2950
  exports.PASSWORD_MAX_LENGTH = PASSWORD_MAX_LENGTH;
1594
2951
  exports.PASSWORD_MIN_LENGTH = PASSWORD_MIN_LENGTH;
2952
+ exports.PasskeyLoginButton = PasskeyLoginButton;
2953
+ exports.PasskeySettingsCard = PasskeySettingsCard;
1595
2954
  exports.PasswordPolicyError = PasswordPolicyError;
1596
2955
  exports.PinForm = PinForm;
2956
+ exports.PreferredMethodHint = PreferredMethodHint;
2957
+ exports.PreferredMethodSettingsCard = PreferredMethodSettingsCard;
1597
2958
  exports.ResetPasswordError = ResetPasswordError;
1598
2959
  exports.ResetPasswordForm = ResetPasswordForm;
2960
+ exports.cachePreferredMethod = cachePreferredMethod;
2961
+ exports.clearCachedPreferredMethod = clearCachedPreferredMethod;
1599
2962
  exports.collectUserRoles = collectUserRoles;
1600
2963
  exports.createBffAuthClient = createBffAuthClient;
2964
+ exports.createPreferencesClient = createPreferencesClient;
1601
2965
  exports.defaultAuthTheme = defaultAuthTheme;
2966
+ exports.isAllowedPinDigits = isAllowedPinDigits;
1602
2967
  exports.isPasswordValid = isPasswordValid;
1603
2968
  exports.isValidForgotPasswordEmail = isValidForgotPasswordEmail;
2969
+ exports.readCachedPreferredMethod = readCachedPreferredMethod;
2970
+ exports.readPasskeyError = readPasskeyError;
2971
+ exports.readPasskeyRegistered = readPasskeyRegistered;
1604
2972
  exports.resolvePostLoginRoute = resolvePostLoginRoute;
2973
+ exports.startPasskeyLogin = startPasskeyLogin;
2974
+ exports.startPasskeyRegistration = startPasskeyRegistration;
2975
+ exports.syncPreferredMethodFromServer = syncPreferredMethodFromServer;
1605
2976
  exports.useAuthTheme = useAuthTheme;
1606
2977
  exports.useBffAuth = useBffAuth;
1607
2978
  exports.useBffForgotPassword = useBffForgotPassword;
2979
+ exports.useBffLoginConfig = useBffLoginConfig;
1608
2980
  exports.useBffResetPassword = useBffResetPassword;
2981
+ exports.useDevicePinDisable = useDevicePinDisable;
2982
+ exports.useDevicePinEnroll = useDevicePinEnroll;
2983
+ exports.useDevicePinUnlock = useDevicePinUnlock;
1609
2984
  exports.useForgotPasswordSubmit = useForgotPasswordSubmit;
1610
2985
  exports.useOtpLogin = useOtpLogin;
1611
2986
  exports.usePinLogin = usePinLogin;
2987
+ exports.usePreferredMethodSetting = usePreferredMethodSetting;
1612
2988
  exports.useResetPasswordForm = useResetPasswordForm;
1613
2989
  exports.validatePasswordPolicy = validatePasswordPolicy;
1614
2990
  exports.withTestIdPrefix = withTestIdPrefix;