@dloizides/auth-web 1.2.2 → 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.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { createContext, useState, useRef, useEffect, useCallback, useMemo, useContext } from 'react';
2
- import { View, Text, TextInput, TouchableOpacity, ActivityIndicator, StyleSheet } from 'react-native';
2
+ import { StyleSheet, View, Text, TextInput, TouchableOpacity, ActivityIndicator, Pressable } from 'react-native';
3
3
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
4
4
  import { useMutation } from '@tanstack/react-query';
5
5
  import { BffAuthClient, createFetchHttpClient } from '@dloizides/auth-client';
@@ -33,6 +33,11 @@ var DEFAULT_FORGOT_PASSWORD_LABELS = {
33
33
  networkError: "Something went wrong. Please try again.",
34
34
  invalidEmail: "Enter a valid email address."
35
35
  };
36
+ var DEFAULT_FORGOT_PASSWORD_FIELDS_LABELS = {
37
+ ...DEFAULT_FORGOT_PASSWORD_LABELS,
38
+ cancel: "Cancel",
39
+ close: "Close"
40
+ };
36
41
  var DEFAULT_OTP_LABELS = {
37
42
  requestTitle: "Sign in with a code",
38
43
  requestDescription: "Enter your email and we will send you a one-time code.",
@@ -63,6 +68,77 @@ var DEFAULT_PIN_LABELS = {
63
68
  missingPin: "Enter your event PIN.",
64
69
  invalidPin: "That PIN is incorrect, has expired, or is locked out."
65
70
  };
71
+ var DEFAULT_DEVICE_PIN_UNLOCK_LABELS = {
72
+ title: "Welcome back, {name}",
73
+ titleNoName: "Welcome back",
74
+ description: "Enter your {count}-digit PIN to sign in on this device.",
75
+ pinLabel: "PIN",
76
+ pinPlaceholder: "Enter your PIN",
77
+ submit: "Unlock",
78
+ submitting: "Signing in...",
79
+ usePasswordInstead: "Sign in with password instead",
80
+ usePasswordHint: "Switch to signing in with your username and password",
81
+ errorIncomplete: "Enter all {count} digits of your PIN.",
82
+ errorInvalid: "That PIN is incorrect. Try again.",
83
+ errorLockedOut: "Too many attempts. Try again later.",
84
+ errorLockedOutRetry: "Too many attempts. Try again in {count} seconds.",
85
+ errorRateLimited: "Too many requests. Try again later.",
86
+ errorRateLimitedRetry: "Too many requests. Try again in {count} seconds.",
87
+ errorGeneric: "Something went wrong. Try again, or sign in with your password.",
88
+ digitFilledHint: "PIN digit entered",
89
+ digitEmptyHint: "PIN digit not yet entered"
90
+ };
91
+ var DEFAULT_DEVICE_PIN_ENROLL_LABELS = {
92
+ offerTitle: "Set a PIN for faster sign-in?",
93
+ offerDescription: "Next time, sign in on this device with a short PIN instead of your full password.",
94
+ offerAccept: "Set up a PIN",
95
+ offerAcceptHint: "Open the form to choose a quick sign-in PIN",
96
+ offerSkip: "Not now",
97
+ offerSkipHint: "Dismiss the PIN setup offer",
98
+ formTitle: "Choose your PIN",
99
+ formDescription: "Pick a {count}-digit PIN you will remember. You will use it to sign in on this device.",
100
+ lengthLabel: "PIN length",
101
+ lengthOptionHint: "Use a {count}-digit PIN",
102
+ pinLabel: "New PIN",
103
+ pinPlaceholder: "Enter a new PIN",
104
+ confirmLabel: "Confirm PIN",
105
+ confirmPlaceholder: "Re-enter your PIN",
106
+ submit: "Save PIN",
107
+ submitting: "Saving...",
108
+ cancel: "Cancel",
109
+ cancelHint: "Close the PIN setup form without saving",
110
+ errorMismatch: "The PINs must match and be exactly {count} digits.",
111
+ errorUnauthorized: "Your session has expired. Sign in again to set a PIN.",
112
+ errorForbidden: "A PIN is already set for this session.",
113
+ errorInvalidPin: "That PIN is not allowed. Choose a different one.",
114
+ errorFailed: "Could not set your PIN. Try again later."
115
+ };
116
+ var DEFAULT_DEVICE_PIN_SETTINGS_LABELS = {
117
+ title: "Quick PIN sign-in",
118
+ description: "Sign in on this device with a short PIN instead of your full password.",
119
+ statusEnabled: "Quick PIN sign-in is enabled on this device.",
120
+ statusDisabled: "Quick PIN sign-in is off.",
121
+ enable: "Enable quick PIN sign-in",
122
+ enableHint: "Set a PIN so you can sign in faster on this device",
123
+ disable: "Disable",
124
+ disableHint: "Remove the PIN sign-in from this device",
125
+ disabling: "Disabling...",
126
+ disableFailed: "Could not disable PIN sign-in. Try again later."
127
+ };
128
+ var DEFAULT_PASSKEY_LOGIN_LABELS = {
129
+ signInButton: "Sign in with a passkey",
130
+ signInHint: "Use your fingerprint, face, or security key to sign in",
131
+ errorCancelled: "Passkey sign-in was cancelled. You can try again or sign in another way.",
132
+ errorFailed: "Passkey sign-in didn't work. Try again, or sign in another way."
133
+ };
134
+ var DEFAULT_PASSKEY_SETTINGS_LABELS = {
135
+ title: "Passkeys",
136
+ description: "Add a passkey to sign in with your fingerprint, face, or a security key instead of a password.",
137
+ reauthHint: "You'll be asked to confirm your password before adding a passkey.",
138
+ addButton: "Add a passkey",
139
+ addHint: "Start setting up a passkey for this account",
140
+ registeredSuccess: "Your passkey was added. You can now use it to sign in."
141
+ };
66
142
  var DEFAULT_RESET_PASSWORD_LABELS = {
67
143
  title: "Reset password",
68
144
  description: "Choose a new password for your account.",
@@ -91,6 +167,8 @@ var AuthTestIds = {
91
167
  forgotPasswordForm: "auth-forgot-form",
92
168
  forgotPasswordEmailInput: "auth-forgot-email",
93
169
  forgotPasswordSubmitButton: "auth-forgot-submit",
170
+ forgotPasswordCancelButton: "auth-forgot-cancel",
171
+ forgotPasswordCloseButton: "auth-forgot-close",
94
172
  forgotPasswordError: "auth-forgot-error",
95
173
  forgotPasswordSuccess: "auth-forgot-success",
96
174
  resetPasswordForm: "auth-reset-form",
@@ -109,7 +187,39 @@ var AuthTestIds = {
109
187
  pinForm: "auth-pin-form",
110
188
  pinInput: "auth-pin-input",
111
189
  pinSubmitButton: "auth-pin-submit",
112
- pinError: "auth-pin-error"
190
+ pinError: "auth-pin-error",
191
+ // Device-PIN unlock gate
192
+ devicePinUnlock: "auth-device-pin-unlock",
193
+ devicePinUnlockInput: "auth-device-pin-unlock-input",
194
+ devicePinUnlockSubmit: "auth-device-pin-unlock-submit",
195
+ devicePinUnlockUsePassword: "auth-device-pin-unlock-use-password",
196
+ devicePinUnlockError: "auth-device-pin-unlock-error",
197
+ // Device-PIN enrol form + length picker
198
+ devicePinEnrollForm: "auth-device-pin-enroll-form",
199
+ devicePinEnrollLength: "auth-device-pin-enroll-length",
200
+ devicePinEnrollPin: "auth-device-pin-enroll-pin",
201
+ devicePinEnrollConfirm: "auth-device-pin-enroll-confirm",
202
+ devicePinEnrollSubmit: "auth-device-pin-enroll-submit",
203
+ devicePinEnrollCancel: "auth-device-pin-enroll-cancel",
204
+ devicePinEnrollError: "auth-device-pin-enroll-error",
205
+ // Device-PIN offer (post-login)
206
+ devicePinOffer: "auth-device-pin-offer",
207
+ devicePinOfferAccept: "auth-device-pin-offer-accept",
208
+ devicePinOfferSkip: "auth-device-pin-offer-skip",
209
+ // Device-PIN settings card
210
+ devicePinSettings: "auth-device-pin-settings",
211
+ devicePinSettingsStatus: "auth-device-pin-settings-status",
212
+ devicePinSettingsEnable: "auth-device-pin-settings-enable",
213
+ devicePinSettingsDisable: "auth-device-pin-settings-disable",
214
+ devicePinSettingsError: "auth-device-pin-settings-error",
215
+ // Passkey login button
216
+ passkeyLogin: "auth-passkey-login",
217
+ passkeyLoginButton: "auth-passkey-login-button",
218
+ passkeyLoginError: "auth-passkey-login-error",
219
+ // Passkey settings card
220
+ passkeySettings: "auth-passkey-settings",
221
+ passkeySettingsAdd: "auth-passkey-settings-add",
222
+ passkeySettingsSuccess: "auth-passkey-settings-success"
113
223
  };
114
224
  function withTestIdPrefix(baseId, prefix) {
115
225
  return prefix === void 0 || prefix === "" ? baseId : `${prefix}-${baseId}`;
@@ -203,6 +313,32 @@ function useAuthStyles(theme) {
203
313
  helperText: {
204
314
  fontSize: typography.caption,
205
315
  color: colors.textSecondary
316
+ },
317
+ escapeLink: {
318
+ alignSelf: "center",
319
+ marginTop: spacing.md,
320
+ paddingVertical: spacing.xs / 2
321
+ },
322
+ secondaryButton: {
323
+ borderRadius: radii.input,
324
+ borderWidth: 1,
325
+ borderColor: colors.primary,
326
+ paddingVertical: BUTTON_VERTICAL_PADDING,
327
+ alignItems: "center",
328
+ justifyContent: "center",
329
+ marginTop: spacing.sm,
330
+ backgroundColor: colors.surface
331
+ },
332
+ secondaryButtonText: {
333
+ fontSize: typography.body,
334
+ fontWeight: "600",
335
+ color: colors.primary
336
+ },
337
+ statusText: {
338
+ fontSize: typography.label,
339
+ fontWeight: "600",
340
+ marginTop: spacing.sm,
341
+ color: colors.text
206
342
  }
207
343
  });
208
344
  }, [theme]);
@@ -364,7 +500,7 @@ function LoginForm({
364
500
  testIdPrefix
365
501
  }) {
366
502
  const theme = useAuthTheme(themeProp);
367
- const styles = useAuthStyles(theme);
503
+ const styles3 = useAuthStyles(theme);
368
504
  const labels = useMemo(
369
505
  () => ({ ...DEFAULT_LOGIN_LABELS, ...labelsProp }),
370
506
  [labelsProp]
@@ -391,12 +527,12 @@ function LoginForm({
391
527
  const handleSubmit = useCallback(() => {
392
528
  void runLogin();
393
529
  }, [runLogin]);
394
- const submitButtonStyle = isSubmitting ? [styles.primaryButton, styles.primaryButtonDisabled] : styles.primaryButton;
395
- return /* @__PURE__ */ jsx(View, { style: styles.screen, children: /* @__PURE__ */ jsxs(View, { style: styles.card, testID: withTestIdPrefix(AuthTestIds.loginForm, testIdPrefix), children: [
396
- /* @__PURE__ */ jsx(Text, { style: styles.title, children: labels.title }),
397
- /* @__PURE__ */ jsx(Text, { style: styles.subtitle, children: labels.subtitle }),
398
- /* @__PURE__ */ jsxs(View, { style: styles.fieldGroup, children: [
399
- /* @__PURE__ */ jsx(Text, { style: styles.label, children: labels.usernameLabel }),
530
+ const submitButtonStyle = isSubmitting ? [styles3.primaryButton, styles3.primaryButtonDisabled] : styles3.primaryButton;
531
+ return /* @__PURE__ */ jsx(View, { style: styles3.screen, children: /* @__PURE__ */ jsxs(View, { style: styles3.card, testID: withTestIdPrefix(AuthTestIds.loginForm, testIdPrefix), children: [
532
+ /* @__PURE__ */ jsx(Text, { style: styles3.title, children: labels.title }),
533
+ /* @__PURE__ */ jsx(Text, { style: styles3.subtitle, children: labels.subtitle }),
534
+ /* @__PURE__ */ jsxs(View, { style: styles3.fieldGroup, children: [
535
+ /* @__PURE__ */ jsx(Text, { style: styles3.label, children: labels.usernameLabel }),
400
536
  /* @__PURE__ */ jsx(
401
537
  TextInput,
402
538
  {
@@ -407,15 +543,15 @@ function LoginForm({
407
543
  editable: !isSubmitting,
408
544
  placeholder: labels.usernamePlaceholder,
409
545
  placeholderTextColor: theme.colors.textSecondary,
410
- style: styles.input,
546
+ style: styles3.input,
411
547
  testID: withTestIdPrefix(AuthTestIds.loginUsernameInput, testIdPrefix),
412
548
  value: username,
413
549
  onChangeText: setUsername
414
550
  }
415
551
  )
416
552
  ] }),
417
- /* @__PURE__ */ jsxs(View, { style: styles.fieldGroup, children: [
418
- /* @__PURE__ */ jsx(Text, { style: styles.label, children: labels.passwordLabel }),
553
+ /* @__PURE__ */ jsxs(View, { style: styles3.fieldGroup, children: [
554
+ /* @__PURE__ */ jsx(Text, { style: styles3.label, children: labels.passwordLabel }),
419
555
  /* @__PURE__ */ jsx(
420
556
  TextInput,
421
557
  {
@@ -427,7 +563,7 @@ function LoginForm({
427
563
  editable: !isSubmitting,
428
564
  placeholder: labels.passwordPlaceholder,
429
565
  placeholderTextColor: theme.colors.textSecondary,
430
- style: styles.input,
566
+ style: styles3.input,
431
567
  testID: withTestIdPrefix(AuthTestIds.loginPasswordInput, testIdPrefix),
432
568
  value: password,
433
569
  onChangeText: setPassword
@@ -437,7 +573,7 @@ function LoginForm({
437
573
  errorText !== null ? /* @__PURE__ */ jsx(
438
574
  Text,
439
575
  {
440
- style: styles.errorText,
576
+ style: styles3.errorText,
441
577
  testID: withTestIdPrefix(AuthTestIds.loginError, testIdPrefix),
442
578
  children: errorText
443
579
  }
@@ -449,10 +585,10 @@ function LoginForm({
449
585
  accessibilityLabel: labels.forgotPassword,
450
586
  accessibilityRole: "link",
451
587
  disabled: isSubmitting,
452
- style: styles.fieldGroup,
588
+ style: styles3.fieldGroup,
453
589
  testID: withTestIdPrefix(AuthTestIds.loginForgotLink, testIdPrefix),
454
590
  onPress: onForgotPassword,
455
- children: /* @__PURE__ */ jsx(Text, { style: styles.linkText, children: labels.forgotPassword })
591
+ children: /* @__PURE__ */ jsx(Text, { style: styles3.linkText, children: labels.forgotPassword })
456
592
  }
457
593
  ) : null,
458
594
  /* @__PURE__ */ jsx(
@@ -465,7 +601,7 @@ function LoginForm({
465
601
  style: submitButtonStyle,
466
602
  testID: withTestIdPrefix(AuthTestIds.loginSubmitButton, testIdPrefix),
467
603
  onPress: handleSubmit,
468
- children: isSubmitting ? /* @__PURE__ */ jsx(ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsx(Text, { style: styles.primaryButtonText, children: labels.submit })
604
+ children: isSubmitting ? /* @__PURE__ */ jsx(ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsx(Text, { style: styles3.primaryButtonText, children: labels.submit })
469
605
  }
470
606
  ),
471
607
  onSignUp !== void 0 ? /* @__PURE__ */ jsx(
@@ -475,10 +611,10 @@ function LoginForm({
475
611
  accessibilityLabel: labels.signUp,
476
612
  accessibilityRole: "link",
477
613
  disabled: isSubmitting,
478
- style: styles.fieldGroup,
614
+ style: styles3.fieldGroup,
479
615
  testID: withTestIdPrefix(AuthTestIds.loginSignUpLink, testIdPrefix),
480
616
  onPress: onSignUp,
481
- children: /* @__PURE__ */ jsx(Text, { style: styles.linkText, children: labels.signUp })
617
+ children: /* @__PURE__ */ jsx(Text, { style: styles3.linkText, children: labels.signUp })
482
618
  }
483
619
  ) : null
484
620
  ] }) });
@@ -516,7 +652,7 @@ function ForgotPasswordForm({
516
652
  testIdPrefix
517
653
  }) {
518
654
  const theme = useAuthTheme(themeProp);
519
- const styles = useAuthStyles(theme);
655
+ const styles3 = useAuthStyles(theme);
520
656
  const labels = useMemo(
521
657
  () => ({ ...DEFAULT_FORGOT_PASSWORD_LABELS, ...labelsProp }),
522
658
  [labelsProp]
@@ -548,25 +684,25 @@ function ForgotPasswordForm({
548
684
  }
549
685
  mutation.mutate({ email: trimmedEmail, resetUrlTemplate });
550
686
  }, [email, mutation, resetUrlTemplate, labels.invalidEmail]);
551
- const submitButtonStyle = isPending ? [styles.primaryButton, styles.primaryButtonDisabled] : styles.primaryButton;
552
- return /* @__PURE__ */ jsx(View, { style: styles.screen, children: /* @__PURE__ */ jsxs(
687
+ const submitButtonStyle = isPending ? [styles3.primaryButton, styles3.primaryButtonDisabled] : styles3.primaryButton;
688
+ return /* @__PURE__ */ jsx(View, { style: styles3.screen, children: /* @__PURE__ */ jsxs(
553
689
  View,
554
690
  {
555
- style: styles.card,
691
+ style: styles3.card,
556
692
  testID: withTestIdPrefix(AuthTestIds.forgotPasswordForm, testIdPrefix),
557
693
  children: [
558
- /* @__PURE__ */ jsx(Text, { style: styles.title, children: labels.title }),
694
+ /* @__PURE__ */ jsx(Text, { style: styles3.title, children: labels.title }),
559
695
  submitted ? /* @__PURE__ */ jsx(
560
696
  Text,
561
697
  {
562
- style: styles.successText,
698
+ style: styles3.successText,
563
699
  testID: withTestIdPrefix(AuthTestIds.forgotPasswordSuccess, testIdPrefix),
564
700
  children: labels.successMessage
565
701
  }
566
702
  ) : /* @__PURE__ */ jsxs(Fragment, { children: [
567
- /* @__PURE__ */ jsx(Text, { style: styles.subtitle, children: labels.description }),
568
- /* @__PURE__ */ jsxs(View, { style: styles.fieldGroup, children: [
569
- /* @__PURE__ */ jsx(Text, { style: styles.label, children: labels.emailLabel }),
703
+ /* @__PURE__ */ jsx(Text, { style: styles3.subtitle, children: labels.description }),
704
+ /* @__PURE__ */ jsxs(View, { style: styles3.fieldGroup, children: [
705
+ /* @__PURE__ */ jsx(Text, { style: styles3.label, children: labels.emailLabel }),
570
706
  /* @__PURE__ */ jsx(
571
707
  TextInput,
572
708
  {
@@ -578,7 +714,7 @@ function ForgotPasswordForm({
578
714
  keyboardType: "email-address",
579
715
  placeholder: labels.emailPlaceholder,
580
716
  placeholderTextColor: theme.colors.textSecondary,
581
- style: styles.input,
717
+ style: styles3.input,
582
718
  testID: withTestIdPrefix(AuthTestIds.forgotPasswordEmailInput, testIdPrefix),
583
719
  value: email,
584
720
  onChangeText: setEmail
@@ -588,7 +724,7 @@ function ForgotPasswordForm({
588
724
  errorText !== null ? /* @__PURE__ */ jsx(
589
725
  Text,
590
726
  {
591
- style: styles.errorText,
727
+ style: styles3.errorText,
592
728
  testID: withTestIdPrefix(AuthTestIds.forgotPasswordError, testIdPrefix),
593
729
  children: errorText
594
730
  }
@@ -603,7 +739,7 @@ function ForgotPasswordForm({
603
739
  style: submitButtonStyle,
604
740
  testID: withTestIdPrefix(AuthTestIds.forgotPasswordSubmitButton, testIdPrefix),
605
741
  onPress: handleSubmit,
606
- children: isPending ? /* @__PURE__ */ jsx(ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsx(Text, { style: styles.primaryButtonText, children: labels.submit })
742
+ children: isPending ? /* @__PURE__ */ jsx(ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsx(Text, { style: styles3.primaryButtonText, children: labels.submit })
607
743
  }
608
744
  )
609
745
  ] })
@@ -611,6 +747,182 @@ function ForgotPasswordForm({
611
747
  }
612
748
  ) });
613
749
  }
750
+ var EMAIL_REGEX2 = /^[^@\s]+@[^.\s]+\.[^\s]+$/;
751
+ function isValidForgotPasswordEmail(value) {
752
+ return EMAIL_REGEX2.test(value.trim());
753
+ }
754
+ function useForgotPasswordSubmit({
755
+ client,
756
+ resetUrlTemplate,
757
+ onSuccess
758
+ }) {
759
+ const [email, setEmail] = useState("");
760
+ const [submitted, setSubmitted] = useState(false);
761
+ const [isSubmitting, setIsSubmitting] = useState(false);
762
+ const [hasNetworkError, setHasNetworkError] = useState(false);
763
+ const canSubmit = isValidForgotPasswordEmail(email) && !isSubmitting;
764
+ const submit = useCallback(() => {
765
+ const target = email.trim();
766
+ if (!isValidForgotPasswordEmail(target) || isSubmitting) {
767
+ return;
768
+ }
769
+ setHasNetworkError(false);
770
+ setIsSubmitting(true);
771
+ const request = { email: target, resetUrlTemplate };
772
+ client.forgotPassword(request).then(() => {
773
+ setSubmitted(true);
774
+ onSuccess?.();
775
+ }).catch(() => setHasNetworkError(true)).finally(() => setIsSubmitting(false));
776
+ }, [client, email, isSubmitting, resetUrlTemplate, onSuccess]);
777
+ const reset = useCallback(() => {
778
+ setEmail("");
779
+ setSubmitted(false);
780
+ setIsSubmitting(false);
781
+ setHasNetworkError(false);
782
+ }, []);
783
+ return {
784
+ email,
785
+ setEmail,
786
+ submitted,
787
+ isSubmitting,
788
+ hasNetworkError,
789
+ canSubmit,
790
+ submit,
791
+ reset
792
+ };
793
+ }
794
+ var SECONDARY_BORDER_WIDTH = 1;
795
+ function useModalStyles(theme) {
796
+ return useMemo(
797
+ () => StyleSheet.create({
798
+ body: { padding: theme.spacing.md },
799
+ actions: {
800
+ flexDirection: "row",
801
+ justifyContent: "flex-end",
802
+ alignItems: "center",
803
+ marginTop: theme.spacing.md,
804
+ gap: theme.spacing.sm
805
+ },
806
+ secondaryButton: {
807
+ borderRadius: theme.radii.input,
808
+ paddingVertical: theme.spacing.sm,
809
+ paddingHorizontal: theme.spacing.md,
810
+ borderWidth: SECONDARY_BORDER_WIDTH,
811
+ borderColor: theme.colors.border
812
+ },
813
+ secondaryButtonText: {
814
+ fontSize: theme.typography.body,
815
+ fontWeight: "600",
816
+ color: theme.colors.text
817
+ }
818
+ }),
819
+ [theme]
820
+ );
821
+ }
822
+ function ForgotPasswordFields({
823
+ client,
824
+ theme: themeProp,
825
+ labels: labelsProp,
826
+ resetUrlTemplate,
827
+ visible = true,
828
+ onSuccess,
829
+ onCancel,
830
+ onClose,
831
+ testIdPrefix
832
+ }) {
833
+ const theme = useAuthTheme(themeProp);
834
+ const styles3 = useAuthStyles(theme);
835
+ const modalStyles = useModalStyles(theme);
836
+ const labels = useMemo(
837
+ () => ({ ...DEFAULT_FORGOT_PASSWORD_FIELDS_LABELS, ...labelsProp }),
838
+ [labelsProp]
839
+ );
840
+ const form = useForgotPasswordSubmit({ client, resetUrlTemplate, onSuccess });
841
+ const { reset } = form;
842
+ useEffect(() => {
843
+ if (!visible) {
844
+ reset();
845
+ }
846
+ }, [visible, reset]);
847
+ const submitButtonStyle = form.canSubmit ? styles3.primaryButton : [styles3.primaryButton, styles3.primaryButtonDisabled];
848
+ const handleCancel = () => {
849
+ form.reset();
850
+ onCancel?.();
851
+ };
852
+ const handleClose = () => {
853
+ form.reset();
854
+ onClose?.();
855
+ };
856
+ if (form.submitted) {
857
+ return /* @__PURE__ */ jsxs(View, { style: modalStyles.body, testID: withTestIdPrefix(AuthTestIds.forgotPasswordForm, testIdPrefix), children: [
858
+ /* @__PURE__ */ jsx(Text, { style: styles3.successText, testID: withTestIdPrefix(AuthTestIds.forgotPasswordSuccess, testIdPrefix), children: labels.successMessage }),
859
+ onClose !== void 0 ? /* @__PURE__ */ jsx(View, { style: modalStyles.actions, children: /* @__PURE__ */ jsx(
860
+ TouchableOpacity,
861
+ {
862
+ accessibilityHint: labels.close,
863
+ accessibilityLabel: labels.close,
864
+ accessibilityRole: "button",
865
+ style: styles3.primaryButton,
866
+ testID: withTestIdPrefix(AuthTestIds.forgotPasswordCloseButton, testIdPrefix),
867
+ onPress: handleClose,
868
+ children: /* @__PURE__ */ jsx(Text, { style: styles3.primaryButtonText, children: labels.close })
869
+ }
870
+ ) }) : null
871
+ ] });
872
+ }
873
+ return /* @__PURE__ */ jsxs(View, { style: modalStyles.body, testID: withTestIdPrefix(AuthTestIds.forgotPasswordForm, testIdPrefix), children: [
874
+ /* @__PURE__ */ jsx(Text, { style: styles3.subtitle, children: labels.description }),
875
+ /* @__PURE__ */ jsxs(View, { style: styles3.fieldGroup, children: [
876
+ /* @__PURE__ */ jsx(Text, { style: styles3.label, children: labels.emailLabel }),
877
+ /* @__PURE__ */ jsx(
878
+ TextInput,
879
+ {
880
+ accessibilityHint: labels.emailPlaceholder,
881
+ accessibilityLabel: labels.emailLabel,
882
+ autoCapitalize: "none",
883
+ autoCorrect: false,
884
+ editable: !form.isSubmitting,
885
+ keyboardType: "email-address",
886
+ placeholder: labels.emailPlaceholder,
887
+ placeholderTextColor: theme.colors.textSecondary,
888
+ style: styles3.input,
889
+ testID: withTestIdPrefix(AuthTestIds.forgotPasswordEmailInput, testIdPrefix),
890
+ value: form.email,
891
+ onChangeText: form.setEmail
892
+ }
893
+ )
894
+ ] }),
895
+ form.hasNetworkError ? /* @__PURE__ */ jsx(Text, { style: styles3.errorText, testID: withTestIdPrefix(AuthTestIds.forgotPasswordError, testIdPrefix), children: labels.networkError }) : null,
896
+ /* @__PURE__ */ jsxs(View, { style: modalStyles.actions, children: [
897
+ onCancel !== void 0 ? /* @__PURE__ */ jsx(
898
+ TouchableOpacity,
899
+ {
900
+ accessibilityHint: labels.cancel,
901
+ accessibilityLabel: labels.cancel,
902
+ accessibilityRole: "button",
903
+ disabled: form.isSubmitting,
904
+ style: modalStyles.secondaryButton,
905
+ testID: withTestIdPrefix(AuthTestIds.forgotPasswordCancelButton, testIdPrefix),
906
+ onPress: handleCancel,
907
+ children: /* @__PURE__ */ jsx(Text, { style: modalStyles.secondaryButtonText, children: labels.cancel })
908
+ }
909
+ ) : null,
910
+ /* @__PURE__ */ jsx(
911
+ TouchableOpacity,
912
+ {
913
+ accessibilityHint: labels.submit,
914
+ accessibilityLabel: form.isSubmitting ? labels.submitting : labels.submit,
915
+ accessibilityRole: "button",
916
+ disabled: !form.canSubmit,
917
+ style: submitButtonStyle,
918
+ testID: withTestIdPrefix(AuthTestIds.forgotPasswordSubmitButton, testIdPrefix),
919
+ onPress: form.submit,
920
+ children: form.isSubmitting ? /* @__PURE__ */ jsx(ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsx(Text, { style: styles3.primaryButtonText, children: labels.submit })
921
+ }
922
+ )
923
+ ] })
924
+ ] });
925
+ }
614
926
 
615
927
  // src/hooks/ResetPasswordError.ts
616
928
  var ResetPasswordError = /* @__PURE__ */ ((ResetPasswordError2) => {
@@ -784,24 +1096,24 @@ function ResetPasswordForm({
784
1096
  testIdPrefix
785
1097
  }) {
786
1098
  const theme = useAuthTheme(themeProp);
787
- const styles = useAuthStyles(theme);
1099
+ const styles3 = useAuthStyles(theme);
788
1100
  const labels = useMemo(
789
1101
  () => ({ ...DEFAULT_RESET_PASSWORD_LABELS, ...labelsProp }),
790
1102
  [labelsProp]
791
1103
  );
792
1104
  const form = useResetPasswordForm({ client, token, onSuccess });
793
1105
  const message = errorMessage(form.errorKey, labels);
794
- const submitButtonStyle = form.isSubmitting ? [styles.primaryButton, styles.primaryButtonDisabled] : styles.primaryButton;
795
- return /* @__PURE__ */ jsx(View, { style: styles.screen, children: /* @__PURE__ */ jsxs(
1106
+ const submitButtonStyle = form.isSubmitting ? [styles3.primaryButton, styles3.primaryButtonDisabled] : styles3.primaryButton;
1107
+ return /* @__PURE__ */ jsx(View, { style: styles3.screen, children: /* @__PURE__ */ jsxs(
796
1108
  View,
797
1109
  {
798
- style: styles.card,
1110
+ style: styles3.card,
799
1111
  testID: withTestIdPrefix(AuthTestIds.resetPasswordForm, testIdPrefix),
800
1112
  children: [
801
- /* @__PURE__ */ jsx(Text, { style: styles.title, children: labels.title }),
802
- /* @__PURE__ */ jsx(Text, { style: styles.subtitle, children: labels.description }),
803
- /* @__PURE__ */ jsxs(View, { style: styles.fieldGroup, children: [
804
- /* @__PURE__ */ jsx(Text, { style: styles.label, children: labels.newPasswordLabel }),
1113
+ /* @__PURE__ */ jsx(Text, { style: styles3.title, children: labels.title }),
1114
+ /* @__PURE__ */ jsx(Text, { style: styles3.subtitle, children: labels.description }),
1115
+ /* @__PURE__ */ jsxs(View, { style: styles3.fieldGroup, children: [
1116
+ /* @__PURE__ */ jsx(Text, { style: styles3.label, children: labels.newPasswordLabel }),
805
1117
  /* @__PURE__ */ jsx(
806
1118
  TextInput,
807
1119
  {
@@ -813,15 +1125,15 @@ function ResetPasswordForm({
813
1125
  editable: !form.isSubmitting,
814
1126
  placeholder: labels.newPasswordPlaceholder,
815
1127
  placeholderTextColor: theme.colors.textSecondary,
816
- style: styles.input,
1128
+ style: styles3.input,
817
1129
  testID: withTestIdPrefix(AuthTestIds.resetPasswordNewInput, testIdPrefix),
818
1130
  value: form.newPassword,
819
1131
  onChangeText: form.setNewPassword
820
1132
  }
821
1133
  )
822
1134
  ] }),
823
- /* @__PURE__ */ jsxs(View, { style: styles.fieldGroup, children: [
824
- /* @__PURE__ */ jsx(Text, { style: styles.label, children: labels.confirmPasswordLabel }),
1135
+ /* @__PURE__ */ jsxs(View, { style: styles3.fieldGroup, children: [
1136
+ /* @__PURE__ */ jsx(Text, { style: styles3.label, children: labels.confirmPasswordLabel }),
825
1137
  /* @__PURE__ */ jsx(
826
1138
  TextInput,
827
1139
  {
@@ -833,7 +1145,7 @@ function ResetPasswordForm({
833
1145
  editable: !form.isSubmitting,
834
1146
  placeholder: labels.confirmPasswordPlaceholder,
835
1147
  placeholderTextColor: theme.colors.textSecondary,
836
- style: styles.input,
1148
+ style: styles3.input,
837
1149
  testID: withTestIdPrefix(AuthTestIds.resetPasswordConfirmInput, testIdPrefix),
838
1150
  value: form.confirmPassword,
839
1151
  onChangeText: form.setConfirmPassword
@@ -843,7 +1155,7 @@ function ResetPasswordForm({
843
1155
  message !== null ? /* @__PURE__ */ jsx(
844
1156
  Text,
845
1157
  {
846
- style: styles.errorText,
1158
+ style: styles3.errorText,
847
1159
  testID: withTestIdPrefix(AuthTestIds.resetPasswordError, testIdPrefix),
848
1160
  children: message
849
1161
  }
@@ -858,7 +1170,7 @@ function ResetPasswordForm({
858
1170
  style: submitButtonStyle,
859
1171
  testID: withTestIdPrefix(AuthTestIds.resetPasswordSubmitButton, testIdPrefix),
860
1172
  onPress: form.submit,
861
- children: form.isSubmitting ? /* @__PURE__ */ jsx(ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsx(Text, { style: styles.primaryButtonText, children: labels.submit })
1173
+ children: form.isSubmitting ? /* @__PURE__ */ jsx(ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsx(Text, { style: styles3.primaryButtonText, children: labels.submit })
862
1174
  }
863
1175
  )
864
1176
  ]
@@ -866,7 +1178,7 @@ function ResetPasswordForm({
866
1178
  ) });
867
1179
  }
868
1180
  function OtpRequestStep({
869
- styles,
1181
+ styles: styles3,
870
1182
  theme,
871
1183
  labels,
872
1184
  testIdPrefix,
@@ -875,12 +1187,12 @@ function OtpRequestStep({
875
1187
  onSubmit
876
1188
  }) {
877
1189
  const [email, setEmail] = useState("");
878
- const buttonStyle = isSubmitting ? [styles.primaryButton, styles.primaryButtonDisabled] : styles.primaryButton;
1190
+ const buttonStyle = isSubmitting ? [styles3.primaryButton, styles3.primaryButtonDisabled] : styles3.primaryButton;
879
1191
  return /* @__PURE__ */ jsxs(Fragment, { children: [
880
- /* @__PURE__ */ jsx(Text, { style: styles.title, children: labels.requestTitle }),
881
- /* @__PURE__ */ jsx(Text, { style: styles.subtitle, children: labels.requestDescription }),
882
- /* @__PURE__ */ jsxs(View, { style: styles.fieldGroup, children: [
883
- /* @__PURE__ */ jsx(Text, { style: styles.label, children: labels.emailLabel }),
1192
+ /* @__PURE__ */ jsx(Text, { style: styles3.title, children: labels.requestTitle }),
1193
+ /* @__PURE__ */ jsx(Text, { style: styles3.subtitle, children: labels.requestDescription }),
1194
+ /* @__PURE__ */ jsxs(View, { style: styles3.fieldGroup, children: [
1195
+ /* @__PURE__ */ jsx(Text, { style: styles3.label, children: labels.emailLabel }),
884
1196
  /* @__PURE__ */ jsx(
885
1197
  TextInput,
886
1198
  {
@@ -892,14 +1204,14 @@ function OtpRequestStep({
892
1204
  keyboardType: "email-address",
893
1205
  placeholder: labels.emailPlaceholder,
894
1206
  placeholderTextColor: theme.colors.textSecondary,
895
- style: styles.input,
1207
+ style: styles3.input,
896
1208
  testID: withTestIdPrefix(AuthTestIds.otpEmailInput, testIdPrefix),
897
1209
  value: email,
898
1210
  onChangeText: setEmail
899
1211
  }
900
1212
  )
901
1213
  ] }),
902
- errorText !== null ? /* @__PURE__ */ jsx(Text, { style: styles.errorText, testID: withTestIdPrefix(AuthTestIds.otpError, testIdPrefix), children: errorText }) : null,
1214
+ errorText !== null ? /* @__PURE__ */ jsx(Text, { style: styles3.errorText, testID: withTestIdPrefix(AuthTestIds.otpError, testIdPrefix), children: errorText }) : null,
903
1215
  /* @__PURE__ */ jsx(
904
1216
  TouchableOpacity,
905
1217
  {
@@ -910,13 +1222,13 @@ function OtpRequestStep({
910
1222
  style: buttonStyle,
911
1223
  testID: withTestIdPrefix(AuthTestIds.otpRequestButton, testIdPrefix),
912
1224
  onPress: () => onSubmit(email.trim()),
913
- children: isSubmitting ? /* @__PURE__ */ jsx(ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsx(Text, { style: styles.primaryButtonText, children: labels.requestSubmit })
1225
+ children: isSubmitting ? /* @__PURE__ */ jsx(ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsx(Text, { style: styles3.primaryButtonText, children: labels.requestSubmit })
914
1226
  }
915
1227
  )
916
1228
  ] });
917
1229
  }
918
1230
  function OtpVerifyStep({
919
- styles,
1231
+ styles: styles3,
920
1232
  theme,
921
1233
  labels,
922
1234
  testIdPrefix,
@@ -928,13 +1240,13 @@ function OtpVerifyStep({
928
1240
  onChangeEmail
929
1241
  }) {
930
1242
  const [code, setCode] = useState("");
931
- const buttonStyle = isSubmitting ? [styles.primaryButton, styles.primaryButtonDisabled] : styles.primaryButton;
1243
+ const buttonStyle = isSubmitting ? [styles3.primaryButton, styles3.primaryButtonDisabled] : styles3.primaryButton;
932
1244
  const description = labels.verifyDescription.replace("{identifier}", identifier);
933
1245
  return /* @__PURE__ */ jsxs(Fragment, { children: [
934
- /* @__PURE__ */ jsx(Text, { style: styles.title, children: labels.verifyTitle }),
935
- /* @__PURE__ */ jsx(Text, { style: styles.subtitle, children: description }),
936
- /* @__PURE__ */ jsxs(View, { style: styles.fieldGroup, children: [
937
- /* @__PURE__ */ jsx(Text, { style: styles.label, children: labels.codeLabel }),
1246
+ /* @__PURE__ */ jsx(Text, { style: styles3.title, children: labels.verifyTitle }),
1247
+ /* @__PURE__ */ jsx(Text, { style: styles3.subtitle, children: description }),
1248
+ /* @__PURE__ */ jsxs(View, { style: styles3.fieldGroup, children: [
1249
+ /* @__PURE__ */ jsx(Text, { style: styles3.label, children: labels.codeLabel }),
938
1250
  /* @__PURE__ */ jsx(
939
1251
  TextInput,
940
1252
  {
@@ -946,14 +1258,14 @@ function OtpVerifyStep({
946
1258
  keyboardType: "number-pad",
947
1259
  placeholder: labels.codePlaceholder,
948
1260
  placeholderTextColor: theme.colors.textSecondary,
949
- style: styles.input,
1261
+ style: styles3.input,
950
1262
  testID: withTestIdPrefix(AuthTestIds.otpCodeInput, testIdPrefix),
951
1263
  value: code,
952
1264
  onChangeText: setCode
953
1265
  }
954
1266
  )
955
1267
  ] }),
956
- errorText !== null ? /* @__PURE__ */ jsx(Text, { style: styles.errorText, testID: withTestIdPrefix(AuthTestIds.otpError, testIdPrefix), children: errorText }) : null,
1268
+ errorText !== null ? /* @__PURE__ */ jsx(Text, { style: styles3.errorText, testID: withTestIdPrefix(AuthTestIds.otpError, testIdPrefix), children: errorText }) : null,
957
1269
  /* @__PURE__ */ jsx(
958
1270
  TouchableOpacity,
959
1271
  {
@@ -964,7 +1276,7 @@ function OtpVerifyStep({
964
1276
  style: buttonStyle,
965
1277
  testID: withTestIdPrefix(AuthTestIds.otpVerifyButton, testIdPrefix),
966
1278
  onPress: () => onSubmit(code.trim()),
967
- children: isSubmitting ? /* @__PURE__ */ jsx(ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsx(Text, { style: styles.primaryButtonText, children: labels.verifySubmit })
1279
+ children: isSubmitting ? /* @__PURE__ */ jsx(ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsx(Text, { style: styles3.primaryButtonText, children: labels.verifySubmit })
968
1280
  }
969
1281
  ),
970
1282
  /* @__PURE__ */ jsx(
@@ -974,10 +1286,10 @@ function OtpVerifyStep({
974
1286
  accessibilityLabel: isSubmitting ? labels.resending : labels.resend,
975
1287
  accessibilityRole: "link",
976
1288
  disabled: isSubmitting,
977
- style: styles.fieldGroup,
1289
+ style: styles3.fieldGroup,
978
1290
  testID: withTestIdPrefix(AuthTestIds.otpResendButton, testIdPrefix),
979
1291
  onPress: onResend,
980
- children: /* @__PURE__ */ jsx(Text, { style: styles.linkText, children: isSubmitting ? labels.resending : labels.resend })
1292
+ children: /* @__PURE__ */ jsx(Text, { style: styles3.linkText, children: isSubmitting ? labels.resending : labels.resend })
981
1293
  }
982
1294
  ),
983
1295
  /* @__PURE__ */ jsx(
@@ -989,7 +1301,7 @@ function OtpVerifyStep({
989
1301
  disabled: isSubmitting,
990
1302
  testID: withTestIdPrefix(AuthTestIds.otpChangeEmailButton, testIdPrefix),
991
1303
  onPress: onChangeEmail,
992
- children: /* @__PURE__ */ jsx(Text, { style: styles.linkText, children: labels.changeEmail })
1304
+ children: /* @__PURE__ */ jsx(Text, { style: styles3.linkText, children: labels.changeEmail })
993
1305
  }
994
1306
  )
995
1307
  ] });
@@ -1112,9 +1424,9 @@ function useOtpLogin(options) {
1112
1424
  ]
1113
1425
  );
1114
1426
  }
1115
- var EMAIL_REGEX2 = /^[^@\s]+@[^.\s]+\.[^\s]+$/;
1427
+ var EMAIL_REGEX3 = /^[^@\s]+@[^.\s]+\.[^\s]+$/;
1116
1428
  function isValidEmail2(value) {
1117
- return EMAIL_REGEX2.test(value);
1429
+ return EMAIL_REGEX3.test(value);
1118
1430
  }
1119
1431
  function transportErrorFor(step, error, labels) {
1120
1432
  if (error === null) {
@@ -1158,7 +1470,7 @@ function OtpForm({
1158
1470
  testIdPrefix
1159
1471
  }) {
1160
1472
  const theme = useAuthTheme(themeProp);
1161
- const styles = useAuthStyles(theme);
1473
+ const styles3 = useAuthStyles(theme);
1162
1474
  const labels = useMemo(
1163
1475
  () => ({ ...DEFAULT_OTP_LABELS, ...labelsProp }),
1164
1476
  [labelsProp]
@@ -1176,13 +1488,13 @@ function OtpForm({
1176
1488
  otp.reset();
1177
1489
  }, [otp]);
1178
1490
  const errorText = localError ?? transportErrorFor(otp.step, otp.error, labels);
1179
- return /* @__PURE__ */ jsx(View, { style: styles.screen, children: /* @__PURE__ */ jsx(View, { style: styles.card, testID: withTestIdPrefix(AuthTestIds.otpForm, testIdPrefix), children: otp.step === "requestCode" /* RequestCode */ ? /* @__PURE__ */ jsx(
1491
+ return /* @__PURE__ */ jsx(View, { style: styles3.screen, children: /* @__PURE__ */ jsx(View, { style: styles3.card, testID: withTestIdPrefix(AuthTestIds.otpForm, testIdPrefix), children: otp.step === "requestCode" /* RequestCode */ ? /* @__PURE__ */ jsx(
1180
1492
  OtpRequestStep,
1181
1493
  {
1182
1494
  errorText,
1183
1495
  isSubmitting: otp.isSubmitting,
1184
1496
  labels,
1185
- styles,
1497
+ styles: styles3,
1186
1498
  testIdPrefix,
1187
1499
  theme,
1188
1500
  onSubmit: handleRequest
@@ -1194,7 +1506,7 @@ function OtpForm({
1194
1506
  identifier: otp.identifier,
1195
1507
  isSubmitting: otp.isSubmitting,
1196
1508
  labels,
1197
- styles,
1509
+ styles: styles3,
1198
1510
  testIdPrefix,
1199
1511
  theme,
1200
1512
  onChangeEmail: handleChangeEmail,
@@ -1283,7 +1595,7 @@ function PinForm({
1283
1595
  testIdPrefix
1284
1596
  }) {
1285
1597
  const theme = useAuthTheme(themeProp);
1286
- const styles = useAuthStyles(theme);
1598
+ const styles3 = useAuthStyles(theme);
1287
1599
  const labels = useMemo(
1288
1600
  () => ({ ...DEFAULT_PIN_LABELS, ...labelsProp }),
1289
1601
  [labelsProp]
@@ -1293,12 +1605,12 @@ function PinForm({
1293
1605
  const [pinValue, setPinValue] = useState("");
1294
1606
  const handleSubmit = useSubmitHandler(pin, labels, setLocalError, onSuccess);
1295
1607
  const errorText = localError ?? transportErrorFor2(pin.error, labels);
1296
- const buttonStyle = pin.isSubmitting ? [styles.primaryButton, styles.primaryButtonDisabled] : styles.primaryButton;
1297
- return /* @__PURE__ */ jsx(View, { style: styles.screen, children: /* @__PURE__ */ jsxs(View, { style: styles.card, testID: withTestIdPrefix(AuthTestIds.pinForm, testIdPrefix), children: [
1298
- /* @__PURE__ */ jsx(Text, { style: styles.title, children: labels.title }),
1299
- /* @__PURE__ */ jsx(Text, { style: styles.subtitle, children: labels.description }),
1300
- /* @__PURE__ */ jsxs(View, { style: styles.fieldGroup, children: [
1301
- /* @__PURE__ */ jsx(Text, { style: styles.label, children: labels.pinLabel }),
1608
+ const buttonStyle = pin.isSubmitting ? [styles3.primaryButton, styles3.primaryButtonDisabled] : styles3.primaryButton;
1609
+ return /* @__PURE__ */ jsx(View, { style: styles3.screen, children: /* @__PURE__ */ jsxs(View, { style: styles3.card, testID: withTestIdPrefix(AuthTestIds.pinForm, testIdPrefix), children: [
1610
+ /* @__PURE__ */ jsx(Text, { style: styles3.title, children: labels.title }),
1611
+ /* @__PURE__ */ jsx(Text, { style: styles3.subtitle, children: labels.description }),
1612
+ /* @__PURE__ */ jsxs(View, { style: styles3.fieldGroup, children: [
1613
+ /* @__PURE__ */ jsx(Text, { style: styles3.label, children: labels.pinLabel }),
1302
1614
  /* @__PURE__ */ jsx(
1303
1615
  TextInput,
1304
1616
  {
@@ -1311,7 +1623,7 @@ function PinForm({
1311
1623
  placeholder: labels.pinPlaceholder,
1312
1624
  placeholderTextColor: theme.colors.textSecondary,
1313
1625
  secureTextEntry: true,
1314
- style: styles.input,
1626
+ style: styles3.input,
1315
1627
  testID: withTestIdPrefix(AuthTestIds.pinInput, testIdPrefix),
1316
1628
  value: pinValue,
1317
1629
  onChangeText: setPinValue
@@ -1321,7 +1633,7 @@ function PinForm({
1321
1633
  errorText !== null ? /* @__PURE__ */ jsx(
1322
1634
  Text,
1323
1635
  {
1324
- style: styles.errorText,
1636
+ style: styles3.errorText,
1325
1637
  testID: withTestIdPrefix(AuthTestIds.pinError, testIdPrefix),
1326
1638
  children: errorText
1327
1639
  }
@@ -1336,11 +1648,918 @@ function PinForm({
1336
1648
  style: buttonStyle,
1337
1649
  testID: withTestIdPrefix(AuthTestIds.pinSubmitButton, testIdPrefix),
1338
1650
  onPress: () => handleSubmit(pinValue.trim()),
1339
- children: pin.isSubmitting ? /* @__PURE__ */ jsx(ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsx(Text, { style: styles.primaryButtonText, children: labels.submit })
1651
+ children: pin.isSubmitting ? /* @__PURE__ */ jsx(ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsx(Text, { style: styles3.primaryButtonText, children: labels.submit })
1340
1652
  }
1341
1653
  )
1342
1654
  ] }) });
1343
1655
  }
1656
+ var DOT_SIZE = 18;
1657
+ var DOT_BORDER_WIDTH = 2;
1658
+ var DOT_RADIUS = 9;
1659
+ var ROW_GAP = 12;
1660
+ var ROW_MIN_HEIGHT = 44;
1661
+ var ROW_VERTICAL_MARGIN = 16;
1662
+ var HIDDEN_SIZE = 1;
1663
+ function sanitise(raw, length) {
1664
+ return raw.replace(/\D/g, "").slice(0, length);
1665
+ }
1666
+ function useDotStyles(theme) {
1667
+ return useMemo(
1668
+ () => ({
1669
+ filled: { backgroundColor: theme.colors.primary, borderColor: theme.colors.primary },
1670
+ empty: { backgroundColor: theme.colors.background, borderColor: theme.colors.border }
1671
+ }),
1672
+ [theme]
1673
+ );
1674
+ }
1675
+ function DevicePinInput({
1676
+ value,
1677
+ length,
1678
+ disabled,
1679
+ testID,
1680
+ testIdPrefix,
1681
+ accessibilityLabel,
1682
+ accessibilityHint,
1683
+ filledHint,
1684
+ emptyHint,
1685
+ theme: themeProp,
1686
+ onChange
1687
+ }) {
1688
+ const theme = useAuthTheme(themeProp);
1689
+ const inputRef = useRef(null);
1690
+ const dotStyles = useDotStyles(theme);
1691
+ const cells = Array.from({ length }, (_unused, index) => index);
1692
+ const baseId = withTestIdPrefix(testID, testIdPrefix);
1693
+ return /* @__PURE__ */ jsxs(
1694
+ Pressable,
1695
+ {
1696
+ accessibilityHint,
1697
+ accessibilityLabel,
1698
+ accessibilityRole: "button",
1699
+ disabled,
1700
+ style: styles.row,
1701
+ testID: `${baseId}-row`,
1702
+ onPress: () => inputRef.current?.focus(),
1703
+ children: [
1704
+ cells.map((index) => {
1705
+ const filled = index < value.length;
1706
+ return /* @__PURE__ */ jsx(
1707
+ View,
1708
+ {
1709
+ accessibilityLabel: filled ? filledHint : emptyHint,
1710
+ style: [styles.dot, filled ? dotStyles.filled : dotStyles.empty],
1711
+ testID: `${baseId}-dot-${String(index)}`
1712
+ },
1713
+ index
1714
+ );
1715
+ }),
1716
+ /* @__PURE__ */ jsx(
1717
+ TextInput,
1718
+ {
1719
+ ref: inputRef,
1720
+ accessibilityHint,
1721
+ accessibilityLabel,
1722
+ autoFocus: true,
1723
+ caretHidden: true,
1724
+ editable: !disabled,
1725
+ keyboardType: "number-pad",
1726
+ maxLength: length,
1727
+ secureTextEntry: true,
1728
+ style: styles.hiddenInput,
1729
+ testID: baseId,
1730
+ value,
1731
+ onChangeText: (raw) => onChange(sanitise(raw, length))
1732
+ }
1733
+ )
1734
+ ]
1735
+ }
1736
+ );
1737
+ }
1738
+ var styles = StyleSheet.create({
1739
+ dot: {
1740
+ borderRadius: DOT_RADIUS,
1741
+ borderWidth: DOT_BORDER_WIDTH,
1742
+ height: DOT_SIZE,
1743
+ width: DOT_SIZE
1744
+ },
1745
+ hiddenInput: {
1746
+ height: HIDDEN_SIZE,
1747
+ opacity: 0,
1748
+ position: "absolute",
1749
+ width: HIDDEN_SIZE
1750
+ },
1751
+ row: {
1752
+ alignItems: "center",
1753
+ flexDirection: "row",
1754
+ gap: ROW_GAP,
1755
+ justifyContent: "center",
1756
+ marginVertical: ROW_VERTICAL_MARGIN,
1757
+ minHeight: ROW_MIN_HEIGHT
1758
+ }
1759
+ });
1760
+
1761
+ // src/components/interpolate.ts
1762
+ function interpolate(template, values) {
1763
+ return template.replace(/\{(\w+)\}/g, (match, key) => {
1764
+ const value = values[key];
1765
+ return value === void 0 ? match : String(value);
1766
+ });
1767
+ }
1768
+
1769
+ // src/devicePin/devicePinConstants.ts
1770
+ var DEVICE_PIN_ALLOWED_DIGITS = [4, 6, 8];
1771
+ var DEVICE_PIN_DEFAULT_DIGITS = 4;
1772
+ function isAllowedPinDigits(value) {
1773
+ return DEVICE_PIN_ALLOWED_DIGITS.includes(value);
1774
+ }
1775
+ var PILL_VERTICAL_PADDING = 10;
1776
+ var PILL_FONT_SIZE = 15;
1777
+ function usePickerStyles(theme) {
1778
+ return useMemo(
1779
+ () => ({
1780
+ pill: { borderColor: theme.colors.border },
1781
+ active: { backgroundColor: theme.colors.primary, borderColor: theme.colors.primary },
1782
+ text: { color: theme.colors.text },
1783
+ textActive: { color: theme.colors.onPrimary }
1784
+ }),
1785
+ [theme]
1786
+ );
1787
+ }
1788
+ function DevicePinLengthPicker({
1789
+ selected,
1790
+ disabled,
1791
+ optionHint,
1792
+ testIdPrefix,
1793
+ theme: themeProp,
1794
+ onSelect
1795
+ }) {
1796
+ const theme = useAuthTheme(themeProp);
1797
+ const dynamic = usePickerStyles(theme);
1798
+ const baseId = withTestIdPrefix(AuthTestIds.devicePinEnrollLength, testIdPrefix);
1799
+ return /* @__PURE__ */ jsx(View, { style: styles2.row, children: DEVICE_PIN_ALLOWED_DIGITS.map((option) => {
1800
+ const active = option === selected;
1801
+ return /* @__PURE__ */ jsx(
1802
+ Pressable,
1803
+ {
1804
+ accessibilityHint: interpolate(optionHint, { count: option }),
1805
+ accessibilityLabel: String(option),
1806
+ accessibilityRole: "button",
1807
+ accessibilityState: { selected: active },
1808
+ disabled,
1809
+ style: [styles2.pill, dynamic.pill, active ? dynamic.active : null],
1810
+ testID: `${baseId}-${String(option)}`,
1811
+ onPress: () => onSelect(option),
1812
+ children: /* @__PURE__ */ jsx(Text, { style: [styles2.text, dynamic.text, active ? dynamic.textActive : null], children: String(option) })
1813
+ },
1814
+ option
1815
+ );
1816
+ }) });
1817
+ }
1818
+ var styles2 = StyleSheet.create({
1819
+ pill: {
1820
+ alignItems: "center",
1821
+ borderRadius: 8,
1822
+ borderWidth: 1,
1823
+ flex: 1,
1824
+ paddingVertical: PILL_VERTICAL_PADDING
1825
+ },
1826
+ row: {
1827
+ flexDirection: "row",
1828
+ gap: 8,
1829
+ marginBottom: 8
1830
+ },
1831
+ text: {
1832
+ fontSize: PILL_FONT_SIZE,
1833
+ fontWeight: "700"
1834
+ }
1835
+ });
1836
+
1837
+ // src/devicePin/DevicePinErrorKey.ts
1838
+ var DevicePinErrorKey = /* @__PURE__ */ ((DevicePinErrorKey2) => {
1839
+ DevicePinErrorKey2["Incomplete"] = "incomplete";
1840
+ DevicePinErrorKey2["Invalid"] = "invalid";
1841
+ DevicePinErrorKey2["LockedOut"] = "locked_out";
1842
+ DevicePinErrorKey2["RateLimited"] = "rate_limited";
1843
+ DevicePinErrorKey2["Generic"] = "generic";
1844
+ return DevicePinErrorKey2;
1845
+ })(DevicePinErrorKey || {});
1846
+ function useDevicePinUnlock({
1847
+ client,
1848
+ digits,
1849
+ onSignedIn
1850
+ }) {
1851
+ const [pin, setPinState] = useState("");
1852
+ const [submitting, setSubmitting] = useState(false);
1853
+ const [errorKey, setErrorKey] = useState(null);
1854
+ const [retryAfterSeconds, setRetryAfterSeconds] = useState(null);
1855
+ const setPin = useCallback((next) => {
1856
+ setPinState(next);
1857
+ setErrorKey(null);
1858
+ setRetryAfterSeconds(null);
1859
+ }, []);
1860
+ const submit = useCallback(() => {
1861
+ setErrorKey(null);
1862
+ setRetryAfterSeconds(null);
1863
+ if (pin.length < digits) {
1864
+ setErrorKey("incomplete" /* Incomplete */);
1865
+ return;
1866
+ }
1867
+ setSubmitting(true);
1868
+ client.unlockWithDevicePin({ pin }).then((result) => {
1869
+ if (result.status === "success") {
1870
+ onSignedIn(result.user);
1871
+ return;
1872
+ }
1873
+ if (result.status === "invalid") {
1874
+ setErrorKey("invalid" /* Invalid */);
1875
+ return;
1876
+ }
1877
+ if (result.status === "locked") {
1878
+ setRetryAfterSeconds(result.retryAfterSeconds);
1879
+ setErrorKey("locked_out" /* LockedOut */);
1880
+ return;
1881
+ }
1882
+ if (result.status === "rateLimited") {
1883
+ setRetryAfterSeconds(result.retryAfterSeconds);
1884
+ setErrorKey("rate_limited" /* RateLimited */);
1885
+ return;
1886
+ }
1887
+ setErrorKey("generic" /* Generic */);
1888
+ }).catch(() => {
1889
+ setErrorKey("generic" /* Generic */);
1890
+ }).finally(() => {
1891
+ setSubmitting(false);
1892
+ });
1893
+ }, [client, pin, digits, onSignedIn]);
1894
+ return { pin, submitting, errorKey, retryAfterSeconds, setPin, submit };
1895
+ }
1896
+ function resolveErrorText(errorKey, digits, retryAfter, labels) {
1897
+ if (errorKey === null) {
1898
+ return null;
1899
+ }
1900
+ if (errorKey === "incomplete" /* Incomplete */) {
1901
+ return interpolate(labels.errorIncomplete, { count: digits });
1902
+ }
1903
+ if (errorKey === "invalid" /* Invalid */) {
1904
+ return labels.errorInvalid;
1905
+ }
1906
+ if (errorKey === "locked_out" /* LockedOut */) {
1907
+ return retryAfter !== null ? interpolate(labels.errorLockedOutRetry, { count: retryAfter }) : labels.errorLockedOut;
1908
+ }
1909
+ if (errorKey === "rate_limited" /* RateLimited */) {
1910
+ return retryAfter !== null ? interpolate(labels.errorRateLimitedRetry, { count: retryAfter }) : labels.errorRateLimited;
1911
+ }
1912
+ return labels.errorGeneric;
1913
+ }
1914
+ function DevicePinUnlockScreen({
1915
+ client,
1916
+ digits,
1917
+ rememberedUsername,
1918
+ theme: themeProp,
1919
+ labels: labelsProp,
1920
+ testIdPrefix,
1921
+ onSignedIn,
1922
+ onUsePassword
1923
+ }) {
1924
+ const theme = useAuthTheme(themeProp);
1925
+ const styles3 = useAuthStyles(theme);
1926
+ const labels = useMemo(
1927
+ () => ({ ...DEFAULT_DEVICE_PIN_UNLOCK_LABELS, ...labelsProp }),
1928
+ [labelsProp]
1929
+ );
1930
+ const { pin, submitting, errorKey, retryAfterSeconds, setPin, submit } = useDevicePinUnlock({
1931
+ client,
1932
+ digits,
1933
+ onSignedIn
1934
+ });
1935
+ const hasName = rememberedUsername !== "";
1936
+ const title = hasName ? interpolate(labels.title, { name: rememberedUsername }) : labels.titleNoName;
1937
+ const error = resolveErrorText(errorKey, digits, retryAfterSeconds, labels);
1938
+ const buttonStyle = submitting ? [styles3.primaryButton, styles3.primaryButtonDisabled] : styles3.primaryButton;
1939
+ return /* @__PURE__ */ jsx(View, { style: styles3.screen, children: /* @__PURE__ */ jsxs(
1940
+ View,
1941
+ {
1942
+ style: styles3.card,
1943
+ testID: withTestIdPrefix(AuthTestIds.devicePinUnlock, testIdPrefix),
1944
+ children: [
1945
+ /* @__PURE__ */ jsx(Text, { style: styles3.title, children: title }),
1946
+ /* @__PURE__ */ jsx(Text, { style: styles3.subtitle, children: interpolate(labels.description, { count: digits }) }),
1947
+ /* @__PURE__ */ jsx(
1948
+ DevicePinInput,
1949
+ {
1950
+ accessibilityHint: labels.pinPlaceholder,
1951
+ accessibilityLabel: labels.pinLabel,
1952
+ disabled: submitting,
1953
+ emptyHint: labels.digitEmptyHint,
1954
+ filledHint: labels.digitFilledHint,
1955
+ length: digits,
1956
+ testID: AuthTestIds.devicePinUnlockInput,
1957
+ testIdPrefix,
1958
+ theme,
1959
+ value: pin,
1960
+ onChange: setPin
1961
+ }
1962
+ ),
1963
+ error !== null ? /* @__PURE__ */ jsx(
1964
+ Text,
1965
+ {
1966
+ style: styles3.errorText,
1967
+ testID: withTestIdPrefix(AuthTestIds.devicePinUnlockError, testIdPrefix),
1968
+ children: error
1969
+ }
1970
+ ) : null,
1971
+ /* @__PURE__ */ jsx(
1972
+ TouchableOpacity,
1973
+ {
1974
+ accessibilityHint: labels.submit,
1975
+ accessibilityLabel: submitting ? labels.submitting : labels.submit,
1976
+ accessibilityRole: "button",
1977
+ disabled: submitting,
1978
+ style: buttonStyle,
1979
+ testID: withTestIdPrefix(AuthTestIds.devicePinUnlockSubmit, testIdPrefix),
1980
+ onPress: submit,
1981
+ children: submitting ? /* @__PURE__ */ jsx(ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsx(Text, { style: styles3.primaryButtonText, children: labels.submit })
1982
+ }
1983
+ ),
1984
+ /* @__PURE__ */ jsx(
1985
+ TouchableOpacity,
1986
+ {
1987
+ accessibilityHint: labels.usePasswordHint,
1988
+ accessibilityLabel: labels.usePasswordInstead,
1989
+ accessibilityRole: "button",
1990
+ disabled: submitting,
1991
+ style: styles3.escapeLink,
1992
+ testID: withTestIdPrefix(AuthTestIds.devicePinUnlockUsePassword, testIdPrefix),
1993
+ onPress: onUsePassword,
1994
+ children: /* @__PURE__ */ jsx(Text, { style: styles3.linkText, children: labels.usePasswordInstead })
1995
+ }
1996
+ )
1997
+ ]
1998
+ }
1999
+ ) });
2000
+ }
2001
+
2002
+ // src/devicePin/DevicePinEnrollErrorKey.ts
2003
+ var DevicePinEnrollErrorKey = /* @__PURE__ */ ((DevicePinEnrollErrorKey2) => {
2004
+ DevicePinEnrollErrorKey2["Mismatch"] = "mismatch";
2005
+ DevicePinEnrollErrorKey2["Unauthorized"] = "unauthorized";
2006
+ DevicePinEnrollErrorKey2["Forbidden"] = "forbidden";
2007
+ DevicePinEnrollErrorKey2["InvalidPin"] = "invalid_pin";
2008
+ DevicePinEnrollErrorKey2["Failed"] = "failed";
2009
+ return DevicePinEnrollErrorKey2;
2010
+ })(DevicePinEnrollErrorKey || {});
2011
+ function errorKeyFor(result) {
2012
+ if (result.status === "unauthorized") {
2013
+ return "unauthorized" /* Unauthorized */;
2014
+ }
2015
+ if (result.status === "forbidden") {
2016
+ return "forbidden" /* Forbidden */;
2017
+ }
2018
+ if (result.status === "invalidPin") {
2019
+ return "invalid_pin" /* InvalidPin */;
2020
+ }
2021
+ return "failed" /* Failed */;
2022
+ }
2023
+ function useDevicePinEnroll({
2024
+ client,
2025
+ digits,
2026
+ onEnrolled
2027
+ }) {
2028
+ const [pin, setPinState] = useState("");
2029
+ const [confirmPin, setConfirmState] = useState("");
2030
+ const [submitting, setSubmitting] = useState(false);
2031
+ const [errorKey, setErrorKey] = useState(null);
2032
+ const setPin = useCallback((next) => {
2033
+ setPinState(next);
2034
+ setErrorKey(null);
2035
+ }, []);
2036
+ const setConfirmPin = useCallback((next) => {
2037
+ setConfirmState(next);
2038
+ setErrorKey(null);
2039
+ }, []);
2040
+ const submit = useCallback(() => {
2041
+ setErrorKey(null);
2042
+ const wrongLength = pin.length !== digits;
2043
+ const mismatched = pin !== confirmPin;
2044
+ if (wrongLength || mismatched) {
2045
+ setErrorKey("mismatch" /* Mismatch */);
2046
+ return;
2047
+ }
2048
+ setSubmitting(true);
2049
+ client.enrollDevicePin({ pin, digits }).then((result) => {
2050
+ if (result.status === "success") {
2051
+ onEnrolled();
2052
+ return;
2053
+ }
2054
+ setErrorKey(errorKeyFor(result));
2055
+ }).catch(() => {
2056
+ setErrorKey("failed" /* Failed */);
2057
+ }).finally(() => {
2058
+ setSubmitting(false);
2059
+ });
2060
+ }, [client, pin, confirmPin, digits, onEnrolled]);
2061
+ return { pin, confirmPin, submitting, errorKey, setPin, setConfirmPin, submit };
2062
+ }
2063
+ function resolveErrorText2(errorKey, digits, labels) {
2064
+ if (errorKey === null) {
2065
+ return null;
2066
+ }
2067
+ if (errorKey === "mismatch" /* Mismatch */) {
2068
+ return interpolate(labels.errorMismatch, { count: digits });
2069
+ }
2070
+ if (errorKey === "unauthorized" /* Unauthorized */) {
2071
+ return labels.errorUnauthorized;
2072
+ }
2073
+ if (errorKey === "forbidden" /* Forbidden */) {
2074
+ return labels.errorForbidden;
2075
+ }
2076
+ if (errorKey === "invalid_pin" /* InvalidPin */) {
2077
+ return labels.errorInvalidPin;
2078
+ }
2079
+ return labels.errorFailed;
2080
+ }
2081
+ function DevicePinEnrollForm({
2082
+ client,
2083
+ initialDigits = DEVICE_PIN_DEFAULT_DIGITS,
2084
+ theme: themeProp,
2085
+ labels: labelsProp,
2086
+ testIdPrefix,
2087
+ onEnrolled,
2088
+ onCancel
2089
+ }) {
2090
+ const theme = useAuthTheme(themeProp);
2091
+ const styles3 = useAuthStyles(theme);
2092
+ const labels = useMemo(
2093
+ () => ({ ...DEFAULT_DEVICE_PIN_ENROLL_LABELS, ...labelsProp }),
2094
+ [labelsProp]
2095
+ );
2096
+ const [digits, setDigits] = useState(initialDigits);
2097
+ const { pin, confirmPin, submitting, errorKey, setPin, setConfirmPin, submit } = useDevicePinEnroll({ client, digits, onEnrolled });
2098
+ const error = resolveErrorText2(errorKey, digits, labels);
2099
+ const buttonStyle = submitting ? [styles3.primaryButton, styles3.primaryButtonDisabled] : styles3.primaryButton;
2100
+ return /* @__PURE__ */ jsxs(
2101
+ View,
2102
+ {
2103
+ style: styles3.card,
2104
+ testID: withTestIdPrefix(AuthTestIds.devicePinEnrollForm, testIdPrefix),
2105
+ children: [
2106
+ /* @__PURE__ */ jsx(Text, { style: styles3.title, children: labels.formTitle }),
2107
+ /* @__PURE__ */ jsx(Text, { style: styles3.subtitle, children: interpolate(labels.formDescription, { count: digits }) }),
2108
+ /* @__PURE__ */ jsx(Text, { style: styles3.label, children: labels.lengthLabel }),
2109
+ /* @__PURE__ */ jsx(
2110
+ DevicePinLengthPicker,
2111
+ {
2112
+ disabled: submitting,
2113
+ optionHint: labels.lengthOptionHint,
2114
+ selected: digits,
2115
+ testIdPrefix,
2116
+ theme,
2117
+ onSelect: (option) => {
2118
+ setDigits(option);
2119
+ setPin("");
2120
+ setConfirmPin("");
2121
+ }
2122
+ }
2123
+ ),
2124
+ /* @__PURE__ */ jsx(Text, { style: styles3.label, children: labels.pinLabel }),
2125
+ /* @__PURE__ */ jsx(
2126
+ DevicePinInput,
2127
+ {
2128
+ accessibilityHint: labels.pinPlaceholder,
2129
+ accessibilityLabel: labels.pinLabel,
2130
+ disabled: submitting,
2131
+ emptyHint: labels.pinPlaceholder,
2132
+ filledHint: labels.pinLabel,
2133
+ length: digits,
2134
+ testID: AuthTestIds.devicePinEnrollPin,
2135
+ testIdPrefix,
2136
+ theme,
2137
+ value: pin,
2138
+ onChange: setPin
2139
+ }
2140
+ ),
2141
+ /* @__PURE__ */ jsx(Text, { style: styles3.label, children: labels.confirmLabel }),
2142
+ /* @__PURE__ */ jsx(
2143
+ DevicePinInput,
2144
+ {
2145
+ accessibilityHint: labels.confirmPlaceholder,
2146
+ accessibilityLabel: labels.confirmLabel,
2147
+ disabled: submitting,
2148
+ emptyHint: labels.confirmPlaceholder,
2149
+ filledHint: labels.confirmLabel,
2150
+ length: digits,
2151
+ testID: AuthTestIds.devicePinEnrollConfirm,
2152
+ testIdPrefix,
2153
+ theme,
2154
+ value: confirmPin,
2155
+ onChange: setConfirmPin
2156
+ }
2157
+ ),
2158
+ error !== null ? /* @__PURE__ */ jsx(
2159
+ Text,
2160
+ {
2161
+ style: styles3.errorText,
2162
+ testID: withTestIdPrefix(AuthTestIds.devicePinEnrollError, testIdPrefix),
2163
+ children: error
2164
+ }
2165
+ ) : null,
2166
+ /* @__PURE__ */ jsx(
2167
+ TouchableOpacity,
2168
+ {
2169
+ accessibilityHint: labels.submit,
2170
+ accessibilityLabel: submitting ? labels.submitting : labels.submit,
2171
+ accessibilityRole: "button",
2172
+ disabled: submitting,
2173
+ style: buttonStyle,
2174
+ testID: withTestIdPrefix(AuthTestIds.devicePinEnrollSubmit, testIdPrefix),
2175
+ onPress: submit,
2176
+ children: submitting ? /* @__PURE__ */ jsx(ActivityIndicator, { color: theme.colors.onPrimary, size: "small" }) : /* @__PURE__ */ jsx(Text, { style: styles3.primaryButtonText, children: labels.submit })
2177
+ }
2178
+ ),
2179
+ /* @__PURE__ */ jsx(
2180
+ TouchableOpacity,
2181
+ {
2182
+ accessibilityHint: labels.cancelHint,
2183
+ accessibilityLabel: labels.cancel,
2184
+ accessibilityRole: "button",
2185
+ disabled: submitting,
2186
+ style: styles3.escapeLink,
2187
+ testID: withTestIdPrefix(AuthTestIds.devicePinEnrollCancel, testIdPrefix),
2188
+ onPress: onCancel,
2189
+ children: /* @__PURE__ */ jsx(Text, { style: styles3.linkText, children: labels.cancel })
2190
+ }
2191
+ )
2192
+ ]
2193
+ }
2194
+ );
2195
+ }
2196
+ function DevicePinOffer({
2197
+ client,
2198
+ initialDigits,
2199
+ theme: themeProp,
2200
+ labels: labelsProp,
2201
+ testIdPrefix,
2202
+ onDismiss
2203
+ }) {
2204
+ const theme = useAuthTheme(themeProp);
2205
+ const styles3 = useAuthStyles(theme);
2206
+ const labels = useMemo(
2207
+ () => ({ ...DEFAULT_DEVICE_PIN_ENROLL_LABELS, ...labelsProp }),
2208
+ [labelsProp]
2209
+ );
2210
+ const [expanded, setExpanded] = useState(false);
2211
+ const cardTestId = withTestIdPrefix(AuthTestIds.devicePinOffer, testIdPrefix);
2212
+ if (expanded) {
2213
+ return /* @__PURE__ */ jsx(View, { style: styles3.card, testID: cardTestId, children: /* @__PURE__ */ jsx(
2214
+ DevicePinEnrollForm,
2215
+ {
2216
+ client,
2217
+ initialDigits,
2218
+ labels: labelsProp,
2219
+ testIdPrefix,
2220
+ theme,
2221
+ onCancel: onDismiss,
2222
+ onEnrolled: onDismiss
2223
+ }
2224
+ ) });
2225
+ }
2226
+ return /* @__PURE__ */ jsxs(View, { style: styles3.card, testID: cardTestId, children: [
2227
+ /* @__PURE__ */ jsx(Text, { style: styles3.title, children: labels.offerTitle }),
2228
+ /* @__PURE__ */ jsx(Text, { style: styles3.subtitle, children: labels.offerDescription }),
2229
+ /* @__PURE__ */ jsx(
2230
+ TouchableOpacity,
2231
+ {
2232
+ accessibilityHint: labels.offerAcceptHint,
2233
+ accessibilityLabel: labels.offerAccept,
2234
+ accessibilityRole: "button",
2235
+ style: styles3.primaryButton,
2236
+ testID: withTestIdPrefix(AuthTestIds.devicePinOfferAccept, testIdPrefix),
2237
+ onPress: () => setExpanded(true),
2238
+ children: /* @__PURE__ */ jsx(Text, { style: styles3.primaryButtonText, children: labels.offerAccept })
2239
+ }
2240
+ ),
2241
+ /* @__PURE__ */ jsx(
2242
+ TouchableOpacity,
2243
+ {
2244
+ accessibilityHint: labels.offerSkipHint,
2245
+ accessibilityLabel: labels.offerSkip,
2246
+ accessibilityRole: "button",
2247
+ style: styles3.secondaryButton,
2248
+ testID: withTestIdPrefix(AuthTestIds.devicePinOfferSkip, testIdPrefix),
2249
+ onPress: onDismiss,
2250
+ children: /* @__PURE__ */ jsx(Text, { style: styles3.secondaryButtonText, children: labels.offerSkip })
2251
+ }
2252
+ )
2253
+ ] });
2254
+ }
2255
+ function useDevicePinDisable({
2256
+ client,
2257
+ initialHasPin,
2258
+ onChanged
2259
+ }) {
2260
+ const [hasPin, setHasPin] = useState(initialHasPin);
2261
+ const [disabling, setDisabling] = useState(false);
2262
+ const [failed, setFailed] = useState(false);
2263
+ const disable = useCallback(() => {
2264
+ setFailed(false);
2265
+ setDisabling(true);
2266
+ client.disableDevicePin().then((ok) => {
2267
+ if (ok) {
2268
+ setHasPin(false);
2269
+ onChanged?.(false);
2270
+ return;
2271
+ }
2272
+ setFailed(true);
2273
+ }).catch(() => {
2274
+ setFailed(true);
2275
+ }).finally(() => {
2276
+ setDisabling(false);
2277
+ });
2278
+ }, [client, onChanged]);
2279
+ const markEnabled = useCallback(() => {
2280
+ setHasPin(true);
2281
+ onChanged?.(true);
2282
+ }, [onChanged]);
2283
+ return { hasPin, disabling, failed, disable, markEnabled };
2284
+ }
2285
+ function DevicePinSettingsCard({
2286
+ client,
2287
+ initialHasPin,
2288
+ theme: themeProp,
2289
+ labels: labelsProp,
2290
+ enrollLabels,
2291
+ testIdPrefix,
2292
+ onChanged
2293
+ }) {
2294
+ const theme = useAuthTheme(themeProp);
2295
+ const styles3 = useAuthStyles(theme);
2296
+ const labels = useMemo(
2297
+ () => ({ ...DEFAULT_DEVICE_PIN_SETTINGS_LABELS, ...labelsProp }),
2298
+ [labelsProp]
2299
+ );
2300
+ const resolvedEnrollLabels = useMemo(
2301
+ () => ({ ...DEFAULT_DEVICE_PIN_ENROLL_LABELS, ...enrollLabels }),
2302
+ [enrollLabels]
2303
+ );
2304
+ const [enrolling, setEnrolling] = useState(false);
2305
+ const { hasPin, disabling, failed, disable, markEnabled } = useDevicePinDisable({
2306
+ client,
2307
+ initialHasPin,
2308
+ onChanged
2309
+ });
2310
+ const handleEnrolled = () => {
2311
+ setEnrolling(false);
2312
+ markEnabled();
2313
+ };
2314
+ const disableButtonStyle = disabling ? [styles3.secondaryButton, styles3.primaryButtonDisabled] : styles3.secondaryButton;
2315
+ return /* @__PURE__ */ jsxs(
2316
+ View,
2317
+ {
2318
+ style: styles3.card,
2319
+ testID: withTestIdPrefix(AuthTestIds.devicePinSettings, testIdPrefix),
2320
+ children: [
2321
+ /* @__PURE__ */ jsx(Text, { style: styles3.title, children: labels.title }),
2322
+ /* @__PURE__ */ jsx(Text, { style: styles3.subtitle, children: labels.description }),
2323
+ /* @__PURE__ */ jsx(
2324
+ Text,
2325
+ {
2326
+ style: styles3.statusText,
2327
+ testID: withTestIdPrefix(AuthTestIds.devicePinSettingsStatus, testIdPrefix),
2328
+ children: hasPin ? labels.statusEnabled : labels.statusDisabled
2329
+ }
2330
+ ),
2331
+ failed ? /* @__PURE__ */ jsx(
2332
+ Text,
2333
+ {
2334
+ style: styles3.errorText,
2335
+ testID: withTestIdPrefix(AuthTestIds.devicePinSettingsError, testIdPrefix),
2336
+ children: labels.disableFailed
2337
+ }
2338
+ ) : null,
2339
+ renderAction()
2340
+ ]
2341
+ }
2342
+ );
2343
+ function renderAction() {
2344
+ if (enrolling) {
2345
+ return /* @__PURE__ */ jsx(
2346
+ DevicePinEnrollForm,
2347
+ {
2348
+ client,
2349
+ labels: resolvedEnrollLabels,
2350
+ testIdPrefix,
2351
+ theme,
2352
+ onCancel: () => setEnrolling(false),
2353
+ onEnrolled: handleEnrolled
2354
+ }
2355
+ );
2356
+ }
2357
+ if (hasPin) {
2358
+ return /* @__PURE__ */ jsx(
2359
+ TouchableOpacity,
2360
+ {
2361
+ accessibilityHint: labels.disableHint,
2362
+ accessibilityLabel: disabling ? labels.disabling : labels.disable,
2363
+ accessibilityRole: "button",
2364
+ disabled: disabling,
2365
+ style: disableButtonStyle,
2366
+ testID: withTestIdPrefix(AuthTestIds.devicePinSettingsDisable, testIdPrefix),
2367
+ onPress: disable,
2368
+ children: disabling ? /* @__PURE__ */ jsx(ActivityIndicator, { color: theme.colors.primary, size: "small" }) : /* @__PURE__ */ jsx(Text, { style: styles3.secondaryButtonText, children: labels.disable })
2369
+ }
2370
+ );
2371
+ }
2372
+ return /* @__PURE__ */ jsx(
2373
+ TouchableOpacity,
2374
+ {
2375
+ accessibilityHint: labels.enableHint,
2376
+ accessibilityLabel: labels.enable,
2377
+ accessibilityRole: "button",
2378
+ style: styles3.primaryButton,
2379
+ testID: withTestIdPrefix(AuthTestIds.devicePinSettingsEnable, testIdPrefix),
2380
+ onPress: () => setEnrolling(true),
2381
+ children: /* @__PURE__ */ jsx(Text, { style: styles3.primaryButtonText, children: labels.enable })
2382
+ }
2383
+ );
2384
+ }
2385
+ }
2386
+
2387
+ // src/passkey/passkeyNavigation.ts
2388
+ var PASSKEY_LOGIN_ENDPOINT = "/bff/passkey/login";
2389
+ var PASSKEY_REGISTER_ENDPOINT = "/bff/passkey/register";
2390
+ var RETURN_URL_PARAM = "returnUrl";
2391
+ var PASSKEY_ERROR_PARAM = "passkeyError";
2392
+ var PASSKEY_PARAM = "passkey";
2393
+ var PASSKEY_REGISTERED_VALUE = "registered";
2394
+ var PASSKEY_ERROR_CANCELLED = "cancelled";
2395
+ var PASSKEY_ERROR_FAILED = "failed";
2396
+ function buildNavigationUrl(endpoint, returnUrl) {
2397
+ return `${endpoint}?${RETURN_URL_PARAM}=${encodeURIComponent(returnUrl)}`;
2398
+ }
2399
+ function readSearchParams() {
2400
+ if (typeof window === "undefined") {
2401
+ return null;
2402
+ }
2403
+ return new URLSearchParams(window.location.search);
2404
+ }
2405
+ function startPasskeyLogin(returnUrl) {
2406
+ if (typeof window === "undefined") {
2407
+ return;
2408
+ }
2409
+ window.location.assign(buildNavigationUrl(PASSKEY_LOGIN_ENDPOINT, returnUrl));
2410
+ }
2411
+ function startPasskeyRegistration(returnUrl) {
2412
+ if (typeof window === "undefined") {
2413
+ return;
2414
+ }
2415
+ window.location.assign(buildNavigationUrl(PASSKEY_REGISTER_ENDPOINT, returnUrl));
2416
+ }
2417
+ function readPasskeyError() {
2418
+ const params = readSearchParams();
2419
+ if (params === null) {
2420
+ return null;
2421
+ }
2422
+ const value = params.get(PASSKEY_ERROR_PARAM);
2423
+ if (value === PASSKEY_ERROR_CANCELLED) {
2424
+ return PASSKEY_ERROR_CANCELLED;
2425
+ }
2426
+ if (value === PASSKEY_ERROR_FAILED) {
2427
+ return PASSKEY_ERROR_FAILED;
2428
+ }
2429
+ return null;
2430
+ }
2431
+ function readPasskeyRegistered() {
2432
+ const params = readSearchParams();
2433
+ if (params === null) {
2434
+ return false;
2435
+ }
2436
+ return params.get(PASSKEY_PARAM) === PASSKEY_REGISTERED_VALUE;
2437
+ }
2438
+ var DEFAULT_RETURN_URL = "/";
2439
+ function PasskeyLoginButton({
2440
+ returnUrl = DEFAULT_RETURN_URL,
2441
+ theme: themeProp,
2442
+ labels: labelsProp,
2443
+ testIdPrefix
2444
+ }) {
2445
+ const theme = useAuthTheme(themeProp);
2446
+ const styles3 = useAuthStyles(theme);
2447
+ const labels = useMemo(
2448
+ () => ({ ...DEFAULT_PASSKEY_LOGIN_LABELS, ...labelsProp }),
2449
+ [labelsProp]
2450
+ );
2451
+ const error = readPasskeyError();
2452
+ return /* @__PURE__ */ jsxs(View, { testID: withTestIdPrefix(AuthTestIds.passkeyLogin, testIdPrefix), children: [
2453
+ error !== null ? /* @__PURE__ */ jsx(
2454
+ Text,
2455
+ {
2456
+ style: styles3.errorText,
2457
+ testID: withTestIdPrefix(AuthTestIds.passkeyLoginError, testIdPrefix),
2458
+ children: error === "cancelled" ? labels.errorCancelled : labels.errorFailed
2459
+ }
2460
+ ) : null,
2461
+ /* @__PURE__ */ jsx(
2462
+ TouchableOpacity,
2463
+ {
2464
+ accessibilityHint: labels.signInHint,
2465
+ accessibilityLabel: labels.signInButton,
2466
+ accessibilityRole: "button",
2467
+ style: styles3.secondaryButton,
2468
+ testID: withTestIdPrefix(AuthTestIds.passkeyLoginButton, testIdPrefix),
2469
+ onPress: () => startPasskeyLogin(returnUrl),
2470
+ children: /* @__PURE__ */ jsx(Text, { style: styles3.secondaryButtonText, children: labels.signInButton })
2471
+ }
2472
+ )
2473
+ ] });
2474
+ }
2475
+ var DEFAULT_RETURN_PATH = "/";
2476
+ function readCurrentPath() {
2477
+ if (typeof window === "undefined") {
2478
+ return DEFAULT_RETURN_PATH;
2479
+ }
2480
+ return window.location.pathname;
2481
+ }
2482
+ function PasskeySettingsCard({
2483
+ returnUrl,
2484
+ theme: themeProp,
2485
+ labels: labelsProp,
2486
+ testIdPrefix
2487
+ }) {
2488
+ const theme = useAuthTheme(themeProp);
2489
+ const styles3 = useAuthStyles(theme);
2490
+ const labels = useMemo(
2491
+ () => ({ ...DEFAULT_PASSKEY_SETTINGS_LABELS, ...labelsProp }),
2492
+ [labelsProp]
2493
+ );
2494
+ const justRegistered = readPasskeyRegistered();
2495
+ const target = returnUrl ?? readCurrentPath();
2496
+ return /* @__PURE__ */ jsxs(
2497
+ View,
2498
+ {
2499
+ style: styles3.card,
2500
+ testID: withTestIdPrefix(AuthTestIds.passkeySettings, testIdPrefix),
2501
+ children: [
2502
+ /* @__PURE__ */ jsx(Text, { style: styles3.title, children: labels.title }),
2503
+ /* @__PURE__ */ jsx(Text, { style: styles3.subtitle, children: labels.description }),
2504
+ /* @__PURE__ */ jsx(Text, { style: styles3.helperText, children: labels.reauthHint }),
2505
+ justRegistered ? /* @__PURE__ */ jsx(
2506
+ Text,
2507
+ {
2508
+ style: styles3.successText,
2509
+ testID: withTestIdPrefix(AuthTestIds.passkeySettingsSuccess, testIdPrefix),
2510
+ children: labels.registeredSuccess
2511
+ }
2512
+ ) : null,
2513
+ /* @__PURE__ */ jsx(
2514
+ TouchableOpacity,
2515
+ {
2516
+ accessibilityHint: labels.addHint,
2517
+ accessibilityLabel: labels.addButton,
2518
+ accessibilityRole: "button",
2519
+ style: styles3.primaryButton,
2520
+ testID: withTestIdPrefix(AuthTestIds.passkeySettingsAdd, testIdPrefix),
2521
+ onPress: () => startPasskeyRegistration(target),
2522
+ children: /* @__PURE__ */ jsx(Text, { style: styles3.primaryButtonText, children: labels.addButton })
2523
+ }
2524
+ )
2525
+ ]
2526
+ }
2527
+ );
2528
+ }
2529
+ var EMPTY_CONFIG = {
2530
+ methods: [],
2531
+ registrationEnabled: false,
2532
+ deviceState: {
2533
+ rememberedUsername: null,
2534
+ hasPin: false,
2535
+ pinDigits: null,
2536
+ preferredMethod: null
2537
+ }
2538
+ };
2539
+ function useBffLoginConfig(client) {
2540
+ const [config, setConfig] = useState(EMPTY_CONFIG);
2541
+ const [loading, setLoading] = useState(true);
2542
+ useEffect(() => {
2543
+ let active = true;
2544
+ client.getLoginConfig().then((next) => {
2545
+ if (active) {
2546
+ setConfig(next);
2547
+ }
2548
+ }).catch(() => {
2549
+ if (active) {
2550
+ setConfig(EMPTY_CONFIG);
2551
+ }
2552
+ }).finally(() => {
2553
+ if (active) {
2554
+ setLoading(false);
2555
+ }
2556
+ });
2557
+ return () => {
2558
+ active = false;
2559
+ };
2560
+ }, [client]);
2561
+ return { config, loading };
2562
+ }
1344
2563
  async function lazyFetchHttpClient(request) {
1345
2564
  const fetchImpl = typeof fetch === "function" ? fetch.bind(globalThis) : void 0;
1346
2565
  if (fetchImpl === void 0) {
@@ -1384,6 +2603,6 @@ function resolvePostLoginRoute(user, table) {
1384
2603
  return table.fallback ?? null;
1385
2604
  }
1386
2605
 
1387
- export { AuthTestIds, AuthThemeProvider, BffAuthStatus, DEFAULT_FORGOT_PASSWORD_LABELS, DEFAULT_LOGIN_LABELS, DEFAULT_OTP_LABELS, DEFAULT_PIN_LABELS, DEFAULT_RESET_PASSWORD_LABELS, ForgotPasswordForm, LoginForm, OtpForm, OtpLoginStep, PASSWORD_MAX_LENGTH, PASSWORD_MIN_LENGTH, PasswordPolicyError, PinForm, ResetPasswordError, ResetPasswordForm, collectUserRoles, createBffAuthClient, defaultAuthTheme, isPasswordValid, resolvePostLoginRoute, useAuthTheme, useBffAuth, useBffForgotPassword, useBffResetPassword, useOtpLogin, usePinLogin, useResetPasswordForm, validatePasswordPolicy, withTestIdPrefix };
2606
+ export { AuthTestIds, AuthThemeProvider, BffAuthStatus, DEFAULT_DEVICE_PIN_ENROLL_LABELS, DEFAULT_DEVICE_PIN_SETTINGS_LABELS, DEFAULT_DEVICE_PIN_UNLOCK_LABELS, DEFAULT_FORGOT_PASSWORD_FIELDS_LABELS, DEFAULT_FORGOT_PASSWORD_LABELS, DEFAULT_LOGIN_LABELS, DEFAULT_OTP_LABELS, DEFAULT_PASSKEY_LOGIN_LABELS, DEFAULT_PASSKEY_SETTINGS_LABELS, DEFAULT_PIN_LABELS, DEFAULT_RESET_PASSWORD_LABELS, DEVICE_PIN_ALLOWED_DIGITS, DEVICE_PIN_DEFAULT_DIGITS, DevicePinEnrollErrorKey, DevicePinEnrollForm, DevicePinErrorKey, DevicePinInput, DevicePinLengthPicker, DevicePinOffer, DevicePinSettingsCard, DevicePinUnlockScreen, ForgotPasswordFields, ForgotPasswordForm, LoginForm, OtpForm, OtpLoginStep, PASSWORD_MAX_LENGTH, PASSWORD_MIN_LENGTH, PasskeyLoginButton, PasskeySettingsCard, PasswordPolicyError, PinForm, ResetPasswordError, ResetPasswordForm, collectUserRoles, createBffAuthClient, defaultAuthTheme, isAllowedPinDigits, isPasswordValid, isValidForgotPasswordEmail, readPasskeyError, readPasskeyRegistered, resolvePostLoginRoute, startPasskeyLogin, startPasskeyRegistration, useAuthTheme, useBffAuth, useBffForgotPassword, useBffLoginConfig, useBffResetPassword, useDevicePinDisable, useDevicePinEnroll, useDevicePinUnlock, useForgotPasswordSubmit, useOtpLogin, usePinLogin, useResetPasswordForm, validatePasswordPolicy, withTestIdPrefix };
1388
2607
  //# sourceMappingURL=index.mjs.map
1389
2608
  //# sourceMappingURL=index.mjs.map