@churchapps/apphelper-markdown
Version:
ChurchApps markdown/lexical editor components
86 lines (85 loc) • 5.59 kB
JavaScript
"use client";
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
import React, { useCallback, useMemo } from "react";
import "./editor.css";
import { LexicalComposer } from "@lexical/react/LexicalComposer";
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 { AutoFocusPlugin } from "@lexical/react/LexicalAutoFocusPlugin";
import { LexicalErrorBoundary } from "@lexical/react/LexicalErrorBoundary";
import { ListPlugin } from "@lexical/react/LexicalListPlugin";
import { MarkdownShortcutPlugin } from "@lexical/react/LexicalMarkdownShortcutPlugin";
import { TRANSFORMERS, $convertToMarkdownString, $convertFromMarkdownString } from "@lexical/markdown";
import { HeadingNode, QuoteNode } from "@lexical/rich-text";
import { ListItemNode, ListNode } from "@lexical/list";
import { TableCellNode, TableNode, TableRowNode } from "@lexical/table";
import { AutoLinkNode, LinkNode } from "@lexical/link";
import { CodeHighlightNode, CodeNode } from "@lexical/code";
import { theme } from "./theme";
import { ToolbarPlugin, CustomAutoLinkPlugin, ListMaxIndentLevelPlugin, PLAYGROUND_TRANSFORMERS, ReadOnlyPlugin, ControlledEditorPlugin } from "./plugins";
import FloatingTextFormatToolbarPlugin from "./plugins/FloatingTextMenu/FloatingTextFormatToolbarPlugin";
import { MarkdownModal } from "./MarkdownModal";
import CustomLinkNodePlugin from "./plugins/customLink/CustomLinkNodePlugin";
import { CustomLinkNode } from "./plugins/customLink/CustomLinkNode";
import EmojisPlugin from "./plugins/emoji/EmojisPlugin";
import { EmojiNode } from "./plugins/emoji/EmojiNode";
import EmojiPickerPlugin from "./plugins/emoji/EmojiPickerPlugin";
function Editor({ value, onChange = () => { }, mode = "interactive", textAlign = "left", style, placeholder = "Enter some text...", showFloatingEditor = false, ...props }) {
const [fullScreen, setFullScreen] = React.useState(false);
const handleChange = useCallback((editorState) => {
editorState.read(() => {
const markdown = $convertToMarkdownString(PLAYGROUND_TRANSFORMERS);
onChange(markdown);
});
}, [onChange]);
const onError = useCallback((error) => {
console.error(error);
}, []);
const handleModalOnChange = useCallback((value) => {
onChange(value);
}, [onChange]);
const handleCloseFullScreen = useCallback(() => {
setFullScreen(false);
}, []);
const initialConfig = useMemo(() => ({
editorState: () => $convertFromMarkdownString(value, PLAYGROUND_TRANSFORMERS),
namespace: "editor",
theme,
onError,
nodes: [
HeadingNode,
ListNode,
ListItemNode,
QuoteNode,
CodeNode,
CodeHighlightNode,
TableNode,
TableCellNode,
TableRowNode,
AutoLinkNode,
LinkNode,
CustomLinkNode,
EmojiNode,
{
replace: LinkNode,
with: (node) => (new CustomLinkNode(node.getURL(), node.getTarget(), []))
},
],
markdown: { transformers: PLAYGROUND_TRANSFORMERS }
}), [value, onError]);
const textAlignClass = useMemo(() => {
switch (textAlign) {
case "center":
return "text-center";
case "right":
return "text-right";
case "left":
default:
return "text-left";
}
}, [textAlign]);
return (_jsxs(_Fragment, { children: [_jsx(LexicalComposer, { initialConfig: initialConfig, children: _jsxs("div", { id: "markdown-editor-container", className: mode === "preview" ? `editor-container preview ${textAlignClass}` : `editor-container ${textAlignClass}`, style: useMemo(() => Object.assign({ border: mode === "preview" ? "none" : "1px solid lightgray" }, style), [mode, style]), children: [mode !== "preview" && (_jsx(ToolbarPlugin, { goFullScreen: useCallback(() => { setFullScreen(true); }, []) })), _jsxs("div", { id: "markdown-editor-inner", className: "editor-inner", children: [!fullScreen && (_jsx(RichTextPlugin, { contentEditable: _jsx(ContentEditable, { id: "markdown-editor-content", className: "editor-input", style: { minHeight: mode === "preview" ? "auto" : "150px" }, "data-element": JSON.stringify(props.element) }), placeholder: mode !== "preview" ? (_jsx("div", { id: "markdown-editor-placeholder", className: "editor-placeholder", children: placeholder })) : null, ErrorBoundary: LexicalErrorBoundary })), _jsx(CustomLinkNodePlugin, {}), mode !== "preview" && _jsx(EmojiPickerPlugin, {}), _jsx(EmojisPlugin, {}), showFloatingEditor && _jsx(FloatingTextFormatToolbarPlugin, {}), _jsx(OnChangePlugin, { onChange: handleChange }), mode !== "preview" && _jsx(AutoFocusPlugin, {}), _jsx(HistoryPlugin, {}), _jsx(ListPlugin, {}), _jsx(CustomAutoLinkPlugin, {}), _jsx(ListMaxIndentLevelPlugin, { maxDepth: 7 }), _jsx(ReadOnlyPlugin, { isDisabled: mode === "preview" }), _jsx(ControlledEditorPlugin, { isFullscreen: fullScreen, value: value, isPreview: mode === "preview" }), _jsx(MarkdownShortcutPlugin, { transformers: TRANSFORMERS })] })] }) }), fullScreen && (_jsx(MarkdownModal, { onChange: handleModalOnChange, value: value, hideModal: handleCloseFullScreen }))] }));
}
export default Editor;