"use client"; import { useEffect, useState } from "react"; import { useEditor, EditorContent } from "@tiptap/react"; import StarterKit from "@tiptap/starter-kit"; import Placeholder from "@tiptap/extension-placeholder"; import { Markdown } from "tiptap-markdown"; import { Bold, Code, Heading2, Heading3, Italic, List, ListOrdered } from "lucide-react"; import { cn } from "@/lib/utils"; type Props = { value: string; onChange: (v: string) => void; placeholder?: string; className?: string; }; const mdClasses = "[&_strong]:font-bold [&_em]:italic [&_code]:rounded [&_code]:bg-muted [&_code]:px-1 [&_code]:text-[0.85em] [&_h2]:text-base [&_h2]:font-bold [&_h2]:mt-3 [&_h3]:text-sm [&_h3]:font-bold [&_h3]:mt-2 [&_ul]:list-disc [&_ul]:pr-5 [&_ol]:list-decimal [&_ol]:pr-5 [&_li]:mt-0.5 [&_p]:leading-relaxed [&_p+p]:mt-2 [&_a]:underline [&_a]:text-primary"; export function RichEditor({ value, onChange, placeholder, className }: Props) { const [tab, setTab] = useState<"edit" | "preview">("edit"); const [preview, setPreview] = useState(""); const editor = useEditor({ extensions: [ StarterKit.configure({ codeBlock: false }), Placeholder.configure({ placeholder: placeholder ?? "توضیحات را اینجا بنویسید…" }), Markdown.configure({ transformPastedText: true }), ], content: value, immediatelyRender: false, onUpdate({ editor: e }) { // eslint-disable-next-line @typescript-eslint/no-explicit-any const md = (e.storage as any).markdown?.getMarkdown?.() ?? e.getText(); onChange(md); }, }); useEffect(() => { if (!editor) return; // eslint-disable-next-line @typescript-eslint/no-explicit-any const current = (editor.storage as any).markdown?.getMarkdown?.() ?? editor.getText(); if (current !== value) { editor.commands.setContent(value, { emitUpdate: false }); } }, [value, editor]); useEffect(() => { if (tab !== "preview") return; let cancelled = false; void (async () => { const { marked } = await import("marked"); const DOMPurify = (await import("dompurify")).default; const html = await marked(value); if (!cancelled) setPreview(DOMPurify.sanitize(html)); })(); return () => { cancelled = true; }; }, [tab, value]); const ToolBtn = ({ onClick, active, title, children, }: { onClick: () => void; active?: boolean; title: string; children: React.ReactNode; }) => ( ); return (