Преглед изворни кода

fix: enhance auto-scroll functionality with resize observer and rendering completion handling

Shun Miyazawa пре 1 месец
родитељ
комит
c52f8906d4

+ 59 - 14
apps/app/src/components/PageView/PageView.tsx

@@ -143,23 +143,68 @@ const PageViewComponent = (props: Props): JSX.Element => {
     if (contentContainer == null) return;
 
     const targetId = decodeURIComponent(hash.slice(1));
-    const target = document.getElementById(targetId);
-    if (target != null) {
-      target.scrollIntoView();
-      return;
-    }
 
-    const observer = new MutationObserver(() => {
+    const scrollToTarget = (): boolean => {
       const target = document.getElementById(targetId);
-      if (target != null) {
-        target.scrollIntoView();
-        observer.disconnect();
-      }
-    });
-
-    observer.observe(contentContainer, { childList: true, subtree: true });
+      if (target == null) return false;
+      target.scrollIntoView();
+      return true;
+    };
+
+    // After the initial scroll, watch for data-growi-rendering elements to
+    // appear and then fully disappear. Components such as DrawioViewer may be
+    // mounted AFTER this effect runs (lazy / remark-plugin rendering), so we
+    // cannot just check synchronously — we must observe the full lifecycle.
+    const watchRenderingCompletion = () => {
+      let everSawRendering = false;
+
+      const renderingObserver = new MutationObserver(() => {
+        const hasRendering =
+          contentContainer.querySelector('[data-growi-rendering]') != null;
+
+        if (hasRendering) {
+          // At least one component is still rendering
+          everSawRendering = true;
+          return;
+        }
+
+        if (everSawRendering) {
+          // All rendering-in-progress elements have finished — scroll to the
+          // correct (post-render) position and stop observing
+          scrollToTarget();
+          renderingObserver.disconnect();
+        }
+      });
+
+      renderingObserver.observe(contentContainer, {
+        childList: true,
+        subtree: true,
+        attributes: true,
+        attributeFilter: ['data-growi-rendering'],
+      });
+
+      return renderingObserver;
+    };
+
+    // Wait for the target heading element to appear in DOM first
+    if (!scrollToTarget()) {
+      const targetObserver = new MutationObserver(() => {
+        if (scrollToTarget()) {
+          targetObserver.disconnect();
+          watchRenderingCompletion();
+        }
+      });
+
+      targetObserver.observe(contentContainer, {
+        childList: true,
+        subtree: true,
+      });
+
+      return () => targetObserver.disconnect();
+    }
 
-    return () => observer.disconnect();
+    const renderingObserver = watchRenderingCompletion();
+    return () => renderingObserver.disconnect();
   }, [currentPageId, contentContainerId]);
 
   // *******************************  end  *******************************

+ 3 - 0
packages/remark-drawio/src/components/DrawioViewer.tsx

@@ -127,6 +127,7 @@ export const DrawioViewer = memo((props: DrawioViewerProps): JSX.Element => {
   useEffect(() => {
     if (error != null) {
       onRenderingUpdated?.(null);
+      drawioContainerRef.current?.removeAttribute('data-growi-rendering');
     }
   }, [error, onRenderingUpdated]);
 
@@ -143,6 +144,7 @@ export const DrawioViewer = memo((props: DrawioViewerProps): JSX.Element => {
         if (mxgraphData != null) {
           const mxgraph = JSON.parse(mxgraphData);
           onRenderingUpdated?.(mxgraph.xml);
+          drawioContainerRef.current?.removeAttribute('data-growi-rendering');
         }
       }
     };
@@ -182,6 +184,7 @@ export const DrawioViewer = memo((props: DrawioViewerProps): JSX.Element => {
       className={`drawio-viewer ${styles['drawio-viewer']} p-2`}
       data-begin-line-number-of-markdown={bol}
       data-end-line-number-of-markdown={eol}
+      data-growi-rendering="true"
     >
       {/* show error */}
       {error != null && (

+ 8 - 1
packages/remark-drawio/src/services/renderer/remark-drawio.ts

@@ -4,7 +4,13 @@ import type { Code, Node, Paragraph } from 'mdast';
 import type { Plugin } from 'unified';
 import { visit } from 'unist-util-visit';
 
-const SUPPORTED_ATTRIBUTES = ['diagramIndex', 'bol', 'eol', 'isDarkMode'];
+const SUPPORTED_ATTRIBUTES = [
+  'diagramIndex',
+  'bol',
+  'eol',
+  'isDarkMode',
+  'data-growi-rendering',
+];
 
 interface Data {
   hName?: string;
@@ -34,6 +40,7 @@ function rewriteNode(node: Node, index: number, isDarkMode?: boolean) {
     eol: node.position?.end.line,
     isDarkMode: isDarkMode ? 'true' : 'false',
     key: `drawio-${index}`,
+    'data-growi-rendering': 'true',
   };
 }