"use client" import { useEffect } from "react" import { EditorContent, useEditor } from "@tiptap/react" import Placeholder from "@tiptap/extension-placeholder" import StarterKit from "@tiptap/starter-kit" import { BoldIcon, ItalicIcon, ListIcon, ListOrderedIcon, QuoteIcon, RedoIcon, UndoIcon, } from "lucide-react" import { EditorToolbar } from "./toolbar" import type { BaseEditorProps } from "./types" import { useI18n } from "@/i18n/provider" export type HtmlEditorProps = BaseEditorProps & { value: string onChange: (nextValue: string) => void } export function HtmlEditor({ value, onChange, placeholder, disabled = false, }: HtmlEditorProps) { const t = useI18n() const editorPlaceholder = placeholder ?? t("editor.placeholder") const editor = useEditor({ immediatelyRender: false, extensions: [ StarterKit.configure({ heading: { levels: [1, 2, 3], }, bulletList: { keepMarks: true, keepAttributes: false, }, orderedList: { keepMarks: true, keepAttributes: false, }, }), Placeholder.configure({ placeholder: editorPlaceholder, }), ], content: value, editable: !disabled, onUpdate: ({ editor }) => { onChange(editor.getHTML()) }, editorProps: { attributes: { class: "min-h-64 max-h-96 overflow-y-auto px-4 py-3 text-sm leading-7 text-slate-900 outline-none [&_.ProseMirror-focused]:outline-none [&_p]:m-0 [&_p]:mb-2 [&_h1]:text-2xl [&_h1]:font-bold [&_h1]:mb-3 [&_h2]:text-xl [&_h2]:font-semibold [&_h2]:mb-2 [&_h3]:text-lg [&_h3]:font-semibold [&_h3]:mb-2 [&_ul]:list-disc [&_ul]:pl-6 [&_ol]:list-decimal [&_ol]:pl-6 [&_li]:mb-1 [&_blockquote]:border-l-4 [&_blockquote]:border-muted-foreground [&_blockquote]:pl-4 [&_blockquote]:italic [&_blockquote]:text-muted-foreground", }, }, }) useEffect(() => { if (editor && value !== editor.getHTML()) { editor.commands.setContent(value) } }, [editor, value]) useEffect(() => { if (editor) { editor.setEditable(!disabled) } }, [disabled, editor]) if (!editor) { return null } const toolbarActions = [ { key: "undo", label: t("editor.undo"), icon: UndoIcon, disabled: !editor.can().undo() || disabled, onClick: () => editor.chain().focus().undo().run(), }, { key: "redo", label: t("editor.redo"), icon: RedoIcon, disabled: !editor.can().redo() || disabled, onClick: () => editor.chain().focus().redo().run(), }, { key: "separator-1", type: "separator" as const }, { key: "bold", label: t("editor.bold"), icon: BoldIcon, disabled, pressed: editor.isActive("bold"), onClick: () => editor.chain().focus().toggleBold().run(), }, { key: "italic", label: t("editor.italic"), icon: ItalicIcon, disabled, pressed: editor.isActive("italic"), onClick: () => editor.chain().focus().toggleItalic().run(), }, { key: "separator-2", type: "separator" as const }, { key: "bulletList", label: t("editor.bulletList"), icon: ListIcon, disabled, pressed: editor.isActive("bulletList"), onClick: () => editor.chain().focus().toggleBulletList().run(), }, { key: "orderedList", label: t("editor.orderedList"), icon: ListOrderedIcon, disabled, pressed: editor.isActive("orderedList"), onClick: () => editor.chain().focus().toggleOrderedList().run(), }, { key: "blockquote", label: t("editor.quote"), icon: QuoteIcon, disabled, pressed: editor.isActive("blockquote"), onClick: () => editor.chain().focus().toggleBlockquote().run(), }, ] as const return (