pages235/src/react/useLongPress.ts

63 lines
1.8 KiB
TypeScript

import { useCallback, useRef, useState } from 'react'
interface LongPressOptions {
shouldPreventDefault?: boolean;
delay?: number;
}
const useLongPress = (
onLongPress: () => void,
onClick: () => void,
{ shouldPreventDefault = true, delay = 300 }: LongPressOptions = {}
) => {
const [longPressTriggered, setLongPressTriggered] = useState(false)
const timeout = useRef<number | undefined>()
const target = useRef<EventTarget | null>(null)
const start = useCallback(
(event: React.MouseEvent | React.TouchEvent) => {
if (shouldPreventDefault && event.target) {
event.target.addEventListener('touchend', preventDefault, {
passive: false
})
target.current = event.target
}
timeout.current = window.setTimeout(() => {
onLongPress()
setLongPressTriggered(true)
}, delay)
},
[onLongPress, delay, shouldPreventDefault]
)
const clear = useCallback(
(event: React.MouseEvent | React.TouchEvent) => {
if (timeout.current) clearTimeout(timeout.current)
if (!longPressTriggered) onClick()
setLongPressTriggered(false)
if (shouldPreventDefault && target.current) {
target.current.removeEventListener('touchend', preventDefault)
}
},
[shouldPreventDefault, onClick, longPressTriggered]
)
return {
onMouseDown: (e: React.MouseEvent) => start(e),
onTouchStart: (e: React.TouchEvent) => start(e),
onMouseUp: (e: React.MouseEvent) => clear(e),
onMouseLeave: (e: React.MouseEvent) => clear(e),
onTouchEnd: (e: React.TouchEvent) => clear(e)
}
}
const preventDefault = (event: Event) => {
if (!('touches' in event)) return
const touchEvent = event as TouchEvent
if (touchEvent.touches.length < 2 && event.preventDefault) {
event.preventDefault()
}
}
export default useLongPress