@remotion/studio 4.0.438 → 4.0.440

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 (140) hide show
  1. package/dist/Studio.js +2 -2
  2. package/dist/api/helpers/calc-new-props.js +5 -8
  3. package/dist/api/update-default-props.d.ts +7 -3
  4. package/dist/api/update-default-props.js +7 -21
  5. package/dist/api/visual-control.js +6 -0
  6. package/dist/components/DefaultPropsEditor.d.ts +8 -0
  7. package/dist/components/DefaultPropsEditor.js +15 -0
  8. package/dist/components/Editor.js +0 -14
  9. package/dist/components/EditorContexts.js +6 -3
  10. package/dist/components/KeyboardShortcutsExplainer.js +6 -2
  11. package/dist/components/MenuBuildIndicator.js +1 -0
  12. package/dist/components/MenuToolbar.js +3 -1
  13. package/dist/components/NewComposition/InputDragger.js +2 -2
  14. package/dist/components/NewComposition/RemTextarea.js +4 -0
  15. package/dist/components/ObserveDefaultPropsContext.d.ts +11 -0
  16. package/dist/components/ObserveDefaultPropsContext.js +120 -0
  17. package/dist/components/OptionsPanel.js +90 -28
  18. package/dist/components/RenderModal/CrfSetting.d.ts +1 -1
  19. package/dist/components/RenderModal/DataEditor.d.ts +4 -5
  20. package/dist/components/RenderModal/DataEditor.js +9 -111
  21. package/dist/components/RenderModal/RenderModalJSONPropsEditor.d.ts +1 -1
  22. package/dist/components/RenderModal/RenderModalJSONPropsEditor.js +52 -48
  23. package/dist/components/RenderModal/SchemaEditor/Fieldset.d.ts +0 -1
  24. package/dist/components/RenderModal/SchemaEditor/SchemaEditor.d.ts +4 -9
  25. package/dist/components/RenderModal/SchemaEditor/SchemaEditor.js +2 -61
  26. package/dist/components/RenderModal/SchemaEditor/SchemaErrorMessages.d.ts +0 -1
  27. package/dist/components/RenderModal/SchemaEditor/SchemaErrorMessages.js +2 -3
  28. package/dist/components/RenderModal/SchemaEditor/SchemaLabel.d.ts +0 -6
  29. package/dist/components/RenderModal/SchemaEditor/SchemaLabel.js +2 -5
  30. package/dist/components/RenderModal/SchemaEditor/SchemaSeparationLine.d.ts +3 -1
  31. package/dist/components/RenderModal/SchemaEditor/SchemaSeparationLine.js +1 -1
  32. package/dist/components/RenderModal/SchemaEditor/ZodArrayEditor.d.ts +1 -6
  33. package/dist/components/RenderModal/SchemaEditor/ZodArrayEditor.js +15 -26
  34. package/dist/components/RenderModal/SchemaEditor/ZodArrayItemEditor.d.ts +0 -5
  35. package/dist/components/RenderModal/SchemaEditor/ZodArrayItemEditor.js +7 -12
  36. package/dist/components/RenderModal/SchemaEditor/ZodBooleanEditor.d.ts +0 -7
  37. package/dist/components/RenderModal/SchemaEditor/ZodBooleanEditor.js +5 -15
  38. package/dist/components/RenderModal/SchemaEditor/ZodColorEditor.d.ts +1 -6
  39. package/dist/components/RenderModal/SchemaEditor/ZodColorEditor.js +30 -28
  40. package/dist/components/RenderModal/SchemaEditor/ZodDateEditor.d.ts +1 -6
  41. package/dist/components/RenderModal/SchemaEditor/ZodDateEditor.js +13 -17
  42. package/dist/components/RenderModal/SchemaEditor/ZodDefaultEditor.d.ts +0 -5
  43. package/dist/components/RenderModal/SchemaEditor/ZodDefaultEditor.js +2 -2
  44. package/dist/components/RenderModal/SchemaEditor/ZodDiscriminatedUnionEditor.d.ts +1 -6
  45. package/dist/components/RenderModal/SchemaEditor/ZodDiscriminatedUnionEditor.js +13 -28
  46. package/dist/components/RenderModal/SchemaEditor/ZodEffectEditor.d.ts +1 -5
  47. package/dist/components/RenderModal/SchemaEditor/ZodEffectEditor.js +11 -12
  48. package/dist/components/RenderModal/SchemaEditor/ZodEnumEditor.d.ts +1 -5
  49. package/dist/components/RenderModal/SchemaEditor/ZodEnumEditor.js +12 -16
  50. package/dist/components/RenderModal/SchemaEditor/ZodFieldValidation.d.ts +2 -2
  51. package/dist/components/RenderModal/SchemaEditor/ZodFieldValidation.js +1 -2
  52. package/dist/components/RenderModal/SchemaEditor/ZodMatrixEditor.d.ts +1 -6
  53. package/dist/components/RenderModal/SchemaEditor/ZodMatrixEditor.js +20 -30
  54. package/dist/components/RenderModal/SchemaEditor/ZodNonEditableValue.d.ts +0 -2
  55. package/dist/components/RenderModal/SchemaEditor/ZodNonEditableValue.js +3 -6
  56. package/dist/components/RenderModal/SchemaEditor/ZodNullableEditor.d.ts +0 -5
  57. package/dist/components/RenderModal/SchemaEditor/ZodNullableEditor.js +2 -2
  58. package/dist/components/RenderModal/SchemaEditor/ZodNumberEditor.d.ts +1 -6
  59. package/dist/components/RenderModal/SchemaEditor/ZodNumberEditor.js +16 -21
  60. package/dist/components/RenderModal/SchemaEditor/ZodObjectEditor.d.ts +2 -7
  61. package/dist/components/RenderModal/SchemaEditor/ZodObjectEditor.js +27 -49
  62. package/dist/components/RenderModal/SchemaEditor/ZodOptionalEditor.d.ts +0 -5
  63. package/dist/components/RenderModal/SchemaEditor/ZodOptionalEditor.js +2 -2
  64. package/dist/components/RenderModal/SchemaEditor/ZodOrNullishEditor.d.ts +1 -6
  65. package/dist/components/RenderModal/SchemaEditor/ZodOrNullishEditor.js +8 -15
  66. package/dist/components/RenderModal/SchemaEditor/ZodStaticFileEditor.d.ts +1 -6
  67. package/dist/components/RenderModal/SchemaEditor/ZodStaticFileEditor.js +10 -15
  68. package/dist/components/RenderModal/SchemaEditor/ZodStringEditor.d.ts +1 -6
  69. package/dist/components/RenderModal/SchemaEditor/ZodStringEditor.js +13 -17
  70. package/dist/components/RenderModal/SchemaEditor/ZodSwitch.d.ts +3 -6
  71. package/dist/components/RenderModal/SchemaEditor/ZodSwitch.js +27 -27
  72. package/dist/components/RenderModal/SchemaEditor/ZodTextareaEditor.d.ts +0 -5
  73. package/dist/components/RenderModal/SchemaEditor/ZodTextareaEditor.js +45 -17
  74. package/dist/components/RenderModal/SchemaEditor/ZodTupleEditor.d.ts +1 -6
  75. package/dist/components/RenderModal/SchemaEditor/ZodTupleEditor.js +15 -26
  76. package/dist/components/RenderModal/SchemaEditor/ZodTupleItemEditor.d.ts +0 -5
  77. package/dist/components/RenderModal/SchemaEditor/ZodTupleItemEditor.js +4 -11
  78. package/dist/components/RenderModal/SchemaEditor/ZodUnionEditor.d.ts +0 -5
  79. package/dist/components/RenderModal/SchemaEditor/ZodUnionEditor.js +6 -6
  80. package/dist/components/RenderModal/ServerRenderModal.js +9 -3
  81. package/dist/components/RenderModal/WebRenderModal.js +9 -3
  82. package/dist/components/RenderModal/get-default-codecs.d.ts +5 -5
  83. package/dist/components/RenderModal/get-render-modal-warnings.d.ts +1 -2
  84. package/dist/components/RenderModal/get-render-modal-warnings.js +4 -6
  85. package/dist/components/RenderModal/human-readable-codec.d.ts +1 -1
  86. package/dist/components/RenderModal/human-readable-codec.js +3 -0
  87. package/dist/components/RenderModal/out-name-checker.d.ts +1 -1
  88. package/dist/components/RenderQueue/actions.d.ts +2 -3
  89. package/dist/components/RenderQueue/actions.js +1 -13
  90. package/dist/components/Timeline/Timeline.js +1 -1
  91. package/dist/components/Timeline/TimelineExpandedSection.js +7 -1
  92. package/dist/components/Timeline/TimelineFieldRow.d.ts +1 -0
  93. package/dist/components/Timeline/TimelineFieldRow.js +25 -3
  94. package/dist/components/Timeline/TimelineImageInfo.d.ts +5 -0
  95. package/dist/components/Timeline/TimelineImageInfo.js +61 -0
  96. package/dist/components/Timeline/TimelineListItem.js +1 -2
  97. package/dist/components/Timeline/TimelineNumberField.js +4 -6
  98. package/dist/components/Timeline/TimelineRotationField.js +4 -6
  99. package/dist/components/Timeline/TimelineSequence.js +9 -4
  100. package/dist/components/Timeline/TimelineStack/index.js +3 -1
  101. package/dist/components/Timeline/TimelineTracks.js +1 -1
  102. package/dist/components/Timeline/TimelineTranslateField.js +28 -13
  103. package/dist/components/TopPanel.js +10 -5
  104. package/dist/components/UndoRedoButtons.d.ts +2 -0
  105. package/dist/components/UndoRedoButtons.js +116 -0
  106. package/dist/components/VisualControls/VisualControlHandle.js +18 -18
  107. package/dist/components/VisualControls/VisualControlsUndoSync.d.ts +2 -0
  108. package/dist/components/VisualControls/VisualControlsUndoSync.js +23 -0
  109. package/dist/error-overlay/react-overlay/listen-to-runtime-errors.js +0 -1
  110. package/dist/esm/{chunk-ba0scebn.js → chunk-1x2ychmc.js} +4466 -5252
  111. package/dist/esm/index.mjs +25 -28
  112. package/dist/esm/internals.mjs +4466 -5252
  113. package/dist/esm/previewEntry.mjs +4652 -5497
  114. package/dist/esm/renderEntry.mjs +6 -6
  115. package/dist/helpers/client-id.js +13 -1
  116. package/dist/helpers/document-title.d.ts +0 -1
  117. package/dist/helpers/document-title.js +1 -17
  118. package/dist/helpers/render-modal-sections.d.ts +1 -1
  119. package/dist/helpers/timeline-layout.d.ts +1 -1
  120. package/dist/helpers/timeline-layout.js +1 -1
  121. package/dist/hot-middleware-client/client.d.ts +1 -6
  122. package/dist/hot-middleware-client/client.js +22 -73
  123. package/dist/hot-middleware-client/process-update.d.ts +0 -2
  124. package/dist/hot-middleware-client/process-update.js +6 -14
  125. package/dist/icons/redo.d.ts +3 -0
  126. package/dist/icons/redo.js +8 -0
  127. package/dist/icons/undo.d.ts +3 -0
  128. package/dist/icons/undo.js +8 -0
  129. package/dist/renderEntry.js +7 -6
  130. package/dist/visual-controls/VisualControls.js +9 -5
  131. package/dist/visual-controls/get-current-edited-value.js +5 -4
  132. package/dist/visual-controls/visual-control-store.d.ts +7 -0
  133. package/dist/visual-controls/visual-control-store.js +22 -0
  134. package/package.json +9 -9
  135. package/dist/components/GlobalPropsEditorUpdateButton.d.ts +0 -5
  136. package/dist/components/GlobalPropsEditorUpdateButton.js +0 -78
  137. package/dist/components/RenderModal/SchemaEditor/SchemaSaveButton.d.ts +0 -5
  138. package/dist/components/RenderModal/SchemaEditor/SchemaSaveButton.js +0 -18
  139. package/dist/components/RenderModal/SchemaEditor/local-state.d.ts +0 -25
  140. package/dist/components/RenderModal/SchemaEditor/local-state.js +0 -107
@@ -1,7 +1,7 @@
1
1
  import type { RenderType } from './RenderModalAdvanced';
2
2
  export declare const validateOutnameGui: ({ outName, codec, audioCodec, renderMode, stillImageFormat, separateAudioTo, }: {
3
3
  outName: string;
4
- codec: "aac" | "gif" | "h264" | "h264-mkv" | "h264-ts" | "h265" | "mp3" | "prores" | "vp8" | "vp9" | "wav";
4
+ codec: "aac" | "av1" | "gif" | "h264" | "h264-mkv" | "h264-ts" | "h265" | "mp3" | "prores" | "vp8" | "vp9" | "wav";
5
5
  audioCodec: "aac" | "mp3" | "opus" | "pcm-16";
6
6
  renderMode: RenderType;
7
7
  stillImageFormat: "jpeg" | "pdf" | "png" | "webp" | null;
@@ -1,4 +1,4 @@
1
- import type { CanUpdateDefaultPropsResponse, EnumPath, RecastCodemod, RenderJob, VisualControlChange } from '@remotion/studio-shared';
1
+ import type { EnumPath, RecastCodemod, RenderJob, VisualControlChange } from '@remotion/studio-shared';
2
2
  export declare const addStillRenderJob: ({ compositionId, outName, imageFormat, jpegQuality, frame, scale, logLevel, chromiumOptions, delayRenderTimeout, envVariables, inputProps, offthreadVideoCacheSizeInBytes, offthreadVideoThreads, multiProcessOnLinux, beepOnFinish, metadata, chromeMode, mediaCacheSizeInBytes, }: {
3
3
  compositionId: string;
4
4
  outName: string;
@@ -50,7 +50,7 @@ export declare const addVideoRenderJob: ({ compositionId, outName, imageFormat,
50
50
  jpegQuality: number | null;
51
51
  scale: number;
52
52
  logLevel: "error" | "info" | "trace" | "verbose" | "warn";
53
- codec: "aac" | "gif" | "h264" | "h264-mkv" | "h264-ts" | "h265" | "mp3" | "prores" | "vp8" | "vp9" | "wav";
53
+ codec: "aac" | "av1" | "gif" | "h264" | "h264-mkv" | "h264-ts" | "h265" | "mp3" | "prores" | "vp8" | "vp9" | "wav";
54
54
  concurrency: number;
55
55
  crf: number | null;
56
56
  startFrame: number;
@@ -106,7 +106,6 @@ export declare const cancelRenderJob: (job: RenderJob) => Promise<import("@remot
106
106
  export declare const updateAvailable: (signal: AbortSignal) => Promise<import("@remotion/studio-shared").UpdateAvailableResponse>;
107
107
  export declare const getProjectInfo: (signal: AbortSignal) => Promise<import("@remotion/studio-shared").ProjectInfoResponse>;
108
108
  export declare const callUpdateDefaultPropsApi: (compositionId: string, defaultProps: Record<string, unknown>, enumPaths: EnumPath[]) => Promise<import("@remotion/studio-shared").UpdateDefaultPropsResponse>;
109
- export declare const canUpdateDefaultProps: (compositionId: string, readOnlyStudio: boolean) => Promise<CanUpdateDefaultPropsResponse>;
110
109
  export declare const applyVisualControlChange: ({ fileName, changes, }: {
111
110
  fileName: string;
112
111
  changes: VisualControlChange[];
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.applyVisualControlChange = exports.canUpdateDefaultProps = exports.callUpdateDefaultPropsApi = exports.getProjectInfo = exports.updateAvailable = exports.cancelRenderJob = exports.removeRenderJob = exports.applyCodemod = exports.openInFileExplorer = exports.subscribeToFileExistenceWatcher = exports.unsubscribeFromFileExistenceWatcher = exports.addVideoRenderJob = exports.addSequenceRenderJob = exports.addStillRenderJob = void 0;
3
+ exports.applyVisualControlChange = exports.callUpdateDefaultPropsApi = exports.getProjectInfo = exports.updateAvailable = exports.cancelRenderJob = exports.removeRenderJob = exports.applyCodemod = exports.openInFileExplorer = exports.subscribeToFileExistenceWatcher = exports.unsubscribeFromFileExistenceWatcher = exports.addVideoRenderJob = exports.addSequenceRenderJob = exports.addStillRenderJob = void 0;
4
4
  const no_react_1 = require("remotion/no-react");
5
5
  const call_api_1 = require("../call-api");
6
6
  const addStillRenderJob = ({ compositionId, outName, imageFormat, jpegQuality, frame, scale, logLevel, chromiumOptions, delayRenderTimeout, envVariables, inputProps, offthreadVideoCacheSizeInBytes, offthreadVideoThreads, multiProcessOnLinux, beepOnFinish, metadata, chromeMode, mediaCacheSizeInBytes, }) => {
@@ -172,18 +172,6 @@ const callUpdateDefaultPropsApi = (compositionId, defaultProps, enumPaths) => {
172
172
  });
173
173
  };
174
174
  exports.callUpdateDefaultPropsApi = callUpdateDefaultPropsApi;
175
- const canUpdateDefaultProps = (compositionId, readOnlyStudio) => {
176
- if (readOnlyStudio) {
177
- return Promise.resolve({
178
- canUpdate: false,
179
- reason: 'Read-only studio',
180
- });
181
- }
182
- return (0, call_api_1.callApi)('/api/can-update-default-props', {
183
- compositionId,
184
- });
185
- };
186
- exports.canUpdateDefaultProps = canUpdateDefaultProps;
187
175
  const applyVisualControlChange = ({ fileName, changes, }) => {
188
176
  return (0, call_api_1.callApi)('/api/apply-visual-control-change', {
189
177
  fileName,
@@ -100,7 +100,7 @@ const TimelineInner = () => {
100
100
  var _a;
101
101
  const isExpanded = visualModeEnabled && ((_a = expandedTracks[track.sequence.id]) !== null && _a !== void 0 ? _a : false);
102
102
  return (acc +
103
- (0, timeline_layout_1.getTimelineLayerHeight)(track.sequence.type === 'video' ? 'video' : 'other') +
103
+ (0, timeline_layout_1.getTimelineLayerHeight)(track.sequence.type) +
104
104
  Number(timeline_layout_1.TIMELINE_ITEM_BORDER_BOTTOM) +
105
105
  (isExpanded
106
106
  ? (0, timeline_layout_1.getExpandedTrackHeight)(track.sequence.controls) +
@@ -78,9 +78,15 @@ const TimelineExpandedSection = ({ sequence, originalLocation, nestedDepth, node
78
78
  height: expandedHeight,
79
79
  };
80
80
  }, [expandedHeight]);
81
+ const keysToObserve = (0, react_1.useMemo)(() => {
82
+ if (!schemaFields) {
83
+ return [];
84
+ }
85
+ return schemaFields.map((f) => f.key);
86
+ }, [schemaFields]);
81
87
  return (jsx_runtime_1.jsx("div", { style: style, children: schemaFields
82
88
  ? schemaFields.map((field, i) => {
83
- return (jsx_runtime_1.jsxs(react_1.default.Fragment, { children: [i > 0 ? jsx_runtime_1.jsx("div", { style: separator }) : null, jsx_runtime_1.jsx(TimelineFieldRow_1.TimelineFieldRow, { field: field, overrideId: overrideId, validatedLocation: validatedLocation, nestedDepth: nestedDepth, nodePath: nodePath })
89
+ return (jsx_runtime_1.jsxs(react_1.default.Fragment, { children: [i > 0 ? jsx_runtime_1.jsx("div", { style: separator }) : null, jsx_runtime_1.jsx(TimelineFieldRow_1.TimelineFieldRow, { field: field, overrideId: overrideId, validatedLocation: validatedLocation, nestedDepth: nestedDepth, nodePath: nodePath, keysToObserve: keysToObserve })
84
90
  ] }, field.key));
85
91
  })
86
92
  : 'No schema' }));
@@ -8,4 +8,5 @@ export declare const TimelineFieldRow: React.FC<{
8
8
  readonly validatedLocation: CodePosition | null;
9
9
  readonly nestedDepth: number;
10
10
  readonly nodePath: SequenceNodePath | null;
11
+ readonly keysToObserve: string[];
11
12
  }>;
@@ -18,6 +18,7 @@ const fieldRowBase = {
18
18
  const fieldName = {
19
19
  fontSize: 12,
20
20
  color: 'rgba(255, 255, 255, 0.8)',
21
+ userSelect: 'none',
21
22
  };
22
23
  const fieldLabelRow = {
23
24
  flex: '0 0 50%',
@@ -26,7 +27,7 @@ const fieldLabelRow = {
26
27
  alignItems: 'center',
27
28
  gap: 6,
28
29
  };
29
- const TimelineFieldRow = ({ field, overrideId, validatedLocation, nestedDepth, nodePath }) => {
30
+ const TimelineFieldRow = ({ field, overrideId, validatedLocation, nestedDepth, nodePath, keysToObserve, }) => {
30
31
  var _a, _b, _c, _d;
31
32
  const { setDragOverrides, clearDragOverrides, dragOverrides, codeValues: allPropStatuses, } = (0, react_1.useContext)(remotion_1.Internals.VisualModeOverridesContext);
32
33
  const propStatuses = ((_a = allPropStatuses[overrideId]) !== null && _a !== void 0 ? _a : null);
@@ -42,6 +43,7 @@ const TimelineFieldRow = ({ field, overrideId, validatedLocation, nestedDepth, n
42
43
  defaultValue: field.fieldSchema.default,
43
44
  shouldResortToDefaultValueIfUndefined: true,
44
45
  });
46
+ const { setCodeValues } = (0, react_1.useContext)(remotion_1.Internals.VisualModeOverridesContext);
45
47
  const onSave = (0, react_1.useCallback)((key, value) => {
46
48
  if (!propStatuses || !validatedLocation || !nodePath) {
47
49
  return Promise.reject(new Error('Cannot save'));
@@ -59,8 +61,28 @@ const TimelineFieldRow = ({ field, overrideId, validatedLocation, nestedDepth, n
59
61
  key,
60
62
  value: JSON.stringify(value),
61
63
  defaultValue,
62
- }).then(() => undefined);
63
- }, [propStatuses, validatedLocation, nodePath, field.fieldSchema.default]);
64
+ observedKeys: keysToObserve,
65
+ }).then((data) => {
66
+ if (data.success) {
67
+ if (data.newStatus.canUpdate) {
68
+ setCodeValues(overrideId, data.newStatus.props);
69
+ }
70
+ else {
71
+ setCodeValues(overrideId, null);
72
+ }
73
+ return;
74
+ }
75
+ return Promise.reject(new Error(data.reason));
76
+ });
77
+ }, [
78
+ field.fieldSchema.default,
79
+ keysToObserve,
80
+ nodePath,
81
+ overrideId,
82
+ propStatuses,
83
+ setCodeValues,
84
+ validatedLocation,
85
+ ]);
64
86
  const onDragValueChange = (0, react_1.useCallback)((key, value) => {
65
87
  setDragOverrides(overrideId, key, value);
66
88
  }, [setDragOverrides, overrideId]);
@@ -0,0 +1,5 @@
1
+ import React from 'react';
2
+ export declare const TimelineImageInfo: React.FC<{
3
+ readonly src: string;
4
+ readonly visualizationWidth: number;
5
+ }>;
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TimelineImageInfo = void 0;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const react_1 = require("react");
6
+ const timeline_layout_1 = require("../../helpers/timeline-layout");
7
+ const HEIGHT = (0, timeline_layout_1.getTimelineLayerHeight)('image') - 2;
8
+ const containerStyle = {
9
+ height: HEIGHT,
10
+ width: '100%',
11
+ backgroundColor: 'rgba(0, 0, 0, 0.3)',
12
+ display: 'flex',
13
+ borderTopLeftRadius: 2,
14
+ borderBottomLeftRadius: 2,
15
+ };
16
+ const TimelineImageInfo = ({ src, visualizationWidth }) => {
17
+ const ref = (0, react_1.useRef)(null);
18
+ (0, react_1.useEffect)(() => {
19
+ const { current } = ref;
20
+ if (!current) {
21
+ return;
22
+ }
23
+ const canvas = document.createElement('canvas');
24
+ canvas.width = visualizationWidth * window.devicePixelRatio;
25
+ canvas.height = HEIGHT * window.devicePixelRatio;
26
+ canvas.style.width = visualizationWidth + 'px';
27
+ canvas.style.height = HEIGHT + 'px';
28
+ const ctx = canvas.getContext('2d');
29
+ if (!ctx) {
30
+ return;
31
+ }
32
+ current.appendChild(canvas);
33
+ const img = new Image();
34
+ img.crossOrigin = 'anonymous';
35
+ img.onload = () => {
36
+ const scale = (HEIGHT * window.devicePixelRatio) / img.naturalHeight;
37
+ const scaledWidth = img.naturalWidth * scale;
38
+ const scaledHeight = HEIGHT * window.devicePixelRatio;
39
+ const offscreen = document.createElement('canvas');
40
+ offscreen.width = scaledWidth;
41
+ offscreen.height = scaledHeight;
42
+ const offCtx = offscreen.getContext('2d');
43
+ if (!offCtx) {
44
+ return;
45
+ }
46
+ offCtx.drawImage(img, 0, 0, scaledWidth, scaledHeight);
47
+ const pattern = ctx.createPattern(offscreen, 'repeat-x');
48
+ if (!pattern) {
49
+ return;
50
+ }
51
+ ctx.fillStyle = pattern;
52
+ ctx.fillRect(0, 0, visualizationWidth * window.devicePixelRatio, HEIGHT * window.devicePixelRatio);
53
+ };
54
+ img.src = src;
55
+ return () => {
56
+ current.removeChild(canvas);
57
+ };
58
+ }, [src, visualizationWidth]);
59
+ return jsx_runtime_1.jsx("div", { ref: ref, style: containerStyle });
60
+ };
61
+ exports.TimelineImageInfo = TimelineImageInfo;
@@ -69,8 +69,7 @@ const TimelineListItem = ({ nestedDepth, sequence, isCompact }) => {
69
69
  }, [sequence.id, setHidden]);
70
70
  const outer = (0, react_1.useMemo)(() => {
71
71
  return {
72
- height: (0, timeline_layout_1.getTimelineLayerHeight)(sequence.type === 'video' ? 'video' : 'other') +
73
- timeline_layout_1.TIMELINE_ITEM_BORDER_BOTTOM,
72
+ height: (0, timeline_layout_1.getTimelineLayerHeight)(sequence.type) + timeline_layout_1.TIMELINE_ITEM_BORDER_BOTTOM,
74
73
  color: 'white',
75
74
  fontFamily: 'Arial, Helvetica, sans-serif',
76
75
  display: 'flex',
@@ -12,20 +12,18 @@ const TimelineNumberField = ({ field, effectiveValue, canUpdate, onSave, onDragV
12
12
  setDragValue(newVal);
13
13
  onDragValueChange(field.key, newVal);
14
14
  }, [onDragValueChange, field.key]);
15
- (0, react_1.useEffect)(() => {
16
- setDragValue(null);
17
- onDragEnd();
18
- }, [field.currentValue, onDragEnd]);
19
15
  const onValueChangeEnd = (0, react_1.useCallback)((newVal) => {
20
16
  if (canUpdate && newVal !== codeValue) {
21
- onSave(field.key, newVal).catch(() => {
17
+ onSave(field.key, newVal).finally(() => {
22
18
  setDragValue(null);
19
+ onDragEnd();
23
20
  });
24
21
  }
25
22
  else {
26
23
  setDragValue(null);
24
+ onDragEnd();
27
25
  }
28
- }, [canUpdate, onSave, field.key, codeValue]);
26
+ }, [canUpdate, onSave, field.key, codeValue, onDragEnd]);
29
27
  const onTextChange = (0, react_1.useCallback)((newVal) => {
30
28
  if (canUpdate) {
31
29
  const parsed = Number(newVal);
@@ -22,21 +22,19 @@ const TimelineRotationField = ({ field, effectiveValue, codeValue, canUpdate, on
22
22
  setDragValue(newVal);
23
23
  onDragValueChange(field.key, `${newVal}deg`);
24
24
  }, [onDragValueChange, field.key]);
25
- (0, react_1.useEffect)(() => {
26
- setDragValue(null);
27
- onDragEnd();
28
- }, [field.currentValue, onDragEnd]);
29
25
  const onValueChangeEnd = (0, react_1.useCallback)((newVal) => {
30
26
  const newStr = `${newVal}deg`;
31
27
  if (canUpdate && newStr !== codeValue) {
32
- onSave(field.key, newStr).catch(() => {
28
+ onSave(field.key, newStr).finally(() => {
33
29
  setDragValue(null);
30
+ onDragEnd();
34
31
  });
35
32
  }
36
33
  else {
37
34
  setDragValue(null);
35
+ onDragEnd();
38
36
  }
39
- }, [canUpdate, onSave, field.key, codeValue]);
37
+ }, [canUpdate, onSave, field.key, codeValue, onDragEnd]);
40
38
  const onTextChange = (0, react_1.useCallback)((newVal) => {
41
39
  if (canUpdate) {
42
40
  const parsed = Number(newVal);
@@ -10,11 +10,13 @@ const timeline_layout_1 = require("../../helpers/timeline-layout");
10
10
  const use_max_media_duration_1 = require("../../helpers/use-max-media-duration");
11
11
  const AudioWaveform_1 = require("../AudioWaveform");
12
12
  const LoopedTimelineIndicators_1 = require("./LoopedTimelineIndicators");
13
+ const TimelineImageInfo_1 = require("./TimelineImageInfo");
13
14
  const TimelineSequenceFrame_1 = require("./TimelineSequenceFrame");
14
15
  const TimelineVideoInfo_1 = require("./TimelineVideoInfo");
15
16
  const TimelineWidthProvider_1 = require("./TimelineWidthProvider");
16
17
  const AUDIO_GRADIENT = 'linear-gradient(rgb(16 171 58), rgb(43 165 63) 60%)';
17
18
  const VIDEO_GRADIENT = 'linear-gradient(to top, #8e44ad, #9b59b6)';
19
+ const IMAGE_GRADIENT = 'linear-gradient(to top, #2980b9, #3498db)';
18
20
  const TimelineSequence = ({ s }) => {
19
21
  const windowWidth = (0, react_1.useContext)(TimelineWidthProvider_1.TimelineWidthContext);
20
22
  if (windowWidth === null) {
@@ -51,7 +53,7 @@ const Inner = ({ s, windowWidth }) => {
51
53
  ? s.loopDisplay.durationInFrames * s.loopDisplay.numberOfTimes
52
54
  : s.duration,
53
55
  startFrom: s.loopDisplay ? s.from + s.loopDisplay.startOffset : s.from,
54
- startFromMedia: s.type === 'sequence' ? 0 : s.startMediaFrom,
56
+ startFromMedia: s.type === 'sequence' || s.type === 'image' ? 0 : s.startMediaFrom,
55
57
  maxMediaDuration,
56
58
  video,
57
59
  windowWidth,
@@ -65,11 +67,13 @@ const Inner = ({ s, windowWidth }) => {
65
67
  ? AUDIO_GRADIENT
66
68
  : s.type === 'video'
67
69
  ? VIDEO_GRADIENT
68
- : colors_1.BLUE,
70
+ : s.type === 'image'
71
+ ? IMAGE_GRADIENT
72
+ : colors_1.BLUE,
69
73
  border: get_timeline_sequence_layout_1.SEQUENCE_BORDER_WIDTH + 'px solid rgba(255, 255, 255, 0.2)',
70
74
  borderRadius: 2,
71
75
  position: 'absolute',
72
- height: (0, timeline_layout_1.getTimelineLayerHeight)(s.type === 'video' ? 'video' : 'other'),
76
+ height: (0, timeline_layout_1.getTimelineLayerHeight)(s.type),
73
77
  marginLeft,
74
78
  width,
75
79
  color: 'white',
@@ -103,8 +107,9 @@ const Inner = ({ s, windowWidth }) => {
103
107
  )`,
104
108
  position: 'absolute',
105
109
  right: 0,
106
- } })) : null, s.type === 'audio' ? (jsx_runtime_1.jsx(AudioWaveform_1.AudioWaveform, { src: s.src, doesVolumeChange: s.doesVolumeChange, visualizationWidth: width, startFrom: s.startMediaFrom, durationInFrames: s.duration, volume: s.volume, playbackRate: s.playbackRate })) : null, s.type === 'video' ? (jsx_runtime_1.jsx(TimelineVideoInfo_1.TimelineVideoInfo, { src: s.src, visualizationWidth: width, naturalWidth: naturalWidth, trimBefore: s.startMediaFrom, durationInFrames: s.duration, playbackRate: s.playbackRate })) : null, s.loopDisplay === undefined ? null : (jsx_runtime_1.jsx(LoopedTimelineIndicators_1.LoopedTimelineIndicator, { loops: s.loopDisplay.numberOfTimes })), s.type !== 'audio' &&
110
+ } })) : null, s.type === 'audio' ? (jsx_runtime_1.jsx(AudioWaveform_1.AudioWaveform, { src: s.src, doesVolumeChange: s.doesVolumeChange, visualizationWidth: width, startFrom: s.startMediaFrom, durationInFrames: s.duration, volume: s.volume, playbackRate: s.playbackRate })) : null, s.type === 'video' ? (jsx_runtime_1.jsx(TimelineVideoInfo_1.TimelineVideoInfo, { src: s.src, visualizationWidth: width, naturalWidth: naturalWidth, trimBefore: s.startMediaFrom, durationInFrames: s.duration, playbackRate: s.playbackRate })) : null, s.type === 'image' ? (jsx_runtime_1.jsx(TimelineImageInfo_1.TimelineImageInfo, { src: s.src, visualizationWidth: width })) : null, s.loopDisplay === undefined ? null : (jsx_runtime_1.jsx(LoopedTimelineIndicators_1.LoopedTimelineIndicator, { loops: s.loopDisplay.numberOfTimes })), s.type !== 'audio' &&
107
111
  s.type !== 'video' &&
112
+ s.type !== 'image' &&
108
113
  s.loopDisplay === undefined &&
109
114
  (isInRange || isPremounting || isPostmounting) ? (jsx_runtime_1.jsx("div", { style: {
110
115
  paddingLeft: 5 + (premountWidth !== null && premountWidth !== void 0 ? premountWidth : 0),
@@ -31,7 +31,9 @@ const TimelineStack = ({ isCompact, sequence, originalLocation }) => {
31
31
  const connectionStatus = (0, react_1.useContext)(client_id_1.StudioServerConnectionCtx)
32
32
  .previewServerState.type;
33
33
  const assetPath = (0, react_1.useMemo)(() => {
34
- if (sequence.type !== 'video' && sequence.type !== 'audio') {
34
+ if (sequence.type !== 'video' &&
35
+ sequence.type !== 'audio' &&
36
+ sequence.type !== 'image') {
35
37
  return null;
36
38
  }
37
39
  const isStatic = sequence.src.startsWith(window.remotion_staticBase);
@@ -42,7 +42,7 @@ const TimelineTracks = ({ timeline, hasBeenCut }) => {
42
42
  const isExpanded = (_a = expandedTracks[track.sequence.id]) !== null && _a !== void 0 ? _a : false;
43
43
  return (jsx_runtime_1.jsxs("div", { children: [
44
44
  jsx_runtime_1.jsx("div", { style: {
45
- height: (0, timeline_layout_1.getTimelineLayerHeight)(track.sequence.type === 'video' ? 'video' : 'other'),
45
+ height: (0, timeline_layout_1.getTimelineLayerHeight)(track.sequence.type),
46
46
  marginBottom: timeline_layout_1.TIMELINE_ITEM_BORDER_BOTTOM,
47
47
  }, children: jsx_runtime_1.jsx(TimelineSequence_1.TimelineSequence, { s: track.sequence }) }), visualModeEnabled && isExpanded ? (jsx_runtime_1.jsx("div", { style: getExpandedPlaceholderStyle(track.sequence.controls) })) : null] }, track.sequence.id));
48
48
  })] }), hasBeenCut ? jsx_runtime_1.jsx(MaxTimelineTracks_1.MaxTimelineTracksReached, {}) : null] }));
@@ -29,11 +29,6 @@ const TimelineTranslateField = ({ field, codeValue, effectiveValue, canUpdate, o
29
29
  const [dragY, setDragY] = (0, react_1.useState)(null);
30
30
  const [codeX, codeY] = (0, react_1.useMemo)(() => parseTranslate(String(effectiveValue !== null && effectiveValue !== void 0 ? effectiveValue : '0px 0px')), [effectiveValue]);
31
31
  const makeString = (0, react_1.useCallback)((x, y) => `${x}px ${y}px`, []);
32
- (0, react_1.useEffect)(() => {
33
- setDragX(null);
34
- setDragY(null);
35
- onDragEnd();
36
- }, [field.currentValue, onDragEnd]);
37
32
  const step = field.fieldSchema.type === 'translate' ? ((_a = field.fieldSchema.step) !== null && _a !== void 0 ? _a : 1) : 1;
38
33
  const stepDecimals = (0, react_1.useMemo)(() => (0, timeline_field_utils_1.getDecimalPlaces)(step), [step]);
39
34
  const formatter = (0, react_1.useCallback)((v) => {
@@ -52,14 +47,25 @@ const TimelineTranslateField = ({ field, codeValue, effectiveValue, canUpdate, o
52
47
  const currentY = dragY !== null && dragY !== void 0 ? dragY : codeY;
53
48
  const newStr = makeString(newVal, currentY);
54
49
  if (canUpdate && newStr !== codeValue) {
55
- onSave(field.key, newStr).catch(() => {
50
+ onSave(field.key, newStr).finally(() => {
56
51
  setDragX(null);
52
+ onDragEnd();
57
53
  });
58
54
  }
59
55
  else {
60
56
  setDragX(null);
57
+ onDragEnd();
61
58
  }
62
- }, [canUpdate, onSave, field.key, codeValue, dragY, codeY, makeString]);
59
+ }, [
60
+ dragY,
61
+ codeY,
62
+ makeString,
63
+ canUpdate,
64
+ codeValue,
65
+ onSave,
66
+ field.key,
67
+ onDragEnd,
68
+ ]);
63
69
  const onXTextChange = (0, react_1.useCallback)((newVal) => {
64
70
  if (canUpdate) {
65
71
  const parsed = Number(newVal);
@@ -68,13 +74,11 @@ const TimelineTranslateField = ({ field, codeValue, effectiveValue, canUpdate, o
68
74
  const newStr = makeString(parsed, currentY);
69
75
  if (newStr !== codeValue) {
70
76
  setDragX(parsed);
71
- onSave(field.key, newStr).catch(() => {
72
- setDragX(null);
73
- });
77
+ onSave(field.key, newStr);
74
78
  }
75
79
  }
76
80
  }
77
- }, [canUpdate, onSave, field.key, codeValue, dragY, codeY, makeString]);
81
+ }, [canUpdate, dragY, codeY, makeString, codeValue, onSave, field.key]);
78
82
  // --- Y callbacks ---
79
83
  const onYChange = (0, react_1.useCallback)((newVal) => {
80
84
  setDragY(newVal);
@@ -85,14 +89,25 @@ const TimelineTranslateField = ({ field, codeValue, effectiveValue, canUpdate, o
85
89
  const currentX = dragX !== null && dragX !== void 0 ? dragX : codeX;
86
90
  const newStr = makeString(currentX, newVal);
87
91
  if (canUpdate && newStr !== codeValue) {
88
- onSave(field.key, newStr).catch(() => {
92
+ onSave(field.key, newStr).finally(() => {
89
93
  setDragY(null);
94
+ onDragEnd();
90
95
  });
91
96
  }
92
97
  else {
93
98
  setDragY(null);
99
+ onDragEnd();
94
100
  }
95
- }, [canUpdate, onSave, field.key, codeValue, dragX, codeX, makeString]);
101
+ }, [
102
+ dragX,
103
+ codeX,
104
+ makeString,
105
+ canUpdate,
106
+ codeValue,
107
+ onSave,
108
+ field.key,
109
+ onDragEnd,
110
+ ]);
96
111
  const onYTextChange = (0, react_1.useCallback)((newVal) => {
97
112
  if (canUpdate) {
98
113
  const parsed = Number(newVal);
@@ -39,6 +39,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
39
39
  exports.TopPanel = exports.useResponsiveSidebarStatus = void 0;
40
40
  const jsx_runtime_1 = require("react/jsx-runtime");
41
41
  const react_1 = __importStar(require("react"));
42
+ const remotion_1 = require("remotion");
42
43
  const mobile_layout_1 = require("../helpers/mobile-layout");
43
44
  const use_breakpoint_1 = require("../helpers/use-breakpoint");
44
45
  const editor_rulers_1 = require("../state/editor-rulers");
@@ -48,6 +49,7 @@ const CurrentCompositionSideEffects_1 = require("./CurrentCompositionSideEffects
48
49
  const use_is_ruler_visible_1 = require("./EditorRuler/use-is-ruler-visible");
49
50
  const ExplorerPanel_1 = require("./ExplorerPanel");
50
51
  const MobilePanel_1 = __importDefault(require("./MobilePanel"));
52
+ const ObserveDefaultPropsContext_1 = require("./ObserveDefaultPropsContext");
51
53
  const OptionsPanel_1 = require("./OptionsPanel");
52
54
  const PreviewToolbar_1 = require("./PreviewToolbar");
53
55
  const SplitterContainer_1 = require("./Splitter/SplitterContainer");
@@ -84,6 +86,7 @@ exports.useResponsiveSidebarStatus = useResponsiveSidebarStatus;
84
86
  const TopPanelInner = ({ readOnlyStudio, onMounted, drawRef, bufferStateDelayInMilliseconds }) => {
85
87
  const { setSidebarCollapsedState, sidebarCollapsedStateRight } = (0, react_1.useContext)(sidebar_1.SidebarContext);
86
88
  const rulersAreVisible = (0, use_is_ruler_visible_1.useIsRulerVisible)();
89
+ const { canvasContent } = (0, react_1.useContext)(remotion_1.Internals.CompositionManager);
87
90
  const actualStateLeft = (0, exports.useResponsiveSidebarStatus)();
88
91
  const actualStateRight = (0, react_1.useMemo)(() => {
89
92
  if (sidebarCollapsedStateRight === 'collapsed') {
@@ -107,10 +110,12 @@ const TopPanelInner = ({ readOnlyStudio, onMounted, drawRef, bufferStateDelayInM
107
110
  setSidebarCollapsedState({ left: null, right: 'collapsed' });
108
111
  }, [setSidebarCollapsedState]);
109
112
  const isMobileLayout = (0, mobile_layout_1.useMobileLayout)();
110
- return (jsx_runtime_1.jsxs("div", { style: container, children: [
111
- jsx_runtime_1.jsx("div", { style: row, children: jsx_runtime_1.jsxs(SplitterContainer_1.SplitterContainer, { minFlex: 0.15, maxFlex: 0.4, defaultFlex: 0.2, id: "sidebar-to-preview", orientation: "vertical", children: [actualStateLeft === 'expanded' ? (isMobileLayout ? (jsx_runtime_1.jsx(MobilePanel_1.default, { onClose: onCollapseLeft, children: jsx_runtime_1.jsx(ExplorerPanel_1.ExplorerPanel, { readOnlyStudio: readOnlyStudio }) })) : (jsx_runtime_1.jsx(SplitterElement_1.SplitterElement, { sticky: null, type: "flexer", children: jsx_runtime_1.jsx(ExplorerPanel_1.ExplorerPanel, { readOnlyStudio: readOnlyStudio }) }))) : null, actualStateLeft === 'expanded' ? (jsx_runtime_1.jsx(SplitterHandle_1.SplitterHandle, { allowToCollapse: "left", onCollapse: onCollapseLeft })) : null, jsx_runtime_1.jsx(SplitterElement_1.SplitterElement, { sticky: null, type: "anti-flexer", children: jsx_runtime_1.jsxs(SplitterContainer_1.SplitterContainer, { minFlex: 0.5, maxFlex: 0.8, defaultFlex: 0.7, id: "canvas-to-right-sidebar", orientation: "vertical", children: [
112
- jsx_runtime_1.jsx(SplitterElement_1.SplitterElement, { sticky: null, type: "flexer", children: jsx_runtime_1.jsx("div", { ref: drawRef, style: canvasContainerStyle, children: jsx_runtime_1.jsx(CanvasIfSizeIsAvailable_1.CanvasIfSizeIsAvailable, {}) }) }), actualStateRight === 'expanded' ? (jsx_runtime_1.jsx(SplitterHandle_1.SplitterHandle, { allowToCollapse: "right", onCollapse: onCollapseRight })) : null, actualStateRight === 'expanded' ? (isMobileLayout ? (jsx_runtime_1.jsx(MobilePanel_1.default, { onClose: onCollapseRight, children: jsx_runtime_1.jsx(OptionsPanel_1.OptionsPanel, { readOnlyStudio: readOnlyStudio }) })) : (jsx_runtime_1.jsx(SplitterElement_1.SplitterElement, { sticky: null, type: "anti-flexer", children: jsx_runtime_1.jsx(OptionsPanel_1.OptionsPanel, { readOnlyStudio: readOnlyStudio }) }))) : null] }) })
113
- ] }) }), jsx_runtime_1.jsx(PreviewToolbar_1.PreviewToolbar, { bufferStateDelayInMilliseconds: bufferStateDelayInMilliseconds, readOnlyStudio: readOnlyStudio }), jsx_runtime_1.jsx(CurrentCompositionSideEffects_1.CurrentCompositionKeybindings, { readOnlyStudio: readOnlyStudio }), jsx_runtime_1.jsx(CurrentCompositionSideEffects_1.TitleUpdater, {})
114
- ] }));
113
+ return (jsx_runtime_1.jsx(ObserveDefaultPropsContext_1.ObserveDefaultProps, { compositionId: (canvasContent === null || canvasContent === void 0 ? void 0 : canvasContent.type) === 'composition'
114
+ ? canvasContent.compositionId
115
+ : null, readOnlyStudio: readOnlyStudio, children: jsx_runtime_1.jsxs("div", { style: container, children: [
116
+ jsx_runtime_1.jsx("div", { style: row, children: jsx_runtime_1.jsxs(SplitterContainer_1.SplitterContainer, { minFlex: 0.15, maxFlex: 0.4, defaultFlex: 0.2, id: "sidebar-to-preview", orientation: "vertical", children: [actualStateLeft === 'expanded' ? (isMobileLayout ? (jsx_runtime_1.jsx(MobilePanel_1.default, { onClose: onCollapseLeft, children: jsx_runtime_1.jsx(ExplorerPanel_1.ExplorerPanel, { readOnlyStudio: readOnlyStudio }) })) : (jsx_runtime_1.jsx(SplitterElement_1.SplitterElement, { sticky: null, type: "flexer", children: jsx_runtime_1.jsx(ExplorerPanel_1.ExplorerPanel, { readOnlyStudio: readOnlyStudio }) }))) : null, actualStateLeft === 'expanded' ? (jsx_runtime_1.jsx(SplitterHandle_1.SplitterHandle, { allowToCollapse: "left", onCollapse: onCollapseLeft })) : null, jsx_runtime_1.jsx(SplitterElement_1.SplitterElement, { sticky: null, type: "anti-flexer", children: jsx_runtime_1.jsxs(SplitterContainer_1.SplitterContainer, { minFlex: 0.5, maxFlex: 0.8, defaultFlex: 0.7, id: "canvas-to-right-sidebar", orientation: "vertical", children: [
117
+ jsx_runtime_1.jsx(SplitterElement_1.SplitterElement, { sticky: null, type: "flexer", children: jsx_runtime_1.jsx("div", { ref: drawRef, style: canvasContainerStyle, children: jsx_runtime_1.jsx(CanvasIfSizeIsAvailable_1.CanvasIfSizeIsAvailable, {}) }) }), actualStateRight === 'expanded' ? (jsx_runtime_1.jsx(SplitterHandle_1.SplitterHandle, { allowToCollapse: "right", onCollapse: onCollapseRight })) : null, actualStateRight === 'expanded' ? (isMobileLayout ? (jsx_runtime_1.jsx(MobilePanel_1.default, { onClose: onCollapseRight, children: jsx_runtime_1.jsx(OptionsPanel_1.OptionsPanel, { readOnlyStudio: readOnlyStudio }) })) : (jsx_runtime_1.jsx(SplitterElement_1.SplitterElement, { sticky: null, type: "anti-flexer", children: jsx_runtime_1.jsx(OptionsPanel_1.OptionsPanel, { readOnlyStudio: readOnlyStudio }) }))) : null] }) })
118
+ ] }) }), jsx_runtime_1.jsx(PreviewToolbar_1.PreviewToolbar, { bufferStateDelayInMilliseconds: bufferStateDelayInMilliseconds, readOnlyStudio: readOnlyStudio }), jsx_runtime_1.jsx(CurrentCompositionSideEffects_1.CurrentCompositionKeybindings, { readOnlyStudio: readOnlyStudio }), jsx_runtime_1.jsx(CurrentCompositionSideEffects_1.TitleUpdater, {})
119
+ ] }) }));
115
120
  };
116
121
  exports.TopPanel = react_1.default.memo(TopPanelInner);
@@ -0,0 +1,2 @@
1
+ import React from 'react';
2
+ export declare const UndoRedoButtons: React.FC;
@@ -0,0 +1,116 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.UndoRedoButtons = void 0;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const react_1 = require("react");
6
+ const ShortcutHint_1 = require("../error-overlay/remotion-overlay/ShortcutHint");
7
+ const client_id_1 = require("../helpers/client-id");
8
+ const use_keybinding_1 = require("../helpers/use-keybinding");
9
+ const redo_1 = require("../icons/redo");
10
+ const undo_1 = require("../icons/undo");
11
+ const call_api_1 = require("./call-api");
12
+ const InlineAction_1 = require("./InlineAction");
13
+ const iconStyle = {
14
+ width: 16,
15
+ height: 16,
16
+ };
17
+ const UndoRedoButtons = () => {
18
+ const [undoFile, setUndoFile] = (0, react_1.useState)(null);
19
+ const [redoFile, setRedoFile] = (0, react_1.useState)(null);
20
+ const { subscribeToEvent } = (0, react_1.useContext)(client_id_1.StudioServerConnectionCtx);
21
+ const keybindings = (0, use_keybinding_1.useKeybinding)();
22
+ const undoInFlight = (0, react_1.useRef)(false);
23
+ const redoInFlight = (0, react_1.useRef)(false);
24
+ (0, react_1.useEffect)(() => {
25
+ const unsub = subscribeToEvent('undo-redo-stack-changed', (event) => {
26
+ if (event.type !== 'undo-redo-stack-changed') {
27
+ return;
28
+ }
29
+ setUndoFile(event.undoFile);
30
+ setRedoFile(event.redoFile);
31
+ });
32
+ return () => unsub();
33
+ }, [subscribeToEvent]);
34
+ const onUndo = (0, react_1.useCallback)(() => {
35
+ if (undoInFlight.current) {
36
+ return;
37
+ }
38
+ undoInFlight.current = true;
39
+ (0, call_api_1.callApi)('/api/undo', {})
40
+ .catch(() => {
41
+ // Ignore errors
42
+ })
43
+ .finally(() => {
44
+ undoInFlight.current = false;
45
+ });
46
+ }, []);
47
+ const onRedo = (0, react_1.useCallback)(() => {
48
+ if (redoInFlight.current) {
49
+ return;
50
+ }
51
+ redoInFlight.current = true;
52
+ (0, call_api_1.callApi)('/api/redo', {})
53
+ .catch(() => {
54
+ // Ignore errors
55
+ })
56
+ .finally(() => {
57
+ redoInFlight.current = false;
58
+ });
59
+ }, []);
60
+ (0, react_1.useEffect)(() => {
61
+ const undo = keybindings.registerKeybinding({
62
+ event: 'keydown',
63
+ key: 'z',
64
+ commandCtrlKey: true,
65
+ callback: (e) => {
66
+ if (e.shiftKey) {
67
+ return;
68
+ }
69
+ if (undoFile) {
70
+ onUndo();
71
+ }
72
+ },
73
+ preventDefault: true,
74
+ triggerIfInputFieldFocused: false,
75
+ keepRegisteredWhenNotHighestContext: false,
76
+ });
77
+ const redo = keybindings.registerKeybinding({
78
+ event: 'keydown',
79
+ key: 'y',
80
+ commandCtrlKey: true,
81
+ callback: () => {
82
+ if (redoFile) {
83
+ onRedo();
84
+ }
85
+ },
86
+ preventDefault: true,
87
+ triggerIfInputFieldFocused: false,
88
+ keepRegisteredWhenNotHighestContext: false,
89
+ });
90
+ return () => {
91
+ undo.unregister();
92
+ redo.unregister();
93
+ };
94
+ }, [keybindings, onRedo, onUndo, redoFile, undoFile]);
95
+ const undoTooltip = (0, use_keybinding_1.areKeyboardShortcutsDisabled)()
96
+ ? 'Undo'
97
+ : `Undo (${ShortcutHint_1.cmdOrCtrlCharacter}+Z)`;
98
+ const redoTooltip = (0, use_keybinding_1.areKeyboardShortcutsDisabled)()
99
+ ? 'Redo'
100
+ : `Redo (${ShortcutHint_1.cmdOrCtrlCharacter}+Y)`;
101
+ const renderUndo = (0, react_1.useCallback)((color) => {
102
+ return (jsx_runtime_1.jsx(undo_1.UndoIcon, { style: { ...iconStyle, color, opacity: undoFile ? 1 : 0.5 } }));
103
+ }, [undoFile]);
104
+ const renderRedo = (0, react_1.useCallback)((color) => {
105
+ return (jsx_runtime_1.jsx(redo_1.RedoIcon, { style: { ...iconStyle, color, opacity: redoFile ? 1 : 0.5 } }));
106
+ }, [redoFile]);
107
+ const canUndo = undoFile !== null;
108
+ const canRedo = redoFile !== null;
109
+ if (!canUndo && !canRedo) {
110
+ return null;
111
+ }
112
+ return (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [
113
+ jsx_runtime_1.jsx(InlineAction_1.InlineAction, { onClick: onUndo, renderAction: renderUndo, title: undoTooltip, disabled: !canUndo }), jsx_runtime_1.jsx(InlineAction_1.InlineAction, { onClick: onRedo, renderAction: renderRedo, title: redoTooltip, disabled: !canRedo })
114
+ ] }));
115
+ };
116
+ exports.UndoRedoButtons = UndoRedoButtons;