1- /* eslint-disable react/no-danger */
21import React , {
32 HTMLAttributes ,
4- MutableRefObject ,
53 ReactElement ,
64 useEffect ,
7- useMemo ,
8- useRef ,
95 useState ,
106} from "react" ;
117import cn from "classnames" ;
12- import { useRouter } from "next/router" ;
8+ import { Markdown as MarkdownRenderer } from "react-marked-renderer" ;
9+
10+ import { getLanguage , highlightCode } from "components/Code/utils" ;
1311
1412import styles from "./Markdown.module.scss" ;
15- import { markdownToHTML } from "./utils" ;
13+ import { renderers } from "./renderers" ;
14+ import { transformMarkdown } from "./utils" ;
1615
1716function useMarkdownResolver ( markdown : MarkdownProps [ "children" ] ) : string {
1817 /* eslint-disable react-hooks/rules-of-hooks */
1918 // i will never swap between strings and promises
2019 if ( typeof markdown === "string" ) {
21- return markdown ;
20+ return transformMarkdown ( markdown ) ;
2221 }
2322
2423 const [ resolved , setResolved ] = useState ( "" ) ;
2524 useEffect ( ( ) => {
2625 markdown ( ) . then ( ( md ) => {
2726 if ( typeof md === "string" ) {
28- setResolved ( md ) ;
27+ setResolved ( transformMarkdown ( md ) ) ;
2928 } else if ( typeof md . default === "string" ) {
30- setResolved ( md . default ) ;
29+ setResolved ( transformMarkdown ( md . default ) ) ;
3130 }
3231 } ) ;
3332 } , [ markdown ] ) ;
3433
3534 return resolved ;
3635}
3736
38- interface DangerHTML {
39- __html : string ;
40- }
41-
42- function useHTML ( children : MarkdownChildren ) : DangerHTML {
43- const markdown = useMarkdownResolver ( children ) ;
44- const html = useMemo (
45- ( ) => ( {
46- __html : markdownToHTML ( markdown ) ,
47- } ) ,
48- [ markdown ]
49- ) ;
50-
51- return html ;
52- }
53-
54- function useCustomMarkdownBehavior ( {
55- __html : html ,
56- } : DangerHTML ) : MutableRefObject < HTMLDivElement | null > {
57- const ref = useRef < HTMLDivElement | null > ( null ) ;
58- const router = useRouter ( ) ;
59- useEffect ( ( ) => {
60- const instance = ref . current ;
61- if ( ! instance ) {
62- return ;
63- }
64-
65- const { origin } = window . location ;
66- const links = Array . from (
67- instance . querySelectorAll < HTMLAnchorElement > ( "a[href]" )
68- ) ;
69-
70- links . forEach ( ( link ) => {
71- if ( link . href . startsWith ( origin ) ) {
72- link . onclick = ( event ) => {
73- event . preventDefault ( ) ;
74- const href = link . href . replace ( origin , "" ) ;
75-
76- router . push ( href ) . then ( ( success ) => {
77- if ( success ) {
78- const [ , hash ] = href . split ( "#" ) ;
79- if ( hash ) {
80- const el = document . getElementById ( hash ) ;
81- if ( el && typeof el . focus === "function" ) {
82- el . focus ( ) ;
83- return ;
84- }
85- }
86-
87- window . scrollTo ( 0 , 0 ) ;
88- }
89- } ) ;
90- } ;
91- }
92- } ) ;
93- } , [ html , router ] ) ;
94-
95- return ref ;
96- }
97-
9837export type ResolveMarkdown = ( ) => Promise < string | { default : string } > ;
9938export type MarkdownChildren = string | ResolveMarkdown ;
10039
@@ -109,23 +48,27 @@ export default function Markdown({
10948 disableSinglePMargin,
11049 ...props
11150} : MarkdownProps ) : ReactElement {
112- const html = useHTML ( children ) ;
113- const ref = useCustomMarkdownBehavior ( html ) ;
51+ const markdown = useMarkdownResolver ( children ) ;
11452
11553 return (
11654 < >
11755 < div
11856 { ...props }
119- ref = { ref }
12057 className = { cn (
12158 styles . container ,
12259 {
12360 [ styles . marginless ] : disableSinglePMargin ,
12461 } ,
12562 className
12663 ) }
127- dangerouslySetInnerHTML = { html }
128- />
64+ >
65+ < MarkdownRenderer
66+ markdown = { markdown }
67+ renderers = { renderers }
68+ getLanguage = { getLanguage }
69+ highlightCode = { highlightCode }
70+ />
71+ </ div >
12972 </ >
13073 ) ;
13174}
0 commit comments