All files / app/components MarkdownNoSSR.tsx

100% Statements 18/18
100% Branches 4/4
100% Functions 4/4
100% Lines 16/16

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 8012x   12x 12x 12x 12x 12x                 224x                                                           12x           224x 224x 224x 136x   136x   136x                     136x         136x          
import "@toast-ui/editor/dist/toastui-editor-viewer.css";
 
import { styled } from "@mui/styles";
import ToastUIEditorViewer from "@toast-ui/editor/dist/toastui-editor-viewer";
import { increaseMarkdownHeaderLevel } from "components/Markdown";
import { useEffect, useRef } from "react";
import { escapeRegExp } from "utils/escapeRegExp";
 
interface MarkdownProps {
  className?: string;
  source: string;
  topHeaderLevel?: number;
  allowImages?: "none" | "couchers";
}
 
const StyledRoot = styled("div")(({ theme }) => ({
  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 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 <StyledRoot className={className} ref={rootEl} />;
}