@remotion/studio 4.0.500 → 4.0.501

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 (108) hide show
  1. package/dist/Studio.js +1 -1
  2. package/dist/api/delete-static-file.js +8 -3
  3. package/dist/api/rename-static-file.js +8 -0
  4. package/dist/api/watch-public-folder.js +2 -1
  5. package/dist/api/watch-static-file.js +2 -1
  6. package/dist/api/write-static-file.js +8 -3
  7. package/dist/components/AssetSelector.js +3 -1
  8. package/dist/components/AssetSelectorItem.d.ts +2 -1
  9. package/dist/components/AssetSelectorItem.js +5 -2
  10. package/dist/components/Canvas.js +6 -1
  11. package/dist/components/CaptionInspector.d.ts +10 -0
  12. package/dist/components/CaptionInspector.js +24 -0
  13. package/dist/components/CaptionTextEditor.d.ts +9 -0
  14. package/dist/components/CaptionTextEditor.js +132 -0
  15. package/dist/components/CurrentAsset.js +3 -2
  16. package/dist/components/EditorContexts.d.ts +0 -1
  17. package/dist/components/EditorContexts.js +2 -2
  18. package/dist/components/FpsCounter.js +3 -3
  19. package/dist/components/FullscreenToggle.js +2 -1
  20. package/dist/components/GlobalKeybindings.js +2 -0
  21. package/dist/components/InitialCompositionLoader.d.ts +1 -1
  22. package/dist/components/InlineAction.js +1 -0
  23. package/dist/components/InlineCaptionInspector.d.ts +11 -0
  24. package/dist/components/InlineCaptionInspector.js +108 -0
  25. package/dist/components/InspectorPanel/CompositionInspector.js +5 -3
  26. package/dist/components/InspectorPanel/SelectedInspector.d.ts +1 -0
  27. package/dist/components/InspectorPanel/SelectedInspector.js +2 -2
  28. package/dist/components/InspectorPanel/SequenceSelectionInspector.d.ts +1 -0
  29. package/dist/components/InspectorPanel/SequenceSelectionInspector.js +4 -4
  30. package/dist/components/InspectorPanel/inspector-section-collapse.d.ts +22 -0
  31. package/dist/components/InspectorPanel/inspector-section-collapse.js +165 -0
  32. package/dist/components/InspectorPanel/styles.js +7 -1
  33. package/dist/components/InspectorPanel/use-composition-actions.d.ts +3 -0
  34. package/dist/components/InspectorPanel/use-composition-actions.js +91 -6
  35. package/dist/components/InspectorPanel.js +2 -2
  36. package/dist/components/InspectorSequenceSection.d.ts +2 -1
  37. package/dist/components/InspectorSequenceSection.js +238 -8
  38. package/dist/components/MenuToolbar.js +8 -1
  39. package/dist/components/Modals.js +1 -1
  40. package/dist/components/QuickSwitcher/ExplorerQuickSwitcherTrigger.js +1 -0
  41. package/dist/components/QuickSwitcher/QuickSwitcher.d.ts +5 -0
  42. package/dist/components/QuickSwitcher/QuickSwitcher.js +2 -2
  43. package/dist/components/QuickSwitcher/QuickSwitcherContent.d.ts +5 -0
  44. package/dist/components/QuickSwitcher/QuickSwitcherContent.js +26 -8
  45. package/dist/components/RenderQueue/ClientRenderQueueProcessor.d.ts +0 -1
  46. package/dist/components/RenderQueue/ClientRenderQueueProcessor.js +3 -14
  47. package/dist/components/RenderQueue/RenderQueueDownloadItem.js +2 -2
  48. package/dist/components/SelectedOutlineElement.js +1 -4
  49. package/dist/components/SelectedOutlineOverlay.js +17 -8
  50. package/dist/components/ShowOutlinesProvider.js +4 -1
  51. package/dist/components/Timeline/Timeline.js +19 -5
  52. package/dist/components/Timeline/TimelineAssetField.js +1 -0
  53. package/dist/components/Timeline/TimelineExpandedKeyframeRow.js +8 -2
  54. package/dist/components/Timeline/TimelinePrimitiveFieldValue.d.ts +7 -2
  55. package/dist/components/Timeline/TimelinePrimitiveFieldValue.js +3 -1
  56. package/dist/components/Timeline/TimelineRowChrome.d.ts +3 -0
  57. package/dist/components/Timeline/TimelineRowChrome.js +4 -3
  58. package/dist/components/Timeline/TimelineSelection.d.ts +4 -2
  59. package/dist/components/Timeline/TimelineSelection.js +9 -6
  60. package/dist/components/Timeline/TimelineSequence.js +1 -4
  61. package/dist/components/Timeline/TimelineSequenceItem.js +4 -5
  62. package/dist/components/Timeline/TimelineSequencePropItem.js +9 -10
  63. package/dist/components/Timeline/TimelineTrack.js +4 -2
  64. package/dist/components/Timeline/border-radius-representation.d.ts +16 -0
  65. package/dist/components/Timeline/border-radius-representation.js +60 -0
  66. package/dist/components/Timeline/delete-selected-timeline-item.js +1 -6
  67. package/dist/components/Timeline/get-sequence-prop-reset-changes.d.ts +10 -0
  68. package/dist/components/Timeline/get-sequence-prop-reset-changes.js +33 -0
  69. package/dist/components/Timeline/reset-selected-timeline-props.js +2 -8
  70. package/dist/components/Timeline/save-sequence-prop.d.ts +12 -1
  71. package/dist/components/Timeline/save-sequence-prop.js +25 -1
  72. package/dist/components/Timeline/timeline-field-display-utils.js +1 -0
  73. package/dist/components/Timeline/use-timeline-asset-drop.js +4 -0
  74. package/dist/components/UndoRedoButtons.js +15 -6
  75. package/dist/components/handle-drop.d.ts +3 -2
  76. package/dist/components/handle-drop.js +2 -1
  77. package/dist/components/import-assets.d.ts +4 -2
  78. package/dist/components/import-assets.js +20 -7
  79. package/dist/components/use-element-overwrite-confirmation.d.ts +2 -0
  80. package/dist/components/use-element-overwrite-confirmation.js +73 -0
  81. package/dist/components/use-static-files.js +7 -2
  82. package/dist/error-overlay/react-overlay/effects/resolve-file-source.js +13 -2
  83. package/dist/esm/{chunk-dr1y1vm3.js → chunk-n1kj09yv.js} +7634 -6308
  84. package/dist/esm/index.mjs +24 -8
  85. package/dist/esm/internals.mjs +7634 -6308
  86. package/dist/esm/previewEntry.mjs +7646 -6320
  87. package/dist/esm/renderEntry.mjs +1 -1
  88. package/dist/helpers/browser-studio-operations.d.ts +3 -0
  89. package/dist/helpers/browser-studio-operations.js +14 -0
  90. package/dist/helpers/client-id.d.ts +0 -1
  91. package/dist/helpers/client-id.js +15 -10
  92. package/dist/helpers/download-blob.d.ts +1 -0
  93. package/dist/helpers/download-blob.js +15 -0
  94. package/dist/helpers/inject-css.js +5 -3
  95. package/dist/helpers/open-in-editor.js +26 -5
  96. package/dist/helpers/preview-server-events.js +46 -9
  97. package/dist/helpers/use-create-composition.js +8 -6
  98. package/dist/helpers/use-menu-structure.js +29 -0
  99. package/dist/hot-middleware-client/client.js +3 -3
  100. package/dist/icons/border-radius.d.ts +4 -0
  101. package/dist/icons/border-radius.js +8 -0
  102. package/dist/icons/fullscreen.d.ts +4 -0
  103. package/dist/icons/fullscreen.js +6 -0
  104. package/dist/previewEntry.js +1 -1
  105. package/dist/state/modals.d.ts +4 -0
  106. package/dist/state/timeline-sequence-hover.d.ts +17 -0
  107. package/dist/state/timeline-sequence-hover.js +33 -0
  108. package/package.json +13 -12
package/dist/Studio.js CHANGED
@@ -17,7 +17,7 @@ const getServerDisconnectedDomElement = () => {
17
17
  };
18
18
  const StudioInner = ({ rootComponent, readOnly }) => {
19
19
  var _a, _b;
20
- return (jsx_runtime_1.jsx(remotion_1.Internals.CompositionManagerProvider, { onlyRenderComposition: null, currentCompositionMetadata: null, initialCompositions: [], initialCanvasContent: null, children: jsx_runtime_1.jsx(remotion_1.Internals.RemotionRootContexts, { frameState: null, audioEnabled: window.remotion_audioEnabled, videoEnabled: window.remotion_videoEnabled, logLevel: (_a = window.remotion_logLevel) !== null && _a !== void 0 ? _a : 'info', numberOfAudioTags: window.remotion_numberOfAudioTags, audioLatencyHint: (_b = window.remotion_audioLatencyHint) !== null && _b !== void 0 ? _b : 'playback', previewSampleRate: window.remotion_previewSampleRate, children: jsx_runtime_1.jsx(use_static_files_1.StaticFilesProvider, { children: jsx_runtime_1.jsx(ResolveCompositionConfigInStudio_1.ResolveCompositionConfigInStudio, { children: jsx_runtime_1.jsxs(EditorContexts_1.EditorContexts, { readOnlyStudio: readOnly, children: [
20
+ return (jsx_runtime_1.jsx(remotion_1.Internals.CompositionManagerProvider, { onlyRenderComposition: null, currentCompositionMetadata: null, initialCompositions: [], initialCanvasContent: null, children: jsx_runtime_1.jsx(remotion_1.Internals.RemotionRootContexts, { frameState: null, audioEnabled: window.remotion_audioEnabled, videoEnabled: window.remotion_videoEnabled, logLevel: (_a = window.remotion_logLevel) !== null && _a !== void 0 ? _a : 'info', numberOfAudioTags: window.remotion_numberOfAudioTags, audioLatencyHint: (_b = window.remotion_audioLatencyHint) !== null && _b !== void 0 ? _b : 'playback', previewSampleRate: window.remotion_previewSampleRate, children: jsx_runtime_1.jsx(use_static_files_1.StaticFilesProvider, { children: jsx_runtime_1.jsx(ResolveCompositionConfigInStudio_1.ResolveCompositionConfigInStudio, { children: jsx_runtime_1.jsxs(EditorContexts_1.EditorContexts, { children: [
21
21
  jsx_runtime_1.jsx(Editor_1.Editor, { readOnlyStudio: readOnly, Root: rootComponent }), readOnly
22
22
  ? null
23
23
  : (0, react_dom_1.createPortal)(jsx_runtime_1.jsx(ServerDisconnected_1.ServerDisconnected, {}), getServerDisconnectedDomElement())] }) }) }) }) }));
@@ -3,16 +3,21 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.deleteStaticFile = void 0;
4
4
  const remotion_1 = require("remotion");
5
5
  const call_api_1 = require("../components/call-api");
6
+ const browser_studio_operations_1 = require("../helpers/browser-studio-operations");
6
7
  const deleteStaticFile = async (relativePath) => {
7
8
  if (!(0, remotion_1.getRemotionEnvironment)().isStudio) {
8
9
  throw new Error('deleteStaticFile() is only available in the Studio');
9
10
  }
10
- if (window.remotion_isReadOnlyStudio) {
11
- throw new Error('deleteStaticFile() is not available in Read-Only Studio');
12
- }
13
11
  if (relativePath.startsWith(window.remotion_staticBase)) {
14
12
  relativePath = relativePath.substring(window.remotion_staticBase.length + 1);
15
13
  }
14
+ const browserStudioOperations = (0, browser_studio_operations_1.getBrowserStudioOperations)();
15
+ if (browserStudioOperations) {
16
+ return browserStudioOperations.deleteStaticFile({ relativePath });
17
+ }
18
+ if (window.remotion_isReadOnlyStudio) {
19
+ throw new Error('deleteStaticFile() is not available in Read-Only Studio');
20
+ }
16
21
  const res = await (0, call_api_1.callApi)('/api/delete-static-file', { relativePath });
17
22
  return res;
18
23
  };
@@ -3,10 +3,18 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.renameStaticFile = void 0;
4
4
  const remotion_1 = require("remotion");
5
5
  const call_api_1 = require("../components/call-api");
6
+ const browser_studio_operations_1 = require("../helpers/browser-studio-operations");
6
7
  const renameStaticFile = ({ oldRelativePath, newRelativePath, }) => {
7
8
  if (!(0, remotion_1.getRemotionEnvironment)().isStudio) {
8
9
  throw new Error('renameStaticFile() is only available in the Studio');
9
10
  }
11
+ const browserStudioOperations = (0, browser_studio_operations_1.getBrowserStudioOperations)();
12
+ if (browserStudioOperations) {
13
+ return browserStudioOperations.renameStaticFile({
14
+ oldRelativePath,
15
+ newRelativePath,
16
+ });
17
+ }
10
18
  if (window.remotion_isReadOnlyStudio) {
11
19
  throw new Error('renameStaticFile() is not available in Read-Only Studio');
12
20
  }
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.watchPublicFolder = exports.WATCH_REMOTION_STATIC_FILES = void 0;
4
4
  const remotion_1 = require("remotion");
5
+ const browser_studio_operations_1 = require("../helpers/browser-studio-operations");
5
6
  const get_static_files_1 = require("./get-static-files");
6
7
  exports.WATCH_REMOTION_STATIC_FILES = 'remotion_staticFilesChanged';
7
8
  /*
@@ -14,7 +15,7 @@ const watchPublicFolder = (callback) => {
14
15
  console.warn('The watchPublicFolder() API is only available while using the Remotion Studio.');
15
16
  return { cancel: () => undefined };
16
17
  }
17
- if (window.remotion_isReadOnlyStudio) {
18
+ if (window.remotion_isReadOnlyStudio && !(0, browser_studio_operations_1.getBrowserStudioOperations)()) {
18
19
  throw new Error('watchPublicFolder() is not available in read-only Studio');
19
20
  }
20
21
  const emitUpdate = () => {
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.watchStaticFile = void 0;
4
4
  const remotion_1 = require("remotion");
5
+ const browser_studio_operations_1 = require("../helpers/browser-studio-operations");
5
6
  const watch_public_folder_1 = require("./watch-public-folder");
6
7
  /*
7
8
  * @description Watches for changes in a specific static file and invokes a callback function when the file changes, enabling dynamic updates in your Remotion projects.
@@ -13,7 +14,7 @@ const watchStaticFile = (fileName, callback) => {
13
14
  console.warn('watchStaticFile() is only available while using the Remotion Studio.');
14
15
  return { cancel: () => undefined };
15
16
  }
16
- if (window.remotion_isReadOnlyStudio) {
17
+ if (window.remotion_isReadOnlyStudio && !(0, browser_studio_operations_1.getBrowserStudioOperations)()) {
17
18
  // eslint-disable-next-line no-console
18
19
  console.warn('watchStaticFile() is only available in an interactive Studio.');
19
20
  return { cancel: () => undefined };
@@ -1,14 +1,19 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.writeStaticFile = void 0;
4
+ const browser_studio_operations_1 = require("../helpers/browser-studio-operations");
4
5
  const writeStaticFile = async ({ contents, filePath, }) => {
6
+ if (filePath.includes('\\')) {
7
+ return Promise.reject(new Error('File path cannot contain backslashes'));
8
+ }
9
+ const browserStudioOperations = (0, browser_studio_operations_1.getBrowserStudioOperations)();
10
+ if (browserStudioOperations) {
11
+ return browserStudioOperations.writeStaticFile({ contents, filePath });
12
+ }
5
13
  if (window.remotion_isReadOnlyStudio) {
6
14
  throw new Error('writeStaticFile() is not available in read-only Studio');
7
15
  }
8
16
  const url = new URL(`${window.remotion_staticBase}/api/add-asset`, window.location.origin);
9
- if (filePath.includes('\\')) {
10
- return Promise.reject(new Error('File path cannot contain backslashes'));
11
- }
12
17
  url.search = new URLSearchParams({
13
18
  filePath,
14
19
  }).toString();
@@ -37,6 +37,7 @@ exports.AssetSelector = void 0;
37
37
  const jsx_runtime_1 = require("react/jsx-runtime");
38
38
  const react_1 = require("react");
39
39
  const write_static_file_1 = require("../api/write-static-file");
40
+ const browser_studio_operations_1 = require("../helpers/browser-studio-operations");
40
41
  const client_id_1 = require("../helpers/client-id");
41
42
  const colors_1 = require("../helpers/colors");
42
43
  const create_folder_tree_1 = require("../helpers/create-folder-tree");
@@ -80,7 +81,8 @@ const AssetSelector = ({ readOnlyStudio }) => {
80
81
  const [dropLocation, setDropLocation] = (0, react_1.useState)(null);
81
82
  const connectionStatus = (0, react_1.useContext)(client_id_1.StudioServerConnectionCtx)
82
83
  .previewServerState.type;
83
- const shouldAllowUpload = connectionStatus === 'connected' && !readOnlyStudio;
84
+ const shouldAllowUpload = (0, browser_studio_operations_1.getBrowserStudioOperations)() !== null ||
85
+ (connectionStatus === 'connected' && !readOnlyStudio);
84
86
  const list = (0, react_1.useMemo)(() => {
85
87
  return {
86
88
  ...baseList,
@@ -1,7 +1,8 @@
1
1
  import React from 'react';
2
2
  import type { AssetStructure } from '../helpers/create-folder-tree';
3
3
  import type { ComboboxValue } from './NewComposition/ComboBox';
4
- export declare const getAssetActionAvailability: ({ readOnlyStudio, connectionStatus, publicFolderExists, }: {
4
+ export declare const getAssetActionAvailability: ({ browserStudioCanMutateAssets, readOnlyStudio, connectionStatus, publicFolderExists, }: {
5
+ browserStudioCanMutateAssets: boolean | null;
5
6
  readOnlyStudio: boolean;
6
7
  connectionStatus: "connected" | "disconnected" | "init";
7
8
  publicFolderExists: string | null;
@@ -40,6 +40,7 @@ const react_1 = require("react");
40
40
  const remotion_1 = require("remotion");
41
41
  const no_react_1 = require("remotion/no-react");
42
42
  const delete_static_file_1 = require("../api/delete-static-file");
43
+ const browser_studio_operations_1 = require("../helpers/browser-studio-operations");
43
44
  const client_id_1 = require("../helpers/client-id");
44
45
  const colors_1 = require("../helpers/colors");
45
46
  const copy_text_1 = require("../helpers/copy-text");
@@ -105,9 +106,10 @@ const revealIconStyle = {
105
106
  height: 12,
106
107
  color: colors_1.CURRENT_COLOR,
107
108
  };
108
- const getAssetActionAvailability = ({ readOnlyStudio, connectionStatus, publicFolderExists, }) => {
109
+ const getAssetActionAvailability = ({ browserStudioCanMutateAssets, readOnlyStudio, connectionStatus, publicFolderExists, }) => {
109
110
  return {
110
- mutationsDisabled: readOnlyStudio || connectionStatus !== 'connected',
111
+ mutationsDisabled: browserStudioCanMutateAssets !== true &&
112
+ (readOnlyStudio || connectionStatus !== 'connected'),
111
113
  fileExplorerDisabled: publicFolderExists === null ||
112
114
  readOnlyStudio ||
113
115
  connectionStatus !== 'connected',
@@ -399,6 +401,7 @@ const AssetSelectorItem = ({ item, tabIndex, level, parentFolder, readOnlyStudio
399
401
  });
400
402
  }, [relativePath]);
401
403
  const { mutationsDisabled, fileExplorerDisabled } = (0, exports.getAssetActionAvailability)({
404
+ browserStudioCanMutateAssets: (0, browser_studio_operations_1.getBrowserStudioOperations)() === null ? null : true,
402
405
  readOnlyStudio,
403
406
  connectionStatus,
404
407
  publicFolderExists: window.remotion_publicFolderExists,
@@ -42,6 +42,7 @@ const ResetZoomButton_1 = require("./ResetZoomButton");
42
42
  const SvgImportDialog_1 = require("./SvgImportDialog");
43
43
  const imperative_state_1 = require("./Timeline/imperative-state");
44
44
  const use_resolved_stack_1 = require("./Timeline/use-resolved-stack");
45
+ const use_element_overwrite_confirmation_1 = require("./use-element-overwrite-confirmation");
45
46
  const elementInstallCompositionIdStyle = {
46
47
  fontFamily: 'monospace',
47
48
  fontSize: 13,
@@ -158,6 +159,7 @@ const Canvas = ({ canvasContent, size }) => {
158
159
  const touchPinchRef = (0, react_1.useRef)(null);
159
160
  const keybindings = (0, use_keybinding_1.useKeybinding)();
160
161
  const confirm = (0, ConfirmationDialog_1.useConfirmationDialog)();
162
+ const confirmElementOverwrite = (0, use_element_overwrite_confirmation_1.useElementOverwriteConfirmation)();
161
163
  const chooseSvgImportMode = (0, SvgImportDialog_1.useSvgImportDialog)();
162
164
  const config = remotion_1.Internals.useUnsafeVideoConfig();
163
165
  const areRulersVisible = (0, use_is_ruler_visible_1.useIsRulerVisible)();
@@ -682,6 +684,7 @@ const Canvas = ({ canvasContent, size }) => {
682
684
  element: activeElementInstallRequest.element,
683
685
  compositionFile: activeElementInstallRequest.compositionFile,
684
686
  compositionId: activeElementInstallRequest.compositionId,
687
+ confirmOverwrite: confirmElementOverwrite,
685
688
  dropPosition: null,
686
689
  from: null,
687
690
  });
@@ -703,7 +706,7 @@ const Canvas = ({ canvasContent, size }) => {
703
706
  return () => {
704
707
  canceled = true;
705
708
  };
706
- }, [activeElementInstallRequest, confirm]);
709
+ }, [activeElementInstallRequest, confirm, confirmElementOverwrite]);
707
710
  const onDragOver = (0, react_1.useCallback)((event) => {
708
711
  var _a;
709
712
  var _b;
@@ -871,6 +874,7 @@ const Canvas = ({ canvasContent, size }) => {
871
874
  await (0, handle_drop_1.handleDrop)({
872
875
  chooseSvgImportMode,
873
876
  compositionFile,
877
+ confirmElementOverwrite,
874
878
  compositionId: currentCompositionId,
875
879
  destinationDimensions: contentDimensions === 'none' ? null : contentDimensions,
876
880
  dropPosition,
@@ -888,6 +892,7 @@ const Canvas = ({ canvasContent, size }) => {
888
892
  cannotAddSequence,
889
893
  chooseSvgImportMode,
890
894
  compositionFile,
895
+ confirmElementOverwrite,
891
896
  config,
892
897
  contentDimensions,
893
898
  currentCompositionId,
@@ -0,0 +1,10 @@
1
+ import type { Caption } from '@remotion/captions';
2
+ import React from 'react';
3
+ export declare const CaptionInspector: React.FC<{
4
+ readonly captions: Caption[];
5
+ readonly onTextChange: (captions: Caption[]) => void;
6
+ readonly onTextSave: ((captions: Caption[]) => void) | null;
7
+ readonly onTextCancel: (() => void) | null;
8
+ readonly readOnly: boolean;
9
+ readonly readOnlyTitle: string | null;
10
+ }>;
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CaptionInspector = void 0;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const colors_1 = require("../helpers/colors");
6
+ const CaptionTextEditor_1 = require("./CaptionTextEditor");
7
+ const common_1 = require("./InspectorPanel/common");
8
+ const styles_1 = require("./InspectorPanel/styles");
9
+ const readOnlyStatus = {
10
+ color: colors_1.LIGHT_TEXT,
11
+ fontFamily: 'sans-serif',
12
+ fontSize: 12,
13
+ fontWeight: 'normal',
14
+ lineHeight: '16px',
15
+ marginLeft: 12,
16
+ };
17
+ const CaptionInspector = ({ captions, onTextChange, onTextSave, onTextCancel, readOnly, readOnlyTitle, }) => {
18
+ return (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [
19
+ jsx_runtime_1.jsx(common_1.InspectorSectionDivider, {}), jsx_runtime_1.jsx(common_1.InspectorSectionHeader, { children: jsx_runtime_1.jsxs("div", { style: styles_1.sectionHeaderRow, children: [
20
+ jsx_runtime_1.jsx("div", { style: styles_1.sectionHeaderTitle, children: "Captions" }), jsx_runtime_1.jsx("div", { style: styles_1.sectionHeaderEnd, children: readOnly ? (jsx_runtime_1.jsx("div", { style: readOnlyStatus, title: readOnlyTitle !== null && readOnlyTitle !== void 0 ? readOnlyTitle : undefined, children: "Read only" })) : null })
21
+ ] }) }), jsx_runtime_1.jsx(CaptionTextEditor_1.CaptionTextEditor, { captions: captions, onChange: onTextChange, onSave: onTextSave, onCancel: onTextCancel, readOnly: readOnly })
22
+ ] }));
23
+ };
24
+ exports.CaptionInspector = CaptionInspector;
@@ -0,0 +1,9 @@
1
+ import type { Caption } from '@remotion/captions';
2
+ import React from 'react';
3
+ export declare const CaptionTextEditor: React.FC<{
4
+ readonly captions: Caption[];
5
+ readonly onChange: (captions: Caption[]) => void;
6
+ readonly onSave: ((captions: Caption[]) => void) | null;
7
+ readonly onCancel: (() => void) | null;
8
+ readonly readOnly: boolean;
9
+ }>;
@@ -0,0 +1,132 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CaptionTextEditor = 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 RemInput_1 = require("./NewComposition/RemInput");
8
+ const container = {
9
+ alignSelf: 'stretch',
10
+ backgroundColor: colors_1.BACKGROUND,
11
+ display: 'flex',
12
+ flexDirection: 'column',
13
+ fontFamily: 'sans-serif',
14
+ width: '100%',
15
+ };
16
+ const list = {
17
+ display: 'flex',
18
+ flexDirection: 'column',
19
+ };
20
+ const row = {
21
+ alignItems: 'center',
22
+ borderBottom: `1px solid ${colors_1.LINE_COLOR}`,
23
+ display: 'grid',
24
+ gap: 12,
25
+ gridTemplateColumns: '100px minmax(0, 1fr)',
26
+ padding: '5px 12px',
27
+ };
28
+ const timing = {
29
+ color: colors_1.LIGHT_TEXT,
30
+ fontFamily: 'monospace',
31
+ fontSize: 11,
32
+ fontVariantNumeric: 'tabular-nums',
33
+ lineHeight: '16px',
34
+ textAlign: 'right',
35
+ whiteSpace: 'nowrap',
36
+ };
37
+ const empty = {
38
+ color: colors_1.LIGHT_TEXT,
39
+ fontFamily: 'sans-serif',
40
+ fontSize: 13,
41
+ lineHeight: '18px',
42
+ padding: 12,
43
+ textAlign: 'center',
44
+ };
45
+ const formatMilliseconds = (milliseconds) => {
46
+ return Math.round(milliseconds);
47
+ };
48
+ const CaptionTextEditor = ({ captions, onChange, onSave, onCancel, readOnly }) => {
49
+ const listRef = (0, react_1.useRef)(null);
50
+ const cancelledBlurIndexes = (0, react_1.useRef)(new Set());
51
+ const dirtyRef = (0, react_1.useRef)(false);
52
+ const latestRef = (0, react_1.useRef)({ captions, onSave });
53
+ latestRef.current = { captions, onSave };
54
+ const captionRows = (0, react_1.useMemo)(() => {
55
+ const occurrences = new Map();
56
+ return captions.map((caption) => {
57
+ var _a;
58
+ const signature = [
59
+ caption.startMs,
60
+ caption.endMs,
61
+ caption.timestampMs,
62
+ caption.confidence,
63
+ ].join('-');
64
+ const occurrence = (_a = occurrences.get(signature)) !== null && _a !== void 0 ? _a : 0;
65
+ occurrences.set(signature, occurrence + 1);
66
+ return { caption, key: `${signature}-${occurrence}` };
67
+ });
68
+ }, [captions]);
69
+ const commitPending = (0, react_1.useCallback)(() => {
70
+ var _a, _b;
71
+ if (!dirtyRef.current) {
72
+ return;
73
+ }
74
+ dirtyRef.current = false;
75
+ (_b = (_a = latestRef.current).onSave) === null || _b === void 0 ? void 0 : _b.call(_a, latestRef.current.captions);
76
+ }, []);
77
+ (0, react_1.useEffect)(() => {
78
+ return commitPending;
79
+ }, [commitPending]);
80
+ const updateText = (0, react_1.useCallback)((index, text) => {
81
+ var _a;
82
+ if (((_a = latestRef.current.captions[index]) === null || _a === void 0 ? void 0 : _a.text) === text) {
83
+ return;
84
+ }
85
+ const nextCaptions = latestRef.current.captions.map((caption, captionIndex) => {
86
+ return captionIndex === index ? { ...caption, text } : caption;
87
+ });
88
+ latestRef.current.captions = nextCaptions;
89
+ dirtyRef.current = true;
90
+ onChange(nextCaptions);
91
+ }, [onChange]);
92
+ const focusSibling = (0, react_1.useCallback)((index) => {
93
+ var _a;
94
+ const input = (_a = listRef.current) === null || _a === void 0 ? void 0 : _a.querySelector(`[data-caption-index="${index}"]`);
95
+ input === null || input === void 0 ? void 0 : input.focus();
96
+ input === null || input === void 0 ? void 0 : input.scrollIntoView({ block: 'nearest' });
97
+ }, []);
98
+ return (jsx_runtime_1.jsx("div", { style: container, children: jsx_runtime_1.jsxs("div", { ref: listRef, style: list, children: [captions.length === 0 ? jsx_runtime_1.jsx("div", { style: empty, children: "No captions" }) : null, captionRows.map(({ caption, key }, index) => {
99
+ return (jsx_runtime_1.jsxs("div", { style: row, children: [
100
+ jsx_runtime_1.jsxs("div", { style: timing, children: [formatMilliseconds(caption.startMs), " \u2192", ' ', formatMilliseconds(caption.endMs), " ms"] }), jsx_runtime_1.jsx(RemInput_1.RemotionInput, { "data-caption-index": index, disabled: readOnly, onBlur: (event) => {
101
+ if (cancelledBlurIndexes.current.delete(index)) {
102
+ return;
103
+ }
104
+ updateText(index, event.currentTarget.value);
105
+ commitPending();
106
+ }, onChange: (event) => updateText(index, event.target.value), onKeyDown: (event) => {
107
+ if (event.key === 'ArrowDown' &&
108
+ index < captions.length - 1) {
109
+ event.preventDefault();
110
+ focusSibling(index + 1);
111
+ }
112
+ if (event.key === 'ArrowUp' && index > 0) {
113
+ event.preventDefault();
114
+ focusSibling(index - 1);
115
+ }
116
+ if (event.key === 'Escape') {
117
+ event.preventDefault();
118
+ cancelledBlurIndexes.current.add(index);
119
+ dirtyRef.current = false;
120
+ onCancel === null || onCancel === void 0 ? void 0 : onCancel();
121
+ event.currentTarget.blur();
122
+ }
123
+ }, rightAlign: false, small: true, status: "ok", style: {
124
+ color: colors_1.WHITE,
125
+ fontFamily: 'sans-serif',
126
+ fontSize: 12,
127
+ lineHeight: '16px',
128
+ }, value: caption.text })
129
+ ] }, key));
130
+ })] }) }));
131
+ };
132
+ exports.CaptionTextEditor = CaptionTextEditor;
@@ -5,6 +5,7 @@ const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const studio_shared_1 = require("@remotion/studio-shared");
6
6
  const react_1 = require("react");
7
7
  const remotion_1 = require("remotion");
8
+ const browser_studio_operations_1 = require("../helpers/browser-studio-operations");
8
9
  const client_id_1 = require("../helpers/client-id");
9
10
  const format_media_duration_1 = require("../helpers/format-media-duration");
10
11
  const get_preview_file_type_1 = require("../helpers/get-preview-file-type");
@@ -88,8 +89,8 @@ const AssetInfo = ({ assetName, contentSized = false, onAssetClick, readOnlyStud
88
89
  const imageSrc = (0, exports.getCurrentAssetImageMetadataSource)(assetName);
89
90
  const imageMetadata = (0, use_image_metadata_1.useImageMetadata)(imageSrc);
90
91
  const canRename = onAssetClick === undefined &&
91
- connectionStatus === 'connected' &&
92
- !readOnlyStudio;
92
+ ((0, browser_studio_operations_1.getBrowserStudioOperations)() !== null ||
93
+ (connectionStatus === 'connected' && !readOnlyStudio));
93
94
  const onRename = (0, react_1.useCallback)((newName) => {
94
95
  renameFile(newName).catch(() => undefined);
95
96
  }, [renameFile]);
@@ -1,5 +1,4 @@
1
1
  import React from 'react';
2
2
  export declare const EditorContexts: React.FC<{
3
3
  readonly children: React.ReactNode;
4
- readonly readOnlyStudio: boolean;
5
4
  }>;
@@ -24,8 +24,8 @@ const ShowRulersProvider_1 = require("./ShowRulersProvider");
24
24
  const SnappingProvider_1 = require("./SnappingProvider");
25
25
  const VisualControlsUndoSync_1 = require("./VisualControls/VisualControlsUndoSync");
26
26
  const ZoomGesturesProvider_1 = require("./ZoomGesturesProvider");
27
- const EditorContexts = ({ children, readOnlyStudio }) => {
28
- return (jsx_runtime_1.jsx(get_zod_if_possible_1.ZodProvider, { children: jsx_runtime_1.jsx(VisualControls_1.VisualControlsProvider, { children: jsx_runtime_1.jsxs(client_id_1.PreviewServerConnection, { readOnlyStudio: readOnlyStudio, children: [
27
+ const EditorContexts = ({ children }) => {
28
+ return (jsx_runtime_1.jsx(get_zod_if_possible_1.ZodProvider, { children: jsx_runtime_1.jsx(VisualControls_1.VisualControlsProvider, { children: jsx_runtime_1.jsxs(client_id_1.PreviewServerConnection, { children: [
29
29
  jsx_runtime_1.jsx(VisualControlsUndoSync_1.VisualControlsUndoSync, {}), jsx_runtime_1.jsxs(context_1.RenderQueueContextProvider, { children: [
30
30
  jsx_runtime_1.jsx(ClientRenderQueueProcessor_1.ClientRenderQueueProcessor, {}), jsx_runtime_1.jsx(keybindings_1.KeybindingContextProvider, { children: jsx_runtime_1.jsx(CheckerboardProvider_1.CheckerboardProvider, { children: jsx_runtime_1.jsx(ZoomGesturesProvider_1.ZoomGesturesProvider, { children: jsx_runtime_1.jsx(ShowRulersProvider_1.ShowRulersProvider, { children: jsx_runtime_1.jsx(ShowGuidesProvider_1.ShowGuidesProvider, { children: jsx_runtime_1.jsx(ShowOutlinesProvider_1.ShowOutlinesProvider, { children: jsx_runtime_1.jsx(SnappingProvider_1.SnappingProvider, { children: jsx_runtime_1.jsx(preview_size_1.PreviewSizeProvider, { children: jsx_runtime_1.jsx(ModalsProvider_1.ModalsProvider, { children: jsx_runtime_1.jsx(MediaVolumeProvider_1.MediaVolumeProvider, { children: jsx_runtime_1.jsx(player_1.PlayerInternals.PlayerEmitterProvider, { currentPlaybackRate: null, children: jsx_runtime_1.jsx(sidebar_1.SidebarContextProvider, { children: jsx_runtime_1.jsx(folders_1.FolderContextProvider, { children: jsx_runtime_1.jsx(highest_z_index_1.HighestZIndexProvider, { children: jsx_runtime_1.jsx(SetTimelineInOutProvider_1.SetTimelineInOutProvider, { children: jsx_runtime_1.jsx(ExpandedTracksProvider_1.ExpandedTracksProvider, { children: children }) }) }) }) }) }) }) }) }) }) }) }) }) }) }) })
31
31
  ] })
@@ -6,8 +6,8 @@ const react_1 = require("react");
6
6
  const remotion_1 = require("remotion");
7
7
  const colors_1 = require("../helpers/colors");
8
8
  const label = {
9
- color: colors_1.WHITE,
10
- fontSize: 15,
9
+ color: colors_1.LIGHT_TEXT,
10
+ fontSize: 13,
11
11
  fontFamily: 'Arial, Helvetica, sans-serif',
12
12
  whiteSpace: 'nowrap',
13
13
  };
@@ -59,7 +59,7 @@ const FpsCounter = ({ playbackSpeed }) => {
59
59
  const expectedFps = Math.abs(playbackSpeed) * videoConfig.fps;
60
60
  return {
61
61
  ...label,
62
- color: fps < expectedFps * 0.9 ? colors_1.RED : colors_1.WHITE,
62
+ color: fps < expectedFps * 0.9 ? colors_1.RED : colors_1.LIGHT_TEXT,
63
63
  };
64
64
  }, [fps, playbackSpeed, videoConfig]);
65
65
  if (fps === 0) {
@@ -7,6 +7,7 @@ const remotion_1 = require("remotion");
7
7
  const no_react_1 = require("remotion/no-react");
8
8
  const colors_1 = require("../helpers/colors");
9
9
  const use_keybinding_1 = require("../helpers/use-keybinding");
10
+ const fullscreen_1 = require("../icons/fullscreen");
10
11
  const canvas_ref_1 = require("../state/canvas-ref");
11
12
  const ControlButton_1 = require("./ControlButton");
12
13
  const accessibilityLabel = [
@@ -44,6 +45,6 @@ const FullScreenToggle = () => {
44
45
  f.unregister();
45
46
  };
46
47
  }, [keybindings, onClick]);
47
- return (jsx_runtime_1.jsx(ControlButton_1.ControlButton, { title: accessibilityLabel, "aria-label": accessibilityLabel, onClick: onClick, children: jsx_runtime_1.jsx("svg", { style: { width: 18, height: 18 }, viewBox: "0 0 448 512", fill: colors_1.WHITE_HEX, children: jsx_runtime_1.jsx("path", { d: "M0 180V56c0-13.3 10.7-24 24-24h124c6.6 0 12 5.4 12 12v40c0 6.6-5.4 12-12 12H64v84c0 6.6-5.4 12-12 12H12c-6.6 0-12-5.4-12-12zM288 44v40c0 6.6 5.4 12 12 12h84v84c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12V56c0-13.3-10.7-24-24-24H300c-6.6 0-12 5.4-12 12zm148 276h-40c-6.6 0-12 5.4-12 12v84h-84c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h124c13.3 0 24-10.7 24-24V332c0-6.6-5.4-12-12-12zM160 468v-40c0-6.6-5.4-12-12-12H64v-84c0-6.6-5.4-12-12-12H12c-6.6 0-12 5.4-12 12v124c0 13.3 10.7 24 24 24h124c6.6 0 12-5.4 12-12z" }) }) }));
48
+ return (jsx_runtime_1.jsx(ControlButton_1.ControlButton, { title: accessibilityLabel, "aria-label": accessibilityLabel, onClick: onClick, children: jsx_runtime_1.jsx(fullscreen_1.FullscreenIcon, { color: colors_1.WHITE_HEX, style: { width: 18, height: 18 } }) }));
48
49
  };
49
50
  exports.FullScreenToggle = FullScreenToggle;
@@ -115,6 +115,7 @@ const GlobalKeybindings = () => {
115
115
  : 'compositions',
116
116
  invocationTimestamp: Date.now(),
117
117
  assetSelection: null,
118
+ compositionSelection: null,
118
119
  });
119
120
  },
120
121
  triggerIfInputFieldFocused: true,
@@ -165,6 +166,7 @@ const GlobalKeybindings = () => {
165
166
  mode: 'docs',
166
167
  invocationTimestamp: Date.now(),
167
168
  assetSelection: null,
169
+ compositionSelection: null,
168
170
  });
169
171
  },
170
172
  commandCtrlKey: false,
@@ -1,3 +1,3 @@
1
1
  import type React from 'react';
2
- export declare const useSelectComposition: () => (c: import("remotion").AnyComposition, push: boolean, frame?: number | null) => void;
2
+ export declare const useSelectComposition: () => (c: Pick<import("remotion").AnyComposition, "folderName" | "id" | "parentFolderName">, push: boolean, frame?: number | null) => void;
3
3
  export declare const InitialCompositionLoader: React.FC;
@@ -27,6 +27,7 @@ const InlineAction = ({ renderAction, onClick, disabled, title, unhoveredColor =
27
27
  justifyContent: 'center',
28
28
  alignItems: 'center',
29
29
  borderRadius: 3,
30
+ opacity: disabled ? 0.5 : 1,
30
31
  pointerEvents: disabled ? 'none' : 'auto',
31
32
  };
32
33
  }, [disabled, hovered]);
@@ -0,0 +1,11 @@
1
+ import type { Caption } from '@remotion/captions';
2
+ import React from 'react';
3
+ import type { SequenceControls, SequencePropsSubscriptionKey } from 'remotion';
4
+ import type { CodePosition } from '../error-overlay/react-overlay/utils/get-source-map';
5
+ export declare const InlineCaptionInspector: React.FC<{
6
+ readonly captions: Caption[];
7
+ readonly controls: SequenceControls;
8
+ readonly nodePath: SequencePropsSubscriptionKey;
9
+ readonly readOnlyStudio: boolean;
10
+ readonly validatedLocation: CodePosition;
11
+ }>;
@@ -0,0 +1,108 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.InlineCaptionInspector = 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 client_id_1 = require("../helpers/client-id");
8
+ const CaptionInspector_1 = require("./CaptionInspector");
9
+ const save_sequence_prop_1 = require("./Timeline/save-sequence-prop");
10
+ const serializeCaptions = (captions) => {
11
+ return JSON.stringify(captions);
12
+ };
13
+ const getCaptionPatches = ({ previous, next, }) => {
14
+ if (previous.length !== next.length) {
15
+ return null;
16
+ }
17
+ const patches = [];
18
+ for (const [index, before] of previous.entries()) {
19
+ const after = next[index];
20
+ if (!after) {
21
+ return null;
22
+ }
23
+ if (before.text !== after.text) {
24
+ patches.push({
25
+ index,
26
+ before,
27
+ changes: { text: after.text },
28
+ });
29
+ }
30
+ }
31
+ return patches;
32
+ };
33
+ const InlineCaptionInspector = ({ captions, controls, nodePath, readOnlyStudio, validatedLocation }) => {
34
+ var _a;
35
+ const { previewServerState } = (0, react_1.useContext)(client_id_1.StudioServerConnectionCtx);
36
+ const { propStatuses } = (0, react_1.useContext)(remotion_1.Internals.VisualModePropStatusesContext);
37
+ const { setPropStatuses, setDragOverrides, clearDragOverrides } = (0, react_1.useContext)(remotion_1.Internals.VisualModeSettersContext);
38
+ const captionStatus = (_a = remotion_1.Internals.getPropStatusesCtx(propStatuses, nodePath)) === null || _a === void 0 ? void 0 : _a.captions;
39
+ const clientId = previewServerState.type === 'connected'
40
+ ? previewServerState.clientId
41
+ : null;
42
+ const canSave = !readOnlyStudio && clientId !== null && (captionStatus === null || captionStatus === void 0 ? void 0 : captionStatus.status) === 'static';
43
+ const [draftCaptions, setDraftCaptions] = (0, react_1.useState)(captions);
44
+ const savedCaptions = (0, react_1.useRef)(captions);
45
+ const runtimeSignature = serializeCaptions(captions);
46
+ const lastRuntimeSignature = (0, react_1.useRef)(runtimeSignature);
47
+ (0, react_1.useEffect)(() => {
48
+ if (lastRuntimeSignature.current === runtimeSignature) {
49
+ return;
50
+ }
51
+ lastRuntimeSignature.current = runtimeSignature;
52
+ savedCaptions.current = captions;
53
+ setDraftCaptions(captions);
54
+ clearDragOverrides(nodePath);
55
+ }, [captions, clearDragOverrides, nodePath, runtimeSignature]);
56
+ const updateCaptions = (0, react_1.useCallback)((nextCaptions) => {
57
+ setDraftCaptions(nextCaptions);
58
+ setDragOverrides(nodePath, 'captions', remotion_1.Internals.makeStaticDragOverride(nextCaptions));
59
+ }, [nodePath, setDragOverrides]);
60
+ const cancelCaptions = (0, react_1.useCallback)(() => {
61
+ setDraftCaptions(savedCaptions.current);
62
+ clearDragOverrides(nodePath);
63
+ }, [clearDragOverrides, nodePath]);
64
+ const saveCaptions = (0, react_1.useCallback)((nextCaptions) => {
65
+ const patches = getCaptionPatches({
66
+ previous: savedCaptions.current,
67
+ next: nextCaptions,
68
+ });
69
+ setDraftCaptions(nextCaptions);
70
+ if (!canSave ||
71
+ clientId === null ||
72
+ patches === null ||
73
+ patches.length === 0) {
74
+ clearDragOverrides(nodePath);
75
+ return;
76
+ }
77
+ savedCaptions.current = nextCaptions;
78
+ (0, save_sequence_prop_1.saveInlineCaptionPatches)({
79
+ fileName: validatedLocation.source,
80
+ nodePath,
81
+ schema: controls.schema,
82
+ patches,
83
+ nextCaptions,
84
+ setPropStatuses,
85
+ clientId,
86
+ undoLabel: 'Update captions',
87
+ redoLabel: 'Update captions again',
88
+ });
89
+ clearDragOverrides(nodePath);
90
+ }, [
91
+ canSave,
92
+ clearDragOverrides,
93
+ clientId,
94
+ controls.schema,
95
+ nodePath,
96
+ setPropStatuses,
97
+ validatedLocation.source,
98
+ ]);
99
+ const readOnlyTitle = readOnlyStudio
100
+ ? 'Caption editing is unavailable in read-only Studio'
101
+ : clientId === null
102
+ ? 'Caption editing requires a Studio server connection'
103
+ : (captionStatus === null || captionStatus === void 0 ? void 0 : captionStatus.status) === 'computed'
104
+ ? 'Captions must be a direct inline JSX array to edit them'
105
+ : 'Captions are not ready for editing';
106
+ return (jsx_runtime_1.jsx(CaptionInspector_1.CaptionInspector, { captions: draftCaptions, onTextChange: updateCaptions, onTextSave: saveCaptions, onTextCancel: cancelCaptions, readOnly: !canSave, readOnlyTitle: canSave ? null : readOnlyTitle }));
107
+ };
108
+ exports.InlineCaptionInspector = InlineCaptionInspector;