@enbox/browser 0.3.47 → 0.3.49

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.
@@ -14,9 +14,9 @@
14
14
  * (or deep link on phones), the pairing-code input, progress, success,
15
15
  * and error states.
16
16
  * 3. **Footer** — the wallet identity row ("Connecting with" + the selected
17
- * wallet and the next catalog wallets as tiles, capped so the same wallet
18
- * never appears twice), a More tile that expands the full catalog grid
19
- * with search + custom URL in place, and the alternate-method link.
17
+ * wallet and the next catalog wallets as tiles), a More tile that expands
18
+ * the remaining wallets as a matching grid (search + custom URL) in
19
+ * place — a wallet is never shown twice — and the alternate-method link.
20
20
  *
21
21
  * Theming: the stylesheet is static and reads `--ec-*` design tokens.
22
22
  * Light/dark follows the visitor's system via `prefers-color-scheme` and
@@ -927,29 +927,35 @@ export function runConnectModal(options: ConnectModalOptions): Promise<ConnectRe
927
927
  panel.className = 'wallet-panel';
928
928
  panel.hidden = true;
929
929
 
930
- const hiddenCount = wallets.filter((wallet) => !rowWallets.some((shown) => shown.url === wallet.url)).length;
930
+ // The panel grid holds only the wallets NOT already visible in the
931
+ // row, so expanding never shows the same wallet twice.
932
+ const gridWallets = wallets.filter((wallet) => !rowWallets.some((shown) => shown.url === wallet.url));
933
+
931
934
  const more = document.createElement('button');
932
935
  more.className = 'row-tile more-tile';
933
936
  more.title = 'All wallets';
934
937
  more.setAttribute('aria-expanded', 'false');
935
- more.appendChild(el('span', 'more-count', hiddenCount > 0 ? `+${hiddenCount}` : '⋯'));
938
+ more.appendChild(el('span', 'more-count', gridWallets.length > 0 ? `+${gridWallets.length}` : '⋯'));
936
939
  more.appendChild(el('span', 'row-tile-name', 'More'));
937
940
  more.addEventListener('click', () => {
938
941
  panel.hidden = !panel.hidden;
939
942
  more.setAttribute('aria-expanded', panel.hidden ? 'false' : 'true');
943
+ if (!panel.hidden) {
944
+ updateScrollHint();
945
+ }
940
946
  });
941
947
  row.appendChild(more);
942
948
 
943
949
  const label = rowWallets.length > 0 ? el('div', 'wallet-row-label', 'Connecting with') : undefined;
944
950
 
945
- // Search filter — appears once the catalog outgrows one grid row.
951
+ // Search filter — appears once the grid outgrows one row of tiles.
946
952
  const tiles: Array<{ wallet: (typeof wallets)[number]; el: HTMLButtonElement }> = [];
947
953
  const empty = document.createElement('div');
948
954
  empty.className = 'wallet-empty';
949
- empty.textContent = 'No wallets match your search.';
955
+ empty.textContent = 'No other wallets match your search.';
950
956
  empty.hidden = true;
951
957
 
952
- if (wallets.length > WALLET_SEARCH_THRESHOLD) {
958
+ if (gridWallets.length > WALLET_SEARCH_THRESHOLD) {
953
959
  const search = document.createElement('input');
954
960
  search.type = 'search';
955
961
  search.className = 'wallet-search';
@@ -966,30 +972,37 @@ export function runConnectModal(options: ConnectModalOptions): Promise<ConnectRe
966
972
  if (match) { visible += 1; }
967
973
  }
968
974
  empty.hidden = visible > 0;
975
+ updateScrollHint();
969
976
  });
970
977
  panel.appendChild(search);
971
978
  }
972
979
 
973
- // Square tiles, three per row; past two rows the grid scrolls in
974
- // place so a large catalog never stretches the modal.
980
+ // Tiles matching the identity row, four per row; past three rows the
981
+ // grid scrolls in place, with a bottom fade hinting at more below.
982
+ const scrollWrap = document.createElement('div');
983
+ scrollWrap.className = 'wallet-scroll-wrap';
984
+ scrollWrap.hidden = gridWallets.length === 0;
975
985
  const scroll = document.createElement('div');
976
986
  scroll.className = 'wallet-scroll';
977
987
  const grid = document.createElement('div');
978
988
  grid.className = 'wallet-grid';
979
989
 
980
- for (const wallet of wallets) {
990
+ const updateScrollHint = (): void => {
991
+ const overflowing = scroll.scrollHeight - scroll.clientHeight > 1;
992
+ const atEnd = scroll.scrollTop + scroll.clientHeight >= scroll.scrollHeight - 1;
993
+ scrollWrap.classList.toggle('scroll-hint', overflowing && !atEnd);
994
+ };
995
+ scroll.addEventListener('scroll', updateScrollHint);
996
+
997
+ for (const wallet of gridWallets) {
981
998
  const tile = document.createElement('button');
982
999
  tile.className = 'wallet-tile';
983
- tile.title = wallet.name;
1000
+ tile.title = wallet.description ?? wallet.name;
984
1001
  tile.appendChild(buildWalletIcon(wallet));
985
1002
  const tileName = document.createElement('span');
986
1003
  tileName.className = 'wallet-tile-name';
987
1004
  tileName.textContent = wallet.name;
988
1005
  tile.appendChild(tileName);
989
- if (wallet.url === walletUrl) {
990
- tile.classList.add('selected');
991
- tile.setAttribute('aria-pressed', 'true');
992
- }
993
1006
  tile.addEventListener('click', () => {
994
1007
  selectWallet(wallet.url);
995
1008
  });
@@ -998,7 +1011,8 @@ export function runConnectModal(options: ConnectModalOptions): Promise<ConnectRe
998
1011
  }
999
1012
  scroll.appendChild(grid);
1000
1013
  scroll.appendChild(empty);
1001
- panel.appendChild(scroll);
1014
+ scrollWrap.appendChild(scroll);
1015
+ panel.appendChild(scrollWrap);
1002
1016
 
1003
1017
  // Custom wallet URL (the power-user path, demoted to the disclosure).
1004
1018
  const custom = document.createElement('div');
@@ -1465,7 +1479,7 @@ const MODAL_STYLES = `
1465
1479
  grid-template-columns: repeat(4, 1fr);
1466
1480
  gap: 8px;
1467
1481
  }
1468
- .row-tile {
1482
+ .row-tile, .wallet-tile {
1469
1483
  display: flex;
1470
1484
  flex-direction: column;
1471
1485
  align-items: center;
@@ -1480,15 +1494,15 @@ const MODAL_STYLES = `
1480
1494
  font-size: 11px;
1481
1495
  cursor: pointer;
1482
1496
  }
1483
- .row-tile:hover { border-color: var(--ec-accent); }
1497
+ .row-tile:hover, .wallet-tile:hover { border-color: var(--ec-accent); }
1484
1498
  .row-tile.selected {
1485
1499
  border-color: var(--ec-accent);
1486
1500
  background: var(--ec-accent-soft);
1487
1501
  box-shadow: inset 0 0 0 1px var(--ec-accent);
1488
1502
  }
1489
1503
  .row-tile.selected .row-tile-name { font-weight: 600; }
1490
- .row-tile .wallet-icon { width: 28px; height: 28px; }
1491
- .row-tile-name { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
1504
+ .row-tile .wallet-icon, .wallet-tile .wallet-icon { width: 28px; height: 28px; }
1505
+ .row-tile-name, .wallet-tile-name { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
1492
1506
 
1493
1507
  .more-tile { color: var(--ec-muted); }
1494
1508
  .more-tile:hover { color: var(--ec-text); }
@@ -1514,46 +1528,33 @@ const MODAL_STYLES = `
1514
1528
  }
1515
1529
  .wallet-search:focus { outline: none; border-color: var(--ec-accent); }
1516
1530
 
1517
- .wallet-scroll { max-height: 260px; overflow-y: auto; }
1531
+ /* Cap the grid at three rows of tiles; past that it scrolls in place,
1532
+ and the wrapper's bottom fade hints that more wallets are below. */
1533
+ .wallet-scroll-wrap { position: relative; }
1534
+ .wallet-scroll { max-height: 220px; overflow-y: auto; }
1535
+ .wallet-scroll-wrap.scroll-hint::after {
1536
+ content: '';
1537
+ position: absolute;
1538
+ left: 0;
1539
+ right: 0;
1540
+ bottom: 0;
1541
+ height: 28px;
1542
+ background: linear-gradient(to bottom, transparent, var(--ec-bg));
1543
+ pointer-events: none;
1544
+ }
1518
1545
  .wallet-grid {
1519
1546
  display: grid;
1520
- grid-template-columns: repeat(3, 1fr);
1521
- gap: 8px;
1522
- }
1523
- .wallet-tile {
1524
- aspect-ratio: 1;
1525
- display: flex;
1526
- flex-direction: column;
1527
- align-items: center;
1528
- justify-content: center;
1547
+ grid-template-columns: repeat(4, 1fr);
1529
1548
  gap: 8px;
1530
- padding: 8px;
1531
- min-width: 0;
1532
- background: var(--ec-surface);
1533
- border: 1px solid var(--ec-border);
1534
- border-radius: 12px;
1535
- color: var(--ec-text);
1536
- font-size: 12px;
1537
- cursor: pointer;
1538
- }
1539
- .wallet-tile:hover { border-color: var(--ec-accent); }
1540
- .wallet-tile.selected {
1541
- border-color: var(--ec-accent);
1542
- background: var(--ec-accent-soft);
1543
- box-shadow: inset 0 0 0 1px var(--ec-accent);
1544
1549
  }
1545
- .wallet-tile-name { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
1546
1550
 
1547
1551
  .wallet-icon { position: relative; width: 28px; height: 28px; flex-shrink: 0; display: inline-flex; }
1548
- .wallet-tile .wallet-icon { width: 40px; height: 40px; }
1549
1552
  .wallet-badge {
1550
1553
  width: 100%; height: 100%; border-radius: 8px; display: inline-flex;
1551
1554
  align-items: center; justify-content: center; font-size: 13px;
1552
1555
  font-weight: 600; background: var(--ec-accent-soft); color: var(--ec-accent);
1553
1556
  }
1554
- .wallet-tile .wallet-badge { border-radius: 10px; font-size: 17px; }
1555
1557
  .wallet-img { position: absolute; inset: 0; width: 100%; height: 100%; border-radius: 8px; object-fit: cover; }
1556
- .wallet-tile .wallet-img { border-radius: 10px; }
1557
1558
 
1558
1559
  .wallet-empty { padding: 10px 4px; font-size: 12px; color: var(--ec-muted); text-align: center; }
1559
1560