@pollar/react 0.7.1 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -31,7 +31,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
31
31
 
32
32
  // ../../node_modules/qr.js/lib/ErrorCorrectLevel.js
33
33
  var require_ErrorCorrectLevel = __commonJS({
34
- "../../node_modules/qr.js/lib/ErrorCorrectLevel.js"(exports$1, module) {
34
+ "../../node_modules/qr.js/lib/ErrorCorrectLevel.js"(exports, module) {
35
35
  module.exports = {
36
36
  L: 1,
37
37
  M: 0,
@@ -43,7 +43,7 @@ var require_ErrorCorrectLevel = __commonJS({
43
43
 
44
44
  // ../../node_modules/qr.js/lib/mode.js
45
45
  var require_mode = __commonJS({
46
- "../../node_modules/qr.js/lib/mode.js"(exports$1, module) {
46
+ "../../node_modules/qr.js/lib/mode.js"(exports, module) {
47
47
  module.exports = {
48
48
  MODE_NUMBER: 1 << 0,
49
49
  MODE_ALPHA_NUM: 1 << 1,
@@ -55,7 +55,7 @@ var require_mode = __commonJS({
55
55
 
56
56
  // ../../node_modules/qr.js/lib/8BitByte.js
57
57
  var require_BitByte = __commonJS({
58
- "../../node_modules/qr.js/lib/8BitByte.js"(exports$1, module) {
58
+ "../../node_modules/qr.js/lib/8BitByte.js"(exports, module) {
59
59
  var mode = require_mode();
60
60
  function QR8bitByte(data) {
61
61
  this.mode = mode.MODE_8BIT_BYTE;
@@ -77,7 +77,7 @@ var require_BitByte = __commonJS({
77
77
 
78
78
  // ../../node_modules/qr.js/lib/RSBlock.js
79
79
  var require_RSBlock = __commonJS({
80
- "../../node_modules/qr.js/lib/RSBlock.js"(exports$1, module) {
80
+ "../../node_modules/qr.js/lib/RSBlock.js"(exports, module) {
81
81
  var ECL = require_ErrorCorrectLevel();
82
82
  function QRRSBlock(totalCount, dataCount) {
83
83
  this.totalCount = totalCount;
@@ -326,7 +326,7 @@ var require_RSBlock = __commonJS({
326
326
 
327
327
  // ../../node_modules/qr.js/lib/BitBuffer.js
328
328
  var require_BitBuffer = __commonJS({
329
- "../../node_modules/qr.js/lib/BitBuffer.js"(exports$1, module) {
329
+ "../../node_modules/qr.js/lib/BitBuffer.js"(exports, module) {
330
330
  function QRBitBuffer() {
331
331
  this.buffer = new Array();
332
332
  this.length = 0;
@@ -361,7 +361,7 @@ var require_BitBuffer = __commonJS({
361
361
 
362
362
  // ../../node_modules/qr.js/lib/math.js
363
363
  var require_math = __commonJS({
364
- "../../node_modules/qr.js/lib/math.js"(exports$1, module) {
364
+ "../../node_modules/qr.js/lib/math.js"(exports, module) {
365
365
  var QRMath = {
366
366
  glog: function(n) {
367
367
  if (n < 1) {
@@ -399,7 +399,7 @@ var require_math = __commonJS({
399
399
 
400
400
  // ../../node_modules/qr.js/lib/Polynomial.js
401
401
  var require_Polynomial = __commonJS({
402
- "../../node_modules/qr.js/lib/Polynomial.js"(exports$1, module) {
402
+ "../../node_modules/qr.js/lib/Polynomial.js"(exports, module) {
403
403
  var math = require_math();
404
404
  function QRPolynomial(num, shift) {
405
405
  if (num.length == void 0) {
@@ -451,7 +451,7 @@ var require_Polynomial = __commonJS({
451
451
 
452
452
  // ../../node_modules/qr.js/lib/util.js
453
453
  var require_util = __commonJS({
454
- "../../node_modules/qr.js/lib/util.js"(exports$1, module) {
454
+ "../../node_modules/qr.js/lib/util.js"(exports, module) {
455
455
  var Mode = require_mode();
456
456
  var Polynomial = require_Polynomial();
457
457
  var math = require_math();
@@ -682,7 +682,7 @@ var require_util = __commonJS({
682
682
 
683
683
  // ../../node_modules/qr.js/lib/QRCode.js
684
684
  var require_QRCode = __commonJS({
685
- "../../node_modules/qr.js/lib/QRCode.js"(exports$1, module) {
685
+ "../../node_modules/qr.js/lib/QRCode.js"(exports, module) {
686
686
  var BitByte = require_BitByte();
687
687
  var RSBlock = require_RSBlock();
688
688
  var BitBuffer = require_BitBuffer();
@@ -1028,7 +1028,7 @@ var PollarModalFooter = () => {
1028
1028
  /* @__PURE__ */ jsx("span", { className: "pollar-footer-name", children: "Pollar" }),
1029
1029
  /* @__PURE__ */ jsxs("span", { className: "pollar-footer-version", children: [
1030
1030
  "v",
1031
- "0.7.1"
1031
+ "0.8.0"
1032
1032
  ] })
1033
1033
  ] })
1034
1034
  ] });
@@ -1110,16 +1110,7 @@ function RuleCard({
1110
1110
  validity
1111
1111
  ] })
1112
1112
  ] }),
1113
- /* @__PURE__ */ jsx("div", { className: "pollar-dist-item-action", children: isClaimed ? /* @__PURE__ */ jsx("span", { className: "pollar-dist-item-status", "data-kind": "claimed", children: "Claimed" }) : effectivelyClaimable ? /* @__PURE__ */ jsx(
1114
- "button",
1115
- {
1116
- type: "button",
1117
- className: "pollar-btn-primary pollar-dist-claim-btn",
1118
- onClick: onClaim,
1119
- disabled: isClaiming,
1120
- children: isClaiming ? "Claiming\u2026" : "Claim"
1121
- }
1122
- ) : /* @__PURE__ */ jsx("span", { className: "pollar-dist-item-status", "data-kind": "unavailable", children: reasonLabel(rule.reason) }) }),
1113
+ /* @__PURE__ */ jsx("div", { className: "pollar-dist-item-action", children: isClaimed ? /* @__PURE__ */ jsx("span", { className: "pollar-dist-item-status", "data-kind": "claimed", children: "Claimed" }) : effectivelyClaimable ? /* @__PURE__ */ jsx("button", { type: "button", className: "pollar-btn-primary pollar-dist-claim-btn", onClick: onClaim, disabled: isClaiming, children: isClaiming ? "Claiming\u2026" : "Claim" }) : /* @__PURE__ */ jsx("span", { className: "pollar-dist-item-status", "data-kind": "unavailable", children: reasonLabel(rule.reason) }) }),
1123
1114
  errorMessage && /* @__PURE__ */ jsx("div", { className: "pollar-dist-item-error", children: errorMessage })
1124
1115
  ] });
1125
1116
  }
@@ -1333,10 +1324,20 @@ function KycModalTemplate({
1333
1324
  ] }),
1334
1325
  step === "select_provider" && /* @__PURE__ */ jsxs("div", { className: "pollar-kyc-providers", children: [
1335
1326
  providers.length === 0 && /* @__PURE__ */ jsx("p", { style: { color: "var(--pollar-muted)", textAlign: "center" }, children: "No providers available for your country." }),
1336
- providers.map((p) => /* @__PURE__ */ jsxs("button", { type: "button", className: "pollar-kyc-provider-btn", disabled: isLoading, onClick: () => onSelectProvider(p), children: [
1337
- /* @__PURE__ */ jsx("span", { className: "pollar-kyc-provider-name", children: p.name }),
1338
- /* @__PURE__ */ jsx("span", { className: "pollar-kyc-provider-flow", children: p.flow })
1339
- ] }, p.id))
1327
+ providers.map((p) => /* @__PURE__ */ jsxs(
1328
+ "button",
1329
+ {
1330
+ type: "button",
1331
+ className: "pollar-kyc-provider-btn",
1332
+ disabled: isLoading,
1333
+ onClick: () => onSelectProvider(p),
1334
+ children: [
1335
+ /* @__PURE__ */ jsx("span", { className: "pollar-kyc-provider-name", children: p.name }),
1336
+ /* @__PURE__ */ jsx("span", { className: "pollar-kyc-provider-flow", children: p.flow })
1337
+ ]
1338
+ },
1339
+ p.id
1340
+ ))
1340
1341
  ] }),
1341
1342
  step === "verifying" && selectedProvider && /* @__PURE__ */ jsxs(Fragment, { children: [
1342
1343
  /* @__PURE__ */ jsx("div", { className: "pollar-kyc-iframe-wrap", children: session?.kycUrl ? /* @__PURE__ */ jsx("iframe", { className: "pollar-kyc-iframe", src: session.kycUrl, title: "KYC verification", allow: "camera; microphone" }) : /* @__PURE__ */ jsxs("div", { className: "pollar-kyc-iframe-mock", children: [
@@ -1455,8 +1456,7 @@ function EmailCodeInput({ email, onSubmit }) {
1455
1456
  }
1456
1457
  return /* @__PURE__ */ jsxs("div", { className: "pollar-code-section", children: [
1457
1458
  /* @__PURE__ */ jsxs("p", { className: "pollar-code-label", children: [
1458
- "Enter the 6-digit code sent to",
1459
- " ",
1459
+ "Enter the 6-digit code sent to ",
1460
1460
  email ? /* @__PURE__ */ jsx("strong", { children: email }) : "your email"
1461
1461
  ] }),
1462
1462
  /* @__PURE__ */ jsx("div", { className: "pollar-code-inputs", children: digits.map((digit, i) => /* @__PURE__ */ jsx(
@@ -1480,7 +1480,14 @@ function EmailCodeInput({ email, onSubmit }) {
1480
1480
  }
1481
1481
  var GithubButton = ({ disabled, onClick }) => {
1482
1482
  return /* @__PURE__ */ jsxs("button", { className: "github-button", disabled, onClick, children: [
1483
- /* @__PURE__ */ jsx("svg", { className: "github-button-icon", viewBox: "0 0 24 24", fill: "currentColor", "aria-hidden": true, children: /* @__PURE__ */ jsx("path", { fillRule: "evenodd", d: "M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z", clipRule: "evenodd" }) }),
1483
+ /* @__PURE__ */ jsx("svg", { className: "github-button-icon", viewBox: "0 0 24 24", fill: "currentColor", "aria-hidden": true, children: /* @__PURE__ */ jsx(
1484
+ "path",
1485
+ {
1486
+ fillRule: "evenodd",
1487
+ d: "M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z",
1488
+ clipRule: "evenodd"
1489
+ }
1490
+ ) }),
1484
1491
  /* @__PURE__ */ jsx("span", { className: "github-button-contents", children: "GitHub" })
1485
1492
  ] });
1486
1493
  };
@@ -1533,6 +1540,36 @@ var GoogleButton = ({ disabled, onClick }) => {
1533
1540
  ] })
1534
1541
  ] });
1535
1542
  };
1543
+ function DefaultFreighterAlbedoButtons({ onConnect, isLoading }) {
1544
+ return /* @__PURE__ */ jsxs("div", { className: "pollar-wallet-list", children: [
1545
+ /* @__PURE__ */ jsxs(
1546
+ "button",
1547
+ {
1548
+ type: "button",
1549
+ disabled: isLoading,
1550
+ className: "pollar-wallet-list-btn",
1551
+ onClick: () => onConnect(WalletType.FREIGHTER),
1552
+ children: [
1553
+ /* @__PURE__ */ jsx("img", { src: LOGO_FREIGHTER, alt: "Freighter", className: "pollar-wallet-list-icon" }),
1554
+ /* @__PURE__ */ jsx("span", { className: "pollar-wallet-list-name", children: "Freighter" })
1555
+ ]
1556
+ }
1557
+ ),
1558
+ /* @__PURE__ */ jsxs(
1559
+ "button",
1560
+ {
1561
+ type: "button",
1562
+ disabled: isLoading,
1563
+ className: "pollar-wallet-list-btn",
1564
+ onClick: () => onConnect(WalletType.ALBEDO),
1565
+ children: [
1566
+ /* @__PURE__ */ jsx("img", { src: LOGO_ALBEDO, alt: "Albedo", className: "pollar-wallet-list-icon" }),
1567
+ /* @__PURE__ */ jsx("span", { className: "pollar-wallet-list-name", children: "Albedo" })
1568
+ ]
1569
+ }
1570
+ )
1571
+ ] });
1572
+ }
1536
1573
  var AUTH_STATE_MESSAGES = {
1537
1574
  idle: "",
1538
1575
  creating_session: "Initializing\u2026",
@@ -1577,8 +1614,8 @@ function LoginModalTemplate({
1577
1614
  onEmailChange,
1578
1615
  onEmailSubmit,
1579
1616
  onSocialLogin,
1580
- onFreighterConnect,
1581
- onAlbedoConnect,
1617
+ onWalletConnect,
1618
+ renderWallets,
1582
1619
  authState,
1583
1620
  codeInputKey,
1584
1621
  onCodeSubmit,
@@ -1614,9 +1651,35 @@ function LoginModalTemplate({
1614
1651
  const isEmailCodeError = authState.step === "error" && (authState.errorCode === AUTH_ERROR_CODES.EMAIL_CODE_EXPIRED || authState.errorCode === AUTH_ERROR_CODES.EMAIL_CODE_INVALID);
1615
1652
  const awaitingEmailCode = authState.step === "entering_code" || authState.step === "verifying_email_code" || isEmailCodeError;
1616
1653
  const statusMessage = authState.step === "error" ? authState.message : AUTH_STATE_MESSAGES[authState.step];
1617
- const BackButton = ({ onClick }) => /* @__PURE__ */ jsx("button", { type: "button", className: "pollar-back-btn", onClick, "aria-label": "Back", children: /* @__PURE__ */ jsx("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "M15 19l-7-7 7-7" }) }) });
1654
+ const BackButton = ({ onClick }) => /* @__PURE__ */ jsx("button", { type: "button", className: "pollar-back-btn", onClick, "aria-label": "Back", children: /* @__PURE__ */ jsx(
1655
+ "svg",
1656
+ {
1657
+ width: "20",
1658
+ height: "20",
1659
+ viewBox: "0 0 24 24",
1660
+ fill: "none",
1661
+ stroke: "currentColor",
1662
+ strokeWidth: "2.5",
1663
+ strokeLinecap: "round",
1664
+ strokeLinejoin: "round",
1665
+ children: /* @__PURE__ */ jsx("path", { d: "M15 19l-7-7 7-7" })
1666
+ }
1667
+ ) });
1618
1668
  return /* @__PURE__ */ jsxs("div", { className: "pollar-modal-card pollar-modal", style: cssVars, onClick: (e) => e.stopPropagation(), children: [
1619
- /* @__PURE__ */ jsx("button", { type: "button", className: "pollar-close-btn", onClick: onCancel, "aria-label": "Close", children: /* @__PURE__ */ jsx("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "M18 6L6 18M6 6l12 12" }) }) }),
1669
+ /* @__PURE__ */ jsx("button", { type: "button", className: "pollar-close-btn", onClick: onCancel, "aria-label": "Close", children: /* @__PURE__ */ jsx(
1670
+ "svg",
1671
+ {
1672
+ width: "18",
1673
+ height: "18",
1674
+ viewBox: "0 0 24 24",
1675
+ fill: "none",
1676
+ stroke: "currentColor",
1677
+ strokeWidth: "2.5",
1678
+ strokeLinecap: "round",
1679
+ strokeLinejoin: "round",
1680
+ children: /* @__PURE__ */ jsx("path", { d: "M18 6L6 18M6 6l12 12" })
1681
+ }
1682
+ ) }),
1620
1683
  /* @__PURE__ */ jsxs("div", { className: "pollar-header", children: [
1621
1684
  /* @__PURE__ */ jsx("div", { className: "pollar-logo-wrap", children: /* @__PURE__ */ jsx("img", { src: logoUrl ?? LOGO_POLLAR, alt: "Logo", className: "pollar-logo" }) }),
1622
1685
  /* @__PURE__ */ jsx("h2", { className: "pollar-title", children: appName }),
@@ -1628,34 +1691,7 @@ function LoginModalTemplate({
1628
1691
  }) }, codeInputKey)
1629
1692
  ] }) : showWalletPicker ? /* @__PURE__ */ jsxs(Fragment, { children: [
1630
1693
  /* @__PURE__ */ jsx(BackButton, { onClick: () => setShowWalletPicker(false) }),
1631
- /* @__PURE__ */ jsxs("div", { className: "pollar-wallet-list", children: [
1632
- /* @__PURE__ */ jsxs(
1633
- "button",
1634
- {
1635
- type: "button",
1636
- disabled: isLoading,
1637
- className: "pollar-wallet-list-btn",
1638
- onClick: onFreighterConnect,
1639
- children: [
1640
- /* @__PURE__ */ jsx("img", { src: LOGO_FREIGHTER, alt: "Freighter", className: "pollar-wallet-list-icon" }),
1641
- /* @__PURE__ */ jsx("span", { className: "pollar-wallet-list-name", children: "Freighter" })
1642
- ]
1643
- }
1644
- ),
1645
- /* @__PURE__ */ jsxs(
1646
- "button",
1647
- {
1648
- type: "button",
1649
- disabled: isLoading,
1650
- className: "pollar-wallet-list-btn",
1651
- onClick: onAlbedoConnect,
1652
- children: [
1653
- /* @__PURE__ */ jsx("img", { src: LOGO_ALBEDO, alt: "Albedo", className: "pollar-wallet-list-icon" }),
1654
- /* @__PURE__ */ jsx("span", { className: "pollar-wallet-list-name", children: "Albedo" })
1655
- ]
1656
- }
1657
- )
1658
- ] })
1694
+ renderWallets ? renderWallets({ onConnect: onWalletConnect, authState }) : /* @__PURE__ */ jsx(DefaultFreighterAlbedoButtons, { onConnect: onWalletConnect, isLoading })
1659
1695
  ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
1660
1696
  emailEnabled && /* @__PURE__ */ jsxs("div", { className: "pollar-email-section", children: [
1661
1697
  /* @__PURE__ */ jsx(
@@ -1670,7 +1706,17 @@ function LoginModalTemplate({
1670
1706
  onKeyDown: (e) => e.key === "Enter" && onEmailSubmit?.()
1671
1707
  }
1672
1708
  ),
1673
- /* @__PURE__ */ jsx("button", { type: "button", disabled: isLoading || !email, className: "pollar-btn-primary", style: { marginTop: "0.75rem", width: "100%" }, onClick: onEmailSubmit, children: "Submit" })
1709
+ /* @__PURE__ */ jsx(
1710
+ "button",
1711
+ {
1712
+ type: "button",
1713
+ disabled: isLoading || !email,
1714
+ className: "pollar-btn-primary",
1715
+ style: { marginTop: "0.75rem", width: "100%" },
1716
+ onClick: onEmailSubmit,
1717
+ children: "Submit"
1718
+ }
1719
+ )
1674
1720
  ] }),
1675
1721
  emailEnabled && enabledSocial.length > 0 && /* @__PURE__ */ jsxs("div", { className: "pollar-divider", children: [
1676
1722
  /* @__PURE__ */ jsx("div", { className: "pollar-divider-line" }),
@@ -1688,7 +1734,20 @@ function LoginModalTemplate({
1688
1734
  className: "pollar-wallet-entry-btn",
1689
1735
  onClick: () => setShowWalletPicker(true),
1690
1736
  children: [
1691
- /* @__PURE__ */ jsx("svg", { width: "18", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z" }) }),
1737
+ /* @__PURE__ */ jsx(
1738
+ "svg",
1739
+ {
1740
+ width: "18",
1741
+ height: "20",
1742
+ viewBox: "0 0 24 24",
1743
+ fill: "none",
1744
+ stroke: "currentColor",
1745
+ strokeWidth: "2",
1746
+ strokeLinecap: "round",
1747
+ strokeLinejoin: "round",
1748
+ children: /* @__PURE__ */ jsx("path", { d: "M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z" })
1749
+ }
1750
+ ),
1692
1751
  "Wallet"
1693
1752
  ]
1694
1753
  }
@@ -1708,14 +1767,15 @@ function LoginModalTemplate({
1708
1767
  }
1709
1768
  function LoginModal({ onClose }) {
1710
1769
  const [email, setEmail] = useState("");
1711
- const { getClient, styles, appConfig: config } = usePollar();
1770
+ const { getClient, styles, appConfig: config, renderWallets } = usePollar();
1712
1771
  const [authState, setAuthState] = useState(() => getClient().getAuthState());
1713
1772
  const [codeInputKey, setCodeInputKey] = useState(0);
1714
1773
  const pendingEmail = useRef(null);
1715
1774
  const onCloseRef = useRef(onClose);
1716
1775
  onCloseRef.current = onClose;
1776
+ const autoCloseTimer = useRef(null);
1717
1777
  useEffect(() => {
1718
- return getClient().onAuthStateChange((next) => {
1778
+ const unsubscribe = getClient().onAuthStateChange((next) => {
1719
1779
  setAuthState(next);
1720
1780
  if (next.step === "entering_email" && pendingEmail.current) {
1721
1781
  getClient().sendEmailCode(pendingEmail.current);
@@ -1725,9 +1785,19 @@ function LoginModal({ onClose }) {
1725
1785
  setCodeInputKey((k) => k + 1);
1726
1786
  }
1727
1787
  if (next.step === "authenticated") {
1728
- setTimeout(onCloseRef.current, 1e3);
1788
+ autoCloseTimer.current = setTimeout(() => {
1789
+ autoCloseTimer.current = null;
1790
+ onCloseRef.current();
1791
+ }, 1e3);
1729
1792
  }
1730
1793
  });
1794
+ return () => {
1795
+ unsubscribe();
1796
+ if (autoCloseTimer.current !== null) {
1797
+ clearTimeout(autoCloseTimer.current);
1798
+ autoCloseTimer.current = null;
1799
+ }
1800
+ };
1731
1801
  }, [getClient]);
1732
1802
  const { theme = "light", accentColor = "#005DB4", logoUrl, emailEnabled, embeddedWallets, providers } = styles;
1733
1803
  function handleClose() {
@@ -1779,8 +1849,8 @@ function LoginModal({ onClose }) {
1779
1849
  onEmailChange: setEmail,
1780
1850
  onEmailSubmit: handleEmailSubmit,
1781
1851
  onSocialLogin: handleSocialLogin,
1782
- onFreighterConnect: () => handleWalletConnect(WalletType.FREIGHTER),
1783
- onAlbedoConnect: () => handleWalletConnect(WalletType.ALBEDO),
1852
+ onWalletConnect: handleWalletConnect,
1853
+ ...renderWallets !== void 0 && { renderWallets },
1784
1854
  authState,
1785
1855
  codeInputKey,
1786
1856
  onCodeSubmit: handleVerifyCode,
@@ -1897,8 +1967,26 @@ function RampWidgetTemplate({
1897
1967
  ] }),
1898
1968
  step === "input" && /* @__PURE__ */ jsxs(Fragment, { children: [
1899
1969
  /* @__PURE__ */ jsxs("div", { className: "pollar-ramp-tabs", children: [
1900
- /* @__PURE__ */ jsx("button", { type: "button", className: "pollar-ramp-tab", "data-active": direction === "onramp", onClick: () => onDirectionChange("onramp"), children: "Buy" }),
1901
- /* @__PURE__ */ jsx("button", { type: "button", className: "pollar-ramp-tab", "data-active": direction === "offramp", onClick: () => onDirectionChange("offramp"), children: "Sell" })
1970
+ /* @__PURE__ */ jsx(
1971
+ "button",
1972
+ {
1973
+ type: "button",
1974
+ className: "pollar-ramp-tab",
1975
+ "data-active": direction === "onramp",
1976
+ onClick: () => onDirectionChange("onramp"),
1977
+ children: "Buy"
1978
+ }
1979
+ ),
1980
+ /* @__PURE__ */ jsx(
1981
+ "button",
1982
+ {
1983
+ type: "button",
1984
+ className: "pollar-ramp-tab",
1985
+ "data-active": direction === "offramp",
1986
+ onClick: () => onDirectionChange("offramp"),
1987
+ children: "Sell"
1988
+ }
1989
+ )
1902
1990
  ] }),
1903
1991
  /* @__PURE__ */ jsxs("div", { className: "pollar-ramp-input-row", children: [
1904
1992
  /* @__PURE__ */ jsxs("div", { className: "pollar-ramp-field", children: [
@@ -2003,17 +2091,79 @@ function RampWidgetTemplate({
2003
2091
  ] });
2004
2092
  }
2005
2093
  var MOCK_DEFAULT_QUOTES = [
2006
- { quoteId: "meld-default", provider: "Meld", fee: 1.2, feeCurrency: "USD", rate: 1, rail: "ACH", protocol: "REST", estimatedTime: "~20 min", recommended: true }
2094
+ {
2095
+ quoteId: "meld-default",
2096
+ provider: "Meld",
2097
+ fee: 1.2,
2098
+ feeCurrency: "USD",
2099
+ rate: 1,
2100
+ rail: "ACH",
2101
+ protocol: "REST",
2102
+ estimatedTime: "~20 min",
2103
+ recommended: true
2104
+ }
2007
2105
  ];
2008
2106
  var MOCK_QUOTES = {
2009
2107
  MX: [
2010
- { quoteId: "etherfuse-mx", provider: "Etherfuse", fee: 0.5, feeCurrency: "MXN", rate: 17.2, rail: "SPEI", protocol: "SEP-24", estimatedTime: "~10 min", recommended: true },
2011
- { quoteId: "alfredpay-mx", provider: "AlfredPay", fee: 0.8, feeCurrency: "MXN", rate: 17.1, rail: "SPEI", protocol: "REST", estimatedTime: "~15 min", recommended: false }
2108
+ {
2109
+ quoteId: "etherfuse-mx",
2110
+ provider: "Etherfuse",
2111
+ fee: 0.5,
2112
+ feeCurrency: "MXN",
2113
+ rate: 17.2,
2114
+ rail: "SPEI",
2115
+ protocol: "SEP-24",
2116
+ estimatedTime: "~10 min",
2117
+ recommended: true
2118
+ },
2119
+ {
2120
+ quoteId: "alfredpay-mx",
2121
+ provider: "AlfredPay",
2122
+ fee: 0.8,
2123
+ feeCurrency: "MXN",
2124
+ rate: 17.1,
2125
+ rail: "SPEI",
2126
+ protocol: "REST",
2127
+ estimatedTime: "~15 min",
2128
+ recommended: false
2129
+ }
2130
+ ],
2131
+ BR: [
2132
+ {
2133
+ quoteId: "abroad-br",
2134
+ provider: "Abroad",
2135
+ fee: 0.6,
2136
+ feeCurrency: "BRL",
2137
+ rate: 5.1,
2138
+ rail: "PIX",
2139
+ protocol: "REST",
2140
+ estimatedTime: "~5 min",
2141
+ recommended: true
2142
+ }
2012
2143
  ],
2013
- BR: [{ quoteId: "abroad-br", provider: "Abroad", fee: 0.6, feeCurrency: "BRL", rate: 5.1, rail: "PIX", protocol: "REST", estimatedTime: "~5 min", recommended: true }],
2014
2144
  CO: [
2015
- { quoteId: "abroad-co", provider: "Abroad", fee: 0.7, feeCurrency: "COP", rate: 4100, rail: "PSE", protocol: "REST", estimatedTime: "~10 min", recommended: true },
2016
- { quoteId: "koywe-co", provider: "Koywe", fee: 0.9, feeCurrency: "COP", rate: 4095, rail: "PSE", protocol: "REST", estimatedTime: "~15 min", recommended: false }
2145
+ {
2146
+ quoteId: "abroad-co",
2147
+ provider: "Abroad",
2148
+ fee: 0.7,
2149
+ feeCurrency: "COP",
2150
+ rate: 4100,
2151
+ rail: "PSE",
2152
+ protocol: "REST",
2153
+ estimatedTime: "~10 min",
2154
+ recommended: true
2155
+ },
2156
+ {
2157
+ quoteId: "koywe-co",
2158
+ provider: "Koywe",
2159
+ fee: 0.9,
2160
+ feeCurrency: "COP",
2161
+ rate: 4095,
2162
+ rail: "PSE",
2163
+ protocol: "REST",
2164
+ estimatedTime: "~15 min",
2165
+ recommended: false
2166
+ }
2017
2167
  ],
2018
2168
  DEFAULT: MOCK_DEFAULT_QUOTES
2019
2169
  };
@@ -2108,17 +2258,7 @@ function RampWidget({ onClose }) {
2108
2258
  // src/lib/qr-code/index.tsx
2109
2259
  var import_ErrorCorrectLevel = __toESM(require_ErrorCorrectLevel());
2110
2260
  var import_QRCode = __toESM(require_QRCode());
2111
- var QRCodeSvg = forwardRef(function QRCodeSvg2({
2112
- bgColor,
2113
- bgD,
2114
- fgD,
2115
- fgColor,
2116
- size,
2117
- title,
2118
- viewBoxSize,
2119
- xmlns = "http://www.w3.org/2000/svg",
2120
- ...props
2121
- }, ref) {
2261
+ var QRCodeSvg = forwardRef(function QRCodeSvg2({ bgColor, bgD, fgD, fgColor, size, title, viewBoxSize, xmlns = "http://www.w3.org/2000/svg", ...props }, ref) {
2122
2262
  return /* @__PURE__ */ jsxs("svg", { ...props, height: size, ref, viewBox: `0 0 ${viewBoxSize} ${viewBoxSize}`, width: size, xmlns, children: [
2123
2263
  title ? /* @__PURE__ */ jsx("title", { children: title }) : null,
2124
2264
  /* @__PURE__ */ jsx("path", { d: bgD, fill: bgColor }),
@@ -2144,9 +2284,13 @@ var QRCode = forwardRef(function QRCode2({ bgColor = "#FFFFFF", fgColor = "#0000
2144
2284
  {
2145
2285
  ...props,
2146
2286
  bgColor,
2147
- bgD: cells.map((row, rowIndex) => row.map((cell, cellIndex) => !cell ? `M ${cellIndex} ${rowIndex} l 1 0 0 1 -1 0 Z` : "").join(" ")).join(" "),
2287
+ bgD: cells.map(
2288
+ (row, rowIndex) => row.map((cell, cellIndex) => !cell ? `M ${cellIndex} ${rowIndex} l 1 0 0 1 -1 0 Z` : "").join(" ")
2289
+ ).join(" "),
2148
2290
  fgColor,
2149
- fgD: cells.map((row, rowIndex) => row.map((cell, cellIndex) => cell ? `M ${cellIndex} ${rowIndex} l 1 0 0 1 -1 0 Z` : "").join(" ")).join(" "),
2291
+ fgD: cells.map(
2292
+ (row, rowIndex) => row.map((cell, cellIndex) => cell ? `M ${cellIndex} ${rowIndex} l 1 0 0 1 -1 0 Z` : "").join(" ")
2293
+ ).join(" "),
2150
2294
  ref,
2151
2295
  size,
2152
2296
  viewBoxSize: cells.length
@@ -2192,15 +2336,7 @@ function ReceiveModalTemplate({
2192
2336
  /* @__PURE__ */ jsx("div", { className: "pollar-modal-header-actions", children: /* @__PURE__ */ jsx("button", { type: "button", className: "pollar-modal-close", onClick: onClose, "aria-label": "Close", children: /* @__PURE__ */ jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsx("path", { d: "M2 2l12 12M14 2L2 14", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) }) }) })
2193
2337
  ] }),
2194
2338
  walletAddress ? /* @__PURE__ */ jsxs(Fragment, { children: [
2195
- /* @__PURE__ */ jsx("div", { className: "pollar-receive-qr", children: /* @__PURE__ */ jsx(
2196
- QRCode,
2197
- {
2198
- value: walletAddress,
2199
- size: 180,
2200
- fgColor: isDark ? "#ffffff" : "#111827",
2201
- bgColor: "transparent"
2202
- }
2203
- ) }),
2339
+ /* @__PURE__ */ jsx("div", { className: "pollar-receive-qr", children: /* @__PURE__ */ jsx(QRCode, { value: walletAddress, size: 180, fgColor: isDark ? "#ffffff" : "#111827", bgColor: "transparent" }) }),
2204
2340
  /* @__PURE__ */ jsx("p", { className: "pollar-receive-instructions", children: "Share your Stellar address to receive any asset. Only send Stellar assets to this address." }),
2205
2341
  /* @__PURE__ */ jsxs("div", { className: "pollar-receive-address-row", children: [
2206
2342
  /* @__PURE__ */ jsx("span", { className: "pollar-receive-address", children: walletAddress }),
@@ -2245,11 +2381,22 @@ function ReceiveModal({ onClose }) {
2245
2381
  const { walletAddress, styles } = usePollar();
2246
2382
  const { theme = "light", accentColor = "#005DB4" } = styles;
2247
2383
  const [copied, setCopied] = useState(false);
2384
+ const copyTimerRef = useRef(null);
2385
+ useEffect(
2386
+ () => () => {
2387
+ if (copyTimerRef.current !== null) clearTimeout(copyTimerRef.current);
2388
+ },
2389
+ []
2390
+ );
2248
2391
  function handleCopy() {
2249
2392
  if (!walletAddress) return;
2250
2393
  navigator.clipboard.writeText(walletAddress).then(() => {
2251
2394
  setCopied(true);
2252
- setTimeout(() => setCopied(false), 2e3);
2395
+ if (copyTimerRef.current !== null) clearTimeout(copyTimerRef.current);
2396
+ copyTimerRef.current = setTimeout(() => {
2397
+ copyTimerRef.current = null;
2398
+ setCopied(false);
2399
+ }, 2e3);
2253
2400
  });
2254
2401
  }
2255
2402
  return /* @__PURE__ */ jsx("div", { className: "pollar-overlay", onClick: onClose, children: /* @__PURE__ */ jsx(
@@ -2268,10 +2415,32 @@ var STATUS_MESSAGES = {
2268
2415
  idle: "",
2269
2416
  building: "Building transaction\u2026",
2270
2417
  built: "Ready to sign and send",
2271
- signing: "Signing and sending transaction\u2026",
2418
+ signing: "Signing transaction\u2026",
2419
+ signed: "Signed \u2014 ready to submit",
2420
+ submitting: "Submitting transaction\u2026",
2421
+ submitted: "Submitted \u2014 waiting for confirmation\u2026",
2422
+ "signing-submitting": "Signing and submitting transaction\u2026",
2423
+ "building-signing-submitting": "Processing transaction\u2026",
2272
2424
  success: "Transaction sent successfully",
2273
2425
  error: "Transaction failed"
2274
2426
  };
2427
+ var IN_FLIGHT_STEPS = /* @__PURE__ */ new Set([
2428
+ "building",
2429
+ "signing",
2430
+ "submitting",
2431
+ "submitted",
2432
+ "signing-submitting",
2433
+ "building-signing-submitting"
2434
+ ]);
2435
+ var SHOW_DETAILS_STEPS = /* @__PURE__ */ new Set([
2436
+ "built",
2437
+ "signing",
2438
+ "signed",
2439
+ "submitting",
2440
+ "submitted",
2441
+ "signing-submitting",
2442
+ "success"
2443
+ ]);
2275
2444
  function TxStatusView({
2276
2445
  transaction,
2277
2446
  showXdr,
@@ -2288,10 +2457,10 @@ function TxStatusView({
2288
2457
  const hash = transaction.step === "success" ? transaction.hash : null;
2289
2458
  const errorDetails = transaction.step === "error" ? transaction.details ?? null : null;
2290
2459
  const isBuilt = transaction.step === "built";
2291
- const isSigning = transaction.step === "signing";
2460
+ const isInFlight = IN_FLIGHT_STEPS.has(transaction.step);
2292
2461
  const isSuccess = transaction.step === "success";
2293
2462
  const isError = transaction.step === "error";
2294
- const showDetails = buildData !== null && (isBuilt || isSigning || isSuccess);
2463
+ const showDetails = buildData !== null && SHOW_DETAILS_STEPS.has(transaction.step);
2295
2464
  const walletImg = walletType === WalletType.FREIGHTER ? LOGO_FREIGHTER : walletType === WalletType.ALBEDO ? LOGO_ALBEDO : LOGO_POLLAR;
2296
2465
  const walletAlt = walletType === WalletType.FREIGHTER ? "Freighter" : walletType === WalletType.ALBEDO ? "Albedo" : "Pollar";
2297
2466
  return /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -2334,7 +2503,7 @@ function TxStatusView({
2334
2503
  /* @__PURE__ */ jsx("pre", { className: "pollar-tx-error-details-content", children: errorDetails })
2335
2504
  ] }),
2336
2505
  isBuilt && /* @__PURE__ */ jsx("button", { className: "pollar-btn-primary pollar-tx-sign-btn", onClick: onSignAndSend, children: "Sign & Send" }),
2337
- (isSigning || isSuccess || isError) && /* @__PURE__ */ jsxs("div", { className: "pollar-tx-wallet-spinner", children: [
2506
+ (isInFlight || isSuccess || isError) && /* @__PURE__ */ jsxs("div", { className: "pollar-tx-wallet-spinner", children: [
2338
2507
  /* @__PURE__ */ jsxs("div", { className: "pollar-tx-spinner-ring", children: [
2339
2508
  /* @__PURE__ */ jsxs(
2340
2509
  "svg",
@@ -2342,7 +2511,7 @@ function TxStatusView({
2342
2511
  viewBox: "0 0 88 88",
2343
2512
  width: "88",
2344
2513
  height: "88",
2345
- className: `pollar-tx-spinner-svg${isSigning ? " pollar-tx-spinner-rotating" : ""}`,
2514
+ className: `pollar-tx-spinner-svg${isInFlight ? " pollar-tx-spinner-rotating" : ""}`,
2346
2515
  "aria-hidden": true,
2347
2516
  children: [
2348
2517
  /* @__PURE__ */ jsx("circle", { cx: "44", cy: "44", r: "36", fill: "none", stroke: "var(--pollar-border)", strokeWidth: "3" }),
@@ -2356,9 +2525,9 @@ function TxStatusView({
2356
2525
  stroke: isSuccess ? "var(--pollar-success-text)" : isError ? "var(--pollar-error-text)" : "var(--pollar-accent)",
2357
2526
  strokeWidth: "3",
2358
2527
  strokeLinecap: "round",
2359
- strokeDasharray: isSigning ? "169.6 56.6" : "999 0",
2528
+ strokeDasharray: isInFlight ? "169.6 56.6" : "999 0",
2360
2529
  transform: "rotate(-90 44 44)",
2361
- style: { transition: isSigning ? "none" : "stroke 400ms, stroke-dasharray 400ms" }
2530
+ style: { transition: isInFlight ? "none" : "stroke 400ms, stroke-dasharray 400ms" }
2362
2531
  }
2363
2532
  )
2364
2533
  ]
@@ -2366,7 +2535,7 @@ function TxStatusView({
2366
2535
  ),
2367
2536
  /* @__PURE__ */ jsx("div", { className: "pollar-tx-wallet-icon", children: /* @__PURE__ */ jsx("img", { src: walletImg, alt: walletAlt, className: "pollar-tx-wallet-img" }) })
2368
2537
  ] }),
2369
- isSigning && /* @__PURE__ */ jsx("p", { className: "pollar-tx-spinner-label", children: walletType === WalletType.FREIGHTER ? "Waiting for Freighter\u2026" : walletType === WalletType.ALBEDO ? "Waiting for Albedo\u2026" : "Signing and sending\u2026" }),
2538
+ isInFlight && /* @__PURE__ */ jsx("p", { className: "pollar-tx-spinner-label", children: walletType === WalletType.FREIGHTER ? "Waiting for Freighter\u2026" : walletType === WalletType.ALBEDO ? "Waiting for Albedo\u2026" : "Signing and sending\u2026" }),
2370
2539
  isError && onRetry && "buildData" in transaction && transaction.buildData && /* @__PURE__ */ jsx("button", { className: "pollar-btn-secondary pollar-tx-retry-btn", onClick: onRetry, children: "Try again" })
2371
2540
  ] }),
2372
2541
  isSuccess && hash && /* @__PURE__ */ jsxs("div", { className: "pollar-tx-result", children: [
@@ -2434,7 +2603,7 @@ function TxStatusView({
2434
2603
  ModalStatusBanner,
2435
2604
  {
2436
2605
  message: STATUS_MESSAGES[transaction.step],
2437
- status: isError ? "ERROR" : isSigning || transaction.step === "building" ? "LOADING" : isSuccess ? "SUCCESS" : "NONE"
2606
+ status: isError ? "ERROR" : isInFlight ? "LOADING" : isSuccess ? "SUCCESS" : "NONE"
2438
2607
  }
2439
2608
  )
2440
2609
  ] });
@@ -2611,7 +2780,16 @@ function assetParam(record) {
2611
2780
  return { type: "credit_alphanum12", code: record.code, issuer: record.issuer };
2612
2781
  }
2613
2782
  function SendModal({ onClose }) {
2614
- const { walletBalance, refreshWalletBalance, buildTx, signAndSubmitTx, tx: transaction, walletType, network, styles } = usePollar();
2783
+ const {
2784
+ walletBalance,
2785
+ refreshWalletBalance,
2786
+ buildTx,
2787
+ signAndSubmitTx,
2788
+ tx: transaction,
2789
+ walletType,
2790
+ network,
2791
+ styles
2792
+ } = usePollar();
2615
2793
  const { theme = "light", accentColor = "#005DB4" } = styles;
2616
2794
  const [step, setStep] = useState("form");
2617
2795
  const [amount, setAmount] = useState("");
@@ -2620,9 +2798,16 @@ function SendModal({ onClose }) {
2620
2798
  const [showXdr, setShowXdr] = useState(false);
2621
2799
  const [copied, setCopied] = useState(false);
2622
2800
  const [formError, setFormError] = useState("");
2801
+ const copyTimerRef = useRef(null);
2623
2802
  useEffect(() => {
2624
2803
  void refreshWalletBalance();
2625
2804
  }, [refreshWalletBalance]);
2805
+ useEffect(
2806
+ () => () => {
2807
+ if (copyTimerRef.current !== null) clearTimeout(copyTimerRef.current);
2808
+ },
2809
+ []
2810
+ );
2626
2811
  const balanceData = walletBalance.step === "loaded" ? walletBalance.data : null;
2627
2812
  const allAssets = balanceData?.balances ?? [];
2628
2813
  const sortedAssets = [
@@ -2633,9 +2818,17 @@ function SendModal({ onClose }) {
2633
2818
  const buildData = "buildData" in transaction ? transaction.buildData : null;
2634
2819
  const explorerNetwork = buildData?.summary.network?.toLowerCase().includes("testnet") ? "testnet" : buildData ? "public" : network === "testnet" ? "testnet" : "public";
2635
2820
  const explorerUrl = hash ? `https://stellar.expert/explorer/${explorerNetwork}/tx/${hash}` : null;
2636
- const isInProgress = transaction.step === "building" || transaction.step === "signing";
2821
+ const IN_FLIGHT_STEPS2 = [
2822
+ "building",
2823
+ "signing",
2824
+ "submitting",
2825
+ "submitted",
2826
+ "signing-submitting",
2827
+ "building-signing-submitting"
2828
+ ];
2829
+ const isInProgress = IN_FLIGHT_STEPS2.includes(transaction.step);
2637
2830
  const showBack = step === "tx" && (transaction.step === "error" || transaction.step === "success") && !isInProgress;
2638
- const txTitle = transaction.step === "signing" ? "Sending\u2026" : transaction.step === "success" ? "Sent!" : transaction.step === "error" ? "Send failed" : "Confirm Send";
2831
+ const txTitle = isInProgress ? "Sending\u2026" : transaction.step === "success" ? "Sent!" : transaction.step === "error" ? "Send failed" : "Confirm Send";
2639
2832
  async function handleSubmit() {
2640
2833
  setFormError("");
2641
2834
  if (!selectedAsset) {
@@ -2667,7 +2860,11 @@ function SendModal({ onClose }) {
2667
2860
  if (!hash) return;
2668
2861
  navigator.clipboard.writeText(hash).then(() => {
2669
2862
  setCopied(true);
2670
- setTimeout(() => setCopied(false), 2e3);
2863
+ if (copyTimerRef.current !== null) clearTimeout(copyTimerRef.current);
2864
+ copyTimerRef.current = setTimeout(() => {
2865
+ copyTimerRef.current = null;
2866
+ setCopied(false);
2867
+ }, 2e3);
2671
2868
  });
2672
2869
  }
2673
2870
  async function handleRetry() {
@@ -2817,16 +3014,7 @@ function SessionsModalTemplate({
2817
3014
  "aria-hidden": true,
2818
3015
  children: [
2819
3016
  /* @__PURE__ */ jsx("path", { d: "M11.5 6.5a5 5 0 11-1.5-3.536", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" }),
2820
- /* @__PURE__ */ jsx(
2821
- "path",
2822
- {
2823
- d: "M10 1v3h-3",
2824
- stroke: "currentColor",
2825
- strokeWidth: "1.5",
2826
- strokeLinecap: "round",
2827
- strokeLinejoin: "round"
2828
- }
2829
- )
3017
+ /* @__PURE__ */ jsx("path", { d: "M10 1v3h-3", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })
2830
3018
  ]
2831
3019
  }
2832
3020
  ),
@@ -2894,9 +3082,12 @@ function SessionsModal({ onClose }) {
2894
3082
  const [revokingFamilyId, setRevokingFamilyId] = useState(null);
2895
3083
  const [signingOutEverywhere, setSigningOutEverywhere] = useState(false);
2896
3084
  const mountedRef = useRef(true);
2897
- useEffect(() => () => {
2898
- mountedRef.current = false;
2899
- }, []);
3085
+ useEffect(
3086
+ () => () => {
3087
+ mountedRef.current = false;
3088
+ },
3089
+ []
3090
+ );
2900
3091
  const onCloseRef = useRef(onClose);
2901
3092
  onCloseRef.current = onClose;
2902
3093
  useEffect(() => {
@@ -2928,9 +3119,7 @@ function SessionsModal({ onClose }) {
2928
3119
  await load();
2929
3120
  } catch {
2930
3121
  if (!mountedRef.current) return;
2931
- setState(
2932
- (prev) => prev.step === "loaded" ? { step: "error", message: "Failed to revoke session" } : prev
2933
- );
3122
+ setState((prev) => prev.step === "loaded" ? { step: "error", message: "Failed to revoke session" } : prev);
2934
3123
  } finally {
2935
3124
  if (mountedRef.current) setRevokingFamilyId(null);
2936
3125
  }
@@ -2994,55 +3183,53 @@ function TransactionModalTemplate({
2994
3183
  "--pollar-input-border-radius": "0.5rem",
2995
3184
  "--pollar-card-border-radius": "10px"
2996
3185
  };
2997
- return /* @__PURE__ */ jsxs(
2998
- "div",
2999
- {
3000
- className: "pollar-modal-card pollar-tx-modal",
3001
- "data-theme": theme,
3002
- style: cssVars,
3003
- onClick: (e) => e.stopPropagation(),
3004
- children: [
3005
- /* @__PURE__ */ jsx("div", { className: "pollar-modal-header", children: /* @__PURE__ */ jsx("h2", { className: "pollar-modal-title", children: "Transaction" }) }),
3006
- /* @__PURE__ */ jsx("button", { type: "button", className: "pollar-close-btn", onClick: onClose, "aria-label": "Close", children: /* @__PURE__ */ jsx(
3007
- "svg",
3008
- {
3009
- width: "18",
3010
- height: "18",
3011
- viewBox: "0 0 24 24",
3012
- fill: "none",
3013
- stroke: "currentColor",
3014
- strokeWidth: "2.5",
3015
- strokeLinecap: "round",
3016
- strokeLinejoin: "round",
3017
- "aria-hidden": true,
3018
- children: /* @__PURE__ */ jsx("path", { d: "M18 6L6 18M6 6l12 12" })
3019
- }
3020
- ) }),
3021
- /* @__PURE__ */ jsx(
3022
- TxStatusView,
3023
- {
3024
- transaction,
3025
- showXdr,
3026
- copied,
3027
- explorerUrl,
3028
- walletType,
3029
- onSignAndSend,
3030
- onToggleXdr,
3031
- onCopyHash,
3032
- onRetry,
3033
- onDone: onClose
3034
- }
3035
- ),
3036
- /* @__PURE__ */ jsx(PollarModalFooter, {})
3037
- ]
3038
- }
3039
- );
3186
+ return /* @__PURE__ */ jsxs("div", { className: "pollar-modal-card pollar-tx-modal", "data-theme": theme, style: cssVars, onClick: (e) => e.stopPropagation(), children: [
3187
+ /* @__PURE__ */ jsx("div", { className: "pollar-modal-header", children: /* @__PURE__ */ jsx("h2", { className: "pollar-modal-title", children: "Transaction" }) }),
3188
+ /* @__PURE__ */ jsx("button", { type: "button", className: "pollar-close-btn", onClick: onClose, "aria-label": "Close", children: /* @__PURE__ */ jsx(
3189
+ "svg",
3190
+ {
3191
+ width: "18",
3192
+ height: "18",
3193
+ viewBox: "0 0 24 24",
3194
+ fill: "none",
3195
+ stroke: "currentColor",
3196
+ strokeWidth: "2.5",
3197
+ strokeLinecap: "round",
3198
+ strokeLinejoin: "round",
3199
+ "aria-hidden": true,
3200
+ children: /* @__PURE__ */ jsx("path", { d: "M18 6L6 18M6 6l12 12" })
3201
+ }
3202
+ ) }),
3203
+ /* @__PURE__ */ jsx(
3204
+ TxStatusView,
3205
+ {
3206
+ transaction,
3207
+ showXdr,
3208
+ copied,
3209
+ explorerUrl,
3210
+ walletType,
3211
+ onSignAndSend,
3212
+ onToggleXdr,
3213
+ onCopyHash,
3214
+ onRetry,
3215
+ onDone: onClose
3216
+ }
3217
+ ),
3218
+ /* @__PURE__ */ jsx(PollarModalFooter, {})
3219
+ ] });
3040
3220
  }
3041
3221
  function TransactionModal({ onClose }) {
3042
3222
  const { getClient, styles, tx: transaction, network, walletType } = usePollar();
3043
3223
  const { theme = "light", accentColor = "#005DB4" } = styles;
3044
3224
  const [showXdr, setShowXdr] = useState(false);
3045
3225
  const [copied, setCopied] = useState(false);
3226
+ const copyTimerRef = useRef(null);
3227
+ useEffect(
3228
+ () => () => {
3229
+ if (copyTimerRef.current !== null) clearTimeout(copyTimerRef.current);
3230
+ },
3231
+ []
3232
+ );
3046
3233
  const hash = transaction.step === "success" ? transaction.hash : null;
3047
3234
  const buildData = "buildData" in transaction ? transaction.buildData : null;
3048
3235
  const explorerNetwork = buildData?.summary.network?.toLowerCase().includes("testnet") ? "testnet" : buildData ? "public" : network === "testnet" ? "testnet" : "public";
@@ -3056,7 +3243,11 @@ function TransactionModal({ onClose }) {
3056
3243
  if (!hash) return;
3057
3244
  navigator.clipboard.writeText(hash).then(() => {
3058
3245
  setCopied(true);
3059
- setTimeout(() => setCopied(false), 2e3);
3246
+ if (copyTimerRef.current !== null) clearTimeout(copyTimerRef.current);
3247
+ copyTimerRef.current = setTimeout(() => {
3248
+ copyTimerRef.current = null;
3249
+ setCopied(false);
3250
+ }, 2e3);
3060
3251
  });
3061
3252
  }
3062
3253
  async function handleRetry() {
@@ -3123,97 +3314,128 @@ function TxHistoryModalTemplate({
3123
3314
  const hasPrev = offset > 0;
3124
3315
  const hasNext = offset + PAGE_SIZE < total;
3125
3316
  const showPagination = txHistory.step === "loaded" && total > PAGE_SIZE;
3126
- return /* @__PURE__ */ jsxs("div", { className: "pollar-modal-card pollar-hist-modal", "data-theme": theme, style: cssVars, onClick: (e) => e.stopPropagation(), children: [
3127
- /* @__PURE__ */ jsxs("div", { className: "pollar-modal-header", children: [
3128
- /* @__PURE__ */ jsx("h2", { className: "pollar-modal-title", children: "Transaction History" }),
3129
- /* @__PURE__ */ jsxs("div", { className: "pollar-modal-header-actions", children: [
3130
- /* @__PURE__ */ jsxs("button", { className: "pollar-modal-refresh-btn", onClick: onRefresh, disabled: isLoading, children: [
3131
- /* @__PURE__ */ jsxs(
3132
- "svg",
3133
- {
3134
- className: `pollar-modal-refresh-icon${isLoading ? " spinning" : ""}`,
3135
- width: "13",
3136
- height: "13",
3137
- viewBox: "0 0 13 13",
3138
- fill: "none",
3139
- "aria-hidden": true,
3140
- children: [
3141
- /* @__PURE__ */ jsx(
3142
- "path",
3317
+ return /* @__PURE__ */ jsxs(
3318
+ "div",
3319
+ {
3320
+ className: "pollar-modal-card pollar-hist-modal",
3321
+ "data-theme": theme,
3322
+ style: cssVars,
3323
+ onClick: (e) => e.stopPropagation(),
3324
+ children: [
3325
+ /* @__PURE__ */ jsxs("div", { className: "pollar-modal-header", children: [
3326
+ /* @__PURE__ */ jsx("h2", { className: "pollar-modal-title", children: "Transaction History" }),
3327
+ /* @__PURE__ */ jsxs("div", { className: "pollar-modal-header-actions", children: [
3328
+ /* @__PURE__ */ jsxs("button", { className: "pollar-modal-refresh-btn", onClick: onRefresh, disabled: isLoading, children: [
3329
+ /* @__PURE__ */ jsxs(
3330
+ "svg",
3331
+ {
3332
+ className: `pollar-modal-refresh-icon${isLoading ? " spinning" : ""}`,
3333
+ width: "13",
3334
+ height: "13",
3335
+ viewBox: "0 0 13 13",
3336
+ fill: "none",
3337
+ "aria-hidden": true,
3338
+ children: [
3339
+ /* @__PURE__ */ jsx("path", { d: "M11.5 6.5a5 5 0 11-1.5-3.536", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" }),
3340
+ /* @__PURE__ */ jsx("path", { d: "M10 1v3h-3", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })
3341
+ ]
3342
+ }
3343
+ ),
3344
+ "Refresh"
3345
+ ] }),
3346
+ /* @__PURE__ */ jsx("button", { className: "pollar-modal-close", onClick: onClose, "aria-label": "Close", children: /* @__PURE__ */ jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsx("path", { d: "M2 2l12 12M14 2L2 14", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) }) })
3347
+ ] })
3348
+ ] }),
3349
+ /* @__PURE__ */ jsxs("div", { className: "pollar-hist-list", children: [
3350
+ txHistory.step === "idle" && /* @__PURE__ */ jsx("div", { className: "pollar-modal-empty", children: "Click Refresh to load transactions." }),
3351
+ isLoading && /* @__PURE__ */ jsx("div", { className: "pollar-modal-empty", children: "Loading\u2026" }),
3352
+ txHistory.step === "error" && /* @__PURE__ */ jsx("div", { className: "pollar-modal-empty", children: txHistory.message }),
3353
+ txHistory.step === "loaded" && records.length === 0 && /* @__PURE__ */ jsx("div", { className: "pollar-modal-empty", children: "No transactions yet." }),
3354
+ records.map((record) => {
3355
+ const explorerUrl = `https://stellar.expert/explorer/${record.network === "testnet" ? "testnet" : "public"}/tx/${record.hash}`;
3356
+ return /* @__PURE__ */ jsxs("div", { className: "pollar-hist-item", children: [
3357
+ /* @__PURE__ */ jsx("span", { className: "pollar-hist-item-summary", children: record.summary }),
3358
+ /* @__PURE__ */ jsx(StatusBadge, { status: record.status }),
3359
+ /* @__PURE__ */ jsxs("span", { className: "pollar-hist-item-meta", children: [
3360
+ /* @__PURE__ */ jsx("span", { children: record.operation }),
3361
+ record.feeXlm && /* @__PURE__ */ jsxs("span", { children: [
3362
+ "\xB7 ",
3363
+ record.feeXlm,
3364
+ " XLM"
3365
+ ] }),
3366
+ /* @__PURE__ */ jsxs("span", { children: [
3367
+ "\xB7 ",
3368
+ formatDate(record.createdAt)
3369
+ ] }),
3370
+ /* @__PURE__ */ jsx("span", { children: "\xB7" }),
3371
+ /* @__PURE__ */ jsxs(
3372
+ "a",
3143
3373
  {
3144
- d: "M11.5 6.5a5 5 0 11-1.5-3.536",
3145
- stroke: "currentColor",
3146
- strokeWidth: "1.5",
3147
- strokeLinecap: "round"
3374
+ className: "pollar-hist-item-explorer",
3375
+ href: explorerUrl,
3376
+ target: "_blank",
3377
+ rel: "noopener noreferrer",
3378
+ "aria-label": "View on Stellar Explorer",
3379
+ children: [
3380
+ /* @__PURE__ */ jsxs("svg", { width: "11", height: "11", viewBox: "0 0 13 13", fill: "none", "aria-hidden": true, children: [
3381
+ /* @__PURE__ */ jsx(
3382
+ "path",
3383
+ {
3384
+ d: "M5 2H2a1 1 0 00-1 1v8a1 1 0 001 1h8a1 1 0 001-1V8",
3385
+ stroke: "currentColor",
3386
+ strokeWidth: "1.5",
3387
+ strokeLinecap: "round"
3388
+ }
3389
+ ),
3390
+ /* @__PURE__ */ jsx(
3391
+ "path",
3392
+ {
3393
+ d: "M8 1h4m0 0v4m0-4L6 7",
3394
+ stroke: "currentColor",
3395
+ strokeWidth: "1.5",
3396
+ strokeLinecap: "round",
3397
+ strokeLinejoin: "round"
3398
+ }
3399
+ )
3400
+ ] }),
3401
+ "Explorer"
3402
+ ]
3148
3403
  }
3149
- ),
3150
- /* @__PURE__ */ jsx("path", { d: "M10 1v3h-3", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })
3151
- ]
3152
- }
3153
- ),
3154
- "Refresh"
3404
+ )
3405
+ ] })
3406
+ ] }, record.id);
3407
+ })
3155
3408
  ] }),
3156
- /* @__PURE__ */ jsx("button", { className: "pollar-modal-close", onClick: onClose, "aria-label": "Close", children: /* @__PURE__ */ jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsx("path", { d: "M2 2l12 12M14 2L2 14", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) }) })
3157
- ] })
3158
- ] }),
3159
- /* @__PURE__ */ jsxs("div", { className: "pollar-hist-list", children: [
3160
- txHistory.step === "idle" && /* @__PURE__ */ jsx("div", { className: "pollar-modal-empty", children: "Click Refresh to load transactions." }),
3161
- isLoading && /* @__PURE__ */ jsx("div", { className: "pollar-modal-empty", children: "Loading\u2026" }),
3162
- txHistory.step === "error" && /* @__PURE__ */ jsx("div", { className: "pollar-modal-empty", children: txHistory.message }),
3163
- txHistory.step === "loaded" && records.length === 0 && /* @__PURE__ */ jsx("div", { className: "pollar-modal-empty", children: "No transactions yet." }),
3164
- records.map((record) => {
3165
- const explorerUrl = `https://stellar.expert/explorer/${record.network === "testnet" ? "testnet" : "public"}/tx/${record.hash}`;
3166
- return /* @__PURE__ */ jsxs("div", { className: "pollar-hist-item", children: [
3167
- /* @__PURE__ */ jsx("span", { className: "pollar-hist-item-summary", children: record.summary }),
3168
- /* @__PURE__ */ jsx(StatusBadge, { status: record.status }),
3169
- /* @__PURE__ */ jsxs("span", { className: "pollar-hist-item-meta", children: [
3170
- /* @__PURE__ */ jsx("span", { children: record.operation }),
3171
- record.feeXlm && /* @__PURE__ */ jsxs("span", { children: [
3172
- "\xB7 ",
3173
- record.feeXlm,
3174
- " XLM"
3175
- ] }),
3176
- /* @__PURE__ */ jsxs("span", { children: [
3177
- "\xB7 ",
3178
- formatDate(record.createdAt)
3179
- ] }),
3180
- /* @__PURE__ */ jsx("span", { children: "\xB7" }),
3181
- /* @__PURE__ */ jsxs("a", { className: "pollar-hist-item-explorer", href: explorerUrl, target: "_blank", rel: "noopener noreferrer", "aria-label": "View on Stellar Explorer", children: [
3182
- /* @__PURE__ */ jsxs("svg", { width: "11", height: "11", viewBox: "0 0 13 13", fill: "none", "aria-hidden": true, children: [
3183
- /* @__PURE__ */ jsx("path", { d: "M5 2H2a1 1 0 00-1 1v8a1 1 0 001 1h8a1 1 0 001-1V8", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" }),
3184
- /* @__PURE__ */ jsx("path", { d: "M8 1h4m0 0v4m0-4L6 7", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })
3185
- ] }),
3186
- "Explorer"
3187
- ] })
3409
+ showPagination && /* @__PURE__ */ jsxs("div", { className: "pollar-hist-pagination", children: [
3410
+ /* @__PURE__ */ jsxs("span", { className: "pollar-hist-pagination-info", children: [
3411
+ offset + 1,
3412
+ "\u2013",
3413
+ Math.min(offset + PAGE_SIZE, total),
3414
+ " of ",
3415
+ total
3416
+ ] }),
3417
+ /* @__PURE__ */ jsxs("div", { className: "pollar-hist-pagination-btns", children: [
3418
+ /* @__PURE__ */ jsx("button", { className: "pollar-hist-page-btn", onClick: onPrev, disabled: !hasPrev, children: "\u2190 Prev" }),
3419
+ /* @__PURE__ */ jsx("button", { className: "pollar-hist-page-btn", onClick: onNext, disabled: !hasNext, children: "Next \u2192" })
3188
3420
  ] })
3189
- ] }, record.id);
3190
- })
3191
- ] }),
3192
- showPagination && /* @__PURE__ */ jsxs("div", { className: "pollar-hist-pagination", children: [
3193
- /* @__PURE__ */ jsxs("span", { className: "pollar-hist-pagination-info", children: [
3194
- offset + 1,
3195
- "\u2013",
3196
- Math.min(offset + PAGE_SIZE, total),
3197
- " of ",
3198
- total
3199
- ] }),
3200
- /* @__PURE__ */ jsxs("div", { className: "pollar-hist-pagination-btns", children: [
3201
- /* @__PURE__ */ jsx("button", { className: "pollar-hist-page-btn", onClick: onPrev, disabled: !hasPrev, children: "\u2190 Prev" }),
3202
- /* @__PURE__ */ jsx("button", { className: "pollar-hist-page-btn", onClick: onNext, disabled: !hasNext, children: "Next \u2192" })
3203
- ] })
3204
- ] }),
3205
- /* @__PURE__ */ jsx(PollarModalFooter, {})
3206
- ] });
3421
+ ] }),
3422
+ /* @__PURE__ */ jsx(PollarModalFooter, {})
3423
+ ]
3424
+ }
3425
+ );
3207
3426
  }
3208
3427
  var PAGE_SIZE2 = 10;
3209
3428
  function TxHistoryModal({ onClose }) {
3210
3429
  const { getClient, styles, txHistory } = usePollar();
3211
3430
  const { theme = "light", accentColor = "#005DB4" } = styles;
3212
3431
  const [offset, setOffset] = useState(0);
3213
- const load = useCallback((nextOffset) => {
3214
- setOffset(nextOffset);
3215
- void getClient().fetchTxHistory({ limit: PAGE_SIZE2, offset: nextOffset });
3216
- }, [getClient]);
3432
+ const load = useCallback(
3433
+ (nextOffset) => {
3434
+ setOffset(nextOffset);
3435
+ void getClient().fetchTxHistory({ limit: PAGE_SIZE2, offset: nextOffset });
3436
+ },
3437
+ [getClient]
3438
+ );
3217
3439
  useEffect(() => {
3218
3440
  load(0);
3219
3441
  }, [load]);
@@ -3336,28 +3558,31 @@ function WalletBalanceModal({ onClose }) {
3336
3558
  }
3337
3559
  ) });
3338
3560
  }
3339
- var emptyResponse = {
3340
- application: {
3341
- name: ""
3342
- },
3561
+ var DEFAULT_APP_CONFIG = {
3562
+ application: { name: "" },
3343
3563
  styles: {}
3344
3564
  };
3345
- async function fetchRemoteConfig(client) {
3346
- const content = await client.getAppConfig();
3347
- return content ?? emptyResponse;
3565
+ function sessionsEqual(a, b) {
3566
+ if (a === b) return true;
3567
+ if (!a || !b) return false;
3568
+ return a.clientSessionId === b.clientSessionId && a.userId === b.userId && a.status === b.status && a.token?.accessToken === b.token?.accessToken && a.token?.refreshToken === b.token?.refreshToken && a.token?.expiresAt === b.token?.expiresAt && a.wallet?.publicKey === b.wallet?.publicKey;
3348
3569
  }
3349
3570
  var PollarContext = createContext(null);
3350
- function PollarProvider({ config, styles: propStyles, adapters, children }) {
3351
- const [pollarClient] = useState(() => new PollarClient(config));
3571
+ function PollarProvider({
3572
+ client,
3573
+ appConfig: appConfigProp,
3574
+ ui,
3575
+ adapters,
3576
+ onStorageDegrade,
3577
+ children
3578
+ }) {
3579
+ const [pollarClient] = useState(() => client instanceof PollarClient ? client : new PollarClient(client));
3352
3580
  const [networkState, setNetworkState] = useState(() => pollarClient.getNetworkState());
3353
3581
  const [sessionState, setSessionState] = useState(null);
3354
3582
  const [transaction, setTransaction] = useState({ step: "idle" });
3355
3583
  const [txHistory, setTxHistory] = useState({ step: "idle" });
3356
3584
  const [walletBalance, setWalletBalance] = useState({ step: "idle" });
3357
- const [remoteConfig, setRemoteConfig] = useState(emptyResponse);
3358
- const [styles, setStyles] = useState(propStyles ?? {});
3359
- const propStylesRef = useRef(propStyles);
3360
- propStylesRef.current = propStyles;
3585
+ const [resolvedConfig, setResolvedConfig] = useState(() => appConfigProp ?? DEFAULT_APP_CONFIG);
3361
3586
  useEffect(() => {
3362
3587
  return pollarClient.onTransactionStateChange(setTransaction);
3363
3588
  }, [pollarClient]);
@@ -3372,28 +3597,32 @@ function PollarProvider({ config, styles: propStyles, adapters, children }) {
3372
3597
  setNetworkState(state);
3373
3598
  });
3374
3599
  }, [pollarClient]);
3600
+ useEffect(() => {
3601
+ if (!onStorageDegrade) return;
3602
+ return pollarClient.onStorageDegrade(onStorageDegrade);
3603
+ }, [pollarClient, onStorageDegrade]);
3375
3604
  useEffect(() => {
3376
3605
  return pollarClient.onAuthStateChange((authState) => {
3377
3606
  if (authState.step === "authenticated") {
3378
- setSessionState((prev) => JSON.stringify(prev) !== JSON.stringify(authState.session) ? authState.session : prev);
3607
+ setSessionState((prev) => sessionsEqual(prev, authState.session) ? prev : authState.session);
3379
3608
  } else if (authState.step === "idle") {
3380
3609
  setSessionState(null);
3381
3610
  }
3382
3611
  });
3383
3612
  }, [pollarClient]);
3384
3613
  useEffect(() => {
3385
- const propStyles2 = propStylesRef.current;
3386
- fetchRemoteConfig(pollarClient).then((fetched) => {
3387
- setRemoteConfig(fetched);
3388
- setStyles({
3389
- ...fetched.styles,
3390
- ...propStyles2,
3391
- providers: { ...fetched.styles?.providers, ...propStyles2?.providers }
3392
- });
3393
- }).catch(() => {
3394
- setStyles(propStyles2 ?? {});
3614
+ if (appConfigProp !== void 0) return;
3615
+ let cancelled = false;
3616
+ pollarClient.getAppConfig().then((fetched) => {
3617
+ if (cancelled || !fetched) return;
3618
+ setResolvedConfig(fetched);
3619
+ }).catch((err) => {
3620
+ console.error("[PollarProvider] getAppConfig failed", err);
3395
3621
  });
3396
- }, [pollarClient]);
3622
+ return () => {
3623
+ cancelled = true;
3624
+ };
3625
+ }, [pollarClient, appConfigProp]);
3397
3626
  const [loginModalOpen, setLoginModalOpen] = useState(false);
3398
3627
  const [transactionModalOpen, setTransactionModalOpen] = useState(false);
3399
3628
  const [kycModalOpen, setKycModalOpen] = useState(false);
@@ -3405,13 +3634,13 @@ function PollarProvider({ config, styles: propStyles, adapters, children }) {
3405
3634
  const [receiveModalOpen, setReceiveModalOpen] = useState(false);
3406
3635
  const [sessionsModalOpen, setSessionsModalOpen] = useState(false);
3407
3636
  const [distributionRulesModalOpen, setDistributionRulesModalOpen] = useState(false);
3408
- const adaptersRef = useRef(adapters);
3409
- adaptersRef.current = adapters;
3410
3637
  const walletAddress = sessionState?.wallet?.publicKey || "";
3411
3638
  const getClient = useCallback(() => pollarClient, [pollarClient]);
3412
3639
  const refreshWalletBalance = useCallback(() => pollarClient.refreshBalance(walletAddress), [pollarClient, walletAddress]);
3413
- const contextValue = useMemo(
3414
- () => ({
3640
+ const renderWallets = ui?.renderWallets;
3641
+ const contextValue = useMemo(() => {
3642
+ const styles = resolvedConfig.styles ?? {};
3643
+ return {
3415
3644
  // session
3416
3645
  walletAddress,
3417
3646
  isAuthenticated: !!walletAddress,
@@ -3426,6 +3655,10 @@ function PollarProvider({ config, styles: propStyles, adapters, children }) {
3426
3655
  tx: transaction,
3427
3656
  buildTx: (operation, params, options) => pollarClient.buildTx(operation, params, options),
3428
3657
  signAndSubmitTx: (unsignedXdr) => pollarClient.signAndSubmitTx(unsignedXdr),
3658
+ signTx: (unsignedXdr) => pollarClient.signTx(unsignedXdr),
3659
+ submitTx: (signedXdr) => pollarClient.submitTx(signedXdr),
3660
+ buildAndSignAndSubmitTx: (operation, params, options) => pollarClient.buildAndSignAndSubmitTx(operation, params, options),
3661
+ runTx: (operation, params, options) => pollarClient.runTx(operation, params, options),
3429
3662
  openTxModal: () => setTransactionModalOpen(true),
3430
3663
  // tx history
3431
3664
  txHistory,
@@ -3452,23 +3685,24 @@ function PollarProvider({ config, styles: propStyles, adapters, children }) {
3452
3685
  // ramp
3453
3686
  openRampModal: () => setRampModalOpen(true),
3454
3687
  // config
3455
- appConfig: remoteConfig,
3688
+ appConfig: resolvedConfig,
3456
3689
  styles,
3457
- adapters: adaptersRef.current
3458
- }),
3459
- [
3460
- walletAddress,
3461
- pollarClient,
3462
- getClient,
3463
- transaction,
3464
- txHistory,
3465
- walletBalance,
3466
- refreshWalletBalance,
3467
- networkState,
3468
- remoteConfig,
3469
- styles
3470
- ]
3471
- );
3690
+ renderWallets,
3691
+ adapters
3692
+ };
3693
+ }, [
3694
+ walletAddress,
3695
+ pollarClient,
3696
+ getClient,
3697
+ transaction,
3698
+ txHistory,
3699
+ walletBalance,
3700
+ refreshWalletBalance,
3701
+ networkState,
3702
+ resolvedConfig,
3703
+ adapters,
3704
+ renderWallets
3705
+ ]);
3472
3706
  return /* @__PURE__ */ jsxs(PollarContext.Provider, { value: contextValue, children: [
3473
3707
  children,
3474
3708
  loginModalOpen && /* @__PURE__ */ jsx(ModalErrorBoundary, { onClose: () => setLoginModalOpen(false), children: /* @__PURE__ */ jsx(LoginModal, { onClose: () => setLoginModalOpen(false) }) }),
@@ -3512,7 +3746,7 @@ function createPollarAdapterHook(key) {
3512
3746
  name,
3513
3747
  async (params) => {
3514
3748
  const { unsignedTransaction } = await fn(params);
3515
- await signAndSubmitTx(unsignedTransaction);
3749
+ return signAndSubmitTx(unsignedTransaction);
3516
3750
  }
3517
3751
  ])
3518
3752
  );
@@ -3561,33 +3795,22 @@ function WalletButtonTemplate({
3561
3795
  "aria-busy": isInProgress,
3562
3796
  children: [
3563
3797
  /* @__PURE__ */ jsx("span", { className: "wallet-btn-label", children: cropWallet(walletAddress) }),
3564
- isInProgress ? /* @__PURE__ */ jsxs(
3565
- "svg",
3566
- {
3567
- className: "wallet-btn-spinner",
3568
- viewBox: "0 0 12 12",
3569
- width: "12",
3570
- height: "12",
3571
- fill: "none",
3572
- "aria-hidden": true,
3573
- children: [
3574
- /* @__PURE__ */ jsx("circle", { cx: "6", cy: "6", r: "4.5", stroke: "rgba(255,255,255,0.35)", strokeWidth: "1.5" }),
3575
- /* @__PURE__ */ jsx(
3576
- "circle",
3577
- {
3578
- cx: "6",
3579
- cy: "6",
3580
- r: "4.5",
3581
- stroke: "white",
3582
- strokeWidth: "1.5",
3583
- strokeLinecap: "round",
3584
- strokeDasharray: "14 9",
3585
- transform: "rotate(-90 6 6)"
3586
- }
3587
- )
3588
- ]
3589
- }
3590
- ) : /* @__PURE__ */ jsx(
3798
+ isInProgress ? /* @__PURE__ */ jsxs("svg", { className: "wallet-btn-spinner", viewBox: "0 0 12 12", width: "12", height: "12", fill: "none", "aria-hidden": true, children: [
3799
+ /* @__PURE__ */ jsx("circle", { cx: "6", cy: "6", r: "4.5", stroke: "rgba(255,255,255,0.35)", strokeWidth: "1.5" }),
3800
+ /* @__PURE__ */ jsx(
3801
+ "circle",
3802
+ {
3803
+ cx: "6",
3804
+ cy: "6",
3805
+ r: "4.5",
3806
+ stroke: "white",
3807
+ strokeWidth: "1.5",
3808
+ strokeLinecap: "round",
3809
+ strokeDasharray: "14 9",
3810
+ transform: "rotate(-90 6 6)"
3811
+ }
3812
+ )
3813
+ ] }) : /* @__PURE__ */ jsx(
3591
3814
  "svg",
3592
3815
  {
3593
3816
  className: `wallet-chevron${open ? " open" : ""}`,
@@ -3605,53 +3828,131 @@ function WalletButtonTemplate({
3605
3828
  ),
3606
3829
  open && /* @__PURE__ */ jsxs("div", { className: "wallet-dropdown", style: { backgroundColor: dropdownBg, borderColor: dropdownBorder }, children: [
3607
3830
  /* @__PURE__ */ jsxs("button", { className: "wallet-dropdown-item", style: { color: itemColor }, onClick: onSend, children: [
3608
- /* @__PURE__ */ jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
3609
- /* @__PURE__ */ jsx("line", { x1: "22", y1: "2", x2: "11", y2: "13" }),
3610
- /* @__PURE__ */ jsx("polygon", { points: "22 2 15 22 11 13 2 9 22 2" })
3611
- ] }),
3831
+ /* @__PURE__ */ jsxs(
3832
+ "svg",
3833
+ {
3834
+ width: "14",
3835
+ height: "14",
3836
+ viewBox: "0 0 24 24",
3837
+ fill: "none",
3838
+ stroke: "currentColor",
3839
+ strokeWidth: "2",
3840
+ strokeLinecap: "round",
3841
+ strokeLinejoin: "round",
3842
+ children: [
3843
+ /* @__PURE__ */ jsx("line", { x1: "22", y1: "2", x2: "11", y2: "13" }),
3844
+ /* @__PURE__ */ jsx("polygon", { points: "22 2 15 22 11 13 2 9 22 2" })
3845
+ ]
3846
+ }
3847
+ ),
3612
3848
  "Send"
3613
3849
  ] }),
3614
3850
  /* @__PURE__ */ jsxs("button", { className: "wallet-dropdown-item", style: { color: itemColor }, onClick: onReceive, children: [
3615
- /* @__PURE__ */ jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
3616
- /* @__PURE__ */ jsx("polyline", { points: "8 17 12 21 16 17" }),
3617
- /* @__PURE__ */ jsx("line", { x1: "12", y1: "12", x2: "12", y2: "21" }),
3618
- /* @__PURE__ */ jsx("path", { d: "M20.88 18.09A5 5 0 0 0 18 9h-1.26A8 8 0 1 0 3 16.29" })
3619
- ] }),
3851
+ /* @__PURE__ */ jsxs(
3852
+ "svg",
3853
+ {
3854
+ width: "14",
3855
+ height: "14",
3856
+ viewBox: "0 0 24 24",
3857
+ fill: "none",
3858
+ stroke: "currentColor",
3859
+ strokeWidth: "2",
3860
+ strokeLinecap: "round",
3861
+ strokeLinejoin: "round",
3862
+ children: [
3863
+ /* @__PURE__ */ jsx("polyline", { points: "8 17 12 21 16 17" }),
3864
+ /* @__PURE__ */ jsx("line", { x1: "12", y1: "12", x2: "12", y2: "21" }),
3865
+ /* @__PURE__ */ jsx("path", { d: "M20.88 18.09A5 5 0 0 0 18 9h-1.26A8 8 0 1 0 3 16.29" })
3866
+ ]
3867
+ }
3868
+ ),
3620
3869
  "Receive"
3621
3870
  ] }),
3622
3871
  /* @__PURE__ */ jsx("div", { className: "wallet-dropdown-divider" }),
3623
3872
  /* @__PURE__ */ jsxs("button", { className: "wallet-dropdown-item", style: { color: itemColor }, onClick: onCopy, children: [
3624
- /* @__PURE__ */ jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
3625
- /* @__PURE__ */ jsx("rect", { x: "9", y: "9", width: "13", height: "13", rx: "2" }),
3626
- /* @__PURE__ */ jsx("path", { d: "M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" })
3627
- ] }),
3873
+ /* @__PURE__ */ jsxs(
3874
+ "svg",
3875
+ {
3876
+ width: "14",
3877
+ height: "14",
3878
+ viewBox: "0 0 24 24",
3879
+ fill: "none",
3880
+ stroke: "currentColor",
3881
+ strokeWidth: "2",
3882
+ strokeLinecap: "round",
3883
+ strokeLinejoin: "round",
3884
+ children: [
3885
+ /* @__PURE__ */ jsx("rect", { x: "9", y: "9", width: "13", height: "13", rx: "2" }),
3886
+ /* @__PURE__ */ jsx("path", { d: "M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" })
3887
+ ]
3888
+ }
3889
+ ),
3628
3890
  copied ? "Copied!" : "Copy address"
3629
3891
  ] }),
3630
3892
  /* @__PURE__ */ jsxs("button", { className: "wallet-dropdown-item", style: { color: itemColor }, onClick: onWalletBalance, children: [
3631
- /* @__PURE__ */ jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
3632
- /* @__PURE__ */ jsx("rect", { x: "1", y: "4", width: "22", height: "16", rx: "2", ry: "2" }),
3633
- /* @__PURE__ */ jsx("circle", { cx: "16", cy: "12", r: "2" }),
3634
- /* @__PURE__ */ jsx("path", { d: "M22 8H12" })
3635
- ] }),
3893
+ /* @__PURE__ */ jsxs(
3894
+ "svg",
3895
+ {
3896
+ width: "14",
3897
+ height: "14",
3898
+ viewBox: "0 0 24 24",
3899
+ fill: "none",
3900
+ stroke: "currentColor",
3901
+ strokeWidth: "2",
3902
+ strokeLinecap: "round",
3903
+ strokeLinejoin: "round",
3904
+ children: [
3905
+ /* @__PURE__ */ jsx("rect", { x: "1", y: "4", width: "22", height: "16", rx: "2", ry: "2" }),
3906
+ /* @__PURE__ */ jsx("circle", { cx: "16", cy: "12", r: "2" }),
3907
+ /* @__PURE__ */ jsx("path", { d: "M22 8H12" })
3908
+ ]
3909
+ }
3910
+ ),
3636
3911
  "Wallet balance"
3637
3912
  ] }),
3638
3913
  /* @__PURE__ */ jsxs("button", { className: "wallet-dropdown-item", style: { color: itemColor }, onClick: onTxHistory, children: [
3639
- /* @__PURE__ */ jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
3640
- /* @__PURE__ */ jsx("path", { d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" }),
3641
- /* @__PURE__ */ jsx("polyline", { points: "14,2 14,8 20,8" }),
3642
- /* @__PURE__ */ jsx("line", { x1: "16", y1: "13", x2: "8", y2: "13" }),
3643
- /* @__PURE__ */ jsx("line", { x1: "16", y1: "17", x2: "8", y2: "17" }),
3644
- /* @__PURE__ */ jsx("polyline", { points: "10,9 9,9 8,9" })
3645
- ] }),
3914
+ /* @__PURE__ */ jsxs(
3915
+ "svg",
3916
+ {
3917
+ width: "14",
3918
+ height: "14",
3919
+ viewBox: "0 0 24 24",
3920
+ fill: "none",
3921
+ stroke: "currentColor",
3922
+ strokeWidth: "2",
3923
+ strokeLinecap: "round",
3924
+ strokeLinejoin: "round",
3925
+ children: [
3926
+ /* @__PURE__ */ jsx("path", { d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" }),
3927
+ /* @__PURE__ */ jsx("polyline", { points: "14,2 14,8 20,8" }),
3928
+ /* @__PURE__ */ jsx("line", { x1: "16", y1: "13", x2: "8", y2: "13" }),
3929
+ /* @__PURE__ */ jsx("line", { x1: "16", y1: "17", x2: "8", y2: "17" }),
3930
+ /* @__PURE__ */ jsx("polyline", { points: "10,9 9,9 8,9" })
3931
+ ]
3932
+ }
3933
+ ),
3646
3934
  "Transaction history"
3647
3935
  ] }),
3648
3936
  /* @__PURE__ */ jsx("div", { className: "wallet-dropdown-divider" }),
3649
3937
  /* @__PURE__ */ jsxs("button", { className: "wallet-dropdown-item danger", onClick: onLogout, children: [
3650
- /* @__PURE__ */ jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
3651
- /* @__PURE__ */ jsx("path", { d: "M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4" }),
3652
- /* @__PURE__ */ jsx("polyline", { points: "16,17 21,12 16,7" }),
3653
- /* @__PURE__ */ jsx("line", { x1: "21", y1: "12", x2: "9", y2: "12" })
3654
- ] }),
3938
+ /* @__PURE__ */ jsxs(
3939
+ "svg",
3940
+ {
3941
+ width: "14",
3942
+ height: "14",
3943
+ viewBox: "0 0 24 24",
3944
+ fill: "none",
3945
+ stroke: "currentColor",
3946
+ strokeWidth: "2",
3947
+ strokeLinecap: "round",
3948
+ strokeLinejoin: "round",
3949
+ children: [
3950
+ /* @__PURE__ */ jsx("path", { d: "M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4" }),
3951
+ /* @__PURE__ */ jsx("polyline", { points: "16,17 21,12 16,7" }),
3952
+ /* @__PURE__ */ jsx("line", { x1: "21", y1: "12", x2: "9", y2: "12" })
3953
+ ]
3954
+ }
3955
+ ),
3655
3956
  "Log out"
3656
3957
  ] })
3657
3958
  ] })
@@ -3673,6 +3974,7 @@ function WalletButton() {
3673
3974
  const [open, setOpen] = useState(false);
3674
3975
  const [copied, setCopied] = useState(false);
3675
3976
  const wrapperRef = useRef(null);
3977
+ const copyTimerRef = useRef(null);
3676
3978
  const isInProgress = transaction.step === "building" || transaction.step === "signing";
3677
3979
  const { theme = "light", accentColor = "#005DB4" } = styles;
3678
3980
  const isDark = theme === "dark";
@@ -3688,11 +3990,21 @@ function WalletButton() {
3688
3990
  document.addEventListener("mousedown", handleClickOutside);
3689
3991
  return () => document.removeEventListener("mousedown", handleClickOutside);
3690
3992
  }, []);
3993
+ useEffect(
3994
+ () => () => {
3995
+ if (copyTimerRef.current !== null) clearTimeout(copyTimerRef.current);
3996
+ },
3997
+ []
3998
+ );
3691
3999
  async function handleCopy() {
3692
4000
  if (!walletAddress) return;
3693
4001
  await navigator.clipboard.writeText(walletAddress);
3694
4002
  setCopied(true);
3695
- setTimeout(() => setCopied(false), 1500);
4003
+ if (copyTimerRef.current !== null) clearTimeout(copyTimerRef.current);
4004
+ copyTimerRef.current = setTimeout(() => {
4005
+ copyTimerRef.current = null;
4006
+ setCopied(false);
4007
+ }, 1500);
3696
4008
  }
3697
4009
  function handleLogout() {
3698
4010
  setOpen(false);