@remotion/studio-server 4.0.474 → 4.0.475
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/codemods/effect-param-expression.js +5 -8
- package/dist/codemods/update-keyframes/update-keyframes.d.ts +10 -1
- package/dist/codemods/update-keyframes/update-keyframes.js +325 -12
- package/dist/helpers/imports.js +9 -4
- package/dist/helpers/resolve-composition-component.js +3 -2
- package/dist/preview-server/api-routes.js +2 -0
- package/dist/preview-server/routes/add-keyframes.d.ts +7 -0
- package/dist/preview-server/routes/add-keyframes.js +226 -0
- package/dist/preview-server/routes/can-update-sequence-props.js +0 -3
- package/dist/preview-server/routes/log-updates/format-prop-change.js +1 -1
- package/dist/preview-server/routes/log-updates/formatting.d.ts +6 -0
- package/dist/preview-server/routes/log-updates/formatting.js +256 -1
- package/dist/preview-server/routes/update-effect-keyframe-settings.js +11 -5
- package/dist/preview-server/routes/update-sequence-keyframe-settings.js +11 -5
- package/dist/preview-server/undo-stack.d.ts +3 -1
- package/package.json +6 -6
|
@@ -39,10 +39,7 @@ const imports_1 = require("../helpers/imports");
|
|
|
39
39
|
const update_nested_prop_1 = require("./update-nested-prop");
|
|
40
40
|
const b = recast.types.builders;
|
|
41
41
|
const isNonLinearEasing = (easing) => easing !== 'linear';
|
|
42
|
-
const keyframedParamNeedsEasingImport = (param) =>
|
|
43
|
-
return (param.interpolationFunction !== 'interpolateColors' &&
|
|
44
|
-
param.easing.some(isNonLinearEasing));
|
|
45
|
-
};
|
|
42
|
+
const keyframedParamNeedsEasingImport = (param) => param.easing.some(isNonLinearEasing);
|
|
46
43
|
const getRequiredRemotionImportsForEffectParams = (params) => {
|
|
47
44
|
const requiredImports = new Set();
|
|
48
45
|
for (const param of params) {
|
|
@@ -91,10 +88,10 @@ const makeKeyframedOptions = ({ param, remotionLocalNames, }) => {
|
|
|
91
88
|
if (param.clamping.right !== 'extend') {
|
|
92
89
|
properties.push(b.objectProperty(b.identifier('extrapolateRight'), b.stringLiteral(param.clamping.right)));
|
|
93
90
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
}
|
|
91
|
+
}
|
|
92
|
+
if (keyframedParamNeedsEasingImport(param)) {
|
|
93
|
+
const easingLocalName = (_a = remotionLocalNames.Easing) !== null && _a !== void 0 ? _a : 'Easing';
|
|
94
|
+
properties.push(b.objectProperty(b.identifier('easing'), b.arrayExpression(param.easing.map((easing) => makeEasingExpression({ easing, easingLocalName })))));
|
|
98
95
|
}
|
|
99
96
|
if (param.posterize !== undefined) {
|
|
100
97
|
properties.push(b.objectProperty(b.identifier('posterize'), (0, update_nested_prop_1.parseValueExpression)(param.posterize)));
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { type KeyframeInterpolationFunction } from '@remotion/studio-shared';
|
|
2
|
-
import type { ExtrapolateType, SequenceNodePath, SequenceSchema } from 'remotion';
|
|
2
|
+
import type { CanUpdateSequencePropStatus, ExtrapolateType, SequenceNodePath, SequenceSchema } from 'remotion';
|
|
3
|
+
type KeyframeEasing = Extract<CanUpdateSequencePropStatus, {
|
|
4
|
+
status: 'keyframed';
|
|
5
|
+
}>['easing'][number];
|
|
3
6
|
export type KeyframeOperation = {
|
|
4
7
|
type: 'add';
|
|
5
8
|
frame: number;
|
|
@@ -14,6 +17,10 @@ export type KeyframeOperation = {
|
|
|
14
17
|
right: ExtrapolateType;
|
|
15
18
|
} | undefined;
|
|
16
19
|
posterize: number | undefined;
|
|
20
|
+
} | {
|
|
21
|
+
type: 'easing';
|
|
22
|
+
segmentIndex: number;
|
|
23
|
+
easing: KeyframeEasing;
|
|
17
24
|
} | {
|
|
18
25
|
type: 'move';
|
|
19
26
|
moves: {
|
|
@@ -32,6 +39,7 @@ export type EffectKeyframeUpdate = {
|
|
|
32
39
|
export type IntroducedKeyframeIdentifiers = {
|
|
33
40
|
calleeName: KeyframeInterpolationFunction | null;
|
|
34
41
|
needsFrameHook: boolean;
|
|
42
|
+
needsEasingImport: boolean;
|
|
35
43
|
};
|
|
36
44
|
export declare const updateSequenceKeyframesAst: ({ input, nodePath, updates, schema, }: {
|
|
37
45
|
input: string;
|
|
@@ -89,3 +97,4 @@ export declare const updateEffectKeyframes: ({ input, sequenceNodePath, effectIn
|
|
|
89
97
|
effectCallee: string;
|
|
90
98
|
updatedSequenceNodePath: SequenceNodePath;
|
|
91
99
|
}>;
|
|
100
|
+
export {};
|
|
@@ -44,6 +44,62 @@ const update_effect_props_1 = require("../update-effect-props/update-effect-prop
|
|
|
44
44
|
const update_nested_prop_1 = require("../update-nested-prop");
|
|
45
45
|
const ensure_imports_and_frame_hook_1 = require("./ensure-imports-and-frame-hook");
|
|
46
46
|
const b = recast.types.builders;
|
|
47
|
+
const getObjectPropertyNameFromUpdateKey = (key) => {
|
|
48
|
+
const dotIndex = key.indexOf('.');
|
|
49
|
+
return dotIndex === -1 ? key : key.slice(dotIndex + 1);
|
|
50
|
+
};
|
|
51
|
+
const lineStartsWithPropertyName = ({ line, propertyName, }) => {
|
|
52
|
+
const trimmed = line.trimStart();
|
|
53
|
+
return (trimmed.startsWith(`${propertyName}:`) ||
|
|
54
|
+
trimmed.startsWith(`'${propertyName}':`) ||
|
|
55
|
+
trimmed.startsWith(`"${propertyName}":`));
|
|
56
|
+
};
|
|
57
|
+
const getIndent = (line) => {
|
|
58
|
+
var _a;
|
|
59
|
+
var _b;
|
|
60
|
+
return (_b = (_a = line.match(/^[ \t]*/)) === null || _a === void 0 ? void 0 : _a[0]) !== null && _b !== void 0 ? _b : '';
|
|
61
|
+
};
|
|
62
|
+
const removeBlankLinesFromObjectsWithProperties = ({ input, propertyNames, }) => {
|
|
63
|
+
if (propertyNames.length === 0) {
|
|
64
|
+
return input;
|
|
65
|
+
}
|
|
66
|
+
const lines = input.split('\n');
|
|
67
|
+
const linesToRemove = new Set();
|
|
68
|
+
for (let i = 0; i < lines.length; i++) {
|
|
69
|
+
const propertyName = propertyNames.find((name) => lineStartsWithPropertyName({ line: lines[i], propertyName: name }));
|
|
70
|
+
if (!propertyName) {
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
const propertyIndentLength = getIndent(lines[i]).length;
|
|
74
|
+
let objectStart = i;
|
|
75
|
+
for (let j = i - 1; j >= 0; j--) {
|
|
76
|
+
const trimmed = lines[j].trim();
|
|
77
|
+
if (trimmed.endsWith('{') &&
|
|
78
|
+
getIndent(lines[j]).length < propertyIndentLength) {
|
|
79
|
+
objectStart = j;
|
|
80
|
+
break;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
let objectEnd = i;
|
|
84
|
+
for (let j = i + 1; j < lines.length; j++) {
|
|
85
|
+
const trimmed = lines[j].trim();
|
|
86
|
+
if (trimmed.startsWith('}') &&
|
|
87
|
+
getIndent(lines[j]).length < propertyIndentLength) {
|
|
88
|
+
objectEnd = j;
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
for (let j = objectStart + 1; j < objectEnd; j++) {
|
|
93
|
+
if (lines[j].trim() === '') {
|
|
94
|
+
linesToRemove.add(j);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
if (linesToRemove.size === 0) {
|
|
99
|
+
return input;
|
|
100
|
+
}
|
|
101
|
+
return lines.filter((_, index) => !linesToRemove.has(index)).join('\n');
|
|
102
|
+
};
|
|
47
103
|
const getSupportedCallArgument = (arg) => {
|
|
48
104
|
if (arg === undefined ||
|
|
49
105
|
arg.type === 'ArgumentPlaceholder' ||
|
|
@@ -168,6 +224,173 @@ const setOptionsProperty = ({ options, propertyName, value, }) => {
|
|
|
168
224
|
}
|
|
169
225
|
options.properties.push(b.objectProperty(b.identifier(propertyName), value));
|
|
170
226
|
};
|
|
227
|
+
const isLinearEasing = (easing) => easing === 'linear';
|
|
228
|
+
const getKeyframeEasing = (node) => {
|
|
229
|
+
if (node.type === 'TSAsExpression') {
|
|
230
|
+
return getKeyframeEasing(node.expression);
|
|
231
|
+
}
|
|
232
|
+
if (node.type === 'MemberExpression' &&
|
|
233
|
+
node.object.type === 'Identifier' &&
|
|
234
|
+
node.object.name === 'Easing' &&
|
|
235
|
+
node.property.type === 'Identifier' &&
|
|
236
|
+
node.property.name === 'linear' &&
|
|
237
|
+
node.computed === false) {
|
|
238
|
+
return 'linear';
|
|
239
|
+
}
|
|
240
|
+
if (node.type !== 'CallExpression' ||
|
|
241
|
+
node.callee.type !== 'MemberExpression' ||
|
|
242
|
+
node.callee.object.type !== 'Identifier' ||
|
|
243
|
+
node.callee.object.name !== 'Easing' ||
|
|
244
|
+
node.callee.property.type !== 'Identifier' ||
|
|
245
|
+
node.callee.property.name !== 'bezier' ||
|
|
246
|
+
node.callee.computed ||
|
|
247
|
+
node.arguments.length !== 4) {
|
|
248
|
+
return null;
|
|
249
|
+
}
|
|
250
|
+
const values = node.arguments.map((arg) => {
|
|
251
|
+
if (arg.type === 'ArgumentPlaceholder' ||
|
|
252
|
+
arg.type === 'JSXNamespacedName' ||
|
|
253
|
+
arg.type === 'SpreadElement') {
|
|
254
|
+
return null;
|
|
255
|
+
}
|
|
256
|
+
return getNumericValue(arg);
|
|
257
|
+
});
|
|
258
|
+
if (values.some((value) => value === null)) {
|
|
259
|
+
return null;
|
|
260
|
+
}
|
|
261
|
+
return values;
|
|
262
|
+
};
|
|
263
|
+
const getKeyframeEasingArray = ({ easingNode, segmentCount, }) => {
|
|
264
|
+
if (segmentCount === 0) {
|
|
265
|
+
return [];
|
|
266
|
+
}
|
|
267
|
+
if (easingNode.type === 'TSAsExpression') {
|
|
268
|
+
return getKeyframeEasingArray({
|
|
269
|
+
easingNode: easingNode.expression,
|
|
270
|
+
segmentCount,
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
if (easingNode.type === 'ArrayExpression') {
|
|
274
|
+
if (easingNode.elements.length > segmentCount) {
|
|
275
|
+
return null;
|
|
276
|
+
}
|
|
277
|
+
const parsed = easingNode.elements.map((element) => {
|
|
278
|
+
if (!element || element.type === 'SpreadElement') {
|
|
279
|
+
return null;
|
|
280
|
+
}
|
|
281
|
+
return getKeyframeEasing(element);
|
|
282
|
+
});
|
|
283
|
+
if (parsed.some((value) => value === null)) {
|
|
284
|
+
return null;
|
|
285
|
+
}
|
|
286
|
+
const easingArray = parsed;
|
|
287
|
+
while (easingArray.length < segmentCount) {
|
|
288
|
+
easingArray.push('linear');
|
|
289
|
+
}
|
|
290
|
+
return easingArray;
|
|
291
|
+
}
|
|
292
|
+
const easing = getKeyframeEasing(easingNode);
|
|
293
|
+
if (!easing) {
|
|
294
|
+
return null;
|
|
295
|
+
}
|
|
296
|
+
return new Array(segmentCount).fill(easing);
|
|
297
|
+
};
|
|
298
|
+
const getExistingEasingArray = ({ options, segmentCount, }) => {
|
|
299
|
+
const { prop } = findObjectOptionProperty(options, 'easing');
|
|
300
|
+
if (!prop) {
|
|
301
|
+
return new Array(segmentCount).fill('linear');
|
|
302
|
+
}
|
|
303
|
+
const easing = getKeyframeEasingArray({
|
|
304
|
+
easingNode: prop.value,
|
|
305
|
+
segmentCount,
|
|
306
|
+
});
|
|
307
|
+
if (!easing) {
|
|
308
|
+
throw new Error('Cannot update easing: easing must be inline');
|
|
309
|
+
}
|
|
310
|
+
return easing;
|
|
311
|
+
};
|
|
312
|
+
const getExistingEasingArrayOrNull = ({ options, segmentCount, }) => {
|
|
313
|
+
const { prop } = findObjectOptionProperty(options, 'easing');
|
|
314
|
+
if (!prop) {
|
|
315
|
+
return null;
|
|
316
|
+
}
|
|
317
|
+
return getExistingEasingArray({ options, segmentCount });
|
|
318
|
+
};
|
|
319
|
+
const createEasingExpression = (easing) => {
|
|
320
|
+
if (easing === 'linear') {
|
|
321
|
+
return b.memberExpression(b.identifier('Easing'), b.identifier('linear'));
|
|
322
|
+
}
|
|
323
|
+
return b.callExpression(b.memberExpression(b.identifier('Easing'), b.identifier('bezier')), easing.map((value) => (0, update_nested_prop_1.parseValueExpression)(value)));
|
|
324
|
+
};
|
|
325
|
+
const createEasingArrayExpression = (easing) => b.arrayExpression(easing.map((easingValue) => createEasingExpression(easingValue)));
|
|
326
|
+
const setEasingOption = ({ options, easing, }) => {
|
|
327
|
+
const hasNonLinearEasing = easing.some((easingValue) => !isLinearEasing(easingValue));
|
|
328
|
+
setOptionsProperty({
|
|
329
|
+
options,
|
|
330
|
+
propertyName: 'easing',
|
|
331
|
+
value: hasNonLinearEasing ? createEasingArrayExpression(easing) : null,
|
|
332
|
+
});
|
|
333
|
+
return hasNonLinearEasing;
|
|
334
|
+
};
|
|
335
|
+
const getExtraArgsWithOptions = ({ extraArgs, options, }) => {
|
|
336
|
+
return options.properties.length === 0
|
|
337
|
+
? extraArgs.slice(1)
|
|
338
|
+
: [options, ...extraArgs.slice(1)];
|
|
339
|
+
};
|
|
340
|
+
const getInlineOptionsFromExtraArgs = (extraArgs) => {
|
|
341
|
+
const existingOptions = extraArgs[0];
|
|
342
|
+
if (!existingOptions || existingOptions.type !== 'ObjectExpression') {
|
|
343
|
+
return null;
|
|
344
|
+
}
|
|
345
|
+
return existingOptions;
|
|
346
|
+
};
|
|
347
|
+
const normalizeEasingAfterAddingKeyframe = ({ extraArgs, previousSegmentCount, nextSegmentCount, }) => {
|
|
348
|
+
const options = getInlineOptionsFromExtraArgs(extraArgs);
|
|
349
|
+
if (!options) {
|
|
350
|
+
return { extraArgs, needsEasingImport: false };
|
|
351
|
+
}
|
|
352
|
+
const easing = getExistingEasingArrayOrNull({
|
|
353
|
+
options,
|
|
354
|
+
segmentCount: previousSegmentCount,
|
|
355
|
+
});
|
|
356
|
+
if (easing === null) {
|
|
357
|
+
return { extraArgs, needsEasingImport: false };
|
|
358
|
+
}
|
|
359
|
+
while (easing.length < nextSegmentCount) {
|
|
360
|
+
easing.push('linear');
|
|
361
|
+
}
|
|
362
|
+
return {
|
|
363
|
+
extraArgs: getExtraArgsWithOptions({ extraArgs, options }),
|
|
364
|
+
needsEasingImport: setEasingOption({ options, easing }),
|
|
365
|
+
};
|
|
366
|
+
};
|
|
367
|
+
const normalizeEasingAfterRemovingKeyframe = ({ extraArgs, previousSegmentCount, nextSegmentCount, removedKeyframeIndex, }) => {
|
|
368
|
+
const options = getInlineOptionsFromExtraArgs(extraArgs);
|
|
369
|
+
if (!options) {
|
|
370
|
+
return { extraArgs, needsEasingImport: false };
|
|
371
|
+
}
|
|
372
|
+
const easing = getExistingEasingArrayOrNull({
|
|
373
|
+
options,
|
|
374
|
+
segmentCount: previousSegmentCount,
|
|
375
|
+
});
|
|
376
|
+
if (easing === null) {
|
|
377
|
+
return { extraArgs, needsEasingImport: false };
|
|
378
|
+
}
|
|
379
|
+
if (easing.length > 0) {
|
|
380
|
+
const easingIndexToRemove = removedKeyframeIndex === 0 ? 0 : removedKeyframeIndex - 1;
|
|
381
|
+
easing.splice(easingIndexToRemove, 1);
|
|
382
|
+
}
|
|
383
|
+
while (easing.length > nextSegmentCount) {
|
|
384
|
+
easing.pop();
|
|
385
|
+
}
|
|
386
|
+
while (easing.length < nextSegmentCount) {
|
|
387
|
+
easing.push('linear');
|
|
388
|
+
}
|
|
389
|
+
return {
|
|
390
|
+
extraArgs: getExtraArgsWithOptions({ extraArgs, options }),
|
|
391
|
+
needsEasingImport: setEasingOption({ options, easing }),
|
|
392
|
+
};
|
|
393
|
+
};
|
|
171
394
|
const validatePosterize = (posterize) => {
|
|
172
395
|
if (posterize === undefined) {
|
|
173
396
|
return;
|
|
@@ -227,6 +450,46 @@ const updateKeyframeSettings = ({ expression, clamping, posterize, }) => {
|
|
|
227
450
|
keyframes: existing.keyframes,
|
|
228
451
|
});
|
|
229
452
|
};
|
|
453
|
+
const updateKeyframeEasing = ({ expression, segmentIndex, easing, }) => {
|
|
454
|
+
const existing = getInterpolationExpression(expression);
|
|
455
|
+
if (!existing) {
|
|
456
|
+
throw new Error('Cannot update easing on non-keyframed value');
|
|
457
|
+
}
|
|
458
|
+
const segmentCount = Math.max(0, existing.keyframes.length - 1);
|
|
459
|
+
if (!Number.isInteger(segmentIndex) ||
|
|
460
|
+
segmentIndex < 0 ||
|
|
461
|
+
segmentIndex >= segmentCount) {
|
|
462
|
+
throw new Error('Cannot update easing: segment index out of range');
|
|
463
|
+
}
|
|
464
|
+
const extraArgs = [...existing.extraArgs];
|
|
465
|
+
const existingOptions = extraArgs[0];
|
|
466
|
+
if (existingOptions && existingOptions.type !== 'ObjectExpression') {
|
|
467
|
+
throw new Error('Cannot update easing: options must be inline');
|
|
468
|
+
}
|
|
469
|
+
const options = (existingOptions === null || existingOptions === void 0 ? void 0 : existingOptions.type) === 'ObjectExpression'
|
|
470
|
+
? existingOptions
|
|
471
|
+
: createEmptyOptionsExpression();
|
|
472
|
+
const nextEasing = getExistingEasingArray({ options, segmentCount });
|
|
473
|
+
nextEasing[segmentIndex] = easing;
|
|
474
|
+
const hasNonLinearEasing = nextEasing.some((easingValue) => !isLinearEasing(easingValue));
|
|
475
|
+
setOptionsProperty({
|
|
476
|
+
options,
|
|
477
|
+
propertyName: 'easing',
|
|
478
|
+
value: hasNonLinearEasing ? createEasingArrayExpression(nextEasing) : null,
|
|
479
|
+
});
|
|
480
|
+
const nextExtraArgs = options.properties.length === 0
|
|
481
|
+
? extraArgs.slice(1)
|
|
482
|
+
: [options, ...extraArgs.slice(1)];
|
|
483
|
+
return {
|
|
484
|
+
expression: createInterpolateExpression({
|
|
485
|
+
callee: existing.callee,
|
|
486
|
+
input: existing.input,
|
|
487
|
+
extraArgs: nextExtraArgs,
|
|
488
|
+
keyframes: existing.keyframes,
|
|
489
|
+
}),
|
|
490
|
+
needsEasingImport: hasNonLinearEasing,
|
|
491
|
+
};
|
|
492
|
+
};
|
|
230
493
|
const createInterpolateExpression = ({ callee, input, extraArgs, keyframes, }) => {
|
|
231
494
|
const sortedKeyframes = [...keyframes].sort((first, second) => first.frame - second.frame);
|
|
232
495
|
return b.callExpression(callee, [
|
|
@@ -239,6 +502,7 @@ const createInterpolateExpression = ({ callee, input, extraArgs, keyframes, }) =
|
|
|
239
502
|
const noIntroducedIdentifiers = {
|
|
240
503
|
calleeName: null,
|
|
241
504
|
needsFrameHook: false,
|
|
505
|
+
needsEasingImport: false,
|
|
242
506
|
};
|
|
243
507
|
const addKeyframe = ({ expression, key, frame, value, schema, }) => {
|
|
244
508
|
if (!(0, studio_shared_1.isSchemaFieldKeyframable)({ schema, key })) {
|
|
@@ -261,11 +525,18 @@ const addKeyframe = ({ expression, key, frame, value, schema, }) => {
|
|
|
261
525
|
: existing.keyframes.map((keyframe, index) => index === existingIndex
|
|
262
526
|
? { frame, output: newOutput, value }
|
|
263
527
|
: keyframe);
|
|
528
|
+
const normalizedEasing = existingIndex === -1
|
|
529
|
+
? normalizeEasingAfterAddingKeyframe({
|
|
530
|
+
extraArgs: existing.extraArgs,
|
|
531
|
+
previousSegmentCount: Math.max(existing.keyframes.length - 1, 0),
|
|
532
|
+
nextSegmentCount: Math.max(nextKeyframes.length - 1, 0),
|
|
533
|
+
})
|
|
534
|
+
: { extraArgs: existing.extraArgs, needsEasingImport: false };
|
|
264
535
|
return {
|
|
265
536
|
expression: createInterpolateExpression({
|
|
266
537
|
callee: b.identifier(nextCalleeName),
|
|
267
538
|
input: existing.input,
|
|
268
|
-
extraArgs:
|
|
539
|
+
extraArgs: normalizedEasing.extraArgs,
|
|
269
540
|
keyframes: nextKeyframes,
|
|
270
541
|
}),
|
|
271
542
|
introduced: {
|
|
@@ -273,6 +544,7 @@ const addKeyframe = ({ expression, key, frame, value, schema, }) => {
|
|
|
273
544
|
? schemaCalleeName
|
|
274
545
|
: null,
|
|
275
546
|
needsFrameHook: false,
|
|
547
|
+
needsEasingImport: normalizedEasing.needsEasingImport,
|
|
276
548
|
},
|
|
277
549
|
};
|
|
278
550
|
}
|
|
@@ -302,6 +574,7 @@ const addKeyframe = ({ expression, key, frame, value, schema, }) => {
|
|
|
302
574
|
? callee.name
|
|
303
575
|
: null,
|
|
304
576
|
needsFrameHook: true,
|
|
577
|
+
needsEasingImport: false,
|
|
305
578
|
},
|
|
306
579
|
};
|
|
307
580
|
};
|
|
@@ -316,14 +589,29 @@ const removeKeyframe = ({ expression, frame, }) => {
|
|
|
316
589
|
}
|
|
317
590
|
const nextKeyframes = existing.keyframes.filter((_keyframe, index) => index !== keyframeIndex);
|
|
318
591
|
if (nextKeyframes.length === 0) {
|
|
319
|
-
return
|
|
592
|
+
return {
|
|
593
|
+
expression: existing.keyframes[keyframeIndex].output,
|
|
594
|
+
introduced: noIntroducedIdentifiers,
|
|
595
|
+
};
|
|
320
596
|
}
|
|
321
|
-
|
|
322
|
-
callee: existing.callee,
|
|
323
|
-
input: existing.input,
|
|
597
|
+
const normalizedEasing = normalizeEasingAfterRemovingKeyframe({
|
|
324
598
|
extraArgs: existing.extraArgs,
|
|
325
|
-
|
|
599
|
+
previousSegmentCount: Math.max(existing.keyframes.length - 1, 0),
|
|
600
|
+
nextSegmentCount: Math.max(nextKeyframes.length - 1, 0),
|
|
601
|
+
removedKeyframeIndex: keyframeIndex,
|
|
326
602
|
});
|
|
603
|
+
return {
|
|
604
|
+
expression: createInterpolateExpression({
|
|
605
|
+
callee: existing.callee,
|
|
606
|
+
input: existing.input,
|
|
607
|
+
extraArgs: normalizedEasing.extraArgs,
|
|
608
|
+
keyframes: nextKeyframes,
|
|
609
|
+
}),
|
|
610
|
+
introduced: {
|
|
611
|
+
...noIntroducedIdentifiers,
|
|
612
|
+
needsEasingImport: normalizedEasing.needsEasingImport,
|
|
613
|
+
},
|
|
614
|
+
};
|
|
327
615
|
};
|
|
328
616
|
const moveKeyframes = ({ expression, moves, }) => {
|
|
329
617
|
var _a;
|
|
@@ -395,16 +683,27 @@ const applyKeyframeOperation = ({ expression, key, operation, schema, }) => {
|
|
|
395
683
|
introduced: noIntroducedIdentifiers,
|
|
396
684
|
};
|
|
397
685
|
}
|
|
686
|
+
if (operation.type === 'easing') {
|
|
687
|
+
const updated = updateKeyframeEasing({
|
|
688
|
+
expression,
|
|
689
|
+
segmentIndex: operation.segmentIndex,
|
|
690
|
+
easing: operation.easing,
|
|
691
|
+
});
|
|
692
|
+
return {
|
|
693
|
+
expression: updated.expression,
|
|
694
|
+
introduced: {
|
|
695
|
+
...noIntroducedIdentifiers,
|
|
696
|
+
needsEasingImport: updated.needsEasingImport,
|
|
697
|
+
},
|
|
698
|
+
};
|
|
699
|
+
}
|
|
398
700
|
if (operation.type === 'move') {
|
|
399
701
|
return {
|
|
400
702
|
expression: moveKeyframes({ expression, moves: operation.moves }),
|
|
401
703
|
introduced: noIntroducedIdentifiers,
|
|
402
704
|
};
|
|
403
705
|
}
|
|
404
|
-
return {
|
|
405
|
-
expression: removeKeyframe({ expression, frame: operation.frame }),
|
|
406
|
-
introduced: noIntroducedIdentifiers,
|
|
407
|
-
};
|
|
706
|
+
return removeKeyframe({ expression, frame: operation.frame });
|
|
408
707
|
};
|
|
409
708
|
const getExpressionFromJsxAttribute = (attr) => {
|
|
410
709
|
if (!attr.value) {
|
|
@@ -609,6 +908,9 @@ const updateSequenceKeyframesAst = ({ input, nodePath, updates, schema, }) => {
|
|
|
609
908
|
requiredImports.add('useCurrentFrame');
|
|
610
909
|
needsFrameHook = true;
|
|
611
910
|
}
|
|
911
|
+
if (introduced.needsEasingImport) {
|
|
912
|
+
requiredImports.add('Easing');
|
|
913
|
+
}
|
|
612
914
|
}
|
|
613
915
|
if (needsFrameHook) {
|
|
614
916
|
const fnPath = (0, ensure_imports_and_frame_hook_1.findEnclosingFunctionPath)(jsxPath);
|
|
@@ -641,8 +943,12 @@ const updateSequenceKeyframes = async ({ input, nodePath, updates, schema, prett
|
|
|
641
943
|
input: serialized,
|
|
642
944
|
prettierConfigOverride,
|
|
643
945
|
});
|
|
946
|
+
const outputWithoutInsertedBlankLines = removeBlankLinesFromObjectsWithProperties({
|
|
947
|
+
input: output,
|
|
948
|
+
propertyNames: updates.map((update) => getObjectPropertyNameFromUpdateKey(update.key)),
|
|
949
|
+
});
|
|
644
950
|
return {
|
|
645
|
-
output,
|
|
951
|
+
output: outputWithoutInsertedBlankLines,
|
|
646
952
|
formatted,
|
|
647
953
|
oldValueStrings,
|
|
648
954
|
newValueStrings,
|
|
@@ -699,6 +1005,9 @@ const updateEffectKeyframesAst = ({ input, sequenceNodePath, effectIndex, update
|
|
|
699
1005
|
requiredImports.add('useCurrentFrame');
|
|
700
1006
|
needsFrameHook = true;
|
|
701
1007
|
}
|
|
1008
|
+
if (introduced.needsEasingImport) {
|
|
1009
|
+
requiredImports.add('Easing');
|
|
1010
|
+
}
|
|
702
1011
|
}
|
|
703
1012
|
if (needsFrameHook) {
|
|
704
1013
|
const fnPath = (0, ensure_imports_and_frame_hook_1.findEnclosingFunctionPath)(jsxPath);
|
|
@@ -733,8 +1042,12 @@ const updateEffectKeyframes = async ({ input, sequenceNodePath, effectIndex, upd
|
|
|
733
1042
|
input: serialized,
|
|
734
1043
|
prettierConfigOverride,
|
|
735
1044
|
});
|
|
1045
|
+
const outputWithoutInsertedBlankLines = removeBlankLinesFromObjectsWithProperties({
|
|
1046
|
+
input: output,
|
|
1047
|
+
propertyNames: updates.map((update) => update.key),
|
|
1048
|
+
});
|
|
736
1049
|
return {
|
|
737
|
-
output,
|
|
1050
|
+
output: outputWithoutInsertedBlankLines,
|
|
738
1051
|
formatted,
|
|
739
1052
|
oldValueStrings,
|
|
740
1053
|
newValueStrings,
|
package/dist/helpers/imports.js
CHANGED
|
@@ -105,18 +105,23 @@ const ensureNamedImport = ({ ast, importedName, sourcePath, localName, }) => {
|
|
|
105
105
|
};
|
|
106
106
|
exports.ensureNamedImport = ensureNamedImport;
|
|
107
107
|
const ensureNamedImports = ({ ast, importedNames, sourcePath, }) => {
|
|
108
|
-
var _a
|
|
108
|
+
var _a;
|
|
109
|
+
var _b, _c, _d;
|
|
109
110
|
if (importedNames.size === 0) {
|
|
110
111
|
return;
|
|
111
112
|
}
|
|
112
113
|
const existingImports = findImportDeclarations(ast, sourcePath);
|
|
113
114
|
const existingNames = new Set();
|
|
114
115
|
for (const existingImportDeclaration of existingImports) {
|
|
115
|
-
for (const importSpecifierCandidate of (
|
|
116
|
+
for (const importSpecifierCandidate of (_b = existingImportDeclaration.specifiers) !== null && _b !== void 0 ? _b : []) {
|
|
116
117
|
if (importSpecifierCandidate.type !== 'ImportSpecifier') {
|
|
117
118
|
continue;
|
|
118
119
|
}
|
|
119
|
-
|
|
120
|
+
const importedName = (0, exports.getImportedName)(importSpecifierCandidate);
|
|
121
|
+
const localName = (_c = (_a = importSpecifierCandidate.local) === null || _a === void 0 ? void 0 : _a.name) !== null && _c !== void 0 ? _c : importedName;
|
|
122
|
+
if (localName === importedName) {
|
|
123
|
+
existingNames.add(importedName);
|
|
124
|
+
}
|
|
120
125
|
}
|
|
121
126
|
}
|
|
122
127
|
const existingImport = existingImports.find((candidateImportDeclaration) => !hasNamespaceSpecifier(candidateImportDeclaration));
|
|
@@ -126,7 +131,7 @@ const ensureNamedImports = ({ ast, importedNames, sourcePath, }) => {
|
|
|
126
131
|
continue;
|
|
127
132
|
}
|
|
128
133
|
existingImport.specifiers = [
|
|
129
|
-
...((
|
|
134
|
+
...((_d = existingImport.specifiers) !== null && _d !== void 0 ? _d : []),
|
|
130
135
|
b.importSpecifier(b.identifier(importedName)),
|
|
131
136
|
];
|
|
132
137
|
existingNames.add(importedName);
|
|
@@ -548,12 +548,12 @@ const createComponentElement = ({ localName, props, }) => {
|
|
|
548
548
|
createPositionAbsoluteStyleAttribute(),
|
|
549
549
|
], true), null, []);
|
|
550
550
|
};
|
|
551
|
-
const createAssetElement = ({ localName, staticFileLocalName, src, dimensions, }) => {
|
|
551
|
+
const createAssetElement = ({ addPositionStyle, localName, staticFileLocalName, src, dimensions, }) => {
|
|
552
552
|
return recast.types.builders.jsxElement(recast.types.builders.jsxOpeningElement(recast.types.builders.jsxIdentifier(localName), [
|
|
553
553
|
staticFileLocalName === null
|
|
554
554
|
? createStringSrcAttribute(src)
|
|
555
555
|
: createStaticFileSrcAttribute({ staticFileLocalName, src }),
|
|
556
|
-
createPositionAbsoluteStyleAttribute(),
|
|
556
|
+
...(addPositionStyle ? [createPositionAbsoluteStyleAttribute()] : []),
|
|
557
557
|
...(dimensions
|
|
558
558
|
? [
|
|
559
559
|
createNumberAttribute('width', dimensions.width),
|
|
@@ -1043,6 +1043,7 @@ const createInsertableJsxElement = ({ ast, element, }) => {
|
|
|
1043
1043
|
throw new Error('Unsupported asset type');
|
|
1044
1044
|
}
|
|
1045
1045
|
return createAssetElement({
|
|
1046
|
+
addPositionStyle: element.assetType !== 'audio',
|
|
1046
1047
|
localName,
|
|
1047
1048
|
staticFileLocalName,
|
|
1048
1049
|
src: element.src,
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.allApiRoutes = void 0;
|
|
4
4
|
const add_effect_1 = require("./routes/add-effect");
|
|
5
5
|
const add_effect_keyframe_1 = require("./routes/add-effect-keyframe");
|
|
6
|
+
const add_keyframes_1 = require("./routes/add-keyframes");
|
|
6
7
|
const add_render_1 = require("./routes/add-render");
|
|
7
8
|
const add_sequence_keyframe_1 = require("./routes/add-sequence-keyframe");
|
|
8
9
|
const apply_codemod_1 = require("./routes/apply-codemod");
|
|
@@ -71,6 +72,7 @@ exports.allApiRoutes = {
|
|
|
71
72
|
'/api/move-keyframes': move_keyframes_1.moveKeyframesHandler,
|
|
72
73
|
'/api/add-sequence-keyframe': add_sequence_keyframe_1.addSequenceKeyframeHandler,
|
|
73
74
|
'/api/add-effect-keyframe': add_effect_keyframe_1.addEffectKeyframeHandler,
|
|
75
|
+
'/api/add-keyframes': add_keyframes_1.addKeyframesHandler,
|
|
74
76
|
'/api/update-sequence-keyframe-settings': update_sequence_keyframe_settings_1.updateSequenceKeyframeSettingsHandler,
|
|
75
77
|
'/api/update-effect-keyframe-settings': update_effect_keyframe_settings_1.updateEffectKeyframeSettingsHandler,
|
|
76
78
|
'/api/delete-effect': delete_effect_1.deleteEffectHandler,
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { AddKeyframesRequest, AddKeyframesResponse } from '@remotion/studio-shared';
|
|
2
|
+
import type { ApiHandler } from '../api-types';
|
|
3
|
+
export declare const addKeyframes: ({ sequenceKeyframes, effectKeyframes, clientId, remotionRoot, logLevel, }: AddKeyframesRequest & {
|
|
4
|
+
readonly remotionRoot: string;
|
|
5
|
+
readonly logLevel: "error" | "info" | "trace" | "verbose" | "warn";
|
|
6
|
+
}) => Promise<void>;
|
|
7
|
+
export declare const addKeyframesHandler: ApiHandler<AddKeyframesRequest, AddKeyframesResponse>;
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.addKeyframesHandler = exports.addKeyframes = void 0;
|
|
4
|
+
const node_fs_1 = require("node:fs");
|
|
5
|
+
const renderer_1 = require("@remotion/renderer");
|
|
6
|
+
const update_keyframes_1 = require("../../codemods/update-keyframes/update-keyframes");
|
|
7
|
+
const file_watcher_1 = require("../../file-watcher");
|
|
8
|
+
const resolve_file_inside_project_1 = require("../../helpers/resolve-file-inside-project");
|
|
9
|
+
const undo_stack_1 = require("../undo-stack");
|
|
10
|
+
const watch_ignore_next_change_1 = require("../watch-ignore-next-change");
|
|
11
|
+
const log_effect_update_1 = require("./log-updates/log-effect-update");
|
|
12
|
+
const log_update_1 = require("./log-updates/log-update");
|
|
13
|
+
const save_props_mutex_1 = require("./save-props-mutex");
|
|
14
|
+
const groupBy = (items, getKey) => {
|
|
15
|
+
var _a;
|
|
16
|
+
const groups = new Map();
|
|
17
|
+
for (const item of items) {
|
|
18
|
+
const key = getKey(item);
|
|
19
|
+
const group = (_a = groups.get(key)) !== null && _a !== void 0 ? _a : [];
|
|
20
|
+
group.push(item);
|
|
21
|
+
groups.set(key, group);
|
|
22
|
+
}
|
|
23
|
+
return [...groups.values()];
|
|
24
|
+
};
|
|
25
|
+
const getBatchDescription = ({ totalKeyframes, firstKeyframe, }) => {
|
|
26
|
+
if (totalKeyframes === 1) {
|
|
27
|
+
return {
|
|
28
|
+
undoMessage: `↩️ ${firstKeyframe.key} keyframe removed at frame ${firstKeyframe.frame}`,
|
|
29
|
+
redoMessage: `↪️ ${firstKeyframe.key} keyframe added at frame ${firstKeyframe.frame}`,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
return {
|
|
33
|
+
undoMessage: `↩️ ${totalKeyframes} keyframes removed`,
|
|
34
|
+
redoMessage: `↪️ ${totalKeyframes} keyframes added`,
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
const addKeyframes = async ({ sequenceKeyframes, effectKeyframes, clientId, remotionRoot, logLevel, }) => {
|
|
38
|
+
var _a, _b;
|
|
39
|
+
const totalKeyframes = sequenceKeyframes.length + effectKeyframes.length;
|
|
40
|
+
if (totalKeyframes === 0) {
|
|
41
|
+
throw new Error('No keyframes were specified for adding');
|
|
42
|
+
}
|
|
43
|
+
const fileGroups = new Map();
|
|
44
|
+
for (const [index, keyframe] of sequenceKeyframes.entries()) {
|
|
45
|
+
const { absolutePath, fileRelativeToRoot } = (0, resolve_file_inside_project_1.resolveFileInsideProject)({
|
|
46
|
+
remotionRoot,
|
|
47
|
+
fileName: keyframe.fileName,
|
|
48
|
+
action: 'modify',
|
|
49
|
+
});
|
|
50
|
+
const group = (_a = fileGroups.get(absolutePath)) !== null && _a !== void 0 ? _a : {
|
|
51
|
+
fileRelativeToRoot,
|
|
52
|
+
sequenceKeyframes: [],
|
|
53
|
+
effectKeyframes: [],
|
|
54
|
+
};
|
|
55
|
+
group.sequenceKeyframes.push({
|
|
56
|
+
...keyframe,
|
|
57
|
+
index,
|
|
58
|
+
absolutePath,
|
|
59
|
+
fileRelativeToRoot,
|
|
60
|
+
});
|
|
61
|
+
fileGroups.set(absolutePath, group);
|
|
62
|
+
}
|
|
63
|
+
for (const [index, keyframe] of effectKeyframes.entries()) {
|
|
64
|
+
const { absolutePath, fileRelativeToRoot } = (0, resolve_file_inside_project_1.resolveFileInsideProject)({
|
|
65
|
+
remotionRoot,
|
|
66
|
+
fileName: keyframe.fileName,
|
|
67
|
+
action: 'modify',
|
|
68
|
+
});
|
|
69
|
+
const group = (_b = fileGroups.get(absolutePath)) !== null && _b !== void 0 ? _b : {
|
|
70
|
+
fileRelativeToRoot,
|
|
71
|
+
sequenceKeyframes: [],
|
|
72
|
+
effectKeyframes: [],
|
|
73
|
+
};
|
|
74
|
+
group.effectKeyframes.push({
|
|
75
|
+
...keyframe,
|
|
76
|
+
index,
|
|
77
|
+
absolutePath,
|
|
78
|
+
fileRelativeToRoot,
|
|
79
|
+
});
|
|
80
|
+
fileGroups.set(absolutePath, group);
|
|
81
|
+
}
|
|
82
|
+
const snapshots = [];
|
|
83
|
+
const sequenceLogs = [];
|
|
84
|
+
const effectLogs = [];
|
|
85
|
+
for (const [absolutePath, group] of fileGroups) {
|
|
86
|
+
const fileContents = (0, node_fs_1.readFileSync)(absolutePath, 'utf-8');
|
|
87
|
+
let output = fileContents;
|
|
88
|
+
let firstLogLine = Number.POSITIVE_INFINITY;
|
|
89
|
+
for (const keyframeGroup of groupBy(group.sequenceKeyframes, (keyframe) => JSON.stringify(keyframe.nodePath.nodePath))) {
|
|
90
|
+
const [firstSequenceKeyframe] = keyframeGroup;
|
|
91
|
+
if (!firstSequenceKeyframe) {
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
const result = await (0, update_keyframes_1.updateSequenceKeyframes)({
|
|
95
|
+
input: output,
|
|
96
|
+
nodePath: firstSequenceKeyframe.nodePath.nodePath,
|
|
97
|
+
schema: firstSequenceKeyframe.schema,
|
|
98
|
+
updates: keyframeGroup.map((keyframe) => ({
|
|
99
|
+
key: keyframe.key,
|
|
100
|
+
operation: {
|
|
101
|
+
type: 'add',
|
|
102
|
+
frame: keyframe.frame,
|
|
103
|
+
value: JSON.parse(keyframe.value),
|
|
104
|
+
},
|
|
105
|
+
})),
|
|
106
|
+
});
|
|
107
|
+
output = result.output;
|
|
108
|
+
firstLogLine = Math.min(firstLogLine, result.logLine);
|
|
109
|
+
for (const [keyframeIndex, keyframe] of keyframeGroup.entries()) {
|
|
110
|
+
sequenceLogs.push({
|
|
111
|
+
fileRelativeToRoot: keyframe.fileRelativeToRoot,
|
|
112
|
+
line: result.logLine,
|
|
113
|
+
key: keyframe.key,
|
|
114
|
+
oldValueString: result.oldValueStrings[keyframeIndex],
|
|
115
|
+
newValueString: result.newValueStrings[keyframeIndex],
|
|
116
|
+
formatted: result.formatted,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
for (const keyframeGroup of groupBy(group.effectKeyframes, (keyframe) => `${JSON.stringify(keyframe.sequenceNodePath.nodePath)}:${keyframe.effectIndex}`)) {
|
|
121
|
+
const [firstEffectKeyframe] = keyframeGroup;
|
|
122
|
+
if (!firstEffectKeyframe) {
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
const result = await (0, update_keyframes_1.updateEffectKeyframes)({
|
|
126
|
+
input: output,
|
|
127
|
+
sequenceNodePath: firstEffectKeyframe.sequenceNodePath.nodePath,
|
|
128
|
+
effectIndex: firstEffectKeyframe.effectIndex,
|
|
129
|
+
schema: firstEffectKeyframe.schema,
|
|
130
|
+
updates: keyframeGroup.map((keyframe) => ({
|
|
131
|
+
key: keyframe.key,
|
|
132
|
+
operation: {
|
|
133
|
+
type: 'add',
|
|
134
|
+
frame: keyframe.frame,
|
|
135
|
+
value: JSON.parse(keyframe.value),
|
|
136
|
+
},
|
|
137
|
+
})),
|
|
138
|
+
});
|
|
139
|
+
output = result.output;
|
|
140
|
+
firstLogLine = Math.min(firstLogLine, result.logLine);
|
|
141
|
+
for (const [keyframeIndex, keyframe] of keyframeGroup.entries()) {
|
|
142
|
+
effectLogs.push({
|
|
143
|
+
fileRelativeToRoot: keyframe.fileRelativeToRoot,
|
|
144
|
+
line: result.logLine,
|
|
145
|
+
effectName: result.effectCallee,
|
|
146
|
+
propKey: keyframe.key,
|
|
147
|
+
oldValueString: result.oldValueStrings[keyframeIndex],
|
|
148
|
+
newValueString: result.newValueStrings[keyframeIndex],
|
|
149
|
+
formatted: result.formatted,
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
snapshots.push({
|
|
154
|
+
filePath: absolutePath,
|
|
155
|
+
oldContents: fileContents,
|
|
156
|
+
newContents: output,
|
|
157
|
+
logLine: Number.isFinite(firstLogLine) ? firstLogLine : 1,
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
const [firstKeyframe] = sequenceKeyframes.length > 0 ? sequenceKeyframes : effectKeyframes;
|
|
161
|
+
if (!firstKeyframe) {
|
|
162
|
+
throw new Error('No keyframes were specified for adding');
|
|
163
|
+
}
|
|
164
|
+
(0, undo_stack_1.pushTransactionToUndoStack)({
|
|
165
|
+
snapshots,
|
|
166
|
+
logLevel,
|
|
167
|
+
remotionRoot,
|
|
168
|
+
description: getBatchDescription({ totalKeyframes, firstKeyframe }),
|
|
169
|
+
entryType: sequenceKeyframes.length > 0 && effectKeyframes.length > 0
|
|
170
|
+
? // Dead code for now: sequence props and effect props cannot be selected
|
|
171
|
+
// together yet. Keep the mixed transaction type for the planned UI.
|
|
172
|
+
'keyframe-add'
|
|
173
|
+
: sequenceKeyframes.length > 0
|
|
174
|
+
? 'sequence-props'
|
|
175
|
+
: 'effect-props',
|
|
176
|
+
suppressHmrOnFileRestore: true,
|
|
177
|
+
});
|
|
178
|
+
for (const snapshot of snapshots) {
|
|
179
|
+
(0, undo_stack_1.suppressUndoStackInvalidation)(snapshot.filePath);
|
|
180
|
+
(0, watch_ignore_next_change_1.suppressBundlerUpdateForFile)(snapshot.filePath);
|
|
181
|
+
(0, file_watcher_1.writeFileAndNotifyFileWatchers)(snapshot.filePath, snapshot.newContents, clientId);
|
|
182
|
+
}
|
|
183
|
+
for (const log of sequenceLogs) {
|
|
184
|
+
(0, log_update_1.logUpdate)({
|
|
185
|
+
fileRelativeToRoot: log.fileRelativeToRoot,
|
|
186
|
+
line: log.line,
|
|
187
|
+
key: log.key,
|
|
188
|
+
oldValueString: log.oldValueString,
|
|
189
|
+
newValueString: log.newValueString,
|
|
190
|
+
defaultValueString: null,
|
|
191
|
+
formatted: log.formatted,
|
|
192
|
+
logLevel,
|
|
193
|
+
removedProps: [],
|
|
194
|
+
addedProps: [],
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
for (const log of effectLogs) {
|
|
198
|
+
(0, log_effect_update_1.logEffectUpdate)({
|
|
199
|
+
fileRelativeToRoot: log.fileRelativeToRoot,
|
|
200
|
+
line: log.line,
|
|
201
|
+
effectName: log.effectName,
|
|
202
|
+
propKey: log.propKey,
|
|
203
|
+
oldValueString: log.oldValueString,
|
|
204
|
+
newValueString: log.newValueString,
|
|
205
|
+
defaultValueString: null,
|
|
206
|
+
formatted: log.formatted,
|
|
207
|
+
logLevel,
|
|
208
|
+
removedProps: [],
|
|
209
|
+
addedProps: [],
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
(0, undo_stack_1.printUndoHint)(logLevel);
|
|
213
|
+
};
|
|
214
|
+
exports.addKeyframes = addKeyframes;
|
|
215
|
+
const addKeyframesHandler = ({ input: { sequenceKeyframes, effectKeyframes, clientId }, remotionRoot, logLevel, }) => (0, save_props_mutex_1.withSavePropsLock)(async () => {
|
|
216
|
+
renderer_1.RenderInternals.Log.trace({ indent: false, logLevel }, `[add-keyframes] Received request to add ${sequenceKeyframes.length + effectKeyframes.length} keyframe(s)`);
|
|
217
|
+
await (0, exports.addKeyframes)({
|
|
218
|
+
sequenceKeyframes,
|
|
219
|
+
effectKeyframes,
|
|
220
|
+
clientId,
|
|
221
|
+
remotionRoot,
|
|
222
|
+
logLevel,
|
|
223
|
+
});
|
|
224
|
+
return { success: true };
|
|
225
|
+
});
|
|
226
|
+
exports.addKeyframesHandler = addKeyframesHandler;
|
|
@@ -260,9 +260,6 @@ const getInterpolationMetadata = (interpolationFunction, callExpression, keyfram
|
|
|
260
260
|
}
|
|
261
261
|
const value = property.value;
|
|
262
262
|
if (key === 'easing') {
|
|
263
|
-
if (interpolationFunction === 'interpolateColors') {
|
|
264
|
-
return null;
|
|
265
|
-
}
|
|
266
263
|
const parsedEasing = getKeyframeEasingArray({
|
|
267
264
|
easingNode: value,
|
|
268
265
|
segments,
|
|
@@ -10,7 +10,7 @@ const formatInnerPropChange = ({ key, oldValueString, newValueString, defaultVal
|
|
|
10
10
|
if (defaultValueString !== null && oldValueString === defaultValueString) {
|
|
11
11
|
return (0, formatting_1.formatAddition)({ valueString: newValueString, key });
|
|
12
12
|
}
|
|
13
|
-
return
|
|
13
|
+
return (0, formatting_1.formatPropChangeDelta)({ key, oldValueString, newValueString });
|
|
14
14
|
};
|
|
15
15
|
const formatPropChange = ({ key, oldValueString, newValueString, defaultValueString, removedProps, addedProps, }) => {
|
|
16
16
|
const suffix = (0, format_side_props_1.formatSideProps)({ removedProps, addedProps });
|
|
@@ -7,6 +7,7 @@ export declare const equals: (str: string) => string;
|
|
|
7
7
|
export declare const punctuation: (str: string) => string;
|
|
8
8
|
export declare const stringValue: (str: string) => string;
|
|
9
9
|
export declare const numberValue: (str: string) => string;
|
|
10
|
+
export declare const inlineAddition: (str: string) => string;
|
|
10
11
|
export declare const strikeThrough: (str: string) => string;
|
|
11
12
|
export declare const strikeThroughOrRemovedPrefix: (str: string) => string;
|
|
12
13
|
export declare const addedPrefixIfNoColor: (str: string) => string;
|
|
@@ -15,5 +16,10 @@ export type PropDelta = {
|
|
|
15
16
|
valueString: string;
|
|
16
17
|
};
|
|
17
18
|
export declare const formatPropDelta: ({ key, valueString }: PropDelta) => string;
|
|
19
|
+
export declare const formatPropChangeDelta: ({ key, oldValueString, newValueString, }: {
|
|
20
|
+
key: string;
|
|
21
|
+
oldValueString: string;
|
|
22
|
+
newValueString: string;
|
|
23
|
+
}) => string;
|
|
18
24
|
export declare const formatDeletion: (prop: PropDelta) => string;
|
|
19
25
|
export declare const formatAddition: (prop: PropDelta) => string;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.formatAddition = exports.formatDeletion = exports.formatPropDelta = exports.addedPrefixIfNoColor = exports.strikeThroughOrRemovedPrefix = exports.strikeThrough = exports.numberValue = exports.stringValue = exports.punctuation = exports.equals = exports.attrName = exports.bg = exports.fg = exports.colorValue = exports.colorEnabled = void 0;
|
|
3
|
+
exports.formatAddition = exports.formatDeletion = exports.formatPropChangeDelta = exports.formatPropDelta = exports.addedPrefixIfNoColor = exports.strikeThroughOrRemovedPrefix = exports.strikeThrough = exports.inlineAddition = exports.numberValue = exports.stringValue = exports.punctuation = exports.equals = exports.attrName = exports.bg = exports.fg = exports.colorValue = exports.colorEnabled = void 0;
|
|
4
4
|
const renderer_1 = require("@remotion/renderer");
|
|
5
5
|
const colorEnabled = () => renderer_1.RenderInternals.chalk.enabled();
|
|
6
6
|
exports.colorEnabled = colorEnabled;
|
|
@@ -35,6 +35,8 @@ const stringValue = (str) => (0, exports.fg)(230, 219, 116, str);
|
|
|
35
35
|
exports.stringValue = stringValue;
|
|
36
36
|
const numberValue = (str) => (0, exports.fg)(174, 129, 255, str);
|
|
37
37
|
exports.numberValue = numberValue;
|
|
38
|
+
const inlineAddition = (str) => (0, exports.fg)(166, 226, 46, str);
|
|
39
|
+
exports.inlineAddition = inlineAddition;
|
|
38
40
|
const strikeThrough = (str) => `\u001b[9m\u001b[38;2;255;85;85m${stripAnsi(str)}\u001b[39m\u001b[29m`;
|
|
39
41
|
exports.strikeThrough = strikeThrough;
|
|
40
42
|
const strikeThroughOrRemovedPrefix = (str) => (0, exports.colorEnabled)() ? (0, exports.strikeThrough)(str) : 'removed: ' + str;
|
|
@@ -49,6 +51,25 @@ const formatSimpleProp = (key, value) => {
|
|
|
49
51
|
const formatNestedProp = (parentKey, childKey, value) => {
|
|
50
52
|
return `${(0, exports.attrName)(parentKey)}${(0, exports.equals)('=')}${(0, exports.punctuation)('{{')}${(0, exports.punctuation)(childKey)}${(0, exports.punctuation)(':')} ${(0, exports.colorValue)(value)}${(0, exports.punctuation)('}}')}`;
|
|
51
53
|
};
|
|
54
|
+
const formatValueDelta = ({ oldValueString, newValueString, }) => {
|
|
55
|
+
const withoutUnchangedOptions = shortenUnchangedInterpolateOptions({
|
|
56
|
+
oldValueString,
|
|
57
|
+
newValueString,
|
|
58
|
+
});
|
|
59
|
+
const shortened = removeUnchangedInterpolateOptionProperties(withoutUnchangedOptions);
|
|
60
|
+
const inlineDelta = formatInlineAdditionOrRemoval(shortened);
|
|
61
|
+
if (inlineDelta !== null) {
|
|
62
|
+
return inlineDelta;
|
|
63
|
+
}
|
|
64
|
+
return `${(0, exports.colorValue)(shortened.oldValueString)} ${(0, exports.punctuation)('→')} ${(0, exports.colorValue)(shortened.newValueString)}`;
|
|
65
|
+
};
|
|
66
|
+
const formatSimplePropChange = ({ key, oldValueString, newValueString, }) => {
|
|
67
|
+
return `${(0, exports.attrName)(key)}${(0, exports.equals)('=')}${(0, exports.punctuation)('{')}${formatValueDelta({ oldValueString, newValueString })}${(0, exports.punctuation)('}')}`;
|
|
68
|
+
};
|
|
69
|
+
const formatNestedPropChange = ({ key, oldValueString, newValueString, }) => {
|
|
70
|
+
const dotIdx = key.indexOf('.');
|
|
71
|
+
return `${(0, exports.attrName)(key.slice(0, dotIdx))}${(0, exports.equals)('=')}${(0, exports.punctuation)('{{')}${(0, exports.punctuation)(key.slice(dotIdx + 1))}${(0, exports.punctuation)(':')} ${formatValueDelta({ oldValueString, newValueString })}${(0, exports.punctuation)('}}')}`;
|
|
72
|
+
};
|
|
52
73
|
const formatPropDelta = ({ key, valueString }) => {
|
|
53
74
|
const dotIdx = key.indexOf('.');
|
|
54
75
|
if (dotIdx === -1) {
|
|
@@ -57,6 +78,14 @@ const formatPropDelta = ({ key, valueString }) => {
|
|
|
57
78
|
return formatNestedProp(key.slice(0, dotIdx), key.slice(dotIdx + 1), valueString);
|
|
58
79
|
};
|
|
59
80
|
exports.formatPropDelta = formatPropDelta;
|
|
81
|
+
const formatPropChangeDelta = ({ key, oldValueString, newValueString, }) => {
|
|
82
|
+
const dotIdx = key.indexOf('.');
|
|
83
|
+
if (dotIdx === -1) {
|
|
84
|
+
return formatSimplePropChange({ key, oldValueString, newValueString });
|
|
85
|
+
}
|
|
86
|
+
return formatNestedPropChange({ key, oldValueString, newValueString });
|
|
87
|
+
};
|
|
88
|
+
exports.formatPropChangeDelta = formatPropChangeDelta;
|
|
60
89
|
const formatDeletion = (prop) => {
|
|
61
90
|
const formatted = (0, exports.formatPropDelta)(prop);
|
|
62
91
|
return (0, exports.strikeThroughOrRemovedPrefix)(formatted);
|
|
@@ -67,3 +96,229 @@ const formatAddition = (prop) => {
|
|
|
67
96
|
return (0, exports.addedPrefixIfNoColor)(formatted);
|
|
68
97
|
};
|
|
69
98
|
exports.formatAddition = formatAddition;
|
|
99
|
+
const callStart = 'interpolate(';
|
|
100
|
+
const normalizeArg = (arg) => {
|
|
101
|
+
return arg
|
|
102
|
+
.replace(/\s+/g, ' ')
|
|
103
|
+
.replace(/,(\s*[}\]])/g, '$1')
|
|
104
|
+
.trim();
|
|
105
|
+
};
|
|
106
|
+
const shortenUnchangedOptionProperties = new Set([
|
|
107
|
+
'extrapolateLeft',
|
|
108
|
+
'extrapolateRight',
|
|
109
|
+
]);
|
|
110
|
+
const splitTopLevelArgs = (argsSource) => {
|
|
111
|
+
const args = [];
|
|
112
|
+
let depth = 0;
|
|
113
|
+
let quote = null;
|
|
114
|
+
let start = 0;
|
|
115
|
+
for (let i = 0; i < argsSource.length; i++) {
|
|
116
|
+
const char = argsSource[i];
|
|
117
|
+
const previous = argsSource[i - 1];
|
|
118
|
+
if (quote) {
|
|
119
|
+
if (char === quote && previous !== '\\') {
|
|
120
|
+
quote = null;
|
|
121
|
+
}
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
if (char === "'" || char === '"' || char === '`') {
|
|
125
|
+
quote = char;
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
if (char === '(' || char === '[' || char === '{') {
|
|
129
|
+
depth++;
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
if (char === ')' || char === ']' || char === '}') {
|
|
133
|
+
depth--;
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
if (char === ',' && depth === 0) {
|
|
137
|
+
args.push(argsSource.slice(start, i).trim());
|
|
138
|
+
start = i + 1;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
args.push(argsSource.slice(start).trim());
|
|
142
|
+
return args;
|
|
143
|
+
};
|
|
144
|
+
const getCommonPrefixLength = (oldValueString, newValueString) => {
|
|
145
|
+
const maxLength = Math.min(oldValueString.length, newValueString.length);
|
|
146
|
+
let index = 0;
|
|
147
|
+
while (index < maxLength && oldValueString[index] === newValueString[index]) {
|
|
148
|
+
index++;
|
|
149
|
+
}
|
|
150
|
+
return index;
|
|
151
|
+
};
|
|
152
|
+
const getCommonSuffixLength = ({ oldValueString, newValueString, prefixLength, }) => {
|
|
153
|
+
const maxLength = Math.min(oldValueString.length, newValueString.length) - prefixLength;
|
|
154
|
+
let index = 0;
|
|
155
|
+
while (index < maxLength &&
|
|
156
|
+
oldValueString[oldValueString.length - 1 - index] ===
|
|
157
|
+
newValueString[newValueString.length - 1 - index]) {
|
|
158
|
+
index++;
|
|
159
|
+
}
|
|
160
|
+
return index;
|
|
161
|
+
};
|
|
162
|
+
const minSharedInlineDeltaChars = 12;
|
|
163
|
+
const formatInlineAdditionOrRemoval = ({ oldValueString, newValueString, }) => {
|
|
164
|
+
if (!(0, exports.colorEnabled)()) {
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
const prefixLength = getCommonPrefixLength(oldValueString, newValueString);
|
|
168
|
+
const suffixLength = getCommonSuffixLength({
|
|
169
|
+
oldValueString,
|
|
170
|
+
newValueString,
|
|
171
|
+
prefixLength,
|
|
172
|
+
});
|
|
173
|
+
if (prefixLength + suffixLength < minSharedInlineDeltaChars) {
|
|
174
|
+
return null;
|
|
175
|
+
}
|
|
176
|
+
const oldMiddleEnd = oldValueString.length - suffixLength;
|
|
177
|
+
const newMiddleEnd = newValueString.length - suffixLength;
|
|
178
|
+
const oldMiddle = oldValueString.slice(prefixLength, oldMiddleEnd);
|
|
179
|
+
const newMiddle = newValueString.slice(prefixLength, newMiddleEnd);
|
|
180
|
+
if (oldMiddle.length === 0 && newMiddle.length > 0) {
|
|
181
|
+
return `${newValueString.slice(0, prefixLength)}${(0, exports.inlineAddition)(newMiddle)}${newValueString.slice(newMiddleEnd)}`;
|
|
182
|
+
}
|
|
183
|
+
if (newMiddle.length === 0 && oldMiddle.length > 0) {
|
|
184
|
+
return `${oldValueString.slice(0, prefixLength)}${(0, exports.strikeThrough)(oldMiddle)}${oldValueString.slice(oldMiddleEnd)}`;
|
|
185
|
+
}
|
|
186
|
+
return null;
|
|
187
|
+
};
|
|
188
|
+
const getObjectPropertyKey = (propertySource) => {
|
|
189
|
+
const colonIndex = propertySource.indexOf(':');
|
|
190
|
+
if (colonIndex === -1) {
|
|
191
|
+
return null;
|
|
192
|
+
}
|
|
193
|
+
const key = propertySource.slice(0, colonIndex).trim();
|
|
194
|
+
if (/^[A-Za-z_$][\w$]*$/.test(key)) {
|
|
195
|
+
return key;
|
|
196
|
+
}
|
|
197
|
+
if ((key.startsWith("'") && key.endsWith("'")) ||
|
|
198
|
+
(key.startsWith('"') && key.endsWith('"'))) {
|
|
199
|
+
return key.slice(1, -1);
|
|
200
|
+
}
|
|
201
|
+
return null;
|
|
202
|
+
};
|
|
203
|
+
const parseTopLevelObjectProperties = (objectSource) => {
|
|
204
|
+
const trimmed = objectSource.trim();
|
|
205
|
+
if (!trimmed.startsWith('{') || !trimmed.endsWith('}')) {
|
|
206
|
+
return null;
|
|
207
|
+
}
|
|
208
|
+
const properties = splitTopLevelArgs(trimmed.slice(1, -1))
|
|
209
|
+
.filter(Boolean)
|
|
210
|
+
.map((propertySource) => {
|
|
211
|
+
const key = getObjectPropertyKey(propertySource);
|
|
212
|
+
if (key === null) {
|
|
213
|
+
return null;
|
|
214
|
+
}
|
|
215
|
+
const colonIndex = propertySource.indexOf(':');
|
|
216
|
+
return {
|
|
217
|
+
key,
|
|
218
|
+
value: normalizeArg(propertySource.slice(colonIndex + 1)),
|
|
219
|
+
source: propertySource.trim(),
|
|
220
|
+
};
|
|
221
|
+
});
|
|
222
|
+
if (properties.some((property) => property === null)) {
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
return properties;
|
|
226
|
+
};
|
|
227
|
+
const parseInterpolateCall = (valueString) => {
|
|
228
|
+
const trimmed = valueString.trim();
|
|
229
|
+
if (!trimmed.startsWith(callStart) || !trimmed.endsWith(')')) {
|
|
230
|
+
return null;
|
|
231
|
+
}
|
|
232
|
+
let depth = 0;
|
|
233
|
+
let quote = null;
|
|
234
|
+
for (let i = 'interpolate'.length; i < trimmed.length; i++) {
|
|
235
|
+
const char = trimmed[i];
|
|
236
|
+
const previous = trimmed[i - 1];
|
|
237
|
+
if (quote) {
|
|
238
|
+
if (char === quote && previous !== '\\') {
|
|
239
|
+
quote = null;
|
|
240
|
+
}
|
|
241
|
+
continue;
|
|
242
|
+
}
|
|
243
|
+
if (char === "'" || char === '"' || char === '`') {
|
|
244
|
+
quote = char;
|
|
245
|
+
continue;
|
|
246
|
+
}
|
|
247
|
+
if (char === '(' || char === '[' || char === '{') {
|
|
248
|
+
depth++;
|
|
249
|
+
continue;
|
|
250
|
+
}
|
|
251
|
+
if (char === ')' || char === ']' || char === '}') {
|
|
252
|
+
depth--;
|
|
253
|
+
if (depth === 0 && i !== trimmed.length - 1) {
|
|
254
|
+
return null;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
if (depth !== 0) {
|
|
259
|
+
return null;
|
|
260
|
+
}
|
|
261
|
+
return {
|
|
262
|
+
args: splitTopLevelArgs(trimmed.slice(callStart.length, -1)),
|
|
263
|
+
};
|
|
264
|
+
};
|
|
265
|
+
const shortenUnchangedInterpolateOptions = ({ oldValueString, newValueString, }) => {
|
|
266
|
+
const oldCall = parseInterpolateCall(oldValueString);
|
|
267
|
+
const newCall = parseInterpolateCall(newValueString);
|
|
268
|
+
if (!oldCall ||
|
|
269
|
+
!newCall ||
|
|
270
|
+
oldCall.args.length <= 3 ||
|
|
271
|
+
newCall.args.length <= 3) {
|
|
272
|
+
return { oldValueString, newValueString };
|
|
273
|
+
}
|
|
274
|
+
const oldOptions = oldCall.args.slice(3).map(normalizeArg);
|
|
275
|
+
const newOptions = newCall.args.slice(3).map(normalizeArg);
|
|
276
|
+
if (oldOptions.length !== newOptions.length ||
|
|
277
|
+
oldOptions.some((option, index) => option !== newOptions[index])) {
|
|
278
|
+
return { oldValueString, newValueString };
|
|
279
|
+
}
|
|
280
|
+
return {
|
|
281
|
+
oldValueString: `interpolate(${oldCall.args.slice(0, 3).join(', ')})`,
|
|
282
|
+
newValueString: `interpolate(${newCall.args.slice(0, 3).join(', ')})`,
|
|
283
|
+
};
|
|
284
|
+
};
|
|
285
|
+
const removeUnchangedInterpolateOptionProperties = ({ oldValueString, newValueString, }) => {
|
|
286
|
+
const oldCall = parseInterpolateCall(oldValueString);
|
|
287
|
+
const newCall = parseInterpolateCall(newValueString);
|
|
288
|
+
if (!oldCall ||
|
|
289
|
+
!newCall ||
|
|
290
|
+
oldCall.args.length <= 3 ||
|
|
291
|
+
newCall.args.length <= 3) {
|
|
292
|
+
return { oldValueString, newValueString };
|
|
293
|
+
}
|
|
294
|
+
const oldProperties = parseTopLevelObjectProperties(oldCall.args[3]);
|
|
295
|
+
const newProperties = parseTopLevelObjectProperties(newCall.args[3]);
|
|
296
|
+
if (!oldProperties || !newProperties) {
|
|
297
|
+
return { oldValueString, newValueString };
|
|
298
|
+
}
|
|
299
|
+
const propertiesToRemove = [...shortenUnchangedOptionProperties].filter((propertyName) => {
|
|
300
|
+
const oldProperty = oldProperties.find((property) => property.key === propertyName);
|
|
301
|
+
const newProperty = newProperties.find((property) => property.key === propertyName);
|
|
302
|
+
return (oldProperty !== undefined &&
|
|
303
|
+
newProperty !== undefined &&
|
|
304
|
+
oldProperty.value === newProperty.value);
|
|
305
|
+
});
|
|
306
|
+
if (propertiesToRemove.length === 0) {
|
|
307
|
+
return { oldValueString, newValueString };
|
|
308
|
+
}
|
|
309
|
+
const removeProperties = (call, properties) => {
|
|
310
|
+
const nextOptions = properties.filter((property) => !propertiesToRemove.includes(property.key));
|
|
311
|
+
const nextArgs = nextOptions.length === 0
|
|
312
|
+
? [...call.args.slice(0, 3), ...call.args.slice(4)]
|
|
313
|
+
: [
|
|
314
|
+
...call.args.slice(0, 3),
|
|
315
|
+
`{${nextOptions.map((property) => property.source).join(', ')}}`,
|
|
316
|
+
...call.args.slice(4),
|
|
317
|
+
];
|
|
318
|
+
return `interpolate(${nextArgs.join(', ')})`;
|
|
319
|
+
};
|
|
320
|
+
return {
|
|
321
|
+
oldValueString: removeProperties(oldCall, oldProperties),
|
|
322
|
+
newValueString: removeProperties(newCall, newProperties),
|
|
323
|
+
};
|
|
324
|
+
};
|
|
@@ -30,11 +30,17 @@ const updateEffectKeyframeSettingsHandler = ({ input: { fileName, sequenceNodePa
|
|
|
30
30
|
updates: [
|
|
31
31
|
{
|
|
32
32
|
key,
|
|
33
|
-
operation:
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
33
|
+
operation: settings.type === 'settings'
|
|
34
|
+
? {
|
|
35
|
+
type: 'settings',
|
|
36
|
+
clamping: settings.clamping,
|
|
37
|
+
posterize: settings.posterize,
|
|
38
|
+
}
|
|
39
|
+
: {
|
|
40
|
+
type: 'easing',
|
|
41
|
+
segmentIndex: settings.segmentIndex,
|
|
42
|
+
easing: settings.easing,
|
|
43
|
+
},
|
|
38
44
|
},
|
|
39
45
|
],
|
|
40
46
|
});
|
|
@@ -27,11 +27,17 @@ const updateSequenceKeyframeSettingsHandler = ({ input: { fileName, nodePath, ke
|
|
|
27
27
|
updates: [
|
|
28
28
|
{
|
|
29
29
|
key,
|
|
30
|
-
operation:
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
30
|
+
operation: settings.type === 'settings'
|
|
31
|
+
? {
|
|
32
|
+
type: 'settings',
|
|
33
|
+
clamping: settings.clamping,
|
|
34
|
+
posterize: settings.posterize,
|
|
35
|
+
}
|
|
36
|
+
: {
|
|
37
|
+
type: 'easing',
|
|
38
|
+
segmentIndex: settings.segmentIndex,
|
|
39
|
+
easing: settings.easing,
|
|
40
|
+
},
|
|
35
41
|
},
|
|
36
42
|
],
|
|
37
43
|
});
|
|
@@ -3,7 +3,7 @@ export interface UndoEntryDescription {
|
|
|
3
3
|
undoMessage: string;
|
|
4
4
|
redoMessage: string;
|
|
5
5
|
}
|
|
6
|
-
type UndoEntryType = 'visual-control' | 'default-props' | 'sequence-props' | 'effect-props' | 'keyframe-delete' | 'add-effect' | 'delete-effect' | 'paste-effects' | 'reorder-effect' | 'reorder-sequence' | 'delete-jsx-node' | 'duplicate-jsx-node' | 'insert-jsx-element' | 'delete-composition' | 'rename-composition' | 'duplicate-composition' | 'delete-folder' | 'rename-folder';
|
|
6
|
+
type UndoEntryType = 'visual-control' | 'default-props' | 'sequence-props' | 'effect-props' | 'keyframe-add' | 'keyframe-delete' | 'add-effect' | 'delete-effect' | 'paste-effects' | 'reorder-effect' | 'reorder-sequence' | 'delete-jsx-node' | 'duplicate-jsx-node' | 'insert-jsx-element' | 'delete-composition' | 'rename-composition' | 'duplicate-composition' | 'delete-folder' | 'rename-folder';
|
|
7
7
|
type UndoEntrySnapshot = {
|
|
8
8
|
filePath: string;
|
|
9
9
|
oldContents: string;
|
|
@@ -27,6 +27,8 @@ type UndoEntry = {
|
|
|
27
27
|
entryType: 'sequence-props';
|
|
28
28
|
} | {
|
|
29
29
|
entryType: 'effect-props';
|
|
30
|
+
} | {
|
|
31
|
+
entryType: 'keyframe-add';
|
|
30
32
|
} | {
|
|
31
33
|
entryType: 'keyframe-delete';
|
|
32
34
|
} | {
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"url": "https://github.com/remotion-dev/remotion/tree/main/packages/studio-server"
|
|
4
4
|
},
|
|
5
5
|
"name": "@remotion/studio-server",
|
|
6
|
-
"version": "4.0.
|
|
6
|
+
"version": "4.0.475",
|
|
7
7
|
"description": "Run a Remotion Studio with a server backend",
|
|
8
8
|
"main": "dist",
|
|
9
9
|
"scripts": {
|
|
@@ -27,11 +27,11 @@
|
|
|
27
27
|
"@babel/parser": "7.24.1",
|
|
28
28
|
"semver": "7.5.3",
|
|
29
29
|
"prettier": "3.8.1",
|
|
30
|
-
"remotion": "4.0.
|
|
30
|
+
"remotion": "4.0.475",
|
|
31
31
|
"recast": "0.23.11",
|
|
32
|
-
"@remotion/bundler": "4.0.
|
|
33
|
-
"@remotion/renderer": "4.0.
|
|
34
|
-
"@remotion/studio-shared": "4.0.
|
|
32
|
+
"@remotion/bundler": "4.0.475",
|
|
33
|
+
"@remotion/renderer": "4.0.475",
|
|
34
|
+
"@remotion/studio-shared": "4.0.475",
|
|
35
35
|
"memfs": "3.4.3",
|
|
36
36
|
"open": "8.4.2"
|
|
37
37
|
},
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"ast-types": "0.16.1",
|
|
40
40
|
"react": "19.2.3",
|
|
41
41
|
"@types/semver": "7.5.3",
|
|
42
|
-
"@remotion/eslint-config-internal": "4.0.
|
|
42
|
+
"@remotion/eslint-config-internal": "4.0.475",
|
|
43
43
|
"eslint": "9.19.0",
|
|
44
44
|
"@types/node": "20.12.14",
|
|
45
45
|
"@typescript/native-preview": "7.0.0-dev.20260217.1"
|