import ExampleTheme from "./themes/ExampleTheme"; 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 {AutoFocusPlugin} from "@lexical/react/LexicalAutoFocusPlugin"; import LexicalErrorBoundary from "@lexical/react/LexicalErrorBoundary"; import TreeViewPlugin from "./plugins/TreeViewPlugin"; import ToolbarPlugin from "./plugins/ToolbarPlugin"; import {HeadingNode, QuoteNode} from "@lexical/rich-text"; import {TableCellNode, TableNode, TableRowNode} from "@lexical/table"; import {ListItemNode, ListNode} from "@lexical/list"; import {CodeHighlightNode, CodeNode, $createCodeNode, $isCodeNode} from "@lexical/code"; import {AutoLinkNode, LinkNode} from "@lexical/link"; import {MarkdownShortcutPlugin} from "@lexical/react/LexicalMarkdownShortcutPlugin"; import { TRANSFORMERS, $convertFromMarkdownString, $convertToMarkdownString, } from "@lexical/markdown"; import "./index.less" import {useEffect, useId, useState} from 'react'; import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; import {importFile, overWriteFile, saveFileWithName} from "../../../utils/File" import {$getRoot, CLEAR_HISTORY_COMMAND, $createTextNode,} from "lexical"; import md5 from "md5" import {isEmpty} from "../../../utils/ObjectUtils"; import {useDispatch, useSelector} from "react-redux"; import {updatedSavedFile} from "../../../redux/tableBarItem_reducer"; import {ListPlugin} from "@lexical/react/LexicalListPlugin"; import {LinkPlugin} from "@lexical/react/LexicalLinkPlugin"; import AutoLinkPlugin from "./plugins/AutoLinkPlugin"; import ListMaxIndentLevelPlugin from "./plugins/ListMaxIndentLevelPlugin"; import CodeHighlightPlugin from "./plugins/CodeHighlightPlugin"; import {getFileNameByPath} from "../../../utils/PathOperate"; const {ipcRenderer} = window.require('electron') function Placeholder() { return
Enter some rich text...
; } const editorConfig = { // The editor theme theme: ExampleTheme, // Handling of errors during update onError(error) { throw error; }, // Any custom nodes go here nodes: [ HeadingNode, ListNode, ListItemNode, QuoteNode, CodeNode, CodeHighlightNode, TableNode, TableCellNode, TableRowNode, AutoLinkNode, LinkNode ] }; function OnChangePlugin({onChange}) { const [editor] = useLexicalComposerContext(); console.log('editor', editor) useEffect(() => { return editor.registerUpdateListener(({editorState}) => { onChange(editorState); }); }, [editor, onChange]); } function ImportFilePlugin(props) { const [editor] = useLexicalComposerContext(); useEffect(() => { if (props.filePath) { importFile(props.filePath).then(value => { if (isEmpty(value)) { return } if (props.filePath.endsWith(".md")) { const root = $getRoot(); const firstChild = root.getFirstChild(); if ($isCodeNode(firstChild) && firstChild.getLanguage() === 'markdown') { $convertFromMarkdownString( firstChild.getTextContent(), PLAYGROUND_TRANSFORMERS, ); } else { const markdown = $convertToMarkdownString(PLAYGROUND_TRANSFORMERS); root .clear() .append( $createCodeNode('markdown').append($createTextNode(markdown)), ); } root.selectEnd(); } else { const editorState = editor.parseEditorState( JSON.stringify(JSON.parse(value.toString()).editorState) ); editor.setEditorState(editorState); editor.dispatchCommand(CLEAR_HISTORY_COMMAND, undefined); } }).catch(error => console.error(error) ) } }, []) } // 从字符串化 JSON 设置编辑器状态 // const editorState = editor.parseEditorState(editorStateJSONString); // editor.setEditorState(editorState); export default function Hlexical(props) { console.log("Hlexical(props):this.props.filePath:", props.filePath) const [editorState, setEditorState] = useState(); const dispatch = useDispatch(); function onChange(editorState) { // Call toJSON on the EditorState object, which produces a serialization safe string const editorStateJSON = editorState.toJSON(); console.log('onChange-editorStateJSON') // However, we still have a JavaScript object, so we need to convert it to an actual string with JSON.stringify setEditorState(JSON.stringify(editorStateJSON)); } let pushHotKey = useSelector(state => state.pushHotkeys.data); let activeKey = useSelector(state => state.tableBarItem.activeKey); const saveFile = (event, args) => { console.log("event,args:", event, args) console.log("触发保存pushHotKey:", pushHotKey) if (pushHotKey !== "CTRL+S") { return } let filePath = props.filePath; if (filePath !== activeKey) { console.log("文件不同", filePath, activeKey) return; } console.log("触发保存filePath:", filePath) if (isEmpty(editorState)) { return } const editorStateSave = {"editorState": JSON.parse(editorState)}; let resultSave = JSON.stringify(editorStateSave); // 如果文件地址为空需要用户选择目录并设置文件。 if (!filePath) { let saveDialogReturnValuePromise = saveFileWithName(); console.log("saveDialogReturnValuePromise", saveDialogReturnValuePromise) saveDialogReturnValuePromise.then(result => { if (!result.canceled) { let fileKey = getFileNameByPath(result.filePath) if (isEmpty(fileKey)){ fileKey = fileKey+".lexical" } overWriteFile(fileKey, resultSave) // 修改当前文件名 dispatch(updatedSavedFile({filePath: result.filePath})) // 文件目录更新 dispatch() } }) return } importFile(filePath).then(value => { let save = (isEmpty(value)) || md5(resultSave) !== md5(JSON.stringify(JSON.parse(value.toString()))); if (save) { console.log("保存重写" + filePath) overWriteFile(filePath, resultSave) } }).catch(error => console.error(error) ) } useEffect(() => { ipcRenderer.on("pushHotkeys", saveFile); return () => { console.log("销毁取消监听"); ipcRenderer.removeListener("pushHotkeys", saveFile) }; } ) return (
{/* 富文本插件 */}
} placeholder={} ErrorBoundary={LexicalErrorBoundary} /> {/*黑窗口动态记录当前操作*/} {/**/} {/*markdown 快捷键*/} {/*文件操作导入文件*/} {/**/}
); }