@remotion/studio 4.0.458 → 4.0.460
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/audio-waveform-worker.js +4 -4
- package/dist/components/AudioWaveform.js +4 -4
- package/dist/components/Checkbox.d.ts +7 -0
- package/dist/components/Checkbox.js +38 -24
- package/dist/components/Editor.js +10 -9
- package/dist/components/ExpandedTracksProvider.d.ts +9 -4
- package/dist/components/ExpandedTracksProvider.js +45 -15
- package/dist/components/MenuBuildIndicator.js +0 -1
- package/dist/components/NewComposition/ComboBox.d.ts +1 -0
- package/dist/components/NewComposition/ComboBox.js +14 -5
- package/dist/components/SequencePropsSubscriptionProvider.d.ts +3 -0
- package/dist/components/SequencePropsSubscriptionProvider.js +26 -0
- package/dist/components/Timeline/SequencePropsObserver.d.ts +1 -0
- package/dist/components/Timeline/SequencePropsObserver.js +24 -0
- package/dist/components/Timeline/SubscribeToNodePaths.d.ts +7 -0
- package/dist/components/Timeline/SubscribeToNodePaths.js +15 -0
- package/dist/components/Timeline/Timeline.js +28 -48
- package/dist/components/Timeline/TimelineBooleanField.js +1 -1
- package/dist/components/Timeline/TimelineEnumField.js +18 -10
- package/dist/components/Timeline/TimelineExpandArrowButton.d.ts +1 -0
- package/dist/components/Timeline/TimelineExpandArrowButton.js +5 -3
- package/dist/components/Timeline/TimelineExpandedRow.d.ts +6 -6
- package/dist/components/Timeline/TimelineExpandedRow.js +4 -5
- package/dist/components/Timeline/TimelineExpandedSection.d.ts +2 -2
- package/dist/components/Timeline/TimelineExpandedSection.js +20 -9
- package/dist/components/Timeline/TimelineFieldRow.d.ts +2 -3
- package/dist/components/Timeline/TimelineFieldRow.js +23 -20
- package/dist/components/Timeline/TimelineHeightContainer.d.ts +7 -0
- package/dist/components/Timeline/TimelineHeightContainer.js +18 -0
- package/dist/components/Timeline/TimelineList.js +1 -1
- package/dist/components/Timeline/TimelineListItem.d.ts +2 -0
- package/dist/components/Timeline/TimelineListItem.js +27 -13
- package/dist/components/Timeline/TimelineSchemaField.js +4 -1
- package/dist/components/Timeline/TimelineTracks.js +18 -7
- package/dist/components/Timeline/TimelineVideoInfo.js +25 -140
- package/dist/components/Timeline/sequence-props-subscription-store.d.ts +10 -13
- package/dist/components/Timeline/sequence-props-subscription-store.js +56 -123
- package/dist/components/Timeline/use-sequence-props-subscription.d.ts +6 -6
- package/dist/components/Timeline/use-sequence-props-subscription.js +25 -55
- package/dist/components/Timeline/use-timeline-height.d.ts +5 -0
- package/dist/components/Timeline/use-timeline-height.js +48 -0
- package/dist/components/draw-peaks.js +7 -0
- package/dist/esm/audio-waveform-worker.mjs +9 -14
- package/dist/esm/{chunk-261b3aa0.js → chunk-nrgs0ad5.js} +2810 -2975
- package/dist/esm/internals.mjs +2810 -2975
- package/dist/esm/previewEntry.mjs +2809 -2974
- package/dist/esm/renderEntry.mjs +1 -1
- package/dist/helpers/calculate-timeline.d.ts +3 -2
- package/dist/helpers/calculate-timeline.js +21 -2
- package/dist/helpers/get-timeline-sequence-layout.js +3 -3
- package/dist/helpers/get-timeline-sequence-sort-key.d.ts +6 -1
- package/dist/helpers/timeline-layout.d.ts +18 -9
- package/dist/helpers/timeline-layout.js +24 -16
- package/dist/icons/Checkmark.d.ts +4 -1
- package/dist/icons/Checkmark.js +1 -5
- package/dist/icons/caret.d.ts +3 -1
- package/dist/icons/caret.js +5 -2
- package/package.json +10 -9
- package/dist/components/looped-media-timeline.d.ts +0 -6
- package/dist/components/looped-media-timeline.js +0 -14
- package/dist/helpers/extract-frames.d.ts +0 -18
- package/dist/helpers/extract-frames.js +0 -87
- package/dist/helpers/frame-database.d.ts +0 -16
- package/dist/helpers/frame-database.js +0 -65
- package/dist/helpers/resize-video-frame.d.ts +0 -4
- package/dist/helpers/resize-video-frame.js +0 -39
|
@@ -2,14 +2,11 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.TimelineVideoInfo = void 0;
|
|
4
4
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const timeline_utils_1 = require("@remotion/timeline-utils");
|
|
5
6
|
const react_1 = require("react");
|
|
6
7
|
const remotion_1 = require("remotion");
|
|
7
|
-
const extract_frames_1 = require("../../helpers/extract-frames");
|
|
8
|
-
const frame_database_1 = require("../../helpers/frame-database");
|
|
9
|
-
const resize_video_frame_1 = require("../../helpers/resize-video-frame");
|
|
10
8
|
const timeline_layout_1 = require("../../helpers/timeline-layout");
|
|
11
9
|
const AudioWaveform_1 = require("../AudioWaveform");
|
|
12
|
-
const looped_media_timeline_1 = require("../looped-media-timeline");
|
|
13
10
|
const FILMSTRIP_HEIGHT = timeline_layout_1.TIMELINE_LAYER_HEIGHT_IMAGE - 2;
|
|
14
11
|
const outerStyle = {
|
|
15
12
|
width: '100%',
|
|
@@ -26,132 +23,11 @@ const filmstripContainerStyle = {
|
|
|
26
23
|
fontSize: 10,
|
|
27
24
|
fontFamily: 'Arial, Helvetica',
|
|
28
25
|
};
|
|
29
|
-
const WEBCODECS_TIMESCALE = 1000000;
|
|
30
|
-
const MAX_TIME_DEVIATION = WEBCODECS_TIMESCALE * 0.05;
|
|
31
|
-
const getDurationOfOneFrame = ({ visualizationWidth, aspectRatio, segmentDuration, }) => {
|
|
32
|
-
const framesFitInWidthUnrounded = visualizationWidth / (FILMSTRIP_HEIGHT * aspectRatio);
|
|
33
|
-
return (segmentDuration / framesFitInWidthUnrounded) * WEBCODECS_TIMESCALE;
|
|
34
|
-
};
|
|
35
|
-
const fixRounding = (value) => {
|
|
36
|
-
if (value % 1 >= 0.49999999) {
|
|
37
|
-
return Math.ceil(value);
|
|
38
|
-
}
|
|
39
|
-
return Math.floor(value);
|
|
40
|
-
};
|
|
41
|
-
const calculateTimestampSlots = ({ visualizationWidth, fromSeconds, segmentDuration, aspectRatio, }) => {
|
|
42
|
-
const framesFitInWidthUnrounded = visualizationWidth / (FILMSTRIP_HEIGHT * aspectRatio);
|
|
43
|
-
const framesFitInWidth = Math.ceil(framesFitInWidthUnrounded);
|
|
44
|
-
const durationOfOneFrame = getDurationOfOneFrame({
|
|
45
|
-
visualizationWidth,
|
|
46
|
-
aspectRatio,
|
|
47
|
-
segmentDuration,
|
|
48
|
-
});
|
|
49
|
-
const timestampTargets = [];
|
|
50
|
-
for (let i = 0; i < framesFitInWidth + 1; i++) {
|
|
51
|
-
const target = fromSeconds * WEBCODECS_TIMESCALE + durationOfOneFrame * (i + 0.5);
|
|
52
|
-
const snappedToDuration = (Math.round(fixRounding(target / durationOfOneFrame)) - 1) *
|
|
53
|
-
durationOfOneFrame;
|
|
54
|
-
timestampTargets.push(snappedToDuration);
|
|
55
|
-
}
|
|
56
|
-
return timestampTargets;
|
|
57
|
-
};
|
|
58
|
-
const ensureSlots = ({ filledSlots, naturalWidth, fromSeconds, toSeconds, aspectRatio, }) => {
|
|
59
|
-
const segmentDuration = toSeconds - fromSeconds;
|
|
60
|
-
const timestampTargets = calculateTimestampSlots({
|
|
61
|
-
visualizationWidth: naturalWidth,
|
|
62
|
-
fromSeconds,
|
|
63
|
-
segmentDuration,
|
|
64
|
-
aspectRatio,
|
|
65
|
-
});
|
|
66
|
-
for (const timestamp of timestampTargets) {
|
|
67
|
-
if (!filledSlots.has(timestamp)) {
|
|
68
|
-
filledSlots.set(timestamp, undefined);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
};
|
|
72
|
-
const drawSlot = ({ frame, ctx, filledSlots, visualizationWidth, timestamp, segmentDuration, fromSeconds, }) => {
|
|
73
|
-
const durationOfOneFrame = getDurationOfOneFrame({
|
|
74
|
-
visualizationWidth,
|
|
75
|
-
aspectRatio: frame.displayWidth / frame.displayHeight,
|
|
76
|
-
segmentDuration,
|
|
77
|
-
});
|
|
78
|
-
const relativeTimestamp = timestamp - fromSeconds * WEBCODECS_TIMESCALE;
|
|
79
|
-
const frameIndex = relativeTimestamp / durationOfOneFrame;
|
|
80
|
-
const thumbnailWidth = frame.displayWidth / window.devicePixelRatio;
|
|
81
|
-
const left = Math.floor(frameIndex * thumbnailWidth);
|
|
82
|
-
const right = Math.ceil((frameIndex + 1) * thumbnailWidth);
|
|
83
|
-
ctx.drawImage(frame, left, 0, right - left, frame.displayHeight / window.devicePixelRatio);
|
|
84
|
-
filledSlots.set(timestamp, frame.timestamp);
|
|
85
|
-
};
|
|
86
|
-
const fillWithCachedFrames = ({ ctx, naturalWidth, filledSlots, src, segmentDuration, fromSeconds, }) => {
|
|
87
|
-
const prefix = (0, frame_database_1.getFrameDatabaseKeyPrefix)(src);
|
|
88
|
-
const keys = Array.from(frame_database_1.frameDatabase.keys()).filter((k) => k.startsWith(prefix));
|
|
89
|
-
const targets = Array.from(filledSlots.keys());
|
|
90
|
-
for (const timestamp of targets) {
|
|
91
|
-
let bestKey;
|
|
92
|
-
let bestDistance = Infinity;
|
|
93
|
-
for (const key of keys) {
|
|
94
|
-
const distance = Math.abs((0, frame_database_1.getTimestampFromFrameDatabaseKey)(key) - timestamp);
|
|
95
|
-
if (distance < bestDistance) {
|
|
96
|
-
bestDistance = distance;
|
|
97
|
-
bestKey = key;
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
if (!bestKey) {
|
|
101
|
-
continue;
|
|
102
|
-
}
|
|
103
|
-
const frame = frame_database_1.frameDatabase.get(bestKey);
|
|
104
|
-
if (!frame) {
|
|
105
|
-
continue;
|
|
106
|
-
}
|
|
107
|
-
const alreadyFilled = filledSlots.get(timestamp);
|
|
108
|
-
// Don't fill if a closer frame was already drawn
|
|
109
|
-
if (alreadyFilled &&
|
|
110
|
-
Math.abs(alreadyFilled - timestamp) <=
|
|
111
|
-
Math.abs(frame.frame.timestamp - timestamp)) {
|
|
112
|
-
continue;
|
|
113
|
-
}
|
|
114
|
-
frame.lastUsed = Date.now();
|
|
115
|
-
drawSlot({
|
|
116
|
-
ctx,
|
|
117
|
-
frame: frame.frame,
|
|
118
|
-
filledSlots,
|
|
119
|
-
visualizationWidth: naturalWidth,
|
|
120
|
-
timestamp,
|
|
121
|
-
segmentDuration,
|
|
122
|
-
fromSeconds,
|
|
123
|
-
});
|
|
124
|
-
}
|
|
125
|
-
};
|
|
126
|
-
const fillFrameWhereItFits = ({ frame, filledSlots, ctx, visualizationWidth, segmentDuration, fromSeconds, }) => {
|
|
127
|
-
const slots = Array.from(filledSlots.keys());
|
|
128
|
-
for (let i = 0; i < slots.length; i++) {
|
|
129
|
-
const slot = slots[i];
|
|
130
|
-
if (Math.abs(slot - frame.timestamp) > MAX_TIME_DEVIATION) {
|
|
131
|
-
continue;
|
|
132
|
-
}
|
|
133
|
-
const filled = filledSlots.get(slot);
|
|
134
|
-
// Don't fill if a better timestamp was already filled
|
|
135
|
-
if (filled &&
|
|
136
|
-
Math.abs(filled - slot) <= Math.abs(filled - frame.timestamp)) {
|
|
137
|
-
continue;
|
|
138
|
-
}
|
|
139
|
-
drawSlot({
|
|
140
|
-
ctx,
|
|
141
|
-
frame,
|
|
142
|
-
filledSlots,
|
|
143
|
-
visualizationWidth,
|
|
144
|
-
timestamp: slot,
|
|
145
|
-
segmentDuration,
|
|
146
|
-
fromSeconds,
|
|
147
|
-
});
|
|
148
|
-
}
|
|
149
|
-
};
|
|
150
26
|
const TimelineVideoInfo = ({ src, visualizationWidth, naturalWidth, trimBefore, durationInFrames, playbackRate, volume, doesVolumeChange, premountWidth, postmountWidth, loopDisplay, }) => {
|
|
151
27
|
const { fps } = (0, remotion_1.useVideoConfig)();
|
|
152
28
|
const ref = (0, react_1.useRef)(null);
|
|
153
29
|
const [error, setError] = (0, react_1.useState)(null);
|
|
154
|
-
const aspectRatio = (0, react_1.useRef)((0,
|
|
30
|
+
const aspectRatio = (0, react_1.useRef)((0, timeline_utils_1.getAspectRatioFromCache)(src));
|
|
155
31
|
// for rendering frames
|
|
156
32
|
(0, react_1.useEffect)(() => {
|
|
157
33
|
if (error) {
|
|
@@ -170,11 +46,11 @@ const TimelineVideoInfo = ({ src, visualizationWidth, naturalWidth, trimBefore,
|
|
|
170
46
|
return;
|
|
171
47
|
}
|
|
172
48
|
current.appendChild(canvas);
|
|
173
|
-
const loopWidth = (0,
|
|
49
|
+
const loopWidth = (0, timeline_utils_1.getLoopDisplayWidth)({
|
|
174
50
|
visualizationWidth: naturalWidth,
|
|
175
51
|
loopDisplay,
|
|
176
52
|
});
|
|
177
|
-
const shouldRepeatVideo = (0,
|
|
53
|
+
const shouldRepeatVideo = (0, timeline_utils_1.shouldTileLoopDisplay)(loopDisplay);
|
|
178
54
|
const targetCanvas = shouldRepeatVideo
|
|
179
55
|
? document.createElement('canvas')
|
|
180
56
|
: canvas;
|
|
@@ -211,20 +87,23 @@ const TimelineVideoInfo = ({ src, visualizationWidth, naturalWidth, trimBefore,
|
|
|
211
87
|
const toSeconds = fromSeconds + (visibleDurationInFrames * playbackRate) / fps;
|
|
212
88
|
const targetWidth = shouldRepeatVideo ? targetCanvas.width : naturalWidth;
|
|
213
89
|
if (aspectRatio.current !== null) {
|
|
214
|
-
ensureSlots({
|
|
90
|
+
(0, timeline_utils_1.ensureSlots)({
|
|
215
91
|
filledSlots,
|
|
216
92
|
naturalWidth: targetWidth,
|
|
217
93
|
fromSeconds,
|
|
218
94
|
toSeconds,
|
|
219
95
|
aspectRatio: aspectRatio.current,
|
|
96
|
+
frameHeight: FILMSTRIP_HEIGHT,
|
|
220
97
|
});
|
|
221
|
-
fillWithCachedFrames({
|
|
98
|
+
(0, timeline_utils_1.fillWithCachedFrames)({
|
|
222
99
|
ctx: targetCtx,
|
|
223
100
|
naturalWidth: targetWidth,
|
|
224
101
|
filledSlots,
|
|
225
102
|
src,
|
|
226
103
|
segmentDuration: toSeconds - fromSeconds,
|
|
227
104
|
fromSeconds,
|
|
105
|
+
devicePixelRatio: window.devicePixelRatio,
|
|
106
|
+
frameHeight: FILMSTRIP_HEIGHT,
|
|
228
107
|
});
|
|
229
108
|
repeatTarget();
|
|
230
109
|
const unfilled = Array.from(filledSlots.keys()).filter((timestamp) => !filledSlots.get(timestamp));
|
|
@@ -235,18 +114,19 @@ const TimelineVideoInfo = ({ src, visualizationWidth, naturalWidth, trimBefore,
|
|
|
235
114
|
};
|
|
236
115
|
}
|
|
237
116
|
}
|
|
238
|
-
(0,
|
|
117
|
+
(0, timeline_utils_1.extractFrames)({
|
|
239
118
|
timestampsInSeconds: ({ track, }) => {
|
|
240
119
|
aspectRatio.current = track.width / track.height;
|
|
241
|
-
|
|
242
|
-
ensureSlots({
|
|
120
|
+
timeline_utils_1.aspectRatioCache.set(src, aspectRatio.current);
|
|
121
|
+
(0, timeline_utils_1.ensureSlots)({
|
|
243
122
|
filledSlots,
|
|
244
123
|
fromSeconds,
|
|
245
124
|
toSeconds,
|
|
246
125
|
naturalWidth: targetWidth,
|
|
247
126
|
aspectRatio: aspectRatio.current,
|
|
127
|
+
frameHeight: FILMSTRIP_HEIGHT,
|
|
248
128
|
});
|
|
249
|
-
return Array.from(filledSlots.keys()).map((timestamp) => timestamp / WEBCODECS_TIMESCALE);
|
|
129
|
+
return Array.from(filledSlots.keys()).map((timestamp) => timestamp / timeline_utils_1.WEBCODECS_TIMESCALE);
|
|
250
130
|
},
|
|
251
131
|
src,
|
|
252
132
|
onVideoSample: (sample) => {
|
|
@@ -254,7 +134,7 @@ const TimelineVideoInfo = ({ src, visualizationWidth, naturalWidth, trimBefore,
|
|
|
254
134
|
try {
|
|
255
135
|
frame = sample.toVideoFrame();
|
|
256
136
|
const scale = (FILMSTRIP_HEIGHT / frame.displayHeight) * window.devicePixelRatio;
|
|
257
|
-
const transformed = (0,
|
|
137
|
+
const transformed = (0, timeline_utils_1.resizeVideoFrame)({
|
|
258
138
|
frame,
|
|
259
139
|
scale,
|
|
260
140
|
});
|
|
@@ -262,25 +142,28 @@ const TimelineVideoInfo = ({ src, visualizationWidth, naturalWidth, trimBefore,
|
|
|
262
142
|
frame.close();
|
|
263
143
|
}
|
|
264
144
|
frame = undefined;
|
|
265
|
-
const databaseKey = (0,
|
|
266
|
-
(0,
|
|
145
|
+
const databaseKey = (0, timeline_utils_1.makeFrameDatabaseKey)(src, transformed.timestamp);
|
|
146
|
+
(0, timeline_utils_1.addFrameToCache)(databaseKey, transformed);
|
|
267
147
|
if (aspectRatio.current === null) {
|
|
268
148
|
throw new Error('Aspect ratio is not set');
|
|
269
149
|
}
|
|
270
|
-
ensureSlots({
|
|
150
|
+
(0, timeline_utils_1.ensureSlots)({
|
|
271
151
|
filledSlots,
|
|
272
152
|
fromSeconds,
|
|
273
153
|
toSeconds,
|
|
274
154
|
naturalWidth: targetWidth,
|
|
275
155
|
aspectRatio: aspectRatio.current,
|
|
156
|
+
frameHeight: FILMSTRIP_HEIGHT,
|
|
276
157
|
});
|
|
277
|
-
fillFrameWhereItFits({
|
|
158
|
+
(0, timeline_utils_1.fillFrameWhereItFits)({
|
|
278
159
|
ctx: targetCtx,
|
|
279
160
|
filledSlots,
|
|
280
161
|
visualizationWidth: targetWidth,
|
|
281
162
|
frame: transformed,
|
|
282
163
|
segmentDuration: toSeconds - fromSeconds,
|
|
283
164
|
fromSeconds,
|
|
165
|
+
devicePixelRatio: window.devicePixelRatio,
|
|
166
|
+
frameHeight: FILMSTRIP_HEIGHT,
|
|
284
167
|
});
|
|
285
168
|
repeatTarget();
|
|
286
169
|
}
|
|
@@ -300,13 +183,15 @@ const TimelineVideoInfo = ({ src, visualizationWidth, naturalWidth, trimBefore,
|
|
|
300
183
|
if (controller.signal.aborted) {
|
|
301
184
|
return;
|
|
302
185
|
}
|
|
303
|
-
fillWithCachedFrames({
|
|
186
|
+
(0, timeline_utils_1.fillWithCachedFrames)({
|
|
304
187
|
ctx: targetCtx,
|
|
305
188
|
naturalWidth: targetWidth,
|
|
306
189
|
filledSlots,
|
|
307
190
|
src,
|
|
308
191
|
segmentDuration: toSeconds - fromSeconds,
|
|
309
192
|
fromSeconds,
|
|
193
|
+
devicePixelRatio: window.devicePixelRatio,
|
|
194
|
+
frameHeight: FILMSTRIP_HEIGHT,
|
|
310
195
|
});
|
|
311
196
|
repeatTarget();
|
|
312
197
|
})
|
|
@@ -1,19 +1,16 @@
|
|
|
1
|
-
import type { EventSourceEvent, SequenceNodePath } from '@remotion/studio-shared';
|
|
2
|
-
import { type CanUpdateSequencePropStatus } from 'remotion';
|
|
3
1
|
import type { SequenceSchema } from 'remotion';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
};
|
|
9
|
-
type SubscribeToEvent = (type: EventSourceEvent['type'], listener: (event: EventSourceEvent) => void) => () => void;
|
|
10
|
-
export declare const acquireSequencePropsSubscription: ({ clientId, fileName, line, column, schema, subscribeToEvent, onChange, }: {
|
|
11
|
-
clientId: string;
|
|
2
|
+
import { callApi } from '../call-api';
|
|
3
|
+
type SubscribeResult = Awaited<ReturnType<typeof callApi<'/api/subscribe-to-sequence-props'>>>;
|
|
4
|
+
type ApplyResult = (result: SubscribeResult) => void;
|
|
5
|
+
export declare const acquireSequencePropsSubscription: ({ fileName, line, column, schema, clientId, applyOnce, applyEach, }: {
|
|
12
6
|
fileName: string;
|
|
13
7
|
line: number;
|
|
14
8
|
column: number;
|
|
15
9
|
schema: SequenceSchema;
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
10
|
+
clientId: string;
|
|
11
|
+
applyOnce: ApplyResult;
|
|
12
|
+
applyEach: ApplyResult;
|
|
13
|
+
}) => {
|
|
14
|
+
release: () => void;
|
|
15
|
+
};
|
|
19
16
|
export {};
|
|
@@ -3,149 +3,82 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.acquireSequencePropsSubscription = void 0;
|
|
4
4
|
const remotion_1 = require("remotion");
|
|
5
5
|
const call_api_1 = require("../call-api");
|
|
6
|
-
const
|
|
7
|
-
nodePath: null,
|
|
8
|
-
jsxInMapCallback: false,
|
|
9
|
-
props: null,
|
|
10
|
-
};
|
|
6
|
+
const makeKey = (fileName, line, column) => `${fileName}\0${line}\0${column}`;
|
|
11
7
|
const entries = new Map();
|
|
12
|
-
|
|
13
|
-
const makeKey = (fileName, line, column) => `${fileName}|${line}|${column}`;
|
|
14
|
-
const nodePathsEqual = (a, b) => {
|
|
15
|
-
if (!a || !b) {
|
|
16
|
-
return false;
|
|
17
|
-
}
|
|
18
|
-
return JSON.stringify(a) === JSON.stringify(b);
|
|
19
|
-
};
|
|
20
|
-
const notify = (entry) => {
|
|
21
|
-
for (const listener of entry.listeners) {
|
|
22
|
-
listener(entry.snapshot);
|
|
23
|
-
}
|
|
24
|
-
};
|
|
25
|
-
const handleEvent = (event) => {
|
|
26
|
-
if (event.type !== 'sequence-props-updated') {
|
|
27
|
-
return;
|
|
28
|
-
}
|
|
29
|
-
for (const entry of entries.values()) {
|
|
30
|
-
if (entry.fileName !== event.fileName) {
|
|
31
|
-
continue;
|
|
32
|
-
}
|
|
33
|
-
if (!nodePathsEqual(entry.snapshot.nodePath, event.nodePath)) {
|
|
34
|
-
continue;
|
|
35
|
-
}
|
|
36
|
-
if (event.result.canUpdate) {
|
|
37
|
-
entry.snapshot = {
|
|
38
|
-
nodePath: entry.snapshot.nodePath,
|
|
39
|
-
jsxInMapCallback: event.result.jsxInMapCallback,
|
|
40
|
-
props: event.result.props,
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
else {
|
|
44
|
-
entry.snapshot = {
|
|
45
|
-
nodePath: entry.snapshot.nodePath,
|
|
46
|
-
jsxInMapCallback: false,
|
|
47
|
-
props: null,
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
notify(entry);
|
|
51
|
-
}
|
|
52
|
-
};
|
|
53
|
-
const ensureGlobalListener = (subscribeToEvent) => {
|
|
54
|
-
if (globalUnsubscribe) {
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
globalUnsubscribe = subscribeToEvent('sequence-props-updated', handleEvent);
|
|
58
|
-
};
|
|
59
|
-
const teardownGlobalListenerIfEmpty = () => {
|
|
60
|
-
if (entries.size > 0) {
|
|
61
|
-
return;
|
|
62
|
-
}
|
|
63
|
-
if (globalUnsubscribe) {
|
|
64
|
-
globalUnsubscribe();
|
|
65
|
-
globalUnsubscribe = null;
|
|
66
|
-
}
|
|
67
|
-
};
|
|
68
|
-
const fireUnsubscribe = (fileName, nodePath, clientId) => {
|
|
69
|
-
(0, call_api_1.callApi)('/api/unsubscribe-from-sequence-props', {
|
|
70
|
-
fileName,
|
|
71
|
-
nodePath,
|
|
72
|
-
clientId,
|
|
73
|
-
}).catch(() => {
|
|
74
|
-
// Ignore unsubscribe errors
|
|
75
|
-
});
|
|
76
|
-
};
|
|
77
|
-
const acquireSequencePropsSubscription = ({ clientId, fileName, line, column, schema, subscribeToEvent, onChange, }) => {
|
|
8
|
+
const acquireSequencePropsSubscription = ({ fileName, line, column, schema, clientId, applyOnce, applyEach, }) => {
|
|
78
9
|
const key = makeKey(fileName, line, column);
|
|
79
10
|
let entry = entries.get(key);
|
|
80
11
|
if (!entry) {
|
|
81
|
-
const
|
|
82
|
-
clientId,
|
|
83
|
-
fileName,
|
|
84
|
-
refCount: 0,
|
|
85
|
-
snapshot: INITIAL_SNAPSHOT,
|
|
86
|
-
listeners: new Set(),
|
|
87
|
-
tornDown: false,
|
|
88
|
-
};
|
|
89
|
-
entries.set(key, newEntry);
|
|
90
|
-
ensureGlobalListener(subscribeToEvent);
|
|
91
|
-
(0, call_api_1.callApi)('/api/subscribe-to-sequence-props', {
|
|
12
|
+
const promise = (0, call_api_1.callApi)('/api/subscribe-to-sequence-props', {
|
|
92
13
|
fileName,
|
|
93
14
|
line,
|
|
94
15
|
column,
|
|
95
16
|
schema,
|
|
96
17
|
clientId,
|
|
97
|
-
})
|
|
18
|
+
});
|
|
19
|
+
const created = {
|
|
20
|
+
refCount: 0,
|
|
21
|
+
promise,
|
|
22
|
+
fileName,
|
|
23
|
+
clientId,
|
|
24
|
+
applyOnce,
|
|
25
|
+
};
|
|
26
|
+
entries.set(key, created);
|
|
27
|
+
entry = created;
|
|
28
|
+
promise
|
|
98
29
|
.then((result) => {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
fireUnsubscribe(fileName, result.nodePath, clientId);
|
|
102
|
-
}
|
|
30
|
+
const current = entries.get(key);
|
|
31
|
+
if (current !== created || !current.applyOnce) {
|
|
103
32
|
return;
|
|
104
33
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
jsxInMapCallback: result.jsxInMapCallback,
|
|
109
|
-
props: result.props,
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
else {
|
|
113
|
-
newEntry.snapshot = INITIAL_SNAPSHOT;
|
|
114
|
-
}
|
|
115
|
-
notify(newEntry);
|
|
34
|
+
const cb = current.applyOnce;
|
|
35
|
+
current.applyOnce = null;
|
|
36
|
+
cb(result);
|
|
116
37
|
})
|
|
117
38
|
.catch((err) => {
|
|
118
|
-
|
|
39
|
+
const current = entries.get(key);
|
|
40
|
+
if (current !== created) {
|
|
119
41
|
return;
|
|
120
42
|
}
|
|
43
|
+
current.applyOnce = null;
|
|
121
44
|
remotion_1.Internals.Log.error(err);
|
|
122
|
-
newEntry.snapshot = INITIAL_SNAPSHOT;
|
|
123
|
-
notify(newEntry);
|
|
124
45
|
});
|
|
125
|
-
entry = newEntry;
|
|
126
46
|
}
|
|
127
|
-
entry.refCount
|
|
128
|
-
entry
|
|
129
|
-
|
|
47
|
+
entry.refCount++;
|
|
48
|
+
const acquired = entry;
|
|
49
|
+
acquired.promise.then(applyEach).catch(() => {
|
|
50
|
+
// Error already logged by the first acquirer.
|
|
51
|
+
});
|
|
130
52
|
let released = false;
|
|
131
|
-
return
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
53
|
+
return {
|
|
54
|
+
release: () => {
|
|
55
|
+
if (released) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
released = true;
|
|
59
|
+
acquired.refCount--;
|
|
60
|
+
if (acquired.refCount > 0) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
if (entries.get(key) === acquired) {
|
|
64
|
+
entries.delete(key);
|
|
65
|
+
}
|
|
66
|
+
acquired.promise
|
|
67
|
+
.then((result) => {
|
|
68
|
+
if (!result.canUpdate) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
return (0, call_api_1.callApi)('/api/unsubscribe-from-sequence-props', {
|
|
72
|
+
fileName: acquired.fileName,
|
|
73
|
+
nodePath: result.nodePath,
|
|
74
|
+
clientId: acquired.clientId,
|
|
75
|
+
});
|
|
76
|
+
})
|
|
77
|
+
.catch(() => {
|
|
78
|
+
// Ignore — either the subscribe failed (nothing to clean up) or
|
|
79
|
+
// the unsubscribe failed (server-side TTL will handle it).
|
|
80
|
+
});
|
|
81
|
+
},
|
|
149
82
|
};
|
|
150
83
|
};
|
|
151
84
|
exports.acquireSequencePropsSubscription = acquireSequencePropsSubscription;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type { TSequence } from 'remotion';
|
|
1
|
+
import type { SequenceSchema } from 'remotion';
|
|
3
2
|
import type { OriginalPosition } from '../../error-overlay/react-overlay/utils/get-source-map';
|
|
4
|
-
export declare const useSequencePropsSubscription: (
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
export declare const useSequencePropsSubscription: ({ originalLocation, overrideId, schema, }: {
|
|
4
|
+
overrideId: string;
|
|
5
|
+
schema: SequenceSchema;
|
|
6
|
+
originalLocation: OriginalPosition | null;
|
|
7
|
+
}) => void;
|
|
@@ -5,22 +5,11 @@ const react_1 = require("react");
|
|
|
5
5
|
const remotion_1 = require("remotion");
|
|
6
6
|
const client_id_1 = require("../../helpers/client-id");
|
|
7
7
|
const sequence_props_subscription_store_1 = require("./sequence-props-subscription-store");
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
};
|
|
12
|
-
const
|
|
13
|
-
var _a, _b;
|
|
14
|
-
var _c, _d, _e, _f;
|
|
15
|
-
const { setCodeValues } = (0, react_1.useContext)(remotion_1.Internals.VisualModeOverridesContext);
|
|
16
|
-
const overrideId = (_c = (_a = sequence.controls) === null || _a === void 0 ? void 0 : _a.overrideId) !== null && _c !== void 0 ? _c : null;
|
|
17
|
-
const setPropStatusesForSequence = (0, react_1.useCallback)((statuses) => {
|
|
18
|
-
if (!overrideId) {
|
|
19
|
-
return;
|
|
20
|
-
}
|
|
21
|
-
setCodeValues(overrideId, statuses);
|
|
22
|
-
}, [overrideId, setCodeValues]);
|
|
23
|
-
const { previewServerState: state, subscribeToEvent } = (0, react_1.useContext)(client_id_1.StudioServerConnectionCtx);
|
|
8
|
+
const useSequencePropsSubscription = ({ originalLocation, overrideId, schema, }) => {
|
|
9
|
+
var _a, _b, _c;
|
|
10
|
+
const { setCodeValues } = (0, react_1.useContext)(remotion_1.Internals.VisualModeSettersContext);
|
|
11
|
+
const { setOverrideIdToNodePath } = (0, react_1.useContext)(remotion_1.Internals.OverrideIdsToNodePathsSettersContext);
|
|
12
|
+
const { previewServerState: state } = (0, react_1.useContext)(client_id_1.StudioServerConnectionCtx);
|
|
24
13
|
const clientId = state.type === 'connected' ? state.clientId : undefined;
|
|
25
14
|
const validatedLocation = (0, react_1.useMemo)(() => {
|
|
26
15
|
var _a;
|
|
@@ -35,67 +24,48 @@ const useSequencePropsSubscription = (sequence, originalLocation, visualModeEnab
|
|
|
35
24
|
column: (_a = originalLocation.column) !== null && _a !== void 0 ? _a : 0,
|
|
36
25
|
};
|
|
37
26
|
}, [originalLocation]);
|
|
38
|
-
const
|
|
39
|
-
const
|
|
40
|
-
(0
|
|
41
|
-
isMountedRef.current = true;
|
|
42
|
-
return () => {
|
|
43
|
-
isMountedRef.current = false;
|
|
44
|
-
};
|
|
45
|
-
}, []);
|
|
46
|
-
const schema = (_b = sequence.controls) === null || _b === void 0 ? void 0 : _b.schema;
|
|
47
|
-
const locationSource = (_d = validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.source) !== null && _d !== void 0 ? _d : null;
|
|
48
|
-
const locationLine = (_e = validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.line) !== null && _e !== void 0 ? _e : null;
|
|
49
|
-
const locationColumn = (_f = validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.column) !== null && _f !== void 0 ? _f : null;
|
|
27
|
+
const locationSource = (_a = validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.source) !== null && _a !== void 0 ? _a : null;
|
|
28
|
+
const locationLine = (_b = validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.line) !== null && _b !== void 0 ? _b : null;
|
|
29
|
+
const locationColumn = (_c = validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.column) !== null && _c !== void 0 ? _c : null;
|
|
50
30
|
(0, react_1.useEffect)(() => {
|
|
51
|
-
if (!visualModeEnabled) {
|
|
52
|
-
setPropStatusesForSequence(null);
|
|
53
|
-
setSubscriptionState(EMPTY_STATE);
|
|
54
|
-
return;
|
|
55
|
-
}
|
|
56
31
|
if (!clientId ||
|
|
57
32
|
!locationSource ||
|
|
58
33
|
!locationLine ||
|
|
59
34
|
locationColumn === null ||
|
|
60
35
|
!schema) {
|
|
61
|
-
setPropStatusesForSequence(null);
|
|
62
|
-
setSubscriptionState(EMPTY_STATE);
|
|
63
36
|
return;
|
|
64
37
|
}
|
|
65
|
-
const
|
|
66
|
-
setSubscriptionState({
|
|
67
|
-
nodePath: snapshot.nodePath,
|
|
68
|
-
jsxInMapCallback: snapshot.jsxInMapCallback,
|
|
69
|
-
});
|
|
70
|
-
setPropStatusesForSequence(snapshot.props);
|
|
71
|
-
};
|
|
72
|
-
const release = (0, sequence_props_subscription_store_1.acquireSequencePropsSubscription)({
|
|
73
|
-
clientId,
|
|
38
|
+
const { release } = (0, sequence_props_subscription_store_1.acquireSequencePropsSubscription)({
|
|
74
39
|
fileName: locationSource,
|
|
75
40
|
line: locationLine,
|
|
76
41
|
column: locationColumn,
|
|
77
42
|
schema,
|
|
78
|
-
|
|
79
|
-
|
|
43
|
+
clientId,
|
|
44
|
+
applyOnce: (result) => {
|
|
45
|
+
if (!result.canUpdate) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
setCodeValues(result.nodePath, result);
|
|
49
|
+
},
|
|
50
|
+
applyEach: (result) => {
|
|
51
|
+
if (!result.canUpdate) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
setOverrideIdToNodePath(overrideId, result.nodePath);
|
|
55
|
+
},
|
|
80
56
|
});
|
|
81
57
|
return () => {
|
|
82
58
|
release();
|
|
83
|
-
// Only clear props on true unmount, not on re-subscribe due to
|
|
84
|
-
// location changes — avoids flicker while re-subscribing.
|
|
85
|
-
if (!isMountedRef.current) {
|
|
86
|
-
setPropStatusesForSequence(null);
|
|
87
|
-
}
|
|
88
59
|
};
|
|
89
60
|
}, [
|
|
90
61
|
clientId,
|
|
91
62
|
locationColumn,
|
|
92
63
|
locationLine,
|
|
93
64
|
locationSource,
|
|
65
|
+
overrideId,
|
|
94
66
|
schema,
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
visualModeEnabled,
|
|
67
|
+
setCodeValues,
|
|
68
|
+
setOverrideIdToNodePath,
|
|
98
69
|
]);
|
|
99
|
-
return subscriptionState;
|
|
100
70
|
};
|
|
101
71
|
exports.useSequencePropsSubscription = useSequencePropsSubscription;
|