@remotion/studio 4.0.471 → 4.0.472

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 (91) hide show
  1. package/dist/components/AssetSelector.js +10 -1
  2. package/dist/components/Canvas.js +98 -0
  3. package/dist/components/CompositionSelectorItem.d.ts +1 -0
  4. package/dist/components/CompositionSelectorItem.js +12 -4
  5. package/dist/components/ContextMenu.js +54 -46
  6. package/dist/components/Editor.js +14 -6
  7. package/dist/components/Modals.js +3 -1
  8. package/dist/components/NewComposition/CodemodFooter.js +2 -2
  9. package/dist/components/NewComposition/DeleteFolder.d.ts +6 -0
  10. package/dist/components/NewComposition/DeleteFolder.js +39 -0
  11. package/dist/components/NewComposition/RenameFolder.d.ts +6 -0
  12. package/dist/components/NewComposition/RenameFolder.js +60 -0
  13. package/dist/components/SelectedOutlineOverlay.d.ts +81 -4
  14. package/dist/components/SelectedOutlineOverlay.js +405 -54
  15. package/dist/components/Splitter/SplitterContainer.js +9 -0
  16. package/dist/components/Splitter/SplitterHandle.js +63 -70
  17. package/dist/components/Timeline/Timeline.js +47 -2
  18. package/dist/components/Timeline/TimelineArrayField.d.ts +9 -0
  19. package/dist/components/Timeline/TimelineArrayField.js +210 -0
  20. package/dist/components/Timeline/TimelineBooleanField.d.ts +2 -2
  21. package/dist/components/Timeline/TimelineBooleanField.js +2 -2
  22. package/dist/components/Timeline/TimelineClipboardKeybindings.d.ts +20 -0
  23. package/dist/components/Timeline/TimelineClipboardKeybindings.js +265 -0
  24. package/dist/components/Timeline/TimelineColorField.d.ts +2 -2
  25. package/dist/components/Timeline/TimelineColorField.js +2 -8
  26. package/dist/components/Timeline/TimelineEffectItem.js +2 -2
  27. package/dist/components/Timeline/TimelineEffectPropItem.js +95 -25
  28. package/dist/components/Timeline/TimelineEnumField.d.ts +2 -2
  29. package/dist/components/Timeline/TimelineEnumField.js +3 -3
  30. package/dist/components/Timeline/TimelineKeyframeControls.d.ts +4 -3
  31. package/dist/components/Timeline/TimelineKeyframeControls.js +37 -23
  32. package/dist/components/Timeline/TimelineKeyframedValue.d.ts +7 -2
  33. package/dist/components/Timeline/TimelineKeyframedValue.js +22 -8
  34. package/dist/components/Timeline/TimelineLayerEye.d.ts +1 -0
  35. package/dist/components/Timeline/TimelineLayerEye.js +8 -3
  36. package/dist/components/Timeline/TimelineNumberField.d.ts +2 -2
  37. package/dist/components/Timeline/TimelineNumberField.js +7 -11
  38. package/dist/components/Timeline/TimelinePrimitiveFieldValue.d.ts +17 -0
  39. package/dist/components/Timeline/TimelinePrimitiveFieldValue.js +53 -0
  40. package/dist/components/Timeline/TimelineRotationField.d.ts +2 -2
  41. package/dist/components/Timeline/TimelineRotationField.js +41 -24
  42. package/dist/components/Timeline/TimelineRowChrome.js +8 -7
  43. package/dist/components/Timeline/TimelineScaleField.d.ts +20 -0
  44. package/dist/components/Timeline/TimelineScaleField.js +314 -0
  45. package/dist/components/Timeline/TimelineSchemaField.d.ts +3 -2
  46. package/dist/components/Timeline/TimelineSchemaField.js +8 -42
  47. package/dist/components/Timeline/TimelineSelection.js +3 -2
  48. package/dist/components/Timeline/TimelineSequence.d.ts +1 -0
  49. package/dist/components/Timeline/TimelineSequence.js +51 -10
  50. package/dist/components/Timeline/TimelineSequenceFrame.js +1 -0
  51. package/dist/components/Timeline/TimelineSequenceItem.js +7 -7
  52. package/dist/components/Timeline/TimelineSequencePropItem.js +82 -21
  53. package/dist/components/Timeline/TimelineSequenceRightEdgeDragHandle.d.ts +58 -0
  54. package/dist/components/Timeline/TimelineSequenceRightEdgeDragHandle.js +528 -0
  55. package/dist/components/Timeline/TimelineTrack.js +1 -1
  56. package/dist/components/Timeline/TimelineTranslateField.d.ts +2 -2
  57. package/dist/components/Timeline/TimelineTranslateField.js +21 -25
  58. package/dist/components/Timeline/TimelineUvCoordinateField.d.ts +2 -2
  59. package/dist/components/Timeline/TimelineUvCoordinateField.js +20 -26
  60. package/dist/components/Timeline/call-add-keyframe.js +2 -0
  61. package/dist/components/Timeline/get-node-keyframes.d.ts +5 -2
  62. package/dist/components/Timeline/get-node-keyframes.js +38 -5
  63. package/dist/components/Timeline/get-timeline-keyframes.js +4 -4
  64. package/dist/components/Timeline/reset-selected-timeline-props.js +19 -6
  65. package/dist/components/Timeline/timeline-field-utils.d.ts +1 -0
  66. package/dist/components/Timeline/timeline-field-utils.js +5 -1
  67. package/dist/components/Timeline/timeline-translate-utils.js +6 -2
  68. package/dist/components/Timeline/use-expanded-track-keyframe-rows.js +7 -0
  69. package/dist/components/TopPanel.d.ts +1 -1
  70. package/dist/components/folder-menu-items.d.ts +12 -0
  71. package/dist/components/folder-menu-items.js +147 -0
  72. package/dist/components/import-assets.d.ts +6 -0
  73. package/dist/components/import-assets.js +157 -0
  74. package/dist/esm/{chunk-z0z9d4r0.js → chunk-48grt472.js} +8936 -5886
  75. package/dist/esm/internals.mjs +8936 -5886
  76. package/dist/esm/previewEntry.mjs +8748 -5698
  77. package/dist/esm/renderEntry.mjs +1 -1
  78. package/dist/helpers/calculate-timeline.js +7 -3
  79. package/dist/helpers/create-folder-tree.js +1 -0
  80. package/dist/helpers/detect-file-type.d.ts +69 -0
  81. package/dist/helpers/detect-file-type.js +278 -0
  82. package/dist/helpers/get-folder-id.d.ts +4 -0
  83. package/dist/helpers/get-folder-id.js +7 -0
  84. package/dist/helpers/get-timeline-sequence-sort-key.d.ts +2 -0
  85. package/dist/helpers/timeline-layout.js +5 -1
  86. package/dist/helpers/validate-folder-rename.d.ts +6 -0
  87. package/dist/helpers/validate-folder-rename.js +19 -0
  88. package/dist/state/modals.d.ts +10 -0
  89. package/dist/state/scale-lock.d.ts +18 -0
  90. package/dist/state/scale-lock.js +59 -0
  91. package/package.json +10 -10
@@ -57,8 +57,7 @@ const TimelineUvCoordinateField = ({ field, propStatus, effectiveValue, onSave,
57
57
  const onXChangeEnd = (0, react_1.useCallback)((newVal) => {
58
58
  const currentY = dragY !== null && dragY !== void 0 ? dragY : codeY;
59
59
  const newTuple = [newVal, currentY];
60
- if (propStatus.canUpdate &&
61
- !tuplesEqual(propStatus.codeValue, newTuple)) {
60
+ if (!tuplesEqual(propStatus.codeValue, newTuple)) {
62
61
  onSave(newTuple).finally(() => {
63
62
  setDragX(null);
64
63
  onDragEnd();
@@ -70,17 +69,15 @@ const TimelineUvCoordinateField = ({ field, propStatus, effectiveValue, onSave,
70
69
  }
71
70
  }, [dragY, codeY, propStatus, onSave, onDragEnd]);
72
71
  const onXTextChange = (0, react_1.useCallback)((newVal) => {
73
- if (propStatus.canUpdate) {
74
- const parsed = Number(newVal);
75
- if (!Number.isNaN(parsed)) {
76
- const currentY = dragY !== null && dragY !== void 0 ? dragY : codeY;
77
- const newTuple = [parsed, currentY];
78
- if (!tuplesEqual(propStatus.codeValue, newTuple)) {
79
- setDragX(parsed);
80
- onSave(newTuple).finally(() => {
81
- setDragX(null);
82
- });
83
- }
72
+ const parsed = Number(newVal);
73
+ if (!Number.isNaN(parsed)) {
74
+ const currentY = dragY !== null && dragY !== void 0 ? dragY : codeY;
75
+ const newTuple = [parsed, currentY];
76
+ if (!tuplesEqual(propStatus.codeValue, newTuple)) {
77
+ setDragX(parsed);
78
+ onSave(newTuple).finally(() => {
79
+ setDragX(null);
80
+ });
84
81
  }
85
82
  }
86
83
  }, [propStatus, dragY, codeY, onSave]);
@@ -92,8 +89,7 @@ const TimelineUvCoordinateField = ({ field, propStatus, effectiveValue, onSave,
92
89
  const onYChangeEnd = (0, react_1.useCallback)((newVal) => {
93
90
  const currentX = dragX !== null && dragX !== void 0 ? dragX : codeX;
94
91
  const newTuple = [currentX, newVal];
95
- if (propStatus.canUpdate &&
96
- !tuplesEqual(propStatus.codeValue, newTuple)) {
92
+ if (!tuplesEqual(propStatus.codeValue, newTuple)) {
97
93
  onSave(newTuple).finally(() => {
98
94
  setDragY(null);
99
95
  onDragEnd();
@@ -105,17 +101,15 @@ const TimelineUvCoordinateField = ({ field, propStatus, effectiveValue, onSave,
105
101
  }
106
102
  }, [dragX, codeX, propStatus, onSave, onDragEnd]);
107
103
  const onYTextChange = (0, react_1.useCallback)((newVal) => {
108
- if (propStatus.canUpdate) {
109
- const parsed = Number(newVal);
110
- if (!Number.isNaN(parsed)) {
111
- const currentX = dragX !== null && dragX !== void 0 ? dragX : codeX;
112
- const newTuple = [currentX, parsed];
113
- if (!tuplesEqual(propStatus.codeValue, newTuple)) {
114
- setDragY(parsed);
115
- onSave(newTuple).finally(() => {
116
- setDragY(null);
117
- });
118
- }
104
+ const parsed = Number(newVal);
105
+ if (!Number.isNaN(parsed)) {
106
+ const currentX = dragX !== null && dragX !== void 0 ? dragX : codeX;
107
+ const newTuple = [currentX, parsed];
108
+ if (!tuplesEqual(propStatus.codeValue, newTuple)) {
109
+ setDragY(parsed);
110
+ onSave(newTuple).finally(() => {
111
+ setDragY(null);
112
+ });
119
113
  }
120
114
  }
121
115
  }, [propStatus, onSave, dragX, codeX]);
@@ -13,6 +13,7 @@ const callAddSequenceKeyframe = ({ fileName, nodePath, fieldKey, sourceFrame, va
13
13
  fieldKey,
14
14
  frame: sourceFrame,
15
15
  value,
16
+ schema,
16
17
  }),
17
18
  apiCall: () => (0, call_api_1.callApi)('/api/add-sequence-keyframe', {
18
19
  fileName,
@@ -37,6 +38,7 @@ const callAddEffectKeyframe = ({ fileName, nodePath, effectIndex, fieldKey, sour
37
38
  fieldKey,
38
39
  frame: sourceFrame,
39
40
  value,
41
+ schema,
40
42
  }),
41
43
  apiCall: () => (0, call_api_1.callApi)('/api/add-effect-keyframe', {
42
44
  fileName,
@@ -1,10 +1,13 @@
1
- import { type CodeValues, type SequencePropsSubscriptionKey } from 'remotion';
1
+ import { type CodeValues, type GetDragOverrides, type GetEffectDragOverrides, type SequencePropsSubscriptionKey } from 'remotion';
2
2
  import type { TimelineTreeNode } from '../../helpers/timeline-layout';
3
- export declare const getNodeKeyframes: ({ node, nodePath, codeValues, keyframeDisplayOffset, }: {
3
+ export declare const getNodeKeyframes: ({ node, nodePath, codeValues, keyframeDisplayOffset, getDragOverrides, getEffectDragOverrides, timelinePosition, }: {
4
4
  node: TimelineTreeNode;
5
5
  nodePath: SequencePropsSubscriptionKey;
6
6
  codeValues: CodeValues;
7
7
  keyframeDisplayOffset: number;
8
+ getDragOverrides: GetDragOverrides;
9
+ getEffectDragOverrides: GetEffectDragOverrides;
10
+ timelinePosition: number;
8
11
  }) => {
9
12
  frame: number;
10
13
  value: unknown;
@@ -3,21 +3,54 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getNodeKeyframes = void 0;
4
4
  const remotion_1 = require("remotion");
5
5
  const get_timeline_keyframes_1 = require("./get-timeline-keyframes");
6
- const getNodeKeyframes = ({ node, nodePath, codeValues, keyframeDisplayOffset, }) => {
6
+ const hasOverride = (overrides, key) => Object.prototype.hasOwnProperty.call(overrides, key);
7
+ const withDragOverrideKeyframe = ({ propStatus, keyframeDisplayOffset, timelinePosition, dragOverrideValue, hasDragOverride, }) => {
8
+ if ((dragOverrideValue === null || dragOverrideValue === void 0 ? void 0 : dragOverrideValue.type) === 'keyframed') {
9
+ return (0, get_timeline_keyframes_1.getTimelineKeyframes)(dragOverrideValue.status, keyframeDisplayOffset);
10
+ }
11
+ const keyframes = (0, get_timeline_keyframes_1.getTimelineKeyframes)(propStatus, keyframeDisplayOffset);
12
+ if (!hasDragOverride || (propStatus === null || propStatus === void 0 ? void 0 : propStatus.status) !== 'keyframed') {
13
+ return keyframes;
14
+ }
15
+ const dragKeyframe = {
16
+ frame: timelinePosition,
17
+ value: dragOverrideValue === null || dragOverrideValue === void 0 ? void 0 : dragOverrideValue.value,
18
+ };
19
+ const existingIndex = keyframes.findIndex((keyframe) => keyframe.frame === timelinePosition);
20
+ if (existingIndex !== -1) {
21
+ return keyframes.map((keyframe, index) => index === existingIndex ? dragKeyframe : keyframe);
22
+ }
23
+ return [...keyframes, dragKeyframe].sort((first, second) => first.frame - second.frame);
24
+ };
25
+ const getNodeKeyframes = ({ node, nodePath, codeValues, keyframeDisplayOffset, getDragOverrides, getEffectDragOverrides, timelinePosition, }) => {
7
26
  var _a, _b;
8
27
  if (node.kind !== 'field' || node.field === null) {
9
28
  return [];
10
29
  }
11
30
  if (node.field.kind === 'sequence-field') {
12
- return (0, get_timeline_keyframes_1.getTimelineKeyframes)((_a = remotion_1.Internals.getCodeValuesCtx(codeValues, nodePath)) === null || _a === void 0 ? void 0 : _a[node.field.key], keyframeDisplayOffset);
31
+ const dragOverrides = getDragOverrides(nodePath);
32
+ return withDragOverrideKeyframe({
33
+ propStatus: (_a = remotion_1.Internals.getCodeValuesCtx(codeValues, nodePath)) === null || _a === void 0 ? void 0 : _a[node.field.key],
34
+ keyframeDisplayOffset,
35
+ timelinePosition,
36
+ dragOverrideValue: dragOverrides[node.field.key],
37
+ hasDragOverride: hasOverride(dragOverrides, node.field.key),
38
+ });
13
39
  }
14
40
  const effectStatus = remotion_1.Internals.getEffectCodeValuesCtx({
15
41
  codeValues,
16
42
  nodePath,
17
43
  effectIndex: node.field.effectIndex,
18
44
  });
19
- return (0, get_timeline_keyframes_1.getTimelineKeyframes)(effectStatus.type === 'can-update-effect'
20
- ? (_b = effectStatus.props) === null || _b === void 0 ? void 0 : _b[node.field.key]
21
- : null, keyframeDisplayOffset);
45
+ const effectDragOverrides = getEffectDragOverrides(nodePath, node.field.effectIndex);
46
+ return withDragOverrideKeyframe({
47
+ propStatus: effectStatus.type === 'can-update-effect'
48
+ ? (_b = effectStatus.props) === null || _b === void 0 ? void 0 : _b[node.field.key]
49
+ : null,
50
+ keyframeDisplayOffset,
51
+ timelinePosition,
52
+ dragOverrideValue: effectDragOverrides[node.field.key],
53
+ hasDragOverride: hasOverride(effectDragOverrides, node.field.key),
54
+ });
22
55
  };
23
56
  exports.getNodeKeyframes = getNodeKeyframes;
@@ -2,17 +2,17 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getTimelineKeyframes = exports.getComputedStatusLabel = void 0;
4
4
  const getComputedStatusLabel = (propStatus) => {
5
- if (propStatus.reason === 'computed') {
5
+ if (propStatus.status === 'computed') {
6
6
  return 'computed';
7
7
  }
8
- return 'keyframed';
8
+ throw new Error(`Unsupported prop status: ${propStatus.status}`);
9
9
  };
10
10
  exports.getComputedStatusLabel = getComputedStatusLabel;
11
11
  const getTimelineKeyframes = (propStatus, keyframeDisplayOffset = 0) => {
12
- if (!propStatus || propStatus.canUpdate) {
12
+ if (!propStatus) {
13
13
  return [];
14
14
  }
15
- if (propStatus.reason === 'computed') {
15
+ if (propStatus.status !== 'keyframed') {
16
16
  return [];
17
17
  }
18
18
  const { keyframes } = propStatus;
@@ -9,6 +9,21 @@ const isPropResetSelection = (selection) => selection.type === 'sequence-prop' |
9
9
  selection.type === 'sequence-effect-prop';
10
10
  const isVisibleFieldSchema = (fieldSchema) => fieldSchema !== undefined && fieldSchema.type !== 'hidden';
11
11
  const isNonDefaultCodeValue = ({ codeValue, defaultValue, }) => JSON.stringify(codeValue !== null && codeValue !== void 0 ? codeValue : defaultValue) !== JSON.stringify(defaultValue);
12
+ const isResettablePropStatus = ({ propStatus, defaultValue, }) => {
13
+ if (!propStatus || propStatus.status === 'computed') {
14
+ return false;
15
+ }
16
+ if (defaultValue === undefined) {
17
+ return false;
18
+ }
19
+ if (propStatus.status === 'keyframed') {
20
+ return true;
21
+ }
22
+ return isNonDefaultCodeValue({
23
+ codeValue: propStatus.codeValue,
24
+ defaultValue,
25
+ });
26
+ };
12
27
  const getDefaultValue = (fieldSchema) => fieldSchema.default !== undefined
13
28
  ? JSON.stringify(fieldSchema.default)
14
29
  : null;
@@ -41,9 +56,8 @@ const getTimelinePropResetTargets = ({ selections, sequences, overrideIdsToNodeP
41
56
  const sequenceFieldSchema = sequence.controls.schema[selection.key];
42
57
  const sequencePropStatus = (_a = remotion_1.Internals.getCodeValuesCtx(codeValues, nodePath)) === null || _a === void 0 ? void 0 : _a[selection.key];
43
58
  if (!isVisibleFieldSchema(sequenceFieldSchema) ||
44
- !(sequencePropStatus === null || sequencePropStatus === void 0 ? void 0 : sequencePropStatus.canUpdate) ||
45
- !isNonDefaultCodeValue({
46
- codeValue: sequencePropStatus.codeValue,
59
+ !isResettablePropStatus({
60
+ propStatus: sequencePropStatus,
47
61
  defaultValue: sequenceFieldSchema.default,
48
62
  })) {
49
63
  continue;
@@ -71,9 +85,8 @@ const getTimelinePropResetTargets = ({ selections, sequences, overrideIdsToNodeP
71
85
  : null;
72
86
  if (!effect ||
73
87
  !isVisibleFieldSchema(fieldSchema) ||
74
- !(propStatus === null || propStatus === void 0 ? void 0 : propStatus.canUpdate) ||
75
- !isNonDefaultCodeValue({
76
- codeValue: propStatus.codeValue,
88
+ !isResettablePropStatus({
89
+ propStatus,
77
90
  defaultValue: fieldSchema.default,
78
91
  })) {
79
92
  continue;
@@ -1,2 +1,3 @@
1
1
  export declare const getDecimalPlaces: (num: number) => number;
2
+ export declare const normalizeTimelineNumber: (value: number) => number;
2
3
  export declare const draggerStyle: React.CSSProperties;
@@ -1,12 +1,16 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.draggerStyle = exports.getDecimalPlaces = void 0;
3
+ exports.draggerStyle = exports.normalizeTimelineNumber = exports.getDecimalPlaces = void 0;
4
4
  const getDecimalPlaces = (num) => {
5
5
  const str = String(num);
6
6
  const decimalIndex = str.indexOf('.');
7
7
  return decimalIndex === -1 ? 0 : str.length - decimalIndex - 1;
8
8
  };
9
9
  exports.getDecimalPlaces = getDecimalPlaces;
10
+ const normalizeTimelineNumber = (value) => {
11
+ return Math.round(value * 1000000) / 1000000;
12
+ };
13
+ exports.normalizeTimelineNumber = normalizeTimelineNumber;
10
14
  exports.draggerStyle = {
11
15
  width: 80,
12
16
  };
@@ -1,17 +1,21 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.serializeTranslate = exports.parseTranslate = void 0;
4
+ const timeline_field_utils_1 = require("./timeline-field-utils");
4
5
  const PIXEL_PATTERN = /^(-?\d+(?:\.\d+)?)px(?:\s+(-?\d+(?:\.\d+)?)px)?$/;
5
6
  const parseTranslate = (value) => {
6
7
  const m = value.match(PIXEL_PATTERN);
7
8
  if (!m) {
8
9
  return [0, 0];
9
10
  }
10
- return [Number(m[1]), m[2] !== undefined ? Number(m[2]) : 0];
11
+ return [
12
+ (0, timeline_field_utils_1.normalizeTimelineNumber)(Number(m[1])),
13
+ m[2] !== undefined ? (0, timeline_field_utils_1.normalizeTimelineNumber)(Number(m[2])) : 0,
14
+ ];
11
15
  };
12
16
  exports.parseTranslate = parseTranslate;
13
17
  const formatTranslateCoordinate = (value) => {
14
- const rounded = Math.round(value * 1000) / 1000;
18
+ const rounded = (0, timeline_field_utils_1.normalizeTimelineNumber)(value);
15
19
  return String(Object.is(rounded, -0) ? 0 : rounded);
16
20
  };
17
21
  const serializeTranslate = (x, y) => {
@@ -11,6 +11,7 @@ const useExpandedTrackKeyframeRows = ({ sequence, nodePathInfo, keyframeDisplayO
11
11
  const { getIsExpanded } = (0, react_1.useContext)(ExpandedTracksProvider_1.ExpandedTracksGetterContext);
12
12
  const { codeValues } = (0, react_1.useContext)(remotion_1.Internals.VisualModeCodeValuesContext);
13
13
  const { getDragOverrides, getEffectDragOverrides } = (0, react_1.useContext)(remotion_1.Internals.VisualModeDragOverridesContext);
14
+ const timelinePosition = remotion_1.Internals.Timeline.useTimelinePosition();
14
15
  const tree = (0, react_1.useMemo)(() => (0, timeline_layout_1.buildTimelineTree)({
15
16
  sequence,
16
17
  nodePathInfo,
@@ -38,14 +39,20 @@ const useExpandedTrackKeyframeRows = ({ sequence, nodePathInfo, keyframeDisplayO
38
39
  nodePath: nodePathInfo.sequenceSubscriptionKey,
39
40
  codeValues,
40
41
  keyframeDisplayOffset,
42
+ getDragOverrides,
43
+ getEffectDragOverrides,
44
+ timelinePosition,
41
45
  }),
42
46
  rowKey: (0, timeline_node_path_key_1.timelineNodePathInfoToKey)(node.nodePathInfo),
43
47
  nodePathInfo: node.nodePathInfo,
44
48
  })), [
45
49
  codeValues,
46
50
  flat,
51
+ getDragOverrides,
52
+ getEffectDragOverrides,
47
53
  keyframeDisplayOffset,
48
54
  nodePathInfo.sequenceSubscriptionKey,
55
+ timelinePosition,
49
56
  ]);
50
57
  return { rows, expandedHeight };
51
58
  };
@@ -3,6 +3,6 @@ export declare const useResponsiveSidebarStatus: () => "collapsed" | "expanded";
3
3
  export declare const TopPanel: React.NamedExoticComponent<{
4
4
  readonly readOnlyStudio: boolean;
5
5
  readonly onMounted: () => void;
6
- readonly drawRef: React.RefObject<HTMLDivElement | null>;
6
+ readonly drawRef: React.Ref<HTMLDivElement>;
7
7
  readonly bufferStateDelayInMilliseconds: number;
8
8
  }>;
@@ -0,0 +1,12 @@
1
+ import type { SetStateAction } from 'react';
2
+ import type { ResolvedStackLocation } from 'remotion';
3
+ import type { ModalState } from '../state/modals';
4
+ import type { ComboboxValue } from './NewComposition/ComboBox';
5
+ export declare const getFolderMenuItems: ({ closeMenu, connectionStatus, folder, readOnlyStudio, resolvedLocation, setSelectedModal, }: {
6
+ closeMenu: () => void;
7
+ connectionStatus: "connected" | "disconnected" | "init";
8
+ folder: import("remotion").TFolder;
9
+ readOnlyStudio: boolean;
10
+ resolvedLocation: ResolvedStackLocation | null;
11
+ setSelectedModal: (value: SetStateAction<ModalState | null>) => void;
12
+ }) => ComboboxValue[];
@@ -0,0 +1,147 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getFolderMenuItems = void 0;
4
+ const no_react_1 = require("remotion/no-react");
5
+ const format_file_location_1 = require("../helpers/format-file-location");
6
+ const get_folder_id_1 = require("../helpers/get-folder-id");
7
+ const open_in_editor_1 = require("../helpers/open-in-editor");
8
+ const NotificationCenter_1 = require("./Notifications/NotificationCenter");
9
+ const getFolderMenuItems = ({ closeMenu, connectionStatus, folder, readOnlyStudio, resolvedLocation, setSelectedModal, }) => {
10
+ const editorName = window.remotion_editorName;
11
+ const folderId = (0, get_folder_id_1.getFolderId)({
12
+ folderName: folder.name,
13
+ parentName: folder.parent,
14
+ });
15
+ const fileLocation = (0, format_file_location_1.formatFileLocation)({
16
+ location: resolvedLocation,
17
+ root: window.remotion_cwd,
18
+ });
19
+ const showInEditorDisabled = connectionStatus !== 'connected' || !resolvedLocation;
20
+ const copyFileLocationDisabled = !fileLocation;
21
+ const codemodDisabled = readOnlyStudio || !folder.stack;
22
+ return [
23
+ editorName
24
+ ? {
25
+ id: 'show-folder-in-editor',
26
+ keyHint: null,
27
+ label: `Show folder in ${editorName}`,
28
+ leftItem: null,
29
+ onClick: async () => {
30
+ closeMenu();
31
+ if (!resolvedLocation) {
32
+ return;
33
+ }
34
+ try {
35
+ await (0, open_in_editor_1.openOriginalPositionInEditor)(resolvedLocation);
36
+ }
37
+ catch (err) {
38
+ (0, NotificationCenter_1.showNotification)(err.message, 2000);
39
+ }
40
+ },
41
+ quickSwitcherLabel: `Show folder in ${editorName}`,
42
+ subMenu: null,
43
+ type: 'item',
44
+ value: 'show-folder-in-editor',
45
+ disabled: showInEditorDisabled,
46
+ }
47
+ : null,
48
+ {
49
+ id: 'copy-folder-file-location',
50
+ keyHint: null,
51
+ label: `Copy file location`,
52
+ leftItem: null,
53
+ onClick: () => {
54
+ closeMenu();
55
+ if (!fileLocation) {
56
+ return;
57
+ }
58
+ navigator.clipboard
59
+ .writeText(fileLocation)
60
+ .then(() => {
61
+ (0, NotificationCenter_1.showNotification)('Copied file location to clipboard', 1000);
62
+ })
63
+ .catch((err) => {
64
+ (0, NotificationCenter_1.showNotification)(`Could not copy to clipboard: ${err.message}`, 1000);
65
+ });
66
+ },
67
+ quickSwitcherLabel: 'Copy folder file location',
68
+ subMenu: null,
69
+ type: 'item',
70
+ value: 'copy-folder-file-location',
71
+ disabled: copyFileLocationDisabled,
72
+ },
73
+ editorName || fileLocation
74
+ ? {
75
+ type: 'divider',
76
+ id: 'show-folder-in-editor-divider',
77
+ }
78
+ : null,
79
+ {
80
+ id: 'rename-folder',
81
+ keyHint: null,
82
+ label: `Rename...`,
83
+ leftItem: null,
84
+ onClick: () => {
85
+ closeMenu();
86
+ setSelectedModal({
87
+ type: 'rename-folder',
88
+ folderName: folder.name,
89
+ parentName: folder.parent,
90
+ stack: folder.stack,
91
+ });
92
+ },
93
+ quickSwitcherLabel: 'Rename folder...',
94
+ subMenu: null,
95
+ type: 'item',
96
+ value: 'rename-folder',
97
+ disabled: codemodDisabled,
98
+ },
99
+ {
100
+ id: 'delete-folder',
101
+ keyHint: null,
102
+ label: `Delete...`,
103
+ leftItem: null,
104
+ onClick: () => {
105
+ closeMenu();
106
+ setSelectedModal({
107
+ type: 'delete-folder',
108
+ folderName: folder.name,
109
+ parentName: folder.parent,
110
+ stack: folder.stack,
111
+ });
112
+ },
113
+ quickSwitcherLabel: 'Delete folder...',
114
+ subMenu: null,
115
+ type: 'item',
116
+ value: 'delete-folder',
117
+ disabled: codemodDisabled,
118
+ },
119
+ {
120
+ type: 'divider',
121
+ id: 'copy-folder-id-divider',
122
+ },
123
+ {
124
+ id: 'copy-folder-id',
125
+ keyHint: null,
126
+ label: `Copy ID`,
127
+ leftItem: null,
128
+ onClick: () => {
129
+ closeMenu();
130
+ navigator.clipboard
131
+ .writeText(folderId)
132
+ .then(() => {
133
+ (0, NotificationCenter_1.showNotification)('Copied to clipboard', 1000);
134
+ })
135
+ .catch((err) => {
136
+ (0, NotificationCenter_1.showNotification)(`Could not copy to clipboard: ${err.message}`, 1000);
137
+ });
138
+ },
139
+ quickSwitcherLabel: 'Copy folder ID',
140
+ subMenu: null,
141
+ type: 'item',
142
+ value: 'copy-folder-id',
143
+ disabled: false,
144
+ },
145
+ ].filter(no_react_1.NoReactInternals.truthy);
146
+ };
147
+ exports.getFolderMenuItems = getFolderMenuItems;
@@ -0,0 +1,6 @@
1
+ export declare const pickFilesToImport: () => Promise<File[]>;
2
+ export declare const importAssets: ({ compositionFile, compositionId, files, }: {
3
+ compositionFile: string;
4
+ compositionId: string;
5
+ files: File[];
6
+ }) => Promise<void>;
@@ -0,0 +1,157 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.importAssets = exports.pickFilesToImport = void 0;
4
+ const get_static_files_1 = require("../api/get-static-files");
5
+ const write_static_file_1 = require("../api/write-static-file");
6
+ const detect_file_type_1 = require("../helpers/detect-file-type");
7
+ const call_api_1 = require("./call-api");
8
+ const NotificationCenter_1 = require("./Notifications/NotificationCenter");
9
+ const getAssetElement = ({ fileType, src, }) => {
10
+ if (fileType.type === 'png' ||
11
+ fileType.type === 'jpeg' ||
12
+ fileType.type === 'webp' ||
13
+ fileType.type === 'bmp') {
14
+ return {
15
+ type: 'asset',
16
+ assetType: 'image',
17
+ src,
18
+ dimensions: fileType.dimensions,
19
+ };
20
+ }
21
+ if (fileType.type === 'gif') {
22
+ return {
23
+ type: 'asset',
24
+ assetType: 'gif',
25
+ src,
26
+ dimensions: fileType.dimensions,
27
+ };
28
+ }
29
+ if (fileType.type === 'riff' ||
30
+ fileType.type === 'webm' ||
31
+ fileType.type === 'iso-base-media' ||
32
+ fileType.type === 'transport-stream') {
33
+ return {
34
+ type: 'asset',
35
+ assetType: 'video',
36
+ src,
37
+ dimensions: null,
38
+ };
39
+ }
40
+ return null;
41
+ };
42
+ const getAssetLabel = (element) => {
43
+ if (element.type !== 'asset') {
44
+ throw new Error('Expected asset element');
45
+ }
46
+ if (element.assetType === 'image') {
47
+ return '<Img>';
48
+ }
49
+ if (element.assetType === 'video') {
50
+ return '<Video>';
51
+ }
52
+ return '<Gif>';
53
+ };
54
+ const pickFilesToImport = () => {
55
+ return new Promise((resolve) => {
56
+ const input = document.createElement('input');
57
+ input.type = 'file';
58
+ input.multiple = true;
59
+ input.style.display = 'none';
60
+ let didResolve = false;
61
+ const resolveOnce = (files) => {
62
+ if (didResolve) {
63
+ return;
64
+ }
65
+ didResolve = true;
66
+ input.removeEventListener('change', onChange);
67
+ input.removeEventListener('cancel', onCancel);
68
+ input.remove();
69
+ resolve(files);
70
+ };
71
+ const onChange = () => {
72
+ var _a;
73
+ return resolveOnce(Array.from((_a = input.files) !== null && _a !== void 0 ? _a : []));
74
+ };
75
+ const onCancel = () => resolveOnce([]);
76
+ input.addEventListener('change', onChange);
77
+ input.addEventListener('cancel', onCancel);
78
+ document.body.appendChild(input);
79
+ input.click();
80
+ });
81
+ };
82
+ exports.pickFilesToImport = pickFilesToImport;
83
+ const importAssets = async ({ compositionFile, compositionId, files, }) => {
84
+ if (files.length === 0) {
85
+ return;
86
+ }
87
+ const staticFiles = (0, get_static_files_1.getStaticFiles)();
88
+ const differentExistingFile = files.find((file) => {
89
+ return staticFiles.some((staticFile) => staticFile.name === file.name && staticFile.sizeInBytes !== file.size);
90
+ });
91
+ if (differentExistingFile) {
92
+ (0, NotificationCenter_1.showNotification)(`File with name ${differentExistingFile.name} already exists and is different`, 4000);
93
+ return;
94
+ }
95
+ const insertedLabels = [];
96
+ const addedStaticFiles = [];
97
+ const unsupportedFiles = [];
98
+ const notifyAddedStaticFiles = () => {
99
+ if (addedStaticFiles.length === 1) {
100
+ (0, NotificationCenter_1.showNotification)(`Created ${addedStaticFiles[0]} in public folder`, 3000);
101
+ }
102
+ else if (addedStaticFiles.length > 1) {
103
+ (0, NotificationCenter_1.showNotification)(`Added ${addedStaticFiles.length} files to public folder`, 3000);
104
+ }
105
+ addedStaticFiles.length = 0;
106
+ };
107
+ try {
108
+ for (const file of files) {
109
+ const contents = await file.arrayBuffer();
110
+ const fileType = (0, detect_file_type_1.detectFileType)(new Uint8Array(contents));
111
+ const element = getAssetElement({
112
+ fileType,
113
+ src: file.name,
114
+ });
115
+ if (element === null) {
116
+ unsupportedFiles.push(file.name);
117
+ continue;
118
+ }
119
+ const alreadyExists = staticFiles.some((staticFile) => staticFile.name === file.name && staticFile.sizeInBytes === file.size);
120
+ if (!alreadyExists) {
121
+ await (0, write_static_file_1.writeStaticFile)({
122
+ contents,
123
+ filePath: file.name,
124
+ });
125
+ addedStaticFiles.push(file.name);
126
+ }
127
+ const result = await (0, call_api_1.callApi)('/api/insert-jsx-element', {
128
+ compositionFile,
129
+ compositionId,
130
+ element,
131
+ });
132
+ if (!result.success) {
133
+ notifyAddedStaticFiles();
134
+ (0, NotificationCenter_1.showNotification)(result.reason, 4000);
135
+ return;
136
+ }
137
+ insertedLabels.push(getAssetLabel(element));
138
+ }
139
+ notifyAddedStaticFiles();
140
+ if (insertedLabels.length === 1) {
141
+ (0, NotificationCenter_1.showNotification)(`Added ${insertedLabels[0]} to source file`, 2000);
142
+ }
143
+ else if (insertedLabels.length > 1) {
144
+ (0, NotificationCenter_1.showNotification)(`Added ${insertedLabels.length} assets to source file`, 2000);
145
+ }
146
+ if (unsupportedFiles.length === 1) {
147
+ (0, NotificationCenter_1.showNotification)(`Cannot add ${unsupportedFiles[0]}: Unsupported file type`, 3000);
148
+ }
149
+ else if (unsupportedFiles.length > 1) {
150
+ (0, NotificationCenter_1.showNotification)(`Skipped ${unsupportedFiles.length} unsupported files`, 3000);
151
+ }
152
+ }
153
+ catch (error) {
154
+ (0, NotificationCenter_1.showNotification)(`Could not add asset: ${error instanceof Error ? error.message : String(error)}`, 4000);
155
+ }
156
+ };
157
+ exports.importAssets = importAssets;