@remotion/player 4.0.0-alpha10 → 4.0.0-alpha12

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.
@@ -624,7 +624,12 @@ const useElementSize = (ref, options) => {
624
624
  elementSizeHooks = elementSizeHooks.filter((e) => e !== updateSize);
625
625
  };
626
626
  }, [updateSize]);
627
- return size ? { ...size, refresh: updateSize } : null;
627
+ return useMemo(() => {
628
+ if (!size) {
629
+ return null;
630
+ }
631
+ return { ...size, refresh: updateSize };
632
+ }, [size, updateSize]);
628
633
  };
629
634
 
630
635
  const PLAYER_CSS_CLASSNAME = '__remotion-player';
@@ -707,6 +712,9 @@ const VolumeOffIcon = () => {
707
712
  const VolumeOnIcon = () => {
708
713
  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
714
  };
715
+ const SettingsIcon = ({ iconSize }) => {
716
+ 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" }) }));
717
+ };
710
718
 
711
719
  const BAR_HEIGHT$1 = 5;
712
720
  const KNOB_SIZE$1 = 12;
@@ -749,7 +757,6 @@ const MediaVolumeSlider = ({ displayVerticalVolumeSlider }) => {
749
757
  display: 'inline-flex',
750
758
  background: 'none',
751
759
  border: 'none',
752
- padding: 6,
753
760
  justifyContent: 'center',
754
761
  alignItems: 'center',
755
762
  touchAction: 'none',
@@ -820,6 +827,148 @@ const MediaVolumeSlider = ({ displayVerticalVolumeSlider }) => {
820
827
  } }), 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
828
  };
822
829
 
830
+ // hook to hide a popup/modal when clicked outside
831
+ function useComponentVisible(initialIsVisible) {
832
+ const [isComponentVisible, setIsComponentVisible] = useState(initialIsVisible);
833
+ const ref = useRef(null);
834
+ useEffect(() => {
835
+ const handleClickOutside = (event) => {
836
+ if (ref.current && !ref.current.contains(event.target)) {
837
+ setIsComponentVisible(false);
838
+ }
839
+ };
840
+ document.addEventListener('pointerup', handleClickOutside, true);
841
+ return () => {
842
+ document.removeEventListener('pointerup', handleClickOutside, true);
843
+ };
844
+ }, []);
845
+ return { ref, isComponentVisible, setIsComponentVisible };
846
+ }
847
+
848
+ const playbackPopup = {
849
+ position: 'absolute',
850
+ right: 0,
851
+ width: 125,
852
+ bottom: 35,
853
+ background: '#fff',
854
+ borderRadius: 4,
855
+ overflow: 'hidden',
856
+ color: 'black',
857
+ textAlign: 'left',
858
+ };
859
+ const rateDiv = {
860
+ height: 30,
861
+ paddingRight: 15,
862
+ paddingLeft: 12,
863
+ display: 'flex',
864
+ flexDirection: 'row',
865
+ alignItems: 'center',
866
+ };
867
+ const checkmarkContainer = {
868
+ width: 22,
869
+ display: 'flex',
870
+ alignItems: 'center',
871
+ };
872
+ const checkmarkStyle = {
873
+ width: 14,
874
+ height: 14,
875
+ color: 'black',
876
+ };
877
+ 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" }) }));
878
+ const PlaybackPopup = ({ setIsComponentVisible, playbackRates }) => {
879
+ const { setPlaybackRate, playbackRate } = useContext(Internals.Timeline.TimelineContext);
880
+ const [keyboardSelectedRate, setKeyboardSelectedRate] = useState(playbackRate);
881
+ useEffect(() => {
882
+ const listener = (e) => {
883
+ e.preventDefault();
884
+ if (e.key === 'ArrowUp') {
885
+ const currentIndex = playbackRates.findIndex((rate) => rate === keyboardSelectedRate);
886
+ if (currentIndex === 0) {
887
+ return;
888
+ }
889
+ if (currentIndex === -1) {
890
+ setKeyboardSelectedRate(playbackRates[0]);
891
+ }
892
+ else {
893
+ setKeyboardSelectedRate(playbackRates[currentIndex - 1]);
894
+ }
895
+ }
896
+ else if (e.key === 'ArrowDown') {
897
+ const currentIndex = playbackRates.findIndex((rate) => rate === keyboardSelectedRate);
898
+ if (currentIndex === playbackRates.length - 1) {
899
+ return;
900
+ }
901
+ if (currentIndex === -1) {
902
+ setKeyboardSelectedRate(playbackRates[playbackRates.length - 1]);
903
+ }
904
+ else {
905
+ setKeyboardSelectedRate(playbackRates[currentIndex + 1]);
906
+ }
907
+ }
908
+ else if (e.key === 'Enter') {
909
+ setPlaybackRate(keyboardSelectedRate);
910
+ setIsComponentVisible(false);
911
+ }
912
+ };
913
+ window.addEventListener('keydown', listener);
914
+ return () => {
915
+ window.removeEventListener('keydown', listener);
916
+ };
917
+ }, [
918
+ playbackRates,
919
+ keyboardSelectedRate,
920
+ setPlaybackRate,
921
+ setIsComponentVisible,
922
+ ]);
923
+ const onSelect = useCallback((rate) => {
924
+ setPlaybackRate(rate);
925
+ setIsComponentVisible(false);
926
+ }, [setIsComponentVisible, setPlaybackRate]);
927
+ return (jsx("div", { style: playbackPopup, children: playbackRates.map((rate) => {
928
+ return (jsx(PlaybackrateOption, { selectedRate: playbackRate, onSelect: onSelect, rate: rate, keyboardSelectedRate: keyboardSelectedRate }, rate));
929
+ }) }));
930
+ };
931
+ const PlaybackrateOption = ({ rate, onSelect, selectedRate, keyboardSelectedRate }) => {
932
+ const onClick = useCallback((e) => {
933
+ e.stopPropagation();
934
+ e.preventDefault();
935
+ onSelect(rate);
936
+ }, [onSelect, rate]);
937
+ const [hovered, setHovered] = useState(false);
938
+ const onMouseEnter = useCallback(() => {
939
+ setHovered(true);
940
+ }, []);
941
+ const onMouseLeave = useCallback(() => {
942
+ setHovered(false);
943
+ }, []);
944
+ const actualStyle = useMemo(() => {
945
+ return {
946
+ ...rateDiv,
947
+ backgroundColor: hovered || keyboardSelectedRate === rate ? '#eee' : 'transparent',
948
+ };
949
+ }, [hovered, keyboardSelectedRate, rate]);
950
+ 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));
951
+ };
952
+ const playbackButton = {
953
+ position: 'relative',
954
+ display: 'inline-flex',
955
+ alignItems: 'center',
956
+ padding: '6px 0 6px 0',
957
+ border: 'none',
958
+ background: 'none',
959
+ height: 36,
960
+ cursor: 'pointer',
961
+ };
962
+ const PlaybackrateControl = ({ playbackRates }) => {
963
+ const { ref, isComponentVisible, setIsComponentVisible } = useComponentVisible(false);
964
+ const onClick = useCallback((e) => {
965
+ e.stopPropagation();
966
+ e.preventDefault();
967
+ setIsComponentVisible(!isComponentVisible);
968
+ }, [isComponentVisible, setIsComponentVisible]);
969
+ 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 }))] }) }));
970
+ };
971
+
823
972
  const getFrameFromX = (clientX, durationInFrames, width) => {
824
973
  var _a;
825
974
  const pos = clientX;
@@ -1047,7 +1196,7 @@ const leftPartStyle = {
1047
1196
  alignItems: 'center',
1048
1197
  };
1049
1198
  const xSpacer = {
1050
- width: 10,
1199
+ width: 12,
1051
1200
  };
1052
1201
  const ySpacer = {
1053
1202
  height: 8,
@@ -1057,7 +1206,7 @@ const flex1 = {
1057
1206
  };
1058
1207
  const fullscreen = {};
1059
1208
  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, }) => {
1209
+ const Controls = ({ durationInFrames, hovered, isFullscreen, fps, player, showVolumeControls, onFullscreenButtonClick, allowFullscreen, onExitFullscreenButtonClick, spaceKeyToPlayOrPause, onSeekEnd, onSeekStart, inFrame, outFrame, initiallyShowControls, playerWidth, renderPlayPauseButton, renderFullscreenButton, alwaysShowControls, showPlaybackRateControl, }) => {
1061
1210
  const playButtonRef = useRef(null);
1062
1211
  const frame = Internals.Timeline.useTimelinePosition();
1063
1212
  const [supportsFullscreen, setSupportsFullscreen] = useState(false);
@@ -1127,7 +1276,24 @@ const Controls = ({ durationInFrames, hovered, isFullscreen, fps, player, showVo
1127
1276
  textOverflow: 'ellipsis',
1128
1277
  };
1129
1278
  }, [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
1279
+ const playbackRates = useMemo(() => {
1280
+ if (showPlaybackRateControl === true) {
1281
+ return [0.5, 0.8, 1, 1.2, 1.5, 1.8, 2, 2.5, 3];
1282
+ }
1283
+ if (Array.isArray(showPlaybackRateControl)) {
1284
+ for (const rate of showPlaybackRateControl) {
1285
+ if (typeof rate !== 'number') {
1286
+ throw new Error('Every item in showPlaybackRateControl must be a number');
1287
+ }
1288
+ if (rate <= 0) {
1289
+ throw new Error('Every item in showPlaybackRateControl must be positive');
1290
+ }
1291
+ }
1292
+ return showPlaybackRateControl;
1293
+ }
1294
+ return null;
1295
+ }, [showPlaybackRateControl]);
1296
+ 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
1297
  ? onExitFullscreenButtonClick
1132
1298
  : 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
1299
  };
@@ -1220,7 +1386,7 @@ if (reactVersion$1 === '0') {
1220
1386
  throw new Error(`Version ${reactVersion$1} of "react" is not supported by Remotion`);
1221
1387
  }
1222
1388
  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) => {
1389
+ 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
1390
  var _a, _b, _c, _d;
1225
1391
  const config = Internals.useUnsafeVideoConfig();
1226
1392
  const video = Internals.useVideo();
@@ -1496,7 +1662,7 @@ const PlayerUI = ({ controls, style, loop, autoPlay, allowFullscreen, inputProps
1496
1662
  showPosterWhenEnded && player.isLastFrame && !player.isPlaying(),
1497
1663
  showPosterWhenUnplayed && !player.hasPlayed && !player.isPlaying(),
1498
1664
  ].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] }));
1665
+ 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
1666
  if (IS_NODE && !doesReactVersionSupportSuspense$1) {
1501
1667
  return (jsx("div", { ref: container, style: outerStyle, className: className, children: content }));
1502
1668
  }
@@ -1682,7 +1848,7 @@ const componentOrNullIfLazy = (props) => {
1682
1848
  }
1683
1849
  return null;
1684
1850
  };
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) => {
1851
+ 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
1852
  if (typeof window !== 'undefined') {
1687
1853
  // eslint-disable-next-line react-hooks/rules-of-hooks
1688
1854
  useLayoutEffect(() => {
@@ -1710,6 +1876,7 @@ const PlayerFn = ({ durationInFrames, compositionHeight, compositionWidth, fps,
1710
1876
  const rootRef = useRef(null);
1711
1877
  const audioAndVideoTags = useRef([]);
1712
1878
  const imperativePlaying = useRef(false);
1879
+ const [currentPlaybackRate, setCurrentPlaybackRate] = useState(playbackRate);
1713
1880
  if (typeof compositionHeight !== 'number') {
1714
1881
  throw new TypeError(`'compositionHeight' must be a number but got '${typeof compositionHeight}' instead`);
1715
1882
  }
@@ -1765,10 +1932,13 @@ const PlayerFn = ({ durationInFrames, compositionHeight, compositionWidth, fps,
1765
1932
  numberOfSharedAudioTags < 0) {
1766
1933
  throw new TypeError(`'numberOfSharedAudioTags' must be an integer but got '${numberOfSharedAudioTags}' instead`);
1767
1934
  }
1768
- validatePlaybackRate(playbackRate);
1935
+ validatePlaybackRate(currentPlaybackRate);
1769
1936
  useEffect(() => {
1770
- emitter.dispatchRateChange(playbackRate);
1771
- }, [emitter, playbackRate]);
1937
+ emitter.dispatchRateChange(currentPlaybackRate);
1938
+ }, [emitter, currentPlaybackRate]);
1939
+ useEffect(() => {
1940
+ setCurrentPlaybackRate(playbackRate);
1941
+ }, [playbackRate]);
1772
1942
  useImperativeHandle(ref, () => rootRef.current, []);
1773
1943
  const timelineContextValue = useMemo(() => {
1774
1944
  return {
@@ -1776,14 +1946,14 @@ const PlayerFn = ({ durationInFrames, compositionHeight, compositionWidth, fps,
1776
1946
  playing,
1777
1947
  rootId,
1778
1948
  shouldRegisterSequences: false,
1779
- playbackRate,
1949
+ playbackRate: currentPlaybackRate,
1780
1950
  imperativePlaying,
1781
- setPlaybackRate: () => {
1782
- throw new Error('playback rate');
1951
+ setPlaybackRate: (rate) => {
1952
+ setCurrentPlaybackRate(rate);
1783
1953
  },
1784
1954
  audioAndVideoTags,
1785
1955
  };
1786
- }, [frame, playbackRate, playing, rootId]);
1956
+ }, [frame, currentPlaybackRate, playing, rootId]);
1787
1957
  const setTimelineContextValue = useMemo(() => {
1788
1958
  return {
1789
1959
  setFrame,
@@ -1803,7 +1973,7 @@ const PlayerFn = ({ durationInFrames, compositionHeight, compositionWidth, fps,
1803
1973
  const actualInputProps = useMemo(() => inputProps !== null && inputProps !== void 0 ? inputProps : {}, [inputProps]);
1804
1974
  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
1975
  ? 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 }) }) }) }) }));
1976
+ : 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
1977
  };
1808
1978
  const forward$1 = forwardRef;
1809
1979
  /**
@@ -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
+ };