@remotion/studio 4.0.464 → 4.0.465

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.
@@ -3,6 +3,7 @@ import React from 'react';
3
3
  export declare const CodemodFooter: React.FC<{
4
4
  readonly valid: boolean;
5
5
  readonly codemod: RecastCodemod;
6
+ readonly stack: string | null;
6
7
  readonly loadingNotification: React.ReactNode;
7
8
  readonly successNotification: React.ReactNode;
8
9
  readonly errorNotification: string;
@@ -4,33 +4,25 @@ exports.CodemodFooter = void 0;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const react_1 = require("react");
6
6
  const ShortcutHint_1 = require("../../error-overlay/remotion-overlay/ShortcutHint");
7
+ const resolved_stack_to_symbolicated_1 = require("../../helpers/resolved-stack-to-symbolicated");
7
8
  const use_keybinding_1 = require("../../helpers/use-keybinding");
8
9
  const modals_1 = require("../../state/modals");
9
10
  const layout_1 = require("../layout");
10
11
  const ModalButton_1 = require("../ModalButton");
11
12
  const NotificationCenter_1 = require("../Notifications/NotificationCenter");
12
13
  const actions_1 = require("../RenderQueue/actions");
14
+ const use_resolved_stack_1 = require("../Timeline/use-resolved-stack");
13
15
  const DiffPreview_1 = require("./DiffPreview");
14
- const CodemodFooter = ({ codemod, valid, loadingNotification, successNotification, errorNotification, genericSubmitLabel, submitLabel, onSuccess, }) => {
16
+ const CodemodFooter = ({ codemod, stack, valid, loadingNotification, successNotification, errorNotification, genericSubmitLabel, submitLabel, onSuccess, }) => {
17
+ var _a;
15
18
  const [submitting, setSubmitting] = (0, react_1.useState)(false);
16
19
  const { setSelectedModal } = (0, react_1.useContext)(modals_1.ModalsContext);
17
20
  const [codemodStatus, setCanApplyCodemod] = (0, react_1.useState)({
18
21
  type: 'loading',
19
22
  });
20
- const [projectInfo, setProjectInfo] = (0, react_1.useState)(null);
21
- (0, react_1.useEffect)(() => {
22
- const controller = new AbortController();
23
- (0, actions_1.getProjectInfo)(controller.signal)
24
- .then((info) => {
25
- setProjectInfo(info.projectInfo);
26
- })
27
- .catch((err) => {
28
- (0, NotificationCenter_1.showNotification)(`Could not get project info: ${err.message}. Unable to duplicate composition`, 3000);
29
- });
30
- return () => {
31
- controller.abort();
32
- };
33
- }, []);
23
+ const resolvedLocation = (0, use_resolved_stack_1.useResolvedStack)(stack);
24
+ const symbolicatedStack = (0, react_1.useMemo)(() => (0, resolved_stack_to_symbolicated_1.resolvedStackToSymbolicated)(resolvedLocation), [resolvedLocation]);
25
+ const relativeFilePath = (_a = symbolicatedStack === null || symbolicatedStack === void 0 ? void 0 : symbolicatedStack.originalFileName) !== null && _a !== void 0 ? _a : null;
34
26
  const trigger = (0, react_1.useCallback)(() => {
35
27
  setSubmitting(true);
36
28
  setSelectedModal(null);
@@ -38,6 +30,7 @@ const CodemodFooter = ({ codemod, valid, loadingNotification, successNotificatio
38
30
  (0, actions_1.applyCodemod)({
39
31
  codemod,
40
32
  dryRun: false,
33
+ symbolicatedStack,
41
34
  signal: new AbortController().signal,
42
35
  })
43
36
  .then(() => {
@@ -54,11 +47,13 @@ const CodemodFooter = ({ codemod, valid, loadingNotification, successNotificatio
54
47
  onSuccess,
55
48
  setSelectedModal,
56
49
  successNotification,
50
+ symbolicatedStack,
57
51
  ]);
58
52
  const getCanApplyCodemod = (0, react_1.useCallback)(async (signal) => {
59
53
  const res = await (0, actions_1.applyCodemod)({
60
54
  codemod,
61
55
  dryRun: true,
56
+ symbolicatedStack,
62
57
  signal,
63
58
  });
64
59
  if (res.success) {
@@ -70,8 +65,25 @@ const CodemodFooter = ({ codemod, valid, loadingNotification, successNotificatio
70
65
  error: res.reason,
71
66
  });
72
67
  }
73
- }, [codemod]);
68
+ }, [codemod, symbolicatedStack]);
74
69
  (0, react_1.useEffect)(() => {
70
+ if (!stack) {
71
+ setCanApplyCodemod({
72
+ type: 'fail',
73
+ error: 'Could not determine where this composition is defined',
74
+ });
75
+ return;
76
+ }
77
+ if (!(0, use_resolved_stack_1.hasResolvedStack)(stack)) {
78
+ return;
79
+ }
80
+ if (!symbolicatedStack) {
81
+ setCanApplyCodemod({
82
+ type: 'fail',
83
+ error: 'Could not resolve the source location of this composition',
84
+ });
85
+ return;
86
+ }
75
87
  const abortController = new AbortController();
76
88
  let aborted = false;
77
89
  getCanApplyCodemod(abortController.signal)
@@ -80,16 +92,16 @@ const CodemodFooter = ({ codemod, valid, loadingNotification, successNotificatio
80
92
  if (aborted) {
81
93
  return;
82
94
  }
83
- (0, NotificationCenter_1.showNotification)(`Cannot duplicate composition: ${err.message}`, 3000);
95
+ (0, NotificationCenter_1.showNotification)(`${errorNotification}: ${err.message}`, 3000);
84
96
  });
85
97
  return () => {
86
98
  aborted = true;
87
99
  abortController.abort();
88
100
  };
89
- }, [getCanApplyCodemod]);
101
+ }, [errorNotification, getCanApplyCodemod, stack, symbolicatedStack]);
90
102
  const disabled = !valid ||
91
103
  submitting ||
92
- projectInfo === null ||
104
+ symbolicatedStack === null ||
93
105
  codemodStatus.type !== 'success';
94
106
  const { registerKeybinding } = (0, use_keybinding_1.useKeybinding)();
95
107
  (0, react_1.useEffect)(() => {
@@ -100,7 +112,7 @@ const CodemodFooter = ({ codemod, valid, loadingNotification, successNotificatio
100
112
  callback() {
101
113
  trigger();
102
114
  },
103
- commandCtrlKey: true,
115
+ commandCtrlKey: false,
104
116
  key: 'Enter',
105
117
  event: 'keydown',
106
118
  preventDefault: true,
@@ -112,9 +124,9 @@ const CodemodFooter = ({ codemod, valid, loadingNotification, successNotificatio
112
124
  };
113
125
  }, [disabled, registerKeybinding, trigger, valid]);
114
126
  return (jsx_runtime_1.jsxs(layout_1.Row, { align: "center", children: [
115
- jsx_runtime_1.jsx(DiffPreview_1.CodemodDiffPreview, { status: codemodStatus }), jsx_runtime_1.jsx(layout_1.Flex, {}), jsx_runtime_1.jsx(layout_1.Spacing, { block: true, x: 2 }), jsx_runtime_1.jsxs(ModalButton_1.ModalButton, { onClick: trigger, disabled: disabled, children: [projectInfo && projectInfo.relativeRootFile
116
- ? submitLabel({ relativeRootPath: projectInfo.relativeRootFile })
117
- : genericSubmitLabel, jsx_runtime_1.jsx(ShortcutHint_1.ShortcutHint, { keyToPress: "\u21B5", cmdOrCtrl: true })
127
+ jsx_runtime_1.jsx(DiffPreview_1.CodemodDiffPreview, { status: codemodStatus }), jsx_runtime_1.jsx(layout_1.Flex, {}), jsx_runtime_1.jsx(layout_1.Spacing, { block: true, x: 2 }), jsx_runtime_1.jsxs(ModalButton_1.ModalButton, { onClick: trigger, disabled: disabled, children: [relativeFilePath
128
+ ? submitLabel({ relativeRootPath: relativeFilePath })
129
+ : genericSubmitLabel, jsx_runtime_1.jsx(ShortcutHint_1.ShortcutHint, { keyToPress: "\u21B5", cmdOrCtrl: false })
118
130
  ] })
119
131
  ] }));
120
132
  };
@@ -16,11 +16,13 @@ const content = {
16
16
  minWidth: 500,
17
17
  };
18
18
  const DeleteCompositionLoaded = ({ compositionId }) => {
19
+ var _a;
19
20
  const context = (0, react_1.useContext)(ResolveCompositionBeforeModal_1.ResolvedCompositionContext);
20
21
  if (!context) {
21
22
  throw new Error('Resolved composition context');
22
23
  }
23
24
  const { unresolved } = context;
25
+ const compositionStack = (_a = unresolved.stack) !== null && _a !== void 0 ? _a : null;
24
26
  const codemod = (0, react_1.useMemo)(() => {
25
27
  return {
26
28
  type: 'delete-composition',
@@ -36,7 +38,7 @@ const DeleteCompositionLoaded = ({ compositionId }) => {
36
38
  jsx_runtime_1.jsx("br", {}),
37
39
  "The associated ",
38
40
  jsx_runtime_1.jsx("code", { style: styles_1.inlineCodeSnippet, children: "component" }),
39
- " will remain in your code."] }), jsx_runtime_1.jsx(ModalFooter_1.ModalFooterContainer, { children: jsx_runtime_1.jsx(CodemodFooter_1.CodemodFooter, { errorNotification: `Could not delete composition`, loadingNotification: 'Deleting', successNotification: `Deleted ${unresolved.id}`, genericSubmitLabel: `Delete`, submitLabel: ({ relativeRootPath }) => `Delete from ${relativeRootPath}`, codemod: codemod, valid: true, onSuccess: null }) })
41
+ " will remain in your code."] }), jsx_runtime_1.jsx(ModalFooter_1.ModalFooterContainer, { children: jsx_runtime_1.jsx(CodemodFooter_1.CodemodFooter, { errorNotification: `Could not delete composition`, loadingNotification: 'Deleting', successNotification: `Deleted ${unresolved.id}`, genericSubmitLabel: `Delete`, submitLabel: ({ relativeRootPath }) => `Delete from ${relativeRootPath}`, codemod: codemod, stack: compositionStack, valid: true, onSuccess: null }) })
40
42
  ] })
41
43
  ] }));
42
44
  };
@@ -11,7 +11,7 @@ const CodemodDiffPreview = ({ status }) => {
11
11
  return (jsx_runtime_1.jsx("span", { style: { color: colors_1.FAIL_COLOR, fontSize: 13, lineHeight: 1.2 }, children: status.error }));
12
12
  }
13
13
  return (jsx_runtime_1.jsxs("div", { style: { lineHeight: 1.2 }, children: [
14
- jsx_runtime_1.jsx("span", { style: { color: colors_1.LIGHT_TEXT, fontSize: 13, lineHeight: 1.2 }, children: "This will edit your Root file." }), jsx_runtime_1.jsx("br", {}), jsx_runtime_1.jsxs("span", { style: { color: colors_1.BLUE, fontSize: 13, lineHeight: 1.2 }, children: [status.diff.additions, " addition", status.diff.additions === 1 ? '' : 's', ","] }), ' ', jsx_runtime_1.jsxs("span", { style: {
14
+ jsx_runtime_1.jsx("span", { style: { color: colors_1.LIGHT_TEXT, fontSize: 13, lineHeight: 1.2 }, children: "This will edit your codebase." }), jsx_runtime_1.jsx("br", {}), jsx_runtime_1.jsxs("span", { style: { color: colors_1.BLUE, fontSize: 13, lineHeight: 1.2 }, children: [status.diff.additions, " addition", status.diff.additions === 1 ? '' : 's', ","] }), ' ', jsx_runtime_1.jsxs("span", { style: {
15
15
  color: colors_1.SELECTED_GUIDE,
16
16
  fontSize: 13,
17
17
  lineHeight: 1.2,
@@ -29,11 +29,13 @@ const comboBoxStyle = {
29
29
  width: 190,
30
30
  };
31
31
  const DuplicateCompositionLoaded = ({ initialType }) => {
32
+ var _a;
32
33
  const context = (0, react_1.useContext)(ResolveCompositionBeforeModal_1.ResolvedCompositionContext);
33
34
  if (!context) {
34
35
  throw new Error('Resolved composition context');
35
36
  }
36
37
  const { resolved, unresolved } = context;
38
+ const compositionStack = (_a = unresolved.stack) !== null && _a !== void 0 ? _a : null;
37
39
  const [initialCompType] = (0, react_1.useState)(initialType);
38
40
  const hadDimensionsDefined = unresolved.width && unresolved.height;
39
41
  const hadFpsDefined = unresolved.fps !== undefined;
@@ -199,7 +201,7 @@ const DuplicateCompositionLoaded = ({ initialType }) => {
199
201
  ] })
200
202
  ] })) : null, type === 'composition' && hadDurationDefined ? (jsx_runtime_1.jsx(NewCompDuration_1.NewCompDuration, { durationInFrames: durationInFrames, setDurationInFrames: setDurationInFrames })) : null, type === 'composition' && hadFpsDefined ? (jsx_runtime_1.jsxs("div", { style: layout_2.optionRow, children: [
201
203
  jsx_runtime_1.jsx("div", { style: layout_2.label, children: "FPS" }), jsx_runtime_1.jsx("div", { style: layout_2.rightRow, children: jsx_runtime_1.jsx(InputDragger_1.InputDragger, { type: "number", value: selectedFrameRate, onTextChange: onTextFpsChange, placeholder: "Frame rate (fps)", name: "fps", min: 1, required: true, status: "ok", max: 240, step: 0.01, onValueChange: onFpsChange, rightAlign: false }) })
202
- ] })) : null] }), jsx_runtime_1.jsx(ModalFooter_1.ModalFooterContainer, { children: jsx_runtime_1.jsx(CodemodFooter_1.CodemodFooter, { loadingNotification: 'Duplicating...', errorNotification: 'Could not duplicate composition', successNotification: `Duplicated ${unresolved.id} as ${newId}`, genericSubmitLabel: 'Duplicate', submitLabel: ({ relativeRootPath }) => `Add to ${relativeRootPath}`, codemod: codemod, valid: valid, onSuccess: onDuplicateSuccess }) })
204
+ ] })) : null] }), jsx_runtime_1.jsx(ModalFooter_1.ModalFooterContainer, { children: jsx_runtime_1.jsx(CodemodFooter_1.CodemodFooter, { loadingNotification: 'Duplicating...', errorNotification: 'Could not duplicate composition', successNotification: `Duplicated ${unresolved.id} as ${newId}`, genericSubmitLabel: 'Duplicate', submitLabel: ({ relativeRootPath }) => `Add to ${relativeRootPath}`, codemod: codemod, stack: compositionStack, valid: valid, onSuccess: onDuplicateSuccess }) })
203
205
  ] })
204
206
  ] }));
205
207
  };
@@ -22,11 +22,13 @@ const content = {
22
22
  minWidth: 500,
23
23
  };
24
24
  const RenameCompositionLoaded = () => {
25
+ var _a;
25
26
  const context = (0, react_1.useContext)(ResolveCompositionBeforeModal_1.ResolvedCompositionContext);
26
27
  if (!context) {
27
28
  throw new Error('Resolved composition context');
28
29
  }
29
- const { resolved } = context;
30
+ const { resolved, unresolved } = context;
31
+ const compositionStack = (_a = unresolved.stack) !== null && _a !== void 0 ? _a : null;
30
32
  const { compositions } = (0, react_1.useContext)(remotion_1.Internals.CompositionManager);
31
33
  const [newId, setName] = (0, react_1.useState)(() => {
32
34
  return resolved.result.id;
@@ -55,7 +57,7 @@ const RenameCompositionLoaded = () => {
55
57
  jsx_runtime_1.jsx(RemInput_1.RemotionInput, { value: newId, onChange: onNameChange, type: "text", autoFocus: true, placeholder: "Composition ID", status: "ok", rightAlign: true }), compNameErrMessage ? (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [
56
58
  jsx_runtime_1.jsx(layout_1.Spacing, { y: 1, block: true }), jsx_runtime_1.jsx(ValidationMessage_1.ValidationMessage, { align: "flex-start", message: compNameErrMessage, type: "error" })
57
59
  ] })) : null] }) })
58
- ] }) }), jsx_runtime_1.jsx(ModalFooter_1.ModalFooterContainer, { children: jsx_runtime_1.jsx(CodemodFooter_1.CodemodFooter, { loadingNotification: 'Renaming...', errorNotification: 'Could not rename composition', successNotification: `Renamed to ${newId}`, genericSubmitLabel: 'Rename', submitLabel: ({ relativeRootPath }) => `Modify ${relativeRootPath}`, codemod: codemod, valid: valid, onSuccess: null }) })
60
+ ] }) }), jsx_runtime_1.jsx(ModalFooter_1.ModalFooterContainer, { children: jsx_runtime_1.jsx(CodemodFooter_1.CodemodFooter, { loadingNotification: 'Renaming...', errorNotification: 'Could not rename composition', successNotification: `Renamed to ${newId}`, genericSubmitLabel: 'Rename', submitLabel: ({ relativeRootPath }) => `Modify ${relativeRootPath}`, codemod: codemod, stack: compositionStack, valid: valid, onSuccess: null }) })
59
61
  ] })
60
62
  ] }));
61
63
  };
@@ -97,9 +97,10 @@ export declare const subscribeToFileExistenceWatcher: ({ file, clientId, }: {
97
97
  export declare const openInFileExplorer: ({ directory }: {
98
98
  directory: string;
99
99
  }) => Promise<void>;
100
- export declare const applyCodemod: ({ codemod, dryRun, signal, }: {
100
+ export declare const applyCodemod: ({ codemod, dryRun, symbolicatedStack, signal, }: {
101
101
  codemod: RecastCodemod;
102
102
  dryRun: boolean;
103
+ symbolicatedStack: import("@remotion/studio-shared").SymbolicatedStackFrame | null;
103
104
  signal: AbortSignal;
104
105
  }) => Promise<import("@remotion/studio-shared").ApplyCodemodResponse>;
105
106
  export declare const removeRenderJob: (job: RenderJob) => Promise<undefined>;
@@ -133,10 +133,11 @@ const openInFileExplorer = ({ directory }) => {
133
133
  return (0, call_api_1.callApi)('/api/open-in-file-explorer', body);
134
134
  };
135
135
  exports.openInFileExplorer = openInFileExplorer;
136
- const applyCodemod = ({ codemod, dryRun, signal, }) => {
136
+ const applyCodemod = ({ codemod, dryRun, symbolicatedStack, signal, }) => {
137
137
  const body = {
138
138
  codemod,
139
139
  dryRun,
140
+ symbolicatedStack,
140
141
  };
141
142
  return (0, call_api_1.callApi)('/api/apply-codemod', body, signal);
142
143
  };
@@ -6,6 +6,9 @@ const react_1 = require("react");
6
6
  const remotion_1 = require("remotion");
7
7
  const client_id_1 = require("../../helpers/client-id");
8
8
  const timeline_layout_1 = require("../../helpers/timeline-layout");
9
+ const call_api_1 = require("../call-api");
10
+ const ContextMenu_1 = require("../ContextMenu");
11
+ const NotificationCenter_1 = require("../Notifications/NotificationCenter");
9
12
  const save_effect_prop_1 = require("./save-effect-prop");
10
13
  const TimelineExpandArrowButton_1 = require("./TimelineExpandArrowButton");
11
14
  const TimelineLayerEye_1 = require("./TimelineLayerEye");
@@ -37,6 +40,54 @@ const TimelineEffectGroupRow = ({ label, nodePathInfo, effectIndex, effectSchema
37
40
  return false;
38
41
  }, [disabledStatus]);
39
42
  const canToggle = previewConnected && disabledStatus !== null && disabledStatus.canUpdate;
43
+ const deleteDisabled = !previewConnected ||
44
+ effectStatus.type !== 'can-update-effect' ||
45
+ !validatedLocation.source;
46
+ const onDeleteEffectFromSource = (0, react_1.useCallback)(async () => {
47
+ if (deleteDisabled) {
48
+ return;
49
+ }
50
+ try {
51
+ const result = await (0, call_api_1.callApi)('/api/delete-effect', {
52
+ fileName: validatedLocation.source,
53
+ sequenceNodePath: nodePath,
54
+ effectIndex,
55
+ });
56
+ if (result.success) {
57
+ (0, NotificationCenter_1.showNotification)('Removed effect from source file', 2000);
58
+ }
59
+ else {
60
+ (0, NotificationCenter_1.showNotification)(result.reason, 4000);
61
+ }
62
+ }
63
+ catch (err) {
64
+ (0, NotificationCenter_1.showNotification)(err.message, 4000);
65
+ }
66
+ }, [deleteDisabled, effectIndex, nodePath, validatedLocation.source]);
67
+ const contextMenuValues = (0, react_1.useMemo)(() => {
68
+ if (!previewConnected) {
69
+ return [];
70
+ }
71
+ return [
72
+ {
73
+ type: 'item',
74
+ id: 'delete-effect',
75
+ keyHint: null,
76
+ label: 'Delete',
77
+ leftItem: null,
78
+ disabled: deleteDisabled,
79
+ onClick: () => {
80
+ if (deleteDisabled) {
81
+ return;
82
+ }
83
+ onDeleteEffectFromSource();
84
+ },
85
+ quickSwitcherLabel: null,
86
+ subMenu: null,
87
+ value: 'delete-effect',
88
+ },
89
+ ];
90
+ }, [deleteDisabled, onDeleteEffectFromSource, previewConnected]);
40
91
  const onToggle = (0, react_1.useCallback)((type) => {
41
92
  if (!canToggle || previewServerState.type !== 'connected') {
42
93
  return;
@@ -71,6 +122,7 @@ const TimelineEffectGroupRow = ({ label, nodePathInfo, effectIndex, effectSchema
71
122
  height: timeline_layout_1.TREE_GROUP_ROW_HEIGHT,
72
123
  paddingRight: timeline_layout_1.EXPANDED_SECTION_PADDING_RIGHT,
73
124
  }), []);
74
- return (jsx_runtime_1.jsx(TimelineRowChrome_1.TimelineRowChrome, { depth: rowDepth, eye: canToggle ? (jsx_runtime_1.jsx(TimelineLayerEye_1.TimelineLayerEye, { type: "effect", hidden: isDisabled, onInvoked: onToggle })) : (jsx_runtime_1.jsx(TimelineLayerEye_1.TimelineLayerEyeSpacer, {})), arrow: jsx_runtime_1.jsx(TimelineExpandArrowButton_1.TimelineExpandArrowButton, { isExpanded: isExpanded, onClick: () => toggleTrack(nodePathInfo), label: `${label} section`, disabled: false }), style: rowStyle, children: jsx_runtime_1.jsx("span", { style: rowLabel, children: label }) }));
125
+ const row = (jsx_runtime_1.jsx(TimelineRowChrome_1.TimelineRowChrome, { depth: rowDepth, eye: canToggle ? (jsx_runtime_1.jsx(TimelineLayerEye_1.TimelineLayerEye, { type: "effect", hidden: isDisabled, onInvoked: onToggle })) : (jsx_runtime_1.jsx(TimelineLayerEye_1.TimelineLayerEyeSpacer, {})), arrow: jsx_runtime_1.jsx(TimelineExpandArrowButton_1.TimelineExpandArrowButton, { isExpanded: isExpanded, onClick: () => toggleTrack(nodePathInfo), label: `${label} section`, disabled: false }), style: rowStyle, children: jsx_runtime_1.jsx("span", { style: rowLabel, children: label }) }));
126
+ return previewConnected ? (jsx_runtime_1.jsx(ContextMenu_1.ContextMenu, { values: contextMenuValues, children: row })) : (row);
75
127
  };
76
128
  exports.TimelineEffectGroupRow = TimelineEffectGroupRow;
@@ -7,14 +7,13 @@ const remotion_1 = require("remotion");
7
7
  const colors_1 = require("../../helpers/colors");
8
8
  const timeline_layout_1 = require("../../helpers/timeline-layout");
9
9
  const render_frame_1 = require("../../state/render-frame");
10
- const SplitterHandle_1 = require("../Splitter/SplitterHandle");
11
10
  const TimeValue_1 = require("../TimeValue");
12
11
  const timeline_refs_1 = require("./timeline-refs");
13
12
  const timeline_scroll_logic_1 = require("./timeline-scroll-logic");
14
13
  const TimelineWidthProvider_1 = require("./TimelineWidthProvider");
15
14
  exports.TIMELINE_TIME_INDICATOR_HEIGHT = 39;
16
15
  const container = {
17
- height: exports.TIMELINE_TIME_INDICATOR_HEIGHT - 4,
16
+ height: exports.TIMELINE_TIME_INDICATOR_HEIGHT,
18
17
  boxShadow: `0 0 4px ${colors_1.TIMELINE_BACKGROUND}`,
19
18
  position: 'absolute',
20
19
  backgroundColor: colors_1.TIMELINE_BACKGROUND,
@@ -94,10 +93,8 @@ const TimelineTimeIndicatorsInner = ({ windowWidth, durationInFrames, fps }) =>
94
93
  const style = (0, react_1.useMemo)(() => {
95
94
  return {
96
95
  ...container,
97
- width: windowWidth - SplitterHandle_1.SPLITTER_HANDLE_SIZE / 2,
96
+ width: windowWidth,
98
97
  overflow: 'hidden',
99
- // Since
100
- marginLeft: SplitterHandle_1.SPLITTER_HANDLE_SIZE / 2,
101
98
  pointerEvents: 'none',
102
99
  };
103
100
  }, [windowWidth]);
@@ -119,9 +116,7 @@ const TimelineTimeIndicatorsInner = ({ windowWidth, durationInFrames, fps }) =>
119
116
  frame: index * fps,
120
117
  style: {
121
118
  ...secondTick,
122
- left: frameInterval * index * fps +
123
- timeline_layout_1.TIMELINE_PADDING -
124
- SplitterHandle_1.SPLITTER_HANDLE_SIZE / 2,
119
+ left: frameInterval * index * fps + timeline_layout_1.TIMELINE_PADDING,
125
120
  },
126
121
  showTime: index > 0,
127
122
  };
@@ -134,9 +129,7 @@ const TimelineTimeIndicatorsInner = ({ windowWidth, durationInFrames, fps }) =>
134
129
  frame: index,
135
130
  style: {
136
131
  ...tick,
137
- left: frameInterval * index +
138
- timeline_layout_1.TIMELINE_PADDING -
139
- SplitterHandle_1.SPLITTER_HANDLE_SIZE / 2,
132
+ left: frameInterval * index + timeline_layout_1.TIMELINE_PADDING,
140
133
  height: index % fps === 0
141
134
  ? 10
142
135
  : (index / frameMarkerEveryNth) % 2 === 0
@@ -7,6 +7,7 @@ const react_1 = require("react");
7
7
  const remotion_1 = require("remotion");
8
8
  const timeline_layout_1 = require("../../helpers/timeline-layout");
9
9
  const AudioWaveform_1 = require("../AudioWaveform");
10
+ const get_timeline_video_info_widths_1 = require("./get-timeline-video-info-widths");
10
11
  const FILMSTRIP_HEIGHT = timeline_layout_1.TIMELINE_LAYER_HEIGHT_IMAGE - 2;
11
12
  const outerStyle = {
12
13
  width: '100%',
@@ -16,7 +17,6 @@ const outerStyle = {
16
17
  };
17
18
  const filmstripContainerStyle = {
18
19
  height: FILMSTRIP_HEIGHT,
19
- width: '100%',
20
20
  backgroundColor: 'rgba(0, 0, 0, 0.3)',
21
21
  display: 'flex',
22
22
  borderTopLeftRadius: 2,
@@ -28,6 +28,14 @@ const TimelineVideoInfo = ({ src, visualizationWidth, naturalWidth, trimBefore,
28
28
  const ref = (0, react_1.useRef)(null);
29
29
  const [error, setError] = (0, react_1.useState)(null);
30
30
  const aspectRatio = (0, react_1.useRef)((0, timeline_utils_1.getAspectRatioFromCache)(src));
31
+ const { mediaVisualizationWidth, mediaNaturalWidth } = (0, react_1.useMemo)(() => {
32
+ return (0, get_timeline_video_info_widths_1.getTimelineVideoInfoWidths)({
33
+ visualizationWidth,
34
+ naturalWidth,
35
+ premountWidth,
36
+ postmountWidth,
37
+ });
38
+ }, [naturalWidth, postmountWidth, premountWidth, visualizationWidth]);
31
39
  // for rendering frames
32
40
  (0, react_1.useEffect)(() => {
33
41
  if (error) {
@@ -39,7 +47,7 @@ const TimelineVideoInfo = ({ src, visualizationWidth, naturalWidth, trimBefore,
39
47
  }
40
48
  const controller = new AbortController();
41
49
  const canvas = document.createElement('canvas');
42
- canvas.width = visualizationWidth;
50
+ canvas.width = mediaVisualizationWidth;
43
51
  canvas.height = FILMSTRIP_HEIGHT;
44
52
  const ctx = canvas.getContext('2d');
45
53
  if (!ctx) {
@@ -47,7 +55,7 @@ const TimelineVideoInfo = ({ src, visualizationWidth, naturalWidth, trimBefore,
47
55
  }
48
56
  current.appendChild(canvas);
49
57
  const loopWidth = (0, timeline_utils_1.getLoopDisplayWidth)({
50
- visualizationWidth: naturalWidth,
58
+ visualizationWidth: mediaNaturalWidth,
51
59
  loopDisplay,
52
60
  });
53
61
  const shouldRepeatVideo = (0, timeline_utils_1.shouldTileLoopDisplay)(loopDisplay);
@@ -85,7 +93,9 @@ const TimelineVideoInfo = ({ src, visualizationWidth, naturalWidth, trimBefore,
85
93
  // Trim is applied first, then playbackRate. Each composition frame
86
94
  // advances the source video by `playbackRate` source frames.
87
95
  const toSeconds = fromSeconds + (visibleDurationInFrames * playbackRate) / fps;
88
- const targetWidth = shouldRepeatVideo ? targetCanvas.width : naturalWidth;
96
+ const targetWidth = shouldRepeatVideo
97
+ ? targetCanvas.width
98
+ : mediaNaturalWidth;
89
99
  if (aspectRatio.current !== null) {
90
100
  (0, timeline_utils_1.ensureSlots)({
91
101
  filledSlots,
@@ -207,13 +217,20 @@ const TimelineVideoInfo = ({ src, visualizationWidth, naturalWidth, trimBefore,
207
217
  error,
208
218
  fps,
209
219
  loopDisplay,
210
- naturalWidth,
220
+ mediaNaturalWidth,
221
+ mediaVisualizationWidth,
211
222
  playbackRate,
212
223
  src,
213
224
  trimBefore,
214
- visualizationWidth,
215
225
  ]);
216
- const audioWidth = visualizationWidth - premountWidth - postmountWidth;
226
+ const audioWidth = mediaVisualizationWidth;
227
+ const filmstripStyle = (0, react_1.useMemo)(() => {
228
+ return {
229
+ ...filmstripContainerStyle,
230
+ width: mediaVisualizationWidth,
231
+ marginLeft: premountWidth,
232
+ };
233
+ }, [mediaVisualizationWidth, premountWidth]);
217
234
  const audioStyle = (0, react_1.useMemo)(() => {
218
235
  return {
219
236
  height: timeline_layout_1.TIMELINE_LAYER_HEIGHT_AUDIO,
@@ -223,7 +240,7 @@ const TimelineVideoInfo = ({ src, visualizationWidth, naturalWidth, trimBefore,
223
240
  };
224
241
  }, [audioWidth, premountWidth]);
225
242
  return (jsx_runtime_1.jsxs("div", { style: outerStyle, children: [
226
- jsx_runtime_1.jsx("div", { ref: ref, style: filmstripContainerStyle }), jsx_runtime_1.jsx("div", { style: audioStyle, children: jsx_runtime_1.jsx(AudioWaveform_1.AudioWaveform, { src: src, visualizationWidth: audioWidth, startFrom: trimBefore, durationInFrames: durationInFrames, volume: volume, doesVolumeChange: doesVolumeChange, playbackRate: playbackRate, loopDisplay: loopDisplay }) })
243
+ jsx_runtime_1.jsx("div", { ref: ref, style: filmstripStyle }), jsx_runtime_1.jsx("div", { style: audioStyle, children: jsx_runtime_1.jsx(AudioWaveform_1.AudioWaveform, { src: src, visualizationWidth: audioWidth, startFrom: trimBefore, durationInFrames: durationInFrames, volume: volume, doesVolumeChange: doesVolumeChange, playbackRate: playbackRate, loopDisplay: loopDisplay }) })
227
244
  ] }));
228
245
  };
229
246
  exports.TimelineVideoInfo = TimelineVideoInfo;
@@ -0,0 +1,9 @@
1
+ export declare const getTimelineVideoInfoWidths: ({ visualizationWidth, naturalWidth, premountWidth, postmountWidth, }: {
2
+ visualizationWidth: number;
3
+ naturalWidth: number;
4
+ premountWidth: number;
5
+ postmountWidth: number;
6
+ }) => {
7
+ mediaVisualizationWidth: number;
8
+ mediaNaturalWidth: number;
9
+ };
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getTimelineVideoInfoWidths = void 0;
4
+ const getTimelineVideoInfoWidths = ({ visualizationWidth, naturalWidth, premountWidth, postmountWidth, }) => {
5
+ const mountWidth = premountWidth + postmountWidth;
6
+ return {
7
+ mediaVisualizationWidth: Math.max(0, visualizationWidth - mountWidth),
8
+ mediaNaturalWidth: Math.max(0, naturalWidth - mountWidth),
9
+ };
10
+ };
11
+ exports.getTimelineVideoInfoWidths = getTimelineVideoInfoWidths;
@@ -1,2 +1,3 @@
1
1
  import type { ResolvedStackLocation } from 'remotion';
2
+ export declare const hasResolvedStack: (stack: string | null) => boolean;
2
3
  export declare const useResolvedStack: (stack: string | null) => ResolvedStackLocation | null;
@@ -1,10 +1,17 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.useResolvedStack = void 0;
3
+ exports.useResolvedStack = exports.hasResolvedStack = void 0;
4
4
  const react_1 = require("react");
5
5
  const remotion_1 = require("remotion");
6
6
  const get_stack_1 = require("./TimelineStack/get-stack");
7
7
  const resolvedCache = new Map();
8
+ const hasResolvedStack = (stack) => {
9
+ if (!stack) {
10
+ return true;
11
+ }
12
+ return resolvedCache.has(stack);
13
+ };
14
+ exports.hasResolvedStack = hasResolvedStack;
8
15
  const inFlight = new Set();
9
16
  const subscribers = new Map();
10
17
  const useResolvedStack = (stack) => {
@@ -40,6 +47,8 @@ const useResolvedStack = (stack) => {
40
47
  .catch((err) => {
41
48
  // eslint-disable-next-line no-console
42
49
  console.error('Could not get original location of Sequence', err);
50
+ resolvedCache.set(stack, null);
51
+ subs.forEach((fn) => fn(null));
43
52
  })
44
53
  .finally(() => {
45
54
  inFlight.delete(stack);