@remotion/studio 4.0.483 → 4.0.484

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/dist/components/ColorPicker/ColorPicker.js +65 -3
  2. package/dist/components/ColorPicker/ColorPickerPopup.d.ts +1 -0
  3. package/dist/components/ColorPicker/ColorPickerPopup.js +3 -2
  4. package/dist/components/InspectorPanel/EasingInspector.js +184 -10
  5. package/dist/components/InspectorPanel/KeyframeEasingNavigator.d.ts +14 -0
  6. package/dist/components/InspectorPanel/KeyframeEasingNavigator.js +146 -0
  7. package/dist/components/InspectorPanel/KeyframeInspector.d.ts +1 -1
  8. package/dist/components/InspectorPanel/KeyframeInspector.js +228 -5
  9. package/dist/components/InspectorPanel/SequenceInspectorHeader.d.ts +17 -0
  10. package/dist/components/InspectorPanel/SequenceInspectorHeader.js +93 -0
  11. package/dist/components/InspectorPanel/SequenceSelectionInspector.js +4 -58
  12. package/dist/components/InspectorPanel/common.d.ts +12 -0
  13. package/dist/components/InspectorPanel/common.js +78 -1
  14. package/dist/components/InspectorPanel/easing-inspector-selection.d.ts +14 -0
  15. package/dist/components/InspectorPanel/easing-inspector-selection.js +18 -0
  16. package/dist/components/InspectorPanel/keyframe-easing-navigator-items.d.ts +24 -0
  17. package/dist/components/InspectorPanel/keyframe-easing-navigator-items.js +40 -0
  18. package/dist/components/InspectorPanel/keyframe-inspector-frame.d.ts +8 -0
  19. package/dist/components/InspectorPanel/keyframe-inspector-frame.js +14 -0
  20. package/dist/components/InspectorPanel/styles.d.ts +1 -0
  21. package/dist/components/InspectorPanel/styles.js +7 -1
  22. package/dist/components/InspectorSequenceSection.js +3 -9
  23. package/dist/components/Preview.js +1 -1
  24. package/dist/components/SelectedOutlineOverlay.d.ts +2 -0
  25. package/dist/components/SelectedOutlineOverlay.js +33 -12
  26. package/dist/components/Timeline/EasingEditorModal.js +9 -4
  27. package/dist/components/Timeline/TimelineDeleteKeybindings.js +11 -1
  28. package/dist/components/Timeline/TimelineEffectPropItem.js +82 -1
  29. package/dist/components/Timeline/TimelineKeyframeControls.js +37 -7
  30. package/dist/components/Timeline/TimelineKeyframeEasingLine.d.ts +4 -0
  31. package/dist/components/Timeline/TimelineKeyframeEasingLine.js +12 -6
  32. package/dist/components/Timeline/TimelineSequenceItem.js +48 -15
  33. package/dist/components/Timeline/TimelineSequenceName.d.ts +1 -0
  34. package/dist/components/Timeline/TimelineSequenceName.js +7 -6
  35. package/dist/components/Timeline/TimelineSequencePropItem.d.ts +1 -1
  36. package/dist/components/Timeline/TimelineSequencePropItem.js +80 -1
  37. package/dist/components/Timeline/TimelineSlider.js +17 -3
  38. package/dist/components/Timeline/delete-selected-timeline-item.d.ts +8 -2
  39. package/dist/components/Timeline/delete-selected-timeline-item.js +80 -1
  40. package/dist/components/Timeline/get-animation-item-selection-for-frame.d.ts +18 -0
  41. package/dist/components/Timeline/get-animation-item-selection-for-frame.js +49 -0
  42. package/dist/components/Timeline/get-easing-selection-after-keyframe-delete.d.ts +15 -0
  43. package/dist/components/Timeline/get-easing-selection-after-keyframe-delete.js +26 -0
  44. package/dist/components/Timeline/save-sequence-prop.js +2 -0
  45. package/dist/components/Timeline/update-selected-easing.d.ts +1 -0
  46. package/dist/components/Timeline/update-selected-easing.js +4 -3
  47. package/dist/esm/{chunk-fq0j774v.js → chunk-9erwh79m.js} +10745 -9242
  48. package/dist/esm/internals.mjs +10745 -9242
  49. package/dist/esm/previewEntry.mjs +10762 -9259
  50. package/dist/esm/renderEntry.mjs +1 -1
  51. package/dist/helpers/use-menu-structure.js +0 -14
  52. package/package.json +11 -11
@@ -78,6 +78,19 @@ const effectDropHighlight = {
78
78
  outlineOffset: -1,
79
79
  };
80
80
  const SEQUENCE_REORDER_MIME_TYPE = 'application/remotion-sequence-reorder';
81
+ const getSequenceNameSaveAction = ({ editedName, currentDisplayName, fallbackDisplayName, hasStaticNameProp, }) => {
82
+ if (!hasStaticNameProp &&
83
+ (editedName === '' || editedName === fallbackDisplayName)) {
84
+ return { type: 'noop' };
85
+ }
86
+ if (hasStaticNameProp && editedName === currentDisplayName) {
87
+ return { type: 'noop' };
88
+ }
89
+ return {
90
+ type: 'save',
91
+ defaultValue: editedName === '' ? JSON.stringify('') : null,
92
+ };
93
+ };
81
94
  let currentSequenceDrag = null;
82
95
  const TimelineSequenceExpandArrow = ({ disabled, isExpanded, nodePathInfo, onToggleExpand, sequence }) => {
83
96
  const { filteredTree } = (0, use_timeline_expanded_tree_1.useTimelineExpandedTree)({
@@ -150,9 +163,9 @@ const getDestinationIndex = ({ fromIndex, insertionIndex, }) => {
150
163
  return insertionIndex > fromIndex ? insertionIndex - 1 : insertionIndex;
151
164
  };
152
165
  const TimelineSequenceItem = ({ nestedDepth, sequence, nodePathInfo, keyframeDisplayOffset, sequenceFrameOffset, trackIndex, }) => {
153
- var _a, _b, _c;
154
- var _d, _e, _f;
155
- const nodePath = (_d = nodePathInfo === null || nodePathInfo === void 0 ? void 0 : nodePathInfo.sequenceSubscriptionKey) !== null && _d !== void 0 ? _d : null;
166
+ var _a, _b, _c, _d;
167
+ var _e, _f, _g, _h;
168
+ const nodePath = (_e = nodePathInfo === null || nodePathInfo === void 0 ? void 0 : nodePathInfo.sequenceSubscriptionKey) !== null && _e !== void 0 ? _e : null;
156
169
  const { previewServerState } = (0, react_1.useContext)(client_id_1.StudioServerConnectionCtx);
157
170
  const previewConnected = previewServerState.type === 'connected';
158
171
  const { getIsExpanded } = (0, react_1.useContext)(ExpandedTracksProvider_1.ExpandedTracksGetterContext);
@@ -190,7 +203,7 @@ const TimelineSequenceItem = ({ nestedDepth, sequence, nodePathInfo, keyframeDis
190
203
  }, [originalLocation]);
191
204
  const canDeleteFromSource = Boolean(nodePath && (validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.source));
192
205
  const nodePathKey = (0, react_1.useMemo)(() => nodePath ? remotion_1.Internals.makeSequencePropsSubscriptionKey(nodePath) : null, [nodePath]);
193
- const parentId = (_e = sequence.parent) !== null && _e !== void 0 ? _e : null;
206
+ const parentId = (_f = sequence.parent) !== null && _f !== void 0 ? _f : null;
194
207
  const canReorderSequence = previewConnected &&
195
208
  Boolean(nodePath && nodePathKey && (validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.source)) &&
196
209
  (nodePathInfo === null || nodePathInfo === void 0 ? void 0 : nodePathInfo.numberOfSequencesWithThisNodePath) === 1;
@@ -453,14 +466,26 @@ const TimelineSequenceItem = ({ nestedDepth, sequence, nodePathInfo, keyframeDis
453
466
  const effective = (propStatus !== null && propStatus !== void 0 ? propStatus : runtimeValue);
454
467
  return effective !== null && effective !== void 0 ? effective : false;
455
468
  }, [codeHiddenStatus, (_a = sequence.controls) === null || _a === void 0 ? void 0 : _a.currentRuntimeValueDotNotation]);
469
+ const fallbackDisplayName = (_g = (_b = sequence.controls) === null || _b === void 0 ? void 0 : _b.componentName) !== null && _g !== void 0 ? _g : '<Sequence>';
470
+ const staticNamePropValue = (codeNameStatus === null || codeNameStatus === void 0 ? void 0 : codeNameStatus.status) === 'static' &&
471
+ typeof codeNameStatus.codeValue === 'string'
472
+ ? codeNameStatus.codeValue
473
+ : null;
474
+ const hasStaticNameProp = staticNamePropValue !== null;
456
475
  const displayName = (0, react_1.useMemo)(() => {
457
- if (codeNameStatus &&
458
- codeNameStatus.status === 'static' &&
459
- typeof codeNameStatus.codeValue === 'string') {
460
- return codeNameStatus.codeValue;
476
+ if (staticNamePropValue !== null) {
477
+ return staticNamePropValue;
478
+ }
479
+ if ((codeNameStatus === null || codeNameStatus === void 0 ? void 0 : codeNameStatus.status) === 'static') {
480
+ return fallbackDisplayName;
461
481
  }
462
482
  return sequence.displayName;
463
- }, [codeNameStatus, sequence.displayName]);
483
+ }, [
484
+ codeNameStatus === null || codeNameStatus === void 0 ? void 0 : codeNameStatus.status,
485
+ fallbackDisplayName,
486
+ sequence.displayName,
487
+ staticNamePropValue,
488
+ ]);
464
489
  const onToggleVisibility = (0, react_1.useCallback)((type) => {
465
490
  if (!sequence.controls ||
466
491
  !nodePath ||
@@ -552,7 +577,7 @@ const TimelineSequenceItem = ({ nestedDepth, sequence, nodePathInfo, keyframeDis
552
577
  const canRenameSelectedSequence = canRenameThisSequence &&
553
578
  selected &&
554
579
  selectedItems.length === 1 &&
555
- ((_b = selectedItems[0]) === null || _b === void 0 ? void 0 : _b.type) === 'sequence';
580
+ ((_c = selectedItems[0]) === null || _c === void 0 ? void 0 : _c.type) === 'sequence';
556
581
  const onCancelRenaming = (0, react_1.useCallback)(() => {
557
582
  setIsRenaming(false);
558
583
  }, []);
@@ -565,7 +590,13 @@ const TimelineSequenceItem = ({ nestedDepth, sequence, nodePathInfo, keyframeDis
565
590
  setIsRenaming(false);
566
591
  return;
567
592
  }
568
- if (name === displayName) {
593
+ const action = getSequenceNameSaveAction({
594
+ editedName: name,
595
+ currentDisplayName: displayName,
596
+ fallbackDisplayName,
597
+ hasStaticNameProp,
598
+ });
599
+ if (action.type === 'noop') {
569
600
  setIsRenaming(false);
570
601
  return;
571
602
  }
@@ -576,7 +607,7 @@ const TimelineSequenceItem = ({ nestedDepth, sequence, nodePathInfo, keyframeDis
576
607
  nodePath,
577
608
  fieldKey: 'name',
578
609
  value: name,
579
- defaultValue: null,
610
+ defaultValue: action.defaultValue,
580
611
  schema: sequence.controls.schema,
581
612
  },
582
613
  ],
@@ -590,6 +621,8 @@ const TimelineSequenceItem = ({ nestedDepth, sequence, nodePathInfo, keyframeDis
590
621
  }, [
591
622
  canRenameThisSequence,
592
623
  displayName,
624
+ fallbackDisplayName,
625
+ hasStaticNameProp,
593
626
  nodePath,
594
627
  previewServerState,
595
628
  sequence.controls,
@@ -640,7 +673,7 @@ const TimelineSequenceItem = ({ nestedDepth, sequence, nodePathInfo, keyframeDis
640
673
  sequenceFrameOffset,
641
674
  setPropStatuses,
642
675
  timelinePosition,
643
- validatedSource: (_f = validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.source) !== null && _f !== void 0 ? _f : null,
676
+ validatedSource: (_h = validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.source) !== null && _h !== void 0 ? _h : null,
644
677
  });
645
678
  const canAddEffect = (nodePathInfo === null || nodePathInfo === void 0 ? void 0 : nodePathInfo.supportsEffects) === true &&
646
679
  previewServerState.type === 'connected' &&
@@ -747,7 +780,7 @@ const TimelineSequenceItem = ({ nestedDepth, sequence, nodePathInfo, keyframeDis
747
780
  const canDropEffect = previewServerState.type === 'connected' &&
748
781
  nodePath !== null &&
749
782
  validatedLocation !== null &&
750
- ((_c = sequence.controls) === null || _c === void 0 ? void 0 : _c.supportsEffects) === true;
783
+ ((_d = sequence.controls) === null || _d === void 0 ? void 0 : _d.supportsEffects) === true;
751
784
  const sequenceReorderLineStyle = (0, react_1.useMemo)(() => {
752
785
  if (!sequenceDropIndicator) {
753
786
  return null;
@@ -805,7 +838,7 @@ const TimelineSequenceItem = ({ nestedDepth, sequence, nodePathInfo, keyframeDis
805
838
  const trackRow = (jsx_runtime_1.jsx(TimelineRowChrome_1.TimelineRowChrome, { depth: nestedDepth, eye: canToggleVisibility ? (jsx_runtime_1.jsx(TimelineLayerEye_1.TimelineLayerEye, { type: sequence.type === 'audio' ? 'speaker' : 'eye', hidden: isItemHidden, onInvoked: onToggleVisibility })) : (jsx_runtime_1.jsx(TimelineLayerEye_1.TimelineLayerEyeSpacer, {})), arrow: hasExpandableContent && nodePathInfo !== null ? (jsx_runtime_1.jsx(TimelineSequenceExpandArrow, { disabled: !previewConnected, isExpanded: isExpanded, nodePathInfo: nodePathInfo, onToggleExpand: onToggleExpand, sequence: sequence })) : (jsx_runtime_1.jsx(TimelineExpandArrowButton_1.TimelineExpandArrowSpacer, {})), style: rowStyle, selected: selected, selectable: selectable, selectionItem: selectionItem, onSelect: onSelect, showSelectedBackground: true, containsSelection: containsSelection, outerHeight: outerHeight, onDragLeave: canDropEffect ? onEffectDragLeave : undefined, onDragOver: canDropEffect ? onEffectDragOver : undefined, onDrop: canDropEffect ? onEffectDrop : undefined, onDoubleClick: canRenameThisSequence || canOpenInEditor
806
839
  ? onSequenceDoubleClick
807
840
  : undefined, children: jsx_runtime_1.jsxs("div", { style: labelContainerStyle, children: [
808
- jsx_runtime_1.jsx(TimelineSequenceName_1.TimelineSequenceName, { displayName: displayName, selected: selected, containsSelection: containsSelection, editing: isRenaming, onCancelEditing: onCancelRenaming, onSaveName: onSaveName }), mediaSrc ? (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [
841
+ jsx_runtime_1.jsx(TimelineSequenceName_1.TimelineSequenceName, { displayName: displayName, fallbackDisplayName: fallbackDisplayName, selected: selected, containsSelection: containsSelection, editing: isRenaming, onCancelEditing: onCancelRenaming, onSaveName: onSaveName }), mediaSrc ? (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [
809
842
  jsx_runtime_1.jsx(layout_1.Spacing, { x: 0.5 }),
810
843
  " ",
811
844
  jsx_runtime_1.jsx(TimelineMediaInfo_1.TimelineMediaInfo, { src: mediaSrc })
@@ -1,6 +1,7 @@
1
1
  import React from 'react';
2
2
  export declare const TimelineSequenceName: React.FC<{
3
3
  readonly displayName: string;
4
+ readonly fallbackDisplayName: string;
4
5
  readonly selected: boolean;
5
6
  readonly containsSelection: boolean;
6
7
  readonly editing: boolean;
@@ -13,7 +13,7 @@ const getTruncatedDisplayName = (displayName) => {
13
13
  }
14
14
  return displayName;
15
15
  };
16
- const TimelineSequenceName = ({ displayName, selected, containsSelection, editing, onCancelEditing, onSaveName, }) => {
16
+ const TimelineSequenceName = ({ displayName, fallbackDisplayName, selected, containsSelection, editing, onCancelEditing, onSaveName, }) => {
17
17
  const inputRef = (0, react_1.useRef)(null);
18
18
  const [draftName, setDraftName] = (0, react_1.useState)(displayName);
19
19
  const cancelNextBlurRef = (0, react_1.useRef)(false);
@@ -53,10 +53,11 @@ const TimelineSequenceName = ({ displayName, selected, containsSelection, editin
53
53
  WebkitUserSelect: 'text',
54
54
  };
55
55
  }, [style]);
56
- const text = getTruncatedDisplayName(displayName) || '<Sequence>';
56
+ const editableDisplayName = displayName || fallbackDisplayName;
57
+ const text = getTruncatedDisplayName(editableDisplayName);
57
58
  (0, react_1.useEffect)(() => {
58
59
  if (!editing) {
59
- setDraftName(displayName);
60
+ setDraftName(editableDisplayName);
60
61
  return;
61
62
  }
62
63
  const input = inputRef.current;
@@ -64,10 +65,10 @@ const TimelineSequenceName = ({ displayName, selected, containsSelection, editin
64
65
  return;
65
66
  }
66
67
  input.focus();
67
- const basenameIndex = displayName.lastIndexOf('.');
68
- const selectionEnd = basenameIndex > 0 ? basenameIndex : displayName.length;
68
+ const basenameIndex = editableDisplayName.lastIndexOf('.');
69
+ const selectionEnd = basenameIndex > 0 ? basenameIndex : editableDisplayName.length;
69
70
  input.setSelectionRange(0, selectionEnd);
70
- }, [displayName, editing]);
71
+ }, [editableDisplayName, editing]);
71
72
  const save = (0, react_1.useCallback)(() => {
72
73
  onSaveName(draftName).catch(() => undefined);
73
74
  }, [draftName, onSaveName]);
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import type { CanUpdateSequencePropStatusKeyframed, SequencePropsSubscriptionKey, InteractivitySchema } from 'remotion';
2
+ import type { CanUpdateSequencePropStatusKeyframed, InteractivitySchema, SequencePropsSubscriptionKey } from 'remotion';
3
3
  import type { CodePosition } from '../../error-overlay/react-overlay/utils/get-source-map';
4
4
  import type { SequenceNodePathInfo } from '../../helpers/get-timeline-sequence-sort-key';
5
5
  import type { SchemaFieldInfo } from '../../helpers/timeline-layout';
@@ -9,6 +9,7 @@ const client_id_1 = require("../../helpers/client-id");
9
9
  const modals_1 = require("../../state/modals");
10
10
  const ContextMenu_1 = require("../ContextMenu");
11
11
  const call_add_keyframe_1 = require("./call-add-keyframe");
12
+ const get_animation_item_selection_for_frame_1 = require("./get-animation-item-selection-for-frame");
12
13
  const save_sequence_prop_1 = require("./save-sequence-prop");
13
14
  const timeline_field_row_layout_1 = require("./timeline-field-row-layout");
14
15
  const TimelineExpandArrowButton_1 = require("./TimelineExpandArrowButton");
@@ -19,6 +20,7 @@ const TimelineLayerEye_1 = require("./TimelineLayerEye");
19
20
  const TimelineRowChrome_1 = require("./TimelineRowChrome");
20
21
  const TimelineSchemaField_1 = require("./TimelineSchemaField");
21
22
  const TimelineSelection_1 = require("./TimelineSelection");
23
+ const update_selected_easing_1 = require("./update-selected-easing");
22
24
  const fieldRowBase = {};
23
25
  const isKeyframedStatus = (status) => {
24
26
  return status.status === 'keyframed';
@@ -162,6 +164,9 @@ const TimelineSequencePropItem = ({ field, validatedLocation, rowDepth, nodePath
162
164
  const { previewServerState } = (0, react_1.useContext)(client_id_1.StudioServerConnectionCtx);
163
165
  const { setSelectedModal } = (0, react_1.useContext)(modals_1.ModalsContext);
164
166
  const selection = (0, TimelineSelection_1.useTimelineRowSelection)(nodePathInfo);
167
+ const { selectItems } = (0, TimelineSelection_1.useTimelineSelection)();
168
+ const setFrame = remotion_1.Internals.useTimelineSetFrame();
169
+ const videoConfig = (0, remotion_1.useVideoConfig)();
165
170
  const timelinePosition = remotion_1.Internals.Timeline.useTimelinePosition();
166
171
  const sourceFrame = timelinePosition - keyframeDisplayOffset;
167
172
  const propStatusesForOverride = remotion_1.Internals.getPropStatusesCtx(visualModePropStatuses, nodePath);
@@ -303,10 +308,84 @@ const TimelineSequencePropItem = ({ field, validatedLocation, rowDepth, nodePath
303
308
  onReset,
304
309
  previewServerState,
305
310
  ]);
311
+ const seekToDisplayFrame = (0, react_1.useCallback)((frame) => {
312
+ setFrame((current) => {
313
+ const next = { ...current, [videoConfig.id]: frame };
314
+ remotion_1.Internals.persistCurrentFrame(next);
315
+ return next;
316
+ });
317
+ }, [setFrame, videoConfig.id]);
318
+ const onPropertyDoubleClick = (0, react_1.useCallback)((event) => {
319
+ if (propStatus === null || propStatus.status === 'computed') {
320
+ return;
321
+ }
322
+ const keyframeSelection = {
323
+ type: 'keyframe',
324
+ nodePathInfo,
325
+ frame: sourceFrame + keyframeDisplayOffset,
326
+ };
327
+ if (propStatus.status === 'static') {
328
+ if (!keyframable || previewServerState.type !== 'connected') {
329
+ return;
330
+ }
331
+ const value = remotion_1.Internals.getEffectiveVisualModeValue({
332
+ propStatus,
333
+ dragOverrideValue,
334
+ frame: sourceFrame,
335
+ defaultValue: field.fieldSchema.default,
336
+ shouldResortToDefaultValueIfUndefined: true,
337
+ });
338
+ event.stopPropagation();
339
+ (0, call_add_keyframe_1.callAddSequenceKeyframe)({
340
+ fileName: validatedLocation.source,
341
+ nodePath,
342
+ fieldKey: field.key,
343
+ sourceFrame,
344
+ value,
345
+ schema,
346
+ setPropStatuses,
347
+ clientId: previewServerState.clientId,
348
+ }).catch(() => undefined);
349
+ selectItems([keyframeSelection], { reveal: true });
350
+ seekToDisplayFrame(keyframeSelection.frame);
351
+ return;
352
+ }
353
+ const targetSelection = (0, get_animation_item_selection_for_frame_1.getAnimationItemSelectionForSourceFrame)({
354
+ includeEasings: (0, update_selected_easing_1.canEditEasingForInterpolationFunction)(propStatus.interpolationFunction),
355
+ keyframeDisplayOffset,
356
+ keyframes: propStatus.keyframes,
357
+ nodePathInfo,
358
+ sourceFrame,
359
+ });
360
+ if (targetSelection === null) {
361
+ return;
362
+ }
363
+ event.stopPropagation();
364
+ selectItems([targetSelection], { reveal: true });
365
+ if (targetSelection.type === 'keyframe') {
366
+ seekToDisplayFrame(targetSelection.frame);
367
+ }
368
+ }, [
369
+ dragOverrideValue,
370
+ field.fieldSchema.default,
371
+ field.key,
372
+ keyframeDisplayOffset,
373
+ keyframable,
374
+ nodePath,
375
+ nodePathInfo,
376
+ previewServerState,
377
+ propStatus,
378
+ schema,
379
+ seekToDisplayFrame,
380
+ selectItems,
381
+ setPropStatuses,
382
+ sourceFrame,
383
+ validatedLocation.source,
384
+ ]);
306
385
  if (propStatus === null) {
307
386
  return null;
308
387
  }
309
- const row = (jsx_runtime_1.jsxs(TimelineRowChrome_1.TimelineRowChrome, { depth: rowDepth, eye: jsx_runtime_1.jsx(TimelineLayerEye_1.TimelineLayerEyeSpacer, {}), keyframeControls: keyframeControls, arrow: jsx_runtime_1.jsx(TimelineExpandArrowButton_1.TimelineExpandArrowSpacer, {}), style: style, selected: selection.selected, selectable: selection.selectable, selectionItem: selection.selectionItem, onSelect: selection.onSelect, showSelectedBackground: true, containsSelection: false, outerHeight: null, children: [
388
+ const row = (jsx_runtime_1.jsxs(TimelineRowChrome_1.TimelineRowChrome, { depth: rowDepth, eye: jsx_runtime_1.jsx(TimelineLayerEye_1.TimelineLayerEyeSpacer, {}), keyframeControls: keyframeControls, arrow: jsx_runtime_1.jsx(TimelineExpandArrowButton_1.TimelineExpandArrowSpacer, {}), style: style, selected: selection.selected, selectable: selection.selectable, selectionItem: selection.selectionItem, onSelect: selection.onSelect, onDoubleClick: onPropertyDoubleClick, showSelectedBackground: true, containsSelection: false, outerHeight: null, children: [
310
389
  jsx_runtime_1.jsx(TimelineFieldLabel_1.TimelineFieldLabel, { rowDepth: rowDepth, selected: selection.selected, label: (_b = field.description) !== null && _b !== void 0 ? _b : field.key }), isKeyframedStatus(propStatus) ? (jsx_runtime_1.jsx("div", { style: timeline_field_row_layout_1.timelineFieldValueColumnStyle, children: jsx_runtime_1.jsx(exports.TimelineSequenceKeyframedValue, { field: field, fileName: validatedLocation.source, nodePath: nodePath, schema: schema, propStatus: propStatus, sourceFrame: sourceFrame }) })) : propStatus.status === 'static' ? (jsx_runtime_1.jsx("div", { style: timeline_field_row_layout_1.timelineFieldValueColumnStyle, children: jsx_runtime_1.jsx(Value, { field: field, nodePath: nodePath, validatedLocation: validatedLocation, schema: schema, propStatus: propStatus }) })) : (jsx_runtime_1.jsx("div", { style: timeline_field_row_layout_1.timelineFieldValueColumnStyle, children: jsx_runtime_1.jsx(TimelineSchemaField_1.TimelineNonEditableStatus, { propStatus: propStatus }) }))] }));
311
390
  return (jsx_runtime_1.jsx(ContextMenu_1.ContextMenu, { values: contextMenuValues, onOpen: selection.selectable ? selection.onSelect : null, children: row }));
312
391
  };
@@ -16,12 +16,18 @@ const container = {
16
16
  top: 0,
17
17
  pointerEvents: 'none',
18
18
  };
19
+ const PLAYHEAD_LINE_WIDTH = 1;
19
20
  const line = {
20
21
  height: '100vh',
21
- width: 1,
22
+ width: PLAYHEAD_LINE_WIDTH,
22
23
  position: 'fixed',
23
24
  backgroundColor: '#f02c00',
24
25
  };
26
+ const PLAYHEAD_CENTER_OFFSET = PLAYHEAD_LINE_WIDTH / 2;
27
+ const getTimelineSliderTransform = ({ durationInFrames, frame, width, }) => {
28
+ const left = (0, get_left_of_timeline_slider_1.getXPositionOfItemInTimelineImperatively)(frame, durationInFrames, width);
29
+ return `translateX(${left - PLAYHEAD_CENTER_OFFSET}px)`;
30
+ };
25
31
  exports.redrawTimelineSliderFast = (0, react_1.createRef)();
26
32
  const TimelineSlider = () => {
27
33
  const videoConfig = remotion_1.Internals.useUnsafeVideoConfig();
@@ -53,7 +59,11 @@ const TimelineSliderInner = () => {
53
59
  if (!el || measuredWidth === undefined || measuredWidth === 0) {
54
60
  return;
55
61
  }
56
- el.style.transform = `translateX(${(0, get_left_of_timeline_slider_1.getXPositionOfItemInTimelineImperatively)(timelinePosition, videoConfig.durationInFrames, measuredWidth)}px)`;
62
+ el.style.transform = getTimelineSliderTransform({
63
+ durationInFrames: videoConfig.durationInFrames,
64
+ frame: timelinePosition,
65
+ width: measuredWidth,
66
+ });
57
67
  }, [
58
68
  timelinePosition,
59
69
  videoConfig.durationInFrames,
@@ -69,7 +79,11 @@ const TimelineSliderInner = () => {
69
79
  if (!current) {
70
80
  throw new Error('unexpectedly did not have ref to timelineslider');
71
81
  }
72
- current.style.transform = `translateX(${(0, get_left_of_timeline_slider_1.getXPositionOfItemInTimelineImperatively)(frame, (0, imperative_state_1.getCurrentDuration)(), (_b = width !== null && width !== void 0 ? width : (_a = timeline_refs_1.sliderAreaRef.current) === null || _a === void 0 ? void 0 : _a.clientWidth) !== null && _b !== void 0 ? _b : 0)}px)`;
82
+ current.style.transform = getTimelineSliderTransform({
83
+ durationInFrames: (0, imperative_state_1.getCurrentDuration)(),
84
+ frame,
85
+ width: (_b = width !== null && width !== void 0 ? width : (_a = timeline_refs_1.sliderAreaRef.current) === null || _a === void 0 ? void 0 : _a.clientWidth) !== null && _b !== void 0 ? _b : 0,
86
+ });
73
87
  },
74
88
  };
75
89
  }, []);
@@ -1,4 +1,4 @@
1
- import type { OverrideIdToNodePaths, TSequence } from 'remotion';
1
+ import type { OverrideIdToNodePaths, PropStatuses, TSequence } from 'remotion';
2
2
  import type { ConfirmationDialogFunction } from '../ConfirmationDialog-types';
3
3
  import type { SetPropStatuses } from './save-sequence-prop';
4
4
  import { type TimelineSelection } from './TimelineSelection';
@@ -10,7 +10,13 @@ export declare const deleteSelectedTimelineItem: ({ selection, sequences, overri
10
10
  clientId: string;
11
11
  confirm: ConfirmationDialogFunction;
12
12
  }) => Promise<boolean> | null;
13
- export declare const getTimelineSelectionAfterDeletingItems: (selections: readonly TimelineSelection[]) => readonly TimelineSelection[];
13
+ export declare const getTimelineSelectionAfterDeletingItems: ({ selections, sequences, overrideIdsToNodePaths, propStatuses, timelinePosition, }: {
14
+ readonly selections: readonly TimelineSelection[];
15
+ readonly sequences?: TSequence[] | undefined;
16
+ readonly overrideIdsToNodePaths?: OverrideIdToNodePaths | undefined;
17
+ readonly propStatuses?: PropStatuses | undefined;
18
+ readonly timelinePosition?: number | undefined;
19
+ }) => readonly TimelineSelection[];
14
20
  export declare const deleteSelectedTimelineItems: ({ selections, sequences, overrideIdsToNodePaths, setPropStatuses, clientId, confirm, }: {
15
21
  selections: readonly TimelineSelection[];
16
22
  sequences: TSequence[];
@@ -1,10 +1,15 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.deleteSelectedTimelineItems = exports.getTimelineSelectionAfterDeletingItems = exports.deleteSelectedTimelineItem = void 0;
4
+ const remotion_1 = require("remotion");
4
5
  const call_api_1 = require("../call-api");
5
6
  const NotificationCenter_1 = require("../Notifications/NotificationCenter");
6
7
  const delete_selected_keyframe_1 = require("./delete-selected-keyframe");
8
+ const find_track_for_node_path_info_1 = require("./find-track-for-node-path-info");
9
+ const get_easing_selection_after_keyframe_delete_1 = require("./get-easing-selection-after-keyframe-delete");
10
+ const parse_keyframe_field_from_node_path_1 = require("./parse-keyframe-field-from-node-path");
7
11
  const TimelineSelection_1 = require("./TimelineSelection");
12
+ const update_selected_easing_1 = require("./update-selected-easing");
8
13
  const confirmDeletingDuplicatedSequences = (nodePathInfos, confirm) => {
9
14
  const duplicatedNodePathInfos = nodePathInfos.filter((nodePathInfo) => nodePathInfo.numberOfSequencesWithThisNodePath > 1);
10
15
  if (duplicatedNodePathInfos.length === 0) {
@@ -150,7 +155,81 @@ const getSequenceSelectionAfterDeletingEffect = (selection) => {
150
155
  },
151
156
  };
152
157
  };
153
- const getTimelineSelectionAfterDeletingItems = (selections) => {
158
+ const getEasingSelectionAfterDeletingKeyframes = ({ selections, sequences, overrideIdsToNodePaths, propStatuses, timelinePosition, }) => {
159
+ var _a;
160
+ if (sequences === undefined ||
161
+ overrideIdsToNodePaths === undefined ||
162
+ propStatuses === undefined ||
163
+ timelinePosition === undefined) {
164
+ return null;
165
+ }
166
+ const keyframeSelections = selections.filter(isKeyframeSelection);
167
+ if (keyframeSelections.length !== 1) {
168
+ return null;
169
+ }
170
+ const [selection] = keyframeSelections;
171
+ if (!selection) {
172
+ return null;
173
+ }
174
+ const field = (0, parse_keyframe_field_from_node_path_1.parseKeyframeFieldFromNodePath)(selection.nodePathInfo.auxiliaryKeys);
175
+ if (field === null) {
176
+ return null;
177
+ }
178
+ const track = (0, find_track_for_node_path_info_1.findTrackForNodePathInfo)({
179
+ sequences,
180
+ overrideIdsToNodePaths,
181
+ nodePathInfo: selection.nodePathInfo,
182
+ });
183
+ if (!track || !track.sequence.controls) {
184
+ return null;
185
+ }
186
+ const nodePath = selection.nodePathInfo.sequenceSubscriptionKey;
187
+ const sourceFrame = selection.frame - track.keyframeDisplayOffset;
188
+ if (field.type === 'sequence') {
189
+ const sequencePropStatus = (_a = remotion_1.Internals.getPropStatusesCtx(propStatuses, nodePath)) === null || _a === void 0 ? void 0 : _a[field.fieldKey];
190
+ if ((sequencePropStatus === null || sequencePropStatus === void 0 ? void 0 : sequencePropStatus.status) !== 'keyframed' ||
191
+ !(0, update_selected_easing_1.canEditEasingForInterpolationFunction)(sequencePropStatus.interpolationFunction)) {
192
+ return null;
193
+ }
194
+ return (0, get_easing_selection_after_keyframe_delete_1.getEasingSelectionAfterKeyframeDelete)({
195
+ deletedSourceFrames: [sourceFrame],
196
+ keyframeDisplayOffset: track.keyframeDisplayOffset,
197
+ nodePathInfo: selection.nodePathInfo,
198
+ propStatus: sequencePropStatus,
199
+ timelinePosition,
200
+ });
201
+ }
202
+ const effectStatus = remotion_1.Internals.getEffectPropStatusesCtx({
203
+ propStatuses,
204
+ nodePath,
205
+ effectIndex: field.effectIndex,
206
+ });
207
+ const effectPropStatus = effectStatus.type === 'can-update-effect'
208
+ ? effectStatus.props[field.fieldKey]
209
+ : null;
210
+ if ((effectPropStatus === null || effectPropStatus === void 0 ? void 0 : effectPropStatus.status) !== 'keyframed' ||
211
+ !(0, update_selected_easing_1.canEditEasingForInterpolationFunction)(effectPropStatus.interpolationFunction)) {
212
+ return null;
213
+ }
214
+ return (0, get_easing_selection_after_keyframe_delete_1.getEasingSelectionAfterKeyframeDelete)({
215
+ deletedSourceFrames: [sourceFrame],
216
+ keyframeDisplayOffset: track.keyframeDisplayOffset,
217
+ nodePathInfo: selection.nodePathInfo,
218
+ propStatus: effectPropStatus,
219
+ timelinePosition,
220
+ });
221
+ };
222
+ const getTimelineSelectionAfterDeletingItems = ({ selections, sequences, overrideIdsToNodePaths, propStatuses, timelinePosition, }) => {
223
+ const easingSelection = getEasingSelectionAfterDeletingKeyframes({
224
+ selections,
225
+ sequences,
226
+ overrideIdsToNodePaths,
227
+ propStatuses,
228
+ timelinePosition,
229
+ });
230
+ if (easingSelection !== null) {
231
+ return [easingSelection];
232
+ }
154
233
  const nextSelections = new Map();
155
234
  for (const selection of selections) {
156
235
  const nextSelection = getSequenceSelectionAfterDeletingEffect(selection);
@@ -0,0 +1,18 @@
1
+ import type { SequenceNodePathInfo } from '../../helpers/get-timeline-sequence-sort-key';
2
+ import type { TimelineSelection } from './TimelineSelection';
3
+ type AnimationItemSelection = Extract<TimelineSelection, {
4
+ type: 'keyframe';
5
+ } | {
6
+ type: 'easing';
7
+ }>;
8
+ type AnimationKeyframe = {
9
+ readonly frame: number;
10
+ };
11
+ export declare const getAnimationItemSelectionForSourceFrame: ({ includeEasings, keyframeDisplayOffset, keyframes, nodePathInfo, sourceFrame, }: {
12
+ readonly includeEasings: boolean;
13
+ readonly keyframeDisplayOffset: number;
14
+ readonly keyframes: readonly AnimationKeyframe[];
15
+ readonly nodePathInfo: SequenceNodePathInfo;
16
+ readonly sourceFrame: number;
17
+ }) => AnimationItemSelection | null;
18
+ export {};
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getAnimationItemSelectionForSourceFrame = void 0;
4
+ const getKeyframeSelection = ({ keyframe, keyframeDisplayOffset, nodePathInfo, }) => {
5
+ return {
6
+ type: 'keyframe',
7
+ nodePathInfo,
8
+ frame: keyframe.frame + keyframeDisplayOffset,
9
+ };
10
+ };
11
+ const getAnimationItemSelectionForSourceFrame = ({ includeEasings, keyframeDisplayOffset, keyframes, nodePathInfo, sourceFrame, }) => {
12
+ const firstKeyframe = keyframes[0];
13
+ if (!firstKeyframe) {
14
+ return null;
15
+ }
16
+ for (let i = 0; i < keyframes.length; i++) {
17
+ const keyframe = keyframes[i];
18
+ if (keyframe.frame === sourceFrame) {
19
+ return getKeyframeSelection({
20
+ keyframe,
21
+ keyframeDisplayOffset,
22
+ nodePathInfo,
23
+ });
24
+ }
25
+ const nextKeyframe = keyframes[i + 1];
26
+ if (!nextKeyframe) {
27
+ continue;
28
+ }
29
+ if (sourceFrame > keyframe.frame && sourceFrame < nextKeyframe.frame) {
30
+ if (!includeEasings) {
31
+ return null;
32
+ }
33
+ return {
34
+ type: 'easing',
35
+ nodePathInfo,
36
+ fromFrame: keyframe.frame + keyframeDisplayOffset,
37
+ toFrame: nextKeyframe.frame + keyframeDisplayOffset,
38
+ segmentIndex: i,
39
+ };
40
+ }
41
+ }
42
+ const lastKeyframe = keyframes[keyframes.length - 1];
43
+ return getKeyframeSelection({
44
+ keyframe: sourceFrame < firstKeyframe.frame ? firstKeyframe : lastKeyframe,
45
+ keyframeDisplayOffset,
46
+ nodePathInfo,
47
+ });
48
+ };
49
+ exports.getAnimationItemSelectionForSourceFrame = getAnimationItemSelectionForSourceFrame;
@@ -0,0 +1,15 @@
1
+ import type { CanUpdateSequencePropStatusKeyframed } from 'remotion';
2
+ import type { SequenceNodePathInfo } from '../../helpers/get-timeline-sequence-sort-key';
3
+ export declare const getEasingSelectionAfterKeyframeDelete: ({ deletedSourceFrames, keyframeDisplayOffset, nodePathInfo, propStatus, timelinePosition, }: {
4
+ readonly deletedSourceFrames: readonly number[];
5
+ readonly keyframeDisplayOffset: number;
6
+ readonly nodePathInfo: SequenceNodePathInfo;
7
+ readonly propStatus: CanUpdateSequencePropStatusKeyframed;
8
+ readonly timelinePosition: number;
9
+ }) => {
10
+ readonly type: "easing";
11
+ readonly nodePathInfo: SequenceNodePathInfo;
12
+ readonly fromFrame: number;
13
+ readonly toFrame: number;
14
+ readonly segmentIndex: number;
15
+ } | null;
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getEasingSelectionAfterKeyframeDelete = void 0;
4
+ const getEasingSelectionAfterKeyframeDelete = ({ deletedSourceFrames, keyframeDisplayOffset, nodePathInfo, propStatus, timelinePosition, }) => {
5
+ const deletedSourceFrameSet = new Set(deletedSourceFrames);
6
+ const remainingKeyframes = propStatus.keyframes.filter((keyframe) => !deletedSourceFrameSet.has(keyframe.frame));
7
+ const sourceFrame = timelinePosition - keyframeDisplayOffset;
8
+ for (let i = 0; i < remainingKeyframes.length - 1; i++) {
9
+ const keyframe = remainingKeyframes[i];
10
+ const nextKeyframe = remainingKeyframes[i + 1];
11
+ if (!keyframe || !nextKeyframe) {
12
+ continue;
13
+ }
14
+ if (sourceFrame > keyframe.frame && sourceFrame < nextKeyframe.frame) {
15
+ return {
16
+ type: 'easing',
17
+ nodePathInfo,
18
+ fromFrame: keyframe.frame + keyframeDisplayOffset,
19
+ toFrame: nextKeyframe.frame + keyframeDisplayOffset,
20
+ segmentIndex: i,
21
+ };
22
+ }
23
+ }
24
+ return null;
25
+ };
26
+ exports.getEasingSelectionAfterKeyframeDelete = getEasingSelectionAfterKeyframeDelete;
@@ -20,6 +20,7 @@ const saveSequenceProps = ({ changes, setPropStatuses, clientId, undoLabel, redo
20
20
  previous: prev,
21
21
  fieldKey: change.fieldKey,
22
22
  value: change.value,
23
+ defaultValue: change.defaultValue,
23
24
  schema: change.schema,
24
25
  }),
25
26
  apiCall: () => (0, call_api_1.callApi)('/api/save-sequence-props', {
@@ -45,6 +46,7 @@ const saveSequenceProps = ({ changes, setPropStatuses, clientId, undoLabel, redo
45
46
  previous: prev,
46
47
  fieldKey: change.fieldKey,
47
48
  value: change.value,
49
+ defaultValue: change.defaultValue,
48
50
  schema: change.schema,
49
51
  }));
50
52
  }
@@ -23,6 +23,7 @@ export type SelectedEasingUpdate = {
23
23
  readonly currentEasing: TimelineEasingValue;
24
24
  readonly propStatus: CanUpdateSequencePropStatusKeyframed;
25
25
  };
26
+ export declare const canEditEasingForInterpolationFunction: (interpolationFunction: string) => boolean;
26
27
  export declare const getSelectedEasingUpdate: ({ selection, sequences, overrideIdsToNodePaths, propStatuses, }: {
27
28
  selection: {
28
29
  readonly type: "easing";
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.updateSelectedTimelineEasings = exports.getTimelineEasingValueForSelection = exports.getEasingSelections = exports.makeEasingDragOverride = exports.getSelectedEasingUpdates = exports.getSelectedEasingUpdate = void 0;
3
+ exports.updateSelectedTimelineEasings = exports.getTimelineEasingValueForSelection = exports.getEasingSelections = exports.makeEasingDragOverride = exports.getSelectedEasingUpdates = exports.getSelectedEasingUpdate = exports.canEditEasingForInterpolationFunction = void 0;
4
4
  const studio_shared_1 = require("@remotion/studio-shared");
5
5
  const remotion_1 = require("remotion");
6
6
  const call_update_keyframe_settings_1 = require("./call-update-keyframe-settings");
@@ -8,6 +8,7 @@ const find_track_for_node_path_info_1 = require("./find-track-for-node-path-info
8
8
  const parse_keyframe_field_from_node_path_1 = require("./parse-keyframe-field-from-node-path");
9
9
  const canEditEasingForInterpolationFunction = (interpolationFunction) => interpolationFunction === 'interpolate' ||
10
10
  interpolationFunction === 'interpolateColors';
11
+ exports.canEditEasingForInterpolationFunction = canEditEasingForInterpolationFunction;
11
12
  const isEasingSelection = (selection) => selection.type === 'easing';
12
13
  const getSelectedEasingUpdate = ({ selection, sequences, overrideIdsToNodePaths, propStatuses, }) => {
13
14
  var _a;
@@ -33,7 +34,7 @@ const getSelectedEasingUpdate = ({ selection, sequences, overrideIdsToNodePaths,
33
34
  }
34
35
  const sequencePropStatus = (_a = remotion_1.Internals.getPropStatusesCtx(propStatuses, nodePath)) === null || _a === void 0 ? void 0 : _a[field.fieldKey];
35
36
  if ((sequencePropStatus === null || sequencePropStatus === void 0 ? void 0 : sequencePropStatus.status) !== 'keyframed' ||
36
- !canEditEasingForInterpolationFunction(sequencePropStatus.interpolationFunction)) {
37
+ !(0, exports.canEditEasingForInterpolationFunction)(sequencePropStatus.interpolationFunction)) {
37
38
  return null;
38
39
  }
39
40
  return {
@@ -60,7 +61,7 @@ const getSelectedEasingUpdate = ({ selection, sequences, overrideIdsToNodePaths,
60
61
  ? effectStatus.props[field.fieldKey]
61
62
  : null;
62
63
  if ((effectPropStatus === null || effectPropStatus === void 0 ? void 0 : effectPropStatus.status) !== 'keyframed' ||
63
- !canEditEasingForInterpolationFunction(effectPropStatus.interpolationFunction)) {
64
+ !(0, exports.canEditEasingForInterpolationFunction)(effectPropStatus.interpolationFunction)) {
64
65
  return null;
65
66
  }
66
67
  return {