|
1 | 1 | import MarkdownPreview from '@uiw/react-markdown-preview';
|
2 |
| -import styles from './index.module.less'; |
3 |
| -import data from "../../../README.md" |
4 |
| -import { useEffect, useRef } from "react" |
| 2 | +import { Root, Element, RootContent } from 'hast'; |
5 | 3 | import CodeLayout from 'react-code-preview-layout';
|
6 | 4 | import { getMetaId, isMeta, getURLParameters } from 'markdown-react-code-preview-loader';
|
7 |
| -import { CodeComponent, ReactMarkdownNames } from 'react-markdown/lib/ast-to-react'; |
| 5 | +import styles from './index.module.less'; |
| 6 | +import data from "../../../README.md" |
8 | 7 | import { getToolbarExtra } from "./Code"
|
9 |
| -const CodePreview: CodeComponent | ReactMarkdownNames = ({ inline, node, ...props }) => { |
10 |
| - const $dom = useRef<HTMLDivElement>(null); |
11 |
| - const { 'data-meta': meta, ...rest } = props as any; |
12 | 8 |
|
13 |
| - useEffect(() => { |
14 |
| - if ($dom.current) { |
15 |
| - const parentElement = $dom.current.parentElement; |
16 |
| - if (parentElement && parentElement.parentElement) { |
17 |
| - parentElement.parentElement.replaceChild($dom.current, parentElement); |
18 |
| - } |
19 |
| - } |
20 |
| - }, [$dom]); |
21 |
| - |
22 |
| - if (inline || !isMeta(meta)) { |
23 |
| - return <code {...props} />; |
24 |
| - } |
25 |
| - |
26 |
| - const line = node.position?.start.line; |
27 |
| - const metaId = getMetaId(meta) || String(line); |
28 |
| - const Child = data.components[`${metaId}`]; |
29 |
| - if (metaId && typeof Child === 'function') { |
30 |
| - const code = data.data[metaId].value || ''; |
31 |
| - const param = getURLParameters(meta); |
32 |
| - return ( |
33 |
| - <CodeLayout |
34 |
| - ref={$dom} |
35 |
| - toolbarExtra={getToolbarExtra(code, param.codePen === "true", param.codeSandbox === "true")} |
36 |
| - toolbar={param.title || 'Example'} background={"transparent"} code={<pre {...rest} />} text={code}> |
37 |
| - <Child /> |
38 |
| - </CodeLayout> |
39 |
| - ); |
40 |
| - } |
41 |
| - return <code {...rest} />; |
42 |
| -}; |
| 9 | +const Preview = CodeLayout.Preview; |
| 10 | +const Code = CodeLayout.Code; |
| 11 | +const Toolbar = CodeLayout.Toolbar; |
43 | 12 |
|
44 | 13 | export default function Markdown() {
|
45 | 14 | return (
|
46 | 15 | <MarkdownPreview
|
47 | 16 | style={{ padding: '20px 26px' }}
|
48 | 17 | source={data.source}
|
49 | 18 | className={styles.markdown}
|
| 19 | + rehypeRewrite={( |
| 20 | + node: Root | RootContent, |
| 21 | + index: number, |
| 22 | + parent: Root | Element, |
| 23 | + ) => { |
| 24 | + if (node.type === 'element' && parent && parent.type === 'root') { |
| 25 | + const menu = parent.children[1] as Element | undefined; |
| 26 | + let childLength = [...parent.children].filter( |
| 27 | + (item) => item.type !== 'raw', |
| 28 | + ).length; |
| 29 | + const lastChild = parent.children[parent.children.length - 1]; |
| 30 | + if (lastChild?.type === 'raw') { |
| 31 | + childLength = parent.children.length - 2; |
| 32 | + } |
| 33 | + if ( |
| 34 | + (index + 1 === childLength || |
| 35 | + index - 1 === childLength || |
| 36 | + index === childLength) && |
| 37 | + menu?.properties?.class !== 'menu-toc' |
| 38 | + ) { |
| 39 | + const child = [...parent.children].map((item) => { |
| 40 | + if (item.type === 'element' && item.tagName === 'pre') { |
| 41 | + const meta = item.children[0]?.data?.meta as string; |
| 42 | + if (isMeta(meta)) { |
| 43 | + item.tagName = 'div'; |
| 44 | + item.properties = { |
| 45 | + ...item.properties, |
| 46 | + 'data-md': meta, |
| 47 | + 'data-meta': 'preview', |
| 48 | + }; |
| 49 | + return { ...item }; |
| 50 | + } |
| 51 | + } |
| 52 | + return item; |
| 53 | + }); |
| 54 | + parent.children = [ |
| 55 | + { |
| 56 | + type: 'element', |
| 57 | + tagName: 'div', |
| 58 | + children: child as Element[], |
| 59 | + }, |
| 60 | + ]; |
| 61 | + } |
| 62 | + } |
| 63 | + |
| 64 | + }} |
50 | 65 | components={{
|
51 |
| - code: CodePreview |
| 66 | + div: ({ node, ...props }) => { |
| 67 | + const { 'data-meta': meta, 'data-md': metaData, ...rest } = props as any; |
| 68 | + const line = node.position?.start.line; |
| 69 | + const metaId = getMetaId(metaData) || String(line); |
| 70 | + const Child = data.components[metaId]; |
| 71 | + if (meta !== 'preview' || !metaId || typeof Child !== 'function') |
| 72 | + return <div {...props} />; |
| 73 | + const code = data.data[metaId].value || ''; |
| 74 | + const param = getURLParameters(meta); |
| 75 | + const extra = getToolbarExtra(code, param.codePen === "true", param.codeSandbox === "true"); |
| 76 | + return ( |
| 77 | + <CodeLayout disableCheckered style={{ marginBottom: 18 }}> |
| 78 | + <Preview> |
| 79 | + <Child /> |
| 80 | + </Preview> |
| 81 | + <Toolbar extra={extra} text={code}>{param.title || 'Example'}</Toolbar> |
| 82 | + <Code style={{ padding: 0 }}> |
| 83 | + <pre {...rest} /> |
| 84 | + </Code> |
| 85 | + </CodeLayout> |
| 86 | + ); |
| 87 | + }, |
52 | 88 | }}
|
53 | 89 | />
|
54 | 90 | );
|
|
0 commit comments