'use client'; /** * TipTap 기반 WYSIWYG 에디터 */ import { useEditor, EditorContent } from '@tiptap/react'; import { useEffect } from 'react'; import { getEditorExtensions } from './extensions'; import { MenuBar } from './MenuBar'; import { cn } from '@/lib/utils'; interface RichTextEditorProps { value: string; onChange: (value: string) => void; placeholder?: string; onImageUpload?: (file: File) => Promise; className?: string; disabled?: boolean; minHeight?: string; } export function RichTextEditor({ value, onChange, placeholder = '내용을 입력해주세요', onImageUpload, className, disabled = false, minHeight = '200px', }: RichTextEditorProps) { const editor = useEditor({ extensions: getEditorExtensions(placeholder), content: value, editable: !disabled, immediatelyRender: false, // SSR hydration mismatch 방지 onUpdate: ({ editor }) => { onChange(editor.getHTML()); }, editorProps: { attributes: { class: cn( 'prose prose-sm max-w-none focus:outline-none', 'px-4 py-3', disabled && 'opacity-50 cursor-not-allowed' ), style: `min-height: ${minHeight}`, }, }, }); // 외부에서 value가 변경될 때 에디터 업데이트 useEffect(() => { if (editor && value !== editor.getHTML()) { editor.commands.setContent(value); } }, [editor, value]); // disabled 상태 변경 시 반영 useEffect(() => { if (editor) { editor.setEditable(!disabled); } }, [editor, disabled]); return (
{!disabled && }
); } export default RichTextEditor;