@remotion/studio 4.0.512 → 4.0.513

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 (55) hide show
  1. package/dist/components/CompositionSelectorItem.js +14 -1
  2. package/dist/components/InspectorOpenInEditor.js +24 -24
  3. package/dist/components/InspectorPanel/AlignmentControls.js +13 -2
  4. package/dist/components/InspectorPanel/CompositionInspectorHeader.js +12 -8
  5. package/dist/components/InspectorPanel/ConnectedCompositionsSection.js +12 -1
  6. package/dist/components/InspectorPanel/EasingInspector.js +11 -2
  7. package/dist/components/InspectorPanel/KeyframeInspector.js +19 -5
  8. package/dist/components/InspectorPanel/easing-inspector-selection.js +7 -2
  9. package/dist/components/InspectorPanel/inspector-section-collapse.d.ts +1 -0
  10. package/dist/components/SelectedOutlineElement.js +12 -10
  11. package/dist/components/SelectedOutlineOverlay.js +30 -8
  12. package/dist/components/Timeline/TimelineArrayField.js +1 -0
  13. package/dist/components/Timeline/TimelineEffectPropItem.js +10 -4
  14. package/dist/components/Timeline/TimelineKeyframeControls.js +25 -7
  15. package/dist/components/Timeline/TimelineKeyframedValue.js +1 -0
  16. package/dist/components/Timeline/TimelineSequencePropItem.js +11 -4
  17. package/dist/components/Timeline/TimelineSequenceRightEdgeDragHandle.d.ts +3 -0
  18. package/dist/components/Timeline/TimelineSequenceRightEdgeDragHandle.js +96 -18
  19. package/dist/components/Timeline/call-move-keyframe.d.ts +2 -1
  20. package/dist/components/Timeline/call-move-keyframe.js +70 -17
  21. package/dist/components/Timeline/delete-selected-keyframe.d.ts +0 -8
  22. package/dist/components/Timeline/delete-selected-keyframe.js +23 -44
  23. package/dist/components/Timeline/delete-selected-timeline-item.d.ts +0 -8
  24. package/dist/components/Timeline/delete-selected-timeline-item.js +16 -43
  25. package/dist/components/Timeline/get-easing-selection-after-keyframe-delete.js +8 -3
  26. package/dist/components/Timeline/get-sequence-context-menu-items.js +10 -8
  27. package/dist/components/Timeline/get-timeline-keyframes.d.ts +4 -0
  28. package/dist/components/Timeline/get-timeline-keyframes.js +16 -3
  29. package/dist/components/Timeline/keyframe-clipboard.js +9 -2
  30. package/dist/components/Timeline/use-open-sequence-in-apps.js +8 -8
  31. package/dist/components/Timeline/use-timeline-keyframe-drag.js +14 -4
  32. package/dist/components/VisualControls/ClickableFileName.js +13 -6
  33. package/dist/components/composition-menu-items.d.ts +6 -1
  34. package/dist/components/composition-menu-items.js +9 -6
  35. package/dist/components/folder-menu-items.d.ts +4 -1
  36. package/dist/components/folder-menu-items.js +4 -5
  37. package/dist/components/get-open-in-menu-items.d.ts +1 -1
  38. package/dist/components/get-open-in-menu-items.js +15 -13
  39. package/dist/components/sequence-props-api.js +44 -3
  40. package/dist/components/use-default-editor-info.d.ts +8 -0
  41. package/dist/components/use-default-editor-info.js +25 -9
  42. package/dist/error-overlay/remotion-overlay/ErrorDisplay.js +10 -3
  43. package/dist/error-overlay/remotion-overlay/OpenInEditor.d.ts +3 -1
  44. package/dist/error-overlay/remotion-overlay/OpenInEditor.js +6 -6
  45. package/dist/error-overlay/remotion-overlay/Overlay.js +14 -12
  46. package/dist/error-overlay/remotion-overlay/StackFrame.d.ts +2 -1
  47. package/dist/error-overlay/remotion-overlay/StackFrame.js +7 -4
  48. package/dist/esm/{chunk-s8gwjng0.js → chunk-tv7r0jy3.js} +1692 -1322
  49. package/dist/esm/internals.mjs +1692 -1322
  50. package/dist/esm/previewEntry.mjs +3167 -2793
  51. package/dist/esm/renderEntry.mjs +1 -1
  52. package/dist/helpers/open-in-editor.d.ts +6 -4
  53. package/dist/helpers/open-in-editor.js +4 -4
  54. package/dist/helpers/use-menu-structure.js +11 -6
  55. package/package.json +12 -12
@@ -9,6 +9,7 @@ const client_id_1 = require("../../helpers/client-id");
9
9
  const open_in_editor_1 = require("../../helpers/open-in-editor");
10
10
  const call_api_1 = require("../call-api");
11
11
  const ContextMenu_1 = require("../ContextMenu");
12
+ const use_default_editor_info_1 = require("../use-default-editor-info");
12
13
  const call_add_keyframe_1 = require("./call-add-keyframe");
13
14
  const get_timeline_keyframes_1 = require("./get-timeline-keyframes");
14
15
  const save_effect_prop_1 = require("./save-effect-prop");
@@ -224,6 +225,7 @@ const TimelineEffectPropItem = ({ field, validatedLocation, rowDepth, nodePath,
224
225
  var _a;
225
226
  var _b;
226
227
  const { previewServerState } = (0, react_1.useContext)(client_id_1.StudioServerConnectionCtx);
228
+ const { canOpenInEditor, defaultEditorId } = (0, use_default_editor_info_1.useEditorOpening)(previewServerState.type === 'connected');
227
229
  const { setPropStatuses } = (0, react_1.useContext)(remotion_1.Internals.VisualModeSettersContext);
228
230
  const { propStatuses } = (0, react_1.useContext)(remotion_1.Internals.VisualModePropStatusesContext);
229
231
  const { getEffectDragOverrides } = (0, react_1.useContext)(remotion_1.Internals.VisualModeDragOverridesContext);
@@ -241,6 +243,10 @@ const TimelineEffectPropItem = ({ field, validatedLocation, rowDepth, nodePath,
241
243
  const propStatus = effectStatus.type === 'can-update-effect'
242
244
  ? ((_b = (_a = effectStatus.props) === null || _a === void 0 ? void 0 : _a[field.key]) !== null && _b !== void 0 ? _b : null)
243
245
  : null;
246
+ const resolvedKeyframeDisplayOffset = (0, get_timeline_keyframes_1.getKeyframeDisplayOffset)({
247
+ propStatus,
248
+ keyframeDisplayOffset,
249
+ });
244
250
  const dragOverrideValue = (0, react_1.useMemo)(() => {
245
251
  const overrides = getEffectDragOverrides(nodePath, field.effectIndex);
246
252
  return overrides[field.key];
@@ -323,17 +329,17 @@ const TimelineEffectPropItem = ({ field, validatedLocation, rowDepth, nodePath,
323
329
  ];
324
330
  }, [canShowReset, onReset, selection]);
325
331
  const onPropertyDoubleClick = (0, react_1.useCallback)((event) => {
326
- if (!window.remotion_editorName ||
327
- previewServerState.type !== 'connected') {
332
+ if (!canOpenInEditor || !defaultEditorId) {
328
333
  return;
329
334
  }
330
335
  event.stopPropagation();
331
336
  (0, open_in_editor_1.openOriginalPositionInEditorAtProperty)({
337
+ editorId: defaultEditorId,
332
338
  originalPosition: validatedLocation,
333
339
  property: field.key,
334
340
  }).catch(() => undefined);
335
- }, [field.key, previewServerState.type, validatedLocation]);
336
- const row = (jsx_runtime_1.jsx(TimelineRowChrome_1.TimelineRowChrome, { depth: rowDepth, eye: jsx_runtime_1.jsx(TimelineLayerEye_1.TimelineLayerEyeSpacer, {}), keyframeControls: keyframeControls, arrow: jsx_runtime_1.jsx(TimelineExpandArrowButton_1.TimelineExpandArrowSpacer, {}), style: style, selected: selection.selected, selectable: selection.selectable, selectionItem: selection.selectionItem, onSelect: selection.onSelect, onDoubleClick: onPropertyDoubleClick, showSelectedBackground: true, containsSelection: false, isFieldRow: true, outerHeight: null, children: jsx_runtime_1.jsx(TimelineFieldRowContent_1.TimelineFieldRowContent, { field: field, rowDepth: rowDepth, selected: selection.selected, keyframeControls: keyframeControls, children: jsx_runtime_1.jsx(TimelineEffectPropValueAtCurrentFrame, { field: field, nodePath: nodePath, validatedLocation: validatedLocation, keyframeDisplayOffset: keyframeDisplayOffset }) }) }));
341
+ }, [canOpenInEditor, defaultEditorId, field.key, validatedLocation]);
342
+ const row = (jsx_runtime_1.jsx(TimelineRowChrome_1.TimelineRowChrome, { depth: rowDepth, eye: jsx_runtime_1.jsx(TimelineLayerEye_1.TimelineLayerEyeSpacer, {}), keyframeControls: keyframeControls, arrow: jsx_runtime_1.jsx(TimelineExpandArrowButton_1.TimelineExpandArrowSpacer, {}), style: style, selected: selection.selected, selectable: selection.selectable, selectionItem: selection.selectionItem, onSelect: selection.onSelect, onDoubleClick: onPropertyDoubleClick, showSelectedBackground: true, containsSelection: false, isFieldRow: true, outerHeight: null, children: jsx_runtime_1.jsx(TimelineFieldRowContent_1.TimelineFieldRowContent, { field: field, rowDepth: rowDepth, selected: selection.selected, keyframeControls: keyframeControls, children: jsx_runtime_1.jsx(TimelineEffectPropValueAtCurrentFrame, { field: field, nodePath: nodePath, validatedLocation: validatedLocation, keyframeDisplayOffset: resolvedKeyframeDisplayOffset }) }) }));
337
343
  return jsx_runtime_1.jsx(ContextMenu_1.ContextMenu, { getItems: getContextMenuItems, children: row });
338
344
  };
339
345
  exports.TimelineEffectPropItem = TimelineEffectPropItem;
@@ -150,8 +150,15 @@ const resolveKeyframeControlTarget = ({ nodePathInfo, tracks, propStatuses, getD
150
150
  propStatus: sequenceSelectedPropStatus,
151
151
  nodePath,
152
152
  fileName: nodePath.absolutePath,
153
- keyframeDisplayOffset: track.keyframeDisplayOffset,
154
- sourceFrame: timelinePosition - track.keyframeDisplayOffset,
153
+ keyframeDisplayOffset: (0, get_timeline_keyframes_1.getKeyframeDisplayOffset)({
154
+ propStatus: sequenceSelectedPropStatus,
155
+ keyframeDisplayOffset: track.keyframeDisplayOffset,
156
+ }),
157
+ sourceFrame: timelinePosition -
158
+ (0, get_timeline_keyframes_1.getKeyframeDisplayOffset)({
159
+ propStatus: sequenceSelectedPropStatus,
160
+ keyframeDisplayOffset: track.keyframeDisplayOffset,
161
+ }),
155
162
  defaultValue: fieldNode.field.fieldSchema.default,
156
163
  dragOverrideValue: ((_c = getDragOverrides(nodePath)) !== null && _c !== void 0 ? _c : {})[fieldNode.field.key],
157
164
  schema: track.sequence.controls.schema,
@@ -175,8 +182,15 @@ const resolveKeyframeControlTarget = ({ nodePathInfo, tracks, propStatuses, getD
175
182
  propStatus: effectSelectedPropStatus,
176
183
  nodePath,
177
184
  fileName: nodePath.absolutePath,
178
- keyframeDisplayOffset: track.keyframeDisplayOffset,
179
- sourceFrame: timelinePosition - track.keyframeDisplayOffset,
185
+ keyframeDisplayOffset: (0, get_timeline_keyframes_1.getKeyframeDisplayOffset)({
186
+ propStatus: effectSelectedPropStatus,
187
+ keyframeDisplayOffset: track.keyframeDisplayOffset,
188
+ }),
189
+ sourceFrame: timelinePosition -
190
+ (0, get_timeline_keyframes_1.getKeyframeDisplayOffset)({
191
+ propStatus: effectSelectedPropStatus,
192
+ keyframeDisplayOffset: track.keyframeDisplayOffset,
193
+ }),
180
194
  defaultValue: fieldNode.field.fieldSchema.default,
181
195
  dragOverrideValue: getEffectDragOverrides(nodePath, fieldNode.field.effectIndex)[fieldNode.field.key],
182
196
  schema: fieldNode.field.effectSchema,
@@ -297,7 +311,11 @@ const TimelineKeyframeControls = ({ fieldKey, propStatus, nodePath, fileName, ke
297
311
  const clientId = previewServerState.type === 'connected'
298
312
  ? previewServerState.clientId
299
313
  : null;
300
- const jsxFrame = timelinePosition - keyframeDisplayOffset;
314
+ const resolvedKeyframeDisplayOffset = (0, get_timeline_keyframes_1.getKeyframeDisplayOffset)({
315
+ propStatus,
316
+ keyframeDisplayOffset,
317
+ });
318
+ const jsxFrame = timelinePosition - resolvedKeyframeDisplayOffset;
301
319
  const keyframes = (0, react_1.useMemo)(() => (0, get_timeline_keyframes_1.getTimelineKeyframes)(propStatus, keyframeDisplayOffset), [propStatus, keyframeDisplayOffset]);
302
320
  const hasKeyframeAtCurrentFrame = (0, react_1.useMemo)(() => {
303
321
  if (!isKeyframedStatus(propStatus)) {
@@ -336,7 +354,7 @@ const TimelineKeyframeControls = ({ fieldKey, propStatus, nodePath, fileName, ke
336
354
  propStatus,
337
355
  nodePath,
338
356
  fileName,
339
- keyframeDisplayOffset,
357
+ keyframeDisplayOffset: resolvedKeyframeDisplayOffset,
340
358
  sourceFrame: jsxFrame,
341
359
  defaultValue,
342
360
  dragOverrideValue,
@@ -349,7 +367,7 @@ const TimelineKeyframeControls = ({ fieldKey, propStatus, nodePath, fileName, ke
349
367
  fieldKey,
350
368
  fileName,
351
369
  jsxFrame,
352
- keyframeDisplayOffset,
370
+ resolvedKeyframeDisplayOffset,
353
371
  nodePath,
354
372
  nodePathInfo,
355
373
  propStatus,
@@ -22,6 +22,7 @@ const TimelineKeyframedValue = ({ field, propStatus, sourceFrame, dragOverrideVa
22
22
  }, [propStatus, sourceFrame]);
23
23
  const fakeStatus = (0, react_1.useMemo)(() => ({
24
24
  status: 'static',
25
+ keyframeDisplayOffsetAdjustment: null,
25
26
  codeValue: computedValue,
26
27
  }), [computedValue]);
27
28
  const effectiveValue = (0, react_1.useMemo)(() => {
@@ -42,8 +42,10 @@ const client_id_1 = require("../../helpers/client-id");
42
42
  const open_in_editor_1 = require("../../helpers/open-in-editor");
43
43
  const ContextMenu_1 = require("../ContextMenu");
44
44
  const InspectorPanelLayout_1 = require("../InspectorPanelLayout");
45
+ const use_default_editor_info_1 = require("../use-default-editor-info");
45
46
  const call_add_keyframe_1 = require("./call-add-keyframe");
46
47
  const get_sequence_prop_reset_changes_1 = require("./get-sequence-prop-reset-changes");
48
+ const get_timeline_keyframes_1 = require("./get-timeline-keyframes");
47
49
  const save_sequence_prop_1 = require("./save-sequence-prop");
48
50
  const timeline_field_row_layout_1 = require("./timeline-field-row-layout");
49
51
  const TimelineExpandArrowButton_1 = require("./TimelineExpandArrowButton");
@@ -173,7 +175,11 @@ const TimelineSequenceKeyframedValueAtSourceFrame = ({ field, nodePath, propStat
173
175
  };
174
176
  const TimelineSequenceKeyframedValueAtCurrentFrame = ({ keyframeDisplayOffset, ...props }) => {
175
177
  const timelinePosition = remotion_1.Internals.Timeline.useTimelinePosition();
176
- return (jsx_runtime_1.jsx(TimelineSequenceKeyframedValueAtSourceFrame, { ...props, sourceFrame: timelinePosition - keyframeDisplayOffset }));
178
+ const resolvedKeyframeDisplayOffset = (0, get_timeline_keyframes_1.getKeyframeDisplayOffset)({
179
+ propStatus: props.propStatus,
180
+ keyframeDisplayOffset,
181
+ });
182
+ return (jsx_runtime_1.jsx(TimelineSequenceKeyframedValueAtSourceFrame, { ...props, sourceFrame: timelinePosition - resolvedKeyframeDisplayOffset }));
177
183
  };
178
184
  const TimelineSequenceKeyframedValueUnmemoized = (props) => {
179
185
  const { field, fileName, nodePath, schema, propStatus } = props;
@@ -236,6 +242,7 @@ const TimelineSequencePropItem = ({ field, validatedLocation, rowDepth, nodePath
236
242
  const { getDragOverrides } = (0, react_1.useContext)(remotion_1.Internals.VisualModeDragOverridesContext);
237
243
  const { setPropStatuses } = (0, react_1.useContext)(remotion_1.Internals.VisualModeSettersContext);
238
244
  const { previewServerState } = (0, react_1.useContext)(client_id_1.StudioServerConnectionCtx);
245
+ const { canOpenInEditor, defaultEditorId } = (0, use_default_editor_info_1.useEditorOpening)(previewServerState.type === 'connected');
239
246
  const selection = (0, TimelineSelection_1.useTimelineRowSelection)(nodePathInfo);
240
247
  const transform3DMode = (0, react_1.useContext)(Transform3DModeContext_1.Transform3DModeContext);
241
248
  const propStatusesForOverride = remotion_1.Internals.getPropStatusesCtx(visualModePropStatuses, nodePath);
@@ -336,16 +343,16 @@ const TimelineSequencePropItem = ({ field, validatedLocation, rowDepth, nodePath
336
343
  }, [canShowReset, onReset, selection]);
337
344
  const onPropertyDoubleClick = (0, react_1.useCallback)((event) => {
338
345
  var _a;
339
- if (!window.remotion_editorName ||
340
- previewServerState.type !== 'connected') {
346
+ if (!canOpenInEditor || !defaultEditorId) {
341
347
  return;
342
348
  }
343
349
  event.stopPropagation();
344
350
  (0, open_in_editor_1.openOriginalPositionInEditorAtProperty)({
351
+ editorId: defaultEditorId,
345
352
  originalPosition: validatedLocation,
346
353
  property: (_a = field.key.split('.').at(-1)) !== null && _a !== void 0 ? _a : field.key,
347
354
  }).catch(() => undefined);
348
- }, [field.key, previewServerState.type, validatedLocation]);
355
+ }, [canOpenInEditor, defaultEditorId, field.key, validatedLocation]);
349
356
  if (propStatus === null) {
350
357
  return null;
351
358
  }
@@ -32,7 +32,10 @@ export type TimelineSequenceFromDragTarget = {
32
32
  readonly sequenceKeyframes: TimelineSequenceKeyframeDragTarget[];
33
33
  };
34
34
  type TimelineSequenceKeyframeDragTarget = {
35
+ readonly fileName: string;
35
36
  readonly fieldKey: string;
37
+ readonly isDescendant: boolean;
38
+ readonly nodePath: SequencePropsSubscriptionKey;
36
39
  readonly schema: InteractivitySchema;
37
40
  readonly status: CanUpdateSequencePropStatusKeyframed;
38
41
  };
@@ -60,7 +60,7 @@ const baseStyle = {
60
60
  zIndex: 1,
61
61
  touchAction: 'none',
62
62
  };
63
- const getKeyframedSequenceDragTargets = ({ nodePath, sequence, propStatuses, }) => {
63
+ const getKeyframedSequenceDragTargets = ({ nodePath, sequence, propStatuses, isDescendant, }) => {
64
64
  var _a;
65
65
  const status = propStatuses[remotion_1.Internals.makeSequencePropsSubscriptionKey(nodePath)];
66
66
  if (status === null || status === undefined || !status.canUpdate) {
@@ -69,8 +69,18 @@ const getKeyframedSequenceDragTargets = ({ nodePath, sequence, propStatuses, })
69
69
  const sequenceSchema = (_a = sequence.controls) === null || _a === void 0 ? void 0 : _a.schema;
70
70
  const sequenceKeyframes = sequenceSchema === undefined
71
71
  ? []
72
- : Object.entries(status.props).flatMap(([fieldKey, propStatus]) => propStatus.status === 'keyframed'
73
- ? [{ fieldKey, schema: sequenceSchema, status: propStatus }]
72
+ : Object.entries(status.props).flatMap(([fieldKey, propStatus]) => propStatus.status === 'keyframed' &&
73
+ (!isDescendant || propStatus.keyframeDisplayOffsetAdjustment !== null)
74
+ ? [
75
+ {
76
+ fileName: nodePath.absolutePath,
77
+ fieldKey,
78
+ isDescendant,
79
+ nodePath,
80
+ schema: sequenceSchema,
81
+ status: propStatus,
82
+ },
83
+ ]
74
84
  : []);
75
85
  const effectKeyframes = status.effects.flatMap((effectStatus) => {
76
86
  var _a;
@@ -81,11 +91,15 @@ const getKeyframedSequenceDragTargets = ({ nodePath, sequence, propStatuses, })
81
91
  if (effectSchema === undefined) {
82
92
  return [];
83
93
  }
84
- return Object.entries(effectStatus.props).flatMap(([fieldKey, propStatus]) => propStatus.status === 'keyframed'
94
+ return Object.entries(effectStatus.props).flatMap(([fieldKey, propStatus]) => propStatus.status === 'keyframed' &&
95
+ (!isDescendant || propStatus.keyframeDisplayOffsetAdjustment !== null)
85
96
  ? [
86
97
  {
87
98
  effectIndex: effectStatus.effectIndex,
99
+ fileName: nodePath.absolutePath,
88
100
  fieldKey,
101
+ isDescendant,
102
+ nodePath,
89
103
  schema: effectSchema,
90
104
  status: propStatus,
91
105
  },
@@ -94,7 +108,21 @@ const getKeyframedSequenceDragTargets = ({ nodePath, sequence, propStatuses, })
94
108
  });
95
109
  return { effectKeyframes, sequenceKeyframes };
96
110
  };
97
- const shiftKeyframedStatus = ({ status, deltaFrames, }) => {
111
+ const shiftKeyframedStatus = ({ status, deltaFrames, isDescendant, }) => {
112
+ if (isDescendant) {
113
+ const adjustment = status.keyframeDisplayOffsetAdjustment;
114
+ if (adjustment === null) {
115
+ throw new Error('Expected descendant keyframes to use an outer frame clock');
116
+ }
117
+ return {
118
+ ...status,
119
+ keyframeDisplayOffsetAdjustment: null,
120
+ keyframes: status.keyframes.map((keyframe) => ({
121
+ ...keyframe,
122
+ frame: keyframe.frame + adjustment,
123
+ })),
124
+ };
125
+ }
98
126
  return {
99
127
  ...status,
100
128
  keyframes: status.keyframes.map((keyframe) => ({
@@ -352,21 +380,27 @@ const getTimelineSequenceFromDragKeyframeMoves = ({ targets, deltaFrames, }) =>
352
380
  }
353
381
  return {
354
382
  sequenceKeyframes: targets.flatMap((target) => target.sequenceKeyframes.flatMap((keyframeTarget) => keyframeTarget.status.keyframes.map((keyframe) => ({
355
- fileName: target.fileName,
356
- nodePath: target.nodePath,
383
+ fileName: keyframeTarget.fileName,
384
+ nodePath: keyframeTarget.nodePath,
357
385
  fieldKey: keyframeTarget.fieldKey,
358
386
  fromFrame: keyframe.frame,
359
387
  toFrame: keyframe.frame + deltaFrames,
360
388
  schema: keyframeTarget.schema,
389
+ keyframeDisplayOffsetAdjustmentDelta: keyframeTarget.isDescendant
390
+ ? -deltaFrames
391
+ : undefined,
361
392
  })))),
362
393
  effectKeyframes: targets.flatMap((target) => target.effectKeyframes.flatMap((keyframeTarget) => keyframeTarget.status.keyframes.map((keyframe) => ({
363
- fileName: target.fileName,
364
- nodePath: target.nodePath,
394
+ fileName: keyframeTarget.fileName,
395
+ nodePath: keyframeTarget.nodePath,
365
396
  effectIndex: keyframeTarget.effectIndex,
366
397
  fieldKey: keyframeTarget.fieldKey,
367
398
  fromFrame: keyframe.frame,
368
399
  toFrame: keyframe.frame + deltaFrames,
369
400
  schema: keyframeTarget.schema,
401
+ keyframeDisplayOffsetAdjustmentDelta: keyframeTarget.isDescendant
402
+ ? -deltaFrames
403
+ : undefined,
370
404
  })))),
371
405
  };
372
406
  };
@@ -510,6 +544,8 @@ const getTimelineSequenceFromDragTargets = ({ draggedNodePathInfo, selectedItems
510
544
  : [draggedNodePathInfo];
511
545
  const tracks = (0, calculate_timeline_1.calculateTimeline)({ sequences, overrideIdsToNodePaths });
512
546
  const targets = new Map();
547
+ const includedKeyframeNodePaths = new Set();
548
+ const sequencesById = new Map(sequences.map((sequence) => [sequence.id, sequence]));
513
549
  for (const nodePathInfo of targetNodePathInfos) {
514
550
  const track = findSequenceTrack({ tracks, nodePathInfo });
515
551
  const originalSequence = track
@@ -527,11 +563,43 @@ const getTimelineSequenceFromDragTargets = ({ draggedNodePathInfo, selectedItems
527
563
  }
528
564
  const key = (0, studio_shared_1.stringifySequenceSubscriptionKey)(nodePath);
529
565
  if (!targets.has(key)) {
530
- const { effectKeyframes, sequenceKeyframes } = getKeyframedSequenceDragTargets({
531
- nodePath,
532
- sequence: originalSequence,
533
- propStatuses,
566
+ const descendants = sequences.filter((candidate) => {
567
+ var _a;
568
+ var _b;
569
+ let parentId = candidate.id;
570
+ while (parentId !== null) {
571
+ if (parentId === originalSequence.id) {
572
+ return true;
573
+ }
574
+ parentId = (_b = (_a = sequencesById.get(parentId)) === null || _a === void 0 ? void 0 : _a.parent) !== null && _b !== void 0 ? _b : null;
575
+ }
576
+ return false;
577
+ });
578
+ const descendantKeyframes = descendants.flatMap((sequence) => {
579
+ var _a;
580
+ const overrideId = (_a = sequence.controls) === null || _a === void 0 ? void 0 : _a.overrideId;
581
+ const descendantNodePath = overrideId
582
+ ? overrideIdsToNodePaths[overrideId]
583
+ : undefined;
584
+ if (descendantNodePath === undefined) {
585
+ return [];
586
+ }
587
+ const descendantNodePathKey = (0, studio_shared_1.stringifySequenceSubscriptionKey)(descendantNodePath);
588
+ if (includedKeyframeNodePaths.has(descendantNodePathKey)) {
589
+ return [];
590
+ }
591
+ includedKeyframeNodePaths.add(descendantNodePathKey);
592
+ return [
593
+ getKeyframedSequenceDragTargets({
594
+ nodePath: descendantNodePath,
595
+ sequence,
596
+ propStatuses,
597
+ isDescendant: sequence.id !== originalSequence.id,
598
+ }),
599
+ ];
534
600
  });
601
+ const effectKeyframes = descendantKeyframes.flatMap((descendant) => descendant.effectKeyframes);
602
+ const sequenceKeyframes = descendantKeyframes.flatMap((descendant) => descendant.sequenceKeyframes);
535
603
  targets.set(key, {
536
604
  canSnapToTimelineStart: originalSequence.parent === null,
537
605
  effectKeyframes,
@@ -558,9 +626,17 @@ const clearDurationDragOverrides = ({ clearDragOverrides, targets, }) => {
558
626
  const clearFromDragOverrides = ({ clearDragOverrides, clearEffectDragOverrides, targets, }) => {
559
627
  for (const target of targets) {
560
628
  clearDragOverrides(target.nodePath);
561
- const effectIndexes = new Set(target.effectKeyframes.map((keyframe) => keyframe.effectIndex));
562
- for (const effectIndex of effectIndexes) {
563
- clearEffectDragOverrides(target.nodePath, effectIndex);
629
+ for (const keyframeTarget of target.sequenceKeyframes) {
630
+ clearDragOverrides(keyframeTarget.nodePath);
631
+ }
632
+ const clearedEffects = new Set();
633
+ for (const keyframeTarget of target.effectKeyframes) {
634
+ const key = `${(0, studio_shared_1.stringifySequenceSubscriptionKey)(keyframeTarget.nodePath)}:${keyframeTarget.effectIndex}`;
635
+ if (clearedEffects.has(key)) {
636
+ continue;
637
+ }
638
+ clearedEffects.add(key);
639
+ clearEffectDragOverrides(keyframeTarget.nodePath, keyframeTarget.effectIndex);
564
640
  }
565
641
  }
566
642
  };
@@ -916,20 +992,22 @@ const useTimelineSequenceFromDrag = ({ nodePathInfo, windowWidth, timelineDurati
916
992
  });
917
993
  latestRef.current.setDragOverrides(target.nodePath, 'from', remotion_1.Internals.makeStaticDragOverride(nextFrom));
918
994
  for (const keyframeTarget of target.sequenceKeyframes) {
919
- latestRef.current.setDragOverrides(target.nodePath, keyframeTarget.fieldKey, {
995
+ latestRef.current.setDragOverrides(keyframeTarget.nodePath, keyframeTarget.fieldKey, {
920
996
  type: 'keyframed',
921
997
  status: shiftKeyframedStatus({
922
998
  status: keyframeTarget.status,
923
999
  deltaFrames,
1000
+ isDescendant: keyframeTarget.isDescendant,
924
1001
  }),
925
1002
  });
926
1003
  }
927
1004
  for (const keyframeTarget of target.effectKeyframes) {
928
- latestRef.current.setEffectDragOverrides(target.nodePath, keyframeTarget.effectIndex, keyframeTarget.fieldKey, {
1005
+ latestRef.current.setEffectDragOverrides(keyframeTarget.nodePath, keyframeTarget.effectIndex, keyframeTarget.fieldKey, {
929
1006
  type: 'keyframed',
930
1007
  status: shiftKeyframedStatus({
931
1008
  status: keyframeTarget.status,
932
1009
  deltaFrames,
1010
+ isDescendant: keyframeTarget.isDescendant,
933
1011
  }),
934
1012
  });
935
1013
  }
@@ -1,4 +1,4 @@
1
- import type { SequencePropsSubscriptionKey, InteractivitySchema } from 'remotion';
1
+ import type { InteractivitySchema, SequencePropsSubscriptionKey } from 'remotion';
2
2
  import type { SetPropStatuses } from './save-sequence-prop';
3
3
  export type MoveSequenceKeyframeChange = {
4
4
  fileName: string;
@@ -7,6 +7,7 @@ export type MoveSequenceKeyframeChange = {
7
7
  fromFrame: number;
8
8
  toFrame: number;
9
9
  schema: InteractivitySchema;
10
+ keyframeDisplayOffsetAdjustmentDelta?: number;
10
11
  };
11
12
  export type MoveEffectKeyframeChange = MoveSequenceKeyframeChange & {
12
13
  effectIndex: number;
@@ -14,6 +14,27 @@ const groupByNodePath = (keyframes) => {
14
14
  }
15
15
  return [...groups.values()];
16
16
  };
17
+ const applyKeyframeDisplayOffsetAdjustmentDeltas = ({ props, keyframes, }) => {
18
+ const nextProps = { ...props };
19
+ const deltas = new Map();
20
+ for (const keyframe of keyframes) {
21
+ if (keyframe.keyframeDisplayOffsetAdjustmentDelta !== undefined) {
22
+ deltas.set(keyframe.fieldKey, keyframe.keyframeDisplayOffsetAdjustmentDelta);
23
+ }
24
+ }
25
+ for (const [fieldKey, delta] of deltas) {
26
+ const status = nextProps[fieldKey];
27
+ if ((status === null || status === void 0 ? void 0 : status.status) !== 'keyframed' ||
28
+ status.keyframeDisplayOffsetAdjustment === null) {
29
+ continue;
30
+ }
31
+ nextProps[fieldKey] = {
32
+ ...status,
33
+ keyframeDisplayOffsetAdjustment: status.keyframeDisplayOffsetAdjustment + delta,
34
+ };
35
+ }
36
+ return nextProps;
37
+ };
17
38
  const applyOptimisticKeyframeMoves = ({ sequenceKeyframes, effectKeyframes, setPropStatuses, }) => {
18
39
  if (sequenceKeyframes.length === 0 && effectKeyframes.length === 0) {
19
40
  return;
@@ -23,29 +44,61 @@ const applyOptimisticKeyframeMoves = ({ sequenceKeyframes, effectKeyframes, setP
23
44
  if (!firstKeyframe) {
24
45
  continue;
25
46
  }
26
- setPropStatuses(firstKeyframe.nodePath, (prev) => (0, studio_shared_1.optimisticMoveSequenceKeyframes)({
27
- previous: prev,
28
- keyframes: keyframes.map((keyframe) => ({
29
- fieldKey: keyframe.fieldKey,
30
- fromFrame: keyframe.fromFrame,
31
- toFrame: keyframe.toFrame,
32
- })),
33
- }));
47
+ setPropStatuses(firstKeyframe.nodePath, (prev) => {
48
+ const moved = (0, studio_shared_1.optimisticMoveSequenceKeyframes)({
49
+ previous: prev,
50
+ keyframes: keyframes.map((keyframe) => ({
51
+ fieldKey: keyframe.fieldKey,
52
+ fromFrame: keyframe.fromFrame,
53
+ toFrame: keyframe.toFrame,
54
+ })),
55
+ });
56
+ if (!moved.canUpdate) {
57
+ return moved;
58
+ }
59
+ return {
60
+ ...moved,
61
+ props: applyKeyframeDisplayOffsetAdjustmentDeltas({
62
+ props: moved.props,
63
+ keyframes,
64
+ }),
65
+ };
66
+ });
34
67
  }
35
68
  for (const keyframes of groupByNodePath(effectKeyframes)) {
36
69
  const [firstKeyframe] = keyframes;
37
70
  if (!firstKeyframe) {
38
71
  continue;
39
72
  }
40
- setPropStatuses(firstKeyframe.nodePath, (prev) => (0, studio_shared_1.optimisticMoveEffectKeyframes)({
41
- previous: prev,
42
- keyframes: keyframes.map((keyframe) => ({
43
- effectIndex: keyframe.effectIndex,
44
- fieldKey: keyframe.fieldKey,
45
- fromFrame: keyframe.fromFrame,
46
- toFrame: keyframe.toFrame,
47
- })),
48
- }));
73
+ setPropStatuses(firstKeyframe.nodePath, (prev) => {
74
+ const moved = (0, studio_shared_1.optimisticMoveEffectKeyframes)({
75
+ previous: prev,
76
+ keyframes: keyframes.map((keyframe) => ({
77
+ effectIndex: keyframe.effectIndex,
78
+ fieldKey: keyframe.fieldKey,
79
+ fromFrame: keyframe.fromFrame,
80
+ toFrame: keyframe.toFrame,
81
+ })),
82
+ });
83
+ if (!moved.canUpdate) {
84
+ return moved;
85
+ }
86
+ return {
87
+ ...moved,
88
+ effects: moved.effects.map((effect) => {
89
+ if (!effect.canUpdate) {
90
+ return effect;
91
+ }
92
+ return {
93
+ ...effect,
94
+ props: applyKeyframeDisplayOffsetAdjustmentDeltas({
95
+ props: effect.props,
96
+ keyframes: keyframes.filter((keyframe) => keyframe.effectIndex === effect.effectIndex),
97
+ }),
98
+ };
99
+ }),
100
+ };
101
+ });
49
102
  }
50
103
  };
51
104
  exports.applyOptimisticKeyframeMoves = applyOptimisticKeyframeMoves;
@@ -1,14 +1,6 @@
1
1
  import type { OverrideIdToNodePaths, PropStatuses, TSequence } from 'remotion';
2
2
  import type { SequenceNodePathInfo } from '../../helpers/get-timeline-sequence-sort-key';
3
3
  import type { SetPropStatuses } from './save-sequence-prop';
4
- export declare const deleteSelectedKeyframe: ({ nodePathInfo, frame, sequences, overrideIdsToNodePaths, setPropStatuses, clientId, }: {
5
- nodePathInfo: SequenceNodePathInfo;
6
- frame: number;
7
- sequences: TSequence[];
8
- overrideIdsToNodePaths: OverrideIdToNodePaths;
9
- setPropStatuses: SetPropStatuses;
10
- clientId: string;
11
- }) => Promise<void> | null;
12
4
  export declare const deleteSelectedKeyframes: ({ keyframes, sequences, overrideIdsToNodePaths, setPropStatuses, clientId, propStatuses, timelinePosition, }: {
13
5
  keyframes: {
14
6
  nodePathInfo: SequenceNodePathInfo;
@@ -1,13 +1,14 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.deleteSelectedKeyframes = exports.deleteSelectedKeyframe = void 0;
3
+ exports.deleteSelectedKeyframes = void 0;
4
4
  const remotion_1 = require("remotion");
5
5
  const call_delete_keyframe_1 = require("./call-delete-keyframe");
6
6
  const find_track_for_node_path_info_1 = require("./find-track-for-node-path-info");
7
+ const get_timeline_keyframes_1 = require("./get-timeline-keyframes");
7
8
  const parse_keyframe_field_from_node_path_1 = require("./parse-keyframe-field-from-node-path");
8
9
  const getValueWhenLastKeyframeDeleted = ({ propStatus, playheadSourceFrame, }) => {
9
10
  var _a;
10
- if ((propStatus === null || propStatus === void 0 ? void 0 : propStatus.status) !== 'keyframed' || playheadSourceFrame === null) {
11
+ if ((propStatus === null || propStatus === void 0 ? void 0 : propStatus.status) !== 'keyframed') {
11
12
  return null;
12
13
  }
13
14
  return ((_a = remotion_1.Internals.interpolateKeyframedStatus({
@@ -32,10 +33,6 @@ const getSelectedKeyframeDeletion = ({ nodePathInfo, frame, sequences, overrideI
32
33
  if (!(sequence === null || sequence === void 0 ? void 0 : sequence.controls)) {
33
34
  return null;
34
35
  }
35
- const sourceFrame = frame - ((_c = track === null || track === void 0 ? void 0 : track.keyframeDisplayOffset) !== null && _c !== void 0 ? _c : 0);
36
- const playheadSourceFrame = timelinePosition === null
37
- ? null
38
- : timelinePosition - ((_d = track === null || track === void 0 ? void 0 : track.keyframeDisplayOffset) !== null && _d !== void 0 ? _d : 0);
39
36
  const nodePath = nodePathInfo.sequenceSubscriptionKey;
40
37
  const fileName = nodePath.absolutePath;
41
38
  if (field.type === 'effect') {
@@ -43,19 +40,23 @@ const getSelectedKeyframeDeletion = ({ nodePathInfo, frame, sequences, overrideI
43
40
  if (!effect) {
44
41
  return null;
45
42
  }
46
- const effectStatus = propStatuses !== null
47
- ? remotion_1.Internals.getEffectPropStatusesCtx({
48
- propStatuses,
49
- nodePath,
50
- effectIndex: field.effectIndex,
51
- })
52
- : null;
43
+ const effectStatus = remotion_1.Internals.getEffectPropStatusesCtx({
44
+ propStatuses,
45
+ nodePath,
46
+ effectIndex: field.effectIndex,
47
+ });
53
48
  const effectPropStatus = (effectStatus === null || effectStatus === void 0 ? void 0 : effectStatus.type) === 'can-update-effect'
54
49
  ? effectStatus.props[field.fieldKey]
55
50
  : null;
51
+ const effectKeyframeDisplayOffset = (0, get_timeline_keyframes_1.getKeyframeDisplayOffset)({
52
+ propStatus: effectPropStatus,
53
+ keyframeDisplayOffset: (_c = track === null || track === void 0 ? void 0 : track.keyframeDisplayOffset) !== null && _c !== void 0 ? _c : 0,
54
+ });
55
+ const effectSourceFrame = frame - effectKeyframeDisplayOffset;
56
+ const effectPlayheadSourceFrame = timelinePosition - effectKeyframeDisplayOffset;
56
57
  const effectValueWhenLastKeyframeDeleted = getValueWhenLastKeyframeDeleted({
57
58
  propStatus: effectPropStatus,
58
- playheadSourceFrame,
59
+ playheadSourceFrame: effectPlayheadSourceFrame,
59
60
  });
60
61
  return {
61
62
  type: 'effect',
@@ -63,14 +64,18 @@ const getSelectedKeyframeDeletion = ({ nodePathInfo, frame, sequences, overrideI
63
64
  nodePath,
64
65
  effectIndex: field.effectIndex,
65
66
  fieldKey: field.fieldKey,
66
- sourceFrame,
67
+ sourceFrame: effectSourceFrame,
67
68
  schema: effect.schema,
68
69
  valueWhenLastKeyframeDeleted: effectValueWhenLastKeyframeDeleted,
69
70
  };
70
71
  }
71
- const sequencePropStatus = propStatuses !== null
72
- ? (_a = remotion_1.Internals.getPropStatusesCtx(propStatuses, nodePath)) === null || _a === void 0 ? void 0 : _a[field.fieldKey]
73
- : null;
72
+ const sequencePropStatus = (_a = remotion_1.Internals.getPropStatusesCtx(propStatuses, nodePath)) === null || _a === void 0 ? void 0 : _a[field.fieldKey];
73
+ const keyframeDisplayOffset = (0, get_timeline_keyframes_1.getKeyframeDisplayOffset)({
74
+ propStatus: sequencePropStatus,
75
+ keyframeDisplayOffset: (_d = track === null || track === void 0 ? void 0 : track.keyframeDisplayOffset) !== null && _d !== void 0 ? _d : 0,
76
+ });
77
+ const sourceFrame = frame - keyframeDisplayOffset;
78
+ const playheadSourceFrame = timelinePosition - keyframeDisplayOffset;
74
79
  const sequenceValueWhenLastKeyframeDeleted = getValueWhenLastKeyframeDeleted({
75
80
  propStatus: sequencePropStatus,
76
81
  playheadSourceFrame,
@@ -85,32 +90,6 @@ const getSelectedKeyframeDeletion = ({ nodePathInfo, frame, sequences, overrideI
85
90
  valueWhenLastKeyframeDeleted: sequenceValueWhenLastKeyframeDeleted,
86
91
  };
87
92
  };
88
- const deleteSelectedKeyframe = ({ nodePathInfo, frame, sequences, overrideIdsToNodePaths, setPropStatuses, clientId, }) => {
89
- const deletion = getSelectedKeyframeDeletion({
90
- nodePathInfo,
91
- frame,
92
- sequences,
93
- overrideIdsToNodePaths,
94
- propStatuses: null,
95
- timelinePosition: null,
96
- });
97
- if (deletion === null) {
98
- return null;
99
- }
100
- if (deletion.type === 'effect') {
101
- return (0, call_delete_keyframe_1.callDeleteEffectKeyframe)({
102
- ...deletion,
103
- setPropStatuses,
104
- clientId,
105
- });
106
- }
107
- return (0, call_delete_keyframe_1.callDeleteSequenceKeyframe)({
108
- ...deletion,
109
- setPropStatuses,
110
- clientId,
111
- });
112
- };
113
- exports.deleteSelectedKeyframe = deleteSelectedKeyframe;
114
93
  const deleteSelectedKeyframes = ({ keyframes, sequences, overrideIdsToNodePaths, setPropStatuses, clientId, propStatuses, timelinePosition, }) => {
115
94
  const deletions = keyframes
116
95
  .map((keyframe) => getSelectedKeyframeDeletion({