@partylayer/react 0.2.8 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -546,9 +546,17 @@ function PartyLayerKit({
546
546
  const themeValue = typeof theme === "string" ? theme : theme;
547
547
  return /* @__PURE__ */ jsxRuntime.jsx(WalletIconsContext.Provider, { value: walletIcons, children: /* @__PURE__ */ jsxRuntime.jsx(ThemeProvider, { theme: themeValue, children: /* @__PURE__ */ jsxRuntime.jsx(PartyLayerProvider, { client, network, children }) }) });
548
548
  }
549
+ var EXTENSION_TIMEOUT_MS = 15e3;
550
+ var SDK_QR_CONTAINER_ID = "console-wallet-connect-placeholder";
549
551
  function isNativeWallet(wallet) {
550
552
  return wallet.metadata?.source === "native-cip0103";
551
553
  }
554
+ function isDualTransportWallet(wallet) {
555
+ const caps = wallet.capabilities;
556
+ const hasExtension = caps.includes("injected");
557
+ const hasMobile = caps.includes("deeplink") || caps.includes("remoteSigner");
558
+ return hasExtension && hasMobile;
559
+ }
552
560
  function getErrorMessage(error) {
553
561
  const code = "code" in error ? error.code : "";
554
562
  switch (code) {
@@ -591,12 +599,46 @@ function getWalletUrl(wallet) {
591
599
  }
592
600
  function getWalletTransportLabel(wallet) {
593
601
  if (isNativeWallet(wallet)) return "Ready";
594
- if (wallet.capabilities.includes("injected")) return "Browser Extension";
602
+ const hasInjected = wallet.capabilities.includes("injected");
603
+ const hasDeeplink = wallet.capabilities.includes("deeplink");
604
+ const hasRemoteSigner = wallet.capabilities.includes("remoteSigner");
605
+ if (hasInjected && (hasDeeplink || hasRemoteSigner)) return "Extension + Mobile";
606
+ if (hasInjected) return "Browser Extension";
595
607
  if (wallet.capabilities.includes("popup")) return "Scan to connect";
596
- if (wallet.capabilities.includes("deeplink")) return "Mobile wallet";
597
- if (wallet.capabilities.includes("remoteSigner")) return "Enterprise";
608
+ if (hasDeeplink) return "Mobile wallet";
609
+ if (hasRemoteSigner) return "Enterprise";
598
610
  return wallet.capabilities.slice(0, 3).join(", ");
599
611
  }
612
+ function extractSdkQrCode() {
613
+ const container = document.getElementById(SDK_QR_CONTAINER_ID);
614
+ if (!container) return null;
615
+ const svg = container.querySelector("svg");
616
+ if (!svg) return null;
617
+ let deepLinkUrl = null;
618
+ const links = Array.from(container.querySelectorAll("a, button"));
619
+ for (let i = 0; i < links.length; i++) {
620
+ const el = links[i];
621
+ const href = el.href || el.getAttribute("data-href") || "";
622
+ if (href.includes("consolewallet.io/wallet-connect")) {
623
+ deepLinkUrl = href;
624
+ break;
625
+ }
626
+ }
627
+ if (!deepLinkUrl) {
628
+ const anchors = container.querySelectorAll('a[href*="consolewallet"]');
629
+ if (anchors.length > 0) {
630
+ deepLinkUrl = anchors[0].href;
631
+ }
632
+ }
633
+ container.style.display = "none";
634
+ return { svgHtml: svg.outerHTML, deepLinkUrl };
635
+ }
636
+ function removeSdkQrContainer() {
637
+ const container = document.getElementById(SDK_QR_CONTAINER_ID);
638
+ if (container) {
639
+ container.style.display = "none";
640
+ }
641
+ }
600
642
  function CloseIcon({ size = 20, color = "currentColor" }) {
601
643
  return /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
602
644
  /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
@@ -636,6 +678,34 @@ function ExternalLinkIcon({ size = 12, color = "currentColor" }) {
636
678
  /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "10", y1: "14", x2: "21", y2: "3" })
637
679
  ] });
638
680
  }
681
+ function QrCodeIcon({ size = 20, color = "currentColor" }) {
682
+ return /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
683
+ /* @__PURE__ */ jsxRuntime.jsx("rect", { x: "2", y: "2", width: "8", height: "8", rx: "1" }),
684
+ /* @__PURE__ */ jsxRuntime.jsx("rect", { x: "14", y: "2", width: "8", height: "8", rx: "1" }),
685
+ /* @__PURE__ */ jsxRuntime.jsx("rect", { x: "2", y: "14", width: "8", height: "8", rx: "1" }),
686
+ /* @__PURE__ */ jsxRuntime.jsx("rect", { x: "14", y: "14", width: "4", height: "4", rx: "0.5" }),
687
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "22", y1: "14", x2: "22", y2: "18" }),
688
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "18", y1: "22", x2: "22", y2: "22" })
689
+ ] });
690
+ }
691
+ function SmartphoneIcon({ size = 16, color = "currentColor" }) {
692
+ return /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
693
+ /* @__PURE__ */ jsxRuntime.jsx("rect", { x: "5", y: "2", width: "14", height: "20", rx: "2", ry: "2" }),
694
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "12", y1: "18", x2: "12.01", y2: "18" })
695
+ ] });
696
+ }
697
+ function RefreshIcon({ size = 14, color = "currentColor" }) {
698
+ return /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
699
+ /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "23 4 23 10 17 10" }),
700
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M20.49 15a9 9 0 1 1-2.12-9.36L23 10" })
701
+ ] });
702
+ }
703
+ function ClockIcon({ size = 16, color = "currentColor" }) {
704
+ return /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
705
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "10" }),
706
+ /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "12 6 12 12 16 14" })
707
+ ] });
708
+ }
639
709
  function ModalWalletIcon({
640
710
  wallet,
641
711
  size = 48,
@@ -701,14 +771,35 @@ function WalletModal({
701
771
  const [selectedWallet, setSelectedWallet] = react.useState(null);
702
772
  const [closing, setClosing] = react.useState(false);
703
773
  const [connectError, setConnectError] = react.useState(null);
774
+ const [connectPhase, setConnectPhase] = react.useState("default");
775
+ const [qrSvgHtml, setQrSvgHtml] = react.useState(null);
776
+ const [deepLinkUrl, setDeepLinkUrl] = react.useState(null);
777
+ const timeoutRef = react.useRef(null);
778
+ const observerRef = react.useRef(null);
704
779
  const modalRef = react.useRef(null);
780
+ const cleanupConnectResources = react.useCallback(() => {
781
+ if (timeoutRef.current) {
782
+ clearTimeout(timeoutRef.current);
783
+ timeoutRef.current = null;
784
+ }
785
+ if (observerRef.current) {
786
+ observerRef.current.disconnect();
787
+ observerRef.current = null;
788
+ }
789
+ removeSdkQrContainer();
790
+ }, []);
705
791
  react.useEffect(() => {
706
792
  if (isOpen) {
707
793
  setView("list");
708
794
  setSelectedWallet(null);
709
795
  setClosing(false);
796
+ setConnectPhase("default");
797
+ setQrSvgHtml(null);
798
+ setDeepLinkUrl(null);
799
+ cleanupConnectResources();
710
800
  }
711
- }, [isOpen]);
801
+ }, [isOpen, cleanupConnectResources]);
802
+ react.useEffect(() => cleanupConnectResources, [cleanupConnectResources]);
712
803
  react.useEffect(() => {
713
804
  if (!isOpen) return;
714
805
  const handler = (e) => {
@@ -720,33 +811,78 @@ function WalletModal({
720
811
  react.useEffect(() => {
721
812
  if (error && view === "connecting") {
722
813
  setConnectError(error);
814
+ cleanupConnectResources();
723
815
  const code = "code" in error ? error.code : "";
724
- if (code === "WALLET_NOT_INSTALLED") {
816
+ if (code === "WALLET_NOT_INSTALLED" && !isDualTransportWallet(selectedWallet)) {
725
817
  setView("not-installed");
818
+ } else if (code === "WALLET_NOT_INSTALLED" && isDualTransportWallet(selectedWallet)) {
819
+ setConnectPhase("qr");
820
+ setConnectError(null);
726
821
  } else {
727
822
  setView("error");
728
823
  }
729
824
  }
730
- }, [error, view]);
825
+ }, [error, view, selectedWallet, cleanupConnectResources]);
731
826
  const handleClose = react.useCallback(() => {
827
+ cleanupConnectResources();
732
828
  resetConnect();
733
829
  setView("list");
734
830
  setSelectedWallet(null);
735
831
  setConnectError(null);
832
+ setConnectPhase("default");
833
+ setQrSvgHtml(null);
834
+ setDeepLinkUrl(null);
736
835
  setClosing(true);
737
836
  setTimeout(() => {
738
837
  setClosing(false);
739
838
  onClose();
740
839
  }, 150);
741
- }, [onClose, resetConnect]);
840
+ }, [onClose, resetConnect, cleanupConnectResources]);
841
+ const startQrObserver = react.useCallback(() => {
842
+ const existing = extractSdkQrCode();
843
+ if (existing) {
844
+ setQrSvgHtml(existing.svgHtml);
845
+ setDeepLinkUrl(existing.deepLinkUrl);
846
+ setConnectPhase("qr");
847
+ return;
848
+ }
849
+ const observer = new MutationObserver(() => {
850
+ const result = extractSdkQrCode();
851
+ if (result) {
852
+ setQrSvgHtml(result.svgHtml);
853
+ setDeepLinkUrl(result.deepLinkUrl);
854
+ setConnectPhase("qr");
855
+ observer.disconnect();
856
+ observerRef.current = null;
857
+ }
858
+ });
859
+ observer.observe(document.body, { childList: true, subtree: true });
860
+ observerRef.current = observer;
861
+ }, []);
742
862
  const handleWalletClick = react.useCallback(async (wallet) => {
743
863
  setSelectedWallet(wallet);
744
864
  setConnectError(null);
745
865
  setView("connecting");
866
+ setQrSvgHtml(null);
867
+ setDeepLinkUrl(null);
868
+ const isDual = isDualTransportWallet(wallet);
869
+ if (isDual) {
870
+ setConnectPhase("extension");
871
+ startQrObserver();
872
+ timeoutRef.current = setTimeout(() => {
873
+ setConnectPhase((current) => {
874
+ if (current === "extension") return "extension-timeout";
875
+ return current;
876
+ });
877
+ }, EXTENSION_TIMEOUT_MS);
878
+ } else {
879
+ setConnectPhase("default");
880
+ }
746
881
  const session = await connect({
747
882
  walletId: wallet.walletId,
748
883
  preferInstalled: true
749
884
  });
885
+ cleanupConnectResources();
750
886
  if (session) {
751
887
  setView("success");
752
888
  setTimeout(() => {
@@ -754,16 +890,42 @@ function WalletModal({
754
890
  onClose();
755
891
  }, 800);
756
892
  }
757
- }, [connect, onConnect, onClose]);
893
+ }, [connect, onConnect, onClose, startQrObserver, cleanupConnectResources]);
758
894
  const handleRetry = react.useCallback(() => {
759
895
  if (selectedWallet) {
760
896
  handleWalletClick(selectedWallet);
761
897
  }
762
898
  }, [selectedWallet, handleWalletClick]);
899
+ const handleSwitchToMobile = react.useCallback(() => {
900
+ resetConnect();
901
+ setConnectPhase("qr");
902
+ setConnectError(null);
903
+ if (!selectedWallet) return;
904
+ startQrObserver();
905
+ (async () => {
906
+ const session = await connect({
907
+ walletId: selectedWallet.walletId,
908
+ preferInstalled: false
909
+ });
910
+ cleanupConnectResources();
911
+ if (session) {
912
+ setView("success");
913
+ setTimeout(() => {
914
+ onConnect(session.sessionId);
915
+ onClose();
916
+ }, 800);
917
+ }
918
+ })();
919
+ }, [selectedWallet, connect, resetConnect, onConnect, onClose, startQrObserver, cleanupConnectResources]);
763
920
  const handleBackToList = react.useCallback(() => {
921
+ cleanupConnectResources();
922
+ resetConnect();
764
923
  setView("list");
765
924
  setSelectedWallet(null);
766
- }, []);
925
+ setConnectPhase("default");
926
+ setQrSvgHtml(null);
927
+ setDeepLinkUrl(null);
928
+ }, [resetConnect, cleanupConnectResources]);
767
929
  if (!isOpen && !closing) return null;
768
930
  const nativeWallets = wallets.filter(isNativeWallet);
769
931
  const registryWallets = wallets.filter((w) => !isNativeWallet(w));
@@ -821,6 +983,76 @@ function WalletModal({
821
983
  };
822
984
  const closeBtnStyle = { ...closeBtnBase, width: "32px" };
823
985
  const hoverBg = isDark ? "rgba(255,255,255,0.08)" : "rgba(15,23,42,0.06)";
986
+ const primaryBtnStyle = {
987
+ padding: "10px 20px",
988
+ border: "none",
989
+ borderRadius: "10px",
990
+ backgroundColor: theme.colors.primary,
991
+ color: "#0B0F1A",
992
+ cursor: "pointer",
993
+ fontSize: "14px",
994
+ fontWeight: 600,
995
+ fontFamily: theme.fontFamily,
996
+ transition: "all 150ms cubic-bezier(0.2, 0.8, 0.2, 1)"
997
+ };
998
+ const ghostBtnStyle = {
999
+ padding: "10px 20px",
1000
+ border: `1px solid ${theme.colors.border}`,
1001
+ borderRadius: "10px",
1002
+ backgroundColor: "transparent",
1003
+ color: theme.colors.textSecondary,
1004
+ cursor: "pointer",
1005
+ fontSize: "14px",
1006
+ fontWeight: 500,
1007
+ fontFamily: theme.fontFamily,
1008
+ transition: "all 150ms"
1009
+ };
1010
+ const linkStyle = {
1011
+ fontSize: "12px",
1012
+ color: theme.colors.textSecondary,
1013
+ cursor: "pointer",
1014
+ border: "none",
1015
+ background: "none",
1016
+ fontFamily: theme.fontFamily,
1017
+ display: "inline-flex",
1018
+ alignItems: "center",
1019
+ gap: "4px",
1020
+ transition: "color 150ms"
1021
+ };
1022
+ const renderSubHeader = (backAction) => /* @__PURE__ */ jsxRuntime.jsxs("div", { style: headerStyle, children: [
1023
+ /* @__PURE__ */ jsxRuntime.jsxs(
1024
+ "button",
1025
+ {
1026
+ onClick: backAction,
1027
+ style: { ...closeBtnBase, width: "auto", padding: "0 10px", gap: "4px" },
1028
+ onMouseEnter: (e) => {
1029
+ e.currentTarget.style.backgroundColor = hoverBg;
1030
+ },
1031
+ onMouseLeave: (e) => {
1032
+ e.currentTarget.style.backgroundColor = theme.colors.surface;
1033
+ },
1034
+ children: [
1035
+ /* @__PURE__ */ jsxRuntime.jsx(BackIcon, { size: 14, color: theme.colors.textSecondary }),
1036
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: "12px", color: theme.colors.textSecondary, fontWeight: 500 }, children: "Back" })
1037
+ ]
1038
+ }
1039
+ ),
1040
+ /* @__PURE__ */ jsxRuntime.jsx(
1041
+ "button",
1042
+ {
1043
+ onClick: handleClose,
1044
+ style: closeBtnStyle,
1045
+ onMouseEnter: (e) => {
1046
+ e.currentTarget.style.backgroundColor = hoverBg;
1047
+ },
1048
+ onMouseLeave: (e) => {
1049
+ e.currentTarget.style.backgroundColor = theme.colors.surface;
1050
+ },
1051
+ "aria-label": "Close",
1052
+ children: /* @__PURE__ */ jsxRuntime.jsx(CloseIcon, { size: 16, color: theme.colors.textSecondary })
1053
+ }
1054
+ )
1055
+ ] });
824
1056
  const renderWalletItem = (wallet) => {
825
1057
  const isNative = isNativeWallet(wallet);
826
1058
  const iconUrl = resolveWalletIcon(wallet.walletId, walletIcons, wallet.icons?.sm);
@@ -1015,44 +1247,78 @@ function WalletModal({
1015
1247
  ] })
1016
1248
  ] });
1017
1249
  const renderConnectingView = () => {
1250
+ if (!selectedWallet) return null;
1251
+ if (connectPhase === "extension") return renderExtensionPhase();
1252
+ if (connectPhase === "extension-timeout") return renderTimeoutPhase();
1253
+ if (connectPhase === "qr") return renderQrPhase();
1254
+ return renderDefaultConnecting();
1255
+ };
1256
+ const renderDefaultConnecting = () => {
1018
1257
  if (!selectedWallet) return null;
1019
1258
  const iconUrl = resolveWalletIcon(selectedWallet.walletId, walletIcons, selectedWallet.icons?.sm);
1020
1259
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1021
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: headerStyle, children: [
1022
- /* @__PURE__ */ jsxRuntime.jsxs(
1260
+ renderSubHeader(handleBackToList),
1261
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { padding: "24px 32px 40px", textAlign: "center" }, children: [
1262
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
1263
+ position: "relative",
1264
+ width: "80px",
1265
+ height: "80px",
1266
+ margin: "0 auto 24px"
1267
+ }, children: [
1268
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
1269
+ position: "absolute",
1270
+ inset: "-6px",
1271
+ borderRadius: "18px",
1272
+ border: `3px solid ${theme.colors.border}`,
1273
+ borderTopColor: theme.colors.primary,
1274
+ animation: "partylayer-spin 1.2s linear infinite"
1275
+ } }),
1276
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
1277
+ position: "relative",
1278
+ width: "80px",
1279
+ height: "80px",
1280
+ borderRadius: "16px",
1281
+ overflow: "hidden"
1282
+ }, children: /* @__PURE__ */ jsxRuntime.jsx(ModalWalletIcon, { wallet: selectedWallet, size: 80, iconUrl }) })
1283
+ ] }),
1284
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
1285
+ fontSize: "17px",
1286
+ fontWeight: 600,
1287
+ color: theme.colors.text,
1288
+ marginBottom: "8px"
1289
+ }, children: [
1290
+ "Opening ",
1291
+ selectedWallet.name
1292
+ ] }),
1293
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
1294
+ fontSize: "14px",
1295
+ color: theme.colors.textSecondary,
1296
+ lineHeight: 1.5,
1297
+ marginBottom: "32px"
1298
+ }, children: "Confirm the connection in your wallet" }),
1299
+ /* @__PURE__ */ jsxRuntime.jsx(
1023
1300
  "button",
1024
1301
  {
1025
1302
  onClick: handleBackToList,
1026
- style: { ...closeBtnBase, width: "auto", padding: "0 10px", gap: "4px" },
1303
+ style: ghostBtnStyle,
1027
1304
  onMouseEnter: (e) => {
1028
- e.currentTarget.style.backgroundColor = hoverBg;
1029
- },
1030
- onMouseLeave: (e) => {
1031
1305
  e.currentTarget.style.backgroundColor = theme.colors.surface;
1032
1306
  },
1033
- children: [
1034
- /* @__PURE__ */ jsxRuntime.jsx(BackIcon, { size: 14, color: theme.colors.textSecondary }),
1035
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: "12px", color: theme.colors.textSecondary, fontWeight: 500 }, children: "Back" })
1036
- ]
1037
- }
1038
- ),
1039
- /* @__PURE__ */ jsxRuntime.jsx(
1040
- "button",
1041
- {
1042
- onClick: handleClose,
1043
- style: closeBtnStyle,
1044
- onMouseEnter: (e) => {
1045
- e.currentTarget.style.backgroundColor = hoverBg;
1046
- },
1047
1307
  onMouseLeave: (e) => {
1048
- e.currentTarget.style.backgroundColor = theme.colors.surface;
1308
+ e.currentTarget.style.backgroundColor = "transparent";
1049
1309
  },
1050
- "aria-label": "Close",
1051
- children: /* @__PURE__ */ jsxRuntime.jsx(CloseIcon, { size: 16, color: theme.colors.textSecondary })
1310
+ children: "Cancel"
1052
1311
  }
1053
1312
  )
1054
- ] }),
1055
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { padding: "24px 32px 40px", textAlign: "center" }, children: [
1313
+ ] })
1314
+ ] });
1315
+ };
1316
+ const renderExtensionPhase = () => {
1317
+ if (!selectedWallet) return null;
1318
+ const iconUrl = resolveWalletIcon(selectedWallet.walletId, walletIcons, selectedWallet.icons?.sm);
1319
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1320
+ renderSubHeader(handleBackToList),
1321
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { padding: "24px 32px 36px", textAlign: "center" }, children: [
1056
1322
  /* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
1057
1323
  position: "relative",
1058
1324
  width: "80px",
@@ -1082,30 +1348,20 @@ function WalletModal({
1082
1348
  marginBottom: "8px"
1083
1349
  }, children: [
1084
1350
  "Opening ",
1085
- selectedWallet.name
1351
+ selectedWallet.name,
1352
+ "..."
1086
1353
  ] }),
1087
1354
  /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
1088
1355
  fontSize: "14px",
1089
1356
  color: theme.colors.textSecondary,
1090
1357
  lineHeight: 1.5,
1091
- marginBottom: "32px"
1092
- }, children: "Confirm the connection in your wallet" }),
1358
+ marginBottom: "28px"
1359
+ }, children: "Confirm the connection in your wallet extension" }),
1093
1360
  /* @__PURE__ */ jsxRuntime.jsx(
1094
1361
  "button",
1095
1362
  {
1096
1363
  onClick: handleBackToList,
1097
- style: {
1098
- padding: "10px 24px",
1099
- border: `1px solid ${theme.colors.border}`,
1100
- borderRadius: "10px",
1101
- backgroundColor: "transparent",
1102
- color: theme.colors.textSecondary,
1103
- cursor: "pointer",
1104
- fontSize: "14px",
1105
- fontWeight: 500,
1106
- fontFamily: theme.fontFamily,
1107
- transition: "all 150ms"
1108
- },
1364
+ style: ghostBtnStyle,
1109
1365
  onMouseEnter: (e) => {
1110
1366
  e.currentTarget.style.backgroundColor = theme.colors.surface;
1111
1367
  },
@@ -1114,7 +1370,213 @@ function WalletModal({
1114
1370
  },
1115
1371
  children: "Cancel"
1116
1372
  }
1117
- )
1373
+ ),
1374
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { marginTop: "20px" }, children: /* @__PURE__ */ jsxRuntime.jsxs(
1375
+ "button",
1376
+ {
1377
+ onClick: handleSwitchToMobile,
1378
+ style: linkStyle,
1379
+ onMouseEnter: (e) => {
1380
+ e.currentTarget.style.color = theme.colors.text;
1381
+ },
1382
+ onMouseLeave: (e) => {
1383
+ e.currentTarget.style.color = theme.colors.textSecondary;
1384
+ },
1385
+ children: [
1386
+ /* @__PURE__ */ jsxRuntime.jsx(SmartphoneIcon, { size: 12, color: "currentColor" }),
1387
+ "Can't connect? Try mobile",
1388
+ /* @__PURE__ */ jsxRuntime.jsx(ArrowIcon, { size: 10, color: "currentColor" })
1389
+ ]
1390
+ }
1391
+ ) })
1392
+ ] })
1393
+ ] });
1394
+ };
1395
+ const renderTimeoutPhase = () => {
1396
+ if (!selectedWallet) return null;
1397
+ const iconUrl = resolveWalletIcon(selectedWallet.walletId, walletIcons, selectedWallet.icons?.sm);
1398
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1399
+ renderSubHeader(handleBackToList),
1400
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { padding: "16px 32px 36px", textAlign: "center" }, children: [
1401
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
1402
+ position: "relative",
1403
+ width: "64px",
1404
+ height: "64px",
1405
+ margin: "0 auto 20px"
1406
+ }, children: [
1407
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { width: "64px", height: "64px", borderRadius: "14px", overflow: "hidden", opacity: 0.7 }, children: /* @__PURE__ */ jsxRuntime.jsx(ModalWalletIcon, { wallet: selectedWallet, size: 64, iconUrl }) }),
1408
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
1409
+ position: "absolute",
1410
+ bottom: "-4px",
1411
+ right: "-4px",
1412
+ width: "24px",
1413
+ height: "24px",
1414
+ borderRadius: "50%",
1415
+ backgroundColor: theme.colors.warning,
1416
+ display: "flex",
1417
+ alignItems: "center",
1418
+ justifyContent: "center",
1419
+ border: `3px solid ${theme.colors.background}`
1420
+ }, children: /* @__PURE__ */ jsxRuntime.jsx(ClockIcon, { size: 11, color: "#FFFFFF" }) })
1421
+ ] }),
1422
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
1423
+ fontSize: "17px",
1424
+ fontWeight: 600,
1425
+ color: theme.colors.text,
1426
+ marginBottom: "8px"
1427
+ }, children: "Connection timed out" }),
1428
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
1429
+ fontSize: "13px",
1430
+ color: theme.colors.textSecondary,
1431
+ lineHeight: 1.6,
1432
+ maxWidth: "300px",
1433
+ margin: "0 auto 24px"
1434
+ }, children: "The wallet extension didn't respond. You can try again or connect via mobile." }),
1435
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: "10px", justifyContent: "center" }, children: [
1436
+ /* @__PURE__ */ jsxRuntime.jsxs(
1437
+ "button",
1438
+ {
1439
+ onClick: handleRetry,
1440
+ style: primaryBtnStyle,
1441
+ onMouseEnter: (e) => {
1442
+ e.currentTarget.style.backgroundColor = theme.colors.primaryHover;
1443
+ e.currentTarget.style.transform = "translateY(-1px)";
1444
+ },
1445
+ onMouseLeave: (e) => {
1446
+ e.currentTarget.style.backgroundColor = theme.colors.primary;
1447
+ e.currentTarget.style.transform = "translateY(0)";
1448
+ },
1449
+ children: [
1450
+ /* @__PURE__ */ jsxRuntime.jsx(RefreshIcon, { size: 13, color: "#0B0F1A" }),
1451
+ " ",
1452
+ "Try Again"
1453
+ ]
1454
+ }
1455
+ ),
1456
+ /* @__PURE__ */ jsxRuntime.jsxs(
1457
+ "button",
1458
+ {
1459
+ onClick: handleSwitchToMobile,
1460
+ style: ghostBtnStyle,
1461
+ onMouseEnter: (e) => {
1462
+ e.currentTarget.style.backgroundColor = theme.colors.surface;
1463
+ },
1464
+ onMouseLeave: (e) => {
1465
+ e.currentTarget.style.backgroundColor = "transparent";
1466
+ },
1467
+ children: [
1468
+ /* @__PURE__ */ jsxRuntime.jsx(QrCodeIcon, { size: 14, color: "currentColor" }),
1469
+ " ",
1470
+ "Connect via Mobile"
1471
+ ]
1472
+ }
1473
+ )
1474
+ ] })
1475
+ ] })
1476
+ ] });
1477
+ };
1478
+ const renderQrPhase = () => {
1479
+ if (!selectedWallet) return null;
1480
+ const iconUrl = resolveWalletIcon(selectedWallet.walletId, walletIcons, selectedWallet.icons?.sm);
1481
+ const installUrl = getWalletUrl(selectedWallet);
1482
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1483
+ renderSubHeader(handleBackToList),
1484
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { padding: "0 32px 32px", textAlign: "center" }, children: [
1485
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
1486
+ display: "flex",
1487
+ alignItems: "center",
1488
+ justifyContent: "center",
1489
+ gap: "10px",
1490
+ marginBottom: "20px"
1491
+ }, children: [
1492
+ /* @__PURE__ */ jsxRuntime.jsx(ModalWalletIcon, { wallet: selectedWallet, size: 28, iconUrl }),
1493
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: "16px", fontWeight: 600, color: theme.colors.text }, children: selectedWallet.name })
1494
+ ] }),
1495
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
1496
+ width: "260px",
1497
+ height: "260px",
1498
+ margin: "0 auto 16px",
1499
+ borderRadius: "16px",
1500
+ backgroundColor: "#FFFFFF",
1501
+ display: "flex",
1502
+ alignItems: "center",
1503
+ justifyContent: "center",
1504
+ padding: "16px",
1505
+ border: `1px solid ${theme.colors.border}`
1506
+ }, children: qrSvgHtml ? /* @__PURE__ */ jsxRuntime.jsx(
1507
+ "div",
1508
+ {
1509
+ dangerouslySetInnerHTML: { __html: qrSvgHtml },
1510
+ style: {
1511
+ width: "100%",
1512
+ height: "100%",
1513
+ display: "flex",
1514
+ alignItems: "center",
1515
+ justifyContent: "center"
1516
+ }
1517
+ }
1518
+ ) : (
1519
+ /* Loading state while waiting for SDK to generate QR */
1520
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { textAlign: "center" }, children: [
1521
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
1522
+ width: "32px",
1523
+ height: "32px",
1524
+ border: `3px solid ${theme.colors.border}`,
1525
+ borderTop: `3px solid ${theme.colors.primary}`,
1526
+ borderRadius: "50%",
1527
+ animation: "partylayer-spin 0.8s linear infinite",
1528
+ margin: "0 auto 12px"
1529
+ } }),
1530
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: "13px", color: theme.colors.textSecondary }, children: "Generating QR code..." })
1531
+ ] })
1532
+ ) }),
1533
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
1534
+ fontSize: "13px",
1535
+ color: theme.colors.textSecondary,
1536
+ marginBottom: "20px"
1537
+ }, children: [
1538
+ "Scan with ",
1539
+ selectedWallet.name,
1540
+ " mobile app"
1541
+ ] }),
1542
+ deepLinkUrl && /* @__PURE__ */ jsxRuntime.jsxs(
1543
+ "a",
1544
+ {
1545
+ href: deepLinkUrl,
1546
+ target: "_blank",
1547
+ rel: "noopener noreferrer",
1548
+ style: {
1549
+ display: "inline-flex",
1550
+ alignItems: "center",
1551
+ gap: "8px",
1552
+ ...primaryBtnStyle,
1553
+ textDecoration: "none",
1554
+ marginBottom: "12px"
1555
+ },
1556
+ children: [
1557
+ /* @__PURE__ */ jsxRuntime.jsx(SmartphoneIcon, { size: 14, color: "#0B0F1A" }),
1558
+ "Open in ",
1559
+ selectedWallet.name
1560
+ ]
1561
+ }
1562
+ ),
1563
+ installUrl && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { marginTop: "4px" }, children: /* @__PURE__ */ jsxRuntime.jsxs(
1564
+ "a",
1565
+ {
1566
+ href: installUrl,
1567
+ target: "_blank",
1568
+ rel: "noopener noreferrer",
1569
+ style: {
1570
+ ...linkStyle,
1571
+ textDecoration: "none"
1572
+ },
1573
+ children: [
1574
+ /* @__PURE__ */ jsxRuntime.jsx(DownloadIcon, { size: 11, color: "currentColor" }),
1575
+ "Install browser extension",
1576
+ /* @__PURE__ */ jsxRuntime.jsx(ExternalLinkIcon, { size: 10, color: "currentColor" })
1577
+ ]
1578
+ }
1579
+ ) })
1118
1580
  ] })
1119
1581
  ] });
1120
1582
  };
@@ -1174,26 +1636,7 @@ function WalletModal({
1174
1636
  if (!selectedWallet) return null;
1175
1637
  const iconUrl = resolveWalletIcon(selectedWallet.walletId, walletIcons, selectedWallet.icons?.sm);
1176
1638
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1177
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: headerStyle, children: [
1178
- /* @__PURE__ */ jsxRuntime.jsxs(
1179
- "button",
1180
- {
1181
- onClick: handleBackToList,
1182
- style: { ...closeBtnBase, width: "auto", padding: "0 10px", gap: "4px" },
1183
- onMouseEnter: (e) => {
1184
- e.currentTarget.style.backgroundColor = hoverBg;
1185
- },
1186
- onMouseLeave: (e) => {
1187
- e.currentTarget.style.backgroundColor = theme.colors.surface;
1188
- },
1189
- children: [
1190
- /* @__PURE__ */ jsxRuntime.jsx(BackIcon, { size: 14, color: theme.colors.textSecondary }),
1191
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: "12px", color: theme.colors.textSecondary, fontWeight: 500 }, children: "Back" })
1192
- ]
1193
- }
1194
- ),
1195
- /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: handleClose, style: closeBtnStyle, "aria-label": "Close", children: /* @__PURE__ */ jsxRuntime.jsx(CloseIcon, { size: 16, color: theme.colors.textSecondary }) })
1196
- ] }),
1639
+ renderSubHeader(handleBackToList),
1197
1640
  /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { padding: "16px 32px 32px", textAlign: "center" }, children: [
1198
1641
  /* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
1199
1642
  position: "relative",
@@ -1235,18 +1678,7 @@ function WalletModal({
1235
1678
  "button",
1236
1679
  {
1237
1680
  onClick: handleRetry,
1238
- style: {
1239
- padding: "10px 20px",
1240
- border: "none",
1241
- borderRadius: "10px",
1242
- backgroundColor: theme.colors.primary,
1243
- color: "#0B0F1A",
1244
- cursor: "pointer",
1245
- fontSize: "14px",
1246
- fontWeight: 600,
1247
- fontFamily: theme.fontFamily,
1248
- transition: "all 150ms cubic-bezier(0.2, 0.8, 0.2, 1)"
1249
- },
1681
+ style: primaryBtnStyle,
1250
1682
  onMouseEnter: (e) => {
1251
1683
  e.currentTarget.style.backgroundColor = theme.colors.primaryHover;
1252
1684
  e.currentTarget.style.transform = "translateY(-1px)";
@@ -1262,18 +1694,7 @@ function WalletModal({
1262
1694
  "button",
1263
1695
  {
1264
1696
  onClick: handleBackToList,
1265
- style: {
1266
- padding: "10px 20px",
1267
- border: `1px solid ${theme.colors.border}`,
1268
- borderRadius: "10px",
1269
- backgroundColor: "transparent",
1270
- color: theme.colors.textSecondary,
1271
- cursor: "pointer",
1272
- fontSize: "14px",
1273
- fontWeight: 500,
1274
- fontFamily: theme.fontFamily,
1275
- transition: "all 150ms"
1276
- },
1697
+ style: ghostBtnStyle,
1277
1698
  onMouseEnter: (e) => {
1278
1699
  e.currentTarget.style.backgroundColor = theme.colors.surface;
1279
1700
  },
@@ -1292,26 +1713,7 @@ function WalletModal({
1292
1713
  const iconUrl = resolveWalletIcon(selectedWallet.walletId, walletIcons, selectedWallet.icons?.sm);
1293
1714
  const installUrl = getWalletUrl(selectedWallet);
1294
1715
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1295
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: headerStyle, children: [
1296
- /* @__PURE__ */ jsxRuntime.jsxs(
1297
- "button",
1298
- {
1299
- onClick: handleBackToList,
1300
- style: { ...closeBtnBase, width: "auto", padding: "0 10px", gap: "4px" },
1301
- onMouseEnter: (e) => {
1302
- e.currentTarget.style.backgroundColor = hoverBg;
1303
- },
1304
- onMouseLeave: (e) => {
1305
- e.currentTarget.style.backgroundColor = theme.colors.surface;
1306
- },
1307
- children: [
1308
- /* @__PURE__ */ jsxRuntime.jsx(BackIcon, { size: 14, color: theme.colors.textSecondary }),
1309
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: "12px", color: theme.colors.textSecondary, fontWeight: 500 }, children: "Back" })
1310
- ]
1311
- }
1312
- ),
1313
- /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: handleClose, style: closeBtnStyle, "aria-label": "Close", children: /* @__PURE__ */ jsxRuntime.jsx(CloseIcon, { size: 16, color: theme.colors.textSecondary }) })
1314
- ] }),
1716
+ renderSubHeader(handleBackToList),
1315
1717
  /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { padding: "16px 32px 36px", textAlign: "center" }, children: [
1316
1718
  /* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
1317
1719
  position: "relative",
@@ -1403,18 +1805,7 @@ function WalletModal({
1403
1805
  "button",
1404
1806
  {
1405
1807
  onClick: handleRetry,
1406
- style: {
1407
- padding: "10px 20px",
1408
- border: `1px solid ${theme.colors.border}`,
1409
- borderRadius: "10px",
1410
- backgroundColor: "transparent",
1411
- color: theme.colors.textSecondary,
1412
- cursor: "pointer",
1413
- fontSize: "13px",
1414
- fontWeight: 500,
1415
- fontFamily: theme.fontFamily,
1416
- transition: "all 150ms"
1417
- },
1808
+ style: { ...ghostBtnStyle, fontSize: "13px" },
1418
1809
  onMouseEnter: (e) => {
1419
1810
  e.currentTarget.style.backgroundColor = theme.colors.surface;
1420
1811
  },
@@ -1428,18 +1819,7 @@ function WalletModal({
1428
1819
  "button",
1429
1820
  {
1430
1821
  onClick: handleBackToList,
1431
- style: {
1432
- padding: "10px 20px",
1433
- border: `1px solid ${theme.colors.border}`,
1434
- borderRadius: "10px",
1435
- backgroundColor: "transparent",
1436
- color: theme.colors.textSecondary,
1437
- cursor: "pointer",
1438
- fontSize: "13px",
1439
- fontWeight: 500,
1440
- fontFamily: theme.fontFamily,
1441
- transition: "all 150ms"
1442
- },
1822
+ style: { ...ghostBtnStyle, fontSize: "13px" },
1443
1823
  onMouseEnter: (e) => {
1444
1824
  e.currentTarget.style.backgroundColor = theme.colors.surface;
1445
1825
  },
@@ -1491,6 +1871,10 @@ function WalletModal({
1491
1871
  50% { transform: scale(1.02); }
1492
1872
  100% { transform: scale(1); opacity: 1; }
1493
1873
  }
1874
+ /* Hide Console SDK's injected QR modal \u2014 we render our own */
1875
+ #${SDK_QR_CONTAINER_ID} {
1876
+ display: none !important;
1877
+ }
1494
1878
  ` })
1495
1879
  ]
1496
1880
  }