@pollar/react 0.6.0 → 0.7.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/README.md +202 -20
- package/dist/index.css +107 -0
- package/dist/index.css.map +1 -1
- package/dist/index.d.mts +39 -8
- package/dist/index.d.ts +39 -8
- package/dist/index.js +257 -3
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +256 -4
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -1
package/dist/index.mjs
CHANGED
|
@@ -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.
|
|
1031
|
+
"0.7.0"
|
|
1032
1032
|
] })
|
|
1033
1033
|
] })
|
|
1034
1034
|
] });
|
|
@@ -2499,6 +2499,254 @@ function SendModal({ onClose }) {
|
|
|
2499
2499
|
}
|
|
2500
2500
|
) });
|
|
2501
2501
|
}
|
|
2502
|
+
function describeDevice(s) {
|
|
2503
|
+
if (s.deviceLabel) return s.deviceLabel;
|
|
2504
|
+
if (!s.userAgent) return "Unknown device";
|
|
2505
|
+
return parseUserAgent(s.userAgent);
|
|
2506
|
+
}
|
|
2507
|
+
function detectBrowser(ua) {
|
|
2508
|
+
if (/Edg\//.test(ua)) return "Edge";
|
|
2509
|
+
if (/OPR\//.test(ua)) return "Opera";
|
|
2510
|
+
if (/(Chrome|CriOS)\//.test(ua)) return "Chrome";
|
|
2511
|
+
if (/(Firefox|FxiOS)\//.test(ua)) return "Firefox";
|
|
2512
|
+
if (/Safari\//.test(ua)) return "Safari";
|
|
2513
|
+
return null;
|
|
2514
|
+
}
|
|
2515
|
+
function detectOS(ua) {
|
|
2516
|
+
if (/iPhone|iPad|iPod/.test(ua)) return "iOS";
|
|
2517
|
+
if (/Android/.test(ua)) return "Android";
|
|
2518
|
+
if (/Mac OS X/.test(ua)) return "macOS";
|
|
2519
|
+
if (/Windows NT/.test(ua)) return "Windows";
|
|
2520
|
+
if (/Linux/.test(ua)) return "Linux";
|
|
2521
|
+
return null;
|
|
2522
|
+
}
|
|
2523
|
+
function parseUserAgent(ua) {
|
|
2524
|
+
const browser = detectBrowser(ua);
|
|
2525
|
+
const os = detectOS(ua);
|
|
2526
|
+
if (browser && os) return `${os} \u2014 ${browser}`;
|
|
2527
|
+
if (os) return os;
|
|
2528
|
+
if (browser) return browser;
|
|
2529
|
+
return ua.slice(0, 48);
|
|
2530
|
+
}
|
|
2531
|
+
function formatRelative(iso) {
|
|
2532
|
+
if (!iso) return "\u2014";
|
|
2533
|
+
const ts = new Date(iso).getTime();
|
|
2534
|
+
if (!Number.isFinite(ts)) return "\u2014";
|
|
2535
|
+
const diffSec = Math.round((Date.now() - ts) / 1e3);
|
|
2536
|
+
if (diffSec < 0) return "just now";
|
|
2537
|
+
if (diffSec < 60) return `${diffSec}s ago`;
|
|
2538
|
+
const diffMin = Math.round(diffSec / 60);
|
|
2539
|
+
if (diffMin < 60) return `${diffMin}m ago`;
|
|
2540
|
+
const diffHr = Math.round(diffMin / 60);
|
|
2541
|
+
if (diffHr < 24) return `${diffHr}h ago`;
|
|
2542
|
+
const diffDay = Math.round(diffHr / 24);
|
|
2543
|
+
if (diffDay < 30) return `${diffDay}d ago`;
|
|
2544
|
+
return new Date(iso).toLocaleDateString(void 0, { month: "short", day: "numeric", year: "numeric" });
|
|
2545
|
+
}
|
|
2546
|
+
function shortIp(hash) {
|
|
2547
|
+
if (!hash) return "";
|
|
2548
|
+
return hash.slice(0, 8);
|
|
2549
|
+
}
|
|
2550
|
+
function SessionsModalTemplate({
|
|
2551
|
+
theme,
|
|
2552
|
+
accentColor,
|
|
2553
|
+
state,
|
|
2554
|
+
revokingFamilyId,
|
|
2555
|
+
signingOutEverywhere,
|
|
2556
|
+
onRefresh,
|
|
2557
|
+
onRevoke,
|
|
2558
|
+
onLogoutEverywhere,
|
|
2559
|
+
onClose
|
|
2560
|
+
}) {
|
|
2561
|
+
const isDark = theme === "dark";
|
|
2562
|
+
const cssVars = {
|
|
2563
|
+
"--pollar-accent": accentColor,
|
|
2564
|
+
"--pollar-bg": isDark ? "#1a1a1a" : "#ffffff",
|
|
2565
|
+
"--pollar-border": isDark ? "#374151" : "#e5e7eb",
|
|
2566
|
+
"--pollar-text": isDark ? "#ffffff" : "#111827",
|
|
2567
|
+
"--pollar-muted": isDark ? "#9ca3af" : "#6b7280",
|
|
2568
|
+
"--pollar-input-bg": isDark ? "#374151" : "#f9fafb",
|
|
2569
|
+
"--pollar-error-bg": isDark ? "#2a1515" : "#fef2f2",
|
|
2570
|
+
"--pollar-error-border": isDark ? "#7f1d1d" : "#fecaca",
|
|
2571
|
+
"--pollar-error-text": isDark ? "#f87171" : "#dc2626",
|
|
2572
|
+
"--pollar-success-text": isDark ? "#4ade80" : "#16a34a",
|
|
2573
|
+
"--pollar-buttons-border-radius": "6px",
|
|
2574
|
+
"--pollar-buttons-height": "44px",
|
|
2575
|
+
"--pollar-input-height": "44px",
|
|
2576
|
+
"--pollar-input-border-radius": "0.5rem",
|
|
2577
|
+
"--pollar-card-border-radius": "10px"
|
|
2578
|
+
};
|
|
2579
|
+
const isLoading = state.step === "loading";
|
|
2580
|
+
const sessions = state.step === "loaded" ? state.sessions : [];
|
|
2581
|
+
const otherCount = sessions.filter((s) => !s.current).length;
|
|
2582
|
+
return /* @__PURE__ */ jsxs(
|
|
2583
|
+
"div",
|
|
2584
|
+
{
|
|
2585
|
+
className: "pollar-modal-card pollar-sessions-modal",
|
|
2586
|
+
"data-theme": theme,
|
|
2587
|
+
style: cssVars,
|
|
2588
|
+
onClick: (e) => e.stopPropagation(),
|
|
2589
|
+
children: [
|
|
2590
|
+
/* @__PURE__ */ jsxs("div", { className: "pollar-modal-header", children: [
|
|
2591
|
+
/* @__PURE__ */ jsx("h2", { className: "pollar-modal-title", children: "Active sessions" }),
|
|
2592
|
+
/* @__PURE__ */ jsxs("div", { className: "pollar-modal-header-actions", children: [
|
|
2593
|
+
/* @__PURE__ */ jsxs("button", { className: "pollar-modal-refresh-btn", onClick: onRefresh, disabled: isLoading, children: [
|
|
2594
|
+
/* @__PURE__ */ jsxs(
|
|
2595
|
+
"svg",
|
|
2596
|
+
{
|
|
2597
|
+
className: `pollar-modal-refresh-icon${isLoading ? " spinning" : ""}`,
|
|
2598
|
+
width: "13",
|
|
2599
|
+
height: "13",
|
|
2600
|
+
viewBox: "0 0 13 13",
|
|
2601
|
+
fill: "none",
|
|
2602
|
+
"aria-hidden": true,
|
|
2603
|
+
children: [
|
|
2604
|
+
/* @__PURE__ */ jsx("path", { d: "M11.5 6.5a5 5 0 11-1.5-3.536", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" }),
|
|
2605
|
+
/* @__PURE__ */ jsx(
|
|
2606
|
+
"path",
|
|
2607
|
+
{
|
|
2608
|
+
d: "M10 1v3h-3",
|
|
2609
|
+
stroke: "currentColor",
|
|
2610
|
+
strokeWidth: "1.5",
|
|
2611
|
+
strokeLinecap: "round",
|
|
2612
|
+
strokeLinejoin: "round"
|
|
2613
|
+
}
|
|
2614
|
+
)
|
|
2615
|
+
]
|
|
2616
|
+
}
|
|
2617
|
+
),
|
|
2618
|
+
"Refresh"
|
|
2619
|
+
] }),
|
|
2620
|
+
/* @__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" }) }) })
|
|
2621
|
+
] })
|
|
2622
|
+
] }),
|
|
2623
|
+
/* @__PURE__ */ jsxs("div", { className: "pollar-sessions-list", children: [
|
|
2624
|
+
state.step === "idle" && /* @__PURE__ */ jsx("div", { className: "pollar-modal-empty", children: "Loading\u2026" }),
|
|
2625
|
+
isLoading && /* @__PURE__ */ jsx("div", { className: "pollar-modal-empty", children: "Loading\u2026" }),
|
|
2626
|
+
state.step === "error" && /* @__PURE__ */ jsx("div", { className: "pollar-modal-empty", children: state.message }),
|
|
2627
|
+
state.step === "loaded" && sessions.length === 0 && /* @__PURE__ */ jsx("div", { className: "pollar-modal-empty", children: "No active sessions." }),
|
|
2628
|
+
sessions.map((s) => {
|
|
2629
|
+
const isRevoking = revokingFamilyId === s.familyId;
|
|
2630
|
+
return /* @__PURE__ */ jsxs("div", { className: "pollar-sessions-item", "data-current": s.current || void 0, children: [
|
|
2631
|
+
/* @__PURE__ */ jsxs("div", { className: "pollar-sessions-item-main", children: [
|
|
2632
|
+
/* @__PURE__ */ jsx("span", { className: "pollar-sessions-item-device", children: describeDevice(s) }),
|
|
2633
|
+
s.current && /* @__PURE__ */ jsx("span", { className: "pollar-sessions-item-badge", children: "This device" })
|
|
2634
|
+
] }),
|
|
2635
|
+
/* @__PURE__ */ jsxs("div", { className: "pollar-sessions-item-meta", children: [
|
|
2636
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
2637
|
+
"Last used ",
|
|
2638
|
+
formatRelative(s.lastUsedAt ?? s.createdAt)
|
|
2639
|
+
] }),
|
|
2640
|
+
s.ipHash && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2641
|
+
/* @__PURE__ */ jsx("span", { children: "\xB7" }),
|
|
2642
|
+
/* @__PURE__ */ jsxs("span", { title: `ip-hash ${s.ipHash}`, children: [
|
|
2643
|
+
"ip ",
|
|
2644
|
+
shortIp(s.ipHash)
|
|
2645
|
+
] })
|
|
2646
|
+
] })
|
|
2647
|
+
] }),
|
|
2648
|
+
!s.current && /* @__PURE__ */ jsx(
|
|
2649
|
+
"button",
|
|
2650
|
+
{
|
|
2651
|
+
className: "pollar-sessions-item-revoke",
|
|
2652
|
+
onClick: () => onRevoke(s.familyId),
|
|
2653
|
+
disabled: isRevoking || signingOutEverywhere,
|
|
2654
|
+
children: isRevoking ? "Revoking\u2026" : "Revoke"
|
|
2655
|
+
}
|
|
2656
|
+
)
|
|
2657
|
+
] }, s.familyId);
|
|
2658
|
+
})
|
|
2659
|
+
] }),
|
|
2660
|
+
state.step === "loaded" && sessions.length > 0 && /* @__PURE__ */ jsx("div", { className: "pollar-sessions-actions", children: /* @__PURE__ */ jsx(
|
|
2661
|
+
"button",
|
|
2662
|
+
{
|
|
2663
|
+
className: "pollar-sessions-logout-all",
|
|
2664
|
+
onClick: onLogoutEverywhere,
|
|
2665
|
+
disabled: signingOutEverywhere || otherCount === 0,
|
|
2666
|
+
title: otherCount === 0 ? "No other devices to sign out" : void 0,
|
|
2667
|
+
children: signingOutEverywhere ? "Signing out\u2026" : "Sign out everywhere"
|
|
2668
|
+
}
|
|
2669
|
+
) }),
|
|
2670
|
+
/* @__PURE__ */ jsx(PollarModalFooter, {})
|
|
2671
|
+
]
|
|
2672
|
+
}
|
|
2673
|
+
);
|
|
2674
|
+
}
|
|
2675
|
+
function SessionsModal({ onClose }) {
|
|
2676
|
+
const { getClient, styles } = usePollar();
|
|
2677
|
+
const { theme = "light", accentColor = "#005DB4" } = styles;
|
|
2678
|
+
const [state, setState] = useState({ step: "idle" });
|
|
2679
|
+
const [revokingFamilyId, setRevokingFamilyId] = useState(null);
|
|
2680
|
+
const [signingOutEverywhere, setSigningOutEverywhere] = useState(false);
|
|
2681
|
+
const mountedRef = useRef(true);
|
|
2682
|
+
useEffect(() => () => {
|
|
2683
|
+
mountedRef.current = false;
|
|
2684
|
+
}, []);
|
|
2685
|
+
const onCloseRef = useRef(onClose);
|
|
2686
|
+
onCloseRef.current = onClose;
|
|
2687
|
+
useEffect(() => {
|
|
2688
|
+
return getClient().onAuthStateChange((authState) => {
|
|
2689
|
+
if (authState.step === "idle") onCloseRef.current();
|
|
2690
|
+
});
|
|
2691
|
+
}, [getClient]);
|
|
2692
|
+
const load = useCallback(async () => {
|
|
2693
|
+
setState({ step: "loading" });
|
|
2694
|
+
try {
|
|
2695
|
+
const sessions = await getClient().listSessions();
|
|
2696
|
+
if (!mountedRef.current) return;
|
|
2697
|
+
setState({ step: "loaded", sessions });
|
|
2698
|
+
} catch (err) {
|
|
2699
|
+
if (!mountedRef.current) return;
|
|
2700
|
+
const message = err instanceof Error ? err.message : "Failed to load sessions";
|
|
2701
|
+
setState({ step: "error", message });
|
|
2702
|
+
}
|
|
2703
|
+
}, [getClient]);
|
|
2704
|
+
useEffect(() => {
|
|
2705
|
+
void load();
|
|
2706
|
+
}, [load]);
|
|
2707
|
+
const handleRevoke = useCallback(
|
|
2708
|
+
async (familyId) => {
|
|
2709
|
+
setRevokingFamilyId(familyId);
|
|
2710
|
+
try {
|
|
2711
|
+
await getClient().revokeSession(familyId);
|
|
2712
|
+
if (!mountedRef.current) return;
|
|
2713
|
+
await load();
|
|
2714
|
+
} catch {
|
|
2715
|
+
if (!mountedRef.current) return;
|
|
2716
|
+
setState(
|
|
2717
|
+
(prev) => prev.step === "loaded" ? { step: "error", message: "Failed to revoke session" } : prev
|
|
2718
|
+
);
|
|
2719
|
+
} finally {
|
|
2720
|
+
if (mountedRef.current) setRevokingFamilyId(null);
|
|
2721
|
+
}
|
|
2722
|
+
},
|
|
2723
|
+
[getClient, load]
|
|
2724
|
+
);
|
|
2725
|
+
const handleLogoutEverywhere = useCallback(async () => {
|
|
2726
|
+
setSigningOutEverywhere(true);
|
|
2727
|
+
try {
|
|
2728
|
+
await getClient().logoutEverywhere();
|
|
2729
|
+
onClose();
|
|
2730
|
+
} catch {
|
|
2731
|
+
if (!mountedRef.current) return;
|
|
2732
|
+
setSigningOutEverywhere(false);
|
|
2733
|
+
}
|
|
2734
|
+
}, [getClient, onClose]);
|
|
2735
|
+
return /* @__PURE__ */ jsx("div", { className: "pollar-overlay", onClick: onClose, children: /* @__PURE__ */ jsx(
|
|
2736
|
+
SessionsModalTemplate,
|
|
2737
|
+
{
|
|
2738
|
+
theme,
|
|
2739
|
+
accentColor,
|
|
2740
|
+
state,
|
|
2741
|
+
revokingFamilyId,
|
|
2742
|
+
signingOutEverywhere,
|
|
2743
|
+
onRefresh: () => void load(),
|
|
2744
|
+
onRevoke: (familyId) => void handleRevoke(familyId),
|
|
2745
|
+
onLogoutEverywhere: () => void handleLogoutEverywhere(),
|
|
2746
|
+
onClose
|
|
2747
|
+
}
|
|
2748
|
+
) });
|
|
2749
|
+
}
|
|
2502
2750
|
function TransactionModalTemplate({
|
|
2503
2751
|
theme,
|
|
2504
2752
|
accentColor,
|
|
@@ -2940,9 +3188,10 @@ function PollarProvider({ config, styles: propStyles, adapters, children }) {
|
|
|
2940
3188
|
const [walletBalanceModalOpen, setWalletBalanceModalOpen] = useState(false);
|
|
2941
3189
|
const [sendModalOpen, setSendModalOpen] = useState(false);
|
|
2942
3190
|
const [receiveModalOpen, setReceiveModalOpen] = useState(false);
|
|
3191
|
+
const [sessionsModalOpen, setSessionsModalOpen] = useState(false);
|
|
2943
3192
|
const adaptersRef = useRef(adapters);
|
|
2944
3193
|
adaptersRef.current = adapters;
|
|
2945
|
-
const walletAddress = sessionState?.
|
|
3194
|
+
const walletAddress = sessionState?.wallet?.publicKey || "";
|
|
2946
3195
|
const getClient = useCallback(() => pollarClient, [pollarClient]);
|
|
2947
3196
|
const refreshWalletBalance = useCallback(() => pollarClient.refreshBalance(walletAddress), [pollarClient, walletAddress]);
|
|
2948
3197
|
const contextValue = useMemo(
|
|
@@ -2972,6 +3221,8 @@ function PollarProvider({ config, styles: propStyles, adapters, children }) {
|
|
|
2972
3221
|
// send / receive
|
|
2973
3222
|
openSendModal: () => setSendModalOpen(true),
|
|
2974
3223
|
openReceiveModal: () => setReceiveModalOpen(true),
|
|
3224
|
+
// sessions
|
|
3225
|
+
openSessionsModal: () => setSessionsModalOpen(true),
|
|
2975
3226
|
// network
|
|
2976
3227
|
network: networkState.step === "connected" ? networkState.network : "testnet",
|
|
2977
3228
|
setNetwork: (network) => pollarClient.setNetwork(network),
|
|
@@ -3006,7 +3257,8 @@ function PollarProvider({ config, styles: propStyles, adapters, children }) {
|
|
|
3006
3257
|
txHistoryModalOpen && /* @__PURE__ */ jsx(ModalErrorBoundary, { onClose: () => setTxHistoryModalOpen(false), children: /* @__PURE__ */ jsx(TxHistoryModal, { onClose: () => setTxHistoryModalOpen(false) }) }),
|
|
3007
3258
|
walletBalanceModalOpen && /* @__PURE__ */ jsx(ModalErrorBoundary, { onClose: () => setWalletBalanceModalOpen(false), children: /* @__PURE__ */ jsx(WalletBalanceModal, { onClose: () => setWalletBalanceModalOpen(false) }) }),
|
|
3008
3259
|
sendModalOpen && /* @__PURE__ */ jsx(ModalErrorBoundary, { onClose: () => setSendModalOpen(false), children: /* @__PURE__ */ jsx(SendModal, { onClose: () => setSendModalOpen(false) }) }),
|
|
3009
|
-
receiveModalOpen && /* @__PURE__ */ jsx(ModalErrorBoundary, { onClose: () => setReceiveModalOpen(false), children: /* @__PURE__ */ jsx(ReceiveModal, { onClose: () => setReceiveModalOpen(false) }) })
|
|
3260
|
+
receiveModalOpen && /* @__PURE__ */ jsx(ModalErrorBoundary, { onClose: () => setReceiveModalOpen(false), children: /* @__PURE__ */ jsx(ReceiveModal, { onClose: () => setReceiveModalOpen(false) }) }),
|
|
3261
|
+
sessionsModalOpen && /* @__PURE__ */ jsx(ModalErrorBoundary, { onClose: () => setSessionsModalOpen(false), children: /* @__PURE__ */ jsx(SessionsModal, { onClose: () => setSessionsModalOpen(false) }) })
|
|
3010
3262
|
] });
|
|
3011
3263
|
}
|
|
3012
3264
|
function usePollar() {
|
|
@@ -3257,6 +3509,6 @@ function WalletButton() {
|
|
|
3257
3509
|
);
|
|
3258
3510
|
}
|
|
3259
3511
|
|
|
3260
|
-
export { KycModal, KycModalTemplate, KycStatus, LoginModalTemplate, PollarProvider, RampWidget, RampWidgetTemplate, ReceiveModal, ReceiveModalTemplate, RouteDisplay, SendModal, SendModalTemplate, TransactionModalTemplate, TxHistoryModalTemplate, TxStatusView, WalletBalanceModal, WalletBalanceModalTemplate, WalletButton, createPollarAdapterHook, usePollar };
|
|
3512
|
+
export { KycModal, KycModalTemplate, KycStatus, LoginModalTemplate, PollarProvider, RampWidget, RampWidgetTemplate, ReceiveModal, ReceiveModalTemplate, RouteDisplay, SendModal, SendModalTemplate, SessionsModal, SessionsModalTemplate, TransactionModalTemplate, TxHistoryModalTemplate, TxStatusView, WalletBalanceModal, WalletBalanceModalTemplate, WalletButton, createPollarAdapterHook, usePollar };
|
|
3261
3513
|
//# sourceMappingURL=index.mjs.map
|
|
3262
3514
|
//# sourceMappingURL=index.mjs.map
|