UNPKG

@darius_rosendahl/react-use-hoverintent

Version:
89 lines (81 loc) 2.29 kB
import { useState, useEffect, useRef, useImperativeHandle } from 'react'; interface optionType { ref?: React.Ref<HTMLElement | null>; sensitivity?: number; interval?: number; timeout?: number; } export function useHoverIntent(options: optionType) { const { ref, sensitivity = 6, interval = 100, timeout = 0 } = options; const intentRef = useRef<HTMLElement>(null); const [isHovering, setIsHovering] = useState(false); let x = 0, y = 0, pX = 0, pY = 0, timer = 0; const delay = (e: MouseEvent) => { if (timer) { clearTimeout(timer); } return setIsHovering(false); }; const tracker = (e: MouseEvent) => { x = e.clientX; y = e.clientY; }; const compare = (e: MouseEvent) => { if (timer) { clearTimeout(timer); } if (Math.abs(pX - x) + Math.abs(pY - y) < sensitivity) { return setIsHovering(true); } else { pX = x; pY = y; timer = window.setTimeout(() => compare(e), interval); } }; const dispatchOver = (e: MouseEvent) => { if (timer) { clearTimeout(timer); } if (intentRef.current) { intentRef.current.removeEventListener('mousemove', tracker, false); } if (!isHovering) { pX = e.clientX; pY = e.clientY; if (intentRef.current) { intentRef.current.addEventListener('mousemove', tracker, false); } timer = window.setTimeout(() => compare(e), interval); } }; const dispatchOut = (e: MouseEvent) => { if (timer) { clearTimeout(timer); } if (intentRef.current) { intentRef.current.removeEventListener('mousemove', tracker, false); } if (isHovering) { timer = window.setTimeout(() => delay(e), timeout); } }; useEffect(() => { const currentRef = intentRef.current; if (currentRef) { currentRef.addEventListener('mouseover', dispatchOver, false); currentRef.addEventListener('mouseout', dispatchOut, false); } return () => { if (currentRef) { currentRef.removeEventListener('mouseover', dispatchOver, false); currentRef.removeEventListener('mouseout', dispatchOut, false); } }; }); useImperativeHandle(ref, () => intentRef.current, [intentRef]); return [isHovering, intentRef]; }