import { Extension } from "@tiptap/core"; const allowedFonts = [ "Inter", "ui-sans-serif", "ui-serif", "ui-monospace", ] as const; export type AllowedFontFamily = (typeof allowedFonts)[number]; declare module "@tiptap/core" { interface Commands { fontFamily: { setFontFamily: (fontFamily: string) => ReturnType; unsetFontFamily: () => ReturnType; }; } } export const FontFamily = Extension.create({ name: "fontFamily", addGlobalAttributes() { return [ { types: ["textStyle"], attributes: { fontFamily: { default: null, parseHTML: (element) => { const raw = (element as HTMLElement).style.fontFamily; if (!raw) return null; // Normalize: remove quotes and take first family only const first = raw.split(",")[0]?.trim().replace(/^["']|["']$/g, ""); if (!first) return null; return first; }, renderHTML: (attributes) => { const fontFamily = attributes.fontFamily as string | null; if (!fontFamily) return {}; if (!allowedFonts.includes(fontFamily as AllowedFontFamily)) return {}; return { style: `font-family: ${fontFamily}` }; }, }, }, }, ]; }, addCommands() { return { setFontFamily: (fontFamily: string) => ({ chain }) => { if (!allowedFonts.includes(fontFamily as AllowedFontFamily)) return false; return chain().setMark("textStyle", { fontFamily }).run(); }, unsetFontFamily: () => ({ chain }) => { return chain().setMark("textStyle", { fontFamily: null }).removeEmptyTextStyle().run(); }, }; }, });