@remotion/player 4.0.0-alpha10 → 4.0.0-alpha11

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.
@@ -707,6 +707,9 @@ const VolumeOffIcon = () => {
707
707
  const VolumeOnIcon = () => {
708
708
  return (jsx("svg", { width: ICON_SIZE, height: ICON_SIZE, viewBox: "0 0 24 24", children: jsx("path", { d: "M3 10v4c0 .55.45 1 1 1h3l3.29 3.29c.63.63 1.71.18 1.71-.71V6.41c0-.89-1.08-1.34-1.71-.71L7 9H4c-.55 0-1 .45-1 1zm13.5 2A4.5 4.5 0 0014 7.97v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 4.45v.2c0 .38.25.71.6.85C17.18 6.53 19 9.06 19 12s-1.82 5.47-4.4 6.5c-.36.14-.6.47-.6.85v.2c0 .63.63 1.07 1.21.85C18.6 19.11 21 15.84 21 12s-2.4-7.11-5.79-8.4c-.58-.23-1.21.22-1.21.85z", fill: "#fff" }) }));
709
709
  };
710
+ const SettingsIcon = ({ iconSize }) => {
711
+ return (jsx("svg", { xmlns: "http://www.w3.org/2000/svg", height: iconSize !== null && iconSize !== void 0 ? iconSize : ICON_SIZE, viewBox: "0 0 512 512", style: { fill: '#fff' }, children: jsx("path", { d: "M495.9 166.6c3.2 8.7 .5 18.4-6.4 24.6l-43.3 39.4c1.1 8.3 1.7 16.8 1.7 25.4s-.6 17.1-1.7 25.4l43.3 39.4c6.9 6.2 9.6 15.9 6.4 24.6c-4.4 11.9-9.7 23.3-15.8 34.3l-4.7 8.1c-6.6 11-14 21.4-22.1 31.2c-5.9 7.2-15.7 9.6-24.5 6.8l-55.7-17.7c-13.4 10.3-28.2 18.9-44 25.4l-12.5 57.1c-2 9.1-9 16.3-18.2 17.8c-13.8 2.3-28 3.5-42.5 3.5s-28.7-1.2-42.5-3.5c-9.2-1.5-16.2-8.7-18.2-17.8l-12.5-57.1c-15.8-6.5-30.6-15.1-44-25.4L83.1 425.9c-8.8 2.8-18.6 .3-24.5-6.8c-8.1-9.8-15.5-20.2-22.1-31.2l-4.7-8.1c-6.1-11-11.4-22.4-15.8-34.3c-3.2-8.7-.5-18.4 6.4-24.6l43.3-39.4C64.6 273.1 64 264.6 64 256s.6-17.1 1.7-25.4L22.4 191.2c-6.9-6.2-9.6-15.9-6.4-24.6c4.4-11.9 9.7-23.3 15.8-34.3l4.7-8.1c6.6-11 14-21.4 22.1-31.2c5.9-7.2 15.7-9.6 24.5-6.8l55.7 17.7c13.4-10.3 28.2-18.9 44-25.4l12.5-57.1c2-9.1 9-16.3 18.2-17.8C227.3 1.2 241.5 0 256 0s28.7 1.2 42.5 3.5c9.2 1.5 16.2 8.7 18.2 17.8l12.5 57.1c15.8 6.5 30.6 15.1 44 25.4l55.7-17.7c8.8-2.8 18.6-.3 24.5 6.8c8.1 9.8 15.5 20.2 22.1 31.2l4.7 8.1c6.1 11 11.4 22.4 15.8 34.3zM256 336a80 80 0 1 0 0-160 80 80 0 1 0 0 160z" }) }));
712
+ };
710
713
 
711
714
  const BAR_HEIGHT$1 = 5;
712
715
  const KNOB_SIZE$1 = 12;
@@ -749,7 +752,6 @@ const MediaVolumeSlider = ({ displayVerticalVolumeSlider }) => {
749
752
  display: 'inline-flex',
750
753
  background: 'none',
751
754
  border: 'none',
752
- padding: 6,
753
755
  justifyContent: 'center',
754
756
  alignItems: 'center',
755
757
  touchAction: 'none',
@@ -820,6 +822,148 @@ const MediaVolumeSlider = ({ displayVerticalVolumeSlider }) => {
820
822
  } }), 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 ? jsx(VolumeOffIcon, {}) : jsx(VolumeOnIcon, {}) }), (focused || hover) && !mediaMuted ? (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] }));
821
823
  };
822
824
 
825
+ // hook to hide a popup/modal when clicked outside
826
+ function useComponentVisible(initialIsVisible) {
827
+ const [isComponentVisible, setIsComponentVisible] = useState(initialIsVisible);
828
+ const ref = useRef(null);
829
+ useEffect(() => {
830
+ const handleClickOutside = (event) => {
831
+ if (ref.current && !ref.current.contains(event.target)) {
832
+ setIsComponentVisible(false);
833
+ }
834
+ };
835
+ document.addEventListener('pointerup', handleClickOutside, true);
836
+ return () => {
837
+ document.removeEventListener('pointerup', handleClickOutside, true);
838
+ };
839
+ }, []);
840
+ return { ref, isComponentVisible, setIsComponentVisible };
841
+ }
842
+
843
+ const playbackPopup = {
844
+ position: 'absolute',
845
+ right: 0,
846
+ width: 125,
847
+ bottom: 35,
848
+ background: '#fff',
849
+ borderRadius: 4,
850
+ overflow: 'hidden',
851
+ color: 'black',
852
+ textAlign: 'left',
853
+ };
854
+ const rateDiv = {
855
+ height: 30,
856
+ paddingRight: 15,
857
+ paddingLeft: 12,
858
+ display: 'flex',
859
+ flexDirection: 'row',
860
+ alignItems: 'center',
861
+ };
862
+ const checkmarkContainer = {
863
+ width: 22,
864
+ display: 'flex',
865
+ alignItems: 'center',
866
+ };
867
+ const checkmarkStyle = {
868
+ width: 14,
869
+ height: 14,
870
+ color: 'black',
871
+ };
872
+ 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" }) }));
873
+ const PlaybackPopup = ({ setIsComponentVisible, playbackRates }) => {
874
+ const { setPlaybackRate, playbackRate } = useContext(Internals.Timeline.TimelineContext);
875
+ const [keyboardSelectedRate, setKeyboardSelectedRate] = useState(playbackRate);
876
+ useEffect(() => {
877
+ const listener = (e) => {
878
+ e.preventDefault();
879
+ if (e.key === 'ArrowUp') {
880
+ const currentIndex = playbackRates.findIndex((rate) => rate === keyboardSelectedRate);
881
+ if (currentIndex === 0) {
882
+ return;
883
+ }
884
+ if (currentIndex === -1) {
885
+ setKeyboardSelectedRate(playbackRates[0]);
886
+ }
887
+ else {
888
+ setKeyboardSelectedRate(playbackRates[currentIndex - 1]);
889
+ }
890
+ }
891
+ else if (e.key === 'ArrowDown') {
892
+ const currentIndex = playbackRates.findIndex((rate) => rate === keyboardSelectedRate);
893
+ if (currentIndex === playbackRates.length - 1) {
894
+ return;
895
+ }
896
+ if (currentIndex === -1) {
897
+ setKeyboardSelectedRate(playbackRates[playbackRates.length - 1]);
898
+ }
899
+ else {
900
+ setKeyboardSelectedRate(playbackRates[currentIndex + 1]);
901
+ }
902
+ }
903
+ else if (e.key === 'Enter') {
904
+ setPlaybackRate(keyboardSelectedRate);
905
+ setIsComponentVisible(false);
906
+ }
907
+ };
908
+ window.addEventListener('keydown', listener);
909
+ return () => {
910
+ window.removeEventListener('keydown', listener);
911
+ };
912
+ }, [
913
+ playbackRates,
914
+ keyboardSelectedRate,
915
+ setPlaybackRate,
916
+ setIsComponentVisible,
917
+ ]);
918
+ const onSelect = useCallback((rate) => {
919
+ setPlaybackRate(rate);
920
+ setIsComponentVisible(false);
921
+ }, [setIsComponentVisible, setPlaybackRate]);
922
+ return (jsx("div", { style: playbackPopup, children: playbackRates.map((rate) => {
923
+ return (jsx(PlaybackrateOption, { selectedRate: playbackRate, onSelect: onSelect, rate: rate, keyboardSelectedRate: keyboardSelectedRate }, rate));
924
+ }) }));
925
+ };
926
+ const PlaybackrateOption = ({ rate, onSelect, selectedRate, keyboardSelectedRate }) => {
927
+ const onClick = useCallback((e) => {
928
+ e.stopPropagation();
929
+ e.preventDefault();
930
+ onSelect(rate);
931
+ }, [onSelect, rate]);
932
+ const [hovered, setHovered] = useState(false);
933
+ const onMouseEnter = useCallback(() => {
934
+ setHovered(true);
935
+ }, []);
936
+ const onMouseLeave = useCallback(() => {
937
+ setHovered(false);
938
+ }, []);
939
+ const actualStyle = useMemo(() => {
940
+ return {
941
+ ...rateDiv,
942
+ backgroundColor: hovered || keyboardSelectedRate === rate ? '#eee' : 'transparent',
943
+ };
944
+ }, [hovered, keyboardSelectedRate, rate]);
945
+ 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));
946
+ };
947
+ const playbackButton = {
948
+ position: 'relative',
949
+ display: 'inline-flex',
950
+ alignItems: 'center',
951
+ padding: '6px 0 6px 0',
952
+ border: 'none',
953
+ background: 'none',
954
+ height: 36,
955
+ cursor: 'pointer',
956
+ };
957
+ const PlaybackrateControl = ({ playbackRates }) => {
958
+ const { ref, isComponentVisible, setIsComponentVisible } = useComponentVisible(false);
959
+ const onClick = useCallback((e) => {
960
+ e.stopPropagation();
961
+ e.preventDefault();
962
+ setIsComponentVisible(!isComponentVisible);
963
+ }, [isComponentVisible, setIsComponentVisible]);
964
+ return (jsx("div", { ref: ref, children: jsxs("button", { type: "button", "aria-label": "Change playback rate", style: playbackButton, onClick: onClick, children: [jsx(SettingsIcon, { iconSize: 22 }), isComponentVisible && (jsx(PlaybackPopup, { playbackRates: playbackRates, setIsComponentVisible: setIsComponentVisible }))] }) }));
965
+ };
966
+
823
967
  const getFrameFromX = (clientX, durationInFrames, width) => {
824
968
  var _a;
825
969
  const pos = clientX;
@@ -1047,7 +1191,7 @@ const leftPartStyle = {
1047
1191
  alignItems: 'center',
1048
1192
  };
1049
1193
  const xSpacer = {
1050
- width: 10,
1194
+ width: 12,
1051
1195
  };
1052
1196
  const ySpacer = {
1053
1197
  height: 8,
@@ -1057,7 +1201,7 @@ const flex1 = {
1057
1201
  };
1058
1202
  const fullscreen = {};
1059
1203
  const PlayPauseButton = ({ playing }) => playing ? jsx(PauseIcon, {}) : jsx(PlayIcon, {});
1060
- const Controls = ({ durationInFrames, hovered, isFullscreen, fps, player, showVolumeControls, onFullscreenButtonClick, allowFullscreen, onExitFullscreenButtonClick, spaceKeyToPlayOrPause, onSeekEnd, onSeekStart, inFrame, outFrame, initiallyShowControls, playerWidth, renderPlayPauseButton, renderFullscreenButton, alwaysShowControls, }) => {
1204
+ const Controls = ({ durationInFrames, hovered, isFullscreen, fps, player, showVolumeControls, onFullscreenButtonClick, allowFullscreen, onExitFullscreenButtonClick, spaceKeyToPlayOrPause, onSeekEnd, onSeekStart, inFrame, outFrame, initiallyShowControls, playerWidth, renderPlayPauseButton, renderFullscreenButton, alwaysShowControls, showPlaybackRateControl, }) => {
1061
1205
  const playButtonRef = useRef(null);
1062
1206
  const frame = Internals.Timeline.useTimelinePosition();
1063
1207
  const [supportsFullscreen, setSupportsFullscreen] = useState(false);
@@ -1127,7 +1271,24 @@ const Controls = ({ durationInFrames, hovered, isFullscreen, fps, player, showVo
1127
1271
  textOverflow: 'ellipsis',
1128
1272
  };
1129
1273
  }, [maxTimeLabelWidth]);
1130
- return (jsxs("div", { style: containerCss, children: [jsxs("div", { style: controlsRow, children: [jsxs("div", { style: leftPartStyle, children: [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: renderPlayPauseButton === null ? (jsx(PlayPauseButton, { playing: player.playing })) : (renderPlayPauseButton({ playing: player.playing })) }), showVolumeControls ? (jsxs(Fragment, { children: [jsx("div", { style: xSpacer }), jsx(MediaVolumeSlider, { displayVerticalVolumeSlider: displayVerticalVolumeSlider })] })) : null, jsx("div", { style: xSpacer }), jsxs("div", { style: timeLabel, children: [formatTime(frame / fps), " / ", formatTime(durationInFrames / fps)] }), jsx("div", { style: xSpacer })] }), jsx("div", { style: flex1 }), jsx("div", { style: fullscreen, children: supportsFullscreen && allowFullscreen ? (jsx("button", { type: "button", "aria-label": isFullscreen ? 'Exit fullscreen' : 'Enter Fullscreen', title: isFullscreen ? 'Exit fullscreen' : 'Enter Fullscreen', style: buttonStyle, onClick: isFullscreen
1274
+ const playbackRates = useMemo(() => {
1275
+ if (showPlaybackRateControl === true) {
1276
+ return [0.5, 0.8, 1, 1.2, 1.5, 1.8, 2, 2.5, 3];
1277
+ }
1278
+ if (Array.isArray(showPlaybackRateControl)) {
1279
+ for (const rate of showPlaybackRateControl) {
1280
+ if (typeof rate !== 'number') {
1281
+ throw new Error('Every item in showPlaybackRateControl must be a number');
1282
+ }
1283
+ if (rate <= 0) {
1284
+ throw new Error('Every item in showPlaybackRateControl must be positive');
1285
+ }
1286
+ }
1287
+ return showPlaybackRateControl;
1288
+ }
1289
+ return null;
1290
+ }, [showPlaybackRateControl]);
1291
+ return (jsxs("div", { style: containerCss, children: [jsxs("div", { style: controlsRow, children: [jsxs("div", { style: leftPartStyle, children: [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: renderPlayPauseButton === null ? (jsx(PlayPauseButton, { playing: player.playing })) : (renderPlayPauseButton({ playing: player.playing })) }), showVolumeControls ? (jsxs(Fragment, { children: [jsx("div", { style: xSpacer }), jsx(MediaVolumeSlider, { displayVerticalVolumeSlider: displayVerticalVolumeSlider })] })) : null, jsx("div", { style: xSpacer }), jsxs("div", { style: timeLabel, children: [formatTime(frame / fps), " / ", formatTime(durationInFrames / fps)] }), jsx("div", { style: xSpacer })] }), jsx("div", { style: flex1 }), playbackRates && jsx(PlaybackrateControl, { playbackRates: playbackRates }), playbackRates && supportsFullscreen && allowFullscreen ? (jsx("div", { style: xSpacer })) : null, jsx("div", { style: fullscreen, children: supportsFullscreen && allowFullscreen ? (jsx("button", { type: "button", "aria-label": isFullscreen ? 'Exit fullscreen' : 'Enter Fullscreen', title: isFullscreen ? 'Exit fullscreen' : 'Enter Fullscreen', style: buttonStyle, onClick: isFullscreen
1131
1292
  ? onExitFullscreenButtonClick
1132
1293
  : onFullscreenButtonClick, children: renderFullscreenButton === null ? (jsx(FullscreenIcon, { isFullscreen: isFullscreen })) : (renderFullscreenButton({ isFullscreen })) })) : null })] }), jsx("div", { style: ySpacer }), jsx(PlayerSeekBar, { onSeekEnd: onSeekEnd, onSeekStart: onSeekStart, durationInFrames: durationInFrames, inFrame: inFrame, outFrame: outFrame })] }));
1133
1294
  };
@@ -1220,7 +1381,7 @@ if (reactVersion$1 === '0') {
1220
1381
  throw new Error(`Version ${reactVersion$1} of "react" is not supported by Remotion`);
1221
1382
  }
1222
1383
  const doesReactVersionSupportSuspense$1 = parseInt(reactVersion$1, 10) >= 18;
1223
- const PlayerUI = ({ controls, style, loop, autoPlay, allowFullscreen, inputProps, clickToPlay, showVolumeControls, doubleClickToFullscreen, spaceKeyToPlayOrPause, errorFallback, playbackRate, renderLoading, renderPoster, className, moveToBeginningWhenEnded, showPosterWhenUnplayed, showPosterWhenEnded, showPosterWhenPaused, inFrame, outFrame, initiallyShowControls, renderFullscreen: renderFullscreenButton, renderPlayPauseButton, alwaysShowControls, }, ref) => {
1384
+ const PlayerUI = ({ controls, style, loop, autoPlay, allowFullscreen, inputProps, clickToPlay, showVolumeControls, doubleClickToFullscreen, spaceKeyToPlayOrPause, errorFallback, playbackRate, renderLoading, renderPoster, className, moveToBeginningWhenEnded, showPosterWhenUnplayed, showPosterWhenEnded, showPosterWhenPaused, inFrame, outFrame, initiallyShowControls, renderFullscreen: renderFullscreenButton, renderPlayPauseButton, alwaysShowControls, showPlaybackRateControl, }, ref) => {
1224
1385
  var _a, _b, _c, _d;
1225
1386
  const config = Internals.useUnsafeVideoConfig();
1226
1387
  const video = Internals.useVideo();
@@ -1496,7 +1657,7 @@ const PlayerUI = ({ controls, style, loop, autoPlay, allowFullscreen, inputProps
1496
1657
  showPosterWhenEnded && player.isLastFrame && !player.isPlaying(),
1497
1658
  showPosterWhenUnplayed && !player.hasPlayed && !player.isPlaying(),
1498
1659
  ].some(Boolean);
1499
- const content = (jsxs(Fragment, { children: [jsx("div", { style: outer, onClick: clickToPlay ? handleClick : undefined, onDoubleClick: doubleClickToFullscreen ? handleDoubleClick : undefined, children: jsx("div", { style: containerStyle, className: PLAYER_CSS_CLASSNAME, children: VideoComponent ? (jsx(ErrorBoundary, { onError: onError, errorFallback: errorFallback, children: jsx(VideoComponent, { ...((_c = video === null || video === void 0 ? void 0 : video.defaultProps) !== null && _c !== void 0 ? _c : {}), ...(inputProps !== null && inputProps !== void 0 ? inputProps : {}) }) })) : null }) }), shouldShowPoster ? (jsx("div", { style: outer, onClick: clickToPlay ? handleClick : undefined, onDoubleClick: doubleClickToFullscreen ? handleDoubleClick : undefined, children: poster })) : null, controls ? (jsx(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: (_d = canvasSize === null || canvasSize === void 0 ? void 0 : canvasSize.width) !== null && _d !== void 0 ? _d : 0, renderFullscreenButton: renderFullscreenButton, renderPlayPauseButton: renderPlayPauseButton, alwaysShowControls: alwaysShowControls })) : null] }));
1660
+ const content = (jsxs(Fragment, { children: [jsx("div", { style: outer, onClick: clickToPlay ? handleClick : undefined, onDoubleClick: doubleClickToFullscreen ? handleDoubleClick : undefined, children: jsx("div", { style: containerStyle, className: PLAYER_CSS_CLASSNAME, children: VideoComponent ? (jsx(ErrorBoundary, { onError: onError, errorFallback: errorFallback, children: jsx(VideoComponent, { ...((_c = video === null || video === void 0 ? void 0 : video.defaultProps) !== null && _c !== void 0 ? _c : {}), ...(inputProps !== null && inputProps !== void 0 ? inputProps : {}) }) })) : null }) }), shouldShowPoster ? (jsx("div", { style: outer, onClick: clickToPlay ? handleClick : undefined, onDoubleClick: doubleClickToFullscreen ? handleDoubleClick : undefined, children: poster })) : null, controls ? (jsx(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: (_d = canvasSize === null || canvasSize === void 0 ? void 0 : canvasSize.width) !== null && _d !== void 0 ? _d : 0, renderFullscreenButton: renderFullscreenButton, renderPlayPauseButton: renderPlayPauseButton, alwaysShowControls: alwaysShowControls, showPlaybackRateControl: showPlaybackRateControl })) : null] }));
1500
1661
  if (IS_NODE && !doesReactVersionSupportSuspense$1) {
1501
1662
  return (jsx("div", { ref: container, style: outerStyle, className: className, children: content }));
1502
1663
  }
@@ -1682,7 +1843,7 @@ const componentOrNullIfLazy = (props) => {
1682
1843
  }
1683
1844
  return null;
1684
1845
  };
1685
- 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, renderFullscreenButton, renderPlayPauseButton, alwaysShowControls = false, initiallyMuted = false, ...componentProps }, ref) => {
1846
+ 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, renderFullscreenButton, renderPlayPauseButton, alwaysShowControls = false, initiallyMuted = false, showPlaybackRateControl = false, ...componentProps }, ref) => {
1686
1847
  if (typeof window !== 'undefined') {
1687
1848
  // eslint-disable-next-line react-hooks/rules-of-hooks
1688
1849
  useLayoutEffect(() => {
@@ -1710,6 +1871,7 @@ const PlayerFn = ({ durationInFrames, compositionHeight, compositionWidth, fps,
1710
1871
  const rootRef = useRef(null);
1711
1872
  const audioAndVideoTags = useRef([]);
1712
1873
  const imperativePlaying = useRef(false);
1874
+ const [currentPlaybackRate, setCurrentPlaybackRate] = useState(playbackRate);
1713
1875
  if (typeof compositionHeight !== 'number') {
1714
1876
  throw new TypeError(`'compositionHeight' must be a number but got '${typeof compositionHeight}' instead`);
1715
1877
  }
@@ -1765,10 +1927,13 @@ const PlayerFn = ({ durationInFrames, compositionHeight, compositionWidth, fps,
1765
1927
  numberOfSharedAudioTags < 0) {
1766
1928
  throw new TypeError(`'numberOfSharedAudioTags' must be an integer but got '${numberOfSharedAudioTags}' instead`);
1767
1929
  }
1768
- validatePlaybackRate(playbackRate);
1930
+ validatePlaybackRate(currentPlaybackRate);
1769
1931
  useEffect(() => {
1770
- emitter.dispatchRateChange(playbackRate);
1771
- }, [emitter, playbackRate]);
1932
+ emitter.dispatchRateChange(currentPlaybackRate);
1933
+ }, [emitter, currentPlaybackRate]);
1934
+ useEffect(() => {
1935
+ setCurrentPlaybackRate(playbackRate);
1936
+ }, [playbackRate]);
1772
1937
  useImperativeHandle(ref, () => rootRef.current, []);
1773
1938
  const timelineContextValue = useMemo(() => {
1774
1939
  return {
@@ -1776,14 +1941,14 @@ const PlayerFn = ({ durationInFrames, compositionHeight, compositionWidth, fps,
1776
1941
  playing,
1777
1942
  rootId,
1778
1943
  shouldRegisterSequences: false,
1779
- playbackRate,
1944
+ playbackRate: currentPlaybackRate,
1780
1945
  imperativePlaying,
1781
- setPlaybackRate: () => {
1782
- throw new Error('playback rate');
1946
+ setPlaybackRate: (rate) => {
1947
+ setCurrentPlaybackRate(rate);
1783
1948
  },
1784
1949
  audioAndVideoTags,
1785
1950
  };
1786
- }, [frame, playbackRate, playing, rootId]);
1951
+ }, [frame, currentPlaybackRate, playing, rootId]);
1787
1952
  const setTimelineContextValue = useMemo(() => {
1788
1953
  return {
1789
1954
  setFrame,
@@ -1803,7 +1968,7 @@ const PlayerFn = ({ durationInFrames, compositionHeight, compositionWidth, fps,
1803
1968
  const actualInputProps = useMemo(() => inputProps !== null && inputProps !== void 0 ? inputProps : {}, [inputProps]);
1804
1969
  return (jsx(Internals.IsPlayerContextProvider, { children: jsx(SharedPlayerContexts, { timelineContext: timelineContextValue, component: component, compositionHeight: compositionHeight, compositionWidth: compositionWidth, durationInFrames: durationInFrames, fps: fps, inputProps: actualInputProps, numberOfSharedAudioTags: numberOfSharedAudioTags, initiallyMuted: initiallyMuted, children: jsx(Internals.Timeline.SetTimelineContext.Provider, { value: setTimelineContextValue, children: jsx(PlayerEventEmitterContext.Provider, { value: emitter, children: jsx(PlayerUI$1, { 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'
1805
1970
  ? clickToPlay
1806
- : Boolean(controls), showVolumeControls: Boolean(showVolumeControls), doubleClickToFullscreen: Boolean(doubleClickToFullscreen), 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, renderFullscreen: renderFullscreenButton !== null && renderFullscreenButton !== void 0 ? renderFullscreenButton : null, renderPlayPauseButton: renderPlayPauseButton !== null && renderPlayPauseButton !== void 0 ? renderPlayPauseButton : null, alwaysShowControls: alwaysShowControls }) }) }) }) }));
1971
+ : Boolean(controls), showVolumeControls: Boolean(showVolumeControls), doubleClickToFullscreen: Boolean(doubleClickToFullscreen), spaceKeyToPlayOrPause: Boolean(spaceKeyToPlayOrPause), playbackRate: currentPlaybackRate, 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, renderFullscreen: renderFullscreenButton !== null && renderFullscreenButton !== void 0 ? renderFullscreenButton : null, renderPlayPauseButton: renderPlayPauseButton !== null && renderPlayPauseButton !== void 0 ? renderPlayPauseButton : null, alwaysShowControls: alwaysShowControls, showPlaybackRateControl: showPlaybackRateControl }) }) }) }) }));
1807
1972
  };
1808
1973
  const forward$1 = forwardRef;
1809
1974
  /**
@@ -0,0 +1,5 @@
1
+ export default function useComponentVisible(initialIsVisible: boolean): {
2
+ ref: import("react").RefObject<HTMLDivElement>;
3
+ isComponentVisible: boolean;
4
+ setIsComponentVisible: import("react").Dispatch<import("react").SetStateAction<boolean>>;
5
+ };