import sanitizeHtml from "sanitize-html"; import type { JSONContent } from "@tiptap/react"; import { generateHTML } from "@tiptap/html"; import StarterKit from "@tiptap/starter-kit"; import Underline from "@tiptap/extension-underline"; import Link from "@tiptap/extension-link"; import { TextStyle } from "@tiptap/extension-text-style"; import Color from "@tiptap/extension-color"; import Highlight from "@tiptap/extension-highlight"; import { FontFamily } from "@/lib/tiptap/fontFamily"; export function richTextToSafeHtml(doc: JSONContent): string { const raw = generateHTML(doc, [ StarterKit, Underline, Link.configure({ openOnClick: false, autolink: false, HTMLAttributes: { rel: "noopener noreferrer", target: "_blank" }, }), TextStyle, FontFamily, Color, Highlight, ]); return sanitizeHtml(raw, { allowedTags: [ "p", "br", "h1", "h2", "h3", "blockquote", "strong", "em", "u", "a", "ul", "ol", "li", "code", "pre", "span" ], allowedAttributes: { a: ["href", "rel", "target"], span: ["style"], code: ["class"], pre: ["class"], p: ["class"], h1: ["class"], h2: ["class"], h3: ["class"], blockquote: ["class"], ul: ["class"], ol: ["class"], li: ["class"] }, allowedSchemes: ["http", "https", "mailto"], allowProtocolRelative: false, allowedStyles: { span: { color: [/^#[0-9a-fA-F]{3,8}$/], "background-color": [/^#[0-9a-fA-F]{3,8}$/], "font-family": [/^(Inter|ui-sans-serif|ui-serif|ui-monospace)$/], }, }, }); }