diff --git a/apps/admin/src/components/EditorShell.tsx b/apps/admin/src/components/EditorShell.tsx index 4de5238..653dbff 100644 --- a/apps/admin/src/components/EditorShell.tsx +++ b/apps/admin/src/components/EditorShell.tsx @@ -1,4 +1,4 @@ -import { Box, Button, Stack, TextField, Typography } from '@mui/material'; +import { Box, Button, Stack, Typography } from '@mui/material'; import AdminLayout from '../layout/AdminLayout'; import Recorder from '../features/recorder/Recorder'; import RichEditor from './RichEditor'; diff --git a/apps/admin/src/components/RichEditor.tsx b/apps/admin/src/components/RichEditor.tsx index 19e70fa..3fac8ea 100644 --- a/apps/admin/src/components/RichEditor.tsx +++ b/apps/admin/src/components/RichEditor.tsx @@ -1,4 +1,4 @@ -import { useEffect } from 'react'; +import { forwardRef, useEffect, useImperativeHandle } from 'react'; import { EditorContent, useEditor } from '@tiptap/react'; import StarterKit from '@tiptap/starter-kit'; import Link from '@tiptap/extension-link'; @@ -6,38 +6,39 @@ import Placeholder from '@tiptap/extension-placeholder'; import Image from '@tiptap/extension-image'; import { Button, Stack } from '@mui/material'; -export default function RichEditor({ - value, - onChange, - placeholder, -}: { +export type RichEditorHandle = { + insertImage: (src: string, alt?: string) => void; +}; + +type Props = { value: string; onChange: (html: string) => void; placeholder?: string; -}) { +}; + +const RichEditor = forwardRef(({ value, onChange, placeholder }, ref) => { const editor = useEditor({ extensions: [ StarterKit, Link.configure({ openOnClick: true }), - Placeholder.configure({ placeholder: placeholder || 'Write something…' }), + Placeholder.configure({ placeholder: placeholder ?? 'Write something…' }), Image.configure({ inline: false, allowBase64: false }), ], - content: value || '', - onUpdate: ({ editor }) => { - const html = editor.getHTML(); - onChange(html); - }, - editorProps: { - attributes: { - class: 'tiptap-content', - }, - }, + content: value ?? '', + onUpdate: ({ editor }) => onChange(editor.getHTML()), + editorProps: { attributes: { class: 'tiptap-content' } }, }); - // keep external value in sync if it changes (basic) + useImperativeHandle(ref, () => ({ + insertImage: (src: string, alt?: string) => { + if (!editor) return; + editor.chain().focus().setImage({ src, alt }).run(); + }, + }), [editor]); + useEffect(() => { if (editor && value !== editor.getHTML()) { - editor.commands.setContent(value || '', { emitUpdate: false }); + editor.commands.setContent(value ?? '', { emitUpdate: false }); } }, [value, editor]); @@ -45,34 +46,27 @@ export default function RichEditor({
); -} +}); + +export default RichEditor;