forked from facebook/docusaurus
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add mermaid diagram support ootb facebook#1258
- Loading branch information
Showing
18 changed files
with
1,246 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
62 changes: 62 additions & 0 deletions
62
packages/docusaurus-mdx-loader/src/remark/mermaid/__tests__/index.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
/** | ||
* Copyright (c) Facebook, Inc. and its affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
|
||
import {createCompiler} from '@mdx-js/mdx'; | ||
import mermaid from '..'; | ||
|
||
describe('mermaid remark plugin', () => { | ||
function createTestCompiler() { | ||
return createCompiler({ | ||
remarkPlugins: [mermaid], | ||
}); | ||
} | ||
|
||
it('no mermaid', async () => { | ||
const mdxCompiler = createTestCompiler(); | ||
const result = await mdxCompiler.process( | ||
'# Heading 1\n\nNo Mermaid diagram :(', | ||
); | ||
expect(result.contents).toBe( | ||
'\n\n\nconst layoutProps = {\n \n};\nconst MDXLayout = "wrapper"\nexport default function MDXContent({\n components,\n ...props\n}) {\n return <MDXLayout {...layoutProps} {...props} components={components} mdxType="MDXLayout">\n <h1>{`Heading 1`}</h1>\n <p>{`No Mermaid diagram :(`}</p>\n </MDXLayout>;\n}\n\n;\nMDXContent.isMDXComponent = true;', | ||
); | ||
}); | ||
|
||
it('basic', async () => { | ||
const mdxCompiler = createTestCompiler(); | ||
const result = await mdxCompiler.process(`# Heading 1\n | ||
\`\`\`mermaid | ||
graph TD; | ||
A-->B; | ||
A-->C; | ||
B-->D; | ||
C-->D; | ||
\`\`\``); | ||
expect(result.contents).toBe(` | ||
const layoutProps = { | ||
${' '} | ||
}; | ||
const MDXLayout = "wrapper" | ||
export default function MDXContent({ | ||
components, | ||
...props | ||
}) { | ||
return <MDXLayout {...layoutProps} {...props} components={components} mdxType="MDXLayout"> | ||
<h1>{\`Heading 1\`}</h1> | ||
<mermaid value={\`graph TD; | ||
A-->B; | ||
A-->C; | ||
B-->D; | ||
C-->D;\`} /> | ||
</MDXLayout>; | ||
} | ||
; | ||
MDXContent.isMDXComponent = true;`); | ||
}); | ||
}); |
48 changes: 48 additions & 0 deletions
48
packages/docusaurus-mdx-loader/src/remark/mermaid/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
/** | ||
* Copyright (c) Facebook, Inc. and its affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
|
||
import visit from 'unist-util-visit'; | ||
import type {Transformer} from 'unified'; | ||
import type {Data, Literal, Node, Parent} from 'unist'; | ||
|
||
type CodeMermaid = Literal<string> & { | ||
type: 'code'; | ||
lang: 'mermaid'; | ||
}; | ||
|
||
function processMermaidNode( | ||
node: CodeMermaid, | ||
index: number, | ||
parent: Parent<Node<Data> | Literal, Data>, | ||
) { | ||
parent.children.splice(index, 1, { | ||
type: 'jsx', | ||
value: `<mermaid value={\`${node.value}\`}/>`, | ||
position: node.position, | ||
}); | ||
} | ||
|
||
export default function plugin(): Transformer { | ||
return async (root) => { | ||
// Find all the mermaid diagram code blocks. i.e. ```mermaid | ||
const instances: [CodeMermaid, number, Parent<Node<Data>, Data>][] = []; | ||
visit( | ||
root, | ||
{type: 'code', lang: 'mermaid'}, | ||
(node: CodeMermaid, index, parent) => { | ||
if (parent) { | ||
instances.push([node, index, parent]); | ||
} | ||
}, | ||
); | ||
|
||
// Replace each Mermaid code block with the Mermaid component | ||
instances.forEach(([node, index, parent]) => { | ||
processMermaidNode(node, index, parent); | ||
}); | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
14 changes: 14 additions & 0 deletions
14
packages/docusaurus-theme-classic/src/theme/MDXComponents/Mermaid.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
/** | ||
* Copyright (c) Facebook, Inc. and its affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
|
||
import React from 'react'; | ||
import Mermaid from '@theme/Mermaid'; | ||
import type {Props} from '@theme/MDXComponents/Mermaid'; | ||
|
||
export default function MDXMermaid(props: Props): JSX.Element { | ||
return <Mermaid {...props} />; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
64 changes: 64 additions & 0 deletions
64
packages/docusaurus-theme-classic/src/theme/Mermaid/index.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
/** | ||
* Copyright (c) Facebook, Inc. and its affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
|
||
import React, {useEffect, useState} from 'react'; | ||
import useIsBrowser from '@docusaurus/useIsBrowser'; | ||
import mermaid from 'mermaid'; | ||
import type {Props} from '@theme/Mermaid'; | ||
|
||
/** | ||
* Assign a unique ID to each mermaid svg as per requirements | ||
* of `mermaid.render`. | ||
*/ | ||
let id = 0; | ||
|
||
export default function Mermaid({value}: Props): JSX.Element { | ||
// When theme updates, rerender the SVG. | ||
const [svg, setSvg] = useState<string>(''); | ||
const isBrowser = useIsBrowser(); | ||
|
||
useEffect(() => { | ||
const render = () => { | ||
mermaid.render(`mermaid-svg-${id.toString()}`, value, (renderedSvg) => | ||
setSvg(renderedSvg), | ||
); | ||
id += 1; | ||
}; | ||
|
||
render(); | ||
|
||
if (isBrowser) { | ||
const html: HTMLHtmlElement = document.querySelector('html')!; | ||
|
||
const observer = new MutationObserver((mutations) => { | ||
for (const mutation of mutations) { | ||
if ( | ||
mutation.type !== 'attributes' || | ||
mutation.attributeName !== 'data-mermaid' | ||
) { | ||
continue; | ||
} | ||
render(); | ||
break; | ||
} | ||
}); | ||
|
||
observer.observe(html, {attributes: true}); | ||
return () => { | ||
try { | ||
observer.disconnect(); | ||
} catch { | ||
// Do nothing | ||
} | ||
}; | ||
} | ||
return undefined; | ||
}, [isBrowser, value]); | ||
|
||
// eslint-disable-next-line react/no-danger | ||
return <div dangerouslySetInnerHTML={{__html: svg}} />; | ||
} |
Oops, something went wrong.