@remotion/studio
Version:
APIs for interacting with the Remotion Studio
174 lines (173 loc) • 7.83 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Combobox = 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 noop_1 = require("../../helpers/noop");
const caret_1 = require("../../icons/caret");
const z_index_1 = require("../../state/z-index");
const layout_1 = require("../layout");
const is_menu_item_1 = require("../Menu/is-menu-item");
const portals_1 = require("../Menu/portals");
const styles_1 = require("../Menu/styles");
const MenuContent_1 = require("./MenuContent");
const container = {
padding: '8px 10px',
display: 'inline-block',
backgroundColor: colors_1.INPUT_BACKGROUND,
borderWidth: 1,
borderStyle: 'solid',
maxWidth: '100%',
};
const label = {
flex: 1,
overflow: 'hidden',
textOverflow: 'ellipsis',
fontSize: 14,
textAlign: 'left',
};
const Combobox = ({ values, selectedId, style: customStyle, title }) => {
const [hovered, setIsHovered] = (0, react_1.useState)(false);
const [opened, setOpened] = (0, react_1.useState)(false);
const ref = (0, react_1.useRef)(null);
const { tabIndex, currentZIndex } = (0, z_index_1.useZIndex)();
const size = player_1.PlayerInternals.useElementSize(ref, {
triggerOnWindowResize: true,
shouldApplyCssTransforms: true,
});
const refresh = size === null || size === void 0 ? void 0 : size.refresh;
const onHide = (0, react_1.useCallback)(() => {
setOpened(false);
}, []);
(0, react_1.useEffect)(() => {
const { current } = ref;
if (!current) {
return;
}
const onMouseEnter = () => setIsHovered(true);
const onMouseLeave = () => setIsHovered(false);
const onPointerDown = () => {
return setOpened((o) => {
if (!o) {
refresh === null || refresh === void 0 ? void 0 : refresh();
}
return !o;
});
};
const onClick = (e) => {
e.stopPropagation();
const isKeyboardInitiated = e.detail === 0;
if (!isKeyboardInitiated) {
return;
}
return setOpened((o) => {
if (!o) {
refresh === null || refresh === void 0 ? void 0 : refresh();
window.addEventListener('pointerup', (evt) => {
if (!(0, is_menu_item_1.isMenuItem)(evt.target)) {
setOpened(false);
}
}, {
once: true,
});
}
return !o;
});
};
current.addEventListener('mouseenter', onMouseEnter);
current.addEventListener('mouseleave', onMouseLeave);
current.addEventListener('pointerdown', onPointerDown);
current.addEventListener('click', onClick);
return () => {
current.removeEventListener('mouseenter', onMouseEnter);
current.removeEventListener('mouseleave', onMouseLeave);
current.removeEventListener('pointerdown', onPointerDown);
current.removeEventListener('click', onClick);
};
}, [refresh]);
const spaceToBottom = (0, react_1.useMemo)(() => {
const margin = 10;
if (size && opened) {
return size.windowSize.height - (size.top + size.height) - margin;
}
return 0;
}, [opened, size]);
const spaceToTop = (0, react_1.useMemo)(() => {
const margin = 10;
if (size && opened) {
return size.top - margin;
}
return 0;
}, [opened, size]);
const derivedMaxHeight = (0, react_1.useMemo)(() => {
return spaceToTop > spaceToBottom ? spaceToTop : spaceToBottom;
}, [spaceToBottom, spaceToTop]);
const isMobileLayout = (0, mobile_layout_1.useMobileLayout)();
const portalStyle = (0, react_1.useMemo)(() => {
if (!opened || !size) {
return null;
}
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 {
...(verticalLayout === 'top'
? {
...styles_1.menuContainerTowardsBottom,
top: size.top + size.height,
}
: {
...styles_1.menuContainerTowardsTop,
bottom: size.windowSize.height - size.top,
}),
...(horizontalLayout === 'left'
? {
left: size.left,
}
: canOpenOnLeft
? {
right: size.windowSize.width - size.left - size.width,
}
: { left: 0 }),
};
}, [isMobileLayout, opened, size, spaceToBottom, spaceToTop]);
const selected = values.find((v) => v.id === selectedId);
const style = (0, react_1.useMemo)(() => {
return {
...container,
...(customStyle !== null && customStyle !== void 0 ? customStyle : {}),
userSelect: 'none',
WebkitUserSelect: 'none',
color: 'white',
display: 'inline-flex',
flexDirection: 'row',
alignItems: 'center',
borderColor: opened
? colors_1.SELECTED_BACKGROUND
: hovered
? colors_1.INPUT_BORDER_COLOR_HOVERED
: colors_1.INPUT_BORDER_COLOR_UNHOVERED,
};
}, [customStyle, hovered, opened]);
return (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [
jsx_runtime_1.jsxs("button", { ref: ref, title: title, tabIndex: tabIndex, type: "button", style: style, className: is_menu_item_1.MENU_INITIATOR_CLASSNAME, children: [selected ? (jsx_runtime_1.jsx("div", { title: typeof selected.label === 'string' ? selected.label : undefined, style: label, children: selected === null || selected === void 0 ? void 0 : selected.label })) : null, jsx_runtime_1.jsx(layout_1.Spacing, { x: 1 }),
" ",
jsx_runtime_1.jsx(caret_1.CaretDown, {})
] }), portalStyle
? react_dom_1.default.createPortal(jsx_runtime_1.jsx("div", { style: styles_1.fullScreenOverlay, children: jsx_runtime_1.jsx("div", { style: styles_1.outerPortal, className: "css-reset", children: jsx_runtime_1.jsx(z_index_1.HigherZIndex, { onOutsideClick: onHide, onEscape: onHide, children: jsx_runtime_1.jsx("div", { style: portalStyle, children: jsx_runtime_1.jsx(MenuContent_1.MenuContent, { onNextMenu: noop_1.noop, onPreviousMenu: noop_1.noop, values: values, onHide: onHide, leaveLeftSpace: true, preselectIndex: values.findIndex((v) => selected && v.id === selected.id), topItemCanBeUnselected: false, fixedHeight: derivedMaxHeight }) }) }) }) }), (0, portals_1.getPortal)(currentZIndex))
: null] }));
};
exports.Combobox = Combobox;