diff options
| author | Adam Soltys <[email protected]> | 2026-09-02 12:14:25 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2026-09-02 12:14:25 -0700 |
| commit | 79ebdaa0426cc9dc474a61876207ff19fbc5aa22 (patch) | |
| tree | 8da4bc1857d54aa5503fc1bba4fa0d2197d7e2af /src/app.js | |
| parent | 92594d6b1290c4985c33276cf5203ace2c5d6c61 (diff) | |
| download | coinosv3-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
Diffstat (limited to 'src/app.js')
| -rw-r--r-- | src/app.js | 16 |
1 files changed, 14 insertions, 2 deletions
@@ -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); } |
