@remotion/cli 3.3.82 → 3.3.83

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 (45) hide show
  1. package/dist/codemods/update-default-props.js +7 -8
  2. package/dist/color-math.d.ts +1 -0
  3. package/dist/color-math.js +12 -0
  4. package/dist/config/index.d.ts +1 -0
  5. package/dist/config/index.js +3 -0
  6. package/dist/config/user-agent.d.ts +4 -0
  7. package/dist/config/user-agent.js +12 -0
  8. package/dist/editor/components/Canvas.js +1 -4
  9. package/dist/editor/components/NewComposition/RemInputTypeColor.d.ts +8 -0
  10. package/dist/editor/components/NewComposition/RemInputTypeColor.js +53 -0
  11. package/dist/editor/components/RenderModal/RenderModal.js +8 -7
  12. package/dist/editor/components/RenderModal/RenderModalAdvanced.js +2 -0
  13. package/dist/editor/components/RenderModal/RenderModalData.js +42 -12
  14. package/dist/editor/components/RenderModal/RenderModalJSONInputPropsEditor.d.ts +1 -0
  15. package/dist/editor/components/RenderModal/RenderModalJSONInputPropsEditor.js +22 -2
  16. package/dist/editor/components/RenderModal/SchemaEditor/ZodColorEditor.d.ts +14 -0
  17. package/dist/editor/components/RenderModal/SchemaEditor/ZodColorEditor.js +108 -0
  18. package/dist/editor/components/RenderModal/SchemaEditor/ZodSwitch.js +4 -0
  19. package/dist/editor/components/RenderModal/SchemaEditor/create-zod-values.js +3 -0
  20. package/dist/editor/components/RenderToolbarIcon.js +3 -1
  21. package/dist/editor/components/RendersTab.js +3 -3
  22. package/dist/editor/components/RightPanel.js +2 -7
  23. package/dist/editor/components/SidebarCollapserControls.js +81 -10
  24. package/dist/editor/components/SizeSelector.js +1 -1
  25. package/dist/editor/components/Tabs/index.d.ts +1 -0
  26. package/dist/editor/components/Tabs/index.js +12 -5
  27. package/dist/editor/components/Tabs/vertical.d.ts +12 -0
  28. package/dist/editor/components/Tabs/vertical.js +57 -0
  29. package/dist/ffmpeg.js +2 -2
  30. package/dist/get-cli-options.js +1 -0
  31. package/dist/parse-command-line.d.ts +1 -0
  32. package/dist/parse-command-line.js +3 -0
  33. package/dist/preview-server/routes/can-update-default-props.d.ts +4 -0
  34. package/dist/preview-server/routes/can-update-default-props.js +38 -0
  35. package/package.json +6 -6
  36. package/dist/editor/components/CheckerboardContext.d.ts +0 -0
  37. package/dist/editor/components/CheckerboardContext.js +0 -1
  38. package/dist/editor/components/CollapsedSidebarExpander.d.ts +0 -5
  39. package/dist/editor/components/CollapsedSidebarExpander.js +0 -40
  40. package/dist/editor/components/RenderModal/SchemaEditor/ZodOrNullEditor.d.ts +0 -15
  41. package/dist/editor/components/RenderModal/SchemaEditor/ZodOrNullEditor.js +0 -45
  42. package/dist/editor/components/RenderModal/SchemaEditor/schema-serialization.d.ts +0 -2
  43. package/dist/editor/components/RenderModal/SchemaEditor/schema-serialization.js +0 -21
  44. package/dist/editor/components/SidebarContent.d.ts +0 -5
  45. package/dist/editor/components/SidebarContent.js +0 -53
@@ -61,7 +61,7 @@ const findEndPosition = (input, currentPosition) => {
61
61
  }
62
62
  throw new Error('Could not find end of defaultProps');
63
63
  };
64
- const findEnder = (input, position, maxPosition) => {
64
+ const findEnder = (input, position, maxPosition, compositionId) => {
65
65
  let currentPosition = position;
66
66
  while (currentPosition < maxPosition) {
67
67
  const next = findEndPosition(input, currentPosition);
@@ -72,7 +72,7 @@ const findEnder = (input, position, maxPosition) => {
72
72
  }
73
73
  return [position, currentPosition + 1];
74
74
  }
75
- throw new Error('did not find string');
75
+ throw new Error(`No \`defaultProps\` prop found in the <Composition/> tag with the ID "${compositionId}".`);
76
76
  };
77
77
  const findTerminators = (input, position) => {
78
78
  const nextComposition = input.indexOf('<Composition', position);
@@ -101,23 +101,22 @@ const stringifyDefaultProps = (props) => {
101
101
  .replace(/__ADD_AS_CONST__"/g, '" as const');
102
102
  };
103
103
  // TODO: Add more sanity checks
104
- // TODO: better error messages
105
104
  const updateDefaultProps = async ({ input, compositionId, newDefaultProps, }) => {
106
105
  const starter = findStarter({ input, compositionId });
107
106
  const START_TOKEN = 'defaultProps={';
108
107
  const start = input.indexOf(START_TOKEN, starter);
109
108
  if (start === -1) {
110
- throw new Error('Could not find defaultProps in <Composition> tag');
109
+ throw new Error(`No \`defaultProps\` prop found in the <Composition/> tag with the ID "${compositionId}".`);
111
110
  }
112
111
  const maxEnd = findTerminators(input, starter);
113
- const [startPos, endPos] = findEnder(input, start + START_TOKEN.length, maxEnd);
112
+ const [startPos, endPos] = findEnder(input, start + START_TOKEN.length, maxEnd, compositionId);
114
113
  // eslint-disable-next-line @typescript-eslint/consistent-type-imports
115
114
  let prettier = null;
116
115
  try {
117
116
  prettier = await Promise.resolve().then(() => __importStar(require('prettier')));
118
117
  }
119
118
  catch (err) {
120
- throw new Error('Cannot save default props because Prettier cannot be found in the current project.');
119
+ throw new Error('Prettier cannot be found in the current project.');
121
120
  }
122
121
  const { format, resolveConfig, resolveConfigFile } = prettier;
123
122
  const newFile = input.substring(0, startPos) +
@@ -125,11 +124,11 @@ const updateDefaultProps = async ({ input, compositionId, newDefaultProps, }) =>
125
124
  input.substring(endPos);
126
125
  const configFilePath = await resolveConfigFile();
127
126
  if (!configFilePath) {
128
- throw new Error('prettier config file not found');
127
+ throw new Error('The Prettier config file was not found');
129
128
  }
130
129
  const prettierConfig = await resolveConfig(configFilePath);
131
130
  if (!prettierConfig) {
132
- throw new Error('Prettier config not found');
131
+ throw new Error(`The Prettier config at ${configFilePath} could not be read`);
133
132
  }
134
133
  const prettified = format(newFile, {
135
134
  ...prettierConfig,
@@ -0,0 +1 @@
1
+ export declare const colorWithNewOpacity: (color: string, opacity: number) => string;
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.colorWithNewOpacity = void 0;
4
+ const remotion_1 = require("remotion");
5
+ const colorWithNewOpacity = (color, opacity) => {
6
+ const { r, g, b } = remotion_1.Internals.parseColor(color);
7
+ if (opacity >= 255) {
8
+ return `#${r.toString(16)}${g.toString(16)}${b.toString(16)}`;
9
+ }
10
+ return `rgba(${r}, ${g}, ${b}, ${(opacity / 255).toFixed(2)})`;
11
+ };
12
+ exports.colorWithNewOpacity = colorWithNewOpacity;
@@ -56,5 +56,6 @@ export declare const ConfigInternals: {
56
56
  getNumberOfGifLoops: () => import("./number-of-gif-loops").Loop;
57
57
  getWebpackPolling: () => number | null;
58
58
  getShouldOpenBrowser: () => boolean;
59
+ getChromiumUserAgent: () => string | null;
59
60
  };
60
61
  export declare const overrideRemotion: () => void;
@@ -82,6 +82,7 @@ const public_dir_1 = require("./public-dir");
82
82
  const quality_2 = require("./quality");
83
83
  const scale_2 = require("./scale");
84
84
  const timeout_2 = require("./timeout");
85
+ const user_agent_1 = require("./user-agent");
85
86
  const webpack_caching_2 = require("./webpack-caching");
86
87
  const webpack_poll_1 = require("./webpack-poll");
87
88
  const width_1 = require("./width");
@@ -110,6 +111,7 @@ const Puppeteer = {
110
111
  setChromiumIgnoreCertificateErrors: chromium_flags_2.setChromiumIgnoreCertificateErrors,
111
112
  setChromiumHeadlessMode: chromium_flags_2.setChromiumHeadlessMode,
112
113
  setChromiumOpenGlRenderer: chromium_flags_2.setChromiumOpenGlRenderer,
114
+ setChromiumUserAgent: user_agent_1.setChromiumUserAgent,
113
115
  };
114
116
  const Rendering = {
115
117
  setDotEnvLocation: env_file_2.setDotEnvLocation,
@@ -207,6 +209,7 @@ exports.ConfigInternals = {
207
209
  getNumberOfGifLoops: number_of_gif_loops_1.getNumberOfGifLoops,
208
210
  getWebpackPolling: webpack_poll_1.getWebpackPolling,
209
211
  getShouldOpenBrowser: open_browser_1.getShouldOpenBrowser,
212
+ getChromiumUserAgent: user_agent_1.getChromiumUserAgent,
210
213
  };
211
214
  const overrideRemotion = () => {
212
215
  Object.assign(remotion_1.Config, exports.Config);
@@ -0,0 +1,4 @@
1
+ declare type UserAgent = string | null;
2
+ export declare const setChromiumUserAgent: (newAgent: UserAgent) => void;
3
+ export declare const getChromiumUserAgent: () => UserAgent;
4
+ export {};
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getChromiumUserAgent = exports.setChromiumUserAgent = void 0;
4
+ let userAgent = null;
5
+ const setChromiumUserAgent = (newAgent) => {
6
+ userAgent = newAgent;
7
+ };
8
+ exports.setChromiumUserAgent = setChromiumUserAgent;
9
+ const getChromiumUserAgent = () => {
10
+ return userAgent;
11
+ };
12
+ exports.getChromiumUserAgent = getChromiumUserAgent;
@@ -37,10 +37,7 @@ const Canvas = () => {
37
37
  triggerOnWindowResize: false,
38
38
  shouldApplyCssTransforms: true,
39
39
  });
40
- const isFit = previewSize.size === 'auto' ||
41
- (previewSize.size === 1 &&
42
- previewSize.translation.x === 0 &&
43
- previewSize.translation.y === 0);
40
+ const isFit = previewSize.size === 'auto';
44
41
  const onWheel = (0, react_1.useCallback)((e) => {
45
42
  if (!editorZoomGestures) {
46
43
  return;
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ import type { RemInputStatus } from './RemInput';
3
+ declare type Props = React.DetailedHTMLProps<React.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement> & {
4
+ status: RemInputStatus;
5
+ };
6
+ export declare const inputBaseStyle: React.CSSProperties;
7
+ export declare const RemInputTypeColor: React.ForwardRefExoticComponent<Pick<Props, "key" | "status" | keyof React.InputHTMLAttributes<HTMLInputElement>> & React.RefAttributes<HTMLInputElement>>;
8
+ export {};
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RemInputTypeColor = exports.inputBaseStyle = void 0;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const react_1 = require("react");
6
+ const colors_1 = require("../../helpers/colors");
7
+ const z_index_1 = require("../../state/z-index");
8
+ const RemInput_1 = require("./RemInput");
9
+ exports.inputBaseStyle = {
10
+ padding: 0,
11
+ borderStyle: 'solid',
12
+ borderWidth: 1,
13
+ };
14
+ const RemInputTypeColorForwardRef = ({ status, ...props }, ref) => {
15
+ const [isFocused, setIsFocused] = (0, react_1.useState)(false);
16
+ const [isHovered, setIsHovered] = (0, react_1.useState)(false);
17
+ const inputRef = (0, react_1.useRef)(null);
18
+ const { tabIndex } = (0, z_index_1.useZIndex)();
19
+ const style = (0, react_1.useMemo)(() => {
20
+ var _a;
21
+ return {
22
+ backgroundColor: colors_1.INPUT_BACKGROUND,
23
+ ...exports.inputBaseStyle,
24
+ borderColor: (0, RemInput_1.getInputBorderColor)({ isFocused, isHovered, status }),
25
+ ...((_a = props.style) !== null && _a !== void 0 ? _a : {}),
26
+ };
27
+ }, [isFocused, isHovered, props.style, status]);
28
+ (0, react_1.useImperativeHandle)(ref, () => {
29
+ return inputRef.current;
30
+ }, []);
31
+ (0, react_1.useEffect)(() => {
32
+ if (!inputRef.current) {
33
+ return;
34
+ }
35
+ const { current } = inputRef;
36
+ const onFocus = () => setIsFocused(true);
37
+ const onBlur = () => setIsFocused(false);
38
+ const onMouseEnter = () => setIsHovered(true);
39
+ const onMouseLeave = () => setIsHovered(false);
40
+ current.addEventListener('focus', onFocus);
41
+ current.addEventListener('blur', onBlur);
42
+ current.addEventListener('mouseenter', onMouseEnter);
43
+ current.addEventListener('mouseleave', onMouseLeave);
44
+ return () => {
45
+ current.removeEventListener('focus', onFocus);
46
+ current.removeEventListener('blur', onBlur);
47
+ current.removeEventListener('mouseenter', onMouseEnter);
48
+ current.removeEventListener('mouseleave', onMouseLeave);
49
+ };
50
+ }, [inputRef]);
51
+ return ((0, jsx_runtime_1.jsx)("input", { ref: inputRef, type: "color", tabIndex: tabIndex, ...props, style: style }));
52
+ };
53
+ exports.RemInputTypeColor = (0, react_1.forwardRef)(RemInputTypeColorForwardRef);
@@ -24,7 +24,7 @@ const ModalHeader_1 = require("../ModalHeader");
24
24
  const actions_1 = require("../RenderQueue/actions");
25
25
  const RightPanel_1 = require("../RightPanel");
26
26
  const SegmentedControl_1 = require("../SegmentedControl");
27
- const Tabs_1 = require("../Tabs");
27
+ const vertical_1 = require("../Tabs/vertical");
28
28
  const CrfSetting_1 = require("./CrfSetting");
29
29
  const out_name_checker_1 = require("./out-name-checker");
30
30
  const RenderModalAdvanced_1 = require("./RenderModalAdvanced");
@@ -103,6 +103,7 @@ const buttonStyle = {
103
103
  const flexer = {
104
104
  flex: 1,
105
105
  };
106
+ // TODO: Copy edited props from Props editor to Render modal
106
107
  const RenderModal = ({ compositionId, initialFrame, initialVideoImageFormat, initialStillImageFormat, initialJpegQuality, initialScale, initialVerbose, initialOutName, initialRenderType, initialVideoCodecForAudioTab, initialVideoCodecForVideoTab, initialConcurrency, maxConcurrency, minConcurrency, initialMuted, initialEnforceAudioTrack, initialProResProfile, initialPixelFormat, initialVideoBitrate, initialAudioBitrate, initialEveryNthFrame, initialNumberOfGifLoops, initialDelayRenderTimeout, initialAudioCodec, initialEnvVariables, initialDisableWebSecurity, initialGl, initialHeadless, initialIgnoreCertificateErrors, }) => {
107
108
  const { setSelectedModal } = (0, react_1.useContext)(modals_1.ModalsContext);
108
109
  const onQuit = (0, react_1.useCallback)(() => {
@@ -284,10 +285,10 @@ const RenderModal = ({ compositionId, initialFrame, initialVideoImageFormat, ini
284
285
  setStillImageFormat(format);
285
286
  setDefaultOutName({ type: 'still', imageFormat: format });
286
287
  }, [setDefaultOutName]);
287
- const { setSidebarCollapsedStateRight } = (0, react_1.useContext)(sidebar_1.SidebarContext);
288
+ const { setSidebarCollapsedState } = (0, react_1.useContext)(sidebar_1.SidebarContext);
288
289
  const onClickStill = (0, react_1.useCallback)(() => {
289
290
  var _a;
290
- setSidebarCollapsedStateRight('expanded');
291
+ setSidebarCollapsedState({ left: null, right: 'expanded' });
291
292
  (0, RightPanel_1.persistSelectedPanel)('renders');
292
293
  (_a = RightPanel_1.rightSidebarTabs.current) === null || _a === void 0 ? void 0 : _a.selectRendersPanel();
293
294
  dispatchIfMounted({ type: 'start' });
@@ -312,7 +313,7 @@ const RenderModal = ({ compositionId, initialFrame, initialVideoImageFormat, ini
312
313
  dispatchIfMounted({ type: 'fail' });
313
314
  });
314
315
  }, [
315
- setSidebarCollapsedStateRight,
316
+ setSidebarCollapsedState,
316
317
  dispatchIfMounted,
317
318
  compositionId,
318
319
  outName,
@@ -337,7 +338,7 @@ const RenderModal = ({ compositionId, initialFrame, initialVideoImageFormat, ini
337
338
  const audioCodec = deriveFinalAudioCodec(codec, userSelectedAudioCodec);
338
339
  const onClickVideo = (0, react_1.useCallback)(() => {
339
340
  var _a;
340
- setSidebarCollapsedStateRight('expanded');
341
+ setSidebarCollapsedState({ left: null, right: 'expanded' });
341
342
  (0, RightPanel_1.persistSelectedPanel)('renders');
342
343
  (_a = RightPanel_1.rightSidebarTabs.current) === null || _a === void 0 ? void 0 : _a.selectRendersPanel();
343
344
  dispatchIfMounted({ type: 'start' });
@@ -376,7 +377,7 @@ const RenderModal = ({ compositionId, initialFrame, initialVideoImageFormat, ini
376
377
  dispatchIfMounted({ type: 'fail' });
377
378
  });
378
379
  }, [
379
- setSidebarCollapsedStateRight,
380
+ setSidebarCollapsedState,
380
381
  dispatchIfMounted,
381
382
  compositionId,
382
383
  outName,
@@ -561,6 +562,6 @@ const RenderModal = ({ compositionId, initialFrame, initialVideoImageFormat, ini
561
562
  backgroundColor: outnameValidation.valid
562
563
  ? 'var(--blue)'
563
564
  : 'var(--blue-disabled)',
564
- }, children: [state.type === 'idle' ? `Render ${renderMode}` : 'Rendering...', (0, jsx_runtime_1.jsx)(ShortcutHint_1.ShortcutHint, { keyToPress: "\u21B5", cmdOrCtrl: true })] })] }), (0, jsx_runtime_1.jsxs)("div", { style: horizontalLayout, children: [(0, jsx_runtime_1.jsxs)("div", { style: leftSidebar, children: [shownTabs.includes('general') ? ((0, jsx_runtime_1.jsxs)(Tabs_1.Tab, { style: horizontalTab, selected: tab === 'general', onClick: () => setTab('general'), children: [(0, jsx_runtime_1.jsx)("div", { style: iconContainer, children: (0, jsx_runtime_1.jsx)(file_1.FileIcon, { style: icon }) }), "General"] })) : null, shownTabs.includes('data') ? ((0, jsx_runtime_1.jsxs)(Tabs_1.Tab, { style: horizontalTab, selected: tab === 'data', onClick: () => setTab('data'), children: [(0, jsx_runtime_1.jsx)("div", { style: iconContainer, children: (0, jsx_runtime_1.jsx)(data_1.DataIcon, { style: icon }) }), "Input Props"] })) : null, shownTabs.includes('picture') ? ((0, jsx_runtime_1.jsxs)(Tabs_1.Tab, { style: horizontalTab, selected: tab === 'picture', onClick: () => setTab('picture'), children: [(0, jsx_runtime_1.jsx)("div", { style: iconContainer, children: (0, jsx_runtime_1.jsx)(frame_1.PicIcon, { style: icon }) }), "Picture"] })) : null, shownTabs.includes('audio') ? ((0, jsx_runtime_1.jsxs)(Tabs_1.Tab, { style: horizontalTab, selected: tab === 'audio', onClick: () => setTab('audio'), children: [(0, jsx_runtime_1.jsx)("div", { style: iconContainer, children: (0, jsx_runtime_1.jsx)(audio_1.AudioIcon, { style: icon }) }), "Audio"] })) : null, shownTabs.includes('gif') ? ((0, jsx_runtime_1.jsxs)(Tabs_1.Tab, { style: horizontalTab, selected: tab === 'gif', onClick: () => setTab('gif'), children: [(0, jsx_runtime_1.jsx)("div", { style: iconContainer, children: (0, jsx_runtime_1.jsx)(gif_1.GifIcon, { style: icon }) }), "GIF"] })) : null, shownTabs.includes('advanced') ? ((0, jsx_runtime_1.jsxs)(Tabs_1.Tab, { style: horizontalTab, selected: tab === 'advanced', onClick: () => setTab('advanced'), children: [(0, jsx_runtime_1.jsx)("div", { style: iconContainer, children: (0, jsx_runtime_1.jsx)(gear_1.GearIcon, { style: icon }) }), "Other"] })) : null] }), (0, jsx_runtime_1.jsx)("div", { style: rightPanel, className: is_menu_item_1.VERTICAL_SCROLLBAR_CLASSNAME, children: tab === 'general' ? ((0, jsx_runtime_1.jsx)(RenderModalBasic_1.RenderModalBasic, { codec: codec, currentComposition: currentComposition, frame: frame, imageFormatOptions: imageFormatOptions, outName: outName, proResProfile: proResProfile, renderMode: renderMode, setVideoCodec: setCodec, setFrame: setFrame, setOutName: setOutName, setProResProfile: setProResProfile, endFrame: endFrame, setEndFrame: setEndFrame, setStartFrame: setStartFrame, startFrame: startFrame, validationMessage: outnameValidation.valid ? null : outnameValidation.error.message })) : tab === 'picture' ? ((0, jsx_runtime_1.jsx)(RenderModalPicture_1.RenderModalPicture, { renderMode: renderMode, scale: scale, setScale: setScale, pixelFormat: pixelFormat, setPixelFormat: setPixelFormat, imageFormatOptions: imageFormatOptions, crf: crf, setCrf: setCrf, customTargetVideoBitrate: customTargetVideoBitrate, maxCrf: maxCrf, minCrf: minCrf, jpegQuality: jpegQuality, qualityControlType: qualityControlType, setJpegQuality: setJpegQuality, setCustomTargetVideoBitrateValue: setCustomTargetVideoBitrateValue, setQualityControl: setQualityControl, shouldDisplayCrfOption: shouldDisplayCrfOption, videoImageFormat: videoImageFormat, stillImageFormat: stillImageFormat })) : tab === 'audio' ? ((0, jsx_runtime_1.jsx)(RenderModalAudio_1.RenderModalAudio, { muted: muted, renderMode: renderMode, setMuted: setMuted, codec: codec, audioCodec: audioCodec, setAudioCodec: setAudioCodec, enforceAudioTrack: enforceAudioTrack, setEnforceAudioTrackState: setEnforceAudioTrackState, customTargetAudioBitrate: customTargetAudioBitrate, setCustomTargetAudioBitrateValue: setCustomTargetAudioBitrateValue, setShouldHaveCustomTargetAudioBitrate: setShouldHaveCustomTargetAudioBitrate, shouldHaveCustomTargetAudioBitrate: shouldHaveCustomTargetAudioBitrate })) : tab === 'gif' ? ((0, jsx_runtime_1.jsx)(RenderModalGif_1.RenderModalGif, { everyNthFrame: everyNthFrame, limitNumberOfGifLoops: limitNumberOfGifLoops, numberOfGifLoopsSetting: numberOfGifLoopsSetting, setEveryNthFrameSetting: setEveryNthFrameSetting, setLimitNumberOfGifLoops: setLimitNumberOfGifLoops, setNumberOfGifLoopsSetting: setNumberOfGifLoopsSetting })) : tab === 'data' ? ((0, jsx_runtime_1.jsx)(RenderModalData_1.RenderModalData, { inputProps: inputProps, setInputProps: setInputProps, composition: currentComposition, compact: false, mayShowSaveButton: false })) : ((0, jsx_runtime_1.jsx)(RenderModalAdvanced_1.RenderModalAdvanced, { concurrency: concurrency, maxConcurrency: maxConcurrency, minConcurrency: minConcurrency, renderMode: renderMode, setConcurrency: setConcurrency, setVerboseLogging: setVerboseLogging, verbose: verbose, delayRenderTimeout: delayRenderTimeout, setDelayRenderTimeout: setDelayRenderTimeout, disallowParallelEncoding: disallowParallelEncoding, setDisallowParallelEncoding: setDisallowParallelEncoding, setDisableWebSecurity: setDisableWebSecurity, setIgnoreCertificateErrors: setIgnoreCertificateErrors, setHeadless: setHeadless, headless: headless, ignoreCertificateErrors: ignoreCertificateErrors, disableWebSecurity: disableWebSecurity, openGlOption: openGlOption, setOpenGlOption: setOpenGlOption, setEnvVariables: setEnvVariables, envVariables: envVariables })) })] })] }));
565
+ }, children: [state.type === 'idle' ? `Render ${renderMode}` : 'Rendering...', (0, jsx_runtime_1.jsx)(ShortcutHint_1.ShortcutHint, { keyToPress: "\u21B5", cmdOrCtrl: true })] })] }), (0, jsx_runtime_1.jsxs)("div", { style: horizontalLayout, children: [(0, jsx_runtime_1.jsxs)("div", { style: leftSidebar, children: [shownTabs.includes('general') ? ((0, jsx_runtime_1.jsxs)(vertical_1.VerticalTab, { style: horizontalTab, selected: tab === 'general', onClick: () => setTab('general'), children: [(0, jsx_runtime_1.jsx)("div", { style: iconContainer, children: (0, jsx_runtime_1.jsx)(file_1.FileIcon, { style: icon }) }), "General"] })) : null, shownTabs.includes('data') ? ((0, jsx_runtime_1.jsxs)(vertical_1.VerticalTab, { style: horizontalTab, selected: tab === 'data', onClick: () => setTab('data'), children: [(0, jsx_runtime_1.jsx)("div", { style: iconContainer, children: (0, jsx_runtime_1.jsx)(data_1.DataIcon, { style: icon }) }), "Input Props"] })) : null, shownTabs.includes('picture') ? ((0, jsx_runtime_1.jsxs)(vertical_1.VerticalTab, { style: horizontalTab, selected: tab === 'picture', onClick: () => setTab('picture'), children: [(0, jsx_runtime_1.jsx)("div", { style: iconContainer, children: (0, jsx_runtime_1.jsx)(frame_1.PicIcon, { style: icon }) }), "Picture"] })) : null, shownTabs.includes('audio') ? ((0, jsx_runtime_1.jsxs)(vertical_1.VerticalTab, { style: horizontalTab, selected: tab === 'audio', onClick: () => setTab('audio'), children: [(0, jsx_runtime_1.jsx)("div", { style: iconContainer, children: (0, jsx_runtime_1.jsx)(audio_1.AudioIcon, { style: icon }) }), "Audio"] })) : null, shownTabs.includes('gif') ? ((0, jsx_runtime_1.jsxs)(vertical_1.VerticalTab, { style: horizontalTab, selected: tab === 'gif', onClick: () => setTab('gif'), children: [(0, jsx_runtime_1.jsx)("div", { style: iconContainer, children: (0, jsx_runtime_1.jsx)(gif_1.GifIcon, { style: icon }) }), "GIF"] })) : null, shownTabs.includes('advanced') ? ((0, jsx_runtime_1.jsxs)(vertical_1.VerticalTab, { style: horizontalTab, selected: tab === 'advanced', onClick: () => setTab('advanced'), children: [(0, jsx_runtime_1.jsx)("div", { style: iconContainer, children: (0, jsx_runtime_1.jsx)(gear_1.GearIcon, { style: icon }) }), "Other"] })) : null] }), (0, jsx_runtime_1.jsx)("div", { style: rightPanel, className: is_menu_item_1.VERTICAL_SCROLLBAR_CLASSNAME, children: tab === 'general' ? ((0, jsx_runtime_1.jsx)(RenderModalBasic_1.RenderModalBasic, { codec: codec, currentComposition: currentComposition, frame: frame, imageFormatOptions: imageFormatOptions, outName: outName, proResProfile: proResProfile, renderMode: renderMode, setVideoCodec: setCodec, setFrame: setFrame, setOutName: setOutName, setProResProfile: setProResProfile, endFrame: endFrame, setEndFrame: setEndFrame, setStartFrame: setStartFrame, startFrame: startFrame, validationMessage: outnameValidation.valid ? null : outnameValidation.error.message })) : tab === 'picture' ? ((0, jsx_runtime_1.jsx)(RenderModalPicture_1.RenderModalPicture, { renderMode: renderMode, scale: scale, setScale: setScale, pixelFormat: pixelFormat, setPixelFormat: setPixelFormat, imageFormatOptions: imageFormatOptions, crf: crf, setCrf: setCrf, customTargetVideoBitrate: customTargetVideoBitrate, maxCrf: maxCrf, minCrf: minCrf, jpegQuality: jpegQuality, qualityControlType: qualityControlType, setJpegQuality: setJpegQuality, setCustomTargetVideoBitrateValue: setCustomTargetVideoBitrateValue, setQualityControl: setQualityControl, shouldDisplayCrfOption: shouldDisplayCrfOption, videoImageFormat: videoImageFormat, stillImageFormat: stillImageFormat })) : tab === 'audio' ? ((0, jsx_runtime_1.jsx)(RenderModalAudio_1.RenderModalAudio, { muted: muted, renderMode: renderMode, setMuted: setMuted, codec: codec, audioCodec: audioCodec, setAudioCodec: setAudioCodec, enforceAudioTrack: enforceAudioTrack, setEnforceAudioTrackState: setEnforceAudioTrackState, customTargetAudioBitrate: customTargetAudioBitrate, setCustomTargetAudioBitrateValue: setCustomTargetAudioBitrateValue, setShouldHaveCustomTargetAudioBitrate: setShouldHaveCustomTargetAudioBitrate, shouldHaveCustomTargetAudioBitrate: shouldHaveCustomTargetAudioBitrate })) : tab === 'gif' ? ((0, jsx_runtime_1.jsx)(RenderModalGif_1.RenderModalGif, { everyNthFrame: everyNthFrame, limitNumberOfGifLoops: limitNumberOfGifLoops, numberOfGifLoopsSetting: numberOfGifLoopsSetting, setEveryNthFrameSetting: setEveryNthFrameSetting, setLimitNumberOfGifLoops: setLimitNumberOfGifLoops, setNumberOfGifLoopsSetting: setNumberOfGifLoopsSetting })) : tab === 'data' ? ((0, jsx_runtime_1.jsx)(RenderModalData_1.RenderModalData, { inputProps: inputProps, setInputProps: setInputProps, composition: currentComposition, compact: false, mayShowSaveButton: false })) : ((0, jsx_runtime_1.jsx)(RenderModalAdvanced_1.RenderModalAdvanced, { concurrency: concurrency, maxConcurrency: maxConcurrency, minConcurrency: minConcurrency, renderMode: renderMode, setConcurrency: setConcurrency, setVerboseLogging: setVerboseLogging, verbose: verbose, delayRenderTimeout: delayRenderTimeout, setDelayRenderTimeout: setDelayRenderTimeout, disallowParallelEncoding: disallowParallelEncoding, setDisallowParallelEncoding: setDisallowParallelEncoding, setDisableWebSecurity: setDisableWebSecurity, setIgnoreCertificateErrors: setIgnoreCertificateErrors, setHeadless: setHeadless, headless: headless, ignoreCertificateErrors: ignoreCertificateErrors, disableWebSecurity: disableWebSecurity, openGlOption: openGlOption, setOpenGlOption: setOpenGlOption, setEnvVariables: setEnvVariables, envVariables: envVariables })) })] })] }));
565
566
  };
566
567
  exports.RenderModal = RenderModal;
@@ -51,8 +51,10 @@ const RenderModalAdvanced = ({ renderMode, maxConcurrency, minConcurrency, setCo
51
51
  });
52
52
  }, [extendedOpenGlOptions, openGlOption, setOpenGlOption]);
53
53
  return ((0, jsx_runtime_1.jsxs)("div", { style: container, className: is_menu_item_1.VERTICAL_SCROLLBAR_CLASSNAME, children: [renderMode === 'still' ? null : ((0, jsx_runtime_1.jsx)(NumberSetting_1.NumberSetting, { min: minConcurrency, max: maxConcurrency, step: 1, name: "Concurrency", formatter: (w) => `${w}x`, onValueChanged: setConcurrency, value: concurrency })), (0, jsx_runtime_1.jsx)(NumberSetting_1.NumberSetting
54
+ // TODO: Should be right aligned
54
55
  // Also appears in packages/renderer/src/validate-puppeteer-timeout.ts
55
56
  , {
57
+ // TODO: Should be right aligned
56
58
  // Also appears in packages/renderer/src/validate-puppeteer-timeout.ts
57
59
  min: 7000, max: 900000, name: "delayRender() timeout", onValueChanged: setDelayRenderTimeout, formatter: (w) => `${w}ms`, step: 1000, value: delayRenderTimeout }), (0, jsx_runtime_1.jsxs)("div", { style: layout_1.optionRow, children: [(0, jsx_runtime_1.jsx)("div", { style: layout_1.label, children: "No parallel encoding" }), (0, jsx_runtime_1.jsx)("div", { style: layout_1.rightRow, children: (0, jsx_runtime_1.jsx)(Checkbox_1.Checkbox, { checked: disallowParallelEncoding, onChange: onDisallowParallelEncodingChanged }) })] }), (0, jsx_runtime_1.jsxs)("div", { style: layout_1.optionRow, children: [(0, jsx_runtime_1.jsx)("div", { style: layout_1.label, children: "Verbose logging" }), (0, jsx_runtime_1.jsx)("div", { style: layout_1.rightRow, children: (0, jsx_runtime_1.jsx)(Checkbox_1.Checkbox, { checked: verbose, onChange: onVerboseLoggingChanged }) })] }), (0, jsx_runtime_1.jsx)(RenderModalHr_1.RenderModalHr, {}), (0, jsx_runtime_1.jsxs)("div", { style: layout_1.optionRow, children: [(0, jsx_runtime_1.jsx)("div", { style: layout_1.label, children: "Disable web security" }), (0, jsx_runtime_1.jsx)("div", { style: layout_1.rightRow, children: (0, jsx_runtime_1.jsx)(Checkbox_1.Checkbox, { checked: disableWebSecurity, onChange: onDisableWebSecurityChanged }) })] }), (0, jsx_runtime_1.jsxs)("div", { style: layout_1.optionRow, children: [(0, jsx_runtime_1.jsx)("div", { style: layout_1.label, children: "Ignore certificate errors " }), (0, jsx_runtime_1.jsx)("div", { style: layout_1.rightRow, children: (0, jsx_runtime_1.jsx)(Checkbox_1.Checkbox, { checked: ignoreCertificateErrors, onChange: onIgnoreCertificatErrors }) })] }), (0, jsx_runtime_1.jsxs)("div", { style: layout_1.optionRow, children: [(0, jsx_runtime_1.jsx)("div", { style: layout_1.label, children: "Headless mode" }), (0, jsx_runtime_1.jsx)("div", { style: layout_1.rightRow, children: (0, jsx_runtime_1.jsx)(Checkbox_1.Checkbox, { checked: headless, onChange: onHeadless }) })] }), (0, jsx_runtime_1.jsxs)("div", { style: layout_1.optionRow, children: [(0, jsx_runtime_1.jsx)("div", { style: layout_1.label, children: "OpenGL render backend" }), (0, jsx_runtime_1.jsx)("div", { style: layout_1.rightRow, children: (0, jsx_runtime_1.jsx)(ComboBox_1.Combobox, { values: openGlOptions, selectedId: openGlOption, title: "OpenGl option" }) })] }), (0, jsx_runtime_1.jsx)(RenderModalHr_1.RenderModalHr, {}), (0, jsx_runtime_1.jsx)(RenderModalEnvironmentVariables_1.RenderModalEnvironmentVariables, { envVariables: envVariables, setEnvVariables: setEnvVariables })] }));
58
60
  };
@@ -3,7 +3,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.RenderModalData = 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 colors_1 = require("../../helpers/colors");
8
+ const ValidationMessage_1 = require("../NewComposition/ValidationMessage");
9
+ const layout_1 = require("../layout");
7
10
  const actions_1 = require("../RenderQueue/actions");
8
11
  const SegmentedControl_1 = require("../SegmentedControl");
9
12
  const RenderModalJSONInputPropsEditor_1 = require("./RenderModalJSONInputPropsEditor");
@@ -15,31 +18,57 @@ const outer = {
15
18
  overflow: 'hidden',
16
19
  };
17
20
  const controlContainer = {
18
- flexDirection: 'row',
21
+ flexDirection: 'column',
19
22
  display: 'flex',
20
- paddingLeft: 12,
21
- paddingTop: 12,
22
- paddingBottom: 12,
23
+ padding: 12,
23
24
  borderBottom: `1px solid ${colors_1.BORDER_COLOR}`,
24
25
  };
26
+ const tabWrapper = {
27
+ display: 'flex',
28
+ marginBottom: '4px',
29
+ flexDirection: 'row',
30
+ };
31
+ const spacer = {
32
+ flex: 1,
33
+ };
25
34
  const RenderModalData = ({ composition, inputProps, setInputProps, compact, mayShowSaveButton }) => {
26
35
  const [mode, setMode] = (0, react_1.useState)('schema');
27
36
  const [valBeforeSafe, setValBeforeSafe] = (0, react_1.useState)(inputProps);
28
37
  const zodValidationResult = (0, react_1.useMemo)(() => {
29
38
  return composition.schema.safeParse(inputProps);
30
39
  }, [composition.schema, inputProps]);
31
- const [canSaveDefaultProps, setCanSaveDefaultProps] = (0, react_1.useState)(false);
32
- const showSaveButton = mayShowSaveButton && canSaveDefaultProps;
33
- // TODO: Show reason
40
+ const cliProps = (0, remotion_1.getInputProps)();
41
+ const [canSaveDefaultProps, setCanSaveDefaultProps] = (0, react_1.useState)({
42
+ canUpdate: false,
43
+ reason: 'Loading...',
44
+ determined: false,
45
+ });
46
+ const showSaveButton = mayShowSaveButton && canSaveDefaultProps.canUpdate;
47
+ // TODO: Disable if Preview Server is disconnected
34
48
  // TODO: Update if root file is updated
49
+ // TODO: Segment the state for different compositions
35
50
  (0, react_1.useEffect)(() => {
36
51
  (0, actions_1.canUpdateDefaultProps)(composition.id)
37
52
  .then((can) => {
38
- setCanSaveDefaultProps(can.canUpdate);
53
+ if (can.canUpdate) {
54
+ setCanSaveDefaultProps({
55
+ canUpdate: true,
56
+ });
57
+ }
58
+ else {
59
+ setCanSaveDefaultProps({
60
+ canUpdate: false,
61
+ reason: can.reason,
62
+ determined: true,
63
+ });
64
+ }
39
65
  })
40
- .catch(() => {
41
- // TODO: Use error as reason
42
- setCanSaveDefaultProps(false);
66
+ .catch((err) => {
67
+ setCanSaveDefaultProps({
68
+ canUpdate: false,
69
+ reason: err.message,
70
+ determined: true,
71
+ });
43
72
  });
44
73
  }, [composition.id]);
45
74
  const modeItems = (0, react_1.useMemo)(() => {
@@ -72,6 +101,7 @@ const RenderModalData = ({ composition, inputProps, setInputProps, compact, mayS
72
101
  const onSave = (0, react_1.useCallback)((updater) => {
73
102
  (0, actions_1.updateDefaultProps)(composition.id, updater(composition.defaultProps));
74
103
  }, [composition.defaultProps, composition.id]);
75
- return ((0, jsx_runtime_1.jsxs)("div", { style: outer, children: [(0, jsx_runtime_1.jsx)("div", { style: controlContainer, children: (0, jsx_runtime_1.jsx)(SegmentedControl_1.SegmentedControl, { items: modeItems, needsWrapping: false }) }), mode === 'schema' ? ((0, jsx_runtime_1.jsx)(SchemaEditor_1.SchemaEditor, { value: inputProps, setValue: setInputProps, schema: composition.schema, zodValidationResult: zodValidationResult, compact: compact, defaultProps: composition.defaultProps, onSave: onSave, showSaveButton: showSaveButton })) : ((0, jsx_runtime_1.jsx)(RenderModalJSONInputPropsEditor_1.RenderModalJSONInputPropsEditor, { value: inputProps !== null && inputProps !== void 0 ? inputProps : {}, setValue: setInputProps, zodValidationResult: zodValidationResult, switchToSchema: switchToSchema, onSave: onUpdate, valBeforeSafe: valBeforeSafe }))] }));
104
+ return ((0, jsx_runtime_1.jsxs)("div", { style: outer, children: [(0, jsx_runtime_1.jsxs)("div", { style: controlContainer, children: [(0, jsx_runtime_1.jsxs)("div", { style: tabWrapper, children: [(0, jsx_runtime_1.jsx)(SegmentedControl_1.SegmentedControl, { items: modeItems, needsWrapping: false }), (0, jsx_runtime_1.jsx)("div", { style: spacer })] }), Object.keys(cliProps).length > 0 ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(layout_1.Spacing, { y: 1 }), (0, jsx_runtime_1.jsx)(ValidationMessage_1.ValidationMessage, { message: "The data that was passed using --props takes priority over the data you enter here.", align: "flex-start", type: "warning" })] })) : null, canSaveDefaultProps.canUpdate === false &&
105
+ canSaveDefaultProps.determined ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(layout_1.Spacing, { y: 1 }), (0, jsx_runtime_1.jsx)(ValidationMessage_1.ValidationMessage, { message: `Can't save default props: ${canSaveDefaultProps.reason}`, align: "flex-start", type: "warning" })] })) : null] }), mode === 'schema' ? ((0, jsx_runtime_1.jsx)(SchemaEditor_1.SchemaEditor, { value: inputProps, setValue: setInputProps, schema: composition.schema, zodValidationResult: zodValidationResult, compact: compact, defaultProps: composition.defaultProps, onSave: onSave, showSaveButton: showSaveButton })) : ((0, jsx_runtime_1.jsx)(RenderModalJSONInputPropsEditor_1.RenderModalJSONInputPropsEditor, { value: inputProps !== null && inputProps !== void 0 ? inputProps : {}, setValue: setInputProps, zodValidationResult: zodValidationResult, switchToSchema: switchToSchema, onSave: onUpdate, valBeforeSafe: valBeforeSafe, showSaveButton: showSaveButton }))] }));
76
106
  };
77
107
  exports.RenderModalData = RenderModalData;
@@ -7,4 +7,5 @@ export declare const RenderModalJSONInputPropsEditor: React.FC<{
7
7
  switchToSchema: () => void;
8
8
  onSave: () => void;
9
9
  valBeforeSafe: unknown;
10
+ showSaveButton: boolean;
10
11
  }>;
@@ -27,6 +27,7 @@ exports.RenderModalJSONInputPropsEditor = void 0;
27
27
  const jsx_runtime_1 = require("react/jsx-runtime");
28
28
  const react_1 = __importStar(require("react"));
29
29
  const Button_1 = require("../../../preview-server/error-overlay/remotion-overlay/Button");
30
+ const use_keybinding_1 = require("../../helpers/use-keybinding");
30
31
  const layout_1 = require("../layout");
31
32
  const RemTextarea_1 = require("../NewComposition/RemTextarea");
32
33
  const ValidationMessage_1 = require("../NewComposition/ValidationMessage");
@@ -58,7 +59,8 @@ const scrollable = {
58
59
  flex: 1,
59
60
  };
60
61
  // TODO: Note if custom 'remotion-date:' pattern has been used
61
- const RenderModalJSONInputPropsEditor = ({ setValue, value, zodValidationResult, switchToSchema, onSave, valBeforeSafe, }) => {
62
+ const RenderModalJSONInputPropsEditor = ({ setValue, value, zodValidationResult, switchToSchema, onSave, valBeforeSafe, showSaveButton, }) => {
63
+ const keybindings = (0, use_keybinding_1.useKeybinding)();
62
64
  const [localValue, setLocalValue] = react_1.default.useState(() => {
63
65
  return parseJSON((0, date_serialization_1.serializeJSONWithDate)(value, 2));
64
66
  });
@@ -92,7 +94,25 @@ const RenderModalJSONInputPropsEditor = ({ setValue, value, zodValidationResult,
92
94
  const hasChanged = (0, react_1.useMemo)(() => {
93
95
  return value && JSON.stringify(value) !== JSON.stringify(valBeforeSafe);
94
96
  }, [valBeforeSafe, value]);
97
+ const onQuickSave = (0, react_1.useCallback)(() => {
98
+ if (hasChanged) {
99
+ onSave();
100
+ }
101
+ }, [hasChanged, onSave]);
102
+ (0, react_1.useEffect)(() => {
103
+ const save = keybindings.registerKeybinding({
104
+ event: 'keydown',
105
+ key: 's',
106
+ commandCtrlKey: true,
107
+ callback: onQuickSave,
108
+ preventDefault: true,
109
+ triggerIfInputFieldFocused: true,
110
+ });
111
+ return () => {
112
+ save.unregister();
113
+ };
114
+ }, [keybindings, onQuickSave, onSave]);
95
115
  // TODO: Indicate saving progress
96
- return ((0, jsx_runtime_1.jsxs)("div", { style: scrollable, children: [(0, jsx_runtime_1.jsx)(RemTextarea_1.RemTextarea, { onChange: onChange, value: localValue.str, status: localValue.validJSON ? 'ok' : 'error', style: style }), (0, jsx_runtime_1.jsx)(layout_1.Spacing, { y: 1 }), localValue.validJSON === false ? ((0, jsx_runtime_1.jsx)(ValidationMessage_1.ValidationMessage, { align: "flex-start", message: localValue.error, type: "error" })) : zodValidationResult.success === false ? ((0, jsx_runtime_1.jsx)("button", { type: "button", style: schemaButton, onClick: switchToSchema, children: (0, jsx_runtime_1.jsx)(ValidationMessage_1.ValidationMessage, { align: "flex-start", message: "Does not match schema", type: "warning" }) })) : null, (0, jsx_runtime_1.jsx)(layout_1.Spacing, { y: 1 }), (0, jsx_runtime_1.jsxs)(layout_1.Row, { children: [(0, jsx_runtime_1.jsx)(Button_1.Button, { disabled: !localValue.validJSON, onClick: onPretty, children: "Format JSON" }), (0, jsx_runtime_1.jsx)(layout_1.Spacing, { x: 1 }), (0, jsx_runtime_1.jsx)(Button_1.Button, { onClick: onSave, disabled: !zodValidationResult.success || !hasChanged, children: "Save" })] })] }));
116
+ return ((0, jsx_runtime_1.jsxs)("div", { style: scrollable, children: [(0, jsx_runtime_1.jsx)(RemTextarea_1.RemTextarea, { onChange: onChange, value: localValue.str, status: localValue.validJSON ? 'ok' : 'error', style: style }), (0, jsx_runtime_1.jsx)(layout_1.Spacing, { y: 1 }), localValue.validJSON === false ? ((0, jsx_runtime_1.jsx)(ValidationMessage_1.ValidationMessage, { align: "flex-start", message: localValue.error, type: "error" })) : zodValidationResult.success === false ? ((0, jsx_runtime_1.jsx)("button", { type: "button", style: schemaButton, onClick: switchToSchema, children: (0, jsx_runtime_1.jsx)(ValidationMessage_1.ValidationMessage, { align: "flex-start", message: "Does not match schema", type: "warning" }) })) : null, (0, jsx_runtime_1.jsx)(layout_1.Spacing, { y: 1 }), (0, jsx_runtime_1.jsxs)(layout_1.Row, { children: [(0, jsx_runtime_1.jsx)(Button_1.Button, { disabled: !localValue.validJSON, onClick: onPretty, children: "Format JSON" }), (0, jsx_runtime_1.jsx)(layout_1.Spacing, { x: 1 }), (0, jsx_runtime_1.jsx)(Button_1.Button, { onClick: onSave, disabled: !zodValidationResult.success || !hasChanged || !showSaveButton, children: "Save" })] })] }));
97
117
  };
98
118
  exports.RenderModalJSONInputPropsEditor = RenderModalJSONInputPropsEditor;
@@ -0,0 +1,14 @@
1
+ import React from 'react';
2
+ import type { z } from 'remotion';
3
+ import type { JSONPath } from './zod-types';
4
+ export declare const ZodColorEditor: React.FC<{
5
+ schema: z.ZodTypeAny;
6
+ jsonPath: JSONPath;
7
+ value: string;
8
+ defaultValue: string;
9
+ setValue: React.Dispatch<React.SetStateAction<string>>;
10
+ onSave: (updater: (oldNum: unknown) => string) => void;
11
+ onRemove: null | (() => void);
12
+ compact: boolean;
13
+ showSaveButton: boolean;
14
+ }>;
@@ -0,0 +1,108 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ZodColorEditor = void 0;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const react_1 = require("react");
6
+ const remotion_1 = require("remotion");
7
+ const color_math_1 = require("../../../../color-math");
8
+ const layout_1 = require("../../layout");
9
+ const InputDragger_1 = require("../../NewComposition/InputDragger");
10
+ const RemInput_1 = require("../../NewComposition/RemInput");
11
+ const RemInputTypeColor_1 = require("../../NewComposition/RemInputTypeColor");
12
+ const ValidationMessage_1 = require("../../NewComposition/ValidationMessage");
13
+ const layout_2 = require("../layout");
14
+ const SchemaLabel_1 = require("./SchemaLabel");
15
+ const fullWidth = {
16
+ width: '100%',
17
+ };
18
+ const ZodColorEditor = ({ jsonPath, value, setValue, showSaveButton, defaultValue, schema, compact, onSave, onRemove, }) => {
19
+ const [localValue, setLocalValue] = (0, react_1.useState)(() => {
20
+ return {
21
+ value,
22
+ zodValidation: schema.safeParse(value),
23
+ };
24
+ });
25
+ const onValueChange = (0, react_1.useCallback)((newValue) => {
26
+ const safeParse = schema.safeParse(newValue);
27
+ const newLocalState = {
28
+ value: newValue,
29
+ zodValidation: safeParse,
30
+ };
31
+ setLocalValue(newLocalState);
32
+ if (safeParse.success) {
33
+ setValue(newValue);
34
+ }
35
+ }, [schema, setValue]);
36
+ const { a, b, g, r } = localValue.zodValidation.success
37
+ ? remotion_1.Internals.parseColor(localValue.value)
38
+ : { a: 1, b: 0, g: 0, r: 0 };
39
+ const onChange = (0, react_1.useCallback)((e) => {
40
+ const newColor = (0, color_math_1.colorWithNewOpacity)(e.target.value, Math.round(a));
41
+ const safeParse = schema.safeParse(newColor);
42
+ const newLocalState = {
43
+ value: newColor,
44
+ zodValidation: safeParse,
45
+ };
46
+ setLocalValue(newLocalState);
47
+ if (safeParse.success) {
48
+ setValue(newColor);
49
+ }
50
+ }, [a, schema, setValue]);
51
+ const onTextChange = (0, react_1.useCallback)((e) => {
52
+ const newValue = e.target.value;
53
+ const safeParse = schema.safeParse(newValue);
54
+ const newLocalState = {
55
+ value: newValue,
56
+ zodValidation: safeParse,
57
+ };
58
+ setLocalValue(newLocalState);
59
+ if (safeParse.success) {
60
+ setValue(newValue);
61
+ }
62
+ }, [schema, setValue]);
63
+ const reset = (0, react_1.useCallback)(() => {
64
+ onValueChange(defaultValue);
65
+ }, [defaultValue, onValueChange]);
66
+ const save = (0, react_1.useCallback)(() => {
67
+ onSave(() => value);
68
+ }, [onSave, value]);
69
+ const rgb = `#${r.toString(16).padStart(2, '0')}${g
70
+ .toString(16)
71
+ .padStart(2, '0')}${b.toString(16).padStart(2, '0')}`;
72
+ const status = localValue.zodValidation.success ? 'ok' : 'error';
73
+ const colorPicker = (0, react_1.useMemo)(() => {
74
+ return {
75
+ height: 39,
76
+ width: 45,
77
+ display: 'inline-block',
78
+ };
79
+ }, []);
80
+ const onOpacityChange = (0, react_1.useCallback)((newValue) => {
81
+ const newColor = (0, color_math_1.colorWithNewOpacity)(localValue.value, Math.round((Number(newValue) / 100) * 255));
82
+ const safeParse = schema.safeParse(newColor);
83
+ const newLocalState = {
84
+ value: newColor,
85
+ zodValidation: safeParse,
86
+ };
87
+ setLocalValue(newLocalState);
88
+ if (safeParse.success) {
89
+ setValue(newColor);
90
+ }
91
+ }, [localValue.value, schema, setValue]);
92
+ const onOpacityValueChange = (0, react_1.useCallback)((newValue) => {
93
+ const newColor = (0, color_math_1.colorWithNewOpacity)(localValue.value, Math.round((Number(newValue) / 100) * 255));
94
+ const safeParse = schema.safeParse(newColor);
95
+ const newLocalState = {
96
+ value: String(newColor),
97
+ zodValidation: safeParse,
98
+ };
99
+ setLocalValue(newLocalState);
100
+ if (safeParse.success) {
101
+ setValue(newColor);
102
+ }
103
+ }, [localValue.value, schema, setValue]);
104
+ return ((0, jsx_runtime_1.jsxs)("div", { style: compact ? layout_2.narrowOption : layout_2.optionRow, children: [(0, jsx_runtime_1.jsx)(SchemaLabel_1.SchemaLabel, { compact: compact, isDefaultValue: value === defaultValue, jsonPath: jsonPath, onReset: reset, onSave: save, showSaveButton: showSaveButton, onRemove: onRemove }), (0, jsx_runtime_1.jsxs)("div", { style: fullWidth, children: [(0, jsx_runtime_1.jsxs)(layout_1.Row, { align: "center", children: [(0, jsx_runtime_1.jsx)("div", { style: colorPicker, children: (0, jsx_runtime_1.jsx)(RemInputTypeColor_1.RemInputTypeColor, { type: "color", style: {
105
+ height: 39,
106
+ }, value: rgb, onChange: onChange, className: "__remotion_color_picker", status: status }) }), (0, jsx_runtime_1.jsx)(layout_1.Spacing, { x: 1, block: true }), (0, jsx_runtime_1.jsx)(RemInput_1.RemotionInput, { value: localValue.value, status: status, placeholder: jsonPath.join('.'), onChange: onTextChange }), (0, jsx_runtime_1.jsx)(layout_1.Spacing, { x: 1 }), (0, jsx_runtime_1.jsx)(InputDragger_1.InputDragger, { onTextChange: onOpacityChange, onValueChange: onOpacityValueChange, status: status, value: (a / 255) * 100, min: 0, max: 100, step: 1, formatter: (v) => `${Math.round(Number(v))}%` })] }), !localValue.zodValidation.success && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(layout_1.Spacing, { y: 1, block: true }), (0, jsx_runtime_1.jsx)(ValidationMessage_1.ValidationMessage, { align: "flex-end", message: localValue.zodValidation.error.format()._errors[0], type: "error" })] }))] })] }));
107
+ };
108
+ exports.ZodColorEditor = ZodColorEditor;
@@ -5,6 +5,7 @@ const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const remotion_1 = require("remotion");
6
6
  const ZodArrayEditor_1 = require("./ZodArrayEditor");
7
7
  const ZodBooleanEditor_1 = require("./ZodBooleanEditor");
8
+ const ZodColorEditor_1 = require("./ZodColorEditor");
8
9
  const ZodDateEditor_1 = require("./ZodDateEditor");
9
10
  const ZodEffectEditor_1 = require("./ZodEffectEditor");
10
11
  const ZodEnumEditor_1 = require("./ZodEnumEditor");
@@ -55,6 +56,9 @@ const ZodSwitch = ({ schema, jsonPath, compact, value, setValue, defaultValue, o
55
56
  return ((0, jsx_runtime_1.jsx)(ZodEnumEditor_1.ZodEnumEditor, { setValue: setValue, value: value, jsonPath: jsonPath, schema: schema, compact: compact, defaultValue: defaultValue, onSave: onSave, showSaveButton: showSaveButton, onRemove: onRemove }));
56
57
  }
57
58
  if (typeName === remotion_1.z.ZodFirstPartyTypeKind.ZodEffects) {
59
+ if (schema._def.description === remotion_1.Internals.REMOTION_COLOR_BRAND) {
60
+ return ((0, jsx_runtime_1.jsx)(ZodColorEditor_1.ZodColorEditor, { value: value, setValue: setValue, jsonPath: jsonPath, schema: schema, compact: compact, onSave: onSave, defaultValue: defaultValue, showSaveButton: showSaveButton, onRemove: onRemove }));
61
+ }
58
62
  return ((0, jsx_runtime_1.jsx)(ZodEffectEditor_1.ZodEffectEditor, { value: value, setValue: setValue, jsonPath: jsonPath, schema: schema, compact: compact, defaultValue: defaultValue, onSave: onSave, showSaveButton: showSaveButton, onRemove: onRemove }));
59
63
  }
60
64
  if (typeName === remotion_1.z.ZodFirstPartyTypeKind.ZodUnion) {
@@ -59,6 +59,9 @@ const createZodValues = (schema) => {
59
59
  return def.value;
60
60
  }
61
61
  case remotion_1.z.ZodFirstPartyTypeKind.ZodEffects: {
62
+ if (schema._def.description === remotion_1.Internals.REMOTION_COLOR_BRAND) {
63
+ return '#ffffff';
64
+ }
62
65
  return (0, exports.createZodValues)(def.schema);
63
66
  }
64
67
  case remotion_1.z.ZodFirstPartyTypeKind.ZodIntersection: {
@@ -7,6 +7,7 @@ const remotion_1 = require("remotion");
7
7
  const get_default_out_name_1 = require("../../get-default-out-name");
8
8
  const get_default_video_contexts_1 = require("../../preview-server/render-queue/get-default-video-contexts");
9
9
  const client_id_1 = require("../helpers/client-id");
10
+ const use_keybinding_1 = require("../helpers/use-keybinding");
10
11
  const render_1 = require("../icons/render");
11
12
  const modals_1 = require("../state/modals");
12
13
  const ControlButton_1 = require("./ControlButton");
@@ -20,8 +21,9 @@ const RenderButton = () => {
20
21
  },
21
22
  };
22
23
  }, []);
24
+ const shortcut = (0, use_keybinding_1.areKeyboardShortcutsDisabled)() ? '' : '(R)';
23
25
  const tooltip = type === 'connected'
24
- ? 'Export the current composition'
26
+ ? 'Export the current composition ' + shortcut
25
27
  : 'Connect to the preview server to render';
26
28
  const video = remotion_1.Internals.useVideo();
27
29
  const frame = (0, remotion_1.useCurrentFrame)();