-
Notifications
You must be signed in to change notification settings - Fork 291
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Updating markdown implementation to allow for GFM (#109)
- Loading branch information
Showing
6 changed files
with
337 additions
and
25 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
import insane, { AllowedTags } from 'insane'; | ||
import { marked, Renderer } from 'marked'; | ||
import React, { CSSProperties, useMemo } from 'react'; | ||
|
||
const ALLOWED_TAGS: AllowedTags[] = [ | ||
'a', | ||
'article', | ||
'b', | ||
'blockquote', | ||
'br', | ||
'caption', | ||
'code', | ||
'del', | ||
'details', | ||
'div', | ||
'em', | ||
'h1', | ||
'h2', | ||
'h3', | ||
'h4', | ||
'h5', | ||
'h6', | ||
'hr', | ||
'i', | ||
'img', | ||
'ins', | ||
'kbd', | ||
'li', | ||
'main', | ||
'ol', | ||
'p', | ||
'pre', | ||
'section', | ||
'span', | ||
'strong', | ||
'sub', | ||
'summary', | ||
'sup', | ||
'table', | ||
'tbody', | ||
'td', | ||
'th', | ||
'thead', | ||
'tr', | ||
'u', | ||
'ul', | ||
]; | ||
const GENERIC_ALLOWED_ATTRIBUTES = ['style', 'title']; | ||
|
||
function sanitizer(html: string): string { | ||
return insane(html, { | ||
allowedTags: ALLOWED_TAGS, | ||
allowedAttributes: { | ||
...ALLOWED_TAGS.reduce<Record<string, string[]>>((res, tag) => { | ||
res[tag] = [...GENERIC_ALLOWED_ATTRIBUTES]; | ||
return res; | ||
}, {}), | ||
img: ['src', 'srcset', 'alt', 'width', 'height', ...GENERIC_ALLOWED_ATTRIBUTES], | ||
table: ['width', ...GENERIC_ALLOWED_ATTRIBUTES], | ||
td: ['width', ...GENERIC_ALLOWED_ATTRIBUTES], | ||
a: ['href', 'target', ...GENERIC_ALLOWED_ATTRIBUTES], | ||
}, | ||
}); | ||
} | ||
|
||
class CustomRenderer extends Renderer { | ||
table(header: string, body: string) { | ||
return `<table width="100%"> | ||
<thead> | ||
${header}</thead> | ||
<tbody> | ||
${body}</tbody> | ||
</table>`; | ||
} | ||
|
||
link(href: string, title: string | null, text: string) { | ||
if (!title) { | ||
return `<a href="${href}" target="_blank">${text}</a>`; | ||
} | ||
return `<a href="${href}" title="${title}" target="_blank">${text}</a>`; | ||
} | ||
} | ||
|
||
function renderMarkdownString(str: string): string { | ||
const html = marked.parse(str, { | ||
async: false, | ||
breaks: true, | ||
gfm: true, | ||
pedantic: false, | ||
silent: false, | ||
renderer: new CustomRenderer(), | ||
}); | ||
if (typeof html !== 'string') { | ||
throw new Error('marked.parse did not return a string'); | ||
} | ||
return sanitizer(html); | ||
} | ||
|
||
type Props = { | ||
style: CSSProperties; | ||
markdown: string; | ||
}; | ||
export default function EmailMarkdown({ markdown, ...props }: Props) { | ||
const data = useMemo(() => renderMarkdownString(markdown), [markdown]); | ||
return <div {...props} dangerouslySetInnerHTML={{ __html: data }} />; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.