From a6e6083e4c758a9c07dc7a4ea38f880c561cb365 Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Sun, 28 Jun 2026 03:50:35 -0700 Subject: Stop input/select fields losing focus MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two causes, both fixed: - _scanSpMempool emitted on every WS push even when our pending set was unchanged. The mainnet mempool churns constantly, so this re-rendered the whole app every few seconds, stealing focus mid-type. Now it only emits when our pending SP set actually changes. - render() rebuilds the DOM (replaceChildren), which inherently drops focus. Added focus + caret preservation: capture the focused field's index-path and selection before the rebuild, restore them after. So any render source (poll, payment push, scan) is now invisible to someone typing. Verified via CDP: typing 'bc1q…' in the Send address, caret at 6, then forcing a re-render — focus, value, and caret all retained. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/wallet.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'src/wallet.js') diff --git a/src/wallet.js b/src/wallet.js index 006441c..5943d86 100644 --- a/src/wallet.js +++ b/src/wallet.js @@ -602,12 +602,13 @@ export class Wallet { // any pending that just confirmed, so an outpoint never appears twice. const confNow = this.spUtxos.filter((u) => u.confirmed); const confNowIds = new Set(confNow.map((u) => `${u.txid}:${u.vout}`)); - const prevPending = this.spUtxos.length - confNow.length; + const oldPendingIds = new Set(this.spUtxos.filter((u) => !u.confirmed).map((u) => `${u.txid}:${u.vout}`)); const freshPending = pending.filter((p) => !confNowIds.has(`${p.txid}:${p.vout}`)); + // Only emit when our pending set actually changed — the mempool churns + // constantly, and a no-op emit would re-render and steal input focus. + const changed = freshPending.length !== oldPendingIds.size || freshPending.some((p) => !oldPendingIds.has(`${p.txid}:${p.vout}`)); this.spUtxos = [...confNow, ...freshPending]; - if (freshPending.length !== prevPending || freshPending.length) this._recomputeBalanceFromChains(); - this.saveCache(); - this.emit(); + if (changed) { this._recomputeBalanceFromChains(); this.saveCache(); this.emit(); } } } finally { this._spMempoolBusy = false; -- cgit v1.2.3