fix: reserve space for all error/status messages — closes #123
All checks were successful
check / check (push) Successful in 22s

Replace display:none (hidden class) with visibility:hidden/visible for all
error, warning, and status message elements across the extension UI. This
prevents layout shift when messages appear or disappear.

Changes:
- helpers.js: showError/hideError now use visibility instead of hidden class
- index.html: all error/status divs use visibility:hidden + min-height
- confirmTx.js: warnings, errors, fee section use visibility
- approval.js: tx-error, sign-error, danger-warning use visibility
- addressDetail.js: export-privkey-flash uses visibility
- deleteWallet.js: delete-wallet-flash uses visibility
- addWallet.js: phrase-warning uses visibility
- receive.js: erc20-warning uses visibility
- addToken.js: add-token-info uses visibility
- settingsAddToken.js: settings-addtoken-info uses visibility
This commit is contained in:
clawbot 2026-02-28 16:30:43 -08:00
parent 5f01d9f111
commit 813993f17c
10 changed files with 67 additions and 41 deletions

View File

@ -107,7 +107,8 @@
</div>
<div
id="add-wallet-phrase-warning"
class="text-xs mb-2 border border-border border-dashed p-2 hidden"
class="text-xs mb-2 border border-border border-dashed p-2"
style="visibility: hidden"
>
Write these words down and keep them safe. Anyone with
them can take your funds; if you lose them, your wallet
@ -375,7 +376,8 @@
</p>
<div
id="export-privkey-flash"
class="text-xs mb-2 hidden"
class="text-xs mb-2 min-h-[1.25rem]"
style="visibility: hidden"
></div>
<div id="export-privkey-password-section" class="mb-2">
<label class="block mb-1">Password</label>
@ -579,13 +581,17 @@
<div class="text-xs text-muted mb-1">Your balance</div>
<div id="confirm-balance" class="text-xs"></div>
</div>
<div id="confirm-fee" class="mb-3 hidden">
<div id="confirm-fee" class="mb-3" style="visibility: hidden">
<div class="text-xs text-muted mb-1">
Estimated network fee
</div>
<div id="confirm-fee-amount" class="text-xs"></div>
</div>
<div id="confirm-warnings" class="mb-2 hidden"></div>
<div
id="confirm-warnings"
class="mb-2"
style="visibility: hidden"
></div>
<div
id="confirm-recipient-warning"
class="mb-2"
@ -601,7 +607,8 @@
</div>
<div
id="confirm-errors"
class="mb-2 border border-border border-dashed p-2 hidden"
class="mb-2 border border-border border-dashed p-2"
style="visibility: hidden; min-height: 1.25rem"
></div>
<div class="mb-2">
<label class="block mb-1 text-xs">Password</label>
@ -614,6 +621,7 @@
<div
id="confirm-tx-password-error"
class="text-xs mb-2 min-h-[1.25rem]"
style="visibility: hidden"
></div>
<button
id="btn-confirm-send"
@ -728,7 +736,8 @@
</button>
<div
id="receive-erc20-warning"
class="text-xs border border-border border-dashed p-2 mt-3 hidden"
class="text-xs border border-border border-dashed p-2 mt-3"
style="visibility: hidden"
></div>
</div>
@ -756,7 +765,8 @@
</div>
<div
id="add-token-info"
class="text-xs text-muted mb-2 hidden"
class="text-xs text-muted mb-2 min-h-[1.25rem]"
style="visibility: hidden"
></div>
<div class="mb-2">
<label class="block mb-1 text-xs text-muted"
@ -938,7 +948,8 @@
</p>
<div
id="delete-wallet-flash"
class="text-xs text-red-500 mb-2 hidden"
class="text-xs text-red-500 mb-2 min-h-[1.25rem]"
style="visibility: hidden"
></div>
<div class="mb-2">
<label class="block mb-1">Password</label>
@ -1013,7 +1024,8 @@
/>
<div
id="settings-addtoken-info"
class="text-xs text-muted mt-1 hidden"
class="text-xs text-muted mt-1 min-h-[1.25rem]"
style="visibility: hidden"
></div>
<button
id="btn-settings-addtoken-manual"
@ -1139,7 +1151,8 @@
</div>
<div
id="approve-tx-error"
class="text-xs mb-2 border border-border border-dashed p-1 min-h-[1.25rem] hidden"
class="text-xs mb-2 border border-border border-dashed p-1 min-h-[1.25rem]"
style="visibility: hidden"
></div>
<div class="flex justify-between">
<button
@ -1167,8 +1180,10 @@
<div
id="approve-sign-danger-warning"
class="hidden mb-3 p-2 text-xs font-bold"
class="mb-3 p-2 text-xs font-bold"
style="
visibility: hidden;
min-height: 1.25rem;
background: #fee2e2;
color: #991b1b;
border: 2px solid #dc2626;
@ -1205,7 +1220,8 @@
</div>
<div
id="approve-sign-error"
class="text-xs mb-2 border border-border border-dashed p-1 min-h-[1.25rem] hidden"
class="text-xs mb-2 border border-border border-dashed p-1 min-h-[1.25rem]"
style="visibility: hidden"
></div>
<div class="flex justify-between">
<button

View File

@ -7,7 +7,8 @@ const { log } = require("../../shared/log");
function show() {
$("add-token-address").value = "";
$("add-token-info").classList.add("hidden");
$("add-token-info").textContent = "";
$("add-token-info").style.visibility = "hidden";
const list = $("common-token-list");
list.innerHTML = getTopTokens(25)
.map(
@ -45,7 +46,7 @@ function init(ctx) {
}
const infoEl = $("add-token-info");
infoEl.textContent = "Looking up token...";
infoEl.classList.remove("hidden");
infoEl.style.visibility = "visible";
log.debugf("Looking up token contract", contractAddr);
try {
const info = await lookupTokenInfo(contractAddr, state.rpcUrl);
@ -63,7 +64,8 @@ function init(ctx) {
const detail = e.shortMessage || e.message || String(e);
log.errorf("Token lookup failed for", contractAddr, detail);
showFlash(detail);
infoEl.classList.add("hidden");
infoEl.textContent = "";
infoEl.style.visibility = "hidden";
}
});

View File

@ -71,7 +71,7 @@ function show() {
$("import-xprv-key").value = "";
$("add-wallet-password").value = "";
$("add-wallet-password-confirm").value = "";
$("add-wallet-phrase-warning").classList.add("hidden");
$("add-wallet-phrase-warning").style.visibility = "hidden";
switchMode("mnemonic");
showView("add-wallet");
}
@ -281,7 +281,7 @@ function init(ctx) {
// Generate mnemonic
$("btn-generate-phrase").addEventListener("click", () => {
$("wallet-mnemonic").value = generateMnemonic();
$("add-wallet-phrase-warning").classList.remove("hidden");
$("add-wallet-phrase-warning").style.visibility = "visible";
});
// Import / confirm

View File

@ -312,8 +312,8 @@ function init(_ctx) {
$("export-privkey-address").textContent = addr.address;
$("export-privkey-address").dataset.full = addr.address;
$("export-privkey-password").value = "";
$("export-privkey-flash").classList.add("hidden");
$("export-privkey-flash").textContent = "";
$("export-privkey-flash").style.visibility = "hidden";
$("export-privkey-password-section").classList.remove("hidden");
$("export-privkey-result").classList.add("hidden");
$("export-privkey-value").textContent = "";
@ -324,7 +324,7 @@ function init(_ctx) {
const password = $("export-privkey-password").value;
if (!password) {
$("export-privkey-flash").textContent = "Password is required.";
$("export-privkey-flash").classList.remove("hidden");
$("export-privkey-flash").style.visibility = "visible";
return;
}
const btn = $("btn-export-privkey-confirm");
@ -345,10 +345,10 @@ function init(_ctx) {
$("export-privkey-password-section").classList.add("hidden");
$("export-privkey-value").textContent = privateKey;
$("export-privkey-result").classList.remove("hidden");
$("export-privkey-flash").classList.add("hidden");
$("export-privkey-flash").style.visibility = "hidden";
} catch {
$("export-privkey-flash").textContent = "Wrong password.";
$("export-privkey-flash").classList.remove("hidden");
$("export-privkey-flash").style.visibility = "visible";
} finally {
btn.disabled = false;
btn.classList.remove("text-muted");

View File

@ -269,7 +269,7 @@ function showTxApproval(details) {
}
$("approve-tx-password").value = "";
$("approve-tx-error").classList.add("hidden");
hideError("approve-tx-error");
showView("approve-tx");
}
@ -351,10 +351,10 @@ function showSignApproval(details) {
if (warningEl) {
if (sp.dangerWarning) {
warningEl.textContent = sp.dangerWarning;
warningEl.classList.remove("hidden");
warningEl.style.visibility = "visible";
} else {
warningEl.textContent = "";
warningEl.classList.add("hidden");
warningEl.style.visibility = "hidden";
}
}

View File

@ -186,9 +186,10 @@ function show(txInfo) {
`<div class="border border-border border-dashed p-2 mb-1 text-xs font-bold">WARNING: ${w}</div>`,
)
.join("");
warningsEl.classList.remove("hidden");
warningsEl.style.visibility = "visible";
} else {
warningsEl.classList.add("hidden");
warningsEl.innerHTML = "";
warningsEl.style.visibility = "hidden";
}
// Check for errors
@ -226,11 +227,12 @@ function show(txInfo) {
errorsEl.innerHTML = errors
.map((e) => `<div class="text-xs">${e}</div>`)
.join("");
errorsEl.classList.remove("hidden");
errorsEl.style.visibility = "visible";
sendBtn.disabled = true;
sendBtn.classList.add("text-muted");
} else {
errorsEl.classList.add("hidden");
errorsEl.innerHTML = "";
errorsEl.style.visibility = "hidden";
sendBtn.disabled = false;
sendBtn.classList.remove("text-muted");
}
@ -240,7 +242,7 @@ function show(txInfo) {
hideError("confirm-tx-password-error");
// Gas estimate — show placeholder then fetch async
$("confirm-fee").classList.remove("hidden");
$("confirm-fee").style.visibility = "visible";
$("confirm-fee-amount").textContent = "Estimating...";
state.viewData = { pendingTx: txInfo };
showView("confirm-tx");

View File

@ -12,7 +12,7 @@ function show(walletIdx) {
wallet.name || "Wallet " + (walletIdx + 1);
$("delete-wallet-password").value = "";
$("delete-wallet-flash").textContent = "";
$("delete-wallet-flash").classList.add("hidden");
$("delete-wallet-flash").style.visibility = "hidden";
showView("delete-wallet-confirm");
}
@ -29,14 +29,14 @@ function init(_ctx) {
if (!pw) {
$("delete-wallet-flash").textContent =
"Please enter your password.";
$("delete-wallet-flash").classList.remove("hidden");
$("delete-wallet-flash").style.visibility = "visible";
return;
}
if (deleteWalletIndex === null) {
$("delete-wallet-flash").textContent =
"No wallet selected for deletion.";
$("delete-wallet-flash").classList.remove("hidden");
$("delete-wallet-flash").style.visibility = "visible";
return;
}
@ -52,7 +52,7 @@ function init(_ctx) {
await decryptWithPassword(wallet.encryptedSecret, pw);
} catch (_e) {
$("delete-wallet-flash").textContent = "Wrong password.";
$("delete-wallet-flash").classList.remove("hidden");
$("delete-wallet-flash").style.visibility = "visible";
btn.disabled = false;
btn.classList.remove("text-muted");
return;

View File

@ -40,11 +40,13 @@ function $(id) {
function showError(id, msg) {
const el = $(id);
el.textContent = msg;
el.classList.remove("hidden");
el.style.visibility = "visible";
}
function hideError(id) {
$(id).classList.add("hidden");
const el = $(id);
el.textContent = "";
el.style.visibility = "hidden";
}
function showView(name) {

View File

@ -53,9 +53,10 @@ function show() {
"This is an ERC-20 token. Only send " +
symbol +
" on the Ethereum network to this address. Sending tokens on other networks will result in permanent loss.";
warningEl.classList.remove("hidden");
warningEl.style.visibility = "visible";
} else {
warningEl.classList.add("hidden");
warningEl.textContent = "";
warningEl.style.visibility = "hidden";
}
showView("receive");
}

View File

@ -73,7 +73,8 @@ function renderDropdown() {
function show() {
$("settings-addtoken-address").value = "";
$("settings-addtoken-info").classList.add("hidden");
$("settings-addtoken-info").textContent = "";
$("settings-addtoken-info").style.visibility = "hidden";
renderTop10();
renderDropdown();
showView("settings-addtoken");
@ -129,7 +130,7 @@ function init(_ctx) {
}
const infoEl = $("settings-addtoken-info");
infoEl.textContent = "Looking up token...";
infoEl.classList.remove("hidden");
infoEl.style.visibility = "visible";
log.debugf("Looking up token contract", addr);
try {
const info = await lookupTokenInfo(addr, state.rpcUrl);
@ -143,7 +144,8 @@ function init(_ctx) {
await saveState();
showFlash("Added " + info.symbol);
$("settings-addtoken-address").value = "";
infoEl.classList.add("hidden");
infoEl.textContent = "";
infoEl.style.visibility = "hidden";
renderTop10();
renderDropdown();
ctx.doRefreshAndRender();
@ -151,7 +153,8 @@ function init(_ctx) {
const detail = e.shortMessage || e.message || String(e);
log.errorf("Token lookup failed for", addr, detail);
showFlash(detail);
infoEl.classList.add("hidden");
infoEl.textContent = "";
infoEl.style.visibility = "hidden";
}
});
}