@remotion/studio 4.0.476 → 4.0.478
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.
- package/dist/components/Canvas.js +40 -1
- package/dist/components/CanvasIfSizeIsAvailable.js +2 -6
- package/dist/components/ControlButton.d.ts +1 -0
- package/dist/components/ControlButton.js +7 -2
- package/dist/components/EditorGuides/Guide.js +151 -21
- package/dist/components/EditorRuler/Ruler.js +20 -24
- package/dist/components/EditorRuler/index.js +26 -13
- package/dist/components/InlineAction.js +1 -0
- package/dist/components/MenuToolbar.d.ts +1 -0
- package/dist/components/MenuToolbar.js +4 -1
- package/dist/components/OutlineToggle.js +1 -1
- package/dist/components/SelectedOutlineElement.d.ts +17 -0
- package/dist/components/SelectedOutlineElement.js +1009 -0
- package/dist/components/SelectedOutlineOverlay.d.ts +4 -210
- package/dist/components/SelectedOutlineOverlay.js +68 -1637
- package/dist/components/SelectedOutlineUvControls.js +1 -1
- package/dist/components/ShowGuidesProvider.js +4 -4
- package/dist/components/Timeline/SubscribeToNodePaths.d.ts +2 -1
- package/dist/components/Timeline/SubscribeToNodePaths.js +2 -1
- package/dist/components/Timeline/Timeline.js +3 -1
- package/dist/components/Timeline/TimelineClipboardKeybindings.js +9 -10
- package/dist/components/Timeline/TimelineDeleteKeybindings.js +15 -4
- package/dist/components/Timeline/TimelineKeyframeEasingLine.js +7 -11
- package/dist/components/Timeline/TimelineList.js +1 -1
- package/dist/components/Timeline/TimelineSelection.d.ts +27 -13
- package/dist/components/Timeline/TimelineSelection.js +47 -28
- package/dist/components/Timeline/TimelineSequence.js +156 -3
- package/dist/components/Timeline/TimelineSequenceFrame.d.ts +1 -0
- package/dist/components/Timeline/TimelineSequenceFrame.js +17 -6
- package/dist/components/Timeline/TimelineSequenceItem.d.ts +1 -0
- package/dist/components/Timeline/TimelineSequenceItem.js +90 -130
- package/dist/components/Timeline/TimelineVideoInfo.d.ts +1 -0
- package/dist/components/Timeline/TimelineVideoInfo.js +93 -8
- package/dist/components/Timeline/delete-selected-timeline-item.js +4 -0
- package/dist/components/Timeline/duplicate-selected-timeline-item.d.ts +8 -2
- package/dist/components/Timeline/duplicate-selected-timeline-item.js +32 -3
- package/dist/components/Timeline/get-sequence-context-menu-items.d.ts +20 -0
- package/dist/components/Timeline/get-sequence-context-menu-items.js +160 -0
- package/dist/components/Timeline/sequence-props-subscription-store.d.ts +2 -1
- package/dist/components/Timeline/sequence-props-subscription-store.js +11 -3
- package/dist/components/Timeline/should-clear-selection-on-pointer-down.d.ts +2 -0
- package/dist/components/Timeline/should-clear-selection-on-pointer-down.js +16 -2
- package/dist/components/Timeline/timeline-video-filmstrip-times.d.ts +17 -0
- package/dist/components/Timeline/timeline-video-filmstrip-times.js +22 -0
- package/dist/components/Timeline/update-selected-easing.d.ts +4 -6
- package/dist/components/Timeline/use-sequence-props-subscription.d.ts +2 -1
- package/dist/components/Timeline/use-sequence-props-subscription.js +3 -1
- package/dist/components/Timeline/use-timeline-keyframe-drag.d.ts +37 -1
- package/dist/components/Timeline/use-timeline-keyframe-drag.js +282 -1
- package/dist/components/import-assets.d.ts +45 -8
- package/dist/components/import-assets.js +227 -12
- package/dist/components/selected-outline-drag.d.ts +140 -0
- package/dist/components/selected-outline-drag.js +475 -0
- package/dist/components/selected-outline-measurement.d.ts +67 -0
- package/dist/components/selected-outline-measurement.js +355 -0
- package/dist/components/selected-outline-types.d.ts +121 -0
- package/dist/components/selected-outline-types.js +15 -0
- package/dist/components/selected-outline-uv.d.ts +1 -0
- package/dist/components/selected-outline-uv.js +12 -0
- package/dist/error-overlay/remotion-overlay/Overlay.js +3 -0
- package/dist/esm/{chunk-0atarw3p.js → chunk-hrw9799x.js} +12812 -11386
- package/dist/esm/internals.mjs +12812 -11386
- package/dist/esm/previewEntry.mjs +21059 -19629
- package/dist/esm/renderEntry.mjs +1 -1
- package/dist/helpers/editor-guide-selection.d.ts +31 -0
- package/dist/helpers/editor-guide-selection.js +58 -0
- package/dist/helpers/editor-ruler.d.ts +3 -3
- package/dist/helpers/editor-ruler.js +16 -18
- package/dist/helpers/get-preview-file-type.js +1 -1
- package/dist/helpers/ruler-canvas-size.d.ts +5 -0
- package/dist/helpers/ruler-canvas-size.js +17 -0
- package/dist/state/editor-guides.d.ts +2 -2
- package/dist/state/editor-guides.js +2 -2
- package/package.json +11 -11
|
@@ -8,6 +8,7 @@ const remotion_1 = require("remotion");
|
|
|
8
8
|
const timeline_layout_1 = require("../../helpers/timeline-layout");
|
|
9
9
|
const AudioWaveform_1 = require("../AudioWaveform");
|
|
10
10
|
const get_timeline_video_info_widths_1 = require("./get-timeline-video-info-widths");
|
|
11
|
+
const timeline_video_filmstrip_times_1 = require("./timeline-video-filmstrip-times");
|
|
11
12
|
const outerStyle = {
|
|
12
13
|
width: '100%',
|
|
13
14
|
height: '100%',
|
|
@@ -22,7 +23,8 @@ const filmstripContainerStyle = {
|
|
|
22
23
|
fontSize: 10,
|
|
23
24
|
fontFamily: 'Arial, Helvetica',
|
|
24
25
|
};
|
|
25
|
-
const
|
|
26
|
+
const MAX_FROZEN_FRAME_CACHE_DEVIATION = timeline_utils_1.WEBCODECS_TIMESCALE * 0.05;
|
|
27
|
+
const TimelineVideoInfo = ({ src, visualizationWidth, naturalWidth, trimBefore, durationInFrames, playbackRate, volume, doesVolumeChange, premountWidth, postmountWidth, loopDisplay, frozenMediaFrame, }) => {
|
|
26
28
|
const { fps } = (0, remotion_1.useVideoConfig)();
|
|
27
29
|
const ref = (0, react_1.useRef)(null);
|
|
28
30
|
const [error, setError] = (0, react_1.useState)(null);
|
|
@@ -53,6 +55,94 @@ const TimelineVideoInfo = ({ src, visualizationWidth, naturalWidth, trimBefore,
|
|
|
53
55
|
return;
|
|
54
56
|
}
|
|
55
57
|
current.appendChild(canvas);
|
|
58
|
+
const drawRepeatedFrame = (frame) => {
|
|
59
|
+
const thumbnailWidth = Math.max(1, frame.displayWidth / window.devicePixelRatio);
|
|
60
|
+
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
61
|
+
for (let x = 0; x < canvas.width; x += thumbnailWidth) {
|
|
62
|
+
ctx.drawImage(frame, x, 0, thumbnailWidth, timeline_layout_1.TIMELINE_LAYER_FILMSTRIP_HEIGHT);
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
const getCachedFrozenFrame = (timestamp) => {
|
|
66
|
+
const prefix = (0, timeline_utils_1.getFrameDatabaseKeyPrefix)(src);
|
|
67
|
+
const keys = Array.from(timeline_utils_1.frameDatabase.keys()).filter((k) => k.startsWith(prefix));
|
|
68
|
+
let bestDistance = Infinity;
|
|
69
|
+
let bestFrame = null;
|
|
70
|
+
for (const key of keys) {
|
|
71
|
+
const frame = timeline_utils_1.frameDatabase.get(key);
|
|
72
|
+
if (!frame) {
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
const distance = Math.abs((0, timeline_utils_1.getTimestampFromFrameDatabaseKey)(key) - timestamp);
|
|
76
|
+
if (distance < bestDistance) {
|
|
77
|
+
bestDistance = distance;
|
|
78
|
+
bestFrame = frame.frame;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return bestDistance <= MAX_FROZEN_FRAME_CACHE_DEVIATION
|
|
82
|
+
? bestFrame
|
|
83
|
+
: null;
|
|
84
|
+
};
|
|
85
|
+
const times = (0, timeline_video_filmstrip_times_1.getTimelineVideoFilmstripTimes)({
|
|
86
|
+
trimBefore,
|
|
87
|
+
durationInFrames,
|
|
88
|
+
playbackRate,
|
|
89
|
+
fps,
|
|
90
|
+
loopDisplay,
|
|
91
|
+
frozenMediaFrame,
|
|
92
|
+
});
|
|
93
|
+
if (times.type === 'frozen') {
|
|
94
|
+
const timestamp = times.timestampInSeconds * timeline_utils_1.WEBCODECS_TIMESCALE;
|
|
95
|
+
const cachedFrame = getCachedFrozenFrame(timestamp);
|
|
96
|
+
if (cachedFrame) {
|
|
97
|
+
drawRepeatedFrame(cachedFrame);
|
|
98
|
+
return () => {
|
|
99
|
+
current.removeChild(canvas);
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
(0, timeline_utils_1.extractFrames)({
|
|
103
|
+
timestampsInSeconds: ({ track, }) => {
|
|
104
|
+
aspectRatio.current = track.width / track.height;
|
|
105
|
+
timeline_utils_1.aspectRatioCache.set(src, aspectRatio.current);
|
|
106
|
+
return [times.timestampInSeconds];
|
|
107
|
+
},
|
|
108
|
+
src,
|
|
109
|
+
onVideoSample: (sample) => {
|
|
110
|
+
let frame;
|
|
111
|
+
try {
|
|
112
|
+
frame = sample.toVideoFrame();
|
|
113
|
+
const scale = (timeline_layout_1.TIMELINE_LAYER_FILMSTRIP_HEIGHT / frame.displayHeight) *
|
|
114
|
+
window.devicePixelRatio;
|
|
115
|
+
const transformed = (0, timeline_utils_1.resizeVideoFrame)({
|
|
116
|
+
frame,
|
|
117
|
+
scale,
|
|
118
|
+
});
|
|
119
|
+
if (transformed !== frame) {
|
|
120
|
+
frame.close();
|
|
121
|
+
}
|
|
122
|
+
frame = undefined;
|
|
123
|
+
const databaseKey = (0, timeline_utils_1.makeFrameDatabaseKey)(src, transformed.timestamp);
|
|
124
|
+
(0, timeline_utils_1.addFrameToCache)(databaseKey, transformed);
|
|
125
|
+
drawRepeatedFrame(transformed);
|
|
126
|
+
}
|
|
127
|
+
catch (e) {
|
|
128
|
+
if (frame) {
|
|
129
|
+
frame.close();
|
|
130
|
+
}
|
|
131
|
+
throw e;
|
|
132
|
+
}
|
|
133
|
+
finally {
|
|
134
|
+
sample.close();
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
signal: controller.signal,
|
|
138
|
+
}).catch((e) => {
|
|
139
|
+
setError(e);
|
|
140
|
+
});
|
|
141
|
+
return () => {
|
|
142
|
+
controller.abort();
|
|
143
|
+
current.removeChild(canvas);
|
|
144
|
+
};
|
|
145
|
+
}
|
|
56
146
|
const loopWidth = (0, timeline_utils_1.getLoopDisplayWidth)({
|
|
57
147
|
visualizationWidth: mediaNaturalWidth,
|
|
58
148
|
loopDisplay,
|
|
@@ -85,13 +175,7 @@ const TimelineVideoInfo = ({ src, visualizationWidth, naturalWidth, trimBefore,
|
|
|
85
175
|
};
|
|
86
176
|
// desired-timestamp -> filled-timestamp
|
|
87
177
|
const filledSlots = new Map();
|
|
88
|
-
const fromSeconds
|
|
89
|
-
const visibleDurationInFrames = shouldRepeatVideo && loopDisplay
|
|
90
|
-
? loopDisplay.durationInFrames
|
|
91
|
-
: durationInFrames;
|
|
92
|
-
// Trim is applied first, then playbackRate. Each composition frame
|
|
93
|
-
// advances the source video by `playbackRate` source frames.
|
|
94
|
-
const toSeconds = fromSeconds + (visibleDurationInFrames * playbackRate) / fps;
|
|
178
|
+
const { fromSeconds, toSeconds } = times;
|
|
95
179
|
const targetWidth = shouldRepeatVideo
|
|
96
180
|
? targetCanvas.width
|
|
97
181
|
: mediaNaturalWidth;
|
|
@@ -216,6 +300,7 @@ const TimelineVideoInfo = ({ src, visualizationWidth, naturalWidth, trimBefore,
|
|
|
216
300
|
durationInFrames,
|
|
217
301
|
error,
|
|
218
302
|
fps,
|
|
303
|
+
frozenMediaFrame,
|
|
219
304
|
loopDisplay,
|
|
220
305
|
mediaNaturalWidth,
|
|
221
306
|
mediaVisualizationWidth,
|
|
@@ -107,6 +107,8 @@ const deleteSelectedTimelineItem = ({ selection, sequences, overrideIdsToNodePat
|
|
|
107
107
|
return (_a = promise === null || promise === void 0 ? void 0 : promise.then(() => true)) !== null && _a !== void 0 ? _a : null;
|
|
108
108
|
}
|
|
109
109
|
switch (selection.type) {
|
|
110
|
+
case 'guide':
|
|
111
|
+
return null;
|
|
110
112
|
case 'sequence':
|
|
111
113
|
return deleteSequences([selection.nodePathInfo], confirm);
|
|
112
114
|
case 'sequence-effect':
|
|
@@ -175,6 +177,8 @@ const deleteSelectedTimelineItems = ({ selections, sequences, overrideIdsToNodeP
|
|
|
175
177
|
}
|
|
176
178
|
assertTimelineSelectionsHaveSameType(selections);
|
|
177
179
|
switch (firstSelection.type) {
|
|
180
|
+
case 'guide':
|
|
181
|
+
return null;
|
|
178
182
|
case 'sequence':
|
|
179
183
|
return deleteSequences(selections
|
|
180
184
|
.filter(isSequenceRowSelection)
|
|
@@ -3,12 +3,18 @@ import type { ConfirmationDialogFunction } from '../ConfirmationDialog-types';
|
|
|
3
3
|
import type { TimelineSelection } from './TimelineSelection';
|
|
4
4
|
export declare const duplicateSequencesFromSource: (nodePathInfos: readonly SequenceNodePathInfo[], confirm: ConfirmationDialogFunction) => Promise<void>;
|
|
5
5
|
export declare const isDuplicatableSequenceRowSelection: (selection: TimelineSelection) => selection is {
|
|
6
|
-
readonly nodePathInfo: SequenceNodePathInfo;
|
|
7
|
-
} & {
|
|
8
6
|
readonly type: "sequence";
|
|
7
|
+
readonly nodePathInfo: SequenceNodePathInfo;
|
|
9
8
|
} & {
|
|
10
9
|
type: "sequence";
|
|
11
10
|
};
|
|
11
|
+
export declare const isDuplicatableEffectSelection: (selection: TimelineSelection) => selection is {
|
|
12
|
+
readonly type: "sequence-effect";
|
|
13
|
+
readonly nodePathInfo: SequenceNodePathInfo;
|
|
14
|
+
readonly i: number;
|
|
15
|
+
} & {
|
|
16
|
+
type: "sequence-effect";
|
|
17
|
+
};
|
|
12
18
|
export declare const duplicateSelectedTimelineItems: ({ selections, confirm, }: {
|
|
13
19
|
selections: readonly TimelineSelection[];
|
|
14
20
|
confirm: ConfirmationDialogFunction;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.duplicateSelectedTimelineItems = exports.isDuplicatableSequenceRowSelection = exports.duplicateSequencesFromSource = void 0;
|
|
3
|
+
exports.duplicateSelectedTimelineItems = exports.isDuplicatableEffectSelection = exports.isDuplicatableSequenceRowSelection = exports.duplicateSequencesFromSource = void 0;
|
|
4
4
|
const call_api_1 = require("../call-api");
|
|
5
5
|
const NotificationCenter_1 = require("../Notifications/NotificationCenter");
|
|
6
6
|
const confirmDuplicatingProgrammaticallyDuplicatedSequences = (nodePathInfos, confirm) => {
|
|
@@ -61,11 +61,40 @@ const duplicateSequencesFromSource = (nodePathInfos, confirm) => {
|
|
|
61
61
|
exports.duplicateSequencesFromSource = duplicateSequencesFromSource;
|
|
62
62
|
const isDuplicatableSequenceRowSelection = (selection) => selection.type === 'sequence';
|
|
63
63
|
exports.isDuplicatableSequenceRowSelection = isDuplicatableSequenceRowSelection;
|
|
64
|
+
const isDuplicatableEffectSelection = (selection) => selection.type === 'sequence-effect';
|
|
65
|
+
exports.isDuplicatableEffectSelection = isDuplicatableEffectSelection;
|
|
66
|
+
const duplicateEffectsFromSource = (effects) => {
|
|
67
|
+
return (0, call_api_1.callApi)('/api/duplicate-effect', effects.map((effect) => {
|
|
68
|
+
const nodePath = effect.nodePathInfo.sequenceSubscriptionKey;
|
|
69
|
+
return {
|
|
70
|
+
fileName: nodePath.absolutePath,
|
|
71
|
+
sequenceNodePath: nodePath,
|
|
72
|
+
effectIndex: effect.i,
|
|
73
|
+
};
|
|
74
|
+
}))
|
|
75
|
+
.then((result) => {
|
|
76
|
+
if (result.success) {
|
|
77
|
+
(0, NotificationCenter_1.showNotification)(effects.length === 1
|
|
78
|
+
? 'Duplicated effect in source file'
|
|
79
|
+
: 'Duplicated effects in source files', 2000);
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
(0, NotificationCenter_1.showNotification)(result.reason, 4000);
|
|
83
|
+
}
|
|
84
|
+
})
|
|
85
|
+
.catch((err) => {
|
|
86
|
+
(0, NotificationCenter_1.showNotification)(err.message, 4000);
|
|
87
|
+
});
|
|
88
|
+
};
|
|
64
89
|
const duplicateSelectedTimelineItems = ({ selections, confirm, }) => {
|
|
65
90
|
const sequenceSelections = selections.filter(exports.isDuplicatableSequenceRowSelection);
|
|
66
|
-
if (sequenceSelections.length
|
|
91
|
+
if (sequenceSelections.length > 0) {
|
|
92
|
+
return (0, exports.duplicateSequencesFromSource)(sequenceSelections.map((selection) => selection.nodePathInfo), confirm);
|
|
93
|
+
}
|
|
94
|
+
const effectSelections = selections.filter(exports.isDuplicatableEffectSelection);
|
|
95
|
+
if (effectSelections.length === 0) {
|
|
67
96
|
return null;
|
|
68
97
|
}
|
|
69
|
-
return (
|
|
98
|
+
return duplicateEffectsFromSource(effectSelections);
|
|
70
99
|
};
|
|
71
100
|
exports.duplicateSelectedTimelineItems = duplicateSelectedTimelineItems;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ResolvedStackLocation, TSequence } from 'remotion';
|
|
2
|
+
import type { ComboboxValue } from '../NewComposition/ComboBox';
|
|
3
|
+
import type { TimelineAssetLinkInfo } from './timeline-asset-link';
|
|
4
|
+
export declare const getSequenceContextMenuItems: ({ assetLinkInfo, canOpenInEditor, deleteDisabled, disableInteractivityDisabled, duplicateDisabled, fileLocation, includeSourceEditItems, onDeleteSequenceFromSource, onDisableSequenceInteractivity, onDuplicateSequenceFromSource, openInEditor, originalLocation, selectAsset, sequence, sourceActions, }: {
|
|
5
|
+
readonly assetLinkInfo: TimelineAssetLinkInfo | null;
|
|
6
|
+
readonly canOpenInEditor: boolean;
|
|
7
|
+
readonly deleteDisabled: boolean;
|
|
8
|
+
readonly disableInteractivityDisabled: boolean;
|
|
9
|
+
readonly duplicateDisabled: boolean;
|
|
10
|
+
readonly fileLocation: string | null;
|
|
11
|
+
readonly includeSourceEditItems: boolean;
|
|
12
|
+
readonly onDeleteSequenceFromSource: () => void;
|
|
13
|
+
readonly onDisableSequenceInteractivity: () => void;
|
|
14
|
+
readonly onDuplicateSequenceFromSource: () => void;
|
|
15
|
+
readonly openInEditor: () => void;
|
|
16
|
+
readonly originalLocation: ResolvedStackLocation | null;
|
|
17
|
+
readonly selectAsset: (src: string) => void;
|
|
18
|
+
readonly sequence: TSequence;
|
|
19
|
+
readonly sourceActions?: readonly ComboboxValue[] | undefined;
|
|
20
|
+
}) => ComboboxValue[];
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getSequenceContextMenuItems = void 0;
|
|
4
|
+
const no_react_1 = require("remotion/no-react");
|
|
5
|
+
const NotificationCenter_1 = require("../Notifications/NotificationCenter");
|
|
6
|
+
const timeline_asset_link_1 = require("./timeline-asset-link");
|
|
7
|
+
const normalizeMenuDividers = (items) => {
|
|
8
|
+
var _a;
|
|
9
|
+
const normalized = [];
|
|
10
|
+
for (const item of items) {
|
|
11
|
+
if (item.type === 'divider') {
|
|
12
|
+
const previousItem = normalized[normalized.length - 1];
|
|
13
|
+
if (!previousItem || previousItem.type === 'divider') {
|
|
14
|
+
continue;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
normalized.push(item);
|
|
18
|
+
}
|
|
19
|
+
if (((_a = normalized[normalized.length - 1]) === null || _a === void 0 ? void 0 : _a.type) === 'divider') {
|
|
20
|
+
normalized.pop();
|
|
21
|
+
}
|
|
22
|
+
return normalized;
|
|
23
|
+
};
|
|
24
|
+
const getSequenceContextMenuItems = ({ assetLinkInfo, canOpenInEditor, deleteDisabled, disableInteractivityDisabled, duplicateDisabled, fileLocation, includeSourceEditItems, onDeleteSequenceFromSource, onDisableSequenceInteractivity, onDuplicateSequenceFromSource, openInEditor, originalLocation, selectAsset, sequence, sourceActions = [], }) => {
|
|
25
|
+
const editorName = window.remotion_editorName;
|
|
26
|
+
const { documentationLink } = sequence;
|
|
27
|
+
const items = [
|
|
28
|
+
editorName
|
|
29
|
+
? {
|
|
30
|
+
type: 'item',
|
|
31
|
+
id: 'show-in-editor',
|
|
32
|
+
keyHint: null,
|
|
33
|
+
label: `Show in ${editorName}`,
|
|
34
|
+
leftItem: null,
|
|
35
|
+
disabled: !canOpenInEditor || !originalLocation,
|
|
36
|
+
onClick: openInEditor,
|
|
37
|
+
quickSwitcherLabel: null,
|
|
38
|
+
subMenu: null,
|
|
39
|
+
value: 'show-in-editor',
|
|
40
|
+
}
|
|
41
|
+
: null,
|
|
42
|
+
{
|
|
43
|
+
type: 'item',
|
|
44
|
+
id: 'copy-file-location',
|
|
45
|
+
keyHint: null,
|
|
46
|
+
label: 'Copy file location',
|
|
47
|
+
leftItem: null,
|
|
48
|
+
disabled: !fileLocation,
|
|
49
|
+
onClick: () => {
|
|
50
|
+
if (!fileLocation) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
navigator.clipboard
|
|
54
|
+
.writeText(fileLocation)
|
|
55
|
+
.then(() => {
|
|
56
|
+
(0, NotificationCenter_1.showNotification)('Copied file location to clipboard', 1000);
|
|
57
|
+
})
|
|
58
|
+
.catch((err) => {
|
|
59
|
+
(0, NotificationCenter_1.showNotification)(`Could not copy to clipboard: ${err.message}`, 1000);
|
|
60
|
+
});
|
|
61
|
+
},
|
|
62
|
+
quickSwitcherLabel: null,
|
|
63
|
+
subMenu: null,
|
|
64
|
+
value: 'copy-file-location',
|
|
65
|
+
},
|
|
66
|
+
documentationLink
|
|
67
|
+
? {
|
|
68
|
+
type: 'item',
|
|
69
|
+
id: 'open-component-docs',
|
|
70
|
+
keyHint: null,
|
|
71
|
+
label: 'Open component docs',
|
|
72
|
+
leftItem: null,
|
|
73
|
+
disabled: false,
|
|
74
|
+
onClick: () => {
|
|
75
|
+
window.open(documentationLink, '_blank', 'noopener,noreferrer');
|
|
76
|
+
},
|
|
77
|
+
quickSwitcherLabel: null,
|
|
78
|
+
subMenu: null,
|
|
79
|
+
value: 'open-component-docs',
|
|
80
|
+
}
|
|
81
|
+
: null,
|
|
82
|
+
assetLinkInfo
|
|
83
|
+
? {
|
|
84
|
+
type: 'item',
|
|
85
|
+
id: 'show-asset',
|
|
86
|
+
keyHint: null,
|
|
87
|
+
label: 'Show asset',
|
|
88
|
+
leftItem: null,
|
|
89
|
+
disabled: false,
|
|
90
|
+
onClick: () => {
|
|
91
|
+
(0, timeline_asset_link_1.openTimelineAssetLink)(assetLinkInfo, selectAsset);
|
|
92
|
+
},
|
|
93
|
+
quickSwitcherLabel: null,
|
|
94
|
+
subMenu: null,
|
|
95
|
+
value: 'show-asset',
|
|
96
|
+
}
|
|
97
|
+
: null,
|
|
98
|
+
documentationLink || assetLinkInfo
|
|
99
|
+
? {
|
|
100
|
+
type: 'divider',
|
|
101
|
+
id: 'sequence-link-divider',
|
|
102
|
+
}
|
|
103
|
+
: null,
|
|
104
|
+
sourceActions.length > 0
|
|
105
|
+
? {
|
|
106
|
+
type: 'divider',
|
|
107
|
+
id: 'sequence-source-actions-divider',
|
|
108
|
+
}
|
|
109
|
+
: null,
|
|
110
|
+
...sourceActions,
|
|
111
|
+
{
|
|
112
|
+
type: 'item',
|
|
113
|
+
id: 'disable-interactivity',
|
|
114
|
+
keyHint: null,
|
|
115
|
+
label: 'Disable interactivity',
|
|
116
|
+
leftItem: null,
|
|
117
|
+
disabled: disableInteractivityDisabled,
|
|
118
|
+
onClick: onDisableSequenceInteractivity,
|
|
119
|
+
quickSwitcherLabel: null,
|
|
120
|
+
subMenu: null,
|
|
121
|
+
value: 'disable-interactivity',
|
|
122
|
+
},
|
|
123
|
+
includeSourceEditItems
|
|
124
|
+
? {
|
|
125
|
+
type: 'item',
|
|
126
|
+
id: 'duplicate-sequence',
|
|
127
|
+
keyHint: null,
|
|
128
|
+
label: 'Duplicate',
|
|
129
|
+
leftItem: null,
|
|
130
|
+
disabled: duplicateDisabled,
|
|
131
|
+
onClick: onDuplicateSequenceFromSource,
|
|
132
|
+
quickSwitcherLabel: null,
|
|
133
|
+
subMenu: null,
|
|
134
|
+
value: 'duplicate-sequence',
|
|
135
|
+
}
|
|
136
|
+
: null,
|
|
137
|
+
includeSourceEditItems
|
|
138
|
+
? {
|
|
139
|
+
type: 'divider',
|
|
140
|
+
id: 'sequence-duplicate-delete-divider',
|
|
141
|
+
}
|
|
142
|
+
: null,
|
|
143
|
+
includeSourceEditItems
|
|
144
|
+
? {
|
|
145
|
+
type: 'item',
|
|
146
|
+
id: 'delete-sequence',
|
|
147
|
+
keyHint: null,
|
|
148
|
+
label: 'Delete',
|
|
149
|
+
leftItem: null,
|
|
150
|
+
disabled: deleteDisabled,
|
|
151
|
+
onClick: onDeleteSequenceFromSource,
|
|
152
|
+
quickSwitcherLabel: null,
|
|
153
|
+
subMenu: null,
|
|
154
|
+
value: 'delete-sequence',
|
|
155
|
+
}
|
|
156
|
+
: null,
|
|
157
|
+
].filter(no_react_1.NoReactInternals.truthy);
|
|
158
|
+
return normalizeMenuDividers(items);
|
|
159
|
+
};
|
|
160
|
+
exports.getSequenceContextMenuItems = getSequenceContextMenuItems;
|
|
@@ -2,11 +2,12 @@ import type { SequenceNodePath, SequenceSchema } from 'remotion';
|
|
|
2
2
|
import { callApi } from '../call-api';
|
|
3
3
|
type SubscribeResult = Awaited<ReturnType<typeof callApi<'/api/subscribe-to-sequence-props'>>>;
|
|
4
4
|
type ApplyResult = (result: SubscribeResult) => void;
|
|
5
|
-
export declare const acquireSequencePropsSubscription: ({ fileName, line, column, schema, effects, nodePath, clientId, applyOnce, applyEach, }: {
|
|
5
|
+
export declare const acquireSequencePropsSubscription: ({ fileName, line, column, schema, componentIdentity, effects, nodePath, clientId, applyOnce, applyEach, }: {
|
|
6
6
|
fileName: string;
|
|
7
7
|
line: number;
|
|
8
8
|
column: number;
|
|
9
9
|
schema: SequenceSchema;
|
|
10
|
+
componentIdentity: string | null;
|
|
10
11
|
effects: SequenceSchema[];
|
|
11
12
|
nodePath: SequenceNodePath | null;
|
|
12
13
|
clientId: string;
|
|
@@ -4,12 +4,19 @@ exports.acquireSequencePropsSubscription = void 0;
|
|
|
4
4
|
const studio_shared_1 = require("@remotion/studio-shared");
|
|
5
5
|
const remotion_1 = require("remotion");
|
|
6
6
|
const call_api_1 = require("../call-api");
|
|
7
|
-
const makeKey = (fileName, line, column, sequenceKeys, effectKeys) => `${fileName}\0${line}\0${column}\0${sequenceKeys.join('\0')}\0${effectKeys.map((keys) => keys.join('\0')).join('\0\0')}`;
|
|
7
|
+
const makeKey = ({ fileName, line, column, componentIdentity, sequenceKeys, effectKeys, }) => `${fileName}\0${line}\0${column}\0${componentIdentity !== null && componentIdentity !== void 0 ? componentIdentity : ''}\0${sequenceKeys.join('\0')}\0${effectKeys.map((keys) => keys.join('\0')).join('\0\0')}`;
|
|
8
8
|
const entries = new Map();
|
|
9
|
-
const acquireSequencePropsSubscription = ({ fileName, line, column, schema, effects, nodePath, clientId, applyOnce, applyEach, }) => {
|
|
9
|
+
const acquireSequencePropsSubscription = ({ fileName, line, column, schema, componentIdentity, effects, nodePath, clientId, applyOnce, applyEach, }) => {
|
|
10
10
|
const sequenceKeys = (0, studio_shared_1.getAllSchemaKeys)(schema);
|
|
11
11
|
const effectKeys = effects.map((effect) => (0, studio_shared_1.getAllSchemaKeys)(effect));
|
|
12
|
-
const key = makeKey(
|
|
12
|
+
const key = makeKey({
|
|
13
|
+
fileName,
|
|
14
|
+
line,
|
|
15
|
+
column,
|
|
16
|
+
componentIdentity,
|
|
17
|
+
sequenceKeys,
|
|
18
|
+
effectKeys,
|
|
19
|
+
});
|
|
13
20
|
let entry = entries.get(key);
|
|
14
21
|
if (!entry) {
|
|
15
22
|
const promise = (0, call_api_1.callApi)('/api/subscribe-to-sequence-props', {
|
|
@@ -17,6 +24,7 @@ const acquireSequencePropsSubscription = ({ fileName, line, column, schema, effe
|
|
|
17
24
|
line,
|
|
18
25
|
column,
|
|
19
26
|
nodePath,
|
|
27
|
+
componentIdentity,
|
|
20
28
|
keys: (0, studio_shared_1.getAllSchemaKeys)(schema),
|
|
21
29
|
effects: effectKeys,
|
|
22
30
|
clientId,
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
export declare const PREVENT_CLEAR_SELECTION_ON_POINTER_DOWN_ATTR = "data-remotion-prevent-selection-clear";
|
|
1
2
|
export declare const shouldClearSelectionOnPointerDown: (event: {
|
|
2
3
|
readonly button: number;
|
|
4
|
+
readonly target?: EventTarget | null | undefined;
|
|
3
5
|
}) => boolean;
|
|
@@ -1,7 +1,21 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.shouldClearSelectionOnPointerDown = void 0;
|
|
3
|
+
exports.shouldClearSelectionOnPointerDown = exports.PREVENT_CLEAR_SELECTION_ON_POINTER_DOWN_ATTR = void 0;
|
|
4
|
+
exports.PREVENT_CLEAR_SELECTION_ON_POINTER_DOWN_ATTR = 'data-remotion-prevent-selection-clear';
|
|
5
|
+
const isSelectionClearBlocked = (target) => {
|
|
6
|
+
if (target === null ||
|
|
7
|
+
target === undefined ||
|
|
8
|
+
typeof target !== 'object' ||
|
|
9
|
+
!('closest' in target) ||
|
|
10
|
+
typeof target.closest !== 'function') {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
return (target.closest(`[${exports.PREVENT_CLEAR_SELECTION_ON_POINTER_DOWN_ATTR}]`) !== null);
|
|
14
|
+
};
|
|
4
15
|
const shouldClearSelectionOnPointerDown = (event) => {
|
|
5
|
-
|
|
16
|
+
if (event.button !== 0) {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
return !isSelectionClearBlocked(event.target);
|
|
6
20
|
};
|
|
7
21
|
exports.shouldClearSelectionOnPointerDown = shouldClearSelectionOnPointerDown;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { LoopDisplay } from 'remotion';
|
|
2
|
+
export type TimelineVideoFilmstripTimes = {
|
|
3
|
+
type: 'frozen';
|
|
4
|
+
timestampInSeconds: number;
|
|
5
|
+
} | {
|
|
6
|
+
type: 'range';
|
|
7
|
+
fromSeconds: number;
|
|
8
|
+
toSeconds: number;
|
|
9
|
+
};
|
|
10
|
+
export declare const getTimelineVideoFilmstripTimes: ({ trimBefore, durationInFrames, playbackRate, fps, loopDisplay, frozenMediaFrame, }: {
|
|
11
|
+
trimBefore: number;
|
|
12
|
+
durationInFrames: number;
|
|
13
|
+
playbackRate: number;
|
|
14
|
+
fps: number;
|
|
15
|
+
loopDisplay: LoopDisplay | undefined;
|
|
16
|
+
frozenMediaFrame: number | null;
|
|
17
|
+
}) => TimelineVideoFilmstripTimes;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getTimelineVideoFilmstripTimes = void 0;
|
|
4
|
+
const timeline_utils_1 = require("@remotion/timeline-utils");
|
|
5
|
+
const getTimelineVideoFilmstripTimes = ({ trimBefore, durationInFrames, playbackRate, fps, loopDisplay, frozenMediaFrame, }) => {
|
|
6
|
+
if (frozenMediaFrame !== null) {
|
|
7
|
+
return {
|
|
8
|
+
type: 'frozen',
|
|
9
|
+
timestampInSeconds: Math.max(0, frozenMediaFrame / fps),
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
const fromSeconds = trimBefore / fps;
|
|
13
|
+
const visibleDurationInFrames = (0, timeline_utils_1.shouldTileLoopDisplay)(loopDisplay) && loopDisplay
|
|
14
|
+
? loopDisplay.durationInFrames
|
|
15
|
+
: durationInFrames;
|
|
16
|
+
return {
|
|
17
|
+
type: 'range',
|
|
18
|
+
fromSeconds,
|
|
19
|
+
toSeconds: fromSeconds + (visibleDurationInFrames * playbackRate) / fps,
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
exports.getTimelineVideoFilmstripTimes = getTimelineVideoFilmstripTimes;
|
|
@@ -3,19 +3,17 @@ import type { SetPropStatuses } from './save-sequence-prop';
|
|
|
3
3
|
import type { TimelineEasingSelection, TimelineSelection } from './TimelineSelection';
|
|
4
4
|
export type EasingSelection = TimelineEasingSelection;
|
|
5
5
|
export type TimelineEasingValue = 'linear' | [number, number, number, number];
|
|
6
|
-
export declare const getEasingSelections: (selections: readonly TimelineSelection[]) =>
|
|
7
|
-
readonly nodePathInfo: import("../../helpers/get-timeline-sequence-sort-key").SequenceNodePathInfo;
|
|
8
|
-
} & {
|
|
6
|
+
export declare const getEasingSelections: (selections: readonly TimelineSelection[]) => {
|
|
9
7
|
readonly type: "easing";
|
|
8
|
+
readonly nodePathInfo: import("../../helpers/get-timeline-sequence-sort-key").SequenceNodePathInfo;
|
|
10
9
|
readonly fromFrame: number;
|
|
11
10
|
readonly toFrame: number;
|
|
12
11
|
readonly segmentIndex: number;
|
|
13
|
-
}
|
|
12
|
+
}[];
|
|
14
13
|
export declare const getTimelineEasingValueForSelection: ({ selection, sequences, overrideIdsToNodePaths, propStatuses, }: {
|
|
15
14
|
selection: {
|
|
16
|
-
readonly nodePathInfo: import("../../helpers/get-timeline-sequence-sort-key").SequenceNodePathInfo;
|
|
17
|
-
} & {
|
|
18
15
|
readonly type: "easing";
|
|
16
|
+
readonly nodePathInfo: import("../../helpers/get-timeline-sequence-sort-key").SequenceNodePathInfo;
|
|
19
17
|
readonly fromFrame: number;
|
|
20
18
|
readonly toFrame: number;
|
|
21
19
|
readonly segmentIndex: number;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { SequenceSchema } from 'remotion';
|
|
2
2
|
import type { OriginalPosition } from '../../error-overlay/react-overlay/utils/get-source-map';
|
|
3
|
-
export declare const useSequencePropsSubscription: ({ originalLocation, overrideId, schema, effects, }: {
|
|
3
|
+
export declare const useSequencePropsSubscription: ({ originalLocation, overrideId, componentIdentity, schema, effects, }: {
|
|
4
4
|
overrideId: string;
|
|
5
|
+
componentIdentity: string | null;
|
|
5
6
|
schema: SequenceSchema;
|
|
6
7
|
effects: SequenceSchema[];
|
|
7
8
|
originalLocation: OriginalPosition | null;
|
|
@@ -7,7 +7,7 @@ const remotion_1 = require("remotion");
|
|
|
7
7
|
const client_id_1 = require("../../helpers/client-id");
|
|
8
8
|
const ExpandedTracksProvider_1 = require("../ExpandedTracksProvider");
|
|
9
9
|
const sequence_props_subscription_store_1 = require("./sequence-props-subscription-store");
|
|
10
|
-
const useSequencePropsSubscription = ({ originalLocation, overrideId, schema, effects, }) => {
|
|
10
|
+
const useSequencePropsSubscription = ({ originalLocation, overrideId, componentIdentity, schema, effects, }) => {
|
|
11
11
|
var _a, _b, _c;
|
|
12
12
|
const { setPropStatuses } = (0, react_1.useContext)(remotion_1.Internals.VisualModeSettersContext);
|
|
13
13
|
const { setOverrideIdToNodePath } = (0, react_1.useContext)(remotion_1.Internals.OverrideIdsToNodePathsSettersContext);
|
|
@@ -50,6 +50,7 @@ const useSequencePropsSubscription = ({ originalLocation, overrideId, schema, ef
|
|
|
50
50
|
line: locationLine,
|
|
51
51
|
column: locationColumn,
|
|
52
52
|
schema,
|
|
53
|
+
componentIdentity,
|
|
53
54
|
effects,
|
|
54
55
|
nodePath: (_b = nodePathAtResubscribe === null || nodePathAtResubscribe === void 0 ? void 0 : nodePathAtResubscribe.nodePath) !== null && _b !== void 0 ? _b : null,
|
|
55
56
|
clientId,
|
|
@@ -85,6 +86,7 @@ const useSequencePropsSubscription = ({ originalLocation, overrideId, schema, ef
|
|
|
85
86
|
};
|
|
86
87
|
}, [
|
|
87
88
|
clientId,
|
|
89
|
+
componentIdentity,
|
|
88
90
|
effects,
|
|
89
91
|
effectsSignature,
|
|
90
92
|
locationColumn,
|
|
@@ -1,6 +1,30 @@
|
|
|
1
1
|
import type React from 'react';
|
|
2
2
|
import type { SequenceNodePathInfo } from '../../helpers/get-timeline-sequence-sort-key';
|
|
3
|
-
import { type
|
|
3
|
+
import { type TimelineDraggedKeyframe } from './TimelineKeyframeDragState';
|
|
4
|
+
import { type TimelineSelection, type TimelineSelectionInteraction } from './TimelineSelection';
|
|
5
|
+
export declare const getKeyframesForTimelineEasingDrag: ({ currentSelections, interaction, selectionItem, selected, }: {
|
|
6
|
+
readonly currentSelections: readonly TimelineSelection[];
|
|
7
|
+
readonly interaction: TimelineSelectionInteraction;
|
|
8
|
+
readonly selectionItem: {
|
|
9
|
+
readonly type: "easing";
|
|
10
|
+
readonly nodePathInfo: SequenceNodePathInfo;
|
|
11
|
+
readonly fromFrame: number;
|
|
12
|
+
readonly toFrame: number;
|
|
13
|
+
readonly segmentIndex: number;
|
|
14
|
+
};
|
|
15
|
+
readonly selected: boolean;
|
|
16
|
+
}) => ({
|
|
17
|
+
readonly type: "keyframe";
|
|
18
|
+
readonly nodePathInfo: SequenceNodePathInfo;
|
|
19
|
+
readonly frame: number;
|
|
20
|
+
} & {
|
|
21
|
+
type: "keyframe";
|
|
22
|
+
})[];
|
|
23
|
+
export declare const getTimelineSelectionsAfterEasingKeyframeDrag: ({ delta, selections, targets, }: {
|
|
24
|
+
readonly delta: number;
|
|
25
|
+
readonly selections: readonly TimelineSelection[];
|
|
26
|
+
readonly targets: readonly TimelineDraggedKeyframe[];
|
|
27
|
+
}) => TimelineSelection[];
|
|
4
28
|
export declare const useTimelineKeyframeDrag: ({ frame, nodePathInfo, onSelect, selectable, selected, }: {
|
|
5
29
|
readonly frame: number;
|
|
6
30
|
readonly nodePathInfo: SequenceNodePathInfo;
|
|
@@ -8,3 +32,15 @@ export declare const useTimelineKeyframeDrag: ({ frame, nodePathInfo, onSelect,
|
|
|
8
32
|
readonly selectable: boolean;
|
|
9
33
|
readonly selected: boolean;
|
|
10
34
|
}) => (e: React.PointerEvent<HTMLButtonElement>) => void;
|
|
35
|
+
export declare const useTimelineEasingKeyframeDrag: ({ onSelect, selectable, selected, selectionItem, }: {
|
|
36
|
+
readonly onSelect: (interaction?: TimelineSelectionInteraction | undefined) => void;
|
|
37
|
+
readonly selectable: boolean;
|
|
38
|
+
readonly selected: boolean;
|
|
39
|
+
readonly selectionItem: {
|
|
40
|
+
readonly type: "easing";
|
|
41
|
+
readonly nodePathInfo: SequenceNodePathInfo;
|
|
42
|
+
readonly fromFrame: number;
|
|
43
|
+
readonly toFrame: number;
|
|
44
|
+
readonly segmentIndex: number;
|
|
45
|
+
};
|
|
46
|
+
}) => (e: React.PointerEvent<HTMLButtonElement>) => void;
|