mirror of
https://github.com/WonderAliceUwU/OmniArr.git
synced 2026-11-11 04:01:01 +00:00
🐛 fix: ignore taps that end a scroll on mobile
Some mobile browsers fire a click when a scroll gesture ends over a poster, which opened it by accident. Swallow clicks from touches that moved or while a scroll is still settling, so only real taps reach the app.
This commit is contained in:
1 parent
2bb0540ee6
commit
50bdbce1bd
2 files changed
+54
No files matched your search
@@ -2,6 +2,9 @@ import { StrictMode } from 'react'
|
||||
import { createRoot } from 'react-dom/client'
|
||||
import './index.css'
|
||||
import App from './App'
|
||||
import { installTapGuard } from './tapGuard'
|
||||
|
||||
installTapGuard()
|
||||
|
||||
createRoot(document.getElementById('root')!).render(
|
||||
<StrictMode>
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
// Some mobile browsers (notably iOS, and installed web apps) fire a click when
|
||||
// a scroll gesture ends on top of a poster, which opens it by accident. This
|
||||
// swallows clicks that come from a touch that moved or from a scroll that was
|
||||
// still settling, so only real taps reach the app.
|
||||
|
||||
const TAP_SLOP_PX = 10
|
||||
const SCROLL_SETTLE_MS = 120
|
||||
const TOUCH_CLICK_WINDOW_MS = 800
|
||||
|
||||
export function installTapGuard() {
|
||||
let startX = 0
|
||||
let startY = 0
|
||||
let moved = false
|
||||
let lastTouchEndAt = 0
|
||||
let lastScrollAt = 0
|
||||
|
||||
window.addEventListener('touchstart', (event) => {
|
||||
const touch = event.touches[0]
|
||||
startX = touch?.clientX ?? 0
|
||||
startY = touch?.clientY ?? 0
|
||||
moved = false
|
||||
}, { capture: true, passive: true })
|
||||
|
||||
window.addEventListener('touchmove', (event) => {
|
||||
const touch = event.touches[0]
|
||||
if (touch && Math.hypot(touch.clientX - startX, touch.clientY - startY) > TAP_SLOP_PX) {
|
||||
moved = true
|
||||
}
|
||||
}, { capture: true, passive: true })
|
||||
|
||||
window.addEventListener('touchend', () => {
|
||||
lastTouchEndAt = Date.now()
|
||||
}, { capture: true, passive: true })
|
||||
|
||||
// Scroll events don't bubble, so listen in the capture phase to see every
|
||||
// scroll container (page, carousels, episode lists).
|
||||
document.addEventListener('scroll', () => {
|
||||
lastScrollAt = Date.now()
|
||||
}, { capture: true, passive: true })
|
||||
|
||||
window.addEventListener('click', (event) => {
|
||||
const now = Date.now()
|
||||
if (now - lastTouchEndAt > TOUCH_CLICK_WINDOW_MS) {
|
||||
return
|
||||
}
|
||||
if (moved || now - lastScrollAt < SCROLL_SETTLE_MS) {
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
}
|
||||
}, { capture: true })
|
||||
}
|
||||
Reference in new issue
Block a user