diff --git a/package-lock.json b/package-lock.json
index 46c3439..518ad1b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -25,6 +25,7 @@
"@electron-forge/maker-rpm": "^6.0.4",
"@electron-forge/maker-squirrel": "^6.0.4",
"@electron-forge/maker-zip": "^6.0.4",
+ "@excalidraw/excalidraw": "^0.17.0",
"@lexical/react": "^0.12.6",
"@reduxjs/toolkit": "^1.9.3",
"@testing-library/jest-dom": "^5.16.5",
@@ -4071,6 +4072,16 @@
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}
},
+ "node_modules/@excalidraw/excalidraw": {
+ "version": "0.17.3",
+ "resolved": "https://registry.npmmirror.com/@excalidraw/excalidraw/-/excalidraw-0.17.3.tgz",
+ "integrity": "sha512-t+0sR30AboKcINt0WUJmSAC1cJy6npO37j/zONvuWvSh6XDOGoL1E0L+WYKJMBzp4wnOQhRIghQJmdfktQlO8w==",
+ "dev": true,
+ "peerDependencies": {
+ "react": "^17.0.2 || ^18.2.0",
+ "react-dom": "^17.0.2 || ^18.2.0"
+ }
+ },
"node_modules/@gar/promisify": {
"version": "1.1.3",
"resolved": "https://registry.npmmirror.com/@gar/promisify/-/promisify-1.1.3.tgz",
diff --git a/package.json b/package.json
index 8bdd4f5..11c6f81 100644
--- a/package.json
+++ b/package.json
@@ -8,6 +8,7 @@
"devDependencies": {
"@ant-design/pro-components": "^2.3.57",
"@craco/craco": "^6.0.0",
+ "@excalidraw/excalidraw": "^0.17.0",
"@electron-forge/cli": "^6.0.4",
"@electron-forge/maker-deb": "^6.0.4",
"@electron-forge/maker-rpm": "^6.0.4",
diff --git a/src/pages/Note/Hlexical/index.jsx b/src/pages/Note/Hlexical/index.jsx
index 048f450..56da82e 100644
--- a/src/pages/Note/Hlexical/index.jsx
+++ b/src/pages/Note/Hlexical/index.jsx
@@ -30,6 +30,7 @@ import {HorizontalRulePlugin} from "@lexical/react/LexicalHorizontalRulePlugin"
import InlineImagePlugin from "./plugins/InlineImagePlugin";
import {TablePlugin} from "@lexical/react/LexicalTablePlugin";
import TableCellActionMenuPlugin from './plugins/TableActionMenuPlugin';
+import ExcalidrawPlugin from "./plugins/ExcalidrawPlugin";
function Placeholder() {
return
Enter some rich text...
;
}
@@ -80,8 +81,6 @@ export default function Hlexical(props) {
/>
{/* 表格单元格操作 */}
-
-
{/*markdown 快捷键*/}
@@ -94,13 +93,9 @@ export default function Hlexical(props) {
{/*页分割线*/}
{/*目录加载*/}
- {/* 表格加载 */}
- {/**/}
- {/**/}
- {/* {(tableOfContentsArray) => {*/}
- {/* return ;*/}
- {/* }}*/}
- {/**/}
+
+ {/* 画图 */}
+
diff --git a/src/pages/Note/Hlexical/nodes/ExcalidrawNode/ExcalidrawComponent.jsx b/src/pages/Note/Hlexical/nodes/ExcalidrawNode/ExcalidrawComponent.jsx
new file mode 100644
index 0000000..4d4cadd
--- /dev/null
+++ b/src/pages/Note/Hlexical/nodes/ExcalidrawNode/ExcalidrawComponent.jsx
@@ -0,0 +1,222 @@
+import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
+import {useLexicalNodeSelection} from '@lexical/react/useLexicalNodeSelection';
+import {mergeRegister} from '@lexical/utils';
+import {
+ $getNodeByKey,
+ $getSelection,
+ $isNodeSelection,
+ CLICK_COMMAND,
+ COMMAND_PRIORITY_LOW,
+ KEY_BACKSPACE_COMMAND,
+ KEY_DELETE_COMMAND,
+} from 'lexical';
+import {useCallback, useEffect, useMemo, useRef, useState} from 'react';
+import * as React from 'react';
+
+import ImageResizer from '../../plugins/Input/ImageResizer';
+import {$isExcalidrawNode} from '.';
+import ExcalidrawImage from './ExcalidrawImage';
+import ExcalidrawModal from './ExcalidrawModal';
+
+export default function ExcalidrawComponent({
+ nodeKey,
+ data,
+}) {
+ const [editor] = useLexicalComposerContext();
+ const [isModalOpen, setModalOpen] = useState (
+ data === '[]' && editor.isEditable(),
+ );
+ const imageContainerRef = useRef(null);
+ const buttonRef = useRef(null);
+ const captionButtonRef = useRef(null);
+ const [isSelected, setSelected, clearSelection] =
+ useLexicalNodeSelection(nodeKey);
+ const [isResizing, setIsResizing] = useState(false);
+
+ const onDelete = useCallback(
+ (event) => {
+ if (isSelected && $isNodeSelection($getSelection())) {
+ event.preventDefault();
+ editor.update(() => {
+ const node = $getNodeByKey(nodeKey);
+ if ($isExcalidrawNode(node)) {
+ node.remove();
+ }
+ });
+ }
+ return false;
+ },
+ [editor, isSelected, nodeKey],
+ );
+
+ // Set editor to readOnly if excalidraw is open to prevent unwanted changes
+ useEffect(() => {
+ if (isModalOpen) {
+ editor.setEditable(false);
+ } else {
+ editor.setEditable(true);
+ }
+ }, [isModalOpen, editor]);
+
+ useEffect(() => {
+ return mergeRegister(
+ editor.registerCommand(
+ CLICK_COMMAND,
+ (event) => {
+ const buttonElem = buttonRef.current;
+ const eventTarget = event.target;
+
+ if (isResizing) {
+ return true;
+ }
+
+ if (buttonElem !== null && buttonElem.contains(eventTarget)) {
+ if (!event.shiftKey) {
+ clearSelection();
+ }
+ setSelected(!isSelected);
+ if (event.detail > 1) {
+ setModalOpen(true);
+ }
+ return true;
+ }
+
+ return false;
+ },
+ COMMAND_PRIORITY_LOW,
+ ),
+ editor.registerCommand(
+ KEY_DELETE_COMMAND,
+ onDelete,
+ COMMAND_PRIORITY_LOW,
+ ),
+ editor.registerCommand(
+ KEY_BACKSPACE_COMMAND,
+ onDelete,
+ COMMAND_PRIORITY_LOW,
+ ),
+ );
+ }, [clearSelection, editor, isSelected, isResizing, onDelete, setSelected]);
+
+ const deleteNode = useCallback(() => {
+ setModalOpen(false);
+ return editor.update(() => {
+ const node = $getNodeByKey(nodeKey);
+ if ($isExcalidrawNode(node)) {
+ node.remove();
+ }
+ });
+ }, [editor, nodeKey]);
+
+ const setData = (
+ els,
+ aps,
+ fls,
+ ) => {
+ if (!editor.isEditable()) {
+ return;
+ }
+ return editor.update(() => {
+ const node = $getNodeByKey(nodeKey);
+ if ($isExcalidrawNode(node)) {
+ if (els.length > 0 || Object.keys(fls).length > 0) {
+ node.setData(
+ JSON.stringify({
+ appState: aps,
+ elements: els,
+ files: fls,
+ }),
+ );
+ } else {
+ node.remove();
+ }
+ }
+ });
+ };
+
+ const onResizeStart = () => {
+ setIsResizing(true);
+ };
+
+ const onResizeEnd = (
+ nextWidth,
+ nextHeight,
+ ) => {
+ // Delay hiding the resize bars for click case
+ setTimeout(() => {
+ setIsResizing(false);
+ }, 200);
+
+ editor.update(() => {
+ const node = $getNodeByKey(nodeKey);
+
+ if ($isExcalidrawNode(node)) {
+ node.setWidth(nextWidth);
+ node.setHeight(nextHeight);
+ }
+ });
+ };
+
+ const openModal = useCallback(() => {
+ setModalOpen(true);
+ }, []);
+
+ const {
+ elements = [],
+ files = {},
+ appState = {},
+ } = useMemo(() => JSON.parse(data), [data]);
+
+ return (
+ <>
+ setModalOpen(false)}
+ onSave={(els, aps, fls) => {
+ editor.setEditable(true);
+ setData(els, aps, fls);
+ setModalOpen(false);
+ }}
+ closeOnClickOutside={false}
+ />
+ {elements.length > 0 && (
+