@phantom/react-sdk 1.0.0-beta.21 → 1.0.0-beta.24
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 +372 -52
- package/dist/index.d.ts +47 -17
- package/dist/index.js +894 -199
- package/dist/index.mjs +903 -196
- package/package.json +13 -6
package/dist/index.mjs
CHANGED
|
@@ -1,31 +1,768 @@
|
|
|
1
1
|
// src/PhantomProvider.tsx
|
|
2
|
-
import {
|
|
2
|
+
import { useState as useState8, useEffect as useEffect5, useMemo as useMemo3 } from "react";
|
|
3
3
|
import { BrowserSDK } from "@phantom/browser-sdk";
|
|
4
|
-
import {
|
|
4
|
+
import { mergeTheme, darkTheme, ThemeProvider } from "@phantom/wallet-sdk-ui";
|
|
5
|
+
|
|
6
|
+
// src/PhantomContext.ts
|
|
7
|
+
import { createContext, useContext } from "react";
|
|
5
8
|
var PhantomContext = createContext(void 0);
|
|
6
|
-
function
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
9
|
+
function usePhantom() {
|
|
10
|
+
const context = useContext(PhantomContext);
|
|
11
|
+
if (!context) {
|
|
12
|
+
throw new Error("usePhantom must be used within a PhantomProvider");
|
|
13
|
+
}
|
|
14
|
+
return context;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// src/ModalProvider.tsx
|
|
18
|
+
import { useState as useState7, useCallback as useCallback5, useMemo as useMemo2 } from "react";
|
|
19
|
+
|
|
20
|
+
// src/ModalContext.ts
|
|
21
|
+
import { createContext as createContext2, useContext as useContext2 } from "react";
|
|
22
|
+
var ModalContext = createContext2(void 0);
|
|
23
|
+
function useModal() {
|
|
24
|
+
const context = useContext2(ModalContext);
|
|
25
|
+
if (!context) {
|
|
26
|
+
throw new Error("useModal must be used within a ModalProvider");
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
open: context.openModal,
|
|
30
|
+
close: context.closeModal,
|
|
31
|
+
isOpened: context.isModalOpen
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// src/ModalProvider.tsx
|
|
36
|
+
import { isMobileDevice as isMobileDevice2 } from "@phantom/browser-sdk";
|
|
37
|
+
import { Modal } from "@phantom/wallet-sdk-ui";
|
|
38
|
+
|
|
39
|
+
// src/components/ConnectModalContent.tsx
|
|
40
|
+
import { useState as useState4, useCallback as useCallback3, useMemo } from "react";
|
|
41
|
+
import {
|
|
42
|
+
isMobileDevice,
|
|
43
|
+
getDeeplinkToPhantom
|
|
44
|
+
} from "@phantom/browser-sdk";
|
|
45
|
+
import {
|
|
46
|
+
Button,
|
|
47
|
+
LoginWithPhantomButton,
|
|
48
|
+
Icon as Icon2,
|
|
49
|
+
BoundedIcon,
|
|
50
|
+
Text,
|
|
51
|
+
hexToRgba,
|
|
52
|
+
useTheme as useTheme2,
|
|
53
|
+
ModalHeader
|
|
54
|
+
} from "@phantom/wallet-sdk-ui";
|
|
55
|
+
import { getProviderName } from "@phantom/constants";
|
|
56
|
+
|
|
57
|
+
// src/hooks/useIsExtensionInstalled.ts
|
|
58
|
+
import * as React from "react";
|
|
59
|
+
import { waitForPhantomExtension } from "@phantom/browser-sdk";
|
|
60
|
+
function useIsExtensionInstalled() {
|
|
61
|
+
const [isLoading, setIsLoading] = React.useState(true);
|
|
62
|
+
const [isInstalled, setIsInstalled] = React.useState(false);
|
|
63
|
+
React.useEffect(() => {
|
|
64
|
+
let isMounted = true;
|
|
65
|
+
const checkExtension = async () => {
|
|
66
|
+
try {
|
|
67
|
+
setIsLoading(true);
|
|
68
|
+
const result = await waitForPhantomExtension(3e3);
|
|
69
|
+
if (isMounted) {
|
|
70
|
+
setIsInstalled(result);
|
|
71
|
+
}
|
|
72
|
+
} catch (error) {
|
|
73
|
+
if (isMounted) {
|
|
74
|
+
setIsInstalled(false);
|
|
75
|
+
}
|
|
76
|
+
} finally {
|
|
77
|
+
if (isMounted) {
|
|
78
|
+
setIsLoading(false);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
checkExtension();
|
|
83
|
+
return () => {
|
|
84
|
+
isMounted = false;
|
|
85
|
+
};
|
|
86
|
+
}, []);
|
|
87
|
+
return { isLoading, isInstalled };
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// src/hooks/useIsPhantomLoginAvailable.ts
|
|
91
|
+
import * as React2 from "react";
|
|
92
|
+
import { isPhantomLoginAvailable } from "@phantom/browser-sdk";
|
|
93
|
+
function useIsPhantomLoginAvailable() {
|
|
94
|
+
const [isLoading, setIsLoading] = React2.useState(true);
|
|
95
|
+
const [isAvailable, setIsAvailable] = React2.useState(false);
|
|
96
|
+
React2.useEffect(() => {
|
|
97
|
+
let isMounted = true;
|
|
98
|
+
const checkPhantomLogin = async () => {
|
|
99
|
+
try {
|
|
100
|
+
setIsLoading(true);
|
|
101
|
+
const result = await isPhantomLoginAvailable(3e3);
|
|
102
|
+
if (isMounted) {
|
|
103
|
+
setIsAvailable(result);
|
|
104
|
+
}
|
|
105
|
+
} catch (error) {
|
|
106
|
+
if (isMounted) {
|
|
107
|
+
setIsAvailable(false);
|
|
108
|
+
}
|
|
109
|
+
} finally {
|
|
110
|
+
if (isMounted) {
|
|
111
|
+
setIsLoading(false);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
checkPhantomLogin();
|
|
116
|
+
return () => {
|
|
117
|
+
isMounted = false;
|
|
118
|
+
};
|
|
119
|
+
}, []);
|
|
120
|
+
return { isLoading, isAvailable };
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// src/hooks/useConnect.ts
|
|
124
|
+
import { useCallback } from "react";
|
|
125
|
+
function useConnect() {
|
|
126
|
+
const { sdk, isConnecting, isLoading, connectError } = usePhantom();
|
|
127
|
+
const connect = useCallback(
|
|
128
|
+
async (options) => {
|
|
129
|
+
if (!sdk) {
|
|
130
|
+
throw new Error("SDK not initialized");
|
|
131
|
+
}
|
|
132
|
+
try {
|
|
133
|
+
const result = await sdk.connect(options);
|
|
134
|
+
return result;
|
|
135
|
+
} catch (err) {
|
|
136
|
+
console.error("Error connecting to Phantom:", err);
|
|
137
|
+
throw err;
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
[sdk]
|
|
141
|
+
);
|
|
142
|
+
return {
|
|
143
|
+
connect,
|
|
144
|
+
isConnecting,
|
|
145
|
+
isLoading,
|
|
146
|
+
error: connectError
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// src/hooks/useDiscoveredWallets.ts
|
|
151
|
+
import { useCallback as useCallback2, useState as useState3, useEffect as useEffect3 } from "react";
|
|
152
|
+
function useDiscoveredWallets() {
|
|
153
|
+
const { sdk } = usePhantom();
|
|
154
|
+
const [wallets, setWallets] = useState3([]);
|
|
155
|
+
const [isLoading, setIsLoading] = useState3(true);
|
|
156
|
+
const [error, setError] = useState3(null);
|
|
157
|
+
const refetch = useCallback2(async () => {
|
|
158
|
+
if (!sdk) {
|
|
159
|
+
setWallets([]);
|
|
160
|
+
setError(null);
|
|
161
|
+
setIsLoading(false);
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
try {
|
|
165
|
+
setIsLoading(true);
|
|
166
|
+
setError(null);
|
|
167
|
+
const initialWallets = sdk.getDiscoveredWallets();
|
|
168
|
+
if (initialWallets.length > 0) {
|
|
169
|
+
setWallets(initialWallets);
|
|
170
|
+
setIsLoading(false);
|
|
171
|
+
} else {
|
|
172
|
+
await sdk.discoverWallets();
|
|
173
|
+
const discoveredWallets = sdk.getDiscoveredWallets();
|
|
174
|
+
setWallets(discoveredWallets);
|
|
175
|
+
setIsLoading(false);
|
|
176
|
+
}
|
|
177
|
+
} catch (err) {
|
|
178
|
+
const error2 = err instanceof Error ? err : new Error("Failed to fetch discovered wallets");
|
|
179
|
+
setError(error2);
|
|
180
|
+
setWallets([]);
|
|
181
|
+
setIsLoading(false);
|
|
182
|
+
}
|
|
183
|
+
}, [sdk]);
|
|
184
|
+
useEffect3(() => {
|
|
185
|
+
refetch();
|
|
186
|
+
}, [refetch]);
|
|
187
|
+
return {
|
|
188
|
+
wallets,
|
|
189
|
+
isLoading,
|
|
190
|
+
error,
|
|
191
|
+
refetch
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// src/components/ChainIcon.tsx
|
|
196
|
+
import { Icon, useTheme } from "@phantom/wallet-sdk-ui";
|
|
197
|
+
import { jsx } from "react/jsx-runtime";
|
|
198
|
+
var IconWrapper = ({ children }) => {
|
|
199
|
+
const theme = useTheme();
|
|
200
|
+
return /* @__PURE__ */ jsx(
|
|
201
|
+
"span",
|
|
202
|
+
{
|
|
203
|
+
style: {
|
|
204
|
+
display: "inline-flex",
|
|
205
|
+
alignItems: "center",
|
|
206
|
+
justifyContent: "center",
|
|
207
|
+
borderRadius: "4px",
|
|
208
|
+
backgroundColor: theme.aux,
|
|
209
|
+
color: theme.text,
|
|
210
|
+
padding: "2px"
|
|
211
|
+
},
|
|
212
|
+
children
|
|
213
|
+
}
|
|
214
|
+
);
|
|
215
|
+
};
|
|
216
|
+
function ChainIcon({ addressType, size = 8 }) {
|
|
217
|
+
const theme = useTheme();
|
|
218
|
+
const type = addressType.toLowerCase();
|
|
219
|
+
if (type.includes("solana")) {
|
|
220
|
+
return /* @__PURE__ */ jsx(IconWrapper, { children: /* @__PURE__ */ jsx(Icon, { type: "solana", size, color: theme.text }) });
|
|
221
|
+
}
|
|
222
|
+
if (type.includes("ethereum") || type.includes("evm")) {
|
|
223
|
+
return /* @__PURE__ */ jsx(IconWrapper, { children: /* @__PURE__ */ jsx(Icon, { type: "ethereum", size, color: theme.text }) });
|
|
224
|
+
}
|
|
225
|
+
if (type.includes("bitcoin")) {
|
|
226
|
+
return /* @__PURE__ */ jsx(IconWrapper, { children: /* @__PURE__ */ jsx(Icon, { type: "bitcoin", size, color: theme.text }) });
|
|
227
|
+
}
|
|
228
|
+
if (type.includes("sui")) {
|
|
229
|
+
return /* @__PURE__ */ jsx(IconWrapper, { children: /* @__PURE__ */ jsx(Icon, { type: "sui", size, color: theme.text }) });
|
|
230
|
+
}
|
|
231
|
+
return /* @__PURE__ */ jsx(
|
|
232
|
+
"span",
|
|
233
|
+
{
|
|
234
|
+
style: {
|
|
235
|
+
display: "inline-flex",
|
|
236
|
+
alignItems: "center",
|
|
237
|
+
justifyContent: "center",
|
|
238
|
+
borderRadius: "4px",
|
|
239
|
+
backgroundColor: theme.aux,
|
|
240
|
+
color: theme.text,
|
|
241
|
+
fontSize: "6px",
|
|
242
|
+
fontWeight: "bold",
|
|
243
|
+
lineHeight: "1",
|
|
244
|
+
padding: "2px"
|
|
245
|
+
},
|
|
246
|
+
title: addressType,
|
|
247
|
+
children: addressType.charAt(0).toUpperCase()
|
|
248
|
+
}
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// src/components/ConnectModalContent.tsx
|
|
253
|
+
import { Fragment, jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
254
|
+
function ConnectModalContent({ appIcon, appName = "App Name", onClose }) {
|
|
255
|
+
const theme = useTheme2();
|
|
256
|
+
const { isLoading, allowedProviders } = usePhantom();
|
|
257
|
+
const baseConnect = useConnect();
|
|
258
|
+
const isExtensionInstalled = useIsExtensionInstalled();
|
|
259
|
+
const isPhantomLoginAvailable2 = useIsPhantomLoginAvailable();
|
|
260
|
+
const isMobile = useMemo(() => isMobileDevice(), []);
|
|
261
|
+
const { wallets: discoveredWallets } = useDiscoveredWallets();
|
|
262
|
+
const [isConnecting, setIsConnecting] = useState4(false);
|
|
263
|
+
const [error, setError] = useState4(null);
|
|
264
|
+
const [providerType, setProviderType] = useState4(null);
|
|
265
|
+
const [showOtherWallets, setShowOtherWallets] = useState4(false);
|
|
266
|
+
const [selectedWalletId, setSelectedWalletId] = useState4(null);
|
|
267
|
+
const showDivider = !(allowedProviders.length === 1 && allowedProviders.includes("injected"));
|
|
268
|
+
const shouldShowOtherWalletsButton = discoveredWallets.length > 2;
|
|
269
|
+
const walletsToShowInline = shouldShowOtherWalletsButton ? [] : discoveredWallets;
|
|
270
|
+
const connectWithAuthProvider = useCallback3(
|
|
271
|
+
async (provider, walletId) => {
|
|
272
|
+
try {
|
|
273
|
+
setIsConnecting(true);
|
|
274
|
+
setError(null);
|
|
275
|
+
setProviderType(provider);
|
|
276
|
+
setSelectedWalletId(walletId || null);
|
|
277
|
+
await baseConnect.connect({ provider, walletId });
|
|
278
|
+
onClose();
|
|
279
|
+
} catch {
|
|
280
|
+
const wallet = discoveredWallets.find((w) => w.id === walletId);
|
|
281
|
+
const providerName = wallet?.name || getProviderName(provider);
|
|
282
|
+
setError(`Failed to connect to ${providerName}`);
|
|
283
|
+
} finally {
|
|
284
|
+
setIsConnecting(false);
|
|
285
|
+
setProviderType(null);
|
|
286
|
+
setSelectedWalletId(null);
|
|
287
|
+
}
|
|
288
|
+
},
|
|
289
|
+
[baseConnect, discoveredWallets, onClose]
|
|
290
|
+
);
|
|
291
|
+
const connectWithWallet = useCallback3(
|
|
292
|
+
async (wallet) => {
|
|
293
|
+
await connectWithAuthProvider("injected", wallet.id);
|
|
294
|
+
},
|
|
295
|
+
[connectWithAuthProvider]
|
|
296
|
+
);
|
|
297
|
+
const connectWithDeeplink = useCallback3(() => {
|
|
298
|
+
try {
|
|
299
|
+
setIsConnecting(true);
|
|
300
|
+
setError(null);
|
|
301
|
+
setProviderType("deeplink");
|
|
302
|
+
const deeplinkUrl = getDeeplinkToPhantom();
|
|
303
|
+
window.location.href = deeplinkUrl;
|
|
304
|
+
onClose();
|
|
305
|
+
} catch {
|
|
306
|
+
setError("Failed to open deeplink");
|
|
307
|
+
} finally {
|
|
308
|
+
setIsConnecting(false);
|
|
309
|
+
setProviderType(null);
|
|
310
|
+
}
|
|
311
|
+
}, [onClose]);
|
|
312
|
+
const appIconStyle = {
|
|
313
|
+
width: "56px",
|
|
314
|
+
height: "56px",
|
|
315
|
+
borderRadius: "50%",
|
|
316
|
+
display: "block",
|
|
317
|
+
objectFit: "cover",
|
|
318
|
+
marginBottom: "12px"
|
|
319
|
+
};
|
|
320
|
+
const connectContentContainerStyle = {
|
|
321
|
+
transition: "opacity 0.15s ease-in-out, transform 0.15s ease-in-out",
|
|
322
|
+
display: "flex",
|
|
323
|
+
flexDirection: "column",
|
|
324
|
+
alignItems: "center",
|
|
325
|
+
gap: "12px",
|
|
326
|
+
padding: "0 32px"
|
|
327
|
+
};
|
|
328
|
+
const otherWalletsContainerStyle = {
|
|
329
|
+
display: "flex",
|
|
330
|
+
flexDirection: "column",
|
|
331
|
+
alignItems: "center",
|
|
332
|
+
gap: "12px",
|
|
333
|
+
maxHeight: "480px",
|
|
334
|
+
overflowY: "auto",
|
|
335
|
+
padding: "0 32px 32px 32px",
|
|
336
|
+
transition: "opacity 0.15s ease-in-out, transform 0.15s ease-in-out"
|
|
337
|
+
};
|
|
338
|
+
const dividerStyle = {
|
|
339
|
+
display: "flex",
|
|
340
|
+
alignItems: "center",
|
|
341
|
+
width: "100%",
|
|
342
|
+
margin: "12px 0",
|
|
343
|
+
...theme.typography.caption,
|
|
344
|
+
color: theme.secondary,
|
|
345
|
+
textTransform: "uppercase"
|
|
346
|
+
};
|
|
347
|
+
const dividerLineStyle = {
|
|
348
|
+
flex: 1,
|
|
349
|
+
height: "1px",
|
|
350
|
+
backgroundColor: hexToRgba(theme.secondary, 0.1)
|
|
351
|
+
};
|
|
352
|
+
const dividerTextStyle = {
|
|
353
|
+
padding: "0 12px"
|
|
354
|
+
};
|
|
355
|
+
const errorStyle = {
|
|
356
|
+
backgroundColor: "rgba(220, 53, 69, 0.1)",
|
|
357
|
+
color: "#ff6b6b",
|
|
358
|
+
border: "1px solid rgba(220, 53, 69, 0.3)",
|
|
359
|
+
borderRadius: theme.borderRadius,
|
|
360
|
+
boxSizing: "border-box",
|
|
361
|
+
padding: "12px",
|
|
362
|
+
width: "100%",
|
|
363
|
+
fontSize: "14px"
|
|
364
|
+
};
|
|
365
|
+
const loadingContainerStyle = {
|
|
366
|
+
display: "flex",
|
|
367
|
+
flexDirection: "column",
|
|
368
|
+
alignItems: "center",
|
|
369
|
+
justifyContent: "center",
|
|
370
|
+
padding: "24px",
|
|
371
|
+
gap: "12px"
|
|
372
|
+
};
|
|
373
|
+
const spinnerStyle = {
|
|
374
|
+
width: "40px",
|
|
375
|
+
height: "40px",
|
|
376
|
+
border: `3px solid ${theme.secondary}`,
|
|
377
|
+
borderTop: `3px solid ${theme.brand}`,
|
|
378
|
+
borderRadius: "50%",
|
|
379
|
+
animation: "spin 1s linear infinite"
|
|
380
|
+
};
|
|
381
|
+
const walletIconStyle = {
|
|
382
|
+
width: "32px",
|
|
383
|
+
height: "32px",
|
|
384
|
+
borderRadius: "8px",
|
|
385
|
+
objectFit: "cover"
|
|
386
|
+
};
|
|
387
|
+
const walletButtonContentStyle = {
|
|
388
|
+
display: "flex",
|
|
389
|
+
alignItems: "center",
|
|
390
|
+
justifyContent: "space-between",
|
|
391
|
+
gap: "8px",
|
|
392
|
+
width: "100%"
|
|
393
|
+
};
|
|
394
|
+
const walletButtonLeftStyle = {
|
|
395
|
+
display: "flex",
|
|
396
|
+
alignItems: "center",
|
|
397
|
+
gap: "8px",
|
|
398
|
+
flex: 1
|
|
399
|
+
};
|
|
400
|
+
const walletNameContainerStyle = {
|
|
401
|
+
display: "flex",
|
|
402
|
+
flexDirection: "column",
|
|
403
|
+
gap: "4px",
|
|
404
|
+
alignItems: "flex-start"
|
|
405
|
+
};
|
|
406
|
+
const chainIndicatorsStyle = {
|
|
407
|
+
display: "flex",
|
|
408
|
+
alignItems: "center",
|
|
409
|
+
gap: "4px"
|
|
410
|
+
};
|
|
411
|
+
const walletButtonRightStyle = {
|
|
412
|
+
display: "flex",
|
|
413
|
+
alignItems: "center",
|
|
414
|
+
gap: "8px",
|
|
415
|
+
color: theme.secondary
|
|
416
|
+
};
|
|
417
|
+
const footerStyle = {
|
|
418
|
+
display: "flex",
|
|
419
|
+
padding: "16px",
|
|
420
|
+
justifyContent: "center",
|
|
421
|
+
alignItems: "center",
|
|
422
|
+
gap: "4px",
|
|
423
|
+
borderTop: "1px solid rgba(152, 151, 156, 0.10)",
|
|
424
|
+
...theme.typography.caption,
|
|
425
|
+
color: theme.secondary
|
|
426
|
+
};
|
|
427
|
+
const contentWrapperStyle = {
|
|
428
|
+
display: "flex",
|
|
429
|
+
flexDirection: "column",
|
|
430
|
+
justifyContent: "space-between",
|
|
431
|
+
gap: "24px"
|
|
432
|
+
};
|
|
433
|
+
return /* @__PURE__ */ jsxs("div", { style: contentWrapperStyle, children: [
|
|
434
|
+
/* @__PURE__ */ jsx2("style", { children: `
|
|
435
|
+
@keyframes spin {
|
|
436
|
+
0% { transform: rotate(0deg); }
|
|
437
|
+
100% { transform: rotate(360deg); }
|
|
438
|
+
}
|
|
439
|
+
` }),
|
|
440
|
+
isLoading ? /* @__PURE__ */ jsxs("div", { style: loadingContainerStyle, children: [
|
|
441
|
+
/* @__PURE__ */ jsx2("div", { style: spinnerStyle }),
|
|
442
|
+
/* @__PURE__ */ jsx2(Text, { variant: "label", color: theme.secondary, children: "Loading..." })
|
|
443
|
+
] }) : showOtherWallets ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
444
|
+
/* @__PURE__ */ jsx2(
|
|
445
|
+
ModalHeader,
|
|
446
|
+
{
|
|
447
|
+
goBack: true,
|
|
448
|
+
onGoBack: () => {
|
|
449
|
+
setError(null);
|
|
450
|
+
setShowOtherWallets(false);
|
|
451
|
+
},
|
|
452
|
+
title: "Other Wallets",
|
|
453
|
+
onClose
|
|
454
|
+
}
|
|
455
|
+
),
|
|
456
|
+
/* @__PURE__ */ jsxs("div", { style: otherWalletsContainerStyle, children: [
|
|
457
|
+
error && /* @__PURE__ */ jsx2("div", { style: errorStyle, children: error }),
|
|
458
|
+
discoveredWallets.map((wallet) => /* @__PURE__ */ jsx2(
|
|
459
|
+
Button,
|
|
460
|
+
{
|
|
461
|
+
onClick: () => connectWithWallet(wallet),
|
|
462
|
+
disabled: isConnecting,
|
|
463
|
+
isLoading: isConnecting && providerType === "injected" && selectedWalletId === wallet.id,
|
|
464
|
+
fullWidth: true,
|
|
465
|
+
children: /* @__PURE__ */ jsxs("span", { style: walletButtonContentStyle, children: [
|
|
466
|
+
/* @__PURE__ */ jsxs("span", { style: walletButtonLeftStyle, children: [
|
|
467
|
+
wallet.icon ? /* @__PURE__ */ jsx2("img", { src: wallet.icon, alt: wallet.name, style: walletIconStyle }) : /* @__PURE__ */ jsx2(BoundedIcon, { type: "wallet", size: 20, background: theme.aux, color: theme.text }),
|
|
468
|
+
/* @__PURE__ */ jsxs("span", { style: walletNameContainerStyle, children: [
|
|
469
|
+
/* @__PURE__ */ jsx2(Text, { variant: "captionBold", children: wallet.name }),
|
|
470
|
+
wallet.addressTypes && wallet.addressTypes.length > 0 && /* @__PURE__ */ jsx2("span", { style: chainIndicatorsStyle, children: wallet.addressTypes.map((addressType) => /* @__PURE__ */ jsx2(ChainIcon, { addressType, size: 8 }, `${wallet.id}-chain-${addressType}`)) })
|
|
471
|
+
] })
|
|
472
|
+
] }),
|
|
473
|
+
/* @__PURE__ */ jsxs("span", { style: walletButtonRightStyle, children: [
|
|
474
|
+
/* @__PURE__ */ jsx2(Text, { variant: "label", color: theme.secondary, children: "Detected" }),
|
|
475
|
+
/* @__PURE__ */ jsx2(Icon2, { type: "chevron-right", size: 16, color: theme.secondary })
|
|
476
|
+
] })
|
|
477
|
+
] })
|
|
478
|
+
},
|
|
479
|
+
wallet.id
|
|
480
|
+
))
|
|
481
|
+
] })
|
|
482
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
483
|
+
/* @__PURE__ */ jsx2(ModalHeader, { title: "Login or Sign Up", onClose }),
|
|
484
|
+
/* @__PURE__ */ jsxs("div", { style: connectContentContainerStyle, children: [
|
|
485
|
+
appIcon && /* @__PURE__ */ jsx2("img", { src: appIcon, alt: appName, style: appIconStyle }),
|
|
486
|
+
error && /* @__PURE__ */ jsx2("div", { style: errorStyle, children: error }),
|
|
487
|
+
isMobile && !isExtensionInstalled.isInstalled && /* @__PURE__ */ jsx2(
|
|
488
|
+
Button,
|
|
489
|
+
{
|
|
490
|
+
onClick: connectWithDeeplink,
|
|
491
|
+
disabled: isConnecting,
|
|
492
|
+
isLoading: isConnecting && providerType === "deeplink",
|
|
493
|
+
fullWidth: true,
|
|
494
|
+
children: isConnecting && providerType === "deeplink" ? "Opening Phantom..." : "Open in Phantom App"
|
|
495
|
+
}
|
|
496
|
+
),
|
|
497
|
+
!isMobile && allowedProviders.includes("phantom") && isPhantomLoginAvailable2.isAvailable && /* @__PURE__ */ jsx2(
|
|
498
|
+
LoginWithPhantomButton,
|
|
499
|
+
{
|
|
500
|
+
onClick: () => connectWithAuthProvider("phantom"),
|
|
501
|
+
disabled: isConnecting,
|
|
502
|
+
isLoading: isConnecting && providerType === "phantom"
|
|
503
|
+
}
|
|
504
|
+
),
|
|
505
|
+
allowedProviders.includes("google") && /* @__PURE__ */ jsx2(
|
|
506
|
+
Button,
|
|
507
|
+
{
|
|
508
|
+
onClick: () => connectWithAuthProvider("google"),
|
|
509
|
+
disabled: isConnecting,
|
|
510
|
+
isLoading: isConnecting && providerType === "google",
|
|
511
|
+
fullWidth: true,
|
|
512
|
+
children: /* @__PURE__ */ jsxs("span", { style: walletButtonContentStyle, children: [
|
|
513
|
+
/* @__PURE__ */ jsxs("span", { style: walletButtonLeftStyle, children: [
|
|
514
|
+
/* @__PURE__ */ jsx2(Icon2, { type: "google", size: 20 }),
|
|
515
|
+
/* @__PURE__ */ jsx2(Text, { variant: "captionBold", children: "Continue with Google" })
|
|
516
|
+
] }),
|
|
517
|
+
/* @__PURE__ */ jsx2("span", { style: walletButtonRightStyle, children: /* @__PURE__ */ jsx2(Icon2, { type: "chevron-right", size: 16, color: theme.secondary }) })
|
|
518
|
+
] })
|
|
519
|
+
}
|
|
520
|
+
),
|
|
521
|
+
allowedProviders.includes("apple") && /* @__PURE__ */ jsx2(
|
|
522
|
+
Button,
|
|
523
|
+
{
|
|
524
|
+
onClick: () => connectWithAuthProvider("apple"),
|
|
525
|
+
disabled: isConnecting,
|
|
526
|
+
isLoading: isConnecting && providerType === "apple",
|
|
527
|
+
fullWidth: true,
|
|
528
|
+
children: /* @__PURE__ */ jsxs("span", { style: walletButtonContentStyle, children: [
|
|
529
|
+
/* @__PURE__ */ jsxs("span", { style: walletButtonLeftStyle, children: [
|
|
530
|
+
/* @__PURE__ */ jsx2(Icon2, { type: "apple", size: 20 }),
|
|
531
|
+
/* @__PURE__ */ jsx2(Text, { variant: "captionBold", children: "Continue with Apple" })
|
|
532
|
+
] }),
|
|
533
|
+
/* @__PURE__ */ jsx2("span", { style: walletButtonRightStyle, children: /* @__PURE__ */ jsx2(Icon2, { type: "chevron-right", size: 16, color: theme.secondary }) })
|
|
534
|
+
] })
|
|
535
|
+
}
|
|
536
|
+
),
|
|
537
|
+
!isMobile && allowedProviders.includes("injected") && isExtensionInstalled.isInstalled && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
538
|
+
showDivider && /* @__PURE__ */ jsxs("div", { style: dividerStyle, children: [
|
|
539
|
+
/* @__PURE__ */ jsx2("div", { style: dividerLineStyle }),
|
|
540
|
+
/* @__PURE__ */ jsx2("span", { style: dividerTextStyle, children: "OR" }),
|
|
541
|
+
/* @__PURE__ */ jsx2("div", { style: dividerLineStyle })
|
|
542
|
+
] }),
|
|
543
|
+
walletsToShowInline.map((wallet) => /* @__PURE__ */ jsx2(
|
|
544
|
+
Button,
|
|
545
|
+
{
|
|
546
|
+
onClick: () => connectWithWallet(wallet),
|
|
547
|
+
disabled: isConnecting,
|
|
548
|
+
isLoading: isConnecting && providerType === "injected" && selectedWalletId === wallet.id,
|
|
549
|
+
fullWidth: true,
|
|
550
|
+
children: /* @__PURE__ */ jsxs("span", { style: walletButtonContentStyle, children: [
|
|
551
|
+
/* @__PURE__ */ jsxs("span", { style: walletButtonLeftStyle, children: [
|
|
552
|
+
wallet.icon ? /* @__PURE__ */ jsx2("img", { src: wallet.icon, alt: wallet.name, style: walletIconStyle }) : /* @__PURE__ */ jsx2(BoundedIcon, { type: "wallet", size: 10, background: theme.aux, color: theme.text }),
|
|
553
|
+
/* @__PURE__ */ jsxs("span", { style: walletNameContainerStyle, children: [
|
|
554
|
+
/* @__PURE__ */ jsx2(Text, { variant: "captionBold", children: wallet.name }),
|
|
555
|
+
wallet.addressTypes && wallet.addressTypes.length > 0 && /* @__PURE__ */ jsx2("span", { style: chainIndicatorsStyle, children: wallet.addressTypes.map((addressType) => /* @__PURE__ */ jsx2(
|
|
556
|
+
ChainIcon,
|
|
557
|
+
{
|
|
558
|
+
addressType,
|
|
559
|
+
size: 8
|
|
560
|
+
},
|
|
561
|
+
`${wallet.id}-chain-${addressType}`
|
|
562
|
+
)) })
|
|
563
|
+
] })
|
|
564
|
+
] }),
|
|
565
|
+
/* @__PURE__ */ jsxs("span", { style: walletButtonRightStyle, children: [
|
|
566
|
+
/* @__PURE__ */ jsx2(Text, { variant: "label", color: theme.secondary, children: "Detected" }),
|
|
567
|
+
/* @__PURE__ */ jsx2(Icon2, { type: "chevron-right", size: 16, color: theme.secondary })
|
|
568
|
+
] })
|
|
569
|
+
] })
|
|
570
|
+
},
|
|
571
|
+
wallet.id
|
|
572
|
+
)),
|
|
573
|
+
shouldShowOtherWalletsButton && /* @__PURE__ */ jsx2(Button, { onClick: () => setShowOtherWallets(true), disabled: isConnecting, fullWidth: true, children: /* @__PURE__ */ jsxs("span", { style: walletButtonContentStyle, children: [
|
|
574
|
+
/* @__PURE__ */ jsxs("span", { style: walletButtonLeftStyle, children: [
|
|
575
|
+
/* @__PURE__ */ jsx2(BoundedIcon, { type: "wallet", size: 20, background: theme.aux, color: theme.text }),
|
|
576
|
+
/* @__PURE__ */ jsx2(Text, { variant: "captionBold", children: "Other Wallets" })
|
|
577
|
+
] }),
|
|
578
|
+
/* @__PURE__ */ jsx2("span", { style: walletButtonRightStyle, children: /* @__PURE__ */ jsx2(Icon2, { type: "chevron-right", size: 16, color: theme.secondary }) })
|
|
579
|
+
] }) })
|
|
580
|
+
] })
|
|
581
|
+
] }),
|
|
582
|
+
/* @__PURE__ */ jsxs("div", { style: footerStyle, children: [
|
|
583
|
+
/* @__PURE__ */ jsx2(Text, { variant: "label", color: theme.secondary, children: "Powered by" }),
|
|
584
|
+
/* @__PURE__ */ jsx2(Icon2, { type: "phantom", size: 16 }),
|
|
585
|
+
/* @__PURE__ */ jsx2(Text, { variant: "label", color: theme.secondary, children: "Phantom" })
|
|
586
|
+
] })
|
|
587
|
+
] })
|
|
588
|
+
] });
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
// src/components/ConnectedModalContent.tsx
|
|
592
|
+
import { useState as useState6, useEffect as useEffect4 } from "react";
|
|
593
|
+
import { Button as Button2, Text as Text2, useTheme as useTheme3, ModalHeader as ModalHeader2 } from "@phantom/wallet-sdk-ui";
|
|
594
|
+
|
|
595
|
+
// src/hooks/useDisconnect.ts
|
|
596
|
+
import { useCallback as useCallback4, useState as useState5 } from "react";
|
|
597
|
+
function useDisconnect() {
|
|
598
|
+
const { sdk } = usePhantom();
|
|
599
|
+
const [isDisconnecting, setIsDisconnecting] = useState5(false);
|
|
600
|
+
const [error, setError] = useState5(null);
|
|
601
|
+
const disconnect = useCallback4(async () => {
|
|
602
|
+
if (!sdk) {
|
|
603
|
+
throw new Error("SDK not initialized");
|
|
604
|
+
}
|
|
605
|
+
setIsDisconnecting(true);
|
|
606
|
+
setError(null);
|
|
607
|
+
try {
|
|
608
|
+
await sdk.disconnect();
|
|
609
|
+
} catch (err) {
|
|
610
|
+
const error2 = err instanceof Error ? err : new Error(String(err));
|
|
611
|
+
setError(error2);
|
|
612
|
+
throw err;
|
|
613
|
+
} finally {
|
|
614
|
+
setIsDisconnecting(false);
|
|
615
|
+
}
|
|
616
|
+
}, [sdk]);
|
|
617
|
+
return {
|
|
618
|
+
disconnect,
|
|
619
|
+
isDisconnecting,
|
|
620
|
+
error
|
|
621
|
+
};
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
// src/components/ConnectedModalContent.tsx
|
|
625
|
+
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
626
|
+
function ConnectedModalContent({ onClose }) {
|
|
627
|
+
const theme = useTheme3();
|
|
628
|
+
const { addresses } = usePhantom();
|
|
629
|
+
const { disconnect } = useDisconnect();
|
|
630
|
+
const [isDisconnecting, setIsDisconnecting] = useState6(false);
|
|
631
|
+
const [disconnectError, setDisconnectError] = useState6(null);
|
|
632
|
+
useEffect4(() => {
|
|
633
|
+
setDisconnectError(null);
|
|
634
|
+
}, []);
|
|
635
|
+
const handleDisconnect = async () => {
|
|
636
|
+
try {
|
|
637
|
+
setIsDisconnecting(true);
|
|
638
|
+
setDisconnectError(null);
|
|
639
|
+
await disconnect();
|
|
640
|
+
onClose();
|
|
641
|
+
} catch (err) {
|
|
642
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
643
|
+
setDisconnectError(error);
|
|
644
|
+
} finally {
|
|
645
|
+
setIsDisconnecting(false);
|
|
646
|
+
}
|
|
647
|
+
};
|
|
648
|
+
const accountListStyle = {
|
|
649
|
+
display: "flex",
|
|
650
|
+
flexDirection: "column",
|
|
651
|
+
gap: "16px",
|
|
652
|
+
width: "100%",
|
|
653
|
+
minWidth: 0,
|
|
654
|
+
boxSizing: "border-box"
|
|
655
|
+
};
|
|
656
|
+
const accountItemStyle = {
|
|
657
|
+
display: "flex",
|
|
658
|
+
flexDirection: "column",
|
|
659
|
+
gap: "8px",
|
|
660
|
+
width: "100%",
|
|
661
|
+
minWidth: 0,
|
|
662
|
+
boxSizing: "border-box"
|
|
663
|
+
};
|
|
664
|
+
const addressTextStyle = {
|
|
665
|
+
fontFamily: "monospace",
|
|
666
|
+
wordBreak: "break-all",
|
|
667
|
+
overflowWrap: "break-word",
|
|
668
|
+
minWidth: 0
|
|
669
|
+
};
|
|
670
|
+
const errorContainerStyle = {
|
|
671
|
+
padding: "12px",
|
|
672
|
+
backgroundColor: "rgba(220, 53, 69, 0.1)",
|
|
673
|
+
borderRadius: theme.borderRadius,
|
|
674
|
+
border: "1px solid rgba(220, 53, 69, 0.3)",
|
|
675
|
+
width: "100%",
|
|
676
|
+
boxSizing: "border-box",
|
|
677
|
+
minWidth: 0
|
|
678
|
+
};
|
|
679
|
+
const contentWrapperStyle = {
|
|
680
|
+
display: "flex",
|
|
681
|
+
flexDirection: "column",
|
|
682
|
+
gap: "24px"
|
|
683
|
+
};
|
|
684
|
+
const accountListContainerStyle = {
|
|
685
|
+
display: "flex",
|
|
686
|
+
flexDirection: "column",
|
|
687
|
+
alignItems: "center",
|
|
688
|
+
gap: "12px",
|
|
689
|
+
padding: "0 32px 24px 32px",
|
|
690
|
+
boxSizing: "border-box",
|
|
691
|
+
width: "100%",
|
|
692
|
+
minWidth: 0
|
|
693
|
+
};
|
|
694
|
+
const disconnectButtonContainerStyle = {
|
|
695
|
+
display: "flex",
|
|
696
|
+
flexDirection: "column",
|
|
697
|
+
alignItems: "center",
|
|
698
|
+
gap: "12px",
|
|
699
|
+
padding: "0 32px 24px 32px",
|
|
700
|
+
boxSizing: "border-box",
|
|
701
|
+
width: "100%",
|
|
702
|
+
minWidth: 0
|
|
703
|
+
};
|
|
704
|
+
return /* @__PURE__ */ jsxs2("div", { style: contentWrapperStyle, children: [
|
|
705
|
+
/* @__PURE__ */ jsx3(ModalHeader2, { title: "Wallet", onClose }),
|
|
706
|
+
/* @__PURE__ */ jsxs2("div", { style: accountListContainerStyle, children: [
|
|
707
|
+
disconnectError && /* @__PURE__ */ jsx3("div", { style: errorContainerStyle, children: /* @__PURE__ */ jsx3(Text2, { variant: "caption", color: theme.error, children: "Failed to disconnect" }) }),
|
|
708
|
+
addresses && addresses.length > 0 && /* @__PURE__ */ jsx3("div", { style: accountListStyle, children: addresses.map((account, index) => /* @__PURE__ */ jsxs2("div", { style: accountItemStyle, children: [
|
|
709
|
+
/* @__PURE__ */ jsx3(Text2, { variant: "label", color: theme.secondary, style: { textTransform: "uppercase" }, children: account.addressType }),
|
|
710
|
+
/* @__PURE__ */ jsx3("div", { style: addressTextStyle, children: /* @__PURE__ */ jsx3(Text2, { variant: "caption", children: account.address }) })
|
|
711
|
+
] }, index)) })
|
|
712
|
+
] }),
|
|
713
|
+
/* @__PURE__ */ jsx3("div", { style: disconnectButtonContainerStyle, children: /* @__PURE__ */ jsx3(Button2, { onClick: handleDisconnect, disabled: isDisconnecting, isLoading: isDisconnecting, fullWidth: true, children: /* @__PURE__ */ jsx3(Text2, { variant: "captionBold", children: isDisconnecting ? "Disconnecting..." : "Disconnect" }) }) })
|
|
714
|
+
] });
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
// src/ModalProvider.tsx
|
|
718
|
+
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
719
|
+
function ModalProvider({ children, appIcon, appName }) {
|
|
720
|
+
const { isConnected } = usePhantom();
|
|
721
|
+
const [isModalOpen, setIsModalOpen] = useState7(false);
|
|
722
|
+
const isMobile = useMemo2(() => isMobileDevice2(), []);
|
|
723
|
+
const openModal = useCallback5(() => {
|
|
724
|
+
setIsModalOpen(true);
|
|
725
|
+
}, []);
|
|
726
|
+
const closeModal = useCallback5(() => {
|
|
727
|
+
setIsModalOpen(false);
|
|
728
|
+
}, []);
|
|
729
|
+
const modalContextValue = useMemo2(
|
|
730
|
+
() => ({
|
|
731
|
+
isModalOpen,
|
|
732
|
+
openModal,
|
|
733
|
+
closeModal
|
|
734
|
+
}),
|
|
735
|
+
[isModalOpen, openModal, closeModal]
|
|
16
736
|
);
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
737
|
+
return /* @__PURE__ */ jsxs3(ModalContext.Provider, { value: modalContextValue, children: [
|
|
738
|
+
children,
|
|
739
|
+
/* @__PURE__ */ jsx4(Modal, { isVisible: isModalOpen, onClose: closeModal, appIcon, appName, isMobile, children: isConnected ? /* @__PURE__ */ jsx4(ConnectedModalContent, { onClose: closeModal }) : /* @__PURE__ */ jsx4(ConnectModalContent, { appIcon, appName, onClose: closeModal }) })
|
|
740
|
+
] });
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
// src/PhantomProvider.tsx
|
|
744
|
+
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
745
|
+
function PhantomProvider({ children, config, debugConfig, theme, appIcon, appName }) {
|
|
746
|
+
const memoizedConfig = useMemo3(() => config, [config]);
|
|
747
|
+
const resolvedTheme = useMemo3(() => mergeTheme(theme || darkTheme), [theme]);
|
|
748
|
+
const [sdk, setSdk] = useState8(null);
|
|
749
|
+
const [isClient, setIsClient] = useState8(false);
|
|
750
|
+
const [isConnected, setIsConnected] = useState8(false);
|
|
751
|
+
const [isConnecting, setIsConnecting] = useState8(false);
|
|
752
|
+
const [isLoading, setIsLoading] = useState8(true);
|
|
753
|
+
const [connectError, setConnectError] = useState8(null);
|
|
754
|
+
const [addresses, setAddresses] = useState8([]);
|
|
755
|
+
const [user, setUser] = useState8(null);
|
|
756
|
+
useEffect5(() => {
|
|
20
757
|
setIsClient(true);
|
|
21
758
|
}, []);
|
|
22
|
-
|
|
759
|
+
useEffect5(() => {
|
|
23
760
|
if (!isClient)
|
|
24
761
|
return;
|
|
25
762
|
const sdkInstance = new BrowserSDK(memoizedConfig);
|
|
26
763
|
setSdk(sdkInstance);
|
|
27
764
|
}, [isClient, memoizedConfig]);
|
|
28
|
-
|
|
765
|
+
useEffect5(() => {
|
|
29
766
|
if (!sdk)
|
|
30
767
|
return;
|
|
31
768
|
const handleConnectStart = () => {
|
|
@@ -37,7 +774,6 @@ function PhantomProvider({ children, config, debugConfig }) {
|
|
|
37
774
|
setIsConnected(true);
|
|
38
775
|
setIsConnecting(false);
|
|
39
776
|
setUser(data);
|
|
40
|
-
setCurrentProviderType(data.providerType || null);
|
|
41
777
|
const addrs = await sdk.getAddresses();
|
|
42
778
|
setAddresses(addrs);
|
|
43
779
|
} catch (err) {
|
|
@@ -73,107 +809,51 @@ function PhantomProvider({ children, config, debugConfig }) {
|
|
|
73
809
|
sdk.off("disconnect", handleDisconnect);
|
|
74
810
|
};
|
|
75
811
|
}, [sdk]);
|
|
76
|
-
|
|
812
|
+
useEffect5(() => {
|
|
77
813
|
if (!debugConfig || !sdk)
|
|
78
814
|
return;
|
|
79
815
|
sdk.configureDebug(debugConfig);
|
|
80
816
|
}, [sdk, debugConfig]);
|
|
81
|
-
|
|
817
|
+
useEffect5(() => {
|
|
82
818
|
if (!isClient || !sdk)
|
|
83
819
|
return;
|
|
84
820
|
const initialize = async () => {
|
|
85
821
|
try {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
console.error("Error checking Phantom extension:", err);
|
|
90
|
-
setIsPhantomAvailable(false);
|
|
91
|
-
}
|
|
92
|
-
if (memoizedConfig.autoConnect !== false) {
|
|
93
|
-
sdk.autoConnect().catch(() => {
|
|
94
|
-
});
|
|
822
|
+
await sdk.autoConnect();
|
|
823
|
+
} catch (error) {
|
|
824
|
+
console.error("Auto-connect error:", error);
|
|
95
825
|
}
|
|
826
|
+
setIsLoading(false);
|
|
96
827
|
};
|
|
97
828
|
initialize();
|
|
98
|
-
}, [sdk,
|
|
99
|
-
const value =
|
|
829
|
+
}, [sdk, isClient]);
|
|
830
|
+
const value = useMemo3(
|
|
100
831
|
() => ({
|
|
101
832
|
sdk,
|
|
102
833
|
isConnected,
|
|
103
834
|
isConnecting,
|
|
835
|
+
isLoading,
|
|
104
836
|
connectError,
|
|
105
837
|
addresses,
|
|
106
|
-
currentProviderType,
|
|
107
|
-
isPhantomAvailable,
|
|
108
838
|
isClient,
|
|
109
|
-
user
|
|
839
|
+
user,
|
|
840
|
+
theme: resolvedTheme,
|
|
841
|
+
allowedProviders: memoizedConfig.providers
|
|
110
842
|
}),
|
|
111
|
-
[
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
// src/hooks/useConnect.ts
|
|
124
|
-
import { useCallback } from "react";
|
|
125
|
-
function useConnect() {
|
|
126
|
-
const { sdk, isConnecting, connectError, currentProviderType, isPhantomAvailable } = usePhantom();
|
|
127
|
-
const connect = useCallback(
|
|
128
|
-
async (options) => {
|
|
129
|
-
if (!sdk) {
|
|
130
|
-
throw new Error("SDK not initialized");
|
|
131
|
-
}
|
|
132
|
-
try {
|
|
133
|
-
const result = await sdk.connect(options);
|
|
134
|
-
return result;
|
|
135
|
-
} catch (err) {
|
|
136
|
-
console.error("Error connecting to Phantom:", err);
|
|
137
|
-
throw err;
|
|
138
|
-
}
|
|
139
|
-
},
|
|
140
|
-
[sdk]
|
|
843
|
+
[
|
|
844
|
+
sdk,
|
|
845
|
+
isConnected,
|
|
846
|
+
isConnecting,
|
|
847
|
+
isLoading,
|
|
848
|
+
connectError,
|
|
849
|
+
addresses,
|
|
850
|
+
isClient,
|
|
851
|
+
user,
|
|
852
|
+
resolvedTheme,
|
|
853
|
+
memoizedConfig.providers
|
|
854
|
+
]
|
|
141
855
|
);
|
|
142
|
-
return {
|
|
143
|
-
connect,
|
|
144
|
-
isConnecting,
|
|
145
|
-
error: connectError,
|
|
146
|
-
currentProviderType,
|
|
147
|
-
isPhantomAvailable
|
|
148
|
-
};
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
// src/hooks/useDisconnect.ts
|
|
152
|
-
import { useCallback as useCallback2, useState as useState2 } from "react";
|
|
153
|
-
function useDisconnect() {
|
|
154
|
-
const { sdk } = usePhantom();
|
|
155
|
-
const [isDisconnecting, setIsDisconnecting] = useState2(false);
|
|
156
|
-
const [error, setError] = useState2(null);
|
|
157
|
-
const disconnect = useCallback2(async () => {
|
|
158
|
-
if (!sdk) {
|
|
159
|
-
throw new Error("SDK not initialized");
|
|
160
|
-
}
|
|
161
|
-
setIsDisconnecting(true);
|
|
162
|
-
setError(null);
|
|
163
|
-
try {
|
|
164
|
-
await sdk.disconnect();
|
|
165
|
-
} catch (err) {
|
|
166
|
-
setError(err);
|
|
167
|
-
throw err;
|
|
168
|
-
} finally {
|
|
169
|
-
setIsDisconnecting(false);
|
|
170
|
-
}
|
|
171
|
-
}, [sdk]);
|
|
172
|
-
return {
|
|
173
|
-
disconnect,
|
|
174
|
-
isDisconnecting,
|
|
175
|
-
error
|
|
176
|
-
};
|
|
856
|
+
return /* @__PURE__ */ jsx5(ThemeProvider, { theme: resolvedTheme, children: /* @__PURE__ */ jsx5(PhantomContext.Provider, { value, children: /* @__PURE__ */ jsx5(ModalProvider, { appIcon, appName, children }) }) });
|
|
177
857
|
}
|
|
178
858
|
|
|
179
859
|
// src/hooks/useAccounts.ts
|
|
@@ -182,82 +862,16 @@ function useAccounts() {
|
|
|
182
862
|
return isConnected ? addresses : null;
|
|
183
863
|
}
|
|
184
864
|
|
|
185
|
-
// src/hooks/useIsExtensionInstalled.ts
|
|
186
|
-
import * as React from "react";
|
|
187
|
-
import { waitForPhantomExtension } from "@phantom/browser-sdk";
|
|
188
|
-
function useIsExtensionInstalled() {
|
|
189
|
-
const [isLoading, setIsLoading] = React.useState(true);
|
|
190
|
-
const [isInstalled, setIsInstalled] = React.useState(false);
|
|
191
|
-
React.useEffect(() => {
|
|
192
|
-
let isMounted = true;
|
|
193
|
-
const checkExtension = async () => {
|
|
194
|
-
try {
|
|
195
|
-
setIsLoading(true);
|
|
196
|
-
const result = await waitForPhantomExtension(3e3);
|
|
197
|
-
if (isMounted) {
|
|
198
|
-
setIsInstalled(result);
|
|
199
|
-
}
|
|
200
|
-
} catch (error) {
|
|
201
|
-
if (isMounted) {
|
|
202
|
-
setIsInstalled(false);
|
|
203
|
-
}
|
|
204
|
-
} finally {
|
|
205
|
-
if (isMounted) {
|
|
206
|
-
setIsLoading(false);
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
};
|
|
210
|
-
checkExtension();
|
|
211
|
-
return () => {
|
|
212
|
-
isMounted = false;
|
|
213
|
-
};
|
|
214
|
-
}, []);
|
|
215
|
-
return { isLoading, isInstalled };
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
// src/hooks/useIsPhantomLoginAvailable.ts
|
|
219
|
-
import * as React2 from "react";
|
|
220
|
-
import { isPhantomLoginAvailable } from "@phantom/browser-sdk";
|
|
221
|
-
function useIsPhantomLoginAvailable() {
|
|
222
|
-
const [isLoading, setIsLoading] = React2.useState(true);
|
|
223
|
-
const [isAvailable, setIsAvailable] = React2.useState(false);
|
|
224
|
-
React2.useEffect(() => {
|
|
225
|
-
let isMounted = true;
|
|
226
|
-
const checkPhantomLogin = async () => {
|
|
227
|
-
try {
|
|
228
|
-
setIsLoading(true);
|
|
229
|
-
const result = await isPhantomLoginAvailable(3e3);
|
|
230
|
-
if (isMounted) {
|
|
231
|
-
setIsAvailable(result);
|
|
232
|
-
}
|
|
233
|
-
} catch (error) {
|
|
234
|
-
if (isMounted) {
|
|
235
|
-
setIsAvailable(false);
|
|
236
|
-
}
|
|
237
|
-
} finally {
|
|
238
|
-
if (isMounted) {
|
|
239
|
-
setIsLoading(false);
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
};
|
|
243
|
-
checkPhantomLogin();
|
|
244
|
-
return () => {
|
|
245
|
-
isMounted = false;
|
|
246
|
-
};
|
|
247
|
-
}, []);
|
|
248
|
-
return { isLoading, isAvailable };
|
|
249
|
-
}
|
|
250
|
-
|
|
251
865
|
// src/hooks/useAutoConfirm.ts
|
|
252
|
-
import { useCallback as
|
|
866
|
+
import { useCallback as useCallback6, useState as useState9, useEffect as useEffect6 } from "react";
|
|
253
867
|
function useAutoConfirm() {
|
|
254
|
-
const { sdk,
|
|
255
|
-
const [status, setStatus] =
|
|
256
|
-
const [supportedChains, setSupportedChains] =
|
|
257
|
-
const [isLoading, setIsLoading] =
|
|
258
|
-
const [error, setError] =
|
|
259
|
-
const isInjected =
|
|
260
|
-
const enable =
|
|
868
|
+
const { sdk, user } = usePhantom();
|
|
869
|
+
const [status, setStatus] = useState9(null);
|
|
870
|
+
const [supportedChains, setSupportedChains] = useState9(null);
|
|
871
|
+
const [isLoading, setIsLoading] = useState9(false);
|
|
872
|
+
const [error, setError] = useState9(null);
|
|
873
|
+
const isInjected = user?.authProvider === "injected";
|
|
874
|
+
const enable = useCallback6(
|
|
261
875
|
async (params) => {
|
|
262
876
|
if (!sdk) {
|
|
263
877
|
throw new Error("SDK not initialized");
|
|
@@ -281,7 +895,7 @@ function useAutoConfirm() {
|
|
|
281
895
|
},
|
|
282
896
|
[sdk, isInjected]
|
|
283
897
|
);
|
|
284
|
-
const disable =
|
|
898
|
+
const disable = useCallback6(async () => {
|
|
285
899
|
if (!sdk) {
|
|
286
900
|
throw new Error("SDK not initialized");
|
|
287
901
|
}
|
|
@@ -302,7 +916,7 @@ function useAutoConfirm() {
|
|
|
302
916
|
setIsLoading(false);
|
|
303
917
|
}
|
|
304
918
|
}, [sdk, isInjected]);
|
|
305
|
-
const refetch =
|
|
919
|
+
const refetch = useCallback6(async () => {
|
|
306
920
|
if (!sdk || !isInjected) {
|
|
307
921
|
return;
|
|
308
922
|
}
|
|
@@ -322,7 +936,7 @@ function useAutoConfirm() {
|
|
|
322
936
|
setIsLoading(false);
|
|
323
937
|
}
|
|
324
938
|
}, [sdk, isInjected]);
|
|
325
|
-
|
|
939
|
+
useEffect6(() => {
|
|
326
940
|
if (sdk && isInjected) {
|
|
327
941
|
refetch();
|
|
328
942
|
} else {
|
|
@@ -343,56 +957,149 @@ function useAutoConfirm() {
|
|
|
343
957
|
}
|
|
344
958
|
|
|
345
959
|
// src/hooks/useSolana.ts
|
|
960
|
+
import { AddressType } from "@phantom/browser-sdk";
|
|
346
961
|
function useSolana() {
|
|
347
|
-
const { sdk,
|
|
348
|
-
if (!isClient || !sdk) {
|
|
962
|
+
const { sdk, isClient, isLoading } = usePhantom();
|
|
963
|
+
if (!isClient || !sdk || isLoading) {
|
|
964
|
+
return {
|
|
965
|
+
solana: {},
|
|
966
|
+
isAvailable: false
|
|
967
|
+
};
|
|
968
|
+
}
|
|
969
|
+
const enabledAddressTypes = sdk.getEnabledAddressTypes();
|
|
970
|
+
const isAvailable = enabledAddressTypes.includes(AddressType.solana);
|
|
971
|
+
if (!isAvailable) {
|
|
972
|
+
return {
|
|
973
|
+
solana: {},
|
|
974
|
+
isAvailable: false
|
|
975
|
+
};
|
|
976
|
+
}
|
|
977
|
+
try {
|
|
978
|
+
return {
|
|
979
|
+
solana: sdk.solana,
|
|
980
|
+
isAvailable: true
|
|
981
|
+
};
|
|
982
|
+
} catch (error) {
|
|
349
983
|
return {
|
|
350
984
|
solana: {},
|
|
351
|
-
// This will be replaced when SDK is ready
|
|
352
985
|
isAvailable: false
|
|
353
986
|
};
|
|
354
987
|
}
|
|
355
|
-
return {
|
|
356
|
-
// Chain instance with connection enforcement for signing methods
|
|
357
|
-
solana: sdk.solana,
|
|
358
|
-
// State
|
|
359
|
-
isAvailable: !!isConnected
|
|
360
|
-
};
|
|
361
988
|
}
|
|
362
989
|
|
|
363
990
|
// src/hooks/useEthereum.ts
|
|
991
|
+
import { AddressType as AddressType2 } from "@phantom/browser-sdk";
|
|
364
992
|
function useEthereum() {
|
|
365
|
-
const { sdk,
|
|
366
|
-
if (!isClient || !sdk) {
|
|
993
|
+
const { sdk, isClient, isLoading } = usePhantom();
|
|
994
|
+
if (!isClient || !sdk || isLoading) {
|
|
367
995
|
return {
|
|
368
996
|
ethereum: {},
|
|
369
|
-
// This will be replaced when SDK is ready
|
|
370
997
|
isAvailable: false
|
|
371
998
|
};
|
|
372
999
|
}
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
1000
|
+
const enabledAddressTypes = sdk.getEnabledAddressTypes();
|
|
1001
|
+
const isAvailable = enabledAddressTypes.includes(AddressType2.ethereum);
|
|
1002
|
+
if (!isAvailable) {
|
|
1003
|
+
return {
|
|
1004
|
+
ethereum: {},
|
|
1005
|
+
isAvailable: false
|
|
1006
|
+
};
|
|
1007
|
+
}
|
|
1008
|
+
try {
|
|
1009
|
+
return {
|
|
1010
|
+
ethereum: sdk.ethereum,
|
|
1011
|
+
isAvailable: true
|
|
1012
|
+
};
|
|
1013
|
+
} catch (error) {
|
|
1014
|
+
return {
|
|
1015
|
+
ethereum: {},
|
|
1016
|
+
isAvailable: false
|
|
1017
|
+
};
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
// src/hooks/index.ts
|
|
1022
|
+
import { useTheme as useTheme4 } from "@phantom/wallet-sdk-ui";
|
|
1023
|
+
|
|
1024
|
+
// src/components/ConnectButton.tsx
|
|
1025
|
+
import { useMemo as useMemo4 } from "react";
|
|
1026
|
+
import { useTheme as useTheme5 } from "@phantom/wallet-sdk-ui";
|
|
1027
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
1028
|
+
function ConnectButton({ addressType, fullWidth = false }) {
|
|
1029
|
+
const theme = useTheme5();
|
|
1030
|
+
const { open } = useModal();
|
|
1031
|
+
const { isConnected, addresses } = usePhantom();
|
|
1032
|
+
const displayAddress = useMemo4(() => {
|
|
1033
|
+
if (!addresses || addresses.length === 0)
|
|
1034
|
+
return null;
|
|
1035
|
+
if (addressType) {
|
|
1036
|
+
return addresses.find((addr) => addr.addressType === addressType);
|
|
1037
|
+
}
|
|
1038
|
+
return addresses[0];
|
|
1039
|
+
}, [addresses, addressType]);
|
|
1040
|
+
const truncatedAddress = useMemo4(() => {
|
|
1041
|
+
if (!displayAddress)
|
|
1042
|
+
return "";
|
|
1043
|
+
const addr = displayAddress.address;
|
|
1044
|
+
if (addr.length <= 12)
|
|
1045
|
+
return addr;
|
|
1046
|
+
return `${addr.slice(0, 6)}...${addr.slice(-4)}`;
|
|
1047
|
+
}, [displayAddress]);
|
|
1048
|
+
const buttonStyle = {
|
|
1049
|
+
width: fullWidth ? "100%" : "auto",
|
|
1050
|
+
padding: "12px 16px",
|
|
1051
|
+
border: "none",
|
|
1052
|
+
borderRadius: theme.borderRadius,
|
|
1053
|
+
fontFamily: theme.typography.captionBold.fontFamily,
|
|
1054
|
+
fontSize: theme.typography.captionBold.fontSize,
|
|
1055
|
+
fontStyle: theme.typography.captionBold.fontStyle,
|
|
1056
|
+
fontWeight: theme.typography.captionBold.fontWeight,
|
|
1057
|
+
lineHeight: theme.typography.captionBold.lineHeight,
|
|
1058
|
+
letterSpacing: theme.typography.captionBold.letterSpacing,
|
|
1059
|
+
cursor: "pointer",
|
|
1060
|
+
transition: "background-color 0.2s",
|
|
1061
|
+
display: "flex",
|
|
1062
|
+
alignItems: "center",
|
|
1063
|
+
justifyContent: "center",
|
|
1064
|
+
gap: "8px",
|
|
1065
|
+
background: theme.aux,
|
|
1066
|
+
color: theme.text
|
|
1067
|
+
};
|
|
1068
|
+
const connectedButtonStyle = {
|
|
1069
|
+
...buttonStyle,
|
|
1070
|
+
background: theme.aux,
|
|
1071
|
+
cursor: "pointer"
|
|
378
1072
|
};
|
|
1073
|
+
if (isConnected && displayAddress) {
|
|
1074
|
+
return /* @__PURE__ */ jsx6("button", { style: connectedButtonStyle, onClick: open, children: /* @__PURE__ */ jsx6("span", { style: { fontFamily: "monospace" }, children: truncatedAddress }) });
|
|
1075
|
+
}
|
|
1076
|
+
return /* @__PURE__ */ jsx6("button", { style: buttonStyle, onClick: open, children: "Connect Wallet" });
|
|
379
1077
|
}
|
|
380
1078
|
|
|
381
1079
|
// src/index.ts
|
|
382
|
-
import {
|
|
1080
|
+
import { darkTheme as darkTheme2, lightTheme, mergeTheme as mergeTheme2 } from "@phantom/wallet-sdk-ui";
|
|
1081
|
+
import { NetworkId, AddressType as AddressType3, DebugLevel, debug, isMobileDevice as isMobileDevice3 } from "@phantom/browser-sdk";
|
|
383
1082
|
export {
|
|
384
|
-
AddressType,
|
|
1083
|
+
AddressType3 as AddressType,
|
|
1084
|
+
ConnectButton,
|
|
385
1085
|
DebugLevel,
|
|
386
1086
|
NetworkId,
|
|
387
1087
|
PhantomProvider,
|
|
1088
|
+
darkTheme2 as darkTheme,
|
|
388
1089
|
debug,
|
|
1090
|
+
isMobileDevice3 as isMobileDevice,
|
|
1091
|
+
lightTheme,
|
|
1092
|
+
mergeTheme2 as mergeTheme,
|
|
389
1093
|
useAccounts,
|
|
390
1094
|
useAutoConfirm,
|
|
391
1095
|
useConnect,
|
|
392
1096
|
useDisconnect,
|
|
1097
|
+
useDiscoveredWallets,
|
|
393
1098
|
useEthereum,
|
|
394
1099
|
useIsExtensionInstalled,
|
|
395
1100
|
useIsPhantomLoginAvailable,
|
|
1101
|
+
useModal,
|
|
396
1102
|
usePhantom,
|
|
397
|
-
useSolana
|
|
1103
|
+
useSolana,
|
|
1104
|
+
useTheme4 as useTheme
|
|
398
1105
|
};
|