Created
July 19, 2020 11:28
-
-
Save boganegru/a4da0b0da0b1233d30b10063b10efa8a to your computer and use it in GitHub Desktop.
This file contains hidden or 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
import React from 'react'; | |
import ReactMarkdown from 'react-markdown'; | |
import { withStyles } from '@material-ui/core/styles'; | |
import Typography from '@material-ui/core/Typography'; | |
import Link from '@material-ui/core/Link'; | |
import Table from "@material-ui/core/Table"; | |
import TableContainer from "@material-ui/core/TableContainer"; | |
import Paper from "@material-ui/core/Paper"; | |
import {TableHead, TableRow, TableCell, TableBody} from "@material-ui/core"; | |
const styles = (theme) => ({ | |
listItem: { | |
marginTop: theme.spacing(1), | |
}, | |
header: { | |
marginTop: theme.spacing(2), | |
} | |
}); | |
function MarkdownParagraph(props) { | |
return <Typography>{props.children}</Typography> | |
} | |
const MarkdownHeading = withStyles(styles)(({ classes, ...props }) => { | |
let variant; | |
switch (props.level) { | |
case 1: | |
variant = "h5"; | |
break; | |
case 2: | |
variant = "h6"; | |
break; | |
case 3: | |
variant = "subtitle1"; | |
break; | |
case 4: | |
variant = "subtitle2"; | |
break; | |
default: | |
variant = "h6"; | |
break; | |
} | |
return <Typography className={classes.header} gutterBottom variant={variant}>{props.children}</Typography> | |
}); | |
const MarkdownListItem = withStyles(styles)(({ classes, ...props }) => { | |
return ( | |
<li className={classes.listItem}> | |
<Typography component="span">{props.children}</Typography> | |
</li> | |
); | |
}); | |
function MarkdownTable(props) { | |
return ( | |
<TableContainer component={Paper}> | |
<Table size="small" aria-label="a dense table">{props.children}</Table> | |
</TableContainer> | |
); | |
} | |
function MarkdownTableCell(props) { | |
return <TableCell><Typography>{props.children}</Typography></TableCell> | |
} | |
function MarkdownTableRow(props) { | |
return <TableRow>{props.children}</TableRow> | |
} | |
function MarkdownTableBody(props) { | |
return <TableBody>{props.children}</TableBody> | |
} | |
function MarkdownTableHead(props) { | |
return <TableHead>{props.children}</TableHead> | |
} | |
const renderers = { | |
heading: MarkdownHeading, | |
paragraph: MarkdownParagraph, | |
link: Link, | |
listItem: MarkdownListItem, | |
table: MarkdownTable, | |
tableHead: MarkdownTableHead, | |
tableBody: MarkdownTableBody, | |
tableRow: MarkdownTableRow, | |
tableCell: MarkdownTableCell, | |
}; | |
export default function Markdown(props) { | |
return <ReactMarkdown escapeHtml={false} renderers={renderers} {...props} />; | |
} |
Thank you that's helpful.
With the new ReactMarkdown API it will be now components
prop instead of renderers
.
<ReactMarkdown
components={{
h1: ...
h2: ...
h3: ...
h4: ...
h5: ...
h6: ...
p: ({ node, ...props }) => (
<Typography gutterBottom variant="body1" {...props} />
),
strong: ({ node, ...props }) => (
<Typography variant="body1" fontWeight="bold" {...props} />
),
em: ({ node, ...props }) => (
<Typography variant="body1" fontStyle="italic" {...props} />
)
}}
>
{markdown}
</ReactMarkdown>
Thank you very much!!
I updated this to use more modern versions of Material UI and (following @Nitzperetz 's change of using components
):
Edit 1: better code highlighting support:
import React from "react";
import { default as ReactMarkdown } from "react-markdown";
import {
Link,
List,
ListItem,
ListItemText,
Paper,
Table,
TableBody,
TableCell,
TableContainer,
TableRow,
Typography,
useTheme,
} from "@mui/material";
import remarkGfm from "remark-gfm";
import { default as SyntaxHighlighter } from "react-syntax-highlighter";
import {
tomorrow as lightHighlightStyle,
tomorrowNight as darkHighlightStyle,
} from "react-syntax-highlighter/dist/cjs/styles/hljs";
import GlobalStyles from "@mui/material/GlobalStyles";
export default function Markdown({ markdown }: { markdown: string; }) {
const theme = useTheme();
return (
<ReactMarkdown
remarkPlugins={[remarkGfm]}
components={{
// *********
// * Links *
// *********
a: ({ href, title, children }) => (<Link href={href} underline={"always"}>{children}</Link>),
// ********
// * Text *
// ********
p: ({ children }) => (<Typography sx={{ mt: 1 }}>{children}</Typography>),
del: ({ children }) => (<Typography sx={{ mt: 1, textDecoration: "line-through" }}>{children}</Typography>),
em: ({ children }) => (<Typography sx={{ mt: 1, fontStyle: "italic" }}>{children}</Typography>),
strong: ({ children }) => (<Typography sx={{ mt: 1, fontWeight: "bold" }}>{children}</Typography>),
b: ({ children }) => (<Typography sx={{ mt: 1, fontWeight: "bold" }}>{children}</Typography>),
h1: ({ children }) => (<Typography gutterBottom sx={{ mt: 2 }} variant={"h1"}>{children}</Typography>),
h2: ({ children }) => (<Typography gutterBottom sx={{ mt: 2 }} variant={"h2"}>{children}</Typography>),
h3: ({ children }) => (<Typography gutterBottom sx={{ mt: 2 }} variant={"h3"}>{children}</Typography>),
h4: ({ children }) => (<Typography gutterBottom sx={{ mt: 2 }} variant={"h4"}>{children}</Typography>),
h5: ({ children }) => (<Typography gutterBottom sx={{ mt: 2 }} variant={"h5"}>{children}</Typography>),
h6: ({ children }) => (<Typography gutterBottom sx={{ mt: 2 }} variant={"h6"}>{children}</Typography>),
// **********
// * Tables *
// **********
table: ({ children }) => (<TableContainer component={Paper} sx={{ mt: 2 }}>
<Table size="small">{children}</Table>
</TableContainer>),
tbody: ({ children }) => (<TableBody>{children}</TableBody>),
// th: ({ children }) => (<TableHead>{children}</TableHead>),
tr: ({ children }) => (<TableRow>{children}</TableRow>),
td: ({ children }) => (<TableCell><Typography>{children}</Typography></TableCell>),
// *********
// * Lists *
// *********
ol: ({ children }) => (<List sx={{
listStyleType: "decimal",
mt: 2,
pl: 2,
"& .MuiListItem-root": {
display: "list-item",
},
}}>{children}</List>),
ul: ({ children }) => (<List sx={{
listStyleType: "disc",
mt: 2,
pl: 2,
"& .MuiListItem-root": {
display: "list-item",
},
}}>{children}</List>),
li: ({ children, ...props }) => (
<ListItem sx={{ m: 0, p: 0, ml: 2 }} disableGutters><ListItemText
sx={{ pl: 0.25 }}>{children}</ListItemText></ListItem>),
// ********
// * Code *
// ********
code: ({ node, inline, className, children, ...props }) => {
const match = /language-(\w+)/.exec(className || "");
return (
<>
<GlobalStyles styles={{ code: { color: "inherit", background: "transparent" } }} />
<SyntaxHighlighter
style={theme.palette.mode === "light" ? lightHighlightStyle : darkHighlightStyle}
language={match ? match[1] : undefined}
PreTag="div"
>
{String(children).replace(/\n$/, "")}
</SyntaxHighlighter>
</>
);
},
}}
>
{markdown}
</ReactMarkdown>
);
}
@nbarrow-inspire-labs very cool! that looks the same as my implementation.
One note - often you would want the code to be inline, I think that use case was not handled in the code above.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks you so much