@remotion/studio 4.0.506 → 4.0.507

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 (119) hide show
  1. package/dist/api/copy-render-output-to-asset.d.ts +4 -0
  2. package/dist/api/copy-render-output-to-asset.js +11 -0
  3. package/dist/components/AssetSelector.js +19 -4
  4. package/dist/components/AssetSelectorItem.js +2 -2
  5. package/dist/components/CodingAgentIcon.d.ts +4 -0
  6. package/dist/components/CodingAgentIcon.js +17 -0
  7. package/dist/components/ConfigureDefaultEditorModal.d.ts +1 -3
  8. package/dist/components/ConfigureDefaultEditorModal.js +67 -77
  9. package/dist/components/ConfigureLicenseModal.d.ts +1 -4
  10. package/dist/components/ConfigureLicenseModal.js +89 -81
  11. package/dist/components/ContextMenu.js +10 -8
  12. package/dist/components/EditorContexts.js +6 -5
  13. package/dist/components/ExpandedTracksProvider.js +10 -53
  14. package/dist/components/InspectorLocationCopy.js +8 -8
  15. package/dist/components/InspectorOpenInEditor.d.ts +1 -0
  16. package/dist/components/InspectorOpenInEditor.js +39 -49
  17. package/dist/components/InspectorPanel/SequenceInspectorHeader.d.ts +3 -0
  18. package/dist/components/InspectorPanel/SequenceInspectorHeader.js +22 -4
  19. package/dist/components/InspectorPanel/SequenceSelectionInspector.js +1 -1
  20. package/dist/components/Menu/MenuSectionHeader.d.ts +4 -0
  21. package/dist/components/Menu/MenuSectionHeader.js +20 -0
  22. package/dist/components/Menu/SubMenu.js +13 -2
  23. package/dist/components/Menu/menu-tree-context.d.ts +3 -0
  24. package/dist/components/Menu/menu-tree-context.js +13 -0
  25. package/dist/components/NewComposition/ComboBox.d.ts +6 -1
  26. package/dist/components/NewComposition/MenuContent.js +27 -19
  27. package/dist/components/NewComposition/menu-typeahead.js +2 -2
  28. package/dist/components/Preview.js +29 -4
  29. package/dist/components/RenderModal/SchemaEditor/ZodEnumEditor.d.ts +1 -0
  30. package/dist/components/RenderModal/SchemaEditor/ZodEnumEditor.js +2 -2
  31. package/dist/components/RenderModal/SchemaEditor/ZodOrNullishEditor.js +3 -3
  32. package/dist/components/RenderModal/SchemaEditor/ZodSwitch.js +1 -1
  33. package/dist/components/RenderModal/ServerRenderModal.js +4 -0
  34. package/dist/components/RenderQueue/RenderQueueItem.js +8 -2
  35. package/dist/components/RenderQueue/actions.d.ts +4 -2
  36. package/dist/components/RenderQueue/actions.js +4 -2
  37. package/dist/components/RenderQueue/index.js +3 -4
  38. package/dist/components/RenderQueue/use-render-output-file-drag.d.ts +8 -0
  39. package/dist/components/RenderQueue/use-render-output-file-drag.js +121 -0
  40. package/dist/components/SegmentedControl.js +0 -1
  41. package/dist/components/SelectedOutlineElement.d.ts +14 -17
  42. package/dist/components/SelectedOutlineElement.js +112 -930
  43. package/dist/components/SelectedOutlineKeyboardControls.d.ts +7 -0
  44. package/dist/components/SelectedOutlineKeyboardControls.js +261 -0
  45. package/dist/components/SelectedOutlineOverlay.d.ts +6 -13
  46. package/dist/components/SelectedOutlineOverlay.js +349 -864
  47. package/dist/components/SelectedOutlinePolygon.d.ts +25 -0
  48. package/dist/components/SelectedOutlinePolygon.js +359 -0
  49. package/dist/components/SelectedOutlineRenderer.d.ts +18 -0
  50. package/dist/components/SelectedOutlineRenderer.js +208 -0
  51. package/dist/components/SelectedOutlineRotationCornerHandle.d.ts +16 -0
  52. package/dist/components/SelectedOutlineRotationCornerHandle.js +269 -0
  53. package/dist/components/SelectedOutlineScaleEdgeLine.d.ts +16 -0
  54. package/dist/components/SelectedOutlineScaleEdgeLine.js +211 -0
  55. package/dist/components/SelectedOutlineSnapIndicators.d.ts +9 -0
  56. package/dist/components/SelectedOutlineSnapIndicators.js +29 -0
  57. package/dist/components/SelectedOutlineTransformOriginHandle.d.ts +9 -0
  58. package/dist/components/SelectedOutlineTransformOriginHandle.js +286 -0
  59. package/dist/components/SelectedOutlineUvControls.d.ts +3 -9
  60. package/dist/components/SelectedOutlineUvControls.js +57 -12
  61. package/dist/components/SettingsContext.d.ts +15 -0
  62. package/dist/components/SettingsContext.js +116 -0
  63. package/dist/components/SettingsModal.js +10 -4
  64. package/dist/components/SettingsModalFooter.d.ts +1 -3
  65. package/dist/components/SettingsModalFooter.js +4 -6
  66. package/dist/components/ShowOutlinesProvider.js +2 -3
  67. package/dist/components/Timeline/EasingEditorModal.js +66 -22
  68. package/dist/components/Timeline/Timeline.js +22 -5
  69. package/dist/components/Timeline/TimelineDuplicateCount.d.ts +4 -0
  70. package/dist/components/Timeline/TimelineDuplicateCount.js +28 -0
  71. package/dist/components/Timeline/TimelineExpandedKeyframeRow.js +3 -23
  72. package/dist/components/Timeline/TimelineExpandedTrackKeyframes.d.ts +4 -2
  73. package/dist/components/Timeline/TimelineExpandedTrackKeyframes.js +11 -1
  74. package/dist/components/Timeline/TimelineSequence.js +28 -25
  75. package/dist/components/Timeline/TimelineSequenceItem.js +49 -27
  76. package/dist/components/Timeline/TimelineTrack.js +2 -1
  77. package/dist/components/Timeline/get-sequence-context-menu-items.d.ts +6 -3
  78. package/dist/components/Timeline/get-sequence-context-menu-items.js +58 -53
  79. package/dist/components/Timeline/use-expanded-track-keyframe-rows.js +36 -4
  80. package/dist/components/Timeline/{use-open-sequence-in-editor.d.ts → use-open-sequence-in-apps.d.ts} +4 -1
  81. package/dist/components/Timeline/{use-open-sequence-in-editor.js → use-open-sequence-in-apps.js} +20 -4
  82. package/dist/components/Timeline/use-timeline-expanded-tree.d.ts +4 -0
  83. package/dist/components/Timeline/use-timeline-expanded-tree.js +45 -1
  84. package/dist/components/get-open-in-menu-items.d.ts +12 -0
  85. package/dist/components/get-open-in-menu-items.js +83 -0
  86. package/dist/components/selected-outline-measurement.d.ts +2 -2
  87. package/dist/components/selected-outline-order.d.ts +12 -0
  88. package/dist/components/selected-outline-order.js +251 -0
  89. package/dist/components/selected-outline-types.d.ts +9 -10
  90. package/dist/components/svg-point-to-client-point.d.ts +2 -0
  91. package/dist/components/svg-point-to-client-point.js +10 -0
  92. package/dist/components/use-auto-save-config.d.ts +8 -0
  93. package/dist/components/use-auto-save-config.js +74 -0
  94. package/dist/components/use-default-editor-info.d.ts +1 -0
  95. package/dist/components/use-default-editor-info.js +10 -30
  96. package/dist/esm/{chunk-jefhcs5z.js → chunk-fgedsvhb.js} +1 -2
  97. package/dist/esm/{chunk-b49ec3nz.js → chunk-ptnd65a9.js} +10602 -9364
  98. package/dist/esm/internals.mjs +10601 -9363
  99. package/dist/esm/previewEntry.mjs +10462 -9224
  100. package/dist/esm/renderEntry.mjs +2 -2
  101. package/dist/helpers/are-sequence-node-path-infos-equal.d.ts +2 -0
  102. package/dist/helpers/are-sequence-node-path-infos-equal.js +27 -0
  103. package/dist/helpers/calculate-timeline.js +3 -3
  104. package/dist/helpers/client-id.js +8 -1
  105. package/dist/helpers/format-file-location.d.ts +1 -1
  106. package/dist/helpers/format-file-location.js +3 -3
  107. package/dist/helpers/migrate-expanded-tracks-for-subscription-key.js +3 -3
  108. package/dist/helpers/open-in-editor.d.ts +1 -0
  109. package/dist/helpers/open-in-editor.js +5 -1
  110. package/dist/helpers/studio-runtime-config.js +3 -0
  111. package/dist/helpers/timeline-node-path-key.d.ts +2 -0
  112. package/dist/helpers/timeline-node-path-key.js +3 -1
  113. package/dist/helpers/use-asset-drag-events.d.ts +2 -1
  114. package/dist/helpers/use-asset-drag-events.js +14 -6
  115. package/dist/helpers/use-menu-structure.js +2 -2
  116. package/dist/helpers/use-runtime-values.d.ts +1 -3
  117. package/dist/state/timeline-sequence-hover.d.ts +9 -3
  118. package/dist/state/timeline-sequence-hover.js +63 -12
  119. package/package.json +12 -12
@@ -75,8 +75,9 @@ const SPRING_FALLBACKS = {
75
75
  stiffness: DEFAULT_SPRING_EASING.stiffness,
76
76
  };
77
77
  const inlineContainer = {
78
- width: '100%',
79
78
  minWidth: 0,
79
+ paddingBottom: 12,
80
+ width: '100%',
80
81
  };
81
82
  const segmentedControlWrapper = {
82
83
  display: 'flex',
@@ -85,27 +86,27 @@ const segmentedControlWrapper = {
85
86
  padding: `0 ${InspectorPanelLayout_1.INSPECTOR_PANEL_HORIZONTAL_PADDING}px`,
86
87
  };
87
88
  const presetButtonsWrapper = {
88
- display: 'flex',
89
- flexWrap: 'wrap',
90
- gap: 6,
91
- justifyContent: 'flex-start',
92
- marginBottom: 8,
93
- padding: `0 ${InspectorPanelLayout_1.INSPECTOR_PANEL_HORIZONTAL_PADDING}px`,
89
+ border: `1px solid ${colors_1.BLACK_ALPHA_60}`,
90
+ borderRadius: 4,
91
+ boxSizing: 'border-box',
92
+ display: 'grid',
93
+ gridTemplateColumns: 'repeat(4, minmax(0, 1fr))',
94
+ margin: `0 ${InspectorPanelLayout_1.INSPECTOR_PANEL_HORIZONTAL_PADDING}px 8px`,
95
+ overflow: 'hidden',
94
96
  };
95
97
  const inspectorPresetButtonsWrapper = {
96
98
  ...presetButtonsWrapper,
97
- padding: `8px ${InspectorPanelLayout_1.INSPECTOR_PANEL_HORIZONTAL_PADDING}px 0`,
99
+ margin: `8px ${InspectorPanelLayout_1.INSPECTOR_PANEL_HORIZONTAL_PADDING}px 0`,
98
100
  };
99
101
  const presetButtonBase = {
100
102
  alignItems: 'center',
101
- backgroundColor: colors_1.INPUT_BACKGROUND,
102
- border: `1px solid ${colors_1.WHITE_ALPHA_05}`,
103
- borderRadius: 4,
103
+ backgroundColor: colors_1.TRANSPARENT,
104
+ border: 'none',
104
105
  display: 'inline-flex',
105
106
  height: 34,
106
107
  justifyContent: 'center',
107
108
  padding: 0,
108
- width: 52,
109
+ width: '100%',
109
110
  };
110
111
  const presetPreviewSvgStyle = {
111
112
  display: 'block',
@@ -172,7 +173,10 @@ const easingToSpring = (easing) => {
172
173
  : DEFAULT_SPRING_EASING;
173
174
  };
174
175
  const easingToMode = (easing) => {
175
- return isSpringEasing(easing) ? 'spring' : 'bezier';
176
+ if (isSpringEasing(easing)) {
177
+ return 'spring';
178
+ }
179
+ return easing.type === 'step1' ? 'hold' : 'bezier';
176
180
  };
177
181
  const roundToDecimalPlaces = (value, decimalPlaces) => {
178
182
  const factor = 10 ** decimalPlaces;
@@ -243,6 +247,7 @@ const areEasingsEqual = (first, second) => {
243
247
  }
244
248
  switch (first.type) {
245
249
  case 'linear':
250
+ case 'step1':
246
251
  return true;
247
252
  case 'spring':
248
253
  return (second.type === 'spring' &&
@@ -322,6 +327,8 @@ const getEasingFunction = (easing) => {
322
327
  switch (easing.type) {
323
328
  case 'linear':
324
329
  return remotion_1.Easing.linear;
330
+ case 'step1':
331
+ return remotion_1.Easing.step1;
325
332
  case 'bezier':
326
333
  return remotion_1.Easing.bezier(easing.x1, easing.y1, easing.x2, easing.y2);
327
334
  case 'spring':
@@ -338,6 +345,13 @@ const getEasingFunction = (easing) => {
338
345
  }
339
346
  };
340
347
  const getPresetPreviewPath = (easing) => {
348
+ if (easing.type === 'step1') {
349
+ const startX = presetPreviewXToSvg(0);
350
+ const endX = presetPreviewXToSvg(1);
351
+ const startY = presetPreviewYToSvg(0);
352
+ const endY = presetPreviewYToSvg(1);
353
+ return `M ${startX} ${startY} L ${endX} ${startY} L ${endX} ${endY}`;
354
+ }
341
355
  const easingFunction = getEasingFunction(easing);
342
356
  const samples = 36;
343
357
  const points = [];
@@ -386,18 +400,24 @@ const EasingGraphScaffold = ({ labels }) => {
386
400
  };
387
401
  const EasingPresetButton = ({ currentEasing, disabled, onClick, preset }) => {
388
402
  const selected = areEasingsEqual(currentEasing, preset.easing);
403
+ const [hovered, setHovered] = (0, react_1.useState)(false);
389
404
  const path = (0, react_1.useMemo)(() => getPresetPreviewPath(preset.easing), [preset.easing]);
405
+ const onPointerEnter = (0, react_1.useCallback)(() => {
406
+ setHovered(true);
407
+ }, []);
408
+ const onPointerLeave = (0, react_1.useCallback)(() => {
409
+ setHovered(false);
410
+ }, []);
390
411
  const style = (0, react_1.useMemo)(() => ({
391
412
  ...presetButtonBase,
392
- backgroundColor: selected ? colors_1.EASING_SELECTED_BACKGROUND : colors_1.INPUT_BACKGROUND,
393
- borderColor: selected ? colors_1.BLUE : colors_1.WHITE_ALPHA_05,
394
- cursor: disabled ? 'not-allowed' : 'pointer',
413
+ backgroundColor: selected ? colors_1.INPUT_BACKGROUND : colors_1.TRANSPARENT,
414
+ cursor: disabled ? 'not-allowed' : undefined,
395
415
  opacity: disabled ? 0.45 : 1,
396
416
  }), [disabled, selected]);
397
417
  const handleClick = (0, react_1.useCallback)(() => {
398
418
  onClick(preset.easing);
399
419
  }, [onClick, preset.easing]);
400
- return (jsx_runtime_1.jsx("button", { type: "button", style: style, title: preset.label, "aria-label": `Apply ${preset.label} easing`, disabled: disabled, onClick: handleClick, children: jsx_runtime_1.jsx("svg", { width: PRESET_PREVIEW_WIDTH, height: PRESET_PREVIEW_HEIGHT, viewBox: `0 0 ${PRESET_PREVIEW_WIDTH} ${PRESET_PREVIEW_HEIGHT}`, style: presetPreviewSvgStyle, "aria-hidden": "true", focusable: false, children: jsx_runtime_1.jsx("path", { d: path, fill: "none", stroke: colors_1.WHITE, strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round" }) }) }));
420
+ return (jsx_runtime_1.jsx("button", { type: "button", style: style, title: preset.label, "aria-label": `Apply ${preset.label} easing`, disabled: disabled, onClick: handleClick, onPointerEnter: onPointerEnter, onPointerLeave: onPointerLeave, children: jsx_runtime_1.jsx("svg", { width: PRESET_PREVIEW_WIDTH, height: PRESET_PREVIEW_HEIGHT, viewBox: `0 0 ${PRESET_PREVIEW_WIDTH} ${PRESET_PREVIEW_HEIGHT}`, style: presetPreviewSvgStyle, "aria-hidden": "true", focusable: false, children: jsx_runtime_1.jsx("path", { d: path, fill: "none", stroke: selected || hovered ? colors_1.WHITE : colors_1.LIGHT_TEXT, strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round" }) }) }));
401
421
  };
402
422
  const EasingEditor = ({ state, renderHeader }) => {
403
423
  var _a, _b;
@@ -590,7 +610,9 @@ const EasingEditor = ({ state, renderHeader }) => {
590
610
  }
591
611
  const easing = nextMode === 'spring'
592
612
  ? serializeSpring(springRef.current)
593
- : serializeBezier(bezierRef.current);
613
+ : nextMode === 'hold'
614
+ ? studio_shared_1.HOLD_KEYFRAME_EASING
615
+ : serializeBezier(bezierRef.current);
594
616
  const version = applyLiveEasing(easing);
595
617
  commitEasing(easing, version);
596
618
  }, [applyLiveEasing, commitEasing, mode, previewServerState.type]);
@@ -605,11 +627,18 @@ const EasingEditor = ({ state, renderHeader }) => {
605
627
  commitEasing(serializeSpring(nextSpring), springVersion);
606
628
  return;
607
629
  }
630
+ if (easing.type === 'step1') {
631
+ setMode('hold');
632
+ const holdVersion = applyLiveEasing(studio_shared_1.HOLD_KEYFRAME_EASING);
633
+ commitEasing(studio_shared_1.HOLD_KEYFRAME_EASING, holdVersion);
634
+ return;
635
+ }
608
636
  const nextBezier = easingToBezier(easing);
609
637
  setMode('bezier');
610
638
  const bezierVersion = setBezierAndPreview(nextBezier);
611
639
  commitEasing(serializeBezier(nextBezier), bezierVersion);
612
640
  }, [
641
+ applyLiveEasing,
613
642
  commitEasing,
614
643
  previewServerState.type,
615
644
  setBezierAndPreview,
@@ -709,9 +738,15 @@ const EasingEditor = ({ state, renderHeader }) => {
709
738
  }
710
739
  return points.join(' ');
711
740
  }, [spring]);
741
+ const holdPath = (0, react_1.useMemo)(() => `M ${startPoint.x} ${startPoint.y} L ${endPoint.x} ${startPoint.y} L ${endPoint.x} ${endPoint.y}`, [endPoint, startPoint]);
712
742
  const disabled = previewServerState.type !== 'connected';
713
743
  const graphLabels = getEasingGraphLabels(getCurrentEasingUpdates());
714
- const currentEasing = (0, react_1.useMemo)(() => mode === 'spring' ? serializeSpring(spring) : serializeBezier(bezier), [bezier, mode, spring]);
744
+ const currentEasing = (0, react_1.useMemo)(() => {
745
+ if (mode === 'spring') {
746
+ return serializeSpring(spring);
747
+ }
748
+ return mode === 'hold' ? studio_shared_1.HOLD_KEYFRAME_EASING : serializeBezier(bezier);
749
+ }, [bezier, mode, spring]);
715
750
  const modeItems = (0, react_1.useMemo)(() => {
716
751
  return [
717
752
  {
@@ -726,12 +761,18 @@ const EasingEditor = ({ state, renderHeader }) => {
726
761
  onClick: () => switchMode('spring'),
727
762
  selected: mode === 'spring',
728
763
  },
764
+ {
765
+ key: 'hold',
766
+ label: 'Hold',
767
+ onClick: () => switchMode('hold'),
768
+ selected: mode === 'hold',
769
+ },
729
770
  ];
730
771
  }, [mode, switchMode]);
731
772
  const coordinatesGrid = (0, react_1.useMemo)(() => ({
732
773
  ...coordinatesGridBase,
733
774
  gridTemplateColumns: 'repeat(2, minmax(0, 1fr))',
734
- padding: '0 12px 12px',
775
+ padding: '0 12px',
735
776
  }), []);
736
777
  const modeSwitcher = (jsx_runtime_1.jsx("div", { style: segmentedControlWrapper, children: jsx_runtime_1.jsx(SegmentedControl_1.SegmentedControl, { items: modeItems, needsWrapping: false }) }));
737
778
  return (jsx_runtime_1.jsxs("div", { style: inlineContainer, children: [renderHeader ? renderHeader(modeItems) : null, jsx_runtime_1.jsx("div", { style: renderHeader ? inspectorPresetButtonsWrapper : presetButtonsWrapper, children: EDITOR_EASING_PRESETS.map((preset) => (jsx_runtime_1.jsx(EasingPresetButton, { currentEasing: currentEasing, disabled: disabled, onClick: applyPreset, preset: preset }, preset.id))) }), mode === 'bezier' ? (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [
@@ -748,7 +789,7 @@ const EasingEditor = ({ state, renderHeader }) => {
748
789
  jsx_runtime_1.jsx("div", { style: coordinateLabel, children: "Y2" }), jsx_runtime_1.jsx("div", { style: coordinateInputWrapper, children: jsx_runtime_1.jsx(InputDragger_1.InputDragger, { type: "number", value: bezier[3], status: "ok", onValueChange: (value) => setCoordinate(1, 'y', value, false), onValueChangeEnd: (value) => setCoordinate(1, 'y', value, true), onTextChange: () => undefined, min: Y_MIN, max: Y_MAX, step: 0.01, formatter: formatNumber, rightAlign: false, style: numberInputStyle, snapToStep: false, disabled: disabled }) })
749
790
  ] })
750
791
  ] })
751
- ] })) : (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [
792
+ ] })) : mode === 'spring' ? (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [
752
793
  jsx_runtime_1.jsxs("svg", { width: SVG_WIDTH, height: SVG_HEIGHT, viewBox: `0 0 ${SVG_WIDTH} ${SVG_HEIGHT}`, style: svgStyle, "aria-label": "Spring easing curve", children: [
753
794
  jsx_runtime_1.jsx(EasingGraphScaffold, { labels: graphLabels }), jsx_runtime_1.jsx("path", { d: springPath, fill: "none", stroke: colors_1.BLUE, strokeWidth: 3 }), jsx_runtime_1.jsx("circle", { cx: xToSvg(0), cy: yToSvg(0), r: 4, fill: colors_1.WHITE }), jsx_runtime_1.jsx("circle", { cx: xToSvg(1), cy: yToSvg(1), r: 4, fill: colors_1.WHITE })
754
795
  ] }), modeSwitcher, jsx_runtime_1.jsxs("div", { style: coordinatesGrid, children: [
@@ -766,6 +807,9 @@ const EasingEditor = ({ state, renderHeader }) => {
766
807
  jsx_runtime_1.jsx("div", { style: coordinateLabel, children: "Allow tail" }), jsx_runtime_1.jsx("div", { style: checkboxWrapper, children: jsx_runtime_1.jsx(Checkbox_1.Checkbox, { checked: (_b = spring.allowTail) !== null && _b !== void 0 ? _b : false, onChange: setAllowTail, name: "spring-allow-tail", disabled: disabled, variant: "small" }) })
767
808
  ] })
768
809
  ] })
769
- ] }))] }));
810
+ ] })) : (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [
811
+ jsx_runtime_1.jsxs("svg", { width: SVG_WIDTH, height: SVG_HEIGHT, viewBox: `0 0 ${SVG_WIDTH} ${SVG_HEIGHT}`, style: svgStyle, "aria-label": "Hold easing curve", children: [
812
+ jsx_runtime_1.jsx(EasingGraphScaffold, { labels: graphLabels }), jsx_runtime_1.jsx("path", { d: holdPath, fill: "none", stroke: colors_1.BLUE, strokeWidth: 3 }), jsx_runtime_1.jsx("circle", { cx: startPoint.x, cy: startPoint.y, r: 4, fill: colors_1.WHITE }), jsx_runtime_1.jsx("circle", { cx: endPoint.x, cy: endPoint.y, r: 4, fill: colors_1.WHITE })
813
+ ] }), modeSwitcher] }))] }));
770
814
  };
771
815
  exports.EasingEditor = EasingEditor;
@@ -45,6 +45,7 @@ const interactivity_enabled_1 = require("../../helpers/interactivity-enabled");
45
45
  const is_current_selected_still_1 = require("../../helpers/is-current-selected-still");
46
46
  const open_in_editor_1 = require("../../helpers/open-in-editor");
47
47
  const studio_runtime_config_1 = require("../../helpers/studio-runtime-config");
48
+ const timeline_node_path_key_1 = require("../../helpers/timeline-node-path-key");
48
49
  const call_api_1 = require("../call-api");
49
50
  const ContextMenu_1 = require("../ContextMenu");
50
51
  const import_assets_1 = require("../import-assets");
@@ -256,13 +257,29 @@ const TimelineInner = () => {
256
257
  const filtered = (0, react_1.useMemo)(() => {
257
258
  return timeline.filter((t) => (0, should_show_track_in_timeline_1.shouldShowTrackInTimeline)(t, durationInFrames));
258
259
  }, [durationInFrames, timeline]);
260
+ // Keep `filtered` complete so a future toggle can show every programmatic
261
+ // instance without recalculating the timeline or losing its instance index.
262
+ const collapsed = (0, react_1.useMemo)(() => {
263
+ const seenNodePaths = new Set();
264
+ return filtered.filter((track) => {
265
+ if (track.nodePathInfo === null) {
266
+ return true;
267
+ }
268
+ const key = (0, timeline_node_path_key_1.timelineSequenceNodePathToKey)(track.nodePathInfo.sequenceSubscriptionKey);
269
+ if (seenNodePaths.has(key)) {
270
+ return false;
271
+ }
272
+ seenNodePaths.add(key);
273
+ return true;
274
+ });
275
+ }, [filtered]);
259
276
  const maxTimelineTracks = (0, studio_runtime_config_1.getStudioMaxTimelineTracks)();
260
277
  const shown = (0, react_1.useMemo)(() => {
261
- return filtered.length > maxTimelineTracks
262
- ? filtered.slice(0, maxTimelineTracks)
263
- : filtered;
264
- }, [filtered, maxTimelineTracks]);
265
- const hasBeenCut = filtered.length > shown.length;
278
+ return collapsed.length > maxTimelineTracks
279
+ ? collapsed.slice(0, maxTimelineTracks)
280
+ : collapsed;
281
+ }, [collapsed, maxTimelineTracks]);
282
+ const hasBeenCut = collapsed.length > shown.length;
266
283
  return (jsx_runtime_1.jsxs(TimelineContextMenuArea, { children: [sequences.map((sequence) => {
267
284
  if (!(0, should_subscribe_to_sequence_props_1.shouldSubscribeToSequenceProps)(sequence, previewInteractive)) {
268
285
  return null;
@@ -0,0 +1,4 @@
1
+ import React from 'react';
2
+ export declare const TimelineDuplicateCount: React.FC<{
3
+ readonly count: number;
4
+ }>;
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TimelineDuplicateCount = void 0;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const colors_1 = require("../../helpers/colors");
6
+ const badgeStyle = {
7
+ alignItems: 'center',
8
+ border: `1px solid ${colors_1.WHITE_ALPHA_20}`,
9
+ borderRadius: 4,
10
+ boxSizing: 'border-box',
11
+ color: colors_1.WHITE_ALPHA_60,
12
+ display: 'inline-flex',
13
+ flexShrink: 0,
14
+ fontSize: 10,
15
+ fontWeight: 300,
16
+ height: 14,
17
+ justifyContent: 'center',
18
+ lineHeight: '12px',
19
+ minWidth: 18,
20
+ padding: '0 3px',
21
+ userSelect: 'none',
22
+ WebkitUserSelect: 'none',
23
+ };
24
+ const TimelineDuplicateCount = ({ count }) => {
25
+ const label = `${count} other programmatically duplicated ${count === 1 ? 'instance is' : 'instances are'} hidden`;
26
+ return (jsx_runtime_1.jsxs("span", { style: badgeStyle, title: label, "aria-label": label, children: ["+", count] }));
27
+ };
28
+ exports.TimelineDuplicateCount = TimelineDuplicateCount;
@@ -35,8 +35,8 @@ var __importStar = (this && this.__importStar) || (function () {
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.TimelineExpandedKeyframeRow = void 0;
37
37
  const jsx_runtime_1 = require("react/jsx-runtime");
38
- const studio_shared_1 = require("@remotion/studio-shared");
39
38
  const react_1 = __importStar(require("react"));
39
+ const are_sequence_node_path_infos_equal_1 = require("../../helpers/are-sequence-node-path-infos-equal");
40
40
  const timeline_layout_1 = require("../../helpers/timeline-layout");
41
41
  const get_timeline_easing_segments_1 = require("./get-timeline-easing-segments");
42
42
  const TimelineKeyframeDiamond_1 = require("./TimelineKeyframeDiamond");
@@ -71,29 +71,9 @@ const areTimelineExpandedKeyframeRowPropsEqual = (prevProps, nextProps) => {
71
71
  prevProps.canEditEasing !== nextProps.canEditEasing ||
72
72
  prevProps.showSeparator !== nextProps.showSeparator ||
73
73
  prevProps.keyframes.length !== nextProps.keyframes.length ||
74
- prevProps.nodePathInfo.index !== nextProps.nodePathInfo.index ||
75
- prevProps.nodePathInfo.numberOfSequencesWithThisNodePath !==
76
- nextProps.nodePathInfo.numberOfSequencesWithThisNodePath ||
77
- prevProps.nodePathInfo.supportsEffects !==
78
- nextProps.nodePathInfo.supportsEffects ||
79
- (0, studio_shared_1.stringifySequenceSubscriptionKey)(prevProps.nodePathInfo.sequenceSubscriptionKey) !==
80
- (0, studio_shared_1.stringifySequenceSubscriptionKey)(nextProps.nodePathInfo.sequenceSubscriptionKey) ||
81
- prevProps.nodePathInfo.auxiliaryKeys.length !==
82
- nextProps.nodePathInfo.auxiliaryKeys.length) {
74
+ !(0, are_sequence_node_path_infos_equal_1.areSequenceNodePathInfosEqual)(prevProps.nodePathInfo, nextProps.nodePathInfo)) {
83
75
  return false;
84
76
  }
85
- const prevVideoConfig = prevProps.nodePathInfo.sequenceSubscriptionKey.videoConfigValues;
86
- const nextVideoConfig = nextProps.nodePathInfo.sequenceSubscriptionKey.videoConfigValues;
87
- if (prevVideoConfig !== nextVideoConfig &&
88
- (prevVideoConfig === null ||
89
- nextVideoConfig === null ||
90
- prevVideoConfig.durationInFrames !== nextVideoConfig.durationInFrames ||
91
- prevVideoConfig.fps !== nextVideoConfig.fps ||
92
- prevVideoConfig.height !== nextVideoConfig.height ||
93
- prevVideoConfig.width !== nextVideoConfig.width)) {
94
- return false;
95
- }
96
- return (prevProps.keyframes.every((keyframe, index) => keyframe.frame === nextProps.keyframes[index].frame) &&
97
- prevProps.nodePathInfo.auxiliaryKeys.every((key, index) => key === nextProps.nodePathInfo.auxiliaryKeys[index]));
77
+ return prevProps.keyframes.every((keyframe, index) => keyframe.frame === nextProps.keyframes[index].frame);
98
78
  };
99
79
  exports.TimelineExpandedKeyframeRow = react_1.default.memo(TimelineExpandedKeyframeRowUnmemoized, areTimelineExpandedKeyframeRowPropsEqual);
@@ -1,8 +1,10 @@
1
1
  import React from 'react';
2
2
  import type { TSequence } from 'remotion';
3
3
  import type { SequenceNodePathInfo } from '../../helpers/get-timeline-sequence-sort-key';
4
- export declare const TimelineExpandedTrackKeyframes: React.NamedExoticComponent<{
4
+ type TimelineExpandedTrackKeyframesProps = {
5
5
  readonly sequence: TSequence;
6
6
  readonly nodePathInfo: SequenceNodePathInfo;
7
7
  readonly keyframeDisplayOffset: number;
8
- }>;
8
+ };
9
+ export declare const TimelineExpandedTrackKeyframes: React.NamedExoticComponent<TimelineExpandedTrackKeyframesProps>;
10
+ export {};
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.TimelineExpandedTrackKeyframes = void 0;
7
7
  const jsx_runtime_1 = require("react/jsx-runtime");
8
8
  const react_1 = __importDefault(require("react"));
9
+ const are_sequence_node_path_infos_equal_1 = require("../../helpers/are-sequence-node-path-infos-equal");
9
10
  const TimelineExpandedKeyframeRow_1 = require("./TimelineExpandedKeyframeRow");
10
11
  const use_expanded_track_keyframe_rows_1 = require("./use-expanded-track-keyframe-rows");
11
12
  const TimelineExpandedTrackKeyframesInner = ({ nodePathInfo, sequence, keyframeDisplayOffset }) => {
@@ -16,4 +17,13 @@ const TimelineExpandedTrackKeyframesInner = ({ nodePathInfo, sequence, keyframeD
16
17
  });
17
18
  return (jsx_runtime_1.jsx("div", { style: { height: expandedHeight }, children: rows.map((row, index) => (jsx_runtime_1.jsx(TimelineExpandedKeyframeRow_1.TimelineExpandedKeyframeRow, { height: row.height, keyframes: row.keyframes, canEditEasing: row.canEditEasing, nodePathInfo: row.nodePathInfo, showSeparator: index > 0 }, row.rowKey))) }));
18
19
  };
19
- exports.TimelineExpandedTrackKeyframes = react_1.default.memo(TimelineExpandedTrackKeyframesInner);
20
+ const areTimelineExpandedTrackKeyframesPropsEqual = (first, second) => {
21
+ var _a, _b, _c, _d;
22
+ return (first.keyframeDisplayOffset === second.keyframeDisplayOffset &&
23
+ ((_a = first.sequence.controls) === null || _a === void 0 ? void 0 : _a.schema) === ((_b = second.sequence.controls) === null || _b === void 0 ? void 0 : _b.schema) &&
24
+ ((_c = first.sequence.controls) === null || _c === void 0 ? void 0 : _c.runtimeValues) ===
25
+ ((_d = second.sequence.controls) === null || _d === void 0 ? void 0 : _d.runtimeValues) &&
26
+ first.sequence.effects === second.sequence.effects &&
27
+ (0, are_sequence_node_path_infos_equal_1.areSequenceNodePathInfosEqual)(first.nodePathInfo, second.nodePathInfo));
28
+ };
29
+ exports.TimelineExpandedTrackKeyframes = react_1.default.memo(TimelineExpandedTrackKeyframesInner, areTimelineExpandedTrackKeyframesPropsEqual);
@@ -39,21 +39,19 @@ const react_1 = __importStar(require("react"));
39
39
  const remotion_1 = require("remotion");
40
40
  const client_id_1 = require("../../helpers/client-id");
41
41
  const colors_1 = require("../../helpers/colors");
42
- const format_file_location_1 = require("../../helpers/format-file-location");
43
42
  const get_sequence_double_click_action_1 = require("../../helpers/get-sequence-double-click-action");
44
43
  const get_timeline_sequence_layout_1 = require("../../helpers/get-timeline-sequence-layout");
45
44
  const interactivity_enabled_1 = require("../../helpers/interactivity-enabled");
46
45
  const is_video_with_last_frame_hold_1 = require("../../helpers/is-video-with-last-frame-hold");
47
- const open_in_editor_1 = require("../../helpers/open-in-editor");
48
46
  const timeline_layout_1 = require("../../helpers/timeline-layout");
49
47
  const use_max_media_duration_1 = require("../../helpers/use-max-media-duration");
48
+ const modals_1 = require("../../state/modals");
50
49
  const AudioWaveform_1 = require("../AudioWaveform");
51
50
  const call_api_1 = require("../call-api");
52
51
  const ConfirmationDialog_1 = require("../ConfirmationDialog");
53
52
  const ContextMenu_1 = require("../ContextMenu");
54
53
  const InitialCompositionLoader_1 = require("../InitialCompositionLoader");
55
54
  const NotificationCenter_1 = require("../Notifications/NotificationCenter");
56
- const use_default_editor_info_1 = require("../use-default-editor-info");
57
55
  const use_select_asset_1 = require("../use-select-asset");
58
56
  const disable_sequence_interactivity_1 = require("./disable-sequence-interactivity");
59
57
  const duplicate_selected_timeline_item_1 = require("./duplicate-selected-timeline-item");
@@ -68,7 +66,7 @@ const TimelineSequenceFrame_1 = require("./TimelineSequenceFrame");
68
66
  const TimelineSequenceRightEdgeDragHandle_1 = require("./TimelineSequenceRightEdgeDragHandle");
69
67
  const TimelineVideoInfo_1 = require("./TimelineVideoInfo");
70
68
  const TimelineWidthProvider_1 = require("./TimelineWidthProvider");
71
- const use_resolved_stack_react_to_change_1 = require("./use-resolved-stack-react-to-change");
69
+ const use_open_sequence_in_apps_1 = require("./use-open-sequence-in-apps");
72
70
  const use_sequence_freeze_frame_menu_item_1 = require("./use-sequence-freeze-frame-menu-item");
73
71
  const TimelineSequenceFn = ({ s, connectedCompositions, nodePathInfo, sequenceFrameOffset }) => {
74
72
  const windowWidth = (0, react_1.useContext)(TimelineWidthProvider_1.TimelineWidthContext);
@@ -159,12 +157,12 @@ const TimelineSequenceInner = ({ s, connectedCompositions, windowWidth, nodePath
159
157
  // Some compositions may not be longer than their media duration,
160
158
  // if that is the case, it needs to be asynchronously determined
161
159
  var _a, _b, _c;
162
- var _d, _e, _f, _g, _h;
160
+ var _d, _e, _f, _g, _h, _j;
163
161
  const video = remotion_1.Internals.useVideo();
164
162
  const maxMediaDuration = (0, use_max_media_duration_1.useMaxMediaDuration)(s, (_d = video === null || video === void 0 ? void 0 : video.fps) !== null && _d !== void 0 ? _d : 30);
165
163
  const effectiveMaxMediaDuration = s.loopDisplay ? null : maxMediaDuration;
166
164
  const extendVideoLastFrame = (0, is_video_with_last_frame_hold_1.isVideoWithLastFrameHold)(s);
167
- const originalLocation = (0, use_resolved_stack_react_to_change_1.useResolveStackAndReactToChange)(s.getStack);
165
+ const { canOpenInEditor, canConfigureApps, codingAgentInfo, editorInfo, openInCodingAgent, openInEditor, originalLocation, } = (0, use_open_sequence_in_apps_1.useOpenSequenceInApps)(s);
168
166
  const validatedLocation = (0, react_1.useMemo)(() => {
169
167
  var _a;
170
168
  if (!originalLocation ||
@@ -199,25 +197,12 @@ const TimelineSequenceInner = ({ s, connectedCompositions, windowWidth, nodePath
199
197
  const { previewServerState } = (0, react_1.useContext)(client_id_1.StudioServerConnectionCtx);
200
198
  const previewConnected = previewServerState.type === 'connected';
201
199
  const previewInteractive = previewConnected && (0, interactivity_enabled_1.isStudioInteractivityEnabled)();
202
- const editorInfo = (0, use_default_editor_info_1.useDefaultEditorInfo)((0, use_default_editor_info_1.canUseEditorPicker)(previewConnected));
203
200
  const { setPropStatuses } = (0, react_1.useContext)(remotion_1.Internals.VisualModeSettersContext);
201
+ const { setSelectedModal } = (0, react_1.useContext)(modals_1.SetSelectedModalContext);
204
202
  const selectAsset = (0, use_select_asset_1.useSelectAsset)();
205
203
  const selectComposition = (0, InitialCompositionLoader_1.useSelectComposition)();
206
204
  const confirm = (0, ConfirmationDialog_1.useConfirmationDialog)();
207
205
  const { onSelect, selectable } = (0, TimelineSelection_1.useTimelineRowSelection)(nodePathInfo);
208
- const fileLocation = (0, react_1.useMemo)(() => (0, format_file_location_1.formatFileLocation)({
209
- location: originalLocation,
210
- root: window.remotion_cwd,
211
- }), [originalLocation]);
212
- const canOpenInEditor = Boolean(window.remotion_editorName && previewConnected && originalLocation);
213
- const openInEditor = (0, react_1.useCallback)((editorId) => {
214
- if (!canOpenInEditor || !originalLocation) {
215
- return;
216
- }
217
- (0, open_in_editor_1.openOriginalPositionInEditor)(originalLocation, editorId).catch((err) => {
218
- (0, NotificationCenter_1.showNotification)(err.message, 2000);
219
- });
220
- }, [canOpenInEditor, originalLocation]);
221
206
  const onSequenceDoubleClick = (0, react_1.useCallback)((e) => {
222
207
  if ((0, TimelineSelection_1.isTimelineSelectionModifierEvent)(e)) {
223
208
  e.stopPropagation();
@@ -253,7 +238,8 @@ const TimelineSequenceInner = ({ s, connectedCompositions, windowWidth, nodePath
253
238
  const canHandleSequenceDoubleClick = connectedCompositions.length === 1 || canOpenInEditor;
254
239
  const canDeleteFromSource = Boolean(nodePath && (validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.source));
255
240
  const deleteDisabled = !previewInteractive || !s.controls || !canDeleteFromSource;
256
- const duplicateDisabled = deleteDisabled;
241
+ const isProgrammaticallyDuplicated = ((_f = nodePathInfo === null || nodePathInfo === void 0 ? void 0 : nodePathInfo.numberOfSequencesWithThisNodePath) !== null && _f !== void 0 ? _f : 1) > 1;
242
+ const duplicateDisabled = deleteDisabled || isProgrammaticallyDuplicated;
257
243
  const disableInteractivityDisabled = !previewInteractive ||
258
244
  !s.showInTimeline ||
259
245
  !nodePath ||
@@ -346,15 +332,28 @@ const TimelineSequenceInner = ({ s, connectedCompositions, windowWidth, nodePath
346
332
  return (0, get_sequence_context_menu_items_1.getSequenceContextMenuItems)({
347
333
  assetLinkInfo: mediaSrc ? (0, timeline_asset_link_1.getTimelineAssetLinkInfo)(mediaSrc) : null,
348
334
  canOpenInEditor,
335
+ codingAgentInfo,
349
336
  deleteDisabled,
350
337
  disableInteractivityDisabled,
351
338
  duplicateDisabled,
352
339
  editorInfo,
353
- fileLocation,
354
340
  includeSourceEditItems: (0, interactivity_enabled_1.isStudioInteractivityEnabled)(),
341
+ isProgrammaticallyDuplicated,
342
+ onConfigureApps: canConfigureApps
343
+ ? () => {
344
+ var _a;
345
+ var _b;
346
+ setSelectedModal({
347
+ type: 'settings',
348
+ initialTab: 'apps',
349
+ initialPublicLicenseKey: (_b = (_a = window.remotion_renderDefaults) === null || _a === void 0 ? void 0 : _a.publicLicenseKey) !== null && _b !== void 0 ? _b : null,
350
+ });
351
+ }
352
+ : null,
355
353
  onDeleteSequenceFromSource,
356
354
  onDisableSequenceInteractivity,
357
355
  onDuplicateSequenceFromSource,
356
+ openInCodingAgent,
358
357
  openInEditor,
359
358
  originalLocation,
360
359
  selectAsset,
@@ -365,17 +364,20 @@ const TimelineSequenceInner = ({ s, connectedCompositions, windowWidth, nodePath
365
364
  });
366
365
  }, [
367
366
  canOpenInEditor,
367
+ canConfigureApps,
368
+ codingAgentInfo,
368
369
  deleteDisabled,
369
370
  disableInteractivityDisabled,
370
371
  duplicateDisabled,
371
372
  editorInfo,
372
- fileLocation,
373
+ isProgrammaticallyDuplicated,
373
374
  mediaSrc,
374
375
  nodePath,
375
376
  onSelect,
376
377
  onDeleteSequenceFromSource,
377
378
  onDisableSequenceInteractivity,
378
379
  onDuplicateSequenceFromSource,
380
+ openInCodingAgent,
379
381
  openInEditor,
380
382
  originalLocation,
381
383
  previewInteractive,
@@ -386,13 +388,14 @@ const TimelineSequenceInner = ({ s, connectedCompositions, windowWidth, nodePath
386
388
  selectable,
387
389
  sequenceFrameOffset,
388
390
  setPropStatuses,
391
+ setSelectedModal,
389
392
  validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.source,
390
393
  ]);
391
394
  const { frozenFrame } = s;
392
395
  const { onPointerDown: onMoveDragPointerDown } = (0, TimelineSequenceRightEdgeDragHandle_1.useTimelineSequenceFromDrag)({
393
396
  nodePathInfo,
394
397
  windowWidth,
395
- timelineDurationInFrames: (_f = video === null || video === void 0 ? void 0 : video.durationInFrames) !== null && _f !== void 0 ? _f : 1,
398
+ timelineDurationInFrames: (_g = video === null || video === void 0 ? void 0 : video.durationInFrames) !== null && _g !== void 0 ? _g : 1,
396
399
  });
397
400
  if (!video) {
398
401
  throw new TypeError('Expected video config');
@@ -464,7 +467,7 @@ const TimelineSequenceInner = ({ s, connectedCompositions, windowWidth, nodePath
464
467
  if (maxMediaDuration === null && !s.loopDisplay) {
465
468
  return null;
466
469
  }
467
- const sequence = (jsx_runtime_1.jsxs(TimelineSequenceCurrentFrame, { s: s, displayDurationInFrames: displayDurationInFrames, premountWidth: premountWidth, postmountWidth: postmountWidth, style: style, nodePathInfo: nodePathInfo, sequenceFrameOffset: sequenceFrameOffset, fromCanUpdate: fromCanUpdate, frozenFrame: frozenFrame, onMoveDragPointerDown: onMoveDragPointerDown, onDoubleClick: canHandleSequenceDoubleClick ? onSequenceDoubleClick : undefined, children: [s.type === 'audio' ? (jsx_runtime_1.jsx("div", { style: mediaVisualizationStyle, children: jsx_runtime_1.jsx(AudioWaveform_1.AudioWaveform, { src: s.src, height: timeline_layout_1.TIMELINE_LAYER_HEIGHT_AUDIO, doesVolumeChange: s.doesVolumeChange, visualizationWidth: mediaVisualizationLayout.width, startFrom: s.startMediaFrom, durationInFrames: s.duration, volume: s.volume, playbackRate: s.playbackRate, loopDisplay: s.loopDisplay }) })) : null, s.type === 'video' ? (jsx_runtime_1.jsx(TimelineVideoInfo_1.TimelineVideoInfo, { src: s.src, visualizationWidth: width, naturalWidth: naturalWidth, startMediaFrom: s.startMediaFrom, mediaFrameAtSequenceZero: s.mediaFrameAtSequenceZero, sequenceFrameOffset: sequenceFrameOffset, durationInFrames: s.duration, playbackRate: s.playbackRate, volume: s.volume, doesVolumeChange: s.doesVolumeChange, premountWidth: premountWidth !== null && premountWidth !== void 0 ? premountWidth : 0, postmountWidth: postmountWidth !== null && postmountWidth !== void 0 ? postmountWidth : 0, loopDisplay: s.loopDisplay, frozenMediaFrame: s.frozenMediaFrame, extendLastFrame: extendVideoLastFrame })) : null, s.type === 'image' ? (jsx_runtime_1.jsx("div", { style: mediaVisualizationStyle, children: jsx_runtime_1.jsx(TimelineImageInfo_1.TimelineImageInfo, { src: s.src, visualizationWidth: mediaVisualizationLayout.width }) })) : null, s.loopDisplay === undefined ? null : (jsx_runtime_1.jsx(LoopedTimelineIndicators_1.LoopedTimelineIndicator, { loops: s.loopDisplay.numberOfTimes })), showLeftEdgeDragHandle && nodePathInfo && validatedLocation ? (jsx_runtime_1.jsx(TimelineSequenceRightEdgeDragHandle_1.TimelineSequenceLeftEdgeDragHandle, { nodePathInfo: nodePathInfo, windowWidth: windowWidth, timelineDurationInFrames: (_g = video.durationInFrames) !== null && _g !== void 0 ? _g : 1 })) : null, showRightEdgeDragHandle && nodePathInfo && validatedLocation ? (jsx_runtime_1.jsx(TimelineSequenceRightEdgeDragHandle_1.TimelineSequenceRightEdgeDragHandle, { nodePathInfo: nodePathInfo, windowWidth: windowWidth, timelineDurationInFrames: (_h = video.durationInFrames) !== null && _h !== void 0 ? _h : 1 })) : null] }));
470
+ const sequence = (jsx_runtime_1.jsxs(TimelineSequenceCurrentFrame, { s: s, displayDurationInFrames: displayDurationInFrames, premountWidth: premountWidth, postmountWidth: postmountWidth, style: style, nodePathInfo: nodePathInfo, sequenceFrameOffset: sequenceFrameOffset, fromCanUpdate: fromCanUpdate, frozenFrame: frozenFrame, onMoveDragPointerDown: onMoveDragPointerDown, onDoubleClick: canHandleSequenceDoubleClick ? onSequenceDoubleClick : undefined, children: [s.type === 'audio' ? (jsx_runtime_1.jsx("div", { style: mediaVisualizationStyle, children: jsx_runtime_1.jsx(AudioWaveform_1.AudioWaveform, { src: s.src, height: timeline_layout_1.TIMELINE_LAYER_HEIGHT_AUDIO, doesVolumeChange: s.doesVolumeChange, visualizationWidth: mediaVisualizationLayout.width, startFrom: s.startMediaFrom, durationInFrames: s.duration, volume: s.volume, playbackRate: s.playbackRate, loopDisplay: s.loopDisplay }) })) : null, s.type === 'video' ? (jsx_runtime_1.jsx(TimelineVideoInfo_1.TimelineVideoInfo, { src: s.src, visualizationWidth: width, naturalWidth: naturalWidth, startMediaFrom: s.startMediaFrom, mediaFrameAtSequenceZero: s.mediaFrameAtSequenceZero, sequenceFrameOffset: sequenceFrameOffset, durationInFrames: s.duration, playbackRate: s.playbackRate, volume: s.volume, doesVolumeChange: s.doesVolumeChange, premountWidth: premountWidth !== null && premountWidth !== void 0 ? premountWidth : 0, postmountWidth: postmountWidth !== null && postmountWidth !== void 0 ? postmountWidth : 0, loopDisplay: s.loopDisplay, frozenMediaFrame: s.frozenMediaFrame, extendLastFrame: extendVideoLastFrame })) : null, s.type === 'image' ? (jsx_runtime_1.jsx("div", { style: mediaVisualizationStyle, children: jsx_runtime_1.jsx(TimelineImageInfo_1.TimelineImageInfo, { src: s.src, visualizationWidth: mediaVisualizationLayout.width }) })) : null, s.loopDisplay === undefined ? null : (jsx_runtime_1.jsx(LoopedTimelineIndicators_1.LoopedTimelineIndicator, { loops: s.loopDisplay.numberOfTimes })), showLeftEdgeDragHandle && nodePathInfo && validatedLocation ? (jsx_runtime_1.jsx(TimelineSequenceRightEdgeDragHandle_1.TimelineSequenceLeftEdgeDragHandle, { nodePathInfo: nodePathInfo, windowWidth: windowWidth, timelineDurationInFrames: (_h = video.durationInFrames) !== null && _h !== void 0 ? _h : 1 })) : null, showRightEdgeDragHandle && nodePathInfo && validatedLocation ? (jsx_runtime_1.jsx(TimelineSequenceRightEdgeDragHandle_1.TimelineSequenceRightEdgeDragHandle, { nodePathInfo: nodePathInfo, windowWidth: windowWidth, timelineDurationInFrames: (_j = video.durationInFrames) !== null && _j !== void 0 ? _j : 1 })) : null] }));
468
471
  return previewConnected || window.remotion_isReadOnlyStudio ? (jsx_runtime_1.jsx(ContextMenu_1.ContextMenu, { getItems: getContextMenuItems, children: sequence })) : (sequence);
469
472
  };
470
473
  exports.TimelineSequence = react_1.default.memo(TimelineSequenceFn);