{"version":3,"sources":["../../src/use-raf-loop/index.ts"],"sourcesContent":["import { useEffect, useRef } from 'react'\nimport { useLatest } from '../use-latest'\nimport { usePausable } from '../use-pausable'\nimport { useStableFn } from '../use-stable-fn'\nimport { noop } from '../utils/basic'\n\nimport type { Pausable } from '../use-pausable'\n\nexport interface UseRafLoopCallbackArgs {\n  /**\n   * The time elapsed since the last frame\n   */\n  delta: number\n  /**\n   * The timestamp of the current frame\n   */\n  timestamp: DOMHighResTimeStamp\n}\n\nexport type UseRafLoopCallback = (args: UseRafLoopCallbackArgs) => void\n\nexport interface UseRafLoopOptions {\n  /**\n   * The maximum fps limit\n   *\n   * @defaultValue undefined\n   */\n  fpsLimit?: number\n  /**\n   * Whether to start the interval immediately on mounted\n   *\n   * @defaultValue true\n   */\n  immediate?: boolean\n  /**\n   * Whether to execute the callback immediately before the interval starts\n   *\n   * @defaultValue false\n   */\n  immediateCallback?: boolean\n}\n\n/**\n * A React Hook that helps to run a function on every frame using [requestAnimationFrame](https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame).\n */\nexport function useRafLoop(callback: UseRafLoopCallback, options: UseRafLoopOptions = {}): Pausable {\n  const { immediate = true, immediateCallback = false, fpsLimit = undefined } = options\n  const limit = fpsLimit ? 1000 / fpsLimit : null\n\n  const rafIdRef = useRef<number | null>(null)\n  const lastTsRef = useRef(0) // timestamp of the last frame\n\n  function clearRafIfActive() {\n    if (rafIdRef.current !== null) {\n      window.cancelAnimationFrame(rafIdRef.current)\n      rafIdRef.current = null\n    }\n  }\n\n  const latest = useLatest({ callback, clearRafIfActive, immediateCallback, immediate, limit })\n\n  const pausable = usePausable(false, clearRafIfActive, () => {\n    latest.current.clearRafIfActive()\n    lastTsRef.current = 0\n    const { immediateCallback, callback } = latest.current\n\n    if (immediateCallback) {\n      callback({ timestamp: 0, delta: 0 })\n    }\n\n    rafIdRef.current = window.requestAnimationFrame(raf)\n  })\n\n  const raf = useStableFn((timestamp: DOMHighResTimeStamp) => {\n    if (!pausable.isActive()) return\n\n    const { limit } = latest.current\n    if (!lastTsRef.current) lastTsRef.current = timestamp\n    const delta = timestamp - lastTsRef.current\n\n    if (limit && delta < limit) {\n      rafIdRef.current = window.requestAnimationFrame(raf)\n      return\n    }\n\n    lastTsRef.current = timestamp\n    latest.current.callback({ delta, timestamp })\n    rafIdRef.current = window.requestAnimationFrame(raf)\n  })\n\n  // biome-ignore lint/correctness/useExhaustiveDependencies: effect should re-run when limit changes\n  useEffect(() => {\n    if (immediate) {\n      pausable.resume()\n    }\n\n    return immediate ? () => pausable.pause() : noop\n  }, [immediate, limit])\n\n  return pausable\n}\n"],"names":["useRafLoop","callback","options","immediate","immediateCallback","fpsLimit","undefined","limit","rafIdRef","useRef","lastTsRef","clearRafIfActive","current","window","cancelAnimationFrame","latest","useLatest","pausable","usePausable","timestamp","delta","requestAnimationFrame","raf","useStableFn","isActive","useEffect","resume","pause","noop"],"mappings":";;;;+BA6CgBA;;;eAAAA;;;qBA7CkB;yBACR;2BACE;2BACA;qBACP;AAyCd,SAASA,WAAWC,QAA4B;QAAEC,UAAAA,iEAA6B,CAAC;IACrF,yBAA8EA,QAAtEC,WAAAA,4CAAY,wDAA0DD,QAApDE,mBAAAA,4DAAoB,wDAAgCF,QAAzBG,UAAAA,0CAAWC;IAChE,IAAMC,QAAQF,WAAW,OAAOA,WAAW;IAE3C,IAAMG,WAAWC,IAAAA,aAAM,EAAgB;IACvC,IAAMC,YAAYD,IAAAA,aAAM,EAAC,GAAG,8BAA8B;;IAE1D,SAASE;QACP,IAAIH,SAASI,OAAO,KAAK,MAAM;YAC7BC,OAAOC,oBAAoB,CAACN,SAASI,OAAO;YAC5CJ,SAASI,OAAO,GAAG;QACrB;IACF;IAEA,IAAMG,SAASC,IAAAA,oBAAS,EAAC;QAAEf,UAAAA;QAAUU,kBAAAA;QAAkBP,mBAAAA;QAAmBD,WAAAA;QAAWI,OAAAA;IAAM;IAE3F,IAAMU,WAAWC,IAAAA,wBAAW,EAAC,OAAOP,kBAAkB;QACpDI,OAAOH,OAAO,CAACD,gBAAgB;QAC/BD,UAAUE,OAAO,GAAG;QACpB,IAAwCG,kBAAAA,OAAOH,OAAO,EAA9CR,oBAAgCW,gBAAhCX,mBAAmBH,aAAac,gBAAbd;QAE3B,IAAIG,mBAAmB;YACrBH,WAAS;gBAAEkB,WAAW;gBAAGC,OAAO;YAAE;QACpC;QAEAZ,SAASI,OAAO,GAAGC,OAAOQ,qBAAqB,CAACC;IAClD;IAEA,IAAMA,MAAMC,IAAAA,wBAAW,EAAC,SAACJ;QACvB,IAAI,CAACF,SAASO,QAAQ,IAAI;QAE1B,IAAM,AAAEjB,QAAUQ,OAAOH,OAAO,CAAxBL;QACR,IAAI,CAACG,UAAUE,OAAO,EAAEF,UAAUE,OAAO,GAAGO;QAC5C,IAAMC,QAAQD,YAAYT,UAAUE,OAAO;QAE3C,IAAIL,SAASa,QAAQb,OAAO;YAC1BC,SAASI,OAAO,GAAGC,OAAOQ,qBAAqB,CAACC;YAChD;QACF;QAEAZ,UAAUE,OAAO,GAAGO;QACpBJ,OAAOH,OAAO,CAACX,QAAQ,CAAC;YAAEmB,OAAAA;YAAOD,WAAAA;QAAU;QAC3CX,SAASI,OAAO,GAAGC,OAAOQ,qBAAqB,CAACC;IAClD;IAEA,mGAAmG;IACnGG,IAAAA,gBAAS,EAAC;QACR,IAAItB,WAAW;YACbc,SAASS,MAAM;QACjB;QAEA,OAAOvB,YAAY;mBAAMc,SAASU,KAAK;YAAKC,WAAI;IAClD,GAAG;QAACzB;QAAWI;KAAM;IAErB,OAAOU;AACT"}