stellar-wallet-kit 2.0.2 → 2.0.5

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,5 +1,6 @@
1
- import React3, { createContext, useState, useEffect, useCallback, useMemo, useContext } from 'react';
1
+ import React3, { createContext, useState, useMemo, useEffect, useCallback, useContext } from 'react';
2
2
  import { isConnected, isAllowed, setAllowed, getUserInfo, getNetwork, signTransaction, signAuthEntry } from '@stellar/freighter-api';
3
+ import { UniversalConnector } from '@reown/appkit-universal-connector';
3
4
 
4
5
  // src/context/WalletContext.tsx
5
6
 
@@ -7,6 +8,8 @@ import { isConnected, isAllowed, setAllowed, getUserInfo, getNetwork, signTransa
7
8
  var WalletType = /* @__PURE__ */ ((WalletType2) => {
8
9
  WalletType2["FREIGHTER"] = "freighter";
9
10
  WalletType2["ALBEDO"] = "albedo";
11
+ WalletType2["WALLETCONNECT"] = "walletconnect";
12
+ WalletType2["LOBSTR"] = "lobstr";
10
13
  return WalletType2;
11
14
  })(WalletType || {});
12
15
  var NetworkType = /* @__PURE__ */ ((NetworkType2) => {
@@ -112,66 +115,6 @@ var FreighterAdapter = class {
112
115
  }
113
116
  };
114
117
 
115
- // src/utils/balanceUtils.ts
116
- var HORIZON_URLS = {
117
- PUBLIC: "https://horizon.stellar.org",
118
- TESTNET: "https://horizon-testnet.stellar.org",
119
- FUTURENET: "https://horizon-futurenet.stellar.org",
120
- STANDALONE: "http://localhost:8000"
121
- };
122
- async function fetchAccountBalances(publicKey, network) {
123
- const horizonUrl = HORIZON_URLS[network];
124
- try {
125
- const response = await fetch(`${horizonUrl}/accounts/${publicKey}`);
126
- if (!response.ok) {
127
- if (response.status === 404) {
128
- throw new Error("Account not found. Make sure the account is funded.");
129
- }
130
- throw new Error(`Failed to fetch account: ${response.statusText}`);
131
- }
132
- const data = await response.json();
133
- return data.balances;
134
- } catch (error) {
135
- console.error("Error fetching balances:", error);
136
- throw error;
137
- }
138
- }
139
- function getNativeBalance(balances) {
140
- const nativeBalance = balances.find((b) => b.asset_type === "native");
141
- return nativeBalance?.balance || "0";
142
- }
143
- function formatBalance(balance, decimals = 7) {
144
- const num = parseFloat(balance);
145
- if (isNaN(num)) return "0";
146
- return num.toFixed(decimals).replace(/\.?0+$/, "");
147
- }
148
- function getAssetBalance(balances, assetCode, assetIssuer) {
149
- if (!assetCode) {
150
- return getNativeBalance(balances);
151
- }
152
- const asset = balances.find(
153
- (b) => b.asset_code === assetCode && (!assetIssuer || b.asset_issuer === assetIssuer)
154
- );
155
- return asset?.balance || "0";
156
- }
157
- function hasSufficientBalance(balances, requiredAmount, assetCode, assetIssuer) {
158
- const balance = getAssetBalance(balances, assetCode, assetIssuer);
159
- return parseFloat(balance) >= parseFloat(requiredAmount);
160
- }
161
- function getTotalValueXLM(balances) {
162
- return getNativeBalance(balances);
163
- }
164
- function groupBalancesByType(balances) {
165
- return balances.reduce((acc, balance) => {
166
- const type = balance.asset_type;
167
- if (!acc[type]) {
168
- acc[type] = [];
169
- }
170
- acc[type].push(balance);
171
- return acc;
172
- }, {});
173
- }
174
-
175
118
  // src/utils/albedoCallback.ts
176
119
  function openAlbedoPopup(url) {
177
120
  const popup = window.open(
@@ -291,39 +234,75 @@ var AlbedoAdapter = class {
291
234
  }
292
235
  };
293
236
 
237
+ // src/utils/balanceUtils.ts
238
+ var HORIZON_URLS = {
239
+ PUBLIC: "https://horizon.stellar.org",
240
+ TESTNET: "https://horizon-testnet.stellar.org",
241
+ FUTURENET: "https://horizon-futurenet.stellar.org",
242
+ STANDALONE: "http://localhost:8000"
243
+ };
244
+ async function fetchAccountBalances(publicKey, network) {
245
+ const horizonUrl = HORIZON_URLS[network];
246
+ try {
247
+ const response = await fetch(`${horizonUrl}/accounts/${publicKey}`);
248
+ if (!response.ok) {
249
+ if (response.status === 404) {
250
+ throw new Error("Account not found. Make sure the account is funded.");
251
+ }
252
+ throw new Error(`Failed to fetch account: ${response.statusText}`);
253
+ }
254
+ const data = await response.json();
255
+ return data.balances;
256
+ } catch (error) {
257
+ console.error("Error fetching balances:", error);
258
+ throw error;
259
+ }
260
+ }
261
+ function getNativeBalance(balances) {
262
+ const nativeBalance = balances.find((b) => b.asset_type === "native");
263
+ return nativeBalance?.balance || "0";
264
+ }
265
+ function formatBalance(balance, decimals = 7) {
266
+ const num = parseFloat(balance);
267
+ if (isNaN(num)) return "0";
268
+ return num.toFixed(decimals).replace(/\.?0+$/, "");
269
+ }
270
+ function getAssetBalance(balances, assetCode, assetIssuer) {
271
+ if (!assetCode) {
272
+ return getNativeBalance(balances);
273
+ }
274
+ const asset = balances.find(
275
+ (b) => b.asset_code === assetCode && (!assetIssuer || b.asset_issuer === assetIssuer)
276
+ );
277
+ return asset?.balance || "0";
278
+ }
279
+ function hasSufficientBalance(balances, requiredAmount, assetCode, assetIssuer) {
280
+ const balance = getAssetBalance(balances, assetCode, assetIssuer);
281
+ return parseFloat(balance) >= parseFloat(requiredAmount);
282
+ }
283
+ function getTotalValueXLM(balances) {
284
+ return getNativeBalance(balances);
285
+ }
286
+ function groupBalancesByType(balances) {
287
+ return balances.reduce((acc, balance) => {
288
+ const type = balance.asset_type;
289
+ if (!acc[type]) {
290
+ acc[type] = [];
291
+ }
292
+ acc[type].push(balance);
293
+ return acc;
294
+ }, {});
295
+ }
296
+
294
297
  // src/context/WalletContext.tsx
298
+ var STORAGE_KEY = "stellar_wallet_kit";
299
+ var isBrowser = typeof window !== "undefined";
295
300
  var DEFAULT_SUPPORTS = {
296
301
  silentReconnect: false,
297
302
  networkDetection: false,
298
303
  authEntrySigning: false
299
304
  };
300
305
  var WalletContext = createContext(void 0);
301
- var STORAGE_KEY = "stellar_wallet_kit";
302
- var getStorageData = () => {
303
- if (typeof window === "undefined") {
304
- return { selectedWallet: null, autoConnect: false };
305
- }
306
- try {
307
- const data = localStorage.getItem(STORAGE_KEY);
308
- return data ? JSON.parse(data) : { selectedWallet: null, autoConnect: false };
309
- } catch {
310
- return { selectedWallet: null, autoConnect: false };
311
- }
312
- };
313
- var setStorageData = (data) => {
314
- if (typeof window === "undefined") return;
315
- try {
316
- const existing = getStorageData();
317
- localStorage.setItem(STORAGE_KEY, JSON.stringify({ ...existing, ...data }));
318
- } catch (error) {
319
- console.error("Failed to save to localStorage:", error);
320
- }
321
- };
322
- var isBrowser = typeof window !== "undefined";
323
- var walletAdapters = {
324
- ["freighter" /* FREIGHTER */]: new FreighterAdapter(),
325
- ["albedo" /* ALBEDO */]: new AlbedoAdapter()
326
- };
327
306
  var walletMetadata = {
328
307
  ["freighter" /* FREIGHTER */]: {
329
308
  id: "freighter" /* FREIGHTER */,
@@ -349,11 +328,55 @@ var walletMetadata = {
349
328
  networkDetection: false,
350
329
  authEntrySigning: true
351
330
  }
331
+ },
332
+ ["walletconnect" /* WALLETCONNECT */]: {
333
+ id: "walletconnect" /* WALLETCONNECT */,
334
+ name: "WalletConnect",
335
+ icon: "https://walletconnect.com/walletconnect-logo.png",
336
+ description: "Connect mobile wallets via WalletConnect",
337
+ kind: "web",
338
+ capabilities: {
339
+ silentReconnect: true,
340
+ networkDetection: false,
341
+ authEntrySigning: false
342
+ }
343
+ },
344
+ ["lobstr" /* LOBSTR */]: {
345
+ id: "lobstr" /* LOBSTR */,
346
+ name: "LOBSTR",
347
+ icon: "https://lobstr.co/favicon.ico",
348
+ description: "LOBSTR mobile wallet",
349
+ kind: "web",
350
+ capabilities: {
351
+ silentReconnect: true,
352
+ networkDetection: false,
353
+ authEntrySigning: false
354
+ }
352
355
  }
353
356
  };
357
+ function getStorageData() {
358
+ if (!isBrowser) {
359
+ return { selectedWallet: null, autoConnect: false };
360
+ }
361
+ try {
362
+ const raw = localStorage.getItem(STORAGE_KEY);
363
+ return raw ? JSON.parse(raw) : { selectedWallet: null, autoConnect: false };
364
+ } catch {
365
+ return { selectedWallet: null, autoConnect: false };
366
+ }
367
+ }
368
+ function setStorageData(data) {
369
+ if (!isBrowser) return;
370
+ const existing = getStorageData();
371
+ localStorage.setItem(
372
+ STORAGE_KEY,
373
+ JSON.stringify({ ...existing, ...data })
374
+ );
375
+ }
354
376
  function WalletProvider({ config = {}, children }) {
355
377
  const [account, setAccount] = useState(null);
356
378
  const [isConnecting, setIsConnecting] = useState(false);
379
+ const [connectingWallet, setConnectingWallet] = useState(null);
357
380
  const [error, setError] = useState(null);
358
381
  const [network, setNetwork] = useState(
359
382
  config.network || "TESTNET" /* TESTNET */
@@ -362,164 +385,138 @@ function WalletProvider({ config = {}, children }) {
362
385
  const [availableWallets, setAvailableWallets] = useState([]);
363
386
  const [isLoadingBalances, setIsLoadingBalances] = useState(false);
364
387
  const isConnected2 = !!account;
388
+ const walletAdapters = useMemo(
389
+ () => ({
390
+ ["freighter" /* FREIGHTER */]: new FreighterAdapter(),
391
+ ["albedo" /* ALBEDO */]: new AlbedoAdapter(),
392
+ ...config.adapters ?? {}
393
+ }),
394
+ [config.adapters]
395
+ );
365
396
  useEffect(() => {
366
397
  if (!isBrowser) return;
367
- const checkWallets = async () => {
398
+ (async () => {
368
399
  const wallets = [];
369
- for (const [type, adapter] of Object.entries(walletAdapters)) {
370
- const walletType = type;
400
+ const entries = Object.entries(walletAdapters);
401
+ for (const [walletType, adapter] of entries) {
402
+ if (!adapter) continue;
371
403
  const meta = walletMetadata[walletType];
372
404
  let installed = true;
373
405
  if (meta.kind === "extension") {
374
406
  installed = await adapter.isAvailable();
375
407
  }
376
- wallets.push({
377
- ...meta,
378
- installed
379
- });
408
+ wallets.push({ ...meta, installed });
380
409
  }
381
410
  setAvailableWallets(wallets);
382
- };
383
- checkWallets();
384
- }, []);
411
+ })();
412
+ }, [walletAdapters]);
385
413
  useEffect(() => {
386
- if (!isBrowser) return;
387
- const autoConnectWallet = async () => {
388
- const storage = getStorageData();
389
- if (config.autoConnect && storage.selectedWallet) {
390
- try {
391
- await connect(storage.selectedWallet);
392
- } catch (err) {
393
- console.error("Auto-connect failed:", err);
394
- }
395
- }
396
- };
397
- autoConnectWallet();
414
+ if (!isBrowser || !config.autoConnect) return;
415
+ const { selectedWallet: selectedWallet2 } = getStorageData();
416
+ if (selectedWallet2) {
417
+ connect(selectedWallet2).catch(() => {
418
+ });
419
+ }
398
420
  }, [config.autoConnect]);
399
421
  const refreshBalances = useCallback(async () => {
400
- if (!account?.publicKey) {
401
- return;
402
- }
422
+ if (!account?.publicKey) return;
403
423
  setIsLoadingBalances(true);
404
424
  try {
405
- const balances = await fetchAccountBalances(account.publicKey, network);
425
+ const balances = await fetchAccountBalances(
426
+ account.publicKey,
427
+ network
428
+ );
406
429
  setAccount((prev) => prev ? { ...prev, balances } : null);
407
- } catch (err) {
408
- console.error("Failed to fetch balances:", err);
409
430
  } finally {
410
431
  setIsLoadingBalances(false);
411
432
  }
412
433
  }, [account?.publicKey, network]);
413
434
  const connect = useCallback(
414
435
  async (walletType) => {
436
+ const type = walletType || config.defaultWallet || "freighter" /* FREIGHTER */;
415
437
  setIsConnecting(true);
438
+ setConnectingWallet(type);
416
439
  setError(null);
417
440
  try {
418
- const typeToConnect = walletType || config.defaultWallet || "freighter" /* FREIGHTER */;
419
- const adapter = walletAdapters[typeToConnect];
441
+ const adapter = walletAdapters[type];
420
442
  if (!adapter) {
421
- throw new Error(`Wallet adapter not found for ${typeToConnect}`);
443
+ throw new Error(`Wallet adapter not configured: ${type}`);
422
444
  }
423
- const meta = walletMetadata[typeToConnect];
445
+ const meta = walletMetadata[type];
424
446
  if (meta.kind === "extension") {
425
- const available = await adapter.isAvailable();
426
- if (!available) {
447
+ const ok = await adapter.isAvailable();
448
+ if (!ok) {
427
449
  throw new Error(`${meta.name} is not installed`);
428
450
  }
429
451
  }
430
- const response = await adapter.connect();
431
- const newAccount = {
432
- address: response.address,
433
- publicKey: response.publicKey,
434
- displayName: `${response.address.slice(
435
- 0,
436
- 4
437
- )}...${response.address.slice(-4)}`
438
- };
439
- setAccount(newAccount);
440
- setSelectedWallet(typeToConnect);
441
- setStorageData({ selectedWallet: typeToConnect, autoConnect: true });
442
- try {
443
- const balances = await fetchAccountBalances(
444
- response.publicKey,
445
- network
446
- );
447
- setAccount((prev) => prev ? { ...prev, balances } : null);
448
- } catch (balanceError) {
449
- console.error("Failed to fetch initial balances:", balanceError);
450
- }
451
- } catch (err) {
452
- const error2 = err instanceof Error ? err : new Error("Failed to connect wallet");
453
- setError(error2);
454
- throw error2;
452
+ const res = await adapter.connect();
453
+ setAccount({
454
+ address: res.address,
455
+ publicKey: res.publicKey,
456
+ displayName: `${res.address.slice(0, 4)}\u2026${res.address.slice(-4)}`
457
+ });
458
+ setSelectedWallet(type);
459
+ setStorageData({ selectedWallet: type, autoConnect: true });
460
+ await refreshBalances();
461
+ } catch (e) {
462
+ setError(e);
463
+ throw e;
455
464
  } finally {
456
465
  setIsConnecting(false);
466
+ setConnectingWallet(null);
457
467
  }
458
468
  },
459
- [config.defaultWallet]
469
+ [config.defaultWallet, refreshBalances, walletAdapters]
460
470
  );
461
471
  const disconnect = useCallback(async () => {
462
- try {
463
- if (selectedWallet) {
464
- const adapter = walletAdapters[selectedWallet];
465
- await adapter.disconnect();
466
- }
467
- setAccount(null);
468
- setSelectedWallet(null);
469
- setError(null);
470
- setStorageData({ selectedWallet: null, autoConnect: false });
471
- } catch (err) {
472
- const error2 = err instanceof Error ? err : new Error("Failed to disconnect wallet");
473
- setError(error2);
474
- throw error2;
472
+ if (selectedWallet) {
473
+ await walletAdapters[selectedWallet]?.disconnect();
475
474
  }
476
- }, [selectedWallet]);
475
+ setAccount(null);
476
+ setSelectedWallet(null);
477
+ setError(null);
478
+ setStorageData({ selectedWallet: null, autoConnect: false });
479
+ }, [selectedWallet, walletAdapters]);
477
480
  const signTransaction2 = useCallback(
478
- async (xdr, options) => {
481
+ (xdr, options) => {
479
482
  if (!selectedWallet) {
480
483
  throw new Error("No wallet connected");
481
484
  }
482
485
  const adapter = walletAdapters[selectedWallet];
486
+ if (!adapter) {
487
+ throw new Error("Wallet adapter missing");
488
+ }
483
489
  return adapter.signTransaction(xdr, options);
484
490
  },
485
- [selectedWallet]
491
+ [selectedWallet, walletAdapters]
486
492
  );
487
493
  const signAuthEntry2 = useCallback(
488
- async (entryXdr, options) => {
494
+ (entryXdr, options) => {
489
495
  if (!selectedWallet) {
490
496
  throw new Error("No wallet connected");
491
497
  }
492
498
  const adapter = walletAdapters[selectedWallet];
499
+ if (!adapter) {
500
+ throw new Error("Wallet adapter missing");
501
+ }
493
502
  return adapter.signAuthEntry(entryXdr, options);
494
503
  },
495
- [selectedWallet]
504
+ [selectedWallet, walletAdapters]
496
505
  );
497
506
  const switchNetwork = useCallback(
498
- async (newNetwork) => {
499
- setNetwork(newNetwork);
500
- if (account?.publicKey) {
501
- await refreshBalances();
502
- }
507
+ async (n) => {
508
+ setNetwork(n);
509
+ await refreshBalances();
503
510
  },
504
- [account?.publicKey, refreshBalances]
511
+ [refreshBalances]
505
512
  );
506
- useEffect(() => {
507
- if (!account?.publicKey || !isBrowser) return;
508
- refreshBalances();
509
- const interval = setInterval(() => {
510
- refreshBalances();
511
- }, 3e4);
512
- return () => clearInterval(interval);
513
- }, [account?.publicKey, refreshBalances]);
514
513
  const supports = useMemo(() => {
515
- if (!selectedWallet) {
516
- return DEFAULT_SUPPORTS;
517
- }
518
- const meta = walletMetadata[selectedWallet];
514
+ if (!selectedWallet) return DEFAULT_SUPPORTS;
515
+ const caps = walletMetadata[selectedWallet].capabilities;
519
516
  return {
520
- silentReconnect: !!meta.capabilities?.silentReconnect,
521
- networkDetection: !!meta.capabilities?.networkDetection,
522
- authEntrySigning: !!meta.capabilities?.authEntrySigning
517
+ silentReconnect: caps?.silentReconnect ?? false,
518
+ networkDetection: caps?.networkDetection ?? false,
519
+ authEntrySigning: caps?.authEntrySigning ?? false
523
520
  };
524
521
  }, [selectedWallet]);
525
522
  const value = useMemo(
@@ -527,6 +524,7 @@ function WalletProvider({ config = {}, children }) {
527
524
  account,
528
525
  isConnected: isConnected2,
529
526
  isConnecting,
527
+ connectingWallet,
530
528
  error,
531
529
  network,
532
530
  selectedWallet,
@@ -544,6 +542,7 @@ function WalletProvider({ config = {}, children }) {
544
542
  account,
545
543
  isConnected2,
546
544
  isConnecting,
545
+ connectingWallet,
547
546
  error,
548
547
  network,
549
548
  selectedWallet,
@@ -561,11 +560,11 @@ function WalletProvider({ config = {}, children }) {
561
560
  return /* @__PURE__ */ React3.createElement(WalletContext.Provider, { value }, children);
562
561
  }
563
562
  function useWallet() {
564
- const context = useContext(WalletContext);
565
- if (context === void 0) {
563
+ const ctx = useContext(WalletContext);
564
+ if (!ctx) {
566
565
  throw new Error("useWallet must be used within a WalletProvider");
567
566
  }
568
- return context;
567
+ return ctx;
569
568
  }
570
569
  function WalletModal({
571
570
  isOpen,
@@ -577,216 +576,149 @@ function WalletModal({
577
576
  appIcon
578
577
  }) {
579
578
  useEffect(() => {
580
- const handleEsc = (e) => {
579
+ const onEsc = (e) => {
581
580
  if (e.key === "Escape") onClose();
582
581
  };
583
582
  if (isOpen) {
584
- document.addEventListener("keydown", handleEsc);
583
+ document.addEventListener("keydown", onEsc);
585
584
  document.body.style.overflow = "hidden";
586
585
  }
587
586
  return () => {
588
- document.removeEventListener("keydown", handleEsc);
589
- document.body.style.overflow = "unset";
587
+ document.removeEventListener("keydown", onEsc);
588
+ document.body.style.overflow = "auto";
590
589
  };
591
590
  }, [isOpen, onClose]);
592
591
  if (!isOpen) return null;
593
- const themeMode = theme?.mode || "light";
594
- const isDark = themeMode === "dark" || themeMode === "auto" && window.matchMedia("(prefers-color-scheme: dark)").matches;
595
- const styles = {
596
- overlay: {
597
- position: "fixed",
598
- top: 0,
599
- left: 0,
600
- right: 0,
601
- bottom: 0,
602
- backgroundColor: theme?.overlayBackground || (isDark ? "rgba(0, 0, 0, 0.8)" : "rgba(0, 0, 0, 0.5)"),
603
- display: "flex",
604
- alignItems: "center",
605
- justifyContent: "center",
606
- zIndex: 9999,
607
- animation: "swk-fade-in 0.2s ease-out"
608
- },
609
- modal: {
610
- backgroundColor: theme?.modalBackground || (isDark ? "#1a1a1a" : "#ffffff"),
611
- borderRadius: theme?.borderRadius || "16px",
612
- padding: "24px",
613
- maxWidth: "420px",
614
- width: "90%",
615
- maxHeight: "80vh",
616
- overflowY: "auto",
617
- boxShadow: isDark ? "0 8px 32px rgba(0, 0, 0, 0.4)" : "0 8px 32px rgba(0, 0, 0, 0.1)",
618
- animation: "swk-slide-up 0.3s ease-out",
619
- fontFamily: theme?.fontFamily || '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif'
620
- },
621
- header: {
622
- display: "flex",
623
- alignItems: "center",
624
- justifyContent: "space-between",
625
- marginBottom: "24px"
626
- },
627
- title: {
628
- fontSize: "20px",
629
- fontWeight: 600,
630
- color: theme?.textColor || (isDark ? "#ffffff" : "#000000"),
631
- margin: 0,
632
- display: "flex",
633
- alignItems: "center",
634
- gap: "12px"
635
- },
636
- closeButton: {
637
- background: "none",
638
- border: "none",
639
- fontSize: "24px",
640
- cursor: "pointer",
641
- padding: "4px",
642
- color: theme?.textColor || (isDark ? "#888888" : "#666666"),
643
- transition: "color 0.2s",
644
- lineHeight: 1
645
- },
646
- walletList: {
647
- display: "flex",
648
- flexDirection: "column",
649
- gap: "12px"
650
- },
651
- walletButton: {
652
- display: "flex",
653
- alignItems: "center",
654
- gap: "16px",
655
- padding: "16px",
656
- border: `1px solid ${isDark ? "#333333" : "#e5e5e5"}`,
657
- borderRadius: theme?.borderRadius || "12px",
658
- background: "none",
659
- cursor: "pointer",
660
- transition: "all 0.2s",
661
- width: "100%",
662
- textAlign: "left",
663
- fontFamily: "inherit"
664
- },
665
- walletIcon: {
666
- width: "40px",
667
- height: "40px",
668
- borderRadius: "8px",
669
- flexShrink: 0
670
- },
671
- walletInfo: {
672
- flex: 1
673
- },
674
- walletName: {
675
- fontSize: "16px",
676
- fontWeight: 500,
677
- color: theme?.textColor || (isDark ? "#ffffff" : "#000000"),
678
- margin: 0,
679
- marginBottom: "4px"
680
- },
681
- walletDescription: {
682
- fontSize: "13px",
683
- color: theme?.textColor || (isDark ? "#888888" : "#666666"),
684
- margin: 0
685
- },
686
- badge: {
687
- padding: "4px 8px",
688
- borderRadius: "6px",
689
- fontSize: "12px",
690
- fontWeight: 500,
691
- flexShrink: 0
692
- },
693
- installedBadge: {
694
- backgroundColor: theme?.primaryColor || (isDark ? "#4CAF50" : "#4CAF50"),
695
- color: "#ffffff"
696
- },
697
- notInstalledBadge: {
698
- backgroundColor: isDark ? "#333333" : "#f0f0f0",
699
- color: isDark ? "#888888" : "#666666"
700
- },
701
- footer: {
702
- marginTop: "24px",
703
- paddingTop: "16px",
704
- borderTop: `1px solid ${isDark ? "#333333" : "#e5e5e5"}`,
705
- fontSize: "13px",
706
- color: isDark ? "#888888" : "#666666",
707
- textAlign: "center"
708
- },
709
- link: {
710
- color: theme?.primaryColor || "#8b5cf6",
711
- textDecoration: "none"
712
- }
713
- };
714
- const handleWalletClick = (wallet) => {
715
- if (wallet.installed) {
716
- onSelectWallet(wallet.id);
717
- } else if (wallet.downloadUrl) {
718
- window.open(wallet.downloadUrl, "_blank");
719
- }
720
- };
592
+ const isDark = theme?.mode === "dark" || theme?.mode === "auto" && window.matchMedia("(prefers-color-scheme: dark)").matches;
593
+ const bg = theme?.modalBackground || (isDark ? "#0f0f11" : "#ffffff");
594
+ const text = theme?.textColor || (isDark ? "#ffffff" : "#0a0a0a");
595
+ const muted = isDark ? "#8b8b8b" : "#6b6b6b";
596
+ const border = isDark ? "#1f1f23" : "#eaeaea";
597
+ const hover = theme?.buttonHoverColor || (isDark ? "#1a1a1f" : "#f6f6f6");
721
598
  return /* @__PURE__ */ React3.createElement(React3.Fragment, null, /* @__PURE__ */ React3.createElement("style", null, `
722
- @keyframes swk-fade-in {
723
- from { opacity: 0; }
724
- to { opacity: 1; }
599
+ .swk-overlay {
600
+ position: fixed;
601
+ inset: 0;
602
+ background: rgba(0,0,0,0.55);
603
+ display: flex;
604
+ align-items: center;
605
+ justify-content: center;
606
+ z-index: 9999;
725
607
  }
726
- @keyframes swk-slide-up {
727
- from {
728
- opacity: 0;
729
- transform: translateY(20px);
730
- }
731
- to {
732
- opacity: 1;
733
- transform: translateY(0);
734
- }
608
+
609
+ .swk-modal {
610
+ width: 420px;
611
+ max-width: 92vw;
612
+ background: ${bg};
613
+ border-radius: 20px;
614
+ padding: 28px;
615
+ box-shadow: 0 20px 60px rgba(0,0,0,0.4);
616
+ font-family: ${theme?.fontFamily || "Inter, system-ui, sans-serif"};
735
617
  }
736
- .swk-wallet-button:hover {
737
- background-color: ${theme?.buttonHoverColor || (isDark ? "#252525" : "#f5f5f5")} !important;
738
- border-color: ${theme?.primaryColor || "#8b5cf6"} !important;
618
+
619
+ .swk-wallet {
620
+ display: flex;
621
+ align-items: center;
622
+ gap: 14px;
623
+ padding: 14px 16px;
624
+ border-radius: 14px;
625
+ cursor: pointer;
626
+ transition: background 0.15s ease;
739
627
  }
740
- .swk-close-button:hover {
741
- color: ${theme?.primaryColor || "#8b5cf6"} !important;
628
+
629
+ .swk-wallet:hover {
630
+ background: ${hover};
742
631
  }
743
- `), /* @__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(
744
- "button",
632
+
633
+ .swk-pill {
634
+ font-size: 12px;
635
+ padding: 4px 10px;
636
+ border-radius: 999px;
637
+ background: ${theme?.primaryColor || "#6c5ce7"};
638
+ color: white;
639
+ font-weight: 500;
640
+ }
641
+ `), /* @__PURE__ */ React3.createElement("div", { className: "swk-overlay", onClick: onClose }, /* @__PURE__ */ React3.createElement("div", { className: "swk-modal", onClick: (e) => e.stopPropagation() }, /* @__PURE__ */ React3.createElement("div", { style: { marginBottom: 24 } }, /* @__PURE__ */ React3.createElement(
642
+ "div",
745
643
  {
746
- className: "swk-close-button",
747
- style: styles.closeButton,
748
- onClick: onClose,
749
- "aria-label": "Close modal"
644
+ style: {
645
+ display: "flex",
646
+ alignItems: "center",
647
+ gap: 12,
648
+ marginBottom: 8
649
+ }
750
650
  },
751
- "\xD7"
752
- )), /* @__PURE__ */ React3.createElement("div", { style: styles.walletList }, wallets.map((wallet) => /* @__PURE__ */ React3.createElement(
753
- "button",
651
+ appIcon && /* @__PURE__ */ React3.createElement(
652
+ "img",
653
+ {
654
+ src: appIcon,
655
+ alt: "",
656
+ style: { width: 32, height: 32, borderRadius: 8 }
657
+ }
658
+ ),
659
+ /* @__PURE__ */ React3.createElement("span", { style: { color: muted, fontSize: 14 } }, "Log in or sign up")
660
+ ), /* @__PURE__ */ React3.createElement(
661
+ "h2",
662
+ {
663
+ style: {
664
+ margin: 0,
665
+ fontSize: 22,
666
+ fontWeight: 600,
667
+ color: text
668
+ }
669
+ },
670
+ appName
671
+ )), /* @__PURE__ */ React3.createElement("div", { style: { display: "flex", flexDirection: "column", gap: 8 } }, wallets.map((wallet, i) => /* @__PURE__ */ React3.createElement(
672
+ "div",
754
673
  {
755
674
  key: wallet.id,
756
- className: "swk-wallet-button",
757
- style: styles.walletButton,
758
- onClick: () => handleWalletClick(wallet),
759
- disabled: !wallet.installed && !wallet.downloadUrl
675
+ className: "swk-wallet",
676
+ onClick: () => onSelectWallet(wallet.id)
760
677
  },
761
678
  /* @__PURE__ */ React3.createElement(
762
679
  "img",
763
680
  {
764
681
  src: wallet.icon,
765
- alt: `${wallet.name} icon`,
766
- style: styles.walletIcon
682
+ alt: wallet.name,
683
+ style: { width: 36, height: 36, borderRadius: 10 }
767
684
  }
768
685
  ),
769
- /* @__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)),
770
- /* @__PURE__ */ React3.createElement(
686
+ /* @__PURE__ */ React3.createElement("div", { style: { flex: 1 } }, /* @__PURE__ */ React3.createElement(
771
687
  "div",
772
688
  {
773
689
  style: {
774
- ...styles.badge,
775
- ...wallet.installed ? styles.installedBadge : styles.notInstalledBadge
690
+ fontSize: 15,
691
+ fontWeight: 500,
692
+ color: text
776
693
  }
777
694
  },
778
- wallet.installed ? "Installed" : "Get"
779
- )
780
- ))), /* @__PURE__ */ React3.createElement("div", { style: styles.footer }, /* @__PURE__ */ React3.createElement("p", { style: { margin: 0 } }, "Don't have a wallet?", " ", /* @__PURE__ */ React3.createElement(
781
- "a",
695
+ wallet.name
696
+ ), wallet.description && /* @__PURE__ */ React3.createElement(
697
+ "div",
698
+ {
699
+ style: {
700
+ fontSize: 13,
701
+ color: muted,
702
+ marginTop: 2
703
+ }
704
+ },
705
+ wallet.description
706
+ )),
707
+ i === 0 && /* @__PURE__ */ React3.createElement("div", { className: "swk-pill" }, "Recent")
708
+ ))), /* @__PURE__ */ React3.createElement(
709
+ "div",
782
710
  {
783
- href: "https://www.stellar.org/ecosystem/projects#wallets",
784
- target: "_blank",
785
- rel: "noopener noreferrer",
786
- style: styles.link
711
+ style: {
712
+ marginTop: 24,
713
+ paddingTop: 16,
714
+ borderTop: `1px solid ${border}`,
715
+ textAlign: "center",
716
+ fontSize: 13,
717
+ color: muted
718
+ }
787
719
  },
788
- "Learn more"
789
- ))))));
720
+ "Powered by Stellar Wallet Kit"
721
+ ))));
790
722
  }
791
723
 
792
724
  // src/components/ConnectButton.tsx
@@ -1000,7 +932,124 @@ function ConnectButton({
1000
932
  "\u{1F6AA} Disconnect"
1001
933
  )))));
1002
934
  }
935
+ var stellarTestnet = {
936
+ id: "testnet",
937
+ chainNamespace: "stellar",
938
+ caipNetworkId: "stellar:testnet",
939
+ name: "Stellar Testnet",
940
+ nativeCurrency: {
941
+ name: "XLM",
942
+ symbol: "XLM",
943
+ decimals: 7
944
+ },
945
+ rpcUrls: {
946
+ default: {
947
+ http: ["https://horizon-testnet.stellar.org"]
948
+ }
949
+ }
950
+ };
951
+ async function getUniversalConnector(projectId) {
952
+ return UniversalConnector.init({
953
+ projectId,
954
+ metadata: {
955
+ name: "Stellar Wallet Kit",
956
+ description: "Connect Stellar wallets",
957
+ url: "https://stellar.org",
958
+ icons: []
959
+ },
960
+ networks: [
961
+ {
962
+ namespace: "stellar",
963
+ chains: [stellarTestnet],
964
+ methods: ["stellar_signTransaction"],
965
+ events: []
966
+ }
967
+ ]
968
+ });
969
+ }
970
+
971
+ // src/adapters/WalletConnectAdapter.ts
972
+ var WalletConnectAdapter = class {
973
+ constructor(projectId) {
974
+ this.type = "walletconnect" /* WALLETCONNECT */;
975
+ this.connector = null;
976
+ this.session = null;
977
+ if (!projectId) {
978
+ throw new Error(
979
+ "WalletConnectAdapter requires a WalletConnect Project ID"
980
+ );
981
+ }
982
+ this.projectId = projectId;
983
+ }
984
+ async isAvailable() {
985
+ return typeof window !== "undefined";
986
+ }
987
+ async getConnector() {
988
+ if (!this.connector) {
989
+ this.connector = await getUniversalConnector(this.projectId);
990
+ }
991
+ return this.connector;
992
+ }
993
+ async connect() {
994
+ const connector = await this.getConnector();
995
+ const { session } = await connector.connect();
996
+ this.session = session;
997
+ const account = session.namespaces.stellar.accounts[0];
998
+ const publicKey = account.split(":")[2];
999
+ return {
1000
+ address: publicKey,
1001
+ publicKey
1002
+ };
1003
+ }
1004
+ async disconnect() {
1005
+ if (this.connector) {
1006
+ await this.connector.disconnect();
1007
+ }
1008
+ this.session = null;
1009
+ }
1010
+ async getPublicKey() {
1011
+ if (!this.session) return null;
1012
+ const account = this.session.namespaces.stellar.accounts[0];
1013
+ return account.split(":")[2];
1014
+ }
1015
+ async getNetwork() {
1016
+ throw new Error("Network detection not supported via WalletConnect");
1017
+ }
1018
+ async signTransaction(xdr, _options) {
1019
+ if (!this.connector || !this.session) {
1020
+ throw new Error("No active WalletConnect session");
1021
+ }
1022
+ const result = await this.connector.request({
1023
+ method: "stellar_signTransaction",
1024
+ params: { xdr }
1025
+ });
1026
+ return {
1027
+ signedTxXdr: result
1028
+ };
1029
+ }
1030
+ async signAuthEntry(_entryXdr, _options) {
1031
+ throw new Error(
1032
+ "Auth entry signing is not supported via WalletConnect"
1033
+ );
1034
+ }
1035
+ };
1036
+
1037
+ // src/wallets/createWalletAdapters.ts
1038
+ function createWalletAdapters(config) {
1039
+ return {
1040
+ // Extension wallet
1041
+ ["freighter" /* FREIGHTER */]: new FreighterAdapter(),
1042
+ // Web wallet
1043
+ ["albedo" /* ALBEDO */]: new AlbedoAdapter(),
1044
+ // WalletConnect (mobile wallets like Lobstr)
1045
+ ...config.walletConnectProjectId ? {
1046
+ ["walletconnect" /* WALLETCONNECT */]: new WalletConnectAdapter(
1047
+ config.walletConnectProjectId
1048
+ )
1049
+ } : {}
1050
+ };
1051
+ }
1003
1052
 
1004
- export { ConnectButton, FreighterAdapter, NetworkType, WalletModal, WalletProvider, WalletType, fetchAccountBalances, formatBalance, getAssetBalance, getNativeBalance, getTotalValueXLM, groupBalancesByType, hasSufficientBalance, useWallet };
1053
+ export { ConnectButton, FreighterAdapter, NetworkType, WalletConnectAdapter, WalletModal, WalletProvider, WalletType, createWalletAdapters, fetchAccountBalances, formatBalance, getAssetBalance, getNativeBalance, getTotalValueXLM, groupBalancesByType, hasSufficientBalance, useWallet };
1005
1054
  //# sourceMappingURL=index.mjs.map
1006
1055
  //# sourceMappingURL=index.mjs.map