{"version":3,"file":"useTimelinePanControl.mjs","names":[],"sources":["../../../src/hooks/viewport/useTimelinePanControl.ts"],"sourcesContent":["import { useTimelineViewportBounds } from '#react/hooks/viewport/useTimelineViewportBounds';\nimport type { TimelineControlCommitDetails } from '#react/hooks/core/timelineControlEvents';\nimport { createTimelineScalarControlProps } from '#react/hooks/core/timelineScalarControlProps';\nimport { useTimelineEngine } from '#react/hooks/core/useTimelineEngine';\nimport { useTimelineScrollLeft } from '#react/hooks/viewport/useTimelineScrollLeft';\nimport { clamp, round } from '@techsquidtv/canvas-timeline-utils';\nimport { useCallback, useMemo } from 'react';\n/**\n * Options for adapting horizontal timeline scroll to a scalar control.\n */\nexport interface TimelinePanControlOptions {\n  /** Minimum scroll offset in pixels. Defaults to 0. */\n  min?: number;\n  /** Maximum scroll offset in pixels. Defaults to the engine max scroll left. */\n  max?: number;\n  /** Slider step in pixels. Defaults to 1. */\n  step?: number;\n  /** Accessible label for the pan control. */\n  label?: string;\n  /**\n   * Called after the hook applies a committed control value to the engine.\n   *\n   * When the underlying scalar control provides commit details, Canvas Timeline\n   * forwards them unchanged as the second argument and does not read their\n   * fields.\n   */\n  onValueCommitted?: (value: number[], eventDetails?: TimelineControlCommitDetails) => void;\n}\n\nfunction formatPanValue(value: number) {\n  const rounded = round(value, 2);\n  return `${rounded} pixels`;\n}\n\n/**\n * Adapts horizontal timeline scroll to a Base UI-compatible scalar slider.\n *\n * Use this hook when an application wants a semantic pan control for\n * `TimelineEngine.scrollLeft`. It overlaps with `useTimelineViewport` only at\n * the engine command layer; this hook adds slider props, bounds, and formatted\n * ARIA value text for custom UI primitives.\n *\n * @param options - Optional scroll bounds, step size, label, and commit callback.\n * @returns Current scroll offset, formatted value text, imperative setters, and props for `Slider.Root` plus `Slider.Thumb`.\n *\n * @example\n * ```tsx\n * const pan = useTimelinePanControl({ step: 40 });\n *\n * return (\n *   <Slider.Root {...pan.rootProps}>\n *     <Slider.Control>\n *       <Slider.Track>\n *         <Slider.Indicator />\n *         <Slider.Thumb {...pan.thumbProps} />\n *       </Slider.Track>\n *     </Slider.Control>\n *   </Slider.Root>\n * );\n * ```\n */\nexport function useTimelinePanControl(options: TimelinePanControlOptions = {}) {\n  const { label: optionLabel, max: optionMax, min: optionMin, onValueCommitted, step } = options;\n  const engine = useTimelineEngine();\n  const bounds = useTimelineViewportBounds();\n  const scrollLeft = useTimelineScrollLeft();\n  const control = useMemo(\n    () => ({\n      label: optionLabel ?? 'Timeline pan',\n      max: optionMax ?? bounds.maxScrollLeft,\n      min: optionMin ?? 0,\n      step: step ?? 1,\n      value: scrollLeft,\n      valueText: formatPanValue(scrollLeft),\n    }),\n    [bounds.maxScrollLeft, optionLabel, optionMax, optionMin, scrollLeft, step]\n  );\n\n  const setValue = useCallback(\n    (nextValue: number) => {\n      engine.setScrollLeft(clamp(nextValue, control.min, control.max));\n    },\n    [control.max, control.min, engine]\n  );\n\n  const commit = useCallback(\n    (nextValue = control.value) => {\n      setValue(nextValue);\n      engine.settle();\n    },\n    [control.value, engine, setValue]\n  );\n\n  return useMemo(() => {\n    const scalarProps = createTimelineScalarControlProps({\n      control,\n      setValue,\n      commit,\n      getAriaValueText: formatPanValue,\n      onEmptyCommit: () => engine.settle(),\n      onValueCommitted,\n    });\n\n    return {\n      /** Accessible label used by the default thumb props. */\n      label: control.label,\n      /** Maximum scroll offset in pixels. */\n      max: control.max,\n      /** Minimum scroll offset in pixels. */\n      min: control.min,\n      /** Slider step in pixels. */\n      step: control.step,\n      /** Current horizontal scroll offset in pixels. */\n      value: control.value,\n      /** Formatted pan value for assistive technology. */\n      valueText: control.valueText,\n      /** Sets horizontal scroll offset without an additional explicit commit callback. */\n      setValue,\n      /** Sets horizontal scroll offset and settles the engine interaction. */\n      commit,\n      /** Formats a scroll offset value for `aria-valuetext`. */\n      getAriaValueText: scalarProps.getAriaValueText,\n      /** Props for a Base UI `Slider.Root`. */\n      rootProps: scalarProps.rootProps,\n      /** Props for a Base UI `Slider.Thumb`. */\n      thumbProps: scalarProps.thumbProps,\n    };\n  }, [commit, control, engine, onValueCommitted, setValue]);\n}\n"],"mappings":";;;;;;;AA6BA,SAAS,eAAe,OAAe;CAErC,OAAO,GADS,MAAM,OAAO,CACb,EAAE;AACpB;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BA,SAAgB,sBAAsB,UAAqC,CAAC,GAAG;CAC7E,MAAM,EAAE,OAAO,aAAa,KAAK,WAAW,KAAK,WAAW,kBAAkB,SAAS;CACvF,MAAM,SAAS,kBAAkB;CACjC,MAAM,SAAS,0BAA0B;CACzC,MAAM,aAAa,sBAAsB;CACzC,MAAM,UAAU,eACP;EACL,OAAO,eAAe;EACtB,KAAK,aAAa,OAAO;EACzB,KAAK,aAAa;EAClB,MAAM,QAAQ;EACd,OAAO;EACP,WAAW,eAAe,UAAU;CACtC,IACA;EAAC,OAAO;EAAe;EAAa;EAAW;EAAW;EAAY;CAAI,CAC5E;CAEA,MAAM,WAAW,aACd,cAAsB;EACrB,OAAO,cAAc,MAAM,WAAW,QAAQ,KAAK,QAAQ,GAAG,CAAC;CACjE,GACA;EAAC,QAAQ;EAAK,QAAQ;EAAK;CAAM,CACnC;CAEA,MAAM,SAAS,aACZ,YAAY,QAAQ,UAAU;EAC7B,SAAS,SAAS;EAClB,OAAO,OAAO;CAChB,GACA;EAAC,QAAQ;EAAO;EAAQ;CAAQ,CAClC;CAEA,OAAO,cAAc;EACnB,MAAM,cAAc,iCAAiC;GACnD;GACA;GACA;GACA,kBAAkB;GAClB,qBAAqB,OAAO,OAAO;GACnC;EACF,CAAC;EAED,OAAO;;GAEL,OAAO,QAAQ;;GAEf,KAAK,QAAQ;;GAEb,KAAK,QAAQ;;GAEb,MAAM,QAAQ;;GAEd,OAAO,QAAQ;;GAEf,WAAW,QAAQ;;GAEnB;;GAEA;;GAEA,kBAAkB,YAAY;;GAE9B,WAAW,YAAY;;GAEvB,YAAY,YAAY;EAC1B;CACF,GAAG;EAAC;EAAQ;EAAS;EAAQ;EAAkB;CAAQ,CAAC;AAC1D"}