@remotion/studio 4.0.469 → 4.0.470

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 (90) hide show
  1. package/dist/Studio.js +1 -1
  2. package/dist/api/save-render-output.js +3 -12
  3. package/dist/components/AudioWaveform.js +19 -2
  4. package/dist/components/ContextMenu.js +5 -1
  5. package/dist/components/EditorContent.js +5 -4
  6. package/dist/components/Menu/MenuItem.d.ts +1 -1
  7. package/dist/components/MenuBuildIndicator.js +0 -1
  8. package/dist/components/NewComposition/InputDragger.js +1 -0
  9. package/dist/components/Preview.js +4 -1
  10. package/dist/components/SelectedOutlineOverlay.d.ts +18 -0
  11. package/dist/components/SelectedOutlineOverlay.js +645 -0
  12. package/dist/components/Timeline/Timeline.js +27 -13
  13. package/dist/components/Timeline/TimelineDeleteKeybindings.d.ts +2 -0
  14. package/dist/components/Timeline/TimelineDeleteKeybindings.js +86 -0
  15. package/dist/components/Timeline/TimelineDragHandler.js +19 -244
  16. package/dist/components/Timeline/{TimelineEffectGroupRow.d.ts → TimelineEffectItem.d.ts} +1 -1
  17. package/dist/components/Timeline/{TimelineEffectGroupRow.js → TimelineEffectItem.js} +50 -33
  18. package/dist/components/Timeline/{TimelineEffectFieldRow.d.ts → TimelineEffectPropItem.d.ts} +2 -1
  19. package/dist/components/Timeline/{TimelineEffectFieldRow.js → TimelineEffectPropItem.js} +97 -8
  20. package/dist/components/Timeline/TimelineExpandArrowButton.js +5 -1
  21. package/dist/components/Timeline/TimelineExpandedKeyframeRow.js +37 -5
  22. package/dist/components/Timeline/TimelineExpandedRow.d.ts +1 -0
  23. package/dist/components/Timeline/TimelineExpandedRow.js +9 -7
  24. package/dist/components/Timeline/TimelineExpandedSection.d.ts +1 -0
  25. package/dist/components/Timeline/TimelineExpandedSection.js +2 -2
  26. package/dist/components/Timeline/TimelineInOutDragHandler.d.ts +2 -0
  27. package/dist/components/Timeline/TimelineInOutDragHandler.js +324 -0
  28. package/dist/components/Timeline/TimelineInOutPointer.js +3 -1
  29. package/dist/components/Timeline/TimelineInOutPointerHandle.d.ts +1 -0
  30. package/dist/components/Timeline/TimelineInOutPointerHandle.js +5 -4
  31. package/dist/components/Timeline/TimelineKeyframeControls.d.ts +17 -0
  32. package/dist/components/Timeline/TimelineKeyframeControls.js +217 -0
  33. package/dist/components/Timeline/TimelineKeyframeDiamond.js +7 -6
  34. package/dist/components/Timeline/TimelineKeyframedValue.d.ts +8 -0
  35. package/dist/components/Timeline/TimelineKeyframedValue.js +36 -0
  36. package/dist/components/Timeline/TimelineList.js +3 -15
  37. package/dist/components/Timeline/TimelineRowChrome.d.ts +3 -1
  38. package/dist/components/Timeline/TimelineRowChrome.js +23 -5
  39. package/dist/components/Timeline/TimelineSelection.d.ts +53 -9
  40. package/dist/components/Timeline/TimelineSelection.js +305 -48
  41. package/dist/components/Timeline/TimelineSequence.d.ts +2 -0
  42. package/dist/components/Timeline/TimelineSequence.js +18 -6
  43. package/dist/components/Timeline/TimelineSequenceFrame.js +1 -0
  44. package/dist/components/Timeline/{TimelineListItem.d.ts → TimelineSequenceItem.d.ts} +2 -1
  45. package/dist/components/Timeline/{TimelineListItem.js → TimelineSequenceItem.js} +49 -33
  46. package/dist/components/Timeline/{TimelineFieldRow.d.ts → TimelineSequencePropItem.d.ts} +2 -1
  47. package/dist/components/Timeline/{TimelineFieldRow.js → TimelineSequencePropItem.js} +81 -5
  48. package/dist/components/Timeline/TimelineTimeIndicators.js +0 -1
  49. package/dist/components/Timeline/TimelineTrack.js +3 -1
  50. package/dist/components/Timeline/TimelineTranslateField.js +14 -22
  51. package/dist/components/Timeline/call-add-keyframe.d.ts +23 -0
  52. package/dist/components/Timeline/call-add-keyframe.js +54 -0
  53. package/dist/components/Timeline/call-delete-keyframe.d.ts +21 -0
  54. package/dist/components/Timeline/call-delete-keyframe.js +50 -0
  55. package/dist/components/Timeline/delete-selected-keyframe.d.ts +11 -0
  56. package/dist/components/Timeline/delete-selected-keyframe.js +51 -0
  57. package/dist/components/Timeline/delete-selected-timeline-item.d.ts +17 -0
  58. package/dist/components/Timeline/delete-selected-timeline-item.js +183 -0
  59. package/dist/components/Timeline/duplicate-selected-timeline-item.d.ts +13 -0
  60. package/dist/components/Timeline/duplicate-selected-timeline-item.js +66 -0
  61. package/dist/components/Timeline/find-track-for-node-path-info.d.ts +7 -0
  62. package/dist/components/Timeline/find-track-for-node-path-info.js +13 -0
  63. package/dist/components/Timeline/get-keyframe-navigation.d.ts +9 -0
  64. package/dist/components/Timeline/get-keyframe-navigation.js +26 -0
  65. package/dist/components/Timeline/parse-keyframe-field-from-node-path.d.ts +8 -0
  66. package/dist/components/Timeline/parse-keyframe-field-from-node-path.js +26 -0
  67. package/dist/components/Timeline/save-sequence-prop.d.ts +14 -2
  68. package/dist/components/Timeline/save-sequence-prop.js +42 -7
  69. package/dist/components/Timeline/timeline-row-layout.d.ts +1 -0
  70. package/dist/components/Timeline/timeline-row-layout.js +2 -1
  71. package/dist/components/Timeline/timeline-translate-utils.d.ts +2 -0
  72. package/dist/components/Timeline/timeline-translate-utils.js +20 -0
  73. package/dist/components/Timeline/use-expanded-track-keyframe-rows.js +10 -3
  74. package/dist/components/composition-menu-items.js +32 -1
  75. package/dist/error-overlay/remotion-overlay/OpenInEditor.js +0 -1
  76. package/dist/esm/{chunk-1mp51e0w.js → chunk-dny42qnq.js} +9896 -6174
  77. package/dist/esm/internals.mjs +9896 -6174
  78. package/dist/esm/previewEntry.mjs +9870 -6148
  79. package/dist/esm/renderEntry.mjs +3 -1
  80. package/dist/helpers/format-file-location.d.ts +9 -0
  81. package/dist/helpers/format-file-location.js +27 -0
  82. package/dist/helpers/get-box-quads-polyfill-internals.d.ts +82 -0
  83. package/dist/helpers/get-box-quads-polyfill-internals.js +2395 -0
  84. package/dist/helpers/get-box-quads-ponyfill.d.ts +10 -0
  85. package/dist/helpers/get-box-quads-ponyfill.js +23 -0
  86. package/dist/helpers/open-in-editor.d.ts +1 -1
  87. package/dist/helpers/open-in-editor.js +11 -26
  88. package/dist/helpers/use-menu-structure.js +8 -16
  89. package/dist/renderEntry.js +2 -2
  90. package/package.json +10 -10
@@ -1,16 +1,18 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.TimelineListItem = void 0;
3
+ exports.TimelineSequenceItem = void 0;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const react_1 = require("react");
6
6
  const remotion_1 = require("remotion");
7
7
  const no_react_1 = require("remotion/no-react");
8
8
  const client_id_1 = require("../../helpers/client-id");
9
+ const format_file_location_1 = require("../../helpers/format-file-location");
9
10
  const timeline_layout_1 = require("../../helpers/timeline-layout");
10
11
  const call_api_1 = require("../call-api");
11
12
  const ContextMenu_1 = require("../ContextMenu");
12
13
  const ExpandedTracksProvider_1 = require("../ExpandedTracksProvider");
13
14
  const NotificationCenter_1 = require("../Notifications/NotificationCenter");
15
+ const duplicate_selected_timeline_item_1 = require("./duplicate-selected-timeline-item");
14
16
  const save_sequence_prop_1 = require("./save-sequence-prop");
15
17
  const TimelineExpandArrowButton_1 = require("./TimelineExpandArrowButton");
16
18
  const TimelineExpandedSection_1 = require("./TimelineExpandedSection");
@@ -29,7 +31,7 @@ const labelContainerStyle = {
29
31
  minWidth: 0,
30
32
  gap: 4,
31
33
  };
32
- const TimelineListItem = ({ nestedDepth, sequence, nodePathInfo }) => {
34
+ const TimelineSequenceItem = ({ nestedDepth, sequence, nodePathInfo, keyframeDisplayOffset }) => {
33
35
  var _a;
34
36
  var _b;
35
37
  const nodePath = (_b = nodePathInfo === null || nodePathInfo === void 0 ? void 0 : nodePathInfo.sequenceSubscriptionKey) !== null && _b !== void 0 ? _b : null;
@@ -43,6 +45,10 @@ const TimelineListItem = ({ nestedDepth, sequence, nodePathInfo }) => {
43
45
  const { onSelect, selectable, selected } = (0, TimelineSelection_1.useTimelineRowSelection)(nodePathInfo);
44
46
  const containsSelection = (0, TimelineSelection_1.useTimelineRowContainsSelection)(nodePathInfo);
45
47
  const { canOpenInEditor, openInEditor, originalLocation } = (0, use_open_sequence_in_editor_1.useOpenSequenceInEditor)(sequence);
48
+ const fileLocation = (0, react_1.useMemo)(() => (0, format_file_location_1.formatFileLocation)({
49
+ location: originalLocation,
50
+ root: window.remotion_cwd,
51
+ }), [originalLocation]);
46
52
  const validatedLocation = (0, react_1.useMemo)(() => {
47
53
  var _a;
48
54
  if (!originalLocation ||
@@ -59,35 +65,12 @@ const TimelineListItem = ({ nestedDepth, sequence, nodePathInfo }) => {
59
65
  const canDeleteFromSource = Boolean(nodePath && (validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.source));
60
66
  const deleteDisabled = (0, react_1.useMemo)(() => !previewConnected || !sequence.controls || !canDeleteFromSource, [previewConnected, sequence.controls, canDeleteFromSource]);
61
67
  const duplicateDisabled = deleteDisabled;
62
- const onDuplicateSequenceFromSource = (0, react_1.useCallback)(async () => {
63
- if (!(validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.source) || !nodePath) {
68
+ const onDuplicateSequenceFromSource = (0, react_1.useCallback)(() => {
69
+ if (!(validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.source) || !nodePathInfo) {
64
70
  return;
65
71
  }
66
- if (nodePathInfo && nodePathInfo.numberOfSequencesWithThisNodePath > 1) {
67
- const message = 'This sequence is programmatically duplicated ' +
68
- nodePathInfo.numberOfSequencesWithThisNodePath +
69
- ' times in the code. Duplicating inserts another copy. Continue?';
70
- // eslint-disable-next-line no-alert -- native confirm before applying duplicate codemod in .map callbacks
71
- if (!window.confirm(message)) {
72
- return;
73
- }
74
- }
75
- try {
76
- const result = await (0, call_api_1.callApi)('/api/duplicate-jsx-node', {
77
- fileName: validatedLocation.source,
78
- nodePath: nodePath.nodePath,
79
- });
80
- if (result.success) {
81
- (0, NotificationCenter_1.showNotification)('Duplicated sequence in source file', 2000);
82
- }
83
- else {
84
- (0, NotificationCenter_1.showNotification)(result.reason, 4000);
85
- }
86
- }
87
- catch (err) {
88
- (0, NotificationCenter_1.showNotification)(err.message, 4000);
89
- }
90
- }, [nodePath, validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.source, nodePathInfo]);
72
+ (0, duplicate_selected_timeline_item_1.duplicateSequencesFromSource)([nodePathInfo]).catch(() => undefined);
73
+ }, [nodePathInfo, validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.source]);
91
74
  const onDeleteSequenceFromSource = (0, react_1.useCallback)(async () => {
92
75
  if (!(validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.source) || !nodePath) {
93
76
  return;
@@ -103,8 +86,12 @@ const TimelineListItem = ({ nestedDepth, sequence, nodePathInfo }) => {
103
86
  }
104
87
  try {
105
88
  const result = await (0, call_api_1.callApi)('/api/delete-jsx-node', {
106
- fileName: validatedLocation.source,
107
- nodePath: nodePath.nodePath,
89
+ nodes: [
90
+ {
91
+ fileName: validatedLocation.source,
92
+ nodePath: nodePath.nodePath,
93
+ },
94
+ ],
108
95
  });
109
96
  if (result.success) {
110
97
  (0, NotificationCenter_1.showNotification)('Removed sequence from source file', 2000);
@@ -146,6 +133,30 @@ const TimelineListItem = ({ nestedDepth, sequence, nodePathInfo }) => {
146
133
  value: 'show-in-editor',
147
134
  }
148
135
  : null,
136
+ {
137
+ type: 'item',
138
+ id: 'copy-file-location',
139
+ keyHint: null,
140
+ label: 'Copy file location',
141
+ leftItem: null,
142
+ disabled: !fileLocation,
143
+ onClick: () => {
144
+ if (!fileLocation) {
145
+ return;
146
+ }
147
+ navigator.clipboard
148
+ .writeText(fileLocation)
149
+ .then(() => {
150
+ (0, NotificationCenter_1.showNotification)('Copied file location to clipboard', 1000);
151
+ })
152
+ .catch((err) => {
153
+ (0, NotificationCenter_1.showNotification)(`Could not copy to clipboard: ${err.message}`, 1000);
154
+ });
155
+ },
156
+ quickSwitcherLabel: null,
157
+ subMenu: null,
158
+ value: 'copy-file-location',
159
+ },
149
160
  documentationLink
150
161
  ? {
151
162
  type: 'item',
@@ -223,6 +234,7 @@ const TimelineListItem = ({ nestedDepth, sequence, nodePathInfo }) => {
223
234
  assetLinkInfo,
224
235
  deleteDisabled,
225
236
  duplicateDisabled,
237
+ fileLocation,
226
238
  onDeleteSequenceFromSource,
227
239
  onDuplicateSequenceFromSource,
228
240
  canOpenInEditor,
@@ -242,6 +254,10 @@ const TimelineListItem = ({ nestedDepth, sequence, nodePathInfo }) => {
242
254
  if (!TimelineSelection_1.SELECTION_ENABLED || !canOpenInEditor) {
243
255
  return;
244
256
  }
257
+ if ((0, TimelineSelection_1.isTimelineSelectionModifierEvent)(e)) {
258
+ e.stopPropagation();
259
+ return;
260
+ }
245
261
  e.stopPropagation();
246
262
  openInEditor();
247
263
  }, [canOpenInEditor, openInEditor]);
@@ -323,6 +339,6 @@ const TimelineListItem = ({ nestedDepth, sequence, nodePathInfo }) => {
323
339
  isExpanded &&
324
340
  hasExpandableContent &&
325
341
  nodePathInfo &&
326
- validatedLocation ? (jsx_runtime_1.jsx(TimelineExpandedSection_1.TimelineExpandedSection, { sequence: sequence, validatedLocation: validatedLocation, nodePathInfo: nodePathInfo, nestedDepth: nestedDepth })) : null] }));
342
+ validatedLocation ? (jsx_runtime_1.jsx(TimelineExpandedSection_1.TimelineExpandedSection, { sequence: sequence, validatedLocation: validatedLocation, nodePathInfo: nodePathInfo, nestedDepth: nestedDepth, keyframeDisplayOffset: keyframeDisplayOffset })) : null] }));
327
343
  };
328
- exports.TimelineListItem = TimelineListItem;
344
+ exports.TimelineSequenceItem = TimelineSequenceItem;
@@ -3,11 +3,12 @@ import type { SequencePropsSubscriptionKey, SequenceSchema } 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';
6
- export declare const TimelineFieldRow: React.FC<{
6
+ export declare const TimelineSequencePropItem: React.FC<{
7
7
  readonly field: SchemaFieldInfo;
8
8
  readonly validatedLocation: CodePosition;
9
9
  readonly rowDepth: number;
10
10
  readonly nodePath: SequencePropsSubscriptionKey;
11
11
  readonly nodePathInfo: SequenceNodePathInfo;
12
12
  readonly schema: SequenceSchema;
13
+ readonly keyframeDisplayOffset: number;
13
14
  }>;
@@ -1,14 +1,17 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.TimelineFieldRow = void 0;
3
+ exports.TimelineSequencePropItem = void 0;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const react_1 = require("react");
6
6
  const remotion_1 = require("remotion");
7
7
  const client_id_1 = require("../../helpers/client-id");
8
+ const ContextMenu_1 = require("../ContextMenu");
8
9
  const save_sequence_prop_1 = require("./save-sequence-prop");
9
10
  const timeline_field_row_layout_1 = require("./timeline-field-row-layout");
10
11
  const TimelineExpandArrowButton_1 = require("./TimelineExpandArrowButton");
11
12
  const TimelineFieldLabel_1 = require("./TimelineFieldLabel");
13
+ const TimelineKeyframeControls_1 = require("./TimelineKeyframeControls");
14
+ const TimelineKeyframedValue_1 = require("./TimelineKeyframedValue");
12
15
  const TimelineLayerEye_1 = require("./TimelineLayerEye");
13
16
  const TimelineRowChrome_1 = require("./TimelineRowChrome");
14
17
  const TimelineSchemaField_1 = require("./TimelineSchemaField");
@@ -86,22 +89,95 @@ const Value = ({ field, nodePath, validatedLocation, schema, codeValue }) => {
86
89
  }, [clearDragOverrides, nodePath]);
87
90
  return (jsx_runtime_1.jsx(TimelineSchemaField_1.TimelineFieldValue, { field: field, propStatus: codeValue, onSave: onSave, onDragValueChange: onDragValueChange, onDragEnd: onDragEnd, effectiveValue: effectiveValue }));
88
91
  };
89
- const TimelineFieldRow = ({ field, validatedLocation, rowDepth, nodePath, nodePathInfo, schema }) => {
92
+ const TimelineSequencePropItem = ({ field, validatedLocation, rowDepth, nodePath, nodePathInfo, schema, keyframeDisplayOffset, }) => {
90
93
  var _a, _b;
91
94
  const { codeValues: visualModeCodeValues } = (0, react_1.useContext)(remotion_1.Internals.VisualModeCodeValuesContext);
95
+ const { getDragOverrides } = (0, react_1.useContext)(remotion_1.Internals.VisualModeDragOverridesContext);
96
+ const { setCodeValues } = (0, react_1.useContext)(remotion_1.Internals.VisualModeSettersContext);
97
+ const { previewServerState } = (0, react_1.useContext)(client_id_1.StudioServerConnectionCtx);
92
98
  const selection = (0, TimelineSelection_1.useTimelineRowSelection)(nodePathInfo);
93
99
  const codeValuesForOverride = remotion_1.Internals.getCodeValuesCtx(visualModeCodeValues, nodePath);
94
100
  const codeValue = (_a = codeValuesForOverride === null || codeValuesForOverride === void 0 ? void 0 : codeValuesForOverride[field.key]) !== null && _a !== void 0 ? _a : null;
101
+ const dragOverrideValue = (0, react_1.useMemo)(() => {
102
+ var _a;
103
+ return ((_a = getDragOverrides(nodePath)) !== null && _a !== void 0 ? _a : {})[field.key];
104
+ }, [getDragOverrides, nodePath, field.key]);
105
+ const keyframeControls = codeValue !== null &&
106
+ (0, TimelineKeyframeControls_1.shouldShowTimelineKeyframeControls)({
107
+ propStatus: codeValue,
108
+ selected: selection.selected,
109
+ }) ? (jsx_runtime_1.jsx(TimelineKeyframeControls_1.TimelineKeyframeControls, { fieldKey: field.key, propStatus: codeValue, nodePath: nodePath, fileName: validatedLocation.source, keyframeDisplayOffset: keyframeDisplayOffset, defaultValue: field.fieldSchema.default, dragOverrideValue: dragOverrideValue, schema: schema, effectIndex: null })) : null;
95
110
  const style = (0, react_1.useMemo)(() => {
96
111
  return {
97
112
  ...fieldRowBase,
98
113
  height: field.rowHeight,
99
114
  };
100
115
  }, [field.rowHeight]);
116
+ const isNonDefault = (0, react_1.useMemo)(() => {
117
+ var _a;
118
+ if (!codeValue || !codeValue.canUpdate) {
119
+ return false;
120
+ }
121
+ const effectiveCodeValue = (_a = codeValue.codeValue) !== null && _a !== void 0 ? _a : field.fieldSchema.default;
122
+ return (JSON.stringify(effectiveCodeValue) !==
123
+ JSON.stringify(field.fieldSchema.default));
124
+ }, [codeValue, field.fieldSchema.default]);
125
+ const canPerformReset = previewServerState.type === 'connected' &&
126
+ codeValue !== null &&
127
+ codeValue.canUpdate;
128
+ const onReset = (0, react_1.useCallback)(() => {
129
+ if (!canPerformReset ||
130
+ previewServerState.type !== 'connected' ||
131
+ codeValue === null ||
132
+ !isNonDefault) {
133
+ return;
134
+ }
135
+ const defaultValue = field.fieldSchema.default !== undefined
136
+ ? JSON.stringify(field.fieldSchema.default)
137
+ : null;
138
+ (0, save_sequence_prop_1.saveSequenceProp)({
139
+ fileName: validatedLocation.source,
140
+ nodePath,
141
+ fieldKey: field.key,
142
+ value: field.fieldSchema.default,
143
+ defaultValue,
144
+ schema,
145
+ setCodeValues,
146
+ clientId: previewServerState.clientId,
147
+ });
148
+ }, [
149
+ canPerformReset,
150
+ field.fieldSchema.default,
151
+ field.key,
152
+ isNonDefault,
153
+ nodePath,
154
+ previewServerState,
155
+ schema,
156
+ setCodeValues,
157
+ validatedLocation.source,
158
+ codeValue,
159
+ ]);
160
+ const contextMenuValues = (0, react_1.useMemo)(() => {
161
+ return [
162
+ {
163
+ type: 'item',
164
+ id: 'reset-sequence-field',
165
+ keyHint: null,
166
+ label: 'Reset',
167
+ leftItem: null,
168
+ disabled: !canPerformReset,
169
+ onClick: onReset,
170
+ quickSwitcherLabel: null,
171
+ subMenu: null,
172
+ value: 'reset-sequence-field',
173
+ },
174
+ ];
175
+ }, [canPerformReset, onReset]);
101
176
  if (codeValue === null) {
102
177
  return null;
103
178
  }
104
- return (jsx_runtime_1.jsxs(TimelineRowChrome_1.TimelineRowChrome, { depth: rowDepth, eye: jsx_runtime_1.jsx(TimelineLayerEye_1.TimelineLayerEyeSpacer, {}), arrow: jsx_runtime_1.jsx(TimelineExpandArrowButton_1.TimelineExpandArrowSpacer, {}), style: style, selected: selection.selected, selectable: selection.selectable, onSelect: selection.onSelect, showSelectedBackground: true, containsSelection: false, outerHeight: null, children: [
105
- jsx_runtime_1.jsx(TimelineFieldLabel_1.TimelineFieldLabel, { rowDepth: rowDepth, selected: selection.selected, label: (_b = field.description) !== null && _b !== void 0 ? _b : field.key }), codeValue.canUpdate ? (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, codeValue: codeValue }) })) : (jsx_runtime_1.jsx("div", { style: timeline_field_row_layout_1.timelineFieldValueColumnStyle, children: jsx_runtime_1.jsx(TimelineSchemaField_1.TimelineNonEditableStatus, { propStatus: codeValue }) }))] }));
179
+ 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, onSelect: selection.onSelect, showSelectedBackground: true, containsSelection: false, outerHeight: null, children: [
180
+ jsx_runtime_1.jsx(TimelineFieldLabel_1.TimelineFieldLabel, { rowDepth: rowDepth, selected: selection.selected, label: (_b = field.description) !== null && _b !== void 0 ? _b : field.key }), codeValue.canUpdate ? (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, codeValue: codeValue }) })) : codeValue.reason === 'keyframed' ? (jsx_runtime_1.jsx("div", { style: timeline_field_row_layout_1.timelineFieldValueColumnStyle, children: jsx_runtime_1.jsx(TimelineKeyframedValue_1.TimelineKeyframedValue, { field: field, propStatus: codeValue, keyframeDisplayOffset: keyframeDisplayOffset }) })) : (jsx_runtime_1.jsx("div", { style: timeline_field_row_layout_1.timelineFieldValueColumnStyle, children: jsx_runtime_1.jsx(TimelineSchemaField_1.TimelineNonEditableStatus, { propStatus: codeValue }) }))] }));
181
+ return (jsx_runtime_1.jsx(ContextMenu_1.ContextMenu, { values: contextMenuValues, onOpen: selection.selectable ? selection.onSelect : null, children: row }));
106
182
  };
107
- exports.TimelineFieldRow = TimelineFieldRow;
183
+ exports.TimelineSequencePropItem = TimelineSequencePropItem;
@@ -14,7 +14,6 @@ const TimelineWidthProvider_1 = require("./TimelineWidthProvider");
14
14
  exports.TIMELINE_TIME_INDICATOR_HEIGHT = 39;
15
15
  const container = {
16
16
  height: exports.TIMELINE_TIME_INDICATOR_HEIGHT,
17
- boxShadow: `0 0 4px ${colors_1.TIMELINE_BACKGROUND}`,
18
17
  position: 'absolute',
19
18
  backgroundColor: colors_1.TIMELINE_BACKGROUND,
20
19
  top: 0,
@@ -42,10 +42,12 @@ const ExpandedTracksProvider_1 = require("../ExpandedTracksProvider");
42
42
  const TimelineExpandedTrackKeyframes_1 = require("./TimelineExpandedTrackKeyframes");
43
43
  const TimelineSelection_1 = require("./TimelineSelection");
44
44
  const TimelineSequence_1 = require("./TimelineSequence");
45
+ const TimelineWidthProvider_1 = require("./TimelineWidthProvider");
45
46
  const TimelineTrackUnmemoized = ({ track }) => {
46
47
  const { getIsExpanded } = (0, react_1.useContext)(ExpandedTracksProvider_1.ExpandedTracksGetterContext);
47
48
  const { previewServerState } = (0, react_1.useContext)(client_id_1.StudioServerConnectionCtx);
48
49
  const previewServerConnected = previewServerState.type === 'connected';
50
+ const timelineWidth = (0, react_1.useContext)(TimelineWidthProvider_1.TimelineWidthContext);
49
51
  const { selected: rowSelected } = (0, TimelineSelection_1.useTimelineRowSelection)(track.nodePathInfo);
50
52
  const containsSelection = (0, TimelineSelection_1.useTimelineRowContainsSelection)(track.nodePathInfo);
51
53
  const layerStyle = (0, react_1.useMemo)(() => ({
@@ -58,7 +60,7 @@ const TimelineTrackUnmemoized = ({ track }) => {
58
60
  getIsExpanded(track.nodePathInfo);
59
61
  const showRowHighlight = track.nodePathInfo !== null && (rowSelected || containsSelection);
60
62
  return (jsx_runtime_1.jsxs("div", { children: [
61
- jsx_runtime_1.jsxs("div", { style: layerStyle, children: [showRowHighlight ? (jsx_runtime_1.jsx("div", { style: TimelineSelection_1.TIMELINE_SELECTED_TRACK_HIGHLIGHT_STYLE })) : null, jsx_runtime_1.jsx(TimelineSequence_1.TimelineSequence, { s: track.sequence })
63
+ jsx_runtime_1.jsxs("div", { style: layerStyle, children: [showRowHighlight && timelineWidth !== null ? (jsx_runtime_1.jsx("div", { style: (0, TimelineSelection_1.getTimelineSelectedTrackHighlightStyle)(timelineWidth) })) : null, jsx_runtime_1.jsx(TimelineSequence_1.TimelineSequence, { s: track.sequence, nodePathInfo: track.nodePathInfo })
62
64
  ] }), showExpandedKeyframes && track.nodePathInfo ? (jsx_runtime_1.jsx(TimelineExpandedTrackKeyframes_1.TimelineExpandedTrackKeyframes, { sequence: track.sequence, nodePathInfo: track.nodePathInfo, keyframeDisplayOffset: track.keyframeDisplayOffset })) : null] }));
63
65
  };
64
66
  exports.TimelineTrack = react_1.default.memo(TimelineTrackUnmemoized);
@@ -5,20 +5,13 @@ const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const react_1 = require("react");
6
6
  const InputDragger_1 = require("../NewComposition/InputDragger");
7
7
  const timeline_field_utils_1 = require("./timeline-field-utils");
8
+ const timeline_translate_utils_1 = require("./timeline-translate-utils");
8
9
  const leftDraggerStyle = {
9
10
  paddingLeft: 0,
10
11
  };
11
12
  const rightDraggerStyle = {
12
13
  paddingRight: 0,
13
14
  };
14
- const PIXEL_PATTERN = /^(-?\d+(?:\.\d+)?)px(?:\s+(-?\d+(?:\.\d+)?)px)?$/;
15
- const parseTranslate = (value) => {
16
- const m = value.match(PIXEL_PATTERN);
17
- if (!m) {
18
- return [0, 0];
19
- }
20
- return [Number(m[1]), m[2] !== undefined ? Number(m[2]) : 0];
21
- };
22
15
  const containerStyle = {
23
16
  display: 'flex',
24
17
  gap: 4,
@@ -27,8 +20,7 @@ const TimelineTranslateField = ({ field, propStatus, effectiveValue, onSave, onD
27
20
  var _a;
28
21
  const [dragX, setDragX] = (0, react_1.useState)(null);
29
22
  const [dragY, setDragY] = (0, react_1.useState)(null);
30
- const [codeX, codeY] = (0, react_1.useMemo)(() => parseTranslate(String(effectiveValue !== null && effectiveValue !== void 0 ? effectiveValue : '0px 0px')), [effectiveValue]);
31
- const makeString = (0, react_1.useCallback)((x, y) => `${x}px ${y}px`, []);
23
+ const [codeX, codeY] = (0, react_1.useMemo)(() => (0, timeline_translate_utils_1.parseTranslate)(String(effectiveValue !== null && effectiveValue !== void 0 ? effectiveValue : '0px 0px')), [effectiveValue]);
32
24
  const step = field.fieldSchema.type === 'translate' ? ((_a = field.fieldSchema.step) !== null && _a !== void 0 ? _a : 1) : 1;
33
25
  const stepDecimals = (0, react_1.useMemo)(() => (0, timeline_field_utils_1.getDecimalPlaces)(step), [step]);
34
26
  const formatter = (0, react_1.useCallback)((v) => {
@@ -41,11 +33,11 @@ const TimelineTranslateField = ({ field, propStatus, effectiveValue, onSave, onD
41
33
  const onXChange = (0, react_1.useCallback)((newVal) => {
42
34
  setDragX(newVal);
43
35
  const currentY = dragY !== null && dragY !== void 0 ? dragY : codeY;
44
- onDragValueChange(makeString(newVal, currentY));
45
- }, [onDragValueChange, dragY, codeY, makeString]);
36
+ onDragValueChange((0, timeline_translate_utils_1.serializeTranslate)(newVal, currentY));
37
+ }, [onDragValueChange, dragY, codeY]);
46
38
  const onXChangeEnd = (0, react_1.useCallback)((newVal) => {
47
39
  const currentY = dragY !== null && dragY !== void 0 ? dragY : codeY;
48
- const newStr = makeString(newVal, currentY);
40
+ const newStr = (0, timeline_translate_utils_1.serializeTranslate)(newVal, currentY);
49
41
  if (propStatus.canUpdate && newStr !== propStatus.codeValue) {
50
42
  onSave(newStr).finally(() => {
51
43
  setDragX(null);
@@ -56,13 +48,13 @@ const TimelineTranslateField = ({ field, propStatus, effectiveValue, onSave, onD
56
48
  setDragX(null);
57
49
  onDragEnd();
58
50
  }
59
- }, [dragY, codeY, makeString, propStatus, onSave, onDragEnd]);
51
+ }, [dragY, codeY, propStatus, onSave, onDragEnd]);
60
52
  const onXTextChange = (0, react_1.useCallback)((newVal) => {
61
53
  if (propStatus.canUpdate) {
62
54
  const parsed = Number(newVal);
63
55
  if (!Number.isNaN(parsed)) {
64
56
  const currentY = dragY !== null && dragY !== void 0 ? dragY : codeY;
65
- const newStr = makeString(parsed, currentY);
57
+ const newStr = (0, timeline_translate_utils_1.serializeTranslate)(parsed, currentY);
66
58
  if (newStr !== propStatus.codeValue) {
67
59
  setDragX(parsed);
68
60
  onSave(newStr).finally(() => {
@@ -71,16 +63,16 @@ const TimelineTranslateField = ({ field, propStatus, effectiveValue, onSave, onD
71
63
  }
72
64
  }
73
65
  }
74
- }, [propStatus, dragY, codeY, makeString, onSave]);
66
+ }, [propStatus, dragY, codeY, onSave]);
75
67
  // --- Y callbacks ---
76
68
  const onYChange = (0, react_1.useCallback)((newVal) => {
77
69
  setDragY(newVal);
78
70
  const currentX = dragX !== null && dragX !== void 0 ? dragX : codeX;
79
- onDragValueChange(makeString(currentX, newVal));
80
- }, [onDragValueChange, dragX, codeX, makeString]);
71
+ onDragValueChange((0, timeline_translate_utils_1.serializeTranslate)(currentX, newVal));
72
+ }, [onDragValueChange, dragX, codeX]);
81
73
  const onYChangeEnd = (0, react_1.useCallback)((newVal) => {
82
74
  const currentX = dragX !== null && dragX !== void 0 ? dragX : codeX;
83
- const newStr = makeString(currentX, newVal);
75
+ const newStr = (0, timeline_translate_utils_1.serializeTranslate)(currentX, newVal);
84
76
  if (propStatus.canUpdate && newStr !== propStatus.codeValue) {
85
77
  onSave(newStr).finally(() => {
86
78
  setDragY(null);
@@ -91,13 +83,13 @@ const TimelineTranslateField = ({ field, propStatus, effectiveValue, onSave, onD
91
83
  setDragY(null);
92
84
  onDragEnd();
93
85
  }
94
- }, [dragX, codeX, makeString, propStatus, onSave, onDragEnd]);
86
+ }, [dragX, codeX, propStatus, onSave, onDragEnd]);
95
87
  const onYTextChange = (0, react_1.useCallback)((newVal) => {
96
88
  if (propStatus.canUpdate) {
97
89
  const parsed = Number(newVal);
98
90
  if (!Number.isNaN(parsed)) {
99
91
  const currentX = dragX !== null && dragX !== void 0 ? dragX : codeX;
100
- const newStr = makeString(currentX, parsed);
92
+ const newStr = (0, timeline_translate_utils_1.serializeTranslate)(currentX, parsed);
101
93
  if (newStr !== propStatus.codeValue) {
102
94
  setDragY(parsed);
103
95
  onSave(newStr).finally(() => {
@@ -106,7 +98,7 @@ const TimelineTranslateField = ({ field, propStatus, effectiveValue, onSave, onD
106
98
  }
107
99
  }
108
100
  }
109
- }, [propStatus, onSave, dragX, codeX, makeString]);
101
+ }, [propStatus, onSave, dragX, codeX]);
110
102
  return (jsx_runtime_1.jsxs("span", { style: containerStyle, children: [
111
103
  jsx_runtime_1.jsx(InputDragger_1.InputDragger, { type: "number", value: dragX !== null && dragX !== void 0 ? dragX : codeX, style: leftDraggerStyle, status: "ok", small: true, onValueChange: onXChange, onValueChangeEnd: onXChangeEnd, onTextChange: onXTextChange, min: -Infinity, max: Infinity, step: step, formatter: formatter, rightAlign: false }), jsx_runtime_1.jsx("div", { style: { marginLeft: -6, marginRight: -6 } }), jsx_runtime_1.jsx(InputDragger_1.InputDragger, { type: "number", value: dragY !== null && dragY !== void 0 ? dragY : codeY, style: rightDraggerStyle, status: "ok", small: true, onValueChange: onYChange, onValueChangeEnd: onYChangeEnd, onTextChange: onYTextChange, min: -Infinity, max: Infinity, step: step, formatter: formatter, rightAlign: false })
112
104
  ] }));
@@ -0,0 +1,23 @@
1
+ import type { SequencePropsSubscriptionKey, SequenceSchema } from 'remotion';
2
+ import type { SetCodeValues } from './save-sequence-prop';
3
+ export declare const callAddSequenceKeyframe: ({ fileName, nodePath, fieldKey, sourceFrame, value, schema, setCodeValues, clientId, }: {
4
+ fileName: string;
5
+ nodePath: SequencePropsSubscriptionKey;
6
+ fieldKey: string;
7
+ sourceFrame: number;
8
+ value: unknown;
9
+ schema: SequenceSchema;
10
+ setCodeValues: SetCodeValues;
11
+ clientId: string;
12
+ }) => Promise<void>;
13
+ export declare const callAddEffectKeyframe: ({ fileName, nodePath, effectIndex, fieldKey, sourceFrame, value, schema, setCodeValues, clientId, }: {
14
+ fileName: string;
15
+ nodePath: SequencePropsSubscriptionKey;
16
+ effectIndex: number;
17
+ fieldKey: string;
18
+ sourceFrame: number;
19
+ value: unknown;
20
+ schema: SequenceSchema;
21
+ setCodeValues: SetCodeValues;
22
+ clientId: string;
23
+ }) => Promise<void>;
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.callAddEffectKeyframe = exports.callAddSequenceKeyframe = void 0;
4
+ const studio_shared_1 = require("@remotion/studio-shared");
5
+ const call_api_1 = require("../call-api");
6
+ const save_prop_queue_1 = require("./save-prop-queue");
7
+ const callAddSequenceKeyframe = ({ fileName, nodePath, fieldKey, sourceFrame, value, schema, setCodeValues, clientId, }) => {
8
+ return (0, save_prop_queue_1.enqueueSavePropChange)({
9
+ nodePath,
10
+ setCodeValues,
11
+ applyOptimistic: (prev) => (0, studio_shared_1.optimisticAddSequenceKeyframe)({
12
+ previous: prev,
13
+ fieldKey,
14
+ frame: sourceFrame,
15
+ value,
16
+ }),
17
+ apiCall: () => (0, call_api_1.callApi)('/api/add-sequence-keyframe', {
18
+ fileName,
19
+ nodePath,
20
+ key: fieldKey,
21
+ frame: sourceFrame,
22
+ value: JSON.stringify(value),
23
+ schema,
24
+ clientId,
25
+ }),
26
+ errorLabel: 'Could not add keyframe',
27
+ });
28
+ };
29
+ exports.callAddSequenceKeyframe = callAddSequenceKeyframe;
30
+ const callAddEffectKeyframe = ({ fileName, nodePath, effectIndex, fieldKey, sourceFrame, value, schema, setCodeValues, clientId, }) => {
31
+ return (0, save_prop_queue_1.enqueueSavePropChange)({
32
+ nodePath,
33
+ setCodeValues,
34
+ applyOptimistic: (prev) => (0, studio_shared_1.optimisticAddEffectKeyframe)({
35
+ previous: prev,
36
+ effectIndex,
37
+ fieldKey,
38
+ frame: sourceFrame,
39
+ value,
40
+ }),
41
+ apiCall: () => (0, call_api_1.callApi)('/api/add-effect-keyframe', {
42
+ fileName,
43
+ sequenceNodePath: nodePath,
44
+ effectIndex,
45
+ key: fieldKey,
46
+ frame: sourceFrame,
47
+ value: JSON.stringify(value),
48
+ schema,
49
+ clientId,
50
+ }),
51
+ errorLabel: 'Could not add keyframe',
52
+ });
53
+ };
54
+ exports.callAddEffectKeyframe = callAddEffectKeyframe;
@@ -0,0 +1,21 @@
1
+ import type { SequencePropsSubscriptionKey, SequenceSchema } from 'remotion';
2
+ import type { SetCodeValues } from './save-sequence-prop';
3
+ export declare const callDeleteSequenceKeyframe: ({ fileName, nodePath, fieldKey, sourceFrame, schema, setCodeValues, clientId, }: {
4
+ fileName: string;
5
+ nodePath: SequencePropsSubscriptionKey;
6
+ fieldKey: string;
7
+ sourceFrame: number;
8
+ schema: SequenceSchema;
9
+ setCodeValues: SetCodeValues;
10
+ clientId: string;
11
+ }) => Promise<void>;
12
+ export declare const callDeleteEffectKeyframe: ({ fileName, nodePath, effectIndex, fieldKey, sourceFrame, schema, setCodeValues, clientId, }: {
13
+ fileName: string;
14
+ nodePath: SequencePropsSubscriptionKey;
15
+ effectIndex: number;
16
+ fieldKey: string;
17
+ sourceFrame: number;
18
+ schema: SequenceSchema;
19
+ setCodeValues: SetCodeValues;
20
+ clientId: string;
21
+ }) => Promise<void>;
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.callDeleteEffectKeyframe = exports.callDeleteSequenceKeyframe = void 0;
4
+ const studio_shared_1 = require("@remotion/studio-shared");
5
+ const call_api_1 = require("../call-api");
6
+ const save_prop_queue_1 = require("./save-prop-queue");
7
+ const callDeleteSequenceKeyframe = ({ fileName, nodePath, fieldKey, sourceFrame, schema, setCodeValues, clientId, }) => {
8
+ return (0, save_prop_queue_1.enqueueSavePropChange)({
9
+ nodePath,
10
+ setCodeValues,
11
+ applyOptimistic: (prev) => (0, studio_shared_1.optimisticDeleteSequenceKeyframe)({
12
+ previous: prev,
13
+ fieldKey,
14
+ frame: sourceFrame,
15
+ }),
16
+ apiCall: () => (0, call_api_1.callApi)('/api/delete-sequence-keyframe', {
17
+ fileName,
18
+ nodePath,
19
+ key: fieldKey,
20
+ frame: sourceFrame,
21
+ schema,
22
+ clientId,
23
+ }),
24
+ errorLabel: 'Could not delete keyframe',
25
+ });
26
+ };
27
+ exports.callDeleteSequenceKeyframe = callDeleteSequenceKeyframe;
28
+ const callDeleteEffectKeyframe = ({ fileName, nodePath, effectIndex, fieldKey, sourceFrame, schema, setCodeValues, clientId, }) => {
29
+ return (0, save_prop_queue_1.enqueueSavePropChange)({
30
+ nodePath,
31
+ setCodeValues,
32
+ applyOptimistic: (prev) => (0, studio_shared_1.optimisticDeleteEffectKeyframe)({
33
+ previous: prev,
34
+ effectIndex,
35
+ fieldKey,
36
+ frame: sourceFrame,
37
+ }),
38
+ apiCall: () => (0, call_api_1.callApi)('/api/delete-effect-keyframe', {
39
+ fileName,
40
+ sequenceNodePath: nodePath,
41
+ effectIndex,
42
+ key: fieldKey,
43
+ frame: sourceFrame,
44
+ schema,
45
+ clientId,
46
+ }),
47
+ errorLabel: 'Could not delete keyframe',
48
+ });
49
+ };
50
+ exports.callDeleteEffectKeyframe = callDeleteEffectKeyframe;
@@ -0,0 +1,11 @@
1
+ import type { OverrideIdToNodePaths, TSequence } from 'remotion';
2
+ import type { SequenceNodePathInfo } from '../../helpers/get-timeline-sequence-sort-key';
3
+ import type { SetCodeValues } from './save-sequence-prop';
4
+ export declare const deleteSelectedKeyframe: ({ nodePathInfo, frame, sequences, overrideIdsToNodePaths, setCodeValues, clientId, }: {
5
+ nodePathInfo: SequenceNodePathInfo;
6
+ frame: number;
7
+ sequences: TSequence[];
8
+ overrideIdsToNodePaths: OverrideIdToNodePaths;
9
+ setCodeValues: SetCodeValues;
10
+ clientId: string;
11
+ }) => Promise<void> | null;
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.deleteSelectedKeyframe = void 0;
4
+ const call_delete_keyframe_1 = require("./call-delete-keyframe");
5
+ const find_track_for_node_path_info_1 = require("./find-track-for-node-path-info");
6
+ const parse_keyframe_field_from_node_path_1 = require("./parse-keyframe-field-from-node-path");
7
+ const deleteSelectedKeyframe = ({ nodePathInfo, frame, sequences, overrideIdsToNodePaths, setCodeValues, clientId, }) => {
8
+ var _a, _b;
9
+ const field = (0, parse_keyframe_field_from_node_path_1.parseKeyframeFieldFromNodePath)(nodePathInfo.auxiliaryKeys);
10
+ if (field === null) {
11
+ return null;
12
+ }
13
+ const track = (0, find_track_for_node_path_info_1.findTrackForNodePathInfo)({
14
+ sequences,
15
+ overrideIdsToNodePaths,
16
+ nodePathInfo,
17
+ });
18
+ const sequence = (_a = track === null || track === void 0 ? void 0 : track.sequence) !== null && _a !== void 0 ? _a : null;
19
+ if (!(sequence === null || sequence === void 0 ? void 0 : sequence.controls)) {
20
+ return null;
21
+ }
22
+ const sourceFrame = frame - ((_b = track === null || track === void 0 ? void 0 : track.keyframeDisplayOffset) !== null && _b !== void 0 ? _b : 0);
23
+ const nodePath = nodePathInfo.sequenceSubscriptionKey;
24
+ const fileName = nodePath.absolutePath;
25
+ if (field.type === 'effect') {
26
+ const effect = sequence.effects[field.effectIndex];
27
+ if (!effect) {
28
+ return null;
29
+ }
30
+ return (0, call_delete_keyframe_1.callDeleteEffectKeyframe)({
31
+ fileName,
32
+ nodePath,
33
+ effectIndex: field.effectIndex,
34
+ fieldKey: field.fieldKey,
35
+ sourceFrame,
36
+ schema: effect.schema,
37
+ setCodeValues,
38
+ clientId,
39
+ });
40
+ }
41
+ return (0, call_delete_keyframe_1.callDeleteSequenceKeyframe)({
42
+ fileName,
43
+ nodePath,
44
+ fieldKey: field.fieldKey,
45
+ sourceFrame,
46
+ schema: sequence.controls.schema,
47
+ setCodeValues,
48
+ clientId,
49
+ });
50
+ };
51
+ exports.deleteSelectedKeyframe = deleteSelectedKeyframe;