Yuki Takei 3 лет назад
Родитель
Сommit
10ffd8c346

+ 21 - 8
packages/app/src/components/PagePresentationModal.tsx

@@ -1,13 +1,13 @@
 import React, { useCallback } from 'react';
 
 import type { PresentationProps } from '@growi/presentation';
+import { useFullScreen } from '@growi/ui';
 import dynamic from 'next/dynamic';
 import type { ReactMarkdownOptions } from 'react-markdown/lib/react-markdown';
 import {
   Modal, ModalBody,
 } from 'reactstrap';
 
-
 import { usePagePresentationModal } from '~/stores/modal';
 import { useSWRxCurrentPage } from '~/stores/page';
 import { usePresentationViewOptions } from '~/stores/renderer';
@@ -30,13 +30,26 @@ const PagePresentationModal = (): JSX.Element => {
   const { data: presentationModalData, close: closePresentationModal } = usePagePresentationModal();
 
   const { isDarkMode } = useNextThemes();
+  const fullscreen = useFullScreen();
 
   const { data: currentPage } = useSWRxCurrentPage();
   const { data: rendererOptions } = usePresentationViewOptions();
 
-  const requestFullscreen = useCallback(() => {
-    document.documentElement.requestFullscreen();
-  }, []);
+  const toggleFullscreenHandler = useCallback(() => {
+    if (fullscreen.active) {
+      fullscreen.exit();
+    }
+    else {
+      fullscreen.enter();
+    }
+  }, [fullscreen]);
+
+  const closeHandler = useCallback(() => {
+    if (fullscreen.active) {
+      fullscreen.exit();
+    }
+    closePresentationModal();
+  }, [fullscreen, closePresentationModal]);
 
   const isOpen = presentationModalData?.isOpened ?? false;
 
@@ -49,15 +62,15 @@ const PagePresentationModal = (): JSX.Element => {
   return (
     <Modal
       isOpen={isOpen}
-      toggle={closePresentationModal}
+      toggle={closeHandler}
       data-testid="page-presentation-modal"
       className={`grw-presentation-modal ${styles['grw-presentation-modal']}`}
     >
       <div className="grw-presentation-controls d-flex">
-        <button className="close btn-fullscreen" type="button" aria-label="fullscreen" onClick={requestFullscreen}>
-          <i className="ti ti-fullscreen" aria-hidden></i>
+        <button className="close btn-fullscreen" type="button" aria-label="fullscreen" onClick={toggleFullscreenHandler}>
+          <i className={`${fullscreen.active ? 'icon-size-actual' : 'icon-size-fullscreen'}`} aria-hidden></i>
         </button>
-        <button className="close btn-close" type="button" aria-label="close" onClick={closePresentationModal}>
+        <button className="close btn-close" type="button" aria-label="close" onClick={closeHandler}>
           <i className="ti ti-close" aria-hidden></i>
         </button>
       </div>

+ 2 - 1
packages/ui/src/index.ts

@@ -3,7 +3,8 @@ export * from './interfaces/breakpoints';
 export * from './components/Attachment/Attachment';
 export * from './components/PagePath/PageListMeta';
 export * from './components/PagePath/PagePathLabel';
+export * from './components/SearchPage/FootstampIcon';
 export * from './components/User/UserPicture';
 
 export * from './utils/browser-utils';
-export * from './components/SearchPage/FootstampIcon';
+export * from './utils/use-fullscreen';

+ 50 - 0
packages/ui/src/utils/use-fullscreen.ts

@@ -0,0 +1,50 @@
+import {
+  useCallback, useEffect, useMemo, useState,
+} from 'react';
+
+export interface FullScreenHandle {
+  active: boolean;
+  enter: () => Promise<void>;
+  exit: () => Promise<void>;
+}
+
+export const useFullScreen = (): FullScreenHandle => {
+  const [active, setActive] = useState(false);
+
+  useEffect(() => {
+    const handleChange = () => {
+      setActive(document.fullscreenElement != null);
+    };
+
+    document.addEventListener('fullscreenchange', handleChange);
+    return function cleanup() {
+      document.removeEventListener('fullscreenchange', handleChange);
+    };
+  }, []);
+
+  const enter = useCallback((elem?: HTMLElement) => {
+    if (document.fullscreenElement != null) {
+      return Promise.resolve();
+    }
+
+    const targetElem = elem ?? document.documentElement;
+    return targetElem.requestFullscreen();
+  }, []);
+
+  const exit = useCallback(() => {
+    if (document.fullscreenElement == null) {
+      return Promise.resolve();
+    }
+
+    return document.exitFullscreen();
+  }, []);
+
+  return useMemo(
+    () => ({
+      active,
+      enter,
+      exit,
+    }),
+    [active, enter, exit],
+  );
+};