@remotion/studio 4.0.516 → 4.0.518

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 (157) hide show
  1. package/dist/components/AssetSelector.js +63 -22
  2. package/dist/components/AssetSelectorItem.d.ts +2 -1
  3. package/dist/components/AssetSelectorItem.js +41 -10
  4. package/dist/components/Canvas.js +15 -12
  5. package/dist/components/CanvasCaptureDropHandler.d.ts +4 -0
  6. package/dist/components/CanvasCaptureDropHandler.js +42 -0
  7. package/dist/components/CanvasOrLoading.js +4 -3
  8. package/dist/components/CaptionInspector.js +1 -1
  9. package/dist/components/CaptionTextEditor.js +32 -8
  10. package/dist/components/CheckboardToggle.js +1 -1
  11. package/dist/components/Checkbox.d.ts +0 -1
  12. package/dist/components/Checkbox.js +2 -19
  13. package/dist/components/CompositionContextButton.js +2 -1
  14. package/dist/components/CompositionSelector.js +1 -1
  15. package/dist/components/ConfigureLicenseModal.js +79 -46
  16. package/dist/components/CurrentAsset.d.ts +1 -1
  17. package/dist/components/CurrentAsset.js +9 -4
  18. package/dist/components/Editor.js +2 -1
  19. package/dist/components/EditorContent.js +11 -5
  20. package/dist/components/EditorContexts.js +2 -1
  21. package/dist/components/EditorRuler/Ruler.d.ts +1 -0
  22. package/dist/components/EditorRuler/Ruler.js +9 -8
  23. package/dist/components/EditorRuler/index.d.ts +1 -0
  24. package/dist/components/EditorRuler/index.js +3 -4
  25. package/dist/components/EditorRuler/use-is-ruler-visible.d.ts +1 -1
  26. package/dist/components/EditorRuler/use-is-ruler-visible.js +8 -2
  27. package/dist/components/ElementInstallConfirmation.d.ts +5 -0
  28. package/dist/components/ElementInstallConfirmation.js +25 -1
  29. package/dist/components/ElementLibraryModal.d.ts +5 -0
  30. package/dist/components/ElementLibraryModal.js +40 -0
  31. package/dist/components/FilePreview.js +71 -0
  32. package/dist/components/InlineCaptionInspector.js +13 -2
  33. package/dist/components/InlineEditableTitle.js +2 -2
  34. package/dist/components/InspectorPanel/CompositionInspector.js +11 -38
  35. package/dist/components/InspectorPanel/CompositionInspectorHeader.js +2 -2
  36. package/dist/components/InspectorPanel/CompositionMetadata.js +11 -4
  37. package/dist/components/InspectorPanel/EasingInspector.js +2 -2
  38. package/dist/components/InspectorPanel/ElementLibraryButton.d.ts +2 -0
  39. package/dist/components/InspectorPanel/ElementLibraryButton.js +139 -0
  40. package/dist/components/InspectorPanel/KeyframeInspector.js +1 -1
  41. package/dist/components/InspectorPanel/SequenceInspectorHeader.js +12 -5
  42. package/dist/components/InspectorPanel/SequenceSelectionInspector.js +1 -3
  43. package/dist/components/InspectorPanel/common.d.ts +0 -1
  44. package/dist/components/InspectorPanel/common.js +3 -7
  45. package/dist/components/InspectorPanel/inspector-selection.d.ts +2 -2
  46. package/dist/components/InspectorPanel/styles.d.ts +0 -1
  47. package/dist/components/InspectorPanel/styles.js +3 -4
  48. package/dist/components/InspectorPanel/use-track-for-selection.d.ts +1 -2
  49. package/dist/components/InspectorSequenceSection.d.ts +1 -2
  50. package/dist/components/InspectorSourceLocation.js +1 -1
  51. package/dist/components/Menu/MenuItem.js +15 -6
  52. package/dist/components/MenuToolbar.js +7 -3
  53. package/dist/components/Modals.js +51 -1
  54. package/dist/components/PlaybackRateSelector.js +3 -6
  55. package/dist/components/Preview.js +83 -5
  56. package/dist/components/PreviewToolbar.js +10 -4
  57. package/dist/components/PreviewToolbarOverflowButton.d.ts +1 -0
  58. package/dist/components/PreviewToolbarOverflowButton.js +9 -2
  59. package/dist/components/QuickSwitcher/ExplorerQuickSwitcherTrigger.d.ts +2 -0
  60. package/dist/components/QuickSwitcher/ExplorerQuickSwitcherTrigger.js +28 -8
  61. package/dist/components/RadioButton.d.ts +6 -0
  62. package/dist/components/RadioButton.js +62 -0
  63. package/dist/components/RenderButton.js +2 -1
  64. package/dist/components/RulersAndGuidesToggle.d.ts +3 -1
  65. package/dist/components/RulersAndGuidesToggle.js +18 -7
  66. package/dist/components/SelectedOutlineKeyboardControls.d.ts +2 -2
  67. package/dist/components/SelectedOutlineOverlay.d.ts +1 -3
  68. package/dist/components/SelectedOutlineOverlay.js +21 -17
  69. package/dist/components/SelectedOutlinePolygon.d.ts +1 -2
  70. package/dist/components/SelectedOutlineRenderer.d.ts +2 -3
  71. package/dist/components/SelectedOutlineRenderer.js +9 -78
  72. package/dist/components/SelectedOutlineUvControls.d.ts +1 -1
  73. package/dist/components/SettingsModal.js +1 -1
  74. package/dist/components/SettingsModalFooter.d.ts +3 -1
  75. package/dist/components/SettingsModalFooter.js +19 -4
  76. package/dist/components/ShowPixelGridProvider.d.ts +4 -0
  77. package/dist/components/ShowPixelGridProvider.js +24 -0
  78. package/dist/components/SidebarCollapserControls.js +2 -2
  79. package/dist/components/SidebarRenderButton.js +2 -1
  80. package/dist/components/Timeline/Timeline.js +41 -0
  81. package/dist/components/Timeline/TimelineClipboardKeybindings.d.ts +6 -7
  82. package/dist/components/Timeline/TimelineDragHandler.js +11 -4
  83. package/dist/components/Timeline/TimelineKeyframeControls.d.ts +1 -2
  84. package/dist/components/Timeline/TimelinePlayCursorSyncer.js +4 -2
  85. package/dist/components/Timeline/TimelineSelection.d.ts +29 -66
  86. package/dist/components/Timeline/TimelineSelection.js +30 -170
  87. package/dist/components/Timeline/TimelineSequenceItem.d.ts +1 -0
  88. package/dist/components/Timeline/TimelineSequenceItem.js +8 -6
  89. package/dist/components/Timeline/TimelineSequenceRightEdgeDragHandle.d.ts +3 -4
  90. package/dist/components/Timeline/delete-selected-timeline-item.d.ts +3 -4
  91. package/dist/components/Timeline/duplicate-selected-timeline-item.d.ts +3 -4
  92. package/dist/components/Timeline/find-track-for-node-path-info.d.ts +1 -1
  93. package/dist/components/Timeline/keyframe-clipboard.d.ts +2 -3
  94. package/dist/components/Timeline/reset-selected-timeline-props.d.ts +2 -3
  95. package/dist/components/Timeline/sequence-prop-clipboard.d.ts +2 -3
  96. package/dist/components/Timeline/split-selected-timeline-item.d.ts +2 -3
  97. package/dist/components/Timeline/timeline-expanded-filter.d.ts +1 -2
  98. package/dist/components/Timeline/timeline-scroll-logic.d.ts +7 -5
  99. package/dist/components/Timeline/timeline-scroll-logic.js +12 -7
  100. package/dist/components/Timeline/update-selected-easing.d.ts +7 -7
  101. package/dist/components/Timeline/use-timeline-asset-drop.js +24 -1
  102. package/dist/components/Timeline/use-timeline-keyframe-drag.d.ts +6 -7
  103. package/dist/components/WebMcp.d.ts +2 -0
  104. package/dist/components/WebMcp.js +945 -0
  105. package/dist/components/canvas-capture-drop.d.ts +4 -0
  106. package/dist/components/canvas-capture-drop.js +22 -0
  107. package/dist/components/composition-menu-items.js +26 -0
  108. package/dist/components/selected-outline-geometry.d.ts +2 -21
  109. package/dist/components/selected-outline-geometry.js +5 -16
  110. package/dist/components/selected-outline-measurement.d.ts +8 -37
  111. package/dist/components/selected-outline-measurement.js +1 -231
  112. package/dist/components/selected-outline-types.d.ts +2 -15
  113. package/dist/components/selected-outline-uv.js +3 -106
  114. package/dist/esm/{chunk-w4244j4n.js → chunk-7prjt5n5.js} +32831 -26820
  115. package/dist/esm/internals.mjs +32831 -26820
  116. package/dist/esm/previewEntry.mjs +17304 -11293
  117. package/dist/esm/renderEntry.mjs +1 -1
  118. package/dist/helpers/calculate-timeline.d.ts +1 -7
  119. package/dist/helpers/calculate-timeline.js +2 -146
  120. package/dist/helpers/create-folder-tree.js +16 -1
  121. package/dist/helpers/editor-ruler.js +6 -5
  122. package/dist/helpers/format-file-location.d.ts +8 -0
  123. package/dist/helpers/format-file-location.js +14 -3
  124. package/dist/helpers/get-asset-metadata.d.ts +19 -0
  125. package/dist/helpers/get-asset-metadata.js +51 -6
  126. package/dist/helpers/get-connected-compositions.d.ts +1 -6
  127. package/dist/helpers/get-connected-compositions.js +2 -8
  128. package/dist/helpers/get-sequence-visible-range.d.ts +1 -5
  129. package/dist/helpers/get-sequence-visible-range.js +6 -51
  130. package/dist/helpers/get-timeline-max-zoom.d.ts +8 -0
  131. package/dist/helpers/get-timeline-max-zoom.js +17 -6
  132. package/dist/helpers/get-timeline-nestedness.d.ts +1 -2
  133. package/dist/helpers/get-timeline-nestedness.js +2 -12
  134. package/dist/helpers/get-timeline-sequence-sort-key.d.ts +2 -22
  135. package/dist/helpers/get-timeline-sequence-sort-key.js +2 -16
  136. package/dist/helpers/hoverable.d.ts +1 -0
  137. package/dist/helpers/hoverable.js +4 -1
  138. package/dist/helpers/is-current-selected-still.js +4 -2
  139. package/dist/helpers/sort-by-nonce-history.d.ts +1 -5
  140. package/dist/helpers/sort-by-nonce-history.js +3 -148
  141. package/dist/helpers/timeline-node-path-key.d.ts +1 -2
  142. package/dist/helpers/timeline-node-path-key.js +2 -2
  143. package/dist/helpers/use-menu-structure.js +20 -0
  144. package/dist/icons/enter.d.ts +4 -0
  145. package/dist/icons/enter.js +10 -0
  146. package/dist/state/editor-pixel-grid.d.ts +8 -0
  147. package/dist/state/editor-pixel-grid.js +18 -0
  148. package/dist/state/modals.d.ts +4 -0
  149. package/dist/state/playbackrate.d.ts +1 -0
  150. package/dist/state/playbackrate.js +4 -1
  151. package/package.json +14 -12
  152. package/dist/components/selected-outline-order.d.ts +0 -12
  153. package/dist/components/selected-outline-order.js +0 -251
  154. package/dist/helpers/get-box-quads-polyfill-internals.d.ts +0 -82
  155. package/dist/helpers/get-box-quads-polyfill-internals.js +0 -2403
  156. package/dist/helpers/get-box-quads-ponyfill.d.ts +0 -10
  157. package/dist/helpers/get-box-quads-ponyfill.js +0 -23
@@ -12,20 +12,29 @@ const colors_1 = require("../../helpers/colors");
12
12
  const hoverable_1 = require("../../helpers/hoverable");
13
13
  const pointer_session_1 = require("../../helpers/pointer-session");
14
14
  const z_index_1 = require("../../state/z-index");
15
+ const menu_toolbar_height_1 = require("../menu-toolbar-height");
15
16
  const MenuContent_1 = require("../NewComposition/MenuContent");
16
17
  const is_menu_item_1 = require("./is-menu-item");
17
18
  const portals_1 = require("./portals");
18
19
  const styles_1 = require("./styles");
20
+ const MENU_ITEM_HEIGHT = 24;
21
+ const MENU_ITEM_VERTICAL_MARGIN = (menu_toolbar_height_1.MENU_TOOLBAR_HEIGHT - MENU_ITEM_HEIGHT) / 2;
19
22
  const container = {
23
+ alignItems: 'center',
24
+ boxSizing: 'border-box',
25
+ display: 'inline-flex',
20
26
  fontSize: 13,
21
- paddingLeft: 10,
22
- paddingRight: 10,
27
+ height: MENU_ITEM_HEIGHT,
28
+ justifyContent: 'center',
29
+ paddingLeft: 8,
30
+ paddingRight: 8,
23
31
  cursor: 'default',
24
- paddingTop: 6,
25
- paddingBottom: 6,
32
+ paddingTop: 0,
33
+ paddingBottom: 0,
26
34
  userSelect: 'none',
27
35
  WebkitUserSelect: 'none',
28
36
  border: 'none',
37
+ borderRadius: 3,
29
38
  };
30
39
  const MenuItem = ({ label: itemName, selected, id, onItemSelected, onItemHovered, onItemQuit, onPreviousMenu, onNextMenu, menu, }) => {
31
40
  const ref = (0, react_1.useRef)(null);
@@ -58,7 +67,7 @@ const MenuItem = ({ label: itemName, selected, id, onItemSelected, onItemHovered
58
67
  return {
59
68
  ...styles_1.menuContainerTowardsBottom,
60
69
  left: size.left,
61
- top: size.top + size.height,
70
+ top: size.top + size.height + MENU_ITEM_VERTICAL_MARGIN,
62
71
  };
63
72
  }, [selected, size]);
64
73
  // Not for styling (which is done via CSS :hover), but for switching
@@ -105,7 +114,7 @@ const MenuItem = ({ label: itemName, selected, id, onItemSelected, onItemHovered
105
114
  var _a, _b;
106
115
  return {
107
116
  ...styles_1.outerPortal,
108
- top: ((_a = size === null || size === void 0 ? void 0 : size.top) !== null && _a !== void 0 ? _a : 0) + ((_b = size === null || size === void 0 ? void 0 : size.height) !== null && _b !== void 0 ? _b : 0),
117
+ top: ((_a = size === null || size === void 0 ? void 0 : size.top) !== null && _a !== void 0 ? _a : 0) + ((_b = size === null || size === void 0 ? void 0 : size.height) !== null && _b !== void 0 ? _b : 0) + MENU_ITEM_VERTICAL_MARGIN,
109
118
  };
110
119
  }, [size]);
111
120
  return (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [
@@ -36,6 +36,10 @@ const row = {
36
36
  const flex = {
37
37
  flex: 1,
38
38
  };
39
+ const menuItems = {
40
+ display: 'inline-flex',
41
+ height: 24,
42
+ };
39
43
  const MenuToolbar = ({ readOnlyStudio }) => {
40
44
  const [selected, setSelected] = (0, react_1.useState)(null);
41
45
  const { previewServerState } = (0, react_1.useContext)(client_id_1.StudioServerConnectionCtx);
@@ -126,9 +130,9 @@ const MenuToolbar = ({ readOnlyStudio }) => {
126
130
  ? 'Quick Switcher'
127
131
  : `Quick Switcher (${ShortcutHint_1.cmdOrCtrlCharacter}+K)`;
128
132
  return (jsx_runtime_1.jsxs(layout_1.Row, { align: "center", className: "css-reset", style: row, onPointerDown: onPointerDown, children: [
129
- jsx_runtime_1.jsxs("div", { style: fixedWidthLeft, children: [mobileLayout ? (jsx_runtime_1.jsx(InlineAction_1.InlineAction, { variant: null, onClick: openQuickSwitcher, renderAction: renderSearchIcon, title: searchTooltip })) : (jsx_runtime_1.jsx(SidebarCollapserControls_1.SidebarCollapserControl, { side: "left" })), structure.map((s) => {
130
- return (jsx_runtime_1.jsx(MenuItem_1.MenuItem, { selected: selected === s.id, onItemSelected: itemClicked, onItemHovered: itemHovered, id: s.id, label: s.label, onItemQuit: onItemQuit, menu: s, onPreviousMenu: onPreviousMenu, onNextMenu: onNextMenu, leaveLeftPadding: s.leaveLeftPadding }, s.id));
131
- }), readOnlyStudio || browserStudioOperations ? null : jsx_runtime_1.jsx(UpdateCheck_1.UpdateCheck, {})] }), mobileLayout ? null : jsx_runtime_1.jsx("div", { style: flex }), jsx_runtime_1.jsx(MenuBuildIndicator_1.MenuBuildIndicator, { mobileLayout: mobileLayout }), jsx_runtime_1.jsx("div", { style: flex }), jsx_runtime_1.jsxs("div", { style: fixedWidthRight, children: [canUndoAndRedo ? jsx_runtime_1.jsx(UndoRedoButtons_1.UndoRedoButtons, {}) : null, jsx_runtime_1.jsx(SidebarCollapserControls_1.SidebarCollapserControl, { side: "right" })
133
+ jsx_runtime_1.jsxs("div", { style: fixedWidthLeft, children: [mobileLayout ? (jsx_runtime_1.jsx(InlineAction_1.InlineAction, { variant: null, onClick: openQuickSwitcher, renderAction: renderSearchIcon, title: searchTooltip })) : (jsx_runtime_1.jsx(SidebarCollapserControls_1.SidebarCollapserControl, { side: "left" })), jsx_runtime_1.jsx("div", { style: menuItems, children: structure.map((s) => {
134
+ return (jsx_runtime_1.jsx(MenuItem_1.MenuItem, { selected: selected === s.id, onItemSelected: itemClicked, onItemHovered: itemHovered, id: s.id, label: s.label, onItemQuit: onItemQuit, menu: s, onPreviousMenu: onPreviousMenu, onNextMenu: onNextMenu, leaveLeftPadding: s.leaveLeftPadding }, s.id));
135
+ }) }), readOnlyStudio || browserStudioOperations ? null : jsx_runtime_1.jsx(UpdateCheck_1.UpdateCheck, {})] }), mobileLayout ? null : jsx_runtime_1.jsx("div", { style: flex }), jsx_runtime_1.jsx(MenuBuildIndicator_1.MenuBuildIndicator, { mobileLayout: mobileLayout }), jsx_runtime_1.jsx("div", { style: flex }), jsx_runtime_1.jsxs("div", { style: fixedWidthRight, children: [canUndoAndRedo ? jsx_runtime_1.jsx(UndoRedoButtons_1.UndoRedoButtons, {}) : null, jsx_runtime_1.jsx(SidebarCollapserControls_1.SidebarCollapserControl, { side: "right" })
132
136
  ] })
133
137
  ] }));
134
138
  };
@@ -11,8 +11,11 @@ const client_id_1 = require("../helpers/client-id");
11
11
  const studio_runtime_config_1 = require("../helpers/studio-runtime-config");
12
12
  const modals_1 = require("../state/modals");
13
13
  const AskAiModal_1 = require("./AskAiModal");
14
+ const call_api_1 = require("./call-api");
14
15
  const ConfirmationDialog_1 = require("./ConfirmationDialog");
15
16
  const EffectPickerModal_1 = require("./EffectPickerModal");
17
+ const ElementInstallConfirmation_1 = require("./ElementInstallConfirmation");
18
+ const ElementLibraryModal_1 = require("./ElementLibraryModal");
16
19
  const FixComputedValueModal_1 = require("./FixComputedValueModal");
17
20
  const DeleteComposition_1 = require("./NewComposition/DeleteComposition");
18
21
  const DeleteFolder_1 = require("./NewComposition/DeleteFolder");
@@ -22,6 +25,7 @@ const NewFolder_1 = require("./NewComposition/NewFolder");
22
25
  const RenameComposition_1 = require("./NewComposition/RenameComposition");
23
26
  const RenameFolder_1 = require("./NewComposition/RenameFolder");
24
27
  const RenameStaticFile_1 = require("./NewComposition/RenameStaticFile");
28
+ const NotificationCenter_1 = require("./Notifications/NotificationCenter");
25
29
  const OverrideInputProps_1 = require("./OverrideInputProps");
26
30
  const QuickSwitcher_1 = __importDefault(require("./QuickSwitcher/QuickSwitcher"));
27
31
  const RenderStatusModal_1 = require("./RenderModal/RenderStatusModal");
@@ -37,6 +41,7 @@ const Modals = ({ readOnlyStudio }) => {
37
41
  const { previewServerState, subscribeToEvent } = (0, react_1.useContext)(client_id_1.StudioServerConnectionCtx);
38
42
  const canRender = previewServerState.type === 'connected';
39
43
  const isBrowserStudio = (0, browser_studio_operations_1.getBrowserStudioOperations)() !== null;
44
+ const confirm = (0, ConfirmationDialog_1.useConfirmationDialog)();
40
45
  (0, react_1.useEffect)(() => {
41
46
  if (isBrowserStudio) {
42
47
  return;
@@ -52,12 +57,57 @@ const Modals = ({ readOnlyStudio }) => {
52
57
  });
53
58
  });
54
59
  }, [isBrowserStudio, setSelectedModal, subscribeToEvent]);
60
+ (0, react_1.useEffect)(() => {
61
+ if (isBrowserStudio) {
62
+ return;
63
+ }
64
+ return subscribeToEvent('element-library-add-request', (event) => {
65
+ if (event.type !== 'element-library-add-request') {
66
+ return;
67
+ }
68
+ (async () => {
69
+ const confirmed = await confirm({
70
+ title: 'Add Element catalog',
71
+ message: (jsx_runtime_1.jsx(ElementInstallConfirmation_1.ElementLibraryAddConfirmation, { displayName: event.displayName, origin: event.origin, url: event.url })),
72
+ confirmLabel: 'Add catalog',
73
+ cancelLabel: 'Cancel',
74
+ });
75
+ if (!confirmed) {
76
+ return;
77
+ }
78
+ if (previewServerState.type !== 'connected') {
79
+ (0, NotificationCenter_1.showNotification)('Could not add catalog: Studio disconnected', 4000);
80
+ return;
81
+ }
82
+ try {
83
+ const result = await (0, call_api_1.callApi)('/api/update-config', {
84
+ clientId: previewServerState.clientId,
85
+ updates: [
86
+ {
87
+ setter: 'addElementLibrary',
88
+ type: 'set',
89
+ value: event.displayName === null
90
+ ? { url: event.url }
91
+ : { url: event.url, displayName: event.displayName },
92
+ },
93
+ ],
94
+ });
95
+ if (!result.success) {
96
+ (0, NotificationCenter_1.showNotification)(`Could not add catalog: ${result.reason}`, 4000);
97
+ }
98
+ }
99
+ catch (error) {
100
+ (0, NotificationCenter_1.showNotification)(`Could not add catalog: ${error.message}`, 4000);
101
+ }
102
+ })();
103
+ });
104
+ }, [confirm, isBrowserStudio, previewServerState, subscribeToEvent]);
55
105
  return (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [modalContextType && modalContextType.type === 'new-comp' && (jsx_runtime_1.jsx(NewComposition_1.NewComposition, { folderName: modalContextType.folderName, parentName: modalContextType.parentName, stack: modalContextType.stack, canvasCapture: modalContextType.canvasCapture })), modalContextType && modalContextType.type === 'new-folder' && (jsx_runtime_1.jsx(NewFolder_1.NewFolder, { parentName: modalContextType.parentName, stack: modalContextType.stack })), modalContextType && modalContextType.type === 'duplicate-comp' && (jsx_runtime_1.jsx(DuplicateComposition_1.DuplicateComposition, { compositionType: modalContextType.compositionType, compositionId: modalContextType.compositionId })), modalContextType && modalContextType.type === 'delete-comp' && (jsx_runtime_1.jsx(DeleteComposition_1.DeleteComposition, { compositionId: modalContextType.compositionId })), modalContextType && modalContextType.type === 'rename-comp' && (jsx_runtime_1.jsx(RenameComposition_1.RenameComposition, { compositionId: modalContextType.compositionId })), modalContextType && modalContextType.type === 'delete-folder' && (jsx_runtime_1.jsx(DeleteFolder_1.DeleteFolder, { folderName: modalContextType.folderName, parentName: modalContextType.parentName, stack: modalContextType.stack })), modalContextType && modalContextType.type === 'rename-folder' && (jsx_runtime_1.jsx(RenameFolder_1.RenameFolder, { folderName: modalContextType.folderName, parentName: modalContextType.parentName, stack: modalContextType.stack })), modalContextType && modalContextType.type === 'rename-static-file' && (jsx_runtime_1.jsx(RenameStaticFile_1.RenameStaticFileModal, { relativePath: modalContextType.relativePath })), modalContextType && modalContextType.type === 'input-props-override' && (jsx_runtime_1.jsx(OverrideInputProps_1.OverrideInputPropsModal, {})), modalContextType &&
56
106
  modalContextType.type === 'settings' &&
57
107
  (!isBrowserStudio ||
58
108
  modalContextType.initialTab === 'packages' ||
59
109
  modalContextType.initialTab === 'shortcuts') ? (jsx_runtime_1.jsx(SettingsModal_1.SettingsModal, { initialTab: modalContextType.initialTab, initialPublicLicenseKey: modalContextType.initialPublicLicenseKey }, `${modalContextType.initialTab}-${modalContextType.initialPublicLicenseKey}`)) : null, modalContextType && modalContextType.type === 'web-render' && (jsx_runtime_1.jsx(WebRenderModal_1.WebRenderModalWithLoader, { ...modalContextType })), modalContextType &&
60
110
  modalContextType.type === 'server-render' &&
61
- (canRender || modalContextType.readOnlyStudio) ? (jsx_runtime_1.jsx(ServerRenderModal_1.RenderModalWithLoader, { readOnlyStudio: (_a = modalContextType.readOnlyStudio) !== null && _a !== void 0 ? _a : false, initialFrame: modalContextType.initialFrame, initialDarkMode: modalContextType.initialDarkMode, compositionId: modalContextType.compositionId, initialVideoImageFormat: modalContextType.initialVideoImageFormat, initialJpegQuality: modalContextType.initialJpegQuality, initialScale: modalContextType.initialScale, initialLogLevel: modalContextType.initialLogLevel, initialOffthreadVideoCacheSizeInBytes: modalContextType.initialOffthreadVideoCacheSizeInBytes, initialOffthreadVideoThreads: modalContextType.initialOffthreadVideoThreads, initialMediaCacheSizeInBytes: modalContextType.initialMediaCacheSizeInBytes, initialConcurrency: modalContextType.initialConcurrency, maxConcurrency: modalContextType.maxConcurrency, minConcurrency: modalContextType.minConcurrency, initialStillImageFormat: modalContextType.initialStillImageFormat, initialMuted: modalContextType.initialMuted, initialEnforceAudioTrack: modalContextType.initialEnforceAudioTrack, initialProResProfile: modalContextType.initialProResProfile, initialx264Preset: modalContextType.initialx264Preset, initialGopSize: modalContextType.initialGopSize, initialPixelFormat: modalContextType.initialPixelFormat, initialAudioBitrate: modalContextType.initialAudioBitrate, initialVideoBitrate: modalContextType.initialVideoBitrate, initialEveryNthFrame: modalContextType.initialEveryNthFrame, initialNumberOfGifLoops: modalContextType.initialNumberOfGifLoops, initialDelayRenderTimeout: modalContextType.initialDelayRenderTimeout, initialEnvVariables: modalContextType.initialEnvVariables, initialDisableWebSecurity: modalContextType.initialDisableWebSecurity, initialGl: modalContextType.initialOpenGlRenderer, initialHeadless: modalContextType.initialHeadless, initialIgnoreCertificateErrors: modalContextType.initialIgnoreCertificateErrors, initialEncodingBufferSize: modalContextType.initialEncodingBufferSize, initialEncodingMaxRate: modalContextType.initialEncodingMaxRate, initialUserAgent: modalContextType.initialUserAgent, initialColorSpace: modalContextType.initialColorSpace, initialMultiProcessOnLinux: modalContextType.initialMultiProcessOnLinux, initialRepro: modalContextType.initialRepro, initialBeep: modalContextType.initialBeep, initialForSeamlessAacConcatenation: modalContextType.initialForSeamlessAacConcatenation, defaultProps: modalContextType.defaultProps, inFrameMark: modalContextType.inFrameMark, outFrameMark: modalContextType.outFrameMark, defaultConfigurationAudioCodec: modalContextType.defaultConfigurationAudioCodec, defaultConfigurationVideoCodec: modalContextType.defaultConfigurationVideoCodec, renderTypeOfLastRender: modalContextType.renderTypeOfLastRender, defaultMetadata: modalContextType.defaulMetadata, initialHardwareAcceleration: modalContextType.initialHardwareAcceleration, initialSampleRate: modalContextType.initialSampleRate, initialChromeMode: modalContextType.initialChromeMode, renderDefaults: modalContextType.renderDefaults })) : null, modalContextType && modalContextType.type === 'render-progress' && (jsx_runtime_1.jsx(RenderStatusModal_1.RenderStatusModal, { jobId: modalContextType.jobId })), modalContextType && modalContextType.type === 'update' && (jsx_runtime_1.jsx(UpdateModal_1.UpdateModal, { info: modalContextType.info, knownBugs: modalContextType.knownBugs })), modalContextType && modalContextType.type === 'fix-computed-value' && (jsx_runtime_1.jsx(FixComputedValueModal_1.FixComputedValueModal, { state: modalContextType })), modalContextType && modalContextType.type === 'quick-switcher' && (jsx_runtime_1.jsx(QuickSwitcher_1.default, { readOnlyStudio: readOnlyStudio, invocationTimestamp: modalContextType.invocationTimestamp, initialMode: modalContextType.mode, assetSelection: modalContextType.assetSelection, compositionSelection: modalContextType.compositionSelection })), modalContextType && modalContextType.type === 'add-effect' && (jsx_runtime_1.jsx(EffectPickerModal_1.EffectPickerModal, { state: modalContextType })), modalContextType && modalContextType.type === 'confirmation-dialog' && (jsx_runtime_1.jsx(ConfirmationDialog_1.ConfirmationDialog, { state: modalContextType })), modalContextType && modalContextType.type === 'svg-import-dialog' && (jsx_runtime_1.jsx(SvgImportDialog_1.SvgImportDialog, { state: modalContextType })), (0, studio_runtime_config_1.getStudioAskAIEnabled)() && jsx_runtime_1.jsx(AskAiModal_1.AskAiModal, {})] }));
111
+ (canRender || modalContextType.readOnlyStudio) ? (jsx_runtime_1.jsx(ServerRenderModal_1.RenderModalWithLoader, { readOnlyStudio: (_a = modalContextType.readOnlyStudio) !== null && _a !== void 0 ? _a : false, initialFrame: modalContextType.initialFrame, initialDarkMode: modalContextType.initialDarkMode, compositionId: modalContextType.compositionId, initialVideoImageFormat: modalContextType.initialVideoImageFormat, initialJpegQuality: modalContextType.initialJpegQuality, initialScale: modalContextType.initialScale, initialLogLevel: modalContextType.initialLogLevel, initialOffthreadVideoCacheSizeInBytes: modalContextType.initialOffthreadVideoCacheSizeInBytes, initialOffthreadVideoThreads: modalContextType.initialOffthreadVideoThreads, initialMediaCacheSizeInBytes: modalContextType.initialMediaCacheSizeInBytes, initialConcurrency: modalContextType.initialConcurrency, maxConcurrency: modalContextType.maxConcurrency, minConcurrency: modalContextType.minConcurrency, initialStillImageFormat: modalContextType.initialStillImageFormat, initialMuted: modalContextType.initialMuted, initialEnforceAudioTrack: modalContextType.initialEnforceAudioTrack, initialProResProfile: modalContextType.initialProResProfile, initialx264Preset: modalContextType.initialx264Preset, initialGopSize: modalContextType.initialGopSize, initialPixelFormat: modalContextType.initialPixelFormat, initialAudioBitrate: modalContextType.initialAudioBitrate, initialVideoBitrate: modalContextType.initialVideoBitrate, initialEveryNthFrame: modalContextType.initialEveryNthFrame, initialNumberOfGifLoops: modalContextType.initialNumberOfGifLoops, initialDelayRenderTimeout: modalContextType.initialDelayRenderTimeout, initialEnvVariables: modalContextType.initialEnvVariables, initialDisableWebSecurity: modalContextType.initialDisableWebSecurity, initialGl: modalContextType.initialOpenGlRenderer, initialHeadless: modalContextType.initialHeadless, initialIgnoreCertificateErrors: modalContextType.initialIgnoreCertificateErrors, initialEncodingBufferSize: modalContextType.initialEncodingBufferSize, initialEncodingMaxRate: modalContextType.initialEncodingMaxRate, initialUserAgent: modalContextType.initialUserAgent, initialColorSpace: modalContextType.initialColorSpace, initialMultiProcessOnLinux: modalContextType.initialMultiProcessOnLinux, initialRepro: modalContextType.initialRepro, initialBeep: modalContextType.initialBeep, initialForSeamlessAacConcatenation: modalContextType.initialForSeamlessAacConcatenation, defaultProps: modalContextType.defaultProps, inFrameMark: modalContextType.inFrameMark, outFrameMark: modalContextType.outFrameMark, defaultConfigurationAudioCodec: modalContextType.defaultConfigurationAudioCodec, defaultConfigurationVideoCodec: modalContextType.defaultConfigurationVideoCodec, renderTypeOfLastRender: modalContextType.renderTypeOfLastRender, defaultMetadata: modalContextType.defaulMetadata, initialHardwareAcceleration: modalContextType.initialHardwareAcceleration, initialSampleRate: modalContextType.initialSampleRate, initialChromeMode: modalContextType.initialChromeMode, renderDefaults: modalContextType.renderDefaults })) : null, modalContextType && modalContextType.type === 'render-progress' && (jsx_runtime_1.jsx(RenderStatusModal_1.RenderStatusModal, { jobId: modalContextType.jobId })), modalContextType && modalContextType.type === 'update' && (jsx_runtime_1.jsx(UpdateModal_1.UpdateModal, { info: modalContextType.info, knownBugs: modalContextType.knownBugs })), modalContextType && modalContextType.type === 'fix-computed-value' && (jsx_runtime_1.jsx(FixComputedValueModal_1.FixComputedValueModal, { state: modalContextType })), modalContextType && modalContextType.type === 'quick-switcher' && (jsx_runtime_1.jsx(QuickSwitcher_1.default, { readOnlyStudio: readOnlyStudio, invocationTimestamp: modalContextType.invocationTimestamp, initialMode: modalContextType.mode, assetSelection: modalContextType.assetSelection, compositionSelection: modalContextType.compositionSelection })), modalContextType && modalContextType.type === 'element-library' && (jsx_runtime_1.jsx(ElementLibraryModal_1.ElementLibraryModal, { name: modalContextType.name, url: modalContextType.url })), modalContextType && modalContextType.type === 'add-effect' && (jsx_runtime_1.jsx(EffectPickerModal_1.EffectPickerModal, { state: modalContextType })), modalContextType && modalContextType.type === 'confirmation-dialog' && (jsx_runtime_1.jsx(ConfirmationDialog_1.ConfirmationDialog, { state: modalContextType })), modalContextType && modalContextType.type === 'svg-import-dialog' && (jsx_runtime_1.jsx(SvgImportDialog_1.SvgImportDialog, { state: modalContextType })), (0, studio_runtime_config_1.getStudioAskAIEnabled)() && jsx_runtime_1.jsx(AskAiModal_1.AskAiModal, {})] }));
62
112
  };
63
113
  exports.Modals = Modals;
@@ -10,9 +10,6 @@ const Checkmark_1 = require("../icons/Checkmark");
10
10
  const playback_rate_1 = require("../icons/playback-rate");
11
11
  const playbackrate_1 = require("../state/playbackrate");
12
12
  const TimelineCombobox_1 = require("./TimelineCombobox");
13
- const commonPlaybackRates = [
14
- -4, -2, -1, -0.5, -0.25, 0.25, 0.5, 1, 1.5, 2, 4,
15
- ];
16
13
  const getPlaybackRateLabel = (playbackRate) => {
17
14
  return `${playbackRate}x`;
18
15
  };
@@ -23,7 +20,7 @@ const usePlaybackRateMenuItems = ({ playbackRate, setPlaybackRate, }) => {
23
20
  type: 'divider',
24
21
  id: 'divider',
25
22
  };
26
- const values = commonPlaybackRates.map((newPlaybackRate) => {
23
+ const values = playbackrate_1.commonPlaybackRates.map((newPlaybackRate) => {
27
24
  return {
28
25
  id: String(newPlaybackRate),
29
26
  label: getPlaybackRateLabel(newPlaybackRate),
@@ -41,7 +38,7 @@ const usePlaybackRateMenuItems = ({ playbackRate, setPlaybackRate, }) => {
41
38
  quickSwitcherLabel: null,
42
39
  };
43
40
  });
44
- const middle = Math.floor(commonPlaybackRates.length / 2);
41
+ const middle = Math.floor(playbackrate_1.commonPlaybackRates.length / 2);
45
42
  return [...values.slice(0, middle), divider, ...values.slice(middle)];
46
43
  }, [playbackRate, setPlaybackRate]);
47
44
  return {
@@ -57,7 +54,7 @@ const PlaybackRateSelector = ({ playbackRate, setPlaybackRate, }) => {
57
54
  playbackRate,
58
55
  setPlaybackRate,
59
56
  });
60
- if (isStill || canvasContent === null || canvasContent.type === 'asset') {
57
+ if (isStill || canvasContent === null) {
61
58
  return null;
62
59
  }
63
60
  return (jsx_runtime_1.jsx(TimelineCombobox_1.TimelineCombobox, { title: accessibilityLabel, labelWidth: 30, selectedId: selectedId, values: items, renderLeftItem: (color) => (jsx_runtime_1.jsx(playback_rate_1.PlaybackRateIcon, { color: color, playbackRate: playbackRate })), unhoveredIconColor: colors_1.WHITE_ALPHA_80 }));
@@ -2,15 +2,20 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.VideoPreview = void 0;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const media_1 = require("@remotion/media");
5
6
  const player_1 = require("@remotion/player");
6
7
  const react_1 = require("react");
8
+ const react_dom_1 = require("react-dom");
7
9
  const remotion_1 = require("remotion");
8
10
  const ErrorLoader_1 = require("../error-overlay/remotion-overlay/ErrorLoader");
11
+ const add_asset_cache_bust_1 = require("../helpers/add-asset-cache-bust");
9
12
  const checkerboard_background_1 = require("../helpers/checkerboard-background");
10
13
  const colors_1 = require("../helpers/colors");
11
14
  const get_preview_file_type_1 = require("../helpers/get-preview-file-type");
12
15
  const studio_fit_padding_1 = require("../helpers/studio-fit-padding");
16
+ const audio_1 = require("../icons/audio");
13
17
  const checkerboard_1 = require("../state/checkerboard");
18
+ const editor_pixel_grid_1 = require("../state/editor-pixel-grid");
14
19
  const is_menu_item_1 = require("./Menu/is-menu-item");
15
20
  const RenderPreview_1 = require("./RenderPreview");
16
21
  const SelectedOutlineOverlay_1 = require("./SelectedOutlineOverlay");
@@ -38,9 +43,13 @@ const assetMetadataErrorContainer = {
38
43
  overflowY: 'auto',
39
44
  };
40
45
  const checkerboardSize = 49;
46
+ const PIXEL_GRID_MIN_SCALE = 4;
41
47
  const containerStyle = (options) => {
42
48
  return {
43
49
  transform: `scale(${options.scale})`,
50
+ // Avoid the background bleeding through opaque compositions at fractional
51
+ // scales due to Chromium compositing the child and background together.
52
+ willChange: 'transform',
44
53
  marginLeft: options.xCorrection,
45
54
  marginTop: options.yCorrection,
46
55
  width: options.width,
@@ -54,6 +63,20 @@ const containerStyle = (options) => {
54
63
  backgroundPosition: (0, checkerboard_background_1.getCheckerboardBackgroundPos)(checkerboardSize) /* Must be half of one side of the square */,
55
64
  };
56
65
  };
66
+ const PixelGrid = ({ scale }) => {
67
+ const { editorShowPixelGrid } = (0, react_1.useContext)(editor_pixel_grid_1.EditorShowPixelGridContext);
68
+ if (!editorShowPixelGrid || scale < PIXEL_GRID_MIN_SCALE) {
69
+ return null;
70
+ }
71
+ return (jsx_runtime_1.jsx("div", { "aria-hidden": "true", className: "css-reset", "data-testid": "pixel-grid", style: {
72
+ position: 'absolute',
73
+ inset: 0,
74
+ pointerEvents: 'none',
75
+ opacity: 0.35,
76
+ backgroundImage: `linear-gradient(to right, ${colors_1.RULER_COLOR} 1px, transparent 1px), linear-gradient(to bottom, ${colors_1.RULER_COLOR} 1px, transparent 1px)`,
77
+ backgroundSize: `${scale}px ${scale}px`,
78
+ } }));
79
+ };
57
80
  const VideoPreview = ({ canvasSize, contentDimensions, canvasContent, assetMetadata, onRetryAssetMetadata, }) => {
58
81
  if (assetMetadata && assetMetadata.type === 'not-found') {
59
82
  return (jsx_runtime_1.jsx("div", { style: centeredContainer, children: jsx_runtime_1.jsx("div", { style: label, children: "File does not exist" }) }));
@@ -61,7 +84,8 @@ const VideoPreview = ({ canvasSize, contentDimensions, canvasContent, assetMetad
61
84
  if (assetMetadata && assetMetadata.type === 'metadata-error') {
62
85
  return (jsx_runtime_1.jsx("div", { style: assetMetadataErrorContainer, className: is_menu_item_1.VERTICAL_SCROLLBAR_CLASSNAME, children: jsx_runtime_1.jsx(ErrorLoader_1.ErrorLoader, { canHaveDismissButton: false, keyboardShortcuts: false, error: assetMetadata.error, onRetry: onRetryAssetMetadata !== null && onRetryAssetMetadata !== void 0 ? onRetryAssetMetadata : null, calculateMetadata: false }, assetMetadata.error.stack) }));
63
86
  }
64
- if (contentDimensions === null) {
87
+ if (contentDimensions === null ||
88
+ (canvasContent.type !== 'composition' && assetMetadata === null)) {
65
89
  return (jsx_runtime_1.jsx("div", { style: centeredContainer, children: jsx_runtime_1.jsx(Spinner_1.Spinner, { duration: 0.5, size: 24 }) }));
66
90
  }
67
91
  return (jsx_runtime_1.jsx(CompWhenItHasDimensions, { contentDimensions: contentDimensions, canvasSize: canvasSize, canvasContent: canvasContent, assetMetadata: assetMetadata }));
@@ -69,6 +93,7 @@ const VideoPreview = ({ canvasSize, contentDimensions, canvasContent, assetMetad
69
93
  exports.VideoPreview = VideoPreview;
70
94
  const CompWhenItHasDimensions = ({ contentDimensions, canvasSize, canvasContent, assetMetadata }) => {
71
95
  const { size: previewSize } = (0, react_1.useContext)(remotion_1.Internals.PreviewSizeContext);
96
+ const { currentAssetMetadata } = (0, react_1.useContext)(remotion_1.Internals.CompositionManager);
72
97
  const [canvasHovered, setCanvasHovered] = (0, react_1.useState)(false);
73
98
  const compositionContainerRef = (0, react_1.useRef)(null);
74
99
  (0, react_1.useEffect)(() => {
@@ -111,6 +136,17 @@ const CompWhenItHasDimensions = ({ contentDimensions, canvasSize, canvasContent,
111
136
  previewSize: previewSize.size,
112
137
  });
113
138
  }, [canvasContent.type, canvasSize, contentDimensions, previewSize.size]);
139
+ const assetFileType = canvasContent.type === 'asset'
140
+ ? (0, get_preview_file_type_1.getPreviewFileType)(canvasContent.asset)
141
+ : null;
142
+ const mediaCompositionFileType = (assetFileType === 'audio' || assetFileType === 'video') &&
143
+ (assetMetadata === null || assetMetadata === void 0 ? void 0 : assetMetadata.type) === 'found' &&
144
+ assetMetadata.mediaMetadata !== null &&
145
+ canvasContent.type === 'asset' &&
146
+ (currentAssetMetadata === null || currentAssetMetadata === void 0 ? void 0 : currentAssetMetadata.asset) === canvasContent.asset &&
147
+ contentDimensions !== 'none'
148
+ ? assetFileType
149
+ : null;
114
150
  const outer = (0, react_1.useMemo)(() => {
115
151
  return {
116
152
  width: contentDimensions === 'none' ? '100%' : contentDimensions.width * scale,
@@ -123,9 +159,12 @@ const CompWhenItHasDimensions = ({ contentDimensions, canvasSize, canvasContent,
123
159
  left: centerX - previewSize.translation.x,
124
160
  top: centerY - previewSize.translation.y,
125
161
  overflow: canvasContent.type === 'composition' ? 'visible' : 'hidden',
126
- justifyContent: canvasContent.type === 'asset' ? 'center' : 'flex-start',
162
+ justifyContent: canvasContent.type === 'asset' && mediaCompositionFileType === null
163
+ ? 'center'
164
+ : 'flex-start',
127
165
  alignItems: canvasContent.type === 'asset' &&
128
- (0, get_preview_file_type_1.getPreviewFileType)(canvasContent.asset) === 'audio'
166
+ mediaCompositionFileType === null &&
167
+ assetFileType === 'audio'
129
168
  ? 'center'
130
169
  : 'normal',
131
170
  };
@@ -137,8 +176,25 @@ const CompWhenItHasDimensions = ({ contentDimensions, canvasSize, canvasContent,
137
176
  previewSize.translation.y,
138
177
  centerY,
139
178
  canvasContent,
179
+ mediaCompositionFileType,
180
+ assetFileType,
140
181
  ]);
141
182
  if (canvasContent.type === 'asset') {
183
+ if (mediaCompositionFileType !== null &&
184
+ (assetMetadata === null || assetMetadata === void 0 ? void 0 : assetMetadata.type) === 'found' &&
185
+ contentDimensions !== 'none') {
186
+ return (jsx_runtime_1.jsxs("div", { ref: compositionContainerRef, className: "remotion-studio-composition-container", style: outer, children: [mediaCompositionFileType === 'audio' ? (jsx_runtime_1.jsx(audio_1.AudioFileIcon, { "aria-label": "Audio asset", color: colors_1.LIGHT_TEXT, role: "img", style: {
187
+ height: 64,
188
+ left: '50%',
189
+ opacity: 0.25,
190
+ pointerEvents: 'none',
191
+ position: 'absolute',
192
+ top: '50%',
193
+ transform: 'translate(-50%, -50%)',
194
+ width: 64,
195
+ } })) : null, jsx_runtime_1.jsx(PortalContainer, { contentDimensions: contentDimensions, offscreen: mediaCompositionFileType === 'audio', scale: scale, xCorrection: xCorrection, yCorrection: yCorrection }), jsx_runtime_1.jsx(AssetMediaComposition, { asset: canvasContent.asset, fetchedAt: assetMetadata.fetchedAt, fileType: mediaCompositionFileType })
196
+ ] }));
197
+ }
142
198
  return (jsx_runtime_1.jsx("div", { style: outer, children: jsx_runtime_1.jsx(StaticFilePreview_1.StaticFilePreview, { assetMetadata: assetMetadata, currentAsset: canvasContent.asset }) }));
143
199
  }
144
200
  if (canvasContent.type === 'output') {
@@ -148,14 +204,35 @@ const CompWhenItHasDimensions = ({ contentDimensions, canvasSize, canvasContent,
148
204
  return (jsx_runtime_1.jsx("div", { style: outer, children: jsx_runtime_1.jsx(RenderPreview_1.RenderPreview, { path: canvasContent.displayName, assetMetadata: assetMetadata, getBlob: canvasContent.getBlob }) }));
149
205
  }
150
206
  return (jsx_runtime_1.jsxs("div", { ref: compositionContainerRef, className: "remotion-studio-composition-container", style: outer, children: [
151
- jsx_runtime_1.jsx(PortalContainer, { contentDimensions: contentDimensions, scale: scale, xCorrection: xCorrection, yCorrection: yCorrection }), jsx_runtime_1.jsx(SelectedOutlineOverlay_1.SelectedOutlineOverlay, { canvasHovered: canvasHovered, compositionHeight: contentDimensions.height, compositionWidth: contentDimensions.width, scale: scale, translationX: previewSize.translation.x, translationY: previewSize.translation.y })
207
+ jsx_runtime_1.jsx(PortalContainer, { contentDimensions: contentDimensions, offscreen: false, scale: scale, xCorrection: xCorrection, yCorrection: yCorrection }), jsx_runtime_1.jsx(PixelGrid, { scale: scale }), jsx_runtime_1.jsx(SelectedOutlineOverlay_1.SelectedOutlineOverlay, { canvasHovered: canvasHovered, compositionHeight: contentDimensions.height, compositionWidth: contentDimensions.width, scale: scale, translationX: previewSize.translation.x, translationY: previewSize.translation.y })
152
208
  ] }));
153
209
  };
154
- const PortalContainer = ({ scale, xCorrection, yCorrection, contentDimensions }) => {
210
+ const AssetMediaComposition = ({ asset, fetchedAt, fileType }) => {
211
+ const src = (0, add_asset_cache_bust_1.addAssetCacheBust)({
212
+ fetchedAt,
213
+ src: (0, remotion_1.staticFile)(asset),
214
+ });
215
+ const style = {
216
+ width: '100%',
217
+ height: '100%',
218
+ };
219
+ return (0, react_dom_1.createPortal)(jsx_runtime_1.jsx(remotion_1.Internals.CanUseRemotionHooksProvider, { children: jsx_runtime_1.jsx(remotion_1.Internals.DisableInteractivityProvider, { children: jsx_runtime_1.jsx("div", { "data-testid": "asset-media-preview", style: style, children: fileType === 'video' ? (jsx_runtime_1.jsx(media_1.Video, { name: asset, src: src, style: style })) : (jsx_runtime_1.jsx(media_1.Audio, { name: asset, src: src })) }) }) }), remotion_1.Internals.portalNode());
220
+ };
221
+ const PortalContainer = ({ offscreen, scale, xCorrection, yCorrection, contentDimensions }) => {
155
222
  const { checkerboard } = (0, react_1.useContext)(checkerboard_1.CheckerboardContext);
156
223
  const { clearSelection } = (0, TimelineSelection_1.useTimelineSelection)();
157
224
  const portalContainer = (0, react_1.useRef)(null);
158
225
  const style = (0, react_1.useMemo)(() => {
226
+ if (offscreen) {
227
+ return {
228
+ height: contentDimensions.height,
229
+ left: -999999,
230
+ overflow: 'hidden',
231
+ position: 'fixed',
232
+ top: 0,
233
+ width: contentDimensions.width,
234
+ };
235
+ }
159
236
  return containerStyle({
160
237
  checkerboard,
161
238
  scale,
@@ -168,6 +245,7 @@ const PortalContainer = ({ scale, xCorrection, yCorrection, contentDimensions })
168
245
  checkerboard,
169
246
  contentDimensions.height,
170
247
  contentDimensions.width,
248
+ offscreen,
171
249
  scale,
172
250
  xCorrection,
173
251
  yCorrection,
@@ -6,6 +6,7 @@ const react_1 = require("react");
6
6
  const remotion_1 = require("remotion");
7
7
  const check_fullscreen_support_1 = require("../helpers/check-fullscreen-support");
8
8
  const colors_1 = require("../helpers/colors");
9
+ const get_preview_file_type_1 = require("../helpers/get-preview-file-type");
9
10
  const is_current_selected_still_1 = require("../helpers/is-current-selected-still");
10
11
  const mobile_layout_1 = require("../helpers/mobile-layout");
11
12
  const timeline_layout_1 = require("../helpers/timeline-layout");
@@ -74,6 +75,10 @@ const PreviewToolbar = ({ readOnlyStudio, bufferStateDelayInMilliseconds }) => {
74
75
  const { setPlayerMuted } = (0, react_1.useContext)(remotion_1.Internals.SetMediaVolumeContext);
75
76
  const { canvasContent } = (0, react_1.useContext)(remotion_1.Internals.CompositionManager);
76
77
  const isVideoComposition = (0, is_current_selected_still_1.useIsVideoComposition)();
78
+ const showCompositionControls = (canvasContent === null || canvasContent === void 0 ? void 0 : canvasContent.type) === 'composition';
79
+ const showCanvasViewControls = showCompositionControls ||
80
+ ((canvasContent === null || canvasContent === void 0 ? void 0 : canvasContent.type) === 'asset' &&
81
+ (0, get_preview_file_type_1.getPreviewFileType)(canvasContent.asset) === 'video');
77
82
  const isStill = (0, is_current_selected_still_1.useIsStill)();
78
83
  const [loop, setLoop] = (0, react_1.useState)((0, loop_1.loadLoopOption)());
79
84
  const isFullscreenSupported = (0, check_fullscreen_support_1.checkFullscreenSupport)();
@@ -84,12 +89,13 @@ const PreviewToolbar = ({ readOnlyStudio, bufferStateDelayInMilliseconds }) => {
84
89
  jsx_runtime_1.jsx("div", { style: padding }), isMobileLayout ? null : (jsx_runtime_1.jsx(PreviewToolbarControl, { children: jsx_runtime_1.jsx(SizeSelector_1.SizeSelector, {}) })), !isMobileLayout && (isStill || isVideoComposition) ? (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [
85
90
  jsx_runtime_1.jsx(layout_1.Spacing, { x: 2 }), jsx_runtime_1.jsx(PreviewToolbarControl, { children: jsx_runtime_1.jsx(PlaybackRateSelector_1.PlaybackRateSelector, { setPlaybackRate: setPlaybackRate, playbackRate: playbackRate }) })
86
91
  ] })) : null, isMobileLayout ? (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [
87
- jsx_runtime_1.jsx(PreviewToolbarControl, { children: jsx_runtime_1.jsx(PreviewToolbarOverflowButton_1.PreviewToolbarOverflowButton, { showFullscreen: Boolean(canvasContent && isFullscreenSupported), showPlaybackRate: isVideoComposition, showLoop: isVideoComposition, showCompositionControls: (canvasContent === null || canvasContent === void 0 ? void 0 : canvasContent.type) === 'composition', playbackRate: playbackRate, setPlaybackRate: setPlaybackRate, loop: loop, setLoop: setLoop }) }), jsx_runtime_1.jsx(layout_1.Spacing, { x: 1.5 })
92
+ jsx_runtime_1.jsx(PreviewToolbarControl, { children: jsx_runtime_1.jsx(PreviewToolbarOverflowButton_1.PreviewToolbarOverflowButton, { showFullscreen: Boolean(canvasContent && isFullscreenSupported), showPlaybackRate: isVideoComposition, showLoop: isVideoComposition, showCanvasViewControls: showCanvasViewControls, showCompositionControls: showCompositionControls, playbackRate: playbackRate, setPlaybackRate: setPlaybackRate, loop: loop, setLoop: setLoop }) }), jsx_runtime_1.jsx(layout_1.Spacing, { x: 1.5 })
88
93
  ] })) : null, isVideoComposition && isMobileLayout ? (jsx_runtime_1.jsx(PreviewToolbarControl, { children: jsx_runtime_1.jsx(MuteToggle_1.MuteToggle, { muted: playerMuted, setMuted: setPlayerMuted }) })) : null] }), jsx_runtime_1.jsx(layout_1.Flex, {}), isVideoComposition && isMobileLayout ? (jsx_runtime_1.jsx("div", { style: centeredPlayButton, children: playPause })) : null, isVideoComposition && !isMobileLayout ? (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [
89
94
  jsx_runtime_1.jsx(layout_1.Spacing, { x: 2 }), playPause, jsx_runtime_1.jsx(layout_1.Spacing, { x: 2 }), jsx_runtime_1.jsx(PreviewToolbarControl, { children: jsx_runtime_1.jsx(LoopToggle_1.LoopToggle, { loop: loop, setLoop: setLoop }) }), jsx_runtime_1.jsx(layout_1.Spacing, { x: 0.75 }), jsx_runtime_1.jsx(PreviewToolbarControl, { children: jsx_runtime_1.jsx(MuteToggle_1.MuteToggle, { muted: playerMuted, setMuted: setPlayerMuted }) }), jsx_runtime_1.jsx(layout_1.Spacing, { x: 2 }), jsx_runtime_1.jsx(PreviewToolbarControl, { children: jsx_runtime_1.jsx(TimelineInOutToggle_1.TimelineInOutPointToggle, {}) }), jsx_runtime_1.jsx(layout_1.Spacing, { x: 2 })
90
- ] })) : null, (canvasContent === null || canvasContent === void 0 ? void 0 : canvasContent.type) === 'composition' ? (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [isMobileLayout ? null : (jsx_runtime_1.jsx(PreviewToolbarControl, { children: jsx_runtime_1.jsx(CheckboardToggle_1.CheckboardToggle, {}) })), isMobileLayout ? null : jsx_runtime_1.jsx(layout_1.Spacing, { x: 0.25 }), isMobileLayout ? null : (jsx_runtime_1.jsx(PreviewToolbarControl, { children: jsx_runtime_1.jsx(OutlineToggle_1.OutlineToggle, {}) })), isMobileLayout ? null : (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [
91
- jsx_runtime_1.jsx(layout_1.Spacing, { x: 0.25 }), jsx_runtime_1.jsx(PreviewToolbarControl, { children: jsx_runtime_1.jsx(RulersAndGuidesToggle_1.RulersAndGuidesToggle, {}) })
92
- ] })), readOnlyStudio || isMobileLayout ? null : (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [
95
+ ] })) : null, showCanvasViewControls ? (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [isMobileLayout ? null : (jsx_runtime_1.jsx(PreviewToolbarControl, { children: jsx_runtime_1.jsx(CheckboardToggle_1.CheckboardToggle, {}) })), isMobileLayout ? null : jsx_runtime_1.jsx(layout_1.Spacing, { x: 0.25 }), isMobileLayout || !showCompositionControls ? null : (jsx_runtime_1.jsx(PreviewToolbarControl, { children: jsx_runtime_1.jsx(OutlineToggle_1.OutlineToggle, {}) })), isMobileLayout ? null : (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [showCompositionControls ? jsx_runtime_1.jsx(layout_1.Spacing, { x: 0.25 }) : null, jsx_runtime_1.jsx(PreviewToolbarControl, { children: jsx_runtime_1.jsx(RulersAndGuidesToggle_1.RulersAndGuidesToggle, { showGuides: showCompositionControls }) })
96
+ ] })), readOnlyStudio ||
97
+ isMobileLayout ||
98
+ !showCompositionControls ? null : (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [
93
99
  jsx_runtime_1.jsx(layout_1.Spacing, { x: 0.25 }), jsx_runtime_1.jsx(PreviewToolbarControl, { children: jsx_runtime_1.jsx(SnappingToggle_1.SnappingToggle, {}) })
94
100
  ] }))] })) : null, jsx_runtime_1.jsx(layout_1.Spacing, { x: 2 }), canvasContent && isFullscreenSupported ? (jsx_runtime_1.jsx(PreviewToolbarControl, { children: jsx_runtime_1.jsx(FullscreenToggle_1.FullScreenToggle, { hidden: isMobileLayout }) })) : null, jsx_runtime_1.jsx(layout_1.Flex, {}), jsx_runtime_1.jsxs("div", { style: sideContainer, children: [
95
101
  jsx_runtime_1.jsx(layout_1.Flex, {}), jsx_runtime_1.jsx(FpsCounter_1.FpsCounter, { playbackSpeed: playbackRate }), jsx_runtime_1.jsx(layout_1.Spacing, { x: 2 }), jsx_runtime_1.jsx(PreviewToolbarControl, { children: jsx_runtime_1.jsx(RenderButton_1.RenderButton, { readOnlyStudio: readOnlyStudio, size: "compact", narrow: isMobileLayout }) }), jsx_runtime_1.jsx(layout_1.Spacing, { x: 1.5 })
@@ -3,6 +3,7 @@ export declare const PreviewToolbarOverflowButton: React.FC<{
3
3
  readonly showFullscreen: boolean;
4
4
  readonly showPlaybackRate: boolean;
5
5
  readonly showLoop: boolean;
6
+ readonly showCanvasViewControls: boolean;
6
7
  readonly showCompositionControls: boolean;
7
8
  readonly playbackRate: number;
8
9
  readonly setPlaybackRate: React.Dispatch<React.SetStateAction<number>>;
@@ -19,7 +19,7 @@ const clickButton = (id) => {
19
19
  var _a;
20
20
  (_a = document.getElementById(id)) === null || _a === void 0 ? void 0 : _a.click();
21
21
  };
22
- const PreviewToolbarOverflowButton = ({ showFullscreen, showPlaybackRate, showLoop, showCompositionControls, playbackRate, setPlaybackRate, loop, setLoop, }) => {
22
+ const PreviewToolbarOverflowButton = ({ showFullscreen, showPlaybackRate, showLoop, showCanvasViewControls, showCompositionControls, playbackRate, setPlaybackRate, loop, setLoop, }) => {
23
23
  const keyboardShortcutsDisabled = (0, use_keybinding_1.areKeyboardShortcutsDisabled)();
24
24
  const { checkerboard, setCheckerboard } = (0, react_1.useContext)(checkerboard_1.CheckerboardContext);
25
25
  const { editorShowOutlines, setEditorShowOutlines } = (0, react_1.useContext)(editor_outlines_1.EditorShowOutlinesContext);
@@ -86,7 +86,7 @@ const PreviewToolbarOverflowButton = ({ showFullscreen, showPlaybackRate, showLo
86
86
  quickSwitcherLabel: null,
87
87
  });
88
88
  }
89
- if (showCompositionControls) {
89
+ if (showCanvasViewControls) {
90
90
  items.push({
91
91
  type: 'item',
92
92
  id: 'checkerboard',
@@ -98,6 +98,8 @@ const PreviewToolbarOverflowButton = ({ showFullscreen, showPlaybackRate, showLo
98
98
  subMenu: null,
99
99
  quickSwitcherLabel: null,
100
100
  });
101
+ }
102
+ if (showCompositionControls) {
101
103
  items.push({
102
104
  type: 'item',
103
105
  id: 'outlines',
@@ -109,6 +111,8 @@ const PreviewToolbarOverflowButton = ({ showFullscreen, showPlaybackRate, showLo
109
111
  subMenu: null,
110
112
  quickSwitcherLabel: null,
111
113
  });
114
+ }
115
+ if (showCanvasViewControls) {
112
116
  items.push({
113
117
  type: 'item',
114
118
  id: 'rulers',
@@ -120,6 +124,8 @@ const PreviewToolbarOverflowButton = ({ showFullscreen, showPlaybackRate, showLo
120
124
  subMenu: null,
121
125
  quickSwitcherLabel: null,
122
126
  });
127
+ }
128
+ if (showCompositionControls) {
123
129
  items.push({
124
130
  type: 'item',
125
131
  id: 'guides',
@@ -154,6 +160,7 @@ const PreviewToolbarOverflowButton = ({ showFullscreen, showPlaybackRate, showLo
154
160
  showFullscreen,
155
161
  showLoop,
156
162
  showPlaybackRate,
163
+ showCanvasViewControls,
157
164
  showCompositionControls,
158
165
  loop,
159
166
  checkerboard,
@@ -1,7 +1,9 @@
1
1
  import React from 'react';
2
+ import type { ComboboxValue } from '../NewComposition/ComboBox';
2
3
  import type { QuickSwitcherMode } from './NoResults';
3
4
  export declare const ExplorerQuickSwitcherTrigger: React.FC<{
4
5
  readonly mode: QuickSwitcherMode;
5
6
  readonly showShortcut: boolean;
6
7
  readonly tabIndex: number;
8
+ readonly getActions: () => ComboboxValue[];
7
9
  }>;
@@ -5,32 +5,46 @@ 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
- padding: '4px 4px 4px 8px',
14
+ padding: '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
+ ...(0, hoverable_1.hoverableStyle)({
32
+ idleBackground: colors_1.WHITE_ALPHA_06,
33
+ hoverBackground: colors_1.WHITE_ALPHA_06,
34
+ idleColor: colors_1.LIGHT_TEXT,
35
+ hoverColor: colors_1.WHITE,
36
+ }),
37
+ };
38
+ const ellipsisSvgProps = {
39
+ style: {
40
+ height: 12,
41
+ },
28
42
  };
29
43
  const shortcutLabel = {
30
44
  fontSize: 11,
31
45
  opacity: 0.6,
32
46
  };
33
- const ExplorerQuickSwitcherTrigger = ({ mode, showShortcut, tabIndex }) => {
47
+ const ExplorerQuickSwitcherTrigger = ({ mode, showShortcut, tabIndex, getActions }) => {
34
48
  const { setSelectedModal } = (0, react_1.useContext)(modals_1.SetSelectedModalContext);
35
49
  const openQuickSwitcher = (0, react_1.useCallback)(() => {
36
50
  setSelectedModal({
@@ -41,6 +55,12 @@ const ExplorerQuickSwitcherTrigger = ({ mode, showShortcut, tabIndex }) => {
41
55
  compositionSelection: null,
42
56
  });
43
57
  }, [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] }) }));
58
+ const renderMoreActions = (0, react_1.useCallback)((color) => {
59
+ return jsx_runtime_1.jsx(ellipsis_1.EllipsisIcon, { svgProps: ellipsisSvgProps, fill: color });
60
+ }, []);
61
+ const moreActionsTitle = mode === 'assets' ? 'More asset actions' : 'More composition actions';
62
+ return (jsx_runtime_1.jsxs("div", { style: quickSwitcherArea, children: [
63
+ 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 })
64
+ ] }));
45
65
  };
46
66
  exports.ExplorerQuickSwitcherTrigger = ExplorerQuickSwitcherTrigger;
@@ -0,0 +1,6 @@
1
+ import React from 'react';
2
+ export declare const RadioButton: React.FC<{
3
+ readonly checked: boolean;
4
+ readonly children: React.ReactNode;
5
+ readonly onClick: () => void;
6
+ }>;