UNPKG

@remotion/player

Version:

React component for embedding a Remotion preview into your app

157 lines (156 loc) • 6.23 kB
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { useCallback, useContext, useEffect, useMemo, useState, } from 'react'; import { Internals } from 'remotion'; import useComponentVisible from './utils/use-component-visible.js'; // To align const BOTTOM = 35; // Arbitrary to clamp the height of the popup const THRESHOLD = 70; const rateDiv = { height: 30, paddingRight: 15, paddingLeft: 12, display: 'flex', flexDirection: 'row', alignItems: 'center', }; const checkmarkContainer = { width: 22, display: 'flex', alignItems: 'center', }; const checkmarkStyle = { width: 14, height: 14, color: 'black', }; export const Checkmark = () => (_jsx("svg", { viewBox: "0 0 512 512", style: checkmarkStyle, children: _jsx("path", { fill: "currentColor", d: "M435.848 83.466L172.804 346.51l-96.652-96.652c-4.686-4.686-12.284-4.686-16.971 0l-28.284 28.284c-4.686 4.686-4.686 12.284 0 16.971l133.421 133.421c4.686 4.686 12.284 4.686 16.971 0l299.813-299.813c4.686-4.686 4.686-12.284 0-16.971l-28.284-28.284c-4.686-4.686-12.284-4.686-16.97 0z" }) })); const PlaybackrateOption = ({ rate, onSelect, selectedRate, keyboardSelectedRate }) => { const onClick = useCallback((e) => { e.stopPropagation(); e.preventDefault(); onSelect(rate); }, [onSelect, rate]); const [hovered, setHovered] = useState(false); const onMouseEnter = useCallback(() => { setHovered(true); }, []); const onMouseLeave = useCallback(() => { setHovered(false); }, []); const isFocused = keyboardSelectedRate === rate; const actualStyle = useMemo(() => { return { ...rateDiv, backgroundColor: hovered || isFocused ? '#eee' : 'transparent', }; }, [hovered, isFocused]); return (_jsxs("div", { onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, tabIndex: 0, style: actualStyle, onClick: onClick, children: [_jsx("div", { style: checkmarkContainer, children: rate === selectedRate ? _jsx(Checkmark, {}) : null }), rate.toFixed(1), "x"] }, rate)); }; const PlaybackPopup = ({ setIsComponentVisible, playbackRates, canvasSize }) => { const { setPlaybackRate, playbackRate } = useContext(Internals.Timeline.TimelineContext); const [keyboardSelectedRate, setKeyboardSelectedRate] = useState(playbackRate); useEffect(() => { const listener = (e) => { e.preventDefault(); if (e.key === 'ArrowUp') { const currentIndex = playbackRates.findIndex((rate) => rate === keyboardSelectedRate); if (currentIndex === 0) { return; } if (currentIndex === -1) { setKeyboardSelectedRate(playbackRates[0]); } else { setKeyboardSelectedRate(playbackRates[currentIndex - 1]); } } else if (e.key === 'ArrowDown') { const currentIndex = playbackRates.findIndex((rate) => rate === keyboardSelectedRate); if (currentIndex === playbackRates.length - 1) { return; } if (currentIndex === -1) { setKeyboardSelectedRate(playbackRates[playbackRates.length - 1]); } else { setKeyboardSelectedRate(playbackRates[currentIndex + 1]); } } else if (e.key === 'Enter') { setPlaybackRate(keyboardSelectedRate); setIsComponentVisible(false); } }; window.addEventListener('keydown', listener); return () => { window.removeEventListener('keydown', listener); }; }, [ playbackRates, keyboardSelectedRate, setPlaybackRate, setIsComponentVisible, ]); const onSelect = useCallback((rate) => { setPlaybackRate(rate); setIsComponentVisible(false); }, [setIsComponentVisible, setPlaybackRate]); const playbackPopup = useMemo(() => { return { position: 'absolute', right: 0, width: 125, maxHeight: canvasSize.height - THRESHOLD - BOTTOM, bottom: 35, background: '#fff', borderRadius: 4, overflow: 'auto', color: 'black', textAlign: 'left', }; }, [canvasSize.height]); return (_jsx("div", { style: playbackPopup, children: playbackRates.map((rate) => { return (_jsx(PlaybackrateOption, { selectedRate: playbackRate, onSelect: onSelect, rate: rate, keyboardSelectedRate: keyboardSelectedRate }, rate)); }) })); }; const label = { fontSize: 13, fontWeight: 'bold', color: 'white', border: '2px solid white', borderRadius: 20, paddingLeft: 8, paddingRight: 8, paddingTop: 2, paddingBottom: 2, }; export const playerButtonStyle = { appearance: 'none', backgroundColor: 'transparent', border: 'none', cursor: 'pointer', paddingLeft: 0, paddingRight: 0, paddingTop: 6, paddingBottom: 6, height: 37, display: 'inline-flex', marginBottom: 0, marginTop: 0, alignItems: 'center', }; const button = { ...playerButtonStyle, position: 'relative', }; export const PlaybackrateControl = ({ playbackRates, canvasSize }) => { const { ref, isComponentVisible, setIsComponentVisible } = useComponentVisible(false); const { playbackRate } = useContext(Internals.Timeline.TimelineContext); const onClick = useCallback((e) => { e.stopPropagation(); e.preventDefault(); setIsComponentVisible((prevIsComponentVisible) => !prevIsComponentVisible); }, [setIsComponentVisible]); return (_jsx("div", { ref: ref, children: _jsxs("button", { type: "button", "aria-label": "Change playback rate", style: button, onClick: onClick, children: [_jsxs("div", { style: label, children: [playbackRate, "x"] }), isComponentVisible && (_jsx(PlaybackPopup, { canvasSize: canvasSize, playbackRates: playbackRates, setIsComponentVisible: setIsComponentVisible }))] }) })); };