@readme/markdown
Version:
ReadMe's React-based Markdown parser
76 lines (66 loc) • 2.24 kB
JSX
const React = require('react');
const PropTypes = require('prop-types');
// Only load CodeMirror in the browser, for SSR
// apps. Necessary because of people like this:
// https://github.com/codemirror/CodeMirror/issues/3701#issuecomment-164904534
const syntaxHighlighter = typeof window !== 'undefined' ? require('@readme/syntax-highlighter') : false;
const copy = require('copy-to-clipboard');
const remapLang = {
c: 'cplusplus',
'c++': 'cplusplus',
cpp: 'cplusplus',
docker: 'dockerfile',
html: 'htmlmixed',
js: 'javascript',
py: 'python',
sh: 'shell',
bash: 'shell',
mysql: 'sql',
};
function CopyCode({ code, rootClass = 'rdmd-code-copy', className = '' }) {
const copyClass = `${rootClass}_copied`;
const button = React.createRef();
/* istanbul ignore next */
const copier = () => {
if (copy(code)) {
const $el = button.current;
$el.classList.add(copyClass);
setTimeout(() => $el.classList.remove(copyClass), 1500);
}
};
return <button ref={button} className={`${rootClass} ${className}`} onClick={copier} />;
}
CopyCode.propTypes = {
className: PropTypes.string,
code: PropTypes.string,
rootClass: PropTypes.string,
};
function Code(props) {
const { className, children, lang, meta } = props;
const langClass = className.search(/lang(?:uage)?-\w+/) >= 0 ? className.match(/\s?lang(?:uage)?-(\w+)/)[1] : '';
const language = lang in remapLang ? remapLang[lang] : lang || langClass;
return (
<React.Fragment>
<code className={['rdmd-code', `lang-${language}`].join(' ')} data-lang={language} name={meta}>
{!syntaxHighlighter || <CopyCode className="fa" code={children[0]} />}
{syntaxHighlighter ? syntaxHighlighter(children[0], language, { tokenizeVariables: true }) : children[0]}
</code>
</React.Fragment>
);
}
Code.propTypes = {
children: PropTypes.arrayOf(PropTypes.string).isRequired,
className: PropTypes.string,
lang: PropTypes.string,
meta: PropTypes.string,
};
Code.defaultProps = {
className: '',
lang: '',
meta: '',
};
module.exports = sanitizeSchema => {
// This is for code blocks class name
sanitizeSchema.attributes.code = ['className', 'lang', 'meta', 'value'];
return Code;
};