@remotion/studio 4.0.521 → 4.0.522

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 (60) hide show
  1. package/dist/components/CanvasIfSizeIsAvailable.js +7 -0
  2. package/dist/components/CopyButton.js +7 -14
  3. package/dist/components/Editor.js +6 -5
  4. package/dist/components/EditorContent.js +1 -1
  5. package/dist/components/ElementInstallConfirmation.js +3 -1
  6. package/dist/components/FixComputedValueModal.js +20 -10
  7. package/dist/components/InspectorLocationCopy.js +10 -5
  8. package/dist/components/MenuBuildIndicator.js +7 -2
  9. package/dist/components/MenuCompositionName.js +62 -6
  10. package/dist/components/RenderModal/CliCopyButton.js +13 -27
  11. package/dist/components/RenderQueue/RenderQueueCopyToClipboard.js +7 -4
  12. package/dist/components/SidebarCollapserControls.js +11 -5
  13. package/dist/components/SkillsSettings.js +9 -5
  14. package/dist/components/Splitter/SplitterContainer.js +63 -10
  15. package/dist/components/Splitter/SplitterContext.d.ts +3 -0
  16. package/dist/components/Splitter/SplitterContext.js +5 -1
  17. package/dist/components/Splitter/SplitterElement.js +11 -2
  18. package/dist/components/Splitter/SplitterHandle.d.ts +1 -0
  19. package/dist/components/Splitter/SplitterHandle.js +55 -25
  20. package/dist/components/Timeline/SubscribeToNodePaths.d.ts +2 -1
  21. package/dist/components/Timeline/SubscribeToNodePaths.js +2 -1
  22. package/dist/components/Timeline/Timeline.js +15 -4
  23. package/dist/components/Timeline/TimelineDragHandler.js +9 -4
  24. package/dist/components/Timeline/TimelinePinchZoom.js +6 -30
  25. package/dist/components/Timeline/TimelinePlayCursorSyncer.js +1 -7
  26. package/dist/components/Timeline/TimelineSequence.js +77 -12
  27. package/dist/components/Timeline/TimelineSequenceItem.js +12 -1
  28. package/dist/components/Timeline/TimelineSequenceRightEdgeDragHandle.d.ts +13 -3
  29. package/dist/components/Timeline/TimelineSequenceRightEdgeDragHandle.js +168 -121
  30. package/dist/components/Timeline/TimelineSlider.js +1 -4
  31. package/dist/components/Timeline/TimelineWidthProvider.js +2 -5
  32. package/dist/components/Timeline/TimelineZoomControls.js +20 -20
  33. package/dist/components/Timeline/get-sequence-split-menu-item.d.ts +11 -0
  34. package/dist/components/Timeline/get-sequence-split-menu-item.js +55 -0
  35. package/dist/components/Timeline/use-sequence-props-subscription.d.ts +3 -2
  36. package/dist/components/Timeline/use-sequence-props-subscription.js +4 -10
  37. package/dist/components/TopPanel.js +3 -19
  38. package/dist/components/UpdatesSettings.js +9 -5
  39. package/dist/components/ZoomPersistor.js +6 -3
  40. package/dist/components/composition-menu-items.js +1 -1
  41. package/dist/esm/{chunk-emw4k5b0.js → chunk-3netyjd9.js} +4917 -4651
  42. package/dist/esm/internals.mjs +4917 -4651
  43. package/dist/esm/previewEntry.mjs +4895 -4629
  44. package/dist/esm/renderEntry.mjs +1 -1
  45. package/dist/helpers/copy-text.js +1 -2
  46. package/dist/helpers/use-copy-feedback.d.ts +4 -0
  47. package/dist/helpers/use-copy-feedback.js +19 -0
  48. package/dist/icons/copy.d.ts +5 -0
  49. package/dist/icons/copy.js +12 -0
  50. package/dist/state/canvas-ref.d.ts +1 -0
  51. package/dist/state/canvas-ref.js +2 -1
  52. package/dist/state/sidebar.d.ts +3 -0
  53. package/dist/state/sidebar.js +6 -1
  54. package/dist/state/timeline-zoom.d.ts +1 -1
  55. package/dist/state/timeline-zoom.js +3 -3
  56. package/dist/visual-controls/VisualControls.js +4 -0
  57. package/package.json +15 -15
  58. package/dist/esm/chunk-vkrvnx2h.js +0 -99378
  59. package/dist/helpers/use-max-media-duration.d.ts +0 -2
  60. package/dist/helpers/use-max-media-duration.js +0 -61
@@ -51,7 +51,20 @@ const save_sequence_prop_1 = require("./save-sequence-prop");
51
51
  const TimelineSelection_1 = require("./TimelineSelection");
52
52
  const HANDLE_INSET = 6;
53
53
  const HANDLE_OUTSET = 8;
54
+ const timelineSequenceEdgeDragThresholdPx = 4;
54
55
  exports.timelineSequenceFromDragSnapThresholdPx = 10;
56
+ const getTimelineSequenceEdgeSelectionInteraction = ({ button, selected, shiftKey, metaKey, ctrlKey, }) => {
57
+ if (button !== 0 ||
58
+ !(0, TimelineSelection_1.shouldSelectTimelineRowOnPointerDown)({
59
+ selected,
60
+ shiftKey,
61
+ metaKey,
62
+ ctrlKey,
63
+ })) {
64
+ return null;
65
+ }
66
+ return { shiftKey, toggleKey: metaKey || ctrlKey };
67
+ };
55
68
  const baseStyle = {
56
69
  position: 'absolute',
57
70
  top: 0,
@@ -233,7 +246,7 @@ const isFromDraggableSequence = (sequence) => {
233
246
  !sequence.isInsideSeries &&
234
247
  Boolean(sequence.controls));
235
248
  };
236
- const getTimelineSequenceDurationDragValue = ({ initialDuration, deltaFrames, minimumDuration = 1, }) => Math.max(minimumDuration, initialDuration + deltaFrames);
249
+ const getTimelineSequenceDurationDragValue = ({ initialDuration, deltaFrames, maximumDuration, minimumDuration = 1, }) => Math.min(maximumDuration, Math.max(minimumDuration, initialDuration + deltaFrames));
237
250
  exports.getTimelineSequenceDurationDragValue = getTimelineSequenceDurationDragValue;
238
251
  const getTimelineSequenceLeftEdgeDragDelta = ({ initialDuration, initialTrimBefore, deltaFrames, playbackRate, minimumDuration = 1, }) => {
239
252
  const minDeltaFrames = 0 - initialTrimBefore / playbackRate;
@@ -307,6 +320,7 @@ const getTimelineSequenceDurationDragChanges = ({ targets, deltaFrames, }) => {
307
320
  const nextValue = (0, exports.getTimelineSequenceDurationDragValue)({
308
321
  initialDuration: target.initialDuration,
309
322
  deltaFrames,
323
+ maximumDuration: target.maximumDuration,
310
324
  minimumDuration: target.minimumDuration,
311
325
  });
312
326
  if (nextValue === target.initialDuration) {
@@ -327,14 +341,11 @@ const getTimelineSequenceDurationDragChanges = ({ targets, deltaFrames, }) => {
327
341
  exports.getTimelineSequenceDurationDragChanges = getTimelineSequenceDurationDragChanges;
328
342
  const getTimelineSequenceFromDragValue = ({ initialFrom, deltaFrames, }) => initialFrom + deltaFrames;
329
343
  exports.getTimelineSequenceFromDragValue = getTimelineSequenceFromDragValue;
330
- const getTimelineSequenceFromDragDelta = ({ deltaFrames, pxPerFrame, snappingEnabled, targets, }) => {
344
+ const getTimelineSequenceFromDragDelta = ({ deltaFrames, timelineDurationInFrames, pxPerFrame, snappingEnabled, targets, }) => {
331
345
  var _a;
332
- if (!snappingEnabled) {
333
- return deltaFrames;
334
- }
335
346
  let closestSnap;
336
347
  for (const target of targets) {
337
- if (!target.canSnapToTimelineStart) {
348
+ if (!snappingEnabled || !target.canSnapToTimelineStart) {
338
349
  continue;
339
350
  }
340
351
  const nextFrom = (0, exports.getTimelineSequenceFromDragValue)({
@@ -351,7 +362,10 @@ const getTimelineSequenceFromDragDelta = ({ deltaFrames, pxPerFrame, snappingEna
351
362
  distancePx,
352
363
  };
353
364
  }
354
- return (_a = closestSnap === null || closestSnap === void 0 ? void 0 : closestSnap.deltaFrames) !== null && _a !== void 0 ? _a : deltaFrames;
365
+ const minimumDelta = Math.max(...targets.map((target) => target.minimumDeltaFrames));
366
+ const maximumDelta = Math.min(...targets.map((target) => timelineDurationInFrames - 1 - target.initialTimelineStart));
367
+ // Clamp the shared delta after snapping so every selected track retains a frame.
368
+ return Math.max(minimumDelta, Math.min(maximumDelta, (_a = closestSnap === null || closestSnap === void 0 ? void 0 : closestSnap.deltaFrames) !== null && _a !== void 0 ? _a : deltaFrames));
355
369
  };
356
370
  exports.getTimelineSequenceFromDragDelta = getTimelineSequenceFromDragDelta;
357
371
  const getTimelineSequenceFromDragChanges = ({ targets, deltaFrames, }) => {
@@ -416,7 +430,7 @@ const findSequenceTrack = ({ tracks, nodePathInfo, }) => {
416
430
  return ((0, studio_shared_1.stringifySequenceExpandedRowKey)(candidate.nodePathInfo.sequenceSubscriptionKey) === key && candidate.nodePathInfo.index === nodePathInfo.index);
417
431
  });
418
432
  };
419
- const getTimelineSequenceDurationDragTargets = ({ draggedNodePathInfo, selectedItems, sequences, overrideIdsToNodePaths, propStatuses, }) => {
433
+ const getTimelineSequenceDurationDragTargets = ({ draggedNodePathInfo, selectedItems, sequences, overrideIdsToNodePaths, propStatuses, timelineDurationInFrames, }) => {
420
434
  var _a;
421
435
  const draggedSelectionKey = (0, TimelineSelection_1.getTimelineSequenceSelectionKey)(draggedNodePathInfo);
422
436
  const selectedSequenceItems = selectedItems.filter((item) => item.type === 'sequence');
@@ -456,13 +470,13 @@ const getTimelineSequenceDurationDragTargets = ({ draggedNodePathInfo, selectedI
456
470
  }
457
471
  const key = (0, studio_shared_1.stringifySequenceSubscriptionKey)(nodePath);
458
472
  if (!targets.has(key)) {
473
+ const minimumDuration = Math.max(1 - originalSequence.from, getMinimumSequenceDuration({ sequence: originalSequence, sequences }));
459
474
  targets.set(key, {
460
475
  fileName: nodePath.absolutePath,
461
476
  initialDuration: originalSequence.duration,
462
- minimumDuration: getMinimumSequenceDuration({
463
- sequence: originalSequence,
464
- sequences,
465
- }),
477
+ maximumDuration: Math.max(minimumDuration, timelineDurationInFrames - track.cascadedStart),
478
+ // A negative start needs enough duration to retain one visible frame.
479
+ minimumDuration,
466
480
  nodePath,
467
481
  schema: controls.schema,
468
482
  });
@@ -558,6 +572,7 @@ const getTimelineSequenceFromDragTargets = ({ draggedNodePathInfo, selectedItems
558
572
  {
559
573
  nodePath: track.nodePathInfo.sequenceSubscriptionKey,
560
574
  originalSequence,
575
+ initialTimelineStart: track.cascadedStart,
561
576
  },
562
577
  ];
563
578
  });
@@ -579,7 +594,7 @@ const getTimelineSequenceFromDragTargets = ({ draggedNodePathInfo, selectedItems
579
594
  });
580
595
  const targets = new Map();
581
596
  const includedKeyframeNodePaths = new Set();
582
- for (const { nodePath, originalSequence, } of sequencesWithoutSelectedAncestors) {
597
+ for (const { nodePath, originalSequence, initialTimelineStart, } of sequencesWithoutSelectedAncestors) {
583
598
  if (!isFromDraggableSequence(originalSequence)) {
584
599
  return null;
585
600
  }
@@ -627,6 +642,8 @@ const getTimelineSequenceFromDragTargets = ({ draggedNodePathInfo, selectedItems
627
642
  const sequenceKeyframes = descendantKeyframes.flatMap((descendant) => descendant.sequenceKeyframes);
628
643
  targets.set(key, {
629
644
  canSnapToTimelineStart: originalSequence.parent === null,
645
+ minimumDeltaFrames: 1 - originalSequence.duration - originalSequence.from,
646
+ initialTimelineStart,
630
647
  effectKeyframes,
631
648
  fileName: nodePath.absolutePath,
632
649
  initialFrom: originalSequence.from,
@@ -665,14 +682,14 @@ const clearFromDragOverrides = ({ clearDragOverrides, clearEffectDragOverrides,
665
682
  }
666
683
  }
667
684
  };
668
- const TimelineSequenceLeftEdgeDragHandleInner = ({ nodePathInfo, windowWidth, timelineDurationInFrames, onDragEnd }) => {
685
+ const TimelineSequenceLeftEdgeDragHandleInner = ({ nodePathInfo, windowWidth, timelineDurationInFrames, onDragEnd, onSelect, selected, }) => {
669
686
  const { setPropStatuses, setDragOverrides, clearDragOverrides } = (0, react_1.useContext)(remotion_1.Internals.VisualModeSettersContext);
670
687
  const propStatusesRef = (0, react_1.useContext)(remotion_1.Internals.VisualModePropStatusesRefContext);
671
688
  const sequencesRef = (0, react_1.useContext)(remotion_1.Internals.SequenceManagerRefContext);
672
689
  const { overrideIdToNodePathMappings } = (0, react_1.useContext)(remotion_1.Internals.OverrideIdsToNodePathsGettersContext);
673
690
  const { previewServerState } = (0, react_1.useContext)(client_id_1.StudioServerConnectionCtx);
674
691
  const currentSelection = (0, TimelineSelection_1.useCurrentTimelineSelectionStateAsRef)();
675
- const [dragging, setDragging] = (0, react_1.useState)(false);
692
+ const stopPointerSessionRef = (0, react_1.useRef)(null);
676
693
  const dragStateRef = (0, react_1.useRef)(null);
677
694
  const latestRef = (0, react_1.useRef)({
678
695
  nodePathInfo,
@@ -682,6 +699,7 @@ const TimelineSequenceLeftEdgeDragHandleInner = ({ nodePathInfo, windowWidth, ti
682
699
  previewServerState,
683
700
  overrideIdToNodePathMappings,
684
701
  onDragEnd,
702
+ onSelect,
685
703
  });
686
704
  latestRef.current = {
687
705
  nodePathInfo,
@@ -691,6 +709,7 @@ const TimelineSequenceLeftEdgeDragHandleInner = ({ nodePathInfo, windowWidth, ti
691
709
  previewServerState,
692
710
  overrideIdToNodePathMappings,
693
711
  onDragEnd,
712
+ onSelect,
694
713
  };
695
714
  const finishDrag = (0, react_1.useCallback)((commit) => {
696
715
  const dragState = dragStateRef.current;
@@ -702,7 +721,11 @@ const TimelineSequenceLeftEdgeDragHandleInner = ({ nodePathInfo, windowWidth, ti
702
721
  document.body.style.userSelect = '';
703
722
  document.body.style.webkitUserSelect = '';
704
723
  (0, ForceSpecificCursor_1.stopForcingSpecificCursor)();
705
- setDragging(false);
724
+ if (commit &&
725
+ !dragState.didMove &&
726
+ dragState.selectionInteraction !== null) {
727
+ latestRef.current.onSelect(dragState.selectionInteraction);
728
+ }
706
729
  const { setPropStatuses: latestSetPropStatuses, clearDragOverrides: latestClear, previewServerState: latestServerState, } = latestRef.current;
707
730
  const changes = (0, exports.getTimelineSequenceLeftEdgeDragChanges)({
708
731
  targets: dragState.targets,
@@ -742,65 +765,61 @@ const TimelineSequenceLeftEdgeDragHandleInner = ({ nodePathInfo, windowWidth, ti
742
765
  });
743
766
  }, []);
744
767
  const onPointerDown = (0, react_1.useCallback)((e) => {
745
- var _a, _b;
768
+ var _a;
769
+ var _b;
746
770
  if (e.button !== 0) {
747
771
  return;
748
772
  }
773
+ e.stopPropagation();
774
+ e.preventDefault();
775
+ const selectionInteraction = getTimelineSequenceEdgeSelectionInteraction({
776
+ button: e.button,
777
+ selected,
778
+ shiftKey: e.shiftKey,
779
+ metaKey: e.metaKey,
780
+ ctrlKey: e.ctrlKey,
781
+ });
749
782
  const pxPerFrame = timelineDurationInFrames > 0
750
783
  ? (windowWidth - timeline_layout_1.TIMELINE_PADDING * 2) / timelineDurationInFrames
751
784
  : 0;
752
- if (pxPerFrame <= 0) {
753
- return;
754
- }
785
+ const canCalculateDelta = Number.isFinite(pxPerFrame) && pxPerFrame > 0;
755
786
  const { nodePathInfo: latestNodePathInfo, overrideIdToNodePathMappings: latestOverrideIdsToNodePaths, } = latestRef.current;
756
787
  const { selectedItems: latestSelectedItems } = currentSelection.current;
757
- const targets = (0, exports.getTimelineSequenceLeftEdgeDragTargets)({
758
- draggedNodePathInfo: latestNodePathInfo,
759
- selectedItems: latestSelectedItems,
760
- sequences: sequencesRef.current,
761
- overrideIdsToNodePaths: latestOverrideIdsToNodePaths,
762
- propStatuses: propStatusesRef.current,
763
- });
764
- if (targets === null || targets.length === 0) {
765
- return;
766
- }
767
- e.stopPropagation();
768
- e.preventDefault();
788
+ const targets = canCalculateDelta
789
+ ? ((_b = (0, exports.getTimelineSequenceLeftEdgeDragTargets)({
790
+ draggedNodePathInfo: latestNodePathInfo,
791
+ selectedItems: latestSelectedItems,
792
+ sequences: sequencesRef.current,
793
+ overrideIdsToNodePaths: latestOverrideIdsToNodePaths,
794
+ propStatuses: propStatusesRef.current,
795
+ })) !== null && _b !== void 0 ? _b : [])
796
+ : [];
797
+ (_a = stopPointerSessionRef.current) === null || _a === void 0 ? void 0 : _a.call(stopPointerSessionRef);
769
798
  dragStateRef.current = {
770
799
  initialClientX: e.clientX,
771
800
  latestDeltaFrames: 0,
772
801
  didMove: false,
773
- pxPerFrame,
802
+ pxPerFrame: canCalculateDelta ? pxPerFrame : 1,
774
803
  pointerId: e.pointerId,
775
- button: e.button,
776
- target: e.currentTarget,
804
+ selectionInteraction,
777
805
  targets,
778
806
  };
779
- (_b = (_a = e.currentTarget).setPointerCapture) === null || _b === void 0 ? void 0 : _b.call(_a, e.pointerId);
780
807
  document.body.style.userSelect = 'none';
781
808
  document.body.style.webkitUserSelect = 'none';
782
809
  (0, ForceSpecificCursor_1.forceSpecificCursor)('ew-resize');
783
- setDragging(true);
784
- }, [
785
- currentSelection,
786
- propStatusesRef,
787
- sequencesRef,
788
- timelineDurationInFrames,
789
- windowWidth,
790
- ]);
791
- (0, react_1.useEffect)(() => {
792
- if (!dragging) {
793
- return;
794
- }
795
- const onMove = (e) => {
810
+ const onMove = (pointerEvent) => {
796
811
  const dragState = dragStateRef.current;
797
- if (!dragState || e.pointerId !== dragState.pointerId) {
812
+ if (!dragState || pointerEvent.pointerId !== dragState.pointerId) {
798
813
  return;
799
814
  }
800
- const dx = e.clientX - dragState.initialClientX;
815
+ const dx = pointerEvent.clientX - dragState.initialClientX;
801
816
  const deltaFrames = Math.round(dx / dragState.pxPerFrame);
802
817
  dragState.latestDeltaFrames = deltaFrames;
803
- if (deltaFrames !== 0) {
818
+ if (Math.abs(dx) >= timelineSequenceEdgeDragThresholdPx ||
819
+ (0, exports.getTimelineSequenceLeftEdgeDragChanges)({
820
+ targets: dragState.targets,
821
+ deltaFrames,
822
+ }).length > 0) {
804
823
  dragState.didMove = true;
805
824
  }
806
825
  for (const target of dragState.targets) {
@@ -819,31 +838,28 @@ const TimelineSequenceLeftEdgeDragHandleInner = ({ nodePathInfo, windowWidth, ti
819
838
  latestRef.current.setDragOverrides(target.nodePath, 'trimBefore', remotion_1.Internals.makeStaticDragOverride(nextValues.trimBefore));
820
839
  }
821
840
  };
822
- const onUp = (e) => {
841
+ const onUp = (pointerEvent) => {
823
842
  const dragState = dragStateRef.current;
824
- if (!dragState || e.pointerId !== dragState.pointerId) {
843
+ if (!dragState || pointerEvent.pointerId !== dragState.pointerId) {
825
844
  return;
826
845
  }
827
846
  // Include the release position even if the final pointermove was skipped.
828
- onMove(e);
847
+ onMove(pointerEvent);
829
848
  finishDrag(true);
830
849
  };
831
- const onCancel = (e) => {
850
+ const onCancel = (pointerEvent) => {
832
851
  const dragState = dragStateRef.current;
833
- if (!dragState || e.pointerId !== dragState.pointerId) {
852
+ if (!dragState || pointerEvent.pointerId !== dragState.pointerId) {
834
853
  return;
835
854
  }
836
855
  finishDrag(false);
837
856
  };
838
- const activeDragState = dragStateRef.current;
839
- if (!activeDragState) {
840
- return;
841
- }
842
- return (0, pointer_session_1.startCapturedPointerSession)({
843
- event: activeDragState,
844
- captureTarget: activeDragState.target,
857
+ stopPointerSessionRef.current = (0, pointer_session_1.startCapturedPointerSession)({
858
+ event: e.nativeEvent,
859
+ captureTarget: e.currentTarget,
845
860
  onMove,
846
861
  onEnd: (reason, endEvent) => {
862
+ stopPointerSessionRef.current = null;
847
863
  if ((reason === 'pointerup' ||
848
864
  reason === 'buttons-released' ||
849
865
  (reason === 'lostpointercapture' && (endEvent === null || endEvent === void 0 ? void 0 : endEvent.buttons) === 0)) &&
@@ -858,7 +874,22 @@ const TimelineSequenceLeftEdgeDragHandleInner = ({ nodePathInfo, windowWidth, ti
858
874
  }
859
875
  },
860
876
  });
861
- }, [dragging, finishDrag]);
877
+ }, [
878
+ currentSelection,
879
+ finishDrag,
880
+ propStatusesRef,
881
+ selected,
882
+ sequencesRef,
883
+ timelineDurationInFrames,
884
+ windowWidth,
885
+ ]);
886
+ (0, react_1.useEffect)(() => {
887
+ return () => {
888
+ var _a;
889
+ (_a = stopPointerSessionRef.current) === null || _a === void 0 ? void 0 : _a.call(stopPointerSessionRef);
890
+ stopPointerSessionRef.current = null;
891
+ };
892
+ }, []);
862
893
  const style = {
863
894
  ...baseStyle,
864
895
  left: -HANDLE_OUTSET,
@@ -1000,7 +1031,9 @@ const useTimelineSequenceFromDrag = ({ nodePathInfo, windowWidth, timelineDurati
1000
1031
  // the global session listeners exist.
1001
1032
  stopPointerSessionRef.current = (0, pointer_session_1.startCapturedPointerSession)({
1002
1033
  event: e.nativeEvent,
1003
- captureTarget: e.currentTarget,
1034
+ // The bar is removed when it leaves the visible timeline. Capture on
1035
+ // a stable element so the move continues until the pointer is released.
1036
+ captureTarget: e.currentTarget.ownerDocument.body,
1004
1037
  onMove: (moveEvent) => {
1005
1038
  const dragState = dragStateRef.current;
1006
1039
  if (!dragState) {
@@ -1008,6 +1041,7 @@ const useTimelineSequenceFromDrag = ({ nodePathInfo, windowWidth, timelineDurati
1008
1041
  }
1009
1042
  const dx = moveEvent.clientX - dragState.initialClientX;
1010
1043
  const deltaFrames = (0, exports.getTimelineSequenceFromDragDelta)({
1044
+ timelineDurationInFrames,
1011
1045
  deltaFrames: Math.round(dx / dragState.pxPerFrame),
1012
1046
  pxPerFrame: dragState.pxPerFrame,
1013
1047
  snappingEnabled: latestRef.current.editorSnapping,
@@ -1073,14 +1107,14 @@ const useTimelineSequenceFromDrag = ({ nodePathInfo, windowWidth, timelineDurati
1073
1107
  };
1074
1108
  };
1075
1109
  exports.useTimelineSequenceFromDrag = useTimelineSequenceFromDrag;
1076
- const TimelineSequenceRightEdgeDragHandleInner = ({ nodePathInfo, windowWidth, timelineDurationInFrames, onDragEnd }) => {
1110
+ const TimelineSequenceRightEdgeDragHandleInner = ({ nodePathInfo, windowWidth, timelineDurationInFrames, onDragEnd, onSelect, selected, }) => {
1077
1111
  const { setPropStatuses, setDragOverrides, clearDragOverrides } = (0, react_1.useContext)(remotion_1.Internals.VisualModeSettersContext);
1078
1112
  const propStatusesRef = (0, react_1.useContext)(remotion_1.Internals.VisualModePropStatusesRefContext);
1079
1113
  const sequencesRef = (0, react_1.useContext)(remotion_1.Internals.SequenceManagerRefContext);
1080
1114
  const { overrideIdToNodePathMappings } = (0, react_1.useContext)(remotion_1.Internals.OverrideIdsToNodePathsGettersContext);
1081
1115
  const { previewServerState } = (0, react_1.useContext)(client_id_1.StudioServerConnectionCtx);
1082
1116
  const currentSelection = (0, TimelineSelection_1.useCurrentTimelineSelectionStateAsRef)();
1083
- const [dragging, setDragging] = (0, react_1.useState)(false);
1117
+ const stopPointerSessionRef = (0, react_1.useRef)(null);
1084
1118
  const dragStateRef = (0, react_1.useRef)(null);
1085
1119
  // Keep latest props/setters available to window listeners installed once at pointerdown.
1086
1120
  const latestRef = (0, react_1.useRef)({
@@ -1091,6 +1125,7 @@ const TimelineSequenceRightEdgeDragHandleInner = ({ nodePathInfo, windowWidth, t
1091
1125
  previewServerState,
1092
1126
  overrideIdToNodePathMappings,
1093
1127
  onDragEnd,
1128
+ onSelect,
1094
1129
  });
1095
1130
  latestRef.current = {
1096
1131
  nodePathInfo,
@@ -1100,6 +1135,7 @@ const TimelineSequenceRightEdgeDragHandleInner = ({ nodePathInfo, windowWidth, t
1100
1135
  previewServerState,
1101
1136
  overrideIdToNodePathMappings,
1102
1137
  onDragEnd,
1138
+ onSelect,
1103
1139
  };
1104
1140
  const finishDrag = (0, react_1.useCallback)((commit) => {
1105
1141
  const dragState = dragStateRef.current;
@@ -1111,7 +1147,11 @@ const TimelineSequenceRightEdgeDragHandleInner = ({ nodePathInfo, windowWidth, t
1111
1147
  document.body.style.userSelect = '';
1112
1148
  document.body.style.webkitUserSelect = '';
1113
1149
  (0, ForceSpecificCursor_1.stopForcingSpecificCursor)();
1114
- setDragging(false);
1150
+ if (commit &&
1151
+ !dragState.didMove &&
1152
+ dragState.selectionInteraction !== null) {
1153
+ latestRef.current.onSelect(dragState.selectionInteraction);
1154
+ }
1115
1155
  const { setPropStatuses: latestSetPropStatuses, clearDragOverrides: latestClear, previewServerState: latestServerState, } = latestRef.current;
1116
1156
  const changes = (0, exports.getTimelineSequenceDurationDragChanges)({
1117
1157
  targets: dragState.targets,
@@ -1149,103 +1189,95 @@ const TimelineSequenceRightEdgeDragHandleInner = ({ nodePathInfo, windowWidth, t
1149
1189
  });
1150
1190
  }, []);
1151
1191
  const onPointerDown = (0, react_1.useCallback)((e) => {
1152
- var _a, _b;
1192
+ var _a;
1193
+ var _b;
1153
1194
  if (e.button !== 0) {
1154
1195
  return;
1155
1196
  }
1197
+ e.stopPropagation();
1198
+ e.preventDefault();
1199
+ const selectionInteraction = getTimelineSequenceEdgeSelectionInteraction({
1200
+ button: e.button,
1201
+ selected,
1202
+ shiftKey: e.shiftKey,
1203
+ metaKey: e.metaKey,
1204
+ ctrlKey: e.ctrlKey,
1205
+ });
1156
1206
  const pxPerFrame = timelineDurationInFrames > 0
1157
1207
  ? (windowWidth - timeline_layout_1.TIMELINE_PADDING * 2) / timelineDurationInFrames
1158
1208
  : 0;
1159
- if (pxPerFrame <= 0) {
1160
- return;
1161
- }
1209
+ const canCalculateDelta = Number.isFinite(pxPerFrame) && pxPerFrame > 0;
1162
1210
  const { nodePathInfo: latestNodePathInfo, overrideIdToNodePathMappings: latestOverrideIdsToNodePaths, } = latestRef.current;
1163
1211
  const { selectedItems: latestSelectedItems } = currentSelection.current;
1164
- const targets = (0, exports.getTimelineSequenceDurationDragTargets)({
1165
- draggedNodePathInfo: latestNodePathInfo,
1166
- selectedItems: latestSelectedItems,
1167
- sequences: sequencesRef.current,
1168
- overrideIdsToNodePaths: latestOverrideIdsToNodePaths,
1169
- propStatuses: propStatusesRef.current,
1170
- });
1171
- if (targets === null || targets.length === 0) {
1172
- return;
1173
- }
1174
- e.stopPropagation();
1175
- e.preventDefault();
1212
+ const targets = canCalculateDelta
1213
+ ? ((_b = (0, exports.getTimelineSequenceDurationDragTargets)({
1214
+ draggedNodePathInfo: latestNodePathInfo,
1215
+ selectedItems: latestSelectedItems,
1216
+ sequences: sequencesRef.current,
1217
+ overrideIdsToNodePaths: latestOverrideIdsToNodePaths,
1218
+ propStatuses: propStatusesRef.current,
1219
+ timelineDurationInFrames,
1220
+ })) !== null && _b !== void 0 ? _b : [])
1221
+ : [];
1222
+ (_a = stopPointerSessionRef.current) === null || _a === void 0 ? void 0 : _a.call(stopPointerSessionRef);
1176
1223
  dragStateRef.current = {
1177
1224
  initialClientX: e.clientX,
1178
1225
  latestDeltaFrames: 0,
1179
1226
  didMove: false,
1180
- pxPerFrame,
1227
+ pxPerFrame: canCalculateDelta ? pxPerFrame : 1,
1181
1228
  pointerId: e.pointerId,
1182
- button: e.button,
1183
- target: e.currentTarget,
1229
+ selectionInteraction,
1184
1230
  targets,
1185
1231
  };
1186
- (_b = (_a = e.currentTarget).setPointerCapture) === null || _b === void 0 ? void 0 : _b.call(_a, e.pointerId);
1187
1232
  document.body.style.userSelect = 'none';
1188
1233
  document.body.style.webkitUserSelect = 'none';
1189
1234
  (0, ForceSpecificCursor_1.forceSpecificCursor)('ew-resize');
1190
- setDragging(true);
1191
- }, [
1192
- currentSelection,
1193
- propStatusesRef,
1194
- sequencesRef,
1195
- timelineDurationInFrames,
1196
- windowWidth,
1197
- ]);
1198
- // Install global pointer listeners while dragging. They survive parent re-renders
1199
- // and element remounts that would otherwise drop React's synthetic handlers or
1200
- // pointer capture.
1201
- (0, react_1.useEffect)(() => {
1202
- if (!dragging) {
1203
- return;
1204
- }
1205
- const onMove = (e) => {
1235
+ const onMove = (pointerEvent) => {
1206
1236
  const dragState = dragStateRef.current;
1207
- if (!dragState || e.pointerId !== dragState.pointerId) {
1237
+ if (!dragState || pointerEvent.pointerId !== dragState.pointerId) {
1208
1238
  return;
1209
1239
  }
1210
- const dx = e.clientX - dragState.initialClientX;
1240
+ const dx = pointerEvent.clientX - dragState.initialClientX;
1211
1241
  const deltaFrames = Math.round(dx / dragState.pxPerFrame);
1212
1242
  dragState.latestDeltaFrames = deltaFrames;
1213
- if (deltaFrames !== 0) {
1243
+ if (Math.abs(dx) >= timelineSequenceEdgeDragThresholdPx ||
1244
+ (0, exports.getTimelineSequenceDurationDragChanges)({
1245
+ targets: dragState.targets,
1246
+ deltaFrames,
1247
+ }).length > 0) {
1214
1248
  dragState.didMove = true;
1215
1249
  }
1216
1250
  for (const target of dragState.targets) {
1217
1251
  latestRef.current.setDragOverrides(target.nodePath, 'durationInFrames', remotion_1.Internals.makeStaticDragOverride((0, exports.getTimelineSequenceDurationDragValue)({
1218
1252
  initialDuration: target.initialDuration,
1219
1253
  deltaFrames,
1254
+ maximumDuration: target.maximumDuration,
1220
1255
  minimumDuration: target.minimumDuration,
1221
1256
  })));
1222
1257
  }
1223
1258
  };
1224
- const onUp = (e) => {
1259
+ const onUp = (pointerEvent) => {
1225
1260
  const dragState = dragStateRef.current;
1226
- if (!dragState || e.pointerId !== dragState.pointerId) {
1261
+ if (!dragState || pointerEvent.pointerId !== dragState.pointerId) {
1227
1262
  return;
1228
1263
  }
1229
1264
  // Include the release position even if the final pointermove was skipped.
1230
- onMove(e);
1265
+ onMove(pointerEvent);
1231
1266
  finishDrag(true);
1232
1267
  };
1233
- const onCancel = (e) => {
1268
+ const onCancel = (pointerEvent) => {
1234
1269
  const dragState = dragStateRef.current;
1235
- if (!dragState || e.pointerId !== dragState.pointerId) {
1270
+ if (!dragState || pointerEvent.pointerId !== dragState.pointerId) {
1236
1271
  return;
1237
1272
  }
1238
1273
  finishDrag(false);
1239
1274
  };
1240
- const activeDragState = dragStateRef.current;
1241
- if (!activeDragState) {
1242
- return;
1243
- }
1244
- return (0, pointer_session_1.startCapturedPointerSession)({
1245
- event: activeDragState,
1246
- captureTarget: activeDragState.target,
1275
+ stopPointerSessionRef.current = (0, pointer_session_1.startCapturedPointerSession)({
1276
+ event: e.nativeEvent,
1277
+ captureTarget: e.currentTarget,
1247
1278
  onMove,
1248
1279
  onEnd: (reason, endEvent) => {
1280
+ stopPointerSessionRef.current = null;
1249
1281
  if ((reason === 'pointerup' ||
1250
1282
  reason === 'buttons-released' ||
1251
1283
  (reason === 'lostpointercapture' && (endEvent === null || endEvent === void 0 ? void 0 : endEvent.buttons) === 0)) &&
@@ -1260,7 +1292,22 @@ const TimelineSequenceRightEdgeDragHandleInner = ({ nodePathInfo, windowWidth, t
1260
1292
  }
1261
1293
  },
1262
1294
  });
1263
- }, [dragging, finishDrag]);
1295
+ }, [
1296
+ currentSelection,
1297
+ finishDrag,
1298
+ propStatusesRef,
1299
+ selected,
1300
+ sequencesRef,
1301
+ timelineDurationInFrames,
1302
+ windowWidth,
1303
+ ]);
1304
+ (0, react_1.useEffect)(() => {
1305
+ return () => {
1306
+ var _a;
1307
+ (_a = stopPointerSessionRef.current) === null || _a === void 0 ? void 0 : _a.call(stopPointerSessionRef);
1308
+ stopPointerSessionRef.current = null;
1309
+ };
1310
+ }, []);
1264
1311
  const style = {
1265
1312
  ...baseStyle,
1266
1313
  right: -HANDLE_OUTSET,
@@ -55,13 +55,10 @@ const TimelineSliderInner = () => {
55
55
  const ref = (0, react_1.useRef)(null);
56
56
  const timelineWidth = (0, react_1.useContext)(TimelineWidthProvider_1.TimelineWidthContext);
57
57
  const { zoom: zoomMap } = (0, react_1.useContext)(timeline_zoom_1.TimelineZoomCtx);
58
- const { canvasContent } = (0, react_1.useContext)(remotion_1.Internals.CompositionManager);
59
58
  if (timelineWidth === null) {
60
59
  throw new Error('Unexpectedly did not have timeline width');
61
60
  }
62
- const zoomLevel = (canvasContent === null || canvasContent === void 0 ? void 0 : canvasContent.type) === 'composition'
63
- ? ((_a = zoomMap[canvasContent.compositionId]) !== null && _a !== void 0 ? _a : null)
64
- : null;
61
+ const zoomLevel = (_a = zoomMap[videoConfig.id]) !== null && _a !== void 0 ? _a : null;
65
62
  (0, react_1.useLayoutEffect)(() => {
66
63
  var _a;
67
64
  const el = ref.current;
@@ -15,7 +15,6 @@ const TimelineWidthProvider = ({ children }) => {
15
15
  shouldApplyCssTransforms: true,
16
16
  });
17
17
  const { zoom: zoomMap } = (0, react_1.useContext)(timeline_zoom_1.TimelineZoomCtx);
18
- const { canvasContent } = (0, react_1.useContext)(remotion_1.Internals.CompositionManager);
19
18
  const videoConfig = remotion_1.Internals.useUnsafeVideoConfig();
20
19
  const width = (0, react_1.useMemo)(() => {
21
20
  var _a, _b;
@@ -28,12 +27,10 @@ const TimelineWidthProvider = ({ children }) => {
28
27
  const zoom = (0, get_timeline_max_zoom_1.getTimelineZoom)({
29
28
  durationInFrames,
30
29
  timelineViewportWidth: scrollableWidth,
31
- zoom: (canvasContent === null || canvasContent === void 0 ? void 0 : canvasContent.type) === 'composition'
32
- ? ((_f = zoomMap[canvasContent.compositionId]) !== null && _f !== void 0 ? _f : null)
33
- : null,
30
+ zoom: videoConfig ? ((_f = zoomMap[videoConfig.id]) !== null && _f !== void 0 ? _f : null) : null,
34
31
  });
35
32
  return (0, get_timeline_max_zoom_1.getTimelineWidth)({ durationInFrames, zoom });
36
- }, [canvasContent, size === null || size === void 0 ? void 0 : size.width, videoConfig === null || videoConfig === void 0 ? void 0 : videoConfig.durationInFrames, zoomMap]);
33
+ }, [size === null || size === void 0 ? void 0 : size.width, videoConfig, zoomMap]);
37
34
  return (jsx_runtime_1.jsx(exports.TimelineWidthContext.Provider, { value: width, children: children }));
38
35
  };
39
36
  exports.TimelineWidthProvider = TimelineWidthProvider;