UNPKG

@remotion/studio

Version:

APIs for interacting with the Remotion Studio

910 lines (909 loc) 39.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.makeSearchResults = exports.useMenuStructure = void 0; const jsx_runtime_1 = require("react/jsx-runtime"); const react_1 = require("react"); const remotion_1 = require("remotion"); const no_react_1 = require("remotion/no-react"); const restart_studio_1 = require("../api/restart-studio"); const AskAiModal_1 = require("../components/AskAiModal"); const layout_1 = require("../components/layout"); const NotificationCenter_1 = require("../components/Notifications/NotificationCenter"); const SizeSelector_1 = require("../components/SizeSelector"); const TimelineInOutToggle_1 = require("../components/TimelineInOutToggle"); const ShortcutHint_1 = require("../error-overlay/remotion-overlay/ShortcutHint"); const Checkmark_1 = require("../icons/Checkmark"); const canvas_ref_1 = require("../state/canvas-ref"); const checkerboard_1 = require("../state/checkerboard"); const editor_guides_1 = require("../state/editor-guides"); const editor_rulers_1 = require("../state/editor-rulers"); const editor_zoom_gestures_1 = require("../state/editor-zoom-gestures"); const modals_1 = require("../state/modals"); const sidebar_1 = require("../state/sidebar"); const check_fullscreen_support_1 = require("./check-fullscreen-support"); const client_id_1 = require("./client-id"); const get_git_menu_item_1 = require("./get-git-menu-item"); const mobile_layout_1 = require("./mobile-layout"); const open_in_editor_1 = require("./open-in-editor"); const pick_color_1 = require("./pick-color"); const show_browser_rendering_1 = require("./show-browser-rendering"); const use_keybinding_1 = require("./use-keybinding"); const openExternal = (link) => { window.open(link, '_blank'); }; const rotate = { transform: `rotate(90deg)`, }; const ICON_SIZE = 16; const getFileMenu = ({ readOnlyStudio, closeMenu, previewServerState, setSelectedModal, }) => { const items = [ window.remotion_isReadOnlyStudio ? { id: 'input-props-override', value: 'input-props-override', label: 'Set input props...', onClick: () => { closeMenu(); setSelectedModal({ type: 'input-props-override', }); }, type: 'item', keyHint: null, leftItem: null, subMenu: null, quickSwitcherLabel: 'Override input props', } : null, readOnlyStudio ? null : { id: 'render', value: 'render', label: 'Render...', onClick: () => { closeMenu(); if (previewServerState !== 'connected') { (0, NotificationCenter_1.showNotification)('Restart the studio to render', 2000); return; } const renderButton = document.getElementById('render-modal-button-server'); renderButton.click(); }, type: 'item', keyHint: 'R', leftItem: null, subMenu: null, quickSwitcherLabel: 'Render...', }, show_browser_rendering_1.SHOW_BROWSER_RENDERING && !readOnlyStudio ? { id: 'render-on-web', value: 'render-on-web', label: 'Render on web...', onClick: () => { closeMenu(); const renderButton = document.getElementById('render-modal-button-client'); renderButton.click(); }, type: 'item', keyHint: null, leftItem: null, subMenu: null, quickSwitcherLabel: 'Render on web...', } : null, window.remotion_editorName && !readOnlyStudio ? { type: 'divider', id: 'open-in-editor-divider', } : null, window.remotion_editorName && !readOnlyStudio ? { id: 'open-in-editor', value: 'open-in-editor', label: `Open in ${window.remotion_editorName}`, onClick: async () => { await (0, open_in_editor_1.openInEditor)({ originalFileName: `${window.remotion_cwd}`, originalLineNumber: 1, originalColumnNumber: 1, originalFunctionName: null, originalScriptCode: null, }) .then((res) => res.json()) .then(({ success }) => { if (!success) { (0, NotificationCenter_1.showNotification)(`Could not open ${window.remotion_editorName}`, 2000); } }) .catch((err) => { // eslint-disable-next-line no-console console.error(err); (0, NotificationCenter_1.showNotification)(`Could not open ${window.remotion_editorName}`, 2000); }); }, type: 'item', keyHint: null, leftItem: null, subMenu: null, quickSwitcherLabel: 'Open in editor...', } : null, (0, get_git_menu_item_1.getGitMenuItem)(), ].filter(no_react_1.NoReactInternals.truthy); if (items.length === 0) { return null; } return { id: 'file', label: 'File', leaveLeftPadding: false, items, quickSwitcherLabel: null, }; }; const useMenuStructure = (closeMenu, readOnlyStudio) => { const { setSelectedModal } = (0, react_1.useContext)(modals_1.ModalsContext); const { checkerboard, setCheckerboard } = (0, react_1.useContext)(checkerboard_1.CheckerboardContext); const { editorZoomGestures, setEditorZoomGestures } = (0, react_1.useContext)(editor_zoom_gestures_1.EditorZoomGesturesContext); const { editorShowRulers, setEditorShowRulers } = (0, react_1.useContext)(editor_rulers_1.EditorShowRulersContext); const { editorShowGuides, setEditorShowGuides } = (0, react_1.useContext)(editor_guides_1.EditorShowGuidesContext); const { size, setSize } = (0, react_1.useContext)(remotion_1.Internals.PreviewSizeContext); const { type } = (0, react_1.useContext)(client_id_1.StudioServerConnectionCtx).previewServerState; const { setSidebarCollapsedState, sidebarCollapsedStateLeft, sidebarCollapsedStateRight, } = (0, react_1.useContext)(sidebar_1.SidebarContext); const sizes = (0, react_1.useMemo)(() => (0, SizeSelector_1.getUniqueSizes)(size), [size]); const isFullscreenSupported = (0, check_fullscreen_support_1.checkFullscreenSupport)(); const { remotion_packageManager } = window; const sizePreselectIndex = sizes.findIndex((s) => String(size.size) === String(s.size)); const mobileLayout = (0, mobile_layout_1.useMobileLayout)(); const structure = (0, react_1.useMemo)(() => { let struct = [ { id: 'remotion', label: (jsx_runtime_1.jsx(layout_1.Row, { align: "center", justify: "center", children: jsx_runtime_1.jsx("svg", { width: ICON_SIZE, height: ICON_SIZE, viewBox: "-100 -100 400 400", style: rotate, children: jsx_runtime_1.jsx("path", { fill: "#fff", stroke: "#fff", strokeWidth: "100", strokeLinejoin: "round", d: "M 2 172 a 196 100 0 0 0 195 5 A 196 240 0 0 0 100 2.259 A 196 240 0 0 0 2 172 z" }) }) })), leaveLeftPadding: false, items: [ { id: 'about', value: 'about', label: 'About Remotion', onClick: () => { closeMenu(); openExternal('https://remotion.dev'); }, type: 'item', keyHint: null, leftItem: null, subMenu: null, quickSwitcherLabel: 'Help: About Remotion', }, { id: 'changelog', value: 'changelog', label: 'Changelog', onClick: () => { closeMenu(); openExternal('https://github.com/remotion-dev/remotion/releases'); }, type: 'item', keyHint: null, leftItem: null, subMenu: null, quickSwitcherLabel: 'Help: Changelog', }, { id: 'license', value: 'license', label: 'License', onClick: () => { closeMenu(); openExternal('https://github.com/remotion-dev/remotion/blob/main/LICENSE.md'); }, type: 'item', keyHint: null, leftItem: null, subMenu: null, quickSwitcherLabel: 'Help: License', }, { id: 'acknowledgements', value: 'acknowledgements', label: 'Acknowledgements', onClick: () => { closeMenu(); openExternal('https://remotion.dev/acknowledgements'); }, type: 'item', keyHint: null, leftItem: null, subMenu: null, quickSwitcherLabel: 'Help: Acknowledgements', }, { type: 'divider', id: 'timeline-divider-1', }, { id: 'restart-studio', value: 'restart-studio', label: 'Restart Studio Server', onClick: () => { closeMenu(); (0, restart_studio_1.restartStudio)(); }, type: 'item', keyHint: null, leftItem: null, subMenu: null, quickSwitcherLabel: 'Restart Studio Server', }, ], quickSwitcherLabel: null, }, getFileMenu({ readOnlyStudio, closeMenu, previewServerState: type, setSelectedModal, }), { id: 'view', label: 'View', leaveLeftPadding: true, items: [ { id: 'preview-size', keyHint: null, label: 'Preview size', onClick: () => undefined, type: 'item', value: 'preview-size', leftItem: null, subMenu: { leaveLeftSpace: true, preselectIndex: sizePreselectIndex, items: sizes.map((newSize) => ({ id: String(newSize.size), keyHint: newSize.size === 1 ? '0' : null, label: (0, SizeSelector_1.getPreviewSizeLabel)(newSize), leftItem: String(newSize.size) === String(size.size) ? (jsx_runtime_1.jsx(Checkmark_1.Checkmark, {})) : null, onClick: () => { closeMenu(); setSize(() => newSize); }, subMenu: null, type: 'item', value: newSize.size, quickSwitcherLabel: null, })), quickSwitcherLabel: null, }, quickSwitcherLabel: null, }, { id: 'editor-zoom-gestures', keyHint: null, label: 'Zoom and Pan Gestures', onClick: () => { closeMenu(); setEditorZoomGestures((c) => !c); }, type: 'item', value: 'editor-zoom-gestures', leftItem: editorZoomGestures ? jsx_runtime_1.jsx(Checkmark_1.Checkmark, {}) : null, subMenu: null, quickSwitcherLabel: editorZoomGestures ? 'Disable Zoom and Pan Gestures' : 'Enable Zoom and Pan Gestures', }, { id: 'show-rulers', keyHint: null, label: 'Show Rulers', onClick: () => { closeMenu(); setEditorShowRulers((c) => !c); }, type: 'item', value: 'show-ruler', leftItem: editorShowRulers ? jsx_runtime_1.jsx(Checkmark_1.Checkmark, {}) : null, subMenu: null, quickSwitcherLabel: editorShowRulers ? 'Hide Rulers' : 'Show Rulers', }, { id: 'show-guides', keyHint: null, label: 'Show Guides', onClick: () => { closeMenu(); setEditorShowGuides((c) => !c); }, type: 'item', value: 'show-guides', leftItem: editorShowGuides ? jsx_runtime_1.jsx(Checkmark_1.Checkmark, {}) : null, subMenu: null, quickSwitcherLabel: editorShowGuides ? 'Hide Guides' : 'Show Guides', }, { id: 'timeline-divider-1', type: 'divider', }, { id: 'left-sidebar', label: 'Left Sidebar', keyHint: null, type: 'item', value: 'preview-size', leftItem: null, quickSwitcherLabel: null, subMenu: { leaveLeftSpace: true, preselectIndex: 0, items: [ { id: 'left-sidebar-responsive', keyHint: null, label: 'Responsive', leftItem: sidebarCollapsedStateLeft === 'responsive' ? (jsx_runtime_1.jsx(Checkmark_1.Checkmark, {})) : null, onClick: () => { closeMenu(); setSidebarCollapsedState({ left: 'responsive', right: null, }); }, subMenu: null, type: 'item', value: 'responsive', quickSwitcherLabel: null, }, { id: 'left-sidebar-expanded', keyHint: null, label: 'Expanded', leftItem: sidebarCollapsedStateLeft === 'expanded' ? (jsx_runtime_1.jsx(Checkmark_1.Checkmark, {})) : null, onClick: () => { closeMenu(); setSidebarCollapsedState({ left: 'expanded', right: null }); }, subMenu: null, type: 'item', value: 'expanded', quickSwitcherLabel: 'Expand', }, { id: 'left-sidebar-collapsed', keyHint: null, label: 'Collapsed', leftItem: sidebarCollapsedStateLeft === 'collapsed' ? (jsx_runtime_1.jsx(Checkmark_1.Checkmark, {})) : null, onClick: () => { closeMenu(); setSidebarCollapsedState({ left: 'collapsed', right: null, }); }, subMenu: null, type: 'item', value: 'collapsed', quickSwitcherLabel: 'Collapse', }, ], }, onClick: () => undefined, }, { id: 'right-sidebar', label: 'Right Sidebar', keyHint: null, type: 'item', value: 'preview-size', leftItem: null, quickSwitcherLabel: null, subMenu: { leaveLeftSpace: true, preselectIndex: 0, items: [ { id: 'sidebar-expanded', keyHint: null, label: 'Expanded', leftItem: sidebarCollapsedStateRight === 'expanded' ? (jsx_runtime_1.jsx(Checkmark_1.Checkmark, {})) : null, onClick: () => { closeMenu(); setSidebarCollapsedState({ left: null, right: 'expanded' }); }, subMenu: null, type: 'item', value: 'expanded', quickSwitcherLabel: 'Expand', }, { id: 'right-sidebar-collapsed', keyHint: null, label: 'Collapsed', leftItem: sidebarCollapsedStateRight === 'collapsed' ? (jsx_runtime_1.jsx(Checkmark_1.Checkmark, {})) : null, onClick: () => { closeMenu(); setSidebarCollapsedState({ left: null, right: 'collapsed', }); }, subMenu: null, type: 'item', value: 'collapsed', quickSwitcherLabel: 'Collapse', }, ], }, onClick: () => undefined, }, { id: 'timeline-divider-2', type: 'divider', }, { id: 'checkerboard', keyHint: 'T', label: 'Transparency as checkerboard', onClick: () => { closeMenu(); setCheckerboard((c) => !c); }, type: 'item', value: 'checkerboard', leftItem: checkerboard ? jsx_runtime_1.jsx(Checkmark_1.Checkmark, {}) : null, subMenu: null, quickSwitcherLabel: checkerboard ? 'Disable Checkerboard Transparency' : 'Enable Checkerboard Transparency', }, { id: 'timeline-divider-3', type: 'divider', }, { id: 'quick-switcher', keyHint: `${ShortcutHint_1.cmdOrCtrlCharacter}+K`, label: 'Quick Switcher', onClick: () => { closeMenu(); setSelectedModal({ type: 'quick-switcher', mode: 'compositions', invocationTimestamp: Date.now(), }); }, type: 'item', value: 'quick-switcher', leftItem: null, subMenu: null, quickSwitcherLabel: 'Switch composition', }, { id: 'in-out-divider-5', type: 'divider', }, { id: 'in-mark', keyHint: 'I', label: 'In Mark', leftItem: null, onClick: () => { var _a; closeMenu(); (_a = TimelineInOutToggle_1.inOutHandles.current) === null || _a === void 0 ? void 0 : _a.inMarkClick(null); }, subMenu: null, type: 'item', value: 'in-mark', quickSwitcherLabel: 'Timeline: Set In Mark', }, { id: 'out-mark', keyHint: 'O', label: 'Out Mark', leftItem: null, onClick: () => { var _a; closeMenu(); (_a = TimelineInOutToggle_1.inOutHandles.current) === null || _a === void 0 ? void 0 : _a.outMarkClick(null); }, subMenu: null, type: 'item', value: 'out-mark', quickSwitcherLabel: 'Timeline: Set Out Mark', }, { id: 'x-mark', keyHint: 'X', label: 'Clear In/Out Marks', leftItem: null, onClick: () => { var _a; closeMenu(); (_a = TimelineInOutToggle_1.inOutHandles.current) === null || _a === void 0 ? void 0 : _a.clearMarks(); }, subMenu: null, type: 'item', value: 'clear-marks', quickSwitcherLabel: 'Timeline: Clear In and Out Mark', }, { id: 'goto-time', keyHint: 'G', label: 'Go to frame', leftItem: null, onClick: () => { var _a; closeMenu(); (_a = remotion_1.Internals.timeValueRef.current) === null || _a === void 0 ? void 0 : _a.goToFrame(); }, subMenu: null, type: 'item', value: 'clear-marks', quickSwitcherLabel: 'Timeline: Go to frame', }, { id: 'fullscreen-divider', type: 'divider', }, isFullscreenSupported ? { id: 'fullscreen', keyHint: null, label: 'Fullscreen', leftItem: null, onClick: () => { var _a; closeMenu(); (_a = canvas_ref_1.drawRef.current) === null || _a === void 0 ? void 0 : _a.requestFullscreen(); }, subMenu: null, type: 'item', value: 'fullscreen', quickSwitcherLabel: 'Go Fullscreen', } : null, ].filter(remotion_1.Internals.truthy), }, { id: 'tools', label: 'Tools', leaveLeftPadding: false, items: [ process.env.ASK_AI_ENABLED ? { id: 'ask-ai', value: 'ask-ai', label: 'Ask AI', onClick: () => { var _a; closeMenu(); (_a = AskAiModal_1.askAiModalRef.current) === null || _a === void 0 ? void 0 : _a.toggle(); }, leftItem: null, keyHint: `${ShortcutHint_1.cmdOrCtrlCharacter}+I`, subMenu: null, type: 'item', quickSwitcherLabel: 'Ask AI', } : null, 'EyeDropper' in window ? { id: 'color-picker', value: 'color-picker', label: 'Color Picker', onClick: () => { closeMenu(); (0, pick_color_1.pickColor)(); }, leftItem: null, keyHint: null, subMenu: null, type: 'item', quickSwitcherLabel: 'Show Color Picker', } : null, { id: 'spring-editor', value: 'spring-editor', label: 'Timing Editor', onClick: () => { closeMenu(); window.open('https://www.remotion.dev/timing-editor', '_blank'); }, leftItem: null, keyHint: null, subMenu: null, type: 'item', quickSwitcherLabel: 'Open spring() Editor', }, ].filter(remotion_1.Internals.truthy), quickSwitcherLabel: null, }, readOnlyStudio || remotion_packageManager === 'unknown' ? null : { id: 'install', label: 'Packages', leaveLeftPadding: false, items: [ { id: 'install-packages', value: 'install-packages', label: 'Install...', onClick: () => { closeMenu(); setSelectedModal({ type: 'install-packages', packageManager: remotion_packageManager, }); }, type: 'item', keyHint: null, leftItem: null, subMenu: null, quickSwitcherLabel: `Install packages`, }, ], }, { id: 'help', label: 'Help', leaveLeftPadding: false, items: [ { id: 'shortcuts', value: 'shortcuts', label: (0, use_keybinding_1.areKeyboardShortcutsDisabled)() ? 'Shortcuts (disabled)' : 'Shortcuts', onClick: () => { closeMenu(); setSelectedModal({ type: 'quick-switcher', mode: 'docs', invocationTimestamp: Date.now(), }); }, keyHint: '?', leftItem: null, subMenu: null, type: 'item', quickSwitcherLabel: (0, use_keybinding_1.areKeyboardShortcutsDisabled)() ? 'Show all Keyboard Shortcuts (disabled)' : 'Show all Keyboard Shortcuts', }, { id: 'docs', value: 'docs', label: 'Docs', onClick: () => { closeMenu(); openExternal('https://remotion.dev/docs'); }, type: 'item', keyHint: null, leftItem: null, subMenu: null, quickSwitcherLabel: 'Visit Documentation', }, { id: 'file-issue', value: 'file-issue', label: 'File an issue', onClick: () => { closeMenu(); openExternal('https://github.com/remotion-dev/remotion/issues/new/choose'); }, type: 'item', keyHint: null, leftItem: null, subMenu: null, quickSwitcherLabel: 'File GitHub issue', }, { id: 'discord', value: 'discord', label: 'Join Discord community', onClick: () => { closeMenu(); openExternal('https://discord.com/invite/6VzzNDwUwV'); }, type: 'item', keyHint: null, leftItem: null, subMenu: null, quickSwitcherLabel: null, }, { id: 'help-divider-6', type: 'divider', }, { id: 'insta', value: 'insta', label: 'Instagram', onClick: () => { closeMenu(); openExternal('https://instagram.com/remotion'); }, type: 'item', keyHint: null, leftItem: null, subMenu: null, quickSwitcherLabel: 'Follow Remotion on Instagram', }, { id: 'x', value: 'x', label: 'X', onClick: () => { closeMenu(); openExternal('https://x.com/remotion'); }, type: 'item', keyHint: null, leftItem: null, subMenu: null, quickSwitcherLabel: 'Follow Remotion on X', }, { id: 'youtube', value: 'youtube', label: 'YouTube', onClick: () => { closeMenu(); openExternal('https://www.youtube.com/@remotion_dev'); }, type: 'item', keyHint: null, leftItem: null, subMenu: null, quickSwitcherLabel: 'Watch Remotion on YouTube', }, { id: 'linkedin', value: 'linkedin', label: 'LinkedIn', onClick: () => { closeMenu(); openExternal('https://www.linkedin.com/company/remotion-dev/'); }, type: 'item', keyHint: null, leftItem: null, subMenu: null, quickSwitcherLabel: 'Follow Remotion on LinkedIn', }, { id: 'tiktok', value: 'tiktok', label: 'TikTok', onClick: () => { closeMenu(); openExternal('https://www.tiktok.com/@remotion'); }, type: 'item', keyHint: null, leftItem: null, subMenu: null, quickSwitcherLabel: 'Follow Remotion on TikTok', }, ], }, ].filter(remotion_1.Internals.truthy); if (mobileLayout) { struct = [ { ...struct[0], items: [ ...struct.slice(1).map((s) => { return { ...s, keyHint: null, onClick: () => undefined, type: 'item', value: s.id, leftItem: null, subMenu: { items: s.items, leaveLeftSpace: true, preselectIndex: 0, }, quickSwitcherLabel: null, }; }), ...struct[0].items, ], }, ]; } return struct; }, [ readOnlyStudio, closeMenu, type, sizePreselectIndex, sizes, editorZoomGestures, editorShowRulers, editorShowGuides, sidebarCollapsedStateLeft, sidebarCollapsedStateRight, checkerboard, isFullscreenSupported, remotion_packageManager, mobileLayout, size.size, setSize, setEditorZoomGestures, setEditorShowRulers, setEditorShowGuides, setSidebarCollapsedState, setCheckerboard, setSelectedModal, ]); return structure; }; exports.useMenuStructure = useMenuStructure; const getItemLabel = (item) => { var _a; if (item.quickSwitcherLabel !== null) { return item.quickSwitcherLabel; } if (typeof item.label === 'string') { return item.label; } return (_a = item.label) === null || _a === void 0 ? void 0 : _a.toString(); }; const itemToSearchResult = (item, setSelectedModal, prefixes) => { if (item.subMenu) { return item.subMenu.items .map((subItem) => { if (subItem.type === 'divider') { return null; } return itemToSearchResult(subItem, setSelectedModal, [ ...prefixes, getItemLabel(item), ]); }) .flat(1) .filter(no_react_1.NoReactInternals.truthy); } return [ { type: 'menu-item', id: item.id, onSelected: () => { setSelectedModal(null); item.onClick(item.id, null); }, title: [...prefixes, getItemLabel(item)].join(': '), }, ]; }; const makeSearchResults = (actions, setSelectedModal) => { const items = actions .map((menu) => { return menu.items.map((item) => { if (item.type === 'divider') { return null; } return itemToSearchResult(item, setSelectedModal, []); }); }) .flat(Infinity) .filter(no_react_1.NoReactInternals.truthy); return items; }; exports.makeSearchResults = makeSearchResults;