|
|
@ -11,19 +11,21 @@ import mermaid from "mermaid";
|
|
|
|
|
|
|
|
|
|
|
|
import LoadingIcon from "../icons/three-dots.svg";
|
|
|
|
import LoadingIcon from "../icons/three-dots.svg";
|
|
|
|
import React from "react";
|
|
|
|
import React from "react";
|
|
|
|
import { useThrottledCallback } from "use-debounce";
|
|
|
|
import { useDebouncedCallback, useThrottledCallback } from "use-debounce";
|
|
|
|
|
|
|
|
|
|
|
|
export function Mermaid(props: { code: string; onError: () => void }) {
|
|
|
|
export function Mermaid(props: { code: string }) {
|
|
|
|
const ref = useRef<HTMLDivElement>(null);
|
|
|
|
const ref = useRef<HTMLDivElement>(null);
|
|
|
|
|
|
|
|
const [hasError, setHasError] = useState(false);
|
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
useEffect(() => {
|
|
|
|
if (props.code && ref.current) {
|
|
|
|
if (props.code && ref.current) {
|
|
|
|
mermaid
|
|
|
|
mermaid
|
|
|
|
.run({
|
|
|
|
.run({
|
|
|
|
nodes: [ref.current],
|
|
|
|
nodes: [ref.current],
|
|
|
|
|
|
|
|
suppressErrors: true,
|
|
|
|
})
|
|
|
|
})
|
|
|
|
.catch((e) => {
|
|
|
|
.catch((e) => {
|
|
|
|
props.onError();
|
|
|
|
setHasError(true);
|
|
|
|
console.error("[Mermaid] ", e.message);
|
|
|
|
console.error("[Mermaid] ", e.message);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -42,10 +44,17 @@ export function Mermaid(props: { code: string; onError: () => void }) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (hasError) {
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
return (
|
|
|
|
<div
|
|
|
|
<div
|
|
|
|
className="no-dark"
|
|
|
|
className="no-dark mermaid"
|
|
|
|
style={{ cursor: "pointer", overflow: "auto" }}
|
|
|
|
style={{
|
|
|
|
|
|
|
|
cursor: "pointer",
|
|
|
|
|
|
|
|
overflow: "auto",
|
|
|
|
|
|
|
|
}}
|
|
|
|
ref={ref}
|
|
|
|
ref={ref}
|
|
|
|
onClick={() => viewSvgInNewWindow()}
|
|
|
|
onClick={() => viewSvgInNewWindow()}
|
|
|
|
>
|
|
|
|
>
|
|
|
@ -56,21 +65,27 @@ export function Mermaid(props: { code: string; onError: () => void }) {
|
|
|
|
|
|
|
|
|
|
|
|
export function PreCode(props: { children: any }) {
|
|
|
|
export function PreCode(props: { children: any }) {
|
|
|
|
const ref = useRef<HTMLPreElement>(null);
|
|
|
|
const ref = useRef<HTMLPreElement>(null);
|
|
|
|
|
|
|
|
const refText = ref.current?.innerText;
|
|
|
|
const [mermaidCode, setMermaidCode] = useState("");
|
|
|
|
const [mermaidCode, setMermaidCode] = useState("");
|
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
const renderMermaid = useDebouncedCallback(() => {
|
|
|
|
if (!ref.current) return;
|
|
|
|
if (!ref.current) return;
|
|
|
|
const mermaidDom = ref.current.querySelector("code.language-mermaid");
|
|
|
|
const mermaidDom = ref.current.querySelector("code.language-mermaid");
|
|
|
|
if (mermaidDom) {
|
|
|
|
if (mermaidDom) {
|
|
|
|
setMermaidCode((mermaidDom as HTMLElement).innerText);
|
|
|
|
setMermaidCode((mermaidDom as HTMLElement).innerText);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}, [props.children]);
|
|
|
|
}, 600);
|
|
|
|
|
|
|
|
|
|
|
|
if (mermaidCode) {
|
|
|
|
useEffect(() => {
|
|
|
|
return <Mermaid code={mermaidCode} onError={() => setMermaidCode("")} />;
|
|
|
|
setTimeout(renderMermaid, 1);
|
|
|
|
}
|
|
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
|
|
|
|
|
|
}, [refText]);
|
|
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
return (
|
|
|
|
|
|
|
|
<>
|
|
|
|
|
|
|
|
{mermaidCode.length > 0 && (
|
|
|
|
|
|
|
|
<Mermaid code={mermaidCode} key={mermaidCode} />
|
|
|
|
|
|
|
|
)}
|
|
|
|
<pre ref={ref}>
|
|
|
|
<pre ref={ref}>
|
|
|
|
<span
|
|
|
|
<span
|
|
|
|
className="copy-code-button"
|
|
|
|
className="copy-code-button"
|
|
|
@ -83,6 +98,7 @@ export function PreCode(props: { children: any }) {
|
|
|
|
></span>
|
|
|
|
></span>
|
|
|
|
{props.children}
|
|
|
|
{props.children}
|
|
|
|
</pre>
|
|
|
|
</pre>
|
|
|
|
|
|
|
|
</>
|
|
|
|
);
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|