Add .gitignore to exclude all node packages and lock files

This commit is contained in:
Adolfo Reyna
2026-02-23 21:56:04 -05:00
parent faae96c9ed
commit dcc5c6c044
9747 changed files with 1555105 additions and 2 deletions
@@ -0,0 +1,7 @@
import React from 'react';
type AskAiModalRef = {
toggle: () => void;
};
export declare const askAiModalRef: React.RefObject<AskAiModalRef | null>;
export declare const AskAiModal: React.FC;
export {};
@@ -0,0 +1,68 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AskAiModal = exports.askAiModalRef = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const react_1 = require("react");
const remotion_1 = require("remotion");
const ModalContainer_1 = require("./ModalContainer");
const ModalHeader_1 = require("./ModalHeader");
const container = {
height: 'calc(100vh - 100px)',
width: 'calc(100vw - 160px)',
maxWidth: 800,
maxHeight: 900,
display: 'block',
};
exports.askAiModalRef = (0, react_1.createRef)();
const AskAiModal = () => {
const [state, setState] = (0, react_1.useState)('never-opened');
const iframe = (0, react_1.useRef)(null);
(0, react_1.useImperativeHandle)(exports.askAiModalRef, () => ({
toggle: () => {
setState((s) => {
var _a, _b, _c;
if (s === 'visible') {
(_a = iframe.current) === null || _a === void 0 ? void 0 : _a.blur();
(_c = (_b = iframe.current) === null || _b === void 0 ? void 0 : _b.contentWindow) === null || _c === void 0 ? void 0 : _c.blur();
}
return s === 'visible' ? 'hidden' : 'visible';
});
},
}), []);
(0, react_1.useEffect)(() => {
const onMessage = (event) => {
var _a;
try {
const json = typeof event.data === 'string' ? JSON.parse(event.data) : event.data;
if (json.type === 'cmd-i') {
(_a = exports.askAiModalRef.current) === null || _a === void 0 ? void 0 : _a.toggle();
}
}
catch (_b) { }
};
window.addEventListener('message', onMessage);
return () => {
window.removeEventListener('message', onMessage);
};
}, []);
const onQuit = (0, react_1.useCallback)(() => {
setState('hidden');
}, [setState]);
// When re-toggling the modal, focus the text box
(0, react_1.useEffect)(() => {
var _a;
if (!iframe.current) {
return;
}
if (state === 'visible') {
(_a = iframe.current.contentWindow) === null || _a === void 0 ? void 0 : _a.postMessage({
type: 'focus',
}, '*');
}
}, [state]);
if (state === 'never-opened') {
return null;
}
return ((0, jsx_runtime_1.jsx)(remotion_1.AbsoluteFill, { style: { display: state === 'visible' ? 'block' : 'none' }, children: (0, jsx_runtime_1.jsxs)(ModalContainer_1.ModalContainer, { noZIndex: state === 'hidden', onOutsideClick: onQuit, onEscape: onQuit, children: [(0, jsx_runtime_1.jsx)(ModalHeader_1.ModalHeader, { title: "Ask AI", onClose: onQuit }), (0, jsx_runtime_1.jsx)("iframe", { ref: iframe, frameBorder: 0, style: container, src: "https://www.remotion.dev/ai-embed", allow: "clipboard-read; clipboard-write" })] }) }));
};
exports.AskAiModal = AskAiModal;
@@ -0,0 +1,4 @@
import React from 'react';
export declare const AssetSelector: React.FC<{
readonly readOnlyStudio: boolean;
}>;
@@ -0,0 +1,165 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AssetSelector = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const react_1 = __importStar(require("react"));
const get_static_files_1 = require("../api/get-static-files");
const write_static_file_1 = require("../api/write-static-file");
const client_id_1 = require("../helpers/client-id");
const colors_1 = require("../helpers/colors");
const create_folder_tree_1 = require("../helpers/create-folder-tree");
const persist_open_folders_1 = require("../helpers/persist-open-folders");
const use_asset_drag_events_1 = __importDefault(require("../helpers/use-asset-drag-events"));
const folders_1 = require("../state/folders");
const z_index_1 = require("../state/z-index");
const AssetSelectorItem_1 = require("./AssetSelectorItem");
const styles_1 = require("./Menu/styles");
const NotificationCenter_1 = require("./Notifications/NotificationCenter");
const container = {
display: 'flex',
flexDirection: 'column',
flex: 1,
overflow: 'hidden',
backgroundColor: colors_1.BACKGROUND,
};
// Some redundancy with packages/cli/src/editor/components/RenderModal/SchemaEditor/SchemaErrorMessages.tsx
const emptyState = {
display: 'flex',
flex: 1,
justifyContent: 'center',
alignItems: 'center',
textAlign: 'center',
padding: '0 12px',
};
const label = {
color: colors_1.LIGHT_TEXT,
lineHeight: 1.5,
fontSize: 14,
};
const list = {
height: '100%',
overflowY: 'auto',
};
const AssetSelector = ({ readOnlyStudio }) => {
const { tabIndex } = (0, z_index_1.useZIndex)();
const { assetFoldersExpanded, setAssetFoldersExpanded } = (0, react_1.useContext)(folders_1.FolderContext);
const [dropLocation, setDropLocation] = (0, react_1.useState)(null);
const { subscribeToEvent } = (0, react_1.useContext)(client_id_1.StudioServerConnectionCtx);
const connectionStatus = (0, react_1.useContext)(client_id_1.StudioServerConnectionCtx)
.previewServerState.type;
const shouldAllowUpload = connectionStatus === 'connected' && !readOnlyStudio;
const [{ publicFolderExists, staticFiles }, setState] = react_1.default.useState(() => {
return {
staticFiles: (0, get_static_files_1.getStaticFiles)(),
publicFolderExists: window.remotion_publicFolderExists,
};
});
const assetTree = (0, react_1.useMemo)(() => {
return (0, create_folder_tree_1.buildAssetFolderStructure)(staticFiles, null, assetFoldersExpanded);
}, [assetFoldersExpanded, staticFiles]);
(0, react_1.useEffect)(() => {
const onUpdate = () => {
setState({
staticFiles: (0, get_static_files_1.getStaticFiles)(),
publicFolderExists: window.remotion_publicFolderExists,
});
};
const unsub = subscribeToEvent('new-public-folder', onUpdate);
return () => {
unsub();
};
}, [subscribeToEvent]);
const toggleFolder = (0, react_1.useCallback)((folderName, parentName) => {
setAssetFoldersExpanded((p) => {
var _a;
const key = [parentName, folderName].filter(Boolean).join('/');
const prev = (_a = p[key]) !== null && _a !== void 0 ? _a : false;
const foldersExpandedState = {
...p,
[key]: !prev,
};
(0, persist_open_folders_1.persistExpandedFolders)('assets', foldersExpandedState);
return foldersExpandedState;
});
}, [setAssetFoldersExpanded]);
const { isDropDiv, onDragEnter, onDragLeave } = (0, use_asset_drag_events_1.default)({
name: null,
parentFolder: null,
dropLocation,
setDropLocation,
});
const onDragOver = (0, react_1.useCallback)((e) => {
e.preventDefault();
}, []);
const onDrop = (0, react_1.useCallback)(async (e) => {
try {
e.preventDefault();
e.stopPropagation();
const { files } = e.dataTransfer;
const assetPath = dropLocation !== null && dropLocation !== void 0 ? dropLocation : null;
const makePath = (file) => {
return [assetPath, file.name].filter(Boolean).join('/');
};
for (const file of files) {
const body = await file.arrayBuffer();
await (0, write_static_file_1.writeStaticFile)({
contents: body,
filePath: makePath(file),
});
}
if (files.length === 1) {
(0, NotificationCenter_1.showNotification)(`Created ${makePath(files[0])}`, 3000);
}
else {
(0, NotificationCenter_1.showNotification)(`Added ${files.length} files to ${assetPath}`, 3000);
}
}
catch (error) {
(0, NotificationCenter_1.showNotification)(`Error during upload: ${error}`, 3000);
}
finally {
setDropLocation(null);
}
}, [dropLocation]);
return ((0, jsx_runtime_1.jsx)("div", { style: container, onDragOver: shouldAllowUpload ? onDragOver : undefined, onDrop: shouldAllowUpload ? onDrop : undefined, children: staticFiles.length === 0 ? (publicFolderExists ? ((0, jsx_runtime_1.jsx)("div", { style: emptyState, children: (0, jsx_runtime_1.jsxs)("div", { style: label, children: ["To add assets, place a file in the", ' ', (0, jsx_runtime_1.jsx)("code", { style: styles_1.inlineCodeSnippet, children: "public" }), " folder of your project or drag and drop a file here."] }) })) : ((0, jsx_runtime_1.jsx)("div", { style: emptyState, children: (0, jsx_runtime_1.jsxs)("div", { style: label, children: ["To add assets, create a folder called", ' ', (0, jsx_runtime_1.jsx)("code", { style: styles_1.inlineCodeSnippet, children: "public" }), " in the root of your project and place a file in it."] }) }))) : ((0, jsx_runtime_1.jsx)("div", { className: "__remotion-vertical-scrollbar", style: {
...list,
backgroundColor: isDropDiv ? colors_1.CLEAR_HOVER : colors_1.BACKGROUND,
}, onDragEnter: onDragEnter, onDragLeave: onDragLeave, children: (0, jsx_runtime_1.jsx)(AssetSelectorItem_1.AssetFolderTree, { item: assetTree, level: 0, parentFolder: null, name: null, tabIndex: tabIndex, toggleFolder: toggleFolder, dropLocation: dropLocation, setDropLocation: setDropLocation }) })) }));
};
exports.AssetSelector = AssetSelector;
@@ -0,0 +1,12 @@
import React from 'react';
import type { AssetStructure } from '../helpers/create-folder-tree';
export declare const AssetFolderTree: React.FC<{
readonly item: AssetStructure;
readonly name: string | null;
readonly parentFolder: string | null;
readonly level: number;
readonly tabIndex: number;
readonly toggleFolder: (folderName: string, parentName: string | null) => void;
readonly dropLocation: string | null;
readonly setDropLocation: React.Dispatch<React.SetStateAction<string | null>>;
}>;
@@ -0,0 +1,237 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AssetFolderTree = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const react_1 = __importStar(require("react"));
const remotion_1 = require("remotion");
const no_react_1 = require("remotion/no-react");
const colors_1 = require("../helpers/colors");
const copy_text_1 = require("../helpers/copy-text");
const mobile_layout_1 = require("../helpers/mobile-layout");
const url_state_1 = require("../helpers/url-state");
const use_asset_drag_events_1 = __importDefault(require("../helpers/use-asset-drag-events"));
const clipboard_1 = require("../icons/clipboard");
const file_1 = require("../icons/file");
const folder_1 = require("../icons/folder");
const sidebar_1 = require("../state/sidebar");
const InlineAction_1 = require("./InlineAction");
const NotificationCenter_1 = require("./Notifications/NotificationCenter");
const actions_1 = require("./RenderQueue/actions");
const layout_1 = require("./layout");
const ASSET_ITEM_HEIGHT = 32;
const iconStyle = {
width: 18,
height: 18,
flexShrink: 0,
};
const itemStyle = {
paddingRight: 10,
paddingTop: 6,
paddingBottom: 6,
fontSize: 13,
display: 'flex',
textDecoration: 'none',
cursor: 'default',
alignItems: 'center',
marginBottom: 1,
appearance: 'none',
border: 'none',
width: '100%',
textAlign: 'left',
backgroundColor: colors_1.BACKGROUND,
height: ASSET_ITEM_HEIGHT,
userSelect: 'none',
WebkitUserSelect: 'none',
};
const labelStyle = {
textAlign: 'left',
textDecoration: 'none',
fontSize: 13,
flex: '1 1 0%',
whiteSpace: 'nowrap',
overflow: 'hidden',
textOverflow: 'ellipsis',
};
const revealIconStyle = {
height: 12,
color: 'currentColor',
};
const AssetFolderItem = ({ tabIndex, item, level, parentFolder, toggleFolder, dropLocation, setDropLocation, }) => {
const [hovered, setHovered] = (0, react_1.useState)(false);
const openFolderTimerRef = (0, react_1.useRef)(null);
const { isDropDiv, onDragEnter, onDragLeave } = (0, use_asset_drag_events_1.default)({
name: item.name,
parentFolder,
dropLocation,
setDropLocation,
});
const onPointerEnter = (0, react_1.useCallback)(() => {
setHovered(true);
}, []);
const onPointerLeave = (0, react_1.useCallback)(() => {
setHovered(false);
}, []);
const folderStyle = (0, react_1.useMemo)(() => {
return {
...itemStyle,
paddingLeft: 4 + level * 8,
backgroundColor: hovered ? colors_1.CLEAR_HOVER : 'transparent',
};
}, [hovered, level]);
const label = (0, react_1.useMemo)(() => {
return {
...labelStyle,
color: hovered ? 'white' : colors_1.LIGHT_TEXT,
};
}, [hovered]);
const onClick = (0, react_1.useCallback)(() => {
toggleFolder(item.name, parentFolder);
}, [item.name, parentFolder, toggleFolder]);
const Icon = item.expanded ? folder_1.ExpandedFolderIcon : folder_1.CollapsedFolderIcon;
return ((0, jsx_runtime_1.jsxs)("div", { onDragEnter: onDragEnter, onDragLeave: onDragLeave, style: {
backgroundColor: isDropDiv ? colors_1.CLEAR_HOVER : colors_1.BACKGROUND,
}, children: [(0, jsx_runtime_1.jsx)("div", { style: folderStyle, onPointerEnter: onPointerEnter, onPointerLeave: onPointerLeave, tabIndex: tabIndex, title: item.name, onClick: onClick, onDragEnter: () => {
if (!item.expanded) {
openFolderTimerRef.current = window.setTimeout(() => {
toggleFolder(item.name, parentFolder);
}, 1000);
}
}, onDragLeave: () => {
if (openFolderTimerRef.current) {
clearTimeout(openFolderTimerRef.current);
}
}, children: (0, jsx_runtime_1.jsxs)(layout_1.Row, { children: [(0, jsx_runtime_1.jsx)(Icon, { style: iconStyle, color: hovered ? 'white' : colors_1.LIGHT_TEXT }), (0, jsx_runtime_1.jsx)(layout_1.Spacing, { x: 1 }), (0, jsx_runtime_1.jsx)("div", { style: label, children: item.name })] }) }), item.expanded ? ((0, jsx_runtime_1.jsx)(exports.AssetFolderTree, { item: item.items, name: item.name, level: level, parentFolder: parentFolder, tabIndex: tabIndex, toggleFolder: toggleFolder, dropLocation: dropLocation, setDropLocation: setDropLocation }, item.name)) : null] }));
};
const AssetFolderTree = ({ item, level, name, parentFolder, toggleFolder, tabIndex, dropLocation, setDropLocation, }) => {
const combinedParents = (0, react_1.useMemo)(() => {
return [parentFolder, name].filter(no_react_1.NoReactInternals.truthy).join('/');
}, [name, parentFolder]);
return ((0, jsx_runtime_1.jsxs)("div", { children: [item.folders.map((folder) => {
return ((0, jsx_runtime_1.jsx)(AssetFolderItem, { item: folder, tabIndex: tabIndex, level: level + 1, parentFolder: combinedParents, toggleFolder: toggleFolder, dropLocation: dropLocation, setDropLocation: setDropLocation }, folder.name));
}), item.files.map((file) => {
return ((0, jsx_runtime_1.jsx)(AssetSelectorItem, { item: file, tabIndex: tabIndex, level: level, parentFolder: combinedParents }, file.src));
})] }));
};
exports.AssetFolderTree = AssetFolderTree;
const AssetSelectorItem = ({ item, tabIndex, level, parentFolder }) => {
const isMobileLayout = (0, mobile_layout_1.useMobileLayout)();
const [hovered, setHovered] = (0, react_1.useState)(false);
const { setSidebarCollapsedState } = (0, react_1.useContext)(sidebar_1.SidebarContext);
const onPointerEnter = (0, react_1.useCallback)(() => {
setHovered(true);
}, []);
const { setCanvasContent } = (0, react_1.useContext)(remotion_1.Internals.CompositionSetters);
const { canvasContent } = (0, react_1.useContext)(remotion_1.Internals.CompositionManager);
const selected = (0, react_1.useMemo)(() => {
if (canvasContent && canvasContent.type === 'asset') {
const nameWOParent = canvasContent.asset.split('/').pop();
return nameWOParent === item.name;
}
return false;
}, [canvasContent, item.name]);
const onPointerLeave = (0, react_1.useCallback)(() => {
setHovered(false);
}, []);
const onClick = (0, react_1.useCallback)(() => {
const relativePath = parentFolder
? parentFolder + '/' + item.name
: item.name;
setCanvasContent({ type: 'asset', asset: relativePath });
(0, url_state_1.pushUrl)(`/assets/${relativePath}`);
if (isMobileLayout) {
setSidebarCollapsedState({ left: 'collapsed', right: 'collapsed' });
}
}, [
isMobileLayout,
item.name,
parentFolder,
setCanvasContent,
setSidebarCollapsedState,
]);
const style = (0, react_1.useMemo)(() => {
return {
...itemStyle,
color: hovered || selected ? 'white' : colors_1.LIGHT_TEXT,
backgroundColor: hovered
? selected
? colors_1.SELECTED_BACKGROUND
: colors_1.CLEAR_HOVER
: selected
? colors_1.SELECTED_BACKGROUND
: 'transparent',
paddingLeft: 12 + level * 8,
};
}, [hovered, level, selected]);
const label = (0, react_1.useMemo)(() => {
return {
...labelStyle,
color: hovered || selected ? 'white' : colors_1.LIGHT_TEXT,
};
}, [hovered, selected]);
const renderFileExplorerAction = (0, react_1.useCallback)((color) => {
return (0, jsx_runtime_1.jsx)(folder_1.ExpandedFolderIcon, { style: revealIconStyle, color: color });
}, []);
const renderCopyAction = (0, react_1.useCallback)((color) => {
return (0, jsx_runtime_1.jsx)(clipboard_1.ClipboardIcon, { style: revealIconStyle, color: color });
}, []);
const revealInExplorer = react_1.default.useCallback((e) => {
e.stopPropagation();
(0, actions_1.openInFileExplorer)({
directory: window.remotion_publicFolderExists +
'/' +
parentFolder +
'/' +
item.name,
}).catch((err) => {
(0, NotificationCenter_1.showNotification)(`Could not open file: ${err.message}`, 2000);
});
}, [item.name, parentFolder]);
const copyToClipboard = (0, react_1.useCallback)((e) => {
e.stopPropagation();
const content = `staticFile("${[parentFolder, item.name].join('/')}")`;
(0, copy_text_1.copyText)(content)
.then(() => {
(0, NotificationCenter_1.showNotification)(`Copied '${content}' to clipboard`, 1000);
})
.catch((err) => {
(0, NotificationCenter_1.showNotification)(`Could not copy: ${err.message}`, 2000);
});
}, [item.name, parentFolder]);
return ((0, jsx_runtime_1.jsx)(layout_1.Row, { align: "center", children: (0, jsx_runtime_1.jsxs)("div", { style: style, onPointerEnter: onPointerEnter, onPointerLeave: onPointerLeave, onClick: onClick, tabIndex: tabIndex, title: item.name, children: [(0, jsx_runtime_1.jsx)(file_1.FileIcon, { style: iconStyle, color: colors_1.LIGHT_TEXT }), (0, jsx_runtime_1.jsx)(layout_1.Spacing, { x: 1 }), (0, jsx_runtime_1.jsx)("div", { style: label, children: item.name }), hovered ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(layout_1.Spacing, { x: 0.5 }), (0, jsx_runtime_1.jsx)(InlineAction_1.InlineAction, { title: "Copy staticFile() name", renderAction: renderCopyAction, onClick: copyToClipboard }), (0, jsx_runtime_1.jsx)(layout_1.Spacing, { x: 0.5 }), (0, jsx_runtime_1.jsx)(InlineAction_1.InlineAction, { title: "Open in Explorer", renderAction: renderFileExplorerAction, onClick: revealInExplorer })] })) : null] }) }));
};
@@ -0,0 +1,10 @@
import React from 'react';
export declare const AudioWaveform: React.FC<{
readonly src: string;
readonly visualizationWidth: number;
readonly startFrom: number;
readonly durationInFrames: number;
readonly volume: string | number;
readonly doesVolumeChange: boolean;
readonly playbackRate: number;
}>;
@@ -0,0 +1,122 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AudioWaveform = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const media_utils_1 = require("@remotion/media-utils");
const react_1 = require("react");
const remotion_1 = require("remotion");
const colors_1 = require("../helpers/colors");
const timeline_layout_1 = require("../helpers/timeline-layout");
const AudioWaveformBar_1 = require("./AudioWaveformBar");
const container = {
display: 'flex',
flexDirection: 'row',
alignItems: 'flex-end',
position: 'absolute',
height: (0, timeline_layout_1.getTimelineLayerHeight)('other'),
};
const errorMessage = {
fontSize: 13,
paddingTop: 6,
paddingBottom: 6,
paddingLeft: 12,
paddingRight: 12,
alignSelf: 'flex-start',
maxWidth: 450,
opacity: 0.75,
};
const canvasStyle = {
position: 'absolute',
};
const AudioWaveform = ({ src, startFrom, durationInFrames, visualizationWidth, volume, doesVolumeChange, playbackRate, }) => {
const [metadata, setMetadata] = (0, react_1.useState)(null);
const [error, setError] = (0, react_1.useState)(null);
const mountState = (0, react_1.useRef)({ isMounted: true });
const vidConf = remotion_1.Internals.useUnsafeVideoConfig();
if (vidConf === null) {
throw new Error('Expected video config');
}
const canvas = (0, react_1.useRef)(null);
(0, react_1.useEffect)(() => {
const { current } = mountState;
current.isMounted = true;
return () => {
current.isMounted = false;
};
}, []);
(0, react_1.useEffect)(() => {
if (!canvas.current) {
return;
}
const context = canvas.current.getContext('2d');
if (!context) {
return;
}
context.clearRect(0, 0, visualizationWidth, (0, timeline_layout_1.getTimelineLayerHeight)('other'));
if (!doesVolumeChange || typeof volume === 'number') {
// The volume is a number, meaning it could change on each frame-
// User did not use the (f: number) => number syntax, so we can't draw
// a visualization.
return;
}
const volumes = volume.split(',').map((v) => Number(v));
context.beginPath();
context.moveTo(0, (0, timeline_layout_1.getTimelineLayerHeight)('other'));
volumes.forEach((v, index) => {
const x = (index / (volumes.length - 1)) * visualizationWidth;
const y = (1 - v) * ((0, timeline_layout_1.getTimelineLayerHeight)('other') - timeline_layout_1.TIMELINE_BORDER * 2) + 1;
if (index === 0) {
context.moveTo(x, y);
}
else {
context.lineTo(x, y);
}
});
context.strokeStyle = colors_1.LIGHT_TRANSPARENT;
context.stroke();
}, [visualizationWidth, metadata, startFrom, volume, doesVolumeChange]);
(0, react_1.useEffect)(() => {
setError(null);
(0, media_utils_1.getAudioData)(src)
.then((data) => {
if (mountState.current.isMounted) {
setMetadata(data);
}
})
.catch((err) => {
if (mountState.current.isMounted) {
setError(err);
}
});
}, [src, vidConf.fps]);
const normalized = (0, react_1.useMemo)(() => {
if (!metadata || metadata.numberOfChannels === 0) {
return [];
}
const numberOfSamples = Math.floor(visualizationWidth / (AudioWaveformBar_1.WAVEFORM_BAR_LENGTH + AudioWaveformBar_1.WAVEFORM_BAR_MARGIN));
return (0, media_utils_1.getWaveformPortion)({
audioData: metadata,
startTimeInSeconds: startFrom / vidConf.fps,
durationInSeconds: Math.min((durationInFrames / vidConf.fps) * playbackRate, metadata.durationInSeconds),
numberOfSamples,
normalize: false,
});
}, [
durationInFrames,
vidConf.fps,
metadata,
playbackRate,
startFrom,
visualizationWidth,
]);
if (error) {
return ((0, jsx_runtime_1.jsx)("div", { style: container, children: (0, jsx_runtime_1.jsx)("div", { style: errorMessage, children: "No waveform available. Audio might not support CORS." }) }));
}
if (!metadata) {
return null;
}
return ((0, jsx_runtime_1.jsxs)("div", { style: container, children: [normalized.map((w) => {
return ((0, jsx_runtime_1.jsx)(AudioWaveformBar_1.AudioWaveformBar, { amplitude: w.amplitude * (typeof volume === 'number' ? volume : 1) }, w.index));
}), (0, jsx_runtime_1.jsx)("canvas", { ref: canvas, style: canvasStyle, width: visualizationWidth, height: (0, timeline_layout_1.getTimelineLayerHeight)('other') })] }));
};
exports.AudioWaveform = AudioWaveform;
@@ -0,0 +1,14 @@
import React from 'react';
export declare const WAVEFORM_BAR_LENGTH = 2;
export declare const WAVEFORM_BAR_MARGIN = 1;
/**
*
* consider a sinus wave with an amplitude going from [-1, 1].
* if we sample it infinitely, and convert all negative samples from negative to positive
* what is the average of all samples?
*
* Answer: 2 / Math.PI = 0.6366
*/
export declare const AudioWaveformBar: React.FC<{
readonly amplitude: number;
}>;
@@ -0,0 +1,33 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AudioWaveformBar = exports.WAVEFORM_BAR_MARGIN = exports.WAVEFORM_BAR_LENGTH = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const react_1 = require("react");
const timeline_layout_1 = require("../helpers/timeline-layout");
exports.WAVEFORM_BAR_LENGTH = 2;
exports.WAVEFORM_BAR_MARGIN = 1;
const container = {
width: exports.WAVEFORM_BAR_LENGTH,
backgroundColor: 'rgba(255, 255, 255, 0.6)',
marginLeft: exports.WAVEFORM_BAR_MARGIN,
borderRadius: 2,
};
// Sonnet:
/**
*
* consider a sinus wave with an amplitude going from [-1, 1].
* if we sample it infinitely, and convert all negative samples from negative to positive
* what is the average of all samples?
*
* Answer: 2 / Math.PI = 0.6366
*/
const AudioWaveformBar = ({ amplitude }) => {
const style = (0, react_1.useMemo)(() => {
return {
...container,
height: (0, timeline_layout_1.getTimelineLayerHeight)('other') * amplitude * (1 / 0.6366),
};
}, [amplitude]);
return (0, jsx_runtime_1.jsx)("div", { style: style });
};
exports.AudioWaveformBar = AudioWaveformBar;
@@ -0,0 +1,12 @@
import React from 'react';
export type ButtonProps = {
readonly onClick: () => void;
readonly disabled?: boolean;
readonly children: React.ReactNode;
readonly style?: React.CSSProperties;
readonly buttonContainerStyle?: React.CSSProperties;
readonly autoFocus?: boolean;
readonly title?: string;
readonly id?: string;
};
export declare const Button: React.ForwardRefExoticComponent<ButtonProps & React.RefAttributes<HTMLButtonElement>>;
@@ -0,0 +1,35 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Button = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const react_1 = require("react");
const colors_1 = require("../helpers/colors");
const button = {
border: `1px solid ${colors_1.INPUT_BORDER_COLOR_UNHOVERED}`,
borderRadius: 4,
backgroundColor: colors_1.INPUT_BACKGROUND,
appearance: 'none',
fontFamily: 'inherit',
fontSize: 14,
color: 'white',
flexDirection: 'row',
};
const ButtonRefForwardFunction = ({ children, onClick, title, disabled, style, id, autoFocus, buttonContainerStyle, }, ref) => {
const combined = (0, react_1.useMemo)(() => {
return {
...button,
...(style !== null && style !== void 0 ? style : {}),
};
}, [style]);
const buttonContainer = (0, react_1.useMemo)(() => {
return {
padding: 10,
cursor: disabled ? 'inherit' : 'pointer',
fontSize: 14,
opacity: disabled ? 0.7 : 1,
...(buttonContainerStyle !== null && buttonContainerStyle !== void 0 ? buttonContainerStyle : {}),
};
}, [buttonContainerStyle, disabled]);
return ((0, jsx_runtime_1.jsx)("button", { ref: ref, id: id, style: combined, type: "button", disabled: disabled, onClick: onClick, autoFocus: autoFocus, title: title, children: (0, jsx_runtime_1.jsx)("div", { className: "css-reset", style: buttonContainer, children: children }) }));
};
exports.Button = (0, react_1.forwardRef)(ButtonRefForwardFunction);
@@ -0,0 +1,7 @@
import type { Size } from '@remotion/player';
import React from 'react';
import type { CanvasContent } from 'remotion';
export declare const Canvas: React.FC<{
readonly canvasContent: CanvasContent;
readonly size: Size;
}>;
@@ -0,0 +1,267 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Canvas = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const react_1 = require("react");
const remotion_1 = require("remotion");
const colors_1 = require("../helpers/colors");
const get_asset_metadata_1 = require("../helpers/get-asset-metadata");
const get_effective_translation_1 = require("../helpers/get-effective-translation");
const smooth_zoom_1 = require("../helpers/smooth-zoom");
const use_keybinding_1 = require("../helpers/use-keybinding");
const canvas_ref_1 = require("../state/canvas-ref");
const editor_guides_1 = require("../state/editor-guides");
const editor_zoom_gestures_1 = require("../state/editor-zoom-gestures");
const EditorGuides_1 = __importDefault(require("./EditorGuides"));
const EditorRuler_1 = require("./EditorRuler");
const use_is_ruler_visible_1 = require("./EditorRuler/use-is-ruler-visible");
const Preview_1 = require("./Preview");
const ResetZoomButton_1 = require("./ResetZoomButton");
const layout_1 = require("./layout");
const container = {
flex: 1,
display: 'flex',
overflow: 'hidden',
position: 'relative',
backgroundColor: colors_1.BACKGROUND,
};
const resetZoom = {
position: 'absolute',
top: layout_1.SPACING_UNIT * 2,
right: layout_1.SPACING_UNIT * 2,
};
const ZOOM_PX_FACTOR = 0.003;
const Canvas = ({ canvasContent, size }) => {
const { setSize, size: previewSize } = (0, react_1.useContext)(remotion_1.Internals.PreviewSizeContext);
const { editorZoomGestures } = (0, react_1.useContext)(editor_zoom_gestures_1.EditorZoomGesturesContext);
const keybindings = (0, use_keybinding_1.useKeybinding)();
const config = remotion_1.Internals.useUnsafeVideoConfig();
const areRulersVisible = (0, use_is_ruler_visible_1.useIsRulerVisible)();
const { editorShowGuides } = (0, react_1.useContext)(editor_guides_1.EditorShowGuidesContext);
const [assetResolution, setAssetResolution] = (0, react_1.useState)(null);
const contentDimensions = (0, react_1.useMemo)(() => {
if ((canvasContent.type === 'asset' ||
canvasContent.type === 'output' ||
canvasContent.type === 'output-blob') &&
assetResolution &&
assetResolution.type === 'found') {
return assetResolution.dimensions;
}
if (config) {
return { width: config.width, height: config.height };
}
return null;
}, [assetResolution, config, canvasContent]);
const isFit = previewSize.size === 'auto';
const onWheel = (0, react_1.useCallback)((e) => {
if (!editorZoomGestures) {
return;
}
if (!size) {
return;
}
if (!contentDimensions || contentDimensions === 'none') {
return;
}
const wantsToZoom = e.ctrlKey || e.metaKey;
if (!wantsToZoom && isFit) {
return;
}
e.preventDefault();
setSize((prevSize) => {
const scale = remotion_1.Internals.calculateScale({
canvasSize: size,
compositionHeight: contentDimensions.height,
compositionWidth: contentDimensions.width,
previewSize: prevSize.size,
});
// Zoom in/out
if (wantsToZoom) {
const oldSize = prevSize.size === 'auto' ? scale : prevSize.size;
const smoothened = (0, smooth_zoom_1.smoothenZoom)(oldSize);
const added = smoothened + e.deltaY * ZOOM_PX_FACTOR;
const unsmoothened = (0, smooth_zoom_1.unsmoothenZoom)(added);
const { centerX, centerY } = (0, get_effective_translation_1.getCenterPointWhileScrolling)({
size,
clientX: e.clientX,
clientY: e.clientY,
compositionWidth: contentDimensions.width,
compositionHeight: contentDimensions.height,
scale,
translation: prevSize.translation,
});
const zoomDifference = unsmoothened - oldSize;
const uvCoordinatesX = centerX / contentDimensions.width;
const uvCoordinatesY = centerY / contentDimensions.height;
const correctionLeft = -uvCoordinatesX * (zoomDifference * contentDimensions.width) +
(1 - uvCoordinatesX) * zoomDifference * contentDimensions.width;
const correctionTop = -uvCoordinatesY * (zoomDifference * contentDimensions.height) +
(1 - uvCoordinatesY) * zoomDifference * contentDimensions.height;
return {
translation: (0, get_effective_translation_1.getEffectiveTranslation)({
translation: {
x: prevSize.translation.x - correctionLeft / 2,
y: prevSize.translation.y - correctionTop / 2,
},
canvasSize: size,
compositionHeight: contentDimensions.height,
compositionWidth: contentDimensions.width,
scale,
}),
size: unsmoothened,
};
}
const effectiveTranslation = (0, get_effective_translation_1.getEffectiveTranslation)({
translation: prevSize.translation,
canvasSize: size,
compositionHeight: contentDimensions.height,
compositionWidth: contentDimensions.width,
scale,
});
// Pan
return {
...prevSize,
translation: (0, get_effective_translation_1.getEffectiveTranslation)({
translation: {
x: effectiveTranslation.x + e.deltaX,
y: effectiveTranslation.y + e.deltaY,
},
canvasSize: size,
compositionHeight: contentDimensions.height,
compositionWidth: contentDimensions.width,
scale,
}),
};
});
}, [editorZoomGestures, contentDimensions, isFit, setSize, size]);
(0, react_1.useEffect)(() => {
const { current } = canvas_ref_1.canvasRef;
if (!current) {
return;
}
current.addEventListener('wheel', onWheel, { passive: false });
return () =>
// @ts-expect-error
current.removeEventListener('wheel', onWheel, {
passive: false,
});
}, [onWheel]);
const onReset = (0, react_1.useCallback)(() => {
setSize(() => {
return {
translation: {
x: 0,
y: 0,
},
size: 'auto',
};
});
}, [setSize]);
const onZoomIn = (0, react_1.useCallback)(() => {
if (!contentDimensions || contentDimensions === 'none') {
return;
}
if (!size) {
return;
}
setSize((prevSize) => {
const scale = remotion_1.Internals.calculateScale({
canvasSize: size,
compositionHeight: contentDimensions.height,
compositionWidth: contentDimensions.width,
previewSize: prevSize.size,
});
return {
translation: {
x: 0,
y: 0,
},
size: Math.min(smooth_zoom_1.MAX_ZOOM, scale * 2),
};
});
}, [contentDimensions, setSize, size]);
const onZoomOut = (0, react_1.useCallback)(() => {
if (!contentDimensions || contentDimensions === 'none') {
return;
}
if (!size) {
return;
}
setSize((prevSize) => {
const scale = remotion_1.Internals.calculateScale({
canvasSize: size,
compositionHeight: contentDimensions.height,
compositionWidth: contentDimensions.width,
previewSize: prevSize.size,
});
return {
translation: {
x: 0,
y: 0,
},
size: Math.max(smooth_zoom_1.MIN_ZOOM, scale / 2),
};
});
}, [contentDimensions, setSize, size]);
(0, react_1.useEffect)(() => {
const resetBinding = keybindings.registerKeybinding({
event: 'keydown',
key: '0',
commandCtrlKey: false,
callback: onReset,
preventDefault: true,
triggerIfInputFieldFocused: false,
keepRegisteredWhenNotHighestContext: false,
});
const zoomIn = keybindings.registerKeybinding({
event: 'keydown',
key: '+',
commandCtrlKey: false,
callback: onZoomIn,
preventDefault: true,
triggerIfInputFieldFocused: false,
keepRegisteredWhenNotHighestContext: false,
});
const zoomOut = keybindings.registerKeybinding({
event: 'keydown',
key: '-',
commandCtrlKey: false,
callback: onZoomOut,
preventDefault: true,
triggerIfInputFieldFocused: false,
keepRegisteredWhenNotHighestContext: false,
});
return () => {
resetBinding.unregister();
zoomIn.unregister();
zoomOut.unregister();
};
}, [keybindings, onReset, onZoomIn, onZoomOut]);
const fetchMetadata = (0, react_1.useCallback)(async () => {
setAssetResolution(null);
if (canvasContent.type === 'composition') {
return;
}
const metadata = await (0, get_asset_metadata_1.getAssetMetadata)(canvasContent, canvasContent.type === 'asset');
setAssetResolution(metadata);
}, [canvasContent]);
(0, react_1.useEffect)(() => {
if (canvasContent.type !== 'asset') {
return;
}
const file = (0, remotion_1.watchStaticFile)(canvasContent.asset, () => {
fetchMetadata();
});
return () => {
file.cancel();
};
}, [canvasContent, fetchMetadata]);
(0, react_1.useEffect)(() => {
fetchMetadata();
}, [fetchMetadata]);
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)("div", { ref: canvas_ref_1.canvasRef, style: container, children: [size ? ((0, jsx_runtime_1.jsx)(Preview_1.VideoPreview, { canvasContent: canvasContent, contentDimensions: contentDimensions, canvasSize: size, assetMetadata: assetResolution })) : null, isFit ? null : ((0, jsx_runtime_1.jsx)("div", { style: resetZoom, className: "css-reset", children: (0, jsx_runtime_1.jsx)(ResetZoomButton_1.ResetZoomButton, { onClick: onReset }) })), editorShowGuides && canvasContent.type === 'composition' && ((0, jsx_runtime_1.jsx)(EditorGuides_1.default, { canvasSize: size, contentDimensions: contentDimensions, assetMetadata: assetResolution }))] }), areRulersVisible && ((0, jsx_runtime_1.jsx)(EditorRuler_1.EditorRulers, { contentDimensions: contentDimensions, canvasSize: size, assetMetadata: assetResolution, containerRef: canvas_ref_1.canvasRef }))] }));
};
exports.Canvas = Canvas;
@@ -0,0 +1 @@
export declare const CanvasIfSizeIsAvailable: React.FC;
@@ -0,0 +1,32 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CanvasIfSizeIsAvailable = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const react_1 = require("react");
const remotion_1 = require("remotion");
const editor_rulers_1 = require("../state/editor-rulers");
const CanvasOrLoading_1 = require("./CanvasOrLoading");
const use_is_ruler_visible_1 = require("./EditorRuler/use-is-ruler-visible");
const CanvasIfSizeIsAvailable = () => {
const rulersAreVisible = (0, use_is_ruler_visible_1.useIsRulerVisible)();
const context = (0, react_1.useContext)(remotion_1.Internals.CurrentScaleContext);
const sizeWithRulersApplied = (0, react_1.useMemo)(() => {
const size = context && context.type === 'canvas-size' ? context.canvasSize : null;
if (!rulersAreVisible) {
return size;
}
if (!size) {
return null;
}
return {
...size,
width: size.width - editor_rulers_1.RULER_WIDTH,
height: size.height - editor_rulers_1.RULER_WIDTH,
};
}, [context, rulersAreVisible]);
if (!sizeWithRulersApplied) {
return null;
}
return (0, jsx_runtime_1.jsx)(CanvasOrLoading_1.CanvasOrLoading, { size: sizeWithRulersApplied });
};
exports.CanvasIfSizeIsAvailable = CanvasIfSizeIsAvailable;
@@ -0,0 +1,5 @@
import type { Size } from '@remotion/player';
import React from 'react';
export declare const CanvasOrLoading: React.FC<{
readonly size: Size;
}>;
@@ -0,0 +1,77 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CanvasOrLoading = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const react_1 = require("react");
const remotion_1 = require("remotion");
const ErrorLoader_1 = require("../error-overlay/remotion-overlay/ErrorLoader");
const colors_1 = require("../helpers/colors");
const timeline_zoom_1 = require("../state/timeline-zoom");
const Canvas_1 = require("./Canvas");
const FramePersistor_1 = require("./FramePersistor");
const is_menu_item_1 = require("./Menu/is-menu-item");
const RefreshCompositionOverlay_1 = require("./RefreshCompositionOverlay");
const RunningCalculateMetadata_1 = require("./RunningCalculateMetadata");
const imperative_state_1 = require("./Timeline/imperative-state");
const timeline_scroll_logic_1 = require("./Timeline/timeline-scroll-logic");
const ZoomPersistor_1 = require("./ZoomPersistor");
const container = {
color: 'white',
flex: 1,
justifyContent: 'center',
alignItems: 'center',
display: 'flex',
backgroundColor: colors_1.BACKGROUND,
flexDirection: 'column',
};
const CanvasOrLoading = ({ size }) => {
const resolved = remotion_1.Internals.useResolvedVideoConfig(null);
const { setZoom } = (0, react_1.useContext)(timeline_zoom_1.TimelineZoomCtx);
const { canvasContent } = (0, react_1.useContext)(remotion_1.Internals.CompositionManager);
(0, react_1.useEffect)(() => {
if ((resolved === null || resolved === void 0 ? void 0 : resolved.type) !== 'success' &&
(resolved === null || resolved === void 0 ? void 0 : resolved.type) !== 'success-and-refreshing') {
return;
}
const c = resolved.result;
setTimeout(() => {
(0, timeline_scroll_logic_1.ensureFrameIsInViewport)({
direction: 'center',
frame: (0, imperative_state_1.getCurrentFrame)(),
durationInFrames: c.durationInFrames,
});
});
}, [resolved, setZoom]);
if (!canvasContent) {
const compname = window.location.pathname.replace('/', '');
return ((0, jsx_runtime_1.jsx)("div", { style: container, className: "css-reset", children: (0, jsx_runtime_1.jsxs)("div", { style: RunningCalculateMetadata_1.loaderLabel, children: ["Composition with ID ", compname, " not found."] }) }));
}
const content = ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(ZoomPersistor_1.ZoomPersistor, {}), (0, jsx_runtime_1.jsx)(Canvas_1.Canvas, { size: size, canvasContent: canvasContent }), (resolved === null || resolved === void 0 ? void 0 : resolved.type) === 'success-and-refreshing' ? ((0, jsx_runtime_1.jsx)(RefreshCompositionOverlay_1.RefreshCompositionOverlay, {})) : null] }));
if (canvasContent.type === 'asset' ||
canvasContent.type === 'output' ||
canvasContent.type === 'output-blob') {
return content;
}
if (!resolved) {
return null;
}
if (resolved.type === 'loading') {
return ((0, jsx_runtime_1.jsx)("div", { style: container, className: "css-reset", children: (0, jsx_runtime_1.jsx)(RunningCalculateMetadata_1.RunningCalculateMetadata, {}) }));
}
if (resolved.type === 'error') {
return (0, jsx_runtime_1.jsx)(ErrorLoading, { error: resolved.error });
}
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(FramePersistor_1.FramePersistor, {}), " ", content] }));
};
exports.CanvasOrLoading = CanvasOrLoading;
const loaderContainer = {
marginLeft: 'auto',
marginRight: 'auto',
width: '100%',
position: 'absolute',
height: '100%',
overflowY: 'auto',
};
const ErrorLoading = ({ error }) => {
return ((0, jsx_runtime_1.jsx)("div", { style: loaderContainer, className: is_menu_item_1.VERTICAL_SCROLLBAR_CLASSNAME, children: (0, jsx_runtime_1.jsx)(ErrorLoader_1.ErrorLoader, { canHaveDismissButton: false, keyboardShortcuts: false, error: error, onRetry: () => { var _a; return (_a = remotion_1.Internals.resolveCompositionsRef.current) === null || _a === void 0 ? void 0 : _a.reloadCurrentlySelectedComposition(); }, calculateMetadata: true }, error.stack) }));
};
@@ -0,0 +1,2 @@
import React from 'react';
export declare const CheckboardToggle: React.FC;
@@ -0,0 +1,26 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CheckboardToggle = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const react_1 = require("react");
const no_react_1 = require("remotion/no-react");
const colors_1 = require("../helpers/colors");
const use_keybinding_1 = require("../helpers/use-keybinding");
const checkerboard_1 = require("../state/checkerboard");
const ControlButton_1 = require("./ControlButton");
const accessibilityLabel = [
'Show transparency as checkerboard',
(0, use_keybinding_1.areKeyboardShortcutsDisabled)() ? null : '(T)',
]
.filter(no_react_1.NoReactInternals.truthy)
.join(' ');
const CheckboardToggle = () => {
const { checkerboard, setCheckerboard } = (0, react_1.useContext)(checkerboard_1.CheckerboardContext);
const onClick = (0, react_1.useCallback)(() => {
setCheckerboard((c) => {
return !c;
});
}, [setCheckerboard]);
return ((0, jsx_runtime_1.jsx)(ControlButton_1.ControlButton, { title: accessibilityLabel, "aria-label": accessibilityLabel, onClick: onClick, children: (0, jsx_runtime_1.jsx)("svg", { "aria-hidden": "true", focusable: "false", "data-prefix": "fas", "data-icon": "game-board-alt", className: "svg-inline--fa fa-game-board-alt fa-w-16", role: "img", xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 512 512", style: { width: 16, height: 16 }, children: (0, jsx_runtime_1.jsx)("path", { fill: checkerboard ? colors_1.BLUE : 'white', d: "M480 0H32A32 32 0 0 0 0 32v448a32 32 0 0 0 32 32h448a32 32 0 0 0 32-32V32a32 32 0 0 0-32-32zm-32 256H256v192H64V256h192V64h192z" }) }) }));
};
exports.CheckboardToggle = CheckboardToggle;
@@ -0,0 +1,8 @@
import React from 'react';
export declare const Checkbox: React.FC<{
readonly checked: boolean;
readonly onChange: React.ChangeEventHandler<HTMLInputElement>;
readonly name: string;
readonly rounded?: boolean;
readonly disabled?: boolean;
}>;
@@ -0,0 +1,54 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Checkbox = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const react_1 = require("react");
const colors_1 = require("../helpers/colors");
const Checkmark_1 = require("../icons/Checkmark");
const size = 20;
const background = {
height: size,
width: size,
position: 'relative',
};
const bullet = {
width: 10,
height: 10,
backgroundColor: colors_1.LIGHT_TEXT,
borderRadius: '50%',
};
const box = {
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
position: 'absolute',
height: size,
width: size,
top: 0,
left: 0,
pointerEvents: 'none',
color: 'white',
};
const Checkbox = ({ checked, onChange, disabled, name, rounded }) => {
const ref = (0, react_1.useRef)(null);
const input = (0, react_1.useMemo)(() => {
return {
appearance: 'none',
background: disabled ? 'transparent' : colors_1.INPUT_BACKGROUND,
border: '1px solid ' + colors_1.INPUT_BORDER_COLOR_UNHOVERED,
height: size,
width: size,
top: 0,
left: 0,
position: 'absolute',
margin: 0,
};
}, [disabled]);
(0, react_1.useEffect)(() => {
if (ref.current) {
ref.current.style.setProperty('border-radius', rounded ? '50%' : '0%', 'important');
}
}, [rounded]);
return ((0, jsx_runtime_1.jsxs)("div", { style: background, children: [(0, jsx_runtime_1.jsx)("input", { ref: ref, style: input, type: 'checkbox', checked: checked, onChange: onChange, disabled: disabled, name: name }), (0, jsx_runtime_1.jsx)("div", { style: box, children: checked ? rounded ? (0, jsx_runtime_1.jsx)("div", { style: bullet }) : (0, jsx_runtime_1.jsx)(Checkmark_1.Checkmark, {}) : null })] }));
};
exports.Checkbox = Checkbox;
@@ -0,0 +1,4 @@
import React from 'react';
export declare const CheckerboardProvider: React.FC<{
readonly children: React.ReactNode;
}>;
@@ -0,0 +1,24 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CheckerboardProvider = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const react_1 = require("react");
const checkerboard_1 = require("../state/checkerboard");
const CheckerboardProvider = ({ children }) => {
const [checkerboard, setCheckerboardState] = (0, react_1.useState)(() => (0, checkerboard_1.loadCheckerboardOption)());
const setCheckerboard = (0, react_1.useCallback)((newValue) => {
setCheckerboardState((prevState) => {
const newVal = newValue(prevState);
(0, checkerboard_1.persistCheckerboardOption)(newVal);
return newVal;
});
}, []);
const checkerboardCtx = (0, react_1.useMemo)(() => {
return {
checkerboard,
setCheckerboard,
};
}, [checkerboard, setCheckerboard]);
return ((0, jsx_runtime_1.jsx)(checkerboard_1.CheckerboardContext.Provider, { value: checkerboardCtx, children: children }));
};
exports.CheckerboardProvider = CheckerboardProvider;
@@ -0,0 +1,4 @@
import type React from 'react';
export declare const CompSelectorRef: React.FC<{
readonly children: React.ReactNode;
}>;
@@ -0,0 +1,82 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CompSelectorRef = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const react_1 = require("react");
const remotion_1 = require("remotion");
const persist_open_folders_1 = require("../helpers/persist-open-folders");
const InitialCompositionLoader_1 = require("./InitialCompositionLoader");
const CompSelectorRef = ({ children }) => {
const { compositions } = (0, react_1.useContext)(remotion_1.Internals.CompositionManager);
const [foldersExpanded, setFoldersExpanded] = (0, react_1.useState)((0, persist_open_folders_1.loadExpandedFolders)('compositions'));
const selectComposition = (0, InitialCompositionLoader_1.useSelectComposition)();
const toggleFolder = (0, react_1.useCallback)((folderName, parentName) => {
setFoldersExpanded((p) => {
var _a;
const key = (0, persist_open_folders_1.openFolderKey)({ folderName, parentName });
const prev = (_a = p[key]) !== null && _a !== void 0 ? _a : false;
const foldersExpandedState = {
...p,
[key]: !prev,
};
(0, persist_open_folders_1.persistExpandedFolders)('compositions', foldersExpandedState);
return foldersExpandedState;
});
}, []);
(0, react_1.useImperativeHandle)(remotion_1.Internals.compositionSelectorRef, () => {
return {
expandComposition: (compName) => {
const compositionToExpand = compositions.find((c) => c.id === compName);
if (!compositionToExpand) {
return;
}
const { folderName, parentFolderName } = compositionToExpand;
if (folderName === null) {
return;
}
setFoldersExpanded((previousState) => {
const foldersExpandedState = {
...previousState,
};
const currentFolder = folderName;
const currentParentName = parentFolderName;
const key = (0, persist_open_folders_1.openFolderKey)({
folderName: currentFolder,
parentName: currentParentName,
});
const splitted = key.split('/');
for (let i = 0; i < splitted.length - 1; i++) {
const allExceptLast = i === 0
? (0, persist_open_folders_1.openFolderKey)({
folderName: splitted.filter((s) => s !== 'no-parent')[0],
parentName: null,
})
: splitted.slice(0, i + 1).join('/');
foldersExpandedState[allExceptLast] = true;
}
(0, persist_open_folders_1.persistExpandedFolders)('compositions', foldersExpandedState);
return foldersExpandedState;
});
},
selectComposition: (compName) => {
const comp = compositions.find((c) => c.id === compName);
if (!comp) {
throw new Error(`Composition ${compName} not found`);
}
selectComposition(comp, true);
},
toggleFolder: (folderName, parentName) => {
toggleFolder(folderName, parentName);
},
};
}, [compositions, selectComposition, toggleFolder]);
const contextValue = (0, react_1.useMemo)(() => {
return {
foldersExpanded,
setFoldersExpanded,
toggleFolder,
};
}, [foldersExpanded, setFoldersExpanded, toggleFolder]);
return ((0, jsx_runtime_1.jsx)(persist_open_folders_1.ExpandedFoldersContext.Provider, { value: contextValue, children: children }));
};
exports.CompSelectorRef = CompSelectorRef;
@@ -0,0 +1,6 @@
import React from 'react';
import type { ComboboxValue } from './NewComposition/ComboBox';
export declare const CompositionContextButton: React.FC<{
readonly visible: boolean;
readonly values: ComboboxValue[];
}>;
@@ -0,0 +1,27 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CompositionContextButton = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const react_1 = require("react");
const client_id_1 = require("../helpers/client-id");
const ellipsis_1 = require("../icons/ellipsis");
const InlineDropdown_1 = require("./InlineDropdown");
const CompositionContextButton = ({ visible, values }) => {
const iconStyle = (0, react_1.useMemo)(() => {
return {
style: {
height: 12,
},
};
}, []);
const connectionStatus = (0, react_1.useContext)(client_id_1.StudioServerConnectionCtx)
.previewServerState.type;
const renderAction = (0, react_1.useCallback)((color) => {
return (0, jsx_runtime_1.jsx)(ellipsis_1.EllipsisIcon, { fill: color, svgProps: iconStyle });
}, [iconStyle]);
if (!visible || connectionStatus !== 'connected') {
return null;
}
return (0, jsx_runtime_1.jsx)(InlineDropdown_1.InlineDropdown, { renderAction: renderAction, values: values });
};
exports.CompositionContextButton = CompositionContextButton;
@@ -0,0 +1,7 @@
import React from 'react';
export declare const useCompositionNavigation: () => {
navigateToNextComposition: () => void;
navigateToPreviousComposition: () => void;
};
export declare const getKeysToExpand: (initialFolderName: string, parentFolderName: string | null, initial?: string[]) => string[];
export declare const CompositionSelector: React.FC;
@@ -0,0 +1,95 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CompositionSelector = exports.getKeysToExpand = exports.useCompositionNavigation = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const react_1 = require("react");
const remotion_1 = require("remotion");
const colors_1 = require("../helpers/colors");
const create_folder_tree_1 = require("../helpers/create-folder-tree");
const persist_open_folders_1 = require("../helpers/persist-open-folders");
const z_index_1 = require("../state/z-index");
const CompositionSelectorItem_1 = require("./CompositionSelectorItem");
const CurrentComposition_1 = require("./CurrentComposition");
const InitialCompositionLoader_1 = require("./InitialCompositionLoader");
const useCompositionNavigation = () => {
const { compositions, canvasContent } = (0, react_1.useContext)(remotion_1.Internals.CompositionManager);
const selectComposition = (0, InitialCompositionLoader_1.useSelectComposition)();
const navigateToNextComposition = (0, react_1.useCallback)(() => {
if (!canvasContent ||
canvasContent.type !== 'composition' ||
compositions.length <= 1) {
return;
}
const currentIndex = compositions.findIndex((c) => c.id === canvasContent.compositionId);
if (currentIndex === -1) {
return;
}
const nextIndex = (currentIndex + 1) % compositions.length;
const nextComposition = compositions[nextIndex];
selectComposition(nextComposition, true);
}, [canvasContent, compositions, selectComposition]);
const navigateToPreviousComposition = (0, react_1.useCallback)(() => {
if (!canvasContent ||
canvasContent.type !== 'composition' ||
compositions.length <= 1) {
return;
}
const currentIndex = compositions.findIndex((c) => c.id === canvasContent.compositionId);
if (currentIndex === -1) {
return;
}
const previousIndex = (currentIndex - 1 + compositions.length) % compositions.length;
const previousComposition = compositions[previousIndex];
selectComposition(previousComposition, true);
}, [canvasContent, compositions, selectComposition]);
return (0, react_1.useMemo)(() => ({
navigateToNextComposition,
navigateToPreviousComposition,
}), [navigateToNextComposition, navigateToPreviousComposition]);
};
exports.useCompositionNavigation = useCompositionNavigation;
const container = {
display: 'flex',
flexDirection: 'column',
flex: 1,
overflow: 'hidden',
backgroundColor: colors_1.BACKGROUND,
};
const getKeysToExpand = (initialFolderName, parentFolderName, initial = []) => {
initial.push((0, persist_open_folders_1.openFolderKey)({
folderName: initialFolderName,
parentName: parentFolderName,
}));
const { name, parent } = (0, create_folder_tree_1.splitParentIntoNameAndParent)(parentFolderName);
if (!name) {
return initial;
}
return (0, exports.getKeysToExpand)(name, parent, initial);
};
exports.getKeysToExpand = getKeysToExpand;
const CompositionSelector = () => {
const { compositions, canvasContent, folders } = (0, react_1.useContext)(remotion_1.Internals.CompositionManager);
const { foldersExpanded } = (0, react_1.useContext)(persist_open_folders_1.ExpandedFoldersContext);
const { tabIndex } = (0, z_index_1.useZIndex)();
const selectComposition = (0, InitialCompositionLoader_1.useSelectComposition)();
const items = (0, react_1.useMemo)(() => {
return (0, create_folder_tree_1.createFolderTree)(compositions, folders, foldersExpanded);
}, [compositions, folders, foldersExpanded]);
const showCurrentComposition = canvasContent && canvasContent.type === 'composition';
const list = (0, react_1.useMemo)(() => {
return {
height: showCurrentComposition
? `calc(100% - ${CurrentComposition_1.CURRENT_COMPOSITION_HEIGHT}px)`
: '100%',
overflowY: 'auto',
};
}, [showCurrentComposition]);
const toggleFolder = (0, react_1.useCallback)((folderName, parentName) => {
var _a;
(_a = remotion_1.Internals.compositionSelectorRef.current) === null || _a === void 0 ? void 0 : _a.toggleFolder(folderName, parentName);
}, []);
return ((0, jsx_runtime_1.jsxs)("div", { style: container, children: [showCurrentComposition ? (0, jsx_runtime_1.jsx)(CurrentComposition_1.CurrentComposition, {}) : null, (0, jsx_runtime_1.jsx)("div", { className: "__remotion-vertical-scrollbar", style: list, children: items.map((c) => {
return ((0, jsx_runtime_1.jsx)(CompositionSelectorItem_1.CompositionSelectorItem, { level: 0, currentComposition: showCurrentComposition ? canvasContent.compositionId : null, selectComposition: selectComposition, toggleFolder: toggleFolder, tabIndex: tabIndex, item: c }, c.key + c.type));
}) })] }));
};
exports.CompositionSelector = CompositionSelector;
@@ -0,0 +1,22 @@
import React from 'react';
import { type _InternalTypes } from 'remotion';
export type CompositionSelectorItemType = {
key: string;
type: 'composition';
composition: _InternalTypes['AnyComposition'];
} | {
key: string;
type: 'folder';
folderName: string;
parentName: string | null;
items: CompositionSelectorItemType[];
expanded: boolean;
};
export declare const CompositionSelectorItem: React.FC<{
readonly item: CompositionSelectorItemType;
readonly currentComposition: string | null;
readonly tabIndex: number;
readonly selectComposition: (c: _InternalTypes['AnyComposition'], push: boolean) => void;
readonly toggleFolder: (folderName: string, parentName: string | null) => void;
readonly level: number;
}>;
@@ -0,0 +1,182 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CompositionSelectorItem = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const react_1 = require("react");
const colors_1 = require("../helpers/colors");
const is_composition_still_1 = require("../helpers/is-composition-still");
const folder_1 = require("../icons/folder");
const still_1 = require("../icons/still");
const video_1 = require("../icons/video");
const modals_1 = require("../state/modals");
const CompositionContextButton_1 = require("./CompositionContextButton");
const ContextMenu_1 = require("./ContextMenu");
const layout_1 = require("./layout");
const NotificationCenter_1 = require("./Notifications/NotificationCenter");
const SidebarRenderButton_1 = require("./SidebarRenderButton");
const COMPOSITION_ITEM_HEIGHT = 32;
const itemStyle = {
paddingRight: 10,
paddingTop: 6,
paddingBottom: 6,
fontSize: 13,
display: 'flex',
textDecoration: 'none',
cursor: 'default',
alignItems: 'center',
marginBottom: 1,
appearance: 'none',
border: 'none',
width: '100%',
textAlign: 'left',
backgroundColor: colors_1.BACKGROUND,
height: COMPOSITION_ITEM_HEIGHT,
};
const labelStyle = {
textAlign: 'left',
textDecoration: 'none',
fontSize: 13,
flex: 1,
whiteSpace: 'nowrap',
overflow: 'hidden',
textOverflow: 'ellipsis',
};
const iconStyle = {
width: 18,
height: 18,
flexShrink: 0,
};
const CompositionSelectorItem = ({ item, level, currentComposition, tabIndex, selectComposition, toggleFolder, }) => {
const selected = (0, react_1.useMemo)(() => {
if (item.type === 'composition') {
return currentComposition === item.composition.id;
}
return false;
}, [item, currentComposition]);
const [hovered, setHovered] = (0, react_1.useState)(false);
const onPointerEnter = (0, react_1.useCallback)(() => {
setHovered(true);
}, []);
const onPointerLeave = (0, react_1.useCallback)(() => {
setHovered(false);
}, []);
const style = (0, react_1.useMemo)(() => {
return {
...itemStyle,
backgroundColor: (0, colors_1.getBackgroundFromHoverState)({ hovered, selected }),
paddingLeft: 12 + level * 8,
};
}, [hovered, level, selected]);
const label = (0, react_1.useMemo)(() => {
return {
...labelStyle,
color: selected || hovered ? 'white' : colors_1.LIGHT_TEXT,
};
}, [hovered, selected]);
const onClick = (0, react_1.useCallback)((evt) => {
evt.preventDefault();
if (item.type === 'composition') {
selectComposition(item.composition, true);
}
else {
toggleFolder(item.folderName, item.parentName);
}
}, [item, selectComposition, toggleFolder]);
const onKeyPress = (0, react_1.useCallback)((evt) => {
if (evt.key === 'Enter') {
onClick(evt);
}
}, [onClick]);
const { setSelectedModal } = (0, react_1.useContext)(modals_1.ModalsContext);
const contextMenu = (0, react_1.useMemo)(() => {
if (item.type === 'composition') {
return [
{
id: 'duplicate',
keyHint: null,
label: `Duplicate...`,
leftItem: null,
onClick: () => {
setSelectedModal({
type: 'duplicate-comp',
compositionId: item.composition.id,
compositionType: item.composition.durationInFrames === 1
? 'still'
: 'composition',
});
},
quickSwitcherLabel: null,
subMenu: null,
type: 'item',
value: 'duplicate',
},
{
id: 'rename',
keyHint: null,
label: `Rename...`,
leftItem: null,
onClick: () => {
setSelectedModal({
type: 'rename-comp',
compositionId: item.composition.id,
});
},
quickSwitcherLabel: null,
subMenu: null,
type: 'item',
value: 'rename',
},
{
id: 'delete',
keyHint: null,
label: `Delete...`,
leftItem: null,
onClick: () => {
setSelectedModal({
type: 'delete-comp',
compositionId: item.composition.id,
});
},
quickSwitcherLabel: null,
subMenu: null,
type: 'item',
value: 'delete',
},
{
type: 'divider',
id: 'copy-id-divider',
},
{
id: 'copy-id',
keyHint: null,
label: `Copy ID`,
leftItem: null,
onClick: () => {
navigator.clipboard
.writeText(item.composition.id)
.catch((err) => {
(0, NotificationCenter_1.showNotification)(`Could not copy to clipboard: ${err.message}`, 1000);
})
.then(() => {
(0, NotificationCenter_1.showNotification)('Copied to clipboard', 1000);
});
},
quickSwitcherLabel: null,
subMenu: null,
type: 'item',
value: 'remove',
},
];
}
return [];
}, [item, setSelectedModal]);
if (item.type === 'folder') {
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)("button", { style: style, onPointerEnter: onPointerEnter, onPointerLeave: onPointerLeave, tabIndex: tabIndex, onClick: onClick, type: "button", title: item.folderName, children: [item.expanded ? ((0, jsx_runtime_1.jsx)(folder_1.ExpandedFolderIcon, { style: iconStyle, color: hovered || selected ? 'white' : colors_1.LIGHT_TEXT })) : ((0, jsx_runtime_1.jsx)(folder_1.CollapsedFolderIcon, { color: hovered || selected ? 'white' : colors_1.LIGHT_TEXT, style: iconStyle })), (0, jsx_runtime_1.jsx)(layout_1.Spacing, { x: 1 }), (0, jsx_runtime_1.jsx)("div", { style: label, children: item.folderName })] }), item.expanded
? item.items.map((childItem) => {
return ((0, jsx_runtime_1.jsx)(exports.CompositionSelectorItem, { currentComposition: currentComposition, selectComposition: selectComposition, item: childItem, tabIndex: tabIndex, level: level + 1, toggleFolder: toggleFolder }, childItem.key + childItem.type));
})
: null] }));
}
return ((0, jsx_runtime_1.jsx)(ContextMenu_1.ContextMenu, { values: contextMenu, children: (0, jsx_runtime_1.jsx)(layout_1.Row, { align: "center", children: (0, jsx_runtime_1.jsxs)("a", { style: style, onPointerEnter: onPointerEnter, onPointerLeave: onPointerLeave, tabIndex: tabIndex, onClick: onClick, onKeyPress: onKeyPress, type: "button", title: item.composition.id, className: "__remotion-composition", "data-compname": item.composition.id, children: [(0, is_composition_still_1.isCompositionStill)(item.composition) ? ((0, jsx_runtime_1.jsx)(still_1.StillIcon, { color: hovered || selected ? 'white' : colors_1.LIGHT_TEXT, style: iconStyle })) : ((0, jsx_runtime_1.jsx)(video_1.FilmIcon, { color: hovered || selected ? 'white' : colors_1.LIGHT_TEXT, style: iconStyle })), (0, jsx_runtime_1.jsx)(layout_1.Spacing, { x: 1 }), (0, jsx_runtime_1.jsx)("div", { style: label, children: item.composition.id }), (0, jsx_runtime_1.jsx)(layout_1.Spacing, { x: 0.5 }), (0, jsx_runtime_1.jsx)(CompositionContextButton_1.CompositionContextButton, { values: contextMenu, visible: hovered }), (0, jsx_runtime_1.jsx)(SidebarRenderButton_1.SidebarRenderButton, { visible: hovered, composition: item.composition })] }) }) }));
};
exports.CompositionSelectorItem = CompositionSelectorItem;
@@ -0,0 +1,6 @@
import React from 'react';
import type { ComboboxValue } from './NewComposition/ComboBox';
export declare const ContextMenu: React.FC<{
readonly children: React.ReactNode;
readonly values: ComboboxValue[];
}>;
@@ -0,0 +1,98 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ContextMenu = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const player_1 = require("@remotion/player");
const react_1 = require("react");
const react_dom_1 = __importDefault(require("react-dom"));
const mobile_layout_1 = require("../helpers/mobile-layout");
const noop_1 = require("../helpers/noop");
const z_index_1 = require("../state/z-index");
const portals_1 = require("./Menu/portals");
const styles_1 = require("./Menu/styles");
const MenuContent_1 = require("./NewComposition/MenuContent");
const ContextMenu = ({ children, values }) => {
const ref = (0, react_1.useRef)(null);
const [opened, setOpened] = (0, react_1.useState)({ type: 'not-open' });
const { currentZIndex } = (0, z_index_1.useZIndex)();
const style = (0, react_1.useMemo)(() => {
return {};
}, []);
const size = player_1.PlayerInternals.useElementSize(ref, {
triggerOnWindowResize: true,
shouldApplyCssTransforms: true,
});
const isMobileLayout = (0, mobile_layout_1.useMobileLayout)();
(0, react_1.useEffect)(() => {
const { current } = ref;
if (!current) {
return;
}
const onClick = (e) => {
e.preventDefault();
e.stopPropagation();
setOpened({ type: 'open', left: e.clientX, top: e.clientY });
return false;
};
current.addEventListener('contextmenu', onClick);
return () => {
current.removeEventListener('contextmenu', onClick);
};
}, [size]);
const spaceToBottom = (0, react_1.useMemo)(() => {
if (size && opened.type === 'open') {
return size.windowSize.height - opened.top;
}
return 0;
}, [opened, size]);
const spaceToTop = (0, react_1.useMemo)(() => {
if (size && opened.type === 'open') {
return opened.top;
}
return 0;
}, [opened, size]);
const portalStyle = (0, react_1.useMemo)(() => {
if (opened.type === 'not-open') {
return;
}
if (!size) {
return;
}
const spaceToRight = size.windowSize.width - size.left;
const spaceToLeft = size.left + size.width;
const minSpaceRequired = isMobileLayout
? styles_1.MAX_MOBILE_MENU_WIDTH
: styles_1.MAX_MENU_WIDTH;
const verticalLayout = spaceToTop > spaceToBottom ? 'bottom' : 'top';
const canOpenOnLeft = spaceToLeft >= minSpaceRequired;
const canOpenOnRight = spaceToRight >= minSpaceRequired;
const horizontalLayout = canOpenOnRight ? 'left' : 'right';
return {
...styles_1.menuContainerTowardsTop,
...(verticalLayout === 'top'
? {
top: opened.top,
}
: {
bottom: size.windowSize.height - opened.top,
}),
...(horizontalLayout === 'left'
? {
left: opened.left,
}
: {
right: canOpenOnLeft ? size.windowSize.width - opened.left : 0,
}),
};
}, [opened, size, isMobileLayout, spaceToTop, spaceToBottom]);
const onHide = (0, react_1.useCallback)(() => {
setOpened({ type: 'not-open' });
}, []);
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("div", { ref: ref, onContextMenu: () => false, style: style, children: children }), portalStyle
? react_dom_1.default.createPortal((0, jsx_runtime_1.jsx)("div", { style: styles_1.fullScreenOverlay, children: (0, jsx_runtime_1.jsx)("div", { style: styles_1.outerPortal, className: "css-reset", children: (0, jsx_runtime_1.jsx)(z_index_1.HigherZIndex, { onOutsideClick: onHide, onEscape: onHide, children: (0, jsx_runtime_1.jsx)("div", { style: portalStyle, children: (0, jsx_runtime_1.jsx)(MenuContent_1.MenuContent, { onNextMenu: noop_1.noop, onPreviousMenu: noop_1.noop, values: values, onHide: onHide, leaveLeftSpace: true, preselectIndex: false, topItemCanBeUnselected: false, fixedHeight: null }) }) }) }) }), (0, portals_1.getPortal)(currentZIndex))
: null] }));
};
exports.ContextMenu = ContextMenu;
@@ -0,0 +1,5 @@
import React from 'react';
export declare const CONTROL_BUTTON_PADDING = 6;
export declare const ControlButton: (props: React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement> & {
readonly title: string;
}) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,21 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ControlButton = exports.CONTROL_BUTTON_PADDING = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const react_1 = require("react");
const z_index_1 = require("../state/z-index");
exports.CONTROL_BUTTON_PADDING = 6;
const ControlButton = (props) => {
const style = (0, react_1.useMemo)(() => {
return {
opacity: props.disabled ? 0.5 : 1,
display: 'inline-flex',
background: 'none',
border: 'none',
padding: exports.CONTROL_BUTTON_PADDING,
};
}, [props.disabled]);
const { tabIndex } = (0, z_index_1.useZIndex)();
return ((0, jsx_runtime_1.jsx)("button", { type: 'button', tabIndex: tabIndex, ...props, style: style }));
};
exports.ControlButton = ControlButton;
@@ -0,0 +1,6 @@
import React from 'react';
export declare const CopyButton: React.FC<{
readonly textToCopy: string;
readonly label: string;
readonly labelWhenCopied: string;
}>;
@@ -0,0 +1,43 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CopyButton = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const react_1 = require("react");
const copy_text_1 = require("../helpers/copy-text");
const Button_1 = require("./Button");
const NotificationCenter_1 = require("./Notifications/NotificationCenter");
const layout_1 = require("./layout");
const iconStyle = {
width: 16,
height: 16,
color: 'white',
};
const buttonContainerStyle = {
display: 'flex',
minWidth: '114px',
};
const copyIcon = ((0, jsx_runtime_1.jsx)("svg", { "aria-hidden": "true", focusable: "false", "data-prefix": "far", "data-icon": "clipboard", className: "svg-inline--fa fa-clipboard fa-w-12", role: "img", xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 384 512", style: iconStyle, children: (0, jsx_runtime_1.jsx)("path", { fill: "currentColor", d: "M336 64h-80c0-35.3-28.7-64-64-64s-64 28.7-64 64H48C21.5 64 0 85.5 0 112v352c0 26.5 21.5 48 48 48h288c26.5 0 48-21.5 48-48V112c0-26.5-21.5-48-48-48zM192 40c13.3 0 24 10.7 24 24s-10.7 24-24 24-24-10.7-24-24 10.7-24 24-24zm144 418c0 3.3-2.7 6-6 6H54c-3.3 0-6-2.7-6-6V118c0-3.3 2.7-6 6-6h42v36c0 6.6 5.4 12 12 12h168c6.6 0 12-5.4 12-12v-36h42c3.3 0 6 2.7 6 6z" }) }));
const labelStyle = {
fontSize: 14,
};
const CopyButton = ({ textToCopy, label, labelWhenCopied }) => {
const [copied, setCopied] = (0, react_1.useState)(false);
const onClick = (0, react_1.useCallback)(() => {
(0, copy_text_1.copyText)(textToCopy)
.then(() => {
setCopied(Date.now());
})
.catch((err) => {
(0, NotificationCenter_1.showNotification)(`Could not copy: ${err.message}`, 2000);
});
}, [textToCopy]);
(0, react_1.useEffect)(() => {
if (!copied) {
return;
}
const to = setTimeout(() => setCopied(false), 2000);
return () => clearTimeout(to);
}, [copied]);
return ((0, jsx_runtime_1.jsxs)(Button_1.Button, { onClick: onClick, buttonContainerStyle: buttonContainerStyle, children: [copyIcon, (0, jsx_runtime_1.jsx)(layout_1.Spacing, { x: 1.5 }), ' ', (0, jsx_runtime_1.jsx)("span", { style: labelStyle, children: copied ? labelWhenCopied : label })] }));
};
exports.CopyButton = CopyButton;
@@ -0,0 +1,2 @@
export declare const CURRENT_COMPOSITION_HEIGHT = 80;
export declare const CurrentComposition: () => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,45 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CurrentComposition = exports.CURRENT_COMPOSITION_HEIGHT = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const remotion_1 = require("remotion");
const colors_1 = require("../helpers/colors");
const is_composition_still_1 = require("../helpers/is-composition-still");
const render_frame_1 = require("../state/render-frame");
exports.CURRENT_COMPOSITION_HEIGHT = 80;
const container = {
height: exports.CURRENT_COMPOSITION_HEIGHT,
display: 'block',
borderBottom: `1px solid ${colors_1.BORDER_COLOR}`,
padding: 12,
color: 'white',
backgroundColor: colors_1.BACKGROUND,
};
const title = {
fontWeight: 'bold',
fontSize: 12,
whiteSpace: 'nowrap',
lineHeight: '18px',
backgroundColor: colors_1.BACKGROUND,
};
const subtitle = {
fontSize: 12,
opacity: 0.8,
whiteSpace: 'nowrap',
lineHeight: '18px',
backgroundColor: colors_1.BACKGROUND,
};
const row = {
display: 'flex',
flexDirection: 'row',
lineHeight: '18px',
backgroundColor: colors_1.BACKGROUND,
};
const CurrentComposition = () => {
const video = remotion_1.Internals.useVideo();
if (!video) {
return (0, jsx_runtime_1.jsx)("div", { style: container });
}
return ((0, jsx_runtime_1.jsx)("div", { style: container, children: (0, jsx_runtime_1.jsx)("div", { style: row, children: (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("div", { style: title, children: video.id }), (0, jsx_runtime_1.jsxs)("div", { style: subtitle, children: [video.width, "x", video.height, (0, is_composition_still_1.isCompositionStill)(video) ? null : `, ${video.fps} FPS`] }), (0, is_composition_still_1.isCompositionStill)(video) ? ((0, jsx_runtime_1.jsx)("div", { style: subtitle, children: "Still" })) : ((0, jsx_runtime_1.jsxs)("div", { style: subtitle, children: ["Duration ", (0, render_frame_1.renderFrame)(video.durationInFrames, video.fps)] }))] }) }) }));
};
exports.CurrentComposition = CurrentComposition;
@@ -0,0 +1,5 @@
import type React from 'react';
export declare const TitleUpdater: React.FC;
export declare const CurrentCompositionKeybindings: React.FC<{
readonly readOnlyStudio: boolean;
}>;
@@ -0,0 +1,74 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CurrentCompositionKeybindings = exports.TitleUpdater = void 0;
const react_1 = require("react");
const remotion_1 = require("remotion");
const client_id_1 = require("../helpers/client-id");
const document_title_1 = require("../helpers/document-title");
const use_keybinding_1 = require("../helpers/use-keybinding");
const NotificationCenter_1 = require("./Notifications/NotificationCenter");
const context_1 = require("./RenderQueue/context");
const TitleUpdater = () => {
const renderQueue = (0, react_1.useContext)(context_1.RenderQueueContext);
const { canvasContent } = (0, react_1.useContext)(remotion_1.Internals.CompositionManager);
const { jobs } = renderQueue;
(0, react_1.useEffect)(() => {
if (!canvasContent) {
(0, document_title_1.setCurrentCanvasContentId)(null);
return;
}
if (canvasContent.type === 'composition') {
(0, document_title_1.setCurrentCanvasContentId)(canvasContent.compositionId);
return;
}
if (canvasContent.type === 'output') {
(0, document_title_1.setCurrentCanvasContentId)(canvasContent.path);
return;
}
if (canvasContent.type === 'output-blob') {
(0, document_title_1.setCurrentCanvasContentId)(canvasContent.displayName);
return;
}
(0, document_title_1.setCurrentCanvasContentId)(canvasContent.asset);
}, [canvasContent]);
(0, react_1.useEffect)(() => {
(0, document_title_1.setRenderJobs)(jobs);
}, [jobs]);
return null;
};
exports.TitleUpdater = TitleUpdater;
const CurrentCompositionKeybindings = ({ readOnlyStudio }) => {
const keybindings = (0, use_keybinding_1.useKeybinding)();
const video = remotion_1.Internals.useVideo();
const { type } = (0, react_1.useContext)(client_id_1.StudioServerConnectionCtx).previewServerState;
const openRenderModal = (0, react_1.useCallback)(() => {
if (!video) {
return;
}
if (readOnlyStudio) {
return (0, NotificationCenter_1.showNotification)('Studio is read-only', 2000);
}
if (type !== 'connected') {
(0, NotificationCenter_1.showNotification)('Studio server is offline', 2000);
return;
}
const renderButton = document.getElementById('render-modal-button');
renderButton.click();
}, [readOnlyStudio, type, video]);
(0, react_1.useEffect)(() => {
const binding = keybindings.registerKeybinding({
event: 'keydown',
key: 'r',
commandCtrlKey: false,
callback: openRenderModal,
preventDefault: true,
triggerIfInputFieldFocused: false,
keepRegisteredWhenNotHighestContext: false,
});
return () => {
binding.unregister();
};
}, [keybindings, openRenderModal]);
return null;
};
exports.CurrentCompositionKeybindings = CurrentCompositionKeybindings;
@@ -0,0 +1,6 @@
import React from 'react';
export declare const BUFFER_STATE_DELAY_IN_MILLISECONDS: number;
export declare const Editor: React.FC<{
readonly Root: React.FC;
readonly readOnlyStudio: boolean;
}>;
@@ -0,0 +1,101 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.Editor = exports.BUFFER_STATE_DELAY_IN_MILLISECONDS = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const player_1 = require("@remotion/player");
const react_1 = __importStar(require("react"));
const remotion_1 = require("remotion");
const colors_1 = require("../helpers/colors");
const noop_1 = require("../helpers/noop");
const canvas_ref_1 = require("../state/canvas-ref");
const timeline_zoom_1 = require("../state/timeline-zoom");
const z_index_1 = require("../state/z-index");
const EditorContent_1 = require("./EditorContent");
const GlobalKeybindings_1 = require("./GlobalKeybindings");
const Modals_1 = require("./Modals");
const NotificationCenter_1 = require("./Notifications/NotificationCenter");
const TopPanel_1 = require("./TopPanel");
const background = {
backgroundColor: colors_1.BACKGROUND,
display: 'flex',
width: '100%',
height: '100%',
flexDirection: 'column',
position: 'absolute',
};
const DEFAULT_BUFFER_STATE_DELAY_IN_MILLISECONDS = 300;
exports.BUFFER_STATE_DELAY_IN_MILLISECONDS = typeof process.env.BUFFER_STATE_DELAY_IN_MILLISECONDS === 'undefined' ||
process.env.BUFFER_STATE_DELAY_IN_MILLISECONDS === null
? DEFAULT_BUFFER_STATE_DELAY_IN_MILLISECONDS
: Number(process.env.BUFFER_STATE_DELAY_IN_MILLISECONDS);
const Editor = ({ Root, readOnlyStudio }) => {
const size = player_1.PlayerInternals.useElementSize(canvas_ref_1.drawRef, {
triggerOnWindowResize: false,
shouldApplyCssTransforms: true,
});
(0, react_1.useEffect)(() => {
if (readOnlyStudio) {
return;
}
const listenToChanges = (e) => {
if (window.remotion_unsavedProps) {
e.returnValue = 'Are you sure you want to leave?';
}
};
window.addEventListener('beforeunload', listenToChanges);
return () => {
window.removeEventListener('beforeunload', listenToChanges);
};
}, [readOnlyStudio]);
const [canvasMounted, setCanvasMounted] = react_1.default.useState(false);
const onMounted = (0, react_1.useCallback)(() => {
setCanvasMounted(true);
}, []);
const value = (0, react_1.useMemo)(() => {
if (!size) {
return null;
}
return {
type: 'canvas-size',
canvasSize: size,
};
}, [size]);
const MemoRoot = (0, react_1.useMemo)(() => {
return react_1.default.memo(Root);
}, [Root]);
return ((0, jsx_runtime_1.jsx)(z_index_1.HigherZIndex, { onEscape: noop_1.noop, onOutsideClick: noop_1.noop, children: (0, jsx_runtime_1.jsxs)(timeline_zoom_1.TimelineZoomContext, { children: [(0, jsx_runtime_1.jsx)(remotion_1.Internals.CurrentScaleContext.Provider, { value: value, children: (0, jsx_runtime_1.jsxs)("div", { style: background, children: [canvasMounted ? (0, jsx_runtime_1.jsx)(MemoRoot, {}) : null, (0, jsx_runtime_1.jsxs)(remotion_1.Internals.CanUseRemotionHooksProvider, { children: [(0, jsx_runtime_1.jsx)(EditorContent_1.EditorContent, { readOnlyStudio: readOnlyStudio, children: (0, jsx_runtime_1.jsx)(TopPanel_1.TopPanel, { drawRef: canvas_ref_1.drawRef, bufferStateDelayInMilliseconds: exports.BUFFER_STATE_DELAY_IN_MILLISECONDS, onMounted: onMounted, readOnlyStudio: readOnlyStudio }) }), (0, jsx_runtime_1.jsx)(GlobalKeybindings_1.GlobalKeybindings, {})] })] }) }), (0, jsx_runtime_1.jsx)(Modals_1.Modals, { readOnlyStudio: readOnlyStudio }), (0, jsx_runtime_1.jsx)(NotificationCenter_1.NotificationCenter, {})] }) }));
};
exports.Editor = Editor;
@@ -0,0 +1,5 @@
import React from 'react';
export declare const EditorContent: React.FC<{
readonly readOnlyStudio: boolean;
readonly children: React.ReactNode;
}>;
@@ -0,0 +1,28 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.EditorContent = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const react_1 = require("react");
const remotion_1 = require("remotion");
const is_current_selected_still_1 = require("../helpers/is-current-selected-still");
const InitialCompositionLoader_1 = require("./InitialCompositionLoader");
const MenuToolbar_1 = require("./MenuToolbar");
const SplitterContainer_1 = require("./Splitter/SplitterContainer");
const SplitterElement_1 = require("./Splitter/SplitterElement");
const SplitterHandle_1 = require("./Splitter/SplitterHandle");
const Timeline_1 = require("./Timeline/Timeline");
const noop = () => undefined;
const container = {
display: 'flex',
flexDirection: 'column',
flex: 1,
height: 0,
};
const EditorContent = ({ readOnlyStudio, children }) => {
const isStill = (0, is_current_selected_still_1.useIsStill)();
const { canvasContent } = (0, react_1.useContext)(remotion_1.Internals.CompositionManager);
// Preventing multiple renders so the update check doesn't get rendered twice and needs to be aborted
const onlyTopPanel = canvasContent === null || isStill || canvasContent.type !== 'composition';
return ((0, jsx_runtime_1.jsxs)("div", { style: container, children: [(0, jsx_runtime_1.jsx)(InitialCompositionLoader_1.InitialCompositionLoader, {}), (0, jsx_runtime_1.jsx)(MenuToolbar_1.MenuToolbar, { readOnlyStudio: readOnlyStudio }), (0, jsx_runtime_1.jsxs)(SplitterContainer_1.SplitterContainer, { orientation: "horizontal", id: "top-to-bottom", maxFlex: 0.9, minFlex: 0.2, defaultFlex: 0.75, children: [(0, jsx_runtime_1.jsx)(SplitterElement_1.SplitterElement, { sticky: null, type: "flexer", children: children }), onlyTopPanel ? null : ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(SplitterHandle_1.SplitterHandle, { allowToCollapse: "none", onCollapse: noop }), (0, jsx_runtime_1.jsx)(SplitterElement_1.SplitterElement, { sticky: null, type: "anti-flexer", children: (0, jsx_runtime_1.jsx)(Timeline_1.Timeline, {}) })] }))] })] }));
};
exports.EditorContent = EditorContent;
@@ -0,0 +1,5 @@
import React from 'react';
export declare const EditorContexts: React.FC<{
readonly children: React.ReactNode;
readonly readOnlyStudio: boolean;
}>;
@@ -0,0 +1,26 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.EditorContexts = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const player_1 = require("@remotion/player");
const client_id_1 = require("../helpers/client-id");
const folders_1 = require("../state/folders");
const highest_z_index_1 = require("../state/highest-z-index");
const keybindings_1 = require("../state/keybindings");
const preview_size_1 = require("../state/preview-size");
const sidebar_1 = require("../state/sidebar");
const VisualControls_1 = require("../visual-controls/VisualControls");
const CheckerboardProvider_1 = require("./CheckerboardProvider");
const get_zod_if_possible_1 = require("./get-zod-if-possible");
const MediaVolumeProvider_1 = require("./MediaVolumeProvider");
const ModalsProvider_1 = require("./ModalsProvider");
const ClientRenderQueueProcessor_1 = require("./RenderQueue/ClientRenderQueueProcessor");
const context_1 = require("./RenderQueue/context");
const SetTimelineInOutProvider_1 = require("./SetTimelineInOutProvider");
const ShowGuidesProvider_1 = require("./ShowGuidesProvider");
const ShowRulersProvider_1 = require("./ShowRulersProvider");
const ZoomGesturesProvider_1 = require("./ZoomGesturesProvider");
const EditorContexts = ({ children, readOnlyStudio }) => {
return ((0, jsx_runtime_1.jsx)(get_zod_if_possible_1.ZodProvider, { children: (0, jsx_runtime_1.jsx)(VisualControls_1.VisualControlsProvider, { children: (0, jsx_runtime_1.jsx)(client_id_1.PreviewServerConnection, { readOnlyStudio: readOnlyStudio, children: (0, jsx_runtime_1.jsxs)(context_1.RenderQueueContextProvider, { children: [(0, jsx_runtime_1.jsx)(ClientRenderQueueProcessor_1.ClientRenderQueueProcessor, {}), (0, jsx_runtime_1.jsx)(keybindings_1.KeybindingContextProvider, { children: (0, jsx_runtime_1.jsx)(CheckerboardProvider_1.CheckerboardProvider, { children: (0, jsx_runtime_1.jsx)(ZoomGesturesProvider_1.ZoomGesturesProvider, { children: (0, jsx_runtime_1.jsx)(ShowRulersProvider_1.ShowRulersProvider, { children: (0, jsx_runtime_1.jsx)(ShowGuidesProvider_1.ShowGuidesProvider, { children: (0, jsx_runtime_1.jsx)(preview_size_1.PreviewSizeProvider, { children: (0, jsx_runtime_1.jsx)(ModalsProvider_1.ModalsProvider, { children: (0, jsx_runtime_1.jsx)(MediaVolumeProvider_1.MediaVolumeProvider, { children: (0, jsx_runtime_1.jsx)(player_1.PlayerInternals.PlayerEmitterProvider, { currentPlaybackRate: null, children: (0, jsx_runtime_1.jsx)(sidebar_1.SidebarContextProvider, { children: (0, jsx_runtime_1.jsx)(folders_1.FolderContextProvider, { children: (0, jsx_runtime_1.jsx)(highest_z_index_1.HighestZIndexProvider, { children: (0, jsx_runtime_1.jsx)(SetTimelineInOutProvider_1.SetTimelineInOutProvider, { children: children }) }) }) }) }) }) }) }) }) }) }) }) })] }) }) }) }));
};
exports.EditorContexts = EditorContexts;
@@ -0,0 +1,12 @@
import type { Guide } from '../../state/editor-guides';
declare const _default: import("react").NamedExoticComponent<{
guide: Guide;
canvasDimensions: {
left: number;
top: number;
width: number;
height: number;
};
scale: number;
}>;
export default _default;
@@ -0,0 +1,91 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const jsx_runtime_1 = require("react/jsx-runtime");
const react_1 = require("react");
const no_react_1 = require("remotion/no-react");
const colors_1 = require("../../helpers/colors");
const editor_guides_1 = require("../../state/editor-guides");
const editor_rulers_1 = require("../../state/editor-rulers");
const ContextMenu_1 = require("../ContextMenu");
const PADDING_FOR_EASY_DRAG = 4;
const GuideComp = ({ guide, canvasDimensions, scale }) => {
const { shouldCreateGuideRef, setGuidesList, setSelectedGuideId, selectedGuideId, setHoveredGuideId, hoveredGuideId, } = (0, react_1.useContext)(editor_guides_1.EditorShowGuidesContext);
const onPointerEnter = (0, react_1.useCallback)(() => {
setHoveredGuideId(() => guide.id);
}, [guide.id, setHoveredGuideId]);
const onPointerLeave = (0, react_1.useCallback)(() => {
setHoveredGuideId(() => null);
}, [setHoveredGuideId]);
const isVerticalGuide = guide.orientation === 'vertical';
const guideStyle = (0, react_1.useMemo)(() => {
const canvasPosition = isVerticalGuide
? canvasDimensions.left
: canvasDimensions.top;
const guidePosition = guide.position * scale + canvasPosition;
return {
position: 'absolute',
width: `${isVerticalGuide ? '1px' : '100%'}`,
height: `${isVerticalGuide ? '100%' : '1px'}`,
left: `${isVerticalGuide ? guidePosition - PADDING_FOR_EASY_DRAG : 0}px`,
top: `${isVerticalGuide ? 0 : guidePosition - PADDING_FOR_EASY_DRAG}px`,
cursor: `${isVerticalGuide ? 'ew-resize' : 'ns-resize'}`,
padding: isVerticalGuide
? `0 ${PADDING_FOR_EASY_DRAG}px`
: `${PADDING_FOR_EASY_DRAG}px 0`,
};
}, [guide, scale, canvasDimensions, isVerticalGuide]);
const guideContentStyle = (0, react_1.useMemo)(() => {
return {
position: 'relative',
minWidth: `${isVerticalGuide ? '1px' : `calc(100% + ${editor_rulers_1.RULER_WIDTH}px`}`,
minHeight: `${isVerticalGuide ? `calc(100% + ${editor_rulers_1.RULER_WIDTH}px` : '1px'}`,
top: `${isVerticalGuide ? `-${editor_rulers_1.RULER_WIDTH}px` : '0px'}`,
left: `${isVerticalGuide ? '0px' : `-${editor_rulers_1.RULER_WIDTH}px`}`,
display: guide.show ? 'block' : 'none',
backgroundColor: selectedGuideId === guide.id || hoveredGuideId === guide.id
? colors_1.SELECTED_GUIDE
: colors_1.UNSELECTED_GUIDE,
};
}, [isVerticalGuide, guide.show, guide.id, selectedGuideId, hoveredGuideId]);
const onMouseDown = (0, react_1.useCallback)((e) => {
e.preventDefault();
if (e.button !== 0) {
return;
}
shouldCreateGuideRef.current = true;
document.body.style.cursor = 'no-drop';
setSelectedGuideId(() => guide.id);
}, [shouldCreateGuideRef, setSelectedGuideId, guide.id]);
const values = (0, react_1.useMemo)(() => {
return [
{
id: '1',
keyHint: null,
label: 'Remove guide',
leftItem: null,
onClick: () => {
setGuidesList((prevState) => {
const newGuides = prevState.filter((selected) => {
return selected.id !== guide.id;
});
(0, editor_guides_1.persistGuidesList)(newGuides);
return newGuides;
});
},
quickSwitcherLabel: null,
subMenu: null,
type: 'item',
value: 'remove',
},
];
}, [guide.id, setGuidesList]);
return ((0, jsx_runtime_1.jsx)(ContextMenu_1.ContextMenu, { values: values, children: (0, jsx_runtime_1.jsx)("div", { style: guideStyle, onMouseDown: onMouseDown, className: "__remotion_editor_guide", onPointerEnter: onPointerEnter, onPointerLeave: onPointerLeave, children: (0, jsx_runtime_1.jsx)("div", { style: guideContentStyle, className: [
'__remotion_editor_guide_content',
selectedGuideId === guide.id || hoveredGuideId === guide.id
? '__remotion_editor_guide_selected'
: null,
]
.filter(no_react_1.NoReactInternals.truthy)
.join(' ') }) }) }));
};
exports.default = (0, react_1.memo)(GuideComp);
@@ -0,0 +1,9 @@
import { type Size } from '@remotion/player';
import type { AssetMetadata } from '../../helpers/get-asset-metadata';
import type { Dimensions } from '../../helpers/is-current-selected-still';
declare const EditorGuides: React.FC<{
canvasSize: Size | null;
contentDimensions: Dimensions | 'none' | null;
assetMetadata: AssetMetadata | null;
}>;
export default EditorGuides;
@@ -0,0 +1,32 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const jsx_runtime_1 = require("react/jsx-runtime");
const react_1 = require("react");
const remotion_1 = require("remotion");
const use_studio_canvas_dimensions_1 = require("../../helpers/use-studio-canvas-dimensions");
const editor_guides_1 = require("../../state/editor-guides");
const Guide_1 = __importDefault(require("./Guide"));
const EditorGuides = ({ canvasSize, contentDimensions, assetMetadata }) => {
const { canvasPosition: canvasDimensions, scale } = (0, use_studio_canvas_dimensions_1.useStudioCanvasDimensions)({
canvasSize,
contentDimensions,
assetMetadata,
});
const { canvasContent } = (0, react_1.useContext)(remotion_1.Internals.CompositionManager);
if (canvasContent === null || canvasContent.type !== 'composition') {
throw new Error('Expected to be in a composition');
}
const { guidesList } = (0, react_1.useContext)(editor_guides_1.EditorShowGuidesContext);
const guidesForThisComposition = (0, react_1.useMemo)(() => {
return guidesList.filter((guide) => {
return guide.compositionId === canvasContent.compositionId;
});
}, [canvasContent.compositionId, guidesList]);
return ((0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: guidesForThisComposition.map((guide) => {
return ((0, jsx_runtime_1.jsx)(Guide_1.default, { guide: guide, canvasDimensions: canvasDimensions, scale: scale }, guide.id));
}) }));
};
exports.default = EditorGuides;
@@ -0,0 +1,17 @@
import type { Size } from '@remotion/player';
import React from 'react';
interface Point {
value: number;
position: number;
}
interface RulerProps {
readonly scale: number;
readonly points: Point[];
readonly originOffset: number;
readonly startMarking: number;
readonly markingGaps: number;
readonly orientation: 'horizontal' | 'vertical';
readonly size: Size;
}
declare const Ruler: React.FC<RulerProps>;
export default Ruler;
@@ -0,0 +1,108 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const jsx_runtime_1 = require("react/jsx-runtime");
const react_1 = require("react");
const remotion_1 = require("remotion");
const colors_1 = require("../../helpers/colors");
const editor_ruler_1 = require("../../helpers/editor-ruler");
const editor_guides_1 = require("../../state/editor-guides");
const editor_rulers_1 = require("../../state/editor-rulers");
const makeGuideId = () => {
return Math.random().toString(36).substring(7);
};
const Ruler = ({ scale, points, originOffset, startMarking, size, markingGaps, orientation, }) => {
const rulerCanvasRef = (0, react_1.useRef)(null);
const isVerticalRuler = orientation === 'vertical';
const { shouldCreateGuideRef, setGuidesList, selectedGuideId, hoveredGuideId, setSelectedGuideId, guidesList, setEditorShowGuides, } = (0, react_1.useContext)(editor_guides_1.EditorShowGuidesContext);
const unsafeVideoConfig = remotion_1.Internals.useUnsafeVideoConfig();
if (!unsafeVideoConfig) {
throw new Error('Video config not set');
}
const [cursor, setCursor] = (0, react_1.useState)(isVerticalRuler ? 'ew-resize' : 'ns-resize');
const selectedOrHoveredGuide = (0, react_1.useMemo)(() => {
var _a, _b;
return ((_b = (_a = guidesList.find((guide) => guide.id === selectedGuideId)) !== null && _a !== void 0 ? _a : guidesList.find((guide) => guide.id === hoveredGuideId)) !== null && _b !== void 0 ? _b : null);
}, [guidesList, hoveredGuideId, selectedGuideId]);
const rulerWidth = isVerticalRuler ? editor_rulers_1.RULER_WIDTH : size.width - editor_rulers_1.RULER_WIDTH;
const rulerHeight = isVerticalRuler ? size.height - editor_rulers_1.RULER_WIDTH : editor_rulers_1.RULER_WIDTH;
(0, react_1.useEffect)(() => {
(0, editor_ruler_1.drawMarkingOnRulerCanvas)({
scale,
points,
startMarking,
originOffset,
markingGaps,
orientation,
rulerCanvasRef,
selectedGuide: selectedOrHoveredGuide,
canvasHeight: rulerHeight * window.devicePixelRatio,
canvasWidth: rulerWidth * window.devicePixelRatio,
});
}, [
scale,
points,
startMarking,
originOffset,
markingGaps,
orientation,
selectedOrHoveredGuide,
size,
rulerHeight,
rulerWidth,
]);
const rulerStyle = (0, react_1.useMemo)(() => ({
position: 'absolute',
background: colors_1.BACKGROUND,
width: rulerWidth,
height: rulerHeight,
left: isVerticalRuler ? 0 : 'unset',
top: isVerticalRuler ? 'unset' : 0,
borderBottom: isVerticalRuler ? undefined : '1px solid ' + colors_1.RULER_COLOR,
borderRight: isVerticalRuler ? '1px solid ' + colors_1.RULER_COLOR : undefined,
cursor,
}), [rulerWidth, rulerHeight, cursor, isVerticalRuler]);
const onMouseDown = (0, react_1.useCallback)((e) => {
if (e.button !== 0) {
return;
}
e.preventDefault();
shouldCreateGuideRef.current = true;
document.body.style.cursor = 'no-drop';
const guideId = makeGuideId();
setEditorShowGuides(() => true);
setSelectedGuideId(() => guideId);
setGuidesList((prevState) => {
return [
...prevState,
{
orientation,
position: -originOffset,
show: false,
id: guideId,
compositionId: unsafeVideoConfig.id,
},
];
});
}, [
shouldCreateGuideRef,
setEditorShowGuides,
setSelectedGuideId,
setGuidesList,
orientation,
originOffset,
unsafeVideoConfig.id,
]);
const changeCursor = (0, react_1.useCallback)((e) => {
e.preventDefault();
if (selectedGuideId !== null) {
setCursor('no-drop');
}
}, [setCursor, selectedGuideId]);
(0, react_1.useEffect)(() => {
if (selectedGuideId === null) {
setCursor(isVerticalRuler ? 'ew-resize' : 'ns-resize');
}
}, [selectedGuideId, isVerticalRuler]);
return ((0, jsx_runtime_1.jsx)("canvas", { ref: rulerCanvasRef, width: rulerWidth * window.devicePixelRatio, height: rulerHeight * window.devicePixelRatio, style: rulerStyle, onPointerDown: onMouseDown, onPointerEnter: changeCursor, onPointerLeave: changeCursor }));
};
exports.default = Ruler;
@@ -0,0 +1,10 @@
import { type Size } from '@remotion/player';
import React from 'react';
import type { AssetMetadata } from '../../helpers/get-asset-metadata';
import type { Dimensions } from '../../helpers/is-current-selected-still';
export declare const EditorRulers: React.FC<{
readonly canvasSize: Size;
readonly contentDimensions: Dimensions | 'none' | null;
readonly assetMetadata: AssetMetadata | null;
readonly containerRef: React.RefObject<HTMLDivElement | null>;
}>;
@@ -0,0 +1,167 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.EditorRulers = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const react_1 = require("react");
const colors_1 = require("../../helpers/colors");
const editor_ruler_1 = require("../../helpers/editor-ruler");
const use_studio_canvas_dimensions_1 = require("../../helpers/use-studio-canvas-dimensions");
const editor_guides_1 = require("../../state/editor-guides");
const editor_rulers_1 = require("../../state/editor-rulers");
const Ruler_1 = __importDefault(require("./Ruler"));
const originBlockStyles = {
position: 'absolute',
top: 0,
left: 0,
borderBottom: '1px solid ' + colors_1.RULER_COLOR,
borderRight: '1px solid ' + colors_1.RULER_COLOR,
width: `${editor_rulers_1.RULER_WIDTH}px`,
height: `${editor_rulers_1.RULER_WIDTH}px`,
background: colors_1.BACKGROUND,
};
const EditorRulers = ({ contentDimensions, canvasSize, assetMetadata, containerRef }) => {
const { scale, canvasPosition } = (0, use_studio_canvas_dimensions_1.useStudioCanvasDimensions)({
canvasSize,
contentDimensions,
assetMetadata,
});
const { shouldCreateGuideRef, shouldDeleteGuideRef, setGuidesList, selectedGuideId, setSelectedGuideId, } = (0, react_1.useContext)(editor_guides_1.EditorShowGuidesContext);
const rulerMarkingGaps = (0, react_1.useMemo)(() => {
const minimumGap = editor_rulers_1.MINIMUM_RULER_MARKING_GAP_PX;
const predefinedGap = editor_rulers_1.PREDEFINED_RULER_SCALE_GAPS.find((gap) => gap * scale > minimumGap);
return predefinedGap || editor_rulers_1.MAXIMUM_PREDEFINED_RULER_SCALE_GAP;
}, [scale]);
const horizontalRulerScaleRange = (0, react_1.useMemo)(() => (0, editor_ruler_1.getRulerScaleRange)({
canvasLength: canvasPosition.width,
scale,
canvasSize,
}), [canvasPosition.width, canvasSize, scale]);
const verticalRulerScaleRange = (0, react_1.useMemo)(() => (0, editor_ruler_1.getRulerScaleRange)({
canvasLength: canvasPosition.height,
scale,
canvasSize,
}), [canvasPosition.height, canvasSize, scale]);
const { points: horizontalRulerPoints, startMarking: horizontalRulerStartMarking, } = (0, react_1.useMemo)(() => (0, editor_ruler_1.getRulerPoints)({
rulerScaleRange: horizontalRulerScaleRange,
rulerMarkingGaps,
scale,
}), [horizontalRulerScaleRange, rulerMarkingGaps, scale]);
const { points: verticalRulerPoints, startMarking: verticalRulerStartMarking } = (0, react_1.useMemo)(() => (0, editor_ruler_1.getRulerPoints)({
rulerScaleRange: verticalRulerScaleRange,
rulerMarkingGaps,
scale,
}), [verticalRulerScaleRange, rulerMarkingGaps, scale]);
const requestAnimationFrameRef = (0, react_1.useRef)(null);
const onMouseMove = (0, react_1.useCallback)((e) => {
if (requestAnimationFrameRef.current) {
cancelAnimationFrame(requestAnimationFrameRef.current);
}
requestAnimationFrameRef.current = requestAnimationFrame(() => {
var _a;
const { clientX: mouseX, clientY: mouseY } = e;
const { left: containerLeft = 0, top: containerTop = 0, right: containerRight = 0, bottom: containerBottom = 0, } = ((_a = containerRef.current) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect()) || {};
if (mouseX < containerLeft ||
mouseX > containerRight ||
mouseY < containerTop ||
mouseY > containerBottom) {
if (!shouldDeleteGuideRef.current) {
shouldDeleteGuideRef.current = true;
}
if (document.body.style.cursor !== 'no-drop') {
document.body.style.cursor = 'no-drop';
}
setGuidesList((prevState) => {
const newGuides = prevState.map((guide) => {
if (guide.id !== selectedGuideId) {
return guide;
}
return {
...guide,
show: false,
};
});
(0, editor_guides_1.persistGuidesList)(newGuides);
return newGuides;
});
}
else {
if (shouldDeleteGuideRef.current) {
shouldDeleteGuideRef.current = false;
}
setGuidesList((prevState) => {
// Intentionally no persist, only persist on mouse up
return prevState.map((guide) => {
if (guide.id !== selectedGuideId) {
return guide;
}
const position = guide.orientation === 'vertical'
? (mouseX - containerLeft) / scale -
canvasPosition.left / scale
: (mouseY - containerTop) / scale -
canvasPosition.top / scale;
const desiredCursor = guide.orientation === 'vertical' ? 'ew-resize' : 'ns-resize';
if (document.body.style.cursor !== desiredCursor) {
document.body.style.cursor = desiredCursor;
}
return {
...guide,
position: Math.floor(position / 1.0),
show: true,
};
});
});
}
});
}, [
containerRef,
shouldDeleteGuideRef,
setGuidesList,
selectedGuideId,
scale,
canvasPosition.left,
canvasPosition.top,
]);
const onMouseUp = (0, react_1.useCallback)(() => {
setGuidesList((prevState) => {
const newGuides = prevState.filter((selected) => {
if (!shouldDeleteGuideRef.current) {
return true;
}
return selected.id !== selectedGuideId;
});
(0, editor_guides_1.persistGuidesList)(newGuides);
return newGuides;
});
shouldDeleteGuideRef.current = false;
document.body.style.cursor = 'auto';
shouldCreateGuideRef.current = false;
setSelectedGuideId(() => null);
document.removeEventListener('pointerup', onMouseUp);
document.removeEventListener('pointermove', onMouseMove);
}, [
selectedGuideId,
shouldCreateGuideRef,
shouldDeleteGuideRef,
setSelectedGuideId,
setGuidesList,
onMouseMove,
]);
(0, react_1.useEffect)(() => {
if (selectedGuideId !== null) {
document.addEventListener('pointermove', onMouseMove);
document.addEventListener('pointerup', onMouseUp);
}
return () => {
document.removeEventListener('pointermove', onMouseMove);
document.removeEventListener('pointerup', onMouseUp);
if (requestAnimationFrameRef.current) {
cancelAnimationFrame(requestAnimationFrameRef.current);
}
};
}, [selectedGuideId, onMouseMove, onMouseUp]);
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("div", { style: originBlockStyles }), (0, jsx_runtime_1.jsx)(Ruler_1.default, { orientation: "horizontal", scale: scale, points: horizontalRulerPoints, startMarking: horizontalRulerStartMarking, markingGaps: rulerMarkingGaps, originOffset: canvasPosition.left, size: canvasSize }), (0, jsx_runtime_1.jsx)(Ruler_1.default, { orientation: "vertical", scale: scale, points: verticalRulerPoints, startMarking: verticalRulerStartMarking, markingGaps: rulerMarkingGaps, originOffset: canvasPosition.top, size: canvasSize })] }));
};
exports.EditorRulers = EditorRulers;
@@ -0,0 +1 @@
export declare const useIsRulerVisible: () => boolean | null;
@@ -0,0 +1,12 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.useIsRulerVisible = void 0;
const react_1 = require("react");
const remotion_1 = require("remotion");
const editor_rulers_1 = require("../../state/editor-rulers");
const useIsRulerVisible = () => {
const { canvasContent } = (0, react_1.useContext)(remotion_1.Internals.CompositionManager);
const { editorShowRulers } = (0, react_1.useContext)(editor_rulers_1.EditorShowRulersContext);
return (editorShowRulers && canvasContent && canvasContent.type === 'composition');
};
exports.useIsRulerVisible = useIsRulerVisible;
@@ -0,0 +1,7 @@
export declare const explorerSidebarTabs: import("react").RefObject<{
selectAssetsPanel: () => void;
selectCompositionPanel: () => void;
} | null>;
export declare const ExplorerPanel: React.FC<{
readOnlyStudio: boolean;
}>;
@@ -0,0 +1,58 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ExplorerPanel = exports.explorerSidebarTabs = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const react_1 = require("react");
const colors_1 = require("../helpers/colors");
const AssetSelector_1 = require("./AssetSelector");
const CompositionSelector_1 = require("./CompositionSelector");
const CompSelectorRef_1 = require("./CompSelectorRef");
const Tabs_1 = require("./Tabs");
const container = {
height: '100%',
width: '100%',
maxWidth: '100%',
display: 'flex',
flexDirection: 'column',
flex: 1,
};
const localStorageKey = 'remotion.sidebarPanel';
const getSelectedPanel = () => {
const panel = localStorage.getItem(localStorageKey);
if (panel === 'assets') {
return 'assets';
}
return 'compositions';
};
const tabsContainer = {
backgroundColor: colors_1.BACKGROUND,
};
const persistSelectedOptionsSidebarPanel = (panel) => {
localStorage.setItem(localStorageKey, panel);
};
exports.explorerSidebarTabs = (0, react_1.createRef)();
const ExplorerPanel = ({ readOnlyStudio }) => {
const [panel, setPanel] = (0, react_1.useState)(() => getSelectedPanel());
const onCompositionsSelected = (0, react_1.useCallback)(() => {
setPanel('compositions');
persistSelectedOptionsSidebarPanel('compositions');
}, []);
const onAssetsSelected = (0, react_1.useCallback)(() => {
setPanel('assets');
persistSelectedOptionsSidebarPanel('assets');
}, []);
(0, react_1.useImperativeHandle)(exports.explorerSidebarTabs, () => {
return {
selectAssetsPanel: () => {
setPanel('assets');
persistSelectedOptionsSidebarPanel('assets');
},
selectCompositionPanel: () => {
setPanel('compositions');
persistSelectedOptionsSidebarPanel('compositions');
},
};
}, []);
return ((0, jsx_runtime_1.jsx)(CompSelectorRef_1.CompSelectorRef, { children: (0, jsx_runtime_1.jsxs)("div", { style: container, className: "css-reset", children: [(0, jsx_runtime_1.jsx)("div", { style: tabsContainer, children: (0, jsx_runtime_1.jsxs)(Tabs_1.Tabs, { children: [(0, jsx_runtime_1.jsx)(Tabs_1.Tab, { selected: panel === 'compositions', onClick: onCompositionsSelected, children: "Compositions" }), (0, jsx_runtime_1.jsx)(Tabs_1.Tab, { selected: panel === 'assets', onClick: onAssetsSelected, children: "Assets" })] }) }), panel === 'compositions' ? ((0, jsx_runtime_1.jsx)(CompositionSelector_1.CompositionSelector, {})) : ((0, jsx_runtime_1.jsx)(AssetSelector_1.AssetSelector, { readOnlyStudio: readOnlyStudio }))] }) }));
};
exports.ExplorerPanel = ExplorerPanel;
@@ -0,0 +1,9 @@
import React from 'react';
import type { AssetMetadata } from '../helpers/get-asset-metadata';
import type { AssetFileType } from './Preview';
export declare const FilePreview: React.FC<{
readonly src: string;
readonly fileType: AssetFileType;
readonly currentAsset: string;
readonly assetMetadata: AssetMetadata | null;
}>;
@@ -0,0 +1,40 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.FilePreview = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const studio_shared_1 = require("@remotion/studio-shared");
const JSONViewer_1 = require("./JSONViewer");
const TextViewer_1 = require("./TextViewer");
const layout_1 = require("./layout");
const msgStyle = {
fontSize: 13,
color: 'white',
fontFamily: 'sans-serif',
display: 'flex',
justifyContent: 'center',
};
const FilePreview = ({ fileType, src, currentAsset, assetMetadata }) => {
if (!assetMetadata) {
throw new Error('expected to have assetMetadata');
}
if (assetMetadata.type === 'not-found') {
throw new Error('expected to have assetMetadata, got "not-found"');
}
if (fileType === 'audio') {
return (0, jsx_runtime_1.jsx)("audio", { src: src, controls: true });
}
if (fileType === 'video') {
return (0, jsx_runtime_1.jsx)("video", { src: src, controls: true });
}
if (fileType === 'image') {
return (0, jsx_runtime_1.jsx)("img", { src: src });
}
if (fileType === 'json') {
return (0, jsx_runtime_1.jsx)(JSONViewer_1.JSONViewer, { src: src });
}
if (fileType === 'txt') {
return (0, jsx_runtime_1.jsx)(TextViewer_1.TextViewer, { src: src });
}
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("div", { style: msgStyle, children: currentAsset }), (0, jsx_runtime_1.jsx)(layout_1.Spacing, { y: 0.5 }), (0, jsx_runtime_1.jsxs)("div", { style: msgStyle, children: ["Size: ", (0, studio_shared_1.formatBytes)(assetMetadata.size), " "] })] }));
};
exports.FilePreview = FilePreview;
@@ -0,0 +1,4 @@
import React from 'react';
export declare const FpsCounter: React.FC<{
readonly playbackSpeed: number;
}>;
@@ -0,0 +1,75 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.FpsCounter = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const react_1 = require("react");
const remotion_1 = require("remotion");
const label = {
color: 'white',
fontSize: 15,
fontFamily: 'Arial, Helvetica, sans-serif',
whiteSpace: 'nowrap',
};
const pushWithMaxSize = (arr, value, maxSize) => {
arr.push(value);
return arr.slice(-maxSize);
};
const FpsCounter = ({ playbackSpeed }) => {
const videoConfig = remotion_1.Internals.useUnsafeVideoConfig();
const [playing] = remotion_1.Internals.Timeline.usePlayingState();
const frame = remotion_1.Internals.Timeline.useTimelinePosition();
const [marker, rerender] = (0, react_1.useState)({});
const [fps, setFps] = (0, react_1.useState)(0);
const previousUpdates = (0, react_1.useRef)([]);
const fpsRef = (0, react_1.useRef)(0);
const playingRef = (0, react_1.useRef)(playing);
(0, react_1.useLayoutEffect)(() => {
fpsRef.current = 0;
previousUpdates.current = [];
playingRef.current = playing;
}, [playing]);
(0, react_1.useLayoutEffect)(() => {
if (playingRef.current === false)
return;
previousUpdates.current = pushWithMaxSize(previousUpdates.current, performance.now(), 15);
if (previousUpdates.current.length < 2)
return;
const diff = Math.max(...previousUpdates.current) -
Math.min(...previousUpdates.current);
const averageDistanceBetween = diff / (previousUpdates.current.length - 1);
fpsRef.current = 1000 / averageDistanceBetween;
if (previousUpdates.current.length === 2)
setFps(fpsRef.current);
/* This effect should depends only on frame, otherwise it will push extra updates to ref and fps will be wrong */
}, [frame]);
(0, react_1.useEffect)(() => {
if (playing) {
const t = setTimeout(() => {
rerender({});
setFps(fpsRef.current);
}, 1000);
return () => clearTimeout(t);
}
}, [marker, playing]);
const style = (0, react_1.useMemo)(() => {
if (!videoConfig) {
return {};
}
const expectedFps = Math.abs(playbackSpeed) * videoConfig.fps;
return {
...label,
color: fps < expectedFps * 0.9 ? 'red' : 'white',
};
}, [fps, playbackSpeed, videoConfig]);
if (fps === 0) {
return null;
}
if (playing === false) {
return null;
}
if (videoConfig === null) {
return null;
}
return (0, jsx_runtime_1.jsxs)("div", { style: style, children: [fps.toFixed(1), " FPS"] });
};
exports.FpsCounter = FpsCounter;
@@ -0,0 +1,2 @@
import type React from 'react';
export declare const FramePersistor: React.FC;
@@ -0,0 +1,22 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.FramePersistor = void 0;
const react_1 = require("react");
const remotion_1 = require("remotion");
const FramePersistor = () => {
const [playing] = remotion_1.Internals.Timeline.usePlayingState();
const config = (0, remotion_1.useVideoConfig)();
const frame = remotion_1.Internals.Timeline.useTimelinePosition();
const setFrame = remotion_1.Internals.useTimelineSetFrame();
(0, react_1.useEffect)(() => {
if (!playing) {
setFrame((f) => {
const newObj = { ...f, [config.id]: frame };
remotion_1.Internals.persistCurrentFrame(newObj);
return newObj;
});
}
}, [config.id, frame, playing, setFrame]);
return null;
};
exports.FramePersistor = FramePersistor;
@@ -0,0 +1 @@
export declare const FullScreenToggle: React.FC<{}>;
@@ -0,0 +1,48 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.FullScreenToggle = 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 use_keybinding_1 = require("../helpers/use-keybinding");
const canvas_ref_1 = require("../state/canvas-ref");
const ControlButton_1 = require("./ControlButton");
const accessibilityLabel = [
'Enter fullscreen preview',
(0, use_keybinding_1.areKeyboardShortcutsDisabled)() ? null : '(F)',
]
.filter(no_react_1.NoReactInternals.truthy)
.join(' ');
const FullScreenToggle = () => {
const keybindings = (0, use_keybinding_1.useKeybinding)();
const { setSize } = (0, react_1.useContext)(remotion_1.Internals.PreviewSizeContext);
const onClick = (0, react_1.useCallback)(() => {
var _a;
(_a = canvas_ref_1.drawRef.current) === null || _a === void 0 ? void 0 : _a.requestFullscreen();
if (document.fullscreenElement)
setSize(() => ({
size: 'auto',
translation: {
x: 0,
y: 0,
},
}));
}, [setSize]);
(0, react_1.useEffect)(() => {
const f = keybindings.registerKeybinding({
event: 'keydown',
key: 'f',
callback: onClick,
commandCtrlKey: false,
preventDefault: true,
triggerIfInputFieldFocused: false,
keepRegisteredWhenNotHighestContext: false,
});
return () => {
f.unregister();
};
}, [keybindings, onClick]);
return ((0, jsx_runtime_1.jsx)(ControlButton_1.ControlButton, { title: accessibilityLabel, "aria-label": accessibilityLabel, onClick: onClick, children: (0, jsx_runtime_1.jsx)("svg", { style: { width: 18, height: 18 }, viewBox: "0 0 448 512", fill: "#fff", children: (0, jsx_runtime_1.jsx)("path", { d: "M0 180V56c0-13.3 10.7-24 24-24h124c6.6 0 12 5.4 12 12v40c0 6.6-5.4 12-12 12H64v84c0 6.6-5.4 12-12 12H12c-6.6 0-12-5.4-12-12zM288 44v40c0 6.6 5.4 12 12 12h84v84c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12V56c0-13.3-10.7-24-24-24H300c-6.6 0-12 5.4-12 12zm148 276h-40c-6.6 0-12 5.4-12 12v84h-84c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h124c13.3 0 24-10.7 24-24V332c0-6.6-5.4-12-12-12zM160 468v-40c0-6.6-5.4-12-12-12H64v-84c0-6.6-5.4-12-12-12H12c-6.6 0-12 5.4-12 12v124c0 13.3 10.7 24 24 24h124c6.6 0 12-5.4 12-12z" }) }) }));
};
exports.FullScreenToggle = FullScreenToggle;
@@ -0,0 +1,2 @@
import type React from 'react';
export declare const GlobalKeybindings: React.FC;
@@ -0,0 +1,119 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.GlobalKeybindings = void 0;
const react_1 = require("react");
const use_keybinding_1 = require("../helpers/use-keybinding");
const checkerboard_1 = require("../state/checkerboard");
const modals_1 = require("../state/modals");
const AskAiModal_1 = require("./AskAiModal");
const CompositionSelector_1 = require("./CompositionSelector");
const NotificationCenter_1 = require("./Notifications/NotificationCenter");
const GlobalKeybindings = () => {
const keybindings = (0, use_keybinding_1.useKeybinding)();
const { setSelectedModal } = (0, react_1.useContext)(modals_1.ModalsContext);
const { setCheckerboard } = (0, react_1.useContext)(checkerboard_1.CheckerboardContext);
const { navigateToNextComposition, navigateToPreviousComposition } = (0, CompositionSelector_1.useCompositionNavigation)();
(0, react_1.useEffect)(() => {
const nKey = keybindings.registerKeybinding({
event: 'keypress',
key: 'n',
callback: () => {
(0, NotificationCenter_1.showNotification)(`To make a new composition, right-click an existing one and select "Duplicate"`, 5000);
},
commandCtrlKey: false,
preventDefault: true,
triggerIfInputFieldFocused: false,
keepRegisteredWhenNotHighestContext: false,
});
const cmdKKey = keybindings.registerKeybinding({
event: 'keydown',
key: 'k',
callback: () => {
setSelectedModal({
type: 'quick-switcher',
mode: 'compositions',
invocationTimestamp: Date.now(),
});
},
triggerIfInputFieldFocused: true,
keepRegisteredWhenNotHighestContext: false,
commandCtrlKey: true,
preventDefault: true,
});
const cmdIKey = process.env.ASK_AI_ENABLED
? keybindings.registerKeybinding({
event: 'keydown',
key: 'i',
callback: () => {
var _a;
(_a = AskAiModal_1.askAiModalRef.current) === null || _a === void 0 ? void 0 : _a.toggle();
},
triggerIfInputFieldFocused: true,
keepRegisteredWhenNotHighestContext: true,
commandCtrlKey: true,
preventDefault: true,
})
: null;
const cKey = keybindings.registerKeybinding({
event: 'keypress',
key: 't',
callback: () => {
setCheckerboard((c) => !c);
},
commandCtrlKey: false,
preventDefault: true,
triggerIfInputFieldFocused: false,
keepRegisteredWhenNotHighestContext: false,
});
const questionMark = keybindings.registerKeybinding({
event: 'keypress',
key: '?',
callback: () => {
setSelectedModal({
type: 'quick-switcher',
mode: 'docs',
invocationTimestamp: Date.now(),
});
},
commandCtrlKey: false,
preventDefault: true,
triggerIfInputFieldFocused: false,
keepRegisteredWhenNotHighestContext: false,
});
const pageDown = keybindings.registerKeybinding({
event: 'keydown',
key: 'PageDown',
callback: navigateToNextComposition,
commandCtrlKey: false,
preventDefault: true,
triggerIfInputFieldFocused: false,
keepRegisteredWhenNotHighestContext: false,
});
const pageUp = keybindings.registerKeybinding({
event: 'keydown',
key: 'PageUp',
callback: navigateToPreviousComposition,
commandCtrlKey: false,
preventDefault: true,
triggerIfInputFieldFocused: false,
keepRegisteredWhenNotHighestContext: false,
});
return () => {
nKey.unregister();
cKey.unregister();
questionMark.unregister();
cmdKKey.unregister();
cmdIKey === null || cmdIKey === void 0 ? void 0 : cmdIKey.unregister();
pageDown.unregister();
pageUp.unregister();
};
}, [
keybindings,
setCheckerboard,
setSelectedModal,
navigateToNextComposition,
navigateToPreviousComposition,
]);
return null;
};
exports.GlobalKeybindings = GlobalKeybindings;
@@ -0,0 +1,5 @@
import React from 'react';
export declare const GlobalPropsEditorUpdateButton: React.FC<{
readonly compositionId: string;
readonly currentDefaultProps: Record<string, unknown>;
}>;
@@ -0,0 +1,76 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.GlobalPropsEditorUpdateButton = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const react_1 = __importStar(require("react"));
const remotion_1 = require("remotion");
const save_default_props_1 = require("../api/save-default-props");
const fast_refresh_context_1 = require("../fast-refresh-context");
const NotificationCenter_1 = require("./Notifications/NotificationCenter");
const SchemaResetButton_1 = require("./RenderModal/SchemaEditor/SchemaResetButton");
const SchemaSaveButton_1 = require("./RenderModal/SchemaEditor/SchemaSaveButton");
const container = {
display: 'inline-block',
flexDirection: 'row',
};
const GlobalPropsEditorUpdateButton = ({ compositionId, currentDefaultProps }) => {
const { fastRefreshes } = (0, react_1.useContext)(fast_refresh_context_1.FastRefreshContext);
const [disabled, setDisabled] = react_1.default.useState(false);
const onClicked = (0, react_1.useCallback)(() => {
setDisabled(true);
window.remotion_ignoreFastRefreshUpdate = fastRefreshes + 1;
(0, save_default_props_1.saveDefaultProps)({
compositionId,
defaultProps: () => currentDefaultProps,
})
.catch((err) => {
(0, NotificationCenter_1.showNotification)(`Cannot update default props: ${err.stack}`, 2000);
})
.finally(() => {
setDisabled(true);
});
}, [compositionId, currentDefaultProps, fastRefreshes]);
const onReset = (0, react_1.useCallback)(() => {
window.remotion_ignoreFastRefreshUpdate = null;
window.dispatchEvent(new CustomEvent(remotion_1.Internals.PROPS_UPDATED_EXTERNALLY, {
detail: {
resetUnsaved: compositionId,
},
}));
}, [compositionId]);
return ((0, jsx_runtime_1.jsxs)("div", { style: container, children: [(0, jsx_runtime_1.jsx)(SchemaResetButton_1.SchemaResetButton, { onClick: onReset }), (0, jsx_runtime_1.jsx)(SchemaSaveButton_1.SchemaSaveButton, { disabled: disabled, onClick: onClicked })] }));
};
exports.GlobalPropsEditorUpdateButton = GlobalPropsEditorUpdateButton;
@@ -0,0 +1,5 @@
import type React from 'react';
import type { _InternalTypes } from 'remotion';
export declare const useSelectAsset: () => (asset: string) => void;
export declare const useSelectComposition: () => (c: _InternalTypes["AnyComposition"], push: boolean) => void;
export declare const InitialCompositionLoader: React.FC;
@@ -0,0 +1,136 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.InitialCompositionLoader = exports.useSelectComposition = exports.useSelectAsset = void 0;
const react_1 = require("react");
const remotion_1 = require("remotion");
const get_static_files_1 = require("../api/get-static-files");
const mobile_layout_1 = require("../helpers/mobile-layout");
const url_state_1 = require("../helpers/url-state");
const folders_1 = require("../state/folders");
const sidebar_1 = require("../state/sidebar");
const CompositionSelector_1 = require("./CompositionSelector");
const ExplorerPanel_1 = require("./ExplorerPanel");
const load_canvas_content_from_url_1 = require("./load-canvas-content-from-url");
const useSelectAsset = () => {
const { setCanvasContent } = (0, react_1.useContext)(remotion_1.Internals.CompositionSetters);
const { setAssetFoldersExpanded } = (0, react_1.useContext)(folders_1.FolderContext);
return (asset) => {
var _a;
setCanvasContent({ type: 'asset', asset });
(_a = ExplorerPanel_1.explorerSidebarTabs.current) === null || _a === void 0 ? void 0 : _a.selectAssetsPanel();
setAssetFoldersExpanded((ex) => {
const split = asset.split('/');
const keysToExpand = split.map((_, i) => {
return split.slice(0, i).join('/');
});
const newState = {
...ex,
};
for (const key of keysToExpand) {
newState[key] = true;
}
return newState;
});
};
};
exports.useSelectAsset = useSelectAsset;
const useSelectComposition = () => {
const { setCompositionFoldersExpanded } = (0, react_1.useContext)(folders_1.FolderContext);
const { setCanvasContent } = (0, react_1.useContext)(remotion_1.Internals.CompositionSetters);
const isMobileLayout = (0, mobile_layout_1.useMobileLayout)();
const { setSidebarCollapsedState } = (0, react_1.useContext)(sidebar_1.SidebarContext);
return (0, react_1.useCallback)((c, push) => {
var _a;
if (push) {
(0, url_state_1.pushUrl)(`/${c.id}`);
}
(_a = ExplorerPanel_1.explorerSidebarTabs.current) === null || _a === void 0 ? void 0 : _a.selectCompositionPanel();
setCanvasContent({ type: 'composition', compositionId: c.id });
const { folderName, parentFolderName } = c;
if (folderName !== null) {
setCompositionFoldersExpanded((ex) => {
const keysToExpand = (0, CompositionSelector_1.getKeysToExpand)(folderName, parentFolderName);
const newState = {
...ex,
};
for (const key of keysToExpand) {
newState[key] = true;
}
return newState;
});
if (isMobileLayout) {
setSidebarCollapsedState({ left: 'collapsed', right: 'collapsed' });
}
}
}, [
isMobileLayout,
setCanvasContent,
setCompositionFoldersExpanded,
setSidebarCollapsedState,
]);
};
exports.useSelectComposition = useSelectComposition;
const InitialCompositionLoader = () => {
const { compositions, canvasContent } = (0, react_1.useContext)(remotion_1.Internals.CompositionManager);
const { setCanvasContent } = (0, react_1.useContext)(remotion_1.Internals.CompositionSetters);
const selectComposition = (0, exports.useSelectComposition)();
const selectAsset = (0, exports.useSelectAsset)();
(0, react_1.useEffect)(() => {
if (canvasContent) {
return;
}
const canvasContentFromUrl = (0, load_canvas_content_from_url_1.deriveCanvasContentFromUrl)();
if (canvasContentFromUrl && canvasContentFromUrl.type === 'composition') {
const exists = compositions.find((c) => c.id === canvasContentFromUrl.compositionId);
if (exists) {
selectComposition(exists, false);
}
return;
}
if (canvasContentFromUrl && canvasContentFromUrl.type === 'asset') {
selectAsset(canvasContentFromUrl.asset);
return;
}
if (canvasContentFromUrl && canvasContentFromUrl.type === 'output') {
setCanvasContent(canvasContentFromUrl);
return;
}
if (compositions.length > 0) {
selectComposition(compositions[0], true);
}
}, [
compositions,
canvasContent,
selectComposition,
setCanvasContent,
selectAsset,
]);
(0, react_1.useEffect)(() => {
const onchange = () => {
const newCanvas = (0, load_canvas_content_from_url_1.deriveCanvasContentFromUrl)();
if (newCanvas && newCanvas.type === 'composition') {
const newComp = (0, url_state_1.getRoute)().substring(1);
const exists = compositions.find((c) => c.id === newComp);
if (exists) {
selectComposition(exists, false);
}
return;
}
if (newCanvas && newCanvas.type === 'asset') {
const staticFiles = (0, get_static_files_1.getStaticFiles)();
const exists = staticFiles.find((file) => {
return file.name === newCanvas.asset;
});
if (exists) {
setCanvasContent(newCanvas);
}
return;
}
setCanvasContent(newCanvas);
};
window.addEventListener('popstate', onchange);
return () => window.removeEventListener('popstate', onchange);
}, [compositions, selectComposition, setCanvasContent]);
return null;
};
exports.InitialCompositionLoader = InitialCompositionLoader;
@@ -0,0 +1,9 @@
import React from 'react';
export type RenderInlineAction = (color: string) => React.ReactNode;
export type InlineActionProps = {
readonly onClick: React.MouseEventHandler<HTMLButtonElement>;
readonly disabled?: boolean;
readonly renderAction: RenderInlineAction;
readonly title?: string;
};
export declare const InlineAction: ({ renderAction, onClick, disabled, title, }: InlineActionProps) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,34 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.InlineAction = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const react_1 = require("react");
const colors_1 = require("../helpers/colors");
const z_index_1 = require("../state/z-index");
const InlineAction = ({ renderAction, onClick, disabled, title, }) => {
const { tabIndex } = (0, z_index_1.useZIndex)();
const [hovered, setHovered] = (0, react_1.useState)(false);
const onPointerEnter = (0, react_1.useCallback)(() => {
setHovered(true);
}, []);
const onPointerLeave = (0, react_1.useCallback)(() => {
setHovered(false);
}, []);
const style = (0, react_1.useMemo)(() => {
return {
border: 'none',
background: disabled
? 'transparent'
: (0, colors_1.getBackgroundFromHoverState)({ hovered, selected: false }),
height: 24,
width: 24,
display: 'inline-flex',
justifyContent: 'center',
alignItems: 'center',
borderRadius: 3,
pointerEvents: disabled ? 'none' : 'auto',
};
}, [disabled, hovered]);
return ((0, jsx_runtime_1.jsx)("button", { type: "button", onPointerEnter: onPointerEnter, onPointerLeave: onPointerLeave, onClick: onClick, style: style, tabIndex: tabIndex, title: title, children: renderAction(hovered ? 'white' : colors_1.LIGHT_TEXT) }));
};
exports.InlineAction = InlineAction;
@@ -0,0 +1,5 @@
import { type InlineActionProps } from './InlineAction';
import type { ComboboxValue } from './NewComposition/ComboBox';
export declare const InlineDropdown: ({ values, ...props }: Omit<InlineActionProps, "onClick"> & {
readonly values: ComboboxValue[];
}) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,85 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.InlineDropdown = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const player_1 = require("@remotion/player");
const react_1 = require("react");
const react_dom_1 = __importDefault(require("react-dom"));
const mobile_layout_1 = require("../helpers/mobile-layout");
const noop_1 = require("../helpers/noop");
const z_index_1 = require("../state/z-index");
const InlineAction_1 = require("./InlineAction");
const portals_1 = require("./Menu/portals");
const styles_1 = require("./Menu/styles");
const MenuContent_1 = require("./NewComposition/MenuContent");
const InlineDropdown = ({ values, ...props }) => {
const ref = (0, react_1.useRef)(null);
const [opened, setOpened] = (0, react_1.useState)({ type: 'not-open' });
const { currentZIndex } = (0, z_index_1.useZIndex)();
const size = player_1.PlayerInternals.useElementSize(ref, {
triggerOnWindowResize: true,
shouldApplyCssTransforms: true,
});
const isMobileLayout = (0, mobile_layout_1.useMobileLayout)();
const onClick = (0, react_1.useCallback)((e) => {
e.preventDefault();
e.stopPropagation();
setOpened({ type: 'open', left: e.clientX, top: e.clientY });
}, []);
const spaceToBottom = (0, react_1.useMemo)(() => {
if (size && opened.type === 'open') {
return size.windowSize.height - opened.top;
}
return 0;
}, [opened, size]);
const spaceToTop = (0, react_1.useMemo)(() => {
if (size && opened.type === 'open') {
return opened.top;
}
return 0;
}, [opened, size]);
const portalStyle = (0, react_1.useMemo)(() => {
if (opened.type === 'not-open') {
return;
}
if (!size) {
return;
}
const spaceToRight = size.windowSize.width - size.left;
const spaceToLeft = size.left + size.width;
const minSpaceRequired = isMobileLayout
? styles_1.MAX_MOBILE_MENU_WIDTH
: styles_1.MAX_MENU_WIDTH;
const verticalLayout = spaceToTop > spaceToBottom ? 'bottom' : 'top';
const canOpenOnLeft = spaceToLeft >= minSpaceRequired;
const canOpenOnRight = spaceToRight >= minSpaceRequired;
const horizontalLayout = canOpenOnRight ? 'left' : 'right';
return {
...styles_1.menuContainerTowardsTop,
...(verticalLayout === 'top'
? {
top: opened.top,
}
: {
bottom: size.windowSize.height - opened.top,
}),
...(horizontalLayout === 'left'
? {
left: opened.left,
}
: {
right: canOpenOnLeft ? size.windowSize.width - opened.left : 0,
}),
};
}, [opened, size, isMobileLayout, spaceToTop, spaceToBottom]);
const onHide = (0, react_1.useCallback)(() => {
setOpened({ type: 'not-open' });
}, []);
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("div", { ref: ref, children: (0, jsx_runtime_1.jsx)(InlineAction_1.InlineAction, { onClick: onClick, ...props }) }), portalStyle
? react_dom_1.default.createPortal((0, jsx_runtime_1.jsx)("div", { style: styles_1.fullScreenOverlay, children: (0, jsx_runtime_1.jsx)("div", { style: styles_1.outerPortal, className: "css-reset", children: (0, jsx_runtime_1.jsx)(z_index_1.HigherZIndex, { onOutsideClick: onHide, onEscape: onHide, children: (0, jsx_runtime_1.jsx)("div", { style: portalStyle, children: (0, jsx_runtime_1.jsx)(MenuContent_1.MenuContent, { onNextMenu: noop_1.noop, onPreviousMenu: noop_1.noop, values: values, onHide: onHide, leaveLeftSpace: true, preselectIndex: false, topItemCanBeUnselected: false, fixedHeight: null }) }) }) }) }), (0, portals_1.getPortal)(currentZIndex))
: null] }));
};
exports.InlineDropdown = InlineDropdown;
@@ -0,0 +1,5 @@
import type { PackageManager } from '@remotion/studio-shared';
import React from 'react';
export declare const InstallPackageModal: React.FC<{
readonly packageManager: PackageManager;
}>;
@@ -0,0 +1,140 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.InstallPackageModal = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const studio_shared_1 = require("@remotion/studio-shared");
const react_1 = __importStar(require("react"));
const remotion_1 = require("remotion");
const install_package_1 = require("../api/install-package");
const restart_studio_1 = require("../api/restart-studio");
const ShortcutHint_1 = require("../error-overlay/remotion-overlay/ShortcutHint");
const client_id_1 = require("../helpers/client-id");
const colors_1 = require("../helpers/colors");
const use_keybinding_1 = require("../helpers/use-keybinding");
const Checkbox_1 = require("./Checkbox");
const InstallablePackage_1 = require("./InstallablePackage");
const is_menu_item_1 = require("./Menu/is-menu-item");
const ModalButton_1 = require("./ModalButton");
const ModalFooter_1 = require("./ModalFooter");
const ModalHeader_1 = require("./ModalHeader");
const DismissableModal_1 = require("./NewComposition/DismissableModal");
const layout_1 = require("./layout");
const container = {
padding: 20,
maxHeight: 400,
overflowY: 'auto',
};
const text = {
fontSize: 14,
};
const InstallPackageModal = ({ packageManager }) => {
const [state, setState] = react_1.default.useState({ type: 'idle' });
const [map, setMap] = react_1.default.useState({});
const { previewServerState: ctx } = (0, react_1.useContext)(client_id_1.StudioServerConnectionCtx);
const selectedPackages = Object.keys(map).filter((pkg) => map[pkg]);
const onClick = (0, react_1.useCallback)(async () => {
if (state.type === 'done') {
setState({ type: 'restarting' });
(0, restart_studio_1.restartStudio)();
return;
}
setState({ type: 'installing' });
try {
await (0, install_package_1.installPackages)(selectedPackages);
setState({ type: 'done' });
}
catch (err) {
setState({ type: 'error', error: err });
}
}, [selectedPackages, state.type]);
const canSelectPackages = state.type === 'idle' && ctx.type === 'connected';
const disabled = !(canSelectPackages || state.type === 'done') ||
selectedPackages.length === 0;
const { registerKeybinding } = (0, use_keybinding_1.useKeybinding)();
(0, react_1.useEffect)(() => {
if (disabled) {
return;
}
const enter = registerKeybinding({
callback() {
onClick();
},
commandCtrlKey: true,
key: 'Enter',
event: 'keydown',
preventDefault: true,
triggerIfInputFieldFocused: true,
keepRegisteredWhenNotHighestContext: true,
});
return () => {
enter.unregister();
};
}, [disabled, onClick, registerKeybinding]);
return ((0, jsx_runtime_1.jsxs)(DismissableModal_1.DismissableModal, { children: [(0, jsx_runtime_1.jsx)(ModalHeader_1.ModalHeader, { title: "Install packages" }), (0, jsx_runtime_1.jsx)("div", { style: container, className: is_menu_item_1.VERTICAL_SCROLLBAR_CLASSNAME, children: state.type === 'done' ? ((0, jsx_runtime_1.jsxs)("div", { style: text, children: ["Installed package", selectedPackages.length === 1 ? '' : 's', ' ', "successfully. Restart the server to complete."] })) : state.type === 'restarting' ? ((0, jsx_runtime_1.jsx)("div", { style: text, children: "Restarting the Studio server..." })) : state.type === 'installing' ? ((0, jsx_runtime_1.jsxs)("div", { style: text, children: ["Installing package", selectedPackages.length === 1 ? '' : 's', ". Check your terminal for progress."] })) : ((0, jsx_runtime_1.jsxs)("div", { style: text, children: [Object.entries(studio_shared_1.installableMap)
.filter(([, install]) => install)
.map(([pkgShort]) => {
var _a, _b;
const pkg = pkgShort === 'core' ? 'remotion' : `@remotion/${pkgShort}`;
const isInstalled = (_b = (_a = window.remotion_installedPackages) === null || _a === void 0 ? void 0 : _a.includes(pkg)) !== null && _b !== void 0 ? _b : false;
const link = studio_shared_1.apiDocs[pkgShort];
const description = studio_shared_1.descriptions[pkgShort];
if (!link) {
throw new Error('No link for ' + pkg);
}
if (!description) {
throw new Error('No description for ' + pkg);
}
return ((0, jsx_runtime_1.jsxs)(layout_1.Row, { align: "center", children: [(0, jsx_runtime_1.jsx)(Checkbox_1.Checkbox, { checked: map[pkg], name: pkg, onChange: () => {
setMap((prev) => ({ ...prev, [pkg]: !prev[pkg] }));
}, disabled: !canSelectPackages || isInstalled }), (0, jsx_runtime_1.jsx)(layout_1.Spacing, { x: 1.5 }), (0, jsx_runtime_1.jsx)(InstallablePackage_1.InstallablePackageComp, { description: description, isInstalled: isInstalled, link: link, pkg: pkg })] }, pkg));
}), studio_shared_1.extraPackages.map((extraPkg) => {
var _a, _b;
const isInstalled = (_b = (_a = window.remotion_installedPackages) === null || _a === void 0 ? void 0 : _a.includes(extraPkg.name)) !== null && _b !== void 0 ? _b : false;
return ((0, jsx_runtime_1.jsxs)(layout_1.Row, { align: "center", children: [(0, jsx_runtime_1.jsx)(Checkbox_1.Checkbox, { checked: map[extraPkg.name], name: extraPkg.name, onChange: () => {
setMap((prev) => ({
...prev,
[extraPkg.name]: !prev[extraPkg.name],
}));
}, disabled: !canSelectPackages || isInstalled }), (0, jsx_runtime_1.jsx)(layout_1.Spacing, { x: 1.5 }), (0, jsx_runtime_1.jsx)(InstallablePackage_1.InstallablePackageComp, { description: extraPkg.description, isInstalled: isInstalled, link: extraPkg.docsUrl, pkg: `${extraPkg.name}@${extraPkg.version}` })] }, extraPkg.name));
})] })) }), (0, jsx_runtime_1.jsx)(ModalFooter_1.ModalFooterContainer, { children: (0, jsx_runtime_1.jsxs)(layout_1.Row, { align: "center", children: [state.type === 'idle' ? ((0, jsx_runtime_1.jsxs)("span", { style: { color: colors_1.LIGHT_TEXT, fontSize: 13, lineHeight: 1.2 }, children: ["This will install ", selectedPackages.length, " package", selectedPackages.length === 1 ? '' : 's', (0, jsx_runtime_1.jsx)("br", {}), "using ", packageManager, ", Remotion v", remotion_1.VERSION] })) : null, (0, jsx_runtime_1.jsx)(layout_1.Flex, {}), (0, jsx_runtime_1.jsxs)(ModalButton_1.ModalButton, { onClick: onClick, disabled: disabled, children: [state.type === 'restarting'
? 'Restarting...'
: state.type === 'installing'
? 'Installing...'
: state.type === 'done'
? 'Restart Server'
: 'Install', disabled ? null : (0, jsx_runtime_1.jsx)(ShortcutHint_1.ShortcutHint, { keyToPress: "\u21B5", cmdOrCtrl: true })] })] }) })] }));
};
exports.InstallPackageModal = InstallPackageModal;
@@ -0,0 +1,7 @@
import React from 'react';
export declare const InstallablePackageComp: React.FC<{
readonly isInstalled: boolean;
readonly pkg: string;
readonly link: string;
readonly description: string;
}>;
@@ -0,0 +1,19 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.InstallablePackageComp = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const colors_1 = require("../helpers/colors");
const FONT_SIZE = 13;
const InstallablePackageComp = ({ isInstalled, pkg, link, description }) => {
return ((0, jsx_runtime_1.jsxs)("div", { style: {
fontSize: FONT_SIZE,
lineHeight: 1.2,
paddingBottom: 4,
paddingTop: 4,
}, children: [(0, jsx_runtime_1.jsx)("a", { href: link, style: {
fontSize: FONT_SIZE,
color: colors_1.TEXT_COLOR,
textDecoration: 'none',
}, target: "_blank", children: pkg }), ' ', isInstalled ? ((0, jsx_runtime_1.jsx)("span", { style: { opacity: 0.3, fontSize: 'inherit' }, children: "(installed)" })) : null, (0, jsx_runtime_1.jsx)("br", {}), (0, jsx_runtime_1.jsx)("span", { style: { color: colors_1.LIGHT_TEXT, fontSize: FONT_SIZE }, children: description })] }));
};
exports.InstallablePackageComp = InstallablePackageComp;
@@ -0,0 +1,4 @@
import React from 'react';
export declare const JSONViewer: React.FC<{
readonly src: string;
}>;
@@ -0,0 +1,26 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.JSONViewer = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const react_1 = require("react");
const RemTextarea_1 = require("./NewComposition/RemTextarea");
const jsonStyle = {
marginTop: 14,
marginBottom: 14,
fontFamily: 'monospace',
flex: 1,
};
const JSONViewer = ({ src }) => {
const [json, setJson] = (0, react_1.useState)(null);
(0, react_1.useEffect)(() => {
fetch(src)
.then((res) => res.json())
.then((jsonRes) => {
setJson(JSON.stringify(jsonRes, null, 2));
});
}, [src]);
return ((0, jsx_runtime_1.jsx)(RemTextarea_1.RemTextarea, { value: json !== null && json !== void 0 ? json : undefined, status: "ok", onChange: () => {
return null;
}, style: jsonStyle }));
};
exports.JSONViewer = JSONViewer;
@@ -0,0 +1,2 @@
import React from 'react';
export declare const KeyboardShortcutsExplainer: React.FC;
File diff suppressed because one or more lines are too long
@@ -0,0 +1,4 @@
import type { Bug } from './UpdateCheck';
export declare const KnownBugs: React.FC<{
bugs: Bug[];
}>;
@@ -0,0 +1,21 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.KnownBugs = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const OpenIssueButton_1 = require("./UpdateModal/OpenIssueButton");
const container = {
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
};
const text = {
fontSize: 14,
flex: 1,
};
const KnownBugs = ({ bugs }) => {
const bugElements = bugs.map((bug) => {
return ((0, jsx_runtime_1.jsxs)("div", { style: container, children: [(0, jsx_runtime_1.jsxs)("div", { style: text, children: ["\uD83E\uDEB2 ", bug.title] }), (0, jsx_runtime_1.jsx)(OpenIssueButton_1.OpenIssueButton, { link: bug.link })] }, bug.description + bug.link));
});
return (0, jsx_runtime_1.jsx)("div", { children: bugElements });
};
exports.KnownBugs = KnownBugs;
@@ -0,0 +1,5 @@
import React from 'react';
export declare const LoopToggle: React.FC<{
readonly loop: boolean;
readonly setLoop: React.Dispatch<React.SetStateAction<boolean>>;
}>;
@@ -0,0 +1,19 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.LoopToggle = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const react_1 = require("react");
const colors_1 = require("../helpers/colors");
const loop_1 = require("../state/loop");
const ControlButton_1 = require("./ControlButton");
const accessibilityLabel = 'Loop video';
const LoopToggle = ({ loop, setLoop }) => {
const onClick = (0, react_1.useCallback)(() => {
setLoop((c) => {
(0, loop_1.persistLoopOption)(!c);
return !c;
});
}, [setLoop]);
return ((0, jsx_runtime_1.jsx)(ControlButton_1.ControlButton, { title: accessibilityLabel, "aria-label": accessibilityLabel, onClick: onClick, children: (0, jsx_runtime_1.jsx)("svg", { viewBox: "0 0 512 512", style: { width: 18, height: 18 }, children: (0, jsx_runtime_1.jsx)("path", { fill: loop ? colors_1.BLUE : 'white', d: "M493.544 181.463c11.956 22.605 18.655 48.4 18.452 75.75C511.339 345.365 438.56 416 350.404 416H192v47.495c0 22.475-26.177 32.268-40.971 17.475l-80-80c-9.372-9.373-9.372-24.569 0-33.941l80-80C166.138 271.92 192 282.686 192 304v48h158.875c52.812 0 96.575-42.182 97.12-94.992.155-15.045-3.17-29.312-9.218-42.046-4.362-9.185-2.421-20.124 4.8-27.284 4.745-4.706 8.641-8.555 11.876-11.786 11.368-11.352 30.579-8.631 38.091 5.571zM64.005 254.992c.545-52.81 44.308-94.992 97.12-94.992H320v47.505c0 22.374 26.121 32.312 40.971 17.465l80-80c9.372-9.373 9.372-24.569 0-33.941l-80-80C346.014 16.077 320 26.256 320 48.545V96H161.596C73.44 96 .661 166.635.005 254.788c-.204 27.35 6.495 53.145 18.452 75.75 7.512 14.202 26.723 16.923 38.091 5.57 3.235-3.231 7.13-7.08 11.876-11.786 7.22-7.16 9.162-18.098 4.8-27.284-6.049-12.735-9.374-27.001-9.219-42.046z" }) }) }));
};
exports.LoopToggle = LoopToggle;
@@ -0,0 +1,4 @@
import React from 'react';
export declare const MediaVolumeProvider: React.FC<{
readonly children: React.ReactNode;
}>;
@@ -0,0 +1,25 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MediaVolumeProvider = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const react_1 = require("react");
const remotion_1 = require("remotion");
const mute_1 = require("../state/mute");
const MediaVolumeProvider = ({ children }) => {
const [mediaMuted, setMediaMuted] = (0, react_1.useState)(() => (0, mute_1.loadMuteOption)());
const [mediaVolume, setMediaVolume] = (0, react_1.useState)(1);
const mediaVolumeContextValue = (0, react_1.useMemo)(() => {
return {
mediaMuted,
mediaVolume,
};
}, [mediaMuted, mediaVolume]);
const setMediaVolumeContextValue = (0, react_1.useMemo)(() => {
return {
setMediaMuted,
setMediaVolume,
};
}, []);
return ((0, jsx_runtime_1.jsx)(remotion_1.Internals.MediaVolumeContext.Provider, { value: mediaVolumeContextValue, children: (0, jsx_runtime_1.jsx)(remotion_1.Internals.SetMediaVolumeContext.Provider, { value: setMediaVolumeContextValue, children: children }) }));
};
exports.MediaVolumeProvider = MediaVolumeProvider;
@@ -0,0 +1,2 @@
import React from 'react';
export declare const MenuDivider: React.FC;
@@ -0,0 +1,15 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MenuDivider = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const colors_1 = require("../../helpers/colors");
const menuDivider = {
marginTop: 4,
marginBottom: 4,
height: 1,
backgroundColor: colors_1.INPUT_BORDER_COLOR_HOVERED,
};
const MenuDivider = () => {
return (0, jsx_runtime_1.jsx)("div", { style: menuDivider });
};
exports.MenuDivider = MenuDivider;
@@ -0,0 +1,22 @@
import type { SetStateAction } from 'react';
import React from 'react';
import type { ComboboxValue } from '../NewComposition/ComboBox';
export type MenuId = 'remotion' | 'file' | 'view' | 'install' | 'tools' | 'help';
export type Menu = {
id: MenuId;
label: React.ReactNode;
items: ComboboxValue[];
leaveLeftPadding: boolean;
};
export declare const MenuItem: React.FC<{
readonly label: React.ReactNode;
readonly id: MenuId;
readonly selected: boolean;
readonly onItemSelected: (s: SetStateAction<string | null>) => void;
readonly onItemHovered: (id: MenuId) => void;
readonly onItemQuit: () => void;
readonly onPreviousMenu: () => void;
readonly onNextMenu: () => void;
readonly menu: Menu;
readonly leaveLeftPadding: boolean;
}>;
@@ -0,0 +1,97 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.MenuItem = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const player_1 = require("@remotion/player");
const react_1 = require("react");
const react_dom_1 = __importDefault(require("react-dom"));
const colors_1 = require("../../helpers/colors");
const z_index_1 = require("../../state/z-index");
const MenuContent_1 = require("../NewComposition/MenuContent");
const is_menu_item_1 = require("./is-menu-item");
const portals_1 = require("./portals");
const styles_1 = require("./styles");
const container = {
fontSize: 13,
color: 'white',
paddingLeft: 10,
paddingRight: 10,
cursor: 'default',
paddingTop: 8,
paddingBottom: 8,
userSelect: 'none',
WebkitUserSelect: 'none',
border: 'none',
};
const MenuItem = ({ label: itemName, selected, id, onItemSelected, onItemHovered, onItemQuit, onPreviousMenu, onNextMenu, menu, }) => {
const [hovered, setHovered] = (0, react_1.useState)(false);
const ref = (0, react_1.useRef)(null);
const size = player_1.PlayerInternals.useElementSize(ref, {
triggerOnWindowResize: true,
shouldApplyCssTransforms: true,
});
const { tabIndex, currentZIndex } = (0, z_index_1.useZIndex)();
const containerStyle = (0, react_1.useMemo)(() => {
return {
...container,
backgroundColor: (0, colors_1.getBackgroundFromHoverState)({
hovered,
selected,
}),
};
}, [hovered, selected]);
const portalStyle = (0, react_1.useMemo)(() => {
if (!selected || !size) {
return null;
}
return {
...styles_1.menuContainerTowardsBottom,
left: size.left,
top: size.top + size.height,
};
}, [selected, size]);
const onPointerEnter = (0, react_1.useCallback)(() => {
onItemHovered(id);
setHovered(true);
}, [id, onItemHovered]);
const onPointerLeave = (0, react_1.useCallback)(() => {
setHovered(false);
}, []);
const onPointerDown = (0, react_1.useCallback)((e) => {
if (e.button !== 0) {
return;
}
onItemSelected(id);
window.addEventListener('pointerup', (evt) => {
if (!(0, is_menu_item_1.isMenuItem)(evt.target)) {
onItemQuit();
}
}, {
once: true,
});
}, [id, onItemQuit, onItemSelected]);
const onClick = (0, react_1.useCallback)((e) => {
e.stopPropagation();
const isKeyboardInitiated = e.detail === 0;
if (!isKeyboardInitiated) {
return;
}
onItemSelected((p) => {
return p === null ? id : null;
});
}, [id, onItemSelected]);
const outerStyle = (0, react_1.useMemo)(() => {
var _a, _b;
return {
...styles_1.outerPortal,
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),
};
}, [size]);
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("button", { ref: ref, role: "button", tabIndex: tabIndex, onPointerEnter: onPointerEnter, onPointerLeave: onPointerLeave, onPointerDown: onPointerDown, onClick: onClick, style: containerStyle, type: "button", className: is_menu_item_1.MENU_INITIATOR_CLASSNAME, children: itemName }), portalStyle
? react_dom_1.default.createPortal((0, jsx_runtime_1.jsx)("div", { className: "css-reset", style: outerStyle, children: (0, jsx_runtime_1.jsx)(z_index_1.HigherZIndex, { onEscape: onItemQuit, onOutsideClick: onItemQuit, children: (0, jsx_runtime_1.jsx)("div", { style: portalStyle, children: (0, jsx_runtime_1.jsx)(MenuContent_1.MenuContent, { onNextMenu: onPreviousMenu, onPreviousMenu: onNextMenu, values: menu.items, onHide: onItemQuit, leaveLeftSpace: menu.leaveLeftPadding, preselectIndex: false, topItemCanBeUnselected: true, fixedHeight: null }) }) }) }), (0, portals_1.getPortal)(currentZIndex))
: null] }));
};
exports.MenuItem = MenuItem;
@@ -0,0 +1,20 @@
import type { PointerEvent } from 'react';
import React from 'react';
import type { SubMenu } from '../NewComposition/ComboBox';
export type SubMenuActivated = false | 'with-mouse' | 'without-mouse';
export declare const MenuSubItem: React.FC<{
readonly label: React.ReactNode;
readonly id: string;
readonly onActionChosen: (id: string, e: PointerEvent<HTMLDivElement>) => void;
readonly selected: boolean;
readonly onItemSelected: (id: string) => void;
readonly keyHint: string | null;
readonly leaveLeftSpace: boolean;
readonly leftItem: React.ReactNode;
readonly subMenu: SubMenu | null;
readonly onQuitMenu: () => void;
readonly onNextMenu: () => void;
readonly subMenuActivated: SubMenuActivated;
readonly setSubMenuActivated: React.Dispatch<React.SetStateAction<SubMenuActivated>>;
readonly disabled?: boolean;
}>;
@@ -0,0 +1,121 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.MenuSubItem = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const player_1 = require("@remotion/player");
const react_1 = require("react");
const react_dom_1 = __importDefault(require("react-dom"));
const colors_1 = require("../../helpers/colors");
const mobile_layout_1 = require("../../helpers/mobile-layout");
const use_keybinding_1 = require("../../helpers/use-keybinding");
const caret_1 = require("../../icons/caret");
const z_index_1 = require("../../state/z-index");
const layout_1 = require("../layout");
const SubMenu_1 = require("./SubMenu");
const is_menu_item_1 = require("./is-menu-item");
const portals_1 = require("./portals");
const styles_1 = require("./styles");
const container = {
paddingTop: 8,
paddingBottom: 8,
paddingLeft: 12,
paddingRight: 8,
cursor: 'default',
};
const labelStyle = {
fontSize: 13,
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
flex: 1,
};
const keyHintCss = {
flexDirection: 'row',
color: colors_1.LIGHT_TEXT,
fontSize: 13,
};
const leftSpace = {
width: 24,
marginLeft: -6,
display: 'inline-flex',
justifyContent: 'center',
alignItems: 'center',
};
const MenuSubItem = ({ label, leaveLeftSpace, leftItem, onActionChosen, id, selected, onItemSelected, keyHint, subMenu, onQuitMenu, subMenuActivated, setSubMenuActivated, disabled, }) => {
const [hovered, setHovered] = (0, react_1.useState)(false);
const ref = (0, react_1.useRef)(null);
const size = player_1.PlayerInternals.useElementSize(ref, {
triggerOnWindowResize: true,
shouldApplyCssTransforms: true,
});
const mobileLayout = (0, mobile_layout_1.useMobileLayout)();
const { currentZIndex } = (0, z_index_1.useZIndex)();
const style = (0, react_1.useMemo)(() => {
return {
...container,
backgroundColor: selected && !disabled ? colors_1.CLEAR_HOVER : 'transparent',
opacity: disabled ? 0.5 : 1,
cursor: disabled ? 'not-allowed' : 'default',
};
}, [selected, disabled]);
const onPointerUp = (0, react_1.useCallback)((e) => {
if (disabled) {
return;
}
if (subMenu) {
setSubMenuActivated('with-mouse');
setHovered(true);
return;
}
onActionChosen(id, e);
}, [disabled, id, onActionChosen, setSubMenuActivated, subMenu]);
const onPointerEnter = (0, react_1.useCallback)(() => {
if (disabled) {
return;
}
onItemSelected(id);
setHovered(true);
}, [disabled, id, onItemSelected]);
const onPointerLeave = (0, react_1.useCallback)(() => {
setHovered(false);
}, []);
const onQuitSubmenu = (0, react_1.useCallback)(() => {
setSubMenuActivated(false);
}, [setSubMenuActivated]);
const portalStyle = (0, react_1.useMemo)(() => {
if (!selected || !size || !subMenu || !subMenuActivated) {
return null;
}
const left = size.left + size.width + styles_1.SUBMENU_LEFT_INSET;
return {
...styles_1.menuContainerTowardsBottom,
left: mobileLayout ? left * 0.7 : left,
top: size.top - styles_1.MENU_VERTICAL_PADDING,
};
}, [mobileLayout, selected, size, subMenu, subMenuActivated]);
(0, react_1.useEffect)(() => {
if (!hovered || !subMenu) {
return;
}
const hi = setTimeout(() => {
setSubMenuActivated('with-mouse');
}, 100);
return () => clearTimeout(hi);
}, [hovered, selected, setSubMenuActivated, subMenu]);
(0, react_1.useEffect)(() => {
var _a;
if (selected) {
(_a = ref.current) === null || _a === void 0 ? void 0 : _a.scrollIntoView({
// block is vertical alignment, inline is horizontal alignment. So we use "block"
block: 'nearest',
});
}
}, [selected]);
return ((0, jsx_runtime_1.jsx)("div", { ref: ref, onPointerEnter: onPointerEnter, onPointerLeave: onPointerLeave, style: style, onPointerUp: onPointerUp, role: "button", className: is_menu_item_1.MENU_ITEM_CLASSNAME, children: (0, jsx_runtime_1.jsxs)(layout_1.Row, { align: "center", children: [leaveLeftSpace ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("div", { style: leftSpace, children: leftItem }), (0, jsx_runtime_1.jsx)(layout_1.Spacing, { x: 1 })] })) : null, (0, jsx_runtime_1.jsx)("div", { style: labelStyle, title: typeof label === 'string' ? label : undefined, children: label }), ' ', (0, jsx_runtime_1.jsx)(layout_1.Spacing, { x: 2 }), subMenu ? (0, jsx_runtime_1.jsx)(caret_1.CaretRight, {}) : null, keyHint && !(0, use_keybinding_1.areKeyboardShortcutsDisabled)() ? ((0, jsx_runtime_1.jsx)("span", { style: keyHintCss, children: keyHint })) : null, portalStyle && subMenu
? react_dom_1.default.createPortal((0, jsx_runtime_1.jsx)(SubMenu_1.SubMenuComponent, { onQuitFullMenu: onQuitMenu, subMenu: subMenu, onQuitSubMenu: onQuitSubmenu, portalStyle: portalStyle, subMenuActivated: subMenuActivated }), (0, portals_1.getPortal)(currentZIndex))
: null] }) }));
};
exports.MenuSubItem = MenuSubItem;
@@ -0,0 +1,10 @@
import React from 'react';
import type { SubMenu } from '../NewComposition/ComboBox';
import type { SubMenuActivated } from './MenuSubItem';
export declare const SubMenuComponent: React.FC<{
readonly portalStyle: React.CSSProperties;
readonly subMenu: SubMenu;
readonly onQuitFullMenu: () => void;
readonly onQuitSubMenu: () => void;
readonly subMenuActivated: SubMenuActivated;
}>;
@@ -0,0 +1,26 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SubMenuComponent = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const react_1 = require("react");
const mobile_layout_1 = require("../../helpers/mobile-layout");
const noop_1 = require("../../helpers/noop");
const z_index_1 = require("../../state/z-index");
const MenuContent_1 = require("../NewComposition/MenuContent");
const portals_1 = require("./portals");
const SubMenuComponent = ({ portalStyle, subMenuActivated, subMenu, onQuitFullMenu, onQuitSubMenu, }) => {
const mobileLayout = (0, mobile_layout_1.useMobileLayout)();
const onOutsideClick = (0, react_1.useCallback)((e) => {
if (portals_1.portals.find((p) => p.contains(e)) || mobileLayout) {
onQuitSubMenu();
}
else {
onQuitFullMenu();
}
}, [mobileLayout, onQuitFullMenu, onQuitSubMenu]);
return ((0, jsx_runtime_1.jsx)(z_index_1.HigherZIndex, { onEscape: onQuitFullMenu, onOutsideClick: onOutsideClick, children: (0, jsx_runtime_1.jsx)("div", { style: portalStyle, className: "css-reset", children: (0, jsx_runtime_1.jsx)(MenuContent_1.MenuContent, { onNextMenu: noop_1.noop, onPreviousMenu: onQuitSubMenu, values: subMenu.items, onHide: onQuitFullMenu, leaveLeftSpace: subMenu.leaveLeftSpace, preselectIndex: subMenuActivated === 'without-mouse' &&
typeof subMenu.preselectIndex === 'number'
? subMenu.preselectIndex
: false, topItemCanBeUnselected: false, fixedHeight: null }) }) }));
};
exports.SubMenuComponent = SubMenuComponent;

Some files were not shown because too many files have changed in this diff Show More