@remotion/studio
Version:
APIs for interacting with the Remotion Studio
248 lines (247 loc) • 10.6 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.PlayPause = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const player_1 = require("@remotion/player");
const react_1 = require("react");
const remotion_1 = require("remotion");
const is_current_selected_still_1 = require("../helpers/is-current-selected-still");
const use_keybinding_1 = require("../helpers/use-keybinding");
const jump_to_start_1 = require("../icons/jump-to-start");
const pause_1 = require("../icons/pause");
const play_1 = require("../icons/play");
const step_back_1 = require("../icons/step-back");
const step_forward_1 = require("../icons/step-forward");
const in_out_1 = require("../state/in-out");
const ControlButton_1 = require("./ControlButton");
const imperative_state_1 = require("./Timeline/imperative-state");
const timeline_scroll_logic_1 = require("./Timeline/timeline-scroll-logic");
const backStyle = {
height: 18,
color: 'white',
};
const forwardBackStyle = {
height: 16,
color: 'white',
};
const iconButton = {
height: 14,
width: 14,
color: 'white',
};
const PlayPause = ({ playbackRate, loop, bufferStateDelayInMilliseconds }) => {
const { inFrame, outFrame } = (0, in_out_1.useTimelineInOutFramePosition)();
const videoConfig = remotion_1.Internals.useUnsafeVideoConfig();
const [showBufferIndicator, setShowBufferState] = (0, react_1.useState)(false);
const { playing, play, pause, pauseAndReturnToPlayStart, frameBack, seek, frameForward, isLastFrame, isFirstFrame, emitter, getCurrentFrame, } = player_1.PlayerInternals.usePlayer();
player_1.PlayerInternals.usePlayback({
loop,
playbackRate,
moveToBeginningWhenEnded: true,
inFrame,
outFrame,
getCurrentFrame,
browserMediaControlsBehavior: {
mode: 'register-media-session',
},
});
const isStill = (0, is_current_selected_still_1.useIsStill)();
(0, react_1.useEffect)(() => {
if (isStill) {
pause();
}
}, [isStill, pause]);
const onSpace = (0, react_1.useCallback)((e) => {
if (playing) {
pause();
}
else {
play();
}
e.preventDefault();
}, [pause, play, playing]);
const onEnter = (0, react_1.useCallback)((e) => {
if (playing) {
// Don't prevent keyboard navigation
e.preventDefault();
pauseAndReturnToPlayStart();
}
}, [pauseAndReturnToPlayStart, playing]);
const onArrowLeft = (0, react_1.useCallback)((e) => {
e.preventDefault();
if (e.altKey) {
seek(0);
(0, timeline_scroll_logic_1.ensureFrameIsInViewport)({
direction: 'fit-left',
durationInFrames: (0, imperative_state_1.getCurrentDuration)(),
frame: 0,
});
}
else if (e.shiftKey) {
frameBack((0, imperative_state_1.getCurrentFps)());
(0, timeline_scroll_logic_1.ensureFrameIsInViewport)({
direction: 'fit-left',
durationInFrames: (0, imperative_state_1.getCurrentDuration)(),
frame: Math.max(0, getCurrentFrame() - (0, imperative_state_1.getCurrentFps)()),
});
}
else {
frameBack(1);
(0, timeline_scroll_logic_1.ensureFrameIsInViewport)({
direction: 'fit-left',
durationInFrames: (0, imperative_state_1.getCurrentDuration)(),
frame: Math.max(0, getCurrentFrame() - 1),
});
}
}, [frameBack, seek, getCurrentFrame]);
const onArrowRight = (0, react_1.useCallback)((e) => {
if (e.altKey) {
seek((0, imperative_state_1.getCurrentDuration)() - 1);
(0, timeline_scroll_logic_1.ensureFrameIsInViewport)({
direction: 'fit-right',
durationInFrames: (0, imperative_state_1.getCurrentDuration)() - 1,
frame: (0, imperative_state_1.getCurrentDuration)() - 1,
});
}
else if (e.shiftKey) {
frameForward((0, imperative_state_1.getCurrentFps)());
(0, timeline_scroll_logic_1.ensureFrameIsInViewport)({
direction: 'fit-right',
durationInFrames: (0, imperative_state_1.getCurrentDuration)(),
frame: Math.min((0, imperative_state_1.getCurrentDuration)() - 1, getCurrentFrame() + (0, imperative_state_1.getCurrentFps)()),
});
}
else {
frameForward(1);
(0, timeline_scroll_logic_1.ensureFrameIsInViewport)({
direction: 'fit-right',
durationInFrames: (0, imperative_state_1.getCurrentDuration)(),
frame: Math.min((0, imperative_state_1.getCurrentDuration)() - 1, getCurrentFrame() + 1),
});
}
e.preventDefault();
}, [frameForward, seek, getCurrentFrame]);
const oneFrameBack = (0, react_1.useCallback)(() => {
frameBack(1);
}, [frameBack]);
const oneFrameForward = (0, react_1.useCallback)(() => {
frameForward(1);
}, [frameForward]);
const jumpToStart = (0, react_1.useCallback)(() => {
seek(inFrame !== null && inFrame !== void 0 ? inFrame : 0);
}, [seek, inFrame]);
const jumpToEnd = (0, react_1.useCallback)(() => {
seek(outFrame !== null && outFrame !== void 0 ? outFrame : (0, imperative_state_1.getCurrentDuration)() - 1);
}, [seek, outFrame]);
const keybindings = (0, use_keybinding_1.useKeybinding)();
(0, react_1.useEffect)(() => {
const arrowLeft = keybindings.registerKeybinding({
event: 'keydown',
key: 'ArrowLeft',
callback: onArrowLeft,
commandCtrlKey: false,
preventDefault: true,
triggerIfInputFieldFocused: false,
keepRegisteredWhenNotHighestContext: false,
});
const arrowRight = keybindings.registerKeybinding({
event: 'keydown',
key: 'ArrowRight',
callback: onArrowRight,
commandCtrlKey: false,
preventDefault: true,
triggerIfInputFieldFocused: false,
keepRegisteredWhenNotHighestContext: false,
});
const space = keybindings.registerKeybinding({
event: 'keydown',
key: ' ',
callback: onSpace,
commandCtrlKey: false,
preventDefault: true,
triggerIfInputFieldFocused: false,
keepRegisteredWhenNotHighestContext: false,
});
const enter = keybindings.registerKeybinding({
event: 'keydown',
key: 'enter',
callback: onEnter,
commandCtrlKey: false,
preventDefault: false,
triggerIfInputFieldFocused: false,
keepRegisteredWhenNotHighestContext: false,
});
const a = keybindings.registerKeybinding({
event: 'keydown',
key: 'a',
callback: jumpToStart,
commandCtrlKey: false,
preventDefault: true,
triggerIfInputFieldFocused: false,
keepRegisteredWhenNotHighestContext: false,
});
const e = keybindings.registerKeybinding({
event: 'keydown',
key: 'e',
callback: jumpToEnd,
commandCtrlKey: false,
preventDefault: true,
triggerIfInputFieldFocused: false,
keepRegisteredWhenNotHighestContext: false,
});
return () => {
arrowLeft.unregister();
arrowRight.unregister();
space.unregister();
enter.unregister();
a.unregister();
e.unregister();
};
}, [
jumpToEnd,
jumpToStart,
keybindings,
onArrowLeft,
onArrowRight,
onEnter,
onSpace,
]);
(0, react_1.useEffect)(() => {
let timeout = null;
let stopped = false;
const onBuffer = () => {
requestAnimationFrame(() => {
stopped = false;
timeout = setTimeout(() => {
if (!stopped) {
setShowBufferState(true);
}
}, bufferStateDelayInMilliseconds);
});
};
const onResume = () => {
requestAnimationFrame(() => {
setShowBufferState(false);
stopped = true;
if (timeout) {
clearTimeout(timeout);
}
});
};
emitter.addEventListener('waiting', onBuffer);
emitter.addEventListener('resume', onResume);
return () => {
emitter.removeEventListener('waiting', onBuffer);
emitter.removeEventListener('resume', onResume);
setShowBufferState(false);
if (timeout) {
clearTimeout(timeout);
}
stopped = true;
};
}, [bufferStateDelayInMilliseconds, emitter]);
return (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [
jsx_runtime_1.jsx(ControlButton_1.ControlButton, { "aria-label": "Jump to beginning", title: "Jump to beginning", disabled: !videoConfig || isFirstFrame, onClick: jumpToStart, children: jsx_runtime_1.jsx(jump_to_start_1.JumpToStart, { style: backStyle }) }), jsx_runtime_1.jsx(ControlButton_1.ControlButton, { "aria-label": "Step back one frame", title: "Step back one frame", disabled: !videoConfig || isFirstFrame, onClick: oneFrameBack, children: jsx_runtime_1.jsx(step_back_1.StepBack, { style: forwardBackStyle }) }), jsx_runtime_1.jsx(ControlButton_1.ControlButton, { "aria-label": playing ? 'Pause' : 'Play', title: playing ? 'Pause' : 'Play', onClick: playing ? pause : play, disabled: !videoConfig, children: playing ? (showBufferIndicator ? (jsx_runtime_1.jsx(player_1.PlayerInternals.BufferingIndicator, { type: "studio" })) : (jsx_runtime_1.jsx(pause_1.Pause, { style: iconButton }))) : (jsx_runtime_1.jsx(play_1.Play, { style: iconButton })) }), jsx_runtime_1.jsx(ControlButton_1.ControlButton, { "aria-label": "Step forward one frame", title: "Step forward one frame", disabled: !videoConfig || isLastFrame, onClick: oneFrameForward, children: jsx_runtime_1.jsx(step_forward_1.StepForward, { style: forwardBackStyle }) })
] }));
};
exports.PlayPause = PlayPause;