{"version":3,"file":"usePlaybackEffect.mjs","names":[],"sources":["../../../src/hooks/core/usePlaybackEffect.ts"],"sourcesContent":["import { useTimelineEngine } from '#react/hooks/core/useTimelineEngine';\nimport type { RationalTime } from '@techsquidtv/canvas-timeline-utils';\nimport { useEffect, useRef } from 'react';\n/**\n * Subscribes to real-time playback events (enter, update, leave) for a specific clip\n * as the global playhead crosses the clip's boundary timestamps.\n *\n * @remarks\n *\n * Use this hook for clip-local effects such as highlighting subtitles, toggling\n * preview overlays, triggering analytics, or coordinating lightweight external\n * state when a known clip becomes active. `onUpdate` can fire every playback\n * tick while the playhead is inside the clip, so keep that callback cheap and\n * avoid broad React state updates for dense timelines.\n *\n * @param clipId - The unique string ID of the target clip to track.\n * @param callbacks - Callback handlers triggered on transition crossings.\n * @param callbacks.onEnter - Called when the playhead enters the clip range.\n * @param callbacks.onUpdate - Called on every frame tick inside the clip range.\n * @param callbacks.onLeave - Called when the playhead moves outside of the clip range.\n * @returns Nothing; the hook manages playback event subscriptions for the component lifetime.\n *\n * @example\n * ```tsx\n * import { useState } from 'react';\n * import { usePlaybackEffect } from '@techsquidtv/canvas-timeline-react';\n *\n * export function ClipActiveBadge({ clipId }: { clipId: string }) {\n *   const [active, setActive] = useState(false);\n *\n *   usePlaybackEffect(clipId, {\n *     onEnter: () => setActive(true),\n *     onLeave: () => setActive(false),\n *   });\n *\n *   return active ? <span>Active now</span> : null;\n * }\n * ```\n *\n * @see {@link useTimelineEvent}\n * @see {@link https://canvastimeline.com/docs/events-and-lifecycle | Events and lifecycle}\n */\nexport function usePlaybackEffect(\n  clipId: string,\n  callbacks: {\n    onEnter?: (time: RationalTime) => void;\n    onUpdate?: (time: RationalTime) => void;\n    onLeave?: (time: RationalTime) => void;\n  }\n) {\n  const engine = useTimelineEngine();\n  const callbacksRef = useRef(callbacks);\n\n  useEffect(() => {\n    callbacksRef.current = callbacks;\n  }, [callbacks]);\n\n  useEffect(() => {\n    const unsubEnter = engine.on('clip:enter', (payload) => {\n      if (payload.clipId === clipId && callbacksRef.current.onEnter) {\n        callbacksRef.current.onEnter(payload.time);\n      }\n    });\n    const unsubUpdate = engine.on('clip:update', (payload) => {\n      if (payload.clipId === clipId && callbacksRef.current.onUpdate) {\n        callbacksRef.current.onUpdate(payload.time);\n      }\n    });\n    const unsubLeave = engine.on('clip:leave', (payload) => {\n      if (payload.clipId === clipId && callbacksRef.current.onLeave) {\n        callbacksRef.current.onLeave(payload.time);\n      }\n    });\n\n    return () => {\n      unsubEnter();\n      unsubUpdate();\n      unsubLeave();\n    };\n  }, [clipId, engine]);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0CA,SAAgB,kBACd,QACA,WAKA;CACA,MAAM,SAAS,kBAAkB;CACjC,MAAM,eAAe,OAAO,SAAS;CAErC,gBAAgB;EACd,aAAa,UAAU;CACzB,GAAG,CAAC,SAAS,CAAC;CAEd,gBAAgB;EACd,MAAM,aAAa,OAAO,GAAG,eAAe,YAAY;GACtD,IAAI,QAAQ,WAAW,UAAU,aAAa,QAAQ,SACpD,aAAa,QAAQ,QAAQ,QAAQ,IAAI;EAE7C,CAAC;EACD,MAAM,cAAc,OAAO,GAAG,gBAAgB,YAAY;GACxD,IAAI,QAAQ,WAAW,UAAU,aAAa,QAAQ,UACpD,aAAa,QAAQ,SAAS,QAAQ,IAAI;EAE9C,CAAC;EACD,MAAM,aAAa,OAAO,GAAG,eAAe,YAAY;GACtD,IAAI,QAAQ,WAAW,UAAU,aAAa,QAAQ,SACpD,aAAa,QAAQ,QAAQ,QAAQ,IAAI;EAE7C,CAAC;EAED,aAAa;GACX,WAAW;GACX,YAAY;GACZ,WAAW;EACb;CACF,GAAG,CAAC,QAAQ,MAAM,CAAC;AACrB"}