@remotion/studio 4.0.521 → 4.0.523

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 (264) hide show
  1. package/dist/api/install-package.js +4 -2
  2. package/dist/components/AssetAudioVolume.d.ts +5 -0
  3. package/dist/components/AssetAudioVolume.js +33 -0
  4. package/dist/components/Canvas.js +5 -6
  5. package/dist/components/CanvasIfSizeIsAvailable.js +7 -0
  6. package/dist/components/CaptionInspector.js +74 -20
  7. package/dist/components/CheckboardToggle.js +8 -6
  8. package/dist/components/Checkbox.d.ts +1 -0
  9. package/dist/components/Checkbox.js +2 -2
  10. package/dist/components/CompositionContextButton.js +4 -1
  11. package/dist/components/CompositionSelectorItem.js +2 -2
  12. package/dist/components/ConfigureLicenseModal.js +1 -1
  13. package/dist/components/CopyButton.js +7 -14
  14. package/dist/components/CurrentAsset.js +40 -6
  15. package/dist/components/Editor.js +6 -5
  16. package/dist/components/EditorContent.js +1 -1
  17. package/dist/components/EditorContexts.js +3 -1
  18. package/dist/components/ElementInstallConfirmation.js +290 -136
  19. package/dist/components/FixComputedValueModal.js +56 -16
  20. package/dist/components/FullscreenToggle.js +9 -8
  21. package/dist/components/GlobalKeybindings.js +50 -49
  22. package/dist/components/HighlightedElementSource.d.ts +5 -0
  23. package/dist/components/HighlightedElementSource.js +78 -0
  24. package/dist/components/InspectorLocationCopy.js +10 -5
  25. package/dist/components/InspectorPanel/MultiSequenceField.d.ts +12 -0
  26. package/dist/components/InspectorPanel/MultiSequenceField.js +131 -0
  27. package/dist/components/InspectorPanel/MultiSequenceInspector.d.ts +8 -0
  28. package/dist/components/InspectorPanel/MultiSequenceInspector.js +102 -0
  29. package/dist/components/InspectorPanel/MultiSequenceNumberField.d.ts +9 -0
  30. package/dist/components/InspectorPanel/MultiSequenceNumberField.js +88 -0
  31. package/dist/components/InspectorPanel.js +4 -0
  32. package/dist/components/InspectorSequenceSection.js +64 -1
  33. package/dist/components/InstallPackage.js +4 -5
  34. package/dist/components/KeyboardShortcutsSettings.js +212 -33
  35. package/dist/components/MenuBuildIndicator.js +7 -2
  36. package/dist/components/MenuCompositionName.js +62 -6
  37. package/dist/components/MenuToolbar.js +7 -5
  38. package/dist/components/ModalContainer.d.ts +1 -0
  39. package/dist/components/ModalContainer.js +2 -2
  40. package/dist/components/Modals.js +3 -1
  41. package/dist/components/ModelManager.d.ts +16 -0
  42. package/dist/components/ModelManager.js +200 -0
  43. package/dist/components/ModelsSettings.d.ts +2 -0
  44. package/dist/components/ModelsSettings.js +133 -0
  45. package/dist/components/NewComposition/DismissableModal.d.ts +1 -0
  46. package/dist/components/NewComposition/DismissableModal.js +2 -2
  47. package/dist/components/NewComposition/InputDragger.d.ts +2 -2
  48. package/dist/components/NewComposition/InputDragger.js +6 -6
  49. package/dist/components/NewComposition/NewFolder.js +11 -8
  50. package/dist/components/NewComposition/RenameFolder.js +17 -10
  51. package/dist/components/OptionalPackageModal.d.ts +11 -0
  52. package/dist/components/OptionalPackageModal.js +155 -0
  53. package/dist/components/PlayPause.js +4 -8
  54. package/dist/components/PlaybackKeyboardShortcutsManager.js +3 -6
  55. package/dist/components/PreviewToolbarOverflowButton.js +11 -2
  56. package/dist/components/QuickSwitcher/ExplorerQuickSwitcherTrigger.js +5 -2
  57. package/dist/components/RadioButton.d.ts +1 -0
  58. package/dist/components/RadioButton.js +2 -2
  59. package/dist/components/RenderButton.js +5 -1
  60. package/dist/components/RenderModal/CliCopyButton.js +13 -27
  61. package/dist/components/RenderModal/NumberSetting.d.ts +6 -1
  62. package/dist/components/RenderModal/NumberSetting.js +2 -2
  63. package/dist/components/RenderModal/RenderModalBasic.js +1 -1
  64. package/dist/components/RenderModal/RenderModalOutputName.d.ts +3 -1
  65. package/dist/components/RenderModal/RenderModalOutputName.js +4 -4
  66. package/dist/components/RenderModal/SeparateAudioOption.js +1 -1
  67. package/dist/components/RenderModal/WebRenderModalBasic.js +1 -1
  68. package/dist/components/RenderQueue/CaptionQueueItem.d.ts +6 -0
  69. package/dist/components/RenderQueue/CaptionQueueItem.js +129 -0
  70. package/dist/components/RenderQueue/CaptionQueueProcessor.d.ts +1 -0
  71. package/dist/components/RenderQueue/CaptionQueueProcessor.js +110 -0
  72. package/dist/components/RenderQueue/CaptionQueueProcessorLoader.d.ts +2 -0
  73. package/dist/components/RenderQueue/CaptionQueueProcessorLoader.js +54 -0
  74. package/dist/components/RenderQueue/RenderQueueCopyToClipboard.js +7 -4
  75. package/dist/components/RenderQueue/RenderQueueItem.js +3 -3
  76. package/dist/components/RenderQueue/VideoMattingQueueItem.d.ts +6 -0
  77. package/dist/components/RenderQueue/VideoMattingQueueItem.js +129 -0
  78. package/dist/components/RenderQueue/VideoMattingQueueProcessor.d.ts +1 -0
  79. package/dist/components/RenderQueue/VideoMattingQueueProcessor.js +105 -0
  80. package/dist/components/RenderQueue/VideoMattingQueueProcessorLoader.d.ts +2 -0
  81. package/dist/components/RenderQueue/VideoMattingQueueProcessorLoader.js +54 -0
  82. package/dist/components/RenderQueue/caption-job-types.d.ts +47 -0
  83. package/dist/components/RenderQueue/caption-job-types.js +7 -0
  84. package/dist/components/RenderQueue/context.d.ts +16 -0
  85. package/dist/components/RenderQueue/context.js +224 -11
  86. package/dist/components/RenderQueue/index.js +34 -10
  87. package/dist/components/RenderQueue/item-style.d.ts +1 -0
  88. package/dist/components/RenderQueue/item-style.js +2 -1
  89. package/dist/components/RenderQueue/load-model-for-job.d.ts +11 -0
  90. package/dist/components/RenderQueue/load-model-for-job.js +14 -0
  91. package/dist/components/RenderQueue/video-matting-job-types.d.ts +38 -0
  92. package/dist/components/RenderQueue/video-matting-job-types.js +5 -0
  93. package/dist/components/RendersTab.js +4 -4
  94. package/dist/components/SegmentedControl.d.ts +2 -2
  95. package/dist/components/SegmentedControl.js +38 -13
  96. package/dist/components/SelectedOutlinePolygon.js +8 -2
  97. package/dist/components/SettingsButton.d.ts +4 -0
  98. package/dist/components/SettingsButton.js +49 -0
  99. package/dist/components/SettingsModal.d.ts +1 -1
  100. package/dist/components/SettingsModal.js +3 -1
  101. package/dist/components/ShowOutlinesProvider.js +12 -0
  102. package/dist/components/SidebarCollapserControls.js +21 -16
  103. package/dist/components/SizeSelector.js +10 -2
  104. package/dist/components/SkillsSettings.js +11 -8
  105. package/dist/components/SnappingToggle.js +5 -2
  106. package/dist/components/Splitter/SplitterContainer.js +63 -10
  107. package/dist/components/Splitter/SplitterContext.d.ts +3 -0
  108. package/dist/components/Splitter/SplitterContext.js +5 -1
  109. package/dist/components/Splitter/SplitterElement.js +11 -2
  110. package/dist/components/Splitter/SplitterHandle.d.ts +1 -0
  111. package/dist/components/Splitter/SplitterHandle.js +55 -25
  112. package/dist/components/Tabs/vertical.d.ts +1 -0
  113. package/dist/components/Tabs/vertical.js +2 -2
  114. package/dist/components/TimeValue.js +2 -3
  115. package/dist/components/Timeline/SequencePropsObserver.js +4 -0
  116. package/dist/components/Timeline/SubscribeToNodePaths.d.ts +2 -1
  117. package/dist/components/Timeline/SubscribeToNodePaths.js +2 -1
  118. package/dist/components/Timeline/Timeline.js +17 -46
  119. package/dist/components/Timeline/TimelineClipboardKeybindings.js +2 -4
  120. package/dist/components/Timeline/TimelineDeleteKeybindings.js +3 -18
  121. package/dist/components/Timeline/TimelineDragHandler.js +11 -6
  122. package/dist/components/Timeline/TimelineExpandedKeyframeRow.js +1 -0
  123. package/dist/components/Timeline/TimelinePinchZoom.js +6 -30
  124. package/dist/components/Timeline/TimelinePlayCursorSyncer.js +1 -7
  125. package/dist/components/Timeline/TimelineRowChrome.js +11 -3
  126. package/dist/components/Timeline/TimelineSchemaField.js +8 -4
  127. package/dist/components/Timeline/TimelineSelection.d.ts +2 -0
  128. package/dist/components/Timeline/TimelineSelection.js +55 -2
  129. package/dist/components/Timeline/TimelineSequence.js +148 -25
  130. package/dist/components/Timeline/TimelineSequenceItem.d.ts +0 -1
  131. package/dist/components/Timeline/TimelineSequenceItem.js +220 -112
  132. package/dist/components/Timeline/TimelineSequenceRightEdgeDragHandle.d.ts +35 -5
  133. package/dist/components/Timeline/TimelineSequenceRightEdgeDragHandle.js +233 -138
  134. package/dist/components/Timeline/TimelineSlider.js +1 -4
  135. package/dist/components/Timeline/TimelineTimeIndicators.js +1 -0
  136. package/dist/components/Timeline/TimelineWidthProvider.js +2 -5
  137. package/dist/components/Timeline/TimelineZoomControls.js +20 -20
  138. package/dist/components/Timeline/get-sequence-split-menu-item.d.ts +11 -0
  139. package/dist/components/Timeline/get-sequence-split-menu-item.js +55 -0
  140. package/dist/components/Timeline/use-asset-timeline-context-menu.d.ts +2 -0
  141. package/dist/components/Timeline/use-asset-timeline-context-menu.js +52 -0
  142. package/dist/components/Timeline/use-sequence-props-subscription.d.ts +3 -2
  143. package/dist/components/Timeline/use-sequence-props-subscription.js +4 -10
  144. package/dist/components/TimelineInOutToggle.js +20 -17
  145. package/dist/components/TopPanel.js +3 -19
  146. package/dist/components/Transcription/LazyModels.d.ts +1 -0
  147. package/dist/components/Transcription/LazyModels.js +5 -0
  148. package/dist/components/Transcription/Models.d.ts +6 -0
  149. package/dist/components/Transcription/Models.js +18 -0
  150. package/dist/components/Transcription/TranscriptionModal.d.ts +3 -0
  151. package/dist/components/Transcription/TranscriptionModal.js +428 -0
  152. package/dist/components/Transcription/TranscriptionModalWithOptionalWhisper.d.ts +5 -0
  153. package/dist/components/Transcription/TranscriptionModalWithOptionalWhisper.js +48 -0
  154. package/dist/components/Transcription/caption-output-name.d.ts +2 -0
  155. package/dist/components/Transcription/caption-output-name.js +10 -0
  156. package/dist/components/Transcription/resample-media-to-16-khz.d.ts +6 -0
  157. package/dist/components/Transcription/resample-media-to-16-khz.js +82 -0
  158. package/dist/components/Transcription/whisper-languages.d.ts +2 -0
  159. package/dist/components/Transcription/whisper-languages.js +104 -0
  160. package/dist/components/Transcription/whisper-webgpu-capability.d.ts +2 -0
  161. package/dist/components/Transcription/whisper-webgpu-capability.js +7 -0
  162. package/dist/components/UndoRedoButtons.js +13 -38
  163. package/dist/components/UpdatesSettings.js +17 -17
  164. package/dist/components/VideoMatting/LazyModels.d.ts +1 -0
  165. package/dist/components/VideoMatting/LazyModels.js +5 -0
  166. package/dist/components/VideoMatting/Models.d.ts +6 -0
  167. package/dist/components/VideoMatting/Models.js +18 -0
  168. package/dist/components/VideoMatting/VideoMattingModal.d.ts +3 -0
  169. package/dist/components/VideoMatting/VideoMattingModal.js +207 -0
  170. package/dist/components/VideoMatting/VideoMattingModalWithOptionalPackage.d.ts +5 -0
  171. package/dist/components/VideoMatting/VideoMattingModalWithOptionalPackage.js +46 -0
  172. package/dist/components/VideoMatting/video-matting-capability.d.ts +2 -0
  173. package/dist/components/VideoMatting/video-matting-capability.js +7 -0
  174. package/dist/components/WebMcp.js +439 -22
  175. package/dist/components/ZoomPersistor.js +6 -3
  176. package/dist/components/composition-menu-items.js +1 -1
  177. package/dist/components/import-assets.d.ts +3 -2
  178. package/dist/components/import-assets.js +5 -9
  179. package/dist/components/keyboard-shortcuts.d.ts +17 -1
  180. package/dist/components/keyboard-shortcuts.js +177 -89
  181. package/dist/components/public-output-name.d.ts +5 -0
  182. package/dist/components/public-output-name.js +60 -0
  183. package/dist/components/use-model-cache-status.d.ts +7 -0
  184. package/dist/components/use-model-cache-status.js +35 -0
  185. package/dist/esm/CaptionQueueProcessor-k0yrm3dj.mjs +211 -0
  186. package/dist/esm/HighlightedElementSource-jfc66k4p.mjs +1236 -0
  187. package/dist/esm/LazyModels-2trdm224.mjs +11 -0
  188. package/dist/esm/LazyModels-fjb5ckaq.mjs +11 -0
  189. package/dist/esm/TranscriptionModal-916jqhry.mjs +1011 -0
  190. package/dist/esm/VideoMattingModal-2tm79s9b.mjs +374 -0
  191. package/dist/esm/VideoMattingQueueProcessor-t1hgm2rm.mjs +109 -0
  192. package/dist/esm/index-1x7bsdh6.mjs +261 -0
  193. package/dist/esm/index-3hgr6gjx.mjs +41 -0
  194. package/dist/esm/index-5qddp5h7.mjs +36 -0
  195. package/dist/esm/index-5zrb1ft4.mjs +39 -0
  196. package/dist/esm/index-6cvm9a65.mjs +45923 -0
  197. package/dist/esm/index-7tt71e8n.mjs +36 -0
  198. package/dist/esm/index-9x6e1dq0.mjs +428 -0
  199. package/dist/esm/index-cw0pnpg5.mjs +50 -0
  200. package/dist/esm/index-czwvnn9g.mjs +35 -0
  201. package/dist/esm/index-hy4xcgty.mjs +1366 -0
  202. package/dist/esm/{chunk-je0h1bgt.js → index-jg13hf2g.mjs} +3 -1
  203. package/dist/esm/{chunk-6jf1natv.js → index-rcv7qkt5.mjs} +18 -1
  204. package/dist/esm/index-sgtmgc4h.mjs +423 -0
  205. package/dist/esm/index-te66vvrp.mjs +142 -0
  206. package/dist/esm/index-v4tr1bft.mjs +20 -0
  207. package/dist/esm/index-x7t2y7ws.mjs +54194 -0
  208. package/dist/esm/index-xhe2m2qr.mjs +1146 -0
  209. package/dist/esm/index.mjs +45 -933
  210. package/dist/esm/internals.mjs +13 -114127
  211. package/dist/esm/previewEntry.mjs +387 -114784
  212. package/dist/esm/renderEntry.mjs +3 -3
  213. package/dist/esm/{chunk-m0jqdbkr.js → resolve-composition-component-location-14148845.mjs} +1 -1
  214. package/dist/helpers/copy-text.js +1 -2
  215. package/dist/helpers/drag-aware-double-click.d.ts +2 -1
  216. package/dist/helpers/drag-aware-double-click.js +12 -1
  217. package/dist/helpers/get-asset-metadata.d.ts +1 -0
  218. package/dist/helpers/get-asset-metadata.js +4 -0
  219. package/dist/helpers/hoverable.js +8 -0
  220. package/dist/helpers/inject-css.js +2 -0
  221. package/dist/helpers/optional-package-dependencies.d.ts +3 -0
  222. package/dist/helpers/optional-package-dependencies.js +24 -0
  223. package/dist/helpers/pointer-session.d.ts +6 -0
  224. package/dist/helpers/pointer-session.js +36 -14
  225. package/dist/helpers/prism-tomorrow.d.ts +1 -0
  226. package/dist/helpers/prism-tomorrow.js +151 -0
  227. package/dist/helpers/sequence-node-path-mutations.js +11 -0
  228. package/dist/helpers/slugify-name.d.ts +1 -0
  229. package/dist/helpers/slugify-name.js +14 -0
  230. package/dist/helpers/studio-runtime-config.d.ts +1 -0
  231. package/dist/helpers/studio-runtime-config.js +6 -1
  232. package/dist/helpers/use-copy-feedback.d.ts +4 -0
  233. package/dist/helpers/use-copy-feedback.js +19 -0
  234. package/dist/helpers/use-keybinding.d.ts +9 -3
  235. package/dist/helpers/use-keybinding.js +8 -9
  236. package/dist/helpers/use-keyboard-shortcut-label.d.ts +2 -0
  237. package/dist/helpers/use-keyboard-shortcut-label.js +15 -0
  238. package/dist/helpers/use-menu-structure.js +58 -13
  239. package/dist/icons/copy.d.ts +5 -0
  240. package/dist/icons/copy.js +12 -0
  241. package/dist/icons/input-props.d.ts +1 -1
  242. package/dist/icons/input-props.js +2 -2
  243. package/dist/icons/models.d.ts +4 -0
  244. package/dist/icons/models.js +7 -0
  245. package/dist/icons/separation.d.ts +4 -0
  246. package/dist/icons/separation.js +7 -0
  247. package/dist/icons/transcription.d.ts +4 -0
  248. package/dist/icons/transcription.js +7 -0
  249. package/dist/icons/upload.js +1 -1
  250. package/dist/state/canvas-ref.d.ts +1 -0
  251. package/dist/state/canvas-ref.js +2 -1
  252. package/dist/state/modals.d.ts +14 -2
  253. package/dist/state/sidebar.d.ts +3 -0
  254. package/dist/state/sidebar.js +6 -1
  255. package/dist/state/timeline-zoom.d.ts +1 -1
  256. package/dist/state/timeline-zoom.js +3 -3
  257. package/dist/visual-controls/VisualControls.js +4 -0
  258. package/package.json +34 -20
  259. package/dist/components/UpdateCheck.d.ts +0 -1
  260. package/dist/components/UpdateCheck.js +0 -79
  261. package/dist/esm/chunk-emw4k5b0.js +0 -99527
  262. package/dist/esm/chunk-vkrvnx2h.js +0 -99378
  263. package/dist/helpers/use-max-media-duration.d.ts +0 -2
  264. package/dist/helpers/use-max-media-duration.js +0 -61
@@ -33,7 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.TimelineSequenceRightEdgeDragHandle = exports.useTimelineSequenceFromDrag = exports.TimelineSequenceLeftEdgeDragHandle = exports.getTimelineSequenceFromDragTargets = exports.getTimelineSequenceLeftEdgeDragTargets = exports.getTimelineSequenceDurationDragTargets = exports.getTimelineSequenceFromDragKeyframeMoves = exports.getTimelineSequenceFromDragChanges = exports.getTimelineSequenceFromDragDelta = exports.getTimelineSequenceFromDragValue = exports.getTimelineSequenceDurationDragChanges = exports.getTimelineSequenceLeftEdgeDragChanges = exports.getTimelineSequenceLeftEdgeDragValues = exports.getTimelineSequenceLeftEdgeDragDelta = exports.getTimelineSequenceDurationDragValue = exports.isTimelineSequenceLeftEdgeDraggable = exports.canResizeTimelineSequenceDuration = exports.isTimelineSequenceDurationDraggable = exports.isCascadingSequence = exports.isTransitionSeriesSequence = exports.timelineSequenceFromDragSnapThresholdPx = void 0;
36
+ exports.TimelineSequenceRightEdgeDragHandle = exports.useTimelineSequenceFromDrag = exports.TimelineSequenceLeftEdgeDragHandle = exports.getTimelineSequenceFromDragTargets = exports.getTimelineSequenceLeftEdgeDragTargets = exports.getTimelineSequenceDurationDragTargets = exports.getTimelineSequenceFromDragKeyframeMoves = exports.getTimelineSequenceFromDragChanges = exports.getTimelineSequenceFromDragDelta = exports.getTimelineSequenceFromDragValue = exports.getTimelineSequenceDurationDragChanges = exports.getTimelineSequenceLeftEdgeDragChanges = exports.getTimelineSequenceLeftEdgeDragValues = exports.getTimelineSequenceLeftEdgeDragDelta = exports.getTimelineSequenceDurationDragValue = exports.isTimelineSequenceLeftEdgeDraggable = exports.canResizeTimelineSequenceDuration = exports.isTimelineSequenceDurationDraggable = exports.isCascadingSequence = exports.isTransitionSeriesSequence = exports.getTimelineSequenceMediaDurationDragLimits = exports.TimelineSequenceMediaDurationDragLimitsProvider = exports.TimelineSequenceMediaDurationDragLimitsContext = exports.timelineSequenceFromDragSnapThresholdPx = void 0;
37
37
  const jsx_runtime_1 = require("react/jsx-runtime");
38
38
  const canvas_1 = require("@remotion/canvas");
39
39
  const studio_shared_1 = require("@remotion/studio-shared");
@@ -51,7 +51,46 @@ 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
+ exports.TimelineSequenceMediaDurationDragLimitsContext = react_1.default.createContext(null);
57
+ const TimelineSequenceMediaDurationDragLimitsProvider = ({ children }) => {
58
+ const limits = (0, react_1.useRef)(new Map());
59
+ return (jsx_runtime_1.jsx(exports.TimelineSequenceMediaDurationDragLimitsContext.Provider, { value: limits, children: children }));
60
+ };
61
+ exports.TimelineSequenceMediaDurationDragLimitsProvider = TimelineSequenceMediaDurationDragLimitsProvider;
62
+ const getTimelineSequenceMediaDurationDragLimits = ({ cascadedStart, displayDurationInFrames, displayStart, effectiveMaxMediaDuration, explicitDurationInFrames, hasImplicitDuration, naturalMediaDuration, timelineDurationInFrames, }) => {
63
+ if (naturalMediaDuration === null ||
64
+ !Number.isFinite(naturalMediaDuration) ||
65
+ naturalMediaDuration <= 0) {
66
+ return null;
67
+ }
68
+ const initialDuration = explicitDurationInFrames !== null && explicitDurationInFrames !== void 0 ? explicitDurationInFrames : Math.ceil(displayStart +
69
+ Math.max(0, Math.min(displayDurationInFrames, timelineDurationInFrames - displayStart, effectiveMaxMediaDuration !== null && effectiveMaxMediaDuration !== void 0 ? effectiveMaxMediaDuration : Infinity)) -
70
+ cascadedStart);
71
+ const maximumDuration =
72
+ // Keeping duration omitted represents the media's natural end. An
73
+ // explicit duration is only useful once its edge is before that end.
74
+ Math.ceil(displayStart + naturalMediaDuration - cascadedStart) -
75
+ (hasImplicitDuration ? 1 : 0);
76
+ if (hasImplicitDuration && initialDuration > maximumDuration) {
77
+ return null;
78
+ }
79
+ return { initialDuration, maximumDuration };
80
+ };
81
+ exports.getTimelineSequenceMediaDurationDragLimits = getTimelineSequenceMediaDurationDragLimits;
82
+ const getTimelineSequenceEdgeSelectionInteraction = ({ button, selected, shiftKey, metaKey, ctrlKey, }) => {
83
+ if (button !== 0 ||
84
+ !(0, TimelineSelection_1.shouldSelectTimelineRowOnPointerDown)({
85
+ selected,
86
+ shiftKey,
87
+ metaKey,
88
+ ctrlKey,
89
+ })) {
90
+ return null;
91
+ }
92
+ return { shiftKey, toggleKey: metaKey || ctrlKey };
93
+ };
55
94
  const baseStyle = {
56
95
  position: 'absolute',
57
96
  top: 0,
@@ -192,14 +231,8 @@ const isTimelineSequenceDurationDraggable = (sequence) => {
192
231
  Boolean(sequence.controls));
193
232
  };
194
233
  exports.isTimelineSequenceDurationDraggable = isTimelineSequenceDurationDraggable;
195
- const canResizeTimelineSequenceDuration = ({ sequence, status, }) => {
196
- if ((status === null || status === void 0 ? void 0 : status.status) !== 'static') {
197
- return false;
198
- }
199
- if (sequence.type === 'audio' || sequence.type === 'video') {
200
- return status.codeValue !== undefined;
201
- }
202
- return true;
234
+ const canResizeTimelineSequenceDuration = ({ status, }) => {
235
+ return (status === null || status === void 0 ? void 0 : status.status) === 'static';
203
236
  };
204
237
  exports.canResizeTimelineSequenceDuration = canResizeTimelineSequenceDuration;
205
238
  const isTimelineSequenceLeftEdgeDraggable = (sequence) => {
@@ -233,7 +266,7 @@ const isFromDraggableSequence = (sequence) => {
233
266
  !sequence.isInsideSeries &&
234
267
  Boolean(sequence.controls));
235
268
  };
236
- const getTimelineSequenceDurationDragValue = ({ initialDuration, deltaFrames, minimumDuration = 1, }) => Math.max(minimumDuration, initialDuration + deltaFrames);
269
+ const getTimelineSequenceDurationDragValue = ({ initialDuration, deltaFrames, maximumDuration, minimumDuration = 1, }) => Math.min(maximumDuration, Math.max(minimumDuration, initialDuration + deltaFrames));
237
270
  exports.getTimelineSequenceDurationDragValue = getTimelineSequenceDurationDragValue;
238
271
  const getTimelineSequenceLeftEdgeDragDelta = ({ initialDuration, initialTrimBefore, deltaFrames, playbackRate, minimumDuration = 1, }) => {
239
272
  const minDeltaFrames = 0 - initialTrimBefore / playbackRate;
@@ -252,7 +285,10 @@ const getTimelineSequenceLeftEdgeDragValues = ({ initialDuration, initialFrom, i
252
285
  return {
253
286
  durationInFrames: initialDuration - clampedDeltaFrames,
254
287
  from: initialFrom + clampedDeltaFrames,
255
- trimBefore: initialTrimBefore + clampedDeltaFrames * playbackRate,
288
+ // Division and multiplication by playbackRate may not cancel exactly.
289
+ trimBefore: clampedDeltaFrames === -initialTrimBefore / playbackRate
290
+ ? 0
291
+ : initialTrimBefore + clampedDeltaFrames * playbackRate,
256
292
  };
257
293
  };
258
294
  exports.getTimelineSequenceLeftEdgeDragValues = getTimelineSequenceLeftEdgeDragValues;
@@ -307,6 +343,7 @@ const getTimelineSequenceDurationDragChanges = ({ targets, deltaFrames, }) => {
307
343
  const nextValue = (0, exports.getTimelineSequenceDurationDragValue)({
308
344
  initialDuration: target.initialDuration,
309
345
  deltaFrames,
346
+ maximumDuration: target.maximumDuration,
310
347
  minimumDuration: target.minimumDuration,
311
348
  });
312
349
  if (nextValue === target.initialDuration) {
@@ -327,14 +364,11 @@ const getTimelineSequenceDurationDragChanges = ({ targets, deltaFrames, }) => {
327
364
  exports.getTimelineSequenceDurationDragChanges = getTimelineSequenceDurationDragChanges;
328
365
  const getTimelineSequenceFromDragValue = ({ initialFrom, deltaFrames, }) => initialFrom + deltaFrames;
329
366
  exports.getTimelineSequenceFromDragValue = getTimelineSequenceFromDragValue;
330
- const getTimelineSequenceFromDragDelta = ({ deltaFrames, pxPerFrame, snappingEnabled, targets, }) => {
367
+ const getTimelineSequenceFromDragDelta = ({ deltaFrames, timelineDurationInFrames, pxPerFrame, snappingEnabled, targets, }) => {
331
368
  var _a;
332
- if (!snappingEnabled) {
333
- return deltaFrames;
334
- }
335
369
  let closestSnap;
336
370
  for (const target of targets) {
337
- if (!target.canSnapToTimelineStart) {
371
+ if (!snappingEnabled || !target.canSnapToTimelineStart) {
338
372
  continue;
339
373
  }
340
374
  const nextFrom = (0, exports.getTimelineSequenceFromDragValue)({
@@ -351,7 +385,10 @@ const getTimelineSequenceFromDragDelta = ({ deltaFrames, pxPerFrame, snappingEna
351
385
  distancePx,
352
386
  };
353
387
  }
354
- return (_a = closestSnap === null || closestSnap === void 0 ? void 0 : closestSnap.deltaFrames) !== null && _a !== void 0 ? _a : deltaFrames;
388
+ const minimumDelta = Math.max(...targets.map((target) => target.minimumDeltaFrames));
389
+ const maximumDelta = Math.min(...targets.map((target) => timelineDurationInFrames - 1 - target.initialTimelineStart));
390
+ // Clamp the shared delta after snapping so every selected track retains a frame.
391
+ return Math.max(minimumDelta, Math.min(maximumDelta, (_a = closestSnap === null || closestSnap === void 0 ? void 0 : closestSnap.deltaFrames) !== null && _a !== void 0 ? _a : deltaFrames));
355
392
  };
356
393
  exports.getTimelineSequenceFromDragDelta = getTimelineSequenceFromDragDelta;
357
394
  const getTimelineSequenceFromDragChanges = ({ targets, deltaFrames, }) => {
@@ -416,8 +453,9 @@ const findSequenceTrack = ({ tracks, nodePathInfo, }) => {
416
453
  return ((0, studio_shared_1.stringifySequenceExpandedRowKey)(candidate.nodePathInfo.sequenceSubscriptionKey) === key && candidate.nodePathInfo.index === nodePathInfo.index);
417
454
  });
418
455
  };
419
- const getTimelineSequenceDurationDragTargets = ({ draggedNodePathInfo, selectedItems, sequences, overrideIdsToNodePaths, propStatuses, }) => {
456
+ const getTimelineSequenceDurationDragTargets = ({ draggedNodePathInfo, draggedSequenceMediaDurationDragLimits, selectedSequenceMediaDurationDragLimits, selectedItems, sequences, overrideIdsToNodePaths, propStatuses, timelineDurationInFrames, }) => {
420
457
  var _a;
458
+ var _b, _c, _d;
421
459
  const draggedSelectionKey = (0, TimelineSelection_1.getTimelineSequenceSelectionKey)(draggedNodePathInfo);
422
460
  const selectedSequenceItems = selectedItems.filter((item) => item.type === 'sequence');
423
461
  const draggedItemIsSelected = selectedSequenceItems.some((item) => (0, TimelineSelection_1.getTimelineSequenceSelectionKey)(item.nodePathInfo) ===
@@ -445,7 +483,6 @@ const getTimelineSequenceDurationDragTargets = ({ draggedNodePathInfo, selectedI
445
483
  const nodePath = track.nodePathInfo.sequenceSubscriptionKey;
446
484
  const durationStatus = (_a = remotion_1.Internals.getPropStatusesCtx(propStatuses, nodePath)) === null || _a === void 0 ? void 0 : _a.durationInFrames;
447
485
  if (!(0, exports.canResizeTimelineSequenceDuration)({
448
- sequence: originalSequence,
449
486
  status: durationStatus,
450
487
  })) {
451
488
  return null;
@@ -456,13 +493,29 @@ const getTimelineSequenceDurationDragTargets = ({ draggedNodePathInfo, selectedI
456
493
  }
457
494
  const key = (0, studio_shared_1.stringifySequenceSubscriptionKey)(nodePath);
458
495
  if (!targets.has(key)) {
496
+ const selectionKey = (0, TimelineSelection_1.getTimelineSequenceSelectionKey)(nodePathInfo);
497
+ const isMedia = originalSequence.type === 'audio' || originalSequence.type === 'video';
498
+ const isDraggedSequence = selectionKey === draggedSelectionKey;
499
+ const mediaDurationDragLimits = isMedia
500
+ ? isDraggedSequence
501
+ ? draggedSequenceMediaDurationDragLimits
502
+ : ((_b = selectedSequenceMediaDurationDragLimits === null || selectedSequenceMediaDurationDragLimits === void 0 ? void 0 : selectedSequenceMediaDurationDragLimits.get(selectionKey)) !== null && _b !== void 0 ? _b : null)
503
+ : null;
504
+ if (isMedia && mediaDurationDragLimits === null) {
505
+ return null;
506
+ }
507
+ const minimumDuration = Math.max(1 - originalSequence.from, getMinimumSequenceDuration({ sequence: originalSequence, sequences }));
508
+ const initialDuration = (_c = mediaDurationDragLimits === null || mediaDurationDragLimits === void 0 ? void 0 : mediaDurationDragLimits.initialDuration) !== null && _c !== void 0 ? _c : originalSequence.duration;
509
+ const constrainedMaximumDuration = Math.min((_d = mediaDurationDragLimits === null || mediaDurationDragLimits === void 0 ? void 0 : mediaDurationDragLimits.maximumDuration) !== null && _d !== void 0 ? _d : Infinity, timelineDurationInFrames - track.cascadedStart);
510
+ const maximumDuration = isMedia
511
+ ? Math.max(minimumDuration, initialDuration, constrainedMaximumDuration)
512
+ : Math.max(minimumDuration, constrainedMaximumDuration);
459
513
  targets.set(key, {
460
514
  fileName: nodePath.absolutePath,
461
- initialDuration: originalSequence.duration,
462
- minimumDuration: getMinimumSequenceDuration({
463
- sequence: originalSequence,
464
- sequences,
465
- }),
515
+ initialDuration,
516
+ maximumDuration,
517
+ // A negative start needs enough duration to retain one visible frame.
518
+ minimumDuration,
466
519
  nodePath,
467
520
  schema: controls.schema,
468
521
  });
@@ -558,6 +611,7 @@ const getTimelineSequenceFromDragTargets = ({ draggedNodePathInfo, selectedItems
558
611
  {
559
612
  nodePath: track.nodePathInfo.sequenceSubscriptionKey,
560
613
  originalSequence,
614
+ initialTimelineStart: track.cascadedStart,
561
615
  },
562
616
  ];
563
617
  });
@@ -579,7 +633,7 @@ const getTimelineSequenceFromDragTargets = ({ draggedNodePathInfo, selectedItems
579
633
  });
580
634
  const targets = new Map();
581
635
  const includedKeyframeNodePaths = new Set();
582
- for (const { nodePath, originalSequence, } of sequencesWithoutSelectedAncestors) {
636
+ for (const { nodePath, originalSequence, initialTimelineStart, } of sequencesWithoutSelectedAncestors) {
583
637
  if (!isFromDraggableSequence(originalSequence)) {
584
638
  return null;
585
639
  }
@@ -627,6 +681,8 @@ const getTimelineSequenceFromDragTargets = ({ draggedNodePathInfo, selectedItems
627
681
  const sequenceKeyframes = descendantKeyframes.flatMap((descendant) => descendant.sequenceKeyframes);
628
682
  targets.set(key, {
629
683
  canSnapToTimelineStart: originalSequence.parent === null,
684
+ minimumDeltaFrames: 1 - originalSequence.duration - originalSequence.from,
685
+ initialTimelineStart,
630
686
  effectKeyframes,
631
687
  fileName: nodePath.absolutePath,
632
688
  initialFrom: originalSequence.from,
@@ -665,14 +721,14 @@ const clearFromDragOverrides = ({ clearDragOverrides, clearEffectDragOverrides,
665
721
  }
666
722
  }
667
723
  };
668
- const TimelineSequenceLeftEdgeDragHandleInner = ({ nodePathInfo, windowWidth, timelineDurationInFrames, onDragEnd }) => {
724
+ const TimelineSequenceLeftEdgeDragHandleInner = ({ nodePathInfo, windowWidth, timelineDurationInFrames, onDragEnd, onSelect, selected, }) => {
669
725
  const { setPropStatuses, setDragOverrides, clearDragOverrides } = (0, react_1.useContext)(remotion_1.Internals.VisualModeSettersContext);
670
726
  const propStatusesRef = (0, react_1.useContext)(remotion_1.Internals.VisualModePropStatusesRefContext);
671
727
  const sequencesRef = (0, react_1.useContext)(remotion_1.Internals.SequenceManagerRefContext);
672
728
  const { overrideIdToNodePathMappings } = (0, react_1.useContext)(remotion_1.Internals.OverrideIdsToNodePathsGettersContext);
673
729
  const { previewServerState } = (0, react_1.useContext)(client_id_1.StudioServerConnectionCtx);
674
730
  const currentSelection = (0, TimelineSelection_1.useCurrentTimelineSelectionStateAsRef)();
675
- const [dragging, setDragging] = (0, react_1.useState)(false);
731
+ const stopPointerSessionRef = (0, react_1.useRef)(null);
676
732
  const dragStateRef = (0, react_1.useRef)(null);
677
733
  const latestRef = (0, react_1.useRef)({
678
734
  nodePathInfo,
@@ -682,6 +738,7 @@ const TimelineSequenceLeftEdgeDragHandleInner = ({ nodePathInfo, windowWidth, ti
682
738
  previewServerState,
683
739
  overrideIdToNodePathMappings,
684
740
  onDragEnd,
741
+ onSelect,
685
742
  });
686
743
  latestRef.current = {
687
744
  nodePathInfo,
@@ -691,6 +748,7 @@ const TimelineSequenceLeftEdgeDragHandleInner = ({ nodePathInfo, windowWidth, ti
691
748
  previewServerState,
692
749
  overrideIdToNodePathMappings,
693
750
  onDragEnd,
751
+ onSelect,
694
752
  };
695
753
  const finishDrag = (0, react_1.useCallback)((commit) => {
696
754
  const dragState = dragStateRef.current;
@@ -702,7 +760,11 @@ const TimelineSequenceLeftEdgeDragHandleInner = ({ nodePathInfo, windowWidth, ti
702
760
  document.body.style.userSelect = '';
703
761
  document.body.style.webkitUserSelect = '';
704
762
  (0, ForceSpecificCursor_1.stopForcingSpecificCursor)();
705
- setDragging(false);
763
+ if (commit &&
764
+ !dragState.didMove &&
765
+ dragState.selectionInteraction !== null) {
766
+ latestRef.current.onSelect(dragState.selectionInteraction);
767
+ }
706
768
  const { setPropStatuses: latestSetPropStatuses, clearDragOverrides: latestClear, previewServerState: latestServerState, } = latestRef.current;
707
769
  const changes = (0, exports.getTimelineSequenceLeftEdgeDragChanges)({
708
770
  targets: dragState.targets,
@@ -742,65 +804,61 @@ const TimelineSequenceLeftEdgeDragHandleInner = ({ nodePathInfo, windowWidth, ti
742
804
  });
743
805
  }, []);
744
806
  const onPointerDown = (0, react_1.useCallback)((e) => {
745
- var _a, _b;
807
+ var _a;
808
+ var _b;
746
809
  if (e.button !== 0) {
747
810
  return;
748
811
  }
812
+ e.stopPropagation();
813
+ e.preventDefault();
814
+ const selectionInteraction = getTimelineSequenceEdgeSelectionInteraction({
815
+ button: e.button,
816
+ selected,
817
+ shiftKey: e.shiftKey,
818
+ metaKey: e.metaKey,
819
+ ctrlKey: e.ctrlKey,
820
+ });
749
821
  const pxPerFrame = timelineDurationInFrames > 0
750
822
  ? (windowWidth - timeline_layout_1.TIMELINE_PADDING * 2) / timelineDurationInFrames
751
823
  : 0;
752
- if (pxPerFrame <= 0) {
753
- return;
754
- }
824
+ const canCalculateDelta = Number.isFinite(pxPerFrame) && pxPerFrame > 0;
755
825
  const { nodePathInfo: latestNodePathInfo, overrideIdToNodePathMappings: latestOverrideIdsToNodePaths, } = latestRef.current;
756
826
  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();
827
+ const targets = canCalculateDelta
828
+ ? ((_b = (0, exports.getTimelineSequenceLeftEdgeDragTargets)({
829
+ draggedNodePathInfo: latestNodePathInfo,
830
+ selectedItems: latestSelectedItems,
831
+ sequences: sequencesRef.current,
832
+ overrideIdsToNodePaths: latestOverrideIdsToNodePaths,
833
+ propStatuses: propStatusesRef.current,
834
+ })) !== null && _b !== void 0 ? _b : [])
835
+ : [];
836
+ (_a = stopPointerSessionRef.current) === null || _a === void 0 ? void 0 : _a.call(stopPointerSessionRef);
769
837
  dragStateRef.current = {
770
838
  initialClientX: e.clientX,
771
839
  latestDeltaFrames: 0,
772
840
  didMove: false,
773
- pxPerFrame,
841
+ pxPerFrame: canCalculateDelta ? pxPerFrame : 1,
774
842
  pointerId: e.pointerId,
775
- button: e.button,
776
- target: e.currentTarget,
843
+ selectionInteraction,
777
844
  targets,
778
845
  };
779
- (_b = (_a = e.currentTarget).setPointerCapture) === null || _b === void 0 ? void 0 : _b.call(_a, e.pointerId);
780
846
  document.body.style.userSelect = 'none';
781
847
  document.body.style.webkitUserSelect = 'none';
782
848
  (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) => {
849
+ const onMove = (pointerEvent) => {
796
850
  const dragState = dragStateRef.current;
797
- if (!dragState || e.pointerId !== dragState.pointerId) {
851
+ if (!dragState || pointerEvent.pointerId !== dragState.pointerId) {
798
852
  return;
799
853
  }
800
- const dx = e.clientX - dragState.initialClientX;
854
+ const dx = pointerEvent.clientX - dragState.initialClientX;
801
855
  const deltaFrames = Math.round(dx / dragState.pxPerFrame);
802
856
  dragState.latestDeltaFrames = deltaFrames;
803
- if (deltaFrames !== 0) {
857
+ if (Math.abs(dx) >= timelineSequenceEdgeDragThresholdPx ||
858
+ (0, exports.getTimelineSequenceLeftEdgeDragChanges)({
859
+ targets: dragState.targets,
860
+ deltaFrames,
861
+ }).length > 0) {
804
862
  dragState.didMove = true;
805
863
  }
806
864
  for (const target of dragState.targets) {
@@ -819,31 +877,28 @@ const TimelineSequenceLeftEdgeDragHandleInner = ({ nodePathInfo, windowWidth, ti
819
877
  latestRef.current.setDragOverrides(target.nodePath, 'trimBefore', remotion_1.Internals.makeStaticDragOverride(nextValues.trimBefore));
820
878
  }
821
879
  };
822
- const onUp = (e) => {
880
+ const onUp = (pointerEvent) => {
823
881
  const dragState = dragStateRef.current;
824
- if (!dragState || e.pointerId !== dragState.pointerId) {
882
+ if (!dragState || pointerEvent.pointerId !== dragState.pointerId) {
825
883
  return;
826
884
  }
827
885
  // Include the release position even if the final pointermove was skipped.
828
- onMove(e);
886
+ onMove(pointerEvent);
829
887
  finishDrag(true);
830
888
  };
831
- const onCancel = (e) => {
889
+ const onCancel = (pointerEvent) => {
832
890
  const dragState = dragStateRef.current;
833
- if (!dragState || e.pointerId !== dragState.pointerId) {
891
+ if (!dragState || pointerEvent.pointerId !== dragState.pointerId) {
834
892
  return;
835
893
  }
836
894
  finishDrag(false);
837
895
  };
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,
896
+ stopPointerSessionRef.current = (0, pointer_session_1.startCapturedPointerSession)({
897
+ event: e.nativeEvent,
898
+ captureTarget: e.currentTarget,
845
899
  onMove,
846
900
  onEnd: (reason, endEvent) => {
901
+ stopPointerSessionRef.current = null;
847
902
  if ((reason === 'pointerup' ||
848
903
  reason === 'buttons-released' ||
849
904
  (reason === 'lostpointercapture' && (endEvent === null || endEvent === void 0 ? void 0 : endEvent.buttons) === 0)) &&
@@ -858,7 +913,22 @@ const TimelineSequenceLeftEdgeDragHandleInner = ({ nodePathInfo, windowWidth, ti
858
913
  }
859
914
  },
860
915
  });
861
- }, [dragging, finishDrag]);
916
+ }, [
917
+ currentSelection,
918
+ finishDrag,
919
+ propStatusesRef,
920
+ selected,
921
+ sequencesRef,
922
+ timelineDurationInFrames,
923
+ windowWidth,
924
+ ]);
925
+ (0, react_1.useEffect)(() => {
926
+ return () => {
927
+ var _a;
928
+ (_a = stopPointerSessionRef.current) === null || _a === void 0 ? void 0 : _a.call(stopPointerSessionRef);
929
+ stopPointerSessionRef.current = null;
930
+ };
931
+ }, []);
862
932
  const style = {
863
933
  ...baseStyle,
864
934
  left: -HANDLE_OUTSET,
@@ -998,16 +1068,17 @@ const useTimelineSequenceFromDrag = ({ nodePathInfo, windowWidth, timelineDurati
998
1068
  document.body.style.webkitUserSelect = 'none';
999
1069
  // Register before React commits so no pointer move can arrive before
1000
1070
  // the global session listeners exist.
1001
- stopPointerSessionRef.current = (0, pointer_session_1.startCapturedPointerSession)({
1071
+ stopPointerSessionRef.current = (0, pointer_session_1.startDeferredCapturedPointerSession)({
1002
1072
  event: e.nativeEvent,
1003
- captureTarget: e.currentTarget,
1004
- onMove: (moveEvent) => {
1073
+ captureTarget: e.currentTarget.ownerDocument.body,
1074
+ onMove: (moveEvent, capturePointer) => {
1005
1075
  const dragState = dragStateRef.current;
1006
1076
  if (!dragState) {
1007
1077
  return;
1008
1078
  }
1009
1079
  const dx = moveEvent.clientX - dragState.initialClientX;
1010
1080
  const deltaFrames = (0, exports.getTimelineSequenceFromDragDelta)({
1081
+ timelineDurationInFrames,
1011
1082
  deltaFrames: Math.round(dx / dragState.pxPerFrame),
1012
1083
  pxPerFrame: dragState.pxPerFrame,
1013
1084
  snappingEnabled: latestRef.current.editorSnapping,
@@ -1015,6 +1086,10 @@ const useTimelineSequenceFromDrag = ({ nodePathInfo, windowWidth, timelineDurati
1015
1086
  });
1016
1087
  dragState.latestDeltaFrames = deltaFrames;
1017
1088
  if (deltaFrames !== 0) {
1089
+ // The bar can be removed when it leaves the visible timeline.
1090
+ // Capture only after a real drag starts so clicks and double-clicks
1091
+ // remain targeted at the bar.
1092
+ capturePointer();
1018
1093
  dragState.didMove = true;
1019
1094
  }
1020
1095
  for (const target of dragState.targets) {
@@ -1073,33 +1148,38 @@ const useTimelineSequenceFromDrag = ({ nodePathInfo, windowWidth, timelineDurati
1073
1148
  };
1074
1149
  };
1075
1150
  exports.useTimelineSequenceFromDrag = useTimelineSequenceFromDrag;
1076
- const TimelineSequenceRightEdgeDragHandleInner = ({ nodePathInfo, windowWidth, timelineDurationInFrames, onDragEnd }) => {
1151
+ const TimelineSequenceRightEdgeDragHandleInner = ({ nodePathInfo, mediaDurationDragLimits, windowWidth, timelineDurationInFrames, onDragEnd, onSelect, selected, }) => {
1077
1152
  const { setPropStatuses, setDragOverrides, clearDragOverrides } = (0, react_1.useContext)(remotion_1.Internals.VisualModeSettersContext);
1078
1153
  const propStatusesRef = (0, react_1.useContext)(remotion_1.Internals.VisualModePropStatusesRefContext);
1079
1154
  const sequencesRef = (0, react_1.useContext)(remotion_1.Internals.SequenceManagerRefContext);
1080
1155
  const { overrideIdToNodePathMappings } = (0, react_1.useContext)(remotion_1.Internals.OverrideIdsToNodePathsGettersContext);
1081
1156
  const { previewServerState } = (0, react_1.useContext)(client_id_1.StudioServerConnectionCtx);
1082
1157
  const currentSelection = (0, TimelineSelection_1.useCurrentTimelineSelectionStateAsRef)();
1083
- const [dragging, setDragging] = (0, react_1.useState)(false);
1158
+ const mediaDurationDragLimitsRegistry = (0, react_1.useContext)(exports.TimelineSequenceMediaDurationDragLimitsContext);
1159
+ const stopPointerSessionRef = (0, react_1.useRef)(null);
1084
1160
  const dragStateRef = (0, react_1.useRef)(null);
1085
1161
  // Keep latest props/setters available to window listeners installed once at pointerdown.
1086
1162
  const latestRef = (0, react_1.useRef)({
1087
1163
  nodePathInfo,
1164
+ mediaDurationDragLimits,
1088
1165
  setPropStatuses,
1089
1166
  setDragOverrides,
1090
1167
  clearDragOverrides,
1091
1168
  previewServerState,
1092
1169
  overrideIdToNodePathMappings,
1093
1170
  onDragEnd,
1171
+ onSelect,
1094
1172
  });
1095
1173
  latestRef.current = {
1096
1174
  nodePathInfo,
1175
+ mediaDurationDragLimits,
1097
1176
  setPropStatuses,
1098
1177
  setDragOverrides,
1099
1178
  clearDragOverrides,
1100
1179
  previewServerState,
1101
1180
  overrideIdToNodePathMappings,
1102
1181
  onDragEnd,
1182
+ onSelect,
1103
1183
  };
1104
1184
  const finishDrag = (0, react_1.useCallback)((commit) => {
1105
1185
  const dragState = dragStateRef.current;
@@ -1111,7 +1191,11 @@ const TimelineSequenceRightEdgeDragHandleInner = ({ nodePathInfo, windowWidth, t
1111
1191
  document.body.style.userSelect = '';
1112
1192
  document.body.style.webkitUserSelect = '';
1113
1193
  (0, ForceSpecificCursor_1.stopForcingSpecificCursor)();
1114
- setDragging(false);
1194
+ if (commit &&
1195
+ !dragState.didMove &&
1196
+ dragState.selectionInteraction !== null) {
1197
+ latestRef.current.onSelect(dragState.selectionInteraction);
1198
+ }
1115
1199
  const { setPropStatuses: latestSetPropStatuses, clearDragOverrides: latestClear, previewServerState: latestServerState, } = latestRef.current;
1116
1200
  const changes = (0, exports.getTimelineSequenceDurationDragChanges)({
1117
1201
  targets: dragState.targets,
@@ -1149,103 +1233,98 @@ const TimelineSequenceRightEdgeDragHandleInner = ({ nodePathInfo, windowWidth, t
1149
1233
  });
1150
1234
  }, []);
1151
1235
  const onPointerDown = (0, react_1.useCallback)((e) => {
1152
- var _a, _b;
1236
+ var _a;
1237
+ var _b, _c;
1153
1238
  if (e.button !== 0) {
1154
1239
  return;
1155
1240
  }
1241
+ e.stopPropagation();
1242
+ e.preventDefault();
1243
+ const selectionInteraction = getTimelineSequenceEdgeSelectionInteraction({
1244
+ button: e.button,
1245
+ selected,
1246
+ shiftKey: e.shiftKey,
1247
+ metaKey: e.metaKey,
1248
+ ctrlKey: e.ctrlKey,
1249
+ });
1156
1250
  const pxPerFrame = timelineDurationInFrames > 0
1157
1251
  ? (windowWidth - timeline_layout_1.TIMELINE_PADDING * 2) / timelineDurationInFrames
1158
1252
  : 0;
1159
- if (pxPerFrame <= 0) {
1160
- return;
1161
- }
1162
- const { nodePathInfo: latestNodePathInfo, overrideIdToNodePathMappings: latestOverrideIdsToNodePaths, } = latestRef.current;
1253
+ const canCalculateDelta = Number.isFinite(pxPerFrame) && pxPerFrame > 0;
1254
+ const { nodePathInfo: latestNodePathInfo, mediaDurationDragLimits: latestMediaDurationDragLimits, overrideIdToNodePathMappings: latestOverrideIdsToNodePaths, } = latestRef.current;
1163
1255
  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();
1256
+ const targets = canCalculateDelta
1257
+ ? ((_c = (0, exports.getTimelineSequenceDurationDragTargets)({
1258
+ draggedNodePathInfo: latestNodePathInfo,
1259
+ draggedSequenceMediaDurationDragLimits: latestMediaDurationDragLimits,
1260
+ selectedSequenceMediaDurationDragLimits: (_b = mediaDurationDragLimitsRegistry === null || mediaDurationDragLimitsRegistry === void 0 ? void 0 : mediaDurationDragLimitsRegistry.current) !== null && _b !== void 0 ? _b : null,
1261
+ selectedItems: latestSelectedItems,
1262
+ sequences: sequencesRef.current,
1263
+ overrideIdsToNodePaths: latestOverrideIdsToNodePaths,
1264
+ propStatuses: propStatusesRef.current,
1265
+ timelineDurationInFrames,
1266
+ })) !== null && _c !== void 0 ? _c : [])
1267
+ : [];
1268
+ (_a = stopPointerSessionRef.current) === null || _a === void 0 ? void 0 : _a.call(stopPointerSessionRef);
1176
1269
  dragStateRef.current = {
1177
1270
  initialClientX: e.clientX,
1178
1271
  latestDeltaFrames: 0,
1179
1272
  didMove: false,
1180
- pxPerFrame,
1273
+ pxPerFrame: canCalculateDelta ? pxPerFrame : 1,
1181
1274
  pointerId: e.pointerId,
1182
- button: e.button,
1183
- target: e.currentTarget,
1275
+ selectionInteraction,
1184
1276
  targets,
1185
1277
  };
1186
- (_b = (_a = e.currentTarget).setPointerCapture) === null || _b === void 0 ? void 0 : _b.call(_a, e.pointerId);
1187
1278
  document.body.style.userSelect = 'none';
1188
1279
  document.body.style.webkitUserSelect = 'none';
1189
1280
  (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) => {
1281
+ const onMove = (pointerEvent) => {
1206
1282
  const dragState = dragStateRef.current;
1207
- if (!dragState || e.pointerId !== dragState.pointerId) {
1283
+ if (!dragState || pointerEvent.pointerId !== dragState.pointerId) {
1208
1284
  return;
1209
1285
  }
1210
- const dx = e.clientX - dragState.initialClientX;
1286
+ const dx = pointerEvent.clientX - dragState.initialClientX;
1211
1287
  const deltaFrames = Math.round(dx / dragState.pxPerFrame);
1212
1288
  dragState.latestDeltaFrames = deltaFrames;
1213
- if (deltaFrames !== 0) {
1289
+ if (Math.abs(dx) >= timelineSequenceEdgeDragThresholdPx ||
1290
+ (0, exports.getTimelineSequenceDurationDragChanges)({
1291
+ targets: dragState.targets,
1292
+ deltaFrames,
1293
+ }).length > 0) {
1214
1294
  dragState.didMove = true;
1215
1295
  }
1216
1296
  for (const target of dragState.targets) {
1217
- latestRef.current.setDragOverrides(target.nodePath, 'durationInFrames', remotion_1.Internals.makeStaticDragOverride((0, exports.getTimelineSequenceDurationDragValue)({
1297
+ const previewValue = (0, exports.getTimelineSequenceDurationDragValue)({
1218
1298
  initialDuration: target.initialDuration,
1219
1299
  deltaFrames,
1300
+ maximumDuration: target.maximumDuration,
1220
1301
  minimumDuration: target.minimumDuration,
1221
- })));
1302
+ });
1303
+ latestRef.current.setDragOverrides(target.nodePath, 'durationInFrames', remotion_1.Internals.makeStaticDragOverride(previewValue));
1222
1304
  }
1223
1305
  };
1224
- const onUp = (e) => {
1306
+ const onUp = (pointerEvent) => {
1225
1307
  const dragState = dragStateRef.current;
1226
- if (!dragState || e.pointerId !== dragState.pointerId) {
1308
+ if (!dragState || pointerEvent.pointerId !== dragState.pointerId) {
1227
1309
  return;
1228
1310
  }
1229
1311
  // Include the release position even if the final pointermove was skipped.
1230
- onMove(e);
1312
+ onMove(pointerEvent);
1231
1313
  finishDrag(true);
1232
1314
  };
1233
- const onCancel = (e) => {
1315
+ const onCancel = (pointerEvent) => {
1234
1316
  const dragState = dragStateRef.current;
1235
- if (!dragState || e.pointerId !== dragState.pointerId) {
1317
+ if (!dragState || pointerEvent.pointerId !== dragState.pointerId) {
1236
1318
  return;
1237
1319
  }
1238
1320
  finishDrag(false);
1239
1321
  };
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,
1322
+ stopPointerSessionRef.current = (0, pointer_session_1.startCapturedPointerSession)({
1323
+ event: e.nativeEvent,
1324
+ captureTarget: e.currentTarget,
1247
1325
  onMove,
1248
1326
  onEnd: (reason, endEvent) => {
1327
+ stopPointerSessionRef.current = null;
1249
1328
  if ((reason === 'pointerup' ||
1250
1329
  reason === 'buttons-released' ||
1251
1330
  (reason === 'lostpointercapture' && (endEvent === null || endEvent === void 0 ? void 0 : endEvent.buttons) === 0)) &&
@@ -1260,7 +1339,23 @@ const TimelineSequenceRightEdgeDragHandleInner = ({ nodePathInfo, windowWidth, t
1260
1339
  }
1261
1340
  },
1262
1341
  });
1263
- }, [dragging, finishDrag]);
1342
+ }, [
1343
+ currentSelection,
1344
+ finishDrag,
1345
+ mediaDurationDragLimitsRegistry,
1346
+ propStatusesRef,
1347
+ selected,
1348
+ sequencesRef,
1349
+ timelineDurationInFrames,
1350
+ windowWidth,
1351
+ ]);
1352
+ (0, react_1.useEffect)(() => {
1353
+ return () => {
1354
+ var _a;
1355
+ (_a = stopPointerSessionRef.current) === null || _a === void 0 ? void 0 : _a.call(stopPointerSessionRef);
1356
+ stopPointerSessionRef.current = null;
1357
+ };
1358
+ }, []);
1264
1359
  const style = {
1265
1360
  ...baseStyle,
1266
1361
  right: -HANDLE_OUTSET,