@remotion/player 4.0.0-umungobongo.5 → 4.0.0-webhook.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,2 +1,5 @@
1
1
  import React from 'react';
2
- export declare const MediaVolumeSlider: React.FC;
2
+ export declare const VOLUME_SLIDER_WIDTH = 100;
3
+ export declare const MediaVolumeSlider: React.FC<{
4
+ displayVerticalVolumeSlider: Boolean;
5
+ }>;
@@ -1,72 +1,22 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.MediaVolumeSlider = void 0;
3
+ exports.MediaVolumeSlider = exports.VOLUME_SLIDER_WIDTH = void 0;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const react_1 = require("react");
6
6
  const remotion_1 = require("remotion");
7
7
  const icons_1 = require("./icons");
8
- const player_css_classname_1 = require("./player-css-classname");
9
8
  const use_hover_state_1 = require("./use-hover-state");
10
9
  const BAR_HEIGHT = 5;
11
10
  const KNOB_SIZE = 12;
12
- const VOLUME_SLIDER_WIDTH = 100;
13
- const scope = `.${player_css_classname_1.VOLUME_SLIDER_INPUT_CSS_CLASSNAME}`;
14
- const sliderStyle = `
15
- ${scope} {
16
- -webkit-appearance: none;
17
- background-color: rgba(255, 255, 255, 0.5);
18
- border-radius: ${BAR_HEIGHT / 2}px;
19
- cursor: pointer;
20
- height: ${BAR_HEIGHT}px;
21
- margin-left: 5px;
22
- width: ${VOLUME_SLIDER_WIDTH}px;
23
- }
24
-
25
- ${scope}::-webkit-slider-thumb {
26
- -webkit-appearance: none;
27
- background-color: white;
28
- border-radius: ${KNOB_SIZE / 2}px;
29
- box-shadow: 0 0 2px black;
30
- height: ${KNOB_SIZE}px;
31
- width: ${KNOB_SIZE}px;
32
- }
33
-
34
- ${scope}::-moz-range-thumb {
35
- -webkit-appearance: none;
36
- background-color: white;
37
- border-radius: ${KNOB_SIZE / 2}px;
38
- box-shadow: 0 0 2px black;
39
- height: ${KNOB_SIZE}px;
40
- width: ${KNOB_SIZE}px;
41
- }
42
- `;
43
- remotion_1.Internals.CSSUtils.injectCSS(sliderStyle);
44
- const parentDivStyle = {
45
- display: 'inline-flex',
46
- background: 'none',
47
- border: 'none',
48
- padding: '6px',
49
- justifyContent: 'center',
50
- alignItems: 'center',
51
- touchAction: 'none',
52
- };
53
- const volumeContainer = {
54
- display: 'inline',
55
- width: icons_1.ICON_SIZE,
56
- height: icons_1.ICON_SIZE,
57
- cursor: 'pointer',
58
- appearance: 'none',
59
- background: 'none',
60
- border: 'none',
61
- padding: 0,
62
- };
63
- const MediaVolumeSlider = () => {
11
+ exports.VOLUME_SLIDER_WIDTH = 100;
12
+ const MediaVolumeSlider = ({ displayVerticalVolumeSlider }) => {
64
13
  const [mediaMuted, setMediaMuted] = remotion_1.Internals.useMediaMutedState();
65
14
  const [mediaVolume, setMediaVolume] = remotion_1.Internals.useMediaVolumeState();
66
15
  const [focused, setFocused] = (0, react_1.useState)(false);
67
16
  const parentDivRef = (0, react_1.useRef)(null);
68
17
  const inputRef = (0, react_1.useRef)(null);
69
18
  const hover = (0, use_hover_state_1.useHoverState)(parentDivRef);
19
+ const [randomClass] = (0, react_1.useState)(() => `slider-${(0, remotion_1.random)(null)}`.replace('.', ''));
70
20
  const isMutedOrZero = mediaMuted || mediaVolume === 0;
71
21
  const onVolumeChange = (e) => {
72
22
  setMediaVolume(parseFloat(e.target.value));
@@ -88,6 +38,81 @@ const MediaVolumeSlider = () => {
88
38
  }
89
39
  setMediaMuted((mute) => !mute);
90
40
  }, [mediaVolume, setMediaMuted, setMediaVolume]);
91
- return ((0, jsx_runtime_1.jsxs)("div", { ref: parentDivRef, style: parentDivStyle, children: [(0, jsx_runtime_1.jsx)("button", { "aria-label": isMutedOrZero ? 'Unmute sound' : 'Mute sound', title: isMutedOrZero ? 'Unmute sound' : 'Mute sound', onClick: onClick, onBlur: onBlur, onFocus: () => setFocused(true), style: volumeContainer, type: "button", children: isMutedOrZero ? (0, jsx_runtime_1.jsx)(icons_1.VolumeOffIcon, {}) : (0, jsx_runtime_1.jsx)(icons_1.VolumeOnIcon, {}) }), (focused || hover) && !mediaMuted ? ((0, jsx_runtime_1.jsx)("input", { ref: inputRef, "aria-label": "Change volume", className: player_css_classname_1.VOLUME_SLIDER_INPUT_CSS_CLASSNAME, max: 1, min: 0, onBlur: () => setFocused(false), onChange: onVolumeChange, step: 0.01, type: "range", value: mediaVolume })) : null] }));
41
+ const parentDivStyle = (0, react_1.useMemo)(() => {
42
+ return {
43
+ display: 'inline-flex',
44
+ background: 'none',
45
+ border: 'none',
46
+ padding: '6px',
47
+ justifyContent: 'center',
48
+ alignItems: 'center',
49
+ touchAction: 'none',
50
+ ...(displayVerticalVolumeSlider && { position: 'relative' }),
51
+ };
52
+ }, [displayVerticalVolumeSlider]);
53
+ const volumeContainer = (0, react_1.useMemo)(() => {
54
+ return {
55
+ display: 'inline',
56
+ width: icons_1.ICON_SIZE,
57
+ height: icons_1.ICON_SIZE,
58
+ cursor: 'pointer',
59
+ appearance: 'none',
60
+ background: 'none',
61
+ border: 'none',
62
+ padding: 0,
63
+ };
64
+ }, []);
65
+ const inputStyle = (0, react_1.useMemo)(() => {
66
+ const commonStyle = {
67
+ WebkitAppearance: 'none',
68
+ backgroundColor: 'rgba(255, 255, 255, 0.5)',
69
+ borderRadius: BAR_HEIGHT / 2,
70
+ cursor: 'pointer',
71
+ height: BAR_HEIGHT,
72
+ width: exports.VOLUME_SLIDER_WIDTH,
73
+ };
74
+ if (displayVerticalVolumeSlider) {
75
+ return {
76
+ ...commonStyle,
77
+ transform: `rotate(-90deg)`,
78
+ position: 'absolute',
79
+ bottom: icons_1.ICON_SIZE + exports.VOLUME_SLIDER_WIDTH / 2 + 5,
80
+ };
81
+ }
82
+ return {
83
+ ...commonStyle,
84
+ marginLeft: 5,
85
+ };
86
+ }, [displayVerticalVolumeSlider]);
87
+ const sliderStyle = `
88
+ .${randomClass}::-webkit-slider-thumb {
89
+ -webkit-appearance: none;
90
+ background-color: white;
91
+ border-radius: ${KNOB_SIZE / 2}px;
92
+ box-shadow: 0 0 2px black;
93
+ height: ${KNOB_SIZE}px;
94
+ width: ${KNOB_SIZE}px;
95
+ }
96
+ .${randomClass} {
97
+ background-image: linear-gradient(
98
+ to right,
99
+ white ${mediaVolume * 100}%, rgba(255, 255, 255, 0) ${mediaVolume * 100}%
100
+ );
101
+ }
102
+
103
+ .${randomClass}::-moz-range-thumb {
104
+ -webkit-appearance: none;
105
+ background-color: white;
106
+ border-radius: ${KNOB_SIZE / 2}px;
107
+ box-shadow: 0 0 2px black;
108
+ height: ${KNOB_SIZE}px;
109
+ width: ${KNOB_SIZE}px;
110
+ }
111
+ `;
112
+ return ((0, jsx_runtime_1.jsxs)("div", { ref: parentDivRef, style: parentDivStyle, children: [(0, jsx_runtime_1.jsx)("style", {
113
+ // eslint-disable-next-line react/no-danger
114
+ dangerouslySetInnerHTML: {
115
+ __html: sliderStyle,
116
+ } }), (0, jsx_runtime_1.jsx)("button", { "aria-label": isMutedOrZero ? 'Unmute sound' : 'Mute sound', title: isMutedOrZero ? 'Unmute sound' : 'Mute sound', onClick: onClick, onBlur: onBlur, onFocus: () => setFocused(true), style: volumeContainer, type: "button", children: isMutedOrZero ? (0, jsx_runtime_1.jsx)(icons_1.VolumeOffIcon, {}) : (0, jsx_runtime_1.jsx)(icons_1.VolumeOnIcon, {}) }), (focused || hover) && !mediaMuted ? ((0, jsx_runtime_1.jsx)("input", { ref: inputRef, "aria-label": "Change volume", className: randomClass, max: 1, min: 0, onBlur: () => setFocused(false), onChange: onVolumeChange, step: 0.01, type: "range", value: mediaVolume, style: inputStyle })) : null] }));
92
117
  };
93
118
  exports.MediaVolumeSlider = MediaVolumeSlider;
package/dist/Player.d.ts CHANGED
@@ -2,7 +2,7 @@ import type { ComponentType, MutableRefObject } from 'react';
2
2
  import React from 'react';
3
3
  import type { CompProps } from 'remotion';
4
4
  import type { PlayerRef } from './player-methods';
5
- import type { RenderLoading } from './PlayerUI';
5
+ import type { RenderLoading, RenderPoster } from './PlayerUI';
6
6
  declare type PropsIfHasProps<Props> = {} extends Props ? {
7
7
  inputProps?: Props;
8
8
  } : {
@@ -31,9 +31,17 @@ export declare type PlayerProps<T> = {
31
31
  renderLoading?: RenderLoading;
32
32
  moveToBeginningWhenEnded?: boolean;
33
33
  className?: string;
34
+ initialFrame?: number;
35
+ renderPoster?: RenderPoster;
36
+ showPosterWhenPaused?: boolean;
37
+ showPosterWhenEnded?: boolean;
38
+ showPosterWhenUnplayed?: boolean;
39
+ inFrame?: number | null;
40
+ outFrame?: number | null;
41
+ initiallyShowControls?: number | boolean;
34
42
  } & PropsIfHasProps<T> & CompProps<T>;
35
43
  export declare const componentOrNullIfLazy: <T>(props: CompProps<T>) => ComponentType<T> | null;
36
- export declare const PlayerFn: <T>({ durationInFrames, compositionHeight, compositionWidth, fps, inputProps, style, controls, loop, autoPlay, showVolumeControls, allowFullscreen, clickToPlay, doubleClickToFullscreen, spaceKeyToPlayOrPause, moveToBeginningWhenEnded, numberOfSharedAudioTags, errorFallback, playbackRate, renderLoading, className, ...componentProps }: PlayerProps<T>, ref: MutableRefObject<PlayerRef>) => JSX.Element;
44
+ export declare const PlayerFn: <T>({ durationInFrames, compositionHeight, compositionWidth, fps, inputProps, style, controls, loop, autoPlay, showVolumeControls, allowFullscreen, clickToPlay, doubleClickToFullscreen, spaceKeyToPlayOrPause, moveToBeginningWhenEnded, numberOfSharedAudioTags, errorFallback, playbackRate, renderLoading, className, showPosterWhenUnplayed, showPosterWhenEnded, showPosterWhenPaused, initialFrame, renderPoster, inFrame, outFrame, initiallyShowControls, ...componentProps }: PlayerProps<T>, ref: MutableRefObject<PlayerRef>) => JSX.Element;
37
45
  declare module 'react' {
38
46
  function forwardRef<T, P = {}>(render: (props: P, ref: React.MutableRefObject<T>) => React.ReactElement | null): (props: P & React.RefAttributes<T>) => React.ReactElement | null;
39
47
  }
package/dist/Player.js CHANGED
@@ -11,9 +11,10 @@ const emitter_context_1 = require("./emitter-context");
11
11
  const event_emitter_1 = require("./event-emitter");
12
12
  const player_css_classname_1 = require("./player-css-classname");
13
13
  const PlayerUI_1 = __importDefault(require("./PlayerUI"));
14
+ const validate_in_out_frame_1 = require("./utils/validate-in-out-frame");
15
+ const validate_initial_frame_1 = require("./utils/validate-initial-frame");
14
16
  const validate_playbackrate_1 = require("./utils/validate-playbackrate");
15
17
  const volume_persistance_1 = require("./volume-persistance");
16
- remotion_1.Internals.CSSUtils.injectCSS(remotion_1.Internals.CSSUtils.makeDefaultCSS(`.${player_css_classname_1.PLAYER_CSS_CLASSNAME}`, '#fff'));
17
18
  const componentOrNullIfLazy = (props) => {
18
19
  if ('component' in props) {
19
20
  return props.component;
@@ -21,7 +22,7 @@ const componentOrNullIfLazy = (props) => {
21
22
  return null;
22
23
  };
23
24
  exports.componentOrNullIfLazy = componentOrNullIfLazy;
24
- const PlayerFn = ({ durationInFrames, compositionHeight, compositionWidth, fps, inputProps, style, controls = false, loop = false, autoPlay = false, showVolumeControls = true, allowFullscreen = true, clickToPlay, doubleClickToFullscreen = false, spaceKeyToPlayOrPause = true, moveToBeginningWhenEnded = true, numberOfSharedAudioTags = 5, errorFallback = () => '⚠️', playbackRate = 1, renderLoading, className, ...componentProps }, ref) => {
25
+ const PlayerFn = ({ durationInFrames, compositionHeight, compositionWidth, fps, inputProps, style, controls = false, loop = false, autoPlay = false, showVolumeControls = true, allowFullscreen = true, clickToPlay, doubleClickToFullscreen = false, spaceKeyToPlayOrPause = true, moveToBeginningWhenEnded = true, numberOfSharedAudioTags = 5, errorFallback = () => '⚠️', playbackRate = 1, renderLoading, className, showPosterWhenUnplayed, showPosterWhenEnded, showPosterWhenPaused, initialFrame, renderPoster, inFrame, outFrame, initiallyShowControls, ...componentProps }, ref) => {
25
26
  if (typeof window !== 'undefined') {
26
27
  // eslint-disable-next-line react-hooks/rules-of-hooks
27
28
  (0, react_1.useLayoutEffect)(() => {
@@ -41,7 +42,8 @@ const PlayerFn = ({ durationInFrames, compositionHeight, compositionWidth, fps,
41
42
  throw new TypeError(`'component' must not be the 'Composition' component. Pass your own React component directly, and set the duration, fps and dimensions as separate props. See https://www.remotion.dev/docs/player/examples for an example.`);
42
43
  }
43
44
  const component = remotion_1.Internals.useLazyComponent(componentProps);
44
- const [frame, setFrame] = (0, react_1.useState)(0);
45
+ (0, validate_initial_frame_1.validateInitialFrame)({ initialFrame, durationInFrames });
46
+ const [frame, setFrame] = (0, react_1.useState)(() => initialFrame !== null && initialFrame !== void 0 ? initialFrame : 0);
45
47
  const [playing, setPlaying] = (0, react_1.useState)(false);
46
48
  const [rootId] = (0, react_1.useState)('player-comp');
47
49
  const [emitter] = (0, react_1.useState)(() => new event_emitter_1.PlayerEmitter());
@@ -60,6 +62,11 @@ const PlayerFn = ({ durationInFrames, compositionHeight, compositionWidth, fps,
60
62
  remotion_1.Internals.validateDimension(compositionWidth, 'compositionWidth', 'of the <Player /> component');
61
63
  remotion_1.Internals.validateDurationInFrames(durationInFrames, 'of the <Player/> component');
62
64
  remotion_1.Internals.validateFps(fps, 'as a prop of the <Player/> component', false);
65
+ (0, validate_in_out_frame_1.validateInOutFrames)({
66
+ durationInFrames,
67
+ inFrame,
68
+ outFrame,
69
+ });
63
70
  if (typeof controls !== 'boolean' && typeof controls !== 'undefined') {
64
71
  throw new TypeError(`'controls' must be a boolean or undefined but got '${typeof controls}' instead`);
65
72
  }
@@ -103,7 +110,7 @@ const PlayerFn = ({ durationInFrames, compositionHeight, compositionWidth, fps,
103
110
  setMediaVolume(vol);
104
111
  (0, volume_persistance_1.persistVolume)(vol);
105
112
  }, []);
106
- (0, react_1.useImperativeHandle)(ref, () => rootRef.current);
113
+ (0, react_1.useImperativeHandle)(ref, () => rootRef.current, []);
107
114
  const timelineContextValue = (0, react_1.useMemo)(() => {
108
115
  return {
109
116
  frame,
@@ -166,6 +173,8 @@ const PlayerFn = ({ durationInFrames, compositionHeight, compositionWidth, fps,
166
173
  unregisterSequence: () => undefined,
167
174
  registerAsset: () => undefined,
168
175
  unregisterAsset: () => undefined,
176
+ currentCompositionMetadata: null,
177
+ setCurrentCompositionMetadata: () => undefined,
169
178
  assets: [],
170
179
  };
171
180
  }, [
@@ -179,9 +188,16 @@ const PlayerFn = ({ durationInFrames, compositionHeight, compositionWidth, fps,
179
188
  const passedInputProps = (0, react_1.useMemo)(() => {
180
189
  return inputProps !== null && inputProps !== void 0 ? inputProps : {};
181
190
  }, [inputProps]);
182
- return ((0, jsx_runtime_1.jsx)(remotion_1.Internals.CanUseRemotionHooksProvider, { children: (0, jsx_runtime_1.jsx)(remotion_1.Internals.Timeline.TimelineContext.Provider, { value: timelineContextValue, children: (0, jsx_runtime_1.jsx)(remotion_1.Internals.Timeline.SetTimelineContext.Provider, { value: setTimelineContextValue, children: (0, jsx_runtime_1.jsx)(remotion_1.Internals.CompositionManager.Provider, { value: compositionManagerContext, children: (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: (0, jsx_runtime_1.jsx)(remotion_1.Internals.SharedAudioContextProvider, { numberOfAudioTags: numberOfSharedAudioTags, children: (0, jsx_runtime_1.jsx)(emitter_context_1.PlayerEventEmitterContext.Provider, { value: emitter, children: (0, jsx_runtime_1.jsx)(PlayerUI_1.default, { ref: rootRef, renderLoading: renderLoading, autoPlay: Boolean(autoPlay), loop: Boolean(loop), controls: Boolean(controls), errorFallback: errorFallback, style: style, inputProps: passedInputProps, allowFullscreen: Boolean(allowFullscreen), moveToBeginningWhenEnded: Boolean(moveToBeginningWhenEnded), clickToPlay: typeof clickToPlay === 'boolean'
183
- ? clickToPlay
184
- : Boolean(controls), showVolumeControls: Boolean(showVolumeControls), setMediaVolume: setMediaVolumeAndPersist, mediaVolume: mediaVolume, mediaMuted: mediaMuted, doubleClickToFullscreen: Boolean(doubleClickToFullscreen), setMediaMuted: setMediaMuted, spaceKeyToPlayOrPause: Boolean(spaceKeyToPlayOrPause), playbackRate: playbackRate, className: className !== null && className !== void 0 ? className : undefined }) }) }) }) }) }) }) }) }));
191
+ if (typeof window !== 'undefined') {
192
+ // eslint-disable-next-line react-hooks/rules-of-hooks
193
+ (0, react_1.useLayoutEffect)(() => {
194
+ // Inject CSS only on client, and also only after the Player has hydrated
195
+ remotion_1.Internals.CSSUtils.injectCSS(remotion_1.Internals.CSSUtils.makeDefaultCSS(`.${player_css_classname_1.PLAYER_CSS_CLASSNAME}`, '#fff'));
196
+ }, []);
197
+ }
198
+ return ((0, jsx_runtime_1.jsx)(remotion_1.Internals.CanUseRemotionHooksProvider, { children: (0, jsx_runtime_1.jsx)(remotion_1.Internals.Timeline.TimelineContext.Provider, { value: timelineContextValue, children: (0, jsx_runtime_1.jsx)(remotion_1.Internals.Timeline.SetTimelineContext.Provider, { value: setTimelineContextValue, children: (0, jsx_runtime_1.jsx)(remotion_1.Internals.CompositionManager.Provider, { value: compositionManagerContext, children: (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: (0, jsx_runtime_1.jsx)(remotion_1.Internals.SharedAudioContextProvider, { numberOfAudioTags: numberOfSharedAudioTags, children: (0, jsx_runtime_1.jsx)(emitter_context_1.PlayerEventEmitterContext.Provider, { value: emitter, children: (0, jsx_runtime_1.jsx)(remotion_1.Internals.PrefetchProvider, { children: (0, jsx_runtime_1.jsx)(PlayerUI_1.default, { ref: rootRef, renderLoading: renderLoading, autoPlay: Boolean(autoPlay), loop: Boolean(loop), controls: Boolean(controls), errorFallback: errorFallback, style: style, inputProps: passedInputProps, allowFullscreen: Boolean(allowFullscreen), moveToBeginningWhenEnded: Boolean(moveToBeginningWhenEnded), clickToPlay: typeof clickToPlay === 'boolean'
199
+ ? clickToPlay
200
+ : Boolean(controls), showVolumeControls: Boolean(showVolumeControls), setMediaVolume: setMediaVolumeAndPersist, mediaVolume: mediaVolume, mediaMuted: mediaMuted, doubleClickToFullscreen: Boolean(doubleClickToFullscreen), setMediaMuted: setMediaMuted, spaceKeyToPlayOrPause: Boolean(spaceKeyToPlayOrPause), playbackRate: playbackRate, className: className !== null && className !== void 0 ? className : undefined, showPosterWhenUnplayed: Boolean(showPosterWhenUnplayed), showPosterWhenEnded: Boolean(showPosterWhenEnded), showPosterWhenPaused: Boolean(showPosterWhenPaused), renderPoster: renderPoster, inFrame: inFrame !== null && inFrame !== void 0 ? inFrame : null, outFrame: outFrame !== null && outFrame !== void 0 ? outFrame : null, initiallyShowControls: initiallyShowControls !== null && initiallyShowControls !== void 0 ? initiallyShowControls : true }) }) }) }) }) }) }) }) }) }));
185
201
  };
186
202
  exports.PlayerFn = PlayerFn;
187
203
  exports.Player = (0, react_1.forwardRef)(exports.PlayerFn);
@@ -1,6 +1,8 @@
1
1
  import type { MouseEventHandler } from 'react';
2
2
  import React from 'react';
3
3
  import type { usePlayer } from './use-player';
4
+ export declare const X_SPACER = 10;
5
+ export declare const X_PADDING = 12;
4
6
  declare global {
5
7
  interface Document {
6
8
  webkitFullscreenEnabled?: boolean;
@@ -22,4 +24,10 @@ export declare const Controls: React.FC<{
22
24
  allowFullscreen: boolean;
23
25
  onExitFullscreenButtonClick: MouseEventHandler<HTMLButtonElement>;
24
26
  spaceKeyToPlayOrPause: boolean;
27
+ onSeekEnd: () => void;
28
+ onSeekStart: () => void;
29
+ inFrame: number | null;
30
+ outFrame: number | null;
31
+ initiallyShowControls: number | boolean;
32
+ playerWidth: number;
25
33
  }>;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Controls = void 0;
3
+ exports.Controls = exports.X_PADDING = exports.X_SPACER = void 0;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const react_1 = require("react");
6
6
  const remotion_1 = require("remotion");
@@ -8,6 +8,9 @@ const format_time_1 = require("./format-time");
8
8
  const icons_1 = require("./icons");
9
9
  const MediaVolumeSlider_1 = require("./MediaVolumeSlider");
10
10
  const PlayerSeekBar_1 = require("./PlayerSeekBar");
11
+ const use_video_controls_resize_1 = require("./use-video-controls-resize");
12
+ exports.X_SPACER = 10;
13
+ exports.X_PADDING = 12;
11
14
  const containerStyle = {
12
15
  boxSizing: 'border-box',
13
16
  position: 'absolute',
@@ -17,8 +20,8 @@ const containerStyle = {
17
20
  paddingBottom: 10,
18
21
  background: 'linear-gradient(transparent, rgba(0, 0, 0, 0.4))',
19
22
  display: 'flex',
20
- paddingRight: 12,
21
- paddingLeft: 12,
23
+ paddingRight: exports.X_PADDING,
24
+ paddingLeft: exports.X_PADDING,
22
25
  flexDirection: 'column',
23
26
  transition: 'opacity 0.3s',
24
27
  };
@@ -57,23 +60,40 @@ const flex1 = {
57
60
  flex: 1,
58
61
  };
59
62
  const fullscreen = {};
60
- const timeLabel = {
61
- color: 'white',
62
- fontFamily: 'sans-serif',
63
- fontSize: 14,
64
- };
65
- const Controls = ({ durationInFrames, hovered, isFullscreen, fps, player, showVolumeControls, onFullscreenButtonClick, allowFullscreen, onExitFullscreenButtonClick, spaceKeyToPlayOrPause, }) => {
63
+ const Controls = ({ durationInFrames, hovered, isFullscreen, fps, player, showVolumeControls, onFullscreenButtonClick, allowFullscreen, onExitFullscreenButtonClick, spaceKeyToPlayOrPause, onSeekEnd, onSeekStart, inFrame, outFrame, initiallyShowControls, playerWidth, }) => {
66
64
  const playButtonRef = (0, react_1.useRef)(null);
67
65
  const frame = remotion_1.Internals.Timeline.useTimelinePosition();
68
66
  const [supportsFullscreen, setSupportsFullscreen] = (0, react_1.useState)(false);
67
+ const { maxTimeLabelWidth, displayVerticalVolumeSlider } = (0, use_video_controls_resize_1.useVideoControlsResize)({ allowFullscreen, playerWidth });
68
+ const [shouldShowInitially, setInitiallyShowControls] = (0, react_1.useState)(() => {
69
+ if (typeof initiallyShowControls === 'boolean') {
70
+ return initiallyShowControls;
71
+ }
72
+ if (typeof initiallyShowControls === 'number') {
73
+ if (initiallyShowControls % 1 !== 0) {
74
+ throw new Error('initiallyShowControls must be an integer or a boolean');
75
+ }
76
+ if (Number.isNaN(initiallyShowControls)) {
77
+ throw new Error('initiallyShowControls must not be NaN');
78
+ }
79
+ if (!Number.isFinite(initiallyShowControls)) {
80
+ throw new Error('initiallyShowControls must be finite');
81
+ }
82
+ if (initiallyShowControls <= 0) {
83
+ throw new Error('initiallyShowControls must be a positive integer');
84
+ }
85
+ return initiallyShowControls;
86
+ }
87
+ throw new TypeError('initiallyShowControls must be a number or a boolean');
88
+ });
69
89
  const containerCss = (0, react_1.useMemo)(() => {
70
90
  // Hide if playing and mouse outside
71
- const shouldShow = hovered || !player.playing;
91
+ const shouldShow = hovered || !player.playing || shouldShowInitially;
72
92
  return {
73
93
  ...containerStyle,
74
94
  opacity: Number(shouldShow),
75
95
  };
76
- }, [hovered, player.playing]);
96
+ }, [hovered, shouldShowInitially, player.playing]);
77
97
  (0, react_1.useEffect)(() => {
78
98
  if (playButtonRef.current && spaceKeyToPlayOrPause) {
79
99
  // This switches focus to play button when player.playing flag changes
@@ -88,8 +108,30 @@ const Controls = ({ durationInFrames, hovered, isFullscreen, fps, player, showVo
88
108
  setSupportsFullscreen((_a = (typeof document !== 'undefined' &&
89
109
  (document.fullscreenEnabled || document.webkitFullscreenEnabled))) !== null && _a !== void 0 ? _a : false);
90
110
  }, []);
91
- return ((0, jsx_runtime_1.jsxs)("div", { style: containerCss, children: [(0, jsx_runtime_1.jsxs)("div", { style: controlsRow, children: [(0, jsx_runtime_1.jsxs)("div", { style: leftPartStyle, children: [(0, jsx_runtime_1.jsx)("button", { ref: playButtonRef, type: "button", style: buttonStyle, onClick: player.playing ? player.pause : player.play, "aria-label": player.playing ? 'Pause video' : 'Play video', title: player.playing ? 'Pause video' : 'Play video', children: player.playing ? (0, jsx_runtime_1.jsx)(icons_1.PauseIcon, {}) : (0, jsx_runtime_1.jsx)(icons_1.PlayIcon, {}) }), showVolumeControls ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("div", { style: xSpacer }), (0, jsx_runtime_1.jsx)(MediaVolumeSlider_1.MediaVolumeSlider, {})] })) : null, (0, jsx_runtime_1.jsx)("div", { style: xSpacer }), (0, jsx_runtime_1.jsxs)("div", { style: timeLabel, children: [(0, format_time_1.formatTime)(frame / fps), " / ", (0, format_time_1.formatTime)(durationInFrames / fps)] }), (0, jsx_runtime_1.jsx)("div", { style: xSpacer })] }), (0, jsx_runtime_1.jsx)("div", { style: flex1 }), (0, jsx_runtime_1.jsx)("div", { style: fullscreen, children: supportsFullscreen && allowFullscreen ? ((0, jsx_runtime_1.jsx)("button", { type: "button", "aria-label": isFullscreen ? 'Exit fullscreen' : 'Enter Fullscreen', title: isFullscreen ? 'Exit fullscreen' : 'Enter Fullscreen', style: buttonStyle, onClick: isFullscreen
111
+ (0, react_1.useEffect)(() => {
112
+ if (shouldShowInitially === false) {
113
+ return;
114
+ }
115
+ const time = shouldShowInitially === true ? 2000 : shouldShowInitially;
116
+ const timeout = setTimeout(() => {
117
+ setInitiallyShowControls(false);
118
+ }, time);
119
+ return () => {
120
+ clearInterval(timeout);
121
+ };
122
+ }, [shouldShowInitially]);
123
+ const timeLabel = (0, react_1.useMemo)(() => {
124
+ return {
125
+ color: 'white',
126
+ fontFamily: 'sans-serif',
127
+ fontSize: 14,
128
+ maxWidth: maxTimeLabelWidth,
129
+ overflow: 'hidden',
130
+ textOverflow: 'ellipsis',
131
+ };
132
+ }, [maxTimeLabelWidth]);
133
+ return ((0, jsx_runtime_1.jsxs)("div", { style: containerCss, children: [(0, jsx_runtime_1.jsxs)("div", { style: controlsRow, children: [(0, jsx_runtime_1.jsxs)("div", { style: leftPartStyle, children: [(0, jsx_runtime_1.jsx)("button", { ref: playButtonRef, type: "button", style: buttonStyle, onClick: player.playing ? player.pause : player.play, "aria-label": player.playing ? 'Pause video' : 'Play video', title: player.playing ? 'Pause video' : 'Play video', children: player.playing ? (0, jsx_runtime_1.jsx)(icons_1.PauseIcon, {}) : (0, jsx_runtime_1.jsx)(icons_1.PlayIcon, {}) }), showVolumeControls ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("div", { style: xSpacer }), (0, jsx_runtime_1.jsx)(MediaVolumeSlider_1.MediaVolumeSlider, { displayVerticalVolumeSlider: displayVerticalVolumeSlider })] })) : null, (0, jsx_runtime_1.jsx)("div", { style: xSpacer }), (0, jsx_runtime_1.jsxs)("div", { style: timeLabel, children: [(0, format_time_1.formatTime)(frame / fps), " / ", (0, format_time_1.formatTime)(durationInFrames / fps)] }), (0, jsx_runtime_1.jsx)("div", { style: xSpacer })] }), (0, jsx_runtime_1.jsx)("div", { style: flex1 }), (0, jsx_runtime_1.jsx)("div", { style: fullscreen, children: supportsFullscreen && allowFullscreen ? ((0, jsx_runtime_1.jsx)("button", { type: "button", "aria-label": isFullscreen ? 'Exit fullscreen' : 'Enter Fullscreen', title: isFullscreen ? 'Exit fullscreen' : 'Enter Fullscreen', style: buttonStyle, onClick: isFullscreen
92
134
  ? onExitFullscreenButtonClick
93
- : onFullscreenButtonClick, children: (0, jsx_runtime_1.jsx)(icons_1.FullscreenIcon, { minimized: !isFullscreen }) })) : null })] }), (0, jsx_runtime_1.jsx)("div", { style: ySpacer }), (0, jsx_runtime_1.jsx)(PlayerSeekBar_1.PlayerSeekBar, { durationInFrames: durationInFrames })] }));
135
+ : onFullscreenButtonClick, children: (0, jsx_runtime_1.jsx)(icons_1.FullscreenIcon, { minimized: !isFullscreen }) })) : null })] }), (0, jsx_runtime_1.jsx)("div", { style: ySpacer }), (0, jsx_runtime_1.jsx)(PlayerSeekBar_1.PlayerSeekBar, { onSeekEnd: onSeekEnd, onSeekStart: onSeekStart, durationInFrames: durationInFrames, inFrame: inFrame, outFrame: outFrame })] }));
94
136
  };
95
137
  exports.Controls = Controls;
@@ -1,4 +1,8 @@
1
1
  /// <reference types="react" />
2
2
  export declare const PlayerSeekBar: React.FC<{
3
3
  durationInFrames: number;
4
+ onSeekStart: () => void;
5
+ onSeekEnd: () => void;
6
+ inFrame: number | null;
7
+ outFrame: number | null;
4
8
  }>;
@@ -30,11 +30,18 @@ const containerStyle = {
30
30
  };
31
31
  const barBackground = {
32
32
  height: BAR_HEIGHT,
33
- backgroundColor: 'rgba(255, 255, 255, 0.5)',
33
+ backgroundColor: 'rgba(255, 255, 255, 0.25)',
34
34
  width: '100%',
35
35
  borderRadius: BAR_HEIGHT / 2,
36
36
  };
37
- const PlayerSeekBar = ({ durationInFrames }) => {
37
+ const findBodyInWhichDivIsLocated = (div) => {
38
+ let current = div;
39
+ while (current.parentElement) {
40
+ current = current.parentElement;
41
+ }
42
+ return current;
43
+ };
44
+ const PlayerSeekBar = ({ durationInFrames, onSeekEnd, onSeekStart, inFrame, outFrame }) => {
38
45
  const containerRef = (0, react_1.useRef)(null);
39
46
  const barHovered = (0, use_hover_state_1.useHoverState)(containerRef);
40
47
  const size = (0, use_element_size_1.useElementSize)(containerRef, {
@@ -57,7 +64,8 @@ const PlayerSeekBar = ({ durationInFrames }) => {
57
64
  dragging: true,
58
65
  wasPlaying: playing,
59
66
  });
60
- }, [size, durationInFrames, pause, seek, playing]);
67
+ onSeekStart();
68
+ }, [size, durationInFrames, pause, seek, playing, onSeekStart]);
61
69
  const onPointerMove = (0, react_1.useCallback)((e) => {
62
70
  var _a;
63
71
  if (!size) {
@@ -82,16 +90,18 @@ const PlayerSeekBar = ({ durationInFrames }) => {
82
90
  else {
83
91
  pause();
84
92
  }
85
- }, [dragging, pause, play]);
93
+ onSeekEnd();
94
+ }, [dragging, onSeekEnd, pause, play]);
86
95
  (0, react_1.useEffect)(() => {
87
96
  if (!dragging.dragging) {
88
97
  return;
89
98
  }
90
- window.addEventListener('pointermove', onPointerMove);
91
- window.addEventListener('pointerup', onPointerUp);
99
+ const body = findBodyInWhichDivIsLocated(containerRef.current);
100
+ body.addEventListener('pointermove', onPointerMove);
101
+ body.addEventListener('pointerup', onPointerUp);
92
102
  return () => {
93
- window.removeEventListener('pointermove', onPointerMove);
94
- window.removeEventListener('pointerup', onPointerUp);
103
+ body.removeEventListener('pointermove', onPointerMove);
104
+ body.removeEventListener('pointerup', onPointerUp);
95
105
  };
96
106
  }, [dragging.dragging, onPointerMove, onPointerUp]);
97
107
  const knobStyle = (0, react_1.useMemo)(() => {
@@ -113,10 +123,24 @@ const PlayerSeekBar = ({ durationInFrames }) => {
113
123
  return {
114
124
  height: BAR_HEIGHT,
115
125
  backgroundColor: 'rgba(255, 255, 255, 1)',
116
- width: (frame / (durationInFrames - 1)) * 100 + '%',
126
+ width: ((frame - (inFrame !== null && inFrame !== void 0 ? inFrame : 0)) / (durationInFrames - 1)) * 100 + '%',
127
+ marginLeft: ((inFrame !== null && inFrame !== void 0 ? inFrame : 0) / (durationInFrames - 1)) * 100 + '%',
128
+ borderRadius: BAR_HEIGHT / 2,
129
+ };
130
+ }, [durationInFrames, frame, inFrame]);
131
+ const active = (0, react_1.useMemo)(() => {
132
+ return {
133
+ height: BAR_HEIGHT,
134
+ backgroundColor: 'rgba(255, 255, 255, 0.25)',
135
+ width: (((outFrame !== null && outFrame !== void 0 ? outFrame : durationInFrames - 1) - (inFrame !== null && inFrame !== void 0 ? inFrame : 0)) /
136
+ (durationInFrames - 1)) *
137
+ 100 +
138
+ '%',
139
+ marginLeft: ((inFrame !== null && inFrame !== void 0 ? inFrame : 0) / (durationInFrames - 1)) * 100 + '%',
117
140
  borderRadius: BAR_HEIGHT / 2,
141
+ position: 'absolute',
118
142
  };
119
- }, [durationInFrames, frame]);
120
- return ((0, jsx_runtime_1.jsxs)("div", { ref: containerRef, onPointerDown: onPointerDown, style: containerStyle, children: [(0, jsx_runtime_1.jsx)("div", { style: barBackground, children: (0, jsx_runtime_1.jsx)("div", { style: fillStyle }) }), (0, jsx_runtime_1.jsx)("div", { style: knobStyle })] }));
143
+ }, [durationInFrames, inFrame, outFrame]);
144
+ return ((0, jsx_runtime_1.jsxs)("div", { ref: containerRef, onPointerDown: onPointerDown, style: containerStyle, children: [(0, jsx_runtime_1.jsxs)("div", { style: barBackground, children: [(0, jsx_runtime_1.jsx)("div", { style: active }), (0, jsx_runtime_1.jsx)("div", { style: fillStyle })] }), (0, jsx_runtime_1.jsx)("div", { style: knobStyle })] }));
121
145
  };
122
146
  exports.PlayerSeekBar = PlayerSeekBar;
@@ -7,6 +7,7 @@ export declare type RenderLoading = (canvas: {
7
7
  height: number;
8
8
  width: number;
9
9
  }) => React.ReactChild;
10
+ export declare type RenderPoster = RenderLoading;
10
11
  declare const _default: (props: {
11
12
  controls: boolean;
12
13
  loop: boolean;
@@ -24,8 +25,15 @@ declare const _default: (props: {
24
25
  mediaVolume: number;
25
26
  errorFallback: ErrorFallback;
26
27
  playbackRate: number;
27
- renderLoading?: RenderLoading | undefined;
28
+ renderLoading: RenderLoading | undefined;
29
+ renderPoster: RenderLoading | undefined;
28
30
  className: string | undefined;
29
31
  moveToBeginningWhenEnded: boolean;
32
+ showPosterWhenPaused: boolean;
33
+ showPosterWhenEnded: boolean;
34
+ showPosterWhenUnplayed: boolean;
35
+ inFrame: number | null;
36
+ outFrame: number | null;
37
+ initiallyShowControls: number | boolean;
30
38
  } & React.RefAttributes<PlayerRef | null>) => React.ReactElement<any, string | React.JSXElementConstructor<any>> | null;
31
39
  export default _default;
package/dist/PlayerUI.js CHANGED
@@ -42,8 +42,8 @@ if (reactVersion === '0') {
42
42
  throw new Error(`Version ${reactVersion} of "react" is not supported by Remotion`);
43
43
  }
44
44
  const doesReactVersionSupportSuspense = parseInt(reactVersion, 10) >= 18;
45
- const PlayerUI = ({ controls, style, loop, autoPlay, allowFullscreen, inputProps, clickToPlay, showVolumeControls, mediaVolume, mediaMuted, doubleClickToFullscreen, setMediaMuted, setMediaVolume, spaceKeyToPlayOrPause, errorFallback, playbackRate, renderLoading, className, moveToBeginningWhenEnded, }, ref) => {
46
- var _a, _b, _c;
45
+ const PlayerUI = ({ controls, style, loop, autoPlay, allowFullscreen, inputProps, clickToPlay, showVolumeControls, mediaVolume, mediaMuted, doubleClickToFullscreen, setMediaMuted, setMediaVolume, spaceKeyToPlayOrPause, errorFallback, playbackRate, renderLoading, renderPoster, className, moveToBeginningWhenEnded, showPosterWhenUnplayed, showPosterWhenEnded, showPosterWhenPaused, inFrame, outFrame, initiallyShowControls, }, ref) => {
46
+ var _a, _b, _c, _d, _e;
47
47
  const config = remotion_1.Internals.useUnsafeVideoConfig();
48
48
  const video = remotion_1.Internals.useVideo();
49
49
  const container = (0, react_1.useRef)(null);
@@ -55,12 +55,13 @@ const PlayerUI = ({ controls, style, loop, autoPlay, allowFullscreen, inputProps
55
55
  const [hasPausedToResume, setHasPausedToResume] = (0, react_1.useState)(false);
56
56
  const [shouldAutoplay, setShouldAutoPlay] = (0, react_1.useState)(autoPlay);
57
57
  const [isFullscreen, setIsFullscreen] = (0, react_1.useState)(() => false);
58
+ const [seeking, setSeeking] = (0, react_1.useState)(false);
58
59
  (0, use_playback_1.usePlayback)({
59
60
  loop,
60
61
  playbackRate,
61
62
  moveToBeginningWhenEnded,
62
- inFrame: null,
63
- outFrame: null,
63
+ inFrame,
64
+ outFrame,
64
65
  });
65
66
  const player = (0, use_player_1.usePlayer)();
66
67
  (0, react_1.useEffect)(() => {
@@ -146,6 +147,18 @@ const PlayerUI = ({ controls, style, loop, autoPlay, allowFullscreen, inputProps
146
147
  };
147
148
  }, [player.emitter]);
148
149
  const durationInFrames = (_a = config === null || config === void 0 ? void 0 : config.durationInFrames) !== null && _a !== void 0 ? _a : 1;
150
+ const layout = (0, react_1.useMemo)(() => {
151
+ if (!config || !canvasSize) {
152
+ return null;
153
+ }
154
+ return (0, calculate_scale_1.calculateCanvasTransformation)({
155
+ canvasSize,
156
+ compositionHeight: config.height,
157
+ compositionWidth: config.width,
158
+ previewSize: 'auto',
159
+ });
160
+ }, [canvasSize, config]);
161
+ const scale = (_b = layout === null || layout === void 0 ? void 0 : layout.scale) !== null && _b !== void 0 ? _b : 1;
149
162
  (0, react_1.useImperativeHandle)(ref, () => {
150
163
  const methods = {
151
164
  play: player.play,
@@ -195,6 +208,7 @@ const PlayerUI = ({ controls, style, loop, autoPlay, allowFullscreen, inputProps
195
208
  unmute: () => {
196
209
  setMediaMuted(false);
197
210
  },
211
+ getScale: () => scale,
198
212
  };
199
213
  return Object.assign(player.emitter, methods);
200
214
  }, [
@@ -209,6 +223,7 @@ const PlayerUI = ({ controls, style, loop, autoPlay, allowFullscreen, inputProps
209
223
  setMediaMuted,
210
224
  setMediaVolume,
211
225
  toggle,
226
+ scale,
212
227
  ]);
213
228
  const VideoComponent = video ? video.component : null;
214
229
  const outerStyle = (0, react_1.useMemo)(() => {
@@ -228,22 +243,11 @@ const PlayerUI = ({ controls, style, loop, autoPlay, allowFullscreen, inputProps
228
243
  ...style,
229
244
  };
230
245
  }, [canvasSize, config, style]);
231
- const layout = (0, react_1.useMemo)(() => {
232
- if (!config || !canvasSize) {
233
- return null;
234
- }
235
- return (0, calculate_scale_1.calculateScale)({
236
- canvasSize,
237
- compositionHeight: config.height,
238
- compositionWidth: config.width,
239
- previewSize: 'auto',
240
- });
241
- }, [canvasSize, config]);
242
246
  const outer = (0, react_1.useMemo)(() => {
243
247
  if (!layout || !config) {
244
248
  return {};
245
249
  }
246
- const { centerX, centerY, scale } = layout;
250
+ const { centerX, centerY } = layout;
247
251
  return {
248
252
  width: config.width * scale,
249
253
  height: config.height * scale,
@@ -254,28 +258,22 @@ const PlayerUI = ({ controls, style, loop, autoPlay, allowFullscreen, inputProps
254
258
  top: centerY,
255
259
  overflow: 'hidden',
256
260
  };
257
- }, [config, layout]);
261
+ }, [config, layout, scale]);
258
262
  const containerStyle = (0, react_1.useMemo)(() => {
259
- if (!config || !canvasSize) {
263
+ if (!config || !canvasSize || !layout) {
260
264
  return {};
261
265
  }
262
- const { scale, xCorrection, yCorrection } = (0, calculate_scale_1.calculateScale)({
263
- canvasSize,
264
- compositionHeight: config.height,
265
- compositionWidth: config.width,
266
- previewSize: 'auto',
267
- });
268
266
  return {
269
267
  position: 'absolute',
270
268
  width: config.width,
271
269
  height: config.height,
272
270
  display: 'flex',
273
271
  transform: `scale(${scale})`,
274
- marginLeft: xCorrection,
275
- marginTop: yCorrection,
272
+ marginLeft: layout.xCorrection,
273
+ marginTop: layout.yCorrection,
276
274
  overflow: 'hidden',
277
275
  };
278
- }, [canvasSize, config]);
276
+ }, [canvasSize, config, layout, scale]);
279
277
  const onError = (0, react_1.useCallback)((error) => {
280
278
  player.pause();
281
279
  // Pay attention to `this context`
@@ -292,6 +290,12 @@ const PlayerUI = ({ controls, style, loop, autoPlay, allowFullscreen, inputProps
292
290
  const onSingleClick = (0, react_1.useCallback)((e) => {
293
291
  toggle(e);
294
292
  }, [toggle]);
293
+ const onSeekStart = (0, react_1.useCallback)(() => {
294
+ setSeeking(true);
295
+ }, []);
296
+ const onSeekEnd = (0, react_1.useCallback)(() => {
297
+ setSeeking(false);
298
+ }, []);
295
299
  const onDoubleClick = (0, react_1.useCallback)(() => {
296
300
  if (isFullscreen) {
297
301
  exitFullscreen();
@@ -310,7 +314,22 @@ const PlayerUI = ({ controls, style, loop, autoPlay, allowFullscreen, inputProps
310
314
  if (!config) {
311
315
  return null;
312
316
  }
313
- const content = ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("div", { style: outer, onClick: clickToPlay ? handleClick : undefined, onDoubleClick: doubleClickToFullscreen ? handleDoubleClick : undefined, children: (0, jsx_runtime_1.jsx)("div", { style: containerStyle, className: player_css_classname_1.PLAYER_CSS_CLASSNAME, children: VideoComponent ? ((0, jsx_runtime_1.jsx)(error_boundary_1.ErrorBoundary, { onError: onError, errorFallback: errorFallback, children: (0, jsx_runtime_1.jsx)(VideoComponent, { ...((_b = video === null || video === void 0 ? void 0 : video.defaultProps) !== null && _b !== void 0 ? _b : {}), ...((_c = inputProps) !== null && _c !== void 0 ? _c : {}) }) })) : null }) }), controls ? ((0, jsx_runtime_1.jsx)(PlayerControls_1.Controls, { fps: config.fps, durationInFrames: config.durationInFrames, hovered: hovered, player: player, onFullscreenButtonClick: onFullscreenButtonClick, isFullscreen: isFullscreen, allowFullscreen: allowFullscreen, showVolumeControls: showVolumeControls, onExitFullscreenButtonClick: onExitFullscreenButtonClick, spaceKeyToPlayOrPause: spaceKeyToPlayOrPause })) : null] }));
317
+ const poster = renderPoster
318
+ ? renderPoster({
319
+ height: outerStyle.height,
320
+ width: outerStyle.width,
321
+ })
322
+ : null;
323
+ if (poster === undefined) {
324
+ throw new TypeError('renderPoster() must return a React element, but undefined was returned');
325
+ }
326
+ const shouldShowPoster = poster &&
327
+ [
328
+ showPosterWhenPaused && !player.isPlaying() && !seeking,
329
+ showPosterWhenEnded && player.isLastFrame && !player.isPlaying(),
330
+ showPosterWhenUnplayed && !player.hasPlayed && !player.isPlaying(),
331
+ ].some(Boolean);
332
+ const content = ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("div", { style: outer, onClick: clickToPlay ? handleClick : undefined, onDoubleClick: doubleClickToFullscreen ? handleDoubleClick : undefined, children: (0, jsx_runtime_1.jsx)("div", { style: containerStyle, className: player_css_classname_1.PLAYER_CSS_CLASSNAME, children: VideoComponent ? ((0, jsx_runtime_1.jsx)(error_boundary_1.ErrorBoundary, { onError: onError, errorFallback: errorFallback, children: (0, jsx_runtime_1.jsx)(VideoComponent, { ...((_c = video === null || video === void 0 ? void 0 : video.defaultProps) !== null && _c !== void 0 ? _c : {}), ...((_d = inputProps) !== null && _d !== void 0 ? _d : {}) }) })) : null }) }), shouldShowPoster ? ((0, jsx_runtime_1.jsx)("div", { style: outer, onClick: clickToPlay ? handleClick : undefined, onDoubleClick: doubleClickToFullscreen ? handleDoubleClick : undefined, children: poster })) : null, controls ? ((0, jsx_runtime_1.jsx)(PlayerControls_1.Controls, { fps: config.fps, durationInFrames: config.durationInFrames, hovered: hovered, player: player, onFullscreenButtonClick: onFullscreenButtonClick, isFullscreen: isFullscreen, allowFullscreen: allowFullscreen, showVolumeControls: showVolumeControls, onExitFullscreenButtonClick: onExitFullscreenButtonClick, spaceKeyToPlayOrPause: spaceKeyToPlayOrPause, onSeekEnd: onSeekEnd, onSeekStart: onSeekStart, inFrame: inFrame, outFrame: outFrame, initiallyShowControls: initiallyShowControls, playerWidth: (_e = canvasSize === null || canvasSize === void 0 ? void 0 : canvasSize.width) !== null && _e !== void 0 ? _e : 0 })) : null] }));
314
333
  if (is_node_1.IS_NODE && !doesReactVersionSupportSuspense) {
315
334
  return ((0, jsx_runtime_1.jsx)("div", { ref: container, style: outerStyle, className: className, children: content }));
316
335
  }
@@ -1,7 +1,13 @@
1
1
  import type { PreviewSize } from './utils/preview-size';
2
2
  import type { Size } from './utils/use-element-size';
3
- export declare const calculateScale: ({ previewSize, compositionWidth, compositionHeight, canvasSize, }: {
4
- previewSize: PreviewSize;
3
+ export declare const calculateScale: ({ canvasSize, compositionHeight, compositionWidth, previewSize, }: {
4
+ previewSize: PreviewSize['size'];
5
+ compositionWidth: number;
6
+ compositionHeight: number;
7
+ canvasSize: Size;
8
+ }) => number;
9
+ export declare const calculateCanvasTransformation: ({ previewSize, compositionWidth, compositionHeight, canvasSize, }: {
10
+ previewSize: PreviewSize['size'];
5
11
  compositionWidth: number;
6
12
  compositionHeight: number;
7
13
  canvasSize: Size;
@@ -1,11 +1,20 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.calculateScale = void 0;
4
- const calculateScale = ({ previewSize, compositionWidth, compositionHeight, canvasSize, }) => {
3
+ exports.calculateCanvasTransformation = exports.calculateScale = void 0;
4
+ const calculateScale = ({ canvasSize, compositionHeight, compositionWidth, previewSize, }) => {
5
5
  const heightRatio = canvasSize.height / compositionHeight;
6
6
  const widthRatio = canvasSize.width / compositionWidth;
7
7
  const ratio = Math.min(heightRatio, widthRatio);
8
- const scale = previewSize === 'auto' ? ratio : Number(previewSize);
8
+ return previewSize === 'auto' ? ratio : Number(previewSize);
9
+ };
10
+ exports.calculateScale = calculateScale;
11
+ const calculateCanvasTransformation = ({ previewSize, compositionWidth, compositionHeight, canvasSize, }) => {
12
+ const scale = (0, exports.calculateScale)({
13
+ canvasSize,
14
+ compositionHeight,
15
+ compositionWidth,
16
+ previewSize,
17
+ });
9
18
  const correction = 0 - (1 - scale) / 2;
10
19
  const xCorrection = correction * compositionWidth;
11
20
  const yCorrection = correction * compositionHeight;
@@ -21,4 +30,4 @@ const calculateScale = ({ previewSize, compositionWidth, compositionHeight, canv
21
30
  scale,
22
31
  };
23
32
  };
24
- exports.calculateScale = calculateScale;
33
+ exports.calculateCanvasTransformation = calculateCanvasTransformation;
@@ -7,6 +7,9 @@ declare type ErrorPayload = {
7
7
  declare type TimeUpdateEventPayload = {
8
8
  frame: number;
9
9
  };
10
+ declare type FrameUpdateEventPayload = {
11
+ frame: number;
12
+ };
10
13
  declare type RateChangeEventPayload = {
11
14
  playbackRate: number;
12
15
  };
@@ -21,6 +24,7 @@ declare type StateEventMap = {
21
24
  ended: undefined;
22
25
  error: ErrorPayload;
23
26
  timeupdate: TimeUpdateEventPayload;
27
+ frameupdate: FrameUpdateEventPayload;
24
28
  fullscreenchange: FullscreenChangeEventPayload;
25
29
  };
26
30
  export declare type EventTypes = keyof StateEventMap;
@@ -42,6 +46,7 @@ export declare class PlayerEmitter {
42
46
  dispatchRatechange(playbackRate: number): void;
43
47
  dispatchError(error: Error): void;
44
48
  dispatchTimeUpdate(event: TimeUpdateEventPayload): void;
49
+ dispatchFrameUpdate(event: FrameUpdateEventPayload): void;
45
50
  dispatchFullscreenChangeUpdate(event: FullscreenChangeEventPayload): void;
46
51
  }
47
52
  export {};
@@ -11,6 +11,7 @@ class PlayerEmitter {
11
11
  ratechange: [],
12
12
  seeked: [],
13
13
  timeupdate: [],
14
+ frameupdate: [],
14
15
  fullscreenchange: [],
15
16
  };
16
17
  }
@@ -52,6 +53,9 @@ class PlayerEmitter {
52
53
  dispatchTimeUpdate(event) {
53
54
  this.dispatchEvent('timeupdate', event);
54
55
  }
56
+ dispatchFrameUpdate(event) {
57
+ this.dispatchEvent('frameupdate', event);
58
+ }
55
59
  dispatchFullscreenChangeUpdate(event) {
56
60
  this.dispatchEvent('fullscreenchange', event);
57
61
  }
package/dist/icons.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import React from 'react';
2
2
  export declare const ICON_SIZE = 25;
3
+ export declare const fullscreenIconSize = 16;
3
4
  export declare const PlayIcon: React.FC;
4
5
  export declare const PauseIcon: React.FC;
5
6
  export declare const FullscreenIcon: React.FC<{
package/dist/icons.js CHANGED
@@ -1,9 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.VolumeOnIcon = exports.VolumeOffIcon = exports.FullscreenIcon = exports.PauseIcon = exports.PlayIcon = exports.ICON_SIZE = void 0;
3
+ exports.VolumeOnIcon = exports.VolumeOffIcon = exports.FullscreenIcon = exports.PauseIcon = exports.PlayIcon = exports.fullscreenIconSize = exports.ICON_SIZE = void 0;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  exports.ICON_SIZE = 25;
6
- const fullscreenIconSize = 16;
6
+ exports.fullscreenIconSize = 16;
7
7
  const rotate = {
8
8
  transform: `rotate(90deg)`,
9
9
  };
@@ -21,7 +21,7 @@ const FullscreenIcon = ({ minimized }) => {
21
21
  const out = minimized ? strokeWidth / 2 : 0;
22
22
  const middleInset = minimized ? strokeWidth / 2 : strokeWidth * 1.6;
23
23
  const inset = minimized ? strokeWidth * 2 : strokeWidth * 1.6;
24
- return ((0, jsx_runtime_1.jsxs)("svg", { viewBox: `0 0 ${viewSize} ${viewSize}`, height: fullscreenIconSize, width: fullscreenIconSize, children: [(0, jsx_runtime_1.jsx)("path", { d: `
24
+ return ((0, jsx_runtime_1.jsxs)("svg", { viewBox: `0 0 ${viewSize} ${viewSize}`, height: exports.fullscreenIconSize, width: exports.fullscreenIconSize, children: [(0, jsx_runtime_1.jsx)("path", { d: `
25
25
  M ${out} ${inset}
26
26
  L ${middleInset} ${middleInset}
27
27
  L ${inset} ${out}
package/dist/index.d.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  /// <reference types="react" />
2
2
  import type { CallbackListener, EventTypes } from './event-emitter';
3
3
  import { PlayerEmitter } from './event-emitter';
4
- export { ErrorFallback, Player } from './Player';
4
+ export { ErrorFallback, Player, PlayerProps } from './Player';
5
5
  export { PlayerMethods, PlayerRef } from './player-methods';
6
- export type { RenderLoading } from './PlayerUI';
7
- export { PreviewSize } from './utils/preview-size';
6
+ export type { RenderLoading, RenderPoster } from './PlayerUI';
7
+ export { PreviewSize, Translation } from './utils/preview-size';
8
8
  export { Size } from './utils/use-element-size';
9
9
  export type { CallbackListener, EventTypes };
10
10
  export declare const PlayerInternals: {
@@ -14,6 +14,7 @@ export declare const PlayerInternals: {
14
14
  frameBack: (frames: number) => void;
15
15
  frameForward: (frames: number) => void;
16
16
  isLastFrame: boolean;
17
+ isFirstFrame: boolean;
17
18
  emitter: PlayerEmitter;
18
19
  playing: boolean;
19
20
  play: (e?: import("react").SyntheticEvent<Element, Event> | undefined) => void;
@@ -22,6 +23,7 @@ export declare const PlayerInternals: {
22
23
  seek: (newFrame: number) => void;
23
24
  getCurrentFrame: () => number;
24
25
  isPlaying: () => boolean;
26
+ hasPlayed: boolean;
25
27
  };
26
28
  usePlayback: ({ loop, playbackRate, moveToBeginningWhenEnded, inFrame, outFrame, }: {
27
29
  loop: boolean;
@@ -34,8 +36,8 @@ export declare const PlayerInternals: {
34
36
  triggerOnWindowResize: boolean;
35
37
  shouldApplyCssTransforms: boolean;
36
38
  }) => import("./utils/use-element-size").Size | null;
37
- calculateScale: ({ previewSize, compositionWidth, compositionHeight, canvasSize, }: {
38
- previewSize: import("./utils/preview-size").PreviewSize;
39
+ calculateCanvasTransformation: ({ previewSize, compositionWidth, compositionHeight, canvasSize, }: {
40
+ previewSize: number | "auto";
39
41
  compositionWidth: number;
40
42
  compositionHeight: number;
41
43
  canvasSize: import("./utils/use-element-size").Size;
@@ -48,4 +50,10 @@ export declare const PlayerInternals: {
48
50
  };
49
51
  useHoverState: (ref: import("react").RefObject<HTMLDivElement>) => boolean;
50
52
  updateAllElementsSizes: () => void;
53
+ calculateScale: ({ canvasSize, compositionHeight, compositionWidth, previewSize, }: {
54
+ previewSize: number | "auto";
55
+ compositionWidth: number;
56
+ compositionHeight: number;
57
+ canvasSize: import("./utils/use-element-size").Size;
58
+ }) => number;
51
59
  };
package/dist/index.js CHANGED
@@ -16,7 +16,8 @@ exports.PlayerInternals = {
16
16
  usePlayer: use_player_1.usePlayer,
17
17
  usePlayback: use_playback_1.usePlayback,
18
18
  useElementSize: use_element_size_1.useElementSize,
19
- calculateScale: calculate_scale_1.calculateScale,
19
+ calculateCanvasTransformation: calculate_scale_1.calculateCanvasTransformation,
20
20
  useHoverState: use_hover_state_1.useHoverState,
21
21
  updateAllElementsSizes: use_element_size_1.updateAllElementsSizes,
22
+ calculateScale: calculate_scale_1.calculateScale,
22
23
  };
@@ -1,2 +1 @@
1
1
  export declare const PLAYER_CSS_CLASSNAME = "__remotion-player";
2
- export declare const VOLUME_SLIDER_INPUT_CSS_CLASSNAME: string;
@@ -1,5 +1,4 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.VOLUME_SLIDER_INPUT_CSS_CLASSNAME = exports.PLAYER_CSS_CLASSNAME = void 0;
3
+ exports.PLAYER_CSS_CLASSNAME = void 0;
4
4
  exports.PLAYER_CSS_CLASSNAME = '__remotion-player';
5
- exports.VOLUME_SLIDER_INPUT_CSS_CLASSNAME = exports.PLAYER_CSS_CLASSNAME.concat('_volume-slider-input');
@@ -16,5 +16,6 @@ export declare type PlayerMethods = {
16
16
  isPlaying: () => boolean;
17
17
  mute: () => void;
18
18
  unmute: () => void;
19
+ getScale: () => number;
19
20
  };
20
21
  export declare type PlayerRef = PlayerEmitter & PlayerMethods;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const validate_in_out_frame_1 = require("../utils/validate-in-out-frame");
4
+ test('Validate in out frames', () => {
5
+ expect(() => (0, validate_in_out_frame_1.validateInOutFrames)({
6
+ durationInFrames: 200,
7
+ inFrame: 201,
8
+ outFrame: undefined,
9
+ })).toThrow(/inFrame must be less than \(durationInFrames - 1\)/);
10
+ expect(() => (0, validate_in_out_frame_1.validateInOutFrames)({
11
+ durationInFrames: 200,
12
+ inFrame: 199,
13
+ outFrame: 201,
14
+ })).toThrow(/outFrame must be less than \(durationInFrames - 1\)/);
15
+ expect(() => (0, validate_in_out_frame_1.validateInOutFrames)({
16
+ durationInFrames: 200,
17
+ inFrame: -10,
18
+ outFrame: null,
19
+ })).toThrow(/inFrame must be greater than 0, but is -10/);
20
+ expect(() => (0, validate_in_out_frame_1.validateInOutFrames)({
21
+ durationInFrames: 200,
22
+ inFrame: null,
23
+ outFrame: -10,
24
+ })).toThrow(/outFrame must be greater than 0, but is -10/);
25
+ expect(() => (0, validate_in_out_frame_1.validateInOutFrames)({
26
+ durationInFrames: 200,
27
+ inFrame: 1.5,
28
+ outFrame: null,
29
+ })).toThrow(/"inFrame" must be an integer, but is 1.5/);
30
+ expect(() => (0, validate_in_out_frame_1.validateInOutFrames)({
31
+ durationInFrames: 200,
32
+ inFrame: 20,
33
+ outFrame: 20,
34
+ })).toThrow(/outFrame must be greater than inFrame, but is 20/);
35
+ expect(() => (0, validate_in_out_frame_1.validateInOutFrames)({
36
+ durationInFrames: 200,
37
+ inFrame: 21,
38
+ outFrame: 20,
39
+ })).toThrow(/outFrame must be greater than inFrame, but is 20 <= 21/);
40
+ expect(() => (0, validate_in_out_frame_1.validateInOutFrames)({
41
+ durationInFrames: 200,
42
+ inFrame: null,
43
+ outFrame: 20,
44
+ })).not.toThrow();
45
+ expect(() => (0, validate_in_out_frame_1.validateInOutFrames)({
46
+ durationInFrames: 200,
47
+ inFrame: null,
48
+ outFrame: null,
49
+ })).not.toThrow();
50
+ expect(() => (0, validate_in_out_frame_1.validateInOutFrames)({
51
+ durationInFrames: 200,
52
+ inFrame: 10,
53
+ outFrame: 20,
54
+ })).not.toThrow();
55
+ });
@@ -51,7 +51,7 @@ test('No durationInFrames should give errors', () => {
51
51
  durationInFrames: undefined, component: test_utils_1.HelloWorld, controls: true, showVolumeControls: true }));
52
52
  }
53
53
  catch (e) {
54
- expect(e.message).toMatch(/The "durationInFrames" prop of the <Player\/> component must be a number, but you passed a value of type undefined/);
54
+ expect(e.message).toMatch(/durationInFrames` must be a number, but is undefined/);
55
55
  }
56
56
  });
57
57
  test('Invalid playbackRate should give error', () => {
@@ -85,5 +85,8 @@ const usePlayback = ({ loop, playbackRate, moveToBeginningWhenEnded, inFrame, ou
85
85
  }, 250);
86
86
  return () => clearInterval(interval);
87
87
  }, [emitter]);
88
+ (0, react_1.useEffect)(() => {
89
+ emitter.dispatchFrameUpdate({ frame });
90
+ }, [emitter, frame]);
88
91
  };
89
92
  exports.usePlayback = usePlayback;
@@ -4,6 +4,7 @@ declare type UsePlayerMethods = {
4
4
  frameBack: (frames: number) => void;
5
5
  frameForward: (frames: number) => void;
6
6
  isLastFrame: boolean;
7
+ isFirstFrame: boolean;
7
8
  emitter: PlayerEmitter;
8
9
  playing: boolean;
9
10
  play: (e?: SyntheticEvent) => void;
@@ -12,6 +13,7 @@ declare type UsePlayerMethods = {
12
13
  seek: (newFrame: number) => void;
13
14
  getCurrentFrame: () => number;
14
15
  isPlaying: () => boolean;
16
+ hasPlayed: boolean;
15
17
  };
16
18
  export declare const usePlayer: () => UsePlayerMethods;
17
19
  export {};
@@ -7,8 +7,9 @@ const emitter_context_1 = require("./emitter-context");
7
7
  const usePlayer = () => {
8
8
  var _a;
9
9
  const [playing, setPlaying, imperativePlaying] = remotion_1.Internals.Timeline.usePlayingState();
10
+ const [hasPlayed, setHasPlayed] = (0, react_1.useState)(false);
10
11
  const frame = remotion_1.Internals.Timeline.useTimelinePosition();
11
- const playStart = (0, react_1.useRef)(0);
12
+ const playStart = (0, react_1.useRef)(frame);
12
13
  const setFrame = remotion_1.Internals.Timeline.useTimelineSetFrame();
13
14
  const setTimelinePosition = remotion_1.Internals.Timeline.useTimelineSetFrame();
14
15
  const audioContext = (0, react_1.useContext)(remotion_1.Internals.SharedAudioContext);
@@ -20,6 +21,7 @@ const usePlayer = () => {
20
21
  const emitter = (0, react_1.useContext)(emitter_context_1.PlayerEventEmitterContext);
21
22
  const lastFrame = ((_a = config === null || config === void 0 ? void 0 : config.durationInFrames) !== null && _a !== void 0 ? _a : 1) - 1;
22
23
  const isLastFrame = frame === lastFrame;
24
+ const isFirstFrame = frame === 0;
23
25
  if (!emitter) {
24
26
  throw new TypeError('Expected Player event emitter context');
25
27
  }
@@ -31,6 +33,7 @@ const usePlayer = () => {
31
33
  if (imperativePlaying.current) {
32
34
  return;
33
35
  }
36
+ setHasPlayed(true);
34
37
  if (isLastFrame) {
35
38
  seek(0);
36
39
  }
@@ -104,21 +107,25 @@ const usePlayer = () => {
104
107
  play,
105
108
  pause,
106
109
  seek,
110
+ isFirstFrame,
107
111
  getCurrentFrame: () => frameRef.current,
108
112
  isPlaying: () => imperativePlaying.current,
109
113
  pauseAndReturnToPlayStart,
114
+ hasPlayed,
110
115
  };
111
116
  }, [
112
- emitter,
113
117
  frameBack,
114
118
  frameForward,
115
- imperativePlaying,
116
119
  isLastFrame,
117
- pause,
118
- play,
120
+ emitter,
119
121
  playing,
120
- pauseAndReturnToPlayStart,
122
+ play,
123
+ pause,
121
124
  seek,
125
+ isFirstFrame,
126
+ pauseAndReturnToPlayStart,
127
+ imperativePlaying,
128
+ hasPlayed,
122
129
  ]);
123
130
  return returnValue;
124
131
  };
@@ -0,0 +1,7 @@
1
+ export declare const useVideoControlsResize: ({ allowFullscreen: allowFullScreen, playerWidth, }: {
2
+ allowFullscreen: boolean;
3
+ playerWidth: number;
4
+ }) => {
5
+ maxTimeLabelWidth: number;
6
+ displayVerticalVolumeSlider: boolean;
7
+ };
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useVideoControlsResize = void 0;
4
+ const react_1 = require("react");
5
+ const icons_1 = require("./icons");
6
+ const MediaVolumeSlider_1 = require("./MediaVolumeSlider");
7
+ const PlayerControls_1 = require("./PlayerControls");
8
+ const useVideoControlsResize = ({ allowFullscreen: allowFullScreen, playerWidth, }) => {
9
+ const resizeInfo = (0, react_1.useMemo)(() => {
10
+ const playPauseIconSize = icons_1.ICON_SIZE;
11
+ const volumeIconSize = icons_1.ICON_SIZE;
12
+ const _fullscreenIconSize = allowFullScreen ? icons_1.fullscreenIconSize : 0;
13
+ const elementsSize = volumeIconSize +
14
+ playPauseIconSize +
15
+ _fullscreenIconSize +
16
+ PlayerControls_1.X_PADDING * 2 +
17
+ PlayerControls_1.X_SPACER * 2;
18
+ const maxTimeLabelWidth = playerWidth - elementsSize;
19
+ const maxTimeLabelWidthWithoutNegativeValue = Math.max(maxTimeLabelWidth, 0);
20
+ const availableTimeLabelWidthIfVolumeOpen = maxTimeLabelWidthWithoutNegativeValue - MediaVolumeSlider_1.VOLUME_SLIDER_WIDTH;
21
+ // If max label width is lower than the volume width
22
+ // then it means we need to take it's width as the max label width
23
+ // otherwise we took the available width when volume open
24
+ const computedLabelWidth = availableTimeLabelWidthIfVolumeOpen < MediaVolumeSlider_1.VOLUME_SLIDER_WIDTH
25
+ ? maxTimeLabelWidthWithoutNegativeValue
26
+ : availableTimeLabelWidthIfVolumeOpen;
27
+ const minWidthForHorizontalDisplay = computedLabelWidth + elementsSize + MediaVolumeSlider_1.VOLUME_SLIDER_WIDTH;
28
+ const displayVerticalVolumeSlider = playerWidth < minWidthForHorizontalDisplay;
29
+ return {
30
+ maxTimeLabelWidth: maxTimeLabelWidthWithoutNegativeValue,
31
+ displayVerticalVolumeSlider,
32
+ };
33
+ }, [allowFullScreen, playerWidth]);
34
+ return resizeInfo;
35
+ };
36
+ exports.useVideoControlsResize = useVideoControlsResize;
@@ -1 +1,8 @@
1
- export declare type PreviewSize = 'auto' | number;
1
+ export declare type Translation = {
2
+ x: number;
3
+ y: number;
4
+ };
5
+ export declare type PreviewSize = {
6
+ size: number | 'auto';
7
+ translation: Translation;
8
+ };
@@ -0,0 +1,6 @@
1
+ export declare const validateSingleFrameFrame: (frame: unknown, variableName: string) => number | null;
2
+ export declare const validateInOutFrames: ({ inFrame, durationInFrames, outFrame, }: {
3
+ inFrame: unknown;
4
+ outFrame: unknown;
5
+ durationInFrames: number;
6
+ }) => void;
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.validateInOutFrames = exports.validateSingleFrameFrame = void 0;
4
+ const validateSingleFrameFrame = (frame, variableName) => {
5
+ if (typeof frame === 'undefined' || frame === null) {
6
+ return frame !== null && frame !== void 0 ? frame : null;
7
+ }
8
+ if (typeof frame !== 'number') {
9
+ throw new TypeError(`"${variableName}" must be a number, but is ${JSON.stringify(frame)}`);
10
+ }
11
+ if (Number.isNaN(frame)) {
12
+ throw new TypeError(`"${variableName}" must not be NaN, but is ${JSON.stringify(frame)}`);
13
+ }
14
+ if (!Number.isFinite(frame)) {
15
+ throw new TypeError(`"${variableName}" must be finite, but is ${JSON.stringify(frame)}`);
16
+ }
17
+ if (frame % 1 !== 0) {
18
+ throw new TypeError(`"${variableName}" must be an integer, but is ${JSON.stringify(frame)}`);
19
+ }
20
+ return frame;
21
+ };
22
+ exports.validateSingleFrameFrame = validateSingleFrameFrame;
23
+ const validateInOutFrames = ({ inFrame, durationInFrames, outFrame, }) => {
24
+ const validatedInFrame = (0, exports.validateSingleFrameFrame)(inFrame, 'inFrame');
25
+ const validateOutFrame = (0, exports.validateSingleFrameFrame)(outFrame, 'outFrame');
26
+ if (validatedInFrame === null && validateOutFrame === null) {
27
+ return;
28
+ }
29
+ // Must not be over the duration
30
+ if (validatedInFrame !== null && validatedInFrame > durationInFrames - 1) {
31
+ throw new Error('inFrame must be less than (durationInFrames - 1), but is ' +
32
+ validatedInFrame);
33
+ }
34
+ if (validateOutFrame !== null && validateOutFrame > durationInFrames - 1) {
35
+ throw new Error('outFrame must be less than (durationInFrames - 1), but is ' +
36
+ validatedInFrame);
37
+ }
38
+ // Must not be under 0
39
+ if (validatedInFrame !== null && validatedInFrame < 0) {
40
+ throw new Error('inFrame must be greater than 0, but is ' + validatedInFrame);
41
+ }
42
+ if (validateOutFrame !== null && validateOutFrame < 0) {
43
+ throw new Error('outFrame must be greater than 0, but is ' + validateOutFrame);
44
+ }
45
+ if (validateOutFrame !== null &&
46
+ validatedInFrame !== null &&
47
+ validateOutFrame <= validatedInFrame) {
48
+ throw new Error('outFrame must be greater than inFrame, but is ' +
49
+ validateOutFrame +
50
+ ' <= ' +
51
+ validatedInFrame);
52
+ }
53
+ };
54
+ exports.validateInOutFrames = validateInOutFrames;
@@ -0,0 +1,4 @@
1
+ export declare const validateInitialFrame: ({ initialFrame, durationInFrames, }: {
2
+ initialFrame: unknown;
3
+ durationInFrames: unknown;
4
+ }) => void;
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.validateInitialFrame = void 0;
4
+ const validateInitialFrame = ({ initialFrame, durationInFrames, }) => {
5
+ if (typeof durationInFrames !== 'number') {
6
+ throw new Error(`\`durationInFrames\` must be a number, but is ${JSON.stringify(durationInFrames)}`);
7
+ }
8
+ if (typeof initialFrame === 'undefined') {
9
+ return;
10
+ }
11
+ if (typeof initialFrame !== 'number') {
12
+ throw new Error(`\`initialFrame\` must be a number, but is ${JSON.stringify(initialFrame)}`);
13
+ }
14
+ if (Number.isNaN(initialFrame)) {
15
+ throw new Error(`\`initialFrame\` must be a number, but is NaN`);
16
+ }
17
+ if (!Number.isFinite(initialFrame)) {
18
+ throw new Error(`\`initialFrame\` must be a number, but is Infinity`);
19
+ }
20
+ if (initialFrame % 1 !== 0) {
21
+ throw new Error(`\`initialFrame\` must be an integer, but is ${JSON.stringify(initialFrame)}`);
22
+ }
23
+ if (initialFrame > durationInFrames - 1) {
24
+ throw new Error(`\`initialFrame\` must be less or equal than \`durationInFrames - 1\`, but is ${JSON.stringify(initialFrame)}`);
25
+ }
26
+ };
27
+ exports.validateInitialFrame = validateInitialFrame;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remotion/player",
3
- "version": "4.0.0-umungobongo.5+220a57d86",
3
+ "version": "4.0.0-webhook.26+c8e41db11",
4
4
  "description": "Remotion Player",
5
5
  "main": "dist/index.js",
6
6
  "sideEffects": false,
@@ -28,7 +28,7 @@
28
28
  ],
29
29
  "license": "SEE LICENSE IN LICENSE.md",
30
30
  "dependencies": {
31
- "remotion": "4.0.0-umungobongo.5+220a57d86"
31
+ "remotion": "4.0.0-webhook.26+c8e41db11"
32
32
  },
33
33
  "peerDependencies": {
34
34
  "react": ">=16.8.0",
@@ -50,7 +50,7 @@
50
50
  "react-dom": "^18.0.0",
51
51
  "ts-jest": "^27.0.5",
52
52
  "typescript": "^4.7.0",
53
- "webpack": "5.72.0"
53
+ "webpack": "5.74.0"
54
54
  },
55
55
  "keywords": [
56
56
  "remotion",
@@ -63,5 +63,5 @@
63
63
  "publishConfig": {
64
64
  "access": "public"
65
65
  },
66
- "gitHead": "220a57d86ddead39e87215c5639ed7aa78aeb417"
66
+ "gitHead": "c8e41db114d645c5183edbf016a22b733243dce2"
67
67
  }