/* eslint-disable react-hooks/rules-of-hooks */ import MarkdownKatex from "@traptitech/markdown-it-katex"; import MarkdownSpoilers from "@traptitech/markdown-it-spoiler"; import "katex/dist/katex.min.css"; import MarkdownIt from "markdown-it"; // @ts-expect-error No typings. import MarkdownEmoji from "markdown-it-emoji/dist/markdown-it-emoji-bare"; // @ts-expect-error No typings. import MarkdownSub from "markdown-it-sub"; // @ts-expect-error No typings. import MarkdownSup from "markdown-it-sup"; import Prism from "prismjs"; import "prismjs/themes/prism-tomorrow.css"; import { RE_MENTIONS } from "revolt.js"; import styles from "./Markdown.module.scss"; import { useCallback, useContext } from "preact/hooks"; import { internalEmit } from "../../lib/eventEmitter"; import { determineLink } from "../../lib/links"; import { useIntermediate } from "../../context/intermediate/Intermediate"; import { AppContext } from "../../context/revoltjs/RevoltClient"; import { generateEmoji } from "../common/Emoji"; import { emojiDictionary } from "../../assets/emojis"; import { MarkdownProps } from "./Markdown"; // TODO: global.d.ts file for defining globals declare global { interface Window { copycode: (element: HTMLDivElement) => void; } } // Handler for code block copy. if (typeof window !== "undefined") { window.copycode = function (element: HTMLDivElement) { try { const code = element.parentElement?.parentElement?.children[1]; if (code) { navigator.clipboard.writeText(code.textContent?.trim() ?? ""); } } catch (e) {} }; } export const md: MarkdownIt = MarkdownIt({ breaks: true, linkify: true, highlight: (str, lang) => { const v = Prism.languages[lang]; if (v) { const out = Prism.highlight(str, v, lang); return `
`; } return `${lang}${out}
${md.utils.escapeHtml(
str,
)}`;
},
})
.disable("image")
.use(MarkdownEmoji, { defs: emojiDictionary })
.use(MarkdownSpoilers)
.use(MarkdownSup)
.use(MarkdownSub)
.use(MarkdownKatex, {
throwOnError: false,
maxExpand: 0,
maxSize: 10,
strict: false,
errorColor: "var(--error)",
});
// TODO: global.d.ts file for defining globals
declare global {
interface Window {
internalHandleURL: (element: HTMLAnchorElement) => void;
}
}
// Include emojis.
md.renderer.rules.emoji = function (token, idx) {
return generateEmoji(token[idx].content);
};
// Force line breaks.
// https://github.com/markdown-it/markdown-it/issues/211#issuecomment-508380611
const defaultParagraphRenderer =
md.renderer.rules.paragraph_open ||
((tokens, idx, options, env, self) =>
self.renderToken(tokens, idx, options));
md.renderer.rules.paragraph_open = function (tokens, idx, options, env, self) {
let result = "";
if (idx > 1) {
const inline = tokens[idx - 2];
const paragraph = tokens[idx];
if (
inline.type === "inline" &&
inline.map &&
inline.map[1] &&
paragraph.map &&
paragraph.map[0]
) {
const diff = paragraph.map[0] - inline.map[1];
if (diff > 0) {
result = "