"use client" import { useEffect } from "react" import { useEditor, EditorContent } from "@tiptap/react" import StarterKit from "@tiptap/starter-kit" import Link from "@tiptap/extension-link" import Placeholder from "@tiptap/extension-placeholder" import { cn } from "@/lib/utils" import sanitize from "sanitize-html" import { Button } from "@/components/ui/button" import { Separator } from "@/components/ui/separator" import { Bold, Italic, Strikethrough, List, ListOrdered, Quote, Undo, Redo, Link as LinkIcon, } from "lucide-react" type RichTextEditorProps = { value?: string onChange?: (html: string) => void className?: string placeholder?: string disabled?: boolean minHeight?: number } export function RichTextEditor({ value, onChange, className, placeholder = "Escreva aqui...", disabled, minHeight = 120, }: RichTextEditorProps) { const editor = useEditor({ extensions: [ StarterKit.configure({ bulletList: { keepMarks: true }, orderedList: { keepMarks: true }, }), Link.configure({ openOnClick: true, autolink: true, protocols: ["http", "https", "mailto"], HTMLAttributes: { rel: "noopener noreferrer", target: "_blank" }, }), Placeholder.configure({ placeholder }), ], editorProps: { attributes: { class: "prose prose-sm max-w-none focus:outline-none text-foreground", }, }, content: value || "", onUpdate({ editor }) { onChange?.(editor.getHTML()) }, editable: !disabled, // Avoid SSR hydration mismatches per Tiptap recommendation immediatelyRender: false, }) // Keep external value in sync when it changes useEffect(() => { if (!editor) return const current = editor.getHTML() if ((value ?? "") !== current) { editor.commands.setContent(value || "", { emitUpdate: false }) } }, [value, editor]) if (!editor) return null return (