useFullscreen.tsx 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. import {MutableRefObject, useCallback, useEffect, useRef, useState} from 'react';
  2. import screenfull from 'screenfull';
  3. // See: https://developer.mozilla.org/en-US/docs/web/api/element/requestfullscreen#options_2
  4. interface FullscreenOptions {
  5. navigationUI: 'hide' | 'show' | 'auto';
  6. }
  7. interface FullscreenHook {
  8. /**
  9. * Render, in fullscreen, the `ref` that this instance relates to. If `ref`
  10. * is unset, then `<html>` will be used.
  11. */
  12. enter: (options?: FullscreenOptions) => void;
  13. /**
  14. * Bring the browser out of fullscreen, regardless of which DOM element is
  15. * currently active.
  16. */
  17. exit: () => void;
  18. /**
  19. * If the browser supports going fullscreen or not. iPhone Safari won't do
  20. * it. https://caniuse.com/fullscreen
  21. */
  22. isEnabled: boolean;
  23. /**
  24. * Whether any element on the page is rendered fullscreen.
  25. */
  26. isFullscreen: boolean;
  27. /**
  28. * The element that this instance of `enter()` will use to go fullscreen.
  29. * Calling `useFullscreen()` a second time will create a different instance of
  30. * `ref` and `enter.
  31. */
  32. ref: MutableRefObject<null | HTMLDivElement>;
  33. /**
  34. * Toggle fullscreen mode on and off, for the `ref` that this instance
  35. * relates to.
  36. */
  37. toggle: () => void;
  38. }
  39. // TODO(replay): move into app/utils/*
  40. export default function useFullscreen(): FullscreenHook {
  41. const ref = useRef<null | HTMLDivElement>(null);
  42. const [isFullscreen, setIsFullscreen] = useState(false);
  43. const enter = useCallback(async (opts: FullscreenOptions = {navigationUI: 'auto'}) => {
  44. if (screenfull.isEnabled && ref.current) {
  45. await screenfull.request(ref.current, opts);
  46. }
  47. }, []);
  48. const exit = useCallback(async () => {
  49. if (screenfull.isEnabled) {
  50. await screenfull.exit();
  51. }
  52. }, []);
  53. const toggle = useCallback(
  54. () => (isFullscreen ? exit() : enter()),
  55. [enter, exit, isFullscreen]
  56. );
  57. useEffect(() => {
  58. const onChange = () => {
  59. setIsFullscreen(screenfull.isFullscreen);
  60. };
  61. screenfull.on('change', onChange);
  62. return () => screenfull.off('change', onChange);
  63. }, []);
  64. return {
  65. enter,
  66. exit,
  67. isEnabled: screenfull.isEnabled,
  68. isFullscreen,
  69. ref,
  70. toggle,
  71. };
  72. }