@abstraxn/signer-react 3.3.10 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/dist/src/ConnectButton.css.d.ts +2 -0
  3. package/dist/src/ConnectButton.css.js +1 -0
  4. package/dist/src/ConnectButton.d.ts +0 -1
  5. package/dist/src/ConnectButton.js +7 -6
  6. package/dist/src/ExternalWalletButtons.css.d.ts +2 -0
  7. package/dist/src/ExternalWalletButtons.css.js +1 -0
  8. package/dist/src/ExternalWalletButtons.d.ts +4 -1
  9. package/dist/src/ExternalWalletButtons.js +6 -1
  10. package/dist/src/WalletModal.css +2 -0
  11. package/dist/src/WalletModal.css.d.ts +2 -0
  12. package/dist/src/WalletModal.css.js +1 -0
  13. package/dist/src/WalletModal.d.ts +2 -2
  14. package/dist/src/WalletModal.js +113 -59
  15. package/dist/src/components/AbstraxnLogo.d.ts +17 -0
  16. package/dist/src/components/AbstraxnLogo.js +29 -0
  17. package/dist/src/components/AbstraxnProvider/AbstraxnProviderInner.js +406 -338
  18. package/dist/src/components/AbstraxnProvider/useAbstraxnProviderBase.d.ts +7 -0
  19. package/dist/src/components/AbstraxnProvider/useAbstraxnProviderBase.js +9 -0
  20. package/dist/src/components/AbstraxnProvider/useWalletInitialization.js +41 -6
  21. package/dist/src/components/OnboardingUI/OnboardingUI.css +99 -4
  22. package/dist/src/components/OnboardingUI/OnboardingUI.css.d.ts +2 -0
  23. package/dist/src/components/OnboardingUI/OnboardingUI.css.js +1 -0
  24. package/dist/src/components/OnboardingUI/OnboardingUIReact.d.ts +0 -1
  25. package/dist/src/components/OnboardingUI/OnboardingUIReact.js +46 -19
  26. package/dist/src/components/OnboardingUI/OnboardingUIWeb.d.ts +24 -1
  27. package/dist/src/components/OnboardingUI/OnboardingUIWeb.js +348 -160
  28. package/dist/src/components/OnboardingUI/components/Divider.d.ts +7 -0
  29. package/dist/src/components/OnboardingUI/components/Divider.js +9 -0
  30. package/dist/src/components/OnboardingUI/components/EmailForm.d.ts +0 -1
  31. package/dist/src/components/OnboardingUI/components/EmailForm.js +1 -2
  32. package/dist/src/components/OnboardingUI/components/MfaForm.d.ts +0 -1
  33. package/dist/src/components/OnboardingUI/components/MfaForm.js +2 -3
  34. package/dist/src/components/OnboardingUI/components/Modal.d.ts +0 -1
  35. package/dist/src/components/OnboardingUI/components/Modal.js +12 -4
  36. package/dist/src/components/OnboardingUI/components/OtpForm.d.ts +0 -1
  37. package/dist/src/components/OnboardingUI/components/OtpForm.js +2 -3
  38. package/dist/src/components/OnboardingUI/components/PasskeyButton.d.ts +0 -1
  39. package/dist/src/components/OnboardingUI/components/PasskeyButton.js +2 -2
  40. package/dist/src/components/OnboardingUI/components/SocialButtons.d.ts +0 -1
  41. package/dist/src/components/OnboardingUI/components/SocialButtons.js +3 -3
  42. package/dist/src/components/OnboardingUI/onboardingShadowContainer.d.ts +9 -0
  43. package/dist/src/components/OnboardingUI/onboardingShadowContainer.js +36 -0
  44. package/dist/src/components/ShadowHost/ShadowHost.d.ts +18 -0
  45. package/dist/src/components/ShadowHost/ShadowHost.js +123 -0
  46. package/dist/src/components/ShadowHost/ShadowHostContext.d.ts +10 -0
  47. package/dist/src/components/ShadowHost/ShadowHostContext.js +14 -0
  48. package/dist/src/components/ShadowHost/index.d.ts +2 -0
  49. package/dist/src/components/ShadowHost/index.js +3 -0
  50. package/dist/src/components/WalletModal/components/ChainSelector.css +9 -0
  51. package/dist/src/components/WalletModal/components/ChainSelector.css.d.ts +2 -0
  52. package/dist/src/components/WalletModal/components/ChainSelector.css.js +1 -0
  53. package/dist/src/components/WalletModal/components/ChainSelector.d.ts +0 -1
  54. package/dist/src/components/WalletModal/components/ChainSelector.js +78 -23
  55. package/dist/src/components/WalletModal/components/CodeInput.d.ts +12 -0
  56. package/dist/src/components/WalletModal/components/CodeInput.js +39 -0
  57. package/dist/src/components/WalletModal/components/ExportKeyModal.css.d.ts +2 -0
  58. package/dist/src/components/WalletModal/components/ExportKeyModal.css.js +1 -0
  59. package/dist/src/components/WalletModal/components/ExportKeyModal.d.ts +0 -2
  60. package/dist/src/components/WalletModal/components/ExportKeyModal.js +2 -4
  61. package/dist/src/components/WalletModal/components/ExportWarningModal.css.d.ts +2 -0
  62. package/dist/src/components/WalletModal/components/ExportWarningModal.css.js +1 -0
  63. package/dist/src/components/WalletModal/components/ExportWarningModal.d.ts +0 -2
  64. package/dist/src/components/WalletModal/components/ExportWarningModal.js +2 -4
  65. package/dist/src/components/WalletModal/components/ManageWalletModal.css +27 -1
  66. package/dist/src/components/WalletModal/components/ManageWalletModal.css.d.ts +2 -0
  67. package/dist/src/components/WalletModal/components/ManageWalletModal.css.js +1 -0
  68. package/dist/src/components/WalletModal/components/ManageWalletModal.d.ts +0 -1
  69. package/dist/src/components/WalletModal/components/ManageWalletModal.js +66 -148
  70. package/dist/src/components/WalletModal/components/MfaVerifyModal.d.ts +15 -0
  71. package/dist/src/components/WalletModal/components/MfaVerifyModal.js +98 -0
  72. package/dist/src/components/WalletModal/components/PreviewTransactionModal.css +2 -12
  73. package/dist/src/components/WalletModal/components/PreviewTransactionModal.css.d.ts +2 -0
  74. package/dist/src/components/WalletModal/components/PreviewTransactionModal.css.js +1 -0
  75. package/dist/src/components/WalletModal/components/PreviewTransactionModal.d.ts +0 -1
  76. package/dist/src/components/WalletModal/components/PreviewTransactionModal.js +0 -1
  77. package/dist/src/components/WalletModal/components/ReceiveModal.css.d.ts +2 -0
  78. package/dist/src/components/WalletModal/components/ReceiveModal.css.js +1 -0
  79. package/dist/src/components/WalletModal/components/ReceiveModal.d.ts +0 -1
  80. package/dist/src/components/WalletModal/components/ReceiveModal.js +2 -2
  81. package/dist/src/components/WalletModal/components/SendModal.css.d.ts +2 -0
  82. package/dist/src/components/WalletModal/components/SendModal.css.js +1 -0
  83. package/dist/src/components/WalletModal/components/SendModal.d.ts +5 -2
  84. package/dist/src/components/WalletModal/components/SendModal.js +25 -82
  85. package/dist/src/components/WalletModal/components/SignMfaModalHost.d.ts +1 -0
  86. package/dist/src/components/WalletModal/components/SignMfaModalHost.js +50 -0
  87. package/dist/src/components/WalletModal/components/SuccessModal.css.d.ts +2 -0
  88. package/dist/src/components/WalletModal/components/SuccessModal.css.js +1 -0
  89. package/dist/src/components/WalletModal/components/SuccessModal.d.ts +0 -1
  90. package/dist/src/components/WalletModal/components/SuccessModal.js +0 -1
  91. package/dist/src/components/WalletModal/components/TokenSelectorModal.css.d.ts +2 -0
  92. package/dist/src/components/WalletModal/components/TokenSelectorModal.css.js +1 -0
  93. package/dist/src/components/WalletModal/components/TokenSelectorModal.d.ts +0 -1
  94. package/dist/src/components/WalletModal/components/TokenSelectorModal.js +0 -1
  95. package/dist/src/components/WalletModal/components/UserAvatar.js +2 -1
  96. package/dist/src/components/WalletModal/components/index.d.ts +3 -0
  97. package/dist/src/components/WalletModal/components/index.js +2 -0
  98. package/dist/src/components/WalletModal/hooks/useSendTransaction.js +18 -6
  99. package/dist/src/components/icons.d.ts +2 -0
  100. package/dist/src/components/icons.js +4 -0
  101. package/dist/src/hooks.d.ts +58 -3
  102. package/dist/src/hooks.js +172 -30
  103. package/dist/src/index.d.ts +1 -1
  104. package/dist/src/index.js +1 -1
  105. package/dist/src/signMfaBridge.d.ts +7 -0
  106. package/dist/src/signMfaBridge.js +20 -0
  107. package/dist/src/types.d.ts +4 -0
  108. package/dist/src/utils/shadowFocus.d.ts +8 -0
  109. package/dist/src/utils/shadowFocus.js +15 -0
  110. package/dist/src/utils/shadowRegistry.d.ts +23 -0
  111. package/dist/src/utils/shadowRegistry.js +36 -0
  112. package/package.json +9 -4
@@ -4,11 +4,14 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
4
4
  */
5
5
  import { useEffect, useRef, useState, useCallback } from "react";
6
6
  import { createPortal } from "react-dom";
7
- import { IoKeyOutline, IoCopyOutline, IoCheckmarkOutline, IoCloudDownloadOutline, IoChevronBack, IoClose, IoPhonePortraitOutline, SiWalletconnect, SiDiscord, SiX, FcGoogle, FiUsers, FiLink, TfiEmail, BiShieldQuarter, } from "../../icons";
7
+ import { IoKeyOutline, IoCopyOutline, IoCheckmarkOutline, IoCloudDownloadOutline, IoChevronBack, CloseIcon, IoPhonePortraitOutline, SiWalletconnect, SiDiscord, SiX, GoogleIcon, FiUsers, FiLink, TfiEmail, BiShieldQuarter, } from "../../icons";
8
8
  import { useAbstraxnWallet } from "../../../AbstraxnProvider";
9
9
  import { useEnableMfa } from "../../../hooks";
10
- import "./ManageWalletModal.css";
11
10
  import { QRCodeSVG } from "qrcode.react";
11
+ import { useShadowHost } from "../../ShadowHost";
12
+ import { CodeInput } from "./CodeInput";
13
+ import { MfaVerifyModal } from "./MfaVerifyModal";
14
+ import { AbstraxnLogo } from "../../AbstraxnLogo";
12
15
  function normalizeLinkedProvider(authProvider) {
13
16
  return authProvider === "otp" ? "email" : authProvider;
14
17
  }
@@ -18,7 +21,7 @@ function normalizeErrorMessage(message) {
18
21
  function AuthMethodIcon({ provider }) {
19
22
  const p = provider.toLowerCase();
20
23
  if (p === "google")
21
- return _jsx(FcGoogle, { size: 20, className: "wallet-modal-provider-icon wallet-modal-provider-icon-google" });
24
+ return _jsx(GoogleIcon, { size: 20, className: "wallet-modal-provider-icon wallet-modal-provider-icon-google" });
22
25
  if (p === "discord")
23
26
  return _jsx(SiDiscord, { size: 20, className: "wallet-modal-provider-icon wallet-modal-provider-icon-discord" });
24
27
  if (p === "x" || p === "twitter")
@@ -31,7 +34,14 @@ function AuthMethodIcon({ provider }) {
31
34
  }
32
35
  export function ManageWalletModal({ ...props }) {
33
36
  const { isOpen, onClose, isExternalWalletConnected, onExportPrivateKey, theme = "dark", userEmail, organizationName, } = props;
34
- const { getSupportedAuthMethods, getLinkedAuthMethods, linkAuthMethod, linkEmail, loginWithOTP, requestOtpForEmailLink, unlinkAuthMethod, whoami, mfaStatus, mfaStatusLoading, prefetchMfaStatus, verifyMfa, disableMfaWithSignedPayload, } = useAbstraxnWallet();
37
+ // Portal target: the enclosing WalletModal's shadow boundary container,
38
+ // so these nested overlays stay inside the isolation boundary instead of
39
+ // escaping to document.body. document.body fallback is purely defensive —
40
+ // this component is never rendered outside a WalletModal shadow boundary
41
+ // in practice.
42
+ const shadowHost = useShadowHost();
43
+ const portalTarget = shadowHost?.container ?? document.body;
44
+ const { getSupportedAuthMethods, getLinkedAuthMethods, linkAuthMethod, linkEmail, loginWithOTP, requestOtpForEmailLink, unlinkAuthMethod, whoami, mfaStatus, mfaStatusLoading, prefetchMfaStatus, verifySignMfa, disableMfaWithSignedPayload, } = useAbstraxnWallet();
35
45
  const [showLinkedProfilesList, setShowLinkedProfilesList] = useState(false);
36
46
  const [supportedMethods, setSupportedMethods] = useState([]);
37
47
  const [linkedMethods, setLinkedMethods] = useState([]);
@@ -61,19 +71,21 @@ export function ManageWalletModal({ ...props }) {
61
71
  const [showMfaDisableAuthModal, setShowMfaDisableAuthModal] = useState(false);
62
72
  const [showMfaDisableConfirmModal, setShowMfaDisableConfirmModal] = useState(false);
63
73
  const [showMfaStatusModal, setShowMfaStatusModal] = useState(false);
64
- const [mfaDisableStep, setMfaDisableStep] = useState("otp");
65
- const [mfaDisableCode, setMfaDisableCode] = useState("");
66
- const [mfaDisableRecoveryCode, setMfaDisableRecoveryCode] = useState("");
67
74
  const [mfaDisableLoading, setMfaDisableLoading] = useState(false);
68
75
  const [mfaDisableError, setMfaDisableError] = useState(null);
69
- const mfaDisableVerifyButtonRef = useRef(null);
70
76
  const hasFetchedLinkedProfilesForOpenRef = useRef(false);
71
77
  const linkedProfilesFetchPromiseRef = useRef(null);
78
+ const clearLinkUnlinkFeedback = useCallback(() => {
79
+ setLinkUnlinkError(null);
80
+ setLinkUnlinkSuccess(null);
81
+ }, []);
72
82
  const showFeedback = useCallback((message, type = "success") => {
73
83
  if (type === "error") {
84
+ setLinkUnlinkSuccess(null);
74
85
  setLinkUnlinkError(message);
75
86
  return;
76
87
  }
88
+ setLinkUnlinkError(null);
77
89
  setLinkUnlinkSuccess(message);
78
90
  }, []);
79
91
  const fetchLinkedProfilesData = useCallback(async () => {
@@ -115,21 +127,34 @@ export function ManageWalletModal({ ...props }) {
115
127
  });
116
128
  }, [getSupportedAuthMethods, getLinkedAuthMethods, isExternalWalletConnected, whoami]);
117
129
  const handleOpenLinkedProfiles = useCallback(() => {
130
+ clearLinkUnlinkFeedback();
118
131
  setShowLinkedProfilesList(true);
119
132
  const hasLinkedProfilesData = supportedMethods.length > 0 || linkedMethods.length > 0;
120
133
  if (!hasLinkedProfilesData && !linkedLoading) {
121
134
  fetchLinkedProfilesData();
122
135
  }
123
- }, [fetchLinkedProfilesData, linkedLoading, linkedMethods.length, supportedMethods.length]);
136
+ }, [
137
+ clearLinkUnlinkFeedback,
138
+ fetchLinkedProfilesData,
139
+ linkedLoading,
140
+ linkedMethods.length,
141
+ supportedMethods.length,
142
+ ]);
143
+ const handleCloseLinkedProfiles = useCallback(() => {
144
+ clearLinkUnlinkFeedback();
145
+ setShowLinkedProfilesList(false);
146
+ }, [clearLinkUnlinkFeedback]);
124
147
  const isProviderLinked = useCallback((provider) => {
125
148
  return linkedMethods.some((m) => normalizeLinkedProvider(m.authProvider) === provider.toLowerCase());
126
149
  }, [linkedMethods]);
127
150
  const handleConnect = useCallback(async (provider) => {
151
+ clearLinkUnlinkFeedback();
128
152
  if (provider.toLowerCase() === "email") {
129
153
  setEmailLinkStep("email");
130
154
  setEmailLinkEmail("");
131
155
  setEmailLinkOtpId(null);
132
156
  setEmailLinkOtpCode("");
157
+ setEmailLinkError(null);
133
158
  return;
134
159
  }
135
160
  if (!linkAuthMethod)
@@ -146,12 +171,12 @@ export function ManageWalletModal({ ...props }) {
146
171
  }
147
172
  catch (err) {
148
173
  const msg = err instanceof Error ? normalizeErrorMessage(err.message) : "Failed to connect";
149
- setLinkUnlinkError(msg);
174
+ showFeedback(msg, "error");
150
175
  }
151
176
  finally {
152
177
  setActionProvider(null);
153
178
  }
154
- }, [linkAuthMethod, fetchLinkedProfilesData, showFeedback]);
179
+ }, [clearLinkUnlinkFeedback, linkAuthMethod, fetchLinkedProfilesData, showFeedback]);
155
180
  const handleSendOtpForLink = useCallback(async () => {
156
181
  if (!emailLinkEmail.trim())
157
182
  return;
@@ -171,7 +196,6 @@ export function ManageWalletModal({ ...props }) {
171
196
  catch (err) {
172
197
  const msg = err instanceof Error ? normalizeErrorMessage(err.message) : "Failed to send OTP";
173
198
  setEmailLinkError(msg);
174
- showFeedback(msg, "error");
175
199
  }
176
200
  finally {
177
201
  setActionProvider(null);
@@ -195,7 +219,6 @@ export function ManageWalletModal({ ...props }) {
195
219
  catch (err) {
196
220
  const msg = err instanceof Error ? normalizeErrorMessage(err.message) : "Failed to resend";
197
221
  setEmailLinkError(msg);
198
- showFeedback(msg, "error");
199
222
  }
200
223
  finally {
201
224
  setEmailLinkResending(false);
@@ -220,7 +243,6 @@ export function ManageWalletModal({ ...props }) {
220
243
  catch (err) {
221
244
  const msg = err instanceof Error ? normalizeErrorMessage(err.message) : "Failed to link email";
222
245
  setEmailLinkError(msg);
223
- showFeedback(msg, "error");
224
246
  }
225
247
  finally {
226
248
  setActionProvider(null);
@@ -300,64 +322,38 @@ export function ManageWalletModal({ ...props }) {
300
322
  const resetMfaDisableState = useCallback(() => {
301
323
  setShowMfaDisableAuthModal(false);
302
324
  setShowMfaDisableConfirmModal(false);
303
- setMfaDisableStep("otp");
304
- setMfaDisableCode("");
305
- setMfaDisableRecoveryCode("");
306
325
  setMfaDisableError(null);
307
326
  setMfaDisableLoading(false);
308
327
  }, []);
309
- const handleMfaDisableVerifyCode = useCallback(async () => {
310
- if (!verifyMfa || mfaDisableCode.trim().length !== 6)
328
+ const handleMfaDisableVerify = useCallback(async (code) => {
329
+ // Must use verifySignMfa (/mfa/verify-sign): disable calls /sign/transaction,
330
+ // which requires sign step-up — login verifyMfa does not clear SIGN_MFA_REQUIRED.
331
+ if (!verifySignMfa)
311
332
  return;
312
333
  setMfaDisableLoading(true);
313
334
  setMfaDisableError(null);
314
335
  try {
315
- await verifyMfa(mfaDisableCode.trim());
336
+ await verifySignMfa(code);
316
337
  setShowMfaDisableAuthModal(false);
317
338
  setShowMfaDisableConfirmModal(true);
318
- setMfaDisableCode("");
319
339
  }
320
340
  catch (err) {
321
- setMfaDisableError(err instanceof Error ? normalizeErrorMessage(err.message) : "Invalid authentication code");
341
+ setMfaDisableError(err instanceof Error
342
+ ? normalizeErrorMessage(err.message)
343
+ : "Invalid authentication code");
322
344
  }
323
345
  finally {
324
346
  setMfaDisableLoading(false);
325
347
  }
326
- }, [verifyMfa, mfaDisableCode]);
327
- const handleMfaDisableVerifyRecoveryCode = useCallback(async () => {
328
- if (!verifyMfa)
329
- return;
330
- const trimmed = mfaDisableRecoveryCode.trim().toUpperCase();
331
- if (!/^[A-Z0-9]{8}$/.test(trimmed)) {
332
- setMfaDisableError("Please enter a valid 8-character backup code");
333
- return;
334
- }
335
- setMfaDisableLoading(true);
336
- setMfaDisableError(null);
337
- try {
338
- await verifyMfa(trimmed);
339
- setShowMfaDisableAuthModal(false);
340
- setShowMfaDisableConfirmModal(true);
341
- setMfaDisableRecoveryCode("");
342
- }
343
- catch (err) {
344
- setMfaDisableError(err instanceof Error ? normalizeErrorMessage(err.message) : "Invalid backup code");
345
- }
346
- finally {
347
- setMfaDisableLoading(false);
348
- }
349
- }, [verifyMfa, mfaDisableRecoveryCode]);
348
+ }, [verifySignMfa]);
350
349
  const openMfaDisableFlow = useCallback(() => {
351
- if (!verifyMfa || !disableMfaWithSignedPayload) {
350
+ if (!verifySignMfa || !disableMfaWithSignedPayload) {
352
351
  return;
353
352
  }
354
353
  setShowMfaStatusModal(false);
355
- setMfaDisableCode("");
356
- setMfaDisableRecoveryCode("");
357
- setMfaDisableStep("otp");
358
354
  setMfaDisableError(null);
359
355
  setShowMfaDisableAuthModal(true);
360
- }, [verifyMfa, disableMfaWithSignedPayload]);
356
+ }, [verifySignMfa, disableMfaWithSignedPayload]);
361
357
  const handleMfaDisableConfirm = useCallback(async () => {
362
358
  if (!disableMfaWithSignedPayload)
363
359
  return;
@@ -452,6 +448,7 @@ export function ManageWalletModal({ ...props }) {
452
448
  const handleDisconnect = useCallback(async (provider) => {
453
449
  if (!unlinkAuthMethod)
454
450
  return;
451
+ clearLinkUnlinkFeedback();
455
452
  setActionProvider(provider);
456
453
  try {
457
454
  await unlinkAuthMethod(provider);
@@ -460,7 +457,7 @@ export function ManageWalletModal({ ...props }) {
460
457
  const message = lower === "passkey"
461
458
  ? "Passkey removed successfully!"
462
459
  : "Provider unlinked successfully!";
463
- setLinkUnlinkSuccess(message);
460
+ showFeedback(message, "success");
464
461
  await fetchLinkedProfilesData();
465
462
  }
466
463
  catch (err) {
@@ -469,7 +466,7 @@ export function ManageWalletModal({ ...props }) {
469
466
  finally {
470
467
  setActionProvider(null);
471
468
  }
472
- }, [unlinkAuthMethod, fetchLinkedProfilesData, showFeedback]);
469
+ }, [clearLinkUnlinkFeedback, unlinkAuthMethod, fetchLinkedProfilesData, showFeedback]);
473
470
  useEffect(() => {
474
471
  if (emailLinkStep !== "otp" || emailLinkResendCooldown <= 0)
475
472
  return;
@@ -514,7 +511,7 @@ export function ManageWalletModal({ ...props }) {
514
511
  }
515
512
  setShowMfaSetupModal(false);
516
513
  resetMfaSetupState();
517
- }, "aria-label": "Back", children: _jsx(IoChevronBack, { size: 20 }) }), _jsx("h2", { className: "wallet-modal-receive-title", children: "Two-Factor Authentication" }), _jsx("button", { className: "wallet-modal-close", onClick: onClose, "aria-label": "Close", children: _jsx(IoClose, { size: 24 }) })] }), _jsx("div", { className: "mfa-redesign-content", children: mfaSetupStep === "setup" ? (_jsxs(_Fragment, { children: [_jsxs("div", { className: "mfa-info-box", children: [_jsx("div", { className: "mfa-info-icon", children: _jsx(IoPhonePortraitOutline, { size: 20 }) }), _jsx("p", { className: "mfa-info-text", children: "Open your authenticator app \u2014 Google Authenticator, Authy, or 1Password \u2014 and scan the QR code below." })] }), _jsxs("div", { className: "mfa-qr-container", children: [mfaQrCode ? (_jsx("div", { className: "mfa-qr-wrapper", children: _jsx(QRCodeSVG, { value: (() => {
514
+ }, "aria-label": "Back", children: _jsx(IoChevronBack, { size: 20 }) }), _jsx("h2", { className: "wallet-modal-receive-title", children: "Two-Factor Authentication" }), _jsx("button", { className: "wallet-modal-close", onClick: onClose, "aria-label": "Close", children: _jsx(CloseIcon, { size: 24 }) })] }), _jsx("div", { className: "mfa-redesign-content", children: mfaSetupStep === "setup" ? (_jsxs(_Fragment, { children: [_jsxs("div", { className: "mfa-info-box", children: [_jsx("div", { className: "mfa-info-icon", children: _jsx(IoPhonePortraitOutline, { size: 20 }) }), _jsx("p", { className: "mfa-info-text", children: "Open your authenticator app \u2014 Google Authenticator, Authy, or 1Password \u2014 and scan the QR code below." })] }), _jsxs("div", { className: "mfa-qr-container", children: [mfaQrCode ? (_jsx("div", { className: "mfa-qr-wrapper", children: _jsx(QRCodeSVG, { value: (() => {
518
515
  const issuer = organizationName ?? "Abstraxn";
519
516
  const label = userEmail ? `${issuer}:${userEmail}` : issuer;
520
517
  return `otpauth://totp/${encodeURIComponent(label)}?secret=${mfaSecret}&issuer=${encodeURIComponent(issuer)}`;
@@ -522,41 +519,9 @@ export function ManageWalletModal({ ...props }) {
522
519
  goToVerify();
523
520
  setMfaSetupCode("");
524
521
  setMfaRecoveryCode("");
525
- }, disabled: mfaSetupLoading || !mfaSecret, children: "Continue" })] })) : mfaSetupStep === "verify" ? (_jsxs("div", { className: "mfa-verification-section", children: [_jsx("div", { className: "mfa-divider", children: _jsx("span", { children: "Enter 6-digit verification code" }) }), mfaSetupError && (_jsx("p", { className: "mfa-setup-error", style: { marginBottom: 12 }, children: mfaSetupError })), _jsx("div", { className: "mfa-otp-grid", children: [0, 1, 2, 3, 4, 5].map((index) => (_jsx("div", { className: "mfa-otp-slot", children: _jsx("input", { type: "text", inputMode: "numeric", maxLength: 1, value: mfaSetupCode[index] || "", onChange: (e) => {
526
- const val = e.target.value.replace(/\D/g, "");
527
- if (val) {
528
- const newCode = mfaSetupCode.split("");
529
- newCode[index] = val;
530
- const combined = newCode.join("").slice(0, 6);
531
- setMfaSetupCode(combined);
532
- if (combined.length === 6) {
533
- window.setTimeout(() => {
534
- mfaSetupVerifyButtonRef.current?.focus();
535
- }, 0);
536
- }
537
- if (index < 5) {
538
- const target = e.target;
539
- const next = target.parentElement?.nextElementSibling?.querySelector("input");
540
- next?.focus();
541
- }
542
- }
543
- }, onKeyDown: (e) => {
544
- if (e.key === "Backspace") {
545
- const target = e.target;
546
- if (!mfaSetupCode[index] && index > 0) {
547
- const prev = target.parentElement?.previousElementSibling?.querySelector("input");
548
- prev?.focus();
549
- const newCode = mfaSetupCode.split("");
550
- newCode[index - 1] = "";
551
- setMfaSetupCode(newCode.join(""));
552
- }
553
- else {
554
- const newCode = mfaSetupCode.split("");
555
- newCode[index] = "";
556
- setMfaSetupCode(newCode.join(""));
557
- }
558
- }
559
- }, className: "mfa-otp-input" }) }, index))) }), _jsx("p", { className: "mfa-refresh-text", children: "Code refreshes every 30 seconds" }), _jsx("button", { ref: mfaSetupVerifyButtonRef, type: "button", className: "mfa-verify-button", onClick: handleVerifyMfaSetup, disabled: mfaSetupLoading || mfaSetupCode.length !== 6, children: mfaSetupLoading ? "Verifying..." : "Verify & continue" }), _jsxs("p", { className: "mfa-trouble-text", children: ["Having trouble?", " ", _jsx("button", { type: "button", className: "mfa-link-button", onClick: () => {
522
+ }, disabled: mfaSetupLoading || !mfaSecret, children: "Continue" })] })) : mfaSetupStep === "verify" ? (_jsxs("div", { className: "mfa-verification-section", children: [_jsx("div", { className: "mfa-divider", children: _jsx("span", { children: "Enter 6-digit verification code" }) }), mfaSetupError && (_jsx("p", { className: "mfa-setup-error", style: { marginBottom: 12 }, children: mfaSetupError })), _jsx(CodeInput, { length: 6, value: mfaSetupCode, onChange: setMfaSetupCode, onComplete: () => window.setTimeout(() => {
523
+ mfaSetupVerifyButtonRef.current?.focus();
524
+ }, 0) }), _jsx("p", { className: "mfa-refresh-text", children: "Code refreshes every 30 seconds" }), _jsx("button", { ref: mfaSetupVerifyButtonRef, type: "button", className: "mfa-verify-button", onClick: handleVerifyMfaSetup, disabled: mfaSetupLoading || mfaSetupCode.length !== 6, children: mfaSetupLoading ? "Verifying..." : "Verify & continue" }), _jsxs("p", { className: "mfa-trouble-text", children: ["Having trouble?", " ", _jsx("button", { type: "button", className: "mfa-link-button", onClick: () => {
560
525
  goToRecovery();
561
526
  setMfaRecoveryCode("");
562
527
  }, children: "Use a recovery code" })] })] })) : (_jsxs("div", { className: "mfa-recovery-section", children: [_jsx("div", { className: "mfa-divider", children: _jsx("span", { children: "Enter 8 charater backup code" }) }), mfaSetupError && (_jsx("p", { className: "mfa-setup-error", style: { marginBottom: 12 }, children: mfaSetupError })), _jsx("input", { type: "text", inputMode: "text", maxLength: 8, value: mfaRecoveryCode, onChange: (e) => {
@@ -571,68 +536,19 @@ export function ManageWalletModal({ ...props }) {
571
536
  }, children: _jsxs("div", { className: `wallet-modal-content wallet-modal-theme-${theme} wallet-modal-manage mfa-redesign-container`, onClick: (e) => e.stopPropagation(), children: [_jsxs("div", { className: "wallet-modal-receive-header", children: [_jsx("button", { className: "wallet-modal-back", onClick: () => {
572
537
  setShowMfaBackupModal(false);
573
538
  reset();
574
- }, "aria-label": "Back", children: _jsx(IoChevronBack, { size: 20 }) }), _jsx("h2", { className: "wallet-modal-receive-title", children: "Backup Codes" }), _jsx("button", { className: "wallet-modal-close", onClick: onClose, "aria-label": "Close", children: _jsx(IoClose, { size: 24 }) })] }), _jsxs("div", { className: "mfa-redesign-content", children: [_jsxs("div", { className: "mfa-info-box", children: [_jsx("div", { className: "mfa-info-icon", children: _jsx(IoKeyOutline, { size: 20 }) }), _jsx("p", { className: "mfa-info-text", children: "Backup codes can be used to access your account if you lose access to your primary authentication method. Store them securely as these codes will not be shown again." })] }), _jsx("div", { className: "wallet-modal-mfa-backup-heading", children: _jsx("span", { className: "wallet-modal-mfa-backup-heading-label", children: "Recovery Codes" }) }), _jsx("div", { className: "wallet-modal-mfa-backup-list", children: mfaBackupCodes.map((code, index) => (_jsx("div", { className: "wallet-modal-mfa-backup-code-wrapper", children: _jsx("code", { className: "wallet-modal-mfa-backup-code", children: code }) }, index))) }), _jsxs("div", { className: "wallet-modal-mfa-backup-actions", children: [_jsxs("button", { type: "button", className: `wallet-modal-mfa-backup-action-btn ${mfaBackupCodesCopied ? 'copied' : ''}`, onClick: handleCopyBackupCodes, disabled: !mfaBackupCodes.length, children: [mfaBackupCodesCopied ? _jsx(IoCheckmarkOutline, { size: 18 }) : _jsx(IoCopyOutline, { size: 18 }), mfaBackupCodesCopied ? "Copied" : "Copy All"] }), _jsxs("button", { type: "button", className: "wallet-modal-mfa-backup-action-btn", onClick: handleDownloadBackupCodes, disabled: !mfaBackupCodes.length, children: [_jsx(IoCloudDownloadOutline, { size: 18 }), "Download"] })] }), _jsx("button", { type: "button", className: "mfa-verify-button", onClick: () => {
539
+ }, "aria-label": "Back", children: _jsx(IoChevronBack, { size: 20 }) }), _jsx("h2", { className: "wallet-modal-receive-title", children: "Backup Codes" }), _jsx("button", { className: "wallet-modal-close", onClick: onClose, "aria-label": "Close", children: _jsx(CloseIcon, { size: 24 }) })] }), _jsxs("div", { className: "mfa-redesign-content", children: [_jsxs("div", { className: "mfa-info-box", children: [_jsx("div", { className: "mfa-info-icon", children: _jsx(IoKeyOutline, { size: 20 }) }), _jsx("p", { className: "mfa-info-text", children: "Backup codes can be used to access your account if you lose access to your primary authentication method. Store them securely as these codes will not be shown again." })] }), _jsx("div", { className: "wallet-modal-mfa-backup-heading", children: _jsx("span", { className: "wallet-modal-mfa-backup-heading-label", children: "Recovery Codes" }) }), _jsx("div", { className: "wallet-modal-mfa-backup-list", children: mfaBackupCodes.map((code, index) => (_jsx("div", { className: "wallet-modal-mfa-backup-code-wrapper", children: _jsx("code", { className: "wallet-modal-mfa-backup-code", children: code }) }, index))) }), _jsxs("div", { className: "wallet-modal-mfa-backup-actions", children: [_jsxs("button", { type: "button", className: `wallet-modal-mfa-backup-action-btn ${mfaBackupCodesCopied ? 'copied' : ''}`, onClick: handleCopyBackupCodes, disabled: !mfaBackupCodes.length, children: [mfaBackupCodesCopied ? _jsx(IoCheckmarkOutline, { size: 18 }) : _jsx(IoCopyOutline, { size: 18 }), mfaBackupCodesCopied ? "Copied" : "Copy All"] }), _jsxs("button", { type: "button", className: "wallet-modal-mfa-backup-action-btn", onClick: handleDownloadBackupCodes, disabled: !mfaBackupCodes.length, children: [_jsx(IoCloudDownloadOutline, { size: 18 }), "Download"] })] }), _jsx("button", { type: "button", className: "mfa-verify-button", onClick: () => {
575
540
  setShowMfaBackupModal(false);
576
541
  reset();
577
542
  }, children: "I've saved these codes" })] })] }) }));
578
543
  }
579
544
  if (showMfaDisableAuthModal) {
580
- return (_jsx("div", { className: `wallet-modal-overlay wallet-modal-theme-${theme}`, onClick: resetMfaDisableState, children: _jsxs("div", { className: `wallet-modal-content wallet-modal-theme-${theme} wallet-modal-manage mfa-redesign-container`, onClick: (e) => e.stopPropagation(), children: [_jsxs("div", { className: "wallet-modal-receive-header", children: [_jsx("button", { className: "wallet-modal-back", onClick: () => {
581
- if (mfaDisableStep === "recovery") {
582
- setMfaDisableStep("otp");
583
- setMfaDisableRecoveryCode("");
584
- setMfaDisableError(null);
585
- return;
586
- }
587
- resetMfaDisableState();
588
- }, "aria-label": "Back", children: _jsx(IoChevronBack, { size: 20 }) }), _jsx("h2", { className: "wallet-modal-receive-title", children: "Verify to disable 2FA" }), _jsx("button", { className: "wallet-modal-close", onClick: onClose, "aria-label": "Close", children: _jsx(IoClose, { size: 24 }) })] }), _jsxs("div", { className: "mfa-redesign-content", children: [_jsx("div", { className: "mfa-info-box", children: _jsx("p", { className: "mfa-info-text", children: "Enter your authentication code to continue." }) }), mfaDisableStep === "otp" ? (_jsxs("div", { className: "mfa-verification-section", children: [_jsx("div", { className: "mfa-divider", children: _jsx("span", { children: "Enter 6-digit verification code" }) }), mfaDisableError && (_jsx("p", { className: "mfa-setup-error", style: { marginBottom: 12 }, children: mfaDisableError })), _jsx("div", { className: "mfa-otp-grid", children: [0, 1, 2, 3, 4, 5].map((index) => (_jsx("div", { className: "mfa-otp-slot", children: _jsx("input", { type: "text", inputMode: "numeric", maxLength: 1, value: mfaDisableCode[index] || "", onChange: (e) => {
589
- const val = e.target.value.replace(/\D/g, "");
590
- if (val) {
591
- const newCode = mfaDisableCode.split("");
592
- newCode[index] = val;
593
- const combined = newCode.join("").slice(0, 6);
594
- setMfaDisableCode(combined);
595
- if (combined.length === 6) {
596
- window.setTimeout(() => {
597
- mfaDisableVerifyButtonRef.current?.focus();
598
- }, 0);
599
- }
600
- if (index < 5) {
601
- const target = e.target;
602
- const next = target.parentElement?.nextElementSibling?.querySelector("input");
603
- next?.focus();
604
- }
605
- }
606
- }, onKeyDown: (e) => {
607
- if (e.key === "Backspace") {
608
- const target = e.target;
609
- if (!mfaDisableCode[index] && index > 0) {
610
- const prev = target.parentElement?.previousElementSibling?.querySelector("input");
611
- prev?.focus();
612
- const newCode = mfaDisableCode.split("");
613
- newCode[index - 1] = "";
614
- setMfaDisableCode(newCode.join(""));
615
- }
616
- else {
617
- const newCode = mfaDisableCode.split("");
618
- newCode[index] = "";
619
- setMfaDisableCode(newCode.join(""));
620
- }
621
- }
622
- }, className: "mfa-otp-input" }) }, index))) }), _jsx("button", { ref: mfaDisableVerifyButtonRef, type: "button", className: "mfa-verify-button", onClick: handleMfaDisableVerifyCode, disabled: mfaDisableLoading || mfaDisableCode.length !== 6, children: mfaDisableLoading ? "Verifying..." : "Verify" }), _jsxs("p", { className: "mfa-trouble-text", children: ["Having trouble?", " ", _jsx("button", { type: "button", className: "mfa-link-button", onClick: () => {
623
- setMfaDisableStep("recovery");
624
- setMfaDisableError(null);
625
- setMfaDisableRecoveryCode("");
626
- }, children: "Use a backup code" })] })] })) : (_jsxs("div", { className: "mfa-recovery-section", children: [_jsx("div", { className: "mfa-divider", children: _jsx("span", { children: "Enter 8 charater backup code" }) }), mfaDisableError && (_jsx("p", { className: "mfa-setup-error", style: { marginBottom: 12 }, children: mfaDisableError })), _jsx("input", { type: "text", inputMode: "text", maxLength: 8, value: mfaDisableRecoveryCode, onChange: (e) => {
627
- const val = e.target.value.toUpperCase().replace(/[^A-Z0-9]/g, "").slice(0, 8);
628
- setMfaDisableRecoveryCode(val);
629
- }, className: "mfa-recovery-field" }), _jsx("button", { type: "button", className: "mfa-verify-button", onClick: handleMfaDisableVerifyRecoveryCode, disabled: mfaDisableLoading || mfaDisableRecoveryCode.trim().length !== 8, children: mfaDisableLoading ? "Verifying..." : "Verify" })] }))] })] }) }));
545
+ return (_jsx(MfaVerifyModal, { isOpen: true, theme: theme, title: "Verify to disable 2FA", description: "Enter your authentication code to continue.", loading: mfaDisableLoading, error: mfaDisableError, onSubmit: handleMfaDisableVerify, onCancel: resetMfaDisableState }));
630
546
  }
631
547
  if (showMfaStatusModal) {
632
- return (_jsx("div", { className: `wallet-modal-overlay wallet-modal-theme-${theme}`, onClick: () => setShowMfaStatusModal(false), children: _jsxs("div", { className: `wallet-modal-content wallet-modal-theme-${theme} wallet-modal-manage mfa-redesign-container`, onClick: (e) => e.stopPropagation(), children: [_jsxs("div", { className: "wallet-modal-receive-header", children: [_jsx("button", { className: "wallet-modal-back", onClick: () => setShowMfaStatusModal(false), "aria-label": "Back", children: _jsx(IoChevronBack, { size: 20 }) }), _jsx("h2", { className: "wallet-modal-receive-title", children: "MFA" }), _jsx("button", { className: "wallet-modal-close", onClick: onClose, "aria-label": "Close", children: _jsx(IoClose, { size: 24 }) })] }), _jsxs("div", { className: "mfa-redesign-content", children: [_jsxs("div", { className: "mfa-info-box mfa-status-enabled-box", children: [_jsx("div", { className: "mfa-info-icon mfa-status-enabled-icon", children: _jsx(IoCheckmarkOutline, { size: 22 }) }), _jsxs("div", { className: "mfa-status-enabled-copy", children: [_jsx("p", { className: "mfa-status-enabled-title", children: "MFA is enabled" }), _jsx("p", { className: "mfa-info-text", children: "Your wallet is protected with an additional verification step." })] })] }), _jsx("button", { type: "button", className: "mfa-verify-button mfa-disable-primary-button", onClick: openMfaDisableFlow, children: "Disable MFA" })] })] }) }));
548
+ return (_jsx("div", { className: `wallet-modal-overlay wallet-modal-theme-${theme}`, onClick: () => setShowMfaStatusModal(false), children: _jsxs("div", { className: `wallet-modal-content wallet-modal-theme-${theme} wallet-modal-manage mfa-redesign-container`, onClick: (e) => e.stopPropagation(), children: [_jsxs("div", { className: "wallet-modal-receive-header", children: [_jsx("button", { className: "wallet-modal-back", onClick: () => setShowMfaStatusModal(false), "aria-label": "Back", children: _jsx(IoChevronBack, { size: 20 }) }), _jsx("h2", { className: "wallet-modal-receive-title", children: "MFA" }), _jsx("button", { className: "wallet-modal-close", onClick: onClose, "aria-label": "Close", children: _jsx(CloseIcon, { size: 24 }) })] }), _jsxs("div", { className: "mfa-redesign-content", children: [_jsxs("div", { className: "mfa-info-box mfa-status-enabled-box", children: [_jsx("div", { className: "mfa-info-icon mfa-status-enabled-icon", children: _jsx(IoCheckmarkOutline, { size: 22 }) }), _jsxs("div", { className: "mfa-status-enabled-copy", children: [_jsx("p", { className: "mfa-status-enabled-title", children: "MFA is enabled" }), _jsx("p", { className: "mfa-info-text", children: "Your wallet is protected with an additional verification step." })] })] }), _jsx("button", { type: "button", className: "mfa-verify-button mfa-disable-primary-button", onClick: openMfaDisableFlow, children: "Disable MFA" })] })] }) }));
633
549
  }
634
550
  if (showLinkedProfilesList) {
635
- return (_jsx("div", { className: `wallet-modal-overlay wallet-modal-theme-${theme}`, onClick: () => setShowLinkedProfilesList(false), children: _jsxs("div", { className: `wallet-modal-content wallet-modal-theme-${theme} wallet-modal-manage`, onClick: (e) => e.stopPropagation(), children: [_jsxs("div", { className: "wallet-modal-receive-header", children: [_jsx("button", { className: "wallet-modal-back", onClick: () => emailLinkStep ? cancelEmailLink() : setShowLinkedProfilesList(false), "aria-label": "Back", children: _jsx(IoChevronBack, { size: 20 }) }), _jsx("h2", { className: "wallet-modal-receive-title", children: emailLinkStep ? "Link email" : "Auth Methods" }), _jsx("button", { className: "wallet-modal-close", onClick: onClose, "aria-label": "Close", children: _jsx(IoClose, { size: 24 }) })] }), _jsx("div", { className: "wallet-modal-manage-content", children: emailLinkStep ? (_jsx("div", { className: "wallet-modal-email-link-flow", children: emailLinkStep === "email" ? (_jsxs("form", { className: "wallet-modal-email-link-form", onSubmit: (e) => {
551
+ return (_jsx("div", { className: `wallet-modal-overlay wallet-modal-theme-${theme}`, onClick: handleCloseLinkedProfiles, children: _jsxs("div", { className: `wallet-modal-content wallet-modal-theme-${theme} wallet-modal-manage`, onClick: (e) => e.stopPropagation(), children: [_jsxs("div", { className: "wallet-modal-receive-header", children: [_jsx("button", { className: "wallet-modal-back", onClick: () => emailLinkStep ? cancelEmailLink() : handleCloseLinkedProfiles(), "aria-label": "Back", children: _jsx(IoChevronBack, { size: 20 }) }), _jsx("h2", { className: "wallet-modal-receive-title", children: emailLinkStep ? "Link email" : "Auth Methods" }), _jsx("button", { className: "wallet-modal-close", onClick: onClose, "aria-label": "Close", children: _jsx(CloseIcon, { size: 24 }) })] }), _jsx("div", { className: "wallet-modal-manage-content", children: emailLinkStep ? (_jsx("div", { className: "wallet-modal-email-link-flow", children: emailLinkStep === "email" ? (_jsxs("form", { className: "wallet-modal-email-link-form", onSubmit: (e) => {
636
552
  e.preventDefault();
637
553
  if (!actionProvider && emailLinkEmail.trim()) {
638
554
  handleSendOtpForLink();
@@ -641,7 +557,7 @@ export function ManageWalletModal({ ...props }) {
641
557
  emailLinkOtpInputsRef.current[index] = el;
642
558
  }, type: "text", inputMode: "numeric", maxLength: 1, className: "mfa-otp-input", value: emailLinkOtpCode[index] || "", onChange: (e) => handleEmailLinkOtpChange(index, e.target.value), onKeyDown: (e) => handleEmailLinkOtpKeyDown(index, e), disabled: actionProvider === "email" || emailLinkResending }) }, index))) }), _jsx("button", { type: "button", className: "wallet-modal-email-link-button", onClick: handleLinkEmailSubmit, disabled: actionProvider === "email" ||
643
559
  emailLinkResending ||
644
- emailLinkOtpCode.trim().length !== 6, children: actionProvider === "email" ? "Linking..." : "Link email" }), _jsxs("p", { className: "wallet-modal-email-link-resend", children: ["Didn't receive the code?", " ", emailLinkResendCooldown > 0 ? (_jsxs("span", { className: "wallet-modal-email-link-resend-cooldown", children: ["Resend in ", emailLinkResendCooldown, "s"] })) : (_jsx("button", { type: "button", className: "wallet-modal-email-link-resend-button", onClick: handleResendOtpForLink, disabled: emailLinkResending || actionProvider === "email", children: emailLinkResending ? "Sending..." : "Resend code" }))] })] })) })) : (_jsxs("div", { className: "wallet-modal-linked-profiles-list", children: [linkedLoading && (_jsx("div", { className: "wallet-modal-linked-profiles-loading", children: "Loading..." })), linkedError && !linkedLoading && (_jsx("div", { className: "wallet-modal-linked-profiles-error", children: linkedError })), !linkedLoading && !linkedError && supportedMethods.length === 0 && (_jsx("div", { className: "wallet-modal-linked-profiles-empty", children: "No auth methods available." })), !linkedLoading &&
560
+ emailLinkOtpCode.trim().length !== 6, children: actionProvider === "email" ? "Linking..." : "Link email" }), _jsxs("p", { className: "wallet-modal-email-link-resend", children: ["Didn't receive the code?", " ", emailLinkResendCooldown > 0 ? (_jsxs("span", { className: "wallet-modal-email-link-resend-cooldown", children: ["Resend in ", emailLinkResendCooldown, "s"] })) : (_jsx("button", { type: "button", className: "wallet-modal-email-link-resend-button", onClick: handleResendOtpForLink, disabled: emailLinkResending || actionProvider === "email", children: emailLinkResending ? "Sending..." : "Resend code" }))] })] })) })) : (_jsxs("div", { className: "wallet-modal-linked-profiles-list", children: [linkedLoading && (_jsx("div", { className: "wallet-modal-linked-profiles-loading", children: "Loading..." })), linkedError && !linkedLoading && (_jsx("div", { className: "wallet-modal-linked-profiles-error", children: linkedError })), !linkedLoading && linkUnlinkSuccess && (_jsx("div", { className: "wallet-modal-linked-profiles-success", role: "status", children: linkUnlinkSuccess })), !linkedLoading && !linkedError && supportedMethods.length === 0 && (_jsx("div", { className: "wallet-modal-linked-profiles-empty", children: "No auth methods available." })), !linkedLoading &&
645
561
  supportedMethods.map((method) => {
646
562
  const linked = isProviderLinked(method.provider);
647
563
  const busy = actionProvider === method.provider;
@@ -663,9 +579,10 @@ export function ManageWalletModal({ ...props }) {
663
579
  ? `Passkey ID: ${unlinkConfirm.id}`
664
580
  : `Provider ID: ${unlinkConfirm.id}` }))] }), _jsx("button", { type: "button", className: "wallet-modal-unlink-confirm-btn", onClick: () => handleDisconnect(unlinkConfirm.provider), disabled: actionProvider === unlinkConfirm.provider, children: unlinkConfirm.provider.toLowerCase() === "passkey"
665
581
  ? "Remove Passkey"
666
- : "Remove Provider" }), _jsx("button", { type: "button", className: "wallet-modal-unlink-confirm-close", onClick: () => setUnlinkConfirm(null), "aria-label": "Close", children: _jsx(IoClose, { size: 24 }) })] }) }), document.body)] }) }));
582
+ : "Remove Provider" }), _jsx("button", { type: "button", className: "wallet-modal-unlink-confirm-close", onClick: () => setUnlinkConfirm(null), "aria-label": "Close", children: _jsx(CloseIcon, { size: 24 }) })] }) }), portalTarget), linkUnlinkError &&
583
+ createPortal(_jsx("div", { className: `wallet-modal-overlay wallet-modal-overlay-layer2 wallet-modal-theme-${theme}`, onClick: () => setLinkUnlinkError(null), children: _jsxs("div", { className: `wallet-modal-content wallet-modal-theme-${theme} wallet-modal-unlink-confirm-modal`, onClick: (e) => e.stopPropagation(), role: "alertdialog", "aria-modal": "true", "aria-labelledby": "wallet-modal-auth-error-title", "aria-describedby": "wallet-modal-auth-error-message", children: [_jsx("div", { className: "wallet-modal-unlink-confirm-icon", "aria-hidden": "true", children: _jsxs("svg", { width: "48", height: "48", viewBox: "0 0 24 24", fill: "none", children: [_jsx("circle", { cx: "12", cy: "12", r: "10", fill: "#ef4444" }), _jsx("path", { d: "M12 8v4M12 16h.01", stroke: "#ffffff", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" })] }) }), _jsx("h3", { id: "wallet-modal-auth-error-title", className: "wallet-modal-unlink-confirm-title", children: "Error" }), _jsx("p", { id: "wallet-modal-auth-error-message", className: "wallet-modal-auth-error-message", children: linkUnlinkError }), _jsx("button", { type: "button", className: "wallet-modal-unlink-confirm-btn", onClick: () => setLinkUnlinkError(null), children: "Ok" }), _jsx("button", { type: "button", className: "wallet-modal-unlink-confirm-close", onClick: () => setLinkUnlinkError(null), "aria-label": "Close", children: _jsx(CloseIcon, { size: 24 }) })] }) }), portalTarget)] }) }));
667
584
  }
668
- return (_jsx("div", { className: `wallet-modal-overlay wallet-modal-theme-${theme}`, onClick: onClose, children: _jsxs("div", { className: `wallet-modal-content wallet-modal-theme-${theme} wallet-modal-manage`, onClick: (e) => e.stopPropagation(), children: [_jsxs("div", { className: "wallet-modal-receive-header", children: [_jsx("button", { className: "wallet-modal-back", onClick: onClose, "aria-label": "Back", children: _jsx(IoChevronBack, { size: 20 }) }), _jsx("h2", { className: "wallet-modal-receive-title", children: "Manage Wallet" }), _jsx("button", { className: "wallet-modal-close", onClick: onClose, "aria-label": "Close", children: _jsx(IoClose, { size: 24 }) })] }), _jsx("div", { className: "wallet-modal-manage-content", children: _jsxs("div", { className: "wallet-modal-manage-list", children: [!isExternalWalletConnected && (_jsxs("button", { className: "wallet-modal-manage-list-item", onClick: handleOpenLinkedProfiles, type: "button", children: [_jsx("div", { className: "wallet-modal-manage-list-icon", "aria-hidden": "true", children: _jsx(FiUsers, { size: 20 }) }), _jsx("span", { className: "wallet-modal-manage-list-label", children: "Auth Methods" }), _jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", className: "wallet-modal-manage-list-arrow", "aria-hidden": "true", children: _jsx("path", { d: "M6 12L10 8L6 4", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) })] })), !isExternalWalletConnected && (_jsxs("button", { className: "wallet-modal-manage-list-item", onClick: () => {
585
+ return (_jsx("div", { className: `wallet-modal-overlay wallet-modal-theme-${theme}`, onClick: onClose, children: _jsxs("div", { className: `wallet-modal-content wallet-modal-theme-${theme} wallet-modal-manage`, onClick: (e) => e.stopPropagation(), children: [_jsxs("div", { className: "wallet-modal-receive-header", children: [_jsx("button", { className: "wallet-modal-back", onClick: onClose, "aria-label": "Back", children: _jsx(IoChevronBack, { size: 20 }) }), _jsx("h2", { className: "wallet-modal-receive-title", children: "Manage Wallet" }), _jsx("button", { className: "wallet-modal-close", onClick: onClose, "aria-label": "Close", children: _jsx(CloseIcon, { size: 24 }) })] }), _jsx("div", { className: "wallet-modal-manage-content", children: _jsxs("div", { className: "wallet-modal-manage-list", children: [!isExternalWalletConnected && (_jsxs("button", { className: "wallet-modal-manage-list-item", onClick: handleOpenLinkedProfiles, type: "button", children: [_jsx("div", { className: "wallet-modal-manage-list-icon", "aria-hidden": "true", children: _jsx(FiUsers, { size: 20 }) }), _jsx("span", { className: "wallet-modal-manage-list-label", children: "Auth Methods" }), _jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", className: "wallet-modal-manage-list-arrow", "aria-hidden": "true", children: _jsx("path", { d: "M6 12L10 8L6 4", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) })] })), !isExternalWalletConnected && (_jsxs("button", { className: "wallet-modal-manage-list-item", onClick: () => {
669
586
  if (mfaStatusLoading)
670
587
  return;
671
588
  if (!canEnableMfaFlow) {
@@ -677,7 +594,7 @@ export function ManageWalletModal({ ...props }) {
677
594
  }
678
595
  startMfaSetup();
679
596
  }, type: "button", children: [_jsx("div", { className: "wallet-modal-manage-list-icon", "aria-hidden": "true", children: _jsx(BiShieldQuarter, { size: 20 }) }), _jsx("span", { className: "wallet-modal-manage-list-label", children: "MFA" }), _jsx("span", { className: `wallet-modal-mfa-badge ${mfaStatus?.enabled ? "wallet-modal-mfa-badge-enabled" : "wallet-modal-mfa-badge-disabled"}`, "aria-hidden": "true", children: mfaStatus?.enabled ? "Enabled" : "Disabled" }), _jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", className: "wallet-modal-manage-list-arrow", "aria-hidden": "true", children: _jsx("path", { d: "M6 12L10 8L6 4", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) })] })), _jsxs("button", { className: "wallet-modal-manage-list-item", onClick: () => showFeedback("Coming soon", "success"), type: "button", children: [_jsx("div", { className: "wallet-modal-manage-list-icon", "aria-hidden": "true", children: _jsx(SiWalletconnect, { size: 20 }) }), _jsx("span", { className: "wallet-modal-manage-list-label", children: "Connect an App" }), _jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", className: "wallet-modal-manage-list-arrow", "aria-hidden": "true", children: _jsx("path", { d: "M6 12L10 8L6 4", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) })] }), !isExternalWalletConnected && (_jsxs("button", { className: "wallet-modal-manage-list-item", onClick: onExportPrivateKey, type: "button", children: [_jsx("div", { className: "wallet-modal-manage-list-icon", "aria-hidden": "true", children: _jsx(IoKeyOutline, { size: 20 }) }), _jsx("span", { className: "wallet-modal-manage-list-label", children: "Export Private Key" }), _jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", className: "wallet-modal-manage-list-arrow", "aria-hidden": "true", children: _jsx("path", { d: "M6 12L10 8L6 4", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) })] }))] }) }), showMfaDisableConfirmModal &&
680
- createPortal(_jsx("div", { className: `wallet-modal-overlay wallet-modal-overlay-layer2 wallet-modal-theme-${theme}`, onClick: () => resetMfaDisableState(), children: _jsxs("div", { className: `wallet-modal-content wallet-modal-theme-${theme} wallet-modal-unlink-confirm-modal`, onClick: (e) => e.stopPropagation(), children: [_jsx("div", { className: "wallet-modal-unlink-confirm-icon", "aria-hidden": "true", children: _jsxs("svg", { width: "48", height: "48", viewBox: "0 0 24 24", fill: "none", children: [_jsx("circle", { cx: "12", cy: "12", r: "10", fill: "#ef4444" }), _jsx("path", { d: "M12 8v4M12 16h.01", stroke: "#ffffff", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" })] }) }), _jsx("h3", { className: "wallet-modal-unlink-confirm-title", children: "Disable two-factor authentication" }), _jsx("p", { className: "wallet-modal-unlink-confirm-subtitle", children: "You are about to disable two-factor authentication. Your account will be less secure. Do you want to continue?" }), mfaDisableError && (_jsx("p", { className: "mfa-setup-error", style: { marginBottom: 12 }, children: mfaDisableError })), _jsxs("div", { className: "wallet-modal-mfa-disable-actions", children: [_jsx("button", { type: "button", className: "wallet-modal-unlink-confirm-btn wallet-modal-mfa-disable-cancel", onClick: () => resetMfaDisableState(), disabled: mfaDisableLoading, children: "Cancel" }), _jsx("button", { type: "button", className: "wallet-modal-unlink-confirm-btn", onClick: () => handleMfaDisableConfirm(), disabled: mfaDisableLoading, children: mfaDisableLoading ? "Disabling..." : "Confirm disable" })] }), _jsx("button", { type: "button", className: "wallet-modal-unlink-confirm-close", onClick: () => resetMfaDisableState(), "aria-label": "Close", children: _jsx(IoClose, { size: 24 }) })] }) }), document.body), unlinkConfirm &&
597
+ createPortal(_jsx("div", { className: `wallet-modal-overlay wallet-modal-overlay-layer2 wallet-modal-theme-${theme}`, onClick: () => resetMfaDisableState(), children: _jsxs("div", { className: `wallet-modal-content wallet-modal-theme-${theme} wallet-modal-unlink-confirm-modal`, onClick: (e) => e.stopPropagation(), children: [_jsx("div", { className: "wallet-modal-unlink-confirm-icon", "aria-hidden": "true", children: _jsxs("svg", { width: "48", height: "48", viewBox: "0 0 24 24", fill: "none", children: [_jsx("circle", { cx: "12", cy: "12", r: "10", fill: "#ef4444" }), _jsx("path", { d: "M12 8v4M12 16h.01", stroke: "#ffffff", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" })] }) }), _jsx("h3", { className: "wallet-modal-unlink-confirm-title", children: "Disable two-factor authentication" }), _jsx("p", { className: "wallet-modal-unlink-confirm-subtitle", children: "You are about to disable two-factor authentication. Your account will be less secure. Do you want to continue?" }), mfaDisableError && (_jsx("p", { className: "mfa-setup-error", style: { marginBottom: 12 }, children: mfaDisableError })), _jsxs("div", { className: "wallet-modal-mfa-disable-actions", children: [_jsx("button", { type: "button", className: "wallet-modal-unlink-confirm-btn wallet-modal-mfa-disable-cancel", onClick: () => resetMfaDisableState(), disabled: mfaDisableLoading, children: "Cancel" }), _jsx("button", { type: "button", className: "wallet-modal-unlink-confirm-btn", onClick: () => handleMfaDisableConfirm(), disabled: mfaDisableLoading, children: mfaDisableLoading ? "Disabling..." : "Confirm disable" })] }), _jsx("button", { type: "button", className: "wallet-modal-unlink-confirm-close", onClick: () => resetMfaDisableState(), "aria-label": "Close", children: _jsx(CloseIcon, { size: 24 }) })] }) }), portalTarget), unlinkConfirm &&
681
598
  createPortal(_jsx("div", { className: `wallet-modal-overlay wallet-modal-overlay-layer2 wallet-modal-theme-${theme}`, onClick: () => setUnlinkConfirm(null), children: _jsxs("div", { className: `wallet-modal-content wallet-modal-theme-${theme} wallet-modal-unlink-confirm-modal`, onClick: (e) => e.stopPropagation(), children: [_jsx("div", { className: "wallet-modal-unlink-confirm-icon", "aria-hidden": "true", children: _jsxs("svg", { width: "48", height: "48", viewBox: "0 0 24 24", fill: "none", children: [_jsx("circle", { cx: "12", cy: "12", r: "10", fill: "#ef4444" }), _jsx("path", { d: "M12 8v4M12 16h.01", stroke: "#ffffff", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" })] }) }), _jsx("h3", { className: "wallet-modal-unlink-confirm-title", children: unlinkConfirm.provider.toLowerCase() === "passkey"
682
599
  ? "Remove Passkey"
683
600
  : "Remove OAuth Provider" }), _jsx("p", { className: "wallet-modal-unlink-confirm-subtitle", children: "This action is irreversible." }), _jsxs("div", { className: "wallet-modal-unlink-confirm-details", children: [_jsx("p", { className: "wallet-modal-unlink-confirm-details-line", children: unlinkConfirm.provider.toLowerCase() === "passkey"
@@ -691,8 +608,9 @@ export function ManageWalletModal({ ...props }) {
691
608
  alignItems: "center",
692
609
  gap: "6px",
693
610
  verticalAlign: "middle",
694
- }, children: [_jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: "18", height: "18", viewBox: "0 0 48 48", fill: "none", style: { display: "inline-block", verticalAlign: "middle" }, children: [_jsx("path", { d: "M47.9082 37.191L23.9541 23.553L0 9.91504L37.7436 -8.13502e-06L47.9082 37.191Z", fill: "url(#paint0_linear_unlink_footer)" }), _jsx("path", { d: "M13.5156 46.3594L10.1846 47.2344L8.99219 42.873L12.4365 42.4111L13.5156 46.3594ZM20.4268 44.5566L17.1152 45.4199L16.125 41.8818L19.5566 41.3721L20.4268 44.5566ZM26.9307 42.834L23.6152 43.6982L22.8438 40.9443L26.2744 40.4326L26.9307 42.834ZM33.5078 41.1074L30.1875 41.9727L29.6328 39.9951L33.0635 39.4844L33.5078 41.1074ZM39.998 39.4014L36.6729 40.2686L36.3359 39.0674L39.7656 38.5508L39.998 39.4014ZM10.1406 33.9434L11.6807 39.5762L8.15918 39.7568L6.46094 33.543L10.1406 33.9434ZM17.6582 34.5996L18.8916 39.1113L15.4199 39.3496L14.0078 34.3076L17.6582 34.5996ZM24.8779 35.332L25.8047 38.7227L22.3252 38.959L21.2266 35.0361L24.8779 35.332ZM32.0918 36.0723L32.7119 38.3398L29.2227 38.5723L28.4375 35.7656L32.0918 36.0723ZM43.2373 38.5488L43.1172 38.1172L47.7939 37.3516L43.2373 38.5488ZM39.3047 36.8096L39.6182 37.9561L36.1221 38.1846L35.6484 36.4961L39.3047 36.8096ZM47.7939 37.3516L43.0107 37.7939L42.8516 37.2236L47.7939 37.3516ZM47.8291 37.2988L42.7227 36.7529L42.5547 36.1523L47.8291 37.2988ZM47.8652 37.2412L42.3711 35.3486L42.2031 34.7471L47.8652 37.2412ZM38.748 34.8604L39.0664 36.0254L35.3369 35.4043L34.8594 33.6982L38.748 34.8604ZM31.0576 32.3994L31.6787 34.6709L27.959 34.0566L27.1719 31.2461L31.0576 32.3994ZM38.0811 32.6318L38.4092 33.8301L34.4893 32.3496L34.1543 31.1523C34.1005 30.9591 34.0322 30.7719 33.9531 30.5918L38.0811 32.6318ZM23.3682 29.9385L24.291 33.3164L20.5801 32.71L19.4844 28.7949L23.3682 29.9385ZM15.6641 27.4805L16.8896 31.9629L13.1875 31.3594L11.7812 26.3379L15.6641 27.4805ZM29.9463 28.4678L30.5693 30.748L26.6201 29.2812L25.8633 26.583C25.8534 26.5431 25.8417 26.5028 25.8281 26.4639L29.9463 28.4678ZM7.6875 25.0938L9.21484 30.6816L5.44727 29.959L3.75781 23.7793L7.6875 25.0938ZM21.5312 23.3623L22.4492 26.7227L18.5059 25.2627L17.4141 21.3643L21.5312 23.3623ZM13.6104 20.1602L14.8242 24.6006L10.8887 23.1387L9.49219 18.1553L13.6104 20.1602ZM5.2168 16.0654L6.72559 21.585L2.70703 19.9473L1.06055 13.8701L5.2168 16.0654Z", fill: "url(#paint1_linear_unlink_footer)" }), _jsxs("defs", { children: [_jsxs("linearGradient", { id: "paint0_linear_unlink_footer", x1: "7.03362", y1: "6.09543", x2: "47.2003", y2: "57.0656", gradientUnits: "userSpaceOnUse", children: [_jsx("stop", { stopColor: "#F878D2" }), _jsx("stop", { offset: "0.393522", stopColor: "#FDCC81" }), _jsx("stop", { offset: "1", stopColor: "#F9A0D9" })] }), _jsxs("linearGradient", { id: "paint1_linear_unlink_footer", x1: "2.53739", y1: "21.5136", x2: "48.7969", y2: "38.5742", gradientUnits: "userSpaceOnUse", children: [_jsx("stop", { stopColor: "#F878D2" }), _jsx("stop", { offset: "0.393522", stopColor: "#FDCC81" }), _jsx("stop", { offset: "1", stopColor: "#F9A0D9" })] })] })] }), _jsx("span", { style: {
611
+ }, children: [_jsx(AbstraxnLogo, { size: 18, gradientId: "abstraxn_logo_unlink_footer" }), _jsx("span", { style: {
695
612
  color: theme === "dark" ? "#ffffff" : "#111827",
696
- }, children: "abstraxn" })] })] }) }), _jsx("button", { type: "button", className: "wallet-modal-unlink-confirm-close", onClick: () => setUnlinkConfirm(null), "aria-label": "Close", children: _jsx(IoClose, { size: 24 }) })] }) }), document.body)] }) }));
613
+ }, children: "abstraxn" })] })] }) }), _jsx("button", { type: "button", className: "wallet-modal-unlink-confirm-close", onClick: () => setUnlinkConfirm(null), "aria-label": "Close", children: _jsx(CloseIcon, { size: 24 }) })] }) }), portalTarget), linkUnlinkError &&
614
+ createPortal(_jsx("div", { className: `wallet-modal-overlay wallet-modal-overlay-layer2 wallet-modal-theme-${theme}`, onClick: () => setLinkUnlinkError(null), children: _jsxs("div", { className: `wallet-modal-content wallet-modal-theme-${theme} wallet-modal-unlink-confirm-modal`, onClick: (e) => e.stopPropagation(), role: "alertdialog", "aria-modal": "true", "aria-labelledby": "wallet-modal-auth-error-title-main", "aria-describedby": "wallet-modal-auth-error-message-main", children: [_jsx("div", { className: "wallet-modal-unlink-confirm-icon", "aria-hidden": "true", children: _jsxs("svg", { width: "48", height: "48", viewBox: "0 0 24 24", fill: "none", children: [_jsx("circle", { cx: "12", cy: "12", r: "10", fill: "#ef4444" }), _jsx("path", { d: "M12 8v4M12 16h.01", stroke: "#ffffff", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" })] }) }), _jsx("h3", { id: "wallet-modal-auth-error-title-main", className: "wallet-modal-unlink-confirm-title", children: "Error" }), _jsx("p", { id: "wallet-modal-auth-error-message-main", className: "wallet-modal-auth-error-message", children: linkUnlinkError }), _jsx("button", { type: "button", className: "wallet-modal-unlink-confirm-btn", onClick: () => setLinkUnlinkError(null), children: "Ok" }), _jsx("button", { type: "button", className: "wallet-modal-unlink-confirm-close", onClick: () => setLinkUnlinkError(null), "aria-label": "Close", children: _jsx(CloseIcon, { size: 24 }) })] }) }), portalTarget)] }) }));
697
615
  }
698
616
  //# sourceMappingURL=ManageWalletModal.js.map
@@ -0,0 +1,15 @@
1
+ export interface MfaVerifyModalProps {
2
+ isOpen: boolean;
3
+ theme?: "light" | "dark";
4
+ title: string;
5
+ description?: string;
6
+ submitLabel?: string;
7
+ loadingLabel?: string;
8
+ loading?: boolean;
9
+ error?: string | null;
10
+ /** When true, portals to document.body with its own ShadowHost (sign step-up). */
11
+ portal?: boolean;
12
+ onSubmit: (code: string) => void;
13
+ onCancel: () => void;
14
+ }
15
+ export declare function MfaVerifyModal({ isOpen, theme, title, description, submitLabel, loadingLabel, loading, error, portal, onSubmit, onCancel, }: MfaVerifyModalProps): import("react/jsx-runtime").JSX.Element | null;
@@ -0,0 +1,98 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * Shared MFA verify UI (OTP + backup code) used by:
4
+ * - Manage Wallet → disable 2FA
5
+ * - Signing step-up (SIGN_MFA_REQUIRED) via SignMfaModalHost
6
+ */
7
+ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
8
+ import { createPortal } from "react-dom";
9
+ import { CloseIcon, IoChevronBack } from "../../icons";
10
+ import { ShadowHost, ShadowHostContext } from "../../ShadowHost";
11
+ import { CodeInput } from "./CodeInput";
12
+ import walletModalCss from "../../../WalletModal.css.js";
13
+ import manageWalletModalCss from "./ManageWalletModal.css.js";
14
+ const MFA_VERIFY_PORTAL_CSS = [walletModalCss, manageWalletModalCss];
15
+ export function MfaVerifyModal({ isOpen, theme = "light", title, description = "Enter your authentication code to continue.", submitLabel = "Verify", loadingLabel = "Verifying...", loading = false, error = null, portal = false, onSubmit, onCancel, }) {
16
+ const [step, setStep] = useState("otp");
17
+ const [otpCode, setOtpCode] = useState("");
18
+ const [recoveryCode, setRecoveryCode] = useState("");
19
+ const [localError, setLocalError] = useState(null);
20
+ const submitRef = useRef(null);
21
+ useEffect(() => {
22
+ if (!isOpen) {
23
+ setStep("otp");
24
+ setOtpCode("");
25
+ setRecoveryCode("");
26
+ setLocalError(null);
27
+ }
28
+ }, [isOpen]);
29
+ useEffect(() => {
30
+ if (!isOpen)
31
+ return;
32
+ const onKey = (e) => {
33
+ if (e.key === "Escape" && !loading)
34
+ onCancel();
35
+ };
36
+ window.addEventListener("keydown", onKey);
37
+ return () => window.removeEventListener("keydown", onKey);
38
+ }, [isOpen, loading, onCancel]);
39
+ const displayError = localError || error;
40
+ const canSubmit = useMemo(() => {
41
+ if (loading)
42
+ return false;
43
+ if (step === "otp")
44
+ return otpCode.length === 6;
45
+ return /^[A-Z0-9]{8}$/.test(recoveryCode.trim().toUpperCase());
46
+ }, [step, otpCode, recoveryCode, loading]);
47
+ const handleSubmit = useCallback(() => {
48
+ setLocalError(null);
49
+ if (step === "otp") {
50
+ if (otpCode.length !== 6) {
51
+ setLocalError("Please enter a 6-digit code");
52
+ return;
53
+ }
54
+ onSubmit(otpCode);
55
+ return;
56
+ }
57
+ const trimmed = recoveryCode.trim().toUpperCase();
58
+ if (!/^[A-Z0-9]{8}$/.test(trimmed)) {
59
+ setLocalError("Please enter a valid 8-character backup code");
60
+ return;
61
+ }
62
+ onSubmit(trimmed);
63
+ }, [step, otpCode, recoveryCode, onSubmit]);
64
+ if (!isOpen || (portal && typeof document === "undefined"))
65
+ return null;
66
+ const content = (_jsx("div", { "data-abstraxn-sdk-root": portal ? true : undefined, className: `wallet-modal-overlay wallet-modal-theme-${theme}`, style: portal ? { zIndex: 10050 } : undefined, onClick: () => {
67
+ if (!loading)
68
+ onCancel();
69
+ }, children: _jsxs("div", { className: `wallet-modal-content wallet-modal-theme-${theme} wallet-modal-manage mfa-redesign-container`, onClick: (e) => e.stopPropagation(), children: [_jsxs("div", { className: "wallet-modal-receive-header", children: [_jsx("button", { type: "button", className: "wallet-modal-back", onClick: () => {
70
+ if (loading)
71
+ return;
72
+ if (step === "recovery") {
73
+ setStep("otp");
74
+ setRecoveryCode("");
75
+ setLocalError(null);
76
+ return;
77
+ }
78
+ onCancel();
79
+ }, "aria-label": "Back", disabled: loading, children: _jsx(IoChevronBack, { size: 20 }) }), _jsx("h2", { className: "wallet-modal-receive-title", children: title }), _jsx("button", { type: "button", className: "wallet-modal-close", onClick: () => {
80
+ if (!loading)
81
+ onCancel();
82
+ }, "aria-label": "Close", disabled: loading, children: _jsx(CloseIcon, { size: 24 }) })] }), _jsxs("div", { className: "mfa-redesign-content", children: [_jsx("div", { className: "mfa-info-box", children: _jsx("p", { className: "mfa-info-text", children: description }) }), step === "otp" ? (_jsxs("div", { className: "mfa-verification-section", children: [_jsx("div", { className: "mfa-divider", children: _jsx("span", { children: "Enter 6-digit verification code" }) }), displayError && (_jsx("p", { className: "mfa-setup-error", style: { marginBottom: 12 }, children: displayError })), _jsx(CodeInput, { length: 6, value: otpCode, onChange: setOtpCode, disabled: loading, onComplete: () => {
83
+ window.setTimeout(() => submitRef.current?.focus(), 0);
84
+ } }), _jsx("button", { ref: submitRef, type: "button", className: "mfa-verify-button", onClick: handleSubmit, disabled: !canSubmit, children: loading ? loadingLabel : submitLabel }), _jsxs("p", { className: "mfa-trouble-text", children: ["Having trouble?", " ", _jsx("button", { type: "button", className: "mfa-link-button", disabled: loading, onClick: () => {
85
+ setStep("recovery");
86
+ setLocalError(null);
87
+ setRecoveryCode("");
88
+ }, children: "Use a backup code" })] })] })) : (_jsxs("div", { className: "mfa-recovery-section", children: [_jsx("div", { className: "mfa-divider", children: _jsx("span", { children: "Enter 8 character backup code" }) }), displayError && (_jsx("p", { className: "mfa-setup-error", style: { marginBottom: 12 }, children: displayError })), _jsx("input", { type: "text", inputMode: "text", maxLength: 8, value: recoveryCode, disabled: loading, onChange: (e) => {
89
+ setRecoveryCode(e.target.value
90
+ .toUpperCase()
91
+ .replace(/[^A-Z0-9]/g, "")
92
+ .slice(0, 8));
93
+ }, className: "mfa-recovery-field", autoFocus: true }), _jsx("button", { type: "button", className: "mfa-verify-button", onClick: handleSubmit, disabled: !canSubmit, children: loading ? loadingLabel : submitLabel })] }))] })] }) }));
94
+ if (!portal)
95
+ return content;
96
+ return createPortal(_jsx(ShadowHostContext.Provider, { value: null, children: _jsx(ShadowHost, { cssTexts: MFA_VERIFY_PORTAL_CSS, children: content }) }), document.body);
97
+ }
98
+ //# sourceMappingURL=MfaVerifyModal.js.map