@remotion/studio 4.0.496 → 4.0.498

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 (109) hide show
  1. package/dist/components/AudioWaveform.js +1 -11
  2. package/dist/components/Canvas.js +22 -203
  3. package/dist/components/Checkbox.js +1 -1
  4. package/dist/components/CompositionSelectorItem.js +2 -10
  5. package/dist/components/ConfigureLicenseModal.d.ts +4 -0
  6. package/dist/components/ConfigureLicenseModal.js +194 -0
  7. package/dist/components/Editor.d.ts +0 -1
  8. package/dist/components/Editor.js +2 -3
  9. package/dist/components/InspectorPanel/AlignmentControls.js +2 -0
  10. package/dist/components/InspectorPanel/CompositionInspector.js +2 -1
  11. package/dist/components/InspectorPanel/ConnectedCompositionsSection.js +27 -2
  12. package/dist/components/InspectorPanel/SequenceSelectionInspector.js +65 -8
  13. package/dist/components/InspectorPanel/use-composition-actions.js +7 -3
  14. package/dist/components/LicenseKeyValidation.d.ts +17 -0
  15. package/dist/components/LicenseKeyValidation.js +113 -0
  16. package/dist/components/Modals.js +2 -1
  17. package/dist/components/NewComposition/CodemodFooter.d.ts +1 -1
  18. package/dist/components/NewComposition/CodemodFooter.js +23 -4
  19. package/dist/components/NewComposition/InputDragger.d.ts +6 -0
  20. package/dist/components/NewComposition/InputDragger.js +12 -3
  21. package/dist/components/NewComposition/NewComposition.js +1 -1
  22. package/dist/components/NewComposition/use-rename-static-file.js +1 -1
  23. package/dist/components/RenderButton.js +0 -1
  24. package/dist/components/RenderModal/WebRenderModal.js +14 -8
  25. package/dist/components/SelectedOutlineElement.js +56 -88
  26. package/dist/components/SelectedOutlineOverlay.d.ts +1 -1
  27. package/dist/components/SelectedOutlineOverlay.js +10 -11
  28. package/dist/components/Timeline/MaxTimelineTracks.d.ts +0 -1
  29. package/dist/components/Timeline/MaxTimelineTracks.js +3 -3
  30. package/dist/components/Timeline/Timeline.js +19 -11
  31. package/dist/components/Timeline/TimelineAssetDropIndicator.d.ts +2 -0
  32. package/dist/components/Timeline/TimelineAssetDropIndicator.js +37 -0
  33. package/dist/components/Timeline/TimelineClipboardKeybindings.js +1 -7
  34. package/dist/components/Timeline/TimelineDragHandler.js +1 -1
  35. package/dist/components/Timeline/TimelineScrollable.js +3 -2
  36. package/dist/components/Timeline/TimelineSelection.d.ts +4 -0
  37. package/dist/components/Timeline/TimelineSelection.js +41 -6
  38. package/dist/components/Timeline/TimelineSequence.js +26 -14
  39. package/dist/components/Timeline/TimelineSequenceFrame.js +2 -4
  40. package/dist/components/Timeline/TimelineSequenceItem.js +7 -5
  41. package/dist/components/Timeline/TimelineSequencePropItem.js +4 -0
  42. package/dist/components/Timeline/TimelineSequenceRightEdgeDragHandle.d.ts +23 -3
  43. package/dist/components/Timeline/TimelineSequenceRightEdgeDragHandle.js +135 -19
  44. package/dist/components/Timeline/TimelineTimeIndicators.d.ts +16 -0
  45. package/dist/components/Timeline/TimelineTimeIndicators.js +154 -35
  46. package/dist/components/Timeline/TimelineTranslateField.js +2 -1
  47. package/dist/components/Timeline/TimelineVideoInfo.d.ts +1 -0
  48. package/dist/components/Timeline/TimelineVideoInfo.js +4 -1
  49. package/dist/components/Timeline/call-update-keyframe-settings.d.ts +17 -0
  50. package/dist/components/Timeline/call-update-keyframe-settings.js +43 -1
  51. package/dist/components/Timeline/delete-selected-timeline-item.d.ts +2 -0
  52. package/dist/components/Timeline/delete-selected-timeline-item.js +5 -4
  53. package/dist/components/Timeline/disable-sequence-interactivity.js +2 -0
  54. package/dist/components/Timeline/get-timeline-media-visualization-layout.d.ts +8 -0
  55. package/dist/components/Timeline/get-timeline-media-visualization-layout.js +10 -0
  56. package/dist/components/Timeline/get-timeline-video-info-widths.js +11 -3
  57. package/dist/components/Timeline/keyframe-clipboard.js +21 -5
  58. package/dist/components/Timeline/reset-selected-timeline-props.js +2 -0
  59. package/dist/components/Timeline/save-sequence-prop.d.ts +5 -3
  60. package/dist/components/Timeline/save-sequence-prop.js +43 -18
  61. package/dist/components/Timeline/should-clear-selection-on-pointer-down.d.ts +2 -0
  62. package/dist/components/Timeline/should-clear-selection-on-pointer-down.js +1 -1
  63. package/dist/components/Timeline/timeline-asset-drop-context.d.ts +1 -0
  64. package/dist/components/Timeline/timeline-asset-drop-context.js +5 -0
  65. package/dist/components/Timeline/timeline-scroll-logic.d.ts +7 -0
  66. package/dist/components/Timeline/timeline-scroll-logic.js +10 -1
  67. package/dist/components/Timeline/update-selected-easing.js +26 -23
  68. package/dist/components/Timeline/use-rename-sequence.js +2 -0
  69. package/dist/components/Timeline/use-sequence-freeze-frame-menu-item.d.ts +5 -0
  70. package/dist/components/Timeline/use-sequence-freeze-frame-menu-item.js +18 -9
  71. package/dist/components/Timeline/use-timeline-asset-drop.d.ts +1 -0
  72. package/dist/components/Timeline/use-timeline-asset-drop.js +168 -0
  73. package/dist/components/composition-menu-items.d.ts +15 -1
  74. package/dist/components/composition-menu-items.js +137 -107
  75. package/dist/components/drop-handler-data.d.ts +13 -0
  76. package/dist/components/drop-handler-data.js +117 -0
  77. package/dist/components/handle-drop.d.ts +13 -0
  78. package/dist/components/handle-drop.js +115 -0
  79. package/dist/components/import-assets.d.ts +26 -8
  80. package/dist/components/import-assets.js +161 -49
  81. package/dist/components/selected-outline-drag.d.ts +11 -1
  82. package/dist/components/selected-outline-drag.js +74 -1
  83. package/dist/esm/{chunk-0v4n7nkh.js → chunk-7a6q9hk2.js} +5271 -4259
  84. package/dist/esm/index.mjs +0 -19
  85. package/dist/esm/internals.mjs +5271 -4259
  86. package/dist/esm/previewEntry.mjs +5475 -4463
  87. package/dist/esm/renderEntry.mjs +1 -1
  88. package/dist/helpers/interactivity-enabled.d.ts +1 -1
  89. package/dist/helpers/interactivity-enabled.js +2 -2
  90. package/dist/helpers/is-video-with-last-frame-hold.d.ts +2 -0
  91. package/dist/helpers/is-video-with-last-frame-hold.js +9 -0
  92. package/dist/helpers/retry-payload.js +0 -1
  93. package/dist/helpers/url-state.d.ts +1 -0
  94. package/dist/helpers/url-state.js +5 -1
  95. package/dist/helpers/use-max-media-duration.js +5 -3
  96. package/dist/helpers/use-menu-structure.js +11 -3
  97. package/dist/icons/duplicate.d.ts +5 -0
  98. package/dist/icons/duplicate.js +10 -0
  99. package/dist/icons/snowflake.d.ts +5 -0
  100. package/dist/icons/snowflake.js +10 -0
  101. package/dist/icons/trash.d.ts +5 -0
  102. package/dist/icons/trash.js +8 -0
  103. package/dist/state/modals.d.ts +3 -1
  104. package/dist/visual-controls/VisualControls.js +1 -1
  105. package/package.json +11 -11
  106. package/dist/components/RenderModal/WebRenderModalLicense.d.ts +0 -9
  107. package/dist/components/RenderModal/WebRenderModalLicense.js +0 -189
  108. package/dist/components/RenderModal/WebRenderModalLicenseKeyDetails.d.ts +0 -13
  109. package/dist/components/RenderModal/WebRenderModalLicenseKeyDetails.js +0 -60
@@ -20,3 +20,20 @@ export declare const callUpdateEffectKeyframeSettings: ({ fileName, nodePath, ef
20
20
  setPropStatuses: SetPropStatuses;
21
21
  clientId: string;
22
22
  }) => Promise<void>;
23
+ type BatchSequenceKeyframeSettingsUpdate = {
24
+ fileName: string;
25
+ nodePath: SequencePropsSubscriptionKey;
26
+ fieldKey: string;
27
+ settings: KeyframeSettings;
28
+ schema: InteractivitySchema;
29
+ };
30
+ type BatchEffectKeyframeSettingsUpdate = BatchSequenceKeyframeSettingsUpdate & {
31
+ effectIndex: number;
32
+ };
33
+ export declare const callBatchUpdateKeyframeSettings: ({ sequenceKeyframes, effectKeyframes, setPropStatuses, clientId, }: {
34
+ sequenceKeyframes: BatchSequenceKeyframeSettingsUpdate[];
35
+ effectKeyframes: BatchEffectKeyframeSettingsUpdate[];
36
+ setPropStatuses: SetPropStatuses;
37
+ clientId: string;
38
+ }) => Promise<void>;
39
+ export {};
@@ -1,8 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.callUpdateEffectKeyframeSettings = exports.callUpdateSequenceKeyframeSettings = void 0;
3
+ exports.callBatchUpdateKeyframeSettings = exports.callUpdateEffectKeyframeSettings = exports.callUpdateSequenceKeyframeSettings = void 0;
4
4
  const studio_shared_1 = require("@remotion/studio-shared");
5
5
  const call_api_1 = require("../call-api");
6
+ const NotificationCenter_1 = require("../Notifications/NotificationCenter");
6
7
  const apply_effect_response_to_prop_statuses_1 = require("./apply-effect-response-to-prop-statuses");
7
8
  const save_prop_queue_1 = require("./save-prop-queue");
8
9
  const callUpdateSequenceKeyframeSettings = ({ fileName, nodePath, fieldKey, settings, schema, setPropStatuses, clientId, }) => {
@@ -50,3 +51,44 @@ const callUpdateEffectKeyframeSettings = ({ fileName, nodePath, effectIndex, fie
50
51
  });
51
52
  };
52
53
  exports.callUpdateEffectKeyframeSettings = callUpdateEffectKeyframeSettings;
54
+ const callBatchUpdateKeyframeSettings = ({ sequenceKeyframes, effectKeyframes, setPropStatuses, clientId, }) => {
55
+ for (const update of sequenceKeyframes) {
56
+ setPropStatuses(update.nodePath, (prev) => (0, studio_shared_1.optimisticUpdateSequenceKeyframeSettings)({
57
+ previous: prev,
58
+ fieldKey: update.fieldKey,
59
+ settings: update.settings,
60
+ }));
61
+ }
62
+ for (const update of effectKeyframes) {
63
+ setPropStatuses(update.nodePath, (prev) => (0, studio_shared_1.optimisticUpdateEffectKeyframeSettings)({
64
+ previous: prev,
65
+ effectIndex: update.effectIndex,
66
+ fieldKey: update.fieldKey,
67
+ settings: update.settings,
68
+ }));
69
+ }
70
+ return (0, call_api_1.callApi)('/api/batch-update-keyframe-settings', {
71
+ sequenceKeyframes: sequenceKeyframes.map((update) => ({
72
+ fileName: update.fileName,
73
+ nodePath: update.nodePath,
74
+ key: update.fieldKey,
75
+ settings: update.settings,
76
+ schema: update.schema,
77
+ })),
78
+ effectKeyframes: effectKeyframes.map((update) => ({
79
+ fileName: update.fileName,
80
+ sequenceNodePath: update.nodePath,
81
+ effectIndex: update.effectIndex,
82
+ key: update.fieldKey,
83
+ settings: update.settings,
84
+ schema: update.schema,
85
+ })),
86
+ clientId,
87
+ })
88
+ .then(() => undefined)
89
+ .catch((err) => {
90
+ (0, NotificationCenter_1.showNotification)(`Could not update keyframe settings: ${err instanceof Error ? err.message : String(err)}`, 4000);
91
+ throw err;
92
+ });
93
+ };
94
+ exports.callBatchUpdateKeyframeSettings = callBatchUpdateKeyframeSettings;
@@ -1,7 +1,9 @@
1
1
  import type { OverrideIdToNodePaths, PropStatuses, TSequence } from 'remotion';
2
+ import type { SequenceNodePathInfo } from '../../helpers/get-timeline-sequence-sort-key';
2
3
  import type { ConfirmationDialogFunction } from '../ConfirmationDialog-types';
3
4
  import type { SetPropStatuses } from './save-sequence-prop';
4
5
  import { type TimelineSelection } from './TimelineSelection';
6
+ export declare const deleteSequencesFromSource: (nodePathInfos: SequenceNodePathInfo[], confirm: ConfirmationDialogFunction) => Promise<boolean>;
5
7
  export declare const deleteSelectedTimelineItem: ({ selection, sequences, overrideIdsToNodePaths, setPropStatuses, clientId, confirm, }: {
6
8
  selection: TimelineSelection;
7
9
  sequences: TSequence[];
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.deleteSelectedTimelineItems = exports.getTimelineSelectionAfterDeletingItems = exports.deleteSelectedTimelineItem = void 0;
3
+ exports.deleteSelectedTimelineItems = exports.getTimelineSelectionAfterDeletingItems = exports.deleteSelectedTimelineItem = exports.deleteSequencesFromSource = void 0;
4
4
  const remotion_1 = require("remotion");
5
5
  const call_api_1 = require("../call-api");
6
6
  const NotificationCenter_1 = require("../Notifications/NotificationCenter");
@@ -32,7 +32,7 @@ const confirmDeletingDuplicatedSequences = (nodePathInfos, confirm) => {
32
32
  confirmLabel: 'Delete',
33
33
  });
34
34
  };
35
- const deleteSequences = async (nodePathInfos, confirm) => {
35
+ const deleteSequencesFromSource = async (nodePathInfos, confirm) => {
36
36
  if (!(await confirmDeletingDuplicatedSequences(nodePathInfos, confirm))) {
37
37
  return false;
38
38
  }
@@ -61,6 +61,7 @@ const deleteSequences = async (nodePathInfos, confirm) => {
61
61
  return true;
62
62
  });
63
63
  };
64
+ exports.deleteSequencesFromSource = deleteSequencesFromSource;
64
65
  const deleteEffects = (effects) => {
65
66
  if (effects.length === 0) {
66
67
  return Promise.resolve(false);
@@ -115,7 +116,7 @@ const deleteSelectedTimelineItem = ({ selection, sequences, overrideIdsToNodePat
115
116
  case 'guide':
116
117
  return null;
117
118
  case 'sequence':
118
- return deleteSequences([selection.nodePathInfo], confirm);
119
+ return (0, exports.deleteSequencesFromSource)([selection.nodePathInfo], confirm);
119
120
  case 'sequence-effect':
120
121
  return deleteEffects([
121
122
  {
@@ -286,7 +287,7 @@ const deleteSelectedTimelineItems = ({ selections, sequences, overrideIdsToNodeP
286
287
  case 'guide':
287
288
  return null;
288
289
  case 'sequence':
289
- return deleteSequences(selections
290
+ return (0, exports.deleteSequencesFromSource)(selections
290
291
  .filter(isSequenceRowSelection)
291
292
  .map((selection) => selection.nodePathInfo), confirm);
292
293
  case 'sequence-effect':
@@ -5,6 +5,8 @@ const no_react_1 = require("remotion/no-react");
5
5
  const save_sequence_prop_1 = require("./save-sequence-prop");
6
6
  const disableSequenceInteractivity = ({ clientId, fileName, nodePath, setPropStatuses, }) => {
7
7
  return (0, save_sequence_prop_1.saveSequenceProps)({
8
+ addedKeyframes: null,
9
+ movedKeyframes: null,
8
10
  changes: [
9
11
  {
10
12
  fileName,
@@ -0,0 +1,8 @@
1
+ export declare const getTimelineMediaVisualizationLayout: ({ visualizationWidth, premountWidth, postmountWidth, }: {
2
+ readonly visualizationWidth: number;
3
+ readonly premountWidth: number;
4
+ readonly postmountWidth: number;
5
+ }) => {
6
+ marginLeft: number;
7
+ width: number;
8
+ };
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getTimelineMediaVisualizationLayout = void 0;
4
+ const getTimelineMediaVisualizationLayout = ({ visualizationWidth, premountWidth, postmountWidth, }) => {
5
+ return {
6
+ marginLeft: premountWidth,
7
+ width: Math.max(0, visualizationWidth - premountWidth - postmountWidth),
8
+ };
9
+ };
10
+ exports.getTimelineMediaVisualizationLayout = getTimelineMediaVisualizationLayout;
@@ -1,11 +1,19 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getTimelineVideoInfoWidths = void 0;
4
+ const get_timeline_media_visualization_layout_1 = require("./get-timeline-media-visualization-layout");
4
5
  const getTimelineVideoInfoWidths = ({ visualizationWidth, naturalWidth, premountWidth, postmountWidth, }) => {
5
- const mountWidth = premountWidth + postmountWidth;
6
6
  return {
7
- mediaVisualizationWidth: Math.max(0, visualizationWidth - mountWidth),
8
- mediaNaturalWidth: Math.max(0, naturalWidth - mountWidth),
7
+ mediaVisualizationWidth: (0, get_timeline_media_visualization_layout_1.getTimelineMediaVisualizationLayout)({
8
+ visualizationWidth,
9
+ premountWidth,
10
+ postmountWidth,
11
+ }).width,
12
+ mediaNaturalWidth: (0, get_timeline_media_visualization_layout_1.getTimelineMediaVisualizationLayout)({
13
+ visualizationWidth: naturalWidth,
14
+ premountWidth,
15
+ postmountWidth,
16
+ }).width,
9
17
  };
10
18
  };
11
19
  exports.getTimelineVideoInfoWidths = getTimelineVideoInfoWidths;
@@ -182,6 +182,10 @@ const getKeyframeClipboardDataFromSelections = ({ selections, sequences, overrid
182
182
  version: 1,
183
183
  remotionClipboard: 'keyframe',
184
184
  fieldType: firstResolved.fieldType,
185
+ field: {
186
+ type: firstResolved.identity.type,
187
+ fieldKey: firstResolved.identity.fieldKey,
188
+ },
185
189
  keyframes: keyframes.map((keyframe) => {
186
190
  return {
187
191
  frameOffset: keyframe.frame - firstFrame,
@@ -214,15 +218,27 @@ const isKeyframeValueCompatible = ({ value, fieldType, }) => {
214
218
  return typeof value === 'string';
215
219
  };
216
220
  const getPasteKeyframeTarget = ({ selectedItems, payload, timelinePosition, sequences, overrideIdsToNodePaths, propStatuses, }) => {
217
- var _a, _b;
221
+ var _a, _b, _c;
218
222
  if (selectedItems.length === 0) {
219
223
  return { type: 'none' };
220
224
  }
221
- const selection = selectedItems[0];
225
+ const resolvedSelectedItems = selectedItems.length === 1 &&
226
+ ((_a = selectedItems[0]) === null || _a === void 0 ? void 0 : _a.type) === 'sequence' &&
227
+ payload.field !== null &&
228
+ payload.field.type === 'sequence'
229
+ ? [
230
+ {
231
+ type: 'sequence-prop',
232
+ nodePathInfo: selectedItems[0].nodePathInfo,
233
+ key: payload.field.fieldKey,
234
+ },
235
+ ]
236
+ : selectedItems;
237
+ const selection = resolvedSelectedItems[0];
222
238
  if (!selection || getKeyframeFieldIdentity(selection) === null) {
223
239
  return { type: 'none' };
224
240
  }
225
- const resolvedFields = selectedItems.map((item) => resolveKeyframeField({
241
+ const resolvedFields = resolvedSelectedItems.map((item) => resolveKeyframeField({
226
242
  selection: item,
227
243
  sequences,
228
244
  overrideIdsToNodePaths,
@@ -239,8 +255,8 @@ const getPasteKeyframeTarget = ({ selectedItems, payload, timelinePosition, sequ
239
255
  sourceFrame: timelinePosition - resolved.keyframeDisplayOffset + keyframe.frameOffset,
240
256
  value: keyframe.value,
241
257
  }));
242
- const firstFrame = (_a = keyframes[0]) === null || _a === void 0 ? void 0 : _a.sourceFrame;
243
- const lastFrame = (_b = keyframes.at(-1)) === null || _b === void 0 ? void 0 : _b.sourceFrame;
258
+ const firstFrame = (_b = keyframes[0]) === null || _b === void 0 ? void 0 : _b.sourceFrame;
259
+ const lastFrame = (_c = keyframes.at(-1)) === null || _c === void 0 ? void 0 : _c.sourceFrame;
244
260
  if (firstFrame === undefined || lastFrame === undefined) {
245
261
  return { type: 'incompatible' };
246
262
  }
@@ -155,6 +155,8 @@ const resetSelectedTimelineProps = ({ selections, sequences, overrideIdsToNodePa
155
155
  const resetPromises = [];
156
156
  if (sequencePropTargets.length > 0) {
157
157
  resetPromises.push((0, save_sequence_prop_1.saveSequenceProps)({
158
+ addedKeyframes: null,
159
+ movedKeyframes: null,
158
160
  changes: sequencePropTargets.map((target) => ({
159
161
  fileName: target.fileName,
160
162
  nodePath: target.nodePath,
@@ -1,5 +1,6 @@
1
1
  import { type SaveSequencePropSourceEdit } from '@remotion/studio-shared';
2
2
  import type { CanUpdateSequencePropsResponse, SequencePropsSubscriptionKey, InteractivitySchema } from 'remotion';
3
+ import type { AddSequenceKeyframeChange } from './call-add-keyframe';
3
4
  import { type MoveEffectKeyframeChange, type MoveSequenceKeyframeChange } from './call-move-keyframe';
4
5
  export type SetPropStatuses = (nodePath: SequencePropsSubscriptionKey, values: (prev: CanUpdateSequencePropsResponse) => CanUpdateSequencePropsResponse) => void;
5
6
  export type SaveSequencePropChange = {
@@ -13,14 +14,15 @@ export type SaveSequencePropChange = {
13
14
  };
14
15
  type SaveSequencePropsOptions = {
15
16
  changes: SaveSequencePropChange[];
16
- movedKeyframes?: {
17
+ addedKeyframes: AddSequenceKeyframeChange[] | null;
18
+ movedKeyframes: {
17
19
  sequenceKeyframes: MoveSequenceKeyframeChange[];
18
20
  effectKeyframes: MoveEffectKeyframeChange[];
19
- };
21
+ } | null;
20
22
  setPropStatuses: SetPropStatuses;
21
23
  clientId: string;
22
24
  undoLabel: string;
23
25
  redoLabel: string;
24
26
  };
25
- export declare const saveSequenceProps: ({ changes, movedKeyframes, setPropStatuses, clientId, undoLabel, redoLabel, }: SaveSequencePropsOptions) => Promise<void>;
27
+ export declare const saveSequenceProps: ({ changes, addedKeyframes, movedKeyframes, setPropStatuses, clientId, undoLabel, redoLabel, }: SaveSequencePropsOptions) => Promise<void>;
26
28
  export {};
@@ -11,16 +11,18 @@ const serializeSequencePropValue = (value) => {
11
11
  }
12
12
  return { type: 'json', serialized: JSON.stringify(value) };
13
13
  };
14
- const saveSequenceProps = ({ changes, movedKeyframes, setPropStatuses, clientId, undoLabel, redoLabel, }) => {
15
- var _a, _b;
16
- const sequenceKeyframes = (_a = movedKeyframes === null || movedKeyframes === void 0 ? void 0 : movedKeyframes.sequenceKeyframes) !== null && _a !== void 0 ? _a : [];
17
- const effectKeyframes = (_b = movedKeyframes === null || movedKeyframes === void 0 ? void 0 : movedKeyframes.effectKeyframes) !== null && _b !== void 0 ? _b : [];
14
+ const saveSequenceProps = ({ changes, addedKeyframes, movedKeyframes, setPropStatuses, clientId, undoLabel, redoLabel, }) => {
15
+ const keyframesToAdd = addedKeyframes === null ? [] : addedKeyframes;
16
+ const sequenceKeyframes = movedKeyframes === null ? [] : movedKeyframes.sequenceKeyframes;
17
+ const effectKeyframes = movedKeyframes === null ? [] : movedKeyframes.effectKeyframes;
18
18
  if (changes.length === 0 &&
19
+ keyframesToAdd.length === 0 &&
19
20
  sequenceKeyframes.length === 0 &&
20
21
  effectKeyframes.length === 0) {
21
22
  return Promise.resolve();
22
23
  }
23
24
  if (changes.length === 1 &&
25
+ keyframesToAdd.length === 0 &&
24
26
  sequenceKeyframes.length === 0 &&
25
27
  effectKeyframes.length === 0) {
26
28
  const change = changes[0];
@@ -51,6 +53,8 @@ const saveSequenceProps = ({ changes, movedKeyframes, setPropStatuses, clientId,
51
53
  sourceEdit: (_a = change.sourceEdit) !== null && _a !== void 0 ? _a : null,
52
54
  },
53
55
  ],
56
+ addedKeyframes: null,
57
+ movedKeyframes: null,
54
58
  clientId,
55
59
  undoLabel,
56
60
  redoLabel,
@@ -64,6 +68,15 @@ const saveSequenceProps = ({ changes, movedKeyframes, setPropStatuses, clientId,
64
68
  effectKeyframes,
65
69
  setPropStatuses,
66
70
  });
71
+ for (const keyframe of keyframesToAdd) {
72
+ setPropStatuses(keyframe.nodePath, (prev) => (0, studio_shared_1.optimisticAddSequenceKeyframe)({
73
+ previous: prev,
74
+ fieldKey: keyframe.fieldKey,
75
+ frame: keyframe.sourceFrame,
76
+ value: keyframe.value,
77
+ schema: keyframe.schema,
78
+ }));
79
+ }
67
80
  for (const change of changes) {
68
81
  setPropStatuses(change.nodePath, (prev) => (0, studio_shared_1.optimisticUpdateForPropStatuses)({
69
82
  previous: prev,
@@ -86,25 +99,37 @@ const saveSequenceProps = ({ changes, movedKeyframes, setPropStatuses, clientId,
86
99
  sourceEdit: (_a = change.sourceEdit) !== null && _a !== void 0 ? _a : null,
87
100
  };
88
101
  }),
89
- movedKeyframes: {
90
- sequenceKeyframes: sequenceKeyframes.map((keyframe) => ({
102
+ addedKeyframes: addedKeyframes === null
103
+ ? null
104
+ : addedKeyframes.map((keyframe) => ({
91
105
  fileName: keyframe.fileName,
92
106
  nodePath: keyframe.nodePath,
93
107
  key: keyframe.fieldKey,
94
- fromFrame: keyframe.fromFrame,
95
- toFrame: keyframe.toFrame,
96
- schema: keyframe.schema,
97
- })),
98
- effectKeyframes: effectKeyframes.map((keyframe) => ({
99
- fileName: keyframe.fileName,
100
- sequenceNodePath: keyframe.nodePath,
101
- effectIndex: keyframe.effectIndex,
102
- key: keyframe.fieldKey,
103
- fromFrame: keyframe.fromFrame,
104
- toFrame: keyframe.toFrame,
108
+ frame: keyframe.sourceFrame,
109
+ value: JSON.stringify(keyframe.value),
105
110
  schema: keyframe.schema,
106
111
  })),
107
- },
112
+ movedKeyframes: movedKeyframes === null
113
+ ? null
114
+ : {
115
+ sequenceKeyframes: sequenceKeyframes.map((keyframe) => ({
116
+ fileName: keyframe.fileName,
117
+ nodePath: keyframe.nodePath,
118
+ key: keyframe.fieldKey,
119
+ fromFrame: keyframe.fromFrame,
120
+ toFrame: keyframe.toFrame,
121
+ schema: keyframe.schema,
122
+ })),
123
+ effectKeyframes: effectKeyframes.map((keyframe) => ({
124
+ fileName: keyframe.fileName,
125
+ sequenceNodePath: keyframe.nodePath,
126
+ effectIndex: keyframe.effectIndex,
127
+ key: keyframe.fieldKey,
128
+ fromFrame: keyframe.fromFrame,
129
+ toFrame: keyframe.toFrame,
130
+ schema: keyframe.schema,
131
+ })),
132
+ },
108
133
  clientId,
109
134
  undoLabel,
110
135
  redoLabel,
@@ -1,5 +1,7 @@
1
1
  export declare const PREVENT_CLEAR_SELECTION_ON_POINTER_DOWN_ATTR = "data-remotion-prevent-selection-clear";
2
2
  export declare const shouldClearSelectionOnPointerDown: (event: {
3
3
  readonly button: number;
4
+ readonly ctrlKey: boolean | null;
5
+ readonly metaKey: boolean | null;
4
6
  readonly target?: EventTarget | null | undefined;
5
7
  }) => boolean;
@@ -13,7 +13,7 @@ const isSelectionClearBlocked = (target) => {
13
13
  return (target.closest(`[${exports.PREVENT_CLEAR_SELECTION_ON_POINTER_DOWN_ATTR}]`) !== null);
14
14
  };
15
15
  const shouldClearSelectionOnPointerDown = (event) => {
16
- if (event.button !== 0) {
16
+ if (event.button !== 0 || event.metaKey === true || event.ctrlKey === true) {
17
17
  return false;
18
18
  }
19
19
  return !isSelectionClearBlocked(event.target);
@@ -0,0 +1 @@
1
+ export declare const TimelineAssetDropFrameContext: import("react").Context<number | null>;
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TimelineAssetDropFrameContext = void 0;
4
+ const react_1 = require("react");
5
+ exports.TimelineAssetDropFrameContext = (0, react_1.createContext)(null);
@@ -35,6 +35,13 @@ export declare const getFrameFromX: ({ clientX, durationInFrames, width, extrapo
35
35
  width: number;
36
36
  extrapolate: "clamp" | "extend";
37
37
  }) => number;
38
+ export declare const getFrameFromTimelineDrop: ({ clientX, durationInFrames, scrollLeft, timelineLeft, timelineWidth, }: {
39
+ clientX: number;
40
+ durationInFrames: number;
41
+ scrollLeft: number;
42
+ timelineLeft: number;
43
+ timelineWidth: number;
44
+ }) => number;
38
45
  /**
39
46
  * Horizontal position inside the scrollable timeline content (0 … scrollWidth)
40
47
  * for a viewport `clientX`, so pinch-anchoring matches the pointer (not a
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.prepareToPreserveTimelineCursor = exports.getScrollLeftToKeepCursorInPlace = exports.viewportClientXToScrollContentX = exports.getFrameFromX = exports.getFrameWhileScrollingRight = exports.getFrameIncrementFromWidth = exports.getScrollPositionForCursorOnRightEdge = exports.getScrollPositionForCursorOnLeftEdge = exports.scrollToTimelineXOffset = exports.ensureFrameIsInViewport = exports.isCursorInViewport = exports.getFrameWhileScrollingLeft = exports.canScrollTimelineIntoDirection = void 0;
3
+ exports.prepareToPreserveTimelineCursor = exports.getScrollLeftToKeepCursorInPlace = exports.viewportClientXToScrollContentX = exports.getFrameFromTimelineDrop = exports.getFrameFromX = exports.getFrameWhileScrollingRight = exports.getFrameIncrementFromWidth = exports.getScrollPositionForCursorOnRightEdge = exports.getScrollPositionForCursorOnLeftEdge = exports.scrollToTimelineXOffset = exports.ensureFrameIsInViewport = exports.isCursorInViewport = exports.getFrameWhileScrollingLeft = exports.canScrollTimelineIntoDirection = void 0;
4
4
  const remotion_1 = require("remotion");
5
5
  const timeline_layout_1 = require("../../helpers/timeline-layout");
6
6
  const timeline_refs_1 = require("./timeline-refs");
@@ -203,6 +203,15 @@ const getFrameFromX = ({ clientX, durationInFrames, width, extrapolate, }) => {
203
203
  return frame;
204
204
  };
205
205
  exports.getFrameFromX = getFrameFromX;
206
+ const getFrameFromTimelineDrop = ({ clientX, durationInFrames, scrollLeft, timelineLeft, timelineWidth, }) => {
207
+ return (0, exports.getFrameFromX)({
208
+ clientX: clientX - timelineLeft + scrollLeft,
209
+ durationInFrames,
210
+ width: timelineWidth,
211
+ extrapolate: 'clamp',
212
+ });
213
+ };
214
+ exports.getFrameFromTimelineDrop = getFrameFromTimelineDrop;
206
215
  /**
207
216
  * Horizontal position inside the scrollable timeline content (0 … scrollWidth)
208
217
  * for a viewport `clientX`, so pinch-anchoring matches the pointer (not a
@@ -132,33 +132,36 @@ const updateSelectedTimelineEasings = ({ selections, sequences, overrideIdsToNod
132
132
  if (updates.length === 0) {
133
133
  return null;
134
134
  }
135
- return Promise.all(updates.map((update) => {
136
- const settings = {
137
- type: 'easing',
138
- segmentIndex: update.segmentIndex,
139
- easing,
140
- };
141
- if (update.type === 'sequence') {
142
- return (0, call_update_keyframe_settings_1.callUpdateSequenceKeyframeSettings)({
143
- fileName: update.fileName,
144
- nodePath: update.nodePath,
145
- fieldKey: update.fieldKey,
146
- settings,
147
- schema: update.schema,
148
- setPropStatuses,
149
- clientId,
150
- });
151
- }
152
- return (0, call_update_keyframe_settings_1.callUpdateEffectKeyframeSettings)({
135
+ return (0, call_update_keyframe_settings_1.callBatchUpdateKeyframeSettings)({
136
+ sequenceKeyframes: updates
137
+ .filter((update) => update.type === 'sequence')
138
+ .map((update) => ({
139
+ fileName: update.fileName,
140
+ nodePath: update.nodePath,
141
+ fieldKey: update.fieldKey,
142
+ settings: {
143
+ type: 'easing',
144
+ segmentIndex: update.segmentIndex,
145
+ easing,
146
+ },
147
+ schema: update.schema,
148
+ })),
149
+ effectKeyframes: updates
150
+ .filter((update) => update.type === 'effect')
151
+ .map((update) => ({
153
152
  fileName: update.fileName,
154
153
  nodePath: update.nodePath,
155
154
  effectIndex: update.effectIndex,
156
155
  fieldKey: update.fieldKey,
157
- settings,
156
+ settings: {
157
+ type: 'easing',
158
+ segmentIndex: update.segmentIndex,
159
+ easing,
160
+ },
158
161
  schema: update.schema,
159
- setPropStatuses,
160
- clientId,
161
- });
162
- })).then(() => undefined);
162
+ })),
163
+ setPropStatuses,
164
+ clientId,
165
+ });
163
166
  };
164
167
  exports.updateSelectedTimelineEasings = updateSelectedTimelineEasings;
@@ -76,6 +76,8 @@ const useRenameSequence = ({ clientId, nodePathInfo, sequence, validatedLocation
76
76
  return;
77
77
  }
78
78
  await (0, save_sequence_prop_1.saveSequenceProps)({
79
+ addedKeyframes: null,
80
+ movedKeyframes: null,
79
81
  changes: [
80
82
  {
81
83
  fileName: validatedLocation.source,
@@ -2,6 +2,11 @@ import type { CanUpdateSequencePropStatus, SequencePropsSubscriptionKey, TSequen
2
2
  import type { ComboboxValue } from '../NewComposition/ComboBox';
3
3
  import { type SetPropStatuses } from './save-sequence-prop';
4
4
  export declare const shouldShowFreezeFrameMenuItem: (sequence: TSequence) => boolean;
5
+ export declare const calculateSequenceFreezeFrame: ({ sequence, sequenceFrameOffset, timelinePosition, }: {
6
+ readonly sequence: TSequence;
7
+ readonly sequenceFrameOffset: number;
8
+ readonly timelinePosition: number;
9
+ }) => number;
5
10
  export declare const useSequenceFreezeFrameMenuItem: ({ clientId, nodePath, propStatusesForOverride, sequence, sequenceFrameOffset, setPropStatuses, timelinePosition, validatedSource, }: {
6
11
  readonly clientId: string | null;
7
12
  readonly nodePath: SequencePropsSubscriptionKey | null;
@@ -1,12 +1,21 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.useSequenceFreezeFrameMenuItem = exports.shouldShowFreezeFrameMenuItem = void 0;
3
+ exports.useSequenceFreezeFrameMenuItem = exports.calculateSequenceFreezeFrame = exports.shouldShowFreezeFrameMenuItem = void 0;
4
4
  const react_1 = require("react");
5
5
  const save_sequence_prop_1 = require("./save-sequence-prop");
6
6
  const shouldShowFreezeFrameMenuItem = (sequence) => {
7
7
  return sequence.type !== 'audio';
8
8
  };
9
9
  exports.shouldShowFreezeFrameMenuItem = shouldShowFreezeFrameMenuItem;
10
+ const calculateSequenceFreezeFrame = ({ sequence, sequenceFrameOffset, timelinePosition, }) => {
11
+ const rawFreezeFrame = Math.round(timelinePosition - sequence.from + sequenceFrameOffset);
12
+ const minFrame = sequenceFrameOffset;
13
+ const maxFrame = Number.isFinite(sequence.duration)
14
+ ? Math.max(minFrame, sequence.duration + sequenceFrameOffset - 1)
15
+ : Infinity;
16
+ return Math.min(Math.max(minFrame, rawFreezeFrame), maxFrame);
17
+ };
18
+ exports.calculateSequenceFreezeFrame = calculateSequenceFreezeFrame;
10
19
  const useSequenceFreezeFrameMenuItem = ({ clientId, nodePath, propStatusesForOverride, sequence, sequenceFrameOffset, setPropStatuses, timelinePosition, validatedSource, }) => {
11
20
  const freezeStatus = propStatusesForOverride === null || propStatusesForOverride === void 0 ? void 0 : propStatusesForOverride.freeze;
12
21
  const isFrozen = (freezeStatus === null || freezeStatus === void 0 ? void 0 : freezeStatus.status) === 'static' &&
@@ -26,13 +35,15 @@ const useSequenceFreezeFrameMenuItem = ({ clientId, nodePath, propStatusesForOve
26
35
  clientId === null) {
27
36
  return;
28
37
  }
29
- const rawFreezeFrame = Math.round(timelinePosition - sequence.from + sequenceFrameOffset);
30
- const maxFrame = Number.isFinite(sequence.duration)
31
- ? Math.max(0, sequence.duration - 1)
32
- : rawFreezeFrame;
33
- const freezeFrame = Math.min(Math.max(0, rawFreezeFrame), maxFrame);
38
+ const freezeFrame = (0, exports.calculateSequenceFreezeFrame)({
39
+ sequence,
40
+ sequenceFrameOffset,
41
+ timelinePosition,
42
+ });
34
43
  const remove = isFrozen;
35
44
  (0, save_sequence_prop_1.saveSequenceProps)({
45
+ addedKeyframes: null,
46
+ movedKeyframes: null,
36
47
  changes: [
37
48
  {
38
49
  fileName: validatedSource,
@@ -53,9 +64,7 @@ const useSequenceFreezeFrameMenuItem = ({ clientId, nodePath, propStatusesForOve
53
64
  clientId,
54
65
  isFrozen,
55
66
  nodePath,
56
- sequence.controls,
57
- sequence.duration,
58
- sequence.from,
67
+ sequence,
59
68
  sequenceFrameOffset,
60
69
  setPropStatuses,
61
70
  timelinePosition,
@@ -0,0 +1 @@
1
+ export declare const useTimelineAssetDrop: () => number | null;