All files / app/components MarkdownNoSSR.tsx

100% Statements 21/21
100% Branches 4/4
100% Functions 4/4
100% Lines 19/19

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 8513x   13x 13x 13x 13x 13x 13x                 47x                                                               13x           275x   275x 275x 275x 130x   130x   130x                     130x         130x     275x    
import "@toast-ui/editor/dist/toastui-editor-viewer.css";
 
import ToastUIEditorViewer from "@toast-ui/editor/dist/toastui-editor-viewer";
import classNames from "classnames";
import { increaseMarkdownHeaderLevel } from "components/Markdown";
import { useEffect, useRef } from "react";
import { escapeRegExp } from "utils/escapeRegExp";
import makeStyles from "utils/makeStyles";
 
interface MarkdownProps {
  className?: string;
  source: string;
  topHeaderLevel?: number;
  allowImages?: "none" | "couchers";
}
 
const useStyles = makeStyles((theme) => ({
  root: {
    fontSize: theme.typography.fontSize,
    fontFamily: theme.typography.fontFamily,
    "& h1, & h2, & h3, & h4, & h5, & h6, & p": {
      borderBottom: "none",
      paddingBottom: 0,
      marginBottom: 0,
      marginTop: theme.spacing(2),
      overflowWrap: "break-word",
    },
    "& h1": theme.typography.h1,
    "& h2": theme.typography.h2,
    "& h3": theme.typography.h3,
    "& h4": theme.typography.h4,
    "& h5": theme.typography.h5,
    "& h6": theme.typography.h6,
    "& p": theme.typography.body1,
    "& ol": theme.typography.body1,
    "& ul": theme.typography.body1,
    "& blockquote": theme.typography.body1,
    "& a": {
      color: theme.palette.primary.main,
    },
    "& img": {
      width: "100%",
      maxWidth: "400px",
      height: "auto",
    },
  },
}));
 
export default function Markdown({
  className,
  source,
  topHeaderLevel = 2,
  allowImages = "none",
}: MarkdownProps) {
  const classes = useStyles();
 
  const rootEl = useRef<HTMLDivElement>(null);
  const viewer = useRef<ToastUIEditorViewer>();
  useEffect(() => {
    let sanitizedSource = increaseMarkdownHeaderLevel(source, topHeaderLevel);
    //remove all html except <br>
    sanitizedSource = sanitizedSource.replace(/<(?!br)([^>]+)>/gi, "");
    //change images ![]() to links []()
    sanitizedSource = sanitizedSource.replace(
      allowImages === "couchers"
        ? new RegExp(
            `!(?=\\[.*]\\((?!${escapeRegExp(
              process.env.NEXT_PUBLIC_MEDIA_BASE_URL
            )}).*\\))`,
            "gi"
          )
        : /!(?=\[.*]\(.*\))/gi,
      ""
    );
    viewer.current = new ToastUIEditorViewer({
      el: rootEl.current!,
      initialValue: sanitizedSource,
      extendedAutolinks: true,
    });
    return () => viewer.current?.destroy();
  }, [source, topHeaderLevel, allowImages]);
 
  return <div className={classNames(className, classes.root)} ref={rootEl} />;
}