uiwjs / react-md-editor

A simple markdown editor with preview, implemented with React.js and TypeScript.
https://uiwjs.github.io/react-md-editor
MIT License
2.04k stars 149 forks source link

Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node. #562

Closed Nquq closed 11 months ago

Nquq commented 11 months ago

Hello!

I have a problem with the mermaid plugin. When I start erasing the word 'mermaid' in the editor, I get an error like in the screenshot.

image

here is my code component

export const Code = ({ inline, children = [], className, ...props }: any) => {
    const mermaidGraphId = useRef(`mermaidGraph${randomId()}`);
    const code = getCode(children);
    const mermaidGraph = useRef(null);

    const handle = useCallback(async () => {
        if (mermaidGraph.current) {
            try {
                const { svg } = await mermaid.render(
                    mermaidGraphId.current,
                    code
                );
                mermaidGraph.current.innerHTML = svg;
            } catch (error) {
                mermaidGraph.current.innerHTML = error;
            }
        }
    }, [mermaidGraph, code]);

    useEffect(() => {
        handle();
    }, [handle]);

    if (
        typeof code === 'string' &&
        typeof className === 'string' &&
        /^language-mermaid/.test(className.toLocaleLowerCase())
    ) {
        return (
            <code ref={mermaidGraph}>
                <code id={mermaidGraphId.current} style={{ display: 'none' }} />
            </code>
        );
    }

    return <code className={String(className)}>{children}</code>;
};

and MDEditor component

<MDEditor
     height={400}
     value={text}
     onChange={text => {
         setText(text);
         setFieldValue('text', text);
      }}
      previewOptions={{
          components: {
              code: Code,
              img: Image
           }
      }}
/>
jaywcjlove commented 11 months ago

@Nquq Did not reproduce your error.

https://github.com/uiwjs/react-md-editor/blob/e660e5605455241e72eb411eaab71d4acd93474b/core/README.md?plain=1#L614-L701

Nquq commented 11 months ago

@jaywcjlove https://codesandbox.io/s/markdown-editor-mermaid-for-react-forked-kdwczt

jaywcjlove commented 11 months ago

@Nquq https://codesandbox.io/embed/markdown-editor-mermaid-for-react-forked-hxqn4r?fontsize=14&hidenavigation=1&theme=dark

Use mermaid@v9

import React, {
  useState,
  useRef,
  Fragment,
  useEffect,
  useCallback
} from "react";
import MDEditor from "@uiw/react-md-editor";
import mermaid from "mermaid";
import { createRoot } from "react-dom/client";
import { getCodeString } from "rehype-rewrite";

const mdMermaid = `The following are some examples of the diagrams, charts and graphs that can be made using Mermaid and the Markdown-inspired text specific to it. 

\`\`\`mermaid
graph TD
A[Hard] -->|Text| B(Round)
B --> C{Decision}
C -->|One| D[Result 1]
C -->|Two| E[Result 2]
\`\`\`

\`\`\`mermaid
sequenceDiagram
Alice->>John: Hello John, how are you?
loop Healthcheck
    John->>John: Fight against hypochondria
end
Note right of John: Rational thoughts!
John-->>Alice: Great!
John->>Bob: How about you?
Bob-->>John: Jolly good!
\`\`\`
`;

const randomid = () => parseInt(String(Math.random() * 1e15), 10).toString(36);
const Code = ({ inline, children = [], className, ...props }) => {
  const demoid = useRef(`dome${randomid()}`);
  const [container, setContainer] = useState(null);
  const isMermaid =
    className && /^language-mermaid/.test(className.toLocaleLowerCase());
  const txt = children[0] || "";
  const code =
    props.node && props.node.children
      ? getCodeString(props.node.children)
      : txt;
  useEffect(() => {
    if (container && isMermaid) {
      try {
        const str = mermaid.render(demoid.current, code);
        container.innerHTML = str;
      } catch (error) {
        container.innerHTML = error;
      }
    }
  }, [container, isMermaid, code, demoid]);

  const refElement = useCallback((node) => {
    if (node !== null) {
      setContainer(node);
    }
  }, []);

  if (isMermaid) {
    return (
      <Fragment>
        <code id={demoid.current} style={{ display: "none" }} />
        <code ref={refElement} data-name="mermaid" />
      </Fragment>
    );
  }
  return <code>{children}</code>;
};

export default function App() {
  const [value, setValue] = useState(mdMermaid);
  return (
    <div data-color-mode="light">
      <MDEditor
        onChange={(newValue = "") => setValue(newValue)}
        textareaProps={{
          placeholder: "Please enter Markdown text"
        }}
        height={500}
        value={value}
        previewOptions={{
          components: {
            code: Code
          }
        }}
      />
    </div>
  );
}

const container = document.getElementById("container");
const root = createRoot(container);
root.render(<App />);
Nquq commented 11 months ago

@jaywcjlove thank a lot!