stellar-wallet-kit 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs ADDED
@@ -0,0 +1,821 @@
1
+ import React3, { createContext, useState, useEffect, useCallback, useMemo, useContext } from 'react';
2
+ import { isConnected, isAllowed, setAllowed, getUserInfo, getNetwork, signTransaction, signAuthEntry } from '@stellar/freighter-api';
3
+
4
+ // src/context/WalletContext.tsx
5
+
6
+ // src/types/index.ts
7
+ var WalletType = /* @__PURE__ */ ((WalletType2) => {
8
+ WalletType2["FREIGHTER"] = "freighter";
9
+ return WalletType2;
10
+ })(WalletType || {});
11
+ var NetworkType = /* @__PURE__ */ ((NetworkType2) => {
12
+ NetworkType2["PUBLIC"] = "PUBLIC";
13
+ NetworkType2["TESTNET"] = "TESTNET";
14
+ NetworkType2["FUTURENET"] = "FUTURENET";
15
+ NetworkType2["STANDALONE"] = "STANDALONE";
16
+ return NetworkType2;
17
+ })(NetworkType || {});
18
+ var FreighterAdapter = class {
19
+ constructor() {
20
+ this.type = "freighter" /* FREIGHTER */;
21
+ }
22
+ async isAvailable() {
23
+ try {
24
+ return await isConnected();
25
+ } catch (error) {
26
+ console.error("Error checking Freighter availability:", error);
27
+ return false;
28
+ }
29
+ }
30
+ async connect() {
31
+ try {
32
+ const connected = await isConnected();
33
+ if (!connected) {
34
+ throw new Error("Freighter wallet is not installed");
35
+ }
36
+ const allowed = await isAllowed();
37
+ if (!allowed) {
38
+ await setAllowed();
39
+ }
40
+ const userInfo = await getUserInfo();
41
+ if (!userInfo || !userInfo.publicKey) {
42
+ throw new Error("Failed to get user information from Freighter");
43
+ }
44
+ return {
45
+ address: userInfo.publicKey,
46
+ publicKey: userInfo.publicKey
47
+ };
48
+ } catch (error) {
49
+ console.error("Error connecting to Freighter:", error);
50
+ throw new Error(`Failed to connect to Freighter: ${error instanceof Error ? error.message : "Unknown error"}`);
51
+ }
52
+ }
53
+ async disconnect() {
54
+ console.log("Freighter disconnect requested - user must disconnect from extension");
55
+ }
56
+ async getPublicKey() {
57
+ try {
58
+ const allowed = await isAllowed();
59
+ if (!allowed) {
60
+ return null;
61
+ }
62
+ const userInfo = await getUserInfo();
63
+ return userInfo?.publicKey || null;
64
+ } catch (error) {
65
+ console.error("Error getting public key:", error);
66
+ return null;
67
+ }
68
+ }
69
+ async getNetwork() {
70
+ try {
71
+ const network = await getNetwork();
72
+ return network;
73
+ } catch (error) {
74
+ console.error("Error getting network:", error);
75
+ throw error;
76
+ }
77
+ }
78
+ async signTransaction(xdr, options) {
79
+ try {
80
+ const result = await signTransaction(xdr, {
81
+ network: options?.network,
82
+ networkPassphrase: options?.networkPassphrase,
83
+ accountToSign: options?.accountToSign
84
+ });
85
+ if (!result || typeof result !== "string") {
86
+ throw new Error("Invalid response from Freighter");
87
+ }
88
+ return {
89
+ signedTxXdr: result
90
+ };
91
+ } catch (error) {
92
+ console.error("Error signing transaction:", error);
93
+ throw new Error(`Failed to sign transaction: ${error instanceof Error ? error.message : "Unknown error"}`);
94
+ }
95
+ }
96
+ async signAuthEntry(entryXdr, options) {
97
+ try {
98
+ const result = await signAuthEntry(entryXdr, {
99
+ accountToSign: options?.accountToSign
100
+ });
101
+ if (!result || typeof result !== "string") {
102
+ throw new Error("Invalid response from Freighter");
103
+ }
104
+ return {
105
+ signedAuthEntry: result
106
+ };
107
+ } catch (error) {
108
+ console.error("Error signing auth entry:", error);
109
+ throw new Error(`Failed to sign auth entry: ${error instanceof Error ? error.message : "Unknown error"}`);
110
+ }
111
+ }
112
+ };
113
+
114
+ // src/utils/balanceUtils.ts
115
+ var HORIZON_URLS = {
116
+ PUBLIC: "https://horizon.stellar.org",
117
+ TESTNET: "https://horizon-testnet.stellar.org",
118
+ FUTURENET: "https://horizon-futurenet.stellar.org",
119
+ STANDALONE: "http://localhost:8000"
120
+ };
121
+ async function fetchAccountBalances(publicKey, network) {
122
+ const horizonUrl = HORIZON_URLS[network];
123
+ try {
124
+ const response = await fetch(`${horizonUrl}/accounts/${publicKey}`);
125
+ if (!response.ok) {
126
+ if (response.status === 404) {
127
+ throw new Error("Account not found. Make sure the account is funded.");
128
+ }
129
+ throw new Error(`Failed to fetch account: ${response.statusText}`);
130
+ }
131
+ const data = await response.json();
132
+ return data.balances;
133
+ } catch (error) {
134
+ console.error("Error fetching balances:", error);
135
+ throw error;
136
+ }
137
+ }
138
+ function getNativeBalance(balances) {
139
+ const nativeBalance = balances.find((b) => b.asset_type === "native");
140
+ return nativeBalance?.balance || "0";
141
+ }
142
+ function formatBalance(balance, decimals = 7) {
143
+ const num = parseFloat(balance);
144
+ if (isNaN(num)) return "0";
145
+ return num.toFixed(decimals).replace(/\.?0+$/, "");
146
+ }
147
+ function getAssetBalance(balances, assetCode, assetIssuer) {
148
+ if (!assetCode) {
149
+ return getNativeBalance(balances);
150
+ }
151
+ const asset = balances.find(
152
+ (b) => b.asset_code === assetCode && (!assetIssuer || b.asset_issuer === assetIssuer)
153
+ );
154
+ return asset?.balance || "0";
155
+ }
156
+ function hasSufficientBalance(balances, requiredAmount, assetCode, assetIssuer) {
157
+ const balance = getAssetBalance(balances, assetCode, assetIssuer);
158
+ return parseFloat(balance) >= parseFloat(requiredAmount);
159
+ }
160
+ function getTotalValueXLM(balances) {
161
+ return getNativeBalance(balances);
162
+ }
163
+ function groupBalancesByType(balances) {
164
+ return balances.reduce((acc, balance) => {
165
+ const type = balance.asset_type;
166
+ if (!acc[type]) {
167
+ acc[type] = [];
168
+ }
169
+ acc[type].push(balance);
170
+ return acc;
171
+ }, {});
172
+ }
173
+
174
+ // src/context/WalletContext.tsx
175
+ var WalletContext = createContext(void 0);
176
+ var STORAGE_KEY = "stellar_wallet_kit";
177
+ var getStorageData = () => {
178
+ if (typeof window === "undefined") {
179
+ return { selectedWallet: null, autoConnect: false };
180
+ }
181
+ try {
182
+ const data = localStorage.getItem(STORAGE_KEY);
183
+ return data ? JSON.parse(data) : { selectedWallet: null, autoConnect: false };
184
+ } catch {
185
+ return { selectedWallet: null, autoConnect: false };
186
+ }
187
+ };
188
+ var setStorageData = (data) => {
189
+ if (typeof window === "undefined") return;
190
+ try {
191
+ const existing = getStorageData();
192
+ localStorage.setItem(STORAGE_KEY, JSON.stringify({ ...existing, ...data }));
193
+ } catch (error) {
194
+ console.error("Failed to save to localStorage:", error);
195
+ }
196
+ };
197
+ var isBrowser = typeof window !== "undefined";
198
+ var walletAdapters = {
199
+ ["freighter" /* FREIGHTER */]: new FreighterAdapter()
200
+ };
201
+ var walletMetadata = {
202
+ ["freighter" /* FREIGHTER */]: {
203
+ id: "freighter" /* FREIGHTER */,
204
+ name: "Freighter",
205
+ icon: "https://stellar.creit.tech/wallet-icons/freighter.svg",
206
+ description: "Freighter browser extension wallet",
207
+ downloadUrl: "https://chrome.google.com/webstore/detail/freighter/bcacfldlkkdogcmkkibnjlakofdplcbk"
208
+ }
209
+ };
210
+ function WalletProvider({ config = {}, children }) {
211
+ const [account, setAccount] = useState(null);
212
+ const [isConnecting, setIsConnecting] = useState(false);
213
+ const [error, setError] = useState(null);
214
+ const [network, setNetwork] = useState(config.network || "TESTNET" /* TESTNET */);
215
+ const [selectedWallet, setSelectedWallet] = useState(null);
216
+ const [availableWallets, setAvailableWallets] = useState([]);
217
+ const [isLoadingBalances, setIsLoadingBalances] = useState(false);
218
+ const isConnected2 = !!account;
219
+ useEffect(() => {
220
+ if (!isBrowser) return;
221
+ const checkWallets = async () => {
222
+ const wallets = [];
223
+ for (const [type, adapter] of Object.entries(walletAdapters)) {
224
+ const installed = await adapter.isAvailable();
225
+ wallets.push({
226
+ ...walletMetadata[type],
227
+ installed
228
+ });
229
+ }
230
+ setAvailableWallets(wallets);
231
+ };
232
+ checkWallets();
233
+ }, []);
234
+ useEffect(() => {
235
+ if (!isBrowser) return;
236
+ const autoConnectWallet = async () => {
237
+ const storage = getStorageData();
238
+ if (config.autoConnect && storage.selectedWallet) {
239
+ try {
240
+ await connect(storage.selectedWallet);
241
+ } catch (err) {
242
+ console.error("Auto-connect failed:", err);
243
+ }
244
+ }
245
+ };
246
+ autoConnectWallet();
247
+ }, [config.autoConnect]);
248
+ const refreshBalances = useCallback(async () => {
249
+ if (!account?.publicKey) {
250
+ return;
251
+ }
252
+ setIsLoadingBalances(true);
253
+ try {
254
+ const balances = await fetchAccountBalances(account.publicKey, network);
255
+ setAccount((prev) => prev ? { ...prev, balances } : null);
256
+ } catch (err) {
257
+ console.error("Failed to fetch balances:", err);
258
+ } finally {
259
+ setIsLoadingBalances(false);
260
+ }
261
+ }, [account?.publicKey, network]);
262
+ const connect = useCallback(async (walletType) => {
263
+ setIsConnecting(true);
264
+ setError(null);
265
+ try {
266
+ const typeToConnect = walletType || config.defaultWallet || "freighter" /* FREIGHTER */;
267
+ const adapter = walletAdapters[typeToConnect];
268
+ if (!adapter) {
269
+ throw new Error(`Wallet adapter not found for ${typeToConnect}`);
270
+ }
271
+ const available = await adapter.isAvailable();
272
+ if (!available) {
273
+ throw new Error(`${walletMetadata[typeToConnect].name} is not installed`);
274
+ }
275
+ const response = await adapter.connect();
276
+ const newAccount = {
277
+ address: response.address,
278
+ publicKey: response.publicKey,
279
+ displayName: `${response.address.slice(0, 4)}...${response.address.slice(-4)}`
280
+ };
281
+ setAccount(newAccount);
282
+ setSelectedWallet(typeToConnect);
283
+ setStorageData({ selectedWallet: typeToConnect, autoConnect: true });
284
+ try {
285
+ const balances = await fetchAccountBalances(response.publicKey, network);
286
+ setAccount((prev) => prev ? { ...prev, balances } : null);
287
+ } catch (balanceError) {
288
+ console.error("Failed to fetch initial balances:", balanceError);
289
+ }
290
+ } catch (err) {
291
+ const error2 = err instanceof Error ? err : new Error("Failed to connect wallet");
292
+ setError(error2);
293
+ throw error2;
294
+ } finally {
295
+ setIsConnecting(false);
296
+ }
297
+ }, [config.defaultWallet]);
298
+ const disconnect = useCallback(async () => {
299
+ try {
300
+ if (selectedWallet) {
301
+ const adapter = walletAdapters[selectedWallet];
302
+ await adapter.disconnect();
303
+ }
304
+ setAccount(null);
305
+ setSelectedWallet(null);
306
+ setError(null);
307
+ setStorageData({ selectedWallet: null, autoConnect: false });
308
+ } catch (err) {
309
+ const error2 = err instanceof Error ? err : new Error("Failed to disconnect wallet");
310
+ setError(error2);
311
+ throw error2;
312
+ }
313
+ }, [selectedWallet]);
314
+ const signTransaction2 = useCallback(async (xdr, options) => {
315
+ if (!selectedWallet) {
316
+ throw new Error("No wallet connected");
317
+ }
318
+ const adapter = walletAdapters[selectedWallet];
319
+ return adapter.signTransaction(xdr, options);
320
+ }, [selectedWallet]);
321
+ const signAuthEntry2 = useCallback(async (entryXdr, options) => {
322
+ if (!selectedWallet) {
323
+ throw new Error("No wallet connected");
324
+ }
325
+ const adapter = walletAdapters[selectedWallet];
326
+ return adapter.signAuthEntry(entryXdr, options);
327
+ }, [selectedWallet]);
328
+ const switchNetwork = useCallback(async (newNetwork) => {
329
+ setNetwork(newNetwork);
330
+ if (account?.publicKey) {
331
+ await refreshBalances();
332
+ }
333
+ }, [account?.publicKey, refreshBalances]);
334
+ useEffect(() => {
335
+ if (!account?.publicKey || !isBrowser) return;
336
+ refreshBalances();
337
+ const interval = setInterval(() => {
338
+ refreshBalances();
339
+ }, 3e4);
340
+ return () => clearInterval(interval);
341
+ }, [account?.publicKey, refreshBalances]);
342
+ const value = useMemo(
343
+ () => ({
344
+ account,
345
+ isConnected: isConnected2,
346
+ isConnecting,
347
+ error,
348
+ network,
349
+ selectedWallet,
350
+ connect,
351
+ disconnect,
352
+ signTransaction: signTransaction2,
353
+ signAuthEntry: signAuthEntry2,
354
+ switchNetwork,
355
+ availableWallets,
356
+ refreshBalances,
357
+ isLoadingBalances
358
+ }),
359
+ [
360
+ account,
361
+ isConnected2,
362
+ isConnecting,
363
+ error,
364
+ network,
365
+ selectedWallet,
366
+ connect,
367
+ disconnect,
368
+ signTransaction2,
369
+ signAuthEntry2,
370
+ switchNetwork,
371
+ availableWallets,
372
+ refreshBalances,
373
+ isLoadingBalances
374
+ ]
375
+ );
376
+ return /* @__PURE__ */ React3.createElement(WalletContext.Provider, { value }, children);
377
+ }
378
+ function useWallet() {
379
+ const context = useContext(WalletContext);
380
+ if (context === void 0) {
381
+ throw new Error("useWallet must be used within a WalletProvider");
382
+ }
383
+ return context;
384
+ }
385
+ function WalletModal({
386
+ isOpen,
387
+ onClose,
388
+ wallets,
389
+ onSelectWallet,
390
+ theme,
391
+ appName = "Your App",
392
+ appIcon
393
+ }) {
394
+ useEffect(() => {
395
+ const handleEsc = (e) => {
396
+ if (e.key === "Escape") onClose();
397
+ };
398
+ if (isOpen) {
399
+ document.addEventListener("keydown", handleEsc);
400
+ document.body.style.overflow = "hidden";
401
+ }
402
+ return () => {
403
+ document.removeEventListener("keydown", handleEsc);
404
+ document.body.style.overflow = "unset";
405
+ };
406
+ }, [isOpen, onClose]);
407
+ if (!isOpen) return null;
408
+ const themeMode = theme?.mode || "light";
409
+ const isDark = themeMode === "dark" || themeMode === "auto" && window.matchMedia("(prefers-color-scheme: dark)").matches;
410
+ const styles = {
411
+ overlay: {
412
+ position: "fixed",
413
+ top: 0,
414
+ left: 0,
415
+ right: 0,
416
+ bottom: 0,
417
+ backgroundColor: theme?.overlayBackground || (isDark ? "rgba(0, 0, 0, 0.8)" : "rgba(0, 0, 0, 0.5)"),
418
+ display: "flex",
419
+ alignItems: "center",
420
+ justifyContent: "center",
421
+ zIndex: 9999,
422
+ animation: "swk-fade-in 0.2s ease-out"
423
+ },
424
+ modal: {
425
+ backgroundColor: theme?.modalBackground || (isDark ? "#1a1a1a" : "#ffffff"),
426
+ borderRadius: theme?.borderRadius || "16px",
427
+ padding: "24px",
428
+ maxWidth: "420px",
429
+ width: "90%",
430
+ maxHeight: "80vh",
431
+ overflowY: "auto",
432
+ boxShadow: isDark ? "0 8px 32px rgba(0, 0, 0, 0.4)" : "0 8px 32px rgba(0, 0, 0, 0.1)",
433
+ animation: "swk-slide-up 0.3s ease-out",
434
+ fontFamily: theme?.fontFamily || '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif'
435
+ },
436
+ header: {
437
+ display: "flex",
438
+ alignItems: "center",
439
+ justifyContent: "space-between",
440
+ marginBottom: "24px"
441
+ },
442
+ title: {
443
+ fontSize: "20px",
444
+ fontWeight: 600,
445
+ color: theme?.textColor || (isDark ? "#ffffff" : "#000000"),
446
+ margin: 0,
447
+ display: "flex",
448
+ alignItems: "center",
449
+ gap: "12px"
450
+ },
451
+ closeButton: {
452
+ background: "none",
453
+ border: "none",
454
+ fontSize: "24px",
455
+ cursor: "pointer",
456
+ padding: "4px",
457
+ color: theme?.textColor || (isDark ? "#888888" : "#666666"),
458
+ transition: "color 0.2s",
459
+ lineHeight: 1
460
+ },
461
+ walletList: {
462
+ display: "flex",
463
+ flexDirection: "column",
464
+ gap: "12px"
465
+ },
466
+ walletButton: {
467
+ display: "flex",
468
+ alignItems: "center",
469
+ gap: "16px",
470
+ padding: "16px",
471
+ border: `1px solid ${isDark ? "#333333" : "#e5e5e5"}`,
472
+ borderRadius: theme?.borderRadius || "12px",
473
+ background: "none",
474
+ cursor: "pointer",
475
+ transition: "all 0.2s",
476
+ width: "100%",
477
+ textAlign: "left",
478
+ fontFamily: "inherit"
479
+ },
480
+ walletIcon: {
481
+ width: "40px",
482
+ height: "40px",
483
+ borderRadius: "8px",
484
+ flexShrink: 0
485
+ },
486
+ walletInfo: {
487
+ flex: 1
488
+ },
489
+ walletName: {
490
+ fontSize: "16px",
491
+ fontWeight: 500,
492
+ color: theme?.textColor || (isDark ? "#ffffff" : "#000000"),
493
+ margin: 0,
494
+ marginBottom: "4px"
495
+ },
496
+ walletDescription: {
497
+ fontSize: "13px",
498
+ color: theme?.textColor || (isDark ? "#888888" : "#666666"),
499
+ margin: 0
500
+ },
501
+ badge: {
502
+ padding: "4px 8px",
503
+ borderRadius: "6px",
504
+ fontSize: "12px",
505
+ fontWeight: 500,
506
+ flexShrink: 0
507
+ },
508
+ installedBadge: {
509
+ backgroundColor: theme?.primaryColor || (isDark ? "#4CAF50" : "#4CAF50"),
510
+ color: "#ffffff"
511
+ },
512
+ notInstalledBadge: {
513
+ backgroundColor: isDark ? "#333333" : "#f0f0f0",
514
+ color: isDark ? "#888888" : "#666666"
515
+ },
516
+ footer: {
517
+ marginTop: "24px",
518
+ paddingTop: "16px",
519
+ borderTop: `1px solid ${isDark ? "#333333" : "#e5e5e5"}`,
520
+ fontSize: "13px",
521
+ color: isDark ? "#888888" : "#666666",
522
+ textAlign: "center"
523
+ },
524
+ link: {
525
+ color: theme?.primaryColor || "#8b5cf6",
526
+ textDecoration: "none"
527
+ }
528
+ };
529
+ const handleWalletClick = (wallet) => {
530
+ if (wallet.installed) {
531
+ onSelectWallet(wallet.id);
532
+ } else if (wallet.downloadUrl) {
533
+ window.open(wallet.downloadUrl, "_blank");
534
+ }
535
+ };
536
+ return /* @__PURE__ */ React3.createElement(React3.Fragment, null, /* @__PURE__ */ React3.createElement("style", null, `
537
+ @keyframes swk-fade-in {
538
+ from { opacity: 0; }
539
+ to { opacity: 1; }
540
+ }
541
+ @keyframes swk-slide-up {
542
+ from {
543
+ opacity: 0;
544
+ transform: translateY(20px);
545
+ }
546
+ to {
547
+ opacity: 1;
548
+ transform: translateY(0);
549
+ }
550
+ }
551
+ .swk-wallet-button:hover {
552
+ background-color: ${theme?.buttonHoverColor || (isDark ? "#252525" : "#f5f5f5")} !important;
553
+ border-color: ${theme?.primaryColor || "#8b5cf6"} !important;
554
+ }
555
+ .swk-close-button:hover {
556
+ color: ${theme?.primaryColor || "#8b5cf6"} !important;
557
+ }
558
+ `), /* @__PURE__ */ React3.createElement("div", { style: styles.overlay, onClick: onClose }, /* @__PURE__ */ React3.createElement("div", { style: styles.modal, onClick: (e) => e.stopPropagation() }, /* @__PURE__ */ React3.createElement("div", { style: styles.header }, /* @__PURE__ */ React3.createElement("h2", { style: styles.title }, appIcon && /* @__PURE__ */ React3.createElement("img", { src: appIcon, alt: "", style: { width: "32px", height: "32px", borderRadius: "8px" } }), "Connect Wallet"), /* @__PURE__ */ React3.createElement(
559
+ "button",
560
+ {
561
+ className: "swk-close-button",
562
+ style: styles.closeButton,
563
+ onClick: onClose,
564
+ "aria-label": "Close modal"
565
+ },
566
+ "\xD7"
567
+ )), /* @__PURE__ */ React3.createElement("div", { style: styles.walletList }, wallets.map((wallet) => /* @__PURE__ */ React3.createElement(
568
+ "button",
569
+ {
570
+ key: wallet.id,
571
+ className: "swk-wallet-button",
572
+ style: styles.walletButton,
573
+ onClick: () => handleWalletClick(wallet),
574
+ disabled: !wallet.installed && !wallet.downloadUrl
575
+ },
576
+ /* @__PURE__ */ React3.createElement(
577
+ "img",
578
+ {
579
+ src: wallet.icon,
580
+ alt: `${wallet.name} icon`,
581
+ style: styles.walletIcon
582
+ }
583
+ ),
584
+ /* @__PURE__ */ React3.createElement("div", { style: styles.walletInfo }, /* @__PURE__ */ React3.createElement("p", { style: styles.walletName }, wallet.name), wallet.description && /* @__PURE__ */ React3.createElement("p", { style: styles.walletDescription }, wallet.description)),
585
+ /* @__PURE__ */ React3.createElement(
586
+ "div",
587
+ {
588
+ style: {
589
+ ...styles.badge,
590
+ ...wallet.installed ? styles.installedBadge : styles.notInstalledBadge
591
+ }
592
+ },
593
+ wallet.installed ? "Installed" : "Get"
594
+ )
595
+ ))), /* @__PURE__ */ React3.createElement("div", { style: styles.footer }, /* @__PURE__ */ React3.createElement("p", { style: { margin: 0 } }, "Don't have a wallet?", " ", /* @__PURE__ */ React3.createElement(
596
+ "a",
597
+ {
598
+ href: "https://www.stellar.org/ecosystem/projects#wallets",
599
+ target: "_blank",
600
+ rel: "noopener noreferrer",
601
+ style: styles.link
602
+ },
603
+ "Learn more"
604
+ ))))));
605
+ }
606
+
607
+ // src/components/ConnectButton.tsx
608
+ function ConnectButton({
609
+ label = "Connect Wallet",
610
+ theme,
611
+ className,
612
+ style,
613
+ showBalance = false,
614
+ onConnect,
615
+ onDisconnect
616
+ }) {
617
+ const {
618
+ account,
619
+ isConnected: isConnected2,
620
+ isConnecting,
621
+ connect,
622
+ disconnect,
623
+ availableWallets,
624
+ selectedWallet,
625
+ refreshBalances,
626
+ isLoadingBalances
627
+ } = useWallet();
628
+ const [isModalOpen, setIsModalOpen] = useState(false);
629
+ const [showDropdown, setShowDropdown] = useState(false);
630
+ const themeMode = theme?.mode || "light";
631
+ const isDark = themeMode === "dark" || themeMode === "auto" && window.matchMedia("(prefers-color-scheme: dark)").matches;
632
+ const defaultButtonStyles = {
633
+ padding: "12px 24px",
634
+ borderRadius: theme?.borderRadius || "12px",
635
+ border: "none",
636
+ fontSize: "15px",
637
+ fontWeight: 500,
638
+ cursor: "pointer",
639
+ transition: "all 0.2s",
640
+ fontFamily: theme?.fontFamily || '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
641
+ ...style
642
+ };
643
+ const connectButtonStyles = {
644
+ ...defaultButtonStyles,
645
+ backgroundColor: theme?.primaryColor || "#8b5cf6",
646
+ color: "#ffffff"
647
+ };
648
+ const accountButtonStyles = {
649
+ ...defaultButtonStyles,
650
+ backgroundColor: isDark ? "#252525" : "#f5f5f5",
651
+ color: theme?.textColor || (isDark ? "#ffffff" : "#000000"),
652
+ border: `1px solid ${isDark ? "#333333" : "#e5e5e5"}`,
653
+ position: "relative",
654
+ display: "flex",
655
+ alignItems: "center",
656
+ gap: "8px"
657
+ };
658
+ const dropdownStyles = {
659
+ position: "absolute",
660
+ top: "calc(100% + 8px)",
661
+ right: 0,
662
+ backgroundColor: theme?.modalBackground || (isDark ? "#1a1a1a" : "#ffffff"),
663
+ border: `1px solid ${isDark ? "#333333" : "#e5e5e5"}`,
664
+ borderRadius: theme?.borderRadius || "12px",
665
+ padding: "8px",
666
+ minWidth: "200px",
667
+ boxShadow: isDark ? "0 4px 16px rgba(0, 0, 0, 0.4)" : "0 4px 16px rgba(0, 0, 0, 0.1)",
668
+ zIndex: 1e3
669
+ };
670
+ const dropdownItemStyles = {
671
+ padding: "12px 16px",
672
+ border: "none",
673
+ background: "none",
674
+ cursor: "pointer",
675
+ width: "100%",
676
+ textAlign: "left",
677
+ fontSize: "14px",
678
+ color: theme?.textColor || (isDark ? "#ffffff" : "#000000"),
679
+ borderRadius: "8px",
680
+ transition: "background-color 0.2s",
681
+ fontFamily: "inherit"
682
+ };
683
+ const handleConnect = async (walletType) => {
684
+ try {
685
+ await connect(walletType);
686
+ setIsModalOpen(false);
687
+ onConnect?.();
688
+ } catch (error) {
689
+ console.error("Connection error:", error);
690
+ }
691
+ };
692
+ const handleDisconnect = async () => {
693
+ try {
694
+ await disconnect();
695
+ setShowDropdown(false);
696
+ onDisconnect?.();
697
+ } catch (error) {
698
+ console.error("Disconnect error:", error);
699
+ }
700
+ };
701
+ const copyAddress = () => {
702
+ if (account?.address) {
703
+ navigator.clipboard.writeText(account.address);
704
+ setShowDropdown(false);
705
+ }
706
+ };
707
+ if (isConnecting) {
708
+ return /* @__PURE__ */ React3.createElement(
709
+ "button",
710
+ {
711
+ className,
712
+ style: connectButtonStyles,
713
+ disabled: true
714
+ },
715
+ "Connecting..."
716
+ );
717
+ }
718
+ if (!isConnected2 || !account) {
719
+ return /* @__PURE__ */ React3.createElement(React3.Fragment, null, /* @__PURE__ */ React3.createElement(
720
+ "button",
721
+ {
722
+ className,
723
+ style: connectButtonStyles,
724
+ onClick: () => setIsModalOpen(true)
725
+ },
726
+ label
727
+ ), /* @__PURE__ */ React3.createElement(
728
+ WalletModal,
729
+ {
730
+ isOpen: isModalOpen,
731
+ onClose: () => setIsModalOpen(false),
732
+ wallets: availableWallets,
733
+ onSelectWallet: handleConnect,
734
+ theme
735
+ }
736
+ ));
737
+ }
738
+ const walletIcon = availableWallets.find((w) => w.id === selectedWallet)?.icon;
739
+ const nativeBalance = account?.balances ? getNativeBalance(account.balances) : null;
740
+ const formattedBalance = nativeBalance ? formatBalance(nativeBalance, 2) : null;
741
+ return /* @__PURE__ */ React3.createElement(React3.Fragment, null, /* @__PURE__ */ React3.createElement("div", { style: { position: "relative" } }, /* @__PURE__ */ React3.createElement(
742
+ "button",
743
+ {
744
+ className,
745
+ style: accountButtonStyles,
746
+ onClick: () => setShowDropdown(!showDropdown)
747
+ },
748
+ walletIcon && /* @__PURE__ */ React3.createElement(
749
+ "img",
750
+ {
751
+ src: walletIcon,
752
+ alt: "Wallet",
753
+ style: { width: "20px", height: "20px", borderRadius: "4px" }
754
+ }
755
+ ),
756
+ /* @__PURE__ */ React3.createElement("div", { style: { display: "flex", flexDirection: "column", alignItems: "flex-start", gap: "2px" } }, /* @__PURE__ */ React3.createElement("span", null, account.displayName), showBalance && formattedBalance && /* @__PURE__ */ React3.createElement("span", { style: { fontSize: "12px", opacity: 0.7, fontWeight: 400 } }, isLoadingBalances ? "..." : `${formattedBalance} XLM`)),
757
+ /* @__PURE__ */ React3.createElement("span", { style: { fontSize: "12px", opacity: 0.7 } }, "\u25BC")
758
+ ), showDropdown && /* @__PURE__ */ React3.createElement(React3.Fragment, null, /* @__PURE__ */ React3.createElement(
759
+ "div",
760
+ {
761
+ style: {
762
+ position: "fixed",
763
+ top: 0,
764
+ left: 0,
765
+ right: 0,
766
+ bottom: 0,
767
+ zIndex: 999
768
+ },
769
+ onClick: () => setShowDropdown(false)
770
+ }
771
+ ), /* @__PURE__ */ React3.createElement("div", { style: dropdownStyles }, /* @__PURE__ */ React3.createElement(
772
+ "button",
773
+ {
774
+ style: dropdownItemStyles,
775
+ onClick: () => {
776
+ refreshBalances();
777
+ setShowDropdown(false);
778
+ },
779
+ onMouseEnter: (e) => {
780
+ e.currentTarget.style.backgroundColor = theme?.buttonHoverColor || (isDark ? "#333333" : "#f0f0f0");
781
+ },
782
+ onMouseLeave: (e) => {
783
+ e.currentTarget.style.backgroundColor = "transparent";
784
+ }
785
+ },
786
+ "\u{1F504} Refresh Balances"
787
+ ), /* @__PURE__ */ React3.createElement(
788
+ "button",
789
+ {
790
+ style: dropdownItemStyles,
791
+ onClick: copyAddress,
792
+ onMouseEnter: (e) => {
793
+ e.currentTarget.style.backgroundColor = theme?.buttonHoverColor || (isDark ? "#333333" : "#f0f0f0");
794
+ },
795
+ onMouseLeave: (e) => {
796
+ e.currentTarget.style.backgroundColor = "transparent";
797
+ }
798
+ },
799
+ "\u{1F4CB} Copy Address"
800
+ ), /* @__PURE__ */ React3.createElement(
801
+ "button",
802
+ {
803
+ style: {
804
+ ...dropdownItemStyles,
805
+ color: "#ef4444"
806
+ },
807
+ onClick: handleDisconnect,
808
+ onMouseEnter: (e) => {
809
+ e.currentTarget.style.backgroundColor = theme?.buttonHoverColor || (isDark ? "#333333" : "#f0f0f0");
810
+ },
811
+ onMouseLeave: (e) => {
812
+ e.currentTarget.style.backgroundColor = "transparent";
813
+ }
814
+ },
815
+ "\u{1F6AA} Disconnect"
816
+ )))));
817
+ }
818
+
819
+ export { ConnectButton, FreighterAdapter, NetworkType, WalletModal, WalletProvider, WalletType, fetchAccountBalances, formatBalance, getAssetBalance, getNativeBalance, getTotalValueXLM, groupBalancesByType, hasSufficientBalance, useWallet };
820
+ //# sourceMappingURL=index.mjs.map
821
+ //# sourceMappingURL=index.mjs.map