@@ -5,10 +5,14 @@ import {VFile} from 'vfile'
55import { VFileMessage } from 'vfile-message'
66import { statistics } from 'vfile-statistics'
77import { reporter } from 'vfile-reporter'
8- import { evaluate } from '@mdx-js/mdx'
8+ import { evaluate , nodeTypes } from '@mdx-js/mdx'
99import remarkGfm from 'remark-gfm'
10+ import rehypeRaw from 'rehype-raw'
1011import remarkFrontmatter from 'remark-frontmatter'
12+ import remarkDirective from 'remark-directive'
1113import remarkMath from 'remark-math'
14+ import { visit as visitEstree } from 'estree-util-visit'
15+ import { removePosition } from 'unist-util-remove-position'
1216import CodeMirror from 'rodemirror'
1317import { basicSetup } from 'codemirror'
1418import { markdown as langMarkdown } from '@codemirror/lang-markdown'
@@ -29,30 +33,41 @@ function useMdx(defaults) {
2933 const [ state , setState ] = useState ( { ...defaults , file : null } )
3034 const { run : setConfig } = useDebounceFn (
3135 async ( config ) => {
32- const file = new VFile ( { basename : 'example.mdx' , value : config . value } )
36+ const basename = config . formatMd ? 'example.md' : 'example.mdx'
37+ const file = new VFile ( { basename, value : config . value } )
3338
3439 const capture = ( name ) => ( ) => ( tree ) => {
3540 file . data [ name ] = tree
3641 }
3742
3843 const remarkPlugins = [ ]
39-
4044 if ( config . gfm ) remarkPlugins . push ( remarkGfm )
4145 if ( config . frontmatter ) remarkPlugins . push ( remarkFrontmatter )
4246 if ( config . math ) remarkPlugins . push ( remarkMath )
43-
47+ if ( config . directive ) remarkPlugins . push ( remarkDirective )
4448 remarkPlugins . push ( capture ( 'mdast' ) )
4549
50+ const rehypePlugins = [ ]
51+ if ( config . rehypeRaw )
52+ rehypePlugins . push ( [ rehypeRaw , { passThrough : nodeTypes } ] )
53+ rehypePlugins . push ( capture ( 'hast' ) )
54+
4655 try {
4756 file . result = (
4857 await evaluate ( file , {
4958 ...runtime ,
5059 useDynamicImport : true ,
5160 remarkPlugins,
52- rehypePlugins : [ capture ( 'hast' ) ] ,
61+ rehypePlugins,
5362 recmaPlugins : [ capture ( 'esast' ) ]
5463 } )
5564 ) . default
65+
66+ if ( ! config . position ) {
67+ removePosition ( file . data . mdast , { force : true } )
68+ removePosition ( file . data . hast , { force : true } )
69+ removePositionEsast ( file . data . esast )
70+ }
5671 } catch ( error ) {
5772 const message =
5873 error instanceof VFileMessage ? error : new VFileMessage ( error )
@@ -107,9 +122,13 @@ export function Editor({children}) {
107122 const defaultValue = children
108123 const extensions = useMemo ( ( ) => [ basicSetup , oneDark , langMarkdown ( ) ] , [ ] )
109124 const [ state , setConfig ] = useMdx ( {
125+ formatMd : false ,
126+ position : false ,
110127 gfm : false ,
111128 frontmatter : false ,
129+ directive : false ,
112130 math : false ,
131+ rehypeRaw : false ,
113132 value : defaultValue
114133 } )
115134 const onUpdate = useCallback (
@@ -132,7 +151,7 @@ export function Editor({children}) {
132151 } , [ state ] )
133152
134153 return (
135- < div >
154+ < div className = "playground-editor" >
136155 < Tabs className = "frame frame-resizeable" >
137156 < TabList className = "frame-tab-bar frame-tab-bar-scroll" >
138157 < Tab
@@ -166,6 +185,41 @@ export function Editor({children}) {
166185 </ TabPanel >
167186 < TabPanel className = "tab-panel-scrollable playground-editor-options-tab-panel" >
168187 < form className = "frame-body frame-body-box" >
188+ < fieldset >
189+ < label >
190+ < input
191+ type = "radio"
192+ name = "language"
193+ checked = { ! state . formatMd }
194+ onChange = { ( ) => {
195+ setConfig ( { ...state , formatMd : false } )
196+ } }
197+ /> { ' ' }
198+ Use < code > MDX</ code >
199+ </ label >
200+ < span style = { { margin : '1em' } } > </ span >
201+ < label >
202+ < input
203+ type = "radio"
204+ name = "language"
205+ checked = { state . formatMd }
206+ onChange = { ( ) => {
207+ setConfig ( { ...state , formatMd : true } )
208+ } }
209+ /> { ' ' }
210+ Use < code > CommonMark</ code >
211+ </ label >
212+ </ fieldset >
213+ < label >
214+ < input
215+ checked = { state . position }
216+ type = "checkbox"
217+ onChange = { ( ) =>
218+ setConfig ( { ...state , position : ! state . position } )
219+ }
220+ /> { ' ' }
221+ Show positional info
222+ </ label >
169223 < label >
170224 < input
171225 checked = { state . gfm }
@@ -201,6 +255,32 @@ export function Editor({children}) {
201255 < code > remark-math</ code >
202256 </ a >
203257 </ label >
258+ < label >
259+ < input
260+ checked = { state . directive }
261+ type = "checkbox"
262+ onChange = { ( ) =>
263+ setConfig ( { ...state , directive : ! state . directive } )
264+ }
265+ /> { ' ' }
266+ Use{ ' ' }
267+ < a href = "https://github.com/remarkjs/remark-directive" >
268+ < code > remark-directive</ code >
269+ </ a >
270+ </ label >
271+ < label >
272+ < input
273+ checked = { state . rehypeRaw }
274+ type = "checkbox"
275+ onChange = { ( ) =>
276+ setConfig ( { ...state , rehypeRaw : ! state . rehypeRaw } )
277+ }
278+ /> { ' ' }
279+ Use{ ' ' }
280+ < a href = "https://github.com/rehypejs/rehype-raw" >
281+ < code > rehype-raw</ code >
282+ </ a >
283+ </ label >
204284 </ form >
205285 </ TabPanel >
206286 </ Tabs >
@@ -324,3 +404,15 @@ export function Editor({children}) {
324404 </ div >
325405 )
326406}
407+
408+ function removePositionEsast ( tree ) {
409+ visitEstree ( tree , remove )
410+ return tree
411+
412+ function remove ( node ) {
413+ delete node . loc
414+ delete node . start
415+ delete node . end
416+ delete node . range
417+ }
418+ }
0 commit comments