|
@@ -1,6 +1,11 @@
|
|
|
import React, { useRef, useEffect, type JSX } from 'react';
|
|
import React, { useRef, useEffect, type JSX } from 'react';
|
|
|
|
|
|
|
|
import mermaid from 'mermaid';
|
|
import mermaid from 'mermaid';
|
|
|
|
|
+import { v7 as uuidV7 } from 'uuid';
|
|
|
|
|
+
|
|
|
|
|
+import loggerFactory from '~/utils/logger';
|
|
|
|
|
+
|
|
|
|
|
+const logger = loggerFactory('growi:features:mermaid:MermaidViewer');
|
|
|
|
|
|
|
|
type MermaidViewerProps = {
|
|
type MermaidViewerProps = {
|
|
|
value: string
|
|
value: string
|
|
@@ -12,20 +17,35 @@ export const MermaidViewer = React.memo((props: MermaidViewerProps): JSX.Element
|
|
|
const ref = useRef<HTMLDivElement>(null);
|
|
const ref = useRef<HTMLDivElement>(null);
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
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]);
|
|
}, [value]);
|
|
|
|
|
|
|
|
return (
|
|
return (
|
|
|
value
|
|
value
|
|
|
? (
|
|
? (
|
|
|
- <div ref={ref} key={value as string}>
|
|
|
|
|
|
|
+ <div ref={ref} key={value}>
|
|
|
{value}
|
|
{value}
|
|
|
</div>
|
|
</div>
|
|
|
)
|
|
)
|
|
|
- : <div key={value as string}></div>
|
|
|
|
|
|
|
+ : <div key={value}></div>
|
|
|
);
|
|
);
|
|
|
});
|
|
});
|
|
|
|
|
+
|
|
|
MermaidViewer.displayName = 'MermaidViewer';
|
|
MermaidViewer.displayName = 'MermaidViewer';
|