@keplar-404/react-timeline-editor 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/dist/components/control_area/index.d.ts +0 -0
  2. package/dist/components/cursor/cursor.d.ts +20 -0
  3. package/dist/components/cut-overlay/CutOverlay.d.ts +202 -0
  4. package/dist/components/edit_area/cross_row_drag.d.ts +50 -0
  5. package/dist/components/edit_area/drag_lines.d.ts +11 -0
  6. package/dist/components/edit_area/drag_preview.d.ts +14 -0
  7. package/dist/components/edit_area/drag_utils.d.ts +39 -0
  8. package/dist/components/edit_area/edit_action.d.ts +19 -0
  9. package/dist/components/edit_area/edit_area.d.ts +56 -0
  10. package/dist/components/edit_area/edit_row.d.ts +27 -0
  11. package/dist/components/edit_area/hooks/use_drag_line.d.ts +33 -0
  12. package/dist/components/edit_area/insertion_line.d.ts +12 -0
  13. package/dist/components/loop-zone/LoopZoneOverlay.d.ts +243 -0
  14. package/dist/components/row_rnd/hooks/useAutoScroll.d.ts +7 -0
  15. package/dist/components/row_rnd/interactable.d.ts +14 -0
  16. package/dist/components/row_rnd/row_rnd.d.ts +3 -0
  17. package/dist/components/row_rnd/row_rnd_interface.d.ts +47 -0
  18. package/dist/components/time_area/time_area.d.ts +17 -0
  19. package/dist/components/timeline.d.ts +3 -0
  20. package/dist/components/transport/TransportBar.d.ts +132 -0
  21. package/dist/components/transport/useTimelinePlayer.d.ts +164 -0
  22. package/dist/index.cjs.js +13 -0
  23. package/dist/index.d.ts +12 -0
  24. package/dist/index.es.js +10102 -0
  25. package/dist/index.umd.js +13 -0
  26. package/dist/interface/common_prop.d.ts +12 -0
  27. package/dist/interface/const.d.ts +28 -0
  28. package/dist/interface/timeline.d.ts +342 -0
  29. package/dist/react-timeline-editor.css +1 -0
  30. package/dist/utils/check_props.d.ts +2 -0
  31. package/dist/utils/deal_class_prefix.d.ts +1 -0
  32. package/dist/utils/deal_data.d.ts +58 -0
  33. package/dist/utils/logger.d.ts +132 -0
  34. package/package.json +70 -0
  35. package/src/components/control_area/index.tsx +1 -0
  36. package/src/components/cursor/cursor.css +26 -0
  37. package/src/components/cursor/cursor.tsx +105 -0
  38. package/src/components/cut-overlay/CutOverlay.css +68 -0
  39. package/src/components/cut-overlay/CutOverlay.tsx +491 -0
  40. package/src/components/edit_area/cross_row_drag.tsx +174 -0
  41. package/src/components/edit_area/drag_lines.css +13 -0
  42. package/src/components/edit_area/drag_lines.tsx +31 -0
  43. package/src/components/edit_area/drag_preview.tsx +50 -0
  44. package/src/components/edit_area/drag_utils.ts +77 -0
  45. package/src/components/edit_area/edit_action.css +56 -0
  46. package/src/components/edit_area/edit_action.tsx +362 -0
  47. package/src/components/edit_area/edit_area.css +24 -0
  48. package/src/components/edit_area/edit_area.tsx +606 -0
  49. package/src/components/edit_area/edit_row.css +78 -0
  50. package/src/components/edit_area/edit_row.tsx +128 -0
  51. package/src/components/edit_area/hooks/use_drag_line.ts +93 -0
  52. package/src/components/edit_area/insertion_line.tsx +39 -0
  53. package/src/components/loop-zone/LoopZoneOverlay.css +65 -0
  54. package/src/components/loop-zone/LoopZoneOverlay.tsx +461 -0
  55. package/src/components/row_rnd/hooks/useAutoScroll.ts +81 -0
  56. package/src/components/row_rnd/interactable.tsx +55 -0
  57. package/src/components/row_rnd/row_rnd.tsx +365 -0
  58. package/src/components/row_rnd/row_rnd_interface.ts +59 -0
  59. package/src/components/time_area/time_area.css +35 -0
  60. package/src/components/time_area/time_area.tsx +93 -0
  61. package/src/components/timeline.css +12 -0
  62. package/src/components/timeline.tsx +227 -0
  63. package/src/components/transport/TransportBar.css +171 -0
  64. package/src/components/transport/TransportBar.tsx +322 -0
  65. package/src/components/transport/useTimelinePlayer.ts +319 -0
  66. package/src/index.tsx +17 -0
  67. package/src/interface/common_prop.ts +13 -0
  68. package/src/interface/const.ts +32 -0
  69. package/src/interface/timeline.ts +329 -0
  70. package/src/utils/check_props.ts +77 -0
  71. package/src/utils/deal_class_prefix.ts +6 -0
  72. package/src/utils/deal_data.ts +159 -0
  73. package/src/utils/logger.ts +239 -0
@@ -0,0 +1,243 @@
1
+ import { default as React } from 'react';
2
+ /**
3
+ * Visual and behavioral configuration for the {@link LoopZoneOverlay} component.
4
+ * All properties are optional — defaults produce a green-themed loop zone.
5
+ *
6
+ * @example
7
+ * ```tsx
8
+ * const loopConfig: LoopZoneConfig = {
9
+ * bandColor: '#a855f7',
10
+ * bandOpacity: 0.1,
11
+ * handleColor: '#c084fc',
12
+ * showBoundaryLines: true,
13
+ * };
14
+ * <LoopZoneOverlay config={loopConfig} ... />
15
+ * ```
16
+ */
17
+ export interface LoopZoneConfig {
18
+ /**
19
+ * CSS color of the loop region shaded band.
20
+ * @default '#10b981'
21
+ */
22
+ bandColor?: string;
23
+ /**
24
+ * Opacity of the loop region band (0–1).
25
+ * Keep this low (< 0.15) so underlying blocks remain visible.
26
+ * @default 0.07
27
+ */
28
+ bandOpacity?: number;
29
+ /**
30
+ * Border/stripe color used on the band's edges and stripe pattern.
31
+ * Falls back to `bandColor` when not set.
32
+ */
33
+ bandBorderColor?: string;
34
+ /**
35
+ * CSS color of the default drag handle grip pills.
36
+ * Falls back to `bandColor` when not set.
37
+ * Has no effect when `renderHandle` is provided.
38
+ */
39
+ handleColor?: string;
40
+ /**
41
+ * Whether to render the dashed vertical boundary lines
42
+ * extending through the edit rows below the time ruler.
43
+ * @default true
44
+ */
45
+ showBoundaryLines?: boolean;
46
+ /**
47
+ * CSS color of the dashed boundary lines.
48
+ * @default 'rgba(16, 185, 129, 0.4)'
49
+ */
50
+ boundaryLineColor?: string;
51
+ }
52
+ /**
53
+ * Props passed into a custom handle renderer supplied via `LoopZoneOverlayProps.renderHandle`.
54
+ *
55
+ * Attach `onMouseDown` to your draggable element to enable the drag interaction.
56
+ * The overlay provides all pixel math — your renderer only needs to call `onMouseDown`.
57
+ *
58
+ * @example
59
+ * ```tsx
60
+ * renderHandle={({ type, time, onMouseDown }) => (
61
+ * <div
62
+ * onMouseDown={onMouseDown}
63
+ * style={{ cursor: 'ew-resize', background: 'purple' }}
64
+ * title={`${type === 'start' ? 'Loop start' : 'Loop end'}: ${time.toFixed(2)}s`}
65
+ * >
66
+ * {type === 'start' ? '⟨' : '⟩'}
67
+ * </div>
68
+ * )}
69
+ * ```
70
+ */
71
+ export interface LoopHandleRenderProps {
72
+ /**
73
+ * Which boundary this handle controls.
74
+ * Use to differentiate styling between the two handles.
75
+ */
76
+ type: 'start' | 'end';
77
+ /**
78
+ * The current time value (in seconds) for this boundary.
79
+ * Useful for displaying a tooltip or label.
80
+ */
81
+ time: number;
82
+ /**
83
+ * Attach this to your draggable element's `onMouseDown` to activate dragging.
84
+ * The LoopZoneOverlay hooks into document `mousemove`/`mouseup` internally —
85
+ * you do not need to manage drag events yourself.
86
+ */
87
+ onMouseDown: (e: React.MouseEvent) => void;
88
+ }
89
+ /**
90
+ * Props for the {@link LoopZoneOverlay} component.
91
+ *
92
+ * Mount this absolutely inside the same container as your `<Timeline>` to render
93
+ * a draggable loop region on top of the timeline ruler and edit area.
94
+ *
95
+ * @example
96
+ * ```tsx
97
+ * const [loopStart, setLoopStart] = useState(1);
98
+ * const [loopEnd, setLoopEnd] = useState(3);
99
+ * const [scrollLeft, setScrollLeft] = useState(0);
100
+ *
101
+ * // Inside your container:
102
+ * <div style={{ position: 'relative' }}>
103
+ * <Timeline
104
+ * ref={timelineRef}
105
+ * scale={1}
106
+ * scaleWidth={160}
107
+ * startLeft={20}
108
+ * onScroll={(p) => setScrollLeft(p.scrollLeft)}
109
+ * ...
110
+ * />
111
+ * {loopEnabled && (
112
+ * <LoopZoneOverlay
113
+ * scale={1}
114
+ * scaleWidth={160}
115
+ * startLeft={20}
116
+ * scrollLeft={scrollLeft}
117
+ * loopStart={loopStart}
118
+ * loopEnd={loopEnd}
119
+ * onLoopStartChange={setLoopStart}
120
+ * onLoopEndChange={setLoopEnd}
121
+ * />
122
+ * )}
123
+ * </div>
124
+ * ```
125
+ */
126
+ export interface LoopZoneOverlayProps {
127
+ /**
128
+ * Duration represented by one scale unit (seconds).
129
+ * Must match the `scale` prop on `<Timeline>`.
130
+ * @default 1
131
+ */
132
+ scale: number;
133
+ /**
134
+ * Width in pixels of one scale unit.
135
+ * Must match the `scaleWidth` prop on `<Timeline>`.
136
+ * @default 160
137
+ */
138
+ scaleWidth: number;
139
+ /**
140
+ * Left inset in pixels before the first scale mark begins.
141
+ * Must match the `startLeft` prop on `<Timeline>`.
142
+ * @default 20
143
+ */
144
+ startLeft: number;
145
+ /**
146
+ * Current horizontal scroll offset of the timeline.
147
+ * Track this via the `onScroll` callback on `<Timeline>`:
148
+ * ```tsx
149
+ * onScroll={(params) => setScrollLeft(params.scrollLeft)}
150
+ * ```
151
+ */
152
+ scrollLeft: number;
153
+ /**
154
+ * Loop region start time in seconds.
155
+ * This is a **controlled** prop — manage it in parent state.
156
+ */
157
+ loopStart: number;
158
+ /**
159
+ * Loop region end time in seconds.
160
+ * Must be greater than `loopStart`.
161
+ * This is a **controlled** prop — manage it in parent state.
162
+ */
163
+ loopEnd: number;
164
+ /**
165
+ * Called when the user drags the start handle to a new time value.
166
+ * Update your `loopStart` state here.
167
+ *
168
+ * @param time - New loop start time in seconds.
169
+ */
170
+ onLoopStartChange: (time: number) => void;
171
+ /**
172
+ * Called when the user drags the end handle to a new time value.
173
+ * Update your `loopEnd` state here.
174
+ *
175
+ * @param time - New loop end time in seconds.
176
+ */
177
+ onLoopEndChange: (time: number) => void;
178
+ /**
179
+ * Fine-grained control over the band color, opacity, handle color, and
180
+ * boundary line appearance. All properties are optional and fall back
181
+ * to green-themed defaults.
182
+ *
183
+ * @see {@link LoopZoneConfig}
184
+ */
185
+ config?: LoopZoneConfig;
186
+ /**
187
+ * Custom render function for the drag handles.
188
+ *
189
+ * When provided, the default SVG grip pill is replaced by whatever
190
+ * your function returns. The function is called once for each handle
191
+ * (`'start'` and `'end'`).
192
+ *
193
+ * You **must** attach the provided `onMouseDown` to your draggable
194
+ * element to preserve the drag interaction.
195
+ *
196
+ * @see {@link LoopHandleRenderProps}
197
+ *
198
+ * @example
199
+ * ```tsx
200
+ * renderHandle={({ type, time, onMouseDown }) => (
201
+ * <MyHandle side={type} label={`${time.toFixed(2)}s`} onMouseDown={onMouseDown} />
202
+ * )}
203
+ * ```
204
+ */
205
+ renderHandle?: (props: LoopHandleRenderProps) => React.ReactNode;
206
+ /**
207
+ * Additional CSS class name appended to the overlay root element.
208
+ * Use to apply custom styles alongside or instead of `config`.
209
+ */
210
+ className?: string;
211
+ /**
212
+ * Inline styles applied to the overlay root element.
213
+ */
214
+ style?: React.CSSProperties;
215
+ }
216
+ /**
217
+ * `LoopZoneOverlay` renders a draggable loop/repeat region on top of a `<Timeline>`.
218
+ *
219
+ * When mounted inside the same positioned container as `<Timeline>`, it draws:
220
+ * - A **semi-transparent band** spanning the ruler and edit rows between `loopStart` and `loopEnd`
221
+ * - Two **draggable handles** at the boundaries (or custom handles via `renderHandle`)
222
+ * - Optional **dashed boundary lines** extending through the edit rows
223
+ *
224
+ * The component is **fully controlled** — it calls `onLoopStartChange` /
225
+ * `onLoopEndChange` as the user drags and does not hold its own loop state.
226
+ *
227
+ * @example
228
+ * ```tsx
229
+ * <LoopZoneOverlay
230
+ * scale={1}
231
+ * scaleWidth={160}
232
+ * startLeft={20}
233
+ * scrollLeft={scrollLeft}
234
+ * loopStart={loopStart}
235
+ * loopEnd={loopEnd}
236
+ * onLoopStartChange={setLoopStart}
237
+ * onLoopEndChange={setLoopEnd}
238
+ * config={{ bandColor: '#6366f1', bandOpacity: 0.1 }}
239
+ * />
240
+ * ```
241
+ */
242
+ declare const LoopZoneOverlay: React.FC<LoopZoneOverlayProps>;
243
+ export default LoopZoneOverlay;
@@ -0,0 +1,7 @@
1
+ import { DragEvent, ResizeEvent } from '@interactjs/types/index';
2
+ export declare function useAutoScroll(target: React.RefObject<HTMLDivElement>): {
3
+ initAutoScroll: () => void;
4
+ dealDragAutoScroll: (e: DragEvent, deltaScroll?: (delta: number) => void) => boolean;
5
+ dealResizeAutoScroll: (e: ResizeEvent, dir: "left" | "right", deltaScroll?: (delta: number) => void) => boolean;
6
+ stopAutoScroll: () => void;
7
+ };
@@ -0,0 +1,14 @@
1
+ import { DraggableOptions } from '@interactjs/actions/drag/plugin';
2
+ import { ResizableOptions } from '@interactjs/actions/resize/plugin';
3
+ import { Interactable } from '@interactjs/types';
4
+ import { FC, ReactElement } from 'react';
5
+ interface InteractCompProps {
6
+ children: ReactElement;
7
+ interactRef: React.MutableRefObject<Interactable | null>;
8
+ draggable: boolean;
9
+ draggableOptions: DraggableOptions;
10
+ resizable: boolean;
11
+ resizableOptions: ResizableOptions;
12
+ }
13
+ export declare const InteractComp: FC<InteractCompProps>;
14
+ export {};
@@ -0,0 +1,3 @@
1
+ import { default as React } from 'react';
2
+ import { RowRndApi, RowRndProps } from './row_rnd_interface';
3
+ export declare const RowDnd: React.ForwardRefExoticComponent<RowRndProps & React.RefAttributes<RowRndApi>>;
@@ -0,0 +1,47 @@
1
+ type EventData = {
2
+ lastLeft: number;
3
+ left: number;
4
+ lastWidth: number;
5
+ width: number;
6
+ };
7
+ export type RndDragStartCallback = () => void;
8
+ export type RndDragCallback = (data: EventData, scrollDelta?: number) => boolean | void;
9
+ export type RndDragEndCallback = (data: Pick<EventData, 'left' | 'width'>) => void;
10
+ export type Direction = "left" | "right";
11
+ export type RndResizeStartCallback = (dir: Direction) => void;
12
+ export type RndResizeCallback = (dir: Direction, data: EventData) => boolean | void;
13
+ export type RndResizeEndCallback = (dir: Direction, data: Pick<EventData, 'left' | 'width'>) => void;
14
+ export interface RowRndApi {
15
+ updateWidth: (size: number) => void;
16
+ updateLeft: (left: number) => void;
17
+ getLeft: () => number;
18
+ getWidth: () => number;
19
+ }
20
+ export interface RowRndProps {
21
+ width?: number;
22
+ left?: number;
23
+ grid?: number;
24
+ start?: number;
25
+ bounds?: {
26
+ left: number;
27
+ right: number;
28
+ };
29
+ edges?: {
30
+ left: boolean | string;
31
+ right: boolean | string;
32
+ };
33
+ onResizeStart?: RndResizeStartCallback;
34
+ onResize?: RndResizeCallback;
35
+ onResizeEnd?: RndResizeEndCallback;
36
+ onDragStart?: RndDragStartCallback;
37
+ onDrag?: RndDragCallback;
38
+ onDragEnd?: RndDragEndCallback;
39
+ parentRef: React.RefObject<HTMLDivElement>;
40
+ deltaScrollLeft?: (delta: number) => void;
41
+ children?: React.ReactNode;
42
+ enableResizing?: boolean;
43
+ enableDragging?: boolean;
44
+ adsorptionPositions?: number[];
45
+ adsorptionDistance?: number;
46
+ }
47
+ export {};
@@ -0,0 +1,17 @@
1
+ import { FC } from 'react';
2
+ import { OnScrollParams } from 'react-virtualized';
3
+ import { CommonProp } from '../../interface/common_prop';
4
+ /** Animation timeline component parameters */
5
+ export type TimeAreaProps = CommonProp & {
6
+ /** Scroll distance from left */
7
+ scrollLeft: number;
8
+ /** Scroll callback, used for synchronous scrolling */
9
+ onScroll: (params: OnScrollParams) => void;
10
+ /** Set cursor position */
11
+ setCursor: (param: {
12
+ left?: number;
13
+ time?: number;
14
+ }) => void;
15
+ };
16
+ /** Animation timeline component */
17
+ export declare const TimeArea: FC<TimeAreaProps>;
@@ -0,0 +1,3 @@
1
+ import { default as React } from 'react';
2
+ import { TimelineEditor, TimelineState } from '../interface/timeline';
3
+ export declare const Timeline: React.ForwardRefExoticComponent<TimelineEditor & React.RefAttributes<TimelineState>>;
@@ -0,0 +1,132 @@
1
+ import { default as React } from 'react';
2
+ import { TimelinePlayerState } from './useTimelinePlayer';
3
+ /**
4
+ * Loop control props for the {@link TransportBar} component.
5
+ * Supply this to enable the loop toggle button and start/end inputs.
6
+ */
7
+ export interface TransportBarLoopProps {
8
+ /**
9
+ * Whether the loop is currently active.
10
+ * Controls the visual state of the loop button (lit vs. dim).
11
+ */
12
+ enabled: boolean;
13
+ /**
14
+ * Loop region start time in seconds.
15
+ */
16
+ start: number;
17
+ /**
18
+ * Loop region end time in seconds.
19
+ */
20
+ end: number;
21
+ /**
22
+ * Called when the user clicks the loop toggle button.
23
+ */
24
+ onToggle: () => void;
25
+ /**
26
+ * Called when the user edits the loop start input.
27
+ * @param time - New start time in seconds.
28
+ */
29
+ onStartChange: (time: number) => void;
30
+ /**
31
+ * Called when the user edits the loop end input.
32
+ * @param time - New end time in seconds.
33
+ */
34
+ onEndChange: (time: number) => void;
35
+ }
36
+ /**
37
+ * Props for the {@link TransportBar} component.
38
+ *
39
+ * @example
40
+ * ```tsx
41
+ * const player = useTimelinePlayer(timelineRef, { loop: { enabled, start, end } });
42
+ *
43
+ * <TransportBar
44
+ * player={player}
45
+ * loop={{ enabled, start, end, onToggle, onStartChange, onEndChange }}
46
+ * />
47
+ * ```
48
+ */
49
+ export interface TransportBarProps {
50
+ /**
51
+ * The return value of `useTimelinePlayer()`.
52
+ * Provides all reactive state and control functions.
53
+ *
54
+ * @see {@link TimelinePlayerState}
55
+ */
56
+ player: TimelinePlayerState;
57
+ /**
58
+ * Optional loop controls.
59
+ * When provided, a loop toggle button (🔁) appears after the stop button,
60
+ * and start/end time inputs appear when the loop is active.
61
+ *
62
+ * @see {@link TransportBarLoopProps}
63
+ */
64
+ loop?: TransportBarLoopProps;
65
+ /**
66
+ * Playback rate options displayed as speed buttons.
67
+ * @default [0.25, 0.5, 1, 2, 4]
68
+ */
69
+ playRates?: number[];
70
+ /**
71
+ * Custom time format function.
72
+ * Receives the current time in seconds, should return a display string.
73
+ *
74
+ * @default Built-in `formatTime` (produces `'M:SS.mm'` format)
75
+ *
76
+ * @example
77
+ * ```tsx
78
+ * formatDisplayTime={(t) => `${(t * 1000).toFixed(0)} ms`}
79
+ * ```
80
+ */
81
+ formatDisplayTime?: (seconds: number) => string;
82
+ /**
83
+ * Additional CSS class name for the transport bar root element.
84
+ */
85
+ className?: string;
86
+ /**
87
+ * Inline styles for the transport bar root element.
88
+ */
89
+ style?: React.CSSProperties;
90
+ }
91
+ /**
92
+ * `TransportBar` is a pre-built playback control bar for use with `<Timeline>`.
93
+ *
94
+ * It renders transport controls (to-start, rewind, play/pause, forward, stop),
95
+ * a time display, playback rate buttons, and optionally a loop toggle with
96
+ * start/end inputs.
97
+ *
98
+ * Pair it with {@link useTimelinePlayer} to wire it to a `<Timeline>` ref:
99
+ *
100
+ * @example
101
+ * ```tsx
102
+ * const timelineRef = useRef<TimelineState>(null);
103
+ * const [loopOn, setLoopOn] = useState(false);
104
+ * const [loopStart, setLoopStart] = useState(1);
105
+ * const [loopEnd, setLoopEnd] = useState(3);
106
+ *
107
+ * const player = useTimelinePlayer(timelineRef, {
108
+ * loop: { enabled: loopOn, start: loopStart, end: loopEnd },
109
+ * });
110
+ *
111
+ * return (
112
+ * <>
113
+ * <TransportBar
114
+ * player={player}
115
+ * loop={{
116
+ * enabled: loopOn, start: loopStart, end: loopEnd,
117
+ * onToggle: () => setLoopOn((v) => !v),
118
+ * onStartChange: setLoopStart,
119
+ * onEndChange: setLoopEnd,
120
+ * }}
121
+ * />
122
+ * <Timeline ref={timelineRef} ... />
123
+ * </>
124
+ * );
125
+ * ```
126
+ *
127
+ * **Building your own UI?**
128
+ * Skip this component entirely and use just `useTimelinePlayer()` to get the state
129
+ * and handlers, then wire them to your own custom controls.
130
+ */
131
+ declare const TransportBar: React.FC<TransportBarProps>;
132
+ export default TransportBar;
@@ -0,0 +1,164 @@
1
+ import { TimelineState } from '../../interface/timeline';
2
+ /**
3
+ * Formats a time value in seconds to a `M:SS.mm` display string.
4
+ *
5
+ * @param seconds - Time in seconds (e.g. `75.4` → `'1:15.40'`).
6
+ * @returns Formatted time string.
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * formatTime(0); // '0:00.00'
11
+ * formatTime(75.4); // '1:15.40'
12
+ * formatTime(3661.1); // '61:01.10'
13
+ * ```
14
+ */
15
+ export declare function formatTime(seconds: number): string;
16
+ /**
17
+ * Loop configuration passed to {@link useTimelinePlayer}.
18
+ *
19
+ * When `enabled` is `true`, the hook automatically resets playback to `start`
20
+ * whenever the current time reaches `end`. The check uses React refs internally,
21
+ * so it never suffers from stale-closure issues even as values change.
22
+ */
23
+ export interface UseTimelinePlayerLoop {
24
+ /**
25
+ * Whether the loop is active. Safe to toggle while the timeline is playing.
26
+ */
27
+ enabled: boolean;
28
+ /**
29
+ * Loop region start time in seconds.
30
+ * Must be less than `end`.
31
+ */
32
+ start: number;
33
+ /**
34
+ * Loop region end time in seconds.
35
+ * Must be greater than `start`.
36
+ */
37
+ end: number;
38
+ }
39
+ /**
40
+ * Options for the {@link useTimelinePlayer} hook.
41
+ */
42
+ export interface UseTimelinePlayerOptions {
43
+ /**
44
+ * Number of seconds to jump when calling `rewind()` or `forward()`.
45
+ * @default 5
46
+ */
47
+ seekStep?: number;
48
+ /**
49
+ * Optional loop configuration.
50
+ * When provided, the hook handles the loop clock internally — no extra code needed.
51
+ *
52
+ * @see {@link UseTimelinePlayerLoop}
53
+ *
54
+ * @example
55
+ * ```tsx
56
+ * const player = useTimelinePlayer(ref, {
57
+ * loop: { enabled: loopOn, start: 1, end: 3 },
58
+ * });
59
+ * ```
60
+ */
61
+ loop?: UseTimelinePlayerLoop;
62
+ }
63
+ /**
64
+ * State and controls returned by {@link useTimelinePlayer}.
65
+ *
66
+ * Destructure what you need — use it with the built-in `<TransportBar>` component
67
+ * or wire it to your own custom controls.
68
+ *
69
+ * @example
70
+ * ```tsx
71
+ * const { isPlaying, currentTime, play, pause, stop } = useTimelinePlayer(ref);
72
+ *
73
+ * <button onClick={isPlaying ? pause : play}>
74
+ * {isPlaying ? '⏸' : '▶'}
75
+ * </button>
76
+ * <span>{formatTime(currentTime)}</span>
77
+ * ```
78
+ */
79
+ export interface TimelinePlayerState {
80
+ /**
81
+ * Whether the timeline is currently playing.
82
+ * Updated automatically from engine events — no polling required.
83
+ */
84
+ isPlaying: boolean;
85
+ /**
86
+ * Current playback position in seconds.
87
+ * Updated on every engine tick — suitable for display.
88
+ */
89
+ currentTime: number;
90
+ /**
91
+ * Current playback rate multiplier (e.g. `1` = 1×, `2` = 2×).
92
+ * Updated when `setPlayRate` is called.
93
+ */
94
+ playRate: number;
95
+ /**
96
+ * Start playback from the current position.
97
+ * Plays to the end of the timeline and then stops.
98
+ */
99
+ play: () => void;
100
+ /**
101
+ * Pause playback at the current position.
102
+ */
103
+ pause: () => void;
104
+ /**
105
+ * Stop playback and reset the cursor to time `0`.
106
+ */
107
+ stop: () => void;
108
+ /**
109
+ * Pause and jump the cursor back to time `0`.
110
+ * Differs from `stop` only in semantics — both do the same thing currently.
111
+ */
112
+ toStart: () => void;
113
+ /**
114
+ * Jump backwards by `seekStep` seconds (clamped to 0).
115
+ */
116
+ rewind: () => void;
117
+ /**
118
+ * Jump forwards by `seekStep` seconds.
119
+ */
120
+ forward: () => void;
121
+ /**
122
+ * Jump to a specific time value (seconds).
123
+ *
124
+ * @param time - Target time in seconds.
125
+ */
126
+ setTime: (time: number) => void;
127
+ /**
128
+ * Change the playback rate multiplier.
129
+ *
130
+ * @param rate - Multiplier value (e.g. `0.5`, `1`, `2`, `4`).
131
+ */
132
+ setPlayRate: (rate: number) => void;
133
+ }
134
+ /**
135
+ * `useTimelinePlayer` manages playback state and controls for a `<Timeline>` component.
136
+ *
137
+ * It attaches engine event listeners (`play`, `paused`, `setTimeByTick`) on mount,
138
+ * exposes reactive state (`isPlaying`, `currentTime`, `playRate`) and all control
139
+ * functions. Optionally handles loop playback internally via the `loop` option.
140
+ *
141
+ * @param ref - A React ref pointing to the `<Timeline>` component's imperative handle.
142
+ * @param options - Optional configuration (`seekStep`, `loop`).
143
+ * @returns {@link TimelinePlayerState} — reactive state + control functions.
144
+ *
145
+ * @example
146
+ * ```tsx
147
+ * const timelineRef = useRef<TimelineState>(null);
148
+ *
149
+ * const player = useTimelinePlayer(timelineRef, {
150
+ * seekStep: 5,
151
+ * loop: { enabled: loopOn, start: loopStart, end: loopEnd },
152
+ * });
153
+ *
154
+ * // Option A: use the pre-built TransportBar
155
+ * <TransportBar player={player} />
156
+ *
157
+ * // Option B: build your own UI
158
+ * <button onClick={player.isPlaying ? player.pause : player.play}>
159
+ * {player.isPlaying ? '⏸' : '▶'}
160
+ * </button>
161
+ * <span>{formatTime(player.currentTime)}</span>
162
+ * ```
163
+ */
164
+ export declare function useTimelinePlayer(ref: React.RefObject<TimelineState>, options?: UseTimelinePlayerOptions): TimelinePlayerState;