@remotion/cli 4.0.43 → 4.0.45

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 (81) hide show
  1. package/dist/config/index.d.ts +1 -1
  2. package/dist/config/log.d.ts +1 -1
  3. package/dist/editor/components/AssetSelector.js +19 -3
  4. package/dist/editor/components/AssetSelectorItem.d.ts +6 -4
  5. package/dist/editor/components/AssetSelectorItem.js +48 -23
  6. package/dist/editor/components/Canvas.d.ts +4 -1
  7. package/dist/editor/components/Canvas.js +54 -30
  8. package/dist/editor/components/CanvasOrLoading.js +9 -1
  9. package/dist/editor/components/CompositionSelector.js +8 -6
  10. package/dist/editor/components/CompositionSelectorItem.d.ts +1 -1
  11. package/dist/editor/components/CompositionSelectorItem.js +1 -7
  12. package/dist/editor/components/CurrentCompositionSideEffects.js +15 -4
  13. package/dist/editor/components/DownloadButton.d.ts +0 -0
  14. package/dist/editor/components/DownloadButton.js +1 -0
  15. package/dist/editor/components/EditorContent.js +6 -1
  16. package/dist/editor/components/ExplorerPanel.js +0 -13
  17. package/dist/editor/components/FilePreview.d.ts +9 -0
  18. package/dist/editor/components/FilePreview.js +40 -0
  19. package/dist/editor/components/FramePersistor.d.ts +0 -1
  20. package/dist/editor/components/FramePersistor.js +1 -5
  21. package/dist/editor/components/InitialCompositionLoader.js +68 -18
  22. package/dist/editor/components/LoopToggle.js +0 -5
  23. package/dist/editor/components/MuteToggle.js +0 -5
  24. package/dist/editor/components/NewComposition/RemInput.d.ts +2 -2
  25. package/dist/editor/components/NewComposition/RemInputTypeColor.d.ts +1 -1
  26. package/dist/editor/components/NewComposition/RemTextarea.d.ts +1 -1
  27. package/dist/editor/components/OptionsPanel.js +7 -7
  28. package/dist/editor/components/PlayPause.js +0 -3
  29. package/dist/editor/components/PlaybackRateSelector.js +3 -1
  30. package/dist/editor/components/Preview.d.ts +8 -0
  31. package/dist/editor/components/Preview.js +97 -30
  32. package/dist/editor/components/PreviewToolbar.js +4 -1
  33. package/dist/editor/components/RenderPreview.d.ts +6 -0
  34. package/dist/editor/components/RenderPreview.js +31 -0
  35. package/dist/editor/components/RenderQueue/RenderQueueCopyToClipboard.js +3 -2
  36. package/dist/editor/components/RenderQueue/RenderQueueItem.d.ts +1 -0
  37. package/dist/editor/components/RenderQueue/RenderQueueItem.js +55 -2
  38. package/dist/editor/components/RenderQueue/RenderQueueItemCancelButton.js +2 -1
  39. package/dist/editor/components/RenderQueue/RenderQueueItemStatus.js +35 -4
  40. package/dist/editor/components/RenderQueue/RenderQueueOpenInFolder.js +3 -2
  41. package/dist/editor/components/RenderQueue/RenderQueueOutputName.js +3 -11
  42. package/dist/editor/components/RenderQueue/RenderQueueRemoveItem.js +2 -1
  43. package/dist/editor/components/RenderQueue/RenderQueueRepeat.js +2 -1
  44. package/dist/editor/components/RenderQueue/index.js +16 -1
  45. package/dist/editor/components/RendersTab.js +9 -1
  46. package/dist/editor/components/SizeSelector.js +24 -0
  47. package/dist/editor/components/StaticFilePreview.d.ts +6 -0
  48. package/dist/editor/components/StaticFilePreview.js +39 -0
  49. package/dist/editor/components/TextViewer.d.ts +4 -0
  50. package/dist/editor/components/TextViewer.js +26 -0
  51. package/dist/editor/components/Timeline/TimelineZoomControls.js +3 -1
  52. package/dist/editor/components/TimelineInOutToggle.js +0 -5
  53. package/dist/editor/components/ZoomPersistor.d.ts +2 -0
  54. package/dist/editor/components/ZoomPersistor.js +35 -7
  55. package/dist/editor/components/layout.d.ts +2 -1
  56. package/dist/editor/components/layout.js +2 -2
  57. package/dist/editor/helpers/checkerboard-background.d.ts +1 -1
  58. package/dist/editor/helpers/colors.d.ts +1 -1
  59. package/dist/editor/helpers/create-folder-tree.d.ts +4 -3
  60. package/dist/editor/helpers/create-folder-tree.js +6 -3
  61. package/dist/editor/helpers/document-title.d.ts +1 -1
  62. package/dist/editor/helpers/document-title.js +14 -8
  63. package/dist/editor/helpers/get-asset-metadata.d.ts +11 -0
  64. package/dist/editor/helpers/get-asset-metadata.js +64 -0
  65. package/dist/editor/helpers/is-current-selected-still.d.ts +4 -3
  66. package/dist/editor/helpers/is-current-selected-still.js +12 -13
  67. package/dist/editor/helpers/persist-open-folders.d.ts +4 -2
  68. package/dist/editor/helpers/persist-open-folders.js +7 -5
  69. package/dist/editor/state/folders.d.ts +4 -2
  70. package/dist/editor/state/folders.js +13 -6
  71. package/dist/get-cli-options.d.ts +2 -2
  72. package/dist/index.d.ts +10 -10
  73. package/dist/log.d.ts +4 -4
  74. package/dist/preview-server/routes.d.ts +5 -3
  75. package/dist/preview-server/routes.js +52 -8
  76. package/dist/preview-server/serve-static.d.ts +6 -1
  77. package/dist/preview-server/serve-static.js +1 -4
  78. package/dist/preview-server/start-server.d.ts +4 -2
  79. package/dist/preview-server/start-server.js +4 -2
  80. package/dist/studio.js +9 -4
  81. package/package.json +8 -8
@@ -0,0 +1,9 @@
1
+ import React from 'react';
2
+ import type { AssetMetadata } from '../helpers/get-asset-metadata';
3
+ import type { AssetFileType } from './Preview';
4
+ export declare const FilePreview: React.FC<{
5
+ src: string;
6
+ fileType: AssetFileType;
7
+ currentAsset: string;
8
+ assetMetadata: AssetMetadata | null;
9
+ }>;
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FilePreview = void 0;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const format_bytes_1 = require("../../format-bytes");
6
+ const JSONViewer_1 = require("./JSONViewer");
7
+ const layout_1 = require("./layout");
8
+ const TextViewer_1 = require("./TextViewer");
9
+ const msgStyle = {
10
+ fontSize: 13,
11
+ color: 'white',
12
+ fontFamily: 'sans-serif',
13
+ display: 'flex',
14
+ justifyContent: 'center',
15
+ };
16
+ const FilePreview = ({ fileType, src, currentAsset, assetMetadata }) => {
17
+ if (!assetMetadata) {
18
+ throw new Error('expected to have assetMetadata');
19
+ }
20
+ if (assetMetadata.type === 'not-found') {
21
+ throw new Error('expected to have assetMetadata, got "not-found"');
22
+ }
23
+ if (fileType === 'audio') {
24
+ return (0, jsx_runtime_1.jsx)("audio", { src: src, controls: true });
25
+ }
26
+ if (fileType === 'video') {
27
+ return (0, jsx_runtime_1.jsx)("video", { src: src, controls: true });
28
+ }
29
+ if (fileType === 'image') {
30
+ return (0, jsx_runtime_1.jsx)("img", { src: src });
31
+ }
32
+ if (fileType === 'json') {
33
+ return (0, jsx_runtime_1.jsx)(JSONViewer_1.JSONViewer, { src: src });
34
+ }
35
+ if (fileType === 'txt') {
36
+ return (0, jsx_runtime_1.jsx)(TextViewer_1.TextViewer, { src: src });
37
+ }
38
+ return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("div", { style: msgStyle, children: currentAsset }), (0, jsx_runtime_1.jsx)(layout_1.Spacing, { y: 0.5 }), (0, jsx_runtime_1.jsxs)("div", { style: msgStyle, children: ["Size: ", (0, format_bytes_1.formatBytes)(assetMetadata.size), " "] })] }));
39
+ };
40
+ exports.FilePreview = FilePreview;
@@ -1,3 +1,2 @@
1
1
  import type React from 'react';
2
- export declare const getCurrentCompositionFromUrl: () => string;
3
2
  export declare const FramePersistor: React.FC;
@@ -1,12 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.FramePersistor = exports.getCurrentCompositionFromUrl = void 0;
3
+ exports.FramePersistor = void 0;
4
4
  const react_1 = require("react");
5
5
  const remotion_1 = require("remotion");
6
- const getCurrentCompositionFromUrl = () => {
7
- return window.location.pathname.substr(1);
8
- };
9
- exports.getCurrentCompositionFromUrl = getCurrentCompositionFromUrl;
10
6
  const FramePersistor = () => {
11
7
  const [playing] = remotion_1.Internals.Timeline.usePlayingState();
12
8
  const config = (0, remotion_1.useVideoConfig)();
@@ -5,18 +5,38 @@ const react_1 = require("react");
5
5
  const remotion_1 = require("remotion");
6
6
  const folders_1 = require("../state/folders");
7
7
  const CompositionSelector_1 = require("./CompositionSelector");
8
- const FramePersistor_1 = require("./FramePersistor");
8
+ const ZoomPersistor_1 = require("./ZoomPersistor");
9
+ const useSelectAsset = () => {
10
+ const { setCanvasContent } = (0, react_1.useContext)(remotion_1.Internals.CompositionManager);
11
+ const { setAssetFoldersExpanded } = (0, react_1.useContext)(folders_1.FolderContext);
12
+ return (asset) => {
13
+ setCanvasContent({ type: 'asset', asset });
14
+ setAssetFoldersExpanded((ex) => {
15
+ const split = asset.split('/');
16
+ const keysToExpand = split.map((_, i) => {
17
+ return split.slice(0, i).join('/');
18
+ });
19
+ const newState = {
20
+ ...ex,
21
+ };
22
+ for (const key of keysToExpand) {
23
+ newState[key] = true;
24
+ }
25
+ return newState;
26
+ });
27
+ };
28
+ };
9
29
  const useSelectComposition = () => {
10
- const { setFoldersExpanded } = (0, react_1.useContext)(folders_1.FolderContext);
11
- const { setCurrentComposition } = (0, react_1.useContext)(remotion_1.Internals.CompositionManager);
30
+ const { setCompositionFoldersExpanded } = (0, react_1.useContext)(folders_1.FolderContext);
31
+ const { setCanvasContent } = (0, react_1.useContext)(remotion_1.Internals.CompositionManager);
12
32
  return (c, push) => {
13
33
  if (push) {
14
34
  window.history.pushState({}, 'Studio', `/${c.id}`);
15
35
  }
16
- setCurrentComposition(c.id);
36
+ setCanvasContent({ type: 'composition', compositionId: c.id });
17
37
  const { folderName, parentFolderName } = c;
18
38
  if (folderName !== null) {
19
- setFoldersExpanded((ex) => {
39
+ setCompositionFoldersExpanded((ex) => {
20
40
  const keysToExpand = (0, CompositionSelector_1.getKeysToExpand)(folderName, parentFolderName);
21
41
  const newState = {
22
42
  ...ex,
@@ -31,35 +51,65 @@ const useSelectComposition = () => {
31
51
  };
32
52
  exports.useSelectComposition = useSelectComposition;
33
53
  const InitialCompositionLoader = () => {
34
- const { compositions, currentComposition } = (0, react_1.useContext)(remotion_1.Internals.CompositionManager);
54
+ const { compositions, canvasContent, setCanvasContent } = (0, react_1.useContext)(remotion_1.Internals.CompositionManager);
35
55
  const selectComposition = (0, exports.useSelectComposition)();
56
+ const selectAsset = useSelectAsset();
36
57
  (0, react_1.useEffect)(() => {
37
- if (currentComposition) {
58
+ if (canvasContent) {
38
59
  return;
39
60
  }
40
- const compositionFromUrl = (0, FramePersistor_1.getCurrentCompositionFromUrl)();
41
- if (compositionFromUrl) {
42
- const exists = compositions.find((c) => c.id === compositionFromUrl);
61
+ const canvasContentFromUrl = (0, ZoomPersistor_1.deriveCanvasContentFromUrl)();
62
+ if (canvasContentFromUrl && canvasContentFromUrl.type === 'composition') {
63
+ const exists = compositions.find((c) => c.id === canvasContentFromUrl.compositionId);
43
64
  if (exists) {
44
- selectComposition(exists, true);
45
- return;
65
+ selectComposition(exists, false);
46
66
  }
67
+ return;
68
+ }
69
+ if (canvasContentFromUrl && canvasContentFromUrl.type === 'asset') {
70
+ selectAsset(canvasContentFromUrl.asset);
71
+ return;
72
+ }
73
+ if (canvasContentFromUrl && canvasContentFromUrl.type === 'output') {
74
+ setCanvasContent(canvasContentFromUrl);
75
+ return;
47
76
  }
48
77
  if (compositions.length > 0) {
49
78
  selectComposition(compositions[0], true);
50
79
  }
51
- }, [compositions, currentComposition, selectComposition]);
80
+ }, [
81
+ compositions,
82
+ canvasContent,
83
+ selectComposition,
84
+ setCanvasContent,
85
+ selectAsset,
86
+ ]);
52
87
  (0, react_1.useEffect)(() => {
53
88
  const onchange = () => {
54
- const newComp = window.location.pathname.substring(1);
55
- const exists = compositions.find((c) => c.id === newComp);
56
- if (exists) {
57
- selectComposition(exists, false);
89
+ const newCanvas = (0, ZoomPersistor_1.deriveCanvasContentFromUrl)();
90
+ if (newCanvas && newCanvas.type === 'composition') {
91
+ const newComp = window.location.pathname.substring(1);
92
+ const exists = compositions.find((c) => c.id === newComp);
93
+ if (exists) {
94
+ selectComposition(exists, false);
95
+ }
96
+ return;
97
+ }
98
+ if (newCanvas && newCanvas.type === 'asset') {
99
+ const staticFiles = (0, remotion_1.getStaticFiles)();
100
+ const exists = staticFiles.find((file) => {
101
+ return file.name === newCanvas.asset;
102
+ });
103
+ if (exists) {
104
+ setCanvasContent(newCanvas);
105
+ }
106
+ return;
58
107
  }
108
+ setCanvasContent(newCanvas);
59
109
  };
60
110
  window.addEventListener('popstate', onchange);
61
111
  return () => window.removeEventListener('popstate', onchange);
62
- }, [compositions, selectComposition]);
112
+ }, [compositions, selectComposition, setCanvasContent]);
63
113
  return null;
64
114
  };
65
115
  exports.InitialCompositionLoader = InitialCompositionLoader;
@@ -4,7 +4,6 @@ exports.LoopToggle = void 0;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const react_1 = require("react");
6
6
  const colors_1 = require("../helpers/colors");
7
- const is_current_selected_still_1 = require("../helpers/is-current-selected-still");
8
7
  const loop_1 = require("../state/loop");
9
8
  const ControlButton_1 = require("./ControlButton");
10
9
  const accessibilityLabel = 'Loop video';
@@ -15,10 +14,6 @@ const LoopToggle = ({ loop, setLoop }) => {
15
14
  return !c;
16
15
  });
17
16
  }, [setLoop]);
18
- const isStill = (0, is_current_selected_still_1.useIsStill)();
19
- if (isStill) {
20
- return null;
21
- }
22
17
  return ((0, jsx_runtime_1.jsx)(ControlButton_1.ControlButton, { title: accessibilityLabel, "aria-label": accessibilityLabel, onClick: onClick, children: (0, jsx_runtime_1.jsx)("svg", { viewBox: "0 0 512 512", style: { width: 18, height: 18 }, children: (0, jsx_runtime_1.jsx)("path", { fill: loop ? colors_1.BLUE : 'white', d: "M493.544 181.463c11.956 22.605 18.655 48.4 18.452 75.75C511.339 345.365 438.56 416 350.404 416H192v47.495c0 22.475-26.177 32.268-40.971 17.475l-80-80c-9.372-9.373-9.372-24.569 0-33.941l80-80C166.138 271.92 192 282.686 192 304v48h158.875c52.812 0 96.575-42.182 97.12-94.992.155-15.045-3.17-29.312-9.218-42.046-4.362-9.185-2.421-20.124 4.8-27.284 4.745-4.706 8.641-8.555 11.876-11.786 11.368-11.352 30.579-8.631 38.091 5.571zM64.005 254.992c.545-52.81 44.308-94.992 97.12-94.992H320v47.505c0 22.374 26.121 32.312 40.971 17.465l80-80c9.372-9.373 9.372-24.569 0-33.941l-80-80C346.014 16.077 320 26.256 320 48.545V96H161.596C73.44 96 .661 166.635.005 254.788c-.204 27.35 6.495 53.145 18.452 75.75 7.512 14.202 26.723 16.923 38.091 5.57 3.235-3.231 7.13-7.08 11.876-11.786 7.22-7.16 9.162-18.098 4.8-27.284-6.049-12.735-9.374-27.001-9.219-42.046z" }) }) }));
23
18
  };
24
19
  exports.LoopToggle = LoopToggle;
@@ -3,7 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MuteToggle = void 0;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const react_1 = require("react");
6
- const is_current_selected_still_1 = require("../helpers/is-current-selected-still");
7
6
  const media_volume_1 = require("../icons/media-volume");
8
7
  const mute_1 = require("../state/mute");
9
8
  const ControlButton_1 = require("./ControlButton");
@@ -15,10 +14,6 @@ const MuteToggle = ({ muted, setMuted }) => {
15
14
  });
16
15
  }, [setMuted]);
17
16
  const accessibilityLabel = muted ? 'Unmute video' : 'Mute video';
18
- const isStill = (0, is_current_selected_still_1.useIsStill)();
19
- if (isStill) {
20
- return null;
21
- }
22
17
  return ((0, jsx_runtime_1.jsx)(ControlButton_1.ControlButton, { title: accessibilityLabel, "aria-label": accessibilityLabel, onClick: onClick, children: muted ? (0, jsx_runtime_1.jsx)(media_volume_1.VolumeOffIcon, {}) : (0, jsx_runtime_1.jsx)(media_volume_1.VolumeOnIcon, {}) }));
23
18
  };
24
19
  exports.MuteToggle = MuteToggle;
@@ -12,6 +12,6 @@ export declare const getInputBorderColor: ({ status, isFocused, isHovered, }: {
12
12
  status: 'error' | 'warning' | 'ok';
13
13
  isFocused: boolean;
14
14
  isHovered: boolean;
15
- }) => "hsla(0, 0%, 100%, 0.15)" | "#ff3232" | "#f1c40f" | "rgba(255, 255, 255, 0.05)" | "rgba(0, 0, 0, 0.6)";
16
- export declare const RemotionInput: React.ForwardRefExoticComponent<Pick<Props, "status" | "key" | "rightAlign" | keyof React.InputHTMLAttributes<HTMLInputElement>> & React.RefAttributes<HTMLInputElement>>;
15
+ }) => "hsla(0, 0%, 100%, 0.15)" | "rgba(0, 0, 0, 0.6)" | "rgba(255, 255, 255, 0.05)" | "#ff3232" | "#f1c40f";
16
+ export declare const RemotionInput: React.ForwardRefExoticComponent<Pick<Props, "key" | keyof React.InputHTMLAttributes<HTMLInputElement> | "status" | "rightAlign"> & React.RefAttributes<HTMLInputElement>>;
17
17
  export {};
@@ -4,5 +4,5 @@ type Props = React.DetailedHTMLProps<React.InputHTMLAttributes<HTMLInputElement>
4
4
  status: RemInputStatus;
5
5
  name: string;
6
6
  };
7
- export declare const RemInputTypeColor: React.ForwardRefExoticComponent<Pick<Props, "status" | "key" | keyof React.InputHTMLAttributes<HTMLInputElement>> & React.RefAttributes<HTMLInputElement>>;
7
+ export declare const RemInputTypeColor: React.ForwardRefExoticComponent<Pick<Props, "key" | keyof React.InputHTMLAttributes<HTMLInputElement> | "status"> & React.RefAttributes<HTMLInputElement>>;
8
8
  export {};
@@ -3,5 +3,5 @@ type Props = React.DetailedHTMLProps<React.InputHTMLAttributes<HTMLTextAreaEleme
3
3
  status: 'error' | 'warning' | 'ok';
4
4
  };
5
5
  export declare const inputBaseStyle: React.CSSProperties;
6
- export declare const RemTextarea: React.ForwardRefExoticComponent<Pick<Props, "status" | "key" | keyof React.InputHTMLAttributes<HTMLTextAreaElement>> & React.RefAttributes<HTMLTextAreaElement>>;
6
+ export declare const RemTextarea: React.ForwardRefExoticComponent<Pick<Props, "key" | "status" | keyof React.InputHTMLAttributes<HTMLTextAreaElement>> & React.RefAttributes<HTMLTextAreaElement>>;
7
7
  export {};
@@ -59,7 +59,7 @@ const OptionsPanel = () => {
59
59
  },
60
60
  };
61
61
  }, []);
62
- const { compositions, currentComposition } = (0, react_1.useContext)(remotion_1.Internals.CompositionManager);
62
+ const { compositions, canvasContent } = (0, react_1.useContext)(remotion_1.Internals.CompositionManager);
63
63
  const circleStyle = (0, react_1.useMemo)(() => {
64
64
  const onTabColor = saving ? colors_1.LIGHT_TEXT : 'white';
65
65
  return {
@@ -69,13 +69,16 @@ const OptionsPanel = () => {
69
69
  };
70
70
  }, [panel, saving]);
71
71
  const composition = (0, react_1.useMemo)(() => {
72
+ if (canvasContent === null || canvasContent.type !== 'composition') {
73
+ return null;
74
+ }
72
75
  for (const comp of compositions) {
73
- if (comp.id === currentComposition) {
76
+ if (comp.id === canvasContent.compositionId) {
74
77
  return comp;
75
78
  }
76
79
  }
77
80
  return null;
78
- }, [compositions, currentComposition]);
81
+ }, [canvasContent, compositions]);
79
82
  const saveToolTip = (0, react_1.useMemo)(() => {
80
83
  return process.env.KEYBOARD_SHORTCUTS_ENABLED
81
84
  ? `Save using ${ShortcutHint_1.cmdOrCtrlCharacter}+S`
@@ -104,9 +107,6 @@ const OptionsPanel = () => {
104
107
  }
105
108
  return !(0, deep_equal_1.deepEqual)(composition.defaultProps, actualProps);
106
109
  }, [actualProps, composition]);
107
- if (composition === null) {
108
- return null;
109
- }
110
- return ((0, jsx_runtime_1.jsxs)("div", { style: container, className: "css-reset", children: [(0, jsx_runtime_1.jsx)("div", { style: tabsContainer, children: (0, jsx_runtime_1.jsxs)(Tabs_1.Tabs, { children: [(0, jsx_runtime_1.jsxs)(Tabs_1.Tab, { selected: panel === 'input-props', onClick: onPropsSelected, style: { justifyContent: 'space-between' }, children: ["Props", unsavedChangesExist ? ((0, jsx_runtime_1.jsx)("div", { title: saveToolTip, style: circleStyle })) : null] }), (0, jsx_runtime_1.jsx)(RendersTab_1.RendersTab, { onClick: onRendersSelected, selected: panel === 'renders' })] }) }), panel === 'renders' ? ((0, jsx_runtime_1.jsx)(RenderQueue_1.RenderQueue, {})) : ((0, jsx_runtime_1.jsx)(DataEditor_1.DataEditor, { unresolvedComposition: composition, inputProps: actualProps, setInputProps: setInputProps, mayShowSaveButton: true, propsEditType: "default-props", saving: saving, setSaving: setSaving }, composition.id))] }));
110
+ return ((0, jsx_runtime_1.jsxs)("div", { style: container, className: "css-reset", children: [(0, jsx_runtime_1.jsx)("div", { style: tabsContainer, children: (0, jsx_runtime_1.jsxs)(Tabs_1.Tabs, { children: [composition ? ((0, jsx_runtime_1.jsxs)(Tabs_1.Tab, { selected: panel === 'input-props', onClick: onPropsSelected, style: { justifyContent: 'space-between' }, children: ["Props", unsavedChangesExist ? ((0, jsx_runtime_1.jsx)("div", { title: saveToolTip, style: circleStyle })) : null] })) : null, (0, jsx_runtime_1.jsx)(RendersTab_1.RendersTab, { onClick: onRendersSelected, selected: panel === 'renders' })] }) }), panel === `input-props` && composition ? ((0, jsx_runtime_1.jsx)(DataEditor_1.DataEditor, { unresolvedComposition: composition, inputProps: actualProps, setInputProps: setInputProps, mayShowSaveButton: true, propsEditType: "default-props", saving: saving, setSaving: setSaving }, composition.id)) : ((0, jsx_runtime_1.jsx)(RenderQueue_1.RenderQueue, {}))] }));
111
111
  };
112
112
  exports.OptionsPanel = OptionsPanel;
@@ -186,9 +186,6 @@ const PlayPause = ({ playbackRate, loop }) => {
186
186
  onEnter,
187
187
  onSpace,
188
188
  ]);
189
- if (isStill) {
190
- return null;
191
- }
192
189
  return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(ControlButton_1.ControlButton, { "aria-label": "Jump to beginning", title: "Jump to beginning", disabled: !videoConfig || isFirstFrame, onClick: jumpToStart, children: (0, jsx_runtime_1.jsx)(jump_to_start_1.JumpToStart, { style: forwardBackStyle }) }), (0, jsx_runtime_1.jsx)(ControlButton_1.ControlButton, { "aria-label": "Step back one frame", title: "Step back one frame", disabled: !videoConfig || isFirstFrame, onClick: oneFrameBack, children: (0, jsx_runtime_1.jsx)(step_back_1.StepBack, { style: forwardBackStyle }) }), (0, jsx_runtime_1.jsx)(ControlButton_1.ControlButton, { "aria-label": playing ? 'Pause' : 'Play', title: playing ? 'Pause' : 'Play', onClick: playing ? pause : play, disabled: !videoConfig, children: playing ? ((0, jsx_runtime_1.jsx)(pause_1.Pause, { style: {
193
190
  height: 14,
194
191
  width: 14,
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.PlaybackRateSelector = void 0;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const react_1 = require("react");
6
+ const remotion_1 = require("remotion");
6
7
  const is_current_selected_still_1 = require("../helpers/is-current-selected-still");
7
8
  const Checkmark_1 = require("../icons/Checkmark");
8
9
  const playbackrate_1 = require("../state/playbackrate");
@@ -17,6 +18,7 @@ const getPlaybackRateLabel = (playbackRate) => {
17
18
  const accessibilityLabel = 'Change the playback rate';
18
19
  const comboStyle = { width: 80 };
19
20
  const PlaybackRateSelector = ({ playbackRate, setPlaybackRate }) => {
21
+ const { canvasContent } = (0, react_1.useContext)(remotion_1.Internals.CompositionManager);
20
22
  const isStill = (0, is_current_selected_still_1.useIsStill)();
21
23
  const style = (0, react_1.useMemo)(() => {
22
24
  return {
@@ -49,7 +51,7 @@ const PlaybackRateSelector = ({ playbackRate, setPlaybackRate }) => {
49
51
  const middle = Math.floor(commonPlaybackRates.length / 2);
50
52
  return [...values.slice(0, middle), divider, ...values.slice(middle)];
51
53
  }, [playbackRate, setPlaybackRate]);
52
- if (isStill) {
54
+ if (isStill || canvasContent === null || canvasContent.type === 'asset') {
53
55
  return null;
54
56
  }
55
57
  return ((0, jsx_runtime_1.jsx)("div", { style: style, "aria-label": accessibilityLabel, children: (0, jsx_runtime_1.jsx)(ComboBox_1.Combobox, { title: accessibilityLabel, style: comboStyle, selectedId: String(playbackRate), values: items }) }));
@@ -1,5 +1,13 @@
1
1
  import type { Size } from '@remotion/player';
2
2
  import React from 'react';
3
+ import type { CanvasContent } from 'remotion';
4
+ import type { AssetMetadata } from '../helpers/get-asset-metadata';
5
+ import type { Dimensions } from '../helpers/is-current-selected-still';
6
+ export type AssetFileType = 'audio' | 'video' | 'image' | 'json' | 'txt' | 'other';
7
+ export declare const getPreviewFileType: (fileName: string | null) => AssetFileType;
3
8
  export declare const VideoPreview: React.FC<{
4
9
  canvasSize: Size;
10
+ contentDimensions: Dimensions | 'none' | null;
11
+ canvasContent: CanvasContent;
12
+ assetMetadata: AssetMetadata | null;
5
13
  }>;
@@ -1,13 +1,58 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.VideoPreview = void 0;
3
+ exports.VideoPreview = exports.getPreviewFileType = void 0;
4
4
  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
8
  const checkerboard_background_1 = require("../helpers/checkerboard-background");
9
+ const colors_1 = require("../helpers/colors");
9
10
  const checkerboard_1 = require("../state/checkerboard");
10
11
  const preview_size_1 = require("../state/preview-size");
12
+ const RenderPreview_1 = require("./RenderPreview");
13
+ const Spinner_1 = require("./Spinner");
14
+ const StaticFilePreview_1 = require("./StaticFilePreview");
15
+ const centeredContainer = {
16
+ display: 'flex',
17
+ flex: 1,
18
+ justifyContent: 'center',
19
+ alignItems: 'center',
20
+ };
21
+ const label = {
22
+ fontFamily: 'sans-serif',
23
+ fontSize: 14,
24
+ color: colors_1.LIGHT_TEXT,
25
+ };
26
+ const getPreviewFileType = (fileName) => {
27
+ var _a;
28
+ if (!fileName) {
29
+ return 'other';
30
+ }
31
+ const audioExtensions = ['mp3', 'wav', 'ogg', 'aac'];
32
+ const videoExtensions = ['mp4', 'avi', 'mkv', 'mov', 'webm'];
33
+ const imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'bmp'];
34
+ const fileExtension = (_a = fileName.split('.').pop()) === null || _a === void 0 ? void 0 : _a.toLowerCase();
35
+ if (fileExtension === undefined) {
36
+ throw new Error('File extension is undefined');
37
+ }
38
+ if (audioExtensions.includes(fileExtension)) {
39
+ return 'audio';
40
+ }
41
+ if (videoExtensions.includes(fileExtension)) {
42
+ return 'video';
43
+ }
44
+ if (imageExtensions.includes(fileExtension)) {
45
+ return 'image';
46
+ }
47
+ if (fileExtension === 'json') {
48
+ return 'json';
49
+ }
50
+ if (fileExtension === 'txt') {
51
+ return 'txt';
52
+ }
53
+ return 'other';
54
+ };
55
+ exports.getPreviewFileType = getPreviewFileType;
11
56
  const checkerboardSize = 49;
12
57
  const containerStyle = (options) => {
13
58
  return {
@@ -24,50 +69,79 @@ const containerStyle = (options) => {
24
69
  backgroundPosition: (0, checkerboard_background_1.getCheckerboardBackgroundPos)(checkerboardSize) /* Must be half of one side of the square */,
25
70
  };
26
71
  };
27
- const Inner = ({ canvasSize }) => {
72
+ const VideoPreview = ({ canvasSize, contentDimensions, canvasContent, assetMetadata }) => {
73
+ if (assetMetadata && assetMetadata.type === 'not-found') {
74
+ return ((0, jsx_runtime_1.jsx)("div", { style: centeredContainer, children: (0, jsx_runtime_1.jsx)("div", { style: label, children: "File does not exist" }) }));
75
+ }
76
+ if (contentDimensions === null) {
77
+ return ((0, jsx_runtime_1.jsx)("div", { style: centeredContainer, children: (0, jsx_runtime_1.jsx)(Spinner_1.Spinner, { duration: 0.5, size: 24 }) }));
78
+ }
79
+ return ((0, jsx_runtime_1.jsx)(CompWhenItHasDimensions, { contentDimensions: contentDimensions, canvasSize: canvasSize, canvasContent: canvasContent, assetMetadata: assetMetadata }));
80
+ };
81
+ exports.VideoPreview = VideoPreview;
82
+ const CompWhenItHasDimensions = ({ contentDimensions, canvasSize, canvasContent, assetMetadata }) => {
28
83
  const { size: previewSize } = (0, react_1.useContext)(preview_size_1.PreviewSizeContext);
29
- const portalContainer = (0, react_1.useRef)(null);
30
- const config = (0, remotion_1.useVideoConfig)();
31
- const { checkerboard } = (0, react_1.useContext)(checkerboard_1.CheckerboardContext);
32
- const { centerX, centerY, yCorrection, xCorrection, scale } = player_1.PlayerInternals.calculateCanvasTransformation({
33
- canvasSize,
34
- compositionHeight: config.height,
35
- compositionWidth: config.width,
36
- previewSize: previewSize.size,
37
- });
84
+ const { centerX, centerY, yCorrection, xCorrection, scale } = (0, react_1.useMemo)(() => {
85
+ if (contentDimensions === 'none') {
86
+ return {
87
+ centerX: 0,
88
+ centerY: 0,
89
+ yCorrection: 0,
90
+ xCorrection: 0,
91
+ scale: 1,
92
+ };
93
+ }
94
+ return player_1.PlayerInternals.calculateCanvasTransformation({
95
+ canvasSize,
96
+ compositionHeight: contentDimensions.height,
97
+ compositionWidth: contentDimensions.width,
98
+ previewSize: previewSize.size,
99
+ });
100
+ }, [canvasSize, contentDimensions, previewSize.size]);
38
101
  const outer = (0, react_1.useMemo)(() => {
39
102
  return {
40
- width: config.width * scale,
41
- height: config.height * scale,
103
+ width: contentDimensions === 'none' ? '100%' : contentDimensions.width * scale,
104
+ height: contentDimensions === 'none'
105
+ ? '100%'
106
+ : contentDimensions.height * scale,
42
107
  display: 'flex',
43
108
  flexDirection: 'column',
44
109
  position: 'absolute',
45
110
  left: centerX - previewSize.translation.x,
46
111
  top: centerY - previewSize.translation.y,
47
112
  overflow: 'hidden',
113
+ justifyContent: canvasContent.type === 'asset' ? 'center' : 'flex-start',
114
+ alignItems: canvasContent.type === 'asset' &&
115
+ (0, exports.getPreviewFileType)(canvasContent.asset) === 'audio'
116
+ ? 'center'
117
+ : 'normal',
48
118
  };
49
119
  }, [
120
+ contentDimensions,
121
+ scale,
50
122
  centerX,
51
- centerY,
52
- config.height,
53
- config.width,
54
123
  previewSize.translation.x,
55
124
  previewSize.translation.y,
56
- scale,
125
+ centerY,
126
+ canvasContent,
57
127
  ]);
128
+ return ((0, jsx_runtime_1.jsx)("div", { style: outer, children: canvasContent.type === 'asset' ? ((0, jsx_runtime_1.jsx)(StaticFilePreview_1.StaticFilePreview, { assetMetadata: assetMetadata, currentAsset: canvasContent.asset })) : canvasContent.type === 'output' ? ((0, jsx_runtime_1.jsx)(RenderPreview_1.RenderPreview, { path: canvasContent.path, assetMetadata: assetMetadata })) : ((0, jsx_runtime_1.jsx)(PortalContainer, { contentDimensions: contentDimensions, scale: scale, xCorrection: xCorrection, yCorrection: yCorrection })) }));
129
+ };
130
+ const PortalContainer = ({ scale, xCorrection, yCorrection, contentDimensions }) => {
131
+ const { checkerboard } = (0, react_1.useContext)(checkerboard_1.CheckerboardContext);
58
132
  const style = (0, react_1.useMemo)(() => {
59
133
  return containerStyle({
60
134
  checkerboard,
61
135
  scale,
62
136
  xCorrection,
63
137
  yCorrection,
64
- width: config.width,
65
- height: config.height,
138
+ width: contentDimensions.width,
139
+ height: contentDimensions.height,
66
140
  });
67
141
  }, [
68
142
  checkerboard,
69
- config.height,
70
- config.width,
143
+ contentDimensions.height,
144
+ contentDimensions.width,
71
145
  scale,
72
146
  xCorrection,
73
147
  yCorrection,
@@ -79,13 +153,6 @@ const Inner = ({ canvasSize }) => {
79
153
  current === null || current === void 0 ? void 0 : current.removeChild(remotion_1.Internals.portalNode());
80
154
  };
81
155
  }, []);
82
- return ((0, jsx_runtime_1.jsx)("div", { style: outer, children: (0, jsx_runtime_1.jsx)("div", { ref: portalContainer, style: style }) }));
83
- };
84
- const VideoPreview = ({ canvasSize }) => {
85
- const config = remotion_1.Internals.useUnsafeVideoConfig();
86
- if (!config) {
87
- return null;
88
- }
89
- return (0, jsx_runtime_1.jsx)(Inner, { canvasSize: canvasSize });
156
+ const portalContainer = (0, react_1.useRef)(null);
157
+ return (0, jsx_runtime_1.jsx)("div", { ref: portalContainer, style: style });
90
158
  };
91
- exports.VideoPreview = VideoPreview;
@@ -5,6 +5,7 @@ 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 colors_1 = require("../helpers/colors");
8
+ const is_current_selected_still_1 = require("../helpers/is-current-selected-still");
8
9
  const timeline_layout_1 = require("../helpers/timeline-layout");
9
10
  const loop_1 = require("../state/loop");
10
11
  const CheckboardToggle_1 = require("./CheckboardToggle");
@@ -45,8 +46,10 @@ const PreviewToolbar = () => {
45
46
  const { playbackRate, setPlaybackRate } = (0, react_1.useContext)(remotion_1.Internals.Timeline.TimelineContext);
46
47
  const { mediaMuted } = (0, react_1.useContext)(remotion_1.Internals.MediaVolumeContext);
47
48
  const { setMediaMuted } = (0, react_1.useContext)(remotion_1.Internals.SetMediaVolumeContext);
49
+ const isVideoComposition = (0, is_current_selected_still_1.useIsVideoComposition)();
50
+ const isStill = (0, is_current_selected_still_1.useIsStill)();
48
51
  const [loop, setLoop] = (0, react_1.useState)((0, loop_1.loadLoopOption)());
49
52
  const isFullscreenSupported = document.fullscreenEnabled || document.webkitFullscreenEnabled;
50
- return ((0, jsx_runtime_1.jsxs)("div", { style: container, className: "css-reset", children: [(0, jsx_runtime_1.jsxs)("div", { style: sideContainer, children: [(0, jsx_runtime_1.jsx)("div", { style: padding }), (0, jsx_runtime_1.jsx)(TimelineZoomControls_1.TimelineZoomControls, {})] }), (0, jsx_runtime_1.jsx)(layout_1.Flex, {}), (0, jsx_runtime_1.jsx)(SizeSelector_1.SizeSelector, {}), (0, jsx_runtime_1.jsx)(PlaybackRateSelector_1.PlaybackRateSelector, { setPlaybackRate: setPlaybackRate, playbackRate: playbackRate }), (0, jsx_runtime_1.jsx)(layout_1.Spacing, { x: 2 }), (0, jsx_runtime_1.jsx)(PlayPause_1.PlayPause, { loop: loop, playbackRate: playbackRate }), (0, jsx_runtime_1.jsx)(layout_1.Spacing, { x: 2 }), (0, jsx_runtime_1.jsx)(LoopToggle_1.LoopToggle, { loop: loop, setLoop: setLoop }), (0, jsx_runtime_1.jsx)(CheckboardToggle_1.CheckboardToggle, {}), (0, jsx_runtime_1.jsx)(TimelineInOutToggle_1.TimelineInOutPointToggle, {}), (0, jsx_runtime_1.jsx)(MuteToggle_1.MuteToggle, { muted: mediaMuted, setMuted: setMediaMuted }), isFullscreenSupported && (0, jsx_runtime_1.jsx)(FullscreenToggle_1.FullScreenToggle, {}), (0, jsx_runtime_1.jsx)(layout_1.Spacing, { x: 2 }), (0, jsx_runtime_1.jsx)(layout_1.Flex, {}), (0, jsx_runtime_1.jsxs)("div", { style: sideContainer, children: [(0, jsx_runtime_1.jsx)(layout_1.Flex, {}), (0, jsx_runtime_1.jsx)(FpsCounter_1.FpsCounter, { playbackSpeed: playbackRate }), (0, jsx_runtime_1.jsx)(layout_1.Spacing, { x: 2 }), (0, jsx_runtime_1.jsx)(RenderButton_1.RenderButton, {}), (0, jsx_runtime_1.jsx)(layout_1.Spacing, { x: 1.5 })] }), (0, jsx_runtime_1.jsx)(PlaybackKeyboardShortcutsManager_1.PlaybackKeyboardShortcutsManager, { setPlaybackRate: setPlaybackRate }), (0, jsx_runtime_1.jsx)(PlaybackRatePersistor_1.PlaybackRatePersistor, {})] }));
53
+ return ((0, jsx_runtime_1.jsxs)("div", { style: container, className: "css-reset", children: [(0, jsx_runtime_1.jsxs)("div", { style: sideContainer, children: [(0, jsx_runtime_1.jsx)("div", { style: padding }), (0, jsx_runtime_1.jsx)(TimelineZoomControls_1.TimelineZoomControls, {})] }), (0, jsx_runtime_1.jsx)(layout_1.Flex, {}), (0, jsx_runtime_1.jsx)(SizeSelector_1.SizeSelector, {}), isStill || isVideoComposition ? ((0, jsx_runtime_1.jsx)(PlaybackRateSelector_1.PlaybackRateSelector, { setPlaybackRate: setPlaybackRate, playbackRate: playbackRate })) : null, isVideoComposition ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(layout_1.Spacing, { x: 2 }), (0, jsx_runtime_1.jsx)(PlayPause_1.PlayPause, { loop: loop, playbackRate: playbackRate }), (0, jsx_runtime_1.jsx)(layout_1.Spacing, { x: 2 }), (0, jsx_runtime_1.jsx)(LoopToggle_1.LoopToggle, { loop: loop, setLoop: setLoop }), (0, jsx_runtime_1.jsx)(CheckboardToggle_1.CheckboardToggle, {}), (0, jsx_runtime_1.jsx)(TimelineInOutToggle_1.TimelineInOutPointToggle, {}), (0, jsx_runtime_1.jsx)(MuteToggle_1.MuteToggle, { muted: mediaMuted, setMuted: setMediaMuted })] })) : null, isFullscreenSupported && (0, jsx_runtime_1.jsx)(FullscreenToggle_1.FullScreenToggle, {}), (0, jsx_runtime_1.jsx)(layout_1.Flex, {}), (0, jsx_runtime_1.jsxs)("div", { style: sideContainer, children: [(0, jsx_runtime_1.jsx)(layout_1.Flex, {}), (0, jsx_runtime_1.jsx)(FpsCounter_1.FpsCounter, { playbackSpeed: playbackRate }), (0, jsx_runtime_1.jsx)(layout_1.Spacing, { x: 2 }), (0, jsx_runtime_1.jsx)(RenderButton_1.RenderButton, {}), (0, jsx_runtime_1.jsx)(layout_1.Spacing, { x: 1.5 })] }), (0, jsx_runtime_1.jsx)(PlaybackKeyboardShortcutsManager_1.PlaybackKeyboardShortcutsManager, { setPlaybackRate: setPlaybackRate }), (0, jsx_runtime_1.jsx)(PlaybackRatePersistor_1.PlaybackRatePersistor, {})] }));
51
54
  };
52
55
  exports.PreviewToolbar = PreviewToolbar;
@@ -0,0 +1,6 @@
1
+ import React from 'react';
2
+ import type { AssetMetadata } from '../helpers/get-asset-metadata';
3
+ export declare const RenderPreview: React.FC<{
4
+ path: string;
5
+ assetMetadata: AssetMetadata | null;
6
+ }>;
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RenderPreview = void 0;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const react_1 = require("react");
6
+ const client_id_1 = require("../helpers/client-id");
7
+ const colors_1 = require("../helpers/colors");
8
+ const get_asset_metadata_1 = require("../helpers/get-asset-metadata");
9
+ const FilePreview_1 = require("./FilePreview");
10
+ const Preview_1 = require("./Preview");
11
+ const msgStyle = {
12
+ fontSize: 13,
13
+ color: 'white',
14
+ fontFamily: 'sans-serif',
15
+ display: 'flex',
16
+ justifyContent: 'center',
17
+ };
18
+ const errMsgStyle = {
19
+ ...msgStyle,
20
+ color: colors_1.LIGHT_TEXT,
21
+ };
22
+ const RenderPreview = ({ path, assetMetadata }) => {
23
+ const fileType = (0, Preview_1.getPreviewFileType)(path);
24
+ const src = get_asset_metadata_1.remotion_outputsBase + path;
25
+ const connectionStatus = (0, react_1.useContext)(client_id_1.StudioServerConnectionCtx).type;
26
+ if (connectionStatus === 'disconnected') {
27
+ return (0, jsx_runtime_1.jsx)("div", { style: errMsgStyle, children: "Studio server disconnected" });
28
+ }
29
+ return ((0, jsx_runtime_1.jsx)(FilePreview_1.FilePreview, { assetMetadata: assetMetadata, currentAsset: path, fileType: fileType, src: src }));
30
+ };
31
+ exports.RenderPreview = RenderPreview;
@@ -27,11 +27,12 @@ const supportsCopyingToClipboard = (job) => {
27
27
  return false;
28
28
  };
29
29
  exports.supportsCopyingToClipboard = supportsCopyingToClipboard;
30
- const RenderQueueCopyToClipboard = ({ job, }) => {
30
+ const RenderQueueCopyToClipboard = ({ job }) => {
31
31
  const renderCopyAction = (0, react_1.useCallback)((color) => {
32
32
  return (0, jsx_runtime_1.jsx)(clipboard_1.ClipboardIcon, { style: revealIconStyle, color: color });
33
33
  }, []);
34
- const onClick = (0, react_1.useCallback)(() => {
34
+ const onClick = (0, react_1.useCallback)((e) => {
35
+ e.stopPropagation();
35
36
  (0, actions_1.copyToClipboard)({ outName: job.outName })
36
37
  .catch((err) => {
37
38
  (0, NotificationCenter_1.sendErrorNotification)(`Could not copy to clipboard: ${err.message}`);
@@ -2,4 +2,5 @@ import React from 'react';
2
2
  import type { RenderJob } from '../../../preview-server/render-queue/job';
3
3
  export declare const RenderQueueItem: React.FC<{
4
4
  job: RenderJob;
5
+ selected: boolean;
5
6
  }>;