Kaynağa Gözat

Merge pull request #10184 from weseek/fix/169030-mermaid-diagrams-are-not-displayed-when-svg-ids-are-duplicated-for-dev7.2.x

fix: Mermaid diagrams are not displayed when svg ids are duplicated (for dev7.2.x)
Yuki Takei 8 ay önce
ebeveyn
işleme
9f47785715

+ 26 - 6
apps/app/src/features/mermaid/components/MermaidViewer.tsx

@@ -1,6 +1,11 @@
 import React, { useRef, useEffect, type JSX } from 'react';
 
 import mermaid from 'mermaid';
+import { v7 as uuidV7 } from 'uuid';
+
+import loggerFactory from '~/utils/logger';
+
+const logger = loggerFactory('growi:features:mermaid:MermaidViewer');
 
 type MermaidViewerProps = {
   value: string
@@ -12,20 +17,35 @@ export const MermaidViewer = React.memo((props: MermaidViewerProps): JSX.Element
   const ref = useRef<HTMLDivElement>(null);
 
   useEffect(() => {
-    if (ref.current != null && value != null) {
-      mermaid.initialize({});
-      mermaid.run({ nodes: [ref.current] });
-    }
+    (async() => {
+      if (ref.current != null && value != null) {
+        mermaid.initialize({});
+        try {
+          // Attempting to render multiple Mermaid diagrams using `mermaid.run` can cause duplicate SVG IDs.
+          // This is because it uses `Date.now()` for ID generation.
+          // ID generation logic: https://github.com/mermaid-js/mermaid/blob/5b241bbb97f81d37df8a84da523dfa53ac13bfd1/packages/mermaid/src/utils.ts#L755-L764
+          // Related issue: https://github.com/mermaid-js/mermaid/issues/4650
+          // Instead of `mermaid.run`, we use `mermaid.render` which allows us to assign a unique ID.
+          const id = `mermaid-${uuidV7()}`;
+          const { svg } = await mermaid.render(id, value, ref.current);
+          ref.current.innerHTML = svg;
+        }
+        catch (err) {
+          logger.error(err);
+        }
+      }
+    })();
   }, [value]);
 
   return (
     value
       ? (
-        <div ref={ref} key={value as string}>
+        <div ref={ref} key={value}>
           {value}
         </div>
       )
-      : <div key={value as string}></div>
+      : <div key={value}></div>
   );
 });
+
 MermaidViewer.displayName = 'MermaidViewer';