import { makeStyles } from '@mui/styles'; import classNames from 'classnames'; import React, { useMemo } from 'react'; import ReactMarkdown from 'react-markdown'; import { Link } from 'react-router'; import { CodeBlock } from '../../components/CodeBlock.js'; import { customDirectives } from './plugins/customDirectives.js'; import { gfmTables } from './plugins/gfmTables.js'; import { symbolLinks } from './plugins/symbolLinks.js'; interface MarkdownParserProps { source: string; } const useStyles = makeStyles( theme => ({ root: { '& table': { borderCollapse: 'collapse' }, '& th, & td': { border: `1px solid ${theme.colors.border}`, padding: theme.spacing.unit }, '& li': { margin: `${theme.spacing.unit * 2}px 0`, '&::marker': { color: '#647d0f' } }, '& code': { outline: `1px solid ${theme.colors.border}`, padding: `0 ${theme.spacing.unit / 4}px`, borderRadius: 3, color: theme.colors.accent.focus, backgroundColor: theme.colors.background.active }, // cancel out the above for code blocks '& pre > code': { outline: '0 none', padding: 0, borderRadius: 0, color: 'inherit', backgroundColor: 'inherit' } }, link: { color: 'inherit', fontWeight: 'bold', textDecoration: 'none', borderBottom: `1.5px solid ${theme.colors.accent.default}`, transition: 'border-color .3s ease-in-out', '&:hover': { borderBottomColor: theme.colors.accent.focus } }, warning: { display: 'flow-root', borderLeft: `${theme.spacing.unit / 2}px solid ${theme.colors.warning}`, backgroundColor: theme.colors.background.active, marginBottom: '1em', padding: '0 1em' }, warningTitle: { fontSize: '1em' } }), { name: 'MarkdownParser' } ); const MarkdownParser: React.FC = ({ source }) => { const classes = useStyles(); const components = useMemo( () => ({ /* eslint-disable @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-call */ a: function MdLink(mdProps: any) { const props = { key: mdProps.nodeKey, className: mdProps.className }; if (mdProps.href.startsWith('/')) { return ( {mdProps.children} ); } return ( {mdProps.children} ); }, // eslint-disable-next-line @typescript-eslint/no-explicit-any code: function MdCodeBlock({ node, inline, className, children, ...props }: any) { if (!inline) { const match = /language-(\w+)/.exec(className || ''); if (match) { return ( ); } } return ( {children} ); } /* eslint-enable @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-call */ }), [classes] ); const customDirectiveClasses = useMemo( () => ({ warning: classes.warning, warningTitle: classes.warningTitle }), [classes] ); return ( {source} ); }; export default React.memo(MarkdownParser);