decane-connect-kit 2.27.0 → 2.29.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -59,11 +59,12 @@ __export(errors_exports, {
59
59
  UnlockTokenRejectedError: () => UnlockTokenRejectedError,
60
60
  UserCancelledError: () => UserCancelledError,
61
61
  WalletEnrolmentError: () => WalletEnrolmentError,
62
+ WalletExistsError: () => WalletExistsError,
62
63
  WebAuthnNotSupportedError: () => WebAuthnNotSupportedError,
63
64
  WrongPasswordError: () => WrongPasswordError,
64
65
  WrongUnlockPasswordError: () => WrongUnlockPasswordError
65
66
  });
66
- var DecaneConnectError, InvalidApiKeyError, OriginNotAllowedError, SessionExpiredError, UnlockRequiredError, ReconnectRequiredError, UserCancelledError, WebAuthnNotSupportedError, InvalidPinError, CallSequenceError, NetworkError, ShareCorruptedError, ProvisioningTimeoutError, NewDeviceError, StaleDeviceShareError, PromptPinNotConfiguredError, PromptPasswordNotConfiguredError, WrongUnlockPasswordError, InvalidAccessTokenError, UnlockTokenRejectedError, AttestationError, RecoveryFailedError, InvalidRecoveryFileError, WrongPasswordError, RecoveryWalletMismatchError, ExportNotAuthorizedError, WalletEnrolmentError, ProvisioningRateLimitedError, EnclaveHttpError;
67
+ var DecaneConnectError, InvalidApiKeyError, OriginNotAllowedError, SessionExpiredError, UnlockRequiredError, ReconnectRequiredError, UserCancelledError, WebAuthnNotSupportedError, InvalidPinError, CallSequenceError, NetworkError, ShareCorruptedError, ProvisioningTimeoutError, NewDeviceError, StaleDeviceShareError, PromptPinNotConfiguredError, PromptPasswordNotConfiguredError, WrongUnlockPasswordError, InvalidAccessTokenError, UnlockTokenRejectedError, AttestationError, RecoveryFailedError, InvalidRecoveryFileError, WrongPasswordError, RecoveryWalletMismatchError, ExportNotAuthorizedError, WalletExistsError, WalletEnrolmentError, ProvisioningRateLimitedError, EnclaveHttpError;
67
68
  var init_errors = __esm({
68
69
  "src/social/errors.ts"() {
69
70
  "use strict";
@@ -212,6 +213,11 @@ var init_errors = __esm({
212
213
  super("EXPORT_NOT_AUTHORIZED", "Export requires a fresh security check", true);
213
214
  }
214
215
  };
216
+ WalletExistsError = class extends DecaneConnectError {
217
+ constructor() {
218
+ super("WALLET_EXISTS", "This account already has a wallet; opening it instead.", true);
219
+ }
220
+ };
215
221
  WalletEnrolmentError = class extends DecaneConnectError {
216
222
  constructor(cause) {
217
223
  super(
@@ -279,6 +285,7 @@ __export(index_exports, {
279
285
  UnlockTokenRejectedError: () => UnlockTokenRejectedError,
280
286
  UserCancelledError: () => UserCancelledError,
281
287
  WalletEnrolmentError: () => WalletEnrolmentError,
288
+ WalletExistsError: () => WalletExistsError,
282
289
  WalletSelector: () => WalletSelector,
283
290
  WeakPasswordError: () => WeakPasswordError,
284
291
  WebAuthnNotSupportedError: () => WebAuthnNotSupportedError,
@@ -2109,7 +2116,9 @@ var ERROR_MAP = {
2109
2116
  // The backend's authMiddleware code for an expired/revoked JWT. Surfacing it
2110
2117
  // as ReconnectRequiredError routes callers to the sign-in UI instead of a
2111
2118
  // generic failure message.
2112
- UNAUTHORIZED: ReconnectRequiredError
2119
+ UNAUTHORIZED: ReconnectRequiredError,
2120
+ // A restorable wallet already exists: the client provisions instead of creating.
2121
+ WALLET_EXISTS: WalletExistsError
2113
2122
  };
2114
2123
  var REQUEST_TIMEOUT_MS = 3e4;
2115
2124
  var ApiClient = class {
@@ -2509,7 +2518,7 @@ function dropCollateral(teeUrl) {
2509
2518
  // src/social/attestation.ts
2510
2519
  init_errors();
2511
2520
 
2512
- // ../../infra/tee-measurement.json
2521
+ // ../infra/tee-measurement.json
2513
2522
  var tee_measurement_default = {
2514
2523
  signerVersion: "0.2.10",
2515
2524
  acceptedMrtd: [
@@ -4471,24 +4480,37 @@ async function createDecaneConnect(config) {
4471
4480
  if (unlockTokenKey) await attachUnlockToken(userId, jwt, unlockTokenKey);
4472
4481
  }
4473
4482
  const serverIv = generateRandomBytes(12);
4474
- await withDeadline(api.putShare(jwt, {
4475
- ciphertext: shareSet.server,
4476
- iv: serverIv,
4477
- wrappedShareMeta: {
4478
- // The server records this on the wallet_created event and nothing else.
4479
- unlockMethod: identityTier ? "identity" : unlockMethod
4480
- // credential IDs, prfSalt, pinSalt stay on-device — never sent to server
4481
- },
4482
- evmAddress,
4483
- solanaAddress,
4484
- tronAddress,
4485
- // Provisional until the enclave has sealed the auth share, just below. A
4486
- // backend that knows the flag keeps this row invisible to hasShare until
4487
- // then, so a creation that fails past this point leaves no wallet behind
4488
- // and the next sign-in simply creates again — with a new key, which is
4489
- // why the backend also replaces the recorded addresses outright.
4490
- pendingEnrolment: true
4491
- }), remainingBudget(), "storing your wallet");
4483
+ try {
4484
+ await withDeadline(api.putShare(jwt, {
4485
+ ciphertext: shareSet.server,
4486
+ iv: serverIv,
4487
+ wrappedShareMeta: {
4488
+ // The server records this on the wallet_created event and nothing else.
4489
+ unlockMethod: identityTier ? "identity" : unlockMethod
4490
+ // credential IDs, prfSalt, pinSalt stay on-device — never sent to server
4491
+ },
4492
+ evmAddress,
4493
+ solanaAddress,
4494
+ tronAddress,
4495
+ // Provisional until the enclave has sealed the auth share, just below. A
4496
+ // backend that knows the flag keeps this row invisible to hasShare until
4497
+ // then, so a creation that fails past this point leaves no wallet behind
4498
+ // and the next sign-in simply creates again — with a new key, which is
4499
+ // why the backend also replaces the recorded addresses outright.
4500
+ pendingEnrolment: true
4501
+ }), remainingBudget(), "storing your wallet");
4502
+ } catch (e) {
4503
+ if (e instanceof WalletExistsError) {
4504
+ zeroize(shareSet.server);
4505
+ zeroize(shareSet.device);
4506
+ zeroize(shareSet.recovery);
4507
+ if (wrappingKey) await storage2.deleteShare(userId).catch(() => {
4508
+ });
4509
+ events.emit("wallet-unlocking");
4510
+ return returningUserUnlock(userId, jwt);
4511
+ }
4512
+ throw e;
4513
+ }
4492
4514
  zeroize(shareSet.server);
4493
4515
  try {
4494
4516
  await enrolBlocking(jwt, new Uint8Array(shareSet.recovery), remainingBudget());
@@ -5579,6 +5601,7 @@ var tokens = {
5579
5601
  accent: "#F5C800",
5580
5602
  accentHover: "#D4A800",
5581
5603
  accentText: "#0D0D0B",
5604
+ accentInk: "#7A5F00",
5582
5605
  badgeEvm: "#1A1917",
5583
5606
  badgeEvmText: "#F5C800",
5584
5607
  badgeSolana: "#F5C800",
@@ -5599,6 +5622,7 @@ var tokens = {
5599
5622
  accent: "#F5C800",
5600
5623
  accentHover: "#FFE04D",
5601
5624
  accentText: "#0D0D0B",
5625
+ accentInk: "#F5C800",
5602
5626
  badgeEvm: "#F5C800",
5603
5627
  badgeEvmText: "#0D0D0B",
5604
5628
  badgeSolana: "#1A1917",
@@ -5624,6 +5648,7 @@ var CSS_VARS = {
5624
5648
  --dc-accent: ${tokens.light.accent};
5625
5649
  --dc-accent-hover: ${tokens.light.accentHover};
5626
5650
  --dc-accent-text: ${tokens.light.accentText};
5651
+ --dc-accent-ink: ${tokens.light.accentInk};
5627
5652
  --dc-badge-evm: ${tokens.light.badgeEvm};
5628
5653
  --dc-badge-evm-text: ${tokens.light.badgeEvmText};
5629
5654
  --dc-badge-sol: ${tokens.light.badgeSolana};
@@ -5645,6 +5670,7 @@ var CSS_VARS = {
5645
5670
  --dc-accent: ${tokens.dark.accent};
5646
5671
  --dc-accent-hover: ${tokens.dark.accentHover};
5647
5672
  --dc-accent-text: ${tokens.dark.accentText};
5673
+ --dc-accent-ink: ${tokens.dark.accentInk};
5648
5674
  --dc-badge-evm: ${tokens.dark.badgeEvm};
5649
5675
  --dc-badge-evm-text: ${tokens.dark.badgeEvmText};
5650
5676
  --dc-badge-sol: ${tokens.dark.badgeSolana};
@@ -5806,6 +5832,54 @@ function XLogo({ size = 14 }) {
5806
5832
  /* @__PURE__ */ import_react.default.createElement("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" })
5807
5833
  );
5808
5834
  }
5835
+ var line = {
5836
+ fill: "none",
5837
+ stroke: "currentColor",
5838
+ strokeWidth: 1.8,
5839
+ strokeLinecap: "round",
5840
+ strokeLinejoin: "round"
5841
+ };
5842
+ function GoogleMark({ size = 18 }) {
5843
+ return /* @__PURE__ */ import_react.default.createElement("svg", { width: size, height: size, viewBox: "0 0 48 48", "aria-hidden": "true", style: { flexShrink: 0 } }, /* @__PURE__ */ import_react.default.createElement("path", { fill: "#EA4335", d: "M24 9.5c3.5 0 6 1.5 7.4 2.8l5.4-5.3C33.5 3.9 29.2 2 24 2 15.4 2 8 7 4.7 14.2l6.3 4.9C12.6 13.4 17.8 9.5 24 9.5z" }), /* @__PURE__ */ import_react.default.createElement("path", { fill: "#4285F4", d: "M46 24.5c0-1.6-.1-2.8-.4-4H24v7.5h12.6c-.3 2.2-1.7 5.5-4.9 7.7l6.1 4.7C41.5 37 46 31.4 46 24.5z" }), /* @__PURE__ */ import_react.default.createElement("path", { fill: "#FBBC05", d: "M11 29.1a13.9 13.9 0 0 1 0-10l-6.3-4.9A22 22 0 0 0 2 24c0 3.5.8 6.9 2.4 9.8L11 29.1z" }), /* @__PURE__ */ import_react.default.createElement("path", { fill: "#34A853", d: "M24 46c5.9 0 10.9-2 14.5-5.4l-6.1-4.7c-1.7 1.2-4 2-8.4 2-6.2 0-11.4-4-13.1-9.6l-6.3 4.9C7.9 40.9 15.3 46 24 46z" }));
5844
+ }
5845
+ function MailIcon({ size = 18 }) {
5846
+ return /* @__PURE__ */ import_react.default.createElement("svg", { width: size, height: size, viewBox: "0 0 24 24", ...line, "aria-hidden": "true", style: { flexShrink: 0 } }, /* @__PURE__ */ import_react.default.createElement("rect", { x: "3", y: "5", width: "18", height: "14", rx: "2.5" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "m3.5 7 8.5 6 8.5-6" }));
5847
+ }
5848
+ function PhoneIcon({ size = 18 }) {
5849
+ return /* @__PURE__ */ import_react.default.createElement("svg", { width: size, height: size, viewBox: "0 0 24 24", ...line, "aria-hidden": "true", style: { flexShrink: 0 } }, /* @__PURE__ */ import_react.default.createElement("rect", { x: "7", y: "2.5", width: "10", height: "19", rx: "2.5" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M11 18h2" }));
5850
+ }
5851
+ function ChatIcon({ size = 18 }) {
5852
+ return /* @__PURE__ */ import_react.default.createElement("svg", { width: size, height: size, viewBox: "0 0 24 24", ...line, "aria-hidden": "true", style: { flexShrink: 0 } }, /* @__PURE__ */ import_react.default.createElement("path", { d: "M4 6.5A2.5 2.5 0 0 1 6.5 4h11A2.5 2.5 0 0 1 20 6.5v7a2.5 2.5 0 0 1-2.5 2.5H10l-4.2 3.2a.6.6 0 0 1-1-.5V16A2.5 2.5 0 0 1 4 13.5z" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M8.5 9h7M8.5 12.5h4.5" }));
5853
+ }
5854
+ function KeyIcon({ size = 18 }) {
5855
+ return /* @__PURE__ */ import_react.default.createElement("svg", { width: size, height: size, viewBox: "0 0 24 24", ...line, "aria-hidden": "true", style: { flexShrink: 0 } }, /* @__PURE__ */ import_react.default.createElement("circle", { cx: "8", cy: "12", r: "4" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M12 12h9M18 12v3M15 12v2.5" }));
5856
+ }
5857
+ function UserIcon({ size = 18 }) {
5858
+ return /* @__PURE__ */ import_react.default.createElement("svg", { width: size, height: size, viewBox: "0 0 24 24", ...line, "aria-hidden": "true", style: { flexShrink: 0 } }, /* @__PURE__ */ import_react.default.createElement("circle", { cx: "12", cy: "8.5", r: "3.8" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M4.5 20a7.5 7.5 0 0 1 15 0" }));
5859
+ }
5860
+ function CopyIcon({ size = 15 }) {
5861
+ return /* @__PURE__ */ import_react.default.createElement("svg", { width: size, height: size, viewBox: "0 0 24 24", ...line, "aria-hidden": "true", style: { flexShrink: 0 } }, /* @__PURE__ */ import_react.default.createElement("rect", { x: "8.5", y: "8.5", width: "12", height: "12", rx: "2.5" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M15.5 8.5V6A2.5 2.5 0 0 0 13 3.5H6A2.5 2.5 0 0 0 3.5 6v7A2.5 2.5 0 0 0 6 15.5h2.5" }));
5862
+ }
5863
+ function CheckIcon({ size = 15 }) {
5864
+ return /* @__PURE__ */ import_react.default.createElement("svg", { width: size, height: size, viewBox: "0 0 24 24", ...line, "aria-hidden": "true", style: { flexShrink: 0 } }, /* @__PURE__ */ import_react.default.createElement("path", { d: "m5 12.5 4.5 4.5L19 7.5" }));
5865
+ }
5866
+ function CloseIcon({ size = 16 }) {
5867
+ return /* @__PURE__ */ import_react.default.createElement("svg", { width: size, height: size, viewBox: "0 0 24 24", ...line, "aria-hidden": "true", style: { flexShrink: 0 } }, /* @__PURE__ */ import_react.default.createElement("path", { d: "M6 6l12 12M18 6 6 18" }));
5868
+ }
5869
+ function ChevronIcon({ size = 16, open = false }) {
5870
+ return /* @__PURE__ */ import_react.default.createElement(
5871
+ "svg",
5872
+ {
5873
+ width: size,
5874
+ height: size,
5875
+ viewBox: "0 0 24 24",
5876
+ ...line,
5877
+ "aria-hidden": "true",
5878
+ style: { flexShrink: 0, transition: "transform .2s", transform: open ? "rotate(180deg)" : "none" }
5879
+ },
5880
+ /* @__PURE__ */ import_react.default.createElement("path", { d: "m6 9 6 6 6-6" })
5881
+ );
5882
+ }
5809
5883
 
5810
5884
  // src/ui/WalletSelector.tsx
5811
5885
  var FONT_URL = "https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap";
@@ -6869,33 +6943,6 @@ function downloadJson(data, filename) {
6869
6943
  a.click();
6870
6944
  URL.revokeObjectURL(url);
6871
6945
  }
6872
- function CopyButton({ value }) {
6873
- const [copied, setCopied] = (0, import_react3.useState)(false);
6874
- async function copy() {
6875
- await navigator.clipboard.writeText(value).catch(() => {
6876
- });
6877
- setCopied(true);
6878
- setTimeout(() => setCopied(false), 1500);
6879
- }
6880
- return /* @__PURE__ */ import_react3.default.createElement(
6881
- "button",
6882
- {
6883
- onClick: copy,
6884
- style: {
6885
- background: "none",
6886
- border: "none",
6887
- cursor: "pointer",
6888
- color: copied ? "var(--dc-accent)" : "var(--dc-text-muted)",
6889
- fontSize: 11,
6890
- fontFamily: "inherit",
6891
- padding: "2px 6px",
6892
- borderRadius: 5,
6893
- transition: "color 0.15s"
6894
- }
6895
- },
6896
- copied ? "\u2713" : "copy"
6897
- );
6898
- }
6899
6946
  function useBalance(kind, address, chain, rpcUrls) {
6900
6947
  const [state, setState] = (0, import_react3.useState)({ loading: false, value: null, symbol: kind === "evm" ? "ETH" : "SOL" });
6901
6948
  (0, import_react3.useEffect)(() => {
@@ -6913,6 +6960,117 @@ function useBalance(kind, address, chain, rpcUrls) {
6913
6960
  }, [kind, address, chain, rpcUrls]);
6914
6961
  return state;
6915
6962
  }
6963
+ var MODAL_CSS = `
6964
+ .dcm-card { position: relative; width: 100%; max-width: 380px; max-height: calc(100vh - 32px); overflow-y: auto;
6965
+ background: var(--dc-bg); color: var(--dc-text); border: 1px solid var(--dc-border); border-radius: 24px;
6966
+ box-shadow: 0 24px 64px -12px rgba(0,0,0,.35), 0 2px 8px rgba(0,0,0,.08);
6967
+ animation: dcm-in .22s cubic-bezier(.2,.8,.2,1); box-sizing: border-box; }
6968
+ .dcm-card *, .dcm-card *::before, .dcm-card *::after { box-sizing: border-box; }
6969
+ @keyframes dcm-in { from { opacity: 0; transform: translateY(8px) scale(.985); } to { opacity: 1; transform: none; } }
6970
+ @keyframes dcm-fade { from { opacity: 0; } to { opacity: 1; } }
6971
+ @media (prefers-reduced-motion: reduce) { .dcm-card, .dcm-backdrop { animation: none !important; } }
6972
+ .dcm-backdrop { position: absolute; inset: 0; background: var(--dc-bg-overlay);
6973
+ backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px); animation: dcm-fade .2s ease; }
6974
+ .dcm-icon-btn { position: absolute; top: 14px; width: 32px; height: 32px; border-radius: 10px; border: 0;
6975
+ background: transparent; color: var(--dc-text-muted); cursor: pointer; display: grid; place-items: center;
6976
+ padding: 0; transition: background .15s, color .15s; z-index: 1; }
6977
+ .dcm-icon-btn:hover { background: var(--dc-surface-hover); color: var(--dc-text); }
6978
+ .dcm-body { padding: 32px 24px 20px; display: flex; flex-direction: column; align-items: center; gap: 14px; text-align: center; }
6979
+ .dcm-title { margin: 4px 0 0; font-size: 20px; font-weight: 600; letter-spacing: -0.02em; line-height: 1.25; color: var(--dc-text); }
6980
+ .dcm-sub { margin: -6px 0 2px; font-size: 13.5px; line-height: 1.5; color: var(--dc-text-secondary); overflow-wrap: anywhere; }
6981
+ .dcm-sub b { color: var(--dc-text); font-weight: 600; }
6982
+ .dcm-methods { width: 100%; display: grid; gap: 8px; margin-top: 4px; }
6983
+ .dcm-method { width: 100%; height: 48px; display: flex; align-items: center; gap: 12px; padding: 0 14px;
6984
+ border-radius: 14px; border: 1px solid var(--dc-border); background: var(--dc-surface); color: var(--dc-text);
6985
+ font-weight: 500; font-size: 14.5px; line-height: 1; font-family: inherit; cursor: pointer; text-align: left;
6986
+ transition: border-color .15s, background .15s; }
6987
+ .dcm-method:hover:not(:disabled) { border-color: var(--dc-text-muted); background: var(--dc-surface-hover); }
6988
+ .dcm-method:disabled { opacity: .6; cursor: default; }
6989
+ .dcm-method:focus-visible, .dcm-primary:focus-visible, .dcm-link:focus-visible, .dcm-icon-btn:focus-visible,
6990
+ .dcm-ghost:focus-visible, .dcm-copy:focus-visible { outline: 2px solid var(--dc-accent); outline-offset: 2px; }
6991
+ .dcm-method > svg { color: var(--dc-text-secondary); }
6992
+ .dcm-method-input { cursor: text; padding-right: 6px; }
6993
+ .dcm-method-input:focus-within { border-color: var(--dc-accent); }
6994
+ .dcm-method-input input { flex: 1; min-width: 0; height: 100%; border: 0; outline: 0; background: transparent;
6995
+ color: var(--dc-text); font-family: inherit; font-size: 14.5px; padding: 0; }
6996
+ .dcm-method-input input::placeholder { color: var(--dc-text-muted); }
6997
+ .dcm-submit { height: 34px; padding: 0 12px; border-radius: 10px; border: 0; background: transparent;
6998
+ color: var(--dc-accent-ink); font-weight: 600; font-size: 13.5px; line-height: 1; font-family: inherit; cursor: pointer; transition: background .15s; }
6999
+ .dcm-submit:hover:not(:disabled) { background: var(--dc-surface-hover); }
7000
+ .dcm-submit:disabled { color: var(--dc-text-muted); cursor: default; }
7001
+ .dcm-form { width: 100%; display: grid; gap: 10px; margin-top: 4px; }
7002
+ .dcm-field { width: 100%; padding: 12px 14px; border-radius: 12px; border: 1px solid var(--dc-border);
7003
+ background: var(--dc-surface); color: var(--dc-text); font-family: inherit; font-size: 15px; outline: none;
7004
+ transition: border-color .15s, box-shadow .15s; }
7005
+ .dcm-field::placeholder { color: var(--dc-text-muted); }
7006
+ .dcm-field:focus { border-color: var(--dc-accent); box-shadow: 0 0 0 3px color-mix(in srgb, var(--dc-accent) 22%, transparent); }
7007
+ .dcm-code { height: 56px; text-align: center; font-family: var(--dc-font-mono); font-size: 24px; letter-spacing: .45em; padding-left: calc(14px + .45em); }
7008
+ .dcm-primary { width: 100%; height: 48px; border-radius: 14px; border: 0; background: var(--dc-accent); color: var(--dc-accent-text);
7009
+ font-weight: 600; font-size: 14.5px; line-height: 1; font-family: inherit; cursor: pointer; display: flex; align-items: center; justify-content: center; gap: 8px;
7010
+ transition: background .15s, opacity .15s; }
7011
+ .dcm-primary:hover:not(:disabled) { background: var(--dc-accent-hover); }
7012
+ .dcm-primary:disabled { opacity: .55; cursor: default; }
7013
+ .dcm-ghost { height: 44px; padding: 0 16px; border-radius: 12px; border: 1px solid var(--dc-border); background: transparent;
7014
+ color: var(--dc-text); font-weight: 500; font-size: 14px; line-height: 1; font-family: inherit; cursor: pointer; transition: background .15s, border-color .15s; white-space: nowrap; }
7015
+ .dcm-ghost:hover:not(:disabled) { background: var(--dc-surface-hover); border-color: var(--dc-text-muted); }
7016
+ .dcm-ghost:disabled { opacity: .55; cursor: default; }
7017
+ .dcm-link { border: 0; background: transparent; color: var(--dc-accent-ink); font-weight: 500; font-size: 13.5px; line-height: 1.4; font-family: inherit;
7018
+ cursor: pointer; padding: 4px; border-radius: 6px; }
7019
+ .dcm-link:hover { text-decoration: underline; text-underline-offset: 3px; }
7020
+ .dcm-badge { width: 52px; height: 52px; border-radius: 16px; display: grid; place-items: center;
7021
+ background: var(--dc-surface); border: 1px solid var(--dc-border); color: var(--dc-text); }
7022
+ .dcm-error { margin: 0; width: 100%; font-size: 13px; line-height: 1.45; color: var(--dc-danger); overflow-wrap: anywhere; }
7023
+ .dcm-protected { width: 100%; display: flex; align-items: center; justify-content: center; gap: 6px;
7024
+ margin-top: 6px; padding-top: 14px; border-top: 1px solid var(--dc-border); font-size: 12.5px; color: var(--dc-text-muted); }
7025
+ .dcm-status { display: inline-flex; align-items: center; gap: 6px; font-size: 12.5px; font-weight: 500; }
7026
+ .dcm-status i { width: 7px; height: 7px; border-radius: 50%; display: block; }
7027
+ .dcm-addresses { width: 100%; border: 1px solid var(--dc-border); border-radius: 16px; overflow: hidden; text-align: left; }
7028
+ .dcm-address { display: flex; align-items: center; gap: 12px; padding: 12px 14px; background: var(--dc-surface); }
7029
+ .dcm-address + .dcm-address { border-top: 1px solid var(--dc-border); }
7030
+ .dcm-address-main { flex: 1; min-width: 0; display: grid; gap: 3px; }
7031
+ .dcm-address-main span { font-size: 13px; color: var(--dc-text-secondary); }
7032
+ .dcm-address-main code { font-family: var(--dc-font-mono); font-size: 13px; color: var(--dc-text); }
7033
+ .dcm-balance { font-family: var(--dc-font-mono); font-size: 13px; color: var(--dc-text); white-space: nowrap; }
7034
+ .dcm-copy { width: 30px; height: 30px; border-radius: 9px; border: 0; background: transparent; color: var(--dc-text-muted);
7035
+ display: grid; place-items: center; cursor: pointer; padding: 0; transition: background .15s, color .15s; }
7036
+ .dcm-copy:hover { background: var(--dc-surface-hover); color: var(--dc-text); }
7037
+ .dcm-panel { width: 100%; border: 1px solid var(--dc-border); border-radius: 16px; text-align: left; overflow: hidden; }
7038
+ .dcm-panel-head { width: 100%; display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 13px 14px;
7039
+ border: 0; background: var(--dc-surface); color: var(--dc-text); font-weight: 500; font-size: 14px; line-height: 1; font-family: inherit; cursor: pointer; }
7040
+ .dcm-panel-head:hover { background: var(--dc-surface-hover); }
7041
+ .dcm-panel-head svg { color: var(--dc-text-muted); }
7042
+ .dcm-panel-body { padding: 14px; border-top: 1px solid var(--dc-border); display: grid; gap: 10px; }
7043
+ .dcm-note { margin: 0; font-size: 13px; line-height: 1.5; color: var(--dc-text-secondary); }
7044
+ .dcm-warn { padding: 12px; border-radius: 12px; font-size: 13px; line-height: 1.5;
7045
+ background: color-mix(in srgb, var(--dc-danger) 9%, transparent); border: 1px solid color-mix(in srgb, var(--dc-danger) 30%, transparent); color: var(--dc-text); }
7046
+ .dcm-warn strong { display: block; margin-bottom: 2px; color: var(--dc-danger); font-weight: 600; }
7047
+ .dcm-check { display: flex; align-items: center; gap: 8px; font-size: 13px; color: var(--dc-text); cursor: pointer; }
7048
+ .dcm-check input { width: 16px; height: 16px; margin: 0; accent-color: var(--dc-accent); }
7049
+ .dcm-row { display: flex; gap: 8px; width: 100%; }
7050
+ .dcm-row > .dcm-primary { flex: 1; height: 44px; border-radius: 12px; }
7051
+ .dcm-actions { width: 100%; display: flex; gap: 8px; }
7052
+ .dcm-actions > * { flex: 1; }
7053
+ `;
7054
+ function injectModalCss() {
7055
+ if (document.getElementById("decane-modal-css")) return;
7056
+ const el = document.createElement("style");
7057
+ el.id = "decane-modal-css";
7058
+ el.textContent = MODAL_CSS;
7059
+ document.head.appendChild(el);
7060
+ }
7061
+ function shortAddress(a, head = 6, tail = 4) {
7062
+ return a.length > head + tail + 1 ? `${a.slice(0, head)}\u2026${a.slice(-tail)}` : a;
7063
+ }
7064
+ function CopyButton({ value, label }) {
7065
+ const [copied, setCopied] = (0, import_react3.useState)(false);
7066
+ async function copy() {
7067
+ await navigator.clipboard.writeText(value).catch(() => {
7068
+ });
7069
+ setCopied(true);
7070
+ setTimeout(() => setCopied(false), 1500);
7071
+ }
7072
+ return /* @__PURE__ */ import_react3.default.createElement("button", { type: "button", className: "dcm-copy", onClick: copy, "aria-label": copied ? "Copied" : `Copy ${label} address`, title: copied ? "Copied" : "Copy address" }, copied ? /* @__PURE__ */ import_react3.default.createElement(CheckIcon, null) : /* @__PURE__ */ import_react3.default.createElement(CopyIcon, null));
7073
+ }
6916
7074
  function AddressRow({
6917
7075
  label,
6918
7076
  address,
@@ -6921,14 +7079,10 @@ function AddressRow({
6921
7079
  rpcUrls
6922
7080
  }) {
6923
7081
  const balance = useBalance(kind, address, chain, rpcUrls);
6924
- const short = `${address.slice(0, 8)}\u2026${address.slice(-6)}`;
6925
- return /* @__PURE__ */ import_react3.default.createElement("div", { style: {
6926
- background: "var(--dc-surface)",
6927
- border: "1px solid var(--dc-border)",
6928
- borderRadius: 10,
6929
- padding: "10px 14px",
6930
- marginBottom: 8
6931
- } }, /* @__PURE__ */ import_react3.default.createElement("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 5 } }, /* @__PURE__ */ import_react3.default.createElement("span", { style: { fontSize: 10, fontWeight: 700, color: "var(--dc-text-muted)", letterSpacing: "0.06em", textTransform: "uppercase" } }, label), /* @__PURE__ */ import_react3.default.createElement("span", { style: { fontSize: 11, fontFamily: "monospace", color: "var(--dc-text)" } }, balance.loading ? "\u2026" : `${formatBalanceDisplay(balance.value)} ${balance.symbol}`)), /* @__PURE__ */ import_react3.default.createElement("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between", gap: 8 } }, /* @__PURE__ */ import_react3.default.createElement("span", { style: { fontSize: 13, fontFamily: "monospace", color: "var(--dc-text)", letterSpacing: "0.02em" } }, short), /* @__PURE__ */ import_react3.default.createElement(CopyButton, { value: address })));
7082
+ return /* @__PURE__ */ import_react3.default.createElement("div", { className: "dcm-address" }, /* @__PURE__ */ import_react3.default.createElement("div", { className: "dcm-address-main" }, /* @__PURE__ */ import_react3.default.createElement("span", null, label), /* @__PURE__ */ import_react3.default.createElement("code", { title: address }, shortAddress(address, 8, 6))), /* @__PURE__ */ import_react3.default.createElement("span", { className: "dcm-balance" }, balance.loading ? "\u2026" : `${formatBalanceDisplay(balance.value)} ${balance.symbol}`), /* @__PURE__ */ import_react3.default.createElement(CopyButton, { value: address, label }));
7083
+ }
7084
+ function ProtectedBy() {
7085
+ return /* @__PURE__ */ import_react3.default.createElement("div", { className: "dcm-protected" }, /* @__PURE__ */ import_react3.default.createElement("span", null, "Protected by"), /* @__PURE__ */ import_react3.default.createElement(DecaneMark, { size: 14, muted: true }), /* @__PURE__ */ import_react3.default.createElement(DecaneWordmark, { size: 12, muted: true }));
6932
7086
  }
6933
7087
  function SignInView({
6934
7088
  onGoogleSignIn,
@@ -6962,6 +7116,7 @@ function SignInView({
6962
7116
  const [showOtherMethods, setShowOtherMethods] = (0, import_react3.useState)(false);
6963
7117
  const [error, setError] = (0, import_react3.useState)("");
6964
7118
  const passkeyFirst = !!canUsePasskey && !!onPasskeySignIn && !showOtherMethods;
7119
+ const busy = googleLoading || kingsChatLoading || xLoading || customLoading || emailLoading || phoneLoading;
6965
7120
  async function handlePasskey() {
6966
7121
  if (!onPasskeySignIn) return;
6967
7122
  setError("");
@@ -7015,7 +7170,7 @@ function SignInView({
7015
7170
  setError("");
7016
7171
  setEmailLoading(true);
7017
7172
  try {
7018
- await onEmailStart(email);
7173
+ await onEmailStart(email.trim());
7019
7174
  setEmailSent(true);
7020
7175
  } catch (e2) {
7021
7176
  setError(e2.message);
@@ -7028,7 +7183,7 @@ function SignInView({
7028
7183
  setError("");
7029
7184
  setEmailLoading(true);
7030
7185
  try {
7031
- await onEmailVerify(email, code);
7186
+ await onEmailVerify(email.trim(), code);
7032
7187
  } catch (e2) {
7033
7188
  setError(e2.message);
7034
7189
  } finally {
@@ -7041,7 +7196,7 @@ function SignInView({
7041
7196
  setError("");
7042
7197
  setPhoneLoading(true);
7043
7198
  try {
7044
- await onPhoneStart(phone);
7199
+ await onPhoneStart(phone.trim());
7045
7200
  setPhoneSent(true);
7046
7201
  } catch (e2) {
7047
7202
  setError(e2.message);
@@ -7055,7 +7210,7 @@ function SignInView({
7055
7210
  setError("");
7056
7211
  setPhoneLoading(true);
7057
7212
  try {
7058
- await onPhoneVerify(phone, phoneCode);
7213
+ await onPhoneVerify(phone.trim(), phoneCode);
7059
7214
  } catch (e2) {
7060
7215
  setError(e2.message);
7061
7216
  } finally {
@@ -7074,226 +7229,67 @@ function SignInView({
7074
7229
  setCustomLoading(false);
7075
7230
  }
7076
7231
  }
7077
- const inputStyle = {
7078
- width: "100%",
7079
- background: "var(--dc-surface)",
7080
- border: "1px solid var(--dc-border)",
7081
- borderRadius: 8,
7082
- color: "var(--dc-text)",
7083
- padding: "9px 12px",
7084
- fontSize: 13,
7085
- outline: "none",
7086
- fontFamily: "inherit",
7087
- boxSizing: "border-box"
7088
- };
7089
- return /* @__PURE__ */ import_react3.default.createElement("div", { style: { padding: "0 16px 16px" } }, resumeHint && !passkeyFirst && /* @__PURE__ */ import_react3.default.createElement("div", { style: { fontSize: 12, color: "var(--dc-text-muted)", marginBottom: 12, textAlign: "center" } }, "Welcome back \u2014 sign in again to resume ", resumeHint), passkeyFirst && /* @__PURE__ */ import_react3.default.createElement("div", null, /* @__PURE__ */ import_react3.default.createElement("div", { style: { fontSize: 12, color: "var(--dc-text-muted)", marginBottom: 12, textAlign: "center" } }, "Welcome back \u2014 unlock to resume", passkeyAddress ? ` ${passkeyAddress.slice(0, 6)}\u2026${passkeyAddress.slice(-4)}` : ""), /* @__PURE__ */ import_react3.default.createElement(
7090
- "button",
7091
- {
7092
- onClick: handlePasskey,
7093
- disabled: passkeyLoading,
7094
- style: {
7095
- width: "100%",
7096
- padding: "11px 0",
7097
- background: "var(--dc-accent)",
7098
- color: "var(--dc-accent-text)",
7099
- border: "none",
7100
- borderRadius: 10,
7101
- fontSize: 13,
7102
- fontWeight: 700,
7103
- cursor: passkeyLoading ? "not-allowed" : "pointer",
7104
- opacity: passkeyLoading ? 0.7 : 1,
7105
- fontFamily: "inherit",
7106
- display: "flex",
7107
- alignItems: "center",
7108
- justifyContent: "center",
7109
- gap: 7
7110
- }
7111
- },
7112
- passkeyLoading ? "Verifying\u2026" : "\u{1F513} Continue with passkey"
7113
- ), /* @__PURE__ */ import_react3.default.createElement(
7114
- "button",
7115
- {
7116
- onClick: () => setShowOtherMethods(true),
7117
- style: {
7118
- width: "100%",
7119
- marginTop: 10,
7120
- background: "none",
7121
- border: "none",
7122
- color: "var(--dc-text-muted)",
7123
- fontSize: 12,
7124
- cursor: "pointer",
7125
- fontFamily: "inherit"
7126
- }
7127
- },
7128
- "Use email or Google instead"
7129
- ), error && /* @__PURE__ */ import_react3.default.createElement("div", { style: { marginTop: 10, fontSize: 12, color: "var(--dc-danger, #ff5533)" } }, error)), !passkeyFirst && authMethods.includes("google") && /* @__PURE__ */ import_react3.default.createElement(
7130
- "button",
7131
- {
7132
- onClick: handleGoogle,
7133
- disabled: googleLoading,
7134
- style: {
7135
- width: "100%",
7136
- padding: "10px 0",
7137
- marginBottom: 10,
7138
- background: "var(--dc-accent)",
7139
- color: "var(--dc-accent-text)",
7140
- border: "none",
7141
- borderRadius: 10,
7142
- fontSize: 13,
7143
- fontWeight: 700,
7144
- cursor: googleLoading ? "not-allowed" : "pointer",
7145
- opacity: googleLoading ? 0.7 : 1,
7146
- fontFamily: "inherit"
7147
- }
7148
- },
7149
- googleLoading ? "Redirecting\u2026" : "Continue with Google"
7150
- ), !passkeyFirst && authMethods.includes("kingschat") && onKingsChatSignIn && /* @__PURE__ */ import_react3.default.createElement(
7151
- "button",
7152
- {
7153
- onClick: handleKingsChat,
7154
- disabled: kingsChatLoading,
7155
- style: {
7156
- width: "100%",
7157
- padding: "10px 0",
7158
- marginBottom: 10,
7159
- background: "var(--dc-surface)",
7160
- color: "var(--dc-text)",
7161
- border: "1px solid var(--dc-border)",
7162
- borderRadius: 10,
7163
- fontSize: 13,
7164
- fontWeight: 700,
7165
- cursor: kingsChatLoading ? "not-allowed" : "pointer",
7166
- opacity: kingsChatLoading ? 0.7 : 1,
7167
- fontFamily: "inherit"
7168
- }
7169
- },
7170
- kingsChatLoading ? "Waiting for KingsChat\u2026" : "Continue with KingsChat"
7171
- ), !passkeyFirst && authMethods.includes("x") && onXSignIn && /* @__PURE__ */ import_react3.default.createElement(
7172
- "button",
7173
- {
7174
- onClick: handleX,
7175
- disabled: xLoading,
7176
- style: {
7177
- width: "100%",
7178
- padding: "10px 0",
7179
- marginBottom: 10,
7180
- background: "var(--dc-surface)",
7181
- color: "var(--dc-text)",
7182
- border: "1px solid var(--dc-border)",
7183
- borderRadius: 10,
7184
- fontSize: 13,
7185
- fontWeight: 700,
7186
- cursor: xLoading ? "not-allowed" : "pointer",
7187
- opacity: xLoading ? 0.7 : 1,
7188
- fontFamily: "inherit",
7189
- display: "flex",
7190
- alignItems: "center",
7191
- justifyContent: "center",
7192
- gap: 8
7193
- }
7194
- },
7195
- /* @__PURE__ */ import_react3.default.createElement(XLogo, null),
7196
- xLoading ? "Redirecting\u2026" : "Continue with X"
7197
- ), !passkeyFirst && authMethods.includes("email") && /* @__PURE__ */ import_react3.default.createElement(import_react3.default.Fragment, null, authMethods.includes("google") && /* @__PURE__ */ import_react3.default.createElement("div", { style: { textAlign: "center", color: "var(--dc-text-muted)", fontSize: 12, margin: "10px 0" } }, "\u2014 or \u2014"), !emailSent ? /* @__PURE__ */ import_react3.default.createElement("form", { onSubmit: handleEmailStart, style: { display: "flex", gap: 8 } }, /* @__PURE__ */ import_react3.default.createElement(
7232
+ function backToMethods() {
7233
+ setEmailSent(false);
7234
+ setCode("");
7235
+ setPhoneSent(false);
7236
+ setPhoneCode("");
7237
+ setError("");
7238
+ }
7239
+ const errorLine = error ? /* @__PURE__ */ import_react3.default.createElement("p", { className: "dcm-error", role: "alert" }, error) : null;
7240
+ if (passkeyFirst) {
7241
+ return /* @__PURE__ */ import_react3.default.createElement("div", { className: "dcm-body" }, /* @__PURE__ */ import_react3.default.createElement("div", { className: "dcm-badge" }, /* @__PURE__ */ import_react3.default.createElement(KeyIcon, { size: 22 })), /* @__PURE__ */ import_react3.default.createElement("h2", { className: "dcm-title" }, "Welcome back"), /* @__PURE__ */ import_react3.default.createElement("p", { className: "dcm-sub" }, passkeyAddress ? /* @__PURE__ */ import_react3.default.createElement(import_react3.default.Fragment, null, "Unlock ", /* @__PURE__ */ import_react3.default.createElement("b", null, shortAddress(passkeyAddress)), " with your passkey.") : "Unlock your wallet with your passkey."), /* @__PURE__ */ import_react3.default.createElement("button", { type: "button", className: "dcm-primary", onClick: handlePasskey, disabled: passkeyLoading }, passkeyLoading ? "Waiting for passkey\u2026" : "Continue with passkey"), errorLine, /* @__PURE__ */ import_react3.default.createElement("button", { type: "button", className: "dcm-link", onClick: () => {
7242
+ setError("");
7243
+ setShowOtherMethods(true);
7244
+ } }, "Use another sign-in method"), /* @__PURE__ */ import_react3.default.createElement(ProtectedBy, null));
7245
+ }
7246
+ if (emailSent || phoneSent) {
7247
+ const isEmail = emailSent;
7248
+ const value = isEmail ? code : phoneCode;
7249
+ const setValue = isEmail ? setCode : setPhoneCode;
7250
+ const loading = isEmail ? emailLoading : phoneLoading;
7251
+ return /* @__PURE__ */ import_react3.default.createElement("form", { className: "dcm-body", onSubmit: isEmail ? handleEmailVerify : handlePhoneVerify }, /* @__PURE__ */ import_react3.default.createElement("div", { className: "dcm-badge" }, isEmail ? /* @__PURE__ */ import_react3.default.createElement(MailIcon, { size: 22 }) : /* @__PURE__ */ import_react3.default.createElement(PhoneIcon, { size: 22 })), /* @__PURE__ */ import_react3.default.createElement("h2", { className: "dcm-title" }, "Enter your code"), /* @__PURE__ */ import_react3.default.createElement("p", { className: "dcm-sub" }, "We sent a 6-digit code to ", /* @__PURE__ */ import_react3.default.createElement("b", null, isEmail ? email.trim() : phone.trim())), /* @__PURE__ */ import_react3.default.createElement("div", { className: "dcm-form" }, /* @__PURE__ */ import_react3.default.createElement(
7252
+ "input",
7253
+ {
7254
+ className: "dcm-field dcm-code",
7255
+ "aria-label": "6-digit code",
7256
+ placeholder: "000000",
7257
+ value,
7258
+ maxLength: 6,
7259
+ autoFocus: true,
7260
+ inputMode: "numeric",
7261
+ autoComplete: "one-time-code",
7262
+ onChange: (e) => setValue(e.target.value.replace(/\D/g, ""))
7263
+ }
7264
+ ), /* @__PURE__ */ import_react3.default.createElement("button", { type: "submit", className: "dcm-primary", disabled: loading || value.length < 6 }, loading ? "Verifying\u2026" : "Continue")), errorLine, /* @__PURE__ */ import_react3.default.createElement("button", { type: "button", className: "dcm-link", onClick: backToMethods }, "Use a different method"), /* @__PURE__ */ import_react3.default.createElement(ProtectedBy, null));
7265
+ }
7266
+ const showPhone = authMethods.includes("phone") && !!onPhoneStart && !!onPhoneVerify;
7267
+ return /* @__PURE__ */ import_react3.default.createElement("div", { className: "dcm-body" }, /* @__PURE__ */ import_react3.default.createElement(DecaneMark, { size: 44 }), /* @__PURE__ */ import_react3.default.createElement("h2", { className: "dcm-title" }, resumeHint ? "Welcome back" : "Log in or sign up"), resumeHint && /* @__PURE__ */ import_react3.default.createElement("p", { className: "dcm-sub" }, "Sign in again to resume ", resumeHint, "."), /* @__PURE__ */ import_react3.default.createElement("div", { className: "dcm-methods" }, authMethods.includes("google") && /* @__PURE__ */ import_react3.default.createElement("button", { type: "button", className: "dcm-method", onClick: handleGoogle, disabled: busy }, /* @__PURE__ */ import_react3.default.createElement(GoogleMark, { size: 18 }), /* @__PURE__ */ import_react3.default.createElement("span", null, googleLoading ? "Redirecting to Google\u2026" : "Google")), authMethods.includes("email") && /* @__PURE__ */ import_react3.default.createElement("form", { className: "dcm-method dcm-method-input", onSubmit: handleEmailStart }, /* @__PURE__ */ import_react3.default.createElement(MailIcon, { size: 18 }), /* @__PURE__ */ import_react3.default.createElement(
7198
7268
  "input",
7199
7269
  {
7200
7270
  type: "email",
7201
7271
  required: true,
7202
7272
  placeholder: "your@email.com",
7273
+ "aria-label": "Email address",
7274
+ autoComplete: "email",
7203
7275
  value: email,
7204
- onChange: (e) => setEmail(e.target.value),
7205
- style: { ...inputStyle, flex: 1 }
7206
- }
7207
- ), /* @__PURE__ */ import_react3.default.createElement("button", { type: "submit", disabled: emailLoading, style: {
7208
- padding: "0 16px",
7209
- background: "var(--dc-surface)",
7210
- border: "1px solid var(--dc-border)",
7211
- borderRadius: 8,
7212
- color: "var(--dc-text)",
7213
- fontSize: 13,
7214
- cursor: "pointer",
7215
- fontFamily: "inherit"
7216
- } }, emailLoading ? "\u2026" : "Send code")) : /* @__PURE__ */ import_react3.default.createElement("form", { onSubmit: handleEmailVerify, style: { display: "flex", gap: 8 } }, /* @__PURE__ */ import_react3.default.createElement(
7217
- "input",
7218
- {
7219
- placeholder: "6-digit code",
7220
- value: code,
7221
- maxLength: 6,
7222
- autoFocus: true,
7223
- onChange: (e) => setCode(e.target.value.replace(/\D/g, "")),
7224
- style: { ...inputStyle, flex: 1, letterSpacing: 4, textAlign: "center" }
7225
- }
7226
- ), /* @__PURE__ */ import_react3.default.createElement("button", { type: "submit", disabled: emailLoading, style: {
7227
- padding: "0 16px",
7228
- background: "var(--dc-accent)",
7229
- color: "var(--dc-accent-text)",
7230
- border: "none",
7231
- borderRadius: 8,
7232
- fontSize: 13,
7233
- fontWeight: 700,
7234
- cursor: "pointer",
7235
- fontFamily: "inherit"
7236
- } }, emailLoading ? "\u2026" : "Verify"))), !passkeyFirst && authMethods.includes("phone") && onPhoneStart && onPhoneVerify && /* @__PURE__ */ import_react3.default.createElement(import_react3.default.Fragment, null, (authMethods.includes("google") || authMethods.includes("email")) && /* @__PURE__ */ import_react3.default.createElement("div", { style: { textAlign: "center", color: "var(--dc-text-muted)", fontSize: 12, margin: "10px 0" } }, "\u2014 or \u2014"), !phoneSent ? /* @__PURE__ */ import_react3.default.createElement("form", { onSubmit: handlePhoneStart, style: { display: "flex", gap: 8 } }, /* @__PURE__ */ import_react3.default.createElement(
7276
+ onChange: (e) => setEmail(e.target.value)
7277
+ }
7278
+ ), /* @__PURE__ */ import_react3.default.createElement("button", { type: "submit", className: "dcm-submit", disabled: busy || !email.trim() }, emailLoading ? "Sending\u2026" : "Submit")), showPhone && /* @__PURE__ */ import_react3.default.createElement("form", { className: "dcm-method dcm-method-input", onSubmit: handlePhoneStart }, /* @__PURE__ */ import_react3.default.createElement(PhoneIcon, { size: 18 }), /* @__PURE__ */ import_react3.default.createElement(
7237
7279
  "input",
7238
7280
  {
7239
7281
  type: "tel",
7240
7282
  required: true,
7241
7283
  placeholder: "+234 801 234 5678",
7284
+ "aria-label": "Phone number",
7285
+ autoComplete: "tel",
7242
7286
  value: phone,
7243
- onChange: (e) => setPhone(e.target.value),
7244
- style: { ...inputStyle, flex: 1 }
7245
- }
7246
- ), /* @__PURE__ */ import_react3.default.createElement("button", { type: "submit", disabled: phoneLoading, style: {
7247
- padding: "0 16px",
7248
- background: "var(--dc-surface)",
7249
- border: "1px solid var(--dc-border)",
7250
- borderRadius: 8,
7251
- color: "var(--dc-text)",
7252
- fontSize: 13,
7253
- cursor: "pointer",
7254
- fontFamily: "inherit"
7255
- } }, phoneLoading ? "\u2026" : "Send code")) : /* @__PURE__ */ import_react3.default.createElement("form", { onSubmit: handlePhoneVerify, style: { display: "flex", gap: 8 } }, /* @__PURE__ */ import_react3.default.createElement(
7256
- "input",
7257
- {
7258
- placeholder: "6-digit code",
7259
- value: phoneCode,
7260
- maxLength: 6,
7261
- autoFocus: true,
7262
- inputMode: "numeric",
7263
- onChange: (e) => setPhoneCode(e.target.value.replace(/\D/g, "")),
7264
- style: { ...inputStyle, flex: 1, letterSpacing: 4, textAlign: "center" }
7265
- }
7266
- ), /* @__PURE__ */ import_react3.default.createElement("button", { type: "submit", disabled: phoneLoading, style: {
7267
- padding: "0 16px",
7268
- background: "var(--dc-accent)",
7269
- color: "var(--dc-accent-text)",
7270
- border: "none",
7271
- borderRadius: 8,
7272
- fontSize: 13,
7273
- fontWeight: 700,
7274
- cursor: "pointer",
7275
- fontFamily: "inherit"
7276
- } }, phoneLoading ? "\u2026" : "Verify"))), !passkeyFirst && customAuthLabel && onCustomAuthSignIn && /* @__PURE__ */ import_react3.default.createElement(import_react3.default.Fragment, null, (authMethods.includes("google") || authMethods.includes("email")) && /* @__PURE__ */ import_react3.default.createElement("div", { style: { textAlign: "center", color: "var(--dc-text-muted)", fontSize: 12, margin: "10px 0" } }, "\u2014 or \u2014"), /* @__PURE__ */ import_react3.default.createElement(
7277
- "button",
7278
- {
7279
- onClick: handleCustomAuth,
7280
- disabled: customLoading,
7281
- style: {
7282
- width: "100%",
7283
- padding: "10px 0",
7284
- background: "var(--dc-surface)",
7285
- color: "var(--dc-text)",
7286
- border: "1px solid var(--dc-border)",
7287
- borderRadius: 10,
7288
- fontSize: 13,
7289
- fontWeight: 600,
7290
- cursor: customLoading ? "not-allowed" : "pointer",
7291
- opacity: customLoading ? 0.7 : 1,
7292
- fontFamily: "inherit"
7293
- }
7294
- },
7295
- customLoading ? "Connecting\u2026" : customAuthLabel
7296
- )), error && /* @__PURE__ */ import_react3.default.createElement("div", { style: { marginTop: 10, fontSize: 12, color: "var(--dc-danger, #ff5533)" } }, error));
7287
+ onChange: (e) => setPhone(e.target.value)
7288
+ }
7289
+ ), /* @__PURE__ */ import_react3.default.createElement("button", { type: "submit", className: "dcm-submit", disabled: busy || !phone.trim() }, phoneLoading ? "Sending\u2026" : "Submit")), authMethods.includes("x") && onXSignIn && /* @__PURE__ */ import_react3.default.createElement("button", { type: "button", className: "dcm-method", onClick: handleX, disabled: busy }, /* @__PURE__ */ import_react3.default.createElement(XLogo, { size: 16 }), /* @__PURE__ */ import_react3.default.createElement("span", null, xLoading ? "Redirecting to X\u2026" : "X")), authMethods.includes("kingschat") && onKingsChatSignIn && /* @__PURE__ */ import_react3.default.createElement("button", { type: "button", className: "dcm-method", onClick: handleKingsChat, disabled: busy }, /* @__PURE__ */ import_react3.default.createElement(ChatIcon, { size: 18 }), /* @__PURE__ */ import_react3.default.createElement("span", null, kingsChatLoading ? "Waiting for KingsChat\u2026" : "KingsChat")), customAuthLabel && onCustomAuthSignIn && /* @__PURE__ */ import_react3.default.createElement("button", { type: "button", className: "dcm-method", onClick: handleCustomAuth, disabled: busy }, /* @__PURE__ */ import_react3.default.createElement(UserIcon, { size: 18 }), /* @__PURE__ */ import_react3.default.createElement("span", null, customLoading ? "Connecting\u2026" : customAuthLabel))), errorLine, canUsePasskey && onPasskeySignIn && /* @__PURE__ */ import_react3.default.createElement("button", { type: "button", className: "dcm-link", onClick: () => {
7290
+ setError("");
7291
+ setShowOtherMethods(false);
7292
+ } }, "Use my passkey instead"), /* @__PURE__ */ import_react3.default.createElement(ProtectedBy, null));
7297
7293
  }
7298
7294
  function RecoverySection({
7299
7295
  addresses,
@@ -7344,60 +7340,34 @@ function RecoverySection({
7344
7340
  setBusy(false);
7345
7341
  }
7346
7342
  }
7347
- const inputStyle = {
7348
- width: "100%",
7349
- background: "var(--dc-bg)",
7350
- border: "1px solid var(--dc-border)",
7351
- borderRadius: 8,
7352
- color: "var(--dc-text)",
7353
- padding: "8px 10px",
7354
- fontSize: 12,
7355
- outline: "none",
7356
- fontFamily: "inherit",
7357
- boxSizing: "border-box"
7358
- };
7359
- const btnStyle = {
7360
- padding: "8px 12px",
7361
- borderRadius: 8,
7362
- fontSize: 12,
7363
- fontWeight: 700,
7364
- cursor: "pointer",
7365
- fontFamily: "inherit",
7366
- border: "none"
7367
- };
7368
- return /* @__PURE__ */ import_react3.default.createElement("div", { style: { margin: "0 16px 14px", border: "1px solid var(--dc-border)", borderRadius: 10, overflow: "hidden" } }, /* @__PURE__ */ import_react3.default.createElement(
7369
- "button",
7343
+ const passwordFields = /* @__PURE__ */ import_react3.default.createElement(import_react3.default.Fragment, null, /* @__PURE__ */ import_react3.default.createElement(
7344
+ "input",
7370
7345
  {
7371
- onClick: () => setExpanded((v) => !v),
7372
- style: {
7373
- width: "100%",
7374
- padding: "10px 14px",
7375
- background: "var(--dc-surface)",
7376
- border: "none",
7377
- display: "flex",
7378
- alignItems: "center",
7379
- justifyContent: "space-between",
7380
- cursor: "pointer",
7381
- fontFamily: "inherit"
7382
- }
7383
- },
7384
- /* @__PURE__ */ import_react3.default.createElement("span", { style: { fontSize: 12, fontWeight: 700, color: "var(--dc-text)" } }, "Recovery"),
7385
- /* @__PURE__ */ import_react3.default.createElement("span", { style: { fontSize: 11, color: "var(--dc-text-muted)" } }, expanded ? "\u25B2" : "\u25BC")
7386
- ), expanded && /* @__PURE__ */ import_react3.default.createElement("div", { style: { padding: "12px 14px", borderTop: "1px solid var(--dc-border)" } }, /* @__PURE__ */ import_react3.default.createElement("p", { style: { fontSize: 11, color: "var(--dc-text-muted)", lineHeight: 1.5, margin: "0 0 10px" } }, "Save a recovery file so you can restore this wallet on a new device."), !mode && /* @__PURE__ */ import_react3.default.createElement("div", { style: { display: "flex", flexDirection: "column", gap: 8 } }, /* @__PURE__ */ import_react3.default.createElement("button", { onClick: () => {
7346
+ className: "dcm-field",
7347
+ type: "password",
7348
+ placeholder: "Password (at least 8 characters)",
7349
+ "aria-label": "Password",
7350
+ autoComplete: "new-password",
7351
+ value: password,
7352
+ onChange: (e) => setPassword(e.target.value)
7353
+ }
7354
+ ), /* @__PURE__ */ import_react3.default.createElement(
7355
+ "input",
7356
+ {
7357
+ className: "dcm-field",
7358
+ placeholder: "Password hint (optional)",
7359
+ "aria-label": "Password hint",
7360
+ value: passwordHint,
7361
+ onChange: (e) => setPasswordHint(e.target.value)
7362
+ }
7363
+ ), error && /* @__PURE__ */ import_react3.default.createElement("p", { className: "dcm-error", role: "alert" }, error));
7364
+ return /* @__PURE__ */ import_react3.default.createElement("div", { className: "dcm-panel" }, /* @__PURE__ */ import_react3.default.createElement("button", { type: "button", className: "dcm-panel-head", onClick: () => setExpanded((v) => !v), "aria-expanded": expanded }, /* @__PURE__ */ import_react3.default.createElement("span", null, "Recovery file"), /* @__PURE__ */ import_react3.default.createElement(ChevronIcon, { open: expanded })), expanded && /* @__PURE__ */ import_react3.default.createElement("div", { className: "dcm-panel-body" }, !mode && /* @__PURE__ */ import_react3.default.createElement(import_react3.default.Fragment, null, /* @__PURE__ */ import_react3.default.createElement("p", { className: "dcm-note" }, "Save a recovery file so you can restore this wallet on a new device."), /* @__PURE__ */ import_react3.default.createElement("button", { type: "button", className: "dcm-primary", style: { height: 44, borderRadius: 12 }, onClick: () => {
7387
7365
  reset();
7388
7366
  setMode("share");
7389
- }, style: { ...btnStyle, background: "var(--dc-accent)", color: "var(--dc-accent-text)" } }, "Generate recovery-share file"), /* @__PURE__ */ import_react3.default.createElement("button", { onClick: () => {
7367
+ } }, "Download recovery-share file"), /* @__PURE__ */ import_react3.default.createElement("button", { type: "button", className: "dcm-ghost", onClick: () => {
7390
7368
  reset();
7391
7369
  setMode("portable");
7392
- }, style: { ...btnStyle, background: "transparent", border: "1px solid var(--dc-border)", color: "var(--dc-text)" } }, "Generate full recovery file")), mode === "share" && /* @__PURE__ */ import_react3.default.createElement("div", { style: { display: "flex", flexDirection: "column", gap: 8 } }, /* @__PURE__ */ import_react3.default.createElement("p", { style: { fontSize: 11, color: "var(--dc-text-muted)", margin: 0 } }, "One share \u2014 useless alone, safe to keep in a password manager or cloud drive. Generating a new one invalidates any previous recovery-share file."), /* @__PURE__ */ import_react3.default.createElement("input", { type: "password", placeholder: "Password (min 8 chars)", value: password, onChange: (e) => setPassword(e.target.value), style: inputStyle }), /* @__PURE__ */ import_react3.default.createElement("input", { placeholder: "Password hint (optional)", value: passwordHint, onChange: (e) => setPasswordHint(e.target.value), style: inputStyle }), error && /* @__PURE__ */ import_react3.default.createElement("div", { style: { fontSize: 11, color: "var(--dc-danger, #ff5533)" } }, error), /* @__PURE__ */ import_react3.default.createElement("div", { style: { display: "flex", gap: 8 } }, /* @__PURE__ */ import_react3.default.createElement("button", { onClick: handleGenerate, disabled: busy, style: { ...btnStyle, flex: 1, background: "var(--dc-accent)", color: "var(--dc-accent-text)" } }, busy ? "Generating\u2026" : "Generate & download"), /* @__PURE__ */ import_react3.default.createElement("button", { onClick: reset, style: { ...btnStyle, background: "transparent", border: "1px solid var(--dc-border)", color: "var(--dc-text-muted)" } }, "Cancel"))), mode === "portable" && /* @__PURE__ */ import_react3.default.createElement("div", { style: { display: "flex", flexDirection: "column", gap: 8 } }, /* @__PURE__ */ import_react3.default.createElement("div", { style: {
7393
- background: "rgba(255,85,51,0.08)",
7394
- border: "1px solid rgba(255,85,51,0.3)",
7395
- borderRadius: 8,
7396
- padding: "8px 10px",
7397
- fontSize: 11,
7398
- color: "#ff9977",
7399
- lineHeight: 1.5
7400
- } }, /* @__PURE__ */ import_react3.default.createElement("strong", { style: { display: "block", marginBottom: 3, color: "#ff5533" } }, "This file controls your wallet"), "Contains two shares \u2014 file plus password gives complete control. Keep it offline, not a cloud drive. This also invalidates your current recovery-share file."), /* @__PURE__ */ import_react3.default.createElement("label", { style: { display: "flex", alignItems: "center", gap: 6, fontSize: 11, color: "var(--dc-text)" } }, /* @__PURE__ */ import_react3.default.createElement("input", { type: "checkbox", checked: confirmed, onChange: (e) => setConfirmed(e.target.checked), style: { width: "auto" } }), "I understand this is a bearer secret"), /* @__PURE__ */ import_react3.default.createElement("input", { type: "password", placeholder: "Password (min 8 chars)", value: password, onChange: (e) => setPassword(e.target.value), style: inputStyle }), /* @__PURE__ */ import_react3.default.createElement("input", { placeholder: "Password hint (optional)", value: passwordHint, onChange: (e) => setPasswordHint(e.target.value), style: inputStyle }), error && /* @__PURE__ */ import_react3.default.createElement("div", { style: { fontSize: 11, color: "var(--dc-danger, #ff5533)" } }, error), /* @__PURE__ */ import_react3.default.createElement("div", { style: { display: "flex", gap: 8 } }, /* @__PURE__ */ import_react3.default.createElement("button", { onClick: handleGenerate, disabled: busy || !confirmed, style: { ...btnStyle, flex: 1, background: "var(--dc-accent)", color: "var(--dc-accent-text)" } }, busy ? "Generating\u2026" : "Generate & download"), /* @__PURE__ */ import_react3.default.createElement("button", { onClick: reset, style: { ...btnStyle, background: "transparent", border: "1px solid var(--dc-border)", color: "var(--dc-text-muted)" } }, "Cancel"))), result && /* @__PURE__ */ import_react3.default.createElement("div", { style: { marginTop: 10, fontSize: 11, color: "var(--dc-text-muted)", lineHeight: 1.5 } }, result.kind === "share" ? "Recovery-share file" : "Full recovery file", " downloaded \u2014 share set is now version ", result.version, ". Any previous recovery file no longer works.")));
7370
+ } }, "Download full recovery file")), mode === "share" && /* @__PURE__ */ import_react3.default.createElement(import_react3.default.Fragment, null, /* @__PURE__ */ import_react3.default.createElement("p", { className: "dcm-note" }, "One share. It is useless on its own, so a password manager or cloud drive is a fine place for it. A new file replaces any previous recovery-share file."), passwordFields, /* @__PURE__ */ import_react3.default.createElement("div", { className: "dcm-row" }, /* @__PURE__ */ import_react3.default.createElement("button", { type: "button", className: "dcm-primary", onClick: handleGenerate, disabled: busy }, busy ? "Preparing\u2026" : "Download"), /* @__PURE__ */ import_react3.default.createElement("button", { type: "button", className: "dcm-ghost", onClick: reset }, "Cancel"))), mode === "portable" && /* @__PURE__ */ import_react3.default.createElement(import_react3.default.Fragment, null, /* @__PURE__ */ import_react3.default.createElement("div", { className: "dcm-warn" }, /* @__PURE__ */ import_react3.default.createElement("strong", null, "This file controls your wallet"), "It holds two shares, so the file plus its password is full control. Keep it offline, not in a cloud drive. It also replaces your current recovery-share file."), /* @__PURE__ */ import_react3.default.createElement("label", { className: "dcm-check" }, /* @__PURE__ */ import_react3.default.createElement("input", { type: "checkbox", checked: confirmed, onChange: (e) => setConfirmed(e.target.checked) }), "I understand anyone with this file and password controls the wallet"), passwordFields, /* @__PURE__ */ import_react3.default.createElement("div", { className: "dcm-row" }, /* @__PURE__ */ import_react3.default.createElement("button", { type: "button", className: "dcm-primary", onClick: handleGenerate, disabled: busy || !confirmed }, busy ? "Preparing\u2026" : "Download"), /* @__PURE__ */ import_react3.default.createElement("button", { type: "button", className: "dcm-ghost", onClick: reset }, "Cancel"))), result && /* @__PURE__ */ import_react3.default.createElement("p", { className: "dcm-note" }, result.kind === "share" ? "Recovery-share file" : "Full recovery file", " downloaded. The share set is now version ", result.version, ", and any earlier recovery file no longer works.")));
7401
7371
  }
7402
7372
  function SocialWalletModal({
7403
7373
  open,
@@ -7408,6 +7378,7 @@ function SocialWalletModal({
7408
7378
  onDisconnect,
7409
7379
  onGoogleSignIn,
7410
7380
  onKingsChatSignIn,
7381
+ onXSignIn,
7411
7382
  onEmailStart,
7412
7383
  onEmailVerify,
7413
7384
  onPhoneStart,
@@ -7426,9 +7397,11 @@ function SocialWalletModal({
7426
7397
  const [timer, setTimer] = (0, import_react3.useState)("");
7427
7398
  const [unlocking, setUnlocking] = (0, import_react3.useState)(false);
7428
7399
  const [disconnecting, setDisconnecting] = (0, import_react3.useState)(false);
7400
+ const [actionError, setActionError] = (0, import_react3.useState)("");
7429
7401
  (0, import_react3.useEffect)(() => {
7430
7402
  if (!open) return;
7431
7403
  injectTokens2(theme);
7404
+ injectModalCss();
7432
7405
  if (theme !== "auto") return;
7433
7406
  const mq = window.matchMedia("(prefers-color-scheme: dark)");
7434
7407
  const h = () => injectTokens2("auto");
@@ -7455,17 +7428,23 @@ function SocialWalletModal({
7455
7428
  if (!open) return null;
7456
7429
  async function handleUnlock() {
7457
7430
  setUnlocking(true);
7431
+ setActionError("");
7458
7432
  try {
7459
7433
  await onUnlock();
7434
+ } catch (e) {
7435
+ setActionError(e.message);
7460
7436
  } finally {
7461
7437
  setUnlocking(false);
7462
7438
  }
7463
7439
  }
7464
7440
  async function handleDisconnect() {
7465
7441
  setDisconnecting(true);
7442
+ setActionError("");
7466
7443
  try {
7467
7444
  await onDisconnect();
7468
7445
  onClose();
7446
+ } catch (e) {
7447
+ setActionError(e.message);
7469
7448
  } finally {
7470
7449
  setDisconnecting(false);
7471
7450
  }
@@ -7473,12 +7452,13 @@ function SocialWalletModal({
7473
7452
  const evmChain = chains?.find((c) => c.startsWith("evm:")) ?? "evm:11155111";
7474
7453
  const solChain = chains?.find((c) => c.startsWith("solana:")) ?? "solana:mainnet";
7475
7454
  const showSignIn = !socialAuth.addresses || socialAuth.needsReconnect;
7455
+ const unlocked = socialAuth.isUnlocked;
7476
7456
  const modal = /* @__PURE__ */ import_react3.default.createElement(
7477
7457
  "div",
7478
7458
  {
7479
7459
  role: "dialog",
7480
7460
  "aria-modal": "true",
7481
- "aria-label": "Social wallet",
7461
+ "aria-label": showSignIn ? "Log in or sign up" : "Your wallet",
7482
7462
  style: {
7483
7463
  position: "fixed",
7484
7464
  inset: 0,
@@ -7487,63 +7467,17 @@ function SocialWalletModal({
7487
7467
  alignItems: "center",
7488
7468
  justifyContent: "center",
7489
7469
  padding: 16,
7490
- fontFamily: "var(--dc-font-sans, system-ui, sans-serif)"
7470
+ fontFamily: "var(--dc-font-sans, system-ui, sans-serif)",
7471
+ WebkitFontSmoothing: "antialiased"
7491
7472
  }
7492
7473
  },
7493
- /* @__PURE__ */ import_react3.default.createElement(
7494
- "div",
7495
- {
7496
- onClick: onClose,
7497
- style: {
7498
- position: "absolute",
7499
- inset: 0,
7500
- background: "var(--dc-bg-overlay)",
7501
- backdropFilter: "blur(8px)",
7502
- WebkitBackdropFilter: "blur(8px)"
7503
- }
7504
- }
7505
- ),
7506
- /* @__PURE__ */ import_react3.default.createElement("div", { style: {
7507
- position: "relative",
7508
- background: "var(--dc-bg)",
7509
- border: "1px solid var(--dc-border)",
7510
- borderRadius: 20,
7511
- width: "100%",
7512
- maxWidth: 380,
7513
- maxHeight: "90vh",
7514
- overflowY: "auto",
7515
- boxShadow: "0 24px 64px rgba(0,0,0,0.6), 0 0 0 1px rgba(255,255,255,0.04)"
7516
- } }, /* @__PURE__ */ import_react3.default.createElement("div", { style: {
7517
- height: 2,
7518
- position: "sticky",
7519
- top: 0,
7520
- zIndex: 1,
7521
- background: "linear-gradient(90deg, transparent, var(--dc-accent) 30%, var(--dc-accent) 70%, transparent)"
7522
- } }), /* @__PURE__ */ import_react3.default.createElement("div", { style: { padding: "18px 20px 16px", display: "flex", alignItems: "center", gap: 11 } }, /* @__PURE__ */ import_react3.default.createElement(DecaneMark, { size: 38 }), /* @__PURE__ */ import_react3.default.createElement("div", { style: { flex: 1 } }, /* @__PURE__ */ import_react3.default.createElement("div", { style: { display: "flex", alignItems: "baseline", gap: 6 } }, /* @__PURE__ */ import_react3.default.createElement(DecaneWordmark, { size: 15 }), /* @__PURE__ */ import_react3.default.createElement("span", { style: { fontSize: 13, fontWeight: 700, color: "var(--dc-text-muted)", letterSpacing: "-0.01em" } }, "wallet")), /* @__PURE__ */ import_react3.default.createElement("div", { style: { fontSize: 11, color: "var(--dc-text-muted)", marginTop: 2 } }, "Non-custodial \xB7 key split three ways")), /* @__PURE__ */ import_react3.default.createElement(
7523
- "button",
7524
- {
7525
- onClick: onClose,
7526
- style: {
7527
- background: "var(--dc-surface)",
7528
- border: "1px solid var(--dc-border)",
7529
- borderRadius: 8,
7530
- width: 28,
7531
- height: 28,
7532
- cursor: "pointer",
7533
- display: "flex",
7534
- alignItems: "center",
7535
- justifyContent: "center",
7536
- color: "var(--dc-text-muted)",
7537
- flexShrink: 0,
7538
- padding: 0
7539
- }
7540
- },
7541
- /* @__PURE__ */ import_react3.default.createElement("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none" }, /* @__PURE__ */ import_react3.default.createElement("path", { d: "M1.5 1.5L10.5 10.5M10.5 1.5L1.5 10.5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" }))
7542
- )), showSignIn ? /* @__PURE__ */ import_react3.default.createElement(
7474
+ /* @__PURE__ */ import_react3.default.createElement("div", { className: "dcm-backdrop", onClick: onClose }),
7475
+ /* @__PURE__ */ import_react3.default.createElement("div", { className: "dcm-card" }, /* @__PURE__ */ import_react3.default.createElement("button", { type: "button", className: "dcm-icon-btn", style: { right: 14 }, onClick: onClose, "aria-label": "Close" }, /* @__PURE__ */ import_react3.default.createElement(CloseIcon, null)), showSignIn ? /* @__PURE__ */ import_react3.default.createElement(
7543
7476
  SignInView,
7544
7477
  {
7545
7478
  onGoogleSignIn,
7546
7479
  onKingsChatSignIn,
7480
+ onXSignIn,
7547
7481
  onEmailStart,
7548
7482
  onEmailVerify,
7549
7483
  onPhoneStart,
@@ -7556,86 +7490,22 @@ function SocialWalletModal({
7556
7490
  passkeyAddress,
7557
7491
  onPasskeySignIn
7558
7492
  }
7559
- ) : /* @__PURE__ */ import_react3.default.createElement(import_react3.default.Fragment, null, /* @__PURE__ */ import_react3.default.createElement("div", { style: {
7560
- margin: "0 16px 14px",
7561
- padding: "8px 14px",
7562
- background: socialAuth.isUnlocked ? "rgba(18,183,106,0.08)" : "rgba(245,200,0,0.08)",
7563
- border: `1px solid ${socialAuth.isUnlocked ? "rgba(18,183,106,0.2)" : "rgba(245,200,0,0.2)"}`,
7564
- borderRadius: 10,
7565
- display: "flex",
7566
- alignItems: "center",
7567
- justifyContent: "space-between"
7568
- } }, /* @__PURE__ */ import_react3.default.createElement("div", { style: { display: "flex", alignItems: "center", gap: 8 } }, /* @__PURE__ */ import_react3.default.createElement("span", { style: {
7569
- width: 7,
7570
- height: 7,
7571
- borderRadius: "50%",
7572
- flexShrink: 0,
7573
- background: socialAuth.isUnlocked ? "#12b76a" : "var(--dc-accent)",
7574
- boxShadow: `0 0 6px ${socialAuth.isUnlocked ? "#12b76a" : "var(--dc-accent)"}`
7575
- } }), /* @__PURE__ */ import_react3.default.createElement("span", { style: {
7576
- fontSize: 12,
7577
- fontWeight: 700,
7578
- color: socialAuth.isUnlocked ? "#12b76a" : "var(--dc-accent)"
7579
- } }, socialAuth.isUnlocked ? "Unlocked" : "Locked")), socialAuth.isUnlocked && timer && /* @__PURE__ */ import_react3.default.createElement("span", { style: { fontSize: 11, color: "var(--dc-text-muted)", fontFamily: "monospace" } }, "expires ", timer)), /* @__PURE__ */ import_react3.default.createElement("div", { style: { padding: "0 16px 14px" } }, socialAuth.addresses?.evm && /* @__PURE__ */ import_react3.default.createElement(AddressRow, { label: "EVM (Ethereum, Base, \u2026)", address: socialAuth.addresses.evm, kind: "evm", chain: evmChain, rpcUrls }), socialAuth.addresses?.solana && /* @__PURE__ */ import_react3.default.createElement(AddressRow, { label: "Solana", address: socialAuth.addresses.solana, kind: "solana", chain: solChain, rpcUrls })), socialAuth.isUnlocked && /* @__PURE__ */ import_react3.default.createElement(
7493
+ ) : /* @__PURE__ */ import_react3.default.createElement("div", { className: "dcm-body" }, /* @__PURE__ */ import_react3.default.createElement(DecaneMark, { size: 44 }), /* @__PURE__ */ import_react3.default.createElement("h2", { className: "dcm-title" }, "Your wallet"), /* @__PURE__ */ import_react3.default.createElement(
7494
+ "span",
7495
+ {
7496
+ className: "dcm-status",
7497
+ style: { color: unlocked ? "#12b76a" : "var(--dc-accent-ink)", marginTop: -8 }
7498
+ },
7499
+ /* @__PURE__ */ import_react3.default.createElement("i", { style: { background: unlocked ? "#12b76a" : "var(--dc-accent)" } }),
7500
+ unlocked ? timer ? `Unlocked, expires in ${timer}` : "Unlocked" : "Locked"
7501
+ ), (socialAuth.addresses?.evm || socialAuth.addresses?.solana) && /* @__PURE__ */ import_react3.default.createElement("div", { className: "dcm-addresses" }, socialAuth.addresses?.evm && /* @__PURE__ */ import_react3.default.createElement(AddressRow, { label: "Ethereum and EVM", address: socialAuth.addresses.evm, kind: "evm", chain: evmChain, rpcUrls }), socialAuth.addresses?.solana && /* @__PURE__ */ import_react3.default.createElement(AddressRow, { label: "Solana", address: socialAuth.addresses.solana, kind: "solana", chain: solChain, rpcUrls })), unlocked && /* @__PURE__ */ import_react3.default.createElement(
7580
7502
  RecoverySection,
7581
7503
  {
7582
7504
  addresses: socialAuth.addresses,
7583
7505
  onRotateShares,
7584
7506
  onExportPortableBackup
7585
7507
  }
7586
- ), /* @__PURE__ */ import_react3.default.createElement("div", { style: {
7587
- padding: "14px 16px",
7588
- borderTop: "1px solid var(--dc-border)",
7589
- display: "flex",
7590
- gap: 8
7591
- } }, !socialAuth.isUnlocked && /* @__PURE__ */ import_react3.default.createElement(
7592
- "button",
7593
- {
7594
- onClick: handleUnlock,
7595
- disabled: unlocking,
7596
- style: {
7597
- flex: 1,
7598
- padding: "10px 0",
7599
- background: "var(--dc-accent)",
7600
- color: "var(--dc-accent-text)",
7601
- border: "none",
7602
- borderRadius: 10,
7603
- fontSize: 13,
7604
- fontWeight: 700,
7605
- cursor: unlocking ? "not-allowed" : "pointer",
7606
- fontFamily: "inherit",
7607
- opacity: unlocking ? 0.7 : 1
7608
- }
7609
- },
7610
- unlocking ? "Unlocking\u2026" : "\u{1F513} Unlock wallet"
7611
- ), /* @__PURE__ */ import_react3.default.createElement(
7612
- "button",
7613
- {
7614
- onClick: handleDisconnect,
7615
- disabled: disconnecting,
7616
- style: {
7617
- flex: socialAuth.isUnlocked ? 1 : 0,
7618
- padding: "10px 16px",
7619
- background: "transparent",
7620
- border: "1px solid var(--dc-border)",
7621
- borderRadius: 10,
7622
- color: "var(--dc-text-muted)",
7623
- fontSize: 13,
7624
- cursor: disconnecting ? "not-allowed" : "pointer",
7625
- fontFamily: "inherit",
7626
- opacity: disconnecting ? 0.7 : 1,
7627
- whiteSpace: "nowrap"
7628
- }
7629
- },
7630
- disconnecting ? "Signing out\u2026" : "Sign out"
7631
- ))), /* @__PURE__ */ import_react3.default.createElement("div", { style: {
7632
- padding: "11px 16px",
7633
- borderTop: "1px solid var(--dc-border)",
7634
- display: "flex",
7635
- alignItems: "center",
7636
- justifyContent: "center",
7637
- gap: 6
7638
- } }, /* @__PURE__ */ import_react3.default.createElement("span", { style: { fontSize: 10.5, color: "var(--dc-text-muted)", letterSpacing: "0.02em" } }, "Secured by"), /* @__PURE__ */ import_react3.default.createElement(DecaneMark, { size: 13, muted: true }), /* @__PURE__ */ import_react3.default.createElement(DecaneWordmark, { size: 11, muted: true })))
7508
+ ), actionError && /* @__PURE__ */ import_react3.default.createElement("p", { className: "dcm-error", role: "alert" }, actionError), /* @__PURE__ */ import_react3.default.createElement("div", { className: "dcm-actions" }, !unlocked && /* @__PURE__ */ import_react3.default.createElement("button", { type: "button", className: "dcm-primary", style: { height: 44, borderRadius: 12 }, onClick: handleUnlock, disabled: unlocking }, unlocking ? "Unlocking\u2026" : "Unlock wallet"), /* @__PURE__ */ import_react3.default.createElement("button", { type: "button", className: "dcm-ghost", onClick: handleDisconnect, disabled: disconnecting }, disconnecting ? "Signing out\u2026" : "Sign out")), /* @__PURE__ */ import_react3.default.createElement(ProtectedBy, null)))
7639
7509
  );
7640
7510
  return (0, import_react_dom2.createPortal)(modal, document.body);
7641
7511
  }
@@ -9052,6 +8922,7 @@ function useSignTypedData() {
9052
8922
  UnlockTokenRejectedError,
9053
8923
  UserCancelledError,
9054
8924
  WalletEnrolmentError,
8925
+ WalletExistsError,
9055
8926
  WalletSelector,
9056
8927
  WeakPasswordError,
9057
8928
  WebAuthnNotSupportedError,