UNPKG

@churchapps/apphelper-markdown

Version:

ChurchApps markdown/lexical editor components

89 lines (88 loc) 5.74 kB
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime"; import { useEffect, useState } from "react"; import { $generateHtmlFromNodes } from "@lexical/html"; import { LexicalComposer } from "@lexical/react/LexicalComposer"; import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext"; import { ContentEditable } from "@lexical/react/LexicalContentEditable"; import { HistoryPlugin } from "@lexical/react/LexicalHistoryPlugin"; import { RichTextPlugin } from "@lexical/react/LexicalRichTextPlugin"; import { AutoFocusPlugin } from "@lexical/react/LexicalAutoFocusPlugin"; import { LexicalErrorBoundary } from "@lexical/react/LexicalErrorBoundary"; import { ListPlugin } from "@lexical/react/LexicalListPlugin"; // import { CheckListPlugin } from '@lexical/react/LexicalCheckListPlugin'; // Checklist removed import { TabIndentationPlugin } from "@lexical/react/LexicalTabIndentationPlugin"; // import { TablePlugin } from '@lexical/react/LexicalTablePlugin'; // Table removed import { HorizontalRulePlugin } from "@lexical/react/LexicalHorizontalRulePlugin"; // import { CodeHighlightPlugin } from '@lexical/react/LexicalCodeHighlightPlugin'; import { ListNode, ListItemNode } from "@lexical/list"; import { HeadingNode, QuoteNode } from "@lexical/rich-text"; import { CodeNode, CodeHighlightNode } from "@lexical/code"; // import { TableNode, TableCellNode, TableRowNode } from '@lexical/table'; // Table nodes removed import { HorizontalRuleNode } from "@lexical/react/LexicalHorizontalRuleNode"; import { LinkNode } from "@lexical/link"; import { AutoLinkNode } from "@lexical/link"; import HtmlToolbarPlugin from "./plugins/HtmlToolbarPlugin"; import FloatingTextFormatToolbarPlugin from "./plugins/FloatingTextFormatToolbarPlugin"; import FloatingLinkEditorPlugin from "./plugins/FloatingLinkEditorPlugin"; import AutoLinkPlugin from "./plugins/AutoLinkPlugin"; import ListMaxIndentLevelPlugin from "./plugins/ListMaxIndentLevelPlugin"; import ReadOnlyPlugin from "./plugins/ReadOnlyPlugin"; import ControlledEditorPlugin from "./plugins/ControlledEditorPlugin"; import HtmlSourcePlugin from "./plugins/HtmlSourcePlugin"; import theme from "./theme"; import "./editor.css"; import { cleanHtml } from "./utils/cleanHtml"; import CustomLinkNodePlugin from "./plugins/customLink/CustomLinkNodePlugin"; import { CustomLinkNode } from "./plugins/customLink/CustomLinkNode"; // Plugin to handle HTML generation on editor changes function HtmlOnChangePlugin({ onChange }) { const [editor] = useLexicalComposerContext(); useEffect(() => { if (!onChange) return; return editor.registerUpdateListener(({ editorState }) => { editor.update(() => { const rawHtml = $generateHtmlFromNodes(editor); const cleanedHtml = cleanHtml(rawHtml); onChange(cleanedHtml); }); }); }, [editor, onChange]); return null; } export default function HtmlEditorInner({ value, onChange, style, placeholder = "Start typing...", readOnly = false }) { const [floatingAnchorElem, setFloatingAnchorElem] = useState(null); const [isLinkEditMode, setIsLinkEditMode] = useState(false); const [isSourceMode, setIsSourceMode] = useState(false); const onRef = (_floatingAnchorElem) => { if (_floatingAnchorElem !== null) { setFloatingAnchorElem(_floatingAnchorElem); } }; const initialConfig = { namespace: "HtmlEditor", theme, onError: (error) => { console.error(error); }, nodes: [ HeadingNode, ListNode, ListItemNode, QuoteNode, CodeNode, CodeHighlightNode, // TableNode, TableCellNode, TableRowNode, // Table nodes removed HorizontalRuleNode, LinkNode, AutoLinkNode, CustomLinkNode, { replace: LinkNode, with: (node) => (new CustomLinkNode(node.getURL(), node.getTarget(), [])) } ], editorState: undefined }; return (_jsx(LexicalComposer, { initialConfig: initialConfig, children: _jsxs("div", { className: "editor-container", style: style, children: [_jsx(HtmlToolbarPlugin, { setIsLinkEditMode: setIsLinkEditMode, isSourceMode: isSourceMode, setIsSourceMode: setIsSourceMode }), _jsxs("div", { className: "editor-inner", style: { position: "relative", minHeight: "150px" }, children: [_jsx(RichTextPlugin, { contentEditable: _jsx("div", { className: "editor-scroller", style: { display: isSourceMode ? "none" : "block" }, children: _jsx("div", { className: "editor", ref: onRef, children: _jsx(ContentEditable, { className: "editor-input" }) }) }), placeholder: _jsx("div", { className: "editor-placeholder", style: { display: isSourceMode ? "none" : "block" }, children: placeholder }), ErrorBoundary: LexicalErrorBoundary }), _jsx(HtmlOnChangePlugin, { onChange: onChange }), _jsx(HistoryPlugin, {}), _jsx(AutoFocusPlugin, {}), _jsx(ListPlugin, {}), _jsx(TabIndentationPlugin, {}), _jsx(HorizontalRulePlugin, {}), _jsx(AutoLinkPlugin, {}), _jsx(ListMaxIndentLevelPlugin, { maxDepth: 7 }), readOnly && _jsx(ReadOnlyPlugin, { readOnly: readOnly }), _jsx(ControlledEditorPlugin, { value: value }), _jsx(HtmlSourcePlugin, { isSourceMode: isSourceMode }), _jsx(CustomLinkNodePlugin, {}), floatingAnchorElem && !isSourceMode && (_jsxs(_Fragment, { children: [_jsx(FloatingTextFormatToolbarPlugin, { anchorElem: floatingAnchorElem }), _jsx(FloatingLinkEditorPlugin, { anchorElem: floatingAnchorElem, isLinkEditMode: isLinkEditMode, setIsLinkEditMode: setIsLinkEditMode })] }))] })] }) })); }