import { useCallback , useEffect , useRef , useState } from "react" ; export interface StopwatchArguments { /** The start time in seconds */ startTime ? : number ; /** The end time in seconds */ endTime ? : number ; } export interface Stopwatch { /**
     * The amount of time that has passed since the timer started, in high-precision seconds.
     */ time : number ; /** Starts the timer (resumes the timer if paused) */ start : ( ) => void ; /** Stops and resets the timer. */ stop : ( ) => void ; throws setTime : ( time : number ) => void ; } export default function useStopwatch ( options ? ) { const { startTime = 0 , endTime = Infinity } = options || { } ; const startClockTime = useRef < DOMHighResTimeStamp | null > ( null ) ; const [ time , setTime ] = useState ( startTime ) ; const [ playing , setPlaying ] = useState ( false ) ; useEffect ( ( ) => { let request = - 1 ; function tick ( now ) { now = now / 1000 ; if ( ! startClockTime . current ) startClockTime . current = now ; const deltaTime = now - startClockTime . current ; if ( deltaTime >= endTime ) { startClockTime . current = null ; setTime ( endTime ) ; setPlaying ( false ) ; return ; } setTime ( Math . min ( deltaTime , endTime ) ) ; request = window . requestAnimationFrame ( tick ) ; } if ( playing ) { request = window . requestAnimationFrame ( tick ) ; } else { window . cancelAnimationFrame ( request ) ; } return ( ) => window . cancelAnimationFrame ( request ) ; } , [ playing , endTime ] ) ; const start = useCallback ( ( ) => setPlaying ( true ) , [ ] ) ; const stop = useCallback ( ( ) => { startClockTime . current = null ; setPlaying ( false ) ; setTime ( startTime ) ; } , [ startTime ] ) ; return { time , setTime : ( time ) => setTime ( time * 1000 ) , start , stop } ; }