diff --git a/core/src/components/TextArea/Markdown.tsx b/core/src/components/TextArea/Markdown.tsx index 2831322fa..69d938cd0 100644 --- a/core/src/components/TextArea/Markdown.tsx +++ b/core/src/components/TextArea/Markdown.tsx @@ -1,4 +1,4 @@ -import React, { useContext, useEffect } from 'react'; +import React, { useContext, useEffect, useState } from 'react'; import { rehype } from 'rehype'; import rehypePrism from 'rehype-prism-plus'; import { IProps } from '../../Types'; @@ -7,12 +7,6 @@ import { EditorContext } from '../../Context'; function html2Escape(sHtml: string) { return ( sHtml - // .replace(/```(\w+)?([\s\S]*?)(\s.+)?```/g, (str: string) => { - // return str.replace( - // /[<&"]/g, - // (c: string) => (({ '<': '<', '>': '>', '&': '&', '"': '"' } as Record)[c]), - // ); - // }) .replace( /[<&"]/g, (c: string) => (({ '<': '<', '>': '>', '&': '&', '"': '"' }) as Record)[c], @@ -26,30 +20,43 @@ export default function Markdown(props: MarkdownProps) { const { prefixCls } = props; const { markdown = '', highlightEnable, dispatch } = useContext(EditorContext); const preRef = React.createRef(); + const [mdStr, setMdStr] = useState(''); + useEffect(() => { if (preRef.current && dispatch) { dispatch({ textareaPre: preRef.current }); } // eslint-disable-next-line react-hooks/exhaustive-deps }, []); - if (!markdown) { - return
;
-  }
-  let mdStr = `
${html2Escape(
-    String.raw`${markdown}`,
-  )}\n
`; - - if (highlightEnable) { - try { - mdStr = rehype() - .data('settings', { fragment: true }) - // https://github.com/uiwjs/react-md-editor/issues/593 - // @ts-ignore - .use(rehypePrism, { ignoreMissing: true }) - .processSync(mdStr) - .toString(); - } catch (error) {} - } + + useEffect(() => { + async function processMarkdown() { + if (!markdown) { + setMdStr(''); + return; + } + + let mdStr = `
${html2Escape(
+        String.raw`${markdown}`,
+      )}\n
`; + + if (highlightEnable) { + try { + mdStr = await rehype() + .data('settings', { fragment: true }) + // https://github.com/uiwjs/react-md-editor/issues/593 + // @ts-ignore + .use(rehypePrism, { ignoreMissing: true }) + .process(mdStr) + .then((file) => file.toString()); + } catch (error) {} + } + + setMdStr(mdStr); + } + + processMarkdown(); + }, [markdown, highlightEnable, prefixCls]); return React.createElement('div', { className: 'wmde-markdown-color', diff --git a/test/editor.test.tsx b/test/editor.test.tsx index ab04d92c9..7ebf96b4f 100644 --- a/test/editor.test.tsx +++ b/test/editor.test.tsx @@ -90,3 +90,48 @@ it('MDEditor KeyboardEvent onHeightChange', async () => { expect(handleChange).lastReturnedWith(500); expect(handleChange).toHaveLength(3); }); + +it('MDEditor supports asynchronous plugins', async () => { + const MyComponent = () => { + const [value, setValue] = React.useState('**Hello world!!!**'); + return ( + { + return (tree) => { + // Example async plugin that adds a class to the first node + return new Promise((resolve) => { + setTimeout(() => { + if (tree.children && tree.children.length > 0) { + tree.children[0].properties = { + ...tree.children[0].properties, + className: 'async-plugin', + }; + } + resolve(tree); + }, 100); + }); + }; + }, + ], + }} + onChange={(value) => { + setValue(value || ''); + }} + /> + ); + }; + render(); + const inputNode = screen.getByTitle('test'); + inputNode.focus(); + fireEvent.change(inputNode, { target: { value: '# title' } }); + inputNode.blur(); + await new Promise((resolve) => setTimeout(resolve, 200)); // Wait for async plugin to complete + const previewNode = screen.getByText('title'); + expect(previewNode).toHaveClass('async-plugin'); +}); diff --git a/www/src/Example.tsx b/www/src/Example.tsx index 16dc15c1f..b51331dde 100644 --- a/www/src/Example.tsx +++ b/www/src/Example.tsx @@ -1,5 +1,6 @@ import React, { Fragment } from 'react'; import rehypeSanitize, { defaultSchema } from 'rehype-sanitize'; +import rehypePrettyCode from 'rehype-pretty-code'; import MDEditor, { MDEditorProps } from '@uiw/react-md-editor'; import styled from 'styled-components'; @@ -51,6 +52,7 @@ const Example = (props = {} as { mdStr: string }) => { }, }, ], + rehypePrettyCode, ], }} height={400}