in src/lib/shared/hooks/useTouchOrHover.js [5:132]
export function useTouchOrHover() {
const ref = useRef()
const [activeEvent, setActiveEvent] = useState()
const [position, setPosition] = useState()
const [isActive, setIsActive] = useState(false)
const [touchRect, setTouchRect] = useState()
useEffect(() => {
const element = ref.current
let touchCancelled = false
const touchStarted = (event) => {
if (event.touches.length > 1) return
touchCancelled = false
const touch = event.touches[0]
const { clientX, clientY } = touch
const rect = element.getBoundingClientRect()
const point = { x: clientX - rect.left, y: clientY - rect.top }
setPosition(point)
const touchRect = {
x: clientX - touch.radiusX,
y: clientY - touch.radiusY,
width: touch.radiusX * 2,
height: touch.radiusY * 2,
}
setTouchRect(touchRect)
setActiveEvent(event)
setIsActive(true)
event.stopPropagation()
}
const touchMoved = (event) => {
if (touchCancelled || event.targetTouches.length !== 1) return
setActiveEvent(event)
const touch = event.targetTouches[0]
const { clientX, clientY } = touch
const rect = element.getBoundingClientRect()
const point = { x: clientX - rect.left, y: clientY - rect.top }
// check if touch is:
// 1. cancelable. if it is not, then another gesture has started
// 2. still inside target rect
// if one of those conditions is not met, we hide the tooltip
if (!event.cancelable || !pointInsideRect(point, rect)) {
setIsActive(false)
touchCancelled = true
} else {
setPosition(point)
setIsActive(true)
}
}
const touchEnded = (event) => {
if (event.cancelable) {
// prevent simulated click events
event.preventDefault()
}
setActiveEvent(null)
setIsActive(false)
setPosition(null)
}
const mouseOver = (event) => {
const { clientX, clientY } = event
const rect = element.getBoundingClientRect()
const x = clientX - rect.left
const y = clientY - rect.top
setPosition({ x, y })
setActiveEvent(event)
setIsActive(true)
}
const mouseMoved = (event) => {
const { clientX, clientY } = event
const rect = element.getBoundingClientRect()
const x = clientX - rect.left
const y = clientY - rect.top
setActiveEvent(event)
setPosition({ x, y })
}
const mouseOut = () => {
setPosition(null)
setActiveEvent(null)
setIsActive(false)
}
element.addEventListener("touchstart", touchStarted)
element.addEventListener("touchmove", touchMoved)
element.addEventListener("touchend", touchEnded)
element.addEventListener("touchcancel", touchEnded)
element.addEventListener("mouseover", mouseOver)
element.addEventListener("mousemove", mouseMoved)
element.addEventListener("mouseout", mouseOut)
return () => {
element.removeEventListener("touchstart", touchStarted)
element.removeEventListener("touchmove", touchMoved)
element.removeEventListener("touchend", mouseOut)
element.removeEventListener("touchcancel", mouseOut)
element.removeEventListener("mouseover", touchStarted)
element.removeEventListener("mousemove", mouseMoved)
element.removeEventListener("mouseout", mouseOut)
}
}, [])
return {
touchOrHoverRef: ref,
touchOrHoverIsActive: isActive,
touchRect,
positionInTarget: position,
activeEvent,
}
}