@phantom/react-sdk 1.0.0-beta.9 → 1.0.2

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