fix: give every address a row of its own, so none wraps or is shortened (closes #380)
All checks were successful
check / check (push) Successful in 1m52s
e2e / e2e-chrome (push) Successful in 2m33s
e2e / e2e-firefox (push) Successful in 56s

The wallet list was the reported case. An address there shared one row with
the [info] and [x] controls, which took about a third of the width off it,
so all 42 characters folded onto a second line. A folded address is not a
cosmetic problem: it turns one string the user is meant to compare against
a known value into two shorter ones, which is the shape an address-poisoning
attack wants.

The fix is the layout, not the CSS. renderAddressHtml() -- the single
renderer behind every common view that shows an address -- now emits an
identity strip (colour dot, wallet title, explorer link, with the ENS name
below it) and then the address alone on a full-width row. The wallet list
moves [info] and [x] up onto the "Address N" line, which was empty to its
right. The transaction rows on Home, the address screen and the token screen
carried a truncateMiddle()d counterparty squeezed in beside the amount;
they now name it on the amount line where we know it, and carry the whole
address on the row below.

With the row to itself, an address fits at every nesting depth the popup
uses, including the transaction detail wells, which are the narrowest
containers it has. .am-address holds nowrap so it cannot fold again, and
overflow-x so that if it ever does not fit -- wider glyphs, a zoom -- the
user can still reach the last character rather than having it clipped away
by #app's overflow-x-hidden with nothing to say it happened.

No caller passes maxLen any more, so the 32-character floor that lived in
those call sites moved into renderAddressHtml(). truncateMiddle() and its
10-character cap are unchanged: the guarantee has to outlive having no
current callers.

tests/e2e measures it in a real Chromium rather than asserting on markup:
whether an address wrapped is a question about glyph advances and the width
of the box it landed in, and nothing in the HTML answers it. Every rendered
address is checked for being whole, occupying one line box, fitting its row
and ending inside the popup's content box, with the document itself not
scrolling sideways -- across Home with a two-address wallet, the address,
token, receive, send and transaction detail screens, the confirmation screen
and the dApp transaction prompt.
This commit is contained in:
clawbot
2026-08-30 02:51:51 +00:00
parent a098bb0c32
commit 4b4d9e7a1d
10 changed files with 356 additions and 75 deletions

View File

@@ -44,3 +44,23 @@ body {
background-color 225ms ease-out,
color 225ms ease-out;
}
/* An address is one atomic string, so it gets a row of its own and never
* breaks across lines. A wrapped address reads as two shorter strings, and
* two shorter strings are exactly what an address-poisoning attack needs
* the user to compare instead of the whole thing. Every view that shows an
* address puts it in one of these, alone: the colour dot, the wallet title,
* the ENS name and the explorer link all live on their own line above, so
* nothing competes with the 42 characters for width.
*
* overflow-x is the escape hatch, not the mechanism. The row is wide enough
* for a full address at every nesting depth the popup uses; if that ever
* stops being true — a font with wider glyphs, a browser zoom — the row
* scrolls and the user can still reach the last character, rather than the
* tail being clipped away by #app's overflow-x-hidden with nothing to say
* it happened. tests/e2e asserts the scroll is never actually needed. */
.am-address {
display: block;
white-space: nowrap;
overflow-x: auto;
}