Просмотр исходного кода

Merge pull request #8535 from weseek/imprv/past-end-for-preview

imprv: pastEnd for Preview
Yuki Takei 2 лет назад
Родитель
Сommit
4aa186b80d

+ 20 - 6
apps/app/src/components/PageEditor/PageEditor.tsx

@@ -1,3 +1,4 @@
+import type { CSSProperties } from 'react';
 import React, {
 import React, {
   useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState,
   useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState,
 } from 'react';
 } from 'react';
@@ -12,9 +13,9 @@ import {
   CodeMirrorEditorMain, GlobalCodeMirrorEditorKey,
   CodeMirrorEditorMain, GlobalCodeMirrorEditorKey,
   useCodeMirrorEditorIsolated, useResolvedThemeForEditor,
   useCodeMirrorEditorIsolated, useResolvedThemeForEditor,
 } from '@growi/editor';
 } from '@growi/editor';
+import { useRect } from '@growi/ui/dist/utils';
 import detectIndent from 'detect-indent';
 import detectIndent from 'detect-indent';
 import { useTranslation } from 'next-i18next';
 import { useTranslation } from 'next-i18next';
-import { useRouter } from 'next/router';
 import { throttle, debounce } from 'throttle-debounce';
 import { throttle, debounce } from 'throttle-debounce';
 
 
 
 
@@ -85,9 +86,8 @@ type Props = {
 export const PageEditor = React.memo((props: Props): JSX.Element => {
 export const PageEditor = React.memo((props: Props): JSX.Element => {
 
 
   const { t } = useTranslation();
   const { t } = useTranslation();
-  const router = useRouter();
 
 
-  const previewRef = useRef<HTMLDivElement>(null);
+  const [previewRect, previewRef] = useRect();
 
 
   const { data: isNotFound } = useIsNotFound();
   const { data: isNotFound } = useIsNotFound();
   const { data: pageId } = useCurrentPageId();
   const { data: pageId } = useCurrentPageId();
@@ -411,6 +411,17 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
   //   };
   //   };
   // }, [onRouterChangeComplete, router.events]);
   // }, [onRouterChangeComplete, router.events]);
 
 
+  const pastEndStyle: CSSProperties | undefined = useMemo(() => {
+    if (previewRect == null) {
+      return undefined;
+    }
+
+    const previewRectHeight = previewRect.height;
+
+    // containerHeight - 1.5 line height
+    return { paddingBottom: `calc(${previewRectHeight}px - 2em)` };
+  }, [previewRect]);
+
   if (!isEditable) {
   if (!isEditable) {
     return <></>;
     return <></>;
   }
   }
@@ -441,14 +452,17 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
             editorKeymap={editorSettings?.keymapMode}
             editorKeymap={editorSettings?.keymapMode}
           />
           />
         </div>
         </div>
-        <div ref={previewRef} onScroll={scrollPreviewHandlerThrottle} className="page-editor-preview-container flex-expand-vert d-none d-lg-flex">
+        <div
+          ref={previewRef}
+          onScroll={scrollPreviewHandlerThrottle}
+          className="page-editor-preview-container flex-expand-vert d-none d-lg-flex"
+        >
           <Preview
           <Preview
             rendererOptions={rendererOptions}
             rendererOptions={rendererOptions}
             markdown={markdownToPreview}
             markdown={markdownToPreview}
             pagePath={currentPagePath}
             pagePath={currentPagePath}
             expandContentWidth={shouldExpandContent}
             expandContentWidth={shouldExpandContent}
-            // TODO: Dynamic changes by height or resizing the last element
-            pastEnd={500}
+            style={pastEndStyle}
           />
           />
         </div>
         </div>
         {/*
         {/*

+ 5 - 6
apps/app/src/components/PageEditor/Preview.tsx

@@ -1,6 +1,5 @@
-import React, {
-  SyntheticEvent, RefObject,
-} from 'react';
+import type { CSSProperties } from 'react';
+import React from 'react';
 
 
 import type { RendererOptions } from '~/interfaces/renderer-options';
 import type { RendererOptions } from '~/interfaces/renderer-options';
 
 
@@ -17,7 +16,7 @@ type Props = {
   markdown?: string,
   markdown?: string,
   pagePath?: string | null,
   pagePath?: string | null,
   expandContentWidth?: boolean,
   expandContentWidth?: boolean,
-  pastEnd?: number,
+  style?: CSSProperties,
   onScroll?: (scrollTop: number) => void,
   onScroll?: (scrollTop: number) => void,
 }
 }
 
 
@@ -25,7 +24,7 @@ const Preview = React.forwardRef((props: Props): JSX.Element => {
 
 
   const {
   const {
     rendererOptions,
     rendererOptions,
-    markdown, pagePath, pastEnd,
+    markdown, pagePath, style,
     expandContentWidth,
     expandContentWidth,
   } = props;
   } = props;
 
 
@@ -34,7 +33,7 @@ const Preview = React.forwardRef((props: Props): JSX.Element => {
   return (
   return (
     <div
     <div
       className={`${moduleClass} ${fluidLayoutClass} ${pagePath === '/Sidebar' ? 'preview-sidebar' : ''}`}
       className={`${moduleClass} ${fluidLayoutClass} ${pagePath === '/Sidebar' ? 'preview-sidebar' : ''}`}
-      style={{ paddingBottom: pastEnd }}
+      style={style}
     >
     >
       { markdown != null && (
       { markdown != null && (
         <RevisionRenderer rendererOptions={rendererOptions} markdown={markdown}></RevisionRenderer>
         <RevisionRenderer rendererOptions={rendererOptions} markdown={markdown}></RevisionRenderer>

+ 1 - 0
packages/ui/src/utils/index.ts

@@ -1,2 +1,3 @@
 export * from './browser-utils';
 export * from './browser-utils';
 export * from './use-fullscreen';
 export * from './use-fullscreen';
+export * from './use-rect';

+ 52 - 0
packages/ui/src/utils/use-rect.ts

@@ -0,0 +1,52 @@
+// ref: https://gist.github.com/morajabi/523d7a642d8c0a2f71fcfa0d8b3d2846?permalink_comment_id=4688158#gistcomment-4688158
+
+import { useState, useRef, useEffect } from 'react';
+
+type MutableRefObject<T> = {
+  current: T
+}
+
+type EventType = 'resize' | 'scroll'
+
+const useEffectInEvent = (
+    event: EventType,
+    useCapture?: boolean,
+    set?: () => void,
+) => {
+  useEffect(() => {
+    if (set) {
+      set();
+      window.addEventListener(event, set, useCapture);
+
+      return () => window.removeEventListener(event, set, useCapture);
+    }
+  }, [event, set, useCapture]);
+};
+
+export const useRect = <T extends HTMLDivElement | null>(
+  event: EventType = 'resize',
+): [DOMRect | undefined, MutableRefObject<T | null>, number] => {
+  const [rect, setRect] = useState<DOMRect>();
+
+  const reference = useRef<T>(null);
+
+  const [screenHeight, setScreenHeight] = useState(window.innerHeight);
+
+  const set = (): void => {
+    setRect(reference.current?.getBoundingClientRect());
+  };
+
+  useEffectInEvent(event, true, set);
+  const handleResize = () => {
+    setScreenHeight(window.innerHeight);
+  };
+
+  useEffect(() => {
+    window.addEventListener(event, handleResize);
+    return () => {
+      window.removeEventListener(event, handleResize);
+    };
+  }, [event]);
+
+  return [rect, reference, screenHeight];
+};