// Usage: // const Button = () => { // const { completion, ...bind } = useTimedEvent(() => { fire(); }, { duration: 1000 }); // return ; // }; import { useEffect, useRef, useState } from "react"; const useTimedEvent = ( callback: (() => void) | (() => Promise), options?: { refreshRate?: number; duration?: number } ) => { const timerId = useRef(null); const [progress, setProgress] = useState(0); const refreshRate = options?.refreshRate ?? 10; const triggerAt = (options?.duration ?? 1000) / refreshRate; const completion = (progress / triggerAt) * 100; useEffect(() => () => clearInterval(timerId.current), []); useEffect(() => { if (progress === triggerAt) { endProgress(); callback(); } }, [progress, triggerAt, callback]); const startProgress = () => { timerId.current = setInterval( () => setProgress((val) => val + 1), refreshRate ); }; const endProgress = () => { setProgress(0); clearInterval(timerId.current); }; const onMouseDown = () => { startProgress(); }; const onTouchStart = () => { startProgress(); }; const onMouseUp = () => { endProgress(); }; const onMouseOut = () => { endProgress(); }; const onTouchEnd = () => { endProgress(); }; return { completion, onMouseDown, onTouchStart, onMouseUp, onMouseOut, onTouchEnd, }; }; export default useTimedEvent;