@remotion/studio 4.0.472 → 4.0.473

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 (133) hide show
  1. package/dist/api/rename-static-file.d.ts +6 -0
  2. package/dist/api/rename-static-file.js +18 -0
  3. package/dist/components/AssetSelector.js +45 -4
  4. package/dist/components/AssetSelectorItem.js +153 -27
  5. package/dist/components/Canvas.js +60 -11
  6. package/dist/components/ConfirmationDialog-types.d.ts +8 -0
  7. package/dist/components/ConfirmationDialog-types.js +2 -0
  8. package/dist/components/ConfirmationDialog.d.ts +7 -0
  9. package/dist/components/ConfirmationDialog.js +103 -0
  10. package/dist/components/ContextMenu.d.ts +9 -1
  11. package/dist/components/ContextMenu.js +49 -5
  12. package/dist/components/CurrentAsset.d.ts +1 -0
  13. package/dist/components/CurrentAsset.js +13 -2
  14. package/dist/components/EditorContent.js +15 -2
  15. package/dist/components/EditorContexts.js +2 -1
  16. package/dist/components/EditorRuler/Ruler.js +2 -0
  17. package/dist/components/ExplorerPanel.d.ts +0 -4
  18. package/dist/components/ExplorerPanel.js +8 -4
  19. package/dist/components/ExplorerPanelRef.d.ts +4 -0
  20. package/dist/components/ExplorerPanelRef.js +5 -0
  21. package/dist/components/FilePreview.d.ts +1 -1
  22. package/dist/components/InitialCompositionLoader.d.ts +0 -1
  23. package/dist/components/InitialCompositionLoader.js +5 -27
  24. package/dist/components/Menu/MenuItem.js +7 -1
  25. package/dist/components/Menu/SubMenu.js +5 -1
  26. package/dist/components/Menu/portals.js +17 -8
  27. package/dist/components/MenuToolbar.js +5 -1
  28. package/dist/components/ModalContainer.js +6 -1
  29. package/dist/components/Modals.js +6 -2
  30. package/dist/components/NewComposition/ComboBox.js +8 -2
  31. package/dist/components/NewComposition/DeleteStaticFile.d.ts +4 -0
  32. package/dist/components/NewComposition/DeleteStaticFile.js +44 -0
  33. package/dist/components/NewComposition/RenameStaticFile.d.ts +4 -0
  34. package/dist/components/NewComposition/RenameStaticFile.js +118 -0
  35. package/dist/components/OptionsPanel.js +5 -1
  36. package/dist/components/OutlineToggle.d.ts +2 -0
  37. package/dist/components/OutlineToggle.js +20 -0
  38. package/dist/components/Preview.d.ts +0 -2
  39. package/dist/components/Preview.js +23 -33
  40. package/dist/components/PreviewToolbar.js +19 -6
  41. package/dist/components/RenderButton.js +8 -2
  42. package/dist/components/RenderPreview.js +2 -2
  43. package/dist/components/SelectedOutlineOverlay.d.ts +24 -0
  44. package/dist/components/SelectedOutlineOverlay.js +190 -22
  45. package/dist/components/ShowOutlinesProvider.d.ts +4 -0
  46. package/dist/components/ShowOutlinesProvider.js +24 -0
  47. package/dist/components/SizeSelector.js +3 -3
  48. package/dist/components/Splitter/SplitterHandle.js +2 -0
  49. package/dist/components/StaticFilePreview.js +2 -2
  50. package/dist/components/Timeline/KeyframeSettingsModal.d.ts +15 -0
  51. package/dist/components/Timeline/KeyframeSettingsModal.js +150 -0
  52. package/dist/components/Timeline/Timeline.js +3 -13
  53. package/dist/components/Timeline/TimelineClipboardKeybindings.d.ts +25 -2
  54. package/dist/components/Timeline/TimelineClipboardKeybindings.js +234 -20
  55. package/dist/components/Timeline/TimelineDeleteKeybindings.js +12 -2
  56. package/dist/components/Timeline/TimelineEffectItem.js +1 -0
  57. package/dist/components/Timeline/TimelineEffectPropItem.js +52 -2
  58. package/dist/components/Timeline/TimelineKeyframeControls.js +5 -15
  59. package/dist/components/Timeline/TimelineKeyframeDiamond.js +24 -21
  60. package/dist/components/Timeline/TimelineKeyframeDiamondIcon.d.ts +6 -0
  61. package/dist/components/Timeline/TimelineKeyframeDiamondIcon.js +14 -0
  62. package/dist/components/Timeline/TimelineKeyframeDragState.d.ts +17 -0
  63. package/dist/components/Timeline/TimelineKeyframeDragState.js +39 -0
  64. package/dist/components/Timeline/TimelineList.js +2 -2
  65. package/dist/components/Timeline/TimelineMediaInfo.d.ts +0 -13
  66. package/dist/components/Timeline/TimelineMediaInfo.js +8 -73
  67. package/dist/components/Timeline/TimelineScaleField.js +1 -1
  68. package/dist/components/Timeline/TimelineSequenceItem.d.ts +1 -0
  69. package/dist/components/Timeline/TimelineSequenceItem.js +276 -22
  70. package/dist/components/Timeline/TimelineSequencePropItem.js +81 -16
  71. package/dist/components/Timeline/TimelineSequenceRightEdgeDragHandle.js +25 -28
  72. package/dist/components/Timeline/apply-effect-response-to-code-values.d.ts +5 -0
  73. package/dist/components/Timeline/apply-effect-response-to-code-values.js +19 -0
  74. package/dist/components/Timeline/call-add-keyframe.js +2 -0
  75. package/dist/components/Timeline/call-move-keyframe.d.ts +19 -0
  76. package/dist/components/Timeline/call-move-keyframe.js +71 -0
  77. package/dist/components/Timeline/call-update-keyframe-settings.d.ts +22 -0
  78. package/dist/components/Timeline/call-update-keyframe-settings.js +52 -0
  79. package/dist/components/Timeline/delete-selected-timeline-item.d.ts +7 -4
  80. package/dist/components/Timeline/delete-selected-timeline-item.js +33 -21
  81. package/dist/components/Timeline/duplicate-selected-timeline-item.d.ts +4 -2
  82. package/dist/components/Timeline/duplicate-selected-timeline-item.js +39 -34
  83. package/dist/components/Timeline/get-bounded-keyframe-drag-delta.d.ts +8 -0
  84. package/dist/components/Timeline/get-bounded-keyframe-drag-delta.js +12 -0
  85. package/dist/components/Timeline/get-keyframe-navigation.d.ts +2 -2
  86. package/dist/components/Timeline/get-keyframe-navigation.js +14 -6
  87. package/dist/components/Timeline/reset-selected-timeline-props.js +3 -2
  88. package/dist/components/Timeline/save-effect-prop.d.ts +14 -3
  89. package/dist/components/Timeline/save-effect-prop.js +36 -18
  90. package/dist/components/Timeline/save-prop-queue.d.ts +2 -1
  91. package/dist/components/Timeline/save-prop-queue.js +5 -2
  92. package/dist/components/Timeline/save-sequence-prop.d.ts +2 -7
  93. package/dist/components/Timeline/save-sequence-prop.js +33 -30
  94. package/dist/components/Timeline/should-clear-selection-on-pointer-down.d.ts +3 -0
  95. package/dist/components/Timeline/should-clear-selection-on-pointer-down.js +7 -0
  96. package/dist/components/Timeline/timeline-asset-link.d.ts +13 -0
  97. package/dist/components/Timeline/timeline-asset-link.js +37 -0
  98. package/dist/components/Timeline/timeline-translate-utils.js +4 -1
  99. package/dist/components/Timeline/use-timeline-keyframe-drag.d.ts +10 -0
  100. package/dist/components/Timeline/use-timeline-keyframe-drag.js +378 -0
  101. package/dist/components/import-assets.d.ts +16 -0
  102. package/dist/components/import-assets.js +155 -18
  103. package/dist/components/load-canvas-content-from-url.d.ts +1 -0
  104. package/dist/components/load-canvas-content-from-url.js +9 -3
  105. package/dist/components/use-select-asset.d.ts +1 -0
  106. package/dist/components/use-select-asset.js +30 -0
  107. package/dist/error-overlay/error-origin.d.ts +3 -0
  108. package/dist/error-overlay/error-origin.js +42 -0
  109. package/dist/error-overlay/react-overlay/listen-to-runtime-errors.js +6 -2
  110. package/dist/error-overlay/remotion-overlay/ErrorLoader.js +38 -0
  111. package/dist/error-overlay/remotion-overlay/ShortcutHint.js +1 -1
  112. package/dist/error-overlay/remotion-overlay/log-studio-error.d.ts +3 -0
  113. package/dist/error-overlay/remotion-overlay/log-studio-error.js +27 -0
  114. package/dist/esm/{chunk-48grt472.js → chunk-q0jkt0zq.js} +21961 -19299
  115. package/dist/esm/internals.mjs +21961 -19299
  116. package/dist/esm/previewEntry.mjs +20600 -17914
  117. package/dist/esm/renderEntry.mjs +1 -1
  118. package/dist/helpers/get-asset-metadata.js +2 -2
  119. package/dist/helpers/get-preview-file-type.d.ts +2 -0
  120. package/dist/helpers/get-preview-file-type.js +33 -0
  121. package/dist/helpers/install-required-package.d.ts +1 -0
  122. package/dist/helpers/install-required-package.js +39 -0
  123. package/dist/helpers/remote-asset-drag.d.ts +4 -0
  124. package/dist/helpers/remote-asset-drag.js +73 -0
  125. package/dist/helpers/use-asset-drag-events.d.ts +5 -2
  126. package/dist/helpers/use-asset-drag-events.js +13 -2
  127. package/dist/hot-middleware-client/client.js +6 -0
  128. package/dist/state/editor-outlines.d.ts +8 -0
  129. package/dist/state/editor-outlines.js +18 -0
  130. package/dist/state/modals.d.ts +19 -2
  131. package/package.json +10 -10
  132. package/dist/helpers/detect-file-type.d.ts +0 -69
  133. package/dist/helpers/detect-file-type.js +0 -278
@@ -8,13 +8,17 @@ const remotion_1 = require("remotion");
8
8
  const no_react_1 = require("remotion/no-react");
9
9
  const client_id_1 = require("../../helpers/client-id");
10
10
  const format_file_location_1 = require("../../helpers/format-file-location");
11
+ const install_required_package_1 = require("../../helpers/install-required-package");
11
12
  const timeline_layout_1 = require("../../helpers/timeline-layout");
12
13
  const call_api_1 = require("../call-api");
14
+ const ConfirmationDialog_1 = require("../ConfirmationDialog");
13
15
  const ContextMenu_1 = require("../ContextMenu");
14
16
  const ExpandedTracksProvider_1 = require("../ExpandedTracksProvider");
15
17
  const NotificationCenter_1 = require("../Notifications/NotificationCenter");
18
+ const use_select_asset_1 = require("../use-select-asset");
16
19
  const duplicate_selected_timeline_item_1 = require("./duplicate-selected-timeline-item");
17
20
  const save_sequence_prop_1 = require("./save-sequence-prop");
21
+ const timeline_asset_link_1 = require("./timeline-asset-link");
18
22
  const TimelineExpandArrowButton_1 = require("./TimelineExpandArrowButton");
19
23
  const TimelineExpandedSection_1 = require("./TimelineExpandedSection");
20
24
  const TimelineItemStack_1 = require("./TimelineItemStack");
@@ -37,6 +41,65 @@ const effectDropHighlight = {
37
41
  outline: '1px solid rgba(0, 155, 255, 0.75)',
38
42
  outlineOffset: -1,
39
43
  };
44
+ const SEQUENCE_REORDER_MIME_TYPE = 'application/remotion-sequence-reorder';
45
+ let currentSequenceDrag = null;
46
+ const sequenceReorderWrapper = {
47
+ position: 'relative',
48
+ };
49
+ const sequenceReorderLineBase = {
50
+ backgroundColor: '#0b84ff',
51
+ height: 2,
52
+ left: 0,
53
+ pointerEvents: 'none',
54
+ position: 'absolute',
55
+ right: 0,
56
+ zIndex: 1,
57
+ };
58
+ const sequenceReorderRejectionStyle = {
59
+ backgroundColor: 'rgba(0, 0, 0, 0.85)',
60
+ border: '1px solid rgba(255, 255, 255, 0.2)',
61
+ borderRadius: 4,
62
+ color: 'white',
63
+ fontSize: 11,
64
+ lineHeight: 1.2,
65
+ maxWidth: 260,
66
+ padding: '3px 6px',
67
+ pointerEvents: 'none',
68
+ position: 'absolute',
69
+ right: 6,
70
+ top: 2,
71
+ zIndex: 2,
72
+ };
73
+ const hasSequenceReorderDragType = (dataTransfer) => {
74
+ return Array.from(dataTransfer.types).includes(SEQUENCE_REORDER_MIME_TYPE);
75
+ };
76
+ const getSequenceReorderDragData = (dataTransfer) => {
77
+ if (currentSequenceDrag) {
78
+ return currentSequenceDrag;
79
+ }
80
+ const value = dataTransfer.getData(SEQUENCE_REORDER_MIME_TYPE);
81
+ if (!value) {
82
+ return null;
83
+ }
84
+ try {
85
+ const parsed = JSON.parse(value);
86
+ if (typeof parsed.nodePathKey === 'string' &&
87
+ typeof parsed.trackIndex === 'number' &&
88
+ (typeof parsed.parentId === 'string' || parsed.parentId === null) &&
89
+ typeof parsed.fileName === 'string' &&
90
+ parsed.nodePath &&
91
+ Array.isArray(parsed.nodePath.nodePath)) {
92
+ return parsed;
93
+ }
94
+ }
95
+ catch (_a) {
96
+ return null;
97
+ }
98
+ return null;
99
+ };
100
+ const getDestinationIndex = ({ fromIndex, insertionIndex, }) => {
101
+ return insertionIndex > fromIndex ? insertionIndex - 1 : insertionIndex;
102
+ };
40
103
  const hasEffectDragType = (dataTransfer) => {
41
104
  return Array.from(dataTransfer.types).some((type) => type === studio_shared_1.EFFECT_DRAG_MIME_TYPE ||
42
105
  type === 'application/json' ||
@@ -59,9 +122,9 @@ const getEffectDragData = (dataTransfer) => {
59
122
  }
60
123
  return null;
61
124
  };
62
- const TimelineSequenceItem = ({ nestedDepth, sequence, nodePathInfo, keyframeDisplayOffset }) => {
125
+ const TimelineSequenceItem = ({ nestedDepth, sequence, nodePathInfo, keyframeDisplayOffset, trackIndex, }) => {
63
126
  var _a, _b;
64
- var _c;
127
+ var _c, _d;
65
128
  const nodePath = (_c = nodePathInfo === null || nodePathInfo === void 0 ? void 0 : nodePathInfo.sequenceSubscriptionKey) !== null && _c !== void 0 ? _c : null;
66
129
  const { previewServerState } = (0, react_1.useContext)(client_id_1.StudioServerConnectionCtx);
67
130
  const previewConnected = previewServerState.type === 'connected';
@@ -69,10 +132,12 @@ const TimelineSequenceItem = ({ nestedDepth, sequence, nodePathInfo, keyframeDis
69
132
  const { toggleTrack } = (0, react_1.useContext)(ExpandedTracksProvider_1.ExpandedTracksSetterContext);
70
133
  const { codeValues } = (0, react_1.useContext)(remotion_1.Internals.VisualModeCodeValuesContext);
71
134
  const { setCodeValues } = (0, react_1.useContext)(remotion_1.Internals.VisualModeSettersContext);
72
- const { setCanvasContent } = (0, react_1.useContext)(remotion_1.Internals.CompositionSetters);
135
+ const selectAsset = (0, use_select_asset_1.useSelectAsset)();
73
136
  const { onSelect, selectable, selected } = (0, TimelineSelection_1.useTimelineRowSelection)(nodePathInfo);
74
137
  const containsSelection = (0, TimelineSelection_1.useTimelineRowContainsSelection)(nodePathInfo);
75
138
  const [effectDropHovered, setEffectDropHovered] = (0, react_1.useState)(false);
139
+ const [sequenceDropIndicator, setSequenceDropIndicator] = (0, react_1.useState)(null);
140
+ const [sequenceDropRejection, setSequenceDropRejection] = (0, react_1.useState)(null);
76
141
  const { canOpenInEditor, openInEditor, originalLocation } = (0, use_open_sequence_in_editor_1.useOpenSequenceInEditor)(sequence);
77
142
  const fileLocation = (0, react_1.useMemo)(() => (0, format_file_location_1.formatFileLocation)({
78
143
  location: originalLocation,
@@ -92,24 +157,35 @@ const TimelineSequenceItem = ({ nestedDepth, sequence, nodePathInfo, keyframeDis
92
157
  };
93
158
  }, [originalLocation]);
94
159
  const canDeleteFromSource = Boolean(nodePath && (validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.source));
160
+ const nodePathKey = (0, react_1.useMemo)(() => nodePath ? remotion_1.Internals.makeSequencePropsSubscriptionKey(nodePath) : null, [nodePath]);
161
+ const parentId = (_d = sequence.parent) !== null && _d !== void 0 ? _d : null;
162
+ const canReorderSequence = TimelineSelection_1.SELECTION_ENABLED &&
163
+ previewConnected &&
164
+ Boolean(nodePath && nodePathKey && (validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.source)) &&
165
+ (nodePathInfo === null || nodePathInfo === void 0 ? void 0 : nodePathInfo.numberOfSequencesWithThisNodePath) === 1;
166
+ const canHandleSequenceDrag = TimelineSelection_1.SELECTION_ENABLED && previewConnected;
167
+ const confirm = (0, ConfirmationDialog_1.useConfirmationDialog)();
95
168
  const deleteDisabled = (0, react_1.useMemo)(() => !previewConnected || !sequence.controls || !canDeleteFromSource, [previewConnected, sequence.controls, canDeleteFromSource]);
96
169
  const duplicateDisabled = deleteDisabled;
97
170
  const onDuplicateSequenceFromSource = (0, react_1.useCallback)(() => {
98
171
  if (!(validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.source) || !nodePathInfo) {
99
172
  return;
100
173
  }
101
- (0, duplicate_selected_timeline_item_1.duplicateSequencesFromSource)([nodePathInfo]).catch(() => undefined);
102
- }, [nodePathInfo, validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.source]);
174
+ (0, duplicate_selected_timeline_item_1.duplicateSequencesFromSource)([nodePathInfo], confirm).catch(() => undefined);
175
+ }, [confirm, nodePathInfo, validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.source]);
103
176
  const onDeleteSequenceFromSource = (0, react_1.useCallback)(async () => {
104
177
  if (!(validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.source) || !nodePath) {
105
178
  return;
106
179
  }
107
180
  if (nodePathInfo && nodePathInfo.numberOfSequencesWithThisNodePath > 1) {
108
- const message = 'This sequence is programmatically duplicated ' +
109
- nodePathInfo.numberOfSequencesWithThisNodePath +
110
- ' times in the code. Deleting removes all instances. Continue?';
111
- // eslint-disable-next-line no-alert -- native confirm before applying duplicate codemod in .map callbacks
112
- if (!window.confirm(message)) {
181
+ const shouldDelete = await confirm({
182
+ title: 'Delete sequence?',
183
+ message: 'This sequence is programmatically duplicated ' +
184
+ nodePathInfo.numberOfSequencesWithThisNodePath +
185
+ ' times in the code. Deleting removes all instances. Continue?',
186
+ confirmLabel: 'Delete',
187
+ });
188
+ if (!shouldDelete) {
113
189
  return;
114
190
  }
115
191
  }
@@ -132,13 +208,173 @@ const TimelineSequenceItem = ({ nestedDepth, sequence, nodePathInfo, keyframeDis
132
208
  catch (err) {
133
209
  (0, NotificationCenter_1.showNotification)(err.message, 4000);
134
210
  }
135
- }, [nodePath, validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.source, nodePathInfo]);
211
+ }, [confirm, nodePath, validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.source, nodePathInfo]);
212
+ const getSequenceDropTarget = (0, react_1.useCallback)((e) => {
213
+ const dragData = getSequenceReorderDragData(e.dataTransfer);
214
+ if (!dragData) {
215
+ return null;
216
+ }
217
+ if (!nodePath || !nodePathKey || !(validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.source)) {
218
+ return {
219
+ type: 'invalid',
220
+ reason: 'This sequence cannot be reordered from source.',
221
+ };
222
+ }
223
+ if (dragData.nodePathKey === nodePathKey) {
224
+ return {
225
+ type: 'invalid',
226
+ reason: 'Drop onto another sequence to reorder.',
227
+ };
228
+ }
229
+ if ((nodePathInfo === null || nodePathInfo === void 0 ? void 0 : nodePathInfo.numberOfSequencesWithThisNodePath) !== 1) {
230
+ return {
231
+ type: 'invalid',
232
+ reason: 'Programmatically duplicated sequences cannot be reordered.',
233
+ };
234
+ }
235
+ if (dragData.parentId !== parentId ||
236
+ dragData.fileName !== validatedLocation.source) {
237
+ return {
238
+ type: 'invalid',
239
+ reason: 'Sequences can only be reordered with direct JSX siblings.',
240
+ };
241
+ }
242
+ const rect = e.currentTarget.getBoundingClientRect();
243
+ const before = e.clientY < rect.top + rect.height / 2;
244
+ const insertionIndex = before ? trackIndex : trackIndex + 1;
245
+ const toIndex = getDestinationIndex({
246
+ fromIndex: dragData.trackIndex,
247
+ insertionIndex,
248
+ });
249
+ if (toIndex === dragData.trackIndex) {
250
+ return {
251
+ type: 'invalid',
252
+ reason: 'This sequence is already in that position.',
253
+ };
254
+ }
255
+ return {
256
+ type: 'valid',
257
+ dragData,
258
+ position: before ? 'before' : 'after',
259
+ };
260
+ }, [
261
+ nodePath,
262
+ nodePathInfo === null || nodePathInfo === void 0 ? void 0 : nodePathInfo.numberOfSequencesWithThisNodePath,
263
+ nodePathKey,
264
+ parentId,
265
+ trackIndex,
266
+ validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.source,
267
+ ]);
268
+ const onSequenceDragStart = (0, react_1.useCallback)((e) => {
269
+ if (!canReorderSequence ||
270
+ !nodePath ||
271
+ !nodePathKey ||
272
+ !(validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.source)) {
273
+ e.preventDefault();
274
+ return;
275
+ }
276
+ const dragData = {
277
+ nodePath,
278
+ nodePathKey,
279
+ trackIndex,
280
+ parentId,
281
+ fileName: validatedLocation.source,
282
+ };
283
+ currentSequenceDrag = dragData;
284
+ e.dataTransfer.effectAllowed = 'move';
285
+ e.dataTransfer.setData(SEQUENCE_REORDER_MIME_TYPE, JSON.stringify(dragData));
286
+ e.stopPropagation();
287
+ }, [
288
+ canReorderSequence,
289
+ nodePath,
290
+ nodePathKey,
291
+ parentId,
292
+ trackIndex,
293
+ validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.source,
294
+ ]);
295
+ const onSequenceDragEnd = (0, react_1.useCallback)(() => {
296
+ currentSequenceDrag = null;
297
+ setSequenceDropIndicator(null);
298
+ setSequenceDropRejection(null);
299
+ }, []);
300
+ const onSequenceDragOver = (0, react_1.useCallback)((e) => {
301
+ if (!hasSequenceReorderDragType(e.dataTransfer)) {
302
+ return;
303
+ }
304
+ const dropTarget = getSequenceDropTarget(e);
305
+ if (!dropTarget) {
306
+ setSequenceDropIndicator(null);
307
+ setSequenceDropRejection(null);
308
+ return;
309
+ }
310
+ if (dropTarget.type === 'invalid') {
311
+ setSequenceDropIndicator(null);
312
+ setSequenceDropRejection(dropTarget.reason);
313
+ e.dataTransfer.dropEffect = 'none';
314
+ return;
315
+ }
316
+ e.preventDefault();
317
+ e.stopPropagation();
318
+ e.dataTransfer.dropEffect = 'move';
319
+ setSequenceDropIndicator(dropTarget.position);
320
+ setSequenceDropRejection(null);
321
+ }, [getSequenceDropTarget]);
322
+ const onSequenceDragLeave = (0, react_1.useCallback)((e) => {
323
+ if (e.currentTarget.contains(e.relatedTarget)) {
324
+ return;
325
+ }
326
+ setSequenceDropIndicator(null);
327
+ setSequenceDropRejection(null);
328
+ }, []);
329
+ const onSequenceDrop = (0, react_1.useCallback)(async (e) => {
330
+ if (!canReorderSequence ||
331
+ previewServerState.type !== 'connected' ||
332
+ !nodePath ||
333
+ !(validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.source)) {
334
+ return;
335
+ }
336
+ const dropTarget = getSequenceDropTarget(e);
337
+ if (!dropTarget || dropTarget.type === 'invalid') {
338
+ setSequenceDropIndicator(null);
339
+ setSequenceDropRejection((dropTarget === null || dropTarget === void 0 ? void 0 : dropTarget.type) === 'invalid' ? dropTarget.reason : null);
340
+ return;
341
+ }
342
+ e.preventDefault();
343
+ e.stopPropagation();
344
+ setSequenceDropIndicator(null);
345
+ setSequenceDropRejection(null);
346
+ currentSequenceDrag = null;
347
+ try {
348
+ const result = await (0, call_api_1.callApi)('/api/reorder-sequence', {
349
+ fileName: validatedLocation.source,
350
+ sourceNodePath: dropTarget.dragData.nodePath,
351
+ targetNodePath: nodePath,
352
+ position: dropTarget.position,
353
+ clientId: previewServerState.clientId,
354
+ });
355
+ if (result.success) {
356
+ (0, NotificationCenter_1.showNotification)('Reordered sequence', 2000);
357
+ }
358
+ else {
359
+ (0, NotificationCenter_1.showNotification)(result.reason, 4000);
360
+ }
361
+ }
362
+ catch (err) {
363
+ (0, NotificationCenter_1.showNotification)(err.message, 4000);
364
+ }
365
+ }, [
366
+ canReorderSequence,
367
+ getSequenceDropTarget,
368
+ nodePath,
369
+ previewServerState,
370
+ validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.source,
371
+ ]);
136
372
  const mediaSrc = sequence.type === 'audio' ||
137
373
  sequence.type === 'video' ||
138
374
  sequence.type === 'image'
139
375
  ? sequence.src
140
376
  : null;
141
- const assetLinkInfo = (0, react_1.useMemo)(() => (mediaSrc ? (0, TimelineMediaInfo_1.getTimelineAssetLinkInfo)(mediaSrc) : null), [mediaSrc]);
377
+ const assetLinkInfo = (0, react_1.useMemo)(() => (mediaSrc ? (0, timeline_asset_link_1.getTimelineAssetLinkInfo)(mediaSrc) : null), [mediaSrc]);
142
378
  const contextMenuValues = (0, react_1.useMemo)(() => {
143
379
  if (!previewConnected) {
144
380
  return [];
@@ -211,7 +447,7 @@ const TimelineSequenceItem = ({ nestedDepth, sequence, nodePathInfo, keyframeDis
211
447
  leftItem: null,
212
448
  disabled: false,
213
449
  onClick: () => {
214
- (0, TimelineMediaInfo_1.openTimelineAssetLink)(assetLinkInfo, setCanvasContent);
450
+ (0, timeline_asset_link_1.openTimelineAssetLink)(assetLinkInfo, selectAsset);
215
451
  },
216
452
  quickSwitcherLabel: null,
217
453
  subMenu: null,
@@ -269,8 +505,8 @@ const TimelineSequenceItem = ({ nestedDepth, sequence, nodePathInfo, keyframeDis
269
505
  canOpenInEditor,
270
506
  openInEditor,
271
507
  previewConnected,
508
+ selectAsset,
272
509
  sequence,
273
- setCanvasContent,
274
510
  ]);
275
511
  const isExpanded = previewConnected && nodePathInfo !== null && getIsExpanded(nodePathInfo);
276
512
  const onToggleExpand = (0, react_1.useCallback)(() => {
@@ -321,15 +557,21 @@ const TimelineSequenceItem = ({ nestedDepth, sequence, nodePathInfo, keyframeDis
321
557
  const defaultValue = fieldSchema && fieldSchema.type === 'boolean'
322
558
  ? JSON.stringify(fieldSchema.default)
323
559
  : null;
324
- (0, save_sequence_prop_1.saveSequenceProp)({
325
- fileName: validatedLocation.source,
326
- nodePath,
327
- fieldKey: 'hidden',
328
- value: newValue,
329
- defaultValue,
330
- schema,
560
+ (0, save_sequence_prop_1.saveSequenceProps)({
561
+ changes: [
562
+ {
563
+ fileName: validatedLocation.source,
564
+ nodePath,
565
+ fieldKey: 'hidden',
566
+ value: newValue,
567
+ defaultValue,
568
+ schema,
569
+ },
570
+ ],
331
571
  setCodeValues,
332
572
  clientId: previewServerState.clientId,
573
+ undoLabel: newValue ? 'Hide sequence' : 'Show sequence',
574
+ redoLabel: newValue ? 'Hide sequence again' : 'Show sequence again',
333
575
  });
334
576
  }, [
335
577
  codeHiddenStatus,
@@ -371,6 +613,15 @@ const TimelineSequenceItem = ({ nestedDepth, sequence, nodePathInfo, keyframeDis
371
613
  nodePath !== null &&
372
614
  validatedLocation !== null &&
373
615
  ((_b = sequence.controls) === null || _b === void 0 ? void 0 : _b.supportsEffects) === true;
616
+ const sequenceReorderLineStyle = (0, react_1.useMemo)(() => {
617
+ if (!sequenceDropIndicator) {
618
+ return null;
619
+ }
620
+ return {
621
+ ...sequenceReorderLineBase,
622
+ ...(sequenceDropIndicator === 'before' ? { top: -1 } : { bottom: -1 }),
623
+ };
624
+ }, [sequenceDropIndicator]);
374
625
  const onEffectDragOver = (0, react_1.useCallback)((e) => {
375
626
  if (!canDropEffect || !hasEffectDragType(e.dataTransfer)) {
376
627
  return;
@@ -401,6 +652,8 @@ const TimelineSequenceItem = ({ nestedDepth, sequence, nodePathInfo, keyframeDis
401
652
  return;
402
653
  }
403
654
  try {
655
+ const requiredPackage = (0, studio_shared_1.getRequiredPackageForEffectImportPath)(dragData.effect.importPath);
656
+ await (0, install_required_package_1.installRequiredPackages)(requiredPackage ? [requiredPackage] : []);
404
657
  const result = await (0, call_api_1.callApi)('/api/add-effect', {
405
658
  fileName: validatedLocation.source,
406
659
  sequenceNodePath: nodePath,
@@ -425,7 +678,8 @@ const TimelineSequenceItem = ({ nestedDepth, sequence, nodePathInfo, keyframeDis
425
678
  : undefined, children: jsx_runtime_1.jsxs("div", { style: labelContainerStyle, children: [
426
679
  jsx_runtime_1.jsx(TimelineSequenceName_1.TimelineSequenceName, { sequence: sequence, selected: selected, containsSelection: containsSelection }), mediaSrc ? jsx_runtime_1.jsx(TimelineMediaInfo_1.TimelineMediaInfo, { src: mediaSrc }) : null, jsx_runtime_1.jsx(TimelineItemStack_1.TimelineItemStack, { originalLocation: originalLocation })
427
680
  ] }) }));
428
- return (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [previewConnected ? (jsx_runtime_1.jsx(ContextMenu_1.ContextMenu, { values: contextMenuValues, onOpen: selectable ? onSelect : null, children: trackRow })) : (trackRow), previewConnected &&
681
+ const draggableTrackRow = canHandleSequenceDrag ? (jsx_runtime_1.jsxs("div", { draggable: canReorderSequence, onDragStart: onSequenceDragStart, onDragEnd: onSequenceDragEnd, onDragOver: onSequenceDragOver, onDragLeave: onSequenceDragLeave, onDrop: onSequenceDrop, style: sequenceReorderWrapper, children: [sequenceReorderLineStyle ? (jsx_runtime_1.jsx("div", { style: sequenceReorderLineStyle })) : null, sequenceDropRejection ? (jsx_runtime_1.jsx("div", { style: sequenceReorderRejectionStyle, children: sequenceDropRejection })) : null, trackRow] })) : (trackRow);
682
+ return (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [previewConnected ? (jsx_runtime_1.jsx(ContextMenu_1.ContextMenu, { values: contextMenuValues, onOpen: selectable ? onSelect : null, children: draggableTrackRow })) : (draggableTrackRow), previewConnected &&
429
683
  isExpanded &&
430
684
  hasExpandableContent &&
431
685
  nodePathInfo &&
@@ -6,6 +6,7 @@ const studio_shared_1 = require("@remotion/studio-shared");
6
6
  const react_1 = require("react");
7
7
  const remotion_1 = require("remotion");
8
8
  const client_id_1 = require("../../helpers/client-id");
9
+ const modals_1 = require("../../state/modals");
9
10
  const ContextMenu_1 = require("../ContextMenu");
10
11
  const call_add_keyframe_1 = require("./call-add-keyframe");
11
12
  const save_sequence_prop_1 = require("./save-sequence-prop");
@@ -57,6 +58,7 @@ const Value = ({ field, nodePath, validatedLocation, schema, codeValue }) => {
57
58
  ? previewServerState.clientId
58
59
  : null;
59
60
  const onSave = (0, react_1.useCallback)((value) => {
61
+ var _a;
60
62
  if (!clientId) {
61
63
  return Promise.reject(new Error('Not connected to studio server'));
62
64
  }
@@ -64,6 +66,7 @@ const Value = ({ field, nodePath, validatedLocation, schema, codeValue }) => {
64
66
  ? JSON.stringify(field.fieldSchema.default)
65
67
  : null;
66
68
  const stringifiedValue = JSON.stringify(value);
69
+ const fieldLabel = (_a = field.description) !== null && _a !== void 0 ? _a : field.key;
67
70
  if (value === codeValue.codeValue) {
68
71
  return Promise.resolve();
69
72
  }
@@ -71,19 +74,26 @@ const Value = ({ field, nodePath, validatedLocation, schema, codeValue }) => {
71
74
  codeValue.codeValue === undefined) {
72
75
  return Promise.resolve();
73
76
  }
74
- return (0, save_sequence_prop_1.saveSequenceProp)({
75
- fileName: validatedLocation.source,
76
- nodePath,
77
- fieldKey: field.key,
78
- value,
79
- defaultValue,
80
- schema,
77
+ return (0, save_sequence_prop_1.saveSequenceProps)({
78
+ changes: [
79
+ {
80
+ fileName: validatedLocation.source,
81
+ nodePath,
82
+ fieldKey: field.key,
83
+ value,
84
+ defaultValue,
85
+ schema,
86
+ },
87
+ ],
81
88
  setCodeValues,
82
89
  clientId,
90
+ undoLabel: `Update ${fieldLabel}`,
91
+ redoLabel: `Update ${fieldLabel} again`,
83
92
  });
84
93
  }, [
85
94
  codeValue,
86
95
  clientId,
96
+ field.description,
87
97
  field.fieldSchema.default,
88
98
  field.key,
89
99
  nodePath,
@@ -111,6 +121,7 @@ const TimelineSequencePropItem = ({ field, validatedLocation, rowDepth, nodePath
111
121
  const { getDragOverrides } = (0, react_1.useContext)(remotion_1.Internals.VisualModeDragOverridesContext);
112
122
  const { setCodeValues, setDragOverrides, clearDragOverrides } = (0, react_1.useContext)(remotion_1.Internals.VisualModeSettersContext);
113
123
  const { previewServerState } = (0, react_1.useContext)(client_id_1.StudioServerConnectionCtx);
124
+ const { setSelectedModal } = (0, react_1.useContext)(modals_1.ModalsContext);
114
125
  const selection = (0, TimelineSelection_1.useTimelineRowSelection)(nodePathInfo);
115
126
  const clientId = previewServerState.type === 'connected'
116
127
  ? previewServerState.clientId
@@ -152,6 +163,7 @@ const TimelineSequencePropItem = ({ field, validatedLocation, rowDepth, nodePath
152
163
  codeValue.status !== 'computed';
153
164
  const canShowReset = canPerformReset && field.fieldSchema.default !== undefined;
154
165
  const onReset = (0, react_1.useCallback)(() => {
166
+ var _a;
155
167
  if (!canShowReset ||
156
168
  !canResetToDefault ||
157
169
  previewServerState.type !== 'connected' ||
@@ -161,19 +173,27 @@ const TimelineSequencePropItem = ({ field, validatedLocation, rowDepth, nodePath
161
173
  const defaultValue = field.fieldSchema.default !== undefined
162
174
  ? JSON.stringify(field.fieldSchema.default)
163
175
  : null;
164
- (0, save_sequence_prop_1.saveSequenceProp)({
165
- fileName: validatedLocation.source,
166
- nodePath,
167
- fieldKey: field.key,
168
- value: field.fieldSchema.default,
169
- defaultValue,
170
- schema,
176
+ const fieldLabel = (_a = field.description) !== null && _a !== void 0 ? _a : field.key;
177
+ (0, save_sequence_prop_1.saveSequenceProps)({
178
+ changes: [
179
+ {
180
+ fileName: validatedLocation.source,
181
+ nodePath,
182
+ fieldKey: field.key,
183
+ value: field.fieldSchema.default,
184
+ defaultValue,
185
+ schema,
186
+ },
187
+ ],
171
188
  setCodeValues,
172
189
  clientId: previewServerState.clientId,
190
+ undoLabel: `Reset ${fieldLabel}`,
191
+ redoLabel: `Reapply ${fieldLabel}`,
173
192
  });
174
193
  }, [
175
194
  canResetToDefault,
176
195
  canShowReset,
196
+ field.description,
177
197
  field.fieldSchema.default,
178
198
  field.key,
179
199
  nodePath,
@@ -218,8 +238,32 @@ const TimelineSequencePropItem = ({ field, validatedLocation, rowDepth, nodePath
218
238
  const onKeyframedDragEnd = (0, react_1.useCallback)(() => {
219
239
  clearDragOverrides(nodePath);
220
240
  }, [clearDragOverrides, nodePath]);
241
+ const onOpenKeyframeSettings = (0, react_1.useCallback)(() => {
242
+ var _a;
243
+ if (codeValue === null || !isKeyframedStatus(codeValue)) {
244
+ return;
245
+ }
246
+ setSelectedModal({
247
+ type: 'keyframe-settings',
248
+ fileName: validatedLocation.source,
249
+ nodePath,
250
+ fieldKey: field.key,
251
+ fieldLabel: (_a = field.description) !== null && _a !== void 0 ? _a : field.key,
252
+ status: codeValue,
253
+ schema,
254
+ effectIndex: null,
255
+ });
256
+ }, [
257
+ codeValue,
258
+ field.description,
259
+ field.key,
260
+ nodePath,
261
+ schema,
262
+ setSelectedModal,
263
+ validatedLocation.source,
264
+ ]);
221
265
  const contextMenuValues = (0, react_1.useMemo)(() => {
222
- return [
266
+ const values = [
223
267
  {
224
268
  type: 'item',
225
269
  id: 'reset-sequence-field',
@@ -233,7 +277,28 @@ const TimelineSequencePropItem = ({ field, validatedLocation, rowDepth, nodePath
233
277
  value: 'reset-sequence-field',
234
278
  },
235
279
  ];
236
- }, [canShowReset, onReset]);
280
+ if (codeValue !== null && isKeyframedStatus(codeValue)) {
281
+ values.push({
282
+ type: 'item',
283
+ id: 'keyframe-settings-sequence-field',
284
+ keyHint: null,
285
+ label: 'Keyframe settings...',
286
+ leftItem: null,
287
+ disabled: previewServerState.type !== 'connected',
288
+ onClick: onOpenKeyframeSettings,
289
+ quickSwitcherLabel: null,
290
+ subMenu: null,
291
+ value: 'keyframe-settings-sequence-field',
292
+ });
293
+ }
294
+ return values;
295
+ }, [
296
+ canShowReset,
297
+ codeValue,
298
+ onOpenKeyframeSettings,
299
+ onReset,
300
+ previewServerState,
301
+ ]);
237
302
  if (codeValue === null) {
238
303
  return null;
239
304
  }
@@ -116,7 +116,12 @@ const getTimelineSequenceDurationDragTargets = ({ draggedNodePathInfo, selectedI
116
116
  const targets = new Map();
117
117
  for (const nodePathInfo of targetNodePathInfos) {
118
118
  const track = findSequenceTrack({ tracks, nodePathInfo });
119
- if (!track || !isDurationDraggableSequence(track.sequence)) {
119
+ const originalSequence = track
120
+ ? sequences.find((sequence) => sequence.id === track.sequence.id)
121
+ : null;
122
+ if (!track ||
123
+ !originalSequence ||
124
+ !isDurationDraggableSequence(originalSequence)) {
120
125
  return null;
121
126
  }
122
127
  const nodePath = nodePathInfo.sequenceSubscriptionKey;
@@ -127,7 +132,7 @@ const getTimelineSequenceDurationDragTargets = ({ draggedNodePathInfo, selectedI
127
132
  if (!targets.has(key)) {
128
133
  targets.set(key, {
129
134
  fileName: nodePath.absolutePath,
130
- initialDuration: track.sequence.duration,
135
+ initialDuration: originalSequence.duration,
131
136
  nodePath,
132
137
  });
133
138
  }
@@ -239,19 +244,15 @@ const useTimelineSequenceFromDrag = ({ nodePathInfo, windowWidth, timelineDurati
239
244
  });
240
245
  return;
241
246
  }
242
- const savePromise = changes.length === 1
243
- ? (0, save_sequence_prop_1.saveSequenceProp)({
244
- ...changes[0],
245
- setCodeValues: latestSetCodeValues,
246
- clientId: latestServerState.clientId,
247
- })
248
- : (0, save_sequence_prop_1.saveSequenceProps)({
249
- changes,
250
- setCodeValues: latestSetCodeValues,
251
- clientId: latestServerState.clientId,
252
- undoLabel: 'Move selected sequences',
253
- redoLabel: 'Move selected sequences back',
254
- });
247
+ const savePromise = (0, save_sequence_prop_1.saveSequenceProps)({
248
+ changes,
249
+ setCodeValues: latestSetCodeValues,
250
+ clientId: latestServerState.clientId,
251
+ undoLabel: changes.length > 1 ? 'Move selected sequences' : 'Move sequence',
252
+ redoLabel: changes.length > 1
253
+ ? 'Move selected sequences back'
254
+ : 'Move sequence back',
255
+ });
255
256
  savePromise
256
257
  .catch((err) => {
257
258
  remotion_1.Internals.Log.error({ logLevel: 'error', tag: null }, 'Could not save from', err);
@@ -408,19 +409,15 @@ const TimelineSequenceRightEdgeDragHandle = ({ nodePathInfo, windowWidth, timeli
408
409
  });
409
410
  return;
410
411
  }
411
- const savePromise = changes.length === 1
412
- ? (0, save_sequence_prop_1.saveSequenceProp)({
413
- ...changes[0],
414
- setCodeValues: latestSetCodeValues,
415
- clientId: latestServerState.clientId,
416
- })
417
- : (0, save_sequence_prop_1.saveSequenceProps)({
418
- changes,
419
- setCodeValues: latestSetCodeValues,
420
- clientId: latestServerState.clientId,
421
- undoLabel: 'Resize selected sequences',
422
- redoLabel: 'Resize selected sequences back',
423
- });
412
+ const savePromise = (0, save_sequence_prop_1.saveSequenceProps)({
413
+ changes,
414
+ setCodeValues: latestSetCodeValues,
415
+ clientId: latestServerState.clientId,
416
+ undoLabel: changes.length > 1 ? 'Resize selected sequences' : 'Resize sequence',
417
+ redoLabel: changes.length > 1
418
+ ? 'Resize selected sequences back'
419
+ : 'Resize sequence back',
420
+ });
424
421
  savePromise
425
422
  .catch((err) => {
426
423
  remotion_1.Internals.Log.error({ logLevel: 'error', tag: null }, 'Could not save durationInFrames', err);
@@ -0,0 +1,5 @@
1
+ import type { CanUpdateEffectPropsResponse, CanUpdateSequencePropsResponse } from 'remotion';
2
+ export declare const applyEffectResponseToCodeValues: ({ previous, response, }: {
3
+ previous: CanUpdateSequencePropsResponse;
4
+ response: CanUpdateEffectPropsResponse;
5
+ }) => CanUpdateSequencePropsResponse;