@remotion/studio 4.0.445 → 4.0.446

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.
@@ -44,6 +44,7 @@ const no_react_1 = require("remotion/no-react");
44
44
  const colors_1 = require("../helpers/colors");
45
45
  const copy_text_1 = require("../helpers/copy-text");
46
46
  const mobile_layout_1 = require("../helpers/mobile-layout");
47
+ const sidebar_scroll_into_view_1 = require("../helpers/sidebar-scroll-into-view");
47
48
  const url_state_1 = require("../helpers/url-state");
48
49
  const use_asset_drag_events_1 = __importDefault(require("../helpers/use-asset-drag-events"));
49
50
  const clipboard_1 = require("../icons/clipboard");
@@ -173,7 +174,16 @@ const AssetSelectorItem = ({ item, tabIndex, level, parentFolder, readOnlyStudio
173
174
  const onPointerLeave = (0, react_1.useCallback)(() => {
174
175
  setHovered(false);
175
176
  }, []);
177
+ const rowRef = (0, react_1.useRef)(null);
178
+ (0, react_1.useLayoutEffect)(() => {
179
+ (0, sidebar_scroll_into_view_1.maybeScrollAssetSidebarRowIntoView)({
180
+ element: rowRef.current,
181
+ assetPath: relativePath,
182
+ selected,
183
+ });
184
+ }, [relativePath, selected]);
176
185
  const onClick = (0, react_1.useCallback)(() => {
186
+ (0, sidebar_scroll_into_view_1.markAssetSidebarScrollFromRowClick)(relativePath);
177
187
  setCanvasContent({ type: 'asset', asset: relativePath });
178
188
  (0, url_state_1.pushUrl)(`/assets/${relativePath}`);
179
189
  if (isMobileLayout) {
@@ -234,7 +244,7 @@ const AssetSelectorItem = ({ item, tabIndex, level, parentFolder, readOnlyStudio
234
244
  (0, NotificationCenter_1.showNotification)(`Could not copy: ${err.message}`, 2000);
235
245
  });
236
246
  }, [item.name, parentFolder]);
237
- return (jsx_runtime_1.jsx(layout_1.Row, { align: "center", children: jsx_runtime_1.jsxs("div", { style: style, onPointerEnter: onPointerEnter, onPointerLeave: onPointerLeave, onClick: onClick, tabIndex: tabIndex, title: item.name, children: [
247
+ return (jsx_runtime_1.jsx(layout_1.Row, { align: "center", children: jsx_runtime_1.jsxs("div", { ref: rowRef, style: style, onPointerEnter: onPointerEnter, onPointerLeave: onPointerLeave, onClick: onClick, tabIndex: tabIndex, title: item.name, children: [
238
248
  jsx_runtime_1.jsx(file_1.FileIcon, { style: iconStyle, color: colors_1.LIGHT_TEXT }), jsx_runtime_1.jsx(layout_1.Spacing, { x: 1 }), jsx_runtime_1.jsx("div", { style: label, children: item.name }), hovered ? (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [
239
249
  jsx_runtime_1.jsx(layout_1.Spacing, { x: 0.5 }), jsx_runtime_1.jsx(InlineAction_1.InlineAction, { title: "Copy staticFile() name", renderAction: renderCopyAction, onClick: copyToClipboard }), readOnlyStudio ? null : (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [
240
250
  jsx_runtime_1.jsx(layout_1.Spacing, { x: 0.5 }), jsx_runtime_1.jsx(InlineAction_1.InlineAction, { title: "Open in Explorer", renderAction: renderFileExplorerAction, onClick: revealInExplorer })
@@ -418,6 +418,6 @@ const Canvas = ({ canvasContent, size }) => {
418
418
  fetchMetadata();
419
419
  }, [fetchMetadata]);
420
420
  return (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [
421
- jsx_runtime_1.jsxs("div", { ref: canvas_ref_1.canvasRef, style: getContainerStyle(editorZoomGestures), children: [size ? (jsx_runtime_1.jsx(Preview_1.VideoPreview, { canvasContent: canvasContent, contentDimensions: contentDimensions, canvasSize: size, assetMetadata: assetResolution })) : null, isFit ? null : (jsx_runtime_1.jsx("div", { style: resetZoom, className: "css-reset", children: jsx_runtime_1.jsx(ResetZoomButton_1.ResetZoomButton, { onClick: onReset }) })), editorShowGuides && canvasContent.type === 'composition' && (jsx_runtime_1.jsx(EditorGuides_1.default, { canvasSize: size, contentDimensions: contentDimensions, assetMetadata: assetResolution }))] }), areRulersVisible && (jsx_runtime_1.jsx(EditorRuler_1.EditorRulers, { contentDimensions: contentDimensions, canvasSize: size, assetMetadata: assetResolution, containerRef: canvas_ref_1.canvasRef }))] }));
421
+ jsx_runtime_1.jsxs("div", { ref: canvas_ref_1.canvasRef, style: getContainerStyle(editorZoomGestures), children: [size ? (jsx_runtime_1.jsx(Preview_1.VideoPreview, { canvasContent: canvasContent, contentDimensions: contentDimensions, canvasSize: size, assetMetadata: assetResolution, onRetryAssetMetadata: fetchMetadata })) : null, isFit ? null : (jsx_runtime_1.jsx("div", { style: resetZoom, className: "css-reset", children: jsx_runtime_1.jsx(ResetZoomButton_1.ResetZoomButton, { onClick: onReset }) })), editorShowGuides && canvasContent.type === 'composition' && (jsx_runtime_1.jsx(EditorGuides_1.default, { canvasSize: size, contentDimensions: contentDimensions, assetMetadata: assetResolution }))] }), areRulersVisible && (jsx_runtime_1.jsx(EditorRuler_1.EditorRulers, { contentDimensions: contentDimensions, canvasSize: size, assetMetadata: assetResolution, containerRef: canvas_ref_1.canvasRef }))] }));
422
422
  };
423
423
  exports.Canvas = Canvas;
@@ -45,7 +45,7 @@ const CanvasOrLoading = ({ size }) => {
45
45
  });
46
46
  }, [resolved, setZoom]);
47
47
  if (renderError) {
48
- return jsx_runtime_1.jsx(ErrorLoading, { error: renderError });
48
+ return (jsx_runtime_1.jsx(ErrorLoading, { error: renderError, calculateMetadataContext: false }));
49
49
  }
50
50
  if (!canvasContent) {
51
51
  const compname = window.location.pathname.replace('/', '');
@@ -65,7 +65,7 @@ const CanvasOrLoading = ({ size }) => {
65
65
  return (jsx_runtime_1.jsx("div", { style: container, className: "css-reset", children: jsx_runtime_1.jsx(RunningCalculateMetadata_1.RunningCalculateMetadata, {}) }));
66
66
  }
67
67
  if (resolved.type === 'error') {
68
- return jsx_runtime_1.jsx(ErrorLoading, { error: resolved.error });
68
+ return jsx_runtime_1.jsx(ErrorLoading, { error: resolved.error, calculateMetadataContext: true });
69
69
  }
70
70
  return (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [
71
71
  jsx_runtime_1.jsx(FramePersistor_1.FramePersistor, {}),
@@ -80,9 +80,9 @@ const loaderContainer = {
80
80
  height: '100%',
81
81
  overflowY: 'auto',
82
82
  };
83
- const ErrorLoading = ({ error }) => {
83
+ const ErrorLoading = ({ error, calculateMetadataContext }) => {
84
84
  return (jsx_runtime_1.jsx("div", { style: loaderContainer, className: is_menu_item_1.VERTICAL_SCROLLBAR_CLASSNAME, children: jsx_runtime_1.jsx(ErrorLoader_1.ErrorLoader, { canHaveDismissButton: false, keyboardShortcuts: false, error: error, onRetry: () => {
85
85
  var _a;
86
86
  return (_a = remotion_1.Internals.resolveCompositionsRef.current) === null || _a === void 0 ? void 0 : _a.reloadCurrentlySelectedComposition();
87
- }, calculateMetadata: true }, error.stack) }));
87
+ }, calculateMetadata: calculateMetadataContext }, error.stack) }));
88
88
  };
@@ -5,6 +5,7 @@ const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const react_1 = require("react");
6
6
  const colors_1 = require("../helpers/colors");
7
7
  const is_composition_still_1 = require("../helpers/is-composition-still");
8
+ const sidebar_scroll_into_view_1 = require("../helpers/sidebar-scroll-into-view");
8
9
  const folder_1 = require("../icons/folder");
9
10
  const still_1 = require("../icons/still");
10
11
  const video_1 = require("../icons/video");
@@ -61,6 +62,18 @@ const CompositionSelectorItem = ({ item, level, currentComposition, tabIndex, se
61
62
  const onPointerLeave = (0, react_1.useCallback)(() => {
62
63
  setHovered(false);
63
64
  }, []);
65
+ const compositionRowRef = (0, react_1.useRef)(null);
66
+ const compositionId = item.type === 'composition' ? item.composition.id : null;
67
+ (0, react_1.useLayoutEffect)(() => {
68
+ if (compositionId === null) {
69
+ return;
70
+ }
71
+ (0, sidebar_scroll_into_view_1.maybeScrollCompositionSidebarRowIntoView)({
72
+ element: compositionRowRef.current,
73
+ compositionId,
74
+ selected,
75
+ });
76
+ }, [compositionId, selected]);
64
77
  const style = (0, react_1.useMemo)(() => {
65
78
  return {
66
79
  ...itemStyle,
@@ -77,6 +90,7 @@ const CompositionSelectorItem = ({ item, level, currentComposition, tabIndex, se
77
90
  const onClick = (0, react_1.useCallback)((evt) => {
78
91
  evt.preventDefault();
79
92
  if (item.type === 'composition') {
93
+ (0, sidebar_scroll_into_view_1.markCompositionSidebarScrollFromRowClick)(item.composition.id);
80
94
  selectComposition(item.composition, true);
81
95
  }
82
96
  else {
@@ -180,7 +194,7 @@ const CompositionSelectorItem = ({ item, level, currentComposition, tabIndex, se
180
194
  })
181
195
  : null] }));
182
196
  }
183
- return (jsx_runtime_1.jsx(ContextMenu_1.ContextMenu, { values: contextMenu, children: jsx_runtime_1.jsx(layout_1.Row, { align: "center", children: jsx_runtime_1.jsxs("a", { style: style, onPointerEnter: onPointerEnter, onPointerLeave: onPointerLeave, tabIndex: tabIndex, onClick: onClick, onKeyPress: onKeyPress, type: "button", title: item.composition.id, className: "__remotion-composition", "data-compname": item.composition.id, children: [(0, is_composition_still_1.isCompositionStill)(item.composition) ? (jsx_runtime_1.jsx(still_1.StillIcon, { color: hovered || selected ? 'white' : colors_1.LIGHT_TEXT, style: iconStyle })) : (jsx_runtime_1.jsx(video_1.FilmIcon, { color: hovered || selected ? 'white' : colors_1.LIGHT_TEXT, style: iconStyle })), jsx_runtime_1.jsx(layout_1.Spacing, { x: 1 }), jsx_runtime_1.jsx("div", { style: label, children: item.composition.id }), jsx_runtime_1.jsx(layout_1.Spacing, { x: 0.5 }), jsx_runtime_1.jsx(CompositionContextButton_1.CompositionContextButton, { values: contextMenu, visible: hovered }), jsx_runtime_1.jsx(SidebarRenderButton_1.SidebarRenderButton, { visible: hovered, composition: item.composition })
197
+ return (jsx_runtime_1.jsx(ContextMenu_1.ContextMenu, { values: contextMenu, children: jsx_runtime_1.jsx(layout_1.Row, { align: "center", children: jsx_runtime_1.jsxs("a", { ref: compositionRowRef, style: style, onPointerEnter: onPointerEnter, onPointerLeave: onPointerLeave, tabIndex: tabIndex, onClick: onClick, onKeyPress: onKeyPress, type: "button", title: item.composition.id, className: "__remotion-composition", "data-compname": item.composition.id, children: [(0, is_composition_still_1.isCompositionStill)(item.composition) ? (jsx_runtime_1.jsx(still_1.StillIcon, { color: hovered || selected ? 'white' : colors_1.LIGHT_TEXT, style: iconStyle })) : (jsx_runtime_1.jsx(video_1.FilmIcon, { color: hovered || selected ? 'white' : colors_1.LIGHT_TEXT, style: iconStyle })), jsx_runtime_1.jsx(layout_1.Spacing, { x: 1 }), jsx_runtime_1.jsx("div", { style: label, children: item.composition.id }), jsx_runtime_1.jsx(layout_1.Spacing, { x: 0.5 }), jsx_runtime_1.jsx(CompositionContextButton_1.CompositionContextButton, { values: contextMenu, visible: hovered }), jsx_runtime_1.jsx(SidebarRenderButton_1.SidebarRenderButton, { visible: hovered, composition: item.composition })
184
198
  ] }) }) }));
185
199
  };
186
200
  exports.CompositionSelectorItem = CompositionSelectorItem;
@@ -20,6 +20,9 @@ const FilePreview = ({ fileType, src, currentAsset, assetMetadata }) => {
20
20
  if (assetMetadata.type === 'not-found') {
21
21
  throw new Error('expected to have assetMetadata, got "not-found"');
22
22
  }
23
+ if (assetMetadata.type === 'metadata-error') {
24
+ throw new Error('unexpected metadata-error in FilePreview');
25
+ }
23
26
  if (fileType === 'audio') {
24
27
  return jsx_runtime_1.jsx("audio", { src: src, controls: true });
25
28
  }
@@ -14,7 +14,7 @@ const use_static_files_1 = require("./use-static-files");
14
14
  const useSelectAsset = () => {
15
15
  const { setCanvasContent } = (0, react_1.useContext)(remotion_1.Internals.CompositionSetters);
16
16
  const { setAssetFoldersExpanded } = (0, react_1.useContext)(folders_1.FolderContext);
17
- return (asset) => {
17
+ return (0, react_1.useCallback)((asset) => {
18
18
  var _a;
19
19
  setCanvasContent({ type: 'asset', asset });
20
20
  (_a = ExplorerPanel_1.explorerSidebarTabs.current) === null || _a === void 0 ? void 0 : _a.selectAssetsPanel();
@@ -31,7 +31,7 @@ const useSelectAsset = () => {
31
31
  }
32
32
  return newState;
33
33
  });
34
- };
34
+ }, [setAssetFoldersExpanded, setCanvasContent]);
35
35
  };
36
36
  exports.useSelectAsset = useSelectAsset;
37
37
  const useSelectComposition = () => {
@@ -134,7 +134,7 @@ const InitialCompositionLoader = () => {
134
134
  return file.name === newCanvas.asset;
135
135
  });
136
136
  if (exists) {
137
- setCanvasContent(newCanvas);
137
+ selectAsset(newCanvas.asset);
138
138
  }
139
139
  return;
140
140
  }
@@ -142,7 +142,13 @@ const InitialCompositionLoader = () => {
142
142
  };
143
143
  window.addEventListener('popstate', onchange);
144
144
  return () => window.removeEventListener('popstate', onchange);
145
- }, [compositions, selectComposition, setCanvasContent, staticFiles]);
145
+ }, [
146
+ compositions,
147
+ selectAsset,
148
+ selectComposition,
149
+ setCanvasContent,
150
+ staticFiles,
151
+ ]);
146
152
  return null;
147
153
  };
148
154
  exports.InitialCompositionLoader = InitialCompositionLoader;
@@ -10,4 +10,5 @@ export declare const VideoPreview: React.FC<{
10
10
  readonly contentDimensions: Dimensions | 'none' | null;
11
11
  readonly canvasContent: CanvasContent;
12
12
  readonly assetMetadata: AssetMetadata | null;
13
+ readonly onRetryAssetMetadata?: () => void;
13
14
  }>;
@@ -5,9 +5,11 @@ const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const player_1 = require("@remotion/player");
6
6
  const react_1 = require("react");
7
7
  const remotion_1 = require("remotion");
8
+ const ErrorLoader_1 = require("../error-overlay/remotion-overlay/ErrorLoader");
8
9
  const checkerboard_background_1 = require("../helpers/checkerboard-background");
9
10
  const colors_1 = require("../helpers/colors");
10
11
  const checkerboard_1 = require("../state/checkerboard");
12
+ const is_menu_item_1 = require("./Menu/is-menu-item");
11
13
  const RenderPreview_1 = require("./RenderPreview");
12
14
  const Spinner_1 = require("./Spinner");
13
15
  const StaticFilePreview_1 = require("./StaticFilePreview");
@@ -22,6 +24,14 @@ const label = {
22
24
  fontSize: 14,
23
25
  color: colors_1.LIGHT_TEXT,
24
26
  };
27
+ const assetMetadataErrorContainer = {
28
+ marginLeft: 'auto',
29
+ marginRight: 'auto',
30
+ width: '100%',
31
+ position: 'absolute',
32
+ height: '100%',
33
+ overflowY: 'auto',
34
+ };
25
35
  const getPreviewFileType = (fileName) => {
26
36
  var _a;
27
37
  if (!fileName) {
@@ -68,10 +78,13 @@ const containerStyle = (options) => {
68
78
  backgroundPosition: (0, checkerboard_background_1.getCheckerboardBackgroundPos)(checkerboardSize) /* Must be half of one side of the square */,
69
79
  };
70
80
  };
71
- const VideoPreview = ({ canvasSize, contentDimensions, canvasContent, assetMetadata }) => {
81
+ const VideoPreview = ({ canvasSize, contentDimensions, canvasContent, assetMetadata, onRetryAssetMetadata, }) => {
72
82
  if (assetMetadata && assetMetadata.type === 'not-found') {
73
83
  return (jsx_runtime_1.jsx("div", { style: centeredContainer, children: jsx_runtime_1.jsx("div", { style: label, children: "File does not exist" }) }));
74
84
  }
85
+ if (assetMetadata && assetMetadata.type === 'metadata-error') {
86
+ return (jsx_runtime_1.jsx("div", { style: assetMetadataErrorContainer, className: is_menu_item_1.VERTICAL_SCROLLBAR_CLASSNAME, children: jsx_runtime_1.jsx(ErrorLoader_1.ErrorLoader, { canHaveDismissButton: false, keyboardShortcuts: false, error: assetMetadata.error, onRetry: onRetryAssetMetadata !== null && onRetryAssetMetadata !== void 0 ? onRetryAssetMetadata : null, calculateMetadata: false }, assetMetadata.error.stack) }));
87
+ }
75
88
  if (contentDimensions === null) {
76
89
  return (jsx_runtime_1.jsx("div", { style: centeredContainer, children: jsx_runtime_1.jsx(Spinner_1.Spinner, { duration: 0.5, size: 24 }) }));
77
90
  }
@@ -48,7 +48,7 @@ const TimelineListItem = ({ nestedDepth, sequence, isCompact }) => {
48
48
  const { hidden, setHidden } = (0, react_1.useContext)(remotion_1.Internals.SequenceVisibilityToggleContext);
49
49
  const { expandedTracks, toggleTrack } = (0, react_1.useContext)(ExpandedTracksProvider_1.ExpandedTracksContext);
50
50
  const originalLocation = (0, use_resolved_stack_1.useResolvedStack)((_a = sequence.stack) !== null && _a !== void 0 ? _a : null);
51
- const nodePath = (0, use_sequence_props_subscription_1.useSequencePropsSubscription)(sequence, originalLocation, visualModeActive);
51
+ const { nodePath, jsxInMapCallback } = (0, use_sequence_props_subscription_1.useSequencePropsSubscription)(sequence, originalLocation, visualModeActive);
52
52
  const validatedLocation = (0, react_1.useMemo)(() => {
53
53
  var _a;
54
54
  if (!originalLocation ||
@@ -64,6 +64,34 @@ const TimelineListItem = ({ nestedDepth, sequence, isCompact }) => {
64
64
  }, [originalLocation]);
65
65
  const canDeleteFromSource = Boolean(nodePath && (validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.source));
66
66
  const deleteDisabled = (0, react_1.useMemo)(() => !previewConnected || !sequence.controls || !canDeleteFromSource, [previewConnected, sequence.controls, canDeleteFromSource]);
67
+ const duplicateDisabled = deleteDisabled;
68
+ const onDuplicateSequenceFromSource = (0, react_1.useCallback)(async () => {
69
+ if (!(validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.source) || !nodePath) {
70
+ return;
71
+ }
72
+ if (jsxInMapCallback) {
73
+ const message = 'This sequence is rendered inside a .map() callback. Duplicating inserts another copy in that callback (affecting each list item). Continue?';
74
+ // eslint-disable-next-line no-alert -- native confirm before applying duplicate codemod in .map callbacks
75
+ if (!window.confirm(message)) {
76
+ return;
77
+ }
78
+ }
79
+ try {
80
+ const result = await (0, call_api_1.callApi)('/api/duplicate-jsx-node', {
81
+ fileName: validatedLocation.source,
82
+ nodePath,
83
+ });
84
+ if (result.success) {
85
+ (0, NotificationCenter_1.showNotification)('Duplicated sequence in source file', 2000);
86
+ }
87
+ else {
88
+ (0, NotificationCenter_1.showNotification)(result.reason, 4000);
89
+ }
90
+ }
91
+ catch (err) {
92
+ (0, NotificationCenter_1.showNotification)(err.message, 4000);
93
+ }
94
+ }, [jsxInMapCallback, nodePath, validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.source]);
67
95
  const onDeleteSequenceFromSource = (0, react_1.useCallback)(async () => {
68
96
  if (!(validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.source) || !nodePath) {
69
97
  return;
@@ -89,6 +117,23 @@ const TimelineListItem = ({ nestedDepth, sequence, isCompact }) => {
89
117
  return [];
90
118
  }
91
119
  return [
120
+ {
121
+ type: 'item',
122
+ id: 'duplicate-sequence',
123
+ keyHint: null,
124
+ label: 'Duplicate',
125
+ leftItem: null,
126
+ disabled: duplicateDisabled,
127
+ onClick: () => {
128
+ if (duplicateDisabled) {
129
+ return;
130
+ }
131
+ onDuplicateSequenceFromSource();
132
+ },
133
+ quickSwitcherLabel: null,
134
+ subMenu: null,
135
+ value: 'duplicate-sequence',
136
+ },
92
137
  {
93
138
  type: 'item',
94
139
  id: 'delete-sequence',
@@ -107,7 +152,13 @@ const TimelineListItem = ({ nestedDepth, sequence, isCompact }) => {
107
152
  value: 'delete-sequence',
108
153
  },
109
154
  ];
110
- }, [deleteDisabled, onDeleteSequenceFromSource, visualModeEnvEnabled]);
155
+ }, [
156
+ deleteDisabled,
157
+ duplicateDisabled,
158
+ onDeleteSequenceFromSource,
159
+ onDuplicateSequenceFromSource,
160
+ visualModeEnvEnabled,
161
+ ]);
111
162
  const isExpanded = visualModeActive && ((_b = expandedTracks[sequence.id]) !== null && _b !== void 0 ? _b : false);
112
163
  const onToggleExpand = (0, react_1.useCallback)(() => {
113
164
  toggleTrack(sequence.id);
@@ -1,4 +1,7 @@
1
1
  import type { SequenceNodePath } from '@remotion/studio-shared';
2
2
  import type { TSequence } from 'remotion';
3
3
  import type { OriginalPosition } from '../../error-overlay/react-overlay/utils/get-source-map';
4
- export declare const useSequencePropsSubscription: (sequence: TSequence, originalLocation: OriginalPosition | null, visualModeEnabled: boolean) => SequenceNodePath | null;
4
+ export declare const useSequencePropsSubscription: (sequence: TSequence, originalLocation: OriginalPosition | null, visualModeEnabled: boolean) => {
5
+ nodePath: SequenceNodePath | null;
6
+ jsxInMapCallback: boolean;
7
+ };
@@ -45,6 +45,7 @@ const useSequencePropsSubscription = (sequence, originalLocation, visualModeEnab
45
45
  currentLocationColumn.current = locationColumn;
46
46
  const nodePathRef = (0, react_1.useRef)(null);
47
47
  const [nodePath, setNodePath] = (0, react_1.useState)(null);
48
+ const [jsxInMapCallback, setJsxInMapCallback] = (0, react_1.useState)(false);
48
49
  const isMountedRef = (0, react_1.useRef)(true);
49
50
  const setNodePathBoth = (0, react_1.useCallback)((next) => {
50
51
  nodePathRef.current = next;
@@ -60,6 +61,7 @@ const useSequencePropsSubscription = (sequence, originalLocation, visualModeEnab
60
61
  if (!visualModeEnabled) {
61
62
  setPropStatusesForSequence(null);
62
63
  setNodePathBoth(null);
64
+ setJsxInMapCallback(false);
63
65
  return;
64
66
  }
65
67
  if (!clientId ||
@@ -69,6 +71,7 @@ const useSequencePropsSubscription = (sequence, originalLocation, visualModeEnab
69
71
  !schemaKeysString) {
70
72
  setPropStatusesForSequence(null);
71
73
  setNodePathBoth(null);
74
+ setJsxInMapCallback(false);
72
75
  return;
73
76
  }
74
77
  const keys = schemaKeysString.split(',');
@@ -88,14 +91,17 @@ const useSequencePropsSubscription = (sequence, originalLocation, visualModeEnab
88
91
  if (result.canUpdate) {
89
92
  setNodePathBoth(result.nodePath);
90
93
  setPropStatusesForSequence(result.props);
94
+ setJsxInMapCallback(result.jsxInMapCallback);
91
95
  }
92
96
  else {
93
97
  setNodePathBoth(null);
94
98
  setPropStatusesForSequence(null);
99
+ setJsxInMapCallback(false);
95
100
  }
96
101
  })
97
102
  .catch((err) => {
98
103
  setNodePathBoth(null);
104
+ setJsxInMapCallback(false);
99
105
  remotion_1.Internals.Log.error(err);
100
106
  setPropStatusesForSequence(null);
101
107
  });
@@ -107,6 +113,7 @@ const useSequencePropsSubscription = (sequence, originalLocation, visualModeEnab
107
113
  setPropStatusesForSequence(null);
108
114
  }
109
115
  setNodePathBoth(null);
116
+ setJsxInMapCallback(false);
110
117
  if (currentNodePath) {
111
118
  (0, call_api_1.callApi)('/api/unsubscribe-from-sequence-props', {
112
119
  fileName: locationSource,
@@ -145,10 +152,12 @@ const useSequencePropsSubscription = (sequence, originalLocation, visualModeEnab
145
152
  }
146
153
  if (event.result.canUpdate) {
147
154
  setPropStatusesForSequence(event.result.props);
155
+ setJsxInMapCallback(event.result.jsxInMapCallback);
148
156
  }
149
157
  else {
150
158
  setPropStatusesForSequence(null);
151
159
  setNodePathBoth(null);
160
+ setJsxInMapCallback(false);
152
161
  }
153
162
  };
154
163
  const unsub = subscribeToEvent('sequence-props-updated', listener);
@@ -164,6 +173,6 @@ const useSequencePropsSubscription = (sequence, originalLocation, visualModeEnab
164
173
  setPropStatusesForSequence,
165
174
  setNodePathBoth,
166
175
  ]);
167
- return nodePath;
176
+ return { nodePath, jsxInMapCallback };
168
177
  };
169
178
  exports.useSequencePropsSubscription = useSequencePropsSubscription;
@@ -65,7 +65,7 @@ const ErrorDisplay = ({ display, keyboardShortcuts, onRetry, canHaveDismissButto
65
65
  ] })) : null, display.stackFrames.length > 0 && window.remotion_editorName ? (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [
66
66
  jsx_runtime_1.jsx(OpenInEditor_1.OpenInEditor, { canHaveKeyboardShortcuts: keyboardShortcuts, stack: display.stackFrames[0] }), jsx_runtime_1.jsx("div", { style: spacer })
67
67
  ] })) : null, jsx_runtime_1.jsx(CopyStackTrace_1.CopyStackTrace, { canHaveKeyboardShortcuts: keyboardShortcuts, errorText: errorTextForCopy }), jsx_runtime_1.jsx("div", { style: spacer }), jsx_runtime_1.jsx(SearchGitHubIssues_1.SearchGithubIssues, { canHaveKeyboardShortcuts: keyboardShortcuts, message: display.error.message }), jsx_runtime_1.jsx("div", { style: spacer }), jsx_runtime_1.jsx(AskOnDiscord_1.AskOnDiscord, { canHaveKeyboardShortcuts: keyboardShortcuts }), onRetry ? (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [
68
- jsx_runtime_1.jsx("div", { style: spacer }), jsx_runtime_1.jsx(Retry_1.RetryButton, { onClick: onRetry })
68
+ jsx_runtime_1.jsx("div", { style: spacer }), jsx_runtime_1.jsx(Retry_1.RetryButton, { onClick: onRetry, label: calculateMetadata ? 'Retry calculateMetadata()' : 'Retry' })
69
69
  ] })) : null, calculateMetadata ? (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [
70
70
  jsx_runtime_1.jsx("br", {}), jsx_runtime_1.jsx(layout_1.Spacing, { y: 0.5 }), jsx_runtime_1.jsx(CalculateMetadataErrorExplainer_1.CalculateMetadataErrorExplainer, {})
71
71
  ] })) : null, display.error instanceof remotion_1.MediaPlaybackError ? (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [
@@ -1,3 +1,4 @@
1
1
  export declare const RetryButton: React.FC<{
2
2
  onClick: () => void;
3
+ readonly label?: string;
3
4
  }>;
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.RetryButton = void 0;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const Button_1 = require("../../components/Button");
6
- const RetryButton = ({ onClick }) => {
7
- return jsx_runtime_1.jsx(Button_1.Button, { onClick: onClick, children: "Retry calculateMetadata()" });
6
+ const RetryButton = ({ onClick, label = 'Retry' }) => {
7
+ return jsx_runtime_1.jsx(Button_1.Button, { onClick: onClick, children: label });
8
8
  };
9
9
  exports.RetryButton = RetryButton;