@remotion/studio 4.0.486 → 4.0.488

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 (67) hide show
  1. package/dist/components/Canvas.js +156 -4
  2. package/dist/components/ContextMenu.js +2 -1
  3. package/dist/components/CurrentComposition.js +43 -2
  4. package/dist/components/EditorContexts.js +2 -1
  5. package/dist/components/GlobalKeybindings.js +19 -0
  6. package/dist/components/InspectorPanel/DefaultInspector.js +2 -1
  7. package/dist/components/InspectorSourceLocation.d.ts +1 -0
  8. package/dist/components/InspectorSourceLocation.js +18 -3
  9. package/dist/components/KeyboardShortcutsExplainer.js +4 -0
  10. package/dist/components/Preview.js +1 -1
  11. package/dist/components/PreviewToolbar.js +2 -1
  12. package/dist/components/RenderButton.js +1 -0
  13. package/dist/components/RenderModal/OptionExplainer.d.ts +11 -1
  14. package/dist/components/RenderModal/OptionExplainer.js +31 -11
  15. package/dist/components/RenderModal/OptionExplainerBubble.d.ts +15 -1
  16. package/dist/components/RenderModal/OptionExplainerBubble.js +17 -3
  17. package/dist/components/RenderModal/SchemaEditor/Fieldset.d.ts +1 -0
  18. package/dist/components/RenderModal/SchemaEditor/Fieldset.js +6 -1
  19. package/dist/components/RenderModal/SchemaEditor/SchemaEditor.js +1 -2
  20. package/dist/components/RenderModal/WebRenderModal.js +5 -2
  21. package/dist/components/RenderModal/WebRenderModalAdvanced.d.ts +3 -0
  22. package/dist/components/RenderModal/WebRenderModalAdvanced.js +92 -5
  23. package/dist/components/RenderModal/WebRenderModalBasic.js +2 -2
  24. package/dist/components/RenderQueue/ClientRenderQueueProcessor.js +1 -0
  25. package/dist/components/RenderQueue/client-side-render-types.d.ts +2 -1
  26. package/dist/components/SelectedOutlineElement.d.ts +4 -0
  27. package/dist/components/SelectedOutlineElement.js +56 -11
  28. package/dist/components/SelectedOutlineOverlay.d.ts +2 -0
  29. package/dist/components/SelectedOutlineOverlay.js +55 -3
  30. package/dist/components/SelectedOutlineUvControls.js +13 -6
  31. package/dist/components/SnappingProvider.d.ts +4 -0
  32. package/dist/components/SnappingProvider.js +24 -0
  33. package/dist/components/SnappingToggle.d.ts +2 -0
  34. package/dist/components/SnappingToggle.js +26 -0
  35. package/dist/components/Splitter/SplitterContext.d.ts +1 -1
  36. package/dist/components/Timeline/Timeline.js +8 -6
  37. package/dist/components/Timeline/TimelineDragHandler.js +2 -1
  38. package/dist/components/Timeline/TimelineSelection.js +8 -1
  39. package/dist/components/Timeline/TimelineSequence.js +15 -8
  40. package/dist/components/Timeline/TimelineSequenceItem.js +63 -51
  41. package/dist/components/VisualControls/ClickableFileName.js +2 -2
  42. package/dist/components/VisualControls/VisualControlsContent.js +9 -1
  43. package/dist/components/effect-drag-and-drop.js +30 -9
  44. package/dist/components/import-assets.d.ts +1 -1
  45. package/dist/components/options-sidebar-tabs.d.ts +1 -0
  46. package/dist/components/options-sidebar-tabs.js +6 -1
  47. package/dist/components/selected-outline-snap.d.ts +36 -0
  48. package/dist/components/selected-outline-snap.js +158 -0
  49. package/dist/esm/{chunk-975rp13y.js → chunk-nn36hyt1.js} +5001 -3970
  50. package/dist/esm/index.mjs +3 -0
  51. package/dist/esm/internals.mjs +5001 -3970
  52. package/dist/esm/previewEntry.mjs +5544 -4513
  53. package/dist/esm/renderEntry.mjs +1 -1
  54. package/dist/helpers/interactivity-enabled.d.ts +1 -0
  55. package/dist/helpers/interactivity-enabled.js +7 -0
  56. package/dist/helpers/retry-payload.js +1 -0
  57. package/dist/helpers/use-menu-structure.js +43 -2
  58. package/dist/icons/magnet.d.ts +3 -0
  59. package/dist/icons/magnet.js +8 -0
  60. package/dist/icons/react.d.ts +5 -0
  61. package/dist/icons/react.js +8 -0
  62. package/dist/state/editor-guides.d.ts +2 -2
  63. package/dist/state/editor-snapping.d.ts +8 -0
  64. package/dist/state/editor-snapping.js +18 -0
  65. package/dist/state/modals.d.ts +2 -1
  66. package/dist/visual-controls/VisualControls.js +4 -0
  67. package/package.json +12 -12
@@ -19,6 +19,8 @@ const use_keybinding_1 = require("../helpers/use-keybinding");
19
19
  const canvas_ref_1 = require("../state/canvas-ref");
20
20
  const editor_guides_1 = require("../state/editor-guides");
21
21
  const editor_zoom_gestures_1 = require("../state/editor-zoom-gestures");
22
+ const call_api_1 = require("./call-api");
23
+ const ConfirmationDialog_1 = require("./ConfirmationDialog");
22
24
  const EditorGuides_1 = __importDefault(require("./EditorGuides"));
23
25
  const EditorRuler_1 = require("./EditorRuler");
24
26
  const use_is_ruler_visible_1 = require("./EditorRuler/use-is-ruler-visible");
@@ -29,6 +31,31 @@ const layout_1 = require("./layout");
29
31
  const Preview_1 = require("./Preview");
30
32
  const ResetZoomButton_1 = require("./ResetZoomButton");
31
33
  const use_resolved_stack_1 = require("./Timeline/use-resolved-stack");
34
+ const elementInstallCompositionIdStyle = {
35
+ fontFamily: 'monospace',
36
+ fontSize: 13,
37
+ };
38
+ const elementInstallCodeDetailsStyle = {
39
+ marginTop: 12,
40
+ fontSize: 13,
41
+ };
42
+ const elementInstallCodeSummaryStyle = {
43
+ cursor: 'pointer',
44
+ fontSize: 13,
45
+ fontWeight: 500,
46
+ };
47
+ const elementInstallCodeBlockStyle = {
48
+ marginTop: 8,
49
+ marginBottom: 0,
50
+ maxHeight: 240,
51
+ overflow: 'auto',
52
+ padding: 12,
53
+ borderRadius: 6,
54
+ backgroundColor: 'rgba(255, 255, 255, 0.06)',
55
+ fontSize: 12,
56
+ lineHeight: 1.5,
57
+ whiteSpace: 'pre',
58
+ };
32
59
  const getContainerStyle = (editorZoomGestures) => ({
33
60
  flex: 1,
34
61
  display: 'flex',
@@ -183,12 +210,20 @@ const Canvas = ({ canvasContent, size }) => {
183
210
  const suppressWheelFromWebKitPinchRef = (0, react_1.useRef)(false);
184
211
  const touchPinchRef = (0, react_1.useRef)(null);
185
212
  const keybindings = (0, use_keybinding_1.useKeybinding)();
213
+ const confirm = (0, ConfirmationDialog_1.useConfirmationDialog)();
186
214
  const config = remotion_1.Internals.useUnsafeVideoConfig();
187
215
  const areRulersVisible = (0, use_is_ruler_visible_1.useIsRulerVisible)();
188
216
  const { editorShowGuides } = (0, react_1.useContext)(editor_guides_1.EditorShowGuidesContext);
189
217
  const { compositions } = (0, react_1.useContext)(remotion_1.Internals.CompositionManager);
190
- const { previewServerState } = (0, react_1.useContext)(client_id_1.StudioServerConnectionCtx);
218
+ const { previewServerState, subscribeToEvent } = (0, react_1.useContext)(client_id_1.StudioServerConnectionCtx);
219
+ const previewServerClientId = previewServerState.type === 'connected'
220
+ ? previewServerState.clientId
221
+ : null;
191
222
  const [isAddingAsset, setIsAddingAsset] = (0, react_1.useState)(false);
223
+ const [installingElementName, setInstallingElementName] = (0, react_1.useState)(null);
224
+ const [pendingElementInstallRequests, setPendingElementInstallRequests] = (0, react_1.useState)([]);
225
+ const [activeElementInstallRequest, setActiveElementInstallRequest] = (0, react_1.useState)(null);
226
+ const lastFocusedAtRef = (0, react_1.useRef)(typeof document === 'undefined' || document.hasFocus() ? Date.now() : null);
192
227
  const [assetResolution, setAssetResolution] = (0, react_1.useState)(null);
193
228
  const currentCompositionId = canvasContent.type === 'composition' ? canvasContent.compositionId : null;
194
229
  const currentComposition = (0, react_1.useMemo)(() => {
@@ -204,12 +239,12 @@ const Canvas = ({ canvasContent, size }) => {
204
239
  compositionFile,
205
240
  compositionId: currentCompositionId,
206
241
  });
207
- const canDropAssets = previewServerState.type === 'connected' &&
242
+ const canInstallElements = previewServerClientId !== null &&
208
243
  !window.remotion_isReadOnlyStudio &&
209
244
  (compositionComponentInfo === null || compositionComponentInfo === void 0 ? void 0 : compositionComponentInfo.canAddSequence) === true &&
210
245
  currentCompositionId !== null &&
211
- compositionFile !== null &&
212
- !isAddingAsset;
246
+ compositionFile !== null;
247
+ const canDropAssets = canInstallElements && !isAddingAsset;
213
248
  const contentDimensions = (0, react_1.useMemo)(() => {
214
249
  if ((canvasContent.type === 'asset' ||
215
250
  canvasContent.type === 'output' ||
@@ -576,6 +611,123 @@ const Canvas = ({ canvasContent, size }) => {
576
611
  (0, react_1.useEffect)(() => {
577
612
  fetchMetadata();
578
613
  }, [fetchMetadata]);
614
+ const updateElementInstallTarget = (0, react_1.useCallback)(() => {
615
+ if (previewServerClientId === null) {
616
+ return;
617
+ }
618
+ (0, call_api_1.callApi)('/api/update-element-install-target', {
619
+ clientId: previewServerClientId,
620
+ compositionFile: canInstallElements ? compositionFile : null,
621
+ compositionId: canInstallElements ? currentCompositionId : null,
622
+ canInstall: canInstallElements,
623
+ lastFocusedAt: lastFocusedAtRef.current,
624
+ readOnly: window.remotion_isReadOnlyStudio,
625
+ }).catch(() => undefined);
626
+ }, [
627
+ canInstallElements,
628
+ compositionFile,
629
+ currentCompositionId,
630
+ previewServerClientId,
631
+ ]);
632
+ (0, react_1.useEffect)(() => {
633
+ updateElementInstallTarget();
634
+ const interval = window.setInterval(updateElementInstallTarget, 2000);
635
+ return () => {
636
+ window.clearInterval(interval);
637
+ };
638
+ }, [updateElementInstallTarget]);
639
+ (0, react_1.useEffect)(() => {
640
+ const markFocused = () => {
641
+ lastFocusedAtRef.current = Date.now();
642
+ updateElementInstallTarget();
643
+ };
644
+ window.addEventListener('focus', markFocused);
645
+ document.addEventListener('pointerdown', markFocused, { capture: true });
646
+ return () => {
647
+ window.removeEventListener('focus', markFocused);
648
+ document.removeEventListener('pointerdown', markFocused, { capture: true });
649
+ };
650
+ }, [updateElementInstallTarget]);
651
+ (0, react_1.useEffect)(() => {
652
+ if (installingElementName === null) {
653
+ return;
654
+ }
655
+ const previousTitle = document.title;
656
+ document.title = `📦 Install ${installingElementName} - Remotion Studio`;
657
+ return () => {
658
+ document.title = previousTitle;
659
+ };
660
+ }, [installingElementName]);
661
+ (0, react_1.useEffect)(() => {
662
+ if (previewServerClientId === null) {
663
+ return;
664
+ }
665
+ return subscribeToEvent('element-install-request', (event) => {
666
+ if (event.type !== 'element-install-request' ||
667
+ event.request.clientId !== previewServerClientId) {
668
+ return;
669
+ }
670
+ setPendingElementInstallRequests((requests) => [
671
+ ...requests,
672
+ event.request,
673
+ ]);
674
+ });
675
+ }, [previewServerClientId, subscribeToEvent]);
676
+ (0, react_1.useEffect)(() => {
677
+ if (activeElementInstallRequest !== null ||
678
+ pendingElementInstallRequests.length === 0) {
679
+ return;
680
+ }
681
+ const [nextRequest, ...remainingRequests] = pendingElementInstallRequests;
682
+ if (!nextRequest) {
683
+ throw new Error('Expected pending Element install request');
684
+ }
685
+ setActiveElementInstallRequest(nextRequest);
686
+ setPendingElementInstallRequests(remainingRequests);
687
+ }, [activeElementInstallRequest, pendingElementInstallRequests]);
688
+ (0, react_1.useEffect)(() => {
689
+ if (activeElementInstallRequest === null) {
690
+ return;
691
+ }
692
+ let canceled = false;
693
+ const handleInstallRequest = async () => {
694
+ setInstallingElementName(activeElementInstallRequest.element.displayName);
695
+ const accepted = await confirm({
696
+ title: 'Install Element',
697
+ message: (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: ["Install \u201C", activeElementInstallRequest.element.displayName, "\u201D into", ' ', jsx_runtime_1.jsx("code", { style: elementInstallCompositionIdStyle, children: activeElementInstallRequest.compositionId }), ' ', "composition? This will create an Element source file and update the composition source.",
698
+ jsx_runtime_1.jsxs("details", { style: elementInstallCodeDetailsStyle, children: [
699
+ jsx_runtime_1.jsx("summary", { style: elementInstallCodeSummaryStyle, children: "Preview Element source" }), jsx_runtime_1.jsx("pre", { style: elementInstallCodeBlockStyle, children: jsx_runtime_1.jsx("code", { children: activeElementInstallRequest.element.sourceCode }) })
700
+ ] })
701
+ ] })),
702
+ confirmLabel: 'Install',
703
+ cancelLabel: 'Cancel',
704
+ });
705
+ if (accepted && !canceled) {
706
+ await (0, import_assets_1.insertElement)({
707
+ element: activeElementInstallRequest.element,
708
+ compositionFile: activeElementInstallRequest.compositionFile,
709
+ compositionId: activeElementInstallRequest.compositionId,
710
+ dropPosition: null,
711
+ });
712
+ }
713
+ };
714
+ handleInstallRequest()
715
+ .finally(() => {
716
+ if (canceled) {
717
+ return;
718
+ }
719
+ setInstallingElementName(null);
720
+ setActiveElementInstallRequest(null);
721
+ })
722
+ .catch((err) => {
723
+ setTimeout(() => {
724
+ throw err;
725
+ }, 0);
726
+ });
727
+ return () => {
728
+ canceled = true;
729
+ };
730
+ }, [activeElementInstallRequest, confirm]);
579
731
  const onDragOver = (0, react_1.useCallback)((event) => {
580
732
  if (!canDropAssets ||
581
733
  (!isFileDragEvent(event) &&
@@ -170,7 +170,8 @@ exports.ContextMenu = react_1.default.forwardRef(({ children, values, onOpen, st
170
170
  return;
171
171
  }
172
172
  if (forwardedRef) {
173
- forwardedRef.current = node;
173
+ forwardedRef.current =
174
+ node;
174
175
  }
175
176
  }, [forwardedRef]);
176
177
  (0, react_1.useEffect)(() => {
@@ -6,6 +6,9 @@ const react_1 = require("react");
6
6
  const remotion_1 = require("remotion");
7
7
  const is_composition_still_1 = require("../helpers/is-composition-still");
8
8
  const open_in_editor_1 = require("../helpers/open-in-editor");
9
+ const react_2 = require("../icons/react");
10
+ const still_1 = require("../icons/still");
11
+ const video_1 = require("../icons/video");
9
12
  const render_frame_1 = require("../state/render-frame");
10
13
  const InlineCompositionName_1 = require("./InlineCompositionName");
11
14
  const InspectorInfoHeader_1 = require("./InspectorInfoHeader");
@@ -13,8 +16,16 @@ const InspectorSourceLocation_1 = require("./InspectorSourceLocation");
13
16
  const NotificationCenter_1 = require("./Notifications/NotificationCenter");
14
17
  const use_resolved_stack_1 = require("./Timeline/use-resolved-stack");
15
18
  exports.CURRENT_COMPOSITION_HEIGHT = InspectorInfoHeader_1.INSPECTOR_INFO_HEADER_MIN_HEIGHT;
19
+ const sourceLocationIconStyle = {
20
+ flexShrink: 0,
21
+ height: 13,
22
+ width: 13,
23
+ };
24
+ const renderReactIcon = (color) => {
25
+ return jsx_runtime_1.jsx(react_2.ReactIcon, { color: color, style: sourceLocationIconStyle });
26
+ };
16
27
  const CurrentComposition = () => {
17
- var _a, _b;
28
+ var _a, _b, _c, _d, _e;
18
29
  const video = remotion_1.Internals.useVideo();
19
30
  const { compositions } = (0, react_1.useContext)(remotion_1.Internals.CompositionManager);
20
31
  const currentComposition = (0, react_1.useMemo)(() => {
@@ -36,6 +47,22 @@ const CurrentComposition = () => {
36
47
  source: resolvedCompositionLocation.source,
37
48
  };
38
49
  }, [resolvedCompositionLocation]);
50
+ const compositionFile = (_b = validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.source) !== null && _b !== void 0 ? _b : null;
51
+ const compositionId = (_c = currentComposition === null || currentComposition === void 0 ? void 0 : currentComposition.id) !== null && _c !== void 0 ? _c : null;
52
+ const compositionComponentInfo = (0, open_in_editor_1.useCachedCompositionComponentInfo)({
53
+ compositionFile,
54
+ compositionId,
55
+ });
56
+ const componentLocation = (_d = compositionComponentInfo === null || compositionComponentInfo === void 0 ? void 0 : compositionComponentInfo.location) !== null && _d !== void 0 ? _d : null;
57
+ (0, react_1.useEffect)(() => {
58
+ if (compositionFile === null || compositionId === null) {
59
+ return;
60
+ }
61
+ (0, open_in_editor_1.preloadCompositionComponentInfo)({
62
+ compositionFile,
63
+ compositionId,
64
+ });
65
+ }, [compositionFile, compositionId]);
39
66
  const openFileLocation = (0, react_1.useCallback)(() => {
40
67
  if (!validatedLocation) {
41
68
  return;
@@ -44,7 +71,21 @@ const CurrentComposition = () => {
44
71
  (0, NotificationCenter_1.showNotification)(err.message, 2000);
45
72
  });
46
73
  }, [validatedLocation]);
74
+ const openComponentLocation = (0, react_1.useCallback)(() => {
75
+ if (!componentLocation) {
76
+ return;
77
+ }
78
+ (0, open_in_editor_1.openOriginalPositionInEditor)(componentLocation).catch((err) => {
79
+ (0, NotificationCenter_1.showNotification)(err.message, 2000);
80
+ });
81
+ }, [componentLocation]);
82
+ const renderCompositionIcon = (0, react_1.useCallback)((color) => {
83
+ if (!video) {
84
+ return null;
85
+ }
86
+ return (0, is_composition_still_1.isCompositionStill)(video) ? (jsx_runtime_1.jsx(still_1.StillIcon, { color: color, style: sourceLocationIconStyle })) : (jsx_runtime_1.jsx(video_1.FilmIcon, { color: color, style: sourceLocationIconStyle }));
87
+ }, [video]);
47
88
  return (jsx_runtime_1.jsx(InspectorInfoHeader_1.InspectorInfoHeader, { children: video ? (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [
48
- jsx_runtime_1.jsx(InlineCompositionName_1.InlineCompositionName, { compositionId: video.id, stack: (_b = currentComposition === null || currentComposition === void 0 ? void 0 : currentComposition.stack) !== null && _b !== void 0 ? _b : null, compositions: compositions }, video.id), jsx_runtime_1.jsx(InspectorSourceLocation_1.InspectorSourceLocation, { location: validatedLocation, canOpen: validatedLocation !== null, onOpen: openFileLocation }), jsx_runtime_1.jsxs(InspectorInfoHeader_1.InspectorInfoSubtitle, { children: [video.width, "x", video.height, (0, is_composition_still_1.isCompositionStill)(video) ? null : `, ${video.fps} FPS`] }), (0, is_composition_still_1.isCompositionStill)(video) ? (jsx_runtime_1.jsx(InspectorInfoHeader_1.InspectorInfoSubtitle, { children: "Still" })) : (jsx_runtime_1.jsxs(InspectorInfoHeader_1.InspectorInfoSubtitle, { children: ["Duration ", (0, render_frame_1.renderFrame)(video.durationInFrames, video.fps)] }))] })) : null }));
89
+ jsx_runtime_1.jsx(InlineCompositionName_1.InlineCompositionName, { compositionId: video.id, stack: (_e = currentComposition === null || currentComposition === void 0 ? void 0 : currentComposition.stack) !== null && _e !== void 0 ? _e : null, compositions: compositions }, video.id), jsx_runtime_1.jsx(InspectorSourceLocation_1.InspectorSourceLocation, { location: validatedLocation, canOpen: validatedLocation !== null, onOpen: openFileLocation, renderIcon: renderCompositionIcon }), jsx_runtime_1.jsx(InspectorSourceLocation_1.InspectorSourceLocation, { location: componentLocation, canOpen: componentLocation !== null, onOpen: openComponentLocation, renderIcon: renderReactIcon }), jsx_runtime_1.jsxs(InspectorInfoHeader_1.InspectorInfoSubtitle, { children: [video.width, "x", video.height, (0, is_composition_still_1.isCompositionStill)(video) ? null : `, ${video.fps} FPS`] }), (0, is_composition_still_1.isCompositionStill)(video) ? (jsx_runtime_1.jsx(InspectorInfoHeader_1.InspectorInfoSubtitle, { children: "Still" })) : (jsx_runtime_1.jsxs(InspectorInfoHeader_1.InspectorInfoSubtitle, { children: ["Duration ", (0, render_frame_1.renderFrame)(video.durationInFrames, video.fps)] }))] })) : null }));
49
90
  };
50
91
  exports.CurrentComposition = CurrentComposition;
@@ -21,12 +21,13 @@ const SetTimelineInOutProvider_1 = require("./SetTimelineInOutProvider");
21
21
  const ShowGuidesProvider_1 = require("./ShowGuidesProvider");
22
22
  const ShowOutlinesProvider_1 = require("./ShowOutlinesProvider");
23
23
  const ShowRulersProvider_1 = require("./ShowRulersProvider");
24
+ const SnappingProvider_1 = require("./SnappingProvider");
24
25
  const VisualControlsUndoSync_1 = require("./VisualControls/VisualControlsUndoSync");
25
26
  const ZoomGesturesProvider_1 = require("./ZoomGesturesProvider");
26
27
  const EditorContexts = ({ children, readOnlyStudio }) => {
27
28
  return (jsx_runtime_1.jsx(get_zod_if_possible_1.ZodProvider, { children: jsx_runtime_1.jsx(VisualControls_1.VisualControlsProvider, { children: jsx_runtime_1.jsxs(client_id_1.PreviewServerConnection, { readOnlyStudio: readOnlyStudio, children: [
28
29
  jsx_runtime_1.jsx(VisualControlsUndoSync_1.VisualControlsUndoSync, {}), jsx_runtime_1.jsxs(context_1.RenderQueueContextProvider, { children: [
29
- jsx_runtime_1.jsx(ClientRenderQueueProcessor_1.ClientRenderQueueProcessor, {}), jsx_runtime_1.jsx(keybindings_1.KeybindingContextProvider, { children: jsx_runtime_1.jsx(CheckerboardProvider_1.CheckerboardProvider, { children: jsx_runtime_1.jsx(ZoomGesturesProvider_1.ZoomGesturesProvider, { children: jsx_runtime_1.jsx(ShowRulersProvider_1.ShowRulersProvider, { children: jsx_runtime_1.jsx(ShowGuidesProvider_1.ShowGuidesProvider, { children: jsx_runtime_1.jsx(ShowOutlinesProvider_1.ShowOutlinesProvider, { children: jsx_runtime_1.jsx(preview_size_1.PreviewSizeProvider, { children: jsx_runtime_1.jsx(ModalsProvider_1.ModalsProvider, { children: jsx_runtime_1.jsx(MediaVolumeProvider_1.MediaVolumeProvider, { children: jsx_runtime_1.jsx(player_1.PlayerInternals.PlayerEmitterProvider, { currentPlaybackRate: null, children: jsx_runtime_1.jsx(sidebar_1.SidebarContextProvider, { children: jsx_runtime_1.jsx(folders_1.FolderContextProvider, { children: jsx_runtime_1.jsx(highest_z_index_1.HighestZIndexProvider, { children: jsx_runtime_1.jsx(SetTimelineInOutProvider_1.SetTimelineInOutProvider, { children: jsx_runtime_1.jsx(ExpandedTracksProvider_1.ExpandedTracksProvider, { children: children }) }) }) }) }) }) }) }) }) }) }) }) }) }) })
30
+ jsx_runtime_1.jsx(ClientRenderQueueProcessor_1.ClientRenderQueueProcessor, {}), jsx_runtime_1.jsx(keybindings_1.KeybindingContextProvider, { children: jsx_runtime_1.jsx(CheckerboardProvider_1.CheckerboardProvider, { children: jsx_runtime_1.jsx(ZoomGesturesProvider_1.ZoomGesturesProvider, { children: jsx_runtime_1.jsx(ShowRulersProvider_1.ShowRulersProvider, { children: jsx_runtime_1.jsx(ShowGuidesProvider_1.ShowGuidesProvider, { children: jsx_runtime_1.jsx(ShowOutlinesProvider_1.ShowOutlinesProvider, { children: jsx_runtime_1.jsx(SnappingProvider_1.SnappingProvider, { children: jsx_runtime_1.jsx(preview_size_1.PreviewSizeProvider, { children: jsx_runtime_1.jsx(ModalsProvider_1.ModalsProvider, { children: jsx_runtime_1.jsx(MediaVolumeProvider_1.MediaVolumeProvider, { children: jsx_runtime_1.jsx(player_1.PlayerInternals.PlayerEmitterProvider, { currentPlaybackRate: null, children: jsx_runtime_1.jsx(sidebar_1.SidebarContextProvider, { children: jsx_runtime_1.jsx(folders_1.FolderContextProvider, { children: jsx_runtime_1.jsx(highest_z_index_1.HighestZIndexProvider, { children: jsx_runtime_1.jsx(SetTimelineInOutProvider_1.SetTimelineInOutProvider, { children: jsx_runtime_1.jsx(ExpandedTracksProvider_1.ExpandedTracksProvider, { children: children }) }) }) }) }) }) }) }) }) }) }) }) }) }) }) })
30
31
  ] })
31
32
  ] }) }) }));
32
33
  };
@@ -9,6 +9,7 @@ const show_browser_rendering_1 = require("../helpers/show-browser-rendering");
9
9
  const timeline_node_path_key_1 = require("../helpers/timeline-node-path-key");
10
10
  const use_keybinding_1 = require("../helpers/use-keybinding");
11
11
  const checkerboard_1 = require("../state/checkerboard");
12
+ const editor_snapping_1 = require("../state/editor-snapping");
12
13
  const modals_1 = require("../state/modals");
13
14
  const AskAiModal_1 = require("./AskAiModal");
14
15
  const CompositionSelector_1 = require("./CompositionSelector");
@@ -25,6 +26,7 @@ const GlobalKeybindings = ({ readOnlyStudio }) => {
25
26
  const keybindings = (0, use_keybinding_1.useKeybinding)();
26
27
  const { setSelectedModal } = (0, react_1.useContext)(modals_1.ModalsContext);
27
28
  const { setCheckerboard } = (0, react_1.useContext)(checkerboard_1.CheckerboardContext);
29
+ const { setEditorSnapping } = (0, react_1.useContext)(editor_snapping_1.EditorSnappingContext);
28
30
  const currentSelection = (0, TimelineSelection_1.useCurrentTimelineSelectionStateAsRef)();
29
31
  const { sequences } = (0, react_1.useContext)(remotion_1.Internals.SequenceManager);
30
32
  const videoConfig = remotion_1.Internals.useUnsafeVideoConfig();
@@ -188,6 +190,21 @@ const GlobalKeybindings = ({ readOnlyStudio }) => {
188
190
  triggerIfInputFieldFocused: false,
189
191
  keepRegisteredWhenNotHighestContext: false,
190
192
  });
193
+ const shiftMKey = keybindings.registerKeybinding({
194
+ event: 'keydown',
195
+ key: 'm',
196
+ callback: (event) => {
197
+ if (!event.shiftKey) {
198
+ return;
199
+ }
200
+ setEditorSnapping((current) => !current);
201
+ event.preventDefault();
202
+ },
203
+ commandCtrlKey: false,
204
+ preventDefault: false,
205
+ triggerIfInputFieldFocused: false,
206
+ keepRegisteredWhenNotHighestContext: false,
207
+ });
191
208
  return () => {
192
209
  for (const sequencePropKey of sequencePropKeys) {
193
210
  sequencePropKey.unregister();
@@ -198,12 +215,14 @@ const GlobalKeybindings = ({ readOnlyStudio }) => {
198
215
  cmdIKey === null || cmdIKey === void 0 ? void 0 : cmdIKey.unregister();
199
216
  pageDown.unregister();
200
217
  pageUp.unregister();
218
+ shiftMKey.unregister();
201
219
  };
202
220
  }, [
203
221
  keybindings,
204
222
  openRenderModal,
205
223
  selectSequenceProp,
206
224
  setCheckerboard,
225
+ setEditorSnapping,
207
226
  setSelectedModal,
208
227
  navigateToNextComposition,
209
228
  navigateToPreviousComposition,
@@ -4,6 +4,7 @@ exports.DefaultInspector = void 0;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const react_1 = require("react");
6
6
  const remotion_1 = require("remotion");
7
+ const interactivity_enabled_1 = require("../../helpers/interactivity-enabled");
7
8
  const VisualControls_1 = require("../../visual-controls/VisualControls");
8
9
  const CurrentAsset_1 = require("../CurrentAsset");
9
10
  const CurrentComposition_1 = require("../CurrentComposition");
@@ -27,7 +28,7 @@ const DefaultInspector = ({ composition, currentDefaultProps, readOnlyStudio, se
27
28
  const { handles: visualControlHandles } = (0, react_1.useContext)(VisualControls_1.VisualControlsContext);
28
29
  const [defaultPropsMode, setDefaultPropsMode] = (0, react_1.useState)('schema');
29
30
  const compositionId = (_a = composition === null || composition === void 0 ? void 0 : composition.id) !== null && _a !== void 0 ? _a : null;
30
- const hasVisualControls = Object.keys(visualControlHandles).length > 0;
31
+ const hasVisualControls = interactivity_enabled_1.studioInteractivityEnabled && Object.keys(visualControlHandles).length > 0;
31
32
  (0, react_1.useEffect)(() => {
32
33
  setDefaultPropsMode('schema');
33
34
  }, [compositionId]);
@@ -4,4 +4,5 @@ export declare const InspectorSourceLocation: React.FC<{
4
4
  readonly location: OriginalPosition | null;
5
5
  readonly canOpen: boolean;
6
6
  readonly onOpen: () => void;
7
+ readonly renderIcon?: (color: string) => React.ReactNode;
7
8
  }>;
@@ -12,7 +12,9 @@ const sourceLocationStyle = {
12
12
  backgroundColor: colors_1.BACKGROUND,
13
13
  border: 'none',
14
14
  boxSizing: 'border-box',
15
- display: 'block',
15
+ display: 'flex',
16
+ alignItems: 'center',
17
+ gap: 4,
16
18
  fontFamily: 'sans-serif',
17
19
  fontSize: 12,
18
20
  height: 18,
@@ -27,7 +29,18 @@ const sourceLocationStyle = {
27
29
  whiteSpace: 'nowrap',
28
30
  width: 'fit-content',
29
31
  };
30
- const InspectorSourceLocation = ({ location, canOpen, onOpen }) => {
32
+ const sourceLocationLabelStyle = {
33
+ color: 'inherit',
34
+ display: 'block',
35
+ fontFamily: 'sans-serif',
36
+ fontSize: 12,
37
+ lineHeight: '18px',
38
+ minWidth: 0,
39
+ overflow: 'hidden',
40
+ textOverflow: 'ellipsis',
41
+ whiteSpace: 'nowrap',
42
+ };
43
+ const InspectorSourceLocation = ({ location, canOpen, onOpen, renderIcon }) => {
31
44
  const [hovered, setHovered] = (0, react_1.useState)(false);
32
45
  const validLocation = (0, react_1.useMemo)(() => {
33
46
  if (!(location === null || location === void 0 ? void 0 : location.source) || location.line === null) {
@@ -57,6 +70,7 @@ const InspectorSourceLocation = ({ location, canOpen, onOpen }) => {
57
70
  cursor: canOpen ? 'pointer' : 'default',
58
71
  };
59
72
  }, [canOpen, hovered]);
73
+ const color = hovered ? colors_1.LIGHT_COLOR : colors_1.LIGHT_TEXT;
60
74
  const onClick = (0, react_1.useCallback)(() => {
61
75
  if (!canOpen) {
62
76
  return;
@@ -66,6 +80,7 @@ const InspectorSourceLocation = ({ location, canOpen, onOpen }) => {
66
80
  if (!label) {
67
81
  return null;
68
82
  }
69
- return (jsx_runtime_1.jsx("button", { type: "button", style: style, title: fileLocation !== null && fileLocation !== void 0 ? fileLocation : undefined, onClick: onClick, onPointerEnter: () => setHovered(true), onPointerLeave: () => setHovered(false), children: label }));
83
+ return (jsx_runtime_1.jsxs("button", { type: "button", style: style, title: fileLocation !== null && fileLocation !== void 0 ? fileLocation : undefined, onClick: onClick, onPointerEnter: () => setHovered(true), onPointerLeave: () => setHovered(false), children: [renderIcon ? renderIcon(color) : null, jsx_runtime_1.jsx("span", { style: sourceLocationLabelStyle, children: label })
84
+ ] }));
70
85
  };
71
86
  exports.InspectorSourceLocation = InspectorSourceLocation;
@@ -102,6 +102,10 @@ const KeyboardShortcutsExplainer = () => {
102
102
  jsx_runtime_1.jsx("div", { style: left, children: jsx_runtime_1.jsx("kbd", { style: key, children: "F" }) }), jsx_runtime_1.jsx("div", { style: right, children: "Enter fullscreen" })
103
103
  ] }), jsx_runtime_1.jsxs(layout_1.Row, { align: "center", children: [
104
104
  jsx_runtime_1.jsx("div", { style: left, children: jsx_runtime_1.jsx("kbd", { style: key, children: "Esc" }) }), jsx_runtime_1.jsx("div", { style: right, children: "Exit fullscreen" })
105
+ ] }), jsx_runtime_1.jsxs(layout_1.Row, { align: "center", children: [
106
+ jsx_runtime_1.jsxs("div", { style: left, children: [
107
+ jsx_runtime_1.jsx("kbd", { style: key, children: jsx_runtime_1.jsx(keys_1.ShiftIcon, {}) }), jsx_runtime_1.jsx(layout_1.Spacing, { x: 0.3 }), jsx_runtime_1.jsx("kbd", { style: key, children: "M" })
108
+ ] }), jsx_runtime_1.jsx("div", { style: right, children: "Enable snapping" })
105
109
  ] })
106
110
  ] }), jsx_runtime_1.jsx(layout_1.Spacing, { x: 8 }), jsx_runtime_1.jsxs(layout_1.Column, { children: [
107
111
  jsx_runtime_1.jsx("div", { style: title, children: "Navigation" }), jsx_runtime_1.jsxs(layout_1.Row, { align: "center", children: [
@@ -122,7 +122,7 @@ const CompWhenItHasDimensions = ({ contentDimensions, canvasSize, canvasContent,
122
122
  return (jsx_runtime_1.jsx("div", { style: outer, children: jsx_runtime_1.jsx(RenderPreview_1.RenderPreview, { path: canvasContent.displayName, assetMetadata: assetMetadata, getBlob: canvasContent.getBlob }) }));
123
123
  }
124
124
  return (jsx_runtime_1.jsxs("div", { style: outer, children: [
125
- jsx_runtime_1.jsx(PortalContainer, { contentDimensions: contentDimensions, scale: scale, xCorrection: xCorrection, yCorrection: yCorrection }), jsx_runtime_1.jsx(SelectedOutlineOverlay_1.SelectedOutlineOverlay, { scale: scale, translationX: previewSize.translation.x, translationY: previewSize.translation.y })
125
+ jsx_runtime_1.jsx(PortalContainer, { contentDimensions: contentDimensions, scale: scale, xCorrection: xCorrection, yCorrection: yCorrection }), jsx_runtime_1.jsx(SelectedOutlineOverlay_1.SelectedOutlineOverlay, { compositionHeight: contentDimensions.height, compositionWidth: contentDimensions.width, scale: scale, translationX: previewSize.translation.x, translationY: previewSize.translation.y })
126
126
  ] }));
127
127
  };
128
128
  const PortalContainer = ({ scale, xCorrection, yCorrection, contentDimensions }) => {
@@ -23,6 +23,7 @@ const PlaybackRateSelector_1 = require("./PlaybackRateSelector");
23
23
  const PlayPause_1 = require("./PlayPause");
24
24
  const RenderButton_1 = require("./RenderButton");
25
25
  const SizeSelector_1 = require("./SizeSelector");
26
+ const SnappingToggle_1 = require("./SnappingToggle");
26
27
  const TimelineZoomControls_1 = require("./Timeline/TimelineZoomControls");
27
28
  const TimelineInOutToggle_1 = require("./TimelineInOutToggle");
28
29
  const TOOLBAR_HEIGHT = 50;
@@ -165,7 +166,7 @@ const PreviewToolbar = ({ readOnlyStudio, bufferStateDelayInMilliseconds }) => {
165
166
  ] }), jsx_runtime_1.jsx(layout_1.Flex, {}), jsx_runtime_1.jsx(PreviewToolbarControl, { children: jsx_runtime_1.jsx(SizeSelector_1.SizeSelector, {}) }), isStill || isVideoComposition ? (jsx_runtime_1.jsx(PreviewToolbarControl, { children: jsx_runtime_1.jsx(PlaybackRateSelector_1.PlaybackRateSelector, { setPlaybackRate: setPlaybackRate, playbackRate: playbackRate }) })) : null] })), isVideoComposition ? (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [
166
167
  jsx_runtime_1.jsx(layout_1.Spacing, { x: 2 }), jsx_runtime_1.jsx(PreviewToolbarControl, { children: jsx_runtime_1.jsx(PlayPause_1.PlayPause, { bufferStateDelayInMilliseconds: bufferStateDelayInMilliseconds, loop: loop, playbackRate: playbackRate, muted: playerMuted }) }), 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(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 })
167
168
  ] })) : null, (canvasContent === null || canvasContent === void 0 ? void 0 : canvasContent.type) === 'composition' ? (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [
168
- jsx_runtime_1.jsx(PreviewToolbarControl, { children: jsx_runtime_1.jsx(CheckboardToggle_1.CheckboardToggle, {}) }), jsx_runtime_1.jsx(PreviewToolbarControl, { children: jsx_runtime_1.jsx(OutlineToggle_1.OutlineToggle, {}) })
169
+ jsx_runtime_1.jsx(PreviewToolbarControl, { children: jsx_runtime_1.jsx(CheckboardToggle_1.CheckboardToggle, {}) }), jsx_runtime_1.jsx(PreviewToolbarControl, { children: jsx_runtime_1.jsx(OutlineToggle_1.OutlineToggle, {}) }), jsx_runtime_1.jsx(PreviewToolbarControl, { children: jsx_runtime_1.jsx(SnappingToggle_1.SnappingToggle, {}) })
169
170
  ] })) : null, jsx_runtime_1.jsx(layout_1.Spacing, { x: 1 }), canvasContent && isFullscreenSupported ? (jsx_runtime_1.jsx(PreviewToolbarControl, { children: jsx_runtime_1.jsx(FullscreenToggle_1.FullScreenToggle, {}) })) : null, jsx_runtime_1.jsx(layout_1.Flex, {}), isMobileLayout && (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [
170
171
  jsx_runtime_1.jsx(layout_1.Flex, {}), jsx_runtime_1.jsx(PreviewToolbarControl, { children: jsx_runtime_1.jsx(SizeSelector_1.SizeSelector, {}) }), isStill || isVideoComposition ? (jsx_runtime_1.jsx(PreviewToolbarControl, { children: jsx_runtime_1.jsx(PlaybackRateSelector_1.PlaybackRateSelector, { setPlaybackRate: setPlaybackRate, playbackRate: playbackRate }) })) : null] })), jsx_runtime_1.jsxs("div", { style: sideContainer, children: [
171
172
  jsx_runtime_1.jsx(layout_1.Flex, {}), !isMobileLayout && 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 }) }), jsx_runtime_1.jsx(layout_1.Spacing, { x: 1.5 })
@@ -271,6 +271,7 @@ const RenderButton = ({ readOnlyStudio, }) => {
271
271
  initialMuted: null,
272
272
  initialMediaCacheSizeInBytes: defaults.mediaCacheSizeInBytes,
273
273
  initialAllowHtmlInCanvas: defaults.allowHtmlInCanvas,
274
+ initialPageResponsiveness: 'medium',
274
275
  });
275
276
  }, [video, setSelectedModal, getCurrentFrame, props, inFrame, outFrame]);
276
277
  const onClick = (0, react_1.useCallback)(() => {
@@ -1,5 +1,15 @@
1
1
  import type { AnyRemotionOption } from '@remotion/renderer';
2
2
  import React from 'react';
3
+ export type OptionExplainerOption = Pick<AnyRemotionOption<unknown>, 'name' | 'description' | 'docLink' | 'ssrName'> & {
4
+ readonly cliFlag?: string;
5
+ };
6
+ export type OptionExplainerInfoRow = {
7
+ readonly label: string;
8
+ readonly value: string;
9
+ };
3
10
  export declare const OptionExplainer: React.FC<{
4
- readonly option: AnyRemotionOption<unknown>;
11
+ readonly option: OptionExplainerOption;
12
+ readonly extraInfoRows?: readonly OptionExplainerInfoRow[];
13
+ readonly showApiOption?: boolean;
14
+ readonly showCliFlag?: boolean;
5
15
  }>;
@@ -11,6 +11,7 @@ const container = {
11
11
  paddingTop: 10,
12
12
  paddingBottom: 10,
13
13
  backgroundColor: colors_1.INPUT_BACKGROUND,
14
+ color: colors_1.WHITE,
14
15
  };
15
16
  const padding = {
16
17
  paddingLeft: 20,
@@ -21,7 +22,9 @@ const title = {
21
22
  };
22
23
  const DESCRIPTION_FONT_SIZE_PX = 14;
23
24
  const description = {
25
+ color: colors_1.LIGHT_TEXT,
24
26
  fontSize: DESCRIPTION_FONT_SIZE_PX,
27
+ lineHeight: 1.5,
25
28
  maxWidth: 400,
26
29
  };
27
30
  const link = {
@@ -51,7 +54,10 @@ const copyWrapper = {
51
54
  display: 'flex',
52
55
  justifyContent: 'flex-end',
53
56
  };
54
- const OptionExplainer = ({ option }) => {
57
+ const OptionExplainer = ({ option, extraInfoRows = [], showApiOption = true, showCliFlag = true, }) => {
58
+ const shouldShowApiOption = showApiOption && option.ssrName !== null;
59
+ const shouldShowCliFlag = showCliFlag && option.cliFlag !== undefined;
60
+ const hasInfoRows = extraInfoRows.length > 0 || shouldShowCliFlag || shouldShowApiOption;
55
61
  return (jsx_runtime_1.jsxs("div", { style: container, className: "__remotion-info-button-container", children: [
56
62
  jsx_runtime_1.jsxs("div", { style: padding, children: [
57
63
  jsx_runtime_1.jsxs("div", { children: [
@@ -59,19 +65,33 @@ const OptionExplainer = ({ option }) => {
59
65
  jsx_runtime_1.jsx(layout_1.Spacing, { x: 1 }), jsx_runtime_1.jsx("a", { style: link, href: option.docLink, target: "_blank", children: "Docs" })
60
66
  ] })) : null] }), jsx_runtime_1.jsxs("div", { style: description, children: [
61
67
  jsx_runtime_1.jsx("style", { children: `
62
- .__remotion-option-explainer-description a,
63
- .__remotion-option-explainer-description code {
68
+ .__remotion-option-explainer-description,
69
+ .__remotion-option-explainer-description * {
70
+ color: inherit;
64
71
  font-size: ${DESCRIPTION_FONT_SIZE_PX}px;
72
+ line-height: inherit;
73
+ }
74
+
75
+ .__remotion-option-explainer-description a {
76
+ color: ${colors_1.BLUE};
77
+ text-decoration: none;
78
+ }
79
+
80
+ .__remotion-option-explainer-description code {
81
+ color: ${colors_1.BLUE};
82
+ font-family: monospace;
65
83
  }
66
84
  ` }), jsx_runtime_1.jsx("div", { className: "__remotion-option-explainer-description", children: option.description('ssr') })
67
85
  ] })
68
- ] }), jsx_runtime_1.jsx(layout_1.Spacing, { y: 0.5, block: true }), jsx_runtime_1.jsx(MenuDivider_1.MenuDivider, {}), jsx_runtime_1.jsx(layout_1.Spacing, { y: 0.5, block: true }), jsx_runtime_1.jsxs("div", { children: [
69
- jsx_runtime_1.jsxs("div", { style: infoRow, children: [
70
- jsx_runtime_1.jsx("div", { style: infoRowLabel, children: "CLI flag" }), jsx_runtime_1.jsx("div", { style: flexSpacer }), jsx_runtime_1.jsxs("code", { children: ["--", option.cliFlag] }), jsx_runtime_1.jsx("div", { style: copyWrapper, children: jsx_runtime_1.jsx(CliCopyButton_1.CliCopyButton, { valueToCopy: option.cliFlag }) })
71
- ] }), option.ssrName ? (jsx_runtime_1.jsxs("div", { style: infoRow, children: [
72
- jsx_runtime_1.jsx("div", { style: infoRowLabel, children: "Node.JS option" }), jsx_runtime_1.jsx("div", { style: flexSpacer }), jsx_runtime_1.jsx("code", { children: option.ssrName }), jsx_runtime_1.jsx(layout_1.Spacing, { x: 3.75 })
73
- ] })) : null, jsx_runtime_1.jsx("div", { style: infoRow })
74
- ] })
75
- ] }));
86
+ ] }), hasInfoRows ? (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [
87
+ jsx_runtime_1.jsx(layout_1.Spacing, { y: 0.5, block: true }), jsx_runtime_1.jsx(MenuDivider_1.MenuDivider, {}), jsx_runtime_1.jsx(layout_1.Spacing, { y: 0.5, block: true }), jsx_runtime_1.jsxs("div", { children: [extraInfoRows.map((row) => (jsx_runtime_1.jsxs("div", { style: infoRow, children: [
88
+ jsx_runtime_1.jsx("div", { style: infoRowLabel, children: row.label }), jsx_runtime_1.jsx("div", { style: flexSpacer }), jsx_runtime_1.jsx("code", { children: row.value }), jsx_runtime_1.jsx("div", { style: copyWrapper, children: jsx_runtime_1.jsx(CliCopyButton_1.CliCopyButton, { valueToCopy: row.value }) })
89
+ ] }, row.label))), shouldShowCliFlag ? (jsx_runtime_1.jsxs("div", { style: infoRow, children: [
90
+ jsx_runtime_1.jsx("div", { style: infoRowLabel, children: "CLI flag" }), jsx_runtime_1.jsx("div", { style: flexSpacer }), jsx_runtime_1.jsxs("code", { children: ["--", option.cliFlag] }), jsx_runtime_1.jsx("div", { style: copyWrapper, children: jsx_runtime_1.jsx(CliCopyButton_1.CliCopyButton, { valueToCopy: option.cliFlag }) })
91
+ ] })) : null, shouldShowApiOption ? (jsx_runtime_1.jsxs("div", { style: infoRow, children: [
92
+ jsx_runtime_1.jsx("div", { style: infoRowLabel, children: "API option" }), jsx_runtime_1.jsx("div", { style: flexSpacer }), jsx_runtime_1.jsx("code", { children: option.ssrName }), jsx_runtime_1.jsx(layout_1.Spacing, { x: 3.75 })
93
+ ] })) : null, jsx_runtime_1.jsx("div", { style: infoRow })
94
+ ] })
95
+ ] })) : null] }));
76
96
  };
77
97
  exports.OptionExplainer = OptionExplainer;
@@ -1,4 +1,18 @@
1
1
  import type { AvailableOptions } from '@remotion/renderer/client';
2
+ import { type OptionExplainerInfoRow } from './OptionExplainer';
2
3
  export declare const OptionExplainerBubble: React.FC<{
3
- id: AvailableOptions;
4
+ readonly id: AvailableOptions;
5
+ readonly extraInfoRows?: readonly OptionExplainerInfoRow[];
6
+ readonly showApiOption?: boolean;
7
+ readonly showCliFlag?: boolean;
8
+ }>;
9
+ export declare const WebRendererOptionExplainerBubble: React.FC<{
10
+ readonly id: AvailableOptions;
11
+ readonly apiName: string;
12
+ }>;
13
+ export declare const WebRendererCustomOptionExplainerBubble: React.FC<{
14
+ readonly apiName: string;
15
+ readonly description: React.ReactNode;
16
+ readonly docLink: string | null;
17
+ readonly name: string;
4
18
  }>;
@@ -1,12 +1,26 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.OptionExplainerBubble = void 0;
3
+ exports.WebRendererCustomOptionExplainerBubble = exports.WebRendererOptionExplainerBubble = exports.OptionExplainerBubble = void 0;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const client_1 = require("@remotion/renderer/client");
6
6
  const InfoBubble_1 = require("./InfoBubble");
7
7
  const OptionExplainer_1 = require("./OptionExplainer");
8
- const OptionExplainerBubble = ({ id }) => {
8
+ const OptionExplainerBubble = ({ id, extraInfoRows, showApiOption, showCliFlag }) => {
9
9
  const option = client_1.BrowserSafeApis.options[id];
10
- return (jsx_runtime_1.jsx(InfoBubble_1.InfoBubble, { title: "Learn more about this option", children: jsx_runtime_1.jsx(OptionExplainer_1.OptionExplainer, { option: option }) }));
10
+ return (jsx_runtime_1.jsx(InfoBubble_1.InfoBubble, { title: "Learn more about this option", children: jsx_runtime_1.jsx(OptionExplainer_1.OptionExplainer, { extraInfoRows: extraInfoRows, option: option, showApiOption: showApiOption, showCliFlag: showCliFlag }) }));
11
11
  };
12
12
  exports.OptionExplainerBubble = OptionExplainerBubble;
13
+ const WebRendererOptionExplainerBubble = ({ id, apiName }) => {
14
+ return (jsx_runtime_1.jsx(exports.OptionExplainerBubble, { extraInfoRows: [{ label: 'API option', value: apiName }], id: id, showApiOption: false, showCliFlag: false }));
15
+ };
16
+ exports.WebRendererOptionExplainerBubble = WebRendererOptionExplainerBubble;
17
+ const WebRendererCustomOptionExplainerBubble = ({ apiName, description, docLink, name }) => {
18
+ const option = {
19
+ description: () => description,
20
+ docLink,
21
+ name,
22
+ ssrName: null,
23
+ };
24
+ return (jsx_runtime_1.jsx(InfoBubble_1.InfoBubble, { title: "Learn more about this option", children: jsx_runtime_1.jsx(OptionExplainer_1.OptionExplainer, { extraInfoRows: [{ label: 'API option', value: apiName }], option: option, showApiOption: false, showCliFlag: false }) }));
25
+ };
26
+ exports.WebRendererCustomOptionExplainerBubble = WebRendererCustomOptionExplainerBubble;