@remotion/studio 4.0.491 → 4.0.493

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 (97) hide show
  1. package/dist/ResolveCompositionConfigInStudio.js +16 -6
  2. package/dist/components/AssetSelectorItem.js +7 -4
  3. package/dist/components/Canvas.js +1 -0
  4. package/dist/components/CompositionOrStillIcon.d.ts +7 -0
  5. package/dist/components/CompositionOrStillIcon.js +11 -0
  6. package/dist/components/CompositionSelector.js +14 -2
  7. package/dist/components/CompositionSelectorItem.js +34 -6
  8. package/dist/components/CurrentAsset.d.ts +6 -0
  9. package/dist/components/CurrentAsset.js +14 -8
  10. package/dist/components/CurrentComposition.d.ts +1 -1
  11. package/dist/components/CurrentComposition.js +3 -4
  12. package/dist/components/InlineEditableTitle.d.ts +1 -0
  13. package/dist/components/InlineEditableTitle.js +12 -7
  14. package/dist/components/InspectorInfoHeader.d.ts +2 -0
  15. package/dist/components/InspectorInfoHeader.js +12 -4
  16. package/dist/components/InspectorPanel/CompositionDimensions.d.ts +6 -0
  17. package/dist/components/InspectorPanel/CompositionDimensions.js +173 -0
  18. package/dist/components/InspectorPanel/ConnectedCompositionsSection.d.ts +9 -0
  19. package/dist/components/InspectorPanel/ConnectedCompositionsSection.js +32 -0
  20. package/dist/components/InspectorPanel/DefaultInspector.js +6 -3
  21. package/dist/components/InspectorPanel/EasingInspector.js +3 -3
  22. package/dist/components/InspectorPanel/KeyframeInspector.js +6 -4
  23. package/dist/components/InspectorPanel/KeyframeSettings.js +1 -1
  24. package/dist/components/InspectorPanel/SequenceInspectorHeader.d.ts +1 -1
  25. package/dist/components/InspectorPanel/SequenceInspectorHeader.js +9 -5
  26. package/dist/components/InspectorPanel/SequenceSelectionInspector.js +5 -1
  27. package/dist/components/InspectorPanel/common.d.ts +2 -1
  28. package/dist/components/InspectorPanel/common.js +11 -7
  29. package/dist/components/InspectorPanel/optimistic-composition-metadata.d.ts +22 -0
  30. package/dist/components/InspectorPanel/optimistic-composition-metadata.js +41 -0
  31. package/dist/components/InspectorPanel/styles.d.ts +2 -0
  32. package/dist/components/InspectorPanel/styles.js +7 -2
  33. package/dist/components/InspectorSequenceSection.js +58 -7
  34. package/dist/components/NewComposition/NewComposition.js +11 -4
  35. package/dist/components/NewComposition/get-new-composition-defaults.d.ts +4 -0
  36. package/dist/components/NewComposition/get-new-composition-defaults.js +13 -0
  37. package/dist/components/SelectedOutlineElement.js +21 -2
  38. package/dist/components/SelectedOutlineOverlay.d.ts +1 -1
  39. package/dist/components/SelectedOutlineOverlay.js +4 -3
  40. package/dist/components/Timeline/Timeline.js +8 -1
  41. package/dist/components/Timeline/TimelineAssetField.d.ts +14 -0
  42. package/dist/components/Timeline/TimelineAssetField.js +125 -0
  43. package/dist/components/Timeline/TimelineClipboardKeybindings.js +133 -1
  44. package/dist/components/Timeline/TimelineExpandedSection.js +1 -0
  45. package/dist/components/Timeline/TimelineFieldLabel.js +4 -2
  46. package/dist/components/Timeline/TimelineKeyframeControls.js +1 -0
  47. package/dist/components/Timeline/TimelineList.js +2 -1
  48. package/dist/components/Timeline/TimelinePrimitiveFieldValue.js +5 -3
  49. package/dist/components/Timeline/TimelineRowChrome.js +8 -6
  50. package/dist/components/Timeline/TimelineRowLayoutContext.d.ts +7 -0
  51. package/dist/components/Timeline/TimelineRowLayoutContext.js +13 -0
  52. package/dist/components/Timeline/TimelineSelection.js +20 -5
  53. package/dist/components/Timeline/TimelineSequenceItem.d.ts +2 -1
  54. package/dist/components/Timeline/TimelineSequenceItem.js +32 -8
  55. package/dist/components/Timeline/TimelineSequenceName.js +4 -0
  56. package/dist/components/Timeline/get-sequence-context-menu-items.js +3 -3
  57. package/dist/components/Timeline/keyframe-clipboard.d.ts +34 -0
  58. package/dist/components/Timeline/keyframe-clipboard.js +278 -0
  59. package/dist/components/Timeline/sequence-props-subscription-store.js +5 -1
  60. package/dist/components/Timeline/timeline-asset-link.d.ts +6 -0
  61. package/dist/components/Timeline/timeline-asset-link.js +27 -1
  62. package/dist/components/Timeline/timeline-field-display-utils.js +3 -1
  63. package/dist/components/Timeline/timeline-field-row-layout.d.ts +1 -1
  64. package/dist/components/Timeline/timeline-field-row-layout.js +2 -2
  65. package/dist/components/Timeline/timeline-row-layout.d.ts +3 -2
  66. package/dist/components/Timeline/timeline-row-layout.js +6 -5
  67. package/dist/components/Timeline/update-selected-easing.d.ts +1 -1
  68. package/dist/components/Timeline/update-selected-easing.js +4 -5
  69. package/dist/components/Timeline/use-expanded-track-keyframe-rows.js +4 -4
  70. package/dist/components/Timeline/use-timeline-expanded-tree.d.ts +2 -1
  71. package/dist/components/Timeline/use-timeline-expanded-tree.js +3 -1
  72. package/dist/components/Timeline/use-timeline-height.js +1 -0
  73. package/dist/components/import-assets.d.ts +10 -2
  74. package/dist/components/import-assets.js +20 -6
  75. package/dist/components/root-composition-menu-items.d.ts +8 -0
  76. package/dist/components/root-composition-menu-items.js +45 -0
  77. package/dist/components/selected-outline-measurement.d.ts +2 -5
  78. package/dist/components/selected-outline-measurement.js +3 -4
  79. package/dist/esm/{chunk-9wh9k3jj.js → chunk-mndqr3zx.js} +7439 -6121
  80. package/dist/esm/internals.mjs +7439 -6121
  81. package/dist/esm/previewEntry.mjs +7371 -6057
  82. package/dist/esm/renderEntry.mjs +1 -1
  83. package/dist/helpers/calculate-timeline.d.ts +2 -1
  84. package/dist/helpers/calculate-timeline.js +36 -5
  85. package/dist/helpers/get-connected-compositions.d.ts +6 -0
  86. package/dist/helpers/get-connected-compositions.js +11 -0
  87. package/dist/helpers/get-file-manager-name.d.ts +1 -0
  88. package/dist/helpers/get-file-manager-name.js +13 -0
  89. package/dist/helpers/get-sequence-double-click-action.d.ts +6 -0
  90. package/dist/helpers/get-sequence-double-click-action.js +13 -0
  91. package/dist/helpers/get-timeline-sequence-sort-key.d.ts +2 -1
  92. package/dist/helpers/timeline-layout.d.ts +2 -1
  93. package/dist/helpers/timeline-layout.js +5 -1
  94. package/dist/helpers/url-state.d.ts +1 -0
  95. package/dist/helpers/url-state.js +8 -6
  96. package/dist/helpers/use-menu-structure.js +4 -2
  97. package/package.json +11 -11
@@ -41,11 +41,16 @@ const colors_1 = require("../helpers/colors");
41
41
  const timeline_layout_1 = require("../helpers/timeline-layout");
42
42
  const plus_1 = require("../icons/plus");
43
43
  const modals_1 = require("../state/modals");
44
+ const CurrentAsset_1 = require("./CurrentAsset");
44
45
  const InlineAction_1 = require("./InlineAction");
45
46
  const styles_1 = require("./InspectorPanel/styles");
47
+ const InspectorPanelLayout_1 = require("./InspectorPanelLayout");
48
+ const timeline_asset_link_1 = require("./Timeline/timeline-asset-link");
46
49
  const TimelineExpandedRow_1 = require("./Timeline/TimelineExpandedRow");
50
+ const TimelineRowLayoutContext_1 = require("./Timeline/TimelineRowLayoutContext");
47
51
  const TimelineSelection_1 = require("./Timeline/TimelineSelection");
48
52
  const use_timeline_expanded_tree_1 = require("./Timeline/use-timeline-expanded-tree");
53
+ const use_select_asset_1 = require("./use-select-asset");
49
54
  const container = {
50
55
  color: colors_1.WHITE,
51
56
  display: 'flex',
@@ -72,6 +77,38 @@ const plusIcon = {
72
77
  width: 15,
73
78
  height: 15,
74
79
  };
80
+ const remoteSourceLabel = {
81
+ color: colors_1.LIGHT_TEXT,
82
+ display: 'flex',
83
+ fontFamily: 'Arial, Helvetica, sans-serif',
84
+ fontSize: 12,
85
+ lineHeight: '18px',
86
+ minWidth: 0,
87
+ overflow: 'hidden',
88
+ padding: `6px ${InspectorPanelLayout_1.INSPECTOR_PANEL_HORIZONTAL_PADDING}px`,
89
+ whiteSpace: 'nowrap',
90
+ };
91
+ const remoteSourceLeading = {
92
+ color: colors_1.LIGHT_TEXT,
93
+ fontFamily: 'Arial, Helvetica, sans-serif',
94
+ fontSize: 12,
95
+ lineHeight: '18px',
96
+ minWidth: 0,
97
+ overflow: 'hidden',
98
+ textOverflow: 'ellipsis',
99
+ whiteSpace: 'nowrap',
100
+ };
101
+ const remoteSourceTrailing = {
102
+ color: colors_1.LIGHT_TEXT,
103
+ flexShrink: 0,
104
+ fontFamily: 'Arial, Helvetica, sans-serif',
105
+ fontSize: 12,
106
+ lineHeight: '18px',
107
+ maxWidth: '55%',
108
+ overflow: 'hidden',
109
+ textOverflow: 'ellipsis',
110
+ whiteSpace: 'nowrap',
111
+ };
75
112
  const isEffectsRoot = (node) => {
76
113
  if (node.kind !== 'group' || node.effectInfo !== null) {
77
114
  return false;
@@ -138,10 +175,22 @@ const InspectorSequenceSection = ({ sequence, validatedLocation, nodePathInfo, k
138
175
  sequence,
139
176
  nodePathInfo,
140
177
  includeTextContent: true,
178
+ includeSourceControls: true,
141
179
  });
142
180
  const [collapsedKeys, setCollapsedKeys] = (0, react_1.useState)(loadInspectorCollapsedKeys);
143
181
  const { previewServerState } = (0, react_1.useContext)(client_id_1.StudioServerConnectionCtx);
144
182
  const { setSelectedModal } = (0, react_1.useContext)(modals_1.ModalsContext);
183
+ const selectAsset = (0, use_select_asset_1.useSelectAsset)();
184
+ const mediaSrc = (0, timeline_asset_link_1.getTimelineAssetSrcFromSchema)(sequence.controls);
185
+ const assetLinkInfo = (0, react_1.useMemo)(() => (mediaSrc ? (0, timeline_asset_link_1.getTimelineAssetLinkInfo)(mediaSrc) : null), [mediaSrc]);
186
+ const localAsset = (assetLinkInfo === null || assetLinkInfo === void 0 ? void 0 : assetLinkInfo.kind) === 'local' ? assetLinkInfo : null;
187
+ const remoteAsset = (assetLinkInfo === null || assetLinkInfo === void 0 ? void 0 : assetLinkInfo.kind) === 'remote' ? assetLinkInfo : null;
188
+ const remoteSourceParts = (0, react_1.useMemo)(() => remoteAsset ? (0, timeline_asset_link_1.splitRemoteSourceForMiddleEllipsis)(remoteAsset.href) : null, [remoteAsset]);
189
+ const jumpToAsset = (0, react_1.useCallback)(() => {
190
+ if (localAsset) {
191
+ (0, timeline_asset_link_1.openTimelineAssetLink)(localAsset, selectAsset);
192
+ }
193
+ }, [localAsset, selectAsset]);
145
194
  const getIsExpanded = (0, react_1.useCallback)((candidate) => {
146
195
  return !collapsedKeys.has(getInspectorExpansionKey(candidate));
147
196
  }, [collapsedKeys]);
@@ -183,7 +232,10 @@ const InspectorSequenceSection = ({ sequence, validatedLocation, nodePathInfo, k
183
232
  }),
184
233
  };
185
234
  }, [getIsExpanded, tree]);
186
- const controlSelectableItems = (0, react_1.useMemo)(() => (0, exports.getInspectorSelectableItems)(controlRows), [controlRows]);
235
+ const controlSelectableItems = (0, react_1.useMemo)(() => (0, exports.getInspectorSelectableItems)(controlRows.filter(({ node }) => {
236
+ var _a;
237
+ return node.kind !== 'field' || ((_a = node.field) === null || _a === void 0 ? void 0 : _a.key) !== 'src';
238
+ })), [controlRows]);
187
239
  const effectSelectableItems = (0, react_1.useMemo)(() => (0, exports.getInspectorSelectableItems)(effectRows), [effectRows]);
188
240
  const controlGroups = (0, react_1.useMemo)(() => getInspectorControlGroups(controlRows), [controlRows]);
189
241
  const { schema } = sequence.controls;
@@ -214,14 +266,13 @@ const InspectorSequenceSection = ({ sequence, validatedLocation, nodePathInfo, k
214
266
  jsx_runtime_1.jsx("div", { style: effectsHeaderTitle, children: "Effects" }), jsx_runtime_1.jsx(InlineAction_1.InlineAction, { disabled: !canAddEffect, onClick: onAddEffect, title: canAddEffect ? 'Add effect' : undefined, renderAction: (color) => jsx_runtime_1.jsx(plus_1.Plus, { color: color, style: plusIcon }) })] }));
215
267
  };
216
268
  const renderRow = ({ node, depth }) => {
217
- return (jsx_runtime_1.jsx(TimelineExpandedRow_1.TimelineExpandedRow, { node: node, depth: depth, nestedDepth: 0, rowDepthBase: 0, getIsExpanded: getIsExpanded, toggleTrack: toggleTrack, validatedLocation: validatedLocation, nodePath: nodePathInfo.sequenceSubscriptionKey, schema: schema, keyframeDisplayOffset: keyframeDisplayOffset, keyframeControlsMode: "inspector" }, JSON.stringify(node.nodePathInfo)));
269
+ return (jsx_runtime_1.jsx(TimelineRowLayoutContext_1.TimelineRowLayoutContext.Provider, { value: TimelineRowLayoutContext_1.INSPECTOR_TIMELINE_ROW_LAYOUT, children: jsx_runtime_1.jsx(TimelineExpandedRow_1.TimelineExpandedRow, { node: node, depth: depth, nestedDepth: 0, rowDepthBase: 0, getIsExpanded: getIsExpanded, toggleTrack: toggleTrack, validatedLocation: validatedLocation, nodePath: nodePathInfo.sequenceSubscriptionKey, schema: schema, keyframeDisplayOffset: keyframeDisplayOffset, keyframeControlsMode: "inspector" }) }, JSON.stringify(node.nodePathInfo)));
218
270
  };
219
271
  if (controlRows.length === 0 && !showEffectsSection) {
220
- return (jsx_runtime_1.jsxs("div", { style: container, children: [
221
- jsx_runtime_1.jsx("div", { style: styles_1.sequenceHeaderDivider }), jsx_runtime_1.jsx("div", { style: emptyState, children: "No schema" })
222
- ] }));
272
+ return (jsx_runtime_1.jsx("div", { style: container, children: jsx_runtime_1.jsx("div", { style: emptyState, children: "No schema" }) }));
223
273
  }
224
- return (jsx_runtime_1.jsxs("div", { style: container, children: [
225
- jsx_runtime_1.jsx("div", { style: styles_1.sequenceHeaderDivider }), controlRows.length > 0 ? (jsx_runtime_1.jsx(TimelineSelection_1.TimelineSelectionOrderProvider, { items: controlSelectableItems, children: controlGroups.map((group, i) => (jsx_runtime_1.jsxs(react_1.default.Fragment, { children: [i === 0 ? null : jsx_runtime_1.jsx("div", { style: controlsEffectsDivider }), renderSectionHeader(group.label), group.id === 'transforms' ? renderTransformControls() : null, group.rows.map(renderRow)] }, group.id))) })) : null, showEffectsSection ? (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [showControlsEffectsDivider ? (jsx_runtime_1.jsx("div", { style: controlsEffectsDivider })) : null, renderEffectsHeader(), effectRows.length === 0 ? (jsx_runtime_1.jsx("div", { style: emptyState, children: "None" })) : (jsx_runtime_1.jsx(TimelineSelection_1.TimelineSelectionOrderProvider, { items: effectSelectableItems, children: effectRows.map(renderRow) }))] })) : null] }));
274
+ return (jsx_runtime_1.jsxs("div", { style: container, children: [controlRows.length > 0 ? (jsx_runtime_1.jsx(TimelineSelection_1.TimelineSelectionOrderProvider, { items: controlSelectableItems, children: controlGroups.map((group, i) => (jsx_runtime_1.jsxs(react_1.default.Fragment, { children: [i === 0 ? null : jsx_runtime_1.jsx("div", { style: controlsEffectsDivider }), renderSectionHeader(group.label), group.id === 'source' && localAsset ? (jsx_runtime_1.jsx(CurrentAsset_1.AssetInfo, { assetName: localAsset.assetPath, contentSized: true, onAssetClick: jumpToAsset, readOnlyStudio: true })) : null, group.id === 'source' && remoteAsset && remoteSourceParts ? (jsx_runtime_1.jsxs("div", { style: remoteSourceLabel, title: remoteAsset.href, children: [
275
+ jsx_runtime_1.jsx("span", { style: remoteSourceLeading, children: remoteSourceParts.leading }), jsx_runtime_1.jsx("span", { style: remoteSourceTrailing, children: remoteSourceParts.trailing })
276
+ ] })) : null, group.id === 'transforms' ? renderTransformControls() : null, group.id === 'source' ? null : group.rows.map(renderRow)] }, group.id))) })) : null, showEffectsSection ? (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [showControlsEffectsDivider ? (jsx_runtime_1.jsx("div", { style: controlsEffectsDivider })) : null, renderEffectsHeader(), effectRows.length > 0 ? (jsx_runtime_1.jsx(TimelineSelection_1.TimelineSelectionOrderProvider, { items: effectSelectableItems, children: effectRows.map(renderRow) })) : null] })) : null] }));
226
277
  };
227
278
  exports.InspectorSequenceSection = InspectorSequenceSection;
@@ -11,6 +11,7 @@ const ModalHeader_1 = require("../ModalHeader");
11
11
  const layout_2 = require("../RenderModal/layout");
12
12
  const CodemodFooter_1 = require("./CodemodFooter");
13
13
  const DismissableModal_1 = require("./DismissableModal");
14
+ const get_new_composition_defaults_1 = require("./get-new-composition-defaults");
14
15
  const InputAndValidationContainer_1 = require("./InputAndValidationContainer");
15
16
  const InputDragger_1 = require("./InputDragger");
16
17
  const NewCompDuration_1 = require("./NewCompDuration");
@@ -28,13 +29,19 @@ const folderPathStyle = {
28
29
  };
29
30
  const NewCompositionLoaded = ({ folderName, parentName, stack }) => {
30
31
  const { compositions } = (0, react_1.useContext)(remotion_1.Internals.CompositionManager);
32
+ const resolvedComposition = remotion_1.Internals.useResolvedVideoConfig(null);
33
+ const initialComposition = (resolvedComposition === null || resolvedComposition === void 0 ? void 0 : resolvedComposition.type) === 'success' ||
34
+ (resolvedComposition === null || resolvedComposition === void 0 ? void 0 : resolvedComposition.type) === 'success-and-refreshing'
35
+ ? resolvedComposition.result
36
+ : null;
37
+ const initialDimensions = (0, get_new_composition_defaults_1.getNewCompositionDefaults)(initialComposition);
31
38
  const [newId, setName] = (0, react_1.useState)(() => (0, use_create_composition_1.getUniqueCompositionName)(compositions));
32
- const [selectedFrameRate, setFrameRate] = (0, react_1.useState)(30);
39
+ const [selectedFrameRate, setFrameRate] = (0, react_1.useState)(initialDimensions.fps);
33
40
  const [size, setSize] = (0, react_1.useState)(() => ({
34
- width: 1920,
35
- height: 1080,
41
+ width: initialDimensions.width,
42
+ height: initialDimensions.height,
36
43
  }));
37
- const [durationInFrames, setDurationInFrames] = (0, react_1.useState)(150);
44
+ const [durationInFrames, setDurationInFrames] = (0, react_1.useState)(initialDimensions.durationInFrames);
38
45
  const onWidthChanged = (0, react_1.useCallback)((newValue) => {
39
46
  setSize((s) => {
40
47
  return {
@@ -0,0 +1,4 @@
1
+ import type { VideoConfig } from 'remotion';
2
+ type CompositionDimensions = Pick<VideoConfig, 'width' | 'height' | 'fps' | 'durationInFrames'>;
3
+ export declare const getNewCompositionDefaults: (composition: CompositionDimensions | null) => CompositionDimensions;
4
+ export {};
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getNewCompositionDefaults = void 0;
4
+ const defaultCompositionDimensions = {
5
+ width: 1920,
6
+ height: 1080,
7
+ fps: 30,
8
+ durationInFrames: 150,
9
+ };
10
+ const getNewCompositionDefaults = (composition) => {
11
+ return composition !== null && composition !== void 0 ? composition : defaultCompositionDimensions;
12
+ };
13
+ exports.getNewCompositionDefaults = getNewCompositionDefaults;
@@ -41,6 +41,8 @@ const no_react_1 = require("remotion/no-react");
41
41
  const client_id_1 = require("../helpers/client-id");
42
42
  const colors_1 = require("../helpers/colors");
43
43
  const format_file_location_1 = require("../helpers/format-file-location");
44
+ const get_connected_compositions_1 = require("../helpers/get-connected-compositions");
45
+ const get_sequence_double_click_action_1 = require("../helpers/get-sequence-double-click-action");
44
46
  const open_in_editor_1 = require("../helpers/open-in-editor");
45
47
  const editor_snapping_1 = require("../state/editor-snapping");
46
48
  const modals_1 = require("../state/modals");
@@ -49,6 +51,7 @@ const ConfirmationDialog_1 = require("./ConfirmationDialog");
49
51
  const ContextMenu_1 = require("./ContextMenu");
50
52
  const effect_drag_and_drop_1 = require("./effect-drag-and-drop");
51
53
  const ForceSpecificCursor_1 = require("./ForceSpecificCursor");
54
+ const InitialCompositionLoader_1 = require("./InitialCompositionLoader");
52
55
  const NotificationCenter_1 = require("./Notifications/NotificationCenter");
53
56
  const selected_outline_drag_1 = require("./selected-outline-drag");
54
57
  const selected_outline_measurement_1 = require("./selected-outline-measurement");
@@ -981,6 +984,8 @@ const SelectedOutlineElement = ({ allDragTargets, allDragOutlines, allRotationDr
981
984
  const updateResolvedStackTrace = (0, react_1.useContext)(remotion_1.Internals.SequenceStackTracesUpdateContext);
982
985
  const confirm = (0, ConfirmationDialog_1.useConfirmationDialog)();
983
986
  const selectAsset = (0, use_select_asset_1.useSelectAsset)();
987
+ const selectComposition = (0, InitialCompositionLoader_1.useSelectComposition)();
988
+ const { compositions } = (0, react_1.useContext)(remotion_1.Internals.CompositionManager);
984
989
  const { setSelectedModal } = (0, react_1.useContext)(modals_1.ModalsContext);
985
990
  const resolveOriginalLocation = react_1.default.useCallback(async (resolveTarget) => {
986
991
  const stack = resolveTarget.sequence.getStack();
@@ -998,14 +1003,23 @@ const SelectedOutlineElement = ({ allDragTargets, allDragOutlines, allRotationDr
998
1003
  return originalLocation;
999
1004
  }, [updateResolvedStackTrace]);
1000
1005
  const onDoubleClickTarget = react_1.default.useCallback((doubleClickTarget, button) => {
1001
- const action = (0, selected_outline_measurement_1.getOutlineDoubleClickAction)({
1006
+ const connectedCompositions = (0, get_connected_compositions_1.getConnectedCompositions)({
1007
+ compositions,
1008
+ singleChildComponent: doubleClickTarget.sequence.singleChildComponent,
1009
+ });
1010
+ const action = (0, get_sequence_double_click_action_1.getSequenceDoubleClickAction)({
1002
1011
  button,
1003
1012
  canOpenInEditor: previewServerState.type === 'connected' &&
1004
1013
  Boolean(window.remotion_editorName),
1014
+ numberOfConnectedCompositions: connectedCompositions.length,
1005
1015
  });
1006
1016
  if (action === null) {
1007
1017
  return false;
1008
1018
  }
1019
+ if (action === 'open-connected-composition') {
1020
+ selectComposition(connectedCompositions[0], true);
1021
+ return true;
1022
+ }
1009
1023
  const openTargetInEditor = async () => {
1010
1024
  const originalLocation = await resolveOriginalLocation(doubleClickTarget);
1011
1025
  if (originalLocation === null) {
@@ -1017,7 +1031,12 @@ const SelectedOutlineElement = ({ allDragTargets, allDragOutlines, allRotationDr
1017
1031
  (0, NotificationCenter_1.showNotification)(err.message, 2000);
1018
1032
  });
1019
1033
  return true;
1020
- }, [previewServerState.type, resolveOriginalLocation]);
1034
+ }, [
1035
+ compositions,
1036
+ previewServerState.type,
1037
+ resolveOriginalLocation,
1038
+ selectComposition,
1039
+ ]);
1021
1040
  const onContextMenuOpen = react_1.default.useCallback(async () => {
1022
1041
  if (target === undefined || previewServerState.type !== 'connected') {
1023
1042
  return false;
@@ -2,7 +2,7 @@ import React from 'react';
2
2
  import { type SelectedOutline } from './selected-outline-geometry';
3
3
  import { type SelectedOutlineTarget } from './selected-outline-types';
4
4
  export { applySelectedOutlineDragAxisLock, applySelectedOutlineTransformOriginAxisLock, compensateTranslateForTransformOrigin, getSelectedOutlineActiveSchema, getSelectedOutlineDragChanges, getSelectedOutlineDragValues, getSelectedOutlineKeyboardNudgeDelta, getSelectedOutlineKeyboardNudgeDeltas, getSelectedOutlineRotationDragChanges, getSelectedOutlineRotationDragStates, getSelectedOutlineRotationDragValues, getSelectedOutlineScaleDragChanges, getSelectedOutlineScaleDragStates, getSelectedOutlineScaleDragValues, getSelectedOutlineScaleEdgeInfo, getSelectedOutlineTransformOriginLockedAxis, isSelectedOutlineDragPastThreshold, selectedOutlineTransformOriginSnapThresholdPx, selectedOutlineUvSnapThresholdPx, snapSelectedOutlineRotationDeltaDegrees, snapSelectedOutlineTransformOriginUv, snapSelectedOutlineUv, } from './selected-outline-drag';
5
- export { getOutlineDoubleClickAction, getOutlineSelectionInteraction, getSelectedEffectFieldsBySequenceKey, getSelectedOutlineRotationCornerInfo, getSelectedOutlineRotationDeltaDegrees, getSelectedOutlineRotationPivot, getSelectedSequenceKeys, getSequencesWithSelectableOutlines, getTransformedSvgViewportPoints, } from './selected-outline-measurement';
5
+ export { getOutlineSelectionInteraction, getSelectedEffectFieldsBySequenceKey, getSelectedOutlineRotationCornerInfo, getSelectedOutlineRotationDeltaDegrees, getSelectedOutlineRotationPivot, getSelectedSequenceKeys, getSequencesWithSelectableOutlines, getTransformedSvgViewportPoints, } from './selected-outline-measurement';
6
6
  export { selectedOutlineDragThresholdPx } from './selected-outline-types';
7
7
  export type { SelectedOutlineDragState, SelectedOutlineRotationDragState, SelectedOutlineScaleDragState, } from './selected-outline-types';
8
8
  type OutlineSequenceParent = {
@@ -33,7 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.SelectedOutlineOverlay = exports.orderOutlinesForRendering = exports.selectedOutlineDragThresholdPx = exports.getTransformedSvgViewportPoints = exports.getSequencesWithSelectableOutlines = exports.getSelectedSequenceKeys = exports.getSelectedOutlineRotationPivot = exports.getSelectedOutlineRotationDeltaDegrees = exports.getSelectedOutlineRotationCornerInfo = exports.getSelectedEffectFieldsBySequenceKey = exports.getOutlineSelectionInteraction = exports.getOutlineDoubleClickAction = exports.snapSelectedOutlineUv = exports.snapSelectedOutlineTransformOriginUv = exports.snapSelectedOutlineRotationDeltaDegrees = exports.selectedOutlineUvSnapThresholdPx = exports.selectedOutlineTransformOriginSnapThresholdPx = exports.isSelectedOutlineDragPastThreshold = exports.getSelectedOutlineTransformOriginLockedAxis = exports.getSelectedOutlineScaleEdgeInfo = exports.getSelectedOutlineScaleDragValues = exports.getSelectedOutlineScaleDragStates = exports.getSelectedOutlineScaleDragChanges = exports.getSelectedOutlineRotationDragValues = exports.getSelectedOutlineRotationDragStates = exports.getSelectedOutlineRotationDragChanges = exports.getSelectedOutlineKeyboardNudgeDeltas = exports.getSelectedOutlineKeyboardNudgeDelta = exports.getSelectedOutlineDragValues = exports.getSelectedOutlineDragChanges = exports.getSelectedOutlineActiveSchema = exports.compensateTranslateForTransformOrigin = exports.applySelectedOutlineTransformOriginAxisLock = exports.applySelectedOutlineDragAxisLock = void 0;
36
+ exports.SelectedOutlineOverlay = exports.orderOutlinesForRendering = exports.selectedOutlineDragThresholdPx = exports.getTransformedSvgViewportPoints = exports.getSequencesWithSelectableOutlines = exports.getSelectedSequenceKeys = exports.getSelectedOutlineRotationPivot = exports.getSelectedOutlineRotationDeltaDegrees = exports.getSelectedOutlineRotationCornerInfo = exports.getSelectedEffectFieldsBySequenceKey = exports.getOutlineSelectionInteraction = exports.snapSelectedOutlineUv = exports.snapSelectedOutlineTransformOriginUv = exports.snapSelectedOutlineRotationDeltaDegrees = exports.selectedOutlineUvSnapThresholdPx = exports.selectedOutlineTransformOriginSnapThresholdPx = exports.isSelectedOutlineDragPastThreshold = exports.getSelectedOutlineTransformOriginLockedAxis = exports.getSelectedOutlineScaleEdgeInfo = exports.getSelectedOutlineScaleDragValues = exports.getSelectedOutlineScaleDragStates = exports.getSelectedOutlineScaleDragChanges = exports.getSelectedOutlineRotationDragValues = exports.getSelectedOutlineRotationDragStates = exports.getSelectedOutlineRotationDragChanges = exports.getSelectedOutlineKeyboardNudgeDeltas = exports.getSelectedOutlineKeyboardNudgeDelta = exports.getSelectedOutlineDragValues = exports.getSelectedOutlineDragChanges = exports.getSelectedOutlineActiveSchema = exports.compensateTranslateForTransformOrigin = exports.applySelectedOutlineTransformOriginAxisLock = exports.applySelectedOutlineDragAxisLock = void 0;
37
37
  const jsx_runtime_1 = require("react/jsx-runtime");
38
38
  const player_1 = require("@remotion/player");
39
39
  const react_1 = __importStar(require("react"));
@@ -82,7 +82,6 @@ Object.defineProperty(exports, "snapSelectedOutlineRotationDeltaDegrees", { enum
82
82
  Object.defineProperty(exports, "snapSelectedOutlineTransformOriginUv", { enumerable: true, get: function () { return selected_outline_drag_2.snapSelectedOutlineTransformOriginUv; } });
83
83
  Object.defineProperty(exports, "snapSelectedOutlineUv", { enumerable: true, get: function () { return selected_outline_drag_2.snapSelectedOutlineUv; } });
84
84
  const selected_outline_measurement_2 = require("./selected-outline-measurement");
85
- Object.defineProperty(exports, "getOutlineDoubleClickAction", { enumerable: true, get: function () { return selected_outline_measurement_2.getOutlineDoubleClickAction; } });
86
85
  Object.defineProperty(exports, "getOutlineSelectionInteraction", { enumerable: true, get: function () { return selected_outline_measurement_2.getOutlineSelectionInteraction; } });
87
86
  Object.defineProperty(exports, "getSelectedEffectFieldsBySequenceKey", { enumerable: true, get: function () { return selected_outline_measurement_2.getSelectedEffectFieldsBySequenceKey; } });
88
87
  Object.defineProperty(exports, "getSelectedOutlineRotationCornerInfo", { enumerable: true, get: function () { return selected_outline_measurement_2.getSelectedOutlineRotationCornerInfo; } });
@@ -363,7 +362,7 @@ exports.orderOutlinesForRendering = orderOutlinesForRendering;
363
362
  const SelectedOutlineOverlay = ({ compositionHeight, compositionWidth, scale, translationX, translationY, }) => {
364
363
  const { selectedItems, selectItem } = (0, TimelineSelection_1.useTimelineSelection)();
365
364
  const { sequences } = (0, react_1.useContext)(remotion_1.Internals.SequenceManager);
366
- const { canvasContent } = (0, react_1.useContext)(remotion_1.Internals.CompositionManager);
365
+ const { canvasContent, compositions } = (0, react_1.useContext)(remotion_1.Internals.CompositionManager);
367
366
  const { propStatuses } = (0, react_1.useContext)(remotion_1.Internals.VisualModePropStatusesContext);
368
367
  const { previewServerState } = (0, react_1.useContext)(client_id_1.StudioServerConnectionCtx);
369
368
  const { overrideIdToNodePathMappings } = (0, react_1.useContext)(remotion_1.Internals.OverrideIdsToNodePathsGettersContext);
@@ -411,6 +410,7 @@ const SelectedOutlineOverlay = ({ compositionHeight, compositionWidth, scale, tr
411
410
  return (0, selected_outline_measurement_1.getSequencesWithSelectableOutlines)({
412
411
  sequences,
413
412
  overrideIdsToNodePaths: overrideIdToNodePathMappings,
413
+ compositions,
414
414
  }).map(({ key, keyframeDisplayOffset, nodePathInfo, sequence }) => {
415
415
  var _a, _b, _c, _d, _e, _f;
416
416
  if (sequence.refForOutline === null) {
@@ -629,6 +629,7 @@ const SelectedOutlineOverlay = ({ compositionHeight, compositionWidth, scale, tr
629
629
  previewServerState,
630
630
  selectedItems,
631
631
  sequences,
632
+ compositions,
632
633
  timelinePosition,
633
634
  ]);
634
635
  (0, react_1.useEffect)(() => {
@@ -204,6 +204,7 @@ const TimelineContextMenuArea = ({ children }) => {
204
204
  const TimelineInner = () => {
205
205
  var _a;
206
206
  const { sequences } = (0, react_1.useContext)(remotion_1.Internals.SequenceManager);
207
+ const { compositions } = (0, react_1.useContext)(remotion_1.Internals.CompositionManager);
207
208
  const videoConfig = remotion_1.Internals.useUnsafeVideoConfig();
208
209
  const isStill = (0, is_current_selected_still_1.useIsStill)();
209
210
  const { overrideIdToNodePathMappings } = (0, react_1.useContext)(remotion_1.Internals.OverrideIdsToNodePathsGettersContext);
@@ -218,8 +219,14 @@ const TimelineInner = () => {
218
219
  return (0, calculate_timeline_1.calculateTimeline)({
219
220
  sequences,
220
221
  overrideIdsToNodePaths: overrideIdToNodePathMappings,
222
+ compositions,
221
223
  });
222
- }, [sequences, videoConfigIsNull, overrideIdToNodePathMappings]);
224
+ }, [
225
+ sequences,
226
+ videoConfigIsNull,
227
+ overrideIdToNodePathMappings,
228
+ compositions,
229
+ ]);
223
230
  const durationInFrames = (_a = videoConfig === null || videoConfig === void 0 ? void 0 : videoConfig.durationInFrames) !== null && _a !== void 0 ? _a : 0;
224
231
  const filtered = (0, react_1.useMemo)(() => {
225
232
  return timeline.filter((t) => (0, should_show_track_in_timeline_1.shouldShowTrackInTimeline)(t, durationInFrames));
@@ -0,0 +1,14 @@
1
+ import React from 'react';
2
+ import type { CanUpdateSequencePropStatusStatic } from 'remotion';
3
+ import type { SchemaFieldInfo, TimelineFieldOnDragValueChange, TimelineFieldOnSave } from '../../helpers/timeline-layout';
4
+ type TimelineAssetFieldProps = {
5
+ readonly field: SchemaFieldInfo;
6
+ readonly propStatus: CanUpdateSequencePropStatusStatic;
7
+ readonly effectiveValue: unknown;
8
+ readonly onSave: TimelineFieldOnSave;
9
+ readonly onDragValueChange: TimelineFieldOnDragValueChange;
10
+ readonly onDragEnd: () => void;
11
+ };
12
+ export declare const isStaticFileAssetValue: (value: unknown) => value is string;
13
+ export declare const TimelineAssetField: React.FC<TimelineAssetFieldProps>;
14
+ export {};
@@ -0,0 +1,125 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TimelineAssetField = exports.isStaticFileAssetValue = void 0;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const react_1 = require("react");
6
+ const no_react_1 = require("remotion/no-react");
7
+ const write_static_file_1 = require("../../api/write-static-file");
8
+ const Checkmark_1 = require("../../icons/Checkmark");
9
+ const import_assets_1 = require("../import-assets");
10
+ const ComboBox_1 = require("../NewComposition/ComboBox");
11
+ const NotificationCenter_1 = require("../Notifications/NotificationCenter");
12
+ const use_static_files_1 = require("../use-static-files");
13
+ const comboboxStyle = {
14
+ marginLeft: 8,
15
+ maxWidth: 180,
16
+ };
17
+ const remoteAssetStyle = {
18
+ display: 'inline-block',
19
+ marginLeft: 8,
20
+ maxWidth: 180,
21
+ overflow: 'hidden',
22
+ textOverflow: 'ellipsis',
23
+ verticalAlign: 'middle',
24
+ whiteSpace: 'nowrap',
25
+ };
26
+ const toFileToken = (name) => {
27
+ return `${no_react_1.NoReactInternals.FILE_TOKEN}${name
28
+ .split('/')
29
+ .map(encodeURIComponent)
30
+ .join('/')}`;
31
+ };
32
+ const toStaticFileUrl = (fileToken) => {
33
+ return `${window.remotion_staticBase}/${fileToken.slice(no_react_1.NoReactInternals.FILE_TOKEN.length)}`;
34
+ };
35
+ const isStaticFileAssetValue = (value) => {
36
+ return (typeof value === 'string' && value.startsWith(no_react_1.NoReactInternals.FILE_TOKEN));
37
+ };
38
+ exports.isStaticFileAssetValue = isStaticFileAssetValue;
39
+ const TimelineStaticFileAssetField = ({ propStatus, effectiveValue, onSave, onDragValueChange, onDragEnd, }) => {
40
+ const staticFiles = (0, use_static_files_1.useStaticFiles)();
41
+ const current = String(effectiveValue !== null && effectiveValue !== void 0 ? effectiveValue : '');
42
+ const onSelect = (0, react_1.useCallback)((sourceValue, previewValue) => {
43
+ if (sourceValue === propStatus.codeValue) {
44
+ return;
45
+ }
46
+ onDragValueChange(previewValue);
47
+ onSave(sourceValue).finally(() => {
48
+ onDragEnd();
49
+ });
50
+ }, [propStatus.codeValue, onDragValueChange, onSave, onDragEnd]);
51
+ const upload = (0, react_1.useCallback)(async () => {
52
+ const [file] = await (0, import_assets_1.pickFilesToImport)({ multiple: false });
53
+ if (!file) {
54
+ return;
55
+ }
56
+ const existing = staticFiles.find((candidate) => candidate.name === file.name);
57
+ if (existing && existing.sizeInBytes !== file.size) {
58
+ (0, NotificationCenter_1.showNotification)(`File with name ${file.name} already exists and is different`, 4000);
59
+ return;
60
+ }
61
+ try {
62
+ if (!existing) {
63
+ await (0, write_static_file_1.writeStaticFile)({
64
+ contents: await file.arrayBuffer(),
65
+ filePath: file.name,
66
+ });
67
+ }
68
+ const fileToken = toFileToken(file.name);
69
+ onSelect(fileToken, toStaticFileUrl(fileToken));
70
+ if (!existing) {
71
+ (0, NotificationCenter_1.showNotification)(`Created ${file.name} in public folder`, 3000);
72
+ }
73
+ }
74
+ catch (error) {
75
+ (0, NotificationCenter_1.showNotification)(`Could not upload asset: ${error instanceof Error ? error.message : String(error)}`, 4000);
76
+ }
77
+ }, [onSelect, staticFiles]);
78
+ const items = (0, react_1.useMemo)(() => {
79
+ const publicFileItems = staticFiles.map((file) => {
80
+ const fileToken = toFileToken(file.name);
81
+ return {
82
+ type: 'item',
83
+ id: fileToken,
84
+ value: fileToken,
85
+ label: file.name,
86
+ onClick: () => onSelect(fileToken, file.src),
87
+ keyHint: null,
88
+ leftItem: fileToken === current ? jsx_runtime_1.jsx(Checkmark_1.Checkmark, {}) : null,
89
+ subMenu: null,
90
+ quickSwitcherLabel: null,
91
+ };
92
+ });
93
+ return [
94
+ ...publicFileItems,
95
+ { type: 'divider', id: 'upload-asset-divider' },
96
+ {
97
+ type: 'item',
98
+ id: 'upload-asset',
99
+ value: 'upload-asset',
100
+ label: 'Upload…',
101
+ onClick: () => {
102
+ upload().catch(() => undefined);
103
+ },
104
+ keyHint: null,
105
+ leftItem: null,
106
+ subMenu: null,
107
+ quickSwitcherLabel: null,
108
+ disabled: window.remotion_isReadOnlyStudio,
109
+ },
110
+ ];
111
+ }, [current, onSelect, staticFiles, upload]);
112
+ return (jsx_runtime_1.jsx(ComboBox_1.Combobox, { small: true, title: current, selectedId: current, values: items, style: comboboxStyle }));
113
+ };
114
+ const TimelineAssetField = (props) => {
115
+ var _a;
116
+ if (props.field.fieldSchema.type !== 'asset') {
117
+ throw new Error('TimelineAssetField rendered for non-asset field');
118
+ }
119
+ if (!(0, exports.isStaticFileAssetValue)(props.effectiveValue)) {
120
+ const remote = String((_a = props.effectiveValue) !== null && _a !== void 0 ? _a : '');
121
+ return (jsx_runtime_1.jsx("span", { style: remoteAssetStyle, title: remote, children: remote }));
122
+ }
123
+ return jsx_runtime_1.jsx(TimelineStaticFileAssetField, { ...props });
124
+ };
125
+ exports.TimelineAssetField = TimelineAssetField;
@@ -9,9 +9,13 @@ const use_keybinding_1 = require("../../helpers/use-keybinding");
9
9
  const call_api_1 = require("../call-api");
10
10
  const ConfirmationDialog_1 = require("../ConfirmationDialog");
11
11
  const NotificationCenter_1 = require("../Notifications/NotificationCenter");
12
+ const call_add_keyframe_1 = require("./call-add-keyframe");
13
+ const call_delete_keyframe_1 = require("./call-delete-keyframe");
14
+ const call_update_keyframe_settings_1 = require("./call-update-keyframe-settings");
12
15
  const delete_selected_timeline_item_1 = require("./delete-selected-timeline-item");
13
16
  const effects_clipboard_1 = require("./effects-clipboard");
14
17
  const find_track_for_node_path_info_1 = require("./find-track-for-node-path-info");
18
+ const keyframe_clipboard_1 = require("./keyframe-clipboard");
15
19
  const save_effect_prop_1 = require("./save-effect-prop");
16
20
  const TimelineSelection_1 = require("./TimelineSelection");
17
21
  const update_selected_easing_1 = require("./update-selected-easing");
@@ -352,6 +356,9 @@ const getPasteEffectPropTarget = ({ selectedItems, payload, propStatuses, sequen
352
356
  exports.getPasteEffectPropTarget = getPasteEffectPropTarget;
353
357
  const TimelineClipboardKeybindings = () => {
354
358
  const keybindings = (0, use_keybinding_1.useKeybinding)();
359
+ const timelinePosition = remotion_1.Internals.Timeline.useTimelinePosition();
360
+ const timelinePositionRef = (0, react_1.useRef)(timelinePosition);
361
+ timelinePositionRef.current = timelinePosition;
355
362
  const { previewServerState } = (0, react_1.useContext)(client_id_1.StudioServerConnectionCtx);
356
363
  const { canSelect } = (0, TimelineSelection_1.useTimelineSelection)();
357
364
  const currentSelection = (0, TimelineSelection_1.useCurrentTimelineSelectionStateAsRef)();
@@ -376,6 +383,30 @@ const TimelineClipboardKeybindings = () => {
376
383
  if (selectedItems.length === 0) {
377
384
  return;
378
385
  }
386
+ const keyframeSelections = selectedItems.filter((selection) => selection.type === 'keyframe');
387
+ if (keyframeSelections.length > 0) {
388
+ e.preventDefault();
389
+ if (selectedItems.some((selection) => selection.type !== 'keyframe' && selection.type !== 'easing')) {
390
+ (0, NotificationCenter_1.showNotification)('Select only keyframes and easings to copy', 3000);
391
+ return;
392
+ }
393
+ const payload = (0, keyframe_clipboard_1.getKeyframeClipboardDataFromSelections)({
394
+ selections: selectedItems,
395
+ sequences,
396
+ overrideIdsToNodePaths: overrideIdToNodePathMappings,
397
+ propStatuses,
398
+ });
399
+ if (payload === null) {
400
+ (0, NotificationCenter_1.showNotification)('Select a continuous keyframe range from one property to copy', 3000);
401
+ return;
402
+ }
403
+ navigator.clipboard
404
+ .writeText(makeClipboardText(payload))
405
+ .catch((err) => {
406
+ (0, NotificationCenter_1.showNotification)(`Could not copy keyframe: ${err.message}`, 2000);
407
+ });
408
+ return;
409
+ }
379
410
  const easingSelections = (0, update_selected_easing_1.getEasingSelections)(selectedItems);
380
411
  if (easingSelections.length > 0) {
381
412
  e.preventDefault();
@@ -543,6 +574,106 @@ const TimelineClipboardKeybindings = () => {
543
574
  .then(() => {
544
575
  const propStatuses = propStatusesRef.current;
545
576
  const sequences = sequencesRef.current;
577
+ const keyframeResult = (0, studio_shared_1.parseKeyframeClipboardDataResult)(text);
578
+ if (keyframeResult.status !== 'invalid') {
579
+ if (keyframeResult.status === 'unsupported-version') {
580
+ (0, NotificationCenter_1.showNotification)('Cannot paste keyframe copied from a different Remotion Studio version', 4000);
581
+ return;
582
+ }
583
+ const keyframeTarget = (0, keyframe_clipboard_1.getPasteKeyframeTarget)({
584
+ selectedItems,
585
+ payload: keyframeResult.data,
586
+ timelinePosition: timelinePositionRef.current,
587
+ sequences,
588
+ overrideIdsToNodePaths: overrideIdToNodePathMappings,
589
+ propStatuses,
590
+ });
591
+ if (keyframeTarget.type !== 'valid') {
592
+ switch (keyframeTarget.type) {
593
+ case 'none':
594
+ (0, NotificationCenter_1.showNotification)('Select a property or keyframe to paste onto', 3000);
595
+ return;
596
+ case 'multiple':
597
+ (0, NotificationCenter_1.showNotification)('Select one property or keyframe to paste onto', 3000);
598
+ return;
599
+ case 'uncopyable':
600
+ (0, NotificationCenter_1.showNotification)('Cannot paste onto a property that cannot be updated', 3000);
601
+ return;
602
+ case 'incompatible':
603
+ (0, NotificationCenter_1.showNotification)('The copied keyframe is not compatible with this property', 3000);
604
+ return;
605
+ default:
606
+ throw new Error(`Unexpected paste target: ${keyframeTarget}`);
607
+ }
608
+ }
609
+ const changes = keyframeTarget.keyframes.map((keyframe) => ({
610
+ fileName: keyframeTarget.fileName,
611
+ nodePath: keyframeTarget.nodePath,
612
+ fieldKey: keyframeTarget.fieldKey,
613
+ sourceFrame: keyframe.sourceFrame,
614
+ value: keyframe.value,
615
+ schema: keyframeTarget.schema,
616
+ }));
617
+ const { effectIndex } = keyframeTarget;
618
+ const deletions = keyframeTarget.keyframesToDelete.map((sourceFrame) => ({
619
+ fileName: keyframeTarget.fileName,
620
+ nodePath: keyframeTarget.nodePath,
621
+ fieldKey: keyframeTarget.fieldKey,
622
+ sourceFrame,
623
+ schema: keyframeTarget.schema,
624
+ }));
625
+ return (0, call_delete_keyframe_1.callDeleteKeyframes)({
626
+ sequenceKeyframes: effectIndex === null ? deletions : [],
627
+ effectKeyframes: effectIndex === null
628
+ ? []
629
+ : deletions.map((deletion) => ({
630
+ ...deletion,
631
+ effectIndex,
632
+ })),
633
+ setPropStatuses,
634
+ clientId,
635
+ })
636
+ .then(() => (0, call_add_keyframe_1.callAddKeyframes)({
637
+ sequenceKeyframes: effectIndex === null ? changes : [],
638
+ effectKeyframes: effectIndex === null
639
+ ? []
640
+ : changes.map((change) => ({ ...change, effectIndex })),
641
+ setPropStatuses,
642
+ clientId,
643
+ }))
644
+ .then(async () => {
645
+ for (const [index, easing] of keyframeTarget.easing.entries()) {
646
+ const settings = {
647
+ type: 'easing',
648
+ segmentIndex: keyframeTarget.firstEasingSegmentIndex + index,
649
+ easing,
650
+ };
651
+ if (effectIndex === null) {
652
+ await (0, call_update_keyframe_settings_1.callUpdateSequenceKeyframeSettings)({
653
+ fileName: keyframeTarget.fileName,
654
+ nodePath: keyframeTarget.nodePath,
655
+ fieldKey: keyframeTarget.fieldKey,
656
+ settings,
657
+ schema: keyframeTarget.schema,
658
+ setPropStatuses,
659
+ clientId,
660
+ });
661
+ }
662
+ else {
663
+ await (0, call_update_keyframe_settings_1.callUpdateEffectKeyframeSettings)({
664
+ fileName: keyframeTarget.fileName,
665
+ nodePath: keyframeTarget.nodePath,
666
+ effectIndex,
667
+ fieldKey: keyframeTarget.fieldKey,
668
+ settings,
669
+ schema: keyframeTarget.schema,
670
+ setPropStatuses,
671
+ clientId,
672
+ });
673
+ }
674
+ }
675
+ });
676
+ }
546
677
  const easingResult = (0, studio_shared_1.parseEasingClipboardDataResult)(text);
547
678
  if (easingResult.status !== 'invalid') {
548
679
  e.preventDefault();
@@ -685,7 +816,7 @@ const TimelineClipboardKeybindings = () => {
685
816
  });
686
817
  })
687
818
  .catch((err) => {
688
- (0, NotificationCenter_1.showNotification)(`Could not paste effects: ${err.message}`, 3000);
819
+ (0, NotificationCenter_1.showNotification)(`Could not paste: ${err.message}`, 3000);
689
820
  });
690
821
  };
691
822
  // Reading ClipboardEvent data avoids the permission prompt caused by
@@ -708,6 +839,7 @@ const TimelineClipboardKeybindings = () => {
708
839
  previewServerState,
709
840
  sequencesRef,
710
841
  setPropStatuses,
842
+ timelinePositionRef,
711
843
  ]);
712
844
  return null;
713
845
  };
@@ -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)(() => {