'use client'; import { useState, useEffect } from 'react'; import { $getRoot, $getSelection, $createParagraphNode, $createTextNode, UNDO_COMMAND, REDO_COMMAND, FORMAT_TEXT_COMMAND } from 'lexical'; import { $generateHtmlFromNodes, $generateNodesFromDOM } from '@lexical/html'; import { LexicalComposer } from '@lexical/react/LexicalComposer'; import { PlainTextPlugin } from '@lexical/react/LexicalPlainTextPlugin'; import { RichTextPlugin } from '@lexical/react/LexicalRichTextPlugin'; import { ContentEditable } from '@lexical/react/LexicalContentEditable'; import { HistoryPlugin } from '@lexical/react/LexicalHistoryPlugin'; import { OnChangePlugin } from '@lexical/react/LexicalOnChangePlugin'; import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'; import { LexicalErrorBoundary } from '@lexical/react/LexicalErrorBoundary'; import { $createHeadingNode } from '@lexical/rich-text'; import { $createListNode, $createListItemNode } from '@lexical/list'; import { $createLinkNode } from '@lexical/link'; import { Box, Toolbar, IconButton, Divider, Select, MenuItem, FormControl } from '@mui/material'; import { FormatBold, FormatItalic, FormatUnderlined, FormatListBulleted, FormatListNumbered, Link, Image, Undo, Redo } from '@mui/icons-material'; const theme = { ltr: 'ltr', rtl: 'rtl', paragraph: 'editor-paragraph', quote: 'editor-quote', heading: { h1: 'editor-heading-h1', h2: 'editor-heading-h2', h3: 'editor-heading-h3', h4: 'editor-heading-h4', h5: 'editor-heading-h5', h6: 'editor-heading-h6', }, list: { nested: { listitem: 'editor-nested-listitem', }, ol: 'editor-list-ol', ul: 'editor-list-ul', listitem: 'editor-listitem', }, image: 'editor-image', link: 'editor-link', text: { bold: 'editor-text-bold', italic: 'editor-text-italic', overflowed: 'editor-text-overflowed', hashtag: 'editor-text-hashtag', underline: 'editor-text-underline', strikethrough: 'editor-text-strikethrough', underlineStrikethrough: 'editor-text-underlineStrikethrough', code: 'editor-text-code', }, code: 'editor-code', codeHighlight: { atrule: 'editor-tokenAttr', attr: 'editor-tokenAttr', boolean: 'editor-tokenProperty', builtin: 'editor-tokenSelector', cdata: 'editor-tokenComment', char: 'editor-tokenSelector', class: 'editor-tokenFunction', 'class-name': 'editor-tokenFunction', comment: 'editor-tokenComment', constant: 'editor-tokenProperty', deleted: 'editor-tokenProperty', doctype: 'editor-tokenComment', entity: 'editor-tokenOperator', function: 'editor-tokenFunction', important: 'editor-tokenVariable', inserted: 'editor-tokenSelector', keyword: 'editor-tokenAttr', namespace: 'editor-tokenVariable', number: 'editor-tokenProperty', operator: 'editor-tokenOperator', prolog: 'editor-tokenComment', property: 'editor-tokenProperty', punctuation: 'editor-tokenPunctuation', regex: 'editor-tokenVariable', selector: 'editor-tokenSelector', string: 'editor-tokenSelector', symbol: 'editor-tokenProperty', tag: 'editor-tokenProperty', url: 'editor-tokenOperator', variable: 'editor-tokenVariable', }, }; interface LexicalEditorProps { value: string; onChange: (value: string) => void; height?: number; } function ToolbarPlugin() { const [editor] = useLexicalComposerContext(); const [headingType, setHeadingType] = useState('paragraph'); const formatText = (format: 'bold' | 'italic' | 'underline') => { editor.dispatchCommand(FORMAT_TEXT_COMMAND, format); }; const insertHeading = (headingType: string) => { editor.update(() => { const selection = $getSelection(); if (selection) { if (headingType === 'paragraph') { const paragraph = $createParagraphNode(); selection.insertNodes([paragraph]); } else { const heading = $createHeadingNode(headingType as any); selection.insertNodes([heading]); } } }); }; return ( formatText('bold')} size="small"> formatText('italic')} size="small"> formatText('underline')} size="small"> editor.dispatchCommand(UNDO_COMMAND, undefined)} size="small" > editor.dispatchCommand(REDO_COMMAND, undefined)} size="small" > ); } function OnChangeHandler({ onChange }: { onChange: (value: string) => void }) { const [editor] = useLexicalComposerContext(); const handleChange = () => { editor.update(() => { const htmlString = $generateHtmlFromNodes(editor, null); onChange(htmlString); }); }; return ; } function InitialContentPlugin({ content }: { content: string }) { const [editor] = useLexicalComposerContext(); useEffect(() => { if (content) { editor.update(() => { const parser = new DOMParser(); const dom = parser.parseFromString(content, 'text/html'); const nodes = $generateNodesFromDOM(editor, dom); const root = $getRoot(); root.clear(); root.append(...nodes); }); } }, [editor, content]); return null; } export function LexicalEditor({ value, onChange, height = 400 }: LexicalEditorProps) { const initialConfig = { namespace: 'MyEditor', theme, onError: (error: Error) => { console.error('Lexical error:', error); }, }; return ( } placeholder={
Start writing your content...
} ErrorBoundary={LexicalErrorBoundary} />
); }