@enbox/browser 0.3.41 → 0.3.42

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.
@@ -4,15 +4,65 @@
4
4
  * Injected into the DOM as a Shadow DOM element to prevent style conflicts.
5
5
  * Inspired by WalletConnect's Web3Modal pattern.
6
6
  *
7
+ * The modal is a single view with three zones:
8
+ *
9
+ * 1. **Quick connect** — a one-tap button that connects with the recommended
10
+ * (first) wallet without scrolling the grid.
11
+ * 2. **Wallet grid** — a scrollable grid of wallet tiles with a search filter.
12
+ * Each tile renders the wallet's own favicon, falling back to a letter
13
+ * badge (never a third-party favicon proxy).
14
+ * 3. **Custom URL** — paste any wallet URL; it is validated against the
15
+ * wallet's `/.well-known/enbox-connect` discovery document before the
16
+ * selection resolves.
17
+ *
7
18
  * @module
8
19
  */
20
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
21
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
22
+ return new (P || (P = Promise))(function (resolve, reject) {
23
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
24
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
25
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
26
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
27
+ });
28
+ };
29
+ /** Path of the wallet's connect discovery document, relative to its origin. */
30
+ export const WALLET_WELL_KNOWN_PATH = '/.well-known/enbox-connect';
31
+ /** Timeout applied to the well-known validation fetch. */
32
+ const WELL_KNOWN_FETCH_TIMEOUT_MS = 6000;
33
+ /**
34
+ * Fetch a wallet's `/.well-known/enbox-connect` discovery document to confirm
35
+ * the origin hosts an Enbox-compatible wallet.
36
+ *
37
+ * Resolves `true` only when the document is reachable and names a
38
+ * `connectServerUrl`. Unreachable origins, non-2xx responses, CORS failures,
39
+ * and malformed documents resolve `false`.
40
+ */
41
+ export function probeWalletWellKnown(origin) {
42
+ return __awaiter(this, void 0, void 0, function* () {
43
+ try {
44
+ const wellKnownUrl = new URL(WALLET_WELL_KNOWN_PATH, origin).toString();
45
+ const response = yield fetch(wellKnownUrl, { signal: AbortSignal.timeout(WELL_KNOWN_FETCH_TIMEOUT_MS) });
46
+ if (!response.ok) {
47
+ return false;
48
+ }
49
+ const payload = yield response.json();
50
+ return typeof (payload === null || payload === void 0 ? void 0 : payload.connectServerUrl) === 'string';
51
+ }
52
+ catch (_a) {
53
+ return false;
54
+ }
55
+ });
56
+ }
9
57
  /** Shows the wallet selector modal and resolves with the chosen wallet URL. */
10
- export function showWalletSelector(wallets) {
58
+ export function showWalletSelector(wallets, options = {}) {
59
+ var _a;
11
60
  if (typeof window === 'undefined' || typeof document === 'undefined') {
12
61
  throw new Error('[@enbox/browser] Wallet selector is only available in browser environments.');
13
62
  }
63
+ const validateWalletUrl = (_a = options.validateWalletUrl) !== null && _a !== void 0 ? _a : probeWalletWellKnown;
14
64
  return new Promise((resolve, reject) => {
15
- var _a, _b;
65
+ var _a, _b, _c;
16
66
  // Create the host element with Shadow DOM isolation.
17
67
  const host = document.createElement('div');
18
68
  host.id = 'enbox-wallet-selector';
@@ -28,8 +78,16 @@ export function showWalletSelector(wallets) {
28
78
  }
29
79
  catch ( /* best effort */_a) { /* best effort */ }
30
80
  };
81
+ const settleResolve = (url) => {
82
+ cleanup();
83
+ resolve(url);
84
+ };
85
+ const settleReject = () => {
86
+ cleanup();
87
+ reject(new Error('[@enbox/browser] Wallet selection cancelled.'));
88
+ };
31
89
  // Detect dark mode.
32
- const isDark = (_a = window.matchMedia) === null || _a === void 0 ? void 0 : _a.call(window, '(prefers-color-scheme: dark)').matches;
90
+ const isDark = (_b = (_a = window.matchMedia) === null || _a === void 0 ? void 0 : _a.call(window, '(prefers-color-scheme: dark)').matches) !== null && _b !== void 0 ? _b : false;
33
91
  // Build styles.
34
92
  const style = document.createElement('style');
35
93
  style.textContent = buildStyles(isDark);
@@ -39,126 +97,248 @@ export function showWalletSelector(wallets) {
39
97
  overlay.className = 'overlay';
40
98
  const modal = document.createElement('div');
41
99
  modal.className = 'modal';
42
- // Header
43
- const header = document.createElement('div');
44
- header.className = 'header';
45
- const title = document.createElement('h2');
46
- title.textContent = 'Connect Wallet';
47
- const closeBtn = document.createElement('button');
48
- closeBtn.className = 'close-btn';
49
- closeBtn.innerHTML = '×';
50
- closeBtn.addEventListener('click', () => {
51
- cleanup();
52
- reject(new Error('[@enbox/browser] Wallet selection cancelled.'));
53
- });
54
- header.appendChild(title);
55
- header.appendChild(closeBtn);
56
- modal.appendChild(header);
57
- // Wallet list
58
- const list = document.createElement('div');
59
- list.className = 'wallet-list';
60
- for (const wallet of wallets) {
61
- const item = document.createElement('button');
62
- item.className = 'wallet-item';
63
- const icon = document.createElement('img');
64
- icon.src = (_b = wallet.icon) !== null && _b !== void 0 ? _b : faviconUrl(wallet.url);
65
- icon.alt = wallet.name;
66
- icon.width = 32;
67
- icon.height = 32;
68
- icon.onerror = () => { icon.style.display = 'none'; };
69
- const textGroup = document.createElement('div');
70
- textGroup.className = 'wallet-text';
71
- const name = document.createElement('span');
72
- name.className = 'wallet-name';
73
- name.textContent = wallet.name;
74
- textGroup.appendChild(name);
75
- if (wallet.description) {
76
- const desc = document.createElement('span');
77
- desc.className = 'wallet-description';
78
- desc.textContent = wallet.description;
79
- textGroup.appendChild(desc);
80
- }
81
- const arrow = document.createElement('span');
82
- arrow.className = 'arrow';
83
- arrow.textContent = '\u203A'; // ›
84
- item.appendChild(icon);
85
- item.appendChild(textGroup);
86
- item.appendChild(arrow);
87
- item.addEventListener('click', () => {
88
- cleanup();
89
- resolve(wallet.url);
90
- });
91
- list.appendChild(item);
100
+ modal.appendChild(buildHeader(settleReject));
101
+ const recommended = wallets[0];
102
+ if (recommended !== undefined) {
103
+ modal.appendChild(buildQuickConnect(recommended, settleResolve));
92
104
  }
93
- modal.appendChild(list);
94
- // Separator
95
- const sep = document.createElement('div');
96
- sep.className = 'separator';
97
- const sepLine1 = document.createElement('div');
98
- sepLine1.className = 'sep-line';
99
- const sepText = document.createElement('span');
100
- sepText.textContent = 'or';
101
- const sepLine2 = document.createElement('div');
102
- sepLine2.className = 'sep-line';
103
- sep.appendChild(sepLine1);
104
- sep.appendChild(sepText);
105
- sep.appendChild(sepLine2);
106
- modal.appendChild(sep);
107
- // Custom URL input
108
- const inputGroup = document.createElement('div');
109
- inputGroup.className = 'input-group';
110
- const input = document.createElement('input');
111
- input.type = 'url';
112
- input.placeholder = 'Enter wallet URL...';
113
- input.className = 'url-input';
114
- const goBtn = document.createElement('button');
115
- goBtn.className = 'go-btn';
116
- goBtn.textContent = 'Connect';
117
- goBtn.disabled = true;
118
- input.addEventListener('input', () => {
119
- goBtn.disabled = !isValidUrl(input.value);
120
- });
121
- input.addEventListener('keydown', (e) => {
122
- if (e.key === 'Enter' && isValidUrl(input.value)) {
123
- cleanup();
124
- resolve(normalizeUrl(input.value));
125
- }
126
- });
127
- goBtn.addEventListener('click', () => {
128
- if (isValidUrl(input.value)) {
129
- cleanup();
130
- resolve(normalizeUrl(input.value));
131
- }
132
- });
133
- inputGroup.appendChild(input);
134
- inputGroup.appendChild(goBtn);
135
- modal.appendChild(inputGroup);
105
+ modal.appendChild(buildWalletGrid(wallets, settleResolve));
106
+ modal.appendChild(buildSeparator());
107
+ modal.appendChild(buildCustomUrl(validateWalletUrl, settleResolve));
136
108
  // Close on overlay click.
137
109
  overlay.addEventListener('click', (e) => {
138
110
  if (e.target === overlay) {
139
- cleanup();
140
- reject(new Error('[@enbox/browser] Wallet selection cancelled.'));
111
+ settleReject();
141
112
  }
142
113
  });
143
114
  // Close on Escape.
144
115
  onKeydown = (e) => {
145
116
  if (e.key === 'Escape') {
146
- cleanup();
147
- reject(new Error('[@enbox/browser] Wallet selection cancelled.'));
117
+ settleReject();
148
118
  }
149
119
  };
150
120
  document.addEventListener('keydown', onKeydown);
151
121
  overlay.appendChild(modal);
152
122
  shadow.appendChild(overlay);
153
123
  document.body.appendChild(host);
154
- // Focus the input for keyboard-first users.
155
- input.focus();
124
+ // Focus the search box for keyboard-first users.
125
+ (_c = shadow.querySelector('.wallet-search')) === null || _c === void 0 ? void 0 : _c.focus();
156
126
  });
157
127
  }
158
- // ─── Helpers ─────────────────────────────────────────────────────
159
- function faviconUrl(walletUrl) {
160
- return `https://t3.gstatic.com/faviconV2?client=SOCIAL&type=FAVICON&fallback_opts=TYPE,SIZE,URL&url=${walletUrl}&size=128`;
128
+ // ─── DOM builders ────────────────────────────────────────────────
129
+ function buildHeader(onCancel) {
130
+ const header = document.createElement('div');
131
+ header.className = 'header';
132
+ const title = document.createElement('h2');
133
+ title.textContent = 'Connect a wallet';
134
+ const closeBtn = document.createElement('button');
135
+ closeBtn.className = 'close-btn';
136
+ closeBtn.setAttribute('aria-label', 'Close');
137
+ closeBtn.innerHTML = '×';
138
+ closeBtn.addEventListener('click', onCancel);
139
+ header.appendChild(title);
140
+ header.appendChild(closeBtn);
141
+ return header;
161
142
  }
143
+ function buildQuickConnect(recommended, onSelect) {
144
+ const quick = document.createElement('button');
145
+ quick.className = 'quick-connect';
146
+ const bolt = document.createElement('span');
147
+ bolt.className = 'quick-bolt';
148
+ bolt.textContent = '⚡'; // ⚡
149
+ const text = document.createElement('span');
150
+ text.className = 'quick-text';
151
+ const label = document.createElement('span');
152
+ label.className = 'quick-label';
153
+ label.textContent = 'Quick connect';
154
+ const sub = document.createElement('span');
155
+ sub.className = 'quick-sub';
156
+ sub.textContent = `Connect with ${recommended.name}`;
157
+ text.appendChild(label);
158
+ text.appendChild(sub);
159
+ quick.appendChild(bolt);
160
+ quick.appendChild(text);
161
+ quick.addEventListener('click', () => onSelect(recommended.url));
162
+ return quick;
163
+ }
164
+ function buildWalletGrid(wallets, onSelect) {
165
+ const section = document.createElement('div');
166
+ section.className = 'grid-section';
167
+ const search = document.createElement('input');
168
+ search.type = 'search';
169
+ search.className = 'wallet-search';
170
+ search.placeholder = 'Search wallets…';
171
+ const grid = document.createElement('div');
172
+ grid.className = 'wallet-grid';
173
+ const empty = document.createElement('div');
174
+ empty.className = 'grid-empty';
175
+ empty.textContent = 'No wallets match your search.';
176
+ empty.style.display = 'none';
177
+ const tiles = wallets.map((wallet) => {
178
+ const tile = buildWalletTile(wallet, onSelect);
179
+ grid.appendChild(tile);
180
+ return { name: wallet.name.toLowerCase(), tile };
181
+ });
182
+ search.addEventListener('input', () => {
183
+ const query = search.value.trim().toLowerCase();
184
+ let visible = 0;
185
+ for (const { name, tile } of tiles) {
186
+ const match = name.includes(query);
187
+ tile.style.display = match ? '' : 'none';
188
+ if (match) {
189
+ visible += 1;
190
+ }
191
+ }
192
+ empty.style.display = visible === 0 ? '' : 'none';
193
+ });
194
+ section.appendChild(search);
195
+ section.appendChild(grid);
196
+ section.appendChild(empty);
197
+ return section;
198
+ }
199
+ function buildWalletTile(wallet, onSelect) {
200
+ var _a;
201
+ const tile = document.createElement('button');
202
+ tile.className = 'wallet-item';
203
+ tile.title = (_a = wallet.description) !== null && _a !== void 0 ? _a : wallet.name;
204
+ tile.appendChild(buildWalletIcon(wallet));
205
+ const name = document.createElement('span');
206
+ name.className = 'wallet-name';
207
+ name.textContent = wallet.name;
208
+ tile.appendChild(name);
209
+ tile.addEventListener('click', () => onSelect(wallet.url));
210
+ return tile;
211
+ }
212
+ /**
213
+ * Build a wallet icon that prefers the wallet's own favicon and degrades to a
214
+ * letter badge. We never call a third-party favicon proxy: those 404 for many
215
+ * origins and leak the wallet URL to the proxy.
216
+ */
217
+ function buildWalletIcon(wallet) {
218
+ const wrap = document.createElement('span');
219
+ wrap.className = 'wallet-icon';
220
+ const badge = document.createElement('span');
221
+ badge.className = 'wallet-badge';
222
+ badge.textContent = wallet.name.charAt(0).toUpperCase();
223
+ wrap.appendChild(badge);
224
+ const sources = iconCandidates(wallet);
225
+ if (sources.length === 0) {
226
+ return wrap;
227
+ }
228
+ const img = document.createElement('img');
229
+ img.className = 'wallet-img';
230
+ img.alt = '';
231
+ img.width = 40;
232
+ img.height = 40;
233
+ let index = 0;
234
+ img.addEventListener('error', () => {
235
+ index += 1;
236
+ if (index < sources.length) {
237
+ img.src = sources[index];
238
+ }
239
+ else {
240
+ img.remove(); // fall back to the letter badge
241
+ }
242
+ });
243
+ img.src = sources[index];
244
+ wrap.appendChild(img);
245
+ return wrap;
246
+ }
247
+ /** Ordered favicon URLs to try for a wallet, most specific first. */
248
+ function iconCandidates(wallet) {
249
+ if (wallet.icon !== undefined) {
250
+ return [wallet.icon];
251
+ }
252
+ let origin;
253
+ try {
254
+ origin = new URL(wallet.url).origin;
255
+ }
256
+ catch (_a) {
257
+ return [];
258
+ }
259
+ return [`${origin}/favicon.svg`, `${origin}/favicon.ico`, `${origin}/favicon.png`];
260
+ }
261
+ function buildSeparator() {
262
+ const sep = document.createElement('div');
263
+ sep.className = 'separator';
264
+ const line1 = document.createElement('div');
265
+ line1.className = 'sep-line';
266
+ const sepText = document.createElement('span');
267
+ sepText.textContent = 'or';
268
+ const line2 = document.createElement('div');
269
+ line2.className = 'sep-line';
270
+ sep.appendChild(line1);
271
+ sep.appendChild(sepText);
272
+ sep.appendChild(line2);
273
+ return sep;
274
+ }
275
+ function buildCustomUrl(validateWalletUrl, onSelect) {
276
+ const section = document.createElement('div');
277
+ section.className = 'custom-section';
278
+ const label = document.createElement('label');
279
+ label.className = 'custom-label';
280
+ label.textContent = 'Have a wallet URL?';
281
+ const inputGroup = document.createElement('div');
282
+ inputGroup.className = 'input-group';
283
+ const input = document.createElement('input');
284
+ input.type = 'url';
285
+ input.placeholder = 'https://your-wallet.example';
286
+ input.className = 'url-input';
287
+ const goBtn = document.createElement('button');
288
+ goBtn.className = 'go-btn';
289
+ goBtn.textContent = 'Connect';
290
+ goBtn.disabled = true;
291
+ const errorLine = document.createElement('div');
292
+ errorLine.className = 'url-error';
293
+ errorLine.style.display = 'none';
294
+ // When validation fails we let the user override, since the popup handshake
295
+ // is the ultimate gate — a valid wallet behind strict CORS should not be
296
+ // permanently blocked.
297
+ let allowUnverified = false;
298
+ const resetState = () => {
299
+ allowUnverified = false;
300
+ goBtn.textContent = 'Connect';
301
+ errorLine.style.display = 'none';
302
+ goBtn.disabled = !isValidUrl(input.value);
303
+ };
304
+ const submit = () => __awaiter(this, void 0, void 0, function* () {
305
+ if (!isValidUrl(input.value)) {
306
+ return;
307
+ }
308
+ const origin = normalizeUrl(input.value);
309
+ if (allowUnverified) {
310
+ onSelect(origin);
311
+ return;
312
+ }
313
+ goBtn.disabled = true;
314
+ goBtn.textContent = 'Verifying…';
315
+ errorLine.style.display = 'none';
316
+ const valid = yield validateWalletUrl(origin);
317
+ if (valid) {
318
+ onSelect(origin);
319
+ return;
320
+ }
321
+ allowUnverified = true;
322
+ goBtn.disabled = false;
323
+ goBtn.textContent = 'Connect anyway';
324
+ errorLine.textContent = `Couldn't verify an Enbox wallet at ${origin}.`;
325
+ errorLine.style.display = '';
326
+ });
327
+ input.addEventListener('input', resetState);
328
+ input.addEventListener('keydown', (e) => {
329
+ if (e.key === 'Enter') {
330
+ void submit();
331
+ }
332
+ });
333
+ goBtn.addEventListener('click', () => void submit());
334
+ inputGroup.appendChild(input);
335
+ inputGroup.appendChild(goBtn);
336
+ section.appendChild(label);
337
+ section.appendChild(inputGroup);
338
+ section.appendChild(errorLine);
339
+ return section;
340
+ }
341
+ // ─── Helpers ─────────────────────────────────────────────────────
162
342
  function isValidUrl(value) {
163
343
  try {
164
344
  const url = new URL(value.includes('://') ? value : `https://${value}`);
@@ -169,12 +349,9 @@ function isValidUrl(value) {
169
349
  }
170
350
  }
171
351
  function normalizeUrl(value) {
172
- if (!value.includes('://')) {
173
- value = `https://${value}`;
174
- }
175
- const url = new URL(value);
352
+ const withScheme = value.includes('://') ? value : `https://${value}`;
176
353
  // Return origin only (strip path/trailing slash).
177
- return url.origin;
354
+ return new URL(withScheme).origin;
178
355
  }
179
356
  function buildStyles(isDark) {
180
357
  const bg = isDark ? '#1a1a2e' : '#ffffff';
@@ -184,6 +361,8 @@ function buildStyles(isDark) {
184
361
  const itemBg = isDark ? '#16213e' : '#f8f9fa';
185
362
  const itemHover = isDark ? '#0f3460' : '#e9ecef';
186
363
  const accent = isDark ? '#4a9eff' : '#0066cc';
364
+ const accentAlt = isDark ? '#7b5cff' : '#5b8def';
365
+ const danger = isDark ? '#ff6b6b' : '#c0392b';
187
366
  const overlayBg = 'rgba(0, 0, 0, 0.5)';
188
367
  return `
189
368
  * { box-sizing: border-box; margin: 0; padding: 0; }
@@ -214,9 +393,9 @@ function buildStyles(isDark) {
214
393
  background: ${bg};
215
394
  color: ${text};
216
395
  border-radius: 16px;
217
- width: 380px;
218
- max-width: 90vw;
219
- max-height: 80vh;
396
+ width: 420px;
397
+ max-width: 92vw;
398
+ max-height: 86vh;
220
399
  overflow-y: auto;
221
400
  padding: 24px;
222
401
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
@@ -227,13 +406,10 @@ function buildStyles(isDark) {
227
406
  display: flex;
228
407
  justify-content: space-between;
229
408
  align-items: center;
230
- margin-bottom: 20px;
409
+ margin-bottom: 18px;
231
410
  }
232
411
 
233
- h2 {
234
- font-size: 18px;
235
- font-weight: 600;
236
- }
412
+ h2 { font-size: 18px; font-weight: 600; }
237
413
 
238
414
  .close-btn {
239
415
  background: none;
@@ -247,51 +423,110 @@ function buildStyles(isDark) {
247
423
  }
248
424
  .close-btn:hover { color: ${text}; background: ${itemBg}; }
249
425
 
250
- .wallet-list {
426
+ .quick-connect {
251
427
  display: flex;
252
- flex-direction: column;
253
- gap: 8px;
428
+ align-items: center;
429
+ gap: 12px;
430
+ width: 100%;
431
+ text-align: left;
432
+ padding: 14px 16px;
433
+ margin-bottom: 18px;
434
+ border: none;
435
+ border-radius: 12px;
436
+ cursor: pointer;
437
+ color: #fff;
438
+ background: linear-gradient(135deg, ${accent}, ${accentAlt});
439
+ transition: filter 0.15s;
440
+ }
441
+ .quick-connect:hover { filter: brightness(1.08); }
442
+ .quick-bolt { font-size: 22px; line-height: 1; }
443
+ .quick-text { display: flex; flex-direction: column; gap: 2px; }
444
+ .quick-label { font-weight: 600; font-size: 15px; }
445
+ .quick-sub { font-size: 12px; opacity: 0.85; }
446
+
447
+ .wallet-search {
448
+ width: 100%;
449
+ padding: 10px 14px;
450
+ margin-bottom: 12px;
451
+ border: 1px solid ${border};
452
+ border-radius: 10px;
453
+ font-size: 14px;
454
+ background: ${itemBg};
455
+ color: ${text};
456
+ outline: none;
457
+ }
458
+ .wallet-search:focus { border-color: ${accent}; }
459
+ .wallet-search::placeholder { color: ${muted}; }
460
+
461
+ .wallet-grid {
462
+ display: grid;
463
+ grid-template-columns: repeat(3, 1fr);
464
+ gap: 10px;
465
+ max-height: 216px;
466
+ overflow-y: auto;
467
+ padding: 2px;
254
468
  }
255
469
 
256
470
  .wallet-item {
257
471
  display: flex;
472
+ flex-direction: column;
258
473
  align-items: center;
259
- gap: 12px;
260
- padding: 12px 16px;
474
+ justify-content: center;
475
+ gap: 8px;
476
+ padding: 14px 8px;
261
477
  background: ${itemBg};
262
478
  border: 1px solid ${border};
263
479
  border-radius: 12px;
264
480
  cursor: pointer;
265
- font-size: 15px;
266
481
  color: ${text};
267
- transition: background 0.15s;
268
- width: 100%;
269
- text-align: left;
482
+ transition: background 0.15s, border-color 0.15s;
270
483
  }
271
- .wallet-item:hover { background: ${itemHover}; }
484
+ .wallet-item:hover { background: ${itemHover}; border-color: ${accent}; }
272
485
 
273
- .wallet-text {
274
- flex: 1;
486
+ .wallet-icon {
487
+ position: relative;
488
+ width: 40px;
489
+ height: 40px;
275
490
  display: flex;
276
- flex-direction: column;
277
- gap: 2px;
278
- min-width: 0;
491
+ align-items: center;
492
+ justify-content: center;
493
+ }
494
+ .wallet-badge {
495
+ position: absolute;
496
+ inset: 0;
497
+ display: flex;
498
+ align-items: center;
499
+ justify-content: center;
500
+ border-radius: 10px;
501
+ background: ${itemHover};
502
+ color: ${text};
503
+ font-size: 18px;
504
+ font-weight: 600;
505
+ }
506
+ .wallet-img {
507
+ position: relative;
508
+ width: 40px;
509
+ height: 40px;
510
+ border-radius: 10px;
511
+ object-fit: cover;
512
+ background: ${bg};
279
513
  }
280
514
 
281
- .wallet-name { font-weight: 500; }
282
-
283
- .wallet-description {
284
- font-size: 12px;
285
- color: ${muted};
286
- white-space: nowrap;
515
+ .wallet-name {
516
+ font-size: 13px;
517
+ font-weight: 500;
518
+ max-width: 100%;
287
519
  overflow: hidden;
288
520
  text-overflow: ellipsis;
521
+ white-space: nowrap;
289
522
  }
290
523
 
291
- .arrow {
292
- font-size: 20px;
524
+ .grid-empty {
525
+ grid-column: 1 / -1;
526
+ padding: 16px;
527
+ text-align: center;
293
528
  color: ${muted};
294
- flex-shrink: 0;
529
+ font-size: 13px;
295
530
  }
296
531
 
297
532
  .separator {
@@ -304,11 +539,15 @@ function buildStyles(isDark) {
304
539
  }
305
540
  .sep-line { flex: 1; height: 1px; background: ${border}; }
306
541
 
307
- .input-group {
308
- display: flex;
309
- gap: 8px;
542
+ .custom-label {
543
+ display: block;
544
+ font-size: 13px;
545
+ color: ${muted};
546
+ margin-bottom: 8px;
310
547
  }
311
548
 
549
+ .input-group { display: flex; gap: 8px; }
550
+
312
551
  .url-input {
313
552
  flex: 1;
314
553
  padding: 10px 14px;
@@ -333,11 +572,14 @@ function buildStyles(isDark) {
333
572
  cursor: pointer;
334
573
  white-space: nowrap;
335
574
  }
336
- .go-btn:disabled {
337
- opacity: 0.4;
338
- cursor: not-allowed;
339
- }
575
+ .go-btn:disabled { opacity: 0.4; cursor: not-allowed; }
340
576
  .go-btn:not(:disabled):hover { filter: brightness(1.1); }
577
+
578
+ .url-error {
579
+ margin-top: 8px;
580
+ font-size: 12px;
581
+ color: ${danger};
582
+ }
341
583
  `;
342
584
  }
343
585
  //# sourceMappingURL=wallet-selector.js.map