|
1 | 1 | import React from 'react';
|
2 |
| -import MarkdownIt from 'markdown-it'; |
| 2 | +import { unified } from 'unified'; |
| 3 | +import remarkParse from 'remark-parse'; |
| 4 | +import remarkRehype from 'remark-rehype'; |
| 5 | +import rehypeRaw from 'rehype-raw'; |
| 6 | +import rehypeAttr from 'rehype-attr'; |
| 7 | +import rehypeSanitize, { defaultSchema } from 'rehype-sanitize'; |
| 8 | +import rehypeStringify from 'rehype-stringify'; |
| 9 | + |
3 | 10 | import MdEditor from 'react-markdown-editor-lite';
|
4 | 11 | // import 'react-markdown-editor-lite/esm/index.less';
|
5 | 12 |
|
6 | 13 | import * as styles from './index.less';
|
7 | 14 |
|
8 |
| -const mdParser = new MarkdownIt('commonmark', { |
9 |
| - html: false, |
10 |
| -}); |
11 |
| - |
12 |
| -const getAttributes = (content: string = 'image') => { |
13 |
| - const attrs = content.split(' '); |
14 |
| - const alt = attrs.shift(); |
15 |
| - |
16 |
| - const attributes = attrs.reduce((prev: string[], curr) => { |
17 |
| - const [key, value] = curr.split('='); |
18 |
| - |
19 |
| - if (!key) { |
20 |
| - return prev; |
21 |
| - } |
22 |
| - |
23 |
| - if (!value) { |
24 |
| - return prev.concat(`${key}`); |
25 |
| - } |
26 |
| - |
27 |
| - return prev.concat(`${key}="${value}"`); |
28 |
| - }, []); |
29 |
| - |
30 |
| - return { |
31 |
| - alt, |
32 |
| - attributes, |
33 |
| - }; |
34 |
| -}; |
35 |
| - |
36 |
| -mdParser.renderer.rules.image = function (tokens, index) { |
37 |
| - const token = tokens[index]; |
38 |
| - const srcIndex = token.attrIndex('src'); |
39 |
| - |
40 |
| - if (!token.attrs) { |
41 |
| - return ''; |
42 |
| - } |
43 |
| - |
44 |
| - const src = token.attrs[srcIndex][1]; |
45 |
| - const content = mdParser.utils.escapeHtml(token.content); |
46 |
| - const { alt, attributes } = getAttributes(content); |
47 |
| - |
48 |
| - return `<img src="${src}" alt="${alt}" ${attributes.join(' ')}/>`; |
49 |
| -}; |
| 15 | +const processor = unified() |
| 16 | + .use(remarkParse) |
| 17 | + .use(remarkRehype, { allowDangerousHtml: true }) |
| 18 | + .use(rehypeRaw) |
| 19 | + .use(rehypeAttr, { properties: 'attr' }) |
| 20 | + .use(rehypeSanitize, { |
| 21 | + ...defaultSchema, |
| 22 | + attributes: { |
| 23 | + ...defaultSchema.attributes, |
| 24 | + img: [...(defaultSchema?.attributes?.img || []), ['style']], |
| 25 | + }, |
| 26 | + }) |
| 27 | + .use(rehypeStringify); |
50 | 28 |
|
51 | 29 | const Markdown: React.FC<Props> = (props) => {
|
52 | 30 | const { value = '', type, onChange, customClassName = '' } = props;
|
@@ -84,7 +62,10 @@ const Markdown: React.FC<Props> = (props) => {
|
84 | 62 | readOnly={type === 'render'}
|
85 | 63 | view={view}
|
86 | 64 | value={value}
|
87 |
| - renderHTML={(text) => mdParser.render(text)} |
| 65 | + renderHTML={async (text) => { |
| 66 | + const content: any = await processor.process(text); |
| 67 | + return content.value; |
| 68 | + }} |
88 | 69 | onChange={(data) => {
|
89 | 70 | onChange && onChange(data.text);
|
90 | 71 | }}
|
|
0 commit comments