fix: a held spinner interrupted by a redraw still commits on release (Chromium blurs the removed field)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
digital-garbage
2026-10-10 00:19:20 +03:00
co-authored by Claude Opus 5.5
parent 57c74268cd
commit f39f5e730a
2 changed files with 19 additions and 1 deletions
+1 -1
View File
@@ -96,7 +96,7 @@ define("number", "md", ({ value = 0, min, max, step = 1, precision, unit, snap,
if (skipped) { skipped = false; commit(); }
};
input.addEventListener("change", () => { if (held) skipped = true; else commit(); });
input.addEventListener("blur", () => { held = skipped = false; commit(); }); // also ends a hold whose release never came
input.addEventListener("blur", () => { if (swapping.depth) return; held = skipped = false; commit(); }); // ends a hold whose release never came; a redraw's blur does not: the release still commits
input.addEventListener("keydown", (e) => {
if (e.key === "Enter") { e.preventDefault(); commit(); }
else if (e.repeat && /^(ArrowUp|ArrowDown|PageUp|PageDown)$/.test(e.key)) held = true;
@@ -755,3 +755,21 @@ test("a field Chromium blurs mid-redraw (still attached) does not commit then; t
region.node.remove();
}
});
test("a held spinner interrupted by a redraw (with Chromium's blur on removal) still commits on release", () => {
let state = 15;
const region = mount(composer.region.stack());
const redraw = () => { const kids = [composer.number.md({ label: "N", value: state, onChange: (v) => { state = v; redraw(); } })]; region.set(kids); };
redraw();
const real = region.node.replaceChildren.bind(region.node);
region.node.replaceChildren = (...kids) => { const f = document.activeElement; if (region.node.contains(f)) { fire(f, "change"); fire(f, "blur"); } real(...kids); };
const box = () => region.node.querySelector('[aria-label="N"]');
box().focus(); fire(box(), "pointerdown");
box().value = "16"; fire(box(), "change"); // a step while held: not committed yet
redraw(); // something else redraws mid-hold
delete region.node.replaceChildren;
window.dispatchEvent(new window.Event("pointerup"));
assert.equal(state, 16);
assert.equal(box().value, "16");
region.node.remove();
});