{"version":3,"file":"useTimelineViewport.mjs","names":[],"sources":["../../../src/hooks/viewport/useTimelineViewport.ts"],"sourcesContent":["import { runTimelineCommand } from '#react/hooks/core/runTimelineCommand';\nimport { useTimelineViewportBounds } from '#react/hooks/viewport/useTimelineViewportBounds';\nimport { timelineCommandOk } from '@techsquidtv/canvas-timeline-core';\nimport type { TimelineCommandResult } from '@techsquidtv/canvas-timeline-core';\nimport { useTimelineEngine } from '#react/hooks/core/useTimelineEngine';\nimport { useTimelineSelector } from '#react/hooks/core/useTimelineSelector';\nimport { useTimelineScrollLeft } from '#react/hooks/viewport/useTimelineScrollLeft';\nimport { useTimelineScrollTop } from '#react/hooks/viewport/useTimelineScrollTop';\nimport { useTimelineZoomScale } from '#react/hooks/viewport/useTimelineZoomScale';\nimport { clamp, fromSeconds, toSeconds } from '@techsquidtv/canvas-timeline-utils';\nimport type { RationalTime } from '@techsquidtv/canvas-timeline-utils';\nimport { useCallback } from 'react';\n/** Result returned by `useTimelineViewport`. */\nexport interface UseTimelineViewportResult {\n  /** Current horizontal timeline scroll offset in pixels. */\n  scrollLeft: number;\n  /** Current vertical timeline scroll offset in pixels. */\n  scrollTop: number;\n  /** Current zoom scale in pixels per second. */\n  zoomScale: number;\n  /** Measured timeline viewport width in pixels. */\n  viewportWidth: number;\n  /** Measured timeline viewport height in pixels. */\n  viewportHeight: number;\n  /** Explicit timeline duration, or undefined when duration follows content bounds. */\n  duration: RationalTime | undefined;\n  /** Maximum timeline content time used for playback and scroll bounds. */\n  maxContentTime: RationalTime;\n  /** Maximum horizontal scroll offset for the current viewport and content duration. */\n  maxScrollLeft: number;\n  /** Maximum vertical scroll offset for the current viewport and track stack. */\n  maxScrollTop: number;\n  /** Raw viewport duration represented by the current width and zoom. */\n  viewportDurationTime: RationalTime;\n  /** Raw viewport duration in seconds represented by the current width and zoom. */\n  viewportDurationSeconds: number;\n  /** Visible viewport start time. */\n  visibleStartTime: RationalTime;\n  /** Visible viewport end time, clamped to content bounds. */\n  visibleEndTime: RationalTime;\n  /** Visible viewport duration, clamped to content bounds. */\n  visibleDurationTime: RationalTime;\n  /** Visible viewport start time in seconds for display-only UI. */\n  visibleStartSeconds: number;\n  /** Visible viewport end time in seconds for display-only UI. */\n  visibleEndSeconds: number;\n  /** Visible viewport duration in seconds for display-only UI. */\n  visibleDurationSeconds: number;\n  /** Sets horizontal scroll offset, with final clamping delegated to the engine. */\n  setScrollLeft: (scrollLeft: number) => TimelineCommandResult;\n  /** Sets vertical scroll offset, with final clamping delegated to the engine. */\n  setScrollTop: (scrollTop: number) => TimelineCommandResult;\n  /** Sets zoom scale, with final clamping delegated to the engine. */\n  setZoomScale: (zoomScale: number) => TimelineCommandResult;\n  /** Stores the measured timeline viewport width in the engine. */\n  setViewportWidth: (width: number) => TimelineCommandResult;\n  /** Stores the measured timeline viewport height in the engine. */\n  setViewportHeight: (height: number) => TimelineCommandResult;\n  /** Sets an explicit timeline duration, or clears it when passed undefined. */\n  setDuration: (duration: RationalTime | undefined) => TimelineCommandResult;\n}\n\n/**\n * Provides canonical viewport metrics and setters for custom timeline chrome.\n *\n * @returns Viewport metrics, visible time range, and viewport setters.\n */\nexport function useTimelineViewport(): UseTimelineViewportResult {\n  const engine = useTimelineEngine();\n  const bounds = useTimelineViewportBounds();\n  const state = useTimelineSelector((state) => ({\n    duration: state.duration,\n    viewportHeight: state.viewportHeight,\n    viewportWidth: state.viewportWidth,\n  }));\n  const scrollLeft = useTimelineScrollLeft();\n  const scrollTop = useTimelineScrollTop();\n  const zoomScale = useTimelineZoomScale();\n\n  const setScrollLeft = useCallback(\n    (nextScrollLeft: number) =>\n      runTimelineCommand(() => {\n        engine.setScrollLeft(nextScrollLeft);\n        return timelineCommandOk();\n      }),\n    [engine]\n  );\n\n  const setZoomScale = useCallback(\n    (nextZoomScale: number) =>\n      runTimelineCommand(() => {\n        engine.setZoomScale(nextZoomScale);\n        return timelineCommandOk();\n      }),\n    [engine]\n  );\n\n  const setScrollTop = useCallback(\n    (nextScrollTop: number) =>\n      runTimelineCommand(() => {\n        engine.setScrollTop(nextScrollTop);\n        return timelineCommandOk();\n      }),\n    [engine]\n  );\n\n  const setViewportWidth = useCallback(\n    (width: number) =>\n      runTimelineCommand(() => {\n        engine.setViewportWidth(width);\n        return timelineCommandOk();\n      }),\n    [engine]\n  );\n\n  const setViewportHeight = useCallback(\n    (height: number) =>\n      runTimelineCommand(() => {\n        engine.setViewportHeight(height);\n        return timelineCommandOk();\n      }),\n    [engine]\n  );\n\n  const setDuration = useCallback(\n    (duration: RationalTime | undefined) =>\n      runTimelineCommand(() => {\n        engine.setDuration(duration);\n        return timelineCommandOk();\n      }),\n    [engine]\n  );\n\n  const viewportWidth = state.viewportWidth || 1000;\n  const viewportHeight = state.viewportHeight ?? 600;\n  const safeZoomScale = Math.max(zoomScale || 0, 0.1);\n  const maxContentTime = bounds.maxContentTime;\n  const duration = state.duration;\n  const maxScrollLeft = bounds.maxScrollLeft;\n  const maxScrollTop = bounds.maxScrollTop;\n  const viewportDurationSeconds = viewportWidth / safeZoomScale;\n  const visibleStartSeconds = clamp(scrollLeft / safeZoomScale, 0, toSeconds(maxContentTime));\n  const visibleEndSeconds = Math.min(\n    toSeconds(maxContentTime),\n    visibleStartSeconds + viewportDurationSeconds\n  );\n  const visibleDurationSeconds = visibleEndSeconds - visibleStartSeconds;\n  const viewportDurationTime = fromSeconds(viewportDurationSeconds, maxContentTime.r);\n  const visibleStartTime = fromSeconds(visibleStartSeconds, maxContentTime.r);\n  const visibleEndTime = fromSeconds(visibleEndSeconds, maxContentTime.r);\n  const visibleDurationTime = fromSeconds(visibleDurationSeconds, maxContentTime.r);\n\n  return {\n    scrollLeft,\n    scrollTop,\n    zoomScale: safeZoomScale,\n    viewportWidth,\n    viewportHeight,\n    duration,\n    maxContentTime,\n    maxScrollLeft,\n    maxScrollTop,\n    viewportDurationTime,\n    viewportDurationSeconds,\n    visibleStartTime,\n    visibleEndTime,\n    visibleDurationTime,\n    visibleStartSeconds,\n    visibleEndSeconds,\n    visibleDurationSeconds,\n    setScrollLeft,\n    setScrollTop,\n    setZoomScale,\n    setViewportWidth,\n    setViewportHeight,\n    setDuration,\n  };\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAmEA,SAAgB,sBAAiD;CAC/D,MAAM,SAAS,kBAAkB;CACjC,MAAM,SAAS,0BAA0B;CACzC,MAAM,QAAQ,qBAAqB,WAAW;EAC5C,UAAU,MAAM;EAChB,gBAAgB,MAAM;EACtB,eAAe,MAAM;CACvB,EAAE;CACF,MAAM,aAAa,sBAAsB;CACzC,MAAM,YAAY,qBAAqB;CACvC,MAAM,YAAY,qBAAqB;CAEvC,MAAM,gBAAgB,aACnB,mBACC,yBAAyB;EACvB,OAAO,cAAc,cAAc;EACnC,OAAO,kBAAkB;CAC3B,CAAC,GACH,CAAC,MAAM,CACT;CAEA,MAAM,eAAe,aAClB,kBACC,yBAAyB;EACvB,OAAO,aAAa,aAAa;EACjC,OAAO,kBAAkB;CAC3B,CAAC,GACH,CAAC,MAAM,CACT;CAEA,MAAM,eAAe,aAClB,kBACC,yBAAyB;EACvB,OAAO,aAAa,aAAa;EACjC,OAAO,kBAAkB;CAC3B,CAAC,GACH,CAAC,MAAM,CACT;CAEA,MAAM,mBAAmB,aACtB,UACC,yBAAyB;EACvB,OAAO,iBAAiB,KAAK;EAC7B,OAAO,kBAAkB;CAC3B,CAAC,GACH,CAAC,MAAM,CACT;CAEA,MAAM,oBAAoB,aACvB,WACC,yBAAyB;EACvB,OAAO,kBAAkB,MAAM;EAC/B,OAAO,kBAAkB;CAC3B,CAAC,GACH,CAAC,MAAM,CACT;CAEA,MAAM,cAAc,aACjB,aACC,yBAAyB;EACvB,OAAO,YAAY,QAAQ;EAC3B,OAAO,kBAAkB;CAC3B,CAAC,GACH,CAAC,MAAM,CACT;CAEA,MAAM,gBAAgB,MAAM,iBAAiB;CAC7C,MAAM,iBAAiB,MAAM,kBAAkB;CAC/C,MAAM,gBAAgB,KAAK,IAAI,aAAa,GAAG,EAAG;CAClD,MAAM,iBAAiB,OAAO;CAC9B,MAAM,WAAW,MAAM;CACvB,MAAM,gBAAgB,OAAO;CAC7B,MAAM,eAAe,OAAO;CAC5B,MAAM,0BAA0B,gBAAgB;CAChD,MAAM,sBAAsB,MAAM,aAAa,eAAe,GAAG,UAAU,cAAc,CAAC;CAC1F,MAAM,oBAAoB,KAAK,IAC7B,UAAU,cAAc,GACxB,sBAAsB,uBACxB;CACA,MAAM,yBAAyB,oBAAoB;CAMnD,OAAO;EACL;EACA;EACA,WAAW;EACX;EACA;EACA;EACA;EACA;EACA;EACA,sBAf2B,YAAY,yBAAyB,eAAe,CAe5D;EACnB;EACA,kBAhBuB,YAAY,qBAAqB,eAAe,CAgBxD;EACf,gBAhBqB,YAAY,mBAAmB,eAAe,CAgBtD;EACb,qBAhB0B,YAAY,wBAAwB,eAAe,CAgB3D;EAClB;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF;AACF"}