Add Markdown component to render markdown

Summary:
Adds a Markdown component to the component library.

The react-markdown library doesn't work out of the box because elements it outputs don't have any styles, e.g. h1, h2, p, em, etc.

So I've added a custom renderer to give styles to each of these that workplace markdown uses.
The only one I haven't done at the moment that I'm aware of is numbered-lists.

There's probably a way to get back the original styling of these elements so we don't need a custom renderer, but this works for now, and also allows us to customise their appearance.

Reviewed By: passy

Differential Revision: D18533085

fbshipit-source-id: a4332a11d34d577a6300074e4dde126362d46a6b
This commit is contained in:
John Knox
2019-11-19 05:51:09 -08:00
committed by Facebook Github Bot
parent 6c4e687d63
commit 352d9c82cb
4 changed files with 405 additions and 3 deletions

View File

@@ -0,0 +1,101 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
import React, {PureComponent, RefObject} from 'react';
import styled from 'react-emotion';
import ReactMarkdown from 'react-markdown';
import ReactDOM from 'react-dom';
import {colors} from './colors';
import {shell} from 'electron';
const Row = styled('div')({
marginTop: 5,
marginBottom: 5,
});
const Heading = styled('div')((props: {level: number}) => ({
fontSize: Math.max(10, 20 - (props.level - 1) * 4),
marginBottom: 10,
fontWeight: 'bold',
}));
const ListItem = styled('li')({
'list-style-type': 'circle',
'list-style-position': 'inside',
marginLeft: 10,
});
const Strong = styled('span')({
fontWeight: 'bold',
});
const Emphasis = styled('span')({
fontStyle: 'italic',
});
const Quote = styled(Row)({
padding: 10,
backgroundColor: '#f1f2f3',
});
const Code = styled('span')({
fontFamily: '"Courier New", Courier, monospace',
backgroundColor: '#f1f2f3',
});
const Pre = styled(Row)({
padding: 10,
backgroundColor: '#f1f2f3',
});
class CodeBlock extends PureComponent<{value: string; language: string}> {
render() {
return (
<Pre>
<Code>{this.props.value}</Code>
</Pre>
);
}
}
const Link = styled('span')({
color: colors.blue,
textDecoration: 'underline',
});
class LinkReference extends PureComponent<{href: string}> {
render() {
return (
<Link onClick={() => shell.openExternal(this.props.href)}>
{this.props.children}
</Link>
);
}
}
export class Markdown extends PureComponent<{
source: string;
}> {
containerRef: RefObject<HTMLDivElement> = React.createRef();
componentDidMount() {
ReactDOM.render(
<ReactMarkdown
source={this.props.source}
renderers={{
heading: Heading,
listItem: ListItem,
paragraph: Row,
strong: Strong,
emphasis: Emphasis,
inlineCode: Code,
code: CodeBlock,
blockquote: Quote,
link: LinkReference,
linkReference: LinkReference,
}}
/>,
this.containerRef.current,
);
}
render() {
return <div ref={this.containerRef}></div>;
}
}