diff --git a/docs/_asset/index.css b/docs/_asset/index.css index 9e5f6a527..076928355 100644 --- a/docs/_asset/index.css +++ b/docs/_asset/index.css @@ -748,6 +748,17 @@ button.success { margin-block: calc(1 / 1.2 * (1em + 1ex)); } +.playground-editor fieldset { + border: 0; + padding: 0; + margin: 0; + min-width: 0; +} + +.playground-editor fieldset label { + display: inline; +} + .frame { /* gray-1 is used for unselected tabs, but gray-2 is really too much * This is a perfect mix between the two: */ diff --git a/docs/_component/editor.client.js b/docs/_component/editor.client.js index c51709646..e5832b534 100644 --- a/docs/_component/editor.client.js +++ b/docs/_component/editor.client.js @@ -5,10 +5,14 @@ import {VFile} from 'vfile' import {VFileMessage} from 'vfile-message' import {statistics} from 'vfile-statistics' import {reporter} from 'vfile-reporter' -import {evaluate} from '@mdx-js/mdx' +import {evaluate, nodeTypes} from '@mdx-js/mdx' import remarkGfm from 'remark-gfm' +import rehypeRaw from 'rehype-raw' import remarkFrontmatter from 'remark-frontmatter' +import remarkDirective from 'remark-directive' import remarkMath from 'remark-math' +import {visit as visitEstree} from 'estree-util-visit' +import {removePosition} from 'unist-util-remove-position' import CodeMirror from 'rodemirror' import {basicSetup} from 'codemirror' import {markdown as langMarkdown} from '@codemirror/lang-markdown' @@ -29,30 +33,41 @@ function useMdx(defaults) { const [state, setState] = useState({...defaults, file: null}) const {run: setConfig} = useDebounceFn( async (config) => { - const file = new VFile({basename: 'example.mdx', value: config.value}) + const basename = config.formatMd ? 'example.md' : 'example.mdx' + const file = new VFile({basename, value: config.value}) const capture = (name) => () => (tree) => { file.data[name] = tree } const remarkPlugins = [] - if (config.gfm) remarkPlugins.push(remarkGfm) if (config.frontmatter) remarkPlugins.push(remarkFrontmatter) if (config.math) remarkPlugins.push(remarkMath) - + if (config.directive) remarkPlugins.push(remarkDirective) remarkPlugins.push(capture('mdast')) + const rehypePlugins = [] + if (config.rehypeRaw) + rehypePlugins.push([rehypeRaw, {passThrough: nodeTypes}]) + rehypePlugins.push(capture('hast')) + try { file.result = ( await evaluate(file, { ...runtime, useDynamicImport: true, remarkPlugins, - rehypePlugins: [capture('hast')], + rehypePlugins, recmaPlugins: [capture('esast')] }) ).default + + if (!config.position) { + removePosition(file.data.mdast, {force: true}) + removePosition(file.data.hast, {force: true}) + removePositionEsast(file.data.esast) + } } catch (error) { const message = error instanceof VFileMessage ? error : new VFileMessage(error) @@ -107,9 +122,13 @@ export function Editor({children}) { const defaultValue = children const extensions = useMemo(() => [basicSetup, oneDark, langMarkdown()], []) const [state, setConfig] = useMdx({ + formatMd: false, + position: false, gfm: false, frontmatter: false, + directive: false, math: false, + rehypeRaw: false, value: defaultValue }) const onUpdate = useCallback( @@ -132,7 +151,7 @@ export function Editor({children}) { }, [state]) return ( -
+
+
+ + + +
+ + +
@@ -324,3 +404,15 @@ export function Editor({children}) {
) } + +function removePositionEsast(tree) { + visitEstree(tree, remove) + return tree + + function remove(node) { + delete node.loc + delete node.start + delete node.end + delete node.range + } +} diff --git a/package-lock.json b/package-lock.json index 1e417f2e1..355c95969 100644 --- a/package-lock.json +++ b/package-lock.json @@ -46,6 +46,7 @@ "eslint-plugin-react-hooks": "^4.0.0", "eslint-plugin-security": "^1.0.0", "estree-util-value-to-estree": "^2.0.0", + "estree-util-visit": "^1.2.1", "globby": "^13.0.0", "hast-to-hyperscript": "^10.0.0", "hast-util-select": "^5.0.0", @@ -86,6 +87,7 @@ "rehype-slug": "^5.0.0", "rehype-stringify": "^9.0.0", "remark-cli": "^11.0.0", + "remark-directive": "^2.0.0", "remark-frontmatter": "^4.0.0", "remark-gemoji": "^7.0.0", "remark-gfm": "^3.0.0", @@ -100,6 +102,7 @@ "typescript": "^5.0.0", "unified": "^10.0.0", "unist-builder": "^3.0.0", + "unist-util-remove-position": "^4.0.2", "unist-util-visit": "^4.0.0", "uvu": "^0.5.0", "vfile": "^5.0.0", @@ -9081,6 +9084,25 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/mdast-util-directive": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/mdast-util-directive/-/mdast-util-directive-2.2.4.tgz", + "integrity": "sha512-sK3ojFP+jpj1n7Zo5ZKvoxP1MvLyzVG63+gm40Z/qI00avzdPCYxt7RBMgofwAva9gBjbDBWVRB/i+UD+fUCzQ==", + "dev": true, + "dependencies": { + "@types/mdast": "^3.0.0", + "@types/unist": "^2.0.0", + "mdast-util-from-markdown": "^1.3.0", + "mdast-util-to-markdown": "^1.5.0", + "parse-entities": "^4.0.0", + "stringify-entities": "^4.0.0", + "unist-util-visit-parents": "^5.1.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/mdast-util-find-and-replace": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-2.2.2.tgz", @@ -9790,6 +9812,25 @@ "uvu": "^0.5.0" } }, + "node_modules/micromark-extension-directive": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/micromark-extension-directive/-/micromark-extension-directive-2.2.0.tgz", + "integrity": "sha512-LWc2mGlJlPEcESz4IHNJR/tpJfWJEEFHGM+6vgCZGXkKMXc/y8rCKB07x5ZNnafIFe0/sjt6DIIihk78/Egj5Q==", + "dev": true, + "dependencies": { + "micromark-factory-space": "^1.0.0", + "micromark-factory-whitespace": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "parse-entities": "^4.0.0", + "uvu": "^0.5.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/micromark-extension-frontmatter": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/micromark-extension-frontmatter/-/micromark-extension-frontmatter-1.0.0.tgz", @@ -14099,6 +14140,22 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/remark-directive": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/remark-directive/-/remark-directive-2.0.1.tgz", + "integrity": "sha512-oosbsUAkU/qmUE78anLaJePnPis4ihsE7Agp0T/oqTzvTea8pOiaYEtfInU/+xMOVTS9PN5AhGOiaIVe4GD8gw==", + "dev": true, + "dependencies": { + "@types/mdast": "^3.0.0", + "mdast-util-directive": "^2.0.0", + "micromark-extension-directive": "^2.0.0", + "unified": "^10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/remark-frontmatter": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/remark-frontmatter/-/remark-frontmatter-4.0.1.tgz", diff --git a/package.json b/package.json index f5f3d0096..cd60ef6b9 100644 --- a/package.json +++ b/package.json @@ -89,6 +89,7 @@ "rehype-slug": "^5.0.0", "rehype-stringify": "^9.0.0", "remark-cli": "^11.0.0", + "remark-directive": "^2.0.0", "remark-frontmatter": "^4.0.0", "remark-gemoji": "^7.0.0", "remark-gfm": "^3.0.0", @@ -104,6 +105,8 @@ "unified": "^10.0.0", "unist-builder": "^3.0.0", "unist-util-visit": "^4.0.0", + "estree-util-visit": "^1.2.1", + "unist-util-remove-position": "^4.0.2", "uvu": "^0.5.0", "vfile": "^5.0.0", "vfile-message": "^3.0.0",