@churchapps/apphelper-markdown
Version:
ChurchApps markdown/lexical editor components
89 lines (88 loc) • 5.74 kB
JavaScript
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 })] }))] })] }) }));
}