@remotion/studio 4.0.496 → 4.0.497

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 (81) hide show
  1. package/dist/components/AudioWaveform.js +1 -11
  2. package/dist/components/Canvas.js +22 -203
  3. package/dist/components/CompositionSelectorItem.js +2 -10
  4. package/dist/components/InspectorPanel/AlignmentControls.js +2 -0
  5. package/dist/components/InspectorPanel/ConnectedCompositionsSection.js +27 -2
  6. package/dist/components/InspectorPanel/SequenceSelectionInspector.js +65 -8
  7. package/dist/components/InspectorPanel/use-composition-actions.js +6 -2
  8. package/dist/components/NewComposition/CodemodFooter.d.ts +1 -1
  9. package/dist/components/NewComposition/CodemodFooter.js +23 -4
  10. package/dist/components/NewComposition/InputDragger.d.ts +6 -0
  11. package/dist/components/NewComposition/InputDragger.js +12 -3
  12. package/dist/components/NewComposition/NewComposition.js +1 -1
  13. package/dist/components/NewComposition/use-rename-static-file.js +1 -1
  14. package/dist/components/SelectedOutlineElement.js +56 -88
  15. package/dist/components/SelectedOutlineOverlay.d.ts +1 -1
  16. package/dist/components/SelectedOutlineOverlay.js +9 -10
  17. package/dist/components/Timeline/Timeline.js +10 -3
  18. package/dist/components/Timeline/TimelineAssetDropIndicator.d.ts +2 -0
  19. package/dist/components/Timeline/TimelineAssetDropIndicator.js +37 -0
  20. package/dist/components/Timeline/TimelineClipboardKeybindings.js +1 -7
  21. package/dist/components/Timeline/TimelineScrollable.js +3 -2
  22. package/dist/components/Timeline/TimelineSelection.d.ts +4 -0
  23. package/dist/components/Timeline/TimelineSelection.js +40 -5
  24. package/dist/components/Timeline/TimelineSequence.js +20 -8
  25. package/dist/components/Timeline/TimelineSequenceFrame.js +2 -4
  26. package/dist/components/Timeline/TimelineSequenceItem.js +2 -0
  27. package/dist/components/Timeline/TimelineSequencePropItem.js +4 -0
  28. package/dist/components/Timeline/TimelineSequenceRightEdgeDragHandle.d.ts +15 -3
  29. package/dist/components/Timeline/TimelineSequenceRightEdgeDragHandle.js +96 -18
  30. package/dist/components/Timeline/TimelineTimeIndicators.d.ts +16 -0
  31. package/dist/components/Timeline/TimelineTimeIndicators.js +154 -35
  32. package/dist/components/Timeline/TimelineTranslateField.js +2 -1
  33. package/dist/components/Timeline/TimelineVideoInfo.d.ts +1 -0
  34. package/dist/components/Timeline/TimelineVideoInfo.js +4 -1
  35. package/dist/components/Timeline/delete-selected-timeline-item.d.ts +2 -0
  36. package/dist/components/Timeline/delete-selected-timeline-item.js +5 -4
  37. package/dist/components/Timeline/disable-sequence-interactivity.js +2 -0
  38. package/dist/components/Timeline/get-timeline-media-visualization-layout.d.ts +8 -0
  39. package/dist/components/Timeline/get-timeline-media-visualization-layout.js +10 -0
  40. package/dist/components/Timeline/get-timeline-video-info-widths.js +11 -3
  41. package/dist/components/Timeline/keyframe-clipboard.js +21 -5
  42. package/dist/components/Timeline/reset-selected-timeline-props.js +2 -0
  43. package/dist/components/Timeline/save-sequence-prop.d.ts +5 -3
  44. package/dist/components/Timeline/save-sequence-prop.js +43 -18
  45. package/dist/components/Timeline/should-clear-selection-on-pointer-down.d.ts +2 -0
  46. package/dist/components/Timeline/should-clear-selection-on-pointer-down.js +1 -1
  47. package/dist/components/Timeline/timeline-asset-drop-context.d.ts +1 -0
  48. package/dist/components/Timeline/timeline-asset-drop-context.js +5 -0
  49. package/dist/components/Timeline/timeline-scroll-logic.d.ts +7 -0
  50. package/dist/components/Timeline/timeline-scroll-logic.js +10 -1
  51. package/dist/components/Timeline/use-rename-sequence.js +2 -0
  52. package/dist/components/Timeline/use-sequence-freeze-frame-menu-item.js +2 -0
  53. package/dist/components/Timeline/use-timeline-asset-drop.d.ts +1 -0
  54. package/dist/components/Timeline/use-timeline-asset-drop.js +168 -0
  55. package/dist/components/composition-menu-items.d.ts +15 -1
  56. package/dist/components/composition-menu-items.js +137 -107
  57. package/dist/components/drop-handler-data.d.ts +13 -0
  58. package/dist/components/drop-handler-data.js +117 -0
  59. package/dist/components/handle-drop.d.ts +13 -0
  60. package/dist/components/handle-drop.js +115 -0
  61. package/dist/components/import-assets.d.ts +26 -8
  62. package/dist/components/import-assets.js +161 -49
  63. package/dist/components/selected-outline-drag.d.ts +11 -1
  64. package/dist/components/selected-outline-drag.js +74 -1
  65. package/dist/esm/{chunk-0v4n7nkh.js → chunk-5wj95bdd.js} +4262 -3392
  66. package/dist/esm/internals.mjs +4262 -3392
  67. package/dist/esm/previewEntry.mjs +4464 -3594
  68. package/dist/esm/renderEntry.mjs +1 -1
  69. package/dist/helpers/is-video-with-last-frame-hold.d.ts +2 -0
  70. package/dist/helpers/is-video-with-last-frame-hold.js +9 -0
  71. package/dist/helpers/url-state.d.ts +1 -0
  72. package/dist/helpers/url-state.js +5 -1
  73. package/dist/helpers/use-max-media-duration.js +5 -3
  74. package/dist/helpers/use-menu-structure.js +2 -0
  75. package/dist/icons/duplicate.d.ts +5 -0
  76. package/dist/icons/duplicate.js +10 -0
  77. package/dist/icons/snowflake.d.ts +5 -0
  78. package/dist/icons/snowflake.js +10 -0
  79. package/dist/icons/trash.d.ts +5 -0
  80. package/dist/icons/trash.js +8 -0
  81. package/package.json +11 -11
@@ -31,16 +31,6 @@ const getContainerStyle = (height) => {
31
31
  height,
32
32
  };
33
33
  };
34
- const errorMessage = {
35
- fontSize: 13,
36
- paddingTop: 6,
37
- paddingBottom: 6,
38
- paddingLeft: 12,
39
- paddingRight: 12,
40
- alignSelf: 'flex-start',
41
- maxWidth: 450,
42
- opacity: 0.75,
43
- };
44
34
  const getWaveformErrorMessage = () => {
45
35
  return new Error('No waveform available. The audio could not be decoded or may not support CORS.');
46
36
  };
@@ -302,7 +292,7 @@ const AudioWaveform = ({ src, height, startFrom, durationInFrames, visualization
302
292
  context.stroke();
303
293
  }, [height, parsedVolume, shouldRenderVolumeOverlay, visualizationWidth]);
304
294
  if (error) {
305
- return (jsx_runtime_1.jsx("div", { style: getContainerStyle(height), children: jsx_runtime_1.jsx("div", { style: errorMessage, children: "No waveform available. The audio could not be decoded or may not support CORS." }) }));
295
+ return null;
306
296
  }
307
297
  if (!canUseWorkerPath && !peaks) {
308
298
  return null;
@@ -5,7 +5,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.Canvas = void 0;
7
7
  const jsx_runtime_1 = require("react/jsx-runtime");
8
- const studio_shared_1 = require("@remotion/studio-shared");
9
8
  const react_1 = require("react");
10
9
  const remotion_1 = require("remotion");
11
10
  const get_static_files_1 = require("../api/get-static-files");
@@ -18,7 +17,6 @@ const get_asset_metadata_1 = require("../helpers/get-asset-metadata");
18
17
  const get_effective_translation_1 = require("../helpers/get-effective-translation");
19
18
  const install_required_package_1 = require("../helpers/install-required-package");
20
19
  const open_in_editor_1 = require("../helpers/open-in-editor");
21
- const remote_asset_drag_1 = require("../helpers/remote-asset-drag");
22
20
  const smooth_zoom_1 = require("../helpers/smooth-zoom");
23
21
  const studio_fit_padding_1 = require("../helpers/studio-fit-padding");
24
22
  const use_keybinding_1 = require("../helpers/use-keybinding");
@@ -27,11 +25,12 @@ const editor_guides_1 = require("../state/editor-guides");
27
25
  const editor_zoom_gestures_1 = require("../state/editor-zoom-gestures");
28
26
  const call_api_1 = require("./call-api");
29
27
  const ConfirmationDialog_1 = require("./ConfirmationDialog");
28
+ const drop_handler_data_1 = require("./drop-handler-data");
30
29
  const EditorGuides_1 = __importDefault(require("./EditorGuides"));
31
30
  const EditorRuler_1 = require("./EditorRuler");
32
31
  const use_is_ruler_visible_1 = require("./EditorRuler/use-is-ruler-visible");
33
32
  const effect_drag_and_drop_1 = require("./effect-drag-and-drop");
34
- const element_drag_and_drop_1 = require("./element-drag-and-drop");
33
+ const handle_drop_1 = require("./handle-drop");
35
34
  const import_assets_1 = require("./import-assets");
36
35
  const layout_1 = require("./layout");
37
36
  const NotificationCenter_1 = require("./Notifications/NotificationCenter");
@@ -101,97 +100,6 @@ const calculateCanvasScale = ({ addFitPadding, canvasSize, compositionHeight, co
101
100
  ? (0, studio_fit_padding_1.calculateStudioScale)(options)
102
101
  : remotion_1.Internals.calculateScale(options);
103
102
  };
104
- const isFileDragEvent = (event) => {
105
- var _a;
106
- var _b;
107
- return Array.from((_b = (_a = event.dataTransfer) === null || _a === void 0 ? void 0 : _a.types) !== null && _b !== void 0 ? _b : []).includes('Files');
108
- };
109
- const isAssetDragEvent = (event) => {
110
- var _a;
111
- var _b;
112
- return Array.from((_b = (_a = event.dataTransfer) === null || _a === void 0 ? void 0 : _a.types) !== null && _b !== void 0 ? _b : []).includes(studio_shared_1.ASSET_DRAG_MIME_TYPE);
113
- };
114
- const isComponentDragEvent = (event) => {
115
- var _a;
116
- var _b;
117
- return Array.from((_b = (_a = event.dataTransfer) === null || _a === void 0 ? void 0 : _a.types) !== null && _b !== void 0 ? _b : []).includes(studio_shared_1.COMPONENT_DRAG_MIME_TYPE);
118
- };
119
- const isCompositionDragEvent = (event) => {
120
- var _a;
121
- var _b;
122
- return Array.from((_b = (_a = event.dataTransfer) === null || _a === void 0 ? void 0 : _a.types) !== null && _b !== void 0 ? _b : []).includes(studio_shared_1.COMPOSITION_DRAG_MIME_TYPE);
123
- };
124
- const isElementDragEvent = (event) => {
125
- var _a;
126
- var _b;
127
- return Array.from((_b = (_a = event.dataTransfer) === null || _a === void 0 ? void 0 : _a.types) !== null && _b !== void 0 ? _b : []).includes(studio_shared_1.ELEMENT_DRAG_MIME_TYPE);
128
- };
129
- const isSfxDragEvent = (event) => {
130
- var _a;
131
- var _b;
132
- return Array.from((_b = (_a = event.dataTransfer) === null || _a === void 0 ? void 0 : _a.types) !== null && _b !== void 0 ? _b : []).includes(studio_shared_1.SFX_DRAG_MIME_TYPE);
133
- };
134
- const isRemoteAssetDragEvent = (event) => {
135
- return (!isFileDragEvent(event) &&
136
- !isAssetDragEvent(event) &&
137
- !isCompositionDragEvent(event) &&
138
- !isComponentDragEvent(event) &&
139
- !isElementDragEvent(event) &&
140
- !isSfxDragEvent(event) &&
141
- (0, remote_asset_drag_1.hasRemoteAssetDragData)(event.dataTransfer));
142
- };
143
- const getAssetDragPath = (event) => {
144
- var _a, _b;
145
- var _c;
146
- const value = (_a = event.dataTransfer) === null || _a === void 0 ? void 0 : _a.getData(studio_shared_1.ASSET_DRAG_MIME_TYPE);
147
- if (!value) {
148
- return null;
149
- }
150
- return (_c = (_b = (0, studio_shared_1.parseAssetDragData)(value)) === null || _b === void 0 ? void 0 : _b.assetPath) !== null && _c !== void 0 ? _c : null;
151
- };
152
- const getCompositionDragData = (event) => {
153
- var _a;
154
- const value = (_a = event.dataTransfer) === null || _a === void 0 ? void 0 : _a.getData(studio_shared_1.COMPOSITION_DRAG_MIME_TYPE);
155
- if (!value) {
156
- return null;
157
- }
158
- return (0, studio_shared_1.parseCompositionDragData)(value);
159
- };
160
- const getComponentDragData = (event) => {
161
- var _a;
162
- for (const type of [
163
- studio_shared_1.COMPONENT_DRAG_MIME_TYPE,
164
- 'application/json',
165
- 'text/plain',
166
- ]) {
167
- const value = (_a = event.dataTransfer) === null || _a === void 0 ? void 0 : _a.getData(type);
168
- if (!value) {
169
- continue;
170
- }
171
- const parsed = (0, studio_shared_1.parseComponentDragData)(value);
172
- if (parsed) {
173
- return parsed;
174
- }
175
- }
176
- return null;
177
- };
178
- const getSfxDragUrl = (event) => {
179
- const { dataTransfer } = event;
180
- if (!dataTransfer) {
181
- return null;
182
- }
183
- for (const type of [studio_shared_1.SFX_DRAG_MIME_TYPE, 'application/json', 'text/plain']) {
184
- const value = dataTransfer.getData(type);
185
- if (!value) {
186
- continue;
187
- }
188
- const parsed = (0, studio_shared_1.parseSfxDragData)(value);
189
- if (parsed) {
190
- return parsed.sfx.url;
191
- }
192
- }
193
- return null;
194
- };
195
103
  const getDropPosition = ({ addFitPadding, clientX, clientY, contentDimensions, previewSize, size, }) => {
196
104
  if (contentDimensions === null || contentDimensions === 'none') {
197
105
  return null;
@@ -766,6 +674,7 @@ const Canvas = ({ canvasContent, size }) => {
766
674
  compositionFile: activeElementInstallRequest.compositionFile,
767
675
  compositionId: activeElementInstallRequest.compositionId,
768
676
  dropPosition: null,
677
+ from: null,
769
678
  });
770
679
  }
771
680
  };
@@ -787,14 +696,7 @@ const Canvas = ({ canvasContent, size }) => {
787
696
  };
788
697
  }, [activeElementInstallRequest, confirm]);
789
698
  const onDragOver = (0, react_1.useCallback)((event) => {
790
- if ((!isFileDragEvent(event) &&
791
- !isAssetDragEvent(event) &&
792
- !isCompositionDragEvent(event) &&
793
- !isComponentDragEvent(event) &&
794
- !isElementDragEvent(event) &&
795
- !isSfxDragEvent(event) &&
796
- !isRemoteAssetDragEvent(event)) ||
797
- !isDragEventInsideCanvas(event)) {
699
+ if (!(0, drop_handler_data_1.isSupportedDropEvent)(event) || !isDragEventInsideCanvas(event)) {
798
700
  return;
799
701
  }
800
702
  if (!canDropAssets && !cannotAddSequence) {
@@ -806,16 +708,7 @@ const Canvas = ({ canvasContent, size }) => {
806
708
  }
807
709
  }, [canDropAssets, cannotAddSequence]);
808
710
  const onDrop = (0, react_1.useCallback)(async (event) => {
809
- var _a;
810
- var _b;
811
- if ((!isFileDragEvent(event) &&
812
- !isAssetDragEvent(event) &&
813
- !isCompositionDragEvent(event) &&
814
- !isComponentDragEvent(event) &&
815
- !isElementDragEvent(event) &&
816
- !isSfxDragEvent(event) &&
817
- !isRemoteAssetDragEvent(event)) ||
818
- !isDragEventInsideCanvas(event)) {
711
+ if (!(0, drop_handler_data_1.isSupportedDropEvent)(event) || !isDragEventInsideCanvas(event)) {
819
712
  return;
820
713
  }
821
714
  if (cannotAddSequence) {
@@ -826,7 +719,8 @@ const Canvas = ({ canvasContent, size }) => {
826
719
  }
827
720
  if (!canDropAssets ||
828
721
  compositionFile === null ||
829
- currentCompositionId === null) {
722
+ currentCompositionId === null ||
723
+ config === null) {
830
724
  return;
831
725
  }
832
726
  if (event.dataTransfer &&
@@ -846,96 +740,16 @@ const Canvas = ({ canvasContent, size }) => {
846
740
  previewSize,
847
741
  size,
848
742
  });
849
- if (isFileDragEvent(event)) {
850
- const files = Array.from((_b = (_a = event.dataTransfer) === null || _a === void 0 ? void 0 : _a.files) !== null && _b !== void 0 ? _b : []);
851
- if (files.length === 0) {
852
- return;
853
- }
854
- const svgImportMode = (0, import_assets_1.hasSvgFile)(files)
855
- ? await chooseSvgImportMode()
856
- : 'image';
857
- if (svgImportMode === null) {
858
- return;
859
- }
860
- await (0, import_assets_1.importAssets)({
861
- files,
862
- compositionFile,
863
- compositionId: currentCompositionId,
864
- destinationDimensions: contentDimensions === 'none' ? null : contentDimensions,
865
- dropPosition,
866
- svgImportMode,
867
- });
868
- }
869
- else if (isAssetDragEvent(event)) {
870
- const assetPath = getAssetDragPath(event);
871
- if (assetPath === null) {
872
- return;
873
- }
874
- await (0, import_assets_1.insertExistingAssets)({
875
- assetPaths: [assetPath],
876
- compositionFile,
877
- compositionId: currentCompositionId,
878
- destinationDimensions: contentDimensions === 'none' ? null : contentDimensions,
879
- dropPosition,
880
- });
881
- }
882
- else if (isSfxDragEvent(event)) {
883
- const url = getSfxDragUrl(event);
884
- if (url === null) {
885
- return;
886
- }
887
- await (0, import_assets_1.insertRemoteAudio)({
888
- url,
889
- compositionFile,
890
- compositionId: currentCompositionId,
891
- });
892
- }
893
- else if (isCompositionDragEvent(event)) {
894
- const compositionDragData = getCompositionDragData(event);
895
- if (compositionDragData === null) {
896
- return;
897
- }
898
- await (0, import_assets_1.insertComposition)({
899
- composition: compositionDragData,
900
- compositionFile,
901
- compositionId: currentCompositionId,
902
- destinationDimensions: contentDimensions === 'none' ? null : contentDimensions,
903
- dropPosition,
904
- });
905
- }
906
- else {
907
- const elementDragData = (0, element_drag_and_drop_1.getElementDragData)(event.dataTransfer);
908
- if (elementDragData !== null) {
909
- await (0, import_assets_1.insertElement)({
910
- element: elementDragData.element,
911
- compositionFile,
912
- compositionId: currentCompositionId,
913
- dropPosition,
914
- });
915
- return;
916
- }
917
- const componentDragData = getComponentDragData(event);
918
- if (componentDragData !== null) {
919
- await (0, import_assets_1.insertComponent)({
920
- component: componentDragData.component,
921
- compositionFile,
922
- compositionId: currentCompositionId,
923
- dropPosition,
924
- });
925
- return;
926
- }
927
- const url = (0, remote_asset_drag_1.getRemoteAssetUrlFromDataTransfer)(event.dataTransfer);
928
- if (url === null) {
929
- return;
930
- }
931
- await (0, import_assets_1.importRemoteAsset)({
932
- url,
933
- compositionFile,
934
- compositionId: currentCompositionId,
935
- destinationDimensions: contentDimensions === 'none' ? null : contentDimensions,
936
- dropPosition,
937
- });
938
- }
743
+ await (0, handle_drop_1.handleDrop)({
744
+ chooseSvgImportMode,
745
+ compositionFile,
746
+ compositionId: currentCompositionId,
747
+ destinationDimensions: contentDimensions === 'none' ? null : contentDimensions,
748
+ dropPosition,
749
+ event,
750
+ fps: config.fps,
751
+ from: null,
752
+ });
939
753
  }
940
754
  finally {
941
755
  setIsAddingAsset(false);
@@ -946,6 +760,7 @@ const Canvas = ({ canvasContent, size }) => {
946
760
  cannotAddSequence,
947
761
  chooseSvgImportMode,
948
762
  compositionFile,
763
+ config,
949
764
  contentDimensions,
950
765
  currentCompositionId,
951
766
  previewSize,
@@ -956,6 +771,7 @@ const Canvas = ({ canvasContent, size }) => {
956
771
  if (!canDropAssets ||
957
772
  compositionFile === null ||
958
773
  currentCompositionId === null ||
774
+ config === null ||
959
775
  event.clipboardData === null ||
960
776
  activeElement instanceof HTMLInputElement ||
961
777
  activeElement instanceof HTMLTextAreaElement ||
@@ -1023,10 +839,12 @@ const Canvas = ({ canvasContent, size }) => {
1023
839
  try {
1024
840
  await (0, import_assets_1.importAssets)({
1025
841
  files,
842
+ fps: config.fps,
1026
843
  compositionFile,
1027
844
  compositionId: currentCompositionId,
1028
845
  destinationDimensions: contentDimensions === 'none' ? null : contentDimensions,
1029
846
  dropPosition,
847
+ from: null,
1030
848
  svgImportMode,
1031
849
  });
1032
850
  }
@@ -1037,6 +855,7 @@ const Canvas = ({ canvasContent, size }) => {
1037
855
  canDropAssets,
1038
856
  chooseSvgImportMode,
1039
857
  compositionFile,
858
+ config,
1040
859
  contentDimensions,
1041
860
  currentCompositionId,
1042
861
  ]);
@@ -18,7 +18,6 @@ const ContextMenu_1 = require("./ContextMenu");
18
18
  const folder_menu_items_1 = require("./folder-menu-items");
19
19
  const layout_1 = require("./layout");
20
20
  const NotificationCenter_1 = require("./Notifications/NotificationCenter");
21
- const open_in_new_window_1 = require("./open-in-new-window");
22
21
  const actions_1 = require("./RenderQueue/actions");
23
22
  const SidebarRenderButton_1 = require("./SidebarRenderButton");
24
23
  const use_resolved_stack_1 = require("./Timeline/use-resolved-stack");
@@ -123,22 +122,15 @@ const CompositionSelectorItem = ({ item, level, currentComposition, tabIndex, se
123
122
  const resolvedLocation = (0, use_resolved_stack_1.useResolvedStack)(item.type === 'composition' ? item.composition.stack : item.folder.stack);
124
123
  const contextMenu = (0, react_1.useMemo)(() => {
125
124
  if (item.type === 'composition') {
126
- const compositionMenuItems = (0, composition_menu_items_1.getCompositionMenuItems)({
125
+ return (0, composition_menu_items_1.getCompositionContextMenuItems)({
127
126
  closeMenu: noop_1.noop,
128
127
  composition: item.composition,
129
128
  connectionStatus,
129
+ includeCompositionManagementItems: true,
130
130
  resolvedLocation,
131
131
  setSelectedModal,
132
132
  readOnlyStudio: window.remotion_isReadOnlyStudio,
133
133
  });
134
- return [
135
- (0, open_in_new_window_1.getOpenInNewWindowMenuItem)(`/${item.composition.id}`),
136
- {
137
- type: 'divider',
138
- id: 'open-in-new-window-divider',
139
- },
140
- ...compositionMenuItems,
141
- ];
142
134
  }
143
135
  return (0, folder_menu_items_1.getFolderMenuItems)({
144
136
  closeMenu: noop_1.noop,
@@ -136,6 +136,8 @@ const AlignmentControls = ({ track }) => {
136
136
  const label = undoLabels[direction];
137
137
  if (!propStatus || propStatus.status === 'static') {
138
138
  (0, save_sequence_prop_1.saveSequenceProps)({
139
+ addedKeyframes: null,
140
+ movedKeyframes: null,
139
141
  changes: [
140
142
  {
141
143
  fileName: nodePath.absolutePath,
@@ -4,9 +4,15 @@ exports.ConnectedCompositionsSection = exports.useConnectedCompositions = void 0
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const react_1 = require("react");
6
6
  const remotion_1 = require("remotion");
7
+ const client_id_1 = require("../../helpers/client-id");
7
8
  const get_connected_compositions_1 = require("../../helpers/get-connected-compositions");
9
+ const noop_1 = require("../../helpers/noop");
10
+ const modals_1 = require("../../state/modals");
11
+ const composition_menu_items_1 = require("../composition-menu-items");
8
12
  const CompositionOrStillIcon_1 = require("../CompositionOrStillIcon");
13
+ const ContextMenu_1 = require("../ContextMenu");
9
14
  const InitialCompositionLoader_1 = require("../InitialCompositionLoader");
15
+ const use_resolved_stack_1 = require("../Timeline/use-resolved-stack");
10
16
  const common_1 = require("./common");
11
17
  const compositionIconStyle = {
12
18
  height: 18,
@@ -17,6 +23,9 @@ const compositionListStyle = {
17
23
  flexDirection: 'column',
18
24
  padding: '6px 0',
19
25
  };
26
+ const compositionContextMenuStyle = {
27
+ width: '100%',
28
+ };
20
29
  const useConnectedCompositions = ({ track, }) => {
21
30
  const { compositions } = (0, react_1.useContext)(remotion_1.Internals.CompositionManager);
22
31
  return (0, react_1.useMemo)(() => (0, get_connected_compositions_1.getConnectedCompositions)({
@@ -26,7 +35,23 @@ const useConnectedCompositions = ({ track, }) => {
26
35
  };
27
36
  exports.useConnectedCompositions = useConnectedCompositions;
28
37
  const ConnectedCompositionsSection = ({ connectedCompositions }) => {
29
- const selectComposition = (0, InitialCompositionLoader_1.useSelectComposition)();
30
- return (jsx_runtime_1.jsx("div", { style: compositionListStyle, children: connectedCompositions.map((composition) => (jsx_runtime_1.jsx(common_1.InspectorInlineAction, { disabled: false, onClick: () => selectComposition(composition, true), renderIcon: (color) => (jsx_runtime_1.jsx(CompositionOrStillIcon_1.CompositionOrStillIcon, { color: color, composition: composition, style: compositionIconStyle })), children: composition.id }, composition.id))) }));
38
+ return (jsx_runtime_1.jsx("div", { style: compositionListStyle, children: connectedCompositions.map((composition) => (jsx_runtime_1.jsx(ConnectedCompositionRow, { composition: composition }, composition.id))) }));
31
39
  };
32
40
  exports.ConnectedCompositionsSection = ConnectedCompositionsSection;
41
+ const ConnectedCompositionRow = ({ composition }) => {
42
+ const selectComposition = (0, InitialCompositionLoader_1.useSelectComposition)();
43
+ const { setSelectedModal } = (0, react_1.useContext)(modals_1.ModalsContext);
44
+ const connectionStatus = (0, react_1.useContext)(client_id_1.StudioServerConnectionCtx)
45
+ .previewServerState.type;
46
+ const resolvedLocation = (0, use_resolved_stack_1.useResolvedStack)(composition.stack);
47
+ const contextMenuItems = (0, react_1.useMemo)(() => (0, composition_menu_items_1.getCompositionContextMenuItems)({
48
+ closeMenu: noop_1.noop,
49
+ composition,
50
+ connectionStatus,
51
+ includeCompositionManagementItems: false,
52
+ readOnlyStudio: window.remotion_isReadOnlyStudio,
53
+ resolvedLocation,
54
+ setSelectedModal,
55
+ }), [composition, connectionStatus, resolvedLocation, setSelectedModal]);
56
+ return (jsx_runtime_1.jsx(ContextMenu_1.ContextMenu, { values: contextMenuItems, onOpen: null, style: compositionContextMenuStyle, children: jsx_runtime_1.jsx(common_1.InspectorInlineAction, { disabled: false, onClick: () => selectComposition(composition, true), renderIcon: (color) => (jsx_runtime_1.jsx(CompositionOrStillIcon_1.CompositionOrStillIcon, { color: color, composition: composition, style: compositionIconStyle })), children: composition.id }) }));
57
+ };
@@ -5,21 +5,35 @@ const jsx_runtime_1 = require("react/jsx-runtime");
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
+ const interactivity_enabled_1 = require("../../helpers/interactivity-enabled");
9
+ const duplicate_1 = require("../../icons/duplicate");
8
10
  const scissors_1 = require("../../icons/scissors");
11
+ const snowflake_1 = require("../../icons/snowflake");
12
+ const trash_1 = require("../../icons/trash");
13
+ const ConfirmationDialog_1 = require("../ConfirmationDialog");
9
14
  const InspectorSequenceSection_1 = require("../InspectorSequenceSection");
10
15
  const is_menu_item_1 = require("../Menu/is-menu-item");
16
+ const delete_selected_timeline_item_1 = require("../Timeline/delete-selected-timeline-item");
17
+ const duplicate_selected_timeline_item_1 = require("../Timeline/duplicate-selected-timeline-item");
11
18
  const split_selected_timeline_item_1 = require("../Timeline/split-selected-timeline-item");
12
19
  const TimelineSelection_1 = require("../Timeline/TimelineSelection");
20
+ const use_sequence_freeze_frame_menu_item_1 = require("../Timeline/use-sequence-freeze-frame-menu-item");
13
21
  const AlignmentControls_1 = require("./AlignmentControls");
14
22
  const common_1 = require("./common");
15
23
  const ConnectedCompositionsSection_1 = require("./ConnectedCompositionsSection");
16
24
  const SequenceInspectorHeader_1 = require("./SequenceInspectorHeader");
17
25
  const styles_1 = require("./styles");
18
26
  const use_track_for_selection_1 = require("./use-track-for-selection");
19
- const splitIconStyle = {
27
+ const actionIconStyle = {
28
+ display: 'block',
20
29
  height: 16,
21
30
  width: 16,
22
31
  };
32
+ const largeActionIconStyle = {
33
+ ...actionIconStyle,
34
+ height: 20,
35
+ width: 20,
36
+ };
23
37
  const SplitSequenceAction = ({ selection, track }) => {
24
38
  const timelinePosition = remotion_1.Internals.Timeline.useTimelinePosition();
25
39
  const { propStatuses } = (0, react_1.useContext)(remotion_1.Internals.VisualModePropStatusesContext);
@@ -30,19 +44,60 @@ const SplitSequenceAction = ({ selection, track }) => {
30
44
  splitFrame: timelinePosition,
31
45
  propStatuses: sequencePropStatuses,
32
46
  }), [selection, sequencePropStatuses, timelinePosition, track.sequence]);
47
+ const canSplit = interactivity_enabled_1.studioInteractivityEnabled &&
48
+ sequencePropStatuses !== undefined &&
49
+ eligibility.canSplit;
33
50
  const onSplit = (0, react_1.useCallback)(() => {
34
- if (!eligibility.canSplit) {
51
+ if (!canSplit || !eligibility.canSplit) {
35
52
  return;
36
53
  }
37
54
  (0, split_selected_timeline_item_1.splitTimelineSequenceFromSource)({
38
55
  nodePathInfo: eligibility.nodePathInfo,
39
56
  splitFrame: timelinePosition,
40
57
  }).catch(() => undefined);
41
- }, [eligibility, timelinePosition]);
42
- if (!eligibility.canSplit) {
43
- return null;
44
- }
45
- return (jsx_runtime_1.jsx(common_1.InspectorActionSection, { children: jsx_runtime_1.jsx(common_1.InspectorInlineAction, { disabled: false, onClick: onSplit, renderIcon: (color) => (jsx_runtime_1.jsx(scissors_1.ScissorsIcon, { style: splitIconStyle, color: color })), children: "Split clip" }) }));
58
+ }, [canSplit, eligibility, timelinePosition]);
59
+ const disabledReason = !interactivity_enabled_1.studioInteractivityEnabled
60
+ ? 'Studio is read-only'
61
+ : sequencePropStatuses === undefined
62
+ ? 'Waiting for sequence prop status'
63
+ : eligibility.canSplit
64
+ ? undefined
65
+ : eligibility.reason;
66
+ return (jsx_runtime_1.jsx(common_1.InspectorInlineAction, { disabled: !canSplit, onClick: onSplit, title: disabledReason, renderIcon: (color) => (jsx_runtime_1.jsx(scissors_1.ScissorsIcon, { style: actionIconStyle, color: color })), children: "Split clip" }));
67
+ };
68
+ const SequenceSourceActions = ({ selection, track, validatedSource }) => {
69
+ const timelinePosition = remotion_1.Internals.Timeline.useTimelinePosition();
70
+ const { previewServerState } = (0, react_1.useContext)(client_id_1.StudioServerConnectionCtx);
71
+ const { propStatuses } = (0, react_1.useContext)(remotion_1.Internals.VisualModePropStatusesContext);
72
+ const { setPropStatuses } = (0, react_1.useContext)(remotion_1.Internals.VisualModeSettersContext);
73
+ const confirm = (0, ConfirmationDialog_1.useConfirmationDialog)();
74
+ const propStatusesForOverride = (0, react_1.useMemo)(() => remotion_1.Internals.getPropStatusesCtx(propStatuses, selection.nodePathInfo.sequenceSubscriptionKey), [propStatuses, selection.nodePathInfo.sequenceSubscriptionKey]);
75
+ const freezeFrameMenuItem = (0, use_sequence_freeze_frame_menu_item_1.useSequenceFreezeFrameMenuItem)({
76
+ clientId: previewServerState.type === 'connected' && interactivity_enabled_1.studioInteractivityEnabled
77
+ ? previewServerState.clientId
78
+ : null,
79
+ nodePath: selection.nodePathInfo.sequenceSubscriptionKey,
80
+ propStatusesForOverride,
81
+ sequence: track.sequence,
82
+ sequenceFrameOffset: track.sequenceFrameOffset,
83
+ setPropStatuses,
84
+ timelinePosition,
85
+ validatedSource,
86
+ });
87
+ const sourceActionsDisabled = previewServerState.type !== 'connected' || !interactivity_enabled_1.studioInteractivityEnabled;
88
+ const onDuplicate = (0, react_1.useCallback)(() => {
89
+ if (sourceActionsDisabled) {
90
+ return;
91
+ }
92
+ (0, duplicate_selected_timeline_item_1.duplicateSequencesFromSource)([selection.nodePathInfo], confirm).catch(() => undefined);
93
+ }, [confirm, selection.nodePathInfo, sourceActionsDisabled]);
94
+ const onDelete = (0, react_1.useCallback)(() => {
95
+ if (sourceActionsDisabled) {
96
+ return;
97
+ }
98
+ (0, delete_selected_timeline_item_1.deleteSequencesFromSource)([selection.nodePathInfo], confirm).catch(() => undefined);
99
+ }, [confirm, selection.nodePathInfo, sourceActionsDisabled]);
100
+ return (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [(freezeFrameMenuItem === null || freezeFrameMenuItem === void 0 ? void 0 : freezeFrameMenuItem.type) === 'item' ? (jsx_runtime_1.jsx(common_1.InspectorInlineAction, { disabled: Boolean(freezeFrameMenuItem.disabled), onClick: () => freezeFrameMenuItem.onClick(freezeFrameMenuItem.id, null), renderIcon: (color) => (jsx_runtime_1.jsx(snowflake_1.SnowflakeIcon, { style: largeActionIconStyle, color: color })), children: freezeFrameMenuItem.label })) : null, jsx_runtime_1.jsx(common_1.InspectorInlineAction, { disabled: sourceActionsDisabled, onClick: onDuplicate, renderIcon: (color) => (jsx_runtime_1.jsx(duplicate_1.DuplicateIcon, { style: largeActionIconStyle, color: color })), children: "Duplicate" }), jsx_runtime_1.jsx(common_1.InspectorInlineAction, { disabled: sourceActionsDisabled, onClick: onDelete, renderIcon: (color) => (jsx_runtime_1.jsx(trash_1.TrashIcon, { style: actionIconStyle, color: color })), children: "Delete" })] }));
46
101
  };
47
102
  const SequenceExpandedInspector = ({ track }) => {
48
103
  const { previewServerState } = (0, react_1.useContext)(client_id_1.StudioServerConnectionCtx);
@@ -88,7 +143,9 @@ const SequenceExpandedInspector = ({ track }) => {
88
143
  return (jsx_runtime_1.jsxs("div", { style: styles_1.selectedContainer, className: is_menu_item_1.VERTICAL_SCROLLBAR_CLASSNAME, onPointerDown: selectSequenceOnInspectorPointerDown, children: [
89
144
  jsx_runtime_1.jsx(SequenceInspectorHeader_1.SequenceInspectorHeader, { sourceLocation: sourceLocation, track: track }), connectedCompositions.length > 0 ? (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [
90
145
  jsx_runtime_1.jsx(common_1.InspectorSectionDivider, {}), jsx_runtime_1.jsx(ConnectedCompositionsSection_1.ConnectedCompositionsSection, { connectedCompositions: connectedCompositions })
91
- ] })) : null, jsx_runtime_1.jsx(InspectorSequenceSection_1.InspectorSequenceSection, { sequence: track.sequence, validatedLocation: validatedLocation, nodePathInfo: track.nodePathInfo, keyframeDisplayOffset: track.keyframeDisplayOffset, renderTransformControls: () => jsx_runtime_1.jsx(AlignmentControls_1.AlignmentControls, { track: track }) }), jsx_runtime_1.jsx(SplitSequenceAction, { selection: sequenceSelection, track: track })
146
+ ] })) : null, jsx_runtime_1.jsx(InspectorSequenceSection_1.InspectorSequenceSection, { sequence: track.sequence, validatedLocation: validatedLocation, nodePathInfo: track.nodePathInfo, keyframeDisplayOffset: track.keyframeDisplayOffset, renderTransformControls: () => jsx_runtime_1.jsx(AlignmentControls_1.AlignmentControls, { track: track }) }), jsx_runtime_1.jsxs(common_1.InspectorActionSection, { children: [
147
+ jsx_runtime_1.jsx(SplitSequenceAction, { selection: sequenceSelection, track: track }), jsx_runtime_1.jsx(SequenceSourceActions, { selection: sequenceSelection, track: track, validatedSource: validatedLocation.source })
148
+ ] })
92
149
  ] }));
93
150
  };
94
151
  const SequenceSelectionInspector = ({ selection }) => {
@@ -57,6 +57,7 @@ const useCompositionActions = () => {
57
57
  const result = await (0, call_api_1.callApi)('/api/insert-jsx-element', {
58
58
  compositionFile,
59
59
  compositionId: currentCompositionId,
60
+ from: null,
60
61
  element: {
61
62
  type: 'solid',
62
63
  width: videoConfig.width,
@@ -80,7 +81,8 @@ const useCompositionActions = () => {
80
81
  const insertAsset = (0, react_1.useCallback)(async () => {
81
82
  if (!canInsertAsset ||
82
83
  currentCompositionId === null ||
83
- compositionFile === null) {
84
+ compositionFile === null ||
85
+ videoConfig === null) {
84
86
  return;
85
87
  }
86
88
  const files = await (0, import_assets_1.pickFilesToImport)();
@@ -91,17 +93,19 @@ const useCompositionActions = () => {
91
93
  try {
92
94
  await (0, import_assets_1.importAssets)({
93
95
  files,
96
+ fps: videoConfig.fps,
94
97
  compositionFile,
95
98
  compositionId: currentCompositionId,
96
99
  destinationDimensions: null,
97
100
  dropPosition: null,
101
+ from: null,
98
102
  svgImportMode: 'image',
99
103
  });
100
104
  }
101
105
  finally {
102
106
  setIsAddingAsset(false);
103
107
  }
104
- }, [canInsertAsset, compositionFile, currentCompositionId]);
108
+ }, [canInsertAsset, compositionFile, currentCompositionId, videoConfig]);
105
109
  return {
106
110
  canInsertAsset,
107
111
  canInsertSolid,
@@ -8,7 +8,7 @@ export declare const CodemodFooter: React.FC<{
8
8
  readonly valid: boolean;
9
9
  readonly codemod: RecastCodemod;
10
10
  readonly stack: string | null;
11
- readonly loadingNotification: React.ReactNode;
11
+ readonly loadingNotification: React.ReactNode | null;
12
12
  readonly successNotification: React.ReactNode;
13
13
  readonly errorNotification: string;
14
14
  readonly genericSubmitLabel: string;
@@ -34,21 +34,40 @@ const CodemodFooter = ({ codemod, stack, valid, loadingNotification, successNoti
34
34
  const trigger = (0, react_1.useCallback)(() => {
35
35
  setSubmitting(true);
36
36
  setSelectedModal(null);
37
- const notification = (0, NotificationCenter_1.showNotification)(loadingNotification, null);
37
+ const notification = loadingNotification === null
38
+ ? null
39
+ : (0, NotificationCenter_1.showNotification)(loadingNotification, null);
38
40
  applyCodemod({
39
41
  symbolicatedStack,
40
42
  signal: new AbortController().signal,
41
43
  })
42
44
  .then((result) => {
43
45
  if (!result.success) {
44
- notification.replaceContent(`${errorNotification}: ${result.reason}`, 2000);
46
+ const message = `${errorNotification}: ${result.reason}`;
47
+ if (notification) {
48
+ notification.replaceContent(message, 2000);
49
+ }
50
+ else {
51
+ (0, NotificationCenter_1.showNotification)(message, 2000);
52
+ }
45
53
  return;
46
54
  }
47
- notification.replaceContent(successNotification, 2000);
55
+ if (notification) {
56
+ notification.replaceContent(successNotification, 2000);
57
+ }
58
+ else {
59
+ (0, NotificationCenter_1.showNotification)(successNotification, 2000);
60
+ }
48
61
  onSuccess === null || onSuccess === void 0 ? void 0 : onSuccess();
49
62
  })
50
63
  .catch((err) => {
51
- notification.replaceContent(`${errorNotification}: ${err.message}`, 2000);
64
+ const message = `${errorNotification}: ${err.message}`;
65
+ if (notification) {
66
+ notification.replaceContent(message, 2000);
67
+ }
68
+ else {
69
+ (0, NotificationCenter_1.showNotification)(message, 2000);
70
+ }
52
71
  });
53
72
  }, [
54
73
  applyCodemod,