aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-09-02 12:14:25 -0700
committerAdam Soltys <[email protected]>2026-09-02 12:14:25 -0700
commit79ebdaa0426cc9dc474a61876207ff19fbc5aa22 (patch)
tree8da4bc1857d54aa5503fc1bba4fa0d2197d7e2af
parent92594d6b1290c4985c33276cf5203ace2c5d6c61 (diff)
downloadcoinosv3-79ebdaa0426cc9dc474a61876207ff19fbc5aa22.tar.gz
coinosv3-79ebdaa0426cc9dc474a61876207ff19fbc5aa22.zip
Tab feedback at touch speed: the strip's active state flips with a direct DOM write that paints in the same frame as the finger, and the heavy pane render runs after that paint (double-rAF) — running it synchronously on pointerdown meant even the button's own light-up waited out a 100ms+ rebuild
Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01MrkLsNScXe9b6BviUSdmMr
-rw-r--r--src/app.js16
1 files changed, 14 insertions, 2 deletions
diff --git a/src/app.js b/src/app.js
index e0b2c04..a818d67 100644
--- a/src/app.js
+++ b/src/app.js
@@ -815,15 +815,27 @@ function tabBtn(label, active, onClick) {
// touch-down for exactly this reason. The click handler stays for
// keyboard/AT activation; re-selecting the current tab is a no-op, so the
// pair firing together costs nothing.
+ //
+ // And feedback comes FIRST: the full re-render can take 100ms+ on a
+ // phone, and running it synchronously meant even the button's own active
+ // state waited for the whole pane to build. Flip the strip's classes with
+ // a direct DOM write (paints this frame), then run the real render after
+ // that paint — double-rAF is the "after the next paint" idiom.
let downAt = 0;
+ const select = (btn) => {
+ if (btn && btn.parentElement) {
+ for (const b of btn.parentElement.children) b.classList.toggle('active', b === btn);
+ }
+ requestAnimationFrame(() => requestAnimationFrame(onClick));
+ };
return h('button', {
class: active ? 'active' : '',
onPointerdown: (e) => {
if (e.button !== 0) return;
downAt = performance.now();
- onClick();
+ select(e.currentTarget);
},
- onClick: () => { if (performance.now() - downAt > 500) onClick(); },
+ onClick: (e) => { if (performance.now() - downAt > 500) select(e.currentTarget); },
}, label);
}