@remotion/studio 4.0.489 → 4.0.491

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/Canvas.js +20 -2
  2. package/dist/components/CurrentComposition.js +4 -1
  3. package/dist/components/EditorContent.js +1 -1
  4. package/dist/components/GlobalKeybindings.d.ts +1 -3
  5. package/dist/components/GlobalKeybindings.js +2 -9
  6. package/dist/components/InspectorLocationCopy.d.ts +7 -0
  7. package/dist/components/InspectorLocationCopy.js +65 -0
  8. package/dist/components/InspectorPanel/AlignmentControls.d.ts +5 -0
  9. package/dist/components/InspectorPanel/AlignmentControls.js +205 -0
  10. package/dist/components/InspectorPanel/EasingInspector.js +8 -2
  11. package/dist/components/InspectorPanel/KeyframeSettings.d.ts +5 -0
  12. package/dist/components/InspectorPanel/KeyframeSettings.js +142 -0
  13. package/dist/components/InspectorPanel/SequenceInspectorHeader.js +4 -3
  14. package/dist/components/InspectorPanel/SequenceSelectionInspector.js +2 -1
  15. package/dist/components/InspectorPanel/alignment-controls.d.ts +12 -0
  16. package/dist/components/InspectorPanel/alignment-controls.js +42 -0
  17. package/dist/components/InspectorSequenceSection.d.ts +1 -0
  18. package/dist/components/InspectorSequenceSection.js +2 -2
  19. package/dist/components/KeyboardShortcutsExplainer.js +4 -0
  20. package/dist/components/MobilePanel.js +9 -3
  21. package/dist/components/Modals.js +1 -2
  22. package/dist/components/NewComposition/CancelButton.d.ts +1 -0
  23. package/dist/components/NewComposition/CancelButton.js +6 -2
  24. package/dist/components/OptionsPanel.js +4 -8
  25. package/dist/components/OutlineToggle.d.ts +3 -1
  26. package/dist/components/OutlineToggle.js +2 -2
  27. package/dist/components/Preview.js +1 -1
  28. package/dist/components/PreviewToolbar.js +1 -1
  29. package/dist/components/RenderButton.js +9 -33
  30. package/dist/components/RenderModal/WebRenderModal.js +3 -8
  31. package/dist/components/RenderModal/WebRenderModalAdvanced.d.ts +0 -2
  32. package/dist/components/RenderModal/WebRenderModalAdvanced.js +2 -9
  33. package/dist/components/RenderQueue/ClientRenderQueueProcessor.js +0 -2
  34. package/dist/components/RenderQueue/client-side-render-types.d.ts +0 -1
  35. package/dist/components/RenderQueue/index.js +0 -9
  36. package/dist/components/SelectedOutlineElement.js +40 -38
  37. package/dist/components/SelectedOutlineOverlay.d.ts +7 -2
  38. package/dist/components/SelectedOutlineOverlay.js +249 -22
  39. package/dist/components/SnappingToggle.d.ts +3 -1
  40. package/dist/components/SnappingToggle.js +2 -2
  41. package/dist/components/Timeline/TimelineClipboardKeybindings.d.ts +20 -1
  42. package/dist/components/Timeline/TimelineClipboardKeybindings.js +304 -155
  43. package/dist/components/Timeline/TimelineEffectPropItem.js +9 -61
  44. package/dist/components/Timeline/TimelineFieldLabel.d.ts +1 -0
  45. package/dist/components/Timeline/TimelineFieldLabel.js +4 -2
  46. package/dist/components/Timeline/TimelineFieldRowContent.d.ts +8 -0
  47. package/dist/components/Timeline/TimelineFieldRowContent.js +16 -0
  48. package/dist/components/Timeline/TimelinePrimitiveFieldValue.js +1 -1
  49. package/dist/components/Timeline/TimelineRowChrome.js +2 -0
  50. package/dist/components/Timeline/TimelineSequence.js +2 -4
  51. package/dist/components/Timeline/TimelineSequenceItem.js +6 -9
  52. package/dist/components/Timeline/TimelineSequenceName.js +1 -3
  53. package/dist/components/Timeline/TimelineSequencePropItem.js +10 -59
  54. package/dist/components/Timeline/TimelineSequenceRightEdgeDragHandle.d.ts +2 -0
  55. package/dist/components/Timeline/TimelineSequenceRightEdgeDragHandle.js +18 -6
  56. package/dist/components/Timeline/TimelineTextContentField.js +12 -5
  57. package/dist/components/Timeline/TimelineVideoInfo.d.ts +3 -1
  58. package/dist/components/Timeline/TimelineVideoInfo.js +11 -4
  59. package/dist/components/Timeline/delete-selected-timeline-item.js +4 -5
  60. package/dist/components/Timeline/effects-clipboard.d.ts +14 -0
  61. package/dist/components/Timeline/effects-clipboard.js +68 -0
  62. package/dist/components/Timeline/get-sequence-context-menu-items.js +37 -0
  63. package/dist/components/Timeline/get-timeline-media-start-frame.d.ts +6 -0
  64. package/dist/components/Timeline/get-timeline-media-start-frame.js +15 -0
  65. package/dist/components/Timeline/sequence-props-subscription-store.d.ts +3 -2
  66. package/dist/components/Timeline/sequence-props-subscription-store.js +4 -2
  67. package/dist/components/Timeline/timeline-field-row-layout.d.ts +1 -0
  68. package/dist/components/Timeline/timeline-field-row-layout.js +8 -1
  69. package/dist/components/Timeline/timeline-row-layout.d.ts +1 -1
  70. package/dist/components/Timeline/timeline-row-layout.js +1 -1
  71. package/dist/components/Timeline/use-sequence-props-subscription.js +10 -1
  72. package/dist/components/import-assets.d.ts +5 -0
  73. package/dist/components/import-assets.js +10 -2
  74. package/dist/components/selected-outline-measurement.d.ts +4 -0
  75. package/dist/components/selected-outline-measurement.js +3 -1
  76. package/dist/components/selected-outline-types.d.ts +1 -6
  77. package/dist/esm/{chunk-jrta3xaf.js → chunk-9wh9k3jj.js} +10393 -9551
  78. package/dist/esm/index.mjs +0 -1
  79. package/dist/esm/internals.mjs +10393 -9551
  80. package/dist/esm/previewEntry.mjs +7603 -6761
  81. package/dist/esm/renderEntry.mjs +1 -1
  82. package/dist/helpers/format-file-location.d.ts +5 -0
  83. package/dist/helpers/format-file-location.js +9 -1
  84. package/dist/helpers/install-required-package.d.ts +1 -0
  85. package/dist/helpers/install-required-package.js +3 -2
  86. package/dist/helpers/retry-payload.js +0 -1
  87. package/dist/helpers/studio-runtime-config.d.ts +0 -1
  88. package/dist/helpers/studio-runtime-config.js +1 -6
  89. package/dist/helpers/use-menu-structure.js +15 -18
  90. package/dist/icons/align-bottom.d.ts +3 -0
  91. package/dist/icons/align-bottom.js +12 -0
  92. package/dist/icons/align-center-horizontal.d.ts +3 -0
  93. package/dist/icons/align-center-horizontal.js +12 -0
  94. package/dist/icons/align-center-vertical.d.ts +3 -0
  95. package/dist/icons/align-center-vertical.js +12 -0
  96. package/dist/icons/align-left.d.ts +3 -0
  97. package/dist/icons/align-left.js +12 -0
  98. package/dist/icons/align-right.d.ts +3 -0
  99. package/dist/icons/align-right.js +12 -0
  100. package/dist/icons/align-top.d.ts +3 -0
  101. package/dist/icons/align-top.js +12 -0
  102. package/dist/state/modals.d.ts +1 -3
  103. package/package.json +11 -11
  104. package/dist/components/RenderModal/WebRendererExperimentalBadge.d.ts +0 -1
  105. package/dist/components/RenderModal/WebRendererExperimentalBadge.js +0 -35
  106. package/dist/components/Timeline/KeyframeSettingsModal.d.ts +0 -15
  107. package/dist/components/Timeline/KeyframeSettingsModal.js +0 -151
  108. package/dist/helpers/show-browser-rendering.d.ts +0 -1
  109. package/dist/helpers/show-browser-rendering.js +0 -5
@@ -1,13 +1,16 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.TimelineClipboardKeybindings = exports.getPasteEffectPropTarget = exports.getEasingClipboardDataFromSelection = exports.getEffectPropClipboardDataFromSelection = exports.getSnapshotsFromSelection = exports.getPasteEffectsTarget = void 0;
3
+ exports.TimelineClipboardKeybindings = exports.getPasteEffectPropTarget = exports.getEasingClipboardDataFromSelection = exports.getEffectPropClipboardDataFromSelection = exports.getEffectsClipboardEnvelopeFromSelections = exports.getEffectClipboardDataFromSelections = exports.getSnapshotsFromSelection = exports.getPasteEffectsTarget = void 0;
4
4
  const studio_shared_1 = require("@remotion/studio-shared");
5
5
  const react_1 = require("react");
6
6
  const remotion_1 = require("remotion");
7
7
  const client_id_1 = require("../../helpers/client-id");
8
8
  const use_keybinding_1 = require("../../helpers/use-keybinding");
9
9
  const call_api_1 = require("../call-api");
10
+ const ConfirmationDialog_1 = require("../ConfirmationDialog");
10
11
  const NotificationCenter_1 = require("../Notifications/NotificationCenter");
12
+ const delete_selected_timeline_item_1 = require("./delete-selected-timeline-item");
13
+ const effects_clipboard_1 = require("./effects-clipboard");
11
14
  const find_track_for_node_path_info_1 = require("./find-track-for-node-path-info");
12
15
  const save_effect_prop_1 = require("./save-effect-prop");
13
16
  const TimelineSelection_1 = require("./TimelineSelection");
@@ -90,6 +93,9 @@ const effectPropStatusToClipboardParam = (prop) => {
90
93
  keyframes: prop.keyframes,
91
94
  easing: prop.easing,
92
95
  clamping: prop.clamping,
96
+ ...(prop.output === undefined || prop.output === 'linear'
97
+ ? {}
98
+ : { output: prop.output }),
93
99
  ...(prop.posterize === undefined ? {} : { posterize: prop.posterize }),
94
100
  };
95
101
  };
@@ -144,6 +150,83 @@ const getSnapshotsFromSelection = ({ selection, propStatuses, }) => {
144
150
  return snapshots;
145
151
  };
146
152
  exports.getSnapshotsFromSelection = getSnapshotsFromSelection;
153
+ const getEffectClipboardDataFromSelections = ({ selectedItems, propStatuses, }) => {
154
+ const firstSelection = selectedItems[0];
155
+ const type = firstSelection ? getCopyType(firstSelection) : null;
156
+ if (type === null) {
157
+ return { type: 'none' };
158
+ }
159
+ if (selectedItems.some((selection) => getCopyType(selection) !== type)) {
160
+ return { type: 'mixed' };
161
+ }
162
+ const snapshots = selectedItems.flatMap((selection) => {
163
+ const itemSnapshots = (0, exports.getSnapshotsFromSelection)({
164
+ selection,
165
+ propStatuses,
166
+ });
167
+ return itemSnapshots !== null && itemSnapshots !== void 0 ? itemSnapshots : [null];
168
+ });
169
+ if (snapshots.some((snapshot) => snapshot === null)) {
170
+ return { type: 'uncopyable' };
171
+ }
172
+ return {
173
+ type: 'valid',
174
+ payload: {
175
+ type,
176
+ version: 3,
177
+ remotionClipboard: 'effects',
178
+ effects: snapshots,
179
+ },
180
+ };
181
+ };
182
+ exports.getEffectClipboardDataFromSelections = getEffectClipboardDataFromSelections;
183
+ const getEffectsClipboardEnvelopeFromSelections = ({ selectedItems, payload, }) => {
184
+ if (payload.type !== 'effects-additive' ||
185
+ selectedItems.some((selection) => selection.type !== 'sequence-effect')) {
186
+ return {
187
+ envelopeVersion: 1,
188
+ payload,
189
+ sourceIdentity: null,
190
+ originalEffectIndices: [],
191
+ };
192
+ }
193
+ const effectSelections = selectedItems;
194
+ const firstSelection = effectSelections[0];
195
+ if (!firstSelection || effectSelections.length !== payload.effects.length) {
196
+ return {
197
+ envelopeVersion: 1,
198
+ payload,
199
+ sourceIdentity: null,
200
+ originalEffectIndices: [],
201
+ };
202
+ }
203
+ const sourceIdentity = makeTargetKey(firstSelection.nodePathInfo.sequenceSubscriptionKey);
204
+ if (effectSelections.some((selection) => makeTargetKey(selection.nodePathInfo.sequenceSubscriptionKey) !==
205
+ sourceIdentity)) {
206
+ return {
207
+ envelopeVersion: 1,
208
+ payload,
209
+ sourceIdentity: null,
210
+ originalEffectIndices: [],
211
+ };
212
+ }
213
+ const indexedEffects = effectSelections
214
+ .map((selection, index) => ({
215
+ effectIndex: selection.i,
216
+ effect: payload.effects[index],
217
+ }))
218
+ .sort((a, b) => a.effectIndex - b.effectIndex);
219
+ return {
220
+ envelopeVersion: 1,
221
+ payload: {
222
+ ...payload,
223
+ effects: indexedEffects.map(({ effect }) => effect),
224
+ },
225
+ sourceIdentity,
226
+ originalEffectIndices: indexedEffects.map(({ effectIndex }) => effectIndex),
227
+ };
228
+ };
229
+ exports.getEffectsClipboardEnvelopeFromSelections = getEffectsClipboardEnvelopeFromSelections;
147
230
  const getEffectPropClipboardDataFromSelection = ({ selection, propStatuses, }) => {
148
231
  if (selection.type !== 'sequence-effect-prop') {
149
232
  return null;
@@ -276,6 +359,7 @@ const TimelineClipboardKeybindings = () => {
276
359
  const { setPropStatuses } = (0, react_1.useContext)(remotion_1.Internals.VisualModeSettersContext);
277
360
  const sequencesRef = (0, react_1.useContext)(remotion_1.Internals.SequenceManagerRefContext);
278
361
  const { overrideIdToNodePathMappings } = (0, react_1.useContext)(remotion_1.Internals.OverrideIdsToNodePathsGettersContext);
362
+ const confirm = (0, ConfirmationDialog_1.useConfirmationDialog)();
279
363
  (0, react_1.useEffect)(() => {
280
364
  if (!canSelect || previewServerState.type !== 'connected') {
281
365
  return;
@@ -345,38 +429,28 @@ const TimelineClipboardKeybindings = () => {
345
429
  });
346
430
  return;
347
431
  }
348
- const firstSelection = selectedItems[0];
349
- const type = firstSelection ? getCopyType(firstSelection) : null;
350
- if (type === null) {
432
+ const effectClipboardData = (0, exports.getEffectClipboardDataFromSelections)({
433
+ selectedItems,
434
+ propStatuses,
435
+ });
436
+ if (effectClipboardData.type === 'none') {
351
437
  return;
352
438
  }
353
- if (selectedItems.some((selection) => getCopyType(selection) !== type)) {
439
+ if (effectClipboardData.type === 'mixed') {
354
440
  e.preventDefault();
355
441
  (0, NotificationCenter_1.showNotification)('Cannot copy individual effects together with all effects', 3000);
356
442
  return;
357
443
  }
358
- const snapshots = selectedItems.flatMap((selection) => {
359
- const itemSnapshots = (0, exports.getSnapshotsFromSelection)({
360
- selection,
361
- propStatuses,
362
- });
363
- return itemSnapshots !== null && itemSnapshots !== void 0 ? itemSnapshots : [null];
364
- });
365
- if (snapshots.some((snapshot) => snapshot === null)) {
444
+ if (effectClipboardData.type === 'uncopyable') {
366
445
  e.preventDefault();
367
446
  (0, NotificationCenter_1.showNotification)('Cannot copy effects because one of them contains values that cannot be copied', 3000);
368
447
  return;
369
448
  }
370
449
  e.preventDefault();
371
450
  navigator.clipboard
372
- .writeText(makeClipboardText({
373
- type,
374
- version: 3,
375
- remotionClipboard: 'effects',
376
- effects: snapshots,
377
- }))
451
+ .writeText(makeClipboardText(effectClipboardData.payload))
378
452
  .then(() => {
379
- (0, NotificationCenter_1.showNotification)(snapshots.length === 1
453
+ (0, NotificationCenter_1.showNotification)(effectClipboardData.payload.effects.length === 1
380
454
  ? 'Copied effect to clipboard'
381
455
  : 'Copied effects to clipboard', 1000);
382
456
  })
@@ -389,169 +463,244 @@ const TimelineClipboardKeybindings = () => {
389
463
  triggerIfInputFieldFocused: false,
390
464
  keepRegisteredWhenNotHighestContext: false,
391
465
  });
392
- const paste = keybindings.registerKeybinding({
466
+ const cut = keybindings.registerKeybinding({
393
467
  event: 'keydown',
394
- key: 'v',
468
+ key: 'x',
395
469
  callback: (e) => {
396
- const { selectedItems } = currentSelection.current;
470
+ const { selectedItems, clearSelection, selectItems } = currentSelection.current;
397
471
  if (selectedItems.length === 0) {
398
472
  return;
399
473
  }
400
- navigator.clipboard
401
- .readText()
402
- .then((text) => {
403
- const propStatuses = propStatusesRef.current;
404
- const sequences = sequencesRef.current;
405
- const easingResult = (0, studio_shared_1.parseEasingClipboardDataResult)(text);
406
- if (easingResult.status !== 'invalid') {
407
- e.preventDefault();
408
- if (easingResult.status === 'unsupported-version') {
409
- (0, NotificationCenter_1.showNotification)('Cannot paste easing copied from a different Remotion Studio version', 4000);
410
- return;
411
- }
412
- const easingSelections = (0, update_selected_easing_1.getEasingSelections)(selectedItems);
413
- if (easingSelections.length === 0 ||
414
- easingSelections.length !== selectedItems.length) {
415
- (0, NotificationCenter_1.showNotification)('Select an easing to paste onto', 3000);
474
+ const effectClipboardData = (0, exports.getEffectClipboardDataFromSelections)({
475
+ selectedItems,
476
+ propStatuses: propStatusesRef.current,
477
+ });
478
+ if (effectClipboardData.type === 'none') {
479
+ return;
480
+ }
481
+ e.preventDefault();
482
+ if (effectClipboardData.type === 'mixed') {
483
+ (0, NotificationCenter_1.showNotification)('Cannot cut individual effects together with all effects', 3000);
484
+ return;
485
+ }
486
+ if (effectClipboardData.type === 'uncopyable') {
487
+ (0, NotificationCenter_1.showNotification)('Cannot cut effects because one of them contains values that cannot be copied', 3000);
488
+ return;
489
+ }
490
+ const envelope = (0, exports.getEffectsClipboardEnvelopeFromSelections)({
491
+ selectedItems,
492
+ payload: effectClipboardData.payload,
493
+ });
494
+ const propStatuses = propStatusesRef.current;
495
+ (0, effects_clipboard_1.writeEffectsClipboardEnvelope)(envelope)
496
+ .then(() => {
497
+ const deletePromise = (0, delete_selected_timeline_item_1.deleteSelectedTimelineItems)({
498
+ selections: selectedItems,
499
+ sequences: sequencesRef.current,
500
+ overrideIdsToNodePaths: overrideIdToNodePathMappings,
501
+ setPropStatuses,
502
+ clientId,
503
+ confirm,
504
+ });
505
+ return deletePromise === null || deletePromise === void 0 ? void 0 : deletePromise.then((deleted) => {
506
+ if (!deleted) {
416
507
  return;
417
508
  }
418
- const updatePromise = (0, update_selected_easing_1.updateSelectedTimelineEasings)({
419
- selections: easingSelections,
420
- sequences,
421
- overrideIdsToNodePaths: overrideIdToNodePathMappings,
509
+ const nextSelection = (0, delete_selected_timeline_item_1.getTimelineSelectionAfterDeletingItems)({
510
+ selections: selectedItems,
422
511
  propStatuses,
423
- setPropStatuses,
424
- clientId,
425
- easing: easingResult.data.easing,
426
512
  });
427
- if (updatePromise === null) {
428
- (0, NotificationCenter_1.showNotification)('Cannot paste onto an easing that cannot be updated', 3000);
429
- return;
430
- }
431
- return updatePromise
432
- .then(() => {
433
- (0, NotificationCenter_1.showNotification)(easingSelections.length === 1
434
- ? 'Pasted easing'
435
- : 'Pasted easing to selected segments', 2000);
436
- })
437
- .catch((err) => {
438
- (0, NotificationCenter_1.showNotification)(`Could not paste easing: ${err.message}`, 3000);
439
- });
440
- }
441
- const effectPropResult = (0, studio_shared_1.parseEffectPropClipboardDataResult)(text);
442
- if (effectPropResult.status !== 'invalid') {
443
- e.preventDefault();
444
- if (effectPropResult.status === 'unsupported-version') {
445
- (0, NotificationCenter_1.showNotification)('Cannot paste effect prop copied from a different Remotion Studio version', 4000);
446
- return;
513
+ if (nextSelection.length === 0) {
514
+ clearSelection();
447
515
  }
448
- const effectPropTarget = (0, exports.getPasteEffectPropTarget)({
449
- selectedItems,
450
- payload: effectPropResult.data,
451
- propStatuses,
452
- sequences,
453
- overrideIdsToNodePaths: overrideIdToNodePathMappings,
454
- });
455
- if (effectPropTarget.type !== 'valid') {
456
- switch (effectPropTarget.type) {
457
- case 'multiple':
458
- (0, NotificationCenter_1.showNotification)('Select one target effect prop or effect to paste onto', 3000);
459
- return;
460
- case 'none':
461
- (0, NotificationCenter_1.showNotification)('Select a matching effect prop or effect to paste onto', 3000);
462
- return;
463
- case 'unsupported':
464
- (0, NotificationCenter_1.showNotification)('This sequence does not support effects', 3000);
465
- return;
466
- case 'effect-type-mismatch':
467
- (0, NotificationCenter_1.showNotification)('Select an effect of the same type to paste this prop', 3000);
468
- return;
469
- case 'prop-mismatch':
470
- (0, NotificationCenter_1.showNotification)('Select the same effect prop, or an effect with that prop', 3000);
471
- return;
472
- case 'uncopyable':
473
- (0, NotificationCenter_1.showNotification)('Cannot paste onto an effect prop that cannot be updated', 3000);
474
- return;
475
- default:
476
- throw new Error(`Unexpected paste target: ${effectPropTarget}`);
477
- }
516
+ else {
517
+ selectItems(nextSelection);
478
518
  }
479
- return (0, save_effect_prop_1.saveEffectProp)({
480
- fileName: effectPropTarget.fileName,
481
- nodePath: effectPropTarget.nodePath,
482
- effectIndex: effectPropTarget.effectIndex,
483
- fieldKey: effectPropTarget.fieldKey,
484
- ...(effectPropResult.data.param.type === 'static'
485
- ? {
486
- type: 'value',
487
- value: effectPropResult.data.param.value,
488
- }
489
- : {
490
- type: 'effect-param',
491
- effectParam: effectPropResult.data.param,
492
- }),
493
- defaultValue: effectPropTarget.defaultValue,
494
- schema: effectPropTarget.schema,
495
- setPropStatuses,
496
- clientId,
497
- }).then(() => {
498
- (0, NotificationCenter_1.showNotification)('Pasted effect prop', 2000);
499
- });
500
- }
501
- const result = (0, studio_shared_1.parseEffectClipboardDataResult)(text);
502
- if (result.status === 'invalid') {
503
- return;
504
- }
519
+ });
520
+ })
521
+ .catch((err) => {
522
+ (0, NotificationCenter_1.showNotification)(`Could not cut effects: ${err.message}`, 2000);
523
+ });
524
+ },
525
+ commandCtrlKey: true,
526
+ preventDefault: false,
527
+ triggerIfInputFieldFocused: false,
528
+ keepRegisteredWhenNotHighestContext: false,
529
+ });
530
+ const handlePaste = (e) => {
531
+ const { activeElement } = document;
532
+ if (activeElement instanceof HTMLInputElement ||
533
+ activeElement instanceof HTMLTextAreaElement) {
534
+ return;
535
+ }
536
+ const { selectedItems } = currentSelection.current;
537
+ if (selectedItems.length === 0 || e.clipboardData === null) {
538
+ return;
539
+ }
540
+ e.preventDefault();
541
+ const { text, envelope } = (0, effects_clipboard_1.readClipboardTextAndEffectsEnvelope)(e.clipboardData);
542
+ Promise.resolve()
543
+ .then(() => {
544
+ const propStatuses = propStatusesRef.current;
545
+ const sequences = sequencesRef.current;
546
+ const easingResult = (0, studio_shared_1.parseEasingClipboardDataResult)(text);
547
+ if (easingResult.status !== 'invalid') {
505
548
  e.preventDefault();
506
- if (result.status === 'unsupported-version') {
507
- (0, NotificationCenter_1.showNotification)('Cannot paste effects copied from a different Remotion Studio version', 4000);
549
+ if (easingResult.status === 'unsupported-version') {
550
+ (0, NotificationCenter_1.showNotification)('Cannot paste easing copied from a different Remotion Studio version', 4000);
508
551
  return;
509
552
  }
510
- const { data: payload } = result;
511
- const target = (0, exports.getPasteEffectsTarget)(selectedItems);
512
- if (target.type === 'multiple') {
513
- (0, NotificationCenter_1.showNotification)('Select one target sequence to paste effects', 3000);
553
+ const easingSelections = (0, update_selected_easing_1.getEasingSelections)(selectedItems);
554
+ if (easingSelections.length === 0 ||
555
+ easingSelections.length !== selectedItems.length) {
556
+ (0, NotificationCenter_1.showNotification)('Select an easing to paste onto', 3000);
514
557
  return;
515
558
  }
516
- if (target.type === 'none') {
517
- (0, NotificationCenter_1.showNotification)('Select a sequence to paste effects onto', 3000);
559
+ const updatePromise = (0, update_selected_easing_1.updateSelectedTimelineEasings)({
560
+ selections: easingSelections,
561
+ sequences,
562
+ overrideIdsToNodePaths: overrideIdToNodePathMappings,
563
+ propStatuses,
564
+ setPropStatuses,
565
+ clientId,
566
+ easing: easingResult.data.easing,
567
+ });
568
+ if (updatePromise === null) {
569
+ (0, NotificationCenter_1.showNotification)('Cannot paste onto an easing that cannot be updated', 3000);
518
570
  return;
519
571
  }
520
- if (target.type === 'unsupported') {
521
- (0, NotificationCenter_1.showNotification)('This sequence does not support effects', 3000);
572
+ return updatePromise
573
+ .then(() => {
574
+ (0, NotificationCenter_1.showNotification)(easingSelections.length === 1
575
+ ? 'Pasted easing'
576
+ : 'Pasted easing to selected segments', 2000);
577
+ })
578
+ .catch((err) => {
579
+ (0, NotificationCenter_1.showNotification)(`Could not paste easing: ${err.message}`, 3000);
580
+ });
581
+ }
582
+ const effectPropResult = (0, studio_shared_1.parseEffectPropClipboardDataResult)(text);
583
+ if (effectPropResult.status !== 'invalid') {
584
+ e.preventDefault();
585
+ if (effectPropResult.status === 'unsupported-version') {
586
+ (0, NotificationCenter_1.showNotification)('Cannot paste effect prop copied from a different Remotion Studio version', 4000);
522
587
  return;
523
588
  }
524
- const { sequenceSubscriptionKey: targetSequenceNodePath } = target.nodePathInfo;
525
- return (0, call_api_1.callApi)('/api/paste-effects', {
526
- targetFileName: targetSequenceNodePath.absolutePath,
527
- targetSequenceNodePath,
528
- type: payload.type,
529
- effects: payload.effects,
530
- clientId,
531
- }).then((pasteResult) => {
532
- if (pasteResult.success) {
533
- (0, NotificationCenter_1.showNotification)('Pasted effects', 2000);
534
- }
535
- else {
536
- (0, NotificationCenter_1.showNotification)(pasteResult.reason, 4000);
589
+ const effectPropTarget = (0, exports.getPasteEffectPropTarget)({
590
+ selectedItems,
591
+ payload: effectPropResult.data,
592
+ propStatuses,
593
+ sequences,
594
+ overrideIdsToNodePaths: overrideIdToNodePathMappings,
595
+ });
596
+ if (effectPropTarget.type !== 'valid') {
597
+ switch (effectPropTarget.type) {
598
+ case 'multiple':
599
+ (0, NotificationCenter_1.showNotification)('Select one target effect prop or effect to paste onto', 3000);
600
+ return;
601
+ case 'none':
602
+ (0, NotificationCenter_1.showNotification)('Select a matching effect prop or effect to paste onto', 3000);
603
+ return;
604
+ case 'unsupported':
605
+ (0, NotificationCenter_1.showNotification)('This sequence does not support effects', 3000);
606
+ return;
607
+ case 'effect-type-mismatch':
608
+ (0, NotificationCenter_1.showNotification)('Select an effect of the same type to paste this prop', 3000);
609
+ return;
610
+ case 'prop-mismatch':
611
+ (0, NotificationCenter_1.showNotification)('Select the same effect prop, or an effect with that prop', 3000);
612
+ return;
613
+ case 'uncopyable':
614
+ (0, NotificationCenter_1.showNotification)('Cannot paste onto an effect prop that cannot be updated', 3000);
615
+ return;
616
+ default:
617
+ throw new Error(`Unexpected paste target: ${effectPropTarget}`);
537
618
  }
619
+ }
620
+ return (0, save_effect_prop_1.saveEffectProp)({
621
+ fileName: effectPropTarget.fileName,
622
+ nodePath: effectPropTarget.nodePath,
623
+ effectIndex: effectPropTarget.effectIndex,
624
+ fieldKey: effectPropTarget.fieldKey,
625
+ ...(effectPropResult.data.param.type === 'static'
626
+ ? {
627
+ type: 'value',
628
+ value: effectPropResult.data.param.value,
629
+ }
630
+ : {
631
+ type: 'effect-param',
632
+ effectParam: effectPropResult.data.param,
633
+ }),
634
+ defaultValue: effectPropTarget.defaultValue,
635
+ schema: effectPropTarget.schema,
636
+ setPropStatuses,
637
+ clientId,
638
+ }).then(() => {
639
+ (0, NotificationCenter_1.showNotification)('Pasted effect prop', 2000);
538
640
  });
539
- })
540
- .catch((err) => {
541
- (0, NotificationCenter_1.showNotification)(`Could not paste effects: ${err.message}`, 3000);
641
+ }
642
+ const result = envelope === null
643
+ ? (0, studio_shared_1.parseEffectClipboardDataResult)(text)
644
+ : { status: 'valid', data: envelope.payload };
645
+ if (result.status === 'invalid') {
646
+ return;
647
+ }
648
+ e.preventDefault();
649
+ if (result.status === 'unsupported-version') {
650
+ (0, NotificationCenter_1.showNotification)('Cannot paste effects copied from a different Remotion Studio version', 4000);
651
+ return;
652
+ }
653
+ const { data: payload } = result;
654
+ const target = (0, exports.getPasteEffectsTarget)(selectedItems);
655
+ if (target.type === 'multiple') {
656
+ (0, NotificationCenter_1.showNotification)('Select one target sequence to paste effects', 3000);
657
+ return;
658
+ }
659
+ if (target.type === 'none') {
660
+ (0, NotificationCenter_1.showNotification)('Select a sequence to paste effects onto', 3000);
661
+ return;
662
+ }
663
+ if (target.type === 'unsupported') {
664
+ (0, NotificationCenter_1.showNotification)('This sequence does not support effects', 3000);
665
+ return;
666
+ }
667
+ const { sequenceSubscriptionKey: targetSequenceNodePath } = target.nodePathInfo;
668
+ const insertAtIndices = (envelope === null || envelope === void 0 ? void 0 : envelope.sourceIdentity) === makeTargetKey(targetSequenceNodePath)
669
+ ? envelope.originalEffectIndices
670
+ : null;
671
+ return (0, call_api_1.callApi)('/api/paste-effects', {
672
+ targetFileName: targetSequenceNodePath.absolutePath,
673
+ targetSequenceNodePath,
674
+ type: payload.type,
675
+ effects: payload.effects,
676
+ clientId,
677
+ insertAtIndices,
678
+ }).then((pasteResult) => {
679
+ if (pasteResult.success) {
680
+ (0, NotificationCenter_1.showNotification)('Pasted effects', 2000);
681
+ }
682
+ else {
683
+ (0, NotificationCenter_1.showNotification)(pasteResult.reason, 4000);
684
+ }
542
685
  });
543
- },
544
- commandCtrlKey: true,
545
- preventDefault: false,
546
- triggerIfInputFieldFocused: false,
547
- keepRegisteredWhenNotHighestContext: false,
548
- });
686
+ })
687
+ .catch((err) => {
688
+ (0, NotificationCenter_1.showNotification)(`Could not paste effects: ${err.message}`, 3000);
689
+ });
690
+ };
691
+ // Reading ClipboardEvent data avoids the permission prompt caused by
692
+ // navigator.clipboard.read().
693
+ if (keybindings.isHighestContext && !(0, use_keybinding_1.areKeyboardShortcutsDisabled)()) {
694
+ document.addEventListener('paste', handlePaste);
695
+ }
549
696
  return () => {
550
697
  copy.unregister();
551
- paste.unregister();
698
+ cut.unregister();
699
+ document.removeEventListener('paste', handlePaste);
552
700
  };
553
701
  }, [
554
702
  canSelect,
703
+ confirm,
555
704
  currentSelection,
556
705
  keybindings,
557
706
  overrideIdToNodePathMappings,