1- import type { StylesType } from 'md-to-react-email' ;
2- import { parseMarkdownToJSX } from 'md-to-react-email' ;
1+ import { marked , Renderer } from 'marked' ;
32import * as React from 'react' ;
3+ import { type StylesType , styles } from './styles' ;
4+ import { parseCssInJsToInlineCss } from './utils/parse-css-in-js-to-inline-css' ;
45
56export type MarkdownProps = Readonly < {
67 children : string ;
@@ -13,15 +14,216 @@ export const Markdown = React.forwardRef<HTMLDivElement, MarkdownProps>(
1314 { children, markdownContainerStyles, markdownCustomStyles, ...props } ,
1415 ref ,
1516 ) => {
16- const parsedMarkdown = parseMarkdownToJSX ( {
17- markdown : children ,
18- customStyles : markdownCustomStyles ,
19- } ) ;
17+ const finalStyles = { ...styles , ...markdownCustomStyles } ;
18+
19+ const renderer = new Renderer ( ) ;
20+ renderer . blockquote = ( { tokens } ) => {
21+ const text = renderer . parser . parse ( tokens ) ;
22+
23+ return `<blockquote${
24+ parseCssInJsToInlineCss ( finalStyles . blockQuote ) !== ''
25+ ? ` style="${ parseCssInJsToInlineCss ( finalStyles . blockQuote ) } "`
26+ : ''
27+ } >\n${ text } </blockquote>\n`;
28+ } ;
29+
30+ renderer . br = ( ) => {
31+ return `<br${
32+ parseCssInJsToInlineCss ( finalStyles . br ) !== ''
33+ ? ` style="${ parseCssInJsToInlineCss ( finalStyles . br ) } "`
34+ : ''
35+ } />`;
36+ } ;
37+
38+ // TODO: Support all options
39+ renderer . code = ( { text } ) => {
40+ text = `${ text . replace ( / \n $ / , '' ) } \n` ;
41+
42+ return `<pre${
43+ parseCssInJsToInlineCss ( finalStyles . codeBlock ) !== ''
44+ ? ` style="${ parseCssInJsToInlineCss ( finalStyles . codeBlock ) } "`
45+ : ''
46+ } ><code>${ text } </code></pre>\n`;
47+ } ;
48+
49+ renderer . codespan = ( { text } ) => {
50+ return `<code${
51+ parseCssInJsToInlineCss ( finalStyles . codeInline ) !== ''
52+ ? ` style="${ parseCssInJsToInlineCss ( finalStyles . codeInline ) } "`
53+ : ''
54+ } >${ text } </code>`;
55+ } ;
56+
57+ renderer . del = ( { tokens } ) => {
58+ const text = renderer . parser . parseInline ( tokens ) ;
59+
60+ return `<del${
61+ parseCssInJsToInlineCss ( finalStyles . strikethrough ) !== ''
62+ ? ` style="${ parseCssInJsToInlineCss ( finalStyles . strikethrough ) } "`
63+ : ''
64+ } >${ text } </del>`;
65+ } ;
66+
67+ renderer . em = ( { tokens } ) => {
68+ const text = renderer . parser . parseInline ( tokens ) ;
69+
70+ return `<em${
71+ parseCssInJsToInlineCss ( finalStyles . italic ) !== ''
72+ ? ` style="${ parseCssInJsToInlineCss ( finalStyles . italic ) } "`
73+ : ''
74+ } >${ text } </em>`;
75+ } ;
76+
77+ renderer . heading = ( { tokens, depth } ) => {
78+ const text = renderer . parser . parseInline ( tokens ) ;
79+
80+ return `<h${ depth } ${
81+ parseCssInJsToInlineCss (
82+ finalStyles [ `h${ depth } ` as keyof StylesType ] ,
83+ ) !== ''
84+ ? ` style="${ parseCssInJsToInlineCss (
85+ finalStyles [ `h${ depth } ` as keyof StylesType ] ,
86+ ) } "`
87+ : ''
88+ } >${ text } </h${ depth } >`;
89+ } ;
90+
91+ renderer . hr = ( ) => {
92+ return `<hr${
93+ parseCssInJsToInlineCss ( finalStyles . hr ) !== ''
94+ ? ` style="${ parseCssInJsToInlineCss ( finalStyles . hr ) } "`
95+ : ''
96+ } />\n`;
97+ } ;
98+
99+ renderer . image = ( { href, text, title } ) => {
100+ return `<img src="${ href . replaceAll ( '"' , '"' ) } " alt="${ text . replaceAll ( '"' , '"' ) } "${
101+ title ? ` title="${ title } "` : ''
102+ } ${
103+ parseCssInJsToInlineCss ( finalStyles . image ) !== ''
104+ ? ` style="${ parseCssInJsToInlineCss ( finalStyles . image ) } "`
105+ : ''
106+ } >`;
107+ } ;
108+
109+ renderer . link = ( { href, title, tokens } ) => {
110+ const text = renderer . parser . parseInline ( tokens ) ;
111+
112+ return `<a href="${ href } " target="_blank"${
113+ title ? ` title="${ title } "` : ''
114+ } ${
115+ parseCssInJsToInlineCss ( finalStyles . link ) !== ''
116+ ? ` style="${ parseCssInJsToInlineCss ( finalStyles . link ) } "`
117+ : ''
118+ } >${ text } </a>`;
119+ } ;
120+
121+ renderer . listitem = ( { tokens } ) => {
122+ const text = renderer . parser . parseInline ( tokens ) ;
123+
124+ return `<li${
125+ parseCssInJsToInlineCss ( finalStyles . li ) !== ''
126+ ? ` style="${ parseCssInJsToInlineCss ( finalStyles . li ) } "`
127+ : ''
128+ } >${ text } </li>\n`;
129+ } ;
130+
131+ renderer . list = ( { items, ordered, start } ) => {
132+ const type = ordered ? 'ol' : 'ul' ;
133+ const startAt = ordered && start !== 1 ? ` start="${ start } "` : '' ;
134+ const styles = parseCssInJsToInlineCss (
135+ finalStyles [ ordered ? 'ol' : 'ul' ] ,
136+ ) ;
137+
138+ return (
139+ '<' +
140+ type +
141+ startAt +
142+ `${ styles !== '' ? ` style="${ styles } "` : '' } >\n` +
143+ items . map ( ( item ) => renderer . listitem ( item ) ) . join ( '' ) +
144+ '</' +
145+ type +
146+ '>\n'
147+ ) ;
148+ } ;
149+
150+ renderer . paragraph = ( { tokens } ) => {
151+ const text = renderer . parser . parseInline ( tokens ) ;
152+
153+ return `<p${
154+ parseCssInJsToInlineCss ( finalStyles . p ) !== ''
155+ ? ` style="${ parseCssInJsToInlineCss ( finalStyles . p ) } "`
156+ : ''
157+ } >${ text } </p>\n`;
158+ } ;
159+
160+ renderer . strong = ( { tokens } ) => {
161+ const text = renderer . parser . parseInline ( tokens ) ;
162+
163+ return `<strong${
164+ parseCssInJsToInlineCss ( finalStyles . bold ) !== ''
165+ ? ` style="${ parseCssInJsToInlineCss ( finalStyles . bold ) } "`
166+ : ''
167+ } >${ text } </strong>`;
168+ } ;
169+
170+ renderer . table = ( { header, rows } ) => {
171+ const styleTable = parseCssInJsToInlineCss ( finalStyles . table ) ;
172+ const styleThead = parseCssInJsToInlineCss ( finalStyles . thead ) ;
173+ const styleTbody = parseCssInJsToInlineCss ( finalStyles . tbody ) ;
174+
175+ const theadRow = renderer . tablerow ( {
176+ text : header . map ( ( cell ) => renderer . tablecell ( cell ) ) . join ( '' ) ,
177+ } ) ;
178+
179+ const tbodyRows = rows
180+ . map ( ( row ) =>
181+ renderer . tablerow ( {
182+ text : row . map ( ( cell ) => renderer . tablecell ( cell ) ) . join ( '' ) ,
183+ } ) ,
184+ )
185+ . join ( '' ) ;
186+
187+ const thead = `<thead${ styleThead ? ` style="${ styleThead } "` : '' } >\n${ theadRow } </thead>` ;
188+ const tbody = `<tbody${ styleTbody ? ` style="${ styleTbody } "` : '' } >${ tbodyRows } </tbody>` ;
189+
190+ return `<table${ styleTable ? ` style="${ styleTable } "` : '' } >\n${ thead } \n${ tbody } </table>\n` ;
191+ } ;
192+
193+ renderer . tablecell = ( { tokens, align, header } ) => {
194+ const text = renderer . parser . parseInline ( tokens ) ;
195+ const type = header ? 'th' : 'td' ;
196+ const tag = align
197+ ? `<${ type } align="${ align } "${
198+ parseCssInJsToInlineCss ( finalStyles . td ) !== ''
199+ ? ` style="${ parseCssInJsToInlineCss ( finalStyles . td ) } "`
200+ : ''
201+ } >`
202+ : `<${ type } ${
203+ parseCssInJsToInlineCss ( finalStyles . td ) !== ''
204+ ? ` style="${ parseCssInJsToInlineCss ( finalStyles . td ) } "`
205+ : ''
206+ } >`;
207+ return `${ tag } ${ text } </${ type } >\n` ;
208+ } ;
209+
210+ renderer . tablerow = ( { text } ) => {
211+ return `<tr${
212+ parseCssInJsToInlineCss ( finalStyles . tr ) !== ''
213+ ? ` style="${ parseCssInJsToInlineCss ( finalStyles . tr ) } "`
214+ : ''
215+ } >\n${ text } </tr>\n`;
216+ } ;
20217
21218 return (
22219 < div
23220 { ...props }
24- dangerouslySetInnerHTML = { { __html : parsedMarkdown } }
221+ dangerouslySetInnerHTML = { {
222+ __html : marked . parse ( children , {
223+ renderer,
224+ async : false ,
225+ } ) ,
226+ } }
25227 data-id = "react-email-markdown"
26228 ref = { ref }
27229 style = { markdownContainerStyles }
0 commit comments