@b3dotfun/sdk 0.1.69-alpha.11 → 0.1.69-alpha.13
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/cjs/anyspend/react/components/checkout/AnySpendCheckout.d.ts +3 -1
- package/dist/cjs/anyspend/react/components/checkout/AnySpendCheckout.js +5 -1
- package/dist/cjs/global-account/react/components/B3Provider/B3Provider.d.ts +4 -1
- package/dist/cjs/global-account/react/components/B3Provider/B3Provider.js +8 -12
- package/dist/cjs/global-account/react/components/B3Provider/B3Provider.native.js +6 -9
- package/dist/cjs/global-account/react/utils/createWagmiConfig.d.ts +4 -13
- package/dist/cjs/global-account/react/utils/createWagmiConfig.js +5 -7
- package/dist/cjs/wallet/react/components/ConnectWallet.d.ts +11 -0
- package/dist/cjs/wallet/react/components/ConnectWallet.js +467 -0
- package/dist/cjs/wallet/react/components/WalletProvider.d.ts +35 -0
- package/dist/cjs/wallet/react/components/WalletProvider.js +20 -0
- package/dist/cjs/wallet/react/hooks/useWalletDisconnect.d.ts +13 -0
- package/dist/cjs/wallet/react/hooks/useWalletDisconnect.js +22 -0
- package/dist/cjs/wallet/react/hooks/useWalletState.d.ts +31 -0
- package/dist/cjs/wallet/react/hooks/useWalletState.js +63 -0
- package/dist/cjs/wallet/react/index.d.ts +5 -0
- package/dist/cjs/wallet/react/index.js +16 -0
- package/dist/cjs/wallet/utils/createWalletConfig.d.ts +21 -0
- package/dist/cjs/wallet/utils/createWalletConfig.js +24 -0
- package/dist/esm/anyspend/react/components/checkout/AnySpendCheckout.d.ts +3 -1
- package/dist/esm/anyspend/react/components/checkout/AnySpendCheckout.js +5 -1
- package/dist/esm/global-account/react/components/B3Provider/B3Provider.d.ts +4 -1
- package/dist/esm/global-account/react/components/B3Provider/B3Provider.js +3 -7
- package/dist/esm/global-account/react/components/B3Provider/B3Provider.native.js +2 -5
- package/dist/esm/global-account/react/utils/createWagmiConfig.d.ts +4 -13
- package/dist/esm/global-account/react/utils/createWagmiConfig.js +5 -7
- package/dist/esm/wallet/react/components/ConnectWallet.d.ts +11 -0
- package/dist/esm/wallet/react/components/ConnectWallet.js +431 -0
- package/dist/esm/wallet/react/components/WalletProvider.d.ts +35 -0
- package/dist/esm/wallet/react/components/WalletProvider.js +17 -0
- package/dist/esm/wallet/react/hooks/useWalletDisconnect.d.ts +13 -0
- package/dist/esm/wallet/react/hooks/useWalletDisconnect.js +19 -0
- package/dist/esm/wallet/react/hooks/useWalletState.d.ts +31 -0
- package/dist/esm/wallet/react/hooks/useWalletState.js +60 -0
- package/dist/esm/wallet/react/index.d.ts +5 -0
- package/dist/esm/wallet/react/index.js +8 -0
- package/dist/esm/wallet/utils/createWalletConfig.d.ts +21 -0
- package/dist/esm/wallet/utils/createWalletConfig.js +21 -0
- package/dist/types/anyspend/react/components/checkout/AnySpendCheckout.d.ts +3 -1
- package/dist/types/global-account/react/components/B3Provider/B3Provider.d.ts +4 -1
- package/dist/types/global-account/react/utils/createWagmiConfig.d.ts +4 -13
- package/dist/types/wallet/react/components/ConnectWallet.d.ts +11 -0
- package/dist/types/wallet/react/components/WalletProvider.d.ts +35 -0
- package/dist/types/wallet/react/hooks/useWalletDisconnect.d.ts +13 -0
- package/dist/types/wallet/react/hooks/useWalletState.d.ts +31 -0
- package/dist/types/wallet/react/index.d.ts +5 -0
- package/dist/types/wallet/utils/createWalletConfig.d.ts +21 -0
- package/package.json +12 -1
- package/src/anyspend/react/components/checkout/AnySpendCheckout.tsx +6 -0
- package/src/global-account/react/components/B3Provider/B3Provider.native.tsx +14 -20
- package/src/global-account/react/components/B3Provider/B3Provider.tsx +41 -45
- package/src/global-account/react/utils/createWagmiConfig.tsx +6 -7
- package/src/wallet/__tests__/createWalletConfig.test.ts +39 -0
- package/src/wallet/react/components/ConnectWallet.tsx +665 -0
- package/src/wallet/react/components/WalletProvider.tsx +64 -0
- package/src/wallet/react/hooks/useWalletDisconnect.ts +22 -0
- package/src/wallet/react/hooks/useWalletState.ts +93 -0
- package/src/wallet/react/index.ts +10 -0
- package/src/wallet/utils/createWalletConfig.ts +39 -0
|
@@ -0,0 +1,467 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.ConnectWallet = ConnectWallet;
|
|
37
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
38
|
+
const DialogPrimitive = __importStar(require("@radix-ui/react-dialog"));
|
|
39
|
+
const react_1 = require("@web3icons/react");
|
|
40
|
+
const utils_1 = require("../../../shared/utils");
|
|
41
|
+
const lucide_react_1 = require("lucide-react");
|
|
42
|
+
const react_2 = require("react");
|
|
43
|
+
const useWalletDisconnect_1 = require("../hooks/useWalletDisconnect");
|
|
44
|
+
const useWalletState_1 = require("../hooks/useWalletState");
|
|
45
|
+
/** Injects the spinner keyframe once into the document head (idempotent via DOM id). */
|
|
46
|
+
function SpinnerKeyframes() {
|
|
47
|
+
(0, react_2.useEffect)(() => {
|
|
48
|
+
if (document.getElementById("b3-spin-keyframes"))
|
|
49
|
+
return;
|
|
50
|
+
const style = document.createElement("style");
|
|
51
|
+
style.id = "b3-spin-keyframes";
|
|
52
|
+
style.textContent = "@keyframes b3-spin { to { transform: rotate(360deg) } }";
|
|
53
|
+
document.head.appendChild(style);
|
|
54
|
+
}, []);
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
const WALLET_DOWNLOAD_URLS = {
|
|
58
|
+
metamask: "https://metamask.io/download/",
|
|
59
|
+
"coinbase wallet": "https://www.coinbase.com/wallet/downloads",
|
|
60
|
+
phantom: "https://phantom.app/download",
|
|
61
|
+
rabby: "https://rabby.io/",
|
|
62
|
+
rainbow: "https://rainbow.me/download",
|
|
63
|
+
walletconnect: "https://walletconnect.com/",
|
|
64
|
+
};
|
|
65
|
+
function getWalletIcon(name, size = 24) {
|
|
66
|
+
switch (name.toLowerCase()) {
|
|
67
|
+
case "metamask":
|
|
68
|
+
return (0, jsx_runtime_1.jsx)(react_1.WalletMetamask, { width: size, height: size });
|
|
69
|
+
case "coinbase wallet":
|
|
70
|
+
return (0, jsx_runtime_1.jsx)(react_1.WalletCoinbase, { width: size, height: size });
|
|
71
|
+
case "phantom":
|
|
72
|
+
return (0, jsx_runtime_1.jsx)(react_1.WalletPhantom, { width: size, height: size });
|
|
73
|
+
case "walletconnect":
|
|
74
|
+
return (0, jsx_runtime_1.jsx)(react_1.WalletWalletConnect, { width: size, height: size });
|
|
75
|
+
case "rabby wallet":
|
|
76
|
+
case "rabby":
|
|
77
|
+
return (0, jsx_runtime_1.jsx)(react_1.WalletRabby, { width: size, height: size });
|
|
78
|
+
case "rainbow":
|
|
79
|
+
return (0, jsx_runtime_1.jsx)(react_1.WalletRainbow, { width: size, height: size });
|
|
80
|
+
default:
|
|
81
|
+
return (0, jsx_runtime_1.jsx)(lucide_react_1.Wallet, { width: size, height: size });
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
// B3 brand colors
|
|
85
|
+
const B3_BLUE = "#3368ef";
|
|
86
|
+
const B3_BLUE_HOVER = "#2554d4";
|
|
87
|
+
const theme = {
|
|
88
|
+
light: {
|
|
89
|
+
bg: "#ffffff",
|
|
90
|
+
cardBg: "#ffffff",
|
|
91
|
+
text: "#1a1a2e",
|
|
92
|
+
textSecondary: "#64748b",
|
|
93
|
+
textTertiary: "#94a3b8",
|
|
94
|
+
border: "#D1D1D6",
|
|
95
|
+
borderLight: "#e2e8f0",
|
|
96
|
+
hoverBg: "#f1f5f9",
|
|
97
|
+
iconBg: "#f1f5f9",
|
|
98
|
+
shadow: "0 20px 24px -4px rgba(10,13,18,0.08), 0 8px 8px -4px rgba(10,13,18,0.03), 0 3px 3px -1.5px rgba(10,13,18,0.04)",
|
|
99
|
+
popoverShadow: "0 10px 30px -5px rgba(10,13,18,0.1), 0 4px 6px -4px rgba(10,13,18,0.05)",
|
|
100
|
+
overlayBg: "rgba(0,0,0,0.8)",
|
|
101
|
+
badgeInstalledBg: "#ecfdf5",
|
|
102
|
+
badgeInstalledText: "#059669",
|
|
103
|
+
badgeInstallBg: "#f1f5f9",
|
|
104
|
+
badgeInstallText: "#64748b",
|
|
105
|
+
connectedDot: "#10b981",
|
|
106
|
+
disconnectBorder: "#fca5a5",
|
|
107
|
+
disconnectText: "#dc2626",
|
|
108
|
+
disconnectHoverBg: "#fef2f2",
|
|
109
|
+
copyHoverBg: "#f1f5f9",
|
|
110
|
+
},
|
|
111
|
+
dark: {
|
|
112
|
+
bg: "#0f0f14",
|
|
113
|
+
cardBg: "#1a1a24",
|
|
114
|
+
text: "#f1f5f9",
|
|
115
|
+
textSecondary: "#94a3b8",
|
|
116
|
+
textTertiary: "#64748b",
|
|
117
|
+
border: "#2a2a3a",
|
|
118
|
+
borderLight: "#2a2a3a",
|
|
119
|
+
hoverBg: "#22222e",
|
|
120
|
+
iconBg: "#22222e",
|
|
121
|
+
shadow: "0 20px 24px -4px rgba(0,0,0,0.3), 0 8px 8px -4px rgba(0,0,0,0.2)",
|
|
122
|
+
popoverShadow: "0 10px 30px -5px rgba(0,0,0,0.4)",
|
|
123
|
+
overlayBg: "rgba(0,0,0,0.85)",
|
|
124
|
+
badgeInstalledBg: "#052e16",
|
|
125
|
+
badgeInstalledText: "#34d399",
|
|
126
|
+
badgeInstallBg: "#22222e",
|
|
127
|
+
badgeInstallText: "#64748b",
|
|
128
|
+
connectedDot: "#34d399",
|
|
129
|
+
disconnectBorder: "#7f1d1d",
|
|
130
|
+
disconnectText: "#f87171",
|
|
131
|
+
disconnectHoverBg: "#1c1017",
|
|
132
|
+
copyHoverBg: "#22222e",
|
|
133
|
+
},
|
|
134
|
+
};
|
|
135
|
+
/**
|
|
136
|
+
* Drop-in wallet connection component styled to match the B3 design system.
|
|
137
|
+
* Uses inline styles — works in any app without tailwind configuration.
|
|
138
|
+
*/
|
|
139
|
+
function ConnectWallet({ theme: themeProp = "light", buttonLabel = "Connect Wallet" }) {
|
|
140
|
+
const { address, isConnected, chain, connectors } = (0, useWalletState_1.useWalletState)();
|
|
141
|
+
const { disconnect } = (0, useWalletDisconnect_1.useWalletDisconnect)();
|
|
142
|
+
const [modalOpen, setModalOpen] = (0, react_2.useState)(false);
|
|
143
|
+
const [popoverOpen, setPopoverOpen] = (0, react_2.useState)(false);
|
|
144
|
+
const [copied, setCopied] = (0, react_2.useState)(false);
|
|
145
|
+
const [hoveredUid, setHoveredUid] = (0, react_2.useState)(null);
|
|
146
|
+
const [btnHover, setBtnHover] = (0, react_2.useState)(false);
|
|
147
|
+
const [disconnectHover, setDisconnectHover] = (0, react_2.useState)(false);
|
|
148
|
+
const [copyHover, setCopyHover] = (0, react_2.useState)(false);
|
|
149
|
+
const [connectingUid, setConnectingUid] = (0, react_2.useState)(null);
|
|
150
|
+
const [connectError, setConnectError] = (0, react_2.useState)(null);
|
|
151
|
+
const [connectSuccess, setConnectSuccess] = (0, react_2.useState)(false);
|
|
152
|
+
const t = theme[themeProp];
|
|
153
|
+
const successTimerRef = (0, react_2.useRef)(null);
|
|
154
|
+
const resetConnectState = (0, react_2.useCallback)(() => {
|
|
155
|
+
setConnectingUid(null);
|
|
156
|
+
setConnectError(null);
|
|
157
|
+
setConnectSuccess(false);
|
|
158
|
+
if (successTimerRef.current) {
|
|
159
|
+
clearTimeout(successTimerRef.current);
|
|
160
|
+
successTimerRef.current = null;
|
|
161
|
+
}
|
|
162
|
+
}, []);
|
|
163
|
+
// Cleanup success timer on unmount
|
|
164
|
+
(0, react_2.useEffect)(() => {
|
|
165
|
+
return () => {
|
|
166
|
+
if (successTimerRef.current)
|
|
167
|
+
clearTimeout(successTimerRef.current);
|
|
168
|
+
};
|
|
169
|
+
}, []);
|
|
170
|
+
const handleConnect = (0, react_2.useCallback)(async (connector) => {
|
|
171
|
+
if (!connector.isInstalled) {
|
|
172
|
+
const url = WALLET_DOWNLOAD_URLS[connector.name.toLowerCase()];
|
|
173
|
+
if (url)
|
|
174
|
+
window.open(url, "_blank", "noopener,noreferrer");
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
setConnectingUid(connector.uid);
|
|
178
|
+
setConnectError(null);
|
|
179
|
+
setConnectSuccess(false);
|
|
180
|
+
try {
|
|
181
|
+
await connector.connect();
|
|
182
|
+
setConnectSuccess(true);
|
|
183
|
+
successTimerRef.current = setTimeout(() => {
|
|
184
|
+
setModalOpen(false);
|
|
185
|
+
resetConnectState();
|
|
186
|
+
}, 800);
|
|
187
|
+
}
|
|
188
|
+
catch (err) {
|
|
189
|
+
const message = err instanceof Error ? err.message : "Connection failed";
|
|
190
|
+
if (message.includes("rejected") || message.includes("denied") || message.includes("User rejected")) {
|
|
191
|
+
setConnectError("Connection rejected");
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
setConnectError(message.length > 60 ? message.slice(0, 60) + "..." : message);
|
|
195
|
+
}
|
|
196
|
+
setConnectingUid(null);
|
|
197
|
+
}
|
|
198
|
+
}, [resetConnectState]);
|
|
199
|
+
const handleDisconnect = (0, react_2.useCallback)(() => {
|
|
200
|
+
disconnect();
|
|
201
|
+
setPopoverOpen(false);
|
|
202
|
+
}, [disconnect]);
|
|
203
|
+
const handleCopyAddress = (0, react_2.useCallback)(async () => {
|
|
204
|
+
if (address) {
|
|
205
|
+
try {
|
|
206
|
+
await navigator.clipboard.writeText(address);
|
|
207
|
+
setCopied(true);
|
|
208
|
+
}
|
|
209
|
+
catch {
|
|
210
|
+
// Clipboard API may be denied
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}, [address]);
|
|
214
|
+
(0, react_2.useEffect)(() => {
|
|
215
|
+
if (!copied)
|
|
216
|
+
return;
|
|
217
|
+
const timer = setTimeout(() => setCopied(false), 2000);
|
|
218
|
+
return () => clearTimeout(timer);
|
|
219
|
+
}, [copied]);
|
|
220
|
+
// Close popover on Escape key
|
|
221
|
+
(0, react_2.useEffect)(() => {
|
|
222
|
+
if (!popoverOpen)
|
|
223
|
+
return;
|
|
224
|
+
const handleKeyDown = (e) => {
|
|
225
|
+
if (e.key === "Escape")
|
|
226
|
+
setPopoverOpen(false);
|
|
227
|
+
};
|
|
228
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
229
|
+
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
230
|
+
}, [popoverOpen]);
|
|
231
|
+
// --- Connected state ---
|
|
232
|
+
if (isConnected && address) {
|
|
233
|
+
return ((0, jsx_runtime_1.jsxs)("div", { style: {
|
|
234
|
+
position: "relative",
|
|
235
|
+
display: "inline-block",
|
|
236
|
+
fontFamily: "-apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif",
|
|
237
|
+
}, children: [(0, jsx_runtime_1.jsxs)("button", { onClick: () => setPopoverOpen(!popoverOpen), "aria-expanded": popoverOpen, "aria-haspopup": "true", style: {
|
|
238
|
+
display: "flex",
|
|
239
|
+
alignItems: "center",
|
|
240
|
+
gap: 10,
|
|
241
|
+
padding: "10px 16px",
|
|
242
|
+
borderRadius: 12,
|
|
243
|
+
border: `1.5px solid ${t.border}`,
|
|
244
|
+
background: t.cardBg,
|
|
245
|
+
color: t.text,
|
|
246
|
+
fontSize: 14,
|
|
247
|
+
fontWeight: 600,
|
|
248
|
+
cursor: "pointer",
|
|
249
|
+
letterSpacing: "-0.01em",
|
|
250
|
+
transition: "all 150ms ease",
|
|
251
|
+
}, children: [(0, jsx_runtime_1.jsx)("span", { style: {
|
|
252
|
+
width: 8,
|
|
253
|
+
height: 8,
|
|
254
|
+
borderRadius: "50%",
|
|
255
|
+
background: t.connectedDot,
|
|
256
|
+
display: "inline-block",
|
|
257
|
+
boxShadow: `0 0 6px ${t.connectedDot}`,
|
|
258
|
+
} }), (0, jsx_runtime_1.jsx)("span", { style: { fontFamily: "'SF Mono', 'Fira Code', 'Cascadia Code', monospace", fontSize: 13 }, children: (0, utils_1.truncateAddress)(address) }), (0, jsx_runtime_1.jsx)(lucide_react_1.ChevronDown, { size: 14, color: t.textTertiary, style: { transition: "transform 200ms", transform: popoverOpen ? "rotate(180deg)" : "none" } })] }), popoverOpen && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("div", { style: { position: "fixed", inset: 0, zIndex: 40 }, onClick: () => setPopoverOpen(false) }), (0, jsx_runtime_1.jsxs)("div", { role: "dialog", "aria-label": "Wallet details", onClick: e => e.stopPropagation(), style: {
|
|
259
|
+
position: "absolute",
|
|
260
|
+
right: 0,
|
|
261
|
+
top: "100%",
|
|
262
|
+
marginTop: 8,
|
|
263
|
+
width: 320,
|
|
264
|
+
borderRadius: 16,
|
|
265
|
+
border: `1.5px solid ${t.border}`,
|
|
266
|
+
background: t.cardBg,
|
|
267
|
+
boxShadow: t.popoverShadow,
|
|
268
|
+
zIndex: 50,
|
|
269
|
+
overflow: "hidden",
|
|
270
|
+
}, children: [(0, jsx_runtime_1.jsxs)("div", { style: {
|
|
271
|
+
padding: "16px 20px 14px",
|
|
272
|
+
borderBottom: `1px solid ${t.borderLight}`,
|
|
273
|
+
display: "flex",
|
|
274
|
+
alignItems: "center",
|
|
275
|
+
justifyContent: "space-between",
|
|
276
|
+
}, children: [(0, jsx_runtime_1.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8 }, children: [(0, jsx_runtime_1.jsx)("span", { style: {
|
|
277
|
+
width: 8,
|
|
278
|
+
height: 8,
|
|
279
|
+
borderRadius: "50%",
|
|
280
|
+
background: t.connectedDot,
|
|
281
|
+
display: "inline-block",
|
|
282
|
+
boxShadow: `0 0 6px ${t.connectedDot}`,
|
|
283
|
+
} }), (0, jsx_runtime_1.jsx)("span", { style: { fontSize: 13, fontWeight: 600, color: t.text, letterSpacing: "-0.01em" }, children: "Connected" })] }), chain && ((0, jsx_runtime_1.jsx)("span", { style: {
|
|
284
|
+
fontSize: 11,
|
|
285
|
+
fontWeight: 600,
|
|
286
|
+
padding: "3px 10px",
|
|
287
|
+
borderRadius: 99,
|
|
288
|
+
background: t.iconBg,
|
|
289
|
+
color: t.textSecondary,
|
|
290
|
+
letterSpacing: "0.02em",
|
|
291
|
+
textTransform: "uppercase",
|
|
292
|
+
}, children: chain.name }))] }), (0, jsx_runtime_1.jsxs)("div", { style: { padding: "12px 12px 16px" }, children: [(0, jsx_runtime_1.jsxs)("button", { onClick: handleCopyAddress, onMouseEnter: () => setCopyHover(true), onMouseLeave: () => setCopyHover(false), style: {
|
|
293
|
+
display: "flex",
|
|
294
|
+
alignItems: "center",
|
|
295
|
+
gap: 10,
|
|
296
|
+
width: "100%",
|
|
297
|
+
padding: "10px 12px",
|
|
298
|
+
borderRadius: 10,
|
|
299
|
+
border: "none",
|
|
300
|
+
background: copyHover ? t.copyHoverBg : "transparent",
|
|
301
|
+
textAlign: "left",
|
|
302
|
+
fontFamily: "'SF Mono', 'Fira Code', 'Cascadia Code', monospace",
|
|
303
|
+
fontSize: 12,
|
|
304
|
+
color: t.text,
|
|
305
|
+
cursor: "pointer",
|
|
306
|
+
marginBottom: 8,
|
|
307
|
+
wordBreak: "break-all",
|
|
308
|
+
lineHeight: 1.5,
|
|
309
|
+
transition: "background 150ms ease",
|
|
310
|
+
}, children: [(0, jsx_runtime_1.jsx)("span", { style: { flex: 1 }, children: address }), copied ? ((0, jsx_runtime_1.jsx)(lucide_react_1.Check, { size: 14, color: t.connectedDot, style: { flexShrink: 0 } })) : ((0, jsx_runtime_1.jsx)(lucide_react_1.Copy, { size: 14, color: t.textTertiary, style: { flexShrink: 0 } }))] }), (0, jsx_runtime_1.jsxs)("button", { onClick: handleDisconnect, onMouseEnter: () => setDisconnectHover(true), onMouseLeave: () => setDisconnectHover(false), style: {
|
|
311
|
+
display: "flex",
|
|
312
|
+
alignItems: "center",
|
|
313
|
+
justifyContent: "center",
|
|
314
|
+
gap: 8,
|
|
315
|
+
width: "100%",
|
|
316
|
+
padding: "10px 16px",
|
|
317
|
+
borderRadius: 10,
|
|
318
|
+
border: `1.5px solid ${t.disconnectBorder}`,
|
|
319
|
+
background: disconnectHover ? t.disconnectHoverBg : "transparent",
|
|
320
|
+
color: t.disconnectText,
|
|
321
|
+
fontSize: 13,
|
|
322
|
+
fontWeight: 600,
|
|
323
|
+
cursor: "pointer",
|
|
324
|
+
transition: "all 150ms ease",
|
|
325
|
+
}, children: [(0, jsx_runtime_1.jsx)(lucide_react_1.LogOut, { size: 15 }), "Disconnect"] })] })] })] }))] }));
|
|
326
|
+
}
|
|
327
|
+
// --- Disconnected state ---
|
|
328
|
+
return ((0, jsx_runtime_1.jsxs)(DialogPrimitive.Root, { open: modalOpen, onOpenChange: open => {
|
|
329
|
+
setModalOpen(open);
|
|
330
|
+
if (!open)
|
|
331
|
+
resetConnectState();
|
|
332
|
+
}, children: [(0, jsx_runtime_1.jsx)(DialogPrimitive.Trigger, { asChild: true, children: (0, jsx_runtime_1.jsx)("button", { onMouseEnter: () => setBtnHover(true), onMouseLeave: () => setBtnHover(false), style: {
|
|
333
|
+
padding: "12px 24px",
|
|
334
|
+
borderRadius: 12,
|
|
335
|
+
border: "none",
|
|
336
|
+
background: btnHover ? B3_BLUE_HOVER : B3_BLUE,
|
|
337
|
+
color: "#ffffff",
|
|
338
|
+
fontSize: 14,
|
|
339
|
+
fontWeight: 600,
|
|
340
|
+
cursor: "pointer",
|
|
341
|
+
letterSpacing: "-0.01em",
|
|
342
|
+
transition: "all 150ms ease",
|
|
343
|
+
boxShadow: btnHover ? `0 4px 12px ${B3_BLUE}40, 0 1px 3px rgba(0,0,0,0.1)` : `0 2px 8px ${B3_BLUE}30`,
|
|
344
|
+
fontFamily: "-apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif",
|
|
345
|
+
}, children: buttonLabel }) }), (0, jsx_runtime_1.jsx)(SpinnerKeyframes, {}), (0, jsx_runtime_1.jsxs)(DialogPrimitive.Portal, { children: [(0, jsx_runtime_1.jsx)(DialogPrimitive.Overlay, { style: {
|
|
346
|
+
position: "fixed",
|
|
347
|
+
inset: 0,
|
|
348
|
+
zIndex: 50,
|
|
349
|
+
background: t.overlayBg,
|
|
350
|
+
backdropFilter: "blur(20px)",
|
|
351
|
+
WebkitBackdropFilter: "blur(20px)",
|
|
352
|
+
} }), (0, jsx_runtime_1.jsxs)(DialogPrimitive.Content, { style: {
|
|
353
|
+
position: "fixed",
|
|
354
|
+
left: "50%",
|
|
355
|
+
top: "50%",
|
|
356
|
+
transform: "translate(-50%, -50%)",
|
|
357
|
+
zIndex: 50,
|
|
358
|
+
width: "calc(100% - 32px)",
|
|
359
|
+
maxWidth: 400,
|
|
360
|
+
borderRadius: 20,
|
|
361
|
+
border: `1.5px solid ${t.border}`,
|
|
362
|
+
background: t.cardBg,
|
|
363
|
+
color: t.text,
|
|
364
|
+
boxShadow: t.shadow,
|
|
365
|
+
overflow: "hidden",
|
|
366
|
+
fontFamily: "-apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif",
|
|
367
|
+
}, children: [(0, jsx_runtime_1.jsxs)("div", { style: {
|
|
368
|
+
display: "flex",
|
|
369
|
+
alignItems: "center",
|
|
370
|
+
justifyContent: "space-between",
|
|
371
|
+
padding: "20px 24px 16px",
|
|
372
|
+
}, children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)(DialogPrimitive.Title, { style: {
|
|
373
|
+
fontSize: 18,
|
|
374
|
+
fontWeight: 700,
|
|
375
|
+
margin: 0,
|
|
376
|
+
letterSpacing: "-0.02em",
|
|
377
|
+
color: t.text,
|
|
378
|
+
}, children: "Connect Wallet" }), (0, jsx_runtime_1.jsx)("p", { style: { fontSize: 13, color: t.textSecondary, margin: "4px 0 0", letterSpacing: "-0.01em" }, children: "Choose your preferred wallet" })] }), (0, jsx_runtime_1.jsx)(DialogPrimitive.Close, { style: {
|
|
379
|
+
background: t.iconBg,
|
|
380
|
+
border: "none",
|
|
381
|
+
cursor: "pointer",
|
|
382
|
+
padding: 8,
|
|
383
|
+
borderRadius: 10,
|
|
384
|
+
color: t.textSecondary,
|
|
385
|
+
display: "flex",
|
|
386
|
+
alignItems: "center",
|
|
387
|
+
justifyContent: "center",
|
|
388
|
+
transition: "all 150ms ease",
|
|
389
|
+
}, children: (0, jsx_runtime_1.jsx)(lucide_react_1.X, { size: 16 }) })] }), connectError && ((0, jsx_runtime_1.jsxs)("div", { style: {
|
|
390
|
+
margin: "0 12px 8px",
|
|
391
|
+
padding: "10px 14px",
|
|
392
|
+
borderRadius: 10,
|
|
393
|
+
background: themeProp === "dark" ? "#1c1017" : "#fef2f2",
|
|
394
|
+
border: `1px solid ${t.disconnectBorder}`,
|
|
395
|
+
display: "flex",
|
|
396
|
+
alignItems: "center",
|
|
397
|
+
gap: 8,
|
|
398
|
+
fontSize: 13,
|
|
399
|
+
color: t.disconnectText,
|
|
400
|
+
}, children: [(0, jsx_runtime_1.jsx)(lucide_react_1.AlertCircle, { size: 16, style: { flexShrink: 0 } }), (0, jsx_runtime_1.jsx)("span", { style: { flex: 1 }, children: connectError }), (0, jsx_runtime_1.jsx)("button", { onClick: () => setConnectError(null), style: { background: "none", border: "none", cursor: "pointer", color: t.disconnectText, padding: 2 }, children: (0, jsx_runtime_1.jsx)(lucide_react_1.X, { size: 14 }) })] })), (0, jsx_runtime_1.jsx)("div", { style: { padding: "0 12px 16px" }, children: connectors.length === 0 ? ((0, jsx_runtime_1.jsx)("p", { style: { padding: "40px 0", textAlign: "center", fontSize: 14, color: t.textSecondary }, children: "No wallets detected" })) : ((0, jsx_runtime_1.jsx)("div", { style: { display: "flex", flexDirection: "column", gap: 4 }, children: connectors.map(connector => {
|
|
401
|
+
const isLoading = connectingUid === connector.uid;
|
|
402
|
+
const isSuccess = connectSuccess && connectingUid === connector.uid;
|
|
403
|
+
const isDisabled = connectingUid !== null && connectingUid !== connector.uid;
|
|
404
|
+
return ((0, jsx_runtime_1.jsxs)("button", { onClick: () => !connectingUid && handleConnect(connector), onMouseEnter: () => setHoveredUid(connector.uid), onMouseLeave: () => setHoveredUid(null), style: {
|
|
405
|
+
display: "flex",
|
|
406
|
+
alignItems: "center",
|
|
407
|
+
gap: 14,
|
|
408
|
+
width: "100%",
|
|
409
|
+
padding: "14px 16px",
|
|
410
|
+
borderRadius: 14,
|
|
411
|
+
border: isLoading
|
|
412
|
+
? `1.5px solid ${B3_BLUE}`
|
|
413
|
+
: isSuccess
|
|
414
|
+
? `1.5px solid ${t.connectedDot}`
|
|
415
|
+
: hoveredUid === connector.uid && !isDisabled
|
|
416
|
+
? `1.5px solid ${B3_BLUE}40`
|
|
417
|
+
: "1.5px solid transparent",
|
|
418
|
+
background: isLoading
|
|
419
|
+
? themeProp === "dark"
|
|
420
|
+
? "#1a1a30"
|
|
421
|
+
: "#eff6ff"
|
|
422
|
+
: isSuccess
|
|
423
|
+
? themeProp === "dark"
|
|
424
|
+
? "#0a1f15"
|
|
425
|
+
: "#ecfdf5"
|
|
426
|
+
: hoveredUid === connector.uid && !isDisabled
|
|
427
|
+
? t.hoverBg
|
|
428
|
+
: "transparent",
|
|
429
|
+
textAlign: "left",
|
|
430
|
+
cursor: isDisabled ? "default" : "pointer",
|
|
431
|
+
color: t.text,
|
|
432
|
+
opacity: isDisabled ? 0.4 : 1,
|
|
433
|
+
transition: "all 150ms ease",
|
|
434
|
+
}, children: [(0, jsx_runtime_1.jsx)("div", { style: {
|
|
435
|
+
width: 44,
|
|
436
|
+
height: 44,
|
|
437
|
+
borderRadius: 12,
|
|
438
|
+
background: t.iconBg,
|
|
439
|
+
display: "flex",
|
|
440
|
+
alignItems: "center",
|
|
441
|
+
justifyContent: "center",
|
|
442
|
+
flexShrink: 0,
|
|
443
|
+
border: `1px solid ${t.borderLight}`,
|
|
444
|
+
}, children: getWalletIcon(connector.name, 24) }), (0, jsx_runtime_1.jsxs)("div", { style: { flex: 1, minWidth: 0 }, children: [(0, jsx_runtime_1.jsx)("div", { style: { fontSize: 14, fontWeight: 600, letterSpacing: "-0.01em" }, children: connector.name }), isLoading && ((0, jsx_runtime_1.jsx)("div", { style: { fontSize: 12, color: B3_BLUE, marginTop: 2 }, children: "Waiting for approval..." })), isSuccess && ((0, jsx_runtime_1.jsx)("div", { style: { fontSize: 12, color: t.connectedDot, marginTop: 2 }, children: "Connected" }))] }), isLoading && ((0, jsx_runtime_1.jsx)(lucide_react_1.Loader2, { size: 18, color: B3_BLUE, style: { flexShrink: 0, animation: "b3-spin 1s linear infinite" } })), isSuccess && (0, jsx_runtime_1.jsx)(lucide_react_1.Check, { size: 18, color: t.connectedDot, style: { flexShrink: 0 } }), !isLoading && !isSuccess && !connector.isInstalled && ((0, jsx_runtime_1.jsx)("span", { style: {
|
|
445
|
+
fontSize: 11,
|
|
446
|
+
fontWeight: 600,
|
|
447
|
+
padding: "4px 10px",
|
|
448
|
+
borderRadius: 99,
|
|
449
|
+
background: t.badgeInstallBg,
|
|
450
|
+
color: t.badgeInstallText,
|
|
451
|
+
letterSpacing: "0.01em",
|
|
452
|
+
}, children: "Install" }))] }, connector.uid));
|
|
453
|
+
}) })) }), (0, jsx_runtime_1.jsxs)("div", { style: {
|
|
454
|
+
padding: "12px 24px 16px",
|
|
455
|
+
borderTop: `1px solid ${t.borderLight}`,
|
|
456
|
+
display: "flex",
|
|
457
|
+
alignItems: "center",
|
|
458
|
+
justifyContent: "center",
|
|
459
|
+
gap: 6,
|
|
460
|
+
}, children: [(0, jsx_runtime_1.jsx)("img", { src: "https://cdn.b3.fun/b3_logo.svg", alt: "B3", width: 16, height: 16 }), (0, jsx_runtime_1.jsx)("span", { style: {
|
|
461
|
+
fontSize: 11,
|
|
462
|
+
fontWeight: 700,
|
|
463
|
+
color: B3_BLUE,
|
|
464
|
+
letterSpacing: "0.06em",
|
|
465
|
+
textTransform: "uppercase",
|
|
466
|
+
}, children: "Powered by B3" })] })] })] })] }));
|
|
467
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { QueryClient } from "@tanstack/react-query";
|
|
2
|
+
import { type Config, type CreateConnectorFn } from "wagmi";
|
|
3
|
+
import type { Chain } from "viem";
|
|
4
|
+
export interface WalletProviderProps {
|
|
5
|
+
children: React.ReactNode;
|
|
6
|
+
/**
|
|
7
|
+
* Chains to support. Defaults to SDK's supportedChains.
|
|
8
|
+
* Must be memoized or defined outside the component — inline arrays cause the
|
|
9
|
+
* wagmi config to rebuild on every render, losing wallet connection state.
|
|
10
|
+
*/
|
|
11
|
+
chains?: Chain[];
|
|
12
|
+
/**
|
|
13
|
+
* Wagmi connectors. Must be memoized or defined outside the component — inline
|
|
14
|
+
* arrays cause the wagmi config to rebuild on every render, losing wallet connection state.
|
|
15
|
+
*/
|
|
16
|
+
connectors?: CreateConnectorFn[];
|
|
17
|
+
/**
|
|
18
|
+
* Optional RPC URL overrides per chain ID.
|
|
19
|
+
* Must be memoized or defined outside the component — inline objects cause the
|
|
20
|
+
* wagmi config to rebuild on every render, losing wallet connection state.
|
|
21
|
+
*/
|
|
22
|
+
rpcUrls?: Record<number, string>;
|
|
23
|
+
/** Escape hatch: pass a fully custom wagmi config. Overrides chains/connectors/rpcUrls. */
|
|
24
|
+
wagmiConfig?: Config;
|
|
25
|
+
/** Provide your own QueryClient for React Query. Defaults to an internal instance. */
|
|
26
|
+
queryClient?: QueryClient;
|
|
27
|
+
/** Whether to auto-reconnect the last wallet on mount. Defaults to false. */
|
|
28
|
+
reconnectOnMount?: boolean;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Standalone wallet connection provider.
|
|
32
|
+
* Wraps ThirdwebProvider, WagmiProvider, and QueryClientProvider.
|
|
33
|
+
* Use wagmi hooks (useAccount, useConnect, useDisconnect) directly inside.
|
|
34
|
+
*/
|
|
35
|
+
export declare function WalletProvider({ children, chains, connectors, rpcUrls, wagmiConfig: wagmiConfigProp, queryClient: queryClientProp, reconnectOnMount, }: WalletProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.WalletProvider = WalletProvider;
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const react_query_1 = require("@tanstack/react-query");
|
|
6
|
+
const react_1 = require("react");
|
|
7
|
+
const react_2 = require("thirdweb/react");
|
|
8
|
+
const wagmi_1 = require("wagmi");
|
|
9
|
+
const createWalletConfig_1 = require("../../utils/createWalletConfig");
|
|
10
|
+
/**
|
|
11
|
+
* Standalone wallet connection provider.
|
|
12
|
+
* Wraps ThirdwebProvider, WagmiProvider, and QueryClientProvider.
|
|
13
|
+
* Use wagmi hooks (useAccount, useConnect, useDisconnect) directly inside.
|
|
14
|
+
*/
|
|
15
|
+
function WalletProvider({ children, chains, connectors, rpcUrls, wagmiConfig: wagmiConfigProp, queryClient: queryClientProp, reconnectOnMount = false, }) {
|
|
16
|
+
const [defaultQueryClient] = (0, react_1.useState)(() => new react_query_1.QueryClient());
|
|
17
|
+
const queryClient = queryClientProp ?? defaultQueryClient;
|
|
18
|
+
const wagmiConfig = (0, react_1.useMemo)(() => wagmiConfigProp ?? (0, createWalletConfig_1.createWalletConfig)({ chains, connectors, rpcUrls }), [wagmiConfigProp, chains, connectors, rpcUrls]);
|
|
19
|
+
return ((0, jsx_runtime_1.jsx)(react_2.ThirdwebProvider, { children: (0, jsx_runtime_1.jsx)(wagmi_1.WagmiProvider, { config: wagmiConfig, reconnectOnMount: reconnectOnMount, children: (0, jsx_runtime_1.jsx)(react_query_1.QueryClientProvider, { client: queryClient, children: children }) }) }));
|
|
20
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Disconnect the current wallet via wagmi.
|
|
3
|
+
* Consumers should use this instead of wagmi's useDisconnect directly
|
|
4
|
+
* to ensure a consistent disconnect API across the wallet module.
|
|
5
|
+
*
|
|
6
|
+
* Note: this only disconnects the wagmi layer. When used inside B3Provider,
|
|
7
|
+
* the thirdweb auth session is managed separately by B3Provider's own logout
|
|
8
|
+
* flow (useAuthentication). ConnectWallet is intended for standalone
|
|
9
|
+
* WalletProvider usage where thirdweb auth is not involved.
|
|
10
|
+
*/
|
|
11
|
+
export declare function useWalletDisconnect(): {
|
|
12
|
+
disconnect: () => void;
|
|
13
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useWalletDisconnect = useWalletDisconnect;
|
|
4
|
+
const react_1 = require("react");
|
|
5
|
+
const wagmi_1 = require("wagmi");
|
|
6
|
+
/**
|
|
7
|
+
* Disconnect the current wallet via wagmi.
|
|
8
|
+
* Consumers should use this instead of wagmi's useDisconnect directly
|
|
9
|
+
* to ensure a consistent disconnect API across the wallet module.
|
|
10
|
+
*
|
|
11
|
+
* Note: this only disconnects the wagmi layer. When used inside B3Provider,
|
|
12
|
+
* the thirdweb auth session is managed separately by B3Provider's own logout
|
|
13
|
+
* flow (useAuthentication). ConnectWallet is intended for standalone
|
|
14
|
+
* WalletProvider usage where thirdweb auth is not involved.
|
|
15
|
+
*/
|
|
16
|
+
function useWalletDisconnect() {
|
|
17
|
+
const { disconnect: wagmiDisconnect } = (0, wagmi_1.useDisconnect)();
|
|
18
|
+
const disconnect = (0, react_1.useCallback)(() => {
|
|
19
|
+
wagmiDisconnect();
|
|
20
|
+
}, [wagmiDisconnect]);
|
|
21
|
+
return { disconnect };
|
|
22
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { Chain } from "viem";
|
|
2
|
+
import type { Connector } from "wagmi";
|
|
3
|
+
export interface WalletConnector {
|
|
4
|
+
/** Display name of the wallet */
|
|
5
|
+
name: string;
|
|
6
|
+
/** Unique identifier for this connector instance */
|
|
7
|
+
uid: string;
|
|
8
|
+
/** Whether the wallet extension/app is detected in the browser */
|
|
9
|
+
isInstalled: boolean;
|
|
10
|
+
/** Connect using this connector. Returns a promise that resolves on success or rejects on failure/rejection. */
|
|
11
|
+
connect: () => Promise<void>;
|
|
12
|
+
/** Raw wagmi connector for advanced use */
|
|
13
|
+
connector: Connector;
|
|
14
|
+
}
|
|
15
|
+
export interface WalletState {
|
|
16
|
+
/** Connected wallet address, or undefined if not connected */
|
|
17
|
+
address: string | undefined;
|
|
18
|
+
/** Whether a wallet is currently connected */
|
|
19
|
+
isConnected: boolean;
|
|
20
|
+
/** Current chain the wallet is connected to */
|
|
21
|
+
chain: Chain | undefined;
|
|
22
|
+
/** Whether a connection attempt is in progress */
|
|
23
|
+
isPending: boolean;
|
|
24
|
+
/** Available wallet connectors, deduplicated by name */
|
|
25
|
+
connectors: WalletConnector[];
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Unified wallet state from both thirdweb and wagmi layers.
|
|
29
|
+
* Provides available connectors with install status and connect functions.
|
|
30
|
+
*/
|
|
31
|
+
export declare function useWalletState(): WalletState;
|