@remotion/studio 4.0.512 → 4.0.514

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 (208) hide show
  1. package/dist/Studio.js +2 -1
  2. package/dist/components/AskAiModal.js +1 -1
  3. package/dist/components/AssetSelector.js +2 -0
  4. package/dist/components/AssetSelectorItem.js +1 -2
  5. package/dist/components/AudioWaveform.d.ts +3 -0
  6. package/dist/components/AudioWaveform.js +55 -67
  7. package/dist/components/Canvas.js +40 -5
  8. package/dist/components/CanvasOrLoading.js +5 -0
  9. package/dist/components/CompositionSelector.js +2 -0
  10. package/dist/components/CompositionSelectorItem.js +14 -1
  11. package/dist/components/ConfigureDefaultEditorModal.js +17 -11
  12. package/dist/components/Editor.js +16 -1
  13. package/dist/components/ElementInstallConfirmation.d.ts +1 -0
  14. package/dist/components/ElementInstallConfirmation.js +4 -2
  15. package/dist/components/FixComputedValueModal.d.ts +9 -0
  16. package/dist/components/FixComputedValueModal.js +217 -0
  17. package/dist/components/InitialCompositionLoader.js +19 -0
  18. package/dist/components/InlineDropdown.js +4 -4
  19. package/dist/components/InspectorInfoHeader.js +3 -3
  20. package/dist/components/InspectorOpenInEditor.js +26 -24
  21. package/dist/components/InspectorPanel/AlignmentControls.js +13 -2
  22. package/dist/components/InspectorPanel/CompositionInspector.js +11 -1
  23. package/dist/components/InspectorPanel/CompositionInspectorHeader.js +12 -8
  24. package/dist/components/InspectorPanel/ConnectedCompositionsSection.js +13 -2
  25. package/dist/components/InspectorPanel/EasingInspector.js +12 -3
  26. package/dist/components/InspectorPanel/KeyframeInspector.js +21 -7
  27. package/dist/components/InspectorPanel/SequenceInspectorHeader.js +1 -1
  28. package/dist/components/InspectorPanel/SequenceSelectionInspector.js +35 -6
  29. package/dist/components/InspectorPanel/common.d.ts +5 -5
  30. package/dist/components/InspectorPanel/common.js +8 -8
  31. package/dist/components/InspectorPanel/easing-inspector-selection.js +7 -2
  32. package/dist/components/InspectorPanel/inspector-section-collapse.d.ts +1 -0
  33. package/dist/components/InspectorPanel/styles.d.ts +1 -1
  34. package/dist/components/InspectorPanel/styles.js +4 -2
  35. package/dist/components/InspectorSourceLocation.d.ts +1 -1
  36. package/dist/components/InspectorSourceLocation.js +2 -2
  37. package/dist/components/LicenseKeyValidation.js +2 -2
  38. package/dist/components/Modals.js +2 -1
  39. package/dist/components/NewComposition/CodemodFooter.d.ts +1 -0
  40. package/dist/components/NewComposition/CodemodFooter.js +10 -8
  41. package/dist/components/NewComposition/DeleteComposition.js +1 -1
  42. package/dist/components/NewComposition/DeleteFolder.js +1 -1
  43. package/dist/components/NewComposition/DuplicateComposition.js +7 -2
  44. package/dist/components/NewComposition/NewComposition.js +1 -1
  45. package/dist/components/NewComposition/NewFolder.js +1 -1
  46. package/dist/components/NewComposition/RenameComposition.js +1 -1
  47. package/dist/components/NewComposition/RenameFolder.js +1 -1
  48. package/dist/components/NewComposition/duplicate-composition-api.d.ts +16 -0
  49. package/dist/components/NewComposition/duplicate-composition-api.js +16 -0
  50. package/dist/components/NoRegisterRoot.js +1 -1
  51. package/dist/components/QuickSwitcher/ExplorerQuickSwitcherTrigger.js +4 -3
  52. package/dist/components/QuickSwitcher/QuickSwitcherContent.js +1 -0
  53. package/dist/components/QuickSwitcher/fuzzy-search.js +1 -1
  54. package/dist/components/RefreshCompositionOverlay.js +1 -1
  55. package/dist/components/RenderButton.js +6 -3
  56. package/dist/components/RenderModal/WebRenderModal.js +6 -2
  57. package/dist/components/RenderModal/WebRenderModalAdvanced.d.ts +2 -0
  58. package/dist/components/RenderModal/WebRenderModalAdvanced.js +9 -2
  59. package/dist/components/RenderModal/render-modals.js +5 -1
  60. package/dist/components/RenderQueue/ClientRenderQueueProcessor.js +5 -1
  61. package/dist/components/RenderQueue/actions.js +12 -2
  62. package/dist/components/RenderQueue/client-side-render-types.d.ts +1 -0
  63. package/dist/components/RenderingSettings.d.ts +2 -0
  64. package/dist/components/RenderingSettings.js +355 -0
  65. package/dist/components/SelectedOutlineElement.js +15 -13
  66. package/dist/components/SelectedOutlineOverlay.js +30 -8
  67. package/dist/components/SelectedOutlinePolygon.d.ts +1 -0
  68. package/dist/components/SelectedOutlinePolygon.js +53 -9
  69. package/dist/components/SettingsContext.d.ts +4 -1
  70. package/dist/components/SettingsContext.js +9 -2
  71. package/dist/components/SettingsModal.d.ts +1 -1
  72. package/dist/components/SettingsModal.js +10 -1
  73. package/dist/components/SettingsModalFooter.js +1 -1
  74. package/dist/components/StudioSettings.d.ts +2 -0
  75. package/dist/components/StudioSettings.js +185 -0
  76. package/dist/components/Timeline/LoopedIndicator.js +1 -1
  77. package/dist/components/Timeline/LoopedTimelineIndicators.d.ts +3 -0
  78. package/dist/components/Timeline/LoopedTimelineIndicators.js +22 -14
  79. package/dist/components/Timeline/Timeline.js +11 -9
  80. package/dist/components/Timeline/TimelineArrayField.js +1 -0
  81. package/dist/components/Timeline/TimelineAssetField.d.ts +2 -2
  82. package/dist/components/Timeline/TimelineAssetField.js +1 -1
  83. package/dist/components/Timeline/TimelineDragHandler.js +62 -76
  84. package/dist/components/Timeline/TimelineEffectItem.js +1 -1
  85. package/dist/components/Timeline/TimelineEffectPropItem.d.ts +4 -2
  86. package/dist/components/Timeline/TimelineEffectPropItem.js +25 -14
  87. package/dist/components/Timeline/TimelineExpandedRow.d.ts +1 -1
  88. package/dist/components/Timeline/TimelineExpandedRow.js +4 -4
  89. package/dist/components/Timeline/TimelineExpandedSection.js +1 -1
  90. package/dist/components/Timeline/TimelineHeightContainer.d.ts +0 -4
  91. package/dist/components/Timeline/TimelineHeightContainer.js +4 -4
  92. package/dist/components/Timeline/TimelineImageInfo.d.ts +1 -0
  93. package/dist/components/Timeline/TimelineImageInfo.js +3 -2
  94. package/dist/components/Timeline/TimelineKeyframeControls.js +31 -8
  95. package/dist/components/Timeline/TimelineKeyframedValue.js +1 -0
  96. package/dist/components/Timeline/TimelineList.d.ts +1 -5
  97. package/dist/components/Timeline/TimelineList.js +14 -9
  98. package/dist/components/Timeline/TimelinePinchZoom.js +5 -5
  99. package/dist/components/Timeline/TimelineRowChrome.d.ts +0 -2
  100. package/dist/components/Timeline/TimelineRowChrome.js +12 -5
  101. package/dist/components/Timeline/TimelineSchemaField.d.ts +7 -3
  102. package/dist/components/Timeline/TimelineSchemaField.js +71 -13
  103. package/dist/components/Timeline/TimelineScrollable.js +3 -1
  104. package/dist/components/Timeline/TimelineSelection.d.ts +5 -2
  105. package/dist/components/Timeline/TimelineSelection.js +90 -103
  106. package/dist/components/Timeline/TimelineSequence.js +59 -25
  107. package/dist/components/Timeline/TimelineSequenceItem.d.ts +1 -1
  108. package/dist/components/Timeline/TimelineSequenceItem.js +15 -9
  109. package/dist/components/Timeline/TimelineSequencePropItem.d.ts +2 -1
  110. package/dist/components/Timeline/TimelineSequencePropItem.js +14 -7
  111. package/dist/components/Timeline/TimelineSequenceRightEdgeDragHandle.d.ts +3 -0
  112. package/dist/components/Timeline/TimelineSequenceRightEdgeDragHandle.js +128 -27
  113. package/dist/components/Timeline/TimelineSlider.js +42 -33
  114. package/dist/components/Timeline/TimelineTimeIndicators.js +90 -98
  115. package/dist/components/Timeline/TimelineTracks.d.ts +0 -2
  116. package/dist/components/Timeline/TimelineTracks.js +11 -4
  117. package/dist/components/Timeline/TimelineTransformOriginField.js +1 -1
  118. package/dist/components/Timeline/TimelineVideoInfo.d.ts +4 -4
  119. package/dist/components/Timeline/TimelineVideoInfo.js +151 -61
  120. package/dist/components/Timeline/TimelineViewport.d.ts +12 -0
  121. package/dist/components/Timeline/TimelineViewport.js +62 -0
  122. package/dist/components/Timeline/TimelineVirtualization.d.ts +22 -0
  123. package/dist/components/Timeline/TimelineVirtualization.js +144 -0
  124. package/dist/components/Timeline/TimelineZoomControls.js +16 -8
  125. package/dist/components/Timeline/call-add-keyframe.js +31 -3
  126. package/dist/components/Timeline/call-delete-keyframe.js +13 -3
  127. package/dist/components/Timeline/call-move-keyframe.d.ts +2 -1
  128. package/dist/components/Timeline/call-move-keyframe.js +81 -18
  129. package/dist/components/Timeline/call-update-keyframe-settings.js +31 -3
  130. package/dist/components/Timeline/delete-selected-keyframe.d.ts +0 -8
  131. package/dist/components/Timeline/delete-selected-keyframe.js +23 -44
  132. package/dist/components/Timeline/delete-selected-timeline-item.d.ts +0 -8
  133. package/dist/components/Timeline/delete-selected-timeline-item.js +18 -44
  134. package/dist/components/Timeline/get-easing-selection-after-keyframe-delete.js +8 -3
  135. package/dist/components/Timeline/get-sequence-context-menu-items.js +10 -8
  136. package/dist/components/Timeline/get-timeline-keyframes.d.ts +5 -2
  137. package/dist/components/Timeline/get-timeline-keyframes.js +16 -10
  138. package/dist/components/Timeline/get-timeline-sequence-visible-layout.d.ts +30 -0
  139. package/dist/components/Timeline/get-timeline-sequence-visible-layout.js +61 -0
  140. package/dist/components/Timeline/keyframe-clipboard.js +9 -2
  141. package/dist/components/Timeline/split-selected-timeline-item.js +2 -2
  142. package/dist/components/Timeline/timeline-scroll-logic.d.ts +24 -0
  143. package/dist/components/Timeline/timeline-scroll-logic.js +127 -4
  144. package/dist/components/Timeline/use-open-sequence-in-apps.js +8 -8
  145. package/dist/components/Timeline/use-timeline-height.d.ts +3 -5
  146. package/dist/components/Timeline/use-timeline-height.js +16 -18
  147. package/dist/components/Timeline/use-timeline-keyframe-drag.js +14 -4
  148. package/dist/components/UpdateCheck.d.ts +2 -10
  149. package/dist/components/UpdateCheck.js +8 -2
  150. package/dist/components/VisualControls/ClickableFileName.js +13 -6
  151. package/dist/components/VisualControls/VisualControlHandle.js +8 -0
  152. package/dist/components/composition-menu-items.d.ts +6 -1
  153. package/dist/components/composition-menu-items.js +9 -6
  154. package/dist/components/delete-jsx-node-api.d.ts +2 -0
  155. package/dist/components/delete-jsx-node-api.js +12 -0
  156. package/dist/components/element-install-api.d.ts +3 -0
  157. package/dist/components/element-install-api.js +19 -0
  158. package/dist/components/folder-menu-items.d.ts +4 -1
  159. package/dist/components/folder-menu-items.js +4 -5
  160. package/dist/components/get-open-in-menu-items.d.ts +1 -1
  161. package/dist/components/get-open-in-menu-items.js +15 -13
  162. package/dist/components/import-assets.js +20 -9
  163. package/dist/components/reorder-sequence-api.d.ts +2 -0
  164. package/dist/components/reorder-sequence-api.js +12 -0
  165. package/dist/components/sequence-props-api.js +44 -3
  166. package/dist/components/split-jsx-sequence-api.d.ts +2 -0
  167. package/dist/components/split-jsx-sequence-api.js +12 -0
  168. package/dist/components/split-video-from-audio-api.d.ts +2 -0
  169. package/dist/components/split-video-from-audio-api.js +12 -0
  170. package/dist/components/use-default-editor-info.d.ts +8 -0
  171. package/dist/components/use-default-editor-info.js +25 -9
  172. package/dist/error-overlay/remotion-overlay/ErrorDisplay.js +10 -3
  173. package/dist/error-overlay/remotion-overlay/OpenInEditor.d.ts +3 -1
  174. package/dist/error-overlay/remotion-overlay/OpenInEditor.js +6 -6
  175. package/dist/error-overlay/remotion-overlay/Overlay.js +14 -12
  176. package/dist/error-overlay/remotion-overlay/StackFrame.d.ts +2 -1
  177. package/dist/error-overlay/remotion-overlay/StackFrame.js +7 -4
  178. package/dist/esm/{chunk-s8gwjng0.js → chunk-xn2q7eem.js} +11983 -8035
  179. package/dist/esm/index.mjs +7 -5
  180. package/dist/esm/internals.mjs +11983 -8035
  181. package/dist/esm/previewEntry.mjs +13059 -9107
  182. package/dist/esm/renderEntry.mjs +2 -3
  183. package/dist/helpers/browser-studio-operations.d.ts +2 -0
  184. package/dist/helpers/browser-studio-operations.js +10 -1
  185. package/dist/helpers/get-timeline-max-zoom.d.ts +26 -0
  186. package/dist/helpers/get-timeline-max-zoom.js +45 -0
  187. package/dist/helpers/inject-css.js +2 -2
  188. package/dist/helpers/open-in-editor.d.ts +6 -4
  189. package/dist/helpers/open-in-editor.js +4 -4
  190. package/dist/helpers/render-codec-label.d.ts +1 -1
  191. package/dist/helpers/retry-payload.js +1 -0
  192. package/dist/helpers/studio-runtime-config.d.ts +1 -1
  193. package/dist/helpers/studio-runtime-config.js +2 -3
  194. package/dist/helpers/timeline-layout.d.ts +3 -1
  195. package/dist/helpers/timeline-layout.js +6 -1
  196. package/dist/helpers/url-state.js +3 -2
  197. package/dist/helpers/use-menu-structure.js +12 -11
  198. package/dist/helpers/use-runtime-values.d.ts +2 -1
  199. package/dist/helpers/use-runtime-values.js +7 -3
  200. package/dist/icons/remotion-triangle.d.ts +2 -0
  201. package/dist/icons/remotion-triangle.js +7 -0
  202. package/dist/renderEntry.js +1 -1
  203. package/dist/state/composition-list.d.ts +13 -0
  204. package/dist/state/composition-list.js +21 -0
  205. package/dist/state/modals.d.ts +7 -1
  206. package/dist/state/timeline-zoom.d.ts +1 -2
  207. package/dist/state/timeline-zoom.js +9 -5
  208. package/package.json +14 -13
@@ -3,16 +3,16 @@ import type { LoopDisplay } from 'remotion';
3
3
  export declare const TimelineVideoInfo: React.NamedExoticComponent<{
4
4
  readonly src: string;
5
5
  readonly visualizationWidth: number;
6
- readonly naturalWidth: number;
6
+ readonly displayOffsetInFrames: number;
7
+ readonly displayDurationInFrames: number;
7
8
  readonly startMediaFrom: number;
8
9
  readonly mediaFrameAtSequenceZero: number | null;
9
10
  readonly sequenceFrameOffset: number;
10
- readonly durationInFrames: number;
11
11
  readonly playbackRate: number;
12
12
  readonly volume: string | number;
13
13
  readonly doesVolumeChange: boolean;
14
- readonly premountWidth: number;
15
- readonly postmountWidth: number;
14
+ readonly muted: boolean;
15
+ readonly marginLeft: number;
16
16
  readonly loopDisplay: LoopDisplay | undefined;
17
17
  readonly frozenMediaFrame: number | null;
18
18
  readonly extendLastFrame: boolean;
@@ -42,7 +42,6 @@ const colors_1 = require("../../helpers/colors");
42
42
  const timeline_layout_1 = require("../../helpers/timeline-layout");
43
43
  const AudioWaveform_1 = require("../AudioWaveform");
44
44
  const get_timeline_media_start_frame_1 = require("./get-timeline-media-start-frame");
45
- const get_timeline_video_info_widths_1 = require("./get-timeline-video-info-widths");
46
45
  const timeline_video_filmstrip_times_1 = require("./timeline-video-filmstrip-times");
47
46
  const outerStyle = {
48
47
  width: '100%',
@@ -59,7 +58,8 @@ const filmstripContainerStyle = {
59
58
  fontFamily: 'Arial, Helvetica',
60
59
  };
61
60
  const MAX_FROZEN_FRAME_CACHE_DEVIATION = timeline_utils_1.WEBCODECS_TIMESCALE * 0.05;
62
- const TimelineVideoInfoInner = ({ src, visualizationWidth, naturalWidth, startMediaFrom, mediaFrameAtSequenceZero, sequenceFrameOffset, durationInFrames, playbackRate, volume, doesVolumeChange, premountWidth, postmountWidth, loopDisplay, frozenMediaFrame, extendLastFrame, }) => {
61
+ const TimelineVideoInfoSegment = ({ src, visualizationWidth, startMediaFrom, mediaFrameAtSequenceZero, sequenceFrameOffset, durationInFrames, sourceOffsetInFrames, tiledLoop, playbackRate, volume, doesVolumeChange, muted, frozenMediaFrame, extendLastFrame, }) => {
62
+ var _a, _b;
63
63
  const { fps } = (0, remotion_1.useVideoConfig)();
64
64
  const ref = (0, react_1.useRef)(null);
65
65
  const [error, setError] = (0, react_1.useState)(null);
@@ -69,15 +69,8 @@ const TimelineVideoInfoInner = ({ src, visualizationWidth, naturalWidth, startMe
69
69
  mediaFrameAtSequenceZero,
70
70
  sequenceFrameOffset,
71
71
  playbackRate,
72
- });
73
- const { mediaVisualizationWidth, mediaNaturalWidth } = (0, react_1.useMemo)(() => {
74
- return (0, get_timeline_video_info_widths_1.getTimelineVideoInfoWidths)({
75
- visualizationWidth,
76
- naturalWidth,
77
- premountWidth,
78
- postmountWidth,
79
- });
80
- }, [naturalWidth, postmountWidth, premountWidth, visualizationWidth]);
72
+ }) +
73
+ sourceOffsetInFrames * playbackRate;
81
74
  // for rendering frames
82
75
  (0, react_1.useEffect)(() => {
83
76
  if (error) {
@@ -88,19 +81,22 @@ const TimelineVideoInfoInner = ({ src, visualizationWidth, naturalWidth, startMe
88
81
  return;
89
82
  }
90
83
  const controller = new AbortController();
84
+ const pixelRatio = window.devicePixelRatio;
91
85
  const canvas = document.createElement('canvas');
92
- canvas.width = mediaVisualizationWidth;
93
- canvas.height = timeline_layout_1.TIMELINE_LAYER_FILMSTRIP_HEIGHT;
86
+ canvas.width = Math.ceil(visualizationWidth * pixelRatio);
87
+ canvas.height = Math.ceil(timeline_layout_1.TIMELINE_LAYER_FILMSTRIP_HEIGHT * pixelRatio);
88
+ canvas.style.width = visualizationWidth + 'px';
89
+ canvas.style.height = timeline_layout_1.TIMELINE_LAYER_FILMSTRIP_HEIGHT + 'px';
94
90
  const ctx = canvas.getContext('2d');
95
91
  if (!ctx) {
96
92
  return;
97
93
  }
98
94
  current.appendChild(canvas);
99
95
  const drawRepeatedFrame = (frame) => {
100
- const thumbnailWidth = Math.max(1, frame.displayWidth / window.devicePixelRatio);
96
+ const thumbnailWidth = Math.max(1, frame.displayWidth);
101
97
  ctx.clearRect(0, 0, canvas.width, canvas.height);
102
98
  for (let x = 0; x < canvas.width; x += thumbnailWidth) {
103
- ctx.drawImage(frame, x, 0, thumbnailWidth, timeline_layout_1.TIMELINE_LAYER_FILMSTRIP_HEIGHT);
99
+ ctx.drawImage(frame, x, 0, thumbnailWidth, canvas.height);
104
100
  }
105
101
  };
106
102
  const getCachedFrozenFrame = (timestamp) => {
@@ -128,7 +124,7 @@ const TimelineVideoInfoInner = ({ src, visualizationWidth, naturalWidth, startMe
128
124
  durationInFrames,
129
125
  playbackRate,
130
126
  fps,
131
- loopDisplay,
127
+ loopDisplay: undefined,
132
128
  frozenMediaFrame,
133
129
  });
134
130
  if (times.type === 'frozen') {
@@ -152,8 +148,7 @@ const TimelineVideoInfoInner = ({ src, visualizationWidth, naturalWidth, startMe
152
148
  let frame;
153
149
  try {
154
150
  frame = sample.toVideoFrame();
155
- const scale = (timeline_layout_1.TIMELINE_LAYER_FILMSTRIP_HEIGHT / frame.displayHeight) *
156
- window.devicePixelRatio;
151
+ const scale = canvas.height / frame.displayHeight;
157
152
  const transformed = (0, timeline_utils_1.resizeVideoFrame)({
158
153
  frame,
159
154
  scale,
@@ -185,42 +180,44 @@ const TimelineVideoInfoInner = ({ src, visualizationWidth, naturalWidth, startMe
185
180
  current.removeChild(canvas);
186
181
  };
187
182
  }
188
- const loopWidth = (0, timeline_utils_1.getLoopDisplayWidth)({
189
- visualizationWidth: mediaNaturalWidth,
190
- loopDisplay,
191
- });
192
- const shouldRepeatVideo = (0, timeline_utils_1.shouldTileLoopDisplay)(loopDisplay);
193
- const targetCanvas = shouldRepeatVideo
194
- ? document.createElement('canvas')
195
- : canvas;
196
- targetCanvas.width = shouldRepeatVideo
197
- ? Math.max(1, Math.ceil(loopWidth))
183
+ const targetCanvas = tiledLoop ? document.createElement('canvas') : canvas;
184
+ targetCanvas.width = tiledLoop
185
+ ? Math.max(1, Math.ceil(tiledLoop.loopWidth * pixelRatio))
198
186
  : canvas.width;
199
187
  targetCanvas.height = canvas.height;
200
- const targetCtx = shouldRepeatVideo ? targetCanvas.getContext('2d') : ctx;
188
+ const targetCtx = tiledLoop ? targetCanvas.getContext('2d') : ctx;
201
189
  if (!targetCtx) {
202
190
  current.removeChild(canvas);
203
191
  return;
204
192
  }
193
+ // desired-timestamp -> filled-timestamp
194
+ const filledSlots = new Map();
195
+ const { fromSeconds, toSeconds } = times;
196
+ const targetWidth = targetCanvas.width;
205
197
  const repeatTarget = () => {
206
- if (!shouldRepeatVideo) {
198
+ if (!tiledLoop) {
207
199
  return;
208
200
  }
209
201
  const pattern = ctx.createPattern(targetCanvas, 'repeat-x');
210
202
  if (!pattern) {
211
203
  return;
212
204
  }
213
- pattern.setTransform(new DOMMatrix().scaleSelf(loopWidth / targetCanvas.width, 1));
205
+ const phase = (tiledLoop.displayOffsetInFrames %
206
+ tiledLoop.loopDisplay.durationInFrames) *
207
+ ((tiledLoop.loopWidth * pixelRatio) /
208
+ tiledLoop.loopDisplay.durationInFrames);
209
+ pattern.setTransform(new DOMMatrix([
210
+ (tiledLoop.loopWidth * pixelRatio) / targetCanvas.width,
211
+ 0,
212
+ 0,
213
+ 1,
214
+ -phase,
215
+ 0,
216
+ ]));
214
217
  ctx.clearRect(0, 0, canvas.width, canvas.height);
215
218
  ctx.fillStyle = pattern;
216
219
  ctx.fillRect(0, 0, canvas.width, canvas.height);
217
220
  };
218
- // desired-timestamp -> filled-timestamp
219
- const filledSlots = new Map();
220
- const { fromSeconds, toSeconds } = times;
221
- const targetWidth = shouldRepeatVideo
222
- ? targetCanvas.width
223
- : mediaNaturalWidth;
224
221
  if (aspectRatio.current !== null) {
225
222
  (0, timeline_utils_1.ensureSlots)({
226
223
  filledSlots,
@@ -228,7 +225,7 @@ const TimelineVideoInfoInner = ({ src, visualizationWidth, naturalWidth, startMe
228
225
  fromSeconds,
229
226
  toSeconds,
230
227
  aspectRatio: aspectRatio.current,
231
- frameHeight: timeline_layout_1.TIMELINE_LAYER_FILMSTRIP_HEIGHT,
228
+ frameHeight: canvas.height,
232
229
  });
233
230
  (0, timeline_utils_1.fillWithCachedFrames)({
234
231
  ctx: targetCtx,
@@ -237,11 +234,11 @@ const TimelineVideoInfoInner = ({ src, visualizationWidth, naturalWidth, startMe
237
234
  src,
238
235
  segmentDuration: toSeconds - fromSeconds,
239
236
  fromSeconds,
240
- devicePixelRatio: window.devicePixelRatio,
241
- frameHeight: timeline_layout_1.TIMELINE_LAYER_FILMSTRIP_HEIGHT,
237
+ devicePixelRatio: 1,
238
+ frameHeight: canvas.height,
242
239
  });
243
240
  repeatTarget();
244
- const unfilled = Array.from(filledSlots.keys()).filter((timestamp) => !filledSlots.get(timestamp));
241
+ const unfilled = Array.from(filledSlots.keys()).filter((timestamp) => filledSlots.get(timestamp) === undefined);
245
242
  // Don't extract frames if all slots are filled
246
243
  if (unfilled.length === 0) {
247
244
  return () => {
@@ -260,17 +257,29 @@ const TimelineVideoInfoInner = ({ src, visualizationWidth, naturalWidth, startMe
260
257
  toSeconds,
261
258
  naturalWidth: targetWidth,
262
259
  aspectRatio: aspectRatio.current,
263
- frameHeight: timeline_layout_1.TIMELINE_LAYER_FILMSTRIP_HEIGHT,
260
+ frameHeight: canvas.height,
261
+ });
262
+ (0, timeline_utils_1.fillWithCachedFrames)({
263
+ ctx: targetCtx,
264
+ naturalWidth: targetWidth,
265
+ filledSlots,
266
+ src,
267
+ segmentDuration: toSeconds - fromSeconds,
268
+ fromSeconds,
269
+ devicePixelRatio: 1,
270
+ frameHeight: canvas.height,
264
271
  });
265
- return Array.from(filledSlots.keys()).map((timestamp) => timestamp / timeline_utils_1.WEBCODECS_TIMESCALE);
272
+ repeatTarget();
273
+ return Array.from(filledSlots.keys())
274
+ .filter((timestamp) => filledSlots.get(timestamp) === undefined)
275
+ .map((timestamp) => timestamp / timeline_utils_1.WEBCODECS_TIMESCALE);
266
276
  },
267
277
  src,
268
278
  onVideoSample: (sample) => {
269
279
  let frame;
270
280
  try {
271
281
  frame = sample.toVideoFrame();
272
- const scale = (timeline_layout_1.TIMELINE_LAYER_FILMSTRIP_HEIGHT / frame.displayHeight) *
273
- window.devicePixelRatio;
282
+ const scale = canvas.height / frame.displayHeight;
274
283
  const transformed = (0, timeline_utils_1.resizeVideoFrame)({
275
284
  frame,
276
285
  scale,
@@ -290,7 +299,7 @@ const TimelineVideoInfoInner = ({ src, visualizationWidth, naturalWidth, startMe
290
299
  toSeconds,
291
300
  naturalWidth: targetWidth,
292
301
  aspectRatio: aspectRatio.current,
293
- frameHeight: timeline_layout_1.TIMELINE_LAYER_FILMSTRIP_HEIGHT,
302
+ frameHeight: canvas.height,
294
303
  });
295
304
  (0, timeline_utils_1.fillFrameWhereItFits)({
296
305
  ctx: targetCtx,
@@ -299,8 +308,8 @@ const TimelineVideoInfoInner = ({ src, visualizationWidth, naturalWidth, startMe
299
308
  frame: transformed,
300
309
  segmentDuration: toSeconds - fromSeconds,
301
310
  fromSeconds,
302
- devicePixelRatio: window.devicePixelRatio,
303
- frameHeight: timeline_layout_1.TIMELINE_LAYER_FILMSTRIP_HEIGHT,
311
+ devicePixelRatio: 1,
312
+ frameHeight: canvas.height,
304
313
  });
305
314
  repeatTarget();
306
315
  }
@@ -327,8 +336,8 @@ const TimelineVideoInfoInner = ({ src, visualizationWidth, naturalWidth, startMe
327
336
  src,
328
337
  segmentDuration: toSeconds - fromSeconds,
329
338
  fromSeconds,
330
- devicePixelRatio: window.devicePixelRatio,
331
- frameHeight: timeline_layout_1.TIMELINE_LAYER_FILMSTRIP_HEIGHT,
339
+ devicePixelRatio: 1,
340
+ frameHeight: canvas.height,
332
341
  });
333
342
  repeatTarget();
334
343
  })
@@ -345,30 +354,111 @@ const TimelineVideoInfoInner = ({ src, visualizationWidth, naturalWidth, startMe
345
354
  extendLastFrame,
346
355
  fps,
347
356
  frozenMediaFrame,
348
- loopDisplay,
349
- mediaNaturalWidth,
350
- mediaVisualizationWidth,
351
357
  mediaStartFrame,
352
358
  playbackRate,
353
359
  src,
360
+ tiledLoop,
361
+ visualizationWidth,
354
362
  ]);
355
- const audioWidth = mediaVisualizationWidth;
363
+ const audioWidth = visualizationWidth;
356
364
  const filmstripStyle = (0, react_1.useMemo)(() => {
357
365
  return {
358
366
  ...filmstripContainerStyle,
359
- width: mediaVisualizationWidth,
360
- marginLeft: premountWidth,
367
+ width: visualizationWidth,
361
368
  };
362
- }, [mediaVisualizationWidth, premountWidth]);
369
+ }, [visualizationWidth]);
363
370
  const audioStyle = (0, react_1.useMemo)(() => {
364
371
  return {
365
372
  width: audioWidth,
366
373
  position: 'relative',
367
- marginLeft: premountWidth,
368
374
  };
369
- }, [audioWidth, premountWidth]);
370
- return (jsx_runtime_1.jsxs("div", { style: outerStyle, children: [
371
- jsx_runtime_1.jsx("div", { ref: ref, style: filmstripStyle }), jsx_runtime_1.jsx("div", { style: audioStyle, children: jsx_runtime_1.jsx(AudioWaveform_1.AudioWaveform, { src: src, height: timeline_layout_1.TIMELINE_VIDEO_INFO_WAVEFORM_HEIGHT, visualizationWidth: audioWidth, startFrom: mediaStartFrame, durationInFrames: durationInFrames, volume: volume, doesVolumeChange: doesVolumeChange, playbackRate: playbackRate, loopDisplay: loopDisplay }) })
375
+ }, [audioWidth]);
376
+ const segmentStyle = (0, react_1.useMemo)(() => {
377
+ return {
378
+ ...outerStyle,
379
+ width: visualizationWidth,
380
+ flexShrink: 0,
381
+ };
382
+ }, [visualizationWidth]);
383
+ return (jsx_runtime_1.jsxs("div", { style: segmentStyle, children: [
384
+ jsx_runtime_1.jsx("div", { ref: ref, style: filmstripStyle }), jsx_runtime_1.jsx("div", { style: audioStyle, children: jsx_runtime_1.jsx(AudioWaveform_1.AudioWaveform, { src: src, height: timeline_layout_1.TIMELINE_VIDEO_INFO_WAVEFORM_HEIGHT, visualizationWidth: audioWidth, startFrom: mediaStartFrame, durationInFrames: durationInFrames, displayOffsetInFrames: (_a = tiledLoop === null || tiledLoop === void 0 ? void 0 : tiledLoop.displayOffsetInFrames) !== null && _a !== void 0 ? _a : 0, displayDurationInFrames: (_b = tiledLoop === null || tiledLoop === void 0 ? void 0 : tiledLoop.displayDurationInFrames) !== null && _b !== void 0 ? _b : durationInFrames, volume: volume, doesVolumeChange: doesVolumeChange, muted: muted, playbackRate: playbackRate, loopDisplay: tiledLoop === null || tiledLoop === void 0 ? void 0 : tiledLoop.loopDisplay }) })
372
385
  ] }));
373
386
  };
387
+ const getVisibleSegments = ({ displayDurationInFrames, displayOffsetInFrames, loopDisplay, }) => {
388
+ if (!loopDisplay ||
389
+ loopDisplay.numberOfTimes <= 1 ||
390
+ loopDisplay.durationInFrames <= 0) {
391
+ return [
392
+ {
393
+ key: 'single',
394
+ displayOffsetInFrames,
395
+ durationInFrames: displayDurationInFrames,
396
+ sourceOffsetInFrames: displayOffsetInFrames,
397
+ },
398
+ ];
399
+ }
400
+ return (0, timeline_utils_1.getLoopDisplaySegments)({
401
+ displayDurationInFrames,
402
+ displayOffsetInFrames,
403
+ loopDurationInFrames: loopDisplay.durationInFrames,
404
+ }).map((segment) => {
405
+ return {
406
+ key: `loop-${segment.loopIndex}`,
407
+ displayOffsetInFrames: segment.absoluteOffsetInFrames,
408
+ durationInFrames: segment.durationInFrames,
409
+ sourceOffsetInFrames: segment.loopOffsetInFrames,
410
+ };
411
+ });
412
+ };
413
+ const TimelineVideoInfoInner = ({ src, visualizationWidth, displayOffsetInFrames, displayDurationInFrames, startMediaFrom, mediaFrameAtSequenceZero, sequenceFrameOffset, playbackRate, volume, doesVolumeChange, muted, marginLeft, loopDisplay, frozenMediaFrame, extendLastFrame, }) => {
414
+ const pixelsPerFrame = visualizationWidth / displayDurationInFrames;
415
+ const loopWidth = loopDisplay
416
+ ? loopDisplay.durationInFrames * pixelsPerFrame
417
+ : null;
418
+ const shouldTileLoop = loopDisplay !== undefined &&
419
+ loopWidth !== null &&
420
+ loopWidth <= visualizationWidth;
421
+ const tiledLoop = (0, react_1.useMemo)(() => {
422
+ if (!shouldTileLoop || !loopDisplay || loopWidth === null) {
423
+ return null;
424
+ }
425
+ return {
426
+ displayDurationInFrames,
427
+ displayOffsetInFrames,
428
+ loopDisplay,
429
+ loopWidth,
430
+ };
431
+ }, [
432
+ displayDurationInFrames,
433
+ displayOffsetInFrames,
434
+ loopDisplay,
435
+ loopWidth,
436
+ shouldTileLoop,
437
+ ]);
438
+ const segments = (0, react_1.useMemo)(() => {
439
+ if (shouldTileLoop) {
440
+ return [];
441
+ }
442
+ return getVisibleSegments({
443
+ displayDurationInFrames,
444
+ displayOffsetInFrames,
445
+ loopDisplay,
446
+ });
447
+ }, [
448
+ displayDurationInFrames,
449
+ displayOffsetInFrames,
450
+ loopDisplay,
451
+ shouldTileLoop,
452
+ ]);
453
+ const getSegmentVolume = (segmentDisplayOffsetInFrames, segmentDurationInFrames) => {
454
+ if (typeof volume === 'number') {
455
+ return volume;
456
+ }
457
+ const values = volume.split(',');
458
+ return values
459
+ .slice(Math.max(0, Math.floor(segmentDisplayOffsetInFrames)), Math.min(values.length, Math.ceil(segmentDisplayOffsetInFrames + segmentDurationInFrames)))
460
+ .join(',');
461
+ };
462
+ return (jsx_runtime_1.jsx("div", { style: { display: 'flex', marginLeft, height: '100%' }, children: tiledLoop ? (jsx_runtime_1.jsx(TimelineVideoInfoSegment, { src: src, visualizationWidth: visualizationWidth, startMediaFrom: startMediaFrom, mediaFrameAtSequenceZero: mediaFrameAtSequenceZero, sequenceFrameOffset: sequenceFrameOffset, durationInFrames: tiledLoop.loopDisplay.durationInFrames, sourceOffsetInFrames: 0, tiledLoop: tiledLoop, playbackRate: playbackRate, volume: volume, doesVolumeChange: doesVolumeChange, muted: muted, frozenMediaFrame: frozenMediaFrame, extendLastFrame: extendLastFrame })) : (segments.map((segment) => (jsx_runtime_1.jsx(TimelineVideoInfoSegment, { src: src, visualizationWidth: segment.durationInFrames * pixelsPerFrame, startMediaFrom: startMediaFrom, mediaFrameAtSequenceZero: mediaFrameAtSequenceZero, sequenceFrameOffset: sequenceFrameOffset, durationInFrames: segment.durationInFrames, sourceOffsetInFrames: segment.sourceOffsetInFrames, tiledLoop: null, playbackRate: playbackRate, volume: getSegmentVolume(segment.sourceOffsetInFrames, segment.durationInFrames), doesVolumeChange: doesVolumeChange, muted: muted, frozenMediaFrame: frozenMediaFrame, extendLastFrame: extendLastFrame }, segment.key)))) }));
463
+ };
374
464
  exports.TimelineVideoInfo = react_1.default.memo(TimelineVideoInfoInner);
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+ type TimelineRenderWindow = {
3
+ readonly left: number;
4
+ readonly width: number;
5
+ };
6
+ export declare const TimelineViewportContext: React.Context<TimelineRenderWindow | null>;
7
+ export declare const getTimelineRenderWindow: (scrollable: HTMLDivElement) => TimelineRenderWindow;
8
+ export declare const TimelineViewportProvider: React.FC<{
9
+ readonly children: React.ReactNode;
10
+ readonly scrollable: React.RefObject<HTMLDivElement | null>;
11
+ }>;
12
+ export {};
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TimelineViewportProvider = exports.getTimelineRenderWindow = exports.TimelineViewportContext = void 0;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const react_1 = require("react");
6
+ exports.TimelineViewportContext = (0, react_1.createContext)(null);
7
+ const getTimelineRenderWindow = (scrollable) => {
8
+ const viewportWidth = scrollable.clientWidth;
9
+ if (viewportWidth === 0) {
10
+ return { left: 0, width: 0 };
11
+ }
12
+ // Move the render window half a viewport before the visible viewport reaches
13
+ // its right edge. This keeps at least half a viewport rendered ahead while
14
+ // retaining the three-viewport-wide window.
15
+ const currentSection = Math.floor((scrollable.scrollLeft + viewportWidth / 2) / viewportWidth);
16
+ const left = Math.max(0, (currentSection - 1) * viewportWidth);
17
+ return {
18
+ left,
19
+ width: viewportWidth * 3,
20
+ };
21
+ };
22
+ exports.getTimelineRenderWindow = getTimelineRenderWindow;
23
+ const TimelineViewportProvider = ({ children, scrollable }) => {
24
+ const [renderWindow, setRenderWindow] = (0, react_1.useState)({
25
+ left: 0,
26
+ width: window.innerWidth * 3,
27
+ });
28
+ const update = (0, react_1.useCallback)(() => {
29
+ const element = scrollable.current;
30
+ if (!element) {
31
+ return;
32
+ }
33
+ const next = (0, exports.getTimelineRenderWindow)(element);
34
+ setRenderWindow((previous) => {
35
+ if (previous.left === next.left && previous.width === next.width) {
36
+ return previous;
37
+ }
38
+ return next;
39
+ });
40
+ }, [scrollable]);
41
+ (0, react_1.useLayoutEffect)(() => {
42
+ let element = null;
43
+ let resizeObserver = null;
44
+ const animationFrame = requestAnimationFrame(() => {
45
+ element = scrollable.current;
46
+ if (!element) {
47
+ return;
48
+ }
49
+ resizeObserver = new ResizeObserver(update);
50
+ resizeObserver.observe(element);
51
+ update();
52
+ element.addEventListener('scroll', update);
53
+ });
54
+ return () => {
55
+ cancelAnimationFrame(animationFrame);
56
+ resizeObserver === null || resizeObserver === void 0 ? void 0 : resizeObserver.disconnect();
57
+ element === null || element === void 0 ? void 0 : element.removeEventListener('scroll', update);
58
+ };
59
+ }, [scrollable, update]);
60
+ return (jsx_runtime_1.jsx(exports.TimelineViewportContext.Provider, { value: renderWindow, children: children }));
61
+ };
62
+ exports.TimelineViewportProvider = TimelineViewportProvider;
@@ -0,0 +1,22 @@
1
+ import { type VirtualItem } from '@tanstack/react-virtual';
2
+ import React from 'react';
3
+ import type { TimelineTrackData } from '../../helpers/get-timeline-sequence-sort-key';
4
+ export type TimelineVirtualRow = {
5
+ readonly afterDropLineOffset: number;
6
+ readonly siblingIndex: number;
7
+ readonly track: TimelineTrackData;
8
+ };
9
+ type TimelineVirtualizationContextValue = {
10
+ readonly rows: readonly TimelineVirtualRow[];
11
+ readonly totalSize: number;
12
+ readonly tracksEnd: number;
13
+ readonly virtualItems: readonly VirtualItem[];
14
+ };
15
+ export declare const TimelineVirtualizationProvider: React.FC<{
16
+ readonly children: React.ReactNode;
17
+ readonly hasBeenCut: boolean;
18
+ readonly isStill: boolean;
19
+ readonly timeline: readonly TimelineTrackData[];
20
+ }>;
21
+ export declare const useTimelineVirtualization: () => TimelineVirtualizationContextValue;
22
+ export {};
@@ -0,0 +1,144 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useTimelineVirtualization = exports.TimelineVirtualizationProvider = void 0;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const react_virtual_1 = require("@tanstack/react-virtual");
6
+ const react_1 = require("react");
7
+ const timeline_layout_1 = require("../../helpers/timeline-layout");
8
+ const MaxTimelineTracks_1 = require("./MaxTimelineTracks");
9
+ const timeline_refs_1 = require("./timeline-refs");
10
+ const TimelineSelection_1 = require("./TimelineSelection");
11
+ const TimelineTimeIndicators_1 = require("./TimelineTimeIndicators");
12
+ const use_timeline_height_1 = require("./use-timeline-height");
13
+ const TimelineVirtualizationContext = (0, react_1.createContext)(null);
14
+ const getSelectionTrackKey = (selection) => {
15
+ if (selection.type === 'guide') {
16
+ return null;
17
+ }
18
+ return (0, TimelineSelection_1.getTimelineSequenceSelectionKey)(selection.nodePathInfo);
19
+ };
20
+ const TimelineVirtualizationProvider = ({ children, hasBeenCut, isStill, timeline }) => {
21
+ const trackHeights = (0, use_timeline_height_1.useTimelineTrackHeights)({ timeline });
22
+ const { revealRequest, selectedItems } = (0, TimelineSelection_1.useTimelineSelection)();
23
+ const paddingStart = isStill ? 0 : TimelineTimeIndicators_1.TIMELINE_TIME_INDICATOR_HEIGHT;
24
+ const paddingEnd = timeline_layout_1.TIMELINE_ITEM_BORDER_BOTTOM +
25
+ (hasBeenCut ? MaxTimelineTracks_1.MAX_TIMELINE_TRACKS_NOTICE_HEIGHT : 0);
26
+ const layout = (0, react_1.useMemo)(() => {
27
+ var _a;
28
+ var _b, _c;
29
+ const siblingIndexes = new Array(timeline.length);
30
+ const subtreeEndIndexes = new Array(timeline.length).fill(timeline.length);
31
+ const openTracks = [];
32
+ const siblingCounts = new Map();
33
+ for (let index = 0; index < timeline.length; index++) {
34
+ const { depth } = timeline[index];
35
+ while (openTracks.length > 0 &&
36
+ openTracks[openTracks.length - 1].depth >= depth) {
37
+ const completed = openTracks.pop();
38
+ subtreeEndIndexes[completed.index] = index;
39
+ }
40
+ const parentIndex = (_b = (_a = openTracks[openTracks.length - 1]) === null || _a === void 0 ? void 0 : _a.index) !== null && _b !== void 0 ? _b : null;
41
+ const siblingIndex = (_c = siblingCounts.get(parentIndex)) !== null && _c !== void 0 ? _c : 0;
42
+ siblingIndexes[index] = siblingIndex;
43
+ siblingCounts.set(parentIndex, siblingIndex + 1);
44
+ openTracks.push({ depth, index });
45
+ }
46
+ const offsets = new Array(timeline.length + 1);
47
+ offsets[0] = paddingStart;
48
+ for (let index = 0; index < trackHeights.length; index++) {
49
+ offsets[index + 1] = offsets[index] + trackHeights[index];
50
+ }
51
+ const rows = timeline.map((track, index) => ({
52
+ afterDropLineOffset: offsets[subtreeEndIndexes[index]] - offsets[index],
53
+ siblingIndex: siblingIndexes[index],
54
+ track,
55
+ }));
56
+ const rootTrackIndexes = new Map();
57
+ for (let index = 0; index < timeline.length; index++) {
58
+ const { nodePathInfo } = timeline[index];
59
+ if (nodePathInfo !== null) {
60
+ rootTrackIndexes.set((0, TimelineSelection_1.getTimelineSequenceSelectionKey)(nodePathInfo), index);
61
+ }
62
+ }
63
+ return {
64
+ rootTrackIndexes,
65
+ rows,
66
+ tracksEnd: offsets[offsets.length - 1],
67
+ };
68
+ }, [paddingStart, timeline, trackHeights]);
69
+ const selectedTrackIndexes = (0, react_1.useMemo)(() => {
70
+ const indexes = new Set();
71
+ if (selectedItems.length !== 1) {
72
+ return indexes;
73
+ }
74
+ for (const selectedItem of selectedItems) {
75
+ const key = getSelectionTrackKey(selectedItem);
76
+ const index = key === null ? undefined : layout.rootTrackIndexes.get(key);
77
+ if (index !== undefined) {
78
+ indexes.add(index);
79
+ }
80
+ }
81
+ return indexes;
82
+ }, [layout.rootTrackIndexes, selectedItems]);
83
+ const trackHeightsRef = (0, react_1.useRef)(trackHeights);
84
+ trackHeightsRef.current = trackHeights;
85
+ const timelineRef = (0, react_1.useRef)(timeline);
86
+ timelineRef.current = timeline;
87
+ const estimateSize = (0, react_1.useCallback)((index) => {
88
+ var _a;
89
+ return (_a = trackHeightsRef.current[index]) !== null && _a !== void 0 ? _a : 0;
90
+ }, []);
91
+ const getItemKey = (0, react_1.useCallback)((index) => {
92
+ var _a;
93
+ var _b;
94
+ return (_b = (_a = timelineRef.current[index]) === null || _a === void 0 ? void 0 : _a.sequence.id) !== null && _b !== void 0 ? _b : index;
95
+ }, []);
96
+ const rangeExtractor = (0, react_1.useCallback)((range) => {
97
+ const indexes = new Set((0, react_virtual_1.defaultRangeExtractor)(range));
98
+ for (const selectedIndex of selectedTrackIndexes) {
99
+ indexes.add(selectedIndex);
100
+ }
101
+ return [...indexes].sort((a, b) => a - b);
102
+ }, [selectedTrackIndexes]);
103
+ const getScrollElement = (0, react_1.useCallback)(() => timeline_refs_1.timelineVerticalScroll.current, []);
104
+ const virtualizer = (0, react_virtual_1.useVirtualizer)({
105
+ count: timeline.length,
106
+ estimateSize,
107
+ getItemKey,
108
+ getScrollElement,
109
+ overscan: 8,
110
+ paddingEnd,
111
+ paddingStart,
112
+ rangeExtractor,
113
+ });
114
+ (0, react_1.useLayoutEffect)(() => {
115
+ virtualizer.measure();
116
+ }, [trackHeights, virtualizer]);
117
+ (0, react_1.useEffect)(() => {
118
+ if (revealRequest === null) {
119
+ return;
120
+ }
121
+ const key = getSelectionTrackKey(revealRequest.item);
122
+ const index = key === null ? undefined : layout.rootTrackIndexes.get(key);
123
+ if (index !== undefined) {
124
+ virtualizer.scrollToIndex(index, { align: 'center' });
125
+ }
126
+ }, [layout.rootTrackIndexes, revealRequest, virtualizer]);
127
+ const virtualItems = virtualizer.getVirtualItems();
128
+ const value = (0, react_1.useMemo)(() => ({
129
+ rows: layout.rows,
130
+ totalSize: layout.tracksEnd + paddingEnd,
131
+ tracksEnd: layout.tracksEnd,
132
+ virtualItems,
133
+ }), [layout.rows, layout.tracksEnd, paddingEnd, virtualItems]);
134
+ return (jsx_runtime_1.jsx(TimelineVirtualizationContext.Provider, { value: value, children: children }));
135
+ };
136
+ exports.TimelineVirtualizationProvider = TimelineVirtualizationProvider;
137
+ const useTimelineVirtualization = () => {
138
+ const context = (0, react_1.useContext)(TimelineVirtualizationContext);
139
+ if (context === null) {
140
+ throw new Error('useTimelineVirtualization must be used inside TimelineVirtualizationProvider');
141
+ }
142
+ return context;
143
+ };
144
+ exports.useTimelineVirtualization = useTimelineVirtualization;