@remotion/studio 4.0.517 → 4.0.519

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 (146) hide show
  1. package/dist/components/AppLaunchButton.d.ts +16 -0
  2. package/dist/components/AppLaunchButton.js +90 -0
  3. package/dist/components/AssetSelector.js +64 -22
  4. package/dist/components/AssetSelectorItem.d.ts +14 -1
  5. package/dist/components/AssetSelectorItem.js +219 -70
  6. package/dist/components/Button.js +20 -7
  7. package/dist/components/Canvas.js +109 -78
  8. package/dist/components/CanvasOrLoading.js +7 -7
  9. package/dist/components/CaptionTextEditor.js +32 -8
  10. package/dist/components/CodingAgentButton.d.ts +7 -0
  11. package/dist/components/CodingAgentButton.js +59 -0
  12. package/dist/components/CompositionContextButton.d.ts +1 -0
  13. package/dist/components/CompositionContextButton.js +7 -3
  14. package/dist/components/CompositionSelector.js +16 -11
  15. package/dist/components/CompositionSelectorItem.js +16 -23
  16. package/dist/components/ConfigureLicenseModal.js +4 -48
  17. package/dist/components/CurrentAsset.js +1 -1
  18. package/dist/components/EditorContent.js +6 -3
  19. package/dist/components/ElementInstallConfirmation.d.ts +25 -7
  20. package/dist/components/ElementInstallConfirmation.js +347 -30
  21. package/dist/components/ElementLibraryModal.js +3 -1
  22. package/dist/components/FixComputedValueModal.js +5 -131
  23. package/dist/components/InitialCompositionLoader.js +3 -2
  24. package/dist/components/InlineCaptionInspector.js +13 -2
  25. package/dist/components/InspectorOpenInEditor.js +48 -33
  26. package/dist/components/InspectorPanel/CompositionInspector.js +35 -3
  27. package/dist/components/InspectorPanel/CompositionInspectorHeader.js +22 -14
  28. package/dist/components/InspectorPanel/ConnectedCompositionsSection.js +3 -1
  29. package/dist/components/InspectorPanel/SequenceInspectorHeader.d.ts +1 -1
  30. package/dist/components/InspectorPanel/SequenceInspectorHeader.js +10 -5
  31. package/dist/components/InspectorPanel/SequenceSelectionInspector.js +1 -1
  32. package/dist/components/InspectorPanel/common.js +1 -0
  33. package/dist/components/InspectorPanel/styles.js +1 -0
  34. package/dist/components/InspectorSequenceSection.js +8 -3
  35. package/dist/components/InspectorSourceLocation.js +5 -1
  36. package/dist/components/KnownBugs.d.ts +1 -1
  37. package/dist/components/KnownBugs.js +1 -1
  38. package/dist/components/LicenseExplanation.d.ts +2 -0
  39. package/dist/components/LicenseExplanation.js +63 -0
  40. package/dist/components/MenuToolbar.js +7 -1
  41. package/dist/components/Modals.js +50 -2
  42. package/dist/components/NewComposition/InputDragger.js +29 -2
  43. package/dist/components/NewComposition/NewCompDuration.js +1 -1
  44. package/dist/components/NewComposition/NewComposition.d.ts +23 -0
  45. package/dist/components/NewComposition/NewComposition.js +217 -80
  46. package/dist/components/{UpdateModal/OpenIssueButton.js → OpenIssueButton.js} +1 -1
  47. package/dist/components/PlaybackRateSelector.js +2 -5
  48. package/dist/components/QuickSwitcher/ExplorerQuickSwitcherTrigger.d.ts +2 -0
  49. package/dist/components/QuickSwitcher/ExplorerQuickSwitcherTrigger.js +28 -7
  50. package/dist/components/QuickSwitcher/QuickSwitcherContent.js +21 -13
  51. package/dist/components/RenderQueue/actions.d.ts +1 -0
  52. package/dist/components/RenderQueue/actions.js +5 -1
  53. package/dist/components/SelectedOutlineCanvasRotation.js +27 -1
  54. package/dist/components/SelectedOutlineElement.js +2 -1
  55. package/dist/components/SelectedOutlineOverlay.js +9 -10
  56. package/dist/components/SelectedOutlinePolygon.d.ts +1 -0
  57. package/dist/components/SelectedOutlinePolygon.js +12 -4
  58. package/dist/components/SelectedOutlineRenderer.d.ts +1 -1
  59. package/dist/components/SelectedOutlineRenderer.js +33 -35
  60. package/dist/components/SettingsContext.js +2 -1
  61. package/dist/components/SettingsModal.d.ts +1 -1
  62. package/dist/components/SettingsModal.js +19 -3
  63. package/dist/components/SidebarRenderButton.d.ts +1 -0
  64. package/dist/components/SidebarRenderButton.js +15 -5
  65. package/dist/components/Timeline/SequencePropsObserver.js +29 -14
  66. package/dist/components/Timeline/TimelineKeyframeControls.js +3 -1
  67. package/dist/components/Timeline/TimelineRowChrome.js +4 -2
  68. package/dist/components/Timeline/TimelineSequence.js +40 -8
  69. package/dist/components/Timeline/TimelineSequenceItem.js +34 -1
  70. package/dist/components/Timeline/TimelineStack/get-stack.d.ts +1 -0
  71. package/dist/components/Timeline/TimelineStack/get-stack.js +35 -3
  72. package/dist/components/Timeline/duplicate-selected-timeline-item.js +23 -25
  73. package/dist/components/Timeline/get-sequence-context-menu-items.d.ts +6 -0
  74. package/dist/components/Timeline/get-sequence-context-menu-items.js +34 -1
  75. package/dist/components/Timeline/sequence-props-subscription-store.d.ts +2 -0
  76. package/dist/components/Timeline/sequence-props-subscription-store.js +22 -1
  77. package/dist/components/Timeline/use-sequence-props-subscription.js +7 -0
  78. package/dist/components/TimelineCombobox.js +1 -0
  79. package/dist/components/UpdateCheck.d.ts +0 -8
  80. package/dist/components/UpdateCheck.js +7 -54
  81. package/dist/components/UpdateStatusContext.d.ts +18 -0
  82. package/dist/components/UpdateStatusContext.js +74 -0
  83. package/dist/components/UpdatesSettings.d.ts +2 -0
  84. package/dist/components/UpdatesSettings.js +251 -0
  85. package/dist/components/WebMcp.d.ts +2 -0
  86. package/dist/components/WebMcp.js +945 -0
  87. package/dist/components/composition-menu-items.js +26 -0
  88. package/dist/components/get-open-in-menu-items.d.ts +4 -0
  89. package/dist/components/get-open-in-menu-items.js +28 -24
  90. package/dist/components/root-composition-menu-items.d.ts +4 -1
  91. package/dist/components/root-composition-menu-items.js +38 -1
  92. package/dist/components/selected-outline-measurement.d.ts +11 -0
  93. package/dist/components/selected-outline-measurement.js +13 -5
  94. package/dist/components/use-configure-default-apps.d.ts +1 -0
  95. package/dist/components/use-configure-default-apps.js +24 -0
  96. package/dist/error-overlay/remotion-overlay/CodeFrame.js +5 -6
  97. package/dist/error-overlay/remotion-overlay/CopyStackTrace.js +1 -1
  98. package/dist/error-overlay/remotion-overlay/ErrorDisplay.js +47 -18
  99. package/dist/error-overlay/remotion-overlay/ErrorLoader.js +1 -1
  100. package/dist/error-overlay/remotion-overlay/ErrorTitle.js +5 -4
  101. package/dist/error-overlay/remotion-overlay/OpenInEditor.js +48 -76
  102. package/dist/error-overlay/remotion-overlay/SearchGitHubIssues.js +1 -1
  103. package/dist/error-overlay/remotion-overlay/ShortcutHint.js +2 -2
  104. package/dist/error-overlay/remotion-overlay/StackFrame.js +13 -8
  105. package/dist/error-overlay/remotion-overlay/Symbolicating.js +1 -1
  106. package/dist/esm/{chunk-gzqm3g2m.js → chunk-1fkq5bfq.js} +24093 -21093
  107. package/dist/esm/chunk-6jf1natv.js +25 -0
  108. package/dist/esm/{chunk-4bxz1d3g.js → chunk-je0h1bgt.js} +1 -28
  109. package/dist/esm/chunk-m0jqdbkr.js +14571 -0
  110. package/dist/esm/index.mjs +0 -2
  111. package/dist/esm/internals.mjs +43231 -25675
  112. package/dist/esm/previewEntry.mjs +46334 -28776
  113. package/dist/esm/renderEntry.mjs +6 -3
  114. package/dist/helpers/can-show-updates.d.ts +5 -0
  115. package/dist/helpers/can-show-updates.js +7 -0
  116. package/dist/helpers/colors.d.ts +0 -3
  117. package/dist/helpers/colors.js +2 -5
  118. package/dist/helpers/create-folder-tree.d.ts +5 -0
  119. package/dist/helpers/create-folder-tree.js +40 -2
  120. package/dist/helpers/format-file-location.d.ts +8 -0
  121. package/dist/helpers/format-file-location.js +14 -3
  122. package/dist/helpers/get-asset-metadata.js +1 -1
  123. package/dist/helpers/get-git-menu-item.d.ts +5 -0
  124. package/dist/helpers/get-git-menu-item.js +15 -1
  125. package/dist/helpers/get-timeline-max-zoom.d.ts +8 -0
  126. package/dist/helpers/get-timeline-max-zoom.js +17 -6
  127. package/dist/helpers/hoverable.d.ts +1 -0
  128. package/dist/helpers/hoverable.js +14 -6
  129. package/dist/helpers/open-in-editor.js +51 -1
  130. package/dist/helpers/preview-server-events.js +3 -0
  131. package/dist/helpers/timeline-layout.d.ts +0 -1
  132. package/dist/helpers/timeline-layout.js +1 -5
  133. package/dist/helpers/url-state.d.ts +1 -0
  134. package/dist/helpers/url-state.js +12 -5
  135. package/dist/icons/enter.d.ts +4 -0
  136. package/dist/icons/enter.js +10 -0
  137. package/dist/renderEntry.js +2 -0
  138. package/dist/state/folders.d.ts +3 -0
  139. package/dist/state/folders.js +40 -1
  140. package/dist/state/modals.d.ts +1 -6
  141. package/dist/state/playbackrate.d.ts +1 -0
  142. package/dist/state/playbackrate.js +4 -1
  143. package/package.json +17 -14
  144. package/dist/components/UpdateModal/UpdateModal.d.ts +0 -6
  145. package/dist/components/UpdateModal/UpdateModal.js +0 -104
  146. /package/dist/components/{UpdateModal/OpenIssueButton.d.ts → OpenIssueButton.d.ts} +0 -0
@@ -5,32 +5,47 @@ const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const react_1 = require("react");
6
6
  const ShortcutHint_1 = require("../../error-overlay/remotion-overlay/ShortcutHint");
7
7
  const colors_1 = require("../../helpers/colors");
8
+ const hoverable_1 = require("../../helpers/hoverable");
8
9
  const use_keybinding_1 = require("../../helpers/use-keybinding");
10
+ const ellipsis_1 = require("../../icons/ellipsis");
9
11
  const modals_1 = require("../../state/modals");
12
+ const InlineDropdown_1 = require("../InlineDropdown");
10
13
  const quickSwitcherArea = {
11
14
  padding: '4px 4px 4px 8px',
12
15
  borderBottom: `1px solid ${colors_1.BLACK_HEX}`,
13
- overflowY: 'auto',
16
+ display: 'flex',
17
+ alignItems: 'center',
18
+ gap: 4,
14
19
  };
15
20
  const quickSwitcherTrigger = {
16
- backgroundColor: colors_1.WHITE_ALPHA_06,
17
21
  borderRadius: 4,
18
22
  padding: '4px 10px 4px 12px',
19
- color: colors_1.LIGHT_TEXT,
20
23
  fontSize: 12,
21
- cursor: 'pointer',
24
+ cursor: 'default',
22
25
  display: 'flex',
23
26
  alignItems: 'center',
24
27
  justifyContent: 'space-between',
25
28
  border: 'none',
26
- width: '100%',
29
+ flex: 1,
27
30
  appearance: 'none',
31
+ userSelect: 'none',
32
+ ...(0, hoverable_1.hoverableStyle)({
33
+ idleBackground: colors_1.WHITE_ALPHA_06,
34
+ hoverBackground: colors_1.WHITE_ALPHA_06,
35
+ idleColor: colors_1.LIGHT_TEXT,
36
+ hoverColor: colors_1.WHITE,
37
+ }),
38
+ };
39
+ const ellipsisSvgProps = {
40
+ style: {
41
+ height: 12,
42
+ },
28
43
  };
29
44
  const shortcutLabel = {
30
45
  fontSize: 11,
31
46
  opacity: 0.6,
32
47
  };
33
- const ExplorerQuickSwitcherTrigger = ({ mode, showShortcut, tabIndex }) => {
48
+ const ExplorerQuickSwitcherTrigger = ({ mode, showShortcut, tabIndex, getActions }) => {
34
49
  const { setSelectedModal } = (0, react_1.useContext)(modals_1.SetSelectedModalContext);
35
50
  const openQuickSwitcher = (0, react_1.useCallback)(() => {
36
51
  setSelectedModal({
@@ -41,6 +56,12 @@ const ExplorerQuickSwitcherTrigger = ({ mode, showShortcut, tabIndex }) => {
41
56
  compositionSelection: null,
42
57
  });
43
58
  }, [mode, setSelectedModal]);
44
- return (jsx_runtime_1.jsx("div", { style: quickSwitcherArea, className: "__remotion-vertical-scrollbar", children: jsx_runtime_1.jsxs("button", { type: "button", style: quickSwitcherTrigger, onClick: openQuickSwitcher, tabIndex: tabIndex, children: ["Search...", showShortcut && !(0, use_keybinding_1.areKeyboardShortcutsDisabled)() ? (jsx_runtime_1.jsxs("span", { style: shortcutLabel, children: [ShortcutHint_1.cmdOrCtrlCharacter, "+K"] })) : null] }) }));
59
+ const renderMoreActions = (0, react_1.useCallback)((color) => {
60
+ return jsx_runtime_1.jsx(ellipsis_1.EllipsisIcon, { svgProps: ellipsisSvgProps, fill: color });
61
+ }, []);
62
+ const moreActionsTitle = mode === 'assets' ? 'More asset actions' : 'More composition actions';
63
+ return (jsx_runtime_1.jsxs("div", { style: quickSwitcherArea, children: [
64
+ jsx_runtime_1.jsxs("button", { type: "button", style: quickSwitcherTrigger, onClick: openQuickSwitcher, tabIndex: tabIndex, className: `${hoverable_1.HOVERABLE_CLASS_NAME} ${hoverable_1.FOCUS_VISIBLE_ONLY_CLASS_NAME}`, children: ["Search...", showShortcut && !(0, use_keybinding_1.areKeyboardShortcutsDisabled)() ? (jsx_runtime_1.jsxs("span", { style: shortcutLabel, children: [ShortcutHint_1.cmdOrCtrlCharacter, "+K"] })) : null] }), jsx_runtime_1.jsx(InlineDropdown_1.InlineDropdown, { variant: null, title: moreActionsTitle, renderAction: renderMoreActions, getItems: getActions, className: hoverable_1.FOCUS_VISIBLE_ONLY_CLASS_NAME })
65
+ ] }));
45
66
  };
46
67
  exports.ExplorerQuickSwitcherTrigger = ExplorerQuickSwitcherTrigger;
@@ -27,6 +27,10 @@ const input = {
27
27
  width: '100%',
28
28
  borderRadius: 4,
29
29
  };
30
+ const touchscreenInput = {
31
+ ...input,
32
+ fontSize: 16,
33
+ };
30
34
  const modeSelector = {
31
35
  paddingLeft: 16,
32
36
  paddingRight: 16,
@@ -42,6 +46,7 @@ const modeItem = {
42
46
  padding: 0,
43
47
  fontSize: 13,
44
48
  cursor: 'pointer',
49
+ userSelect: 'none',
45
50
  };
46
51
  const modeInactive = {
47
52
  ...modeItem,
@@ -126,6 +131,7 @@ const QuickSwitcherContent = ({ initialMode, invocationTimestamp, readOnlyStudio
126
131
  });
127
132
  }, [assetSelection, compositionSelection, initialMode, invocationTimestamp]);
128
133
  const inputRef = (0, react_1.useRef)(null);
134
+ const isTouchscreen = navigator.maxTouchPoints > 0;
129
135
  const selectComposition = (0, InitialCompositionLoader_1.useSelectComposition)();
130
136
  const selectAsset = (0, use_select_asset_1.useSelectAsset)();
131
137
  const closeMenu = (0, react_1.useCallback)(() => undefined, []);
@@ -314,39 +320,41 @@ const QuickSwitcherContent = ({ initialMode, invocationTimestamp, readOnlyStudio
314
320
  setState({ query: e.target.value, selectedIndex: 0 });
315
321
  }, []);
316
322
  const selectedIndexRounded = (0, shared_1.loopIndex)(state.selectedIndex, resultsArray.length);
317
- const onActionsSelected = (0, react_1.useCallback)(() => {
323
+ const focusInput = (0, react_1.useCallback)(() => {
318
324
  var _a;
325
+ if (!isTouchscreen) {
326
+ (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
327
+ }
328
+ }, [isTouchscreen]);
329
+ const onActionsSelected = (0, react_1.useCallback)(() => {
319
330
  setState((s) => ({
320
331
  query: `> ${stripQuery(s.query)}`,
321
332
  selectedIndex: 0,
322
333
  }));
323
- (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
324
- }, []);
334
+ focusInput();
335
+ }, [focusInput]);
325
336
  const onCompositionsSelected = (0, react_1.useCallback)(() => {
326
- var _a;
327
337
  setState((s) => ({
328
338
  query: stripQuery(s.query),
329
339
  selectedIndex: 0,
330
340
  }));
331
- (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
332
- }, []);
341
+ focusInput();
342
+ }, [focusInput]);
333
343
  const onAssetsSelected = (0, react_1.useCallback)(() => {
334
- var _a;
335
344
  setState((s) => ({
336
345
  query: `$ ${stripQuery(s.query)}`,
337
346
  selectedIndex: 0,
338
347
  }));
339
- (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
340
- }, []);
348
+ focusInput();
349
+ }, [focusInput]);
341
350
  const onDocSearchSelected = (0, react_1.useCallback)(() => {
342
- var _a;
343
351
  setState((s) => ({
344
352
  query: `? ${stripQuery(s.query)}`,
345
353
  selectedIndex: 0,
346
354
  }));
347
355
  setDocResults({ type: 'initial' });
348
- (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
349
- }, []);
356
+ focusInput();
357
+ }, [focusInput]);
350
358
  const showSearchLoadingState = mode === 'docs' && docResults.type === 'loading';
351
359
  const showEmptyDocSearch = mode === 'docs' && actualQuery.trim() === '';
352
360
  const placeholder = mode === 'assets'
@@ -360,7 +368,7 @@ const QuickSwitcherContent = ({ initialMode, invocationTimestamp, readOnlyStudio
360
368
  jsx_runtime_1.jsx("button", { onClick: onCompositionsSelected, style: mode === 'compositions' ? modeActive : modeInactive, type: "button", children: "Compositions" }), jsx_runtime_1.jsx(layout_1.Spacing, { x: 1 }), jsx_runtime_1.jsx("button", { onClick: onAssetsSelected, style: mode === 'assets' ? modeActive : modeInactive, type: "button", children: "Assets" }), jsx_runtime_1.jsx(layout_1.Spacing, { x: 1 }), jsx_runtime_1.jsx("button", { onClick: onActionsSelected, style: mode === 'commands' ? modeActive : modeInactive, type: "button", children: "Actions" }), jsx_runtime_1.jsx(layout_1.Spacing, { x: 1 }), jsx_runtime_1.jsx("button", { onClick: onDocSearchSelected, style: mode === 'docs' ? modeActive : modeInactive, type: "button", children: "Documentation" })
361
369
  ] })), jsx_runtime_1.jsx("div", { style: assetSelection === null && compositionSelection === null
362
370
  ? content
363
- : contentWithoutModeSelector, children: jsx_runtime_1.jsx(RemInput_1.RemotionInput, { ref: inputRef, type: "text", style: input, autoFocus: true, status: "ok", value: state.query, onChange: onTextChange, placeholder: placeholder, rightAlign: false }) }), jsx_runtime_1.jsx("div", { style: results, className: is_menu_item_1.VERTICAL_SCROLLBAR_CLASSNAME, children: showEmptyDocSearch ||
371
+ : contentWithoutModeSelector, children: jsx_runtime_1.jsx(RemInput_1.RemotionInput, { ref: inputRef, type: "text", style: isTouchscreen ? touchscreenInput : input, autoFocus: !isTouchscreen, status: "ok", value: state.query, onChange: onTextChange, placeholder: placeholder, rightAlign: false }) }), jsx_runtime_1.jsx("div", { style: results, className: is_menu_item_1.VERTICAL_SCROLLBAR_CLASSNAME, children: showEmptyDocSearch ||
364
372
  showSearchLoadingState ? null : resultsArray.length === 0 ? (jsx_runtime_1.jsx(NoResults_1.QuickSwitcherNoResults, { mode: mode, query: actualQuery })) : (resultsArray.map((result, i) => {
365
373
  return (jsx_runtime_1.jsx(QuickSwitcherResult_1.QuickSwitcherResult, { selected: selectedIndexRounded === i, result: result }, result.id));
366
374
  })) })
@@ -109,6 +109,7 @@ export declare const applyCodemod: ({ codemod, dryRun, symbolicatedStack, signal
109
109
  export declare const removeRenderJob: (job: RenderJob) => Promise<undefined>;
110
110
  export declare const cancelRenderJob: (job: RenderJob) => Promise<import("@remotion/studio-shared").CancelRenderResponse>;
111
111
  export declare const updateAvailable: (signal: AbortSignal) => Promise<import("@remotion/studio-shared").UpdateAvailableResponse>;
112
+ export declare const getReleaseNotes: (currentVersion: string, latestVersion: string, signal: AbortSignal) => Promise<import("@remotion/studio-shared").GetReleaseNotesResponse>;
112
113
  export declare const getProjectInfo: (signal: AbortSignal) => Promise<import("@remotion/studio-shared").ProjectInfoResponse>;
113
114
  export declare const callUpdateDefaultPropsApi: (compositionId: string, defaultProps: Record<string, unknown>, enumPaths: EnumPath[]) => Promise<import("@remotion/studio-shared").UpdateDefaultPropsResponse>;
114
115
  export declare const applyVisualControlChange: ({ fileName, changes, }: {
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
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;
3
+ exports.applyVisualControlChange = exports.callUpdateDefaultPropsApi = exports.getProjectInfo = exports.getReleaseNotes = 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 browser_studio_operations_1 = require("../../helpers/browser-studio-operations");
6
6
  const call_api_1 = require("../call-api");
@@ -166,6 +166,10 @@ const updateAvailable = (signal) => {
166
166
  return (0, call_api_1.callApi)('/api/update-available', {}, signal);
167
167
  };
168
168
  exports.updateAvailable = updateAvailable;
169
+ const getReleaseNotes = (currentVersion, latestVersion, signal) => {
170
+ return (0, call_api_1.callApi)('/api/release-notes', { currentVersion, latestVersion }, signal);
171
+ };
172
+ exports.getReleaseNotes = getReleaseNotes;
169
173
  const getProjectInfo = (signal) => {
170
174
  return (0, call_api_1.callApi)('/api/project-info', {}, signal);
171
175
  };
@@ -38,6 +38,7 @@ const jsx_runtime_1 = require("react/jsx-runtime");
38
38
  const react_1 = __importStar(require("react"));
39
39
  const remotion_1 = require("remotion");
40
40
  const colors_1 = require("../helpers/colors");
41
+ const is_mac_1 = require("../helpers/is-mac");
41
42
  const pointer_session_1 = require("../helpers/pointer-session");
42
43
  const editor_snapping_1 = require("../state/editor-snapping");
43
44
  const canvas_rotation_cursor_1 = require("./canvas-rotation-cursor");
@@ -57,9 +58,34 @@ const SelectedOutlineCanvasRotation = ({ getLatestTargetByKey, layoutTarget, onD
57
58
  const { getDragOverrides } = (0, react_1.useContext)(remotion_1.Internals.VisualModeDragOverridesContext);
58
59
  const { setPropStatuses, setDragOverrides, clearDragOverrides } = (0, react_1.useContext)(remotion_1.Internals.VisualModeSettersContext);
59
60
  const { editorSnapping } = (0, react_1.useContext)(editor_snapping_1.EditorSnappingContext);
61
+ const [commandKeyPressed, setCommandKeyPressed] = react_1.default.useState(false);
60
62
  const cursor = transform3DMode
61
63
  ? canvas_rotation_cursor_1.canvasRotationCursor
62
64
  : canvas2DRotationCursor;
65
+ react_1.default.useEffect(() => {
66
+ const commandKey = is_mac_1.isMac ? 'Meta' : 'Control';
67
+ const onKeyDown = (event) => {
68
+ if (event.key === commandKey) {
69
+ setCommandKeyPressed(true);
70
+ }
71
+ };
72
+ const onKeyUp = (event) => {
73
+ if (event.key === commandKey) {
74
+ setCommandKeyPressed(false);
75
+ }
76
+ };
77
+ const onBlur = () => {
78
+ setCommandKeyPressed(false);
79
+ };
80
+ window.addEventListener('keydown', onKeyDown);
81
+ window.addEventListener('keyup', onKeyUp);
82
+ window.addEventListener('blur', onBlur);
83
+ return () => {
84
+ window.removeEventListener('keydown', onKeyDown);
85
+ window.removeEventListener('keyup', onKeyUp);
86
+ window.removeEventListener('blur', onBlur);
87
+ };
88
+ }, []);
63
89
  const onPointerDown = react_1.default.useCallback((event) => {
64
90
  var _a, _b;
65
91
  if (event.button !== 0) {
@@ -241,6 +267,6 @@ const SelectedOutlineCanvasRotation = ({ getLatestTargetByKey, layoutTarget, onD
241
267
  setDragOverrides,
242
268
  setPropStatuses,
243
269
  ]);
244
- return (jsx_runtime_1.jsx("polygon", { points: outline.points.map((point) => `${point.x},${point.y}`).join(' '), fill: colors_1.TRANSPARENT, pointerEvents: "all", cursor: cursor, onPointerDown: onPointerDown, "data-remotion-studio-canvas-rotation": true }));
270
+ return (jsx_runtime_1.jsx("polygon", { points: outline.points.map((point) => `${point.x},${point.y}`).join(' '), fill: colors_1.TRANSPARENT, pointerEvents: commandKeyPressed ? 'none' : 'all', cursor: commandKeyPressed ? 'default' : cursor, onPointerDown: onPointerDown, "data-remotion-studio-canvas-rotation": true }));
245
271
  };
246
272
  exports.SelectedOutlineCanvasRotation = SelectedOutlineCanvasRotation;
@@ -362,6 +362,7 @@ const SelectedOutlineElementUnmemoized = ({ compositionHeight, compositionWidth,
362
362
  };
363
363
  }, [onContextMenuOpen, outline.key, registerContextMenuOpen]);
364
364
  return (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [
365
- jsx_runtime_1.jsx(SelectedOutlinePolygon_1.SelectedOutlinePolygon, { compositionHeight: compositionHeight, compositionWidth: compositionWidth, containsSelection: (layoutTarget === null || layoutTarget === void 0 ? void 0 : layoutTarget.containsSelection) === true, directlySelected: (layoutTarget === null || layoutTarget === void 0 ? void 0 : layoutTarget.selected) === true, dragging: dragging, getAllDragOutlines: getAllDragOutlines, getAllDragTargets: getAllDragTargets, getLayoutTarget: getLayoutTarget, getTarget: getTarget, hasTarget: layoutTarget !== undefined, hovered: hovered, outline: outline, onDraggingChange: onDraggingChange, onHoverChange: onHoverChange, onSnapPointsChange: onSnapPointsChange, onSelect: onSelect, onDoubleClickTarget: onDoubleClickTarget, scale: scale, showSelectedOutline: (_a = layoutTarget === null || layoutTarget === void 0 ? void 0 : layoutTarget.showSelectedOutline) !== null && _a !== void 0 ? _a : false }), (layoutTarget === null || layoutTarget === void 0 ? void 0 : layoutTarget.selectedForRotation) && (controlTarget === null || controlTarget === void 0 ? void 0 : controlTarget.rotationDrag) ? (jsx_runtime_1.jsx(SelectedOutlineCanvasRotation_1.SelectedOutlineCanvasRotation, { getLatestTargetByKey: getLatestTargetByKey, layoutTarget: layoutTarget, onDraggingChange: onDraggingChange, outline: outline, transform3DMode: controlTarget.rotationDrag.transform3DMode })) : null] }));
365
+ jsx_runtime_1.jsx(SelectedOutlinePolygon_1.SelectedOutlinePolygon, { compositionHeight: compositionHeight, compositionWidth: compositionWidth, containsSelection: (layoutTarget === null || layoutTarget === void 0 ? void 0 : layoutTarget.containsSelection) === true, directlySelected: (layoutTarget === null || layoutTarget === void 0 ? void 0 : layoutTarget.selected) === true, dragging: dragging, getAllDragOutlines: getAllDragOutlines, getAllDragTargets: getAllDragTargets, getLayoutTarget: getLayoutTarget, getTarget: getTarget, hasTarget: layoutTarget !== undefined, hovered: hovered, outline: outline, onDraggingChange: onDraggingChange, onHoverChange: onHoverChange, onSnapPointsChange: onSnapPointsChange, onSelect: onSelect, onDoubleClickTarget: onDoubleClickTarget, scale: scale, showSelectedOutline: (_a = layoutTarget === null || layoutTarget === void 0 ? void 0 : layoutTarget.showSelectedOutline) !== null && _a !== void 0 ? _a : false, translateWithCommandKey: (layoutTarget === null || layoutTarget === void 0 ? void 0 : layoutTarget.selectedForRotation) === true &&
366
+ Boolean(controlTarget === null || controlTarget === void 0 ? void 0 : controlTarget.rotationDrag) }), (layoutTarget === null || layoutTarget === void 0 ? void 0 : layoutTarget.selectedForRotation) && (controlTarget === null || controlTarget === void 0 ? void 0 : controlTarget.rotationDrag) ? (jsx_runtime_1.jsx(SelectedOutlineCanvasRotation_1.SelectedOutlineCanvasRotation, { getLatestTargetByKey: getLatestTargetByKey, layoutTarget: layoutTarget, onDraggingChange: onDraggingChange, outline: outline, transform3DMode: controlTarget.rotationDrag.transform3DMode })) : null] }));
366
367
  };
367
368
  exports.SelectedOutlineElement = react_1.default.memo(SelectedOutlineElementUnmemoized);
@@ -545,13 +545,10 @@ const ActiveSelectedOutlineOverlayUnmemoized = ({ calculateOutlineTargetsForCurr
545
545
  selectableOutlinesForLayout,
546
546
  timelinePosition,
547
547
  ]);
548
- const outlineTargetsRef = (0, react_1.useRef)(outlineTargets);
549
- const getOutlineTargets = (0, react_1.useCallback)(() => outlineTargetsRef.current, []);
550
548
  (0, react_1.useLayoutEffect)(() => {
551
- outlineTargetsRef.current = outlineTargets;
552
549
  updateOutlinesRef.current();
553
- }, [outlineTargets, scale, translationX, translationY]);
554
- return (jsx_runtime_1.jsx(SelectedOutlineRenderer_1.SelectedOutlineRenderer, { compositionHeight: compositionHeight, compositionWidth: compositionWidth, dragging: draggingOutline, getLatestOutlineTargetByKey: getLatestOutlineTargetByKey, getOutlineTargets: getOutlineTargets, onDraggingChange: onDraggingChange, onContextMenuOpenChange: onContextMenuOpenChange, onSelect: onSelect, scale: scale, sequences: sequences, updateOutlinesRef: updateOutlinesRef }));
550
+ }, [scale, translationX, translationY]);
551
+ return (jsx_runtime_1.jsx(SelectedOutlineRenderer_1.SelectedOutlineRenderer, { compositionHeight: compositionHeight, compositionWidth: compositionWidth, dragging: draggingOutline, getLatestOutlineTargetByKey: getLatestOutlineTargetByKey, outlineTargets: outlineTargets, onDraggingChange: onDraggingChange, onContextMenuOpenChange: onContextMenuOpenChange, onSelect: onSelect, scale: scale, sequences: sequences, updateOutlinesRef: updateOutlinesRef }));
555
552
  };
556
553
  const ActiveSelectedOutlineOverlay = react_1.default.memo(ActiveSelectedOutlineOverlayUnmemoized);
557
554
  const SelectedOutlineOverlayUnmemoized = ({ canvasHovered, compositionHeight, compositionWidth, scale, translationX, translationY, }) => {
@@ -634,13 +631,11 @@ const SelectedOutlineOverlayUnmemoized = ({ canvasHovered, compositionHeight, co
634
631
  selectedTransformOriginInfo,
635
632
  sequenceKeysContainingSelection,
636
633
  ]);
637
- const calculateOutlineTargetsRef = (0, react_1.useRef)(calculateOutlineTargetsForCurrentState);
638
634
  const getSelectableOutlinesRef = (0, react_1.useRef)(getSelectableOutlines);
639
635
  const selectableOutlinesCacheRef = (0, react_1.useRef)(null);
640
636
  (0, react_1.useLayoutEffect)(() => {
641
- calculateOutlineTargetsRef.current = calculateOutlineTargetsForCurrentState;
642
637
  getSelectableOutlinesRef.current = getSelectableOutlines;
643
- }, [calculateOutlineTargetsForCurrentState, getSelectableOutlines]);
638
+ }, [getSelectableOutlines]);
644
639
  const getSelectableOutlinesAtFrame = (0, react_1.useCallback)((timelinePosition) => {
645
640
  const currentGetSelectableOutlines = getSelectableOutlinesRef.current;
646
641
  const cached = selectableOutlinesCacheRef.current;
@@ -658,7 +653,7 @@ const SelectedOutlineOverlayUnmemoized = ({ canvasHovered, compositionHeight, co
658
653
  }, []);
659
654
  const getLatestOutlineTargetByKey = (0, react_1.useCallback)((key) => {
660
655
  const timelinePosition = getCurrentFrame();
661
- const target = calculateOutlineTargetsRef.current({
656
+ const target = calculateOutlineTargetsForCurrentState({
662
657
  mode: 'controls',
663
658
  runtimeValuesByStore: new Map(),
664
659
  selectableOutlines: getSelectableOutlinesAtFrame(timelinePosition),
@@ -666,7 +661,11 @@ const SelectedOutlineOverlayUnmemoized = ({ canvasHovered, compositionHeight, co
666
661
  targetTimelinePosition: timelinePosition,
667
662
  })[0];
668
663
  return target;
669
- }, [getCurrentFrame, getSelectableOutlinesAtFrame]);
664
+ }, [
665
+ calculateOutlineTargetsForCurrentState,
666
+ getCurrentFrame,
667
+ getSelectableOutlinesAtFrame,
668
+ ]);
670
669
  const getCurrentSelectableOutlines = (0, react_1.useCallback)(() => getSelectableOutlinesAtFrame(getCurrentFrame()), [getCurrentFrame, getSelectableOutlinesAtFrame]);
671
670
  const onDraggingChange = (0, react_1.useCallback)((dragging) => {
672
671
  setDraggingOutline(dragging);
@@ -23,4 +23,5 @@ export declare const SelectedOutlinePolygon: React.NamedExoticComponent<{
23
23
  readonly onDoubleClickTarget: (target: SelectedOutlineTarget, button: number, sequenceWasDragged: boolean) => boolean;
24
24
  readonly scale: number;
25
25
  readonly showSelectedOutline: boolean;
26
+ readonly translateWithCommandKey: boolean;
26
27
  }>;
@@ -41,6 +41,7 @@ const client_id_1 = require("../helpers/client-id");
41
41
  const colors_1 = require("../helpers/colors");
42
42
  const drag_aware_double_click_1 = require("../helpers/drag-aware-double-click");
43
43
  const interactivity_enabled_1 = require("../helpers/interactivity-enabled");
44
+ const is_mac_1 = require("../helpers/is-mac");
44
45
  const pointer_session_1 = require("../helpers/pointer-session");
45
46
  const editor_guides_1 = require("../state/editor-guides");
46
47
  const editor_snapping_1 = require("../state/editor-snapping");
@@ -57,7 +58,7 @@ const imperative_state_1 = require("./Timeline/imperative-state");
57
58
  const save_sequence_prop_1 = require("./Timeline/save-sequence-prop");
58
59
  const should_clear_selection_on_pointer_down_1 = require("./Timeline/should-clear-selection-on-pointer-down");
59
60
  exports.SELECTED_OUTLINE_KEY_ATTR = 'data-remotion-studio-selected-outline-key';
60
- const SelectedOutlinePolygonUnmemoized = ({ compositionHeight, compositionWidth, containsSelection, directlySelected, dragging, getAllDragOutlines, getAllDragTargets, getLayoutTarget, getTarget, hasTarget, hovered, outline, onDraggingChange, onHoverChange, onSnapPointsChange, onSelect, onDoubleClickTarget, scale, showSelectedOutline, }) => {
61
+ const SelectedOutlinePolygonUnmemoized = ({ compositionHeight, compositionWidth, containsSelection, directlySelected, dragging, getAllDragOutlines, getAllDragTargets, getLayoutTarget, getTarget, hasTarget, hovered, outline, onDraggingChange, onHoverChange, onSnapPointsChange, onSelect, onDoubleClickTarget, scale, showSelectedOutline, translateWithCommandKey, }) => {
61
62
  const { previewServerState } = (0, react_1.useContext)(client_id_1.StudioServerConnectionCtx);
62
63
  const dragAwareDoubleClick = (0, react_1.useMemo)(() => (0, drag_aware_double_click_1.createDragAwareDoubleClickTracker)(), []);
63
64
  const { canvasContent } = (0, react_1.useContext)(remotion_1.Internals.CompositionManager);
@@ -95,7 +96,12 @@ const SelectedOutlinePolygonUnmemoized = ({ compositionHeight, compositionWidth,
95
96
  const { drag, selected } = target;
96
97
  event.preventDefault();
97
98
  event.stopPropagation();
98
- const interaction = (0, selected_outline_measurement_1.getOutlineSelectionInteraction)(event);
99
+ const temporaryTranslate = translateWithCommandKey &&
100
+ (selected || containsSelection) &&
101
+ (is_mac_1.isMac ? event.metaKey : event.ctrlKey);
102
+ const interaction = temporaryTranslate
103
+ ? { shiftKey: false, toggleKey: false }
104
+ : (0, selected_outline_measurement_1.getOutlineSelectionInteraction)(event);
99
105
  const shouldUpdateSelection = !selected || interaction.shiftKey || interaction.toggleKey;
100
106
  const ownerSvg = (_a = polygonRef.current) === null || _a === void 0 ? void 0 : _a.ownerSVGElement;
101
107
  let pointerInsideSelectedOutline = false;
@@ -159,7 +165,7 @@ const SelectedOutlinePolygonUnmemoized = ({ compositionHeight, compositionWidth,
159
165
  let currentPointerY = startPointerY;
160
166
  let axisLocked = false;
161
167
  let dragStarted = false;
162
- let snappingDisabled = event.metaKey || event.ctrlKey;
168
+ let snappingDisabled = !temporaryTranslate && (event.metaKey || event.ctrlKey);
163
169
  let snapTargets = null;
164
170
  const updateDragOverrides = () => {
165
171
  const screenDeltaX = currentPointerX - startPointerX;
@@ -241,7 +247,8 @@ const SelectedOutlinePolygonUnmemoized = ({ compositionHeight, compositionWidth,
241
247
  currentPointerX = moveEvent.clientX;
242
248
  currentPointerY = moveEvent.clientY;
243
249
  axisLocked = moveEvent.shiftKey;
244
- snappingDisabled = moveEvent.metaKey || moveEvent.ctrlKey;
250
+ snappingDisabled =
251
+ !temporaryTranslate && (moveEvent.metaKey || moveEvent.ctrlKey);
245
252
  updateDragOverrides();
246
253
  };
247
254
  const onKeyChange = (keyEvent) => {
@@ -336,6 +343,7 @@ const SelectedOutlinePolygonUnmemoized = ({ compositionHeight, compositionWidth,
336
343
  scale,
337
344
  setPropStatuses,
338
345
  setDragOverrides,
346
+ translateWithCommandKey,
339
347
  ]);
340
348
  const onDoubleClick = react_1.default.useCallback((event) => {
341
349
  const target = getTarget();
@@ -5,7 +5,7 @@ export declare const SelectedOutlineRenderer: React.NamedExoticComponent<{
5
5
  readonly compositionWidth: number;
6
6
  readonly dragging: boolean;
7
7
  readonly getLatestOutlineTargetByKey: (key: string) => SelectedOutlineTarget | undefined;
8
- readonly getOutlineTargets: () => readonly SelectedOutlineLayoutTarget[];
8
+ readonly outlineTargets: readonly SelectedOutlineLayoutTarget[];
9
9
  readonly onDraggingChange: (dragging: boolean) => void;
10
10
  readonly onContextMenuOpenChange: (open: boolean) => void;
11
11
  readonly onSelect: (item: import("@remotion/canvas").CanvasSelectionItem, interaction?: import("@remotion/canvas").CanvasSelectionInteraction | undefined) => void;
@@ -53,13 +53,12 @@ const outlineContainer = {
53
53
  pointerEvents: 'none',
54
54
  overflow: 'visible',
55
55
  };
56
- const emptyRenderState = {
57
- outlines: [],
58
- targets: [],
59
- };
60
- const SelectedOutlineRendererUnmemoized = ({ compositionHeight, compositionWidth, dragging, getLatestOutlineTargetByKey, getOutlineTargets, onDraggingChange, onContextMenuOpenChange, onSelect, scale, sequences, updateOutlinesRef, }) => {
56
+ const SelectedOutlineRendererUnmemoized = ({ compositionHeight, compositionWidth, dragging, getLatestOutlineTargetByKey, outlineTargets, onDraggingChange, onContextMenuOpenChange, onSelect, scale, sequences, updateOutlinesRef, }) => {
61
57
  var _a;
62
- const [renderState, setRenderState] = (0, react_1.useState)(emptyRenderState);
58
+ // Targets are derived props and can receive a new identity on every render.
59
+ // Keep only measured geometry in state to avoid layout-effect update loops.
60
+ const [outlines, setOutlines] = (0, react_1.useState)([]);
61
+ const outlinesRef = (0, react_1.useRef)(outlines);
63
62
  const overlayRef = (0, react_1.useRef)(null);
64
63
  const resizeObserverRef = (0, react_1.useRef)(null);
65
64
  const resizeObserverAnimationFrameRef = (0, react_1.useRef)(null);
@@ -92,22 +91,21 @@ const SelectedOutlineRendererUnmemoized = ({ compositionHeight, compositionWidth
92
91
  const hoveredNodePathKey = (_a = hoveredSequence === null || hoveredSequence === void 0 ? void 0 : hoveredSequence.nodePathKey) !== null && _a !== void 0 ? _a : null;
93
92
  const hoveredTimelineNodePathKey = (hoveredSequence === null || hoveredSequence === void 0 ? void 0 : hoveredSequence.source) === 'timeline' ? hoveredNodePathKey : null;
94
93
  const updateOutlines = (0, react_1.useCallback)(() => {
95
- const targets = getOutlineTargets();
96
- if (overlayRef.current === null || targets.length === 0) {
97
- setRenderState((prevState) => prevState.targets.length === 0 ? prevState : emptyRenderState);
94
+ if (overlayRef.current === null || outlineTargets.length === 0) {
95
+ if (outlinesRef.current.length === 0) {
96
+ return;
97
+ }
98
+ outlinesRef.current = [];
99
+ setOutlines(outlinesRef.current);
98
100
  return;
99
101
  }
100
- const nextOutlines = (0, selected_outline_measurement_1.measureOutlines)(overlayRef.current, targets, hoveredTimelineNodePathKey);
101
- setRenderState((prevState) => {
102
- const outlines = (0, selected_outline_measurement_1.outlinesAreEqual)(prevState.outlines, nextOutlines)
103
- ? prevState.outlines
104
- : nextOutlines;
105
- if (prevState.targets === targets && prevState.outlines === outlines) {
106
- return prevState;
107
- }
108
- return { outlines, targets };
109
- });
110
- }, [getOutlineTargets, hoveredTimelineNodePathKey]);
102
+ const nextOutlines = (0, selected_outline_measurement_1.measureOutlines)(overlayRef.current, outlineTargets, hoveredTimelineNodePathKey);
103
+ if ((0, selected_outline_measurement_1.outlinesAreEqual)(outlinesRef.current, nextOutlines)) {
104
+ return;
105
+ }
106
+ outlinesRef.current = nextOutlines;
107
+ setOutlines(nextOutlines);
108
+ }, [hoveredTimelineNodePathKey, outlineTargets]);
111
109
  (0, react_1.useLayoutEffect)(() => {
112
110
  updateOutlinesRef.current = updateOutlines;
113
111
  updateOutlines();
@@ -150,7 +148,7 @@ const SelectedOutlineRendererUnmemoized = ({ compositionHeight, compositionWidth
150
148
  if (overlayRef.current !== null) {
151
149
  nextObservedElements.add(overlayRef.current);
152
150
  }
153
- for (const target of renderState.targets) {
151
+ for (const target of outlineTargets) {
154
152
  if (target.ref.current !== null) {
155
153
  nextObservedElements.add(target.ref.current);
156
154
  }
@@ -166,31 +164,31 @@ const SelectedOutlineRendererUnmemoized = ({ compositionHeight, compositionWidth
166
164
  }
167
165
  }
168
166
  observedOutlineElementsRef.current = nextObservedElements;
169
- }, [renderState.targets]);
167
+ }, [outlineTargets]);
170
168
  const targetsByKey = (0, react_1.useMemo)(() => {
171
- return new Map(renderState.targets.map((target) => [target.key, target]));
172
- }, [renderState.targets]);
169
+ return new Map(outlineTargets.map((target) => [target.key, target]));
170
+ }, [outlineTargets]);
173
171
  (0, react_1.useEffect)(() => {
174
172
  if ((hoveredSequence === null || hoveredSequence === void 0 ? void 0 : hoveredSequence.source) === 'canvas' &&
175
- !renderState.targets.some((target) => target.key === hoveredSequence.key)) {
173
+ !outlineTargets.some((target) => target.key === hoveredSequence.key)) {
176
174
  setHoveredSequence((currentHover) => (currentHover === null || currentHover === void 0 ? void 0 : currentHover.source) === 'canvas' ? null : currentHover);
177
175
  }
178
- }, [hoveredSequence, renderState.targets, setHoveredSequence]);
176
+ }, [hoveredSequence, outlineTargets, setHoveredSequence]);
179
177
  // Reordering a captured SVG target can cancel the active pointer session.
180
178
  const outlineRenderingOrderRef = (0, react_1.useRef)([]);
181
179
  const outlinesForRendering = (0, react_1.useMemo)(() => {
182
180
  if (!dragging || outlineRenderingOrderRef.current.length === 0) {
183
181
  const orderedOutlines = (0, selected_outline_order_1.orderOutlinesForRendering)({
184
- outlines: renderState.outlines,
182
+ outlines,
185
183
  sequences,
186
184
  targetsByKey,
187
185
  });
188
186
  outlineRenderingOrderRef.current = orderedOutlines.map((outline) => outline.key);
189
187
  return orderedOutlines;
190
188
  }
191
- const currentOutlinesByKey = new Map(renderState.outlines.map((outline) => [outline.key, outline]));
189
+ const currentOutlinesByKey = new Map(outlines.map((outline) => [outline.key, outline]));
192
190
  const frozenKeys = new Set(outlineRenderingOrderRef.current);
193
- const newOutlines = renderState.outlines.filter((outline) => !frozenKeys.has(outline.key));
191
+ const newOutlines = outlines.filter((outline) => !frozenKeys.has(outline.key));
194
192
  outlineRenderingOrderRef.current = [
195
193
  ...outlineRenderingOrderRef.current,
196
194
  ...newOutlines.map((outline) => outline.key),
@@ -199,10 +197,10 @@ const SelectedOutlineRendererUnmemoized = ({ compositionHeight, compositionWidth
199
197
  const outline = currentOutlinesByKey.get(key);
200
198
  return outline === undefined ? [] : [outline];
201
199
  });
202
- }, [dragging, renderState.outlines, sequences, targetsByKey]);
200
+ }, [dragging, outlines, sequences, targetsByKey]);
203
201
  const outlinesByKey = (0, react_1.useMemo)(() => {
204
- return new Map(renderState.outlines.map((outline) => [outline.key, outline]));
205
- }, [renderState.outlines]);
202
+ return new Map(outlines.map((outline) => [outline.key, outline]));
203
+ }, [outlines]);
206
204
  const { outlinesForEditingHandles, outlinesForTransformOrigin, outlinesForUvHandles, } = (0, react_1.useMemo)(() => {
207
205
  const editingHandles = [];
208
206
  const transformOrigin = [];
@@ -228,12 +226,12 @@ const SelectedOutlineRendererUnmemoized = ({ compositionHeight, compositionWidth
228
226
  outlinesForUvHandles: uvHandles,
229
227
  };
230
228
  }, [hoveredNodePathKey, outlinesForRendering, targetsByKey]);
231
- const targetsRef = (0, react_1.useRef)(renderState.targets);
229
+ const targetsRef = (0, react_1.useRef)(outlineTargets);
232
230
  const outlinesByKeyRef = (0, react_1.useRef)(outlinesByKey);
233
231
  (0, react_1.useLayoutEffect)(() => {
234
- targetsRef.current = renderState.targets;
232
+ targetsRef.current = outlineTargets;
235
233
  outlinesByKeyRef.current = outlinesByKey;
236
- }, [outlinesByKey, renderState.targets]);
234
+ }, [outlineTargets, outlinesByKey]);
237
235
  const getAllDragTargets = (0, react_1.useCallback)(() => targetsRef.current.flatMap((target) => {
238
236
  var _a;
239
237
  var _b;
@@ -6,6 +6,7 @@ const react_1 = require("react");
6
6
  const browser_studio_operations_1 = require("../helpers/browser-studio-operations");
7
7
  const client_id_1 = require("../helpers/client-id");
8
8
  const call_api_1 = require("./call-api");
9
+ const UpdateStatusContext_1 = require("./UpdateStatusContext");
9
10
  const SettingsContext = (0, react_1.createContext)(null);
10
11
  const SettingsProvider = ({ children }) => {
11
12
  var _a;
@@ -110,7 +111,7 @@ const SettingsProvider = ({ children }) => {
110
111
  const value = (0, react_1.useMemo)(() => {
111
112
  return { ...settings, setPublicLicenseKey };
112
113
  }, [setPublicLicenseKey, settings]);
113
- return (jsx_runtime_1.jsx(SettingsContext.Provider, { value: value, children: children }));
114
+ return (jsx_runtime_1.jsx(SettingsContext.Provider, { value: value, children: jsx_runtime_1.jsx(UpdateStatusContext_1.UpdateStatusProvider, { children: children }) }));
114
115
  };
115
116
  exports.SettingsProvider = SettingsProvider;
116
117
  const useSettings = () => {
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- type SettingsTab = 'apps' | 'rendering' | 'studio' | 'packages' | 'shortcuts' | 'skills' | 'license';
2
+ type SettingsTab = 'apps' | 'rendering' | 'studio' | 'packages' | 'shortcuts' | 'skills' | 'license' | 'updates';
3
3
  export declare const SettingsModal: React.FC<{
4
4
  readonly initialTab: SettingsTab;
5
5
  readonly initialPublicLicenseKey: string | null;
@@ -4,7 +4,10 @@ exports.SettingsModal = void 0;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const react_1 = require("react");
6
6
  const browser_studio_operations_1 = require("../helpers/browser-studio-operations");
7
+ const can_show_updates_1 = require("../helpers/can-show-updates");
8
+ const client_id_1 = require("../helpers/client-id");
7
9
  const apps_1 = require("../icons/apps");
10
+ const cloud_download_1 = require("../icons/cloud-download");
8
11
  const keyboard_1 = require("../icons/keyboard");
9
12
  const license_1 = require("../icons/license");
10
13
  const package_1 = require("../icons/package");
@@ -26,6 +29,7 @@ const SettingsModalFooter_1 = require("./SettingsModalFooter");
26
29
  const SkillsSettings_1 = require("./SkillsSettings");
27
30
  const StudioSettings_1 = require("./StudioSettings");
28
31
  const vertical_1 = require("./Tabs/vertical");
32
+ const UpdatesSettings_1 = require("./UpdatesSettings");
29
33
  const hiddenPanel = {
30
34
  display: 'none',
31
35
  };
@@ -58,13 +62,20 @@ const keyboardIcon = {
58
62
  const SettingsModal = ({ initialPublicLicenseKey, initialTab }) => {
59
63
  const { setSelectedModal } = (0, react_1.useContext)(modals_1.SetSelectedModalContext);
60
64
  const { setPublicLicenseKey } = (0, SettingsContext_1.useSettings)();
65
+ const { previewServerState } = (0, react_1.useContext)(client_id_1.StudioServerConnectionCtx);
61
66
  const isBrowserStudio = (0, browser_studio_operations_1.getBrowserStudioOperations)() !== null;
67
+ const showUpdates = (0, can_show_updates_1.canShowUpdates)({
68
+ connectionStatus: previewServerState.type,
69
+ isBrowserStudio,
70
+ readOnlyStudio: window.remotion_isReadOnlyStudio,
71
+ });
62
72
  const packageManager = window.remotion_packageManager === 'unknown'
63
73
  ? null
64
74
  : window.remotion_packageManager;
65
75
  const showPackages = (0, browser_studio_operations_1.canInstallPackages)() && (isBrowserStudio || packageManager !== null);
66
- const [tab, setTab] = (0, react_1.useState)(initialTab);
67
- const [openedTabs, setOpenedTabs] = (0, react_1.useState)([initialTab]);
76
+ const safeInitialTab = initialTab === 'updates' && !showUpdates ? 'shortcuts' : initialTab;
77
+ const [tab, setTab] = (0, react_1.useState)(safeInitialTab);
78
+ const [openedTabs, setOpenedTabs] = (0, react_1.useState)([safeInitialTab]);
68
79
  const [packagesFooterContainer, setPackagesFooterContainer] = (0, react_1.useState)(null);
69
80
  const dismiss = (0, react_1.useCallback)(() => {
70
81
  setSelectedModal(null);
@@ -78,11 +89,16 @@ const SettingsModal = ({ initialPublicLicenseKey, initialTab }) => {
78
89
  return [...currentOpenedTabs, newTab];
79
90
  });
80
91
  }, []);
92
+ (0, react_1.useLayoutEffect)(() => {
93
+ if (!showUpdates && tab === 'updates') {
94
+ selectTab('shortcuts');
95
+ }
96
+ }, [selectTab, showUpdates, tab]);
81
97
  (0, react_1.useEffect)(() => {
82
98
  setPublicLicenseKey(initialPublicLicenseKey);
83
99
  }, [initialPublicLicenseKey, setPublicLicenseKey]);
84
100
  return (jsx_runtime_1.jsx(DismissableModal_1.DismissableModal, { panelStyle: render_modals_1.outerModalStyle, children: jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [
85
101
  jsx_runtime_1.jsx(ModalHeader_1.ModalHeader, { title: "Settings", onClose: dismiss }), jsx_runtime_1.jsxs("div", { style: render_modals_1.horizontalLayout, children: [
86
- jsx_runtime_1.jsxs("div", { style: settingsLeftSidebar, children: [isBrowserStudio ? null : (jsx_runtime_1.jsx(vertical_1.VerticalTab, { style: render_modals_1.horizontalTab, selected: tab === 'rendering', onClick: () => selectTab('rendering'), renderIcon: (color) => (jsx_runtime_1.jsx("div", { style: render_modals_1.iconContainer, children: jsx_runtime_1.jsx(video_1.FilmIcon, { color: color, style: render_modals_1.icon }) })), children: "Defaults" })), isBrowserStudio ? null : (jsx_runtime_1.jsx(vertical_1.VerticalTab, { style: render_modals_1.horizontalTab, selected: tab === 'studio', onClick: () => selectTab('studio'), renderIcon: (color) => (jsx_runtime_1.jsx("div", { style: render_modals_1.iconContainer, children: jsx_runtime_1.jsx(remotion_triangle_1.RemotionTriangleIcon, { color: color, style: render_modals_1.icon }) })), children: "Studio" })), jsx_runtime_1.jsx(vertical_1.VerticalTab, { style: render_modals_1.horizontalTab, selected: tab === 'shortcuts', onClick: () => selectTab('shortcuts'), renderIcon: (color) => (jsx_runtime_1.jsx("div", { style: render_modals_1.iconContainer, children: jsx_runtime_1.jsx(keyboard_1.KeyboardIcon, { color: color, style: keyboardIcon }) })), children: "Shortcuts" }), showPackages ? (jsx_runtime_1.jsx(vertical_1.VerticalTab, { style: render_modals_1.horizontalTab, selected: tab === 'packages', onClick: () => selectTab('packages'), renderIcon: (color) => (jsx_runtime_1.jsx("div", { style: render_modals_1.iconContainer, children: jsx_runtime_1.jsx(package_1.PackageIcon, { color: color, style: render_modals_1.icon }) })), children: "Packages" })) : null, isBrowserStudio ? null : (jsx_runtime_1.jsx(vertical_1.VerticalTab, { style: render_modals_1.horizontalTab, selected: tab === 'skills', onClick: () => selectTab('skills'), renderIcon: (color) => (jsx_runtime_1.jsx("div", { style: render_modals_1.iconContainer, children: jsx_runtime_1.jsx(skills_1.SkillsIcon, { color: color, style: skillsIcon }) })), children: "Skills" })), isBrowserStudio ? null : (jsx_runtime_1.jsx(vertical_1.VerticalTab, { style: render_modals_1.horizontalTab, selected: tab === 'apps', onClick: () => selectTab('apps'), renderIcon: (color) => (jsx_runtime_1.jsx("div", { style: render_modals_1.iconContainer, children: jsx_runtime_1.jsx(apps_1.AppsIcon, { color: color, style: appsIcon }) })), children: "Apps" })), isBrowserStudio ? null : (jsx_runtime_1.jsx(vertical_1.VerticalTab, { style: render_modals_1.horizontalTab, selected: tab === 'license', onClick: () => selectTab('license'), renderIcon: (color) => (jsx_runtime_1.jsx("div", { style: render_modals_1.iconContainer, children: jsx_runtime_1.jsx(license_1.LicenseIcon, { color: color, style: render_modals_1.icon }) })), children: "License" }))] }), openedTabs.includes('packages') ? (jsx_runtime_1.jsx("div", { style: tab === 'packages' ? render_modals_1.optionsPanel : hiddenPanel, children: jsx_runtime_1.jsx(InstallPackage_1.InstallPackageSettings, { footerContainer: packagesFooterContainer, packageManager: packageManager }) })) : null, openedTabs.includes('apps') ? (jsx_runtime_1.jsx("div", { style: tab === 'apps' ? settingsOptionsPanel : hiddenPanel, className: is_menu_item_1.VERTICAL_SCROLLBAR_CLASSNAME, children: jsx_runtime_1.jsx(ConfigureDefaultEditorModal_1.DefaultEditorSettings, {}) })) : null, openedTabs.includes('license') ? (jsx_runtime_1.jsx("div", { style: tab === 'license' ? settingsOptionsPanel : hiddenPanel, className: is_menu_item_1.VERTICAL_SCROLLBAR_CLASSNAME, children: jsx_runtime_1.jsx(ConfigureLicenseModal_1.LicenseSettings, {}) })) : null, openedTabs.includes('skills') ? (jsx_runtime_1.jsx("div", { style: tab === 'skills' ? settingsOptionsPanel : hiddenPanel, className: is_menu_item_1.VERTICAL_SCROLLBAR_CLASSNAME, children: jsx_runtime_1.jsx(SkillsSettings_1.SkillsSettings, {}) })) : null, openedTabs.includes('shortcuts') ? (jsx_runtime_1.jsx("div", { style: tab === 'shortcuts' ? settingsOptionsPanel : hiddenPanel, className: is_menu_item_1.VERTICAL_SCROLLBAR_CLASSNAME, children: jsx_runtime_1.jsx(KeyboardShortcutsSettings_1.KeyboardShortcutsSettings, {}) })) : null, openedTabs.includes('rendering') ? (jsx_runtime_1.jsx("div", { style: tab === 'rendering' ? settingsOptionsPanel : hiddenPanel, className: is_menu_item_1.VERTICAL_SCROLLBAR_CLASSNAME, children: jsx_runtime_1.jsx(RenderingSettings_1.RenderingSettings, {}) })) : null, openedTabs.includes('studio') ? (jsx_runtime_1.jsx("div", { style: tab === 'studio' ? settingsOptionsPanel : hiddenPanel, className: is_menu_item_1.VERTICAL_SCROLLBAR_CLASSNAME, children: jsx_runtime_1.jsx(StudioSettings_1.StudioSettings, {}) })) : null] }), tab === 'packages' ? (jsx_runtime_1.jsx("div", { ref: setPackagesFooterContainer })) : isBrowserStudio ? null : (jsx_runtime_1.jsx(SettingsModalFooter_1.SettingsModalFooter, { showLicenseFaq: tab === 'license' }))] }) }));
102
+ jsx_runtime_1.jsxs("div", { style: settingsLeftSidebar, children: [isBrowserStudio ? null : (jsx_runtime_1.jsx(vertical_1.VerticalTab, { style: render_modals_1.horizontalTab, selected: tab === 'rendering', onClick: () => selectTab('rendering'), renderIcon: (color) => (jsx_runtime_1.jsx("div", { style: render_modals_1.iconContainer, children: jsx_runtime_1.jsx(video_1.FilmIcon, { color: color, style: render_modals_1.icon }) })), children: "Defaults" })), isBrowserStudio ? null : (jsx_runtime_1.jsx(vertical_1.VerticalTab, { style: render_modals_1.horizontalTab, selected: tab === 'studio', onClick: () => selectTab('studio'), renderIcon: (color) => (jsx_runtime_1.jsx("div", { style: render_modals_1.iconContainer, children: jsx_runtime_1.jsx(remotion_triangle_1.RemotionTriangleIcon, { color: color, style: render_modals_1.icon }) })), children: "Studio" })), jsx_runtime_1.jsx(vertical_1.VerticalTab, { style: render_modals_1.horizontalTab, selected: tab === 'shortcuts', onClick: () => selectTab('shortcuts'), renderIcon: (color) => (jsx_runtime_1.jsx("div", { style: render_modals_1.iconContainer, children: jsx_runtime_1.jsx(keyboard_1.KeyboardIcon, { color: color, style: keyboardIcon }) })), children: "Shortcuts" }), showPackages ? (jsx_runtime_1.jsx(vertical_1.VerticalTab, { style: render_modals_1.horizontalTab, selected: tab === 'packages', onClick: () => selectTab('packages'), renderIcon: (color) => (jsx_runtime_1.jsx("div", { style: render_modals_1.iconContainer, children: jsx_runtime_1.jsx(package_1.PackageIcon, { color: color, style: render_modals_1.icon }) })), children: "Packages" })) : null, isBrowserStudio ? null : (jsx_runtime_1.jsx(vertical_1.VerticalTab, { style: render_modals_1.horizontalTab, selected: tab === 'skills', onClick: () => selectTab('skills'), renderIcon: (color) => (jsx_runtime_1.jsx("div", { style: render_modals_1.iconContainer, children: jsx_runtime_1.jsx(skills_1.SkillsIcon, { color: color, style: skillsIcon }) })), children: "Skills" })), isBrowserStudio ? null : (jsx_runtime_1.jsx(vertical_1.VerticalTab, { style: render_modals_1.horizontalTab, selected: tab === 'apps', onClick: () => selectTab('apps'), renderIcon: (color) => (jsx_runtime_1.jsx("div", { style: render_modals_1.iconContainer, children: jsx_runtime_1.jsx(apps_1.AppsIcon, { color: color, style: appsIcon }) })), children: "Apps" })), isBrowserStudio ? null : (jsx_runtime_1.jsx(vertical_1.VerticalTab, { style: render_modals_1.horizontalTab, selected: tab === 'license', onClick: () => selectTab('license'), renderIcon: (color) => (jsx_runtime_1.jsx("div", { style: render_modals_1.iconContainer, children: jsx_runtime_1.jsx(license_1.LicenseIcon, { color: color, style: render_modals_1.icon }) })), children: "License" })), showUpdates ? (jsx_runtime_1.jsx(vertical_1.VerticalTab, { style: render_modals_1.horizontalTab, selected: tab === 'updates', onClick: () => selectTab('updates'), renderIcon: (color) => (jsx_runtime_1.jsx("div", { style: render_modals_1.iconContainer, children: jsx_runtime_1.jsx(cloud_download_1.CloudDownloadIcon, { color: color, style: render_modals_1.icon }) })), children: "Updates" })) : null] }), openedTabs.includes('packages') ? (jsx_runtime_1.jsx("div", { style: tab === 'packages' ? render_modals_1.optionsPanel : hiddenPanel, children: jsx_runtime_1.jsx(InstallPackage_1.InstallPackageSettings, { footerContainer: packagesFooterContainer, packageManager: packageManager }) })) : null, openedTabs.includes('apps') ? (jsx_runtime_1.jsx("div", { style: tab === 'apps' ? settingsOptionsPanel : hiddenPanel, className: is_menu_item_1.VERTICAL_SCROLLBAR_CLASSNAME, children: jsx_runtime_1.jsx(ConfigureDefaultEditorModal_1.DefaultEditorSettings, {}) })) : null, openedTabs.includes('license') ? (jsx_runtime_1.jsx("div", { style: tab === 'license' ? settingsOptionsPanel : hiddenPanel, className: is_menu_item_1.VERTICAL_SCROLLBAR_CLASSNAME, children: jsx_runtime_1.jsx(ConfigureLicenseModal_1.LicenseSettings, {}) })) : null, openedTabs.includes('skills') ? (jsx_runtime_1.jsx("div", { style: tab === 'skills' ? settingsOptionsPanel : hiddenPanel, className: is_menu_item_1.VERTICAL_SCROLLBAR_CLASSNAME, children: jsx_runtime_1.jsx(SkillsSettings_1.SkillsSettings, {}) })) : null, openedTabs.includes('shortcuts') ? (jsx_runtime_1.jsx("div", { style: tab === 'shortcuts' ? settingsOptionsPanel : hiddenPanel, className: is_menu_item_1.VERTICAL_SCROLLBAR_CLASSNAME, children: jsx_runtime_1.jsx(KeyboardShortcutsSettings_1.KeyboardShortcutsSettings, {}) })) : null, openedTabs.includes('rendering') ? (jsx_runtime_1.jsx("div", { style: tab === 'rendering' ? settingsOptionsPanel : hiddenPanel, className: is_menu_item_1.VERTICAL_SCROLLBAR_CLASSNAME, children: jsx_runtime_1.jsx(RenderingSettings_1.RenderingSettings, {}) })) : null, openedTabs.includes('studio') ? (jsx_runtime_1.jsx("div", { style: tab === 'studio' ? settingsOptionsPanel : hiddenPanel, className: is_menu_item_1.VERTICAL_SCROLLBAR_CLASSNAME, children: jsx_runtime_1.jsx(StudioSettings_1.StudioSettings, {}) })) : null, showUpdates && openedTabs.includes('updates') ? (jsx_runtime_1.jsx("div", { style: tab === 'updates' ? settingsOptionsPanel : hiddenPanel, className: is_menu_item_1.VERTICAL_SCROLLBAR_CLASSNAME, children: jsx_runtime_1.jsx(UpdatesSettings_1.UpdatesSettings, {}) })) : null] }), tab === 'packages' ? (jsx_runtime_1.jsx("div", { ref: setPackagesFooterContainer })) : isBrowserStudio || tab === 'updates' ? null : (jsx_runtime_1.jsx(SettingsModalFooter_1.SettingsModalFooter, { showLicenseFaq: tab === 'license' }))] }) }));
87
103
  };
88
104
  exports.SettingsModal = SettingsModal;