import React , { useEffect , useRef } from 'react' ; import marked from 'marked' ; import DOMPurify from 'dompurify' ; import emojiToolkit from 'emoji-toolkit' ; import Prism from 'prismjs' ; import { getDefaultMarkedOptions , resetMarkedOptions } from '@/utils/utils' ; import Tocify from './tocify' ; export interface MarkdownBodyProps { markdown : string ; prismPlugin ? : boolean ; toc ? : boolean ; getTocify ? : ( tocify : Tocify ) => void ; } const tocify = new Tocify ( ) ; const MarkdownBody = ( props ) => { const markdownRef = useRef < HTMLDivElement | null > ( null ) ; const runPlugin = async ( ) => { const [ { default : jQuery } , { debounce , throttle } ] = await Promise . all ( [ import ( 'jquery' ) , import ( 'throttle-debounce' ) , ] ) ; jQuery . debounce = debounce ; jQuery . throttle = throttle ; window . jQuery = jQuery ; await Promise . all ( [ import ( 'fluidbox' ) , import ( 'fluidbox/dist/css/fluidbox.min.css' ) , ] ) ; jQuery ( markdownRef . current ) . find ( 'img:not(.joypixels)' ) . each ( function ( ) { jQuery ( this ) . wrap ( `<a href="${ jQuery ( this ) . attr ( 'src' ) }" class="fluidbox" />` ) ; } ) . promise ( ) . done ( ( ) => jQuery ( markdownRef . current ) . find ( 'a.fluidbox' ) . fluidbox ( ) ) ; if ( props . prismPlugin ) { jQuery ( markdownRef . current ) . find ( 'pre' ) . addClass ( 'line-numbers' ) ; Prism . highlightAllUnder ( markdownRef . current as any ) ; } } ; useEffect ( ( ) => { resetMarkedOptions ( ) ; if ( props . toc && props . getTocify ) { props . getTocify ( tocify ) ; } runPlugin ( ) ; } , [ ] ) ; const createMarkup = ( ) => { if ( props . toc ) { tocify . reset ( ) ; const { renderer , ... otherOptions } = getDefaultMarkedOptions ( ) ; renderer . heading = ( text , level ) => { const anchor = tocify . add ( text , level ) ; return `<a id="${ anchor }" href="#${ anchor }" class="anchor-fix"><h${ level }>${ text }</h${ level }></a>\n` ; } ; marked . setOptions ( { renderer , ... otherOptions } ) ; } const markup = DOMPurify . sanitize ( emojiToolkit . toImage ( marked ( props . markdown ) ) ) ; resetMarkedOptions ( ) ; return { __html : markup } ; } ; return ( < div ref = { markdownRef } className = "markdown-body" dangerouslySetInnerHTML = { createMarkup ( ) } / > ) ; } ; export default MarkdownBody ;