@remotion/studio 4.0.482 → 4.0.484

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 (77) hide show
  1. package/dist/components/Canvas.js +19 -0
  2. package/dist/components/ColorPicker/ColorPicker.js +65 -3
  3. package/dist/components/ColorPicker/ColorPickerPopup.d.ts +1 -0
  4. package/dist/components/ColorPicker/ColorPickerPopup.js +3 -2
  5. package/dist/components/InspectorPanel/EasingInspector.js +184 -10
  6. package/dist/components/InspectorPanel/KeyframeEasingNavigator.d.ts +14 -0
  7. package/dist/components/InspectorPanel/KeyframeEasingNavigator.js +146 -0
  8. package/dist/components/InspectorPanel/KeyframeInspector.d.ts +1 -1
  9. package/dist/components/InspectorPanel/KeyframeInspector.js +228 -5
  10. package/dist/components/InspectorPanel/SequenceInspectorHeader.d.ts +17 -0
  11. package/dist/components/InspectorPanel/SequenceInspectorHeader.js +93 -0
  12. package/dist/components/InspectorPanel/SequenceSelectionInspector.js +4 -58
  13. package/dist/components/InspectorPanel/common.d.ts +12 -0
  14. package/dist/components/InspectorPanel/common.js +78 -1
  15. package/dist/components/InspectorPanel/easing-inspector-selection.d.ts +14 -0
  16. package/dist/components/InspectorPanel/easing-inspector-selection.js +18 -0
  17. package/dist/components/InspectorPanel/keyframe-easing-navigator-items.d.ts +24 -0
  18. package/dist/components/InspectorPanel/keyframe-easing-navigator-items.js +40 -0
  19. package/dist/components/InspectorPanel/keyframe-inspector-frame.d.ts +8 -0
  20. package/dist/components/InspectorPanel/keyframe-inspector-frame.js +14 -0
  21. package/dist/components/InspectorPanel/styles.d.ts +1 -0
  22. package/dist/components/InspectorPanel/styles.js +9 -1
  23. package/dist/components/InspectorSequenceSection.js +47 -10
  24. package/dist/components/Preview.js +1 -1
  25. package/dist/components/SelectedOutlineOverlay.d.ts +2 -0
  26. package/dist/components/SelectedOutlineOverlay.js +33 -12
  27. package/dist/components/SelectedOutlineUvControls.js +461 -2
  28. package/dist/components/Timeline/EasingEditorModal.js +48 -5
  29. package/dist/components/Timeline/Timeline.js +2 -1
  30. package/dist/components/Timeline/TimelineDeleteKeybindings.js +11 -1
  31. package/dist/components/Timeline/TimelineEffectItem.js +8 -5
  32. package/dist/components/Timeline/TimelineEffectPropItem.js +82 -1
  33. package/dist/components/Timeline/TimelineExpandedKeyframeRow.js +2 -2
  34. package/dist/components/Timeline/TimelineKeyframeControls.js +37 -7
  35. package/dist/components/Timeline/TimelineKeyframeEasingLine.d.ts +4 -0
  36. package/dist/components/Timeline/TimelineKeyframeEasingLine.js +12 -6
  37. package/dist/components/Timeline/TimelineKeyframedValue.js +1 -0
  38. package/dist/components/Timeline/TimelineRowChrome.js +6 -4
  39. package/dist/components/Timeline/TimelineSelection.d.ts +7 -1
  40. package/dist/components/Timeline/TimelineSelection.js +19 -3
  41. package/dist/components/Timeline/TimelineSequence.js +20 -8
  42. package/dist/components/Timeline/TimelineSequenceItem.js +64 -28
  43. package/dist/components/Timeline/TimelineSequenceName.d.ts +1 -0
  44. package/dist/components/Timeline/TimelineSequenceName.js +7 -6
  45. package/dist/components/Timeline/TimelineSequencePropItem.d.ts +1 -1
  46. package/dist/components/Timeline/TimelineSequencePropItem.js +80 -1
  47. package/dist/components/Timeline/TimelineSequenceRightEdgeDragHandle.d.ts +40 -1
  48. package/dist/components/Timeline/TimelineSequenceRightEdgeDragHandle.js +308 -1
  49. package/dist/components/Timeline/TimelineSlider.js +17 -3
  50. package/dist/components/Timeline/TimelineTrack.js +2 -4
  51. package/dist/components/Timeline/delete-selected-timeline-item.d.ts +8 -2
  52. package/dist/components/Timeline/delete-selected-timeline-item.js +80 -1
  53. package/dist/components/Timeline/get-animation-item-selection-for-frame.d.ts +18 -0
  54. package/dist/components/Timeline/get-animation-item-selection-for-frame.js +49 -0
  55. package/dist/components/Timeline/get-easing-selection-after-keyframe-delete.d.ts +15 -0
  56. package/dist/components/Timeline/get-easing-selection-after-keyframe-delete.js +26 -0
  57. package/dist/components/Timeline/save-sequence-prop.js +2 -0
  58. package/dist/components/Timeline/should-subscribe-to-sequence-props.d.ts +4 -0
  59. package/dist/components/Timeline/should-subscribe-to-sequence-props.js +10 -0
  60. package/dist/components/Timeline/update-selected-easing.d.ts +1 -0
  61. package/dist/components/Timeline/update-selected-easing.js +4 -3
  62. package/dist/components/Timeline/use-sequence-freeze-frame-menu-item.d.ts +2 -1
  63. package/dist/components/Timeline/use-sequence-freeze-frame-menu-item.js +19 -13
  64. package/dist/components/element-drag-and-drop.d.ts +3 -0
  65. package/dist/components/element-drag-and-drop.js +30 -0
  66. package/dist/components/import-assets.d.ts +11 -0
  67. package/dist/components/import-assets.js +23 -1
  68. package/dist/components/selected-outline-uv.d.ts +71 -1
  69. package/dist/components/selected-outline-uv.js +332 -10
  70. package/dist/esm/{chunk-nkqfa5bw.js → chunk-9erwh79m.js} +11896 -9019
  71. package/dist/esm/internals.mjs +11896 -9019
  72. package/dist/esm/previewEntry.mjs +11923 -9046
  73. package/dist/esm/renderEntry.mjs +1 -1
  74. package/dist/helpers/timeline-layout.d.ts +3 -3
  75. package/dist/helpers/timeline-layout.js +3 -1
  76. package/dist/helpers/use-menu-structure.js +0 -14
  77. package/package.json +11 -11
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.TimelineSequenceRightEdgeDragHandle = exports.useTimelineSequenceFromDrag = exports.getTimelineSequenceFromDragTargets = exports.getTimelineSequenceDurationDragTargets = exports.getTimelineSequenceFromDragChanges = exports.getTimelineSequenceFromDragValue = exports.getTimelineSequenceDurationDragChanges = exports.getTimelineSequenceDurationDragValue = void 0;
3
+ exports.TimelineSequenceRightEdgeDragHandle = exports.useTimelineSequenceFromDrag = exports.TimelineSequenceLeftEdgeDragHandle = exports.getTimelineSequenceFromDragTargets = exports.getTimelineSequenceLeftEdgeDragTargets = exports.getTimelineSequenceDurationDragTargets = exports.getTimelineSequenceFromDragChanges = exports.getTimelineSequenceFromDragValue = exports.getTimelineSequenceDurationDragChanges = exports.getTimelineSequenceLeftEdgeDragChanges = exports.getTimelineSequenceLeftEdgeDragValues = exports.getTimelineSequenceLeftEdgeDragDelta = exports.getTimelineSequenceDurationDragValue = void 0;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const studio_shared_1 = require("@remotion/studio-shared");
6
6
  const react_1 = require("react");
@@ -32,12 +32,25 @@ const canUpdateFrom = ({ propStatuses, nodePath, }) => {
32
32
  const status = (_b = (_a = remotion_1.Internals.getPropStatusesCtx(propStatuses, nodePath)) === null || _a === void 0 ? void 0 : _a.from) === null || _b === void 0 ? void 0 : _b.status;
33
33
  return status === 'static';
34
34
  };
35
+ const canUpdateTrimBefore = ({ propStatuses, nodePath, }) => {
36
+ var _a, _b;
37
+ const status = (_b = (_a = remotion_1.Internals.getPropStatusesCtx(propStatuses, nodePath)) === null || _a === void 0 ? void 0 : _a.trimBefore) === null || _b === void 0 ? void 0 : _b.status;
38
+ return status === 'static';
39
+ };
35
40
  const isDurationDraggableSequence = (sequence) => {
36
41
  return ((sequence.type === 'sequence' || sequence.type === 'image') &&
37
42
  !sequence.loopDisplay &&
38
43
  !sequence.isInsideSeries &&
39
44
  Boolean(sequence.controls));
40
45
  };
46
+ const isLeftEdgeDraggableSequence = (sequence) => {
47
+ return (!sequence.isInsideSeries &&
48
+ Boolean(sequence.controls) &&
49
+ (sequence.type === 'sequence' ||
50
+ sequence.type === 'image' ||
51
+ sequence.type === 'audio' ||
52
+ sequence.type === 'video'));
53
+ };
41
54
  const isFromDraggableSequence = (sequence) => {
42
55
  return (!sequence.loopDisplay &&
43
56
  !sequence.isInsideSeries &&
@@ -45,6 +58,68 @@ const isFromDraggableSequence = (sequence) => {
45
58
  };
46
59
  const getTimelineSequenceDurationDragValue = ({ initialDuration, deltaFrames, }) => Math.max(1, initialDuration + deltaFrames);
47
60
  exports.getTimelineSequenceDurationDragValue = getTimelineSequenceDurationDragValue;
61
+ const getTimelineSequenceLeftEdgeDragDelta = ({ initialDuration, initialTrimBefore, deltaFrames, }) => {
62
+ const minDeltaFrames = 0 - initialTrimBefore;
63
+ const maxDeltaFrames = initialDuration - 1;
64
+ return Math.max(minDeltaFrames, Math.min(deltaFrames, maxDeltaFrames));
65
+ };
66
+ exports.getTimelineSequenceLeftEdgeDragDelta = getTimelineSequenceLeftEdgeDragDelta;
67
+ const getTimelineSequenceLeftEdgeDragValues = ({ initialDuration, initialFrom, initialTrimBefore, deltaFrames, }) => {
68
+ const clampedDeltaFrames = (0, exports.getTimelineSequenceLeftEdgeDragDelta)({
69
+ initialDuration,
70
+ initialTrimBefore,
71
+ deltaFrames,
72
+ });
73
+ return {
74
+ durationInFrames: initialDuration - clampedDeltaFrames,
75
+ from: initialFrom + clampedDeltaFrames,
76
+ trimBefore: initialTrimBefore + clampedDeltaFrames,
77
+ };
78
+ };
79
+ exports.getTimelineSequenceLeftEdgeDragValues = getTimelineSequenceLeftEdgeDragValues;
80
+ const getTimelineSequenceLeftEdgeDragChanges = ({ targets, deltaFrames, }) => {
81
+ return targets.flatMap((target) => {
82
+ const nextValues = (0, exports.getTimelineSequenceLeftEdgeDragValues)({
83
+ initialDuration: target.initialDuration,
84
+ initialFrom: target.initialFrom,
85
+ initialTrimBefore: target.initialTrimBefore,
86
+ deltaFrames,
87
+ });
88
+ const changes = [];
89
+ if (nextValues.from !== target.initialFrom) {
90
+ changes.push({
91
+ fileName: target.fileName,
92
+ nodePath: target.nodePath,
93
+ fieldKey: 'from',
94
+ value: nextValues.from,
95
+ defaultValue: '0',
96
+ schema: target.schema,
97
+ });
98
+ }
99
+ if (nextValues.durationInFrames !== target.initialDuration) {
100
+ changes.push({
101
+ fileName: target.fileName,
102
+ nodePath: target.nodePath,
103
+ fieldKey: 'durationInFrames',
104
+ value: nextValues.durationInFrames,
105
+ defaultValue: null,
106
+ schema: target.schema,
107
+ });
108
+ }
109
+ if (nextValues.trimBefore !== target.initialTrimBefore) {
110
+ changes.push({
111
+ fileName: target.fileName,
112
+ nodePath: target.nodePath,
113
+ fieldKey: 'trimBefore',
114
+ value: nextValues.trimBefore,
115
+ defaultValue: '0',
116
+ schema: target.schema,
117
+ });
118
+ }
119
+ return changes;
120
+ });
121
+ };
122
+ exports.getTimelineSequenceLeftEdgeDragChanges = getTimelineSequenceLeftEdgeDragChanges;
48
123
  const getTimelineSequenceDurationDragChanges = ({ targets, deltaFrames, }) => {
49
124
  return targets.flatMap((target) => {
50
125
  const nextValue = (0, exports.getTimelineSequenceDurationDragValue)({
@@ -141,6 +216,60 @@ const getTimelineSequenceDurationDragTargets = ({ draggedNodePathInfo, selectedI
141
216
  return [...targets.values()];
142
217
  };
143
218
  exports.getTimelineSequenceDurationDragTargets = getTimelineSequenceDurationDragTargets;
219
+ const getTimelineSequenceLeftEdgeDragTargets = ({ draggedNodePathInfo, selectedItems, sequences, overrideIdsToNodePaths, propStatuses, }) => {
220
+ var _a, _b;
221
+ const draggedSelectionKey = (0, TimelineSelection_1.getTimelineSequenceSelectionKey)(draggedNodePathInfo);
222
+ const selectedSequenceItems = selectedItems.filter((item) => item.type === 'sequence');
223
+ const draggedItemIsSelected = selectedSequenceItems.some((item) => (0, TimelineSelection_1.getTimelineSequenceSelectionKey)(item.nodePathInfo) ===
224
+ draggedSelectionKey);
225
+ if (draggedItemIsSelected &&
226
+ selectedSequenceItems.length !== selectedItems.length) {
227
+ return null;
228
+ }
229
+ const targetNodePathInfos = draggedItemIsSelected && selectedSequenceItems.length > 1
230
+ ? selectedSequenceItems.map((item) => item.nodePathInfo)
231
+ : [draggedNodePathInfo];
232
+ const tracks = (0, calculate_timeline_1.calculateTimeline)({ sequences, overrideIdsToNodePaths });
233
+ const targets = new Map();
234
+ for (const nodePathInfo of targetNodePathInfos) {
235
+ const track = findSequenceTrack({ tracks, nodePathInfo });
236
+ const originalSequence = track
237
+ ? sequences.find((sequence) => sequence.id === track.sequence.id)
238
+ : null;
239
+ if (!track ||
240
+ !track.nodePathInfo ||
241
+ !originalSequence ||
242
+ !isLeftEdgeDraggableSequence(originalSequence)) {
243
+ return null;
244
+ }
245
+ const nodePath = track.nodePathInfo.sequenceSubscriptionKey;
246
+ const trimsMedia = originalSequence.type === 'audio' || originalSequence.type === 'video';
247
+ if (!canUpdateFrom({ propStatuses, nodePath }) ||
248
+ !canUpdateDurationInFrames({ propStatuses, nodePath }) ||
249
+ !canUpdateTrimBefore({ propStatuses, nodePath })) {
250
+ return null;
251
+ }
252
+ const { controls } = originalSequence;
253
+ if (!controls) {
254
+ return null;
255
+ }
256
+ const key = (0, studio_shared_1.stringifySequenceSubscriptionKey)(nodePath);
257
+ if (!targets.has(key)) {
258
+ targets.set(key, {
259
+ fileName: nodePath.absolutePath,
260
+ initialDuration: originalSequence.duration,
261
+ initialFrom: originalSequence.from,
262
+ initialTrimBefore: trimsMedia
263
+ ? ((_a = originalSequence.trimBefore) !== null && _a !== void 0 ? _a : Math.max(0, originalSequence.startMediaFrom))
264
+ : ((_b = originalSequence.trimBefore) !== null && _b !== void 0 ? _b : 0),
265
+ nodePath,
266
+ schema: controls.schema,
267
+ });
268
+ }
269
+ }
270
+ return [...targets.values()];
271
+ };
272
+ exports.getTimelineSequenceLeftEdgeDragTargets = getTimelineSequenceLeftEdgeDragTargets;
144
273
  const getTimelineSequenceFromDragTargets = ({ draggedNodePathInfo, selectedItems, sequences, overrideIdsToNodePaths, propStatuses, }) => {
145
274
  const draggedSelectionKey = (0, TimelineSelection_1.getTimelineSequenceSelectionKey)(draggedNodePathInfo);
146
275
  const selectedSequenceItems = selectedItems.filter((item) => item.type === 'sequence');
@@ -182,6 +311,11 @@ const getTimelineSequenceFromDragTargets = ({ draggedNodePathInfo, selectedItems
182
311
  return [...targets.values()];
183
312
  };
184
313
  exports.getTimelineSequenceFromDragTargets = getTimelineSequenceFromDragTargets;
314
+ const clearLeftEdgeDragOverrides = ({ clearDragOverrides, targets, }) => {
315
+ for (const target of targets) {
316
+ clearDragOverrides(target.nodePath);
317
+ }
318
+ };
185
319
  const clearDurationDragOverrides = ({ clearDragOverrides, targets, }) => {
186
320
  for (const target of targets) {
187
321
  clearDragOverrides(target.nodePath);
@@ -192,6 +326,179 @@ const clearFromDragOverrides = ({ clearDragOverrides, targets, }) => {
192
326
  clearDragOverrides(target.nodePath);
193
327
  }
194
328
  };
329
+ const TimelineSequenceLeftEdgeDragHandle = ({ nodePathInfo, windowWidth, timelineDurationInFrames }) => {
330
+ const { setPropStatuses, setDragOverrides, clearDragOverrides } = (0, react_1.useContext)(remotion_1.Internals.VisualModeSettersContext);
331
+ const propStatusesRef = (0, react_1.useContext)(remotion_1.Internals.VisualModePropStatusesRefContext);
332
+ const sequencesRef = (0, react_1.useContext)(remotion_1.Internals.SequenceManagerRefContext);
333
+ const { overrideIdToNodePathMappings } = (0, react_1.useContext)(remotion_1.Internals.OverrideIdsToNodePathsGettersContext);
334
+ const { previewServerState } = (0, react_1.useContext)(client_id_1.StudioServerConnectionCtx);
335
+ const currentSelection = (0, TimelineSelection_1.useCurrentTimelineSelectionStateAsRef)();
336
+ const [dragging, setDragging] = (0, react_1.useState)(false);
337
+ const dragStateRef = (0, react_1.useRef)(null);
338
+ const latestRef = (0, react_1.useRef)({
339
+ nodePathInfo,
340
+ setPropStatuses,
341
+ setDragOverrides,
342
+ clearDragOverrides,
343
+ previewServerState,
344
+ overrideIdToNodePathMappings,
345
+ });
346
+ latestRef.current = {
347
+ nodePathInfo,
348
+ setPropStatuses,
349
+ setDragOverrides,
350
+ clearDragOverrides,
351
+ previewServerState,
352
+ overrideIdToNodePathMappings,
353
+ };
354
+ const finishDrag = (0, react_1.useCallback)((commit) => {
355
+ const dragState = dragStateRef.current;
356
+ dragStateRef.current = null;
357
+ document.body.style.userSelect = '';
358
+ document.body.style.webkitUserSelect = '';
359
+ (0, ForceSpecificCursor_1.stopForcingSpecificCursor)();
360
+ setDragging(false);
361
+ if (!dragState) {
362
+ return;
363
+ }
364
+ const { setPropStatuses: latestSetPropStatuses, clearDragOverrides: latestClear, previewServerState: latestServerState, } = latestRef.current;
365
+ const changes = (0, exports.getTimelineSequenceLeftEdgeDragChanges)({
366
+ targets: dragState.targets,
367
+ deltaFrames: dragState.latestDeltaFrames,
368
+ });
369
+ if (!commit ||
370
+ latestServerState.type !== 'connected' ||
371
+ changes.length === 0) {
372
+ clearLeftEdgeDragOverrides({
373
+ clearDragOverrides: latestClear,
374
+ targets: dragState.targets,
375
+ });
376
+ return;
377
+ }
378
+ const savePromise = (0, save_sequence_prop_1.saveSequenceProps)({
379
+ changes,
380
+ setPropStatuses: latestSetPropStatuses,
381
+ clientId: latestServerState.clientId,
382
+ undoLabel: dragState.targets.length > 1
383
+ ? 'Resize selected sequences'
384
+ : 'Resize sequence',
385
+ redoLabel: dragState.targets.length > 1
386
+ ? 'Resize selected sequences back'
387
+ : 'Resize sequence back',
388
+ });
389
+ savePromise
390
+ .catch((err) => {
391
+ remotion_1.Internals.Log.error({ logLevel: 'error', tag: null }, 'Could not save left edge drag', err);
392
+ })
393
+ .finally(() => {
394
+ clearLeftEdgeDragOverrides({
395
+ clearDragOverrides: latestClear,
396
+ targets: dragState.targets,
397
+ });
398
+ });
399
+ }, []);
400
+ const onPointerDown = (0, react_1.useCallback)((e) => {
401
+ if (e.button !== 0) {
402
+ return;
403
+ }
404
+ const pxPerFrame = timelineDurationInFrames > 0
405
+ ? (windowWidth - timeline_layout_1.TIMELINE_PADDING * 2) / timelineDurationInFrames
406
+ : 0;
407
+ if (pxPerFrame <= 0) {
408
+ return;
409
+ }
410
+ const { nodePathInfo: latestNodePathInfo, overrideIdToNodePathMappings: latestOverrideIdsToNodePaths, } = latestRef.current;
411
+ const { selectedItems: latestSelectedItems } = currentSelection.current;
412
+ const targets = (0, exports.getTimelineSequenceLeftEdgeDragTargets)({
413
+ draggedNodePathInfo: latestNodePathInfo,
414
+ selectedItems: latestSelectedItems,
415
+ sequences: sequencesRef.current,
416
+ overrideIdsToNodePaths: latestOverrideIdsToNodePaths,
417
+ propStatuses: propStatusesRef.current,
418
+ });
419
+ if (targets === null || targets.length === 0) {
420
+ return;
421
+ }
422
+ e.stopPropagation();
423
+ e.preventDefault();
424
+ dragStateRef.current = {
425
+ initialClientX: e.clientX,
426
+ latestDeltaFrames: 0,
427
+ pxPerFrame,
428
+ pointerId: e.pointerId,
429
+ targets,
430
+ };
431
+ document.body.style.userSelect = 'none';
432
+ document.body.style.webkitUserSelect = 'none';
433
+ (0, ForceSpecificCursor_1.forceSpecificCursor)('ew-resize');
434
+ setDragging(true);
435
+ }, [
436
+ currentSelection,
437
+ propStatusesRef,
438
+ sequencesRef,
439
+ timelineDurationInFrames,
440
+ windowWidth,
441
+ ]);
442
+ (0, react_1.useEffect)(() => {
443
+ if (!dragging) {
444
+ return;
445
+ }
446
+ const onMove = (e) => {
447
+ const dragState = dragStateRef.current;
448
+ if (!dragState || e.pointerId !== dragState.pointerId) {
449
+ return;
450
+ }
451
+ const dx = e.clientX - dragState.initialClientX;
452
+ const deltaFrames = Math.round(dx / dragState.pxPerFrame);
453
+ dragState.latestDeltaFrames = deltaFrames;
454
+ for (const target of dragState.targets) {
455
+ const nextValues = (0, exports.getTimelineSequenceLeftEdgeDragValues)({
456
+ initialDuration: target.initialDuration,
457
+ initialFrom: target.initialFrom,
458
+ initialTrimBefore: target.initialTrimBefore,
459
+ deltaFrames,
460
+ });
461
+ latestRef.current.setDragOverrides(target.nodePath, 'from', remotion_1.Internals.makeStaticDragOverride(nextValues.from));
462
+ latestRef.current.setDragOverrides(target.nodePath, 'durationInFrames', remotion_1.Internals.makeStaticDragOverride(nextValues.durationInFrames));
463
+ latestRef.current.setDragOverrides(target.nodePath, 'trimBefore', remotion_1.Internals.makeStaticDragOverride(nextValues.trimBefore));
464
+ }
465
+ };
466
+ const onUp = (e) => {
467
+ const dragState = dragStateRef.current;
468
+ if (!dragState || e.pointerId !== dragState.pointerId) {
469
+ return;
470
+ }
471
+ finishDrag(true);
472
+ };
473
+ const onCancel = (e) => {
474
+ const dragState = dragStateRef.current;
475
+ if (!dragState || e.pointerId !== dragState.pointerId) {
476
+ return;
477
+ }
478
+ finishDrag(false);
479
+ };
480
+ const onWindowBlur = () => {
481
+ finishDrag(false);
482
+ };
483
+ window.addEventListener('pointermove', onMove);
484
+ window.addEventListener('pointerup', onUp);
485
+ window.addEventListener('pointercancel', onCancel);
486
+ window.addEventListener('blur', onWindowBlur);
487
+ return () => {
488
+ window.removeEventListener('pointermove', onMove);
489
+ window.removeEventListener('pointerup', onUp);
490
+ window.removeEventListener('pointercancel', onCancel);
491
+ window.removeEventListener('blur', onWindowBlur);
492
+ };
493
+ }, [dragging, finishDrag]);
494
+ const style = {
495
+ ...baseStyle,
496
+ left: 0,
497
+ background: 'transparent',
498
+ };
499
+ return (jsx_runtime_1.jsx("div", { role: "separator", "aria-orientation": "vertical", title: "Drag to trim start", style: style, onPointerDown: onPointerDown }));
500
+ };
501
+ exports.TimelineSequenceLeftEdgeDragHandle = TimelineSequenceLeftEdgeDragHandle;
195
502
  const useTimelineSequenceFromDrag = ({ nodePathInfo, windowWidth, timelineDurationInFrames, }) => {
196
503
  const { setPropStatuses, setDragOverrides, clearDragOverrides } = (0, react_1.useContext)(remotion_1.Internals.VisualModeSettersContext);
197
504
  const propStatusesRef = (0, react_1.useContext)(remotion_1.Internals.VisualModePropStatusesRefContext);
@@ -16,12 +16,18 @@ const container = {
16
16
  top: 0,
17
17
  pointerEvents: 'none',
18
18
  };
19
+ const PLAYHEAD_LINE_WIDTH = 1;
19
20
  const line = {
20
21
  height: '100vh',
21
- width: 1,
22
+ width: PLAYHEAD_LINE_WIDTH,
22
23
  position: 'fixed',
23
24
  backgroundColor: '#f02c00',
24
25
  };
26
+ const PLAYHEAD_CENTER_OFFSET = PLAYHEAD_LINE_WIDTH / 2;
27
+ const getTimelineSliderTransform = ({ durationInFrames, frame, width, }) => {
28
+ const left = (0, get_left_of_timeline_slider_1.getXPositionOfItemInTimelineImperatively)(frame, durationInFrames, width);
29
+ return `translateX(${left - PLAYHEAD_CENTER_OFFSET}px)`;
30
+ };
25
31
  exports.redrawTimelineSliderFast = (0, react_1.createRef)();
26
32
  const TimelineSlider = () => {
27
33
  const videoConfig = remotion_1.Internals.useUnsafeVideoConfig();
@@ -53,7 +59,11 @@ const TimelineSliderInner = () => {
53
59
  if (!el || measuredWidth === undefined || measuredWidth === 0) {
54
60
  return;
55
61
  }
56
- el.style.transform = `translateX(${(0, get_left_of_timeline_slider_1.getXPositionOfItemInTimelineImperatively)(timelinePosition, videoConfig.durationInFrames, measuredWidth)}px)`;
62
+ el.style.transform = getTimelineSliderTransform({
63
+ durationInFrames: videoConfig.durationInFrames,
64
+ frame: timelinePosition,
65
+ width: measuredWidth,
66
+ });
57
67
  }, [
58
68
  timelinePosition,
59
69
  videoConfig.durationInFrames,
@@ -69,7 +79,11 @@ const TimelineSliderInner = () => {
69
79
  if (!current) {
70
80
  throw new Error('unexpectedly did not have ref to timelineslider');
71
81
  }
72
- current.style.transform = `translateX(${(0, get_left_of_timeline_slider_1.getXPositionOfItemInTimelineImperatively)(frame, (0, imperative_state_1.getCurrentDuration)(), (_b = width !== null && width !== void 0 ? width : (_a = timeline_refs_1.sliderAreaRef.current) === null || _a === void 0 ? void 0 : _a.clientWidth) !== null && _b !== void 0 ? _b : 0)}px)`;
82
+ current.style.transform = getTimelineSliderTransform({
83
+ durationInFrames: (0, imperative_state_1.getCurrentDuration)(),
84
+ frame,
85
+ width: (_b = width !== null && width !== void 0 ? width : (_a = timeline_refs_1.sliderAreaRef.current) === null || _a === void 0 ? void 0 : _a.clientWidth) !== null && _b !== void 0 ? _b : 0,
86
+ });
73
87
  },
74
88
  };
75
89
  }, []);
@@ -48,8 +48,7 @@ const TimelineTrackUnmemoized = ({ track }) => {
48
48
  const { previewServerState } = (0, react_1.useContext)(client_id_1.StudioServerConnectionCtx);
49
49
  const previewServerConnected = previewServerState.type === 'connected';
50
50
  const timelineWidth = (0, react_1.useContext)(TimelineWidthProvider_1.TimelineWidthContext);
51
- const { selected: rowSelected } = (0, TimelineSelection_1.useTimelineRowSelection)(track.nodePathInfo);
52
- const containsSelection = (0, TimelineSelection_1.useTimelineRowContainsSelection)(track.nodePathInfo);
51
+ const rowHighlightBackground = (0, TimelineSelection_1.useTimelineRowHighlightBackground)(track.nodePathInfo);
53
52
  const layerStyle = (0, react_1.useMemo)(() => ({
54
53
  height: (0, timeline_layout_1.getTimelineLayerHeight)(track.sequence.type),
55
54
  marginBottom: timeline_layout_1.TIMELINE_ITEM_BORDER_BOTTOM,
@@ -58,9 +57,8 @@ const TimelineTrackUnmemoized = ({ track }) => {
58
57
  const showExpandedKeyframes = track.nodePathInfo !== null &&
59
58
  previewServerConnected &&
60
59
  getIsExpanded(track.nodePathInfo);
61
- const showRowHighlight = track.nodePathInfo !== null && (rowSelected || containsSelection);
62
60
  return (jsx_runtime_1.jsxs("div", { children: [
63
- jsx_runtime_1.jsxs("div", { style: layerStyle, children: [showRowHighlight && timelineWidth !== null ? (jsx_runtime_1.jsx("div", { style: (0, TimelineSelection_1.getTimelineSelectedTrackHighlightStyle)(timelineWidth) })) : null, jsx_runtime_1.jsx(TimelineSequence_1.TimelineSequence, { s: track.sequence, nodePathInfo: track.nodePathInfo, sequenceFrameOffset: track.sequenceFrameOffset })
61
+ jsx_runtime_1.jsxs("div", { style: layerStyle, children: [rowHighlightBackground && timelineWidth !== null ? (jsx_runtime_1.jsx("div", { style: (0, TimelineSelection_1.getTimelineSelectedTrackHighlightStyle)(timelineWidth, rowHighlightBackground) })) : null, jsx_runtime_1.jsx(TimelineSequence_1.TimelineSequence, { s: track.sequence, nodePathInfo: track.nodePathInfo, sequenceFrameOffset: track.sequenceFrameOffset })
64
62
  ] }), showExpandedKeyframes && track.nodePathInfo ? (jsx_runtime_1.jsx(TimelineExpandedTrackKeyframes_1.TimelineExpandedTrackKeyframes, { sequence: track.sequence, nodePathInfo: track.nodePathInfo, keyframeDisplayOffset: track.keyframeDisplayOffset })) : null] }));
65
63
  };
66
64
  exports.TimelineTrack = react_1.default.memo(TimelineTrackUnmemoized);
@@ -1,4 +1,4 @@
1
- import type { OverrideIdToNodePaths, TSequence } from 'remotion';
1
+ import type { OverrideIdToNodePaths, PropStatuses, TSequence } from 'remotion';
2
2
  import type { ConfirmationDialogFunction } from '../ConfirmationDialog-types';
3
3
  import type { SetPropStatuses } from './save-sequence-prop';
4
4
  import { type TimelineSelection } from './TimelineSelection';
@@ -10,7 +10,13 @@ export declare const deleteSelectedTimelineItem: ({ selection, sequences, overri
10
10
  clientId: string;
11
11
  confirm: ConfirmationDialogFunction;
12
12
  }) => Promise<boolean> | null;
13
- export declare const getTimelineSelectionAfterDeletingItems: (selections: readonly TimelineSelection[]) => readonly TimelineSelection[];
13
+ export declare const getTimelineSelectionAfterDeletingItems: ({ selections, sequences, overrideIdsToNodePaths, propStatuses, timelinePosition, }: {
14
+ readonly selections: readonly TimelineSelection[];
15
+ readonly sequences?: TSequence[] | undefined;
16
+ readonly overrideIdsToNodePaths?: OverrideIdToNodePaths | undefined;
17
+ readonly propStatuses?: PropStatuses | undefined;
18
+ readonly timelinePosition?: number | undefined;
19
+ }) => readonly TimelineSelection[];
14
20
  export declare const deleteSelectedTimelineItems: ({ selections, sequences, overrideIdsToNodePaths, setPropStatuses, clientId, confirm, }: {
15
21
  selections: readonly TimelineSelection[];
16
22
  sequences: TSequence[];
@@ -1,10 +1,15 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.deleteSelectedTimelineItems = exports.getTimelineSelectionAfterDeletingItems = exports.deleteSelectedTimelineItem = void 0;
4
+ const remotion_1 = require("remotion");
4
5
  const call_api_1 = require("../call-api");
5
6
  const NotificationCenter_1 = require("../Notifications/NotificationCenter");
6
7
  const delete_selected_keyframe_1 = require("./delete-selected-keyframe");
8
+ const find_track_for_node_path_info_1 = require("./find-track-for-node-path-info");
9
+ const get_easing_selection_after_keyframe_delete_1 = require("./get-easing-selection-after-keyframe-delete");
10
+ const parse_keyframe_field_from_node_path_1 = require("./parse-keyframe-field-from-node-path");
7
11
  const TimelineSelection_1 = require("./TimelineSelection");
12
+ const update_selected_easing_1 = require("./update-selected-easing");
8
13
  const confirmDeletingDuplicatedSequences = (nodePathInfos, confirm) => {
9
14
  const duplicatedNodePathInfos = nodePathInfos.filter((nodePathInfo) => nodePathInfo.numberOfSequencesWithThisNodePath > 1);
10
15
  if (duplicatedNodePathInfos.length === 0) {
@@ -150,7 +155,81 @@ const getSequenceSelectionAfterDeletingEffect = (selection) => {
150
155
  },
151
156
  };
152
157
  };
153
- const getTimelineSelectionAfterDeletingItems = (selections) => {
158
+ const getEasingSelectionAfterDeletingKeyframes = ({ selections, sequences, overrideIdsToNodePaths, propStatuses, timelinePosition, }) => {
159
+ var _a;
160
+ if (sequences === undefined ||
161
+ overrideIdsToNodePaths === undefined ||
162
+ propStatuses === undefined ||
163
+ timelinePosition === undefined) {
164
+ return null;
165
+ }
166
+ const keyframeSelections = selections.filter(isKeyframeSelection);
167
+ if (keyframeSelections.length !== 1) {
168
+ return null;
169
+ }
170
+ const [selection] = keyframeSelections;
171
+ if (!selection) {
172
+ return null;
173
+ }
174
+ const field = (0, parse_keyframe_field_from_node_path_1.parseKeyframeFieldFromNodePath)(selection.nodePathInfo.auxiliaryKeys);
175
+ if (field === null) {
176
+ return null;
177
+ }
178
+ const track = (0, find_track_for_node_path_info_1.findTrackForNodePathInfo)({
179
+ sequences,
180
+ overrideIdsToNodePaths,
181
+ nodePathInfo: selection.nodePathInfo,
182
+ });
183
+ if (!track || !track.sequence.controls) {
184
+ return null;
185
+ }
186
+ const nodePath = selection.nodePathInfo.sequenceSubscriptionKey;
187
+ const sourceFrame = selection.frame - track.keyframeDisplayOffset;
188
+ if (field.type === 'sequence') {
189
+ const sequencePropStatus = (_a = remotion_1.Internals.getPropStatusesCtx(propStatuses, nodePath)) === null || _a === void 0 ? void 0 : _a[field.fieldKey];
190
+ if ((sequencePropStatus === null || sequencePropStatus === void 0 ? void 0 : sequencePropStatus.status) !== 'keyframed' ||
191
+ !(0, update_selected_easing_1.canEditEasingForInterpolationFunction)(sequencePropStatus.interpolationFunction)) {
192
+ return null;
193
+ }
194
+ return (0, get_easing_selection_after_keyframe_delete_1.getEasingSelectionAfterKeyframeDelete)({
195
+ deletedSourceFrames: [sourceFrame],
196
+ keyframeDisplayOffset: track.keyframeDisplayOffset,
197
+ nodePathInfo: selection.nodePathInfo,
198
+ propStatus: sequencePropStatus,
199
+ timelinePosition,
200
+ });
201
+ }
202
+ const effectStatus = remotion_1.Internals.getEffectPropStatusesCtx({
203
+ propStatuses,
204
+ nodePath,
205
+ effectIndex: field.effectIndex,
206
+ });
207
+ const effectPropStatus = effectStatus.type === 'can-update-effect'
208
+ ? effectStatus.props[field.fieldKey]
209
+ : null;
210
+ if ((effectPropStatus === null || effectPropStatus === void 0 ? void 0 : effectPropStatus.status) !== 'keyframed' ||
211
+ !(0, update_selected_easing_1.canEditEasingForInterpolationFunction)(effectPropStatus.interpolationFunction)) {
212
+ return null;
213
+ }
214
+ return (0, get_easing_selection_after_keyframe_delete_1.getEasingSelectionAfterKeyframeDelete)({
215
+ deletedSourceFrames: [sourceFrame],
216
+ keyframeDisplayOffset: track.keyframeDisplayOffset,
217
+ nodePathInfo: selection.nodePathInfo,
218
+ propStatus: effectPropStatus,
219
+ timelinePosition,
220
+ });
221
+ };
222
+ const getTimelineSelectionAfterDeletingItems = ({ selections, sequences, overrideIdsToNodePaths, propStatuses, timelinePosition, }) => {
223
+ const easingSelection = getEasingSelectionAfterDeletingKeyframes({
224
+ selections,
225
+ sequences,
226
+ overrideIdsToNodePaths,
227
+ propStatuses,
228
+ timelinePosition,
229
+ });
230
+ if (easingSelection !== null) {
231
+ return [easingSelection];
232
+ }
154
233
  const nextSelections = new Map();
155
234
  for (const selection of selections) {
156
235
  const nextSelection = getSequenceSelectionAfterDeletingEffect(selection);
@@ -0,0 +1,18 @@
1
+ import type { SequenceNodePathInfo } from '../../helpers/get-timeline-sequence-sort-key';
2
+ import type { TimelineSelection } from './TimelineSelection';
3
+ type AnimationItemSelection = Extract<TimelineSelection, {
4
+ type: 'keyframe';
5
+ } | {
6
+ type: 'easing';
7
+ }>;
8
+ type AnimationKeyframe = {
9
+ readonly frame: number;
10
+ };
11
+ export declare const getAnimationItemSelectionForSourceFrame: ({ includeEasings, keyframeDisplayOffset, keyframes, nodePathInfo, sourceFrame, }: {
12
+ readonly includeEasings: boolean;
13
+ readonly keyframeDisplayOffset: number;
14
+ readonly keyframes: readonly AnimationKeyframe[];
15
+ readonly nodePathInfo: SequenceNodePathInfo;
16
+ readonly sourceFrame: number;
17
+ }) => AnimationItemSelection | null;
18
+ export {};
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getAnimationItemSelectionForSourceFrame = void 0;
4
+ const getKeyframeSelection = ({ keyframe, keyframeDisplayOffset, nodePathInfo, }) => {
5
+ return {
6
+ type: 'keyframe',
7
+ nodePathInfo,
8
+ frame: keyframe.frame + keyframeDisplayOffset,
9
+ };
10
+ };
11
+ const getAnimationItemSelectionForSourceFrame = ({ includeEasings, keyframeDisplayOffset, keyframes, nodePathInfo, sourceFrame, }) => {
12
+ const firstKeyframe = keyframes[0];
13
+ if (!firstKeyframe) {
14
+ return null;
15
+ }
16
+ for (let i = 0; i < keyframes.length; i++) {
17
+ const keyframe = keyframes[i];
18
+ if (keyframe.frame === sourceFrame) {
19
+ return getKeyframeSelection({
20
+ keyframe,
21
+ keyframeDisplayOffset,
22
+ nodePathInfo,
23
+ });
24
+ }
25
+ const nextKeyframe = keyframes[i + 1];
26
+ if (!nextKeyframe) {
27
+ continue;
28
+ }
29
+ if (sourceFrame > keyframe.frame && sourceFrame < nextKeyframe.frame) {
30
+ if (!includeEasings) {
31
+ return null;
32
+ }
33
+ return {
34
+ type: 'easing',
35
+ nodePathInfo,
36
+ fromFrame: keyframe.frame + keyframeDisplayOffset,
37
+ toFrame: nextKeyframe.frame + keyframeDisplayOffset,
38
+ segmentIndex: i,
39
+ };
40
+ }
41
+ }
42
+ const lastKeyframe = keyframes[keyframes.length - 1];
43
+ return getKeyframeSelection({
44
+ keyframe: sourceFrame < firstKeyframe.frame ? firstKeyframe : lastKeyframe,
45
+ keyframeDisplayOffset,
46
+ nodePathInfo,
47
+ });
48
+ };
49
+ exports.getAnimationItemSelectionForSourceFrame = getAnimationItemSelectionForSourceFrame;
@@ -0,0 +1,15 @@
1
+ import type { CanUpdateSequencePropStatusKeyframed } from 'remotion';
2
+ import type { SequenceNodePathInfo } from '../../helpers/get-timeline-sequence-sort-key';
3
+ export declare const getEasingSelectionAfterKeyframeDelete: ({ deletedSourceFrames, keyframeDisplayOffset, nodePathInfo, propStatus, timelinePosition, }: {
4
+ readonly deletedSourceFrames: readonly number[];
5
+ readonly keyframeDisplayOffset: number;
6
+ readonly nodePathInfo: SequenceNodePathInfo;
7
+ readonly propStatus: CanUpdateSequencePropStatusKeyframed;
8
+ readonly timelinePosition: number;
9
+ }) => {
10
+ readonly type: "easing";
11
+ readonly nodePathInfo: SequenceNodePathInfo;
12
+ readonly fromFrame: number;
13
+ readonly toFrame: number;
14
+ readonly segmentIndex: number;
15
+ } | null;
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getEasingSelectionAfterKeyframeDelete = void 0;
4
+ const getEasingSelectionAfterKeyframeDelete = ({ deletedSourceFrames, keyframeDisplayOffset, nodePathInfo, propStatus, timelinePosition, }) => {
5
+ const deletedSourceFrameSet = new Set(deletedSourceFrames);
6
+ const remainingKeyframes = propStatus.keyframes.filter((keyframe) => !deletedSourceFrameSet.has(keyframe.frame));
7
+ const sourceFrame = timelinePosition - keyframeDisplayOffset;
8
+ for (let i = 0; i < remainingKeyframes.length - 1; i++) {
9
+ const keyframe = remainingKeyframes[i];
10
+ const nextKeyframe = remainingKeyframes[i + 1];
11
+ if (!keyframe || !nextKeyframe) {
12
+ continue;
13
+ }
14
+ if (sourceFrame > keyframe.frame && sourceFrame < nextKeyframe.frame) {
15
+ return {
16
+ type: 'easing',
17
+ nodePathInfo,
18
+ fromFrame: keyframe.frame + keyframeDisplayOffset,
19
+ toFrame: nextKeyframe.frame + keyframeDisplayOffset,
20
+ segmentIndex: i,
21
+ };
22
+ }
23
+ }
24
+ return null;
25
+ };
26
+ exports.getEasingSelectionAfterKeyframeDelete = getEasingSelectionAfterKeyframeDelete;