@abstraxn/signer-react 3.3.9 → 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 (114) hide show
  1. package/CHANGELOG.md +44 -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 +81 -20
  102. package/dist/src/hooks.js +194 -36
  103. package/dist/src/index.d.ts +2 -2
  104. package/dist/src/index.js +2 -2
  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/dist/src/walletConnectMobile.d.ts +9 -5
  113. package/dist/src/walletConnectMobile.js +152 -51
  114. package/package.json +9 -4
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Divider Component
3
+ * A horizontal "or" divider used to separate auth method sections
4
+ */
5
+ export declare function Divider({ text }: {
6
+ text?: string;
7
+ }): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,9 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ /**
3
+ * Divider Component
4
+ * A horizontal "or" divider used to separate auth method sections
5
+ */
6
+ export function Divider({ text = 'or' }) {
7
+ return (_jsx("div", { className: "onboarding-divider", children: _jsx("span", { className: "onboarding-divider-text", children: text }) }));
8
+ }
9
+ //# sourceMappingURL=Divider.js.map
@@ -4,7 +4,6 @@
4
4
  */
5
5
  import React from "react";
6
6
  import { OnboardingUIConfig } from "@abstraxn/signer-core";
7
- import "../OnboardingUI.css";
8
7
  export interface EmailFormProps {
9
8
  email: string;
10
9
  onChange: (email: string) => void;
@@ -6,7 +6,6 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
6
6
  import { useMemo } from "react";
7
7
  import { TfiEmail } from "../../icons";
8
8
  import { isValidEmail } from "@abstraxn/signer-core";
9
- import "../OnboardingUI.css";
10
9
  export const EmailForm = ({ email, onChange, onSubmit, loading = false, error = null, config, readOnly = false, }) => {
11
10
  const theme = config?.theme || "light";
12
11
  const labels = config?.labels || {};
@@ -32,6 +31,6 @@ export const EmailForm = ({ email, onChange, onSubmit, loading = false, error =
32
31
  onSubmit();
33
32
  }
34
33
  };
35
- return (_jsx("form", { className: "onboarding-form", onSubmit: handleSubmit, noValidate: true, children: _jsxs("div", { className: "onboarding-input-group", children: [_jsx("label", { htmlFor: "onboarding-email", className: "onboarding-input-label", children: labels.emailLabel || "Email Address" }), _jsxs("div", { className: "onboarding-input-wrapper", children: [_jsx(TfiEmail, { className: "onboarding-input-icon", size: 18 }), _jsx("input", { id: "onboarding-email", type: "email", className: `onboarding-input${readOnly ? " onboarding-email-readonly" : ""}`, placeholder: labels.emailPlaceholder || "Enter your email address", value: email, onChange: readOnly ? undefined : (e) => onChange(e.target.value), onKeyPress: handleKeyPress, disabled: loading, readOnly: readOnly, required: true, autoComplete: "email", autoFocus: true }), _jsx("button", { type: "submit", className: `onboarding-input-arrow-button${hasEmailValue ? " onboarding-input-arrow-button-filled" : ""}`, disabled: loading || !isEmailValid, "aria-label": "Continue", children: loading ? (_jsxs("svg", { className: "onboarding-input-arrow-icon", width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", style: { animation: "spin 1s linear infinite" }, children: [_jsx("line", { x1: "12", y1: "2", x2: "12", y2: "6" }), _jsx("line", { x1: "12", y1: "18", x2: "12", y2: "22" }), _jsx("line", { x1: "4.93", y1: "4.93", x2: "7.76", y2: "7.76" }), _jsx("line", { x1: "16.24", y1: "16.24", x2: "19.07", y2: "19.07" }), _jsx("line", { x1: "2", y1: "12", x2: "6", y2: "12" }), _jsx("line", { x1: "18", y1: "12", x2: "22", y2: "12" }), _jsx("line", { x1: "4.93", y1: "19.07", x2: "7.76", y2: "16.24" }), _jsx("line", { x1: "16.24", y1: "7.76", x2: "19.07", y2: "4.93" })] })) : (_jsxs("svg", { className: "onboarding-input-arrow-icon", width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [_jsx("line", { x1: "5", y1: "12", x2: "19", y2: "12" }), _jsx("polyline", { points: "12 5 19 12 12 19" })] })) })] }), displayError && (_jsx("div", { className: "onboarding-error", role: "alert", children: displayError }))] }) }));
34
+ return (_jsx("form", { className: "onboarding-form", onSubmit: handleSubmit, noValidate: true, children: _jsxs("div", { className: "onboarding-input-group", children: [_jsx("label", { htmlFor: "onboarding-email", className: "onboarding-input-label", children: labels.emailLabel || "Email Address" }), _jsxs("div", { className: "onboarding-input-wrapper", children: [_jsx(TfiEmail, { className: "onboarding-input-icon", size: 18 }), _jsx("input", { id: "onboarding-email", type: "email", className: `onboarding-input${readOnly ? " onboarding-email-readonly" : ""}`, part: "input", placeholder: labels.emailPlaceholder || "Enter your email address", value: email, onChange: readOnly ? undefined : (e) => onChange(e.target.value), onKeyPress: handleKeyPress, disabled: loading, readOnly: readOnly, required: true, autoComplete: "email", autoFocus: true }), _jsx("button", { type: "submit", className: `onboarding-input-arrow-button${hasEmailValue ? " onboarding-input-arrow-button-filled" : ""}`, disabled: loading || !isEmailValid, "aria-label": "Continue", children: loading ? (_jsxs("svg", { className: "onboarding-input-arrow-icon onboarding-button-spinner", width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [_jsx("line", { x1: "12", y1: "2", x2: "12", y2: "6" }), _jsx("line", { x1: "12", y1: "18", x2: "12", y2: "22" }), _jsx("line", { x1: "4.93", y1: "4.93", x2: "7.76", y2: "7.76" }), _jsx("line", { x1: "16.24", y1: "16.24", x2: "19.07", y2: "19.07" }), _jsx("line", { x1: "2", y1: "12", x2: "6", y2: "12" }), _jsx("line", { x1: "18", y1: "12", x2: "22", y2: "12" }), _jsx("line", { x1: "4.93", y1: "19.07", x2: "7.76", y2: "16.24" }), _jsx("line", { x1: "16.24", y1: "7.76", x2: "19.07", y2: "4.93" })] })) : (_jsxs("svg", { className: "onboarding-input-arrow-icon", width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [_jsx("line", { x1: "5", y1: "12", x2: "19", y2: "12" }), _jsx("polyline", { points: "12 5 19 12 12 19" })] })) })] }), displayError && (_jsx("div", { className: "onboarding-error", role: "alert", children: displayError }))] }) }));
36
35
  };
37
36
  //# sourceMappingURL=EmailForm.js.map
@@ -4,7 +4,6 @@
4
4
  */
5
5
  import React from "react";
6
6
  import type { OnboardingUIConfig } from "@abstraxn/signer-core";
7
- import "../OnboardingUI.css";
8
7
  export interface MfaFormProps {
9
8
  code: string;
10
9
  onChange: (code: string) => void;
@@ -1,10 +1,9 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  /**
3
3
  * MfaForm Component
4
4
  * MFA (auth code / TOTP) input form for login verification
5
5
  */
6
6
  import React, { useRef, useEffect } from "react";
7
- import "../OnboardingUI.css";
8
7
  export const MfaForm = ({ code, onChange, onSubmit, onBack, loading = false, error = null, config, }) => {
9
8
  const labels = config?.labels || {};
10
9
  const mfaInputsRef = useRef([]);
@@ -83,6 +82,6 @@ export const MfaForm = ({ code, onChange, onSubmit, onBack, loading = false, err
83
82
  }, type: "text", inputMode: "numeric", pattern: "[0-9]*", maxLength: 1, className: "onboarding-otp-input", value: digit, onChange: (e) => handleDigitChange(index, e.target.value), onKeyDown: (e) => handleKeyDown(index, e), disabled: loading, autoFocus: index === 0, "aria-label": `Authentication code digit ${index + 1}` }, `mfa-input-${index}`))) })), !useBackupCode && (_jsxs("p", { className: "onboarding-mfa-trouble-text", children: ["Having trouble?", " ", _jsx("button", { type: "button", className: "onboarding-mfa-backup-link", onClick: () => {
84
83
  setUseBackupCode(true);
85
84
  onChange("");
86
- }, disabled: loading, children: "Use a backup code" })] })), _jsx("button", { type: "submit", className: "onboarding-button onboarding-button-primary", disabled: loading || code.length !== codeLength, children: loading ? (_jsxs(_Fragment, { children: [_jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", style: { animation: "spin 1s linear infinite" }, children: [_jsx("line", { x1: "12", y1: "2", x2: "12", y2: "6" }), _jsx("line", { x1: "12", y1: "18", x2: "12", y2: "22" }), _jsx("line", { x1: "4.93", y1: "4.93", x2: "7.76", y2: "7.76" }), _jsx("line", { x1: "16.24", y1: "16.24", x2: "19.07", y2: "19.07" }), _jsx("line", { x1: "2", y1: "12", x2: "6", y2: "12" }), _jsx("line", { x1: "18", y1: "12", x2: "22", y2: "12" }), _jsx("line", { x1: "4.93", y1: "19.07", x2: "7.76", y2: "16.24" }), _jsx("line", { x1: "16.24", y1: "7.76", x2: "19.07", y2: "4.93" })] }), "Verifying..."] })) : ("Verify") })] })] }));
85
+ }, disabled: loading, children: "Use a backup code" })] })), _jsx("button", { type: "submit", className: "onboarding-button onboarding-button-primary", part: "button-primary", disabled: loading || code.length !== codeLength, children: loading ? (_jsxs("span", { className: "onboarding-button-loading", children: [_jsxs("svg", { className: "onboarding-button-spinner", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [_jsx("line", { x1: "12", y1: "2", x2: "12", y2: "6" }), _jsx("line", { x1: "12", y1: "18", x2: "12", y2: "22" }), _jsx("line", { x1: "4.93", y1: "4.93", x2: "7.76", y2: "7.76" }), _jsx("line", { x1: "16.24", y1: "16.24", x2: "19.07", y2: "19.07" }), _jsx("line", { x1: "2", y1: "12", x2: "6", y2: "12" }), _jsx("line", { x1: "18", y1: "12", x2: "22", y2: "12" }), _jsx("line", { x1: "4.93", y1: "19.07", x2: "7.76", y2: "16.24" }), _jsx("line", { x1: "16.24", y1: "7.76", x2: "19.07", y2: "4.93" })] }), _jsx("span", { children: "Verifying..." })] })) : ("Verify") })] })] }));
87
86
  };
88
87
  //# sourceMappingURL=MfaForm.js.map
@@ -3,7 +3,6 @@
3
3
  * React Portal-based modal for OnboardingUI
4
4
  */
5
5
  import React from 'react';
6
- import '../OnboardingUI.css';
7
6
  export interface ModalProps {
8
7
  isOpen: boolean;
9
8
  onClose: () => void;
@@ -5,10 +5,17 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
5
5
  */
6
6
  import { useEffect, useRef } from 'react';
7
7
  import { createPortal } from 'react-dom';
8
- import '../OnboardingUI.css';
8
+ import { useShadowHost } from '../../ShadowHost';
9
+ import { getDeepActiveElement } from '../../../utils/shadowFocus';
10
+ import { CloseIcon } from '../../icons';
9
11
  export const Modal = ({ isOpen, onClose, closeOnBackdropClick = true, showCloseButton = false, children, theme = 'light', }) => {
10
12
  const modalRef = useRef(null);
11
13
  const contentRef = useRef(null);
14
+ // Portal target: the enclosing ShadowHost's container, so this modal stays
15
+ // inside the isolation boundary instead of escaping to document.body.
16
+ // document.body fallback is purely defensive.
17
+ const shadowHost = useShadowHost();
18
+ const portalTarget = shadowHost?.container ?? document.body;
12
19
  useEffect(() => {
13
20
  if (isOpen) {
14
21
  // Prevent body scroll
@@ -32,11 +39,12 @@ export const Modal = ({ isOpen, onClose, closeOnBackdropClick = true, showCloseB
32
39
  const firstElement = focusableElements[0];
33
40
  const lastElement = focusableElements[focusableElements.length - 1];
34
41
  if (e.key === 'Tab') {
35
- if (e.shiftKey && document.activeElement === firstElement) {
42
+ const active = getDeepActiveElement();
43
+ if (e.shiftKey && active === firstElement) {
36
44
  e.preventDefault();
37
45
  lastElement.focus();
38
46
  }
39
- else if (!e.shiftKey && document.activeElement === lastElement) {
47
+ else if (!e.shiftKey && active === lastElement) {
40
48
  e.preventDefault();
41
49
  firstElement.focus();
42
50
  }
@@ -59,6 +67,6 @@ export const Modal = ({ isOpen, onClose, closeOnBackdropClick = true, showCloseB
59
67
  return createPortal(_jsx("div", { ref: modalRef, className: `onboarding-modal-overlay onboarding-modal-open onboarding-theme-${theme}`, onClick: handleBackdropClick, role: "dialog", "aria-modal": "true", children: _jsxs("div", { ref: contentRef, className: `onboarding-modal-content onboarding-theme-${theme}`, onClick: (e) => e.stopPropagation(), children: [showCloseButton && (_jsx("button", { type: "button", className: `onboarding-modal-close onboarding-theme-${theme}`, "aria-label": "Close", onClick: (e) => {
60
68
  e.stopPropagation();
61
69
  onClose();
62
- }, children: _jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: 20, height: 20, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [_jsx("path", { d: "M18 6 6 18" }), _jsx("path", { d: "m6 6 12 12" })] }) })), children] }) }), document.body);
70
+ }, children: _jsx(CloseIcon, { size: 20 }) })), children] }) }), portalTarget);
63
71
  };
64
72
  //# sourceMappingURL=Modal.js.map
@@ -4,7 +4,6 @@
4
4
  */
5
5
  import React from "react";
6
6
  import type { OnboardingUIConfig } from "@abstraxn/signer-core";
7
- import "../OnboardingUI.css";
8
7
  export interface OtpFormProps {
9
8
  email: string;
10
9
  otp: string;
@@ -1,11 +1,10 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  /**
3
3
  * OtpForm Component
4
4
  * OTP input form for verification
5
5
  */
6
6
  import React, { useRef, useEffect } from "react";
7
7
  import { TfiEmail } from "../../icons";
8
- import "../OnboardingUI.css";
9
8
  export const OtpForm = ({ email, otp, onChange, onSubmit, onResend, onBack, loading = false, resending = false, requireManualVerify = false, error = null, resendCooldown = 0, config, }) => {
10
9
  const theme = config?.theme || "light";
11
10
  const labels = config?.labels || {};
@@ -69,7 +68,7 @@ export const OtpForm = ({ email, otp, onChange, onSubmit, onResend, onBack, load
69
68
  }, [otp, loading, error, requireManualVerify, onSubmit]);
70
69
  return (_jsxs("div", { className: "onboarding-otp-verification", children: [onBack && (_jsx("button", { type: "button", className: "onboarding-otp-back-button", onClick: onBack, "aria-label": "Go back to email input", disabled: loading || resending, children: _jsx("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: _jsx("path", { d: "M19 12H5M12 19l-7-7 7-7" }) }) })), _jsx("div", { className: "onboarding-otp-icon-container", children: _jsx("div", { className: "onboarding-otp-icon-inner", children: _jsx(TfiEmail, { className: "onboarding-otp-icon", size: 28 }) }) }), _jsx("h1", { className: "onboarding-otp-title", children: labels.otpLabel || "Enter verification code" }), _jsx("p", { className: "onboarding-otp-instruction", children: "We sent a 6-digit code to" }), _jsx("p", { className: "onboarding-otp-email", children: email }), displayError && (_jsx("div", { className: "onboarding-error", role: "alert", children: displayError })), _jsxs("form", { onSubmit: handleSubmit, className: "onboarding-form", children: [_jsx("div", { className: "onboarding-otp-inputs-container", children: otpDigits.map((digit, index) => (_jsx("input", { ref: (el) => {
71
70
  otpInputsRef.current[index] = el;
72
- }, type: "text", inputMode: "numeric", pattern: "[0-9]*", maxLength: 1, className: "onboarding-otp-input", value: digit, onChange: (e) => handleOtpChange(index, e.target.value), onKeyDown: (e) => handleKeyDown(index, e), disabled: loading || resending, autoFocus: index === 0, "aria-label": `OTP digit ${index + 1}` }, `otp-input-${index}`))) }), _jsx("button", { type: "submit", className: "onboarding-button onboarding-button-primary", disabled: loading || resending || otp.length !== 6, children: loading ? (_jsxs(_Fragment, { children: [_jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", style: { animation: "spin 1s linear infinite" }, children: [_jsx("line", { x1: "12", y1: "2", x2: "12", y2: "6" }), _jsx("line", { x1: "12", y1: "18", x2: "12", y2: "22" }), _jsx("line", { x1: "4.93", y1: "4.93", x2: "7.76", y2: "7.76" }), _jsx("line", { x1: "16.24", y1: "16.24", x2: "19.07", y2: "19.07" }), _jsx("line", { x1: "2", y1: "12", x2: "6", y2: "12" }), _jsx("line", { x1: "18", y1: "12", x2: "22", y2: "12" }), _jsx("line", { x1: "4.93", y1: "19.07", x2: "7.76", y2: "16.24" }), _jsx("line", { x1: "16.24", y1: "7.76", x2: "19.07", y2: "4.93" })] }), "Verifying..."] })) : (labels.otpButton || "Verify") })] }), _jsx("div", { className: "onboarding-otp-resend", children: _jsxs("p", { className: "onboarding-otp-resend-text", children: ["Didn't receive the code?", " ", resendCooldown > 0 ? (_jsxs("span", { className: "onboarding-otp-resend-cooldown", children: ["Resend in ", resendCooldown, "s"] })) : (_jsx("a", { href: "#", className: "onboarding-otp-resend-link", onClick: (e) => {
71
+ }, type: "text", inputMode: "numeric", pattern: "[0-9]*", maxLength: 1, className: "onboarding-otp-input", value: digit, onChange: (e) => handleOtpChange(index, e.target.value), onKeyDown: (e) => handleKeyDown(index, e), disabled: loading || resending, autoFocus: index === 0, "aria-label": `OTP digit ${index + 1}` }, `otp-input-${index}`))) }), _jsx("button", { type: "submit", className: "onboarding-button onboarding-button-primary", part: "button-primary", disabled: loading || resending || otp.length !== 6, children: loading ? (_jsxs("span", { className: "onboarding-button-loading", children: [_jsxs("svg", { className: "onboarding-button-spinner", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [_jsx("line", { x1: "12", y1: "2", x2: "12", y2: "6" }), _jsx("line", { x1: "12", y1: "18", x2: "12", y2: "22" }), _jsx("line", { x1: "4.93", y1: "4.93", x2: "7.76", y2: "7.76" }), _jsx("line", { x1: "16.24", y1: "16.24", x2: "19.07", y2: "19.07" }), _jsx("line", { x1: "2", y1: "12", x2: "6", y2: "12" }), _jsx("line", { x1: "18", y1: "12", x2: "22", y2: "12" }), _jsx("line", { x1: "4.93", y1: "19.07", x2: "7.76", y2: "16.24" }), _jsx("line", { x1: "16.24", y1: "7.76", x2: "19.07", y2: "4.93" })] }), _jsx("span", { children: "Verifying..." })] })) : (labels.otpButton || "Verify") })] }), _jsx("div", { className: "onboarding-otp-resend", children: _jsxs("p", { className: "onboarding-otp-resend-text", children: ["Didn't receive the code?", " ", resendCooldown > 0 ? (_jsxs("span", { className: "onboarding-otp-resend-cooldown", children: ["Resend in ", resendCooldown, "s"] })) : (_jsx("a", { href: "#", className: "onboarding-otp-resend-link", onClick: (e) => {
73
72
  e.preventDefault();
74
73
  if (!loading && !resending) {
75
74
  onResend();
@@ -4,7 +4,6 @@
4
4
  */
5
5
  import React from 'react';
6
6
  import type { OnboardingUIConfig } from '@abstraxn/signer-core';
7
- import '../OnboardingUI.css';
8
7
  export interface PasskeyButtonProps {
9
8
  onPasskeyLogin: () => void;
10
9
  onPasskeySignup: () => void;
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import '../OnboardingUI.css';
2
+ import { Divider } from './Divider';
3
3
  export const PasskeyButton = ({ onPasskeyLogin, onPasskeySignup, loading = false, config, }) => {
4
4
  const theme = config?.theme || 'light';
5
5
  const labels = config?.labels || {};
@@ -14,7 +14,7 @@ export const PasskeyButton = ({ onPasskeyLogin, onPasskeySignup, loading = false
14
14
  if (!isWebAuthnAvailable) {
15
15
  return null;
16
16
  }
17
- return (_jsxs(_Fragment, { children: [_jsx("div", { className: "onboarding-divider", children: _jsx("span", { className: "onboarding-divider-text", children: "or" }) }), _jsxs("button", { type: "button", className: "onboarding-button onboarding-button-passkey", onClick: onPasskeyLogin, disabled: loading, children: [_jsx("svg", { className: "onboarding-passkey-icon", width: "20", height: "20", viewBox: "0 0 24 24", fill: "currentColor", xmlns: "http://www.w3.org/2000/svg", children: _jsx("path", { d: "M3.682 19.338v-2.102c0-.476.127-.915.382-1.315.255-.4.603-.708 1.042-.926a14.89 14.89 0 0 1 2.939-1.067c.982-.24 1.966-.36 2.953-.36.352 0 .708.018 1.066.054.358.035.712.084 1.062.147-.015.831.164 1.613.537 2.347a4.882 4.882 0 0 0 1.595 1.822v1.4H3.682Zm15.003 2.713-1.303-1.303v-4.029a2.976 2.976 0 0 1-1.564-1.08 2.944 2.944 0 0 1-.608-1.832c0-.841.297-1.557.891-2.147a2.944 2.944 0 0 1 2.154-.886c.837 0 1.552.295 2.145.886.594.59.89 1.306.89 2.148 0 .656-.182 1.238-.546 1.743a3.018 3.018 0 0 1-1.404 1.084l1.073 1.072-1.294 1.31 1.294 1.301-1.728 1.733ZM11 12.006c-.94 0-1.742-.333-2.405-.999a3.28 3.28 0 0 1-.994-2.4c0-.94.331-1.743.994-2.405A3.276 3.276 0 0 1 11 5.208c.94 0 1.742.331 2.405.994.663.662.994 1.463.994 2.4 0 .939-.331 1.74-.994 2.406a3.27 3.27 0 0 1-2.405.998Zm7.252 2.235a.833.833 0 0 0 .612-.255.842.842 0 0 0 .255-.617.834.834 0 0 0-.253-.614.835.835 0 0 0-.612-.252.85.85 0 0 0-.616.251.823.823 0 0 0-.257.612c0 .24.085.447.257.618a.838.838 0 0 0 .614.257Z" }) }), labels.passkeyLoginButton || 'Continue with Passkey'] }), _jsx("a", { href: "#", className: "onboarding-passkey-signup-link", onClick: (e) => {
17
+ return (_jsxs(_Fragment, { children: [_jsx(Divider, {}), _jsxs("button", { type: "button", className: "onboarding-button onboarding-button-passkey", onClick: onPasskeyLogin, disabled: loading, children: [_jsx("svg", { className: "onboarding-passkey-icon", width: "20", height: "20", viewBox: "0 0 24 24", fill: "currentColor", xmlns: "http://www.w3.org/2000/svg", children: _jsx("path", { d: "M3.682 19.338v-2.102c0-.476.127-.915.382-1.315.255-.4.603-.708 1.042-.926a14.89 14.89 0 0 1 2.939-1.067c.982-.24 1.966-.36 2.953-.36.352 0 .708.018 1.066.054.358.035.712.084 1.062.147-.015.831.164 1.613.537 2.347a4.882 4.882 0 0 0 1.595 1.822v1.4H3.682Zm15.003 2.713-1.303-1.303v-4.029a2.976 2.976 0 0 1-1.564-1.08 2.944 2.944 0 0 1-.608-1.832c0-.841.297-1.557.891-2.147a2.944 2.944 0 0 1 2.154-.886c.837 0 1.552.295 2.145.886.594.59.89 1.306.89 2.148 0 .656-.182 1.238-.546 1.743a3.018 3.018 0 0 1-1.404 1.084l1.073 1.072-1.294 1.31 1.294 1.301-1.728 1.733ZM11 12.006c-.94 0-1.742-.333-2.405-.999a3.28 3.28 0 0 1-.994-2.4c0-.94.331-1.743.994-2.405A3.276 3.276 0 0 1 11 5.208c.94 0 1.742.331 2.405.994.663.662.994 1.463.994 2.4 0 .939-.331 1.74-.994 2.406a3.27 3.27 0 0 1-2.405.998Zm7.252 2.235a.833.833 0 0 0 .612-.255.842.842 0 0 0 .255-.617.834.834 0 0 0-.253-.614.835.835 0 0 0-.612-.252.85.85 0 0 0-.616.251.823.823 0 0 0-.257.612c0 .24.085.447.257.618a.838.838 0 0 0 .614.257Z" }) }), labels.passkeyLoginButton || 'Continue with Passkey'] }), _jsx("a", { href: "#", className: "onboarding-passkey-signup-link", onClick: (e) => {
18
18
  e.preventDefault();
19
19
  onPasskeySignup();
20
20
  }, children: labels.passkeySignupButton || 'Sign up with passkey' })] }));
@@ -4,7 +4,6 @@
4
4
  */
5
5
  import React from 'react';
6
6
  import type { OnboardingUIConfig } from '@abstraxn/signer-core';
7
- import '../OnboardingUI.css';
8
7
  export interface SocialButtonsProps {
9
8
  onGoogleLogin: () => void;
10
9
  onTwitterLogin: () => void;
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import '../OnboardingUI.css';
2
+ import { GoogleIcon } from '../../icons';
3
3
  export const SocialButtons = ({ onGoogleLogin, onTwitterLogin, onDiscordLogin, loading = false, config, }) => {
4
4
  const theme = config?.theme || 'light';
5
5
  const labels = config?.labels || {};
@@ -12,9 +12,9 @@ export const SocialButtons = ({ onGoogleLogin, onTwitterLogin, onDiscordLogin, l
12
12
  }
13
13
  // If only Google is shown, use full button with text
14
14
  if (showGoogle && !showTwitter && !showDiscord) {
15
- return (_jsxs("button", { type: "button", className: "onboarding-button onboarding-button-google", onClick: onGoogleLogin, disabled: loading, children: [_jsxs("svg", { className: "onboarding-google-icon", width: "20", height: "20", viewBox: "0 0 24 24", fill: "currentColor", children: [_jsx("path", { d: "M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z", fill: "#4285F4" }), _jsx("path", { d: "M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z", fill: "#34A853" }), _jsx("path", { d: "M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z", fill: "#FBBC05" }), _jsx("path", { d: "M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z", fill: "#EA4335" })] }), labels.googleButton || 'Continue with Google'] }));
15
+ return (_jsxs("button", { type: "button", className: "onboarding-button onboarding-button-google", part: "button-google", onClick: onGoogleLogin, disabled: loading, children: [_jsx(GoogleIcon, { size: 20, className: "onboarding-google-icon" }), labels.googleButton || 'Continue with Google'] }));
16
16
  }
17
17
  // Multiple social buttons - show as grid with icons only
18
- return (_jsxs("div", { className: "onboarding-social-grid", children: [showGoogle && (_jsx("button", { type: "button", className: "onboarding-button-social-icon", onClick: onGoogleLogin, disabled: loading, "aria-label": "Continue with Google", children: _jsxs("svg", { className: "onboarding-social-icon", width: "20", height: "20", viewBox: "0 0 24 24", fill: "currentColor", children: [_jsx("path", { d: "M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z", fill: "#4285F4" }), _jsx("path", { d: "M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z", fill: "#34A853" }), _jsx("path", { d: "M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z", fill: "#FBBC05" }), _jsx("path", { d: "M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z", fill: "#EA4335" })] }) })), showTwitter && (_jsx("button", { type: "button", className: "onboarding-button-social-icon", onClick: onTwitterLogin, disabled: loading, "aria-label": "Continue with X (Twitter)", children: _jsx("svg", { className: "onboarding-social-icon", width: "20", height: "20", viewBox: "0 0 24 24", fill: "currentColor", children: _jsx("path", { d: "M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z" }) }) })), showDiscord && (_jsx("button", { type: "button", className: "onboarding-button-social-icon", onClick: onDiscordLogin, disabled: loading, "aria-label": "Continue with Discord", children: _jsx("svg", { className: "onboarding-social-icon", width: "20", height: "20", viewBox: "0 0 24 24", fill: "currentColor", children: _jsx("path", { d: "M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 0 0-5.487 0 12.64 12.64 0 0 0-.617-1.25.077.077 0 0 0-.079-.037A19.736 19.736 0 0 0 3.677 4.37a.07.07 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 0 0 .031.057 19.9 19.9 0 0 0 5.993 3.03.078.078 0 0 0 .084-.028c.462-.63.874-1.295 1.226-1.994a.076.076 0 0 0-.041-.106 13.107 13.107 0 0 1-1.872-.892.077.077 0 0 1-.008-.128 10.2 10.2 0 0 0 .372-.292.074.074 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 0 1 .078.01c.12.098.246.198.373.292a.077.077 0 0 1-.006.127 12.299 12.299 0 0 1-1.873.892.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028 19.839 19.839 0 0 0 6.002-3.03.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.03zM8.02 15.33c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.956-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.956 2.418-2.157 2.418zm7.975 0c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.955-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.946 2.418-2.157 2.418z" }) }) }))] }));
18
+ return (_jsxs("div", { className: "onboarding-social-grid", children: [showGoogle && (_jsx("button", { type: "button", className: "onboarding-button-social-icon", onClick: onGoogleLogin, disabled: loading, "aria-label": "Continue with Google", children: _jsx(GoogleIcon, { size: 20, className: "onboarding-social-icon" }) })), showTwitter && (_jsx("button", { type: "button", className: "onboarding-button-social-icon", onClick: onTwitterLogin, disabled: loading, "aria-label": "Continue with X (Twitter)", children: _jsx("svg", { className: "onboarding-social-icon", width: "20", height: "20", viewBox: "0 0 24 24", fill: "currentColor", children: _jsx("path", { d: "M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z" }) }) })), showDiscord && (_jsx("button", { type: "button", className: "onboarding-button-social-icon", onClick: onDiscordLogin, disabled: loading, "aria-label": "Continue with Discord", children: _jsx("svg", { className: "onboarding-social-icon", width: "20", height: "20", viewBox: "0 0 24 24", fill: "currentColor", children: _jsx("path", { d: "M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 0 0-5.487 0 12.64 12.64 0 0 0-.617-1.25.077.077 0 0 0-.079-.037A19.736 19.736 0 0 0 3.677 4.37a.07.07 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 0 0 .031.057 19.9 19.9 0 0 0 5.993 3.03.078.078 0 0 0 .084-.028c.462-.63.874-1.295 1.226-1.994a.076.076 0 0 0-.041-.106 13.107 13.107 0 0 1-1.872-.892.077.077 0 0 1-.008-.128 10.2 10.2 0 0 0 .372-.292.074.074 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 0 1 .078.01c.12.098.246.198.373.292a.077.077 0 0 1-.006.127 12.299 12.299 0 0 1-1.873.892.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028 19.839 19.839 0 0 0 6.002-3.03.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.03zM8.02 15.33c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.956-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.956 2.418-2.157 2.418zm7.975 0c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.955-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.946 2.418-2.157 2.418z" }) }) }))] }));
19
19
  };
20
20
  //# sourceMappingURL=SocialButtons.js.map
@@ -0,0 +1,9 @@
1
+ export interface OnboardingShadowContainer {
2
+ shadowRoot: ShadowRoot;
3
+ /** Stable element inside the shadow root — append the onboarding DOM tree here instead of document.body. */
4
+ container: HTMLElement;
5
+ hostElement: HTMLElement;
6
+ /** Call from destroy() — removes hostElement from document.body and unregisters from shadowRegistry. */
7
+ teardown: () => void;
8
+ }
9
+ export declare function createOnboardingShadowContainer(): OnboardingShadowContainer;
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Per-`OnboardingUIWeb`-instance shadow container factory — NOT a page-wide
3
+ * singleton. Each instance calls this once from init() and owns the result
4
+ * exclusively. A shared singleton would mean tearing down one
5
+ * AbstraxnProvider instance's onboarding modal rips the shadow host out from
6
+ * under a sibling instance's still-mounted modal. See
7
+ * docs/shadow-dom-migration-plan.md for the full rationale.
8
+ */
9
+ import externalWalletButtonsCss from '../../ExternalWalletButtons.css.js';
10
+ import { registerShadowRoot } from '../../utils/shadowRegistry';
11
+ const STACKING_DEFENSE_STYLE = 'position: static; z-index: auto; transform: none; opacity: 1; isolation: auto;';
12
+ export function createOnboardingShadowContainer() {
13
+ const hostElement = document.createElement('div');
14
+ hostElement.setAttribute('data-abstraxn-shadow-host', 'onboarding');
15
+ hostElement.setAttribute('style', STACKING_DEFENSE_STYLE);
16
+ document.body.appendChild(hostElement);
17
+ const shadowRoot = hostElement.attachShadow({ mode: 'open' });
18
+ const container = document.createElement('div');
19
+ container.setAttribute('data-abstraxn-shadow-container', '');
20
+ shadowRoot.appendChild(container);
21
+ // Static, no config dependency — injected once at creation, since
22
+ // ExternalWalletButtons is mounted (via a separate createRoot call in
23
+ // AbstraxnProviderInner.tsx) inside this same shadow root and isn't
24
+ // wrapped by a React ShadowHost of its own.
25
+ const externalWalletStyle = document.createElement('style');
26
+ externalWalletStyle.setAttribute('data-abstraxn-css-key', 'external-wallet-buttons');
27
+ externalWalletStyle.textContent = externalWalletButtonsCss;
28
+ shadowRoot.appendChild(externalWalletStyle);
29
+ const unregister = registerShadowRoot(shadowRoot);
30
+ const teardown = () => {
31
+ unregister();
32
+ hostElement.remove();
33
+ };
34
+ return { shadowRoot, container, hostElement, teardown };
35
+ }
36
+ //# sourceMappingURL=onboardingShadowContainer.js.map
@@ -0,0 +1,18 @@
1
+ /**
2
+ * ShadowHost - wraps children in a Shadow DOM boundary so host-page CSS can
3
+ * never bleed in, and this SDK's CSS can never bleed out.
4
+ *
5
+ * See docs/shadow-dom-migration-plan.md for the full design rationale
6
+ * (two-pass render lifecycle, Strict Mode idempotency, nested-boundary
7
+ * invariant, customCSS precedence, failure modes).
8
+ */
9
+ import { type ReactNode } from 'react';
10
+ export interface ShadowHostProps {
11
+ children: ReactNode;
12
+ /** SDK's own static component styles — fixed at build time, injected once. */
13
+ cssTexts: string[];
14
+ /** Consumer-provided uiConfig.customCSS — runtime-mutable, always injected after cssTexts. */
15
+ customCSS?: string;
16
+ hostTagName?: string;
17
+ }
18
+ export declare function ShadowHost({ children, cssTexts, customCSS, hostTagName }: ShadowHostProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,123 @@
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * ShadowHost - wraps children in a Shadow DOM boundary so host-page CSS can
4
+ * never bleed in, and this SDK's CSS can never bleed out.
5
+ *
6
+ * See docs/shadow-dom-migration-plan.md for the full design rationale
7
+ * (two-pass render lifecycle, Strict Mode idempotency, nested-boundary
8
+ * invariant, customCSS precedence, failure modes).
9
+ */
10
+ import React, { useLayoutEffect, useMemo, useRef, useState, } from 'react';
11
+ import { createPortal } from 'react-dom';
12
+ import { ShadowHostContext, useShadowHost } from './ShadowHostContext';
13
+ import { registerShadowRoot } from '../../utils/shadowRegistry';
14
+ /**
15
+ * Prevents ordinary host-page global CSS (e.g. a broad `div { transform: ... }`
16
+ * reset) from accidentally promoting the shadow host into its own stacking
17
+ * context and trapping the modal's internal z-index inside it.
18
+ */
19
+ const STACKING_DEFENSE_STYLE = {
20
+ position: 'static',
21
+ zIndex: 'auto',
22
+ transform: 'none',
23
+ opacity: 1,
24
+ isolation: 'auto',
25
+ };
26
+ function ensureStyleTagOnce(root, key, cssText) {
27
+ if (root.querySelector(`style[data-abstraxn-css-key="${key}"]`))
28
+ return;
29
+ const style = document.createElement('style');
30
+ style.setAttribute('data-abstraxn-css-key', key);
31
+ style.textContent = cssText;
32
+ root.appendChild(style);
33
+ }
34
+ function upsertStyleTag(root, key, cssText) {
35
+ let style = root.querySelector(`style[data-abstraxn-css-key="${key}"]`);
36
+ if (!style) {
37
+ style = document.createElement('style');
38
+ style.setAttribute('data-abstraxn-css-key', key);
39
+ root.appendChild(style);
40
+ }
41
+ if (style.textContent !== cssText) {
42
+ style.textContent = cssText;
43
+ }
44
+ }
45
+ export function ShadowHost({ children, cssTexts, customCSS, hostTagName = 'div' }) {
46
+ const ancestor = useShadowHost();
47
+ const hostRef = useRef(null);
48
+ const containerRef = useRef(null);
49
+ const unregisterRef = useRef(null);
50
+ const [status, setStatus] = useState('pending');
51
+ // Nested case: extend the ancestor's boundary — keep its stylesheet in sync
52
+ // with whatever this nested instance additionally needs. No new shadow
53
+ // root, no new host element: the nested-boundary invariant is enforced
54
+ // here, not left to callers to remember.
55
+ useLayoutEffect(() => {
56
+ if (!ancestor)
57
+ return;
58
+ cssTexts.forEach((text, i) => ensureStyleTagOnce(ancestor.shadowRoot, `nested-css-${i}`, text));
59
+ // eslint-disable-next-line react-hooks/exhaustive-deps
60
+ }, [ancestor]);
61
+ useLayoutEffect(() => {
62
+ if (ancestor)
63
+ return;
64
+ const root = hostRef.current?.shadowRoot;
65
+ if (!root)
66
+ return;
67
+ if (customCSS !== undefined) {
68
+ upsertStyleTag(root, 'custom', customCSS);
69
+ }
70
+ }, [ancestor, customCSS]);
71
+ // Mount: attach shadow root, inject static cssTexts once, register.
72
+ // Idempotent under React 18 Strict Mode's mount->cleanup->mount dev
73
+ // double-invocation — attachShadow is guarded, the container/style lookups
74
+ // are DOM-existence checks (not trusted booleans), and register/unregister
75
+ // is naturally idempotent since attachShadow can only ever produce one
76
+ // ShadowRoot object per host element.
77
+ useLayoutEffect(() => {
78
+ if (ancestor)
79
+ return;
80
+ const host = hostRef.current;
81
+ if (!host)
82
+ return;
83
+ try {
84
+ const root = host.shadowRoot ?? host.attachShadow({ mode: 'open' });
85
+ let container = root.querySelector('[data-abstraxn-shadow-container]');
86
+ if (!container) {
87
+ container = document.createElement('div');
88
+ container.setAttribute('data-abstraxn-shadow-container', '');
89
+ root.appendChild(container);
90
+ }
91
+ containerRef.current = container;
92
+ cssTexts.forEach((text, i) => ensureStyleTagOnce(root, `css-${i}`, text));
93
+ if (!unregisterRef.current) {
94
+ unregisterRef.current = registerShadowRoot(root);
95
+ }
96
+ setStatus('ready');
97
+ }
98
+ catch (err) {
99
+ console.error('[ShadowHost] attachShadow failed — falling back to un-isolated rendering for this boundary:', err);
100
+ setStatus('fallback');
101
+ }
102
+ return () => {
103
+ unregisterRef.current?.();
104
+ unregisterRef.current = null;
105
+ };
106
+ // cssTexts intentionally omitted from deps: static per component,
107
+ // injected once via the idempotent guard above.
108
+ // eslint-disable-next-line react-hooks/exhaustive-deps
109
+ }, [ancestor]);
110
+ if (ancestor) {
111
+ return _jsx(_Fragment, { children: children });
112
+ }
113
+ const contextValue = useMemo(() => {
114
+ const root = hostRef.current?.shadowRoot;
115
+ const container = containerRef.current;
116
+ if (status !== 'ready' || !root || !container)
117
+ return null;
118
+ return { shadowRoot: root, container };
119
+ // eslint-disable-next-line react-hooks/exhaustive-deps
120
+ }, [status]);
121
+ return (_jsxs(_Fragment, { children: [React.createElement(hostTagName, { ref: hostRef, 'data-abstraxn-shadow-host': true, style: STACKING_DEFENSE_STYLE }, status === 'fallback' ? children : undefined), status === 'ready' && contextValue && (_jsx(ShadowHostContext.Provider, { value: contextValue, children: createPortal(children, contextValue.container) }))] }));
122
+ }
123
+ //# sourceMappingURL=ShadowHost.js.map
@@ -0,0 +1,10 @@
1
+ export interface ShadowHostContextValue {
2
+ shadowRoot: ShadowRoot;
3
+ /** Stable element inside the shadow root — the actual createPortal/createRoot target. */
4
+ container: HTMLElement;
5
+ }
6
+ export declare const ShadowHostContext: import("react").Context<ShadowHostContextValue | null>;
7
+ /** Nullable — returns the enclosing ShadowHost's value, or null if not inside one. */
8
+ export declare function useShadowHost(): ShadowHostContextValue | null;
9
+ /** True if already nested inside another SDK-owned shadow boundary. */
10
+ export declare function useIsInsideShadowHost(): boolean;
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Abstraxn Shadow Host context
3
+ */
4
+ import { createContext, useContext } from 'react';
5
+ export const ShadowHostContext = createContext(null);
6
+ /** Nullable — returns the enclosing ShadowHost's value, or null if not inside one. */
7
+ export function useShadowHost() {
8
+ return useContext(ShadowHostContext);
9
+ }
10
+ /** True if already nested inside another SDK-owned shadow boundary. */
11
+ export function useIsInsideShadowHost() {
12
+ return useShadowHost() !== null;
13
+ }
14
+ //# sourceMappingURL=ShadowHostContext.js.map
@@ -0,0 +1,2 @@
1
+ export { ShadowHost, type ShadowHostProps } from './ShadowHost';
2
+ export { ShadowHostContext, useShadowHost, useIsInsideShadowHost, type ShadowHostContextValue, } from './ShadowHostContext';
@@ -0,0 +1,3 @@
1
+ export { ShadowHost } from './ShadowHost';
2
+ export { ShadowHostContext, useShadowHost, useIsInsideShadowHost, } from './ShadowHostContext';
3
+ //# sourceMappingURL=index.js.map
@@ -226,6 +226,15 @@
226
226
  pointer-events: none;
227
227
  }
228
228
 
229
+ /* Visual-only equivalent of :disabled - deliberately keeps pointer-events enabled so a
230
+ stuck switching state can never silently swallow clicks the way a native disabled
231
+ attribute (or pointer-events: none) would. The JS click guard + safety timeout in
232
+ ChainSelector.tsx handle actually preventing redundant switches. */
233
+ .wallet-modal-chain-item[aria-disabled="true"] {
234
+ opacity: 0.5;
235
+ cursor: not-allowed;
236
+ }
237
+
229
238
  .wallet-modal-chain-item.switching {
230
239
  opacity: 0.7;
231
240
  pointer-events: none;
@@ -0,0 +1,2 @@
1
+ declare const cssText: string;
2
+ export default cssText;
@@ -0,0 +1 @@
1
+ export default "/* Select Network View */\n.wallet-modal-chain-selector-view {\n position: relative;\n width: 100%;\n height: 100%;\n min-height: 450px;\n background: #ffffff;\n display: flex;\n flex-direction: column;\n animation: slideInRight 0.3s ease-out;\n}\n\n@keyframes slideInRight {\n from { transform: translateX(100%); }\n to { transform: translateX(0); }\n}\n\n.wallet-modal-chain-selector-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 0;\n border-bottom: 1px solid #f1f5f9;\n padding-bottom: 16px;\n margin-bottom: 16px;\n}\n\n.wallet-modal-chain-selector-back,\n.wallet-modal-chain-selector-close {\n background: transparent;\n border: none;\n cursor: pointer;\n padding: 8px;\n border-radius: 8px;\n color: #64748b;\n transition: all 0.2s;\n display: flex;\n align-items: center;\n justify-content: center;\n pointer-events: auto;\n user-select: none;\n -webkit-user-select: none;\n width: 36px;\n height: 36px;\n flex-shrink: 0;\n}\n\n.wallet-modal-chain-selector-back:hover,\n.wallet-modal-chain-selector-close:hover {\n background: #f1f5f9;\n color: #111827;\n}\n\n.wallet-modal-chain-selector-back:active,\n.wallet-modal-chain-selector-close:active {\n transform: scale(0.95);\n}\n\n.wallet-modal-content .wallet-modal-chain-selector-title {\n font-size: 18px;\n font-weight: 500;\n margin: 0;\n color: #111827;\n flex: 1;\n text-align: center;\n}\n\n.wallet-modal-chain-selector-content {\n flex: 1;\n overflow-y: auto;\n padding: 0;\n display: flex;\n flex-direction: column;\n gap: 16px;\n}\n\n/* Custom Scrollbar */\n.wallet-modal-chain-selector-content::-webkit-scrollbar {\n width: 8px;\n}\n\n.wallet-modal-chain-selector-content::-webkit-scrollbar-track {\n background: transparent;\n}\n\n.wallet-modal-chain-selector-content::-webkit-scrollbar-thumb {\n background: #cbd5e1;\n border-radius: 10px;\n border: 2px solid transparent;\n background-clip: content-box;\n}\n\n.wallet-modal-chain-selector-content::-webkit-scrollbar-thumb:hover {\n background: #94a3b8;\n background-clip: content-box;\n}\n\n.wallet-modal-theme-dark .wallet-modal-chain-selector-content::-webkit-scrollbar-thumb {\n background: #475569;\n}\n\n/* Tabs */\n.wallet-modal-chain-tabs {\n display: flex;\n gap: 12px;\n}\n\n.wallet-modal-chain-tab {\n padding: 8px 16px;\n border-radius: 10px;\n border: none;\n background: transparent;\n cursor: pointer;\n font-size: 14px;\n font-weight: 600;\n color: #64748b;\n transition: all 0.2s;\n pointer-events: auto;\n user-select: none;\n -webkit-user-select: none;\n}\n\n.wallet-modal-chain-tab:hover {\n color: #111827;\n}\n\n.wallet-modal-chain-tab.active {\n background: #f1f5f9;\n color: #111827;\n}\n\n/* Search */\n.wallet-modal-chain-search-container {\n position: relative;\n width: 100%;\n}\n\n.wallet-modal-chain-search-icon {\n position: absolute;\n left: 16px;\n top: 50%;\n transform: translateY(-50%);\n color: #94a3b8;\n pointer-events: none;\n display: flex;\n}\n\n.wallet-modal-chain-search-input {\n width: 100%;\n padding: 12px 16px 12px 48px;\n border-radius: 12px;\n border: 1px solid #e2e8f0;\n background: #ffffff;\n font-size: 15px;\n outline: none;\n transition: all 0.2s;\n color: #111827;\n box-sizing: border-box;\n pointer-events: auto;\n user-select: text;\n -webkit-user-select: text;\n}\n\n.wallet-modal-chain-search-input:focus {\n border-color: #9333ea;\n}\n\n.wallet-modal-chain-search-input::placeholder {\n color: #94a3b8;\n}\n\n/* List */\n.wallet-modal-chain-list-container {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.wallet-modal-chain-list-header {\n font-size: 13px;\n font-weight: 600;\n color: #94a3b8;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n padding-left: 0;\n}\n\n.wallet-modal-chain-list {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.wallet-modal-chain-item {\n width: 100%;\n padding: 10px 12px;\n border-radius: 12px;\n border: none;\n background: transparent;\n cursor: pointer;\n transition: all 0.2s;\n display: flex;\n align-items: center;\n gap: 16px;\n text-align: left;\n pointer-events: auto;\n user-select: none;\n -webkit-user-select: none;\n}\n\n.wallet-modal-chain-item:hover {\n background: #f8fafc;\n}\n\n.wallet-modal-chain-item.active {\n background: rgba(147, 51, 234, 0.05);\n}\n\n.wallet-modal-chain-item:active {\n transform: scale(0.98);\n}\n\n.wallet-modal-chain-item:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n pointer-events: none;\n}\n\n/* Visual-only equivalent of :disabled - deliberately keeps pointer-events enabled so a\n stuck switching state can never silently swallow clicks the way a native disabled\n attribute (or pointer-events: none) would. The JS click guard + safety timeout in\n ChainSelector.tsx handle actually preventing redundant switches. */\n.wallet-modal-chain-item[aria-disabled=\"true\"] {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.wallet-modal-chain-item.switching {\n opacity: 0.7;\n pointer-events: none;\n}\n\n.wallet-modal-chain-item-icon-wrapper {\n position: relative;\n width: 36px;\n height: 36px;\n flex-shrink: 0;\n}\n\n.wallet-modal-chain-item-icon-img {\n width: 100%;\n height: 100%;\n border-radius: 50%;\n object-fit: cover;\n}\n\n.wallet-modal-chain-item-icon-placeholder {\n width: 100%;\n height: 100%;\n border-radius: 50%;\n background: #f1f5f9;\n display: flex;\n align-items: center;\n justify-content: center;\n font-weight: 700;\n color: #64748b;\n font-size: 14px;\n}\n\n.wallet-modal-chain-item-status {\n position: absolute;\n bottom: -2px;\n right: -2px;\n width: 10px;\n height: 10px;\n border-radius: 50%;\n background: #10b981;\n border: 2px solid #ffffff;\n}\n\n.wallet-modal-chain-item-name {\n flex: 1;\n font-size: 16px;\n font-weight: 600;\n color: #111827;\n}\n\n.wallet-modal-chain-item-checkmark {\n color: #10b981;\n display: flex;\n}\n\n.wallet-modal-chain-no-results {\n padding: 40px 20px;\n text-align: center;\n color: #64748b;\n font-size: 15px;\n}\n\n/* Dark Theme Support */\n.wallet-modal-theme-dark.wallet-modal-chain-selector-view {\n background: #1a1a1a;\n}\n\n.wallet-modal-theme-dark .wallet-modal-chain-selector-header {\n border-color: #2a2a2a;\n}\n\n.wallet-modal-content.wallet-modal-theme-dark .wallet-modal-chain-selector-title {\n color: #ffffff;\n}\n\n.wallet-modal-theme-dark .wallet-modal-chain-tab.active {\n background: #2a2a2a;\n color: #ffffff;\n}\n\n.wallet-modal-theme-dark .wallet-modal-chain-search-input {\n background: #2a2a2a;\n border-color: #3a3a3a;\n color: #ffffff;\n}\n\n.wallet-modal-theme-dark .wallet-modal-chain-item:hover {\n background: #2a2a2a;\n}\n\n.wallet-modal-theme-dark .wallet-modal-chain-item-name {\n color: #ffffff;\n}\n\n.wallet-modal-theme-dark .wallet-modal-chain-item-status {\n border-color: #1a1a1a;\n}\n\n\n";
@@ -1,5 +1,4 @@
1
1
  import type { ChainData } from "../../../chains";
2
- import "./ChainSelector.css";
3
2
  export interface ChainSelectorProps {
4
3
  currentChain: ChainData | null;
5
4
  availableChains: ChainData[];