import { marked, Renderer } from 'marked'; import * as React from 'react'; import { type StylesType, styles } from './styles.js'; import { parseCssInJsToInlineCss } from './utils/parse-css-in-js-to-inline-css.js'; export type MarkdownProps = Readonly<{ children: string; markdownCustomStyles?: StylesType; markdownContainerStyles?: React.CSSProperties; }>; export const Markdown = React.forwardRef( ( { children, markdownContainerStyles, markdownCustomStyles, ...props }, ref, ) => { const finalStyles = { ...styles, ...markdownCustomStyles }; const renderer = new Renderer(); renderer.blockquote = ({ tokens }) => { const text = renderer.parser.parse(tokens); return `\n${text}\n`; }; renderer.br = () => { return ``; }; // TODO: Support all options renderer.code = ({ text }) => { text = `${text.replace(/\n$/, '')}\n`; return `${text}\n`; }; renderer.codespan = ({ text }) => { return `${text}`; }; renderer.del = ({ tokens }) => { const text = renderer.parser.parseInline(tokens); return `${text}`; }; renderer.em = ({ tokens }) => { const text = renderer.parser.parseInline(tokens); return `${text}`; }; renderer.heading = ({ tokens, depth }) => { const text = renderer.parser.parseInline(tokens); return `${text}`; }; renderer.hr = () => { return `\n`; }; renderer.image = ({ href, text, title }) => { return `${text.replaceAll('`; }; renderer.link = ({ href, title, tokens }) => { const text = renderer.parser.parseInline(tokens); return `${text}`; }; renderer.listitem = ({ tokens, loose }) => { const hasNestedList = tokens.some((token) => token.type === 'list'); const text = loose || hasNestedList ? renderer.parser.parse(tokens) : renderer.parser.parseInline(tokens); return `${text}\n`; }; renderer.list = ({ items, ordered, start }) => { const type = ordered ? 'ol' : 'ul'; const startAt = ordered && start !== 1 ? ` start="${start}"` : ''; const styles = parseCssInJsToInlineCss( finalStyles[ordered ? 'ol' : 'ul'], ); return ( '<' + type + startAt + `${styles !== '' ? ` style="${styles}"` : ''}>\n` + items.map((item) => renderer.listitem(item)).join('') + '\n' ); }; renderer.paragraph = ({ tokens }) => { const text = renderer.parser.parseInline(tokens); return `${text}

\n`; }; renderer.strong = ({ tokens }) => { const text = renderer.parser.parseInline(tokens); return `${text}`; }; renderer.table = ({ header, rows }) => { const styleTable = parseCssInJsToInlineCss(finalStyles.table); const styleThead = parseCssInJsToInlineCss(finalStyles.thead); const styleTbody = parseCssInJsToInlineCss(finalStyles.tbody); const theadRow = renderer.tablerow({ text: header.map((cell) => renderer.tablecell(cell)).join(''), }); const tbodyRows = rows .map((row) => renderer.tablerow({ text: row.map((cell) => renderer.tablecell(cell)).join(''), }), ) .join(''); const thead = `\n${theadRow}`; const tbody = `${tbodyRows}`; return `\n${thead}\n${tbody}
\n`; }; renderer.tablecell = ({ tokens, align, header }) => { const text = renderer.parser.parseInline(tokens); const type = header ? 'th' : 'td'; const tag = align ? `<${type} align="${align}"${ parseCssInJsToInlineCss(finalStyles.td) !== '' ? ` style="${parseCssInJsToInlineCss(finalStyles.td)}"` : '' }>` : `<${type}${ parseCssInJsToInlineCss(finalStyles.td) !== '' ? ` style="${parseCssInJsToInlineCss(finalStyles.td)}"` : '' }>`; return `${tag}${text}\n`; }; renderer.tablerow = ({ text }) => { return `\n${text}\n`; }; return (
); }, ); Markdown.displayName = 'Markdown';