@remotion/studio 4.0.490 → 4.0.492

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 (120) hide show
  1. package/dist/components/AssetSelectorItem.js +7 -4
  2. package/dist/components/Canvas.js +2 -0
  3. package/dist/components/CompositionOrStillIcon.d.ts +7 -0
  4. package/dist/components/CompositionOrStillIcon.js +11 -0
  5. package/dist/components/CompositionSelector.js +13 -1
  6. package/dist/components/CompositionSelectorItem.js +33 -5
  7. package/dist/components/CurrentAsset.d.ts +6 -0
  8. package/dist/components/CurrentAsset.js +14 -8
  9. package/dist/components/CurrentComposition.js +4 -1
  10. package/dist/components/EditorContent.js +1 -1
  11. package/dist/components/GlobalKeybindings.d.ts +1 -3
  12. package/dist/components/GlobalKeybindings.js +2 -9
  13. package/dist/components/InlineEditableTitle.d.ts +1 -0
  14. package/dist/components/InlineEditableTitle.js +12 -7
  15. package/dist/components/InspectorInfoHeader.d.ts +1 -0
  16. package/dist/components/InspectorInfoHeader.js +7 -4
  17. package/dist/components/InspectorLocationCopy.d.ts +7 -0
  18. package/dist/components/InspectorLocationCopy.js +65 -0
  19. package/dist/components/InspectorPanel/SequenceCompositionsSection.d.ts +5 -0
  20. package/dist/components/InspectorPanel/SequenceCompositionsSection.js +37 -0
  21. package/dist/components/InspectorPanel/SequenceInspectorHeader.js +6 -4
  22. package/dist/components/InspectorPanel/SequenceSelectionInspector.js +2 -1
  23. package/dist/components/InspectorPanel/common.js +1 -1
  24. package/dist/components/InspectorPanel/get-compositions-matching-single-child.d.ts +6 -0
  25. package/dist/components/InspectorPanel/get-compositions-matching-single-child.js +11 -0
  26. package/dist/components/InspectorSequenceSection.js +57 -3
  27. package/dist/components/KeyboardShortcutsExplainer.js +4 -0
  28. package/dist/components/NewComposition/NewComposition.js +11 -4
  29. package/dist/components/NewComposition/get-new-composition-defaults.d.ts +4 -0
  30. package/dist/components/NewComposition/get-new-composition-defaults.js +13 -0
  31. package/dist/components/OptionsPanel.js +4 -8
  32. package/dist/components/OutlineToggle.d.ts +3 -1
  33. package/dist/components/OutlineToggle.js +2 -2
  34. package/dist/components/PreviewToolbar.js +1 -1
  35. package/dist/components/RenderButton.js +9 -33
  36. package/dist/components/RenderModal/WebRenderModal.js +3 -8
  37. package/dist/components/RenderModal/WebRenderModalAdvanced.d.ts +0 -2
  38. package/dist/components/RenderModal/WebRenderModalAdvanced.js +2 -9
  39. package/dist/components/RenderQueue/ClientRenderQueueProcessor.js +0 -2
  40. package/dist/components/RenderQueue/client-side-render-types.d.ts +0 -1
  41. package/dist/components/RenderQueue/index.js +0 -9
  42. package/dist/components/SelectedOutlineElement.js +40 -38
  43. package/dist/components/SelectedOutlineOverlay.d.ts +1 -1
  44. package/dist/components/SelectedOutlineOverlay.js +2 -13
  45. package/dist/components/SnappingToggle.d.ts +3 -1
  46. package/dist/components/SnappingToggle.js +2 -2
  47. package/dist/components/Timeline/TimelineAssetField.d.ts +14 -0
  48. package/dist/components/Timeline/TimelineAssetField.js +125 -0
  49. package/dist/components/Timeline/TimelineClipboardKeybindings.d.ts +20 -1
  50. package/dist/components/Timeline/TimelineClipboardKeybindings.js +301 -155
  51. package/dist/components/Timeline/TimelineEffectPropItem.js +7 -11
  52. package/dist/components/Timeline/TimelineExpandedSection.js +1 -0
  53. package/dist/components/Timeline/TimelineFieldLabel.d.ts +1 -0
  54. package/dist/components/Timeline/TimelineFieldLabel.js +7 -3
  55. package/dist/components/Timeline/TimelineFieldRowContent.d.ts +8 -0
  56. package/dist/components/Timeline/TimelineFieldRowContent.js +16 -0
  57. package/dist/components/Timeline/TimelineKeyframeControls.js +1 -0
  58. package/dist/components/Timeline/TimelinePrimitiveFieldValue.js +5 -1
  59. package/dist/components/Timeline/TimelineRowChrome.js +8 -4
  60. package/dist/components/Timeline/TimelineRowLayoutContext.d.ts +7 -0
  61. package/dist/components/Timeline/TimelineRowLayoutContext.js +13 -0
  62. package/dist/components/Timeline/TimelineSelection.js +1 -0
  63. package/dist/components/Timeline/TimelineSequence.js +2 -4
  64. package/dist/components/Timeline/TimelineSequenceItem.js +1 -0
  65. package/dist/components/Timeline/TimelineSequencePropItem.js +8 -10
  66. package/dist/components/Timeline/TimelineSequenceRightEdgeDragHandle.d.ts +2 -0
  67. package/dist/components/Timeline/TimelineSequenceRightEdgeDragHandle.js +18 -6
  68. package/dist/components/Timeline/TimelineTextContentField.js +12 -5
  69. package/dist/components/Timeline/TimelineVideoInfo.d.ts +3 -1
  70. package/dist/components/Timeline/TimelineVideoInfo.js +11 -4
  71. package/dist/components/Timeline/delete-selected-timeline-item.js +4 -5
  72. package/dist/components/Timeline/effects-clipboard.d.ts +14 -0
  73. package/dist/components/Timeline/effects-clipboard.js +68 -0
  74. package/dist/components/Timeline/get-sequence-context-menu-items.js +40 -3
  75. package/dist/components/Timeline/get-timeline-media-start-frame.d.ts +6 -0
  76. package/dist/components/Timeline/get-timeline-media-start-frame.js +15 -0
  77. package/dist/components/Timeline/sequence-props-subscription-store.d.ts +3 -2
  78. package/dist/components/Timeline/sequence-props-subscription-store.js +8 -2
  79. package/dist/components/Timeline/timeline-asset-link.d.ts +6 -0
  80. package/dist/components/Timeline/timeline-asset-link.js +27 -1
  81. package/dist/components/Timeline/timeline-field-display-utils.js +1 -0
  82. package/dist/components/Timeline/timeline-field-row-layout.d.ts +2 -1
  83. package/dist/components/Timeline/timeline-field-row-layout.js +10 -3
  84. package/dist/components/Timeline/timeline-row-layout.d.ts +4 -3
  85. package/dist/components/Timeline/timeline-row-layout.js +7 -6
  86. package/dist/components/Timeline/use-expanded-track-keyframe-rows.js +1 -0
  87. package/dist/components/Timeline/use-sequence-props-subscription.js +10 -1
  88. package/dist/components/Timeline/use-timeline-expanded-tree.d.ts +2 -1
  89. package/dist/components/Timeline/use-timeline-expanded-tree.js +3 -1
  90. package/dist/components/Timeline/use-timeline-height.js +1 -0
  91. package/dist/components/import-assets.d.ts +14 -2
  92. package/dist/components/import-assets.js +28 -7
  93. package/dist/components/root-composition-menu-items.d.ts +8 -0
  94. package/dist/components/root-composition-menu-items.js +45 -0
  95. package/dist/components/selected-outline-measurement.d.ts +4 -0
  96. package/dist/components/selected-outline-measurement.js +3 -1
  97. package/dist/components/selected-outline-types.d.ts +1 -6
  98. package/dist/esm/{chunk-16nwrbrm.js → chunk-ewx0568t.js} +7962 -7216
  99. package/dist/esm/index.mjs +0 -1
  100. package/dist/esm/internals.mjs +7962 -7216
  101. package/dist/esm/previewEntry.mjs +7332 -6586
  102. package/dist/esm/renderEntry.mjs +1 -1
  103. package/dist/helpers/format-file-location.d.ts +5 -0
  104. package/dist/helpers/format-file-location.js +9 -1
  105. package/dist/helpers/get-file-manager-name.d.ts +1 -0
  106. package/dist/helpers/get-file-manager-name.js +13 -0
  107. package/dist/helpers/retry-payload.js +0 -1
  108. package/dist/helpers/studio-runtime-config.d.ts +0 -1
  109. package/dist/helpers/studio-runtime-config.js +1 -6
  110. package/dist/helpers/timeline-layout.d.ts +2 -1
  111. package/dist/helpers/timeline-layout.js +5 -1
  112. package/dist/helpers/url-state.d.ts +1 -0
  113. package/dist/helpers/url-state.js +8 -6
  114. package/dist/helpers/use-menu-structure.js +19 -20
  115. package/dist/state/modals.d.ts +0 -1
  116. package/package.json +11 -11
  117. package/dist/components/RenderModal/WebRendererExperimentalBadge.d.ts +0 -1
  118. package/dist/components/RenderModal/WebRendererExperimentalBadge.js +0 -35
  119. package/dist/helpers/show-browser-rendering.d.ts +0 -1
  120. 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");
@@ -147,6 +150,83 @@ const getSnapshotsFromSelection = ({ selection, propStatuses, }) => {
147
150
  return snapshots;
148
151
  };
149
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;
150
230
  const getEffectPropClipboardDataFromSelection = ({ selection, propStatuses, }) => {
151
231
  if (selection.type !== 'sequence-effect-prop') {
152
232
  return null;
@@ -279,6 +359,7 @@ const TimelineClipboardKeybindings = () => {
279
359
  const { setPropStatuses } = (0, react_1.useContext)(remotion_1.Internals.VisualModeSettersContext);
280
360
  const sequencesRef = (0, react_1.useContext)(remotion_1.Internals.SequenceManagerRefContext);
281
361
  const { overrideIdToNodePathMappings } = (0, react_1.useContext)(remotion_1.Internals.OverrideIdsToNodePathsGettersContext);
362
+ const confirm = (0, ConfirmationDialog_1.useConfirmationDialog)();
282
363
  (0, react_1.useEffect)(() => {
283
364
  if (!canSelect || previewServerState.type !== 'connected') {
284
365
  return;
@@ -348,38 +429,28 @@ const TimelineClipboardKeybindings = () => {
348
429
  });
349
430
  return;
350
431
  }
351
- const firstSelection = selectedItems[0];
352
- const type = firstSelection ? getCopyType(firstSelection) : null;
353
- if (type === null) {
432
+ const effectClipboardData = (0, exports.getEffectClipboardDataFromSelections)({
433
+ selectedItems,
434
+ propStatuses,
435
+ });
436
+ if (effectClipboardData.type === 'none') {
354
437
  return;
355
438
  }
356
- if (selectedItems.some((selection) => getCopyType(selection) !== type)) {
439
+ if (effectClipboardData.type === 'mixed') {
357
440
  e.preventDefault();
358
441
  (0, NotificationCenter_1.showNotification)('Cannot copy individual effects together with all effects', 3000);
359
442
  return;
360
443
  }
361
- const snapshots = selectedItems.flatMap((selection) => {
362
- const itemSnapshots = (0, exports.getSnapshotsFromSelection)({
363
- selection,
364
- propStatuses,
365
- });
366
- return itemSnapshots !== null && itemSnapshots !== void 0 ? itemSnapshots : [null];
367
- });
368
- if (snapshots.some((snapshot) => snapshot === null)) {
444
+ if (effectClipboardData.type === 'uncopyable') {
369
445
  e.preventDefault();
370
446
  (0, NotificationCenter_1.showNotification)('Cannot copy effects because one of them contains values that cannot be copied', 3000);
371
447
  return;
372
448
  }
373
449
  e.preventDefault();
374
450
  navigator.clipboard
375
- .writeText(makeClipboardText({
376
- type,
377
- version: 3,
378
- remotionClipboard: 'effects',
379
- effects: snapshots,
380
- }))
451
+ .writeText(makeClipboardText(effectClipboardData.payload))
381
452
  .then(() => {
382
- (0, NotificationCenter_1.showNotification)(snapshots.length === 1
453
+ (0, NotificationCenter_1.showNotification)(effectClipboardData.payload.effects.length === 1
383
454
  ? 'Copied effect to clipboard'
384
455
  : 'Copied effects to clipboard', 1000);
385
456
  })
@@ -392,169 +463,244 @@ const TimelineClipboardKeybindings = () => {
392
463
  triggerIfInputFieldFocused: false,
393
464
  keepRegisteredWhenNotHighestContext: false,
394
465
  });
395
- const paste = keybindings.registerKeybinding({
466
+ const cut = keybindings.registerKeybinding({
396
467
  event: 'keydown',
397
- key: 'v',
468
+ key: 'x',
398
469
  callback: (e) => {
399
- const { selectedItems } = currentSelection.current;
470
+ const { selectedItems, clearSelection, selectItems } = currentSelection.current;
400
471
  if (selectedItems.length === 0) {
401
472
  return;
402
473
  }
403
- navigator.clipboard
404
- .readText()
405
- .then((text) => {
406
- const propStatuses = propStatusesRef.current;
407
- const sequences = sequencesRef.current;
408
- const easingResult = (0, studio_shared_1.parseEasingClipboardDataResult)(text);
409
- if (easingResult.status !== 'invalid') {
410
- e.preventDefault();
411
- if (easingResult.status === 'unsupported-version') {
412
- (0, NotificationCenter_1.showNotification)('Cannot paste easing copied from a different Remotion Studio version', 4000);
413
- return;
414
- }
415
- const easingSelections = (0, update_selected_easing_1.getEasingSelections)(selectedItems);
416
- if (easingSelections.length === 0 ||
417
- easingSelections.length !== selectedItems.length) {
418
- (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) {
419
507
  return;
420
508
  }
421
- const updatePromise = (0, update_selected_easing_1.updateSelectedTimelineEasings)({
422
- selections: easingSelections,
423
- sequences,
424
- overrideIdsToNodePaths: overrideIdToNodePathMappings,
509
+ const nextSelection = (0, delete_selected_timeline_item_1.getTimelineSelectionAfterDeletingItems)({
510
+ selections: selectedItems,
425
511
  propStatuses,
426
- setPropStatuses,
427
- clientId,
428
- easing: easingResult.data.easing,
429
512
  });
430
- if (updatePromise === null) {
431
- (0, NotificationCenter_1.showNotification)('Cannot paste onto an easing that cannot be updated', 3000);
432
- return;
433
- }
434
- return updatePromise
435
- .then(() => {
436
- (0, NotificationCenter_1.showNotification)(easingSelections.length === 1
437
- ? 'Pasted easing'
438
- : 'Pasted easing to selected segments', 2000);
439
- })
440
- .catch((err) => {
441
- (0, NotificationCenter_1.showNotification)(`Could not paste easing: ${err.message}`, 3000);
442
- });
443
- }
444
- const effectPropResult = (0, studio_shared_1.parseEffectPropClipboardDataResult)(text);
445
- if (effectPropResult.status !== 'invalid') {
446
- e.preventDefault();
447
- if (effectPropResult.status === 'unsupported-version') {
448
- (0, NotificationCenter_1.showNotification)('Cannot paste effect prop copied from a different Remotion Studio version', 4000);
449
- return;
513
+ if (nextSelection.length === 0) {
514
+ clearSelection();
450
515
  }
451
- const effectPropTarget = (0, exports.getPasteEffectPropTarget)({
452
- selectedItems,
453
- payload: effectPropResult.data,
454
- propStatuses,
455
- sequences,
456
- overrideIdsToNodePaths: overrideIdToNodePathMappings,
457
- });
458
- if (effectPropTarget.type !== 'valid') {
459
- switch (effectPropTarget.type) {
460
- case 'multiple':
461
- (0, NotificationCenter_1.showNotification)('Select one target effect prop or effect to paste onto', 3000);
462
- return;
463
- case 'none':
464
- (0, NotificationCenter_1.showNotification)('Select a matching effect prop or effect to paste onto', 3000);
465
- return;
466
- case 'unsupported':
467
- (0, NotificationCenter_1.showNotification)('This sequence does not support effects', 3000);
468
- return;
469
- case 'effect-type-mismatch':
470
- (0, NotificationCenter_1.showNotification)('Select an effect of the same type to paste this prop', 3000);
471
- return;
472
- case 'prop-mismatch':
473
- (0, NotificationCenter_1.showNotification)('Select the same effect prop, or an effect with that prop', 3000);
474
- return;
475
- case 'uncopyable':
476
- (0, NotificationCenter_1.showNotification)('Cannot paste onto an effect prop that cannot be updated', 3000);
477
- return;
478
- default:
479
- throw new Error(`Unexpected paste target: ${effectPropTarget}`);
480
- }
516
+ else {
517
+ selectItems(nextSelection);
481
518
  }
482
- return (0, save_effect_prop_1.saveEffectProp)({
483
- fileName: effectPropTarget.fileName,
484
- nodePath: effectPropTarget.nodePath,
485
- effectIndex: effectPropTarget.effectIndex,
486
- fieldKey: effectPropTarget.fieldKey,
487
- ...(effectPropResult.data.param.type === 'static'
488
- ? {
489
- type: 'value',
490
- value: effectPropResult.data.param.value,
491
- }
492
- : {
493
- type: 'effect-param',
494
- effectParam: effectPropResult.data.param,
495
- }),
496
- defaultValue: effectPropTarget.defaultValue,
497
- schema: effectPropTarget.schema,
498
- setPropStatuses,
499
- clientId,
500
- }).then(() => {
501
- (0, NotificationCenter_1.showNotification)('Pasted effect prop', 2000);
502
- });
503
- }
504
- const result = (0, studio_shared_1.parseEffectClipboardDataResult)(text);
505
- if (result.status === 'invalid') {
506
- return;
507
- }
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') {
508
548
  e.preventDefault();
509
- if (result.status === 'unsupported-version') {
510
- (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);
511
551
  return;
512
552
  }
513
- const { data: payload } = result;
514
- const target = (0, exports.getPasteEffectsTarget)(selectedItems);
515
- if (target.type === 'multiple') {
516
- (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);
517
557
  return;
518
558
  }
519
- if (target.type === 'none') {
520
- (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);
521
570
  return;
522
571
  }
523
- if (target.type === 'unsupported') {
524
- (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);
525
587
  return;
526
588
  }
527
- const { sequenceSubscriptionKey: targetSequenceNodePath } = target.nodePathInfo;
528
- return (0, call_api_1.callApi)('/api/paste-effects', {
529
- targetFileName: targetSequenceNodePath.absolutePath,
530
- targetSequenceNodePath,
531
- type: payload.type,
532
- effects: payload.effects,
533
- clientId,
534
- }).then((pasteResult) => {
535
- if (pasteResult.success) {
536
- (0, NotificationCenter_1.showNotification)('Pasted effects', 2000);
537
- }
538
- else {
539
- (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}`);
540
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);
541
640
  });
542
- })
543
- .catch((err) => {
544
- (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
+ }
545
685
  });
546
- },
547
- commandCtrlKey: true,
548
- preventDefault: false,
549
- triggerIfInputFieldFocused: false,
550
- keepRegisteredWhenNotHighestContext: false,
551
- });
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
+ }
552
696
  return () => {
553
697
  copy.unregister();
554
- paste.unregister();
698
+ cut.unregister();
699
+ document.removeEventListener('paste', handlePaste);
555
700
  };
556
701
  }, [
557
702
  canSelect,
703
+ confirm,
558
704
  currentSelection,
559
705
  keybindings,
560
706
  overrideIdToNodePathMappings,
@@ -13,9 +13,8 @@ const get_animation_item_selection_for_frame_1 = require("./get-animation-item-s
13
13
  const get_timeline_keyframes_1 = require("./get-timeline-keyframes");
14
14
  const save_effect_prop_1 = require("./save-effect-prop");
15
15
  const save_prop_queue_1 = require("./save-prop-queue");
16
- const timeline_field_row_layout_1 = require("./timeline-field-row-layout");
17
16
  const TimelineExpandArrowButton_1 = require("./TimelineExpandArrowButton");
18
- const TimelineFieldLabel_1 = require("./TimelineFieldLabel");
17
+ const TimelineFieldRowContent_1 = require("./TimelineFieldRowContent");
19
18
  const TimelineKeyframeControls_1 = require("./TimelineKeyframeControls");
20
19
  const TimelineKeyframedValue_1 = require("./TimelineKeyframedValue");
21
20
  const TimelineLayerEye_1 = require("./TimelineLayerEye");
@@ -213,7 +212,7 @@ const TimelineEffectPropValue = ({ field, nodePath, validatedLocation, sourceFra
213
212
  exports.TimelineEffectPropValue = TimelineEffectPropValue;
214
213
  const TimelineEffectPropItem = ({ field, validatedLocation, rowDepth, nodePath, nodePathInfo, keyframeDisplayOffset, keyframeControlsMode = 'timeline', }) => {
215
214
  var _a;
216
- var _b, _c;
215
+ var _b;
217
216
  const { previewServerState } = (0, react_1.useContext)(client_id_1.StudioServerConnectionCtx);
218
217
  const { setPropStatuses } = (0, react_1.useContext)(remotion_1.Internals.VisualModeSettersContext);
219
218
  const { propStatuses } = (0, react_1.useContext)(remotion_1.Internals.VisualModePropStatusesContext);
@@ -225,11 +224,10 @@ const TimelineEffectPropItem = ({ field, validatedLocation, rowDepth, nodePath,
225
224
  const timelinePosition = remotion_1.Internals.Timeline.useTimelinePosition();
226
225
  const sourceFrame = timelinePosition - keyframeDisplayOffset;
227
226
  const style = (0, react_1.useMemo)(() => {
228
- return {
229
- ...fieldRowBase,
230
- height: field.rowHeight,
231
- };
232
- }, [field.rowHeight]);
227
+ return field.typeName === 'text-content'
228
+ ? fieldRowBase
229
+ : { ...fieldRowBase, height: field.rowHeight };
230
+ }, [field.rowHeight, field.typeName]);
233
231
  const effectStatus = (0, react_1.useMemo)(() => remotion_1.Internals.getEffectPropStatusesCtx({
234
232
  propStatuses,
235
233
  nodePath,
@@ -392,9 +390,7 @@ const TimelineEffectPropItem = ({ field, validatedLocation, rowDepth, nodePath,
392
390
  sourceFrame,
393
391
  validatedLocation.source,
394
392
  ]);
395
- const row = (jsx_runtime_1.jsxs(TimelineRowChrome_1.TimelineRowChrome, { depth: rowDepth, eye: jsx_runtime_1.jsx(TimelineLayerEye_1.TimelineLayerEyeSpacer, {}), keyframeControls: keyframeControls, arrow: jsx_runtime_1.jsx(TimelineExpandArrowButton_1.TimelineExpandArrowSpacer, {}), style: style, selected: selection.selected, selectable: selection.selectable, selectionItem: selection.selectionItem, onSelect: selection.onSelect, onDoubleClick: onPropertyDoubleClick, showSelectedBackground: true, containsSelection: false, outerHeight: null, children: [
396
- jsx_runtime_1.jsx(TimelineFieldLabel_1.TimelineFieldLabel, { rowDepth: rowDepth, selected: selection.selected, label: (_c = field.description) !== null && _c !== void 0 ? _c : field.key }), jsx_runtime_1.jsx("div", { style: timeline_field_row_layout_1.timelineFieldValueColumnStyle, children: jsx_runtime_1.jsx(exports.TimelineEffectPropValue, { field: field, nodePath: nodePath, validatedLocation: validatedLocation, sourceFrame: sourceFrame }) })
397
- ] }));
393
+ const row = (jsx_runtime_1.jsx(TimelineRowChrome_1.TimelineRowChrome, { depth: rowDepth, eye: jsx_runtime_1.jsx(TimelineLayerEye_1.TimelineLayerEyeSpacer, {}), keyframeControls: keyframeControls, arrow: jsx_runtime_1.jsx(TimelineExpandArrowButton_1.TimelineExpandArrowSpacer, {}), style: style, selected: selection.selected, selectable: selection.selectable, selectionItem: selection.selectionItem, onSelect: selection.onSelect, onDoubleClick: onPropertyDoubleClick, showSelectedBackground: true, containsSelection: false, outerHeight: null, children: jsx_runtime_1.jsx(TimelineFieldRowContent_1.TimelineFieldRowContent, { field: field, rowDepth: rowDepth, selected: selection.selected, children: jsx_runtime_1.jsx(exports.TimelineEffectPropValue, { field: field, nodePath: nodePath, validatedLocation: validatedLocation, sourceFrame: sourceFrame }) }) }));
398
394
  return (jsx_runtime_1.jsx(ContextMenu_1.ContextMenu, { values: contextMenuValues, onOpen: selection.selectable ? selection.onSelect : null, children: row }));
399
395
  };
400
396
  exports.TimelineEffectPropItem = TimelineEffectPropItem;
@@ -57,6 +57,7 @@ const TimelineExpandedSection = ({ sequence, validatedLocation, nodePathInfo, ne
57
57
  sequence,
58
58
  nodePathInfo,
59
59
  includeTextContent: false,
60
+ includeSourceControls: false,
60
61
  });
61
62
  const flat = (0, react_1.useMemo)(() => (0, timeline_layout_1.flattenVisibleTreeNodes)({ nodes: filteredTree, getIsExpanded }), [filteredTree, getIsExpanded]);
62
63
  const expandedHeight = (0, react_1.useMemo)(() => {
@@ -3,4 +3,5 @@ export declare const TimelineFieldLabel: React.FC<{
3
3
  readonly rowDepth: number;
4
4
  readonly selected: boolean;
5
5
  readonly label: string;
6
+ readonly stacked?: boolean;
6
7
  }>;
@@ -4,7 +4,9 @@ exports.TimelineFieldLabel = void 0;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const react_1 = require("react");
6
6
  const colors_1 = require("../../helpers/colors");
7
+ const timeline_layout_1 = require("../../helpers/timeline-layout");
7
8
  const timeline_field_row_layout_1 = require("./timeline-field-row-layout");
9
+ const TimelineRowLayoutContext_1 = require("./TimelineRowLayoutContext");
8
10
  const TimelineSelection_1 = require("./TimelineSelection");
9
11
  const fieldNameBase = {
10
12
  fontSize: 12,
@@ -16,12 +18,14 @@ const fieldNameBase = {
16
18
  flex: 1,
17
19
  minWidth: 0,
18
20
  };
19
- const TimelineFieldLabel = ({ rowDepth, selected, label }) => {
21
+ const TimelineFieldLabel = ({ rowDepth, selected, label, stacked = false }) => {
22
+ const { basePadding } = (0, react_1.useContext)(TimelineRowLayoutContext_1.TimelineRowLayoutContext);
20
23
  const labelRowStyle = (0, react_1.useMemo)(() => ({
21
- ...(0, timeline_field_row_layout_1.getTimelineFieldLabelRowStyle)(rowDepth),
24
+ ...(0, timeline_field_row_layout_1.getTimelineFieldLabelRowStyle)(rowDepth, basePadding),
22
25
  ...(0, TimelineSelection_1.getTimelineSelectedLabelStyle)(selected, true),
26
+ ...(stacked ? { flex: `0 0 ${timeline_layout_1.SCHEMA_FIELD_ROW_HEIGHT}px` } : null),
23
27
  alignSelf: 'stretch',
24
- }), [rowDepth, selected]);
28
+ }), [basePadding, rowDepth, selected, stacked]);
25
29
  const fieldNameStyle = (0, react_1.useMemo)(() => ({
26
30
  ...fieldNameBase,
27
31
  color: (0, TimelineSelection_1.getTimelineColor)(selected, true),
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ import type { SchemaFieldInfo } from '../../helpers/timeline-layout';
3
+ export declare const TimelineFieldRowContent: React.FC<{
4
+ readonly field: SchemaFieldInfo;
5
+ readonly rowDepth: number;
6
+ readonly selected: boolean;
7
+ readonly children: React.ReactNode;
8
+ }>;