diff --git a/packages/client/src/tiptap/prose-utils/index.ts b/packages/client/src/tiptap/prose-utils/index.ts index 117fd34e..67f4a1be 100644 --- a/packages/client/src/tiptap/prose-utils/index.ts +++ b/packages/client/src/tiptap/prose-utils/index.ts @@ -19,3 +19,4 @@ export * from './text'; export * from './type'; export * from './upload'; export * from './url'; +export * from './uuid'; diff --git a/packages/client/src/tiptap/prose-utils/node.ts b/packages/client/src/tiptap/prose-utils/node.ts index 81687f4b..b994a178 100644 --- a/packages/client/src/tiptap/prose-utils/node.ts +++ b/packages/client/src/tiptap/prose-utils/node.ts @@ -41,6 +41,7 @@ export function isInCustomNode(state: EditorState, nodeName: string): boolean { return true; } } + return false; } export function isInCodeBlock(state: EditorState): boolean { diff --git a/packages/client/src/tiptap/styles/index.scss b/packages/client/src/tiptap/styles/index.scss index ac8bb5a3..11e2e51a 100644 --- a/packages/client/src/tiptap/styles/index.scss +++ b/packages/client/src/tiptap/styles/index.scss @@ -15,4 +15,4 @@ @import './selection.scss'; @import './table.scss'; @import './title.scss'; -@import './kityminder.scss'; +@import './mind/index.scss'; diff --git a/packages/client/src/tiptap/wrappers/mind/index.tsx b/packages/client/src/tiptap/wrappers/mind/index.tsx index 71b930f0..8e239db2 100644 --- a/packages/client/src/tiptap/wrappers/mind/index.tsx +++ b/packages/client/src/tiptap/wrappers/mind/index.tsx @@ -2,14 +2,10 @@ import { NodeViewWrapper } from '@tiptap/react'; import cls from 'classnames'; import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { Spin, Typography } from '@douyinfe/semi-ui'; -import deepEqual from 'deep-equal'; import { Resizeable } from 'components/resizeable'; import { useToggle } from 'hooks/use-toggle'; -import { clamp, getEditorContainerDOMSize } from 'tiptap/prose-utils'; +import { getEditorContainerDOMSize, uuid } from 'tiptap/prose-utils'; import { Mind } from 'tiptap/extensions/mind'; -import { loadKityMinder } from './kityminder'; -import { Toolbar } from './toolbar'; -import { MIN_ZOOM, MAX_ZOOM, ZOOM_STEP } from './toolbar/constant'; import styles from './index.module.scss'; const { Text } = Typography; @@ -17,12 +13,13 @@ const { Text } = Typography; const INHERIT_SIZE_STYLE = { width: '100%', height: '100%' }; export const MindWrapper = ({ editor, node, updateAttributes }) => { - const $container = useRef(); - const $mind = useRef(); + const $container = useRef(); + const $mind = useRef(null); + const containerId = useRef(`js-mind-container-${uuid()}`); const isEditable = editor.isEditable; const isActive = editor.isActive(Mind.name); const { width: maxWidth } = getEditorContainerDOMSize(editor); - const { data, template, theme, zoom, width, height } = node.attrs; + const { data, width, height } = node.attrs; const [loading, toggleLoading] = useToggle(true); const [error, setError] = useState(null); @@ -42,9 +39,10 @@ export const MindWrapper = ({ editor, node, updateAttributes }) => { return (
); }, [loading, error, width, height]); @@ -52,68 +50,19 @@ export const MindWrapper = ({ editor, node, updateAttributes }) => { const onResize = useCallback( (size) => { updateAttributes({ width: size.width, height: size.height }); - setCenter(); + setTimeout(() => { + $mind.current && $mind.current.toCenter(); + }); }, [updateAttributes] ); - const setZoom = useCallback( - (type: 'minus' | 'plus') => { - return () => { - const minder = $mind.current; - if (!minder) return; - const currentZoom = minder.getZoomValue(); - const nextZoom = clamp( - type === 'minus' ? currentZoom - ZOOM_STEP : currentZoom + ZOOM_STEP, - MIN_ZOOM, - MAX_ZOOM - ); - minder.execCommand('zoom', nextZoom); - isEditable && updateAttributes({ zoom: nextZoom }); - }; - }, - [editor, zoom, isEditable, updateAttributes] - ); - - const setCenter = useCallback(() => { - const minder = $mind.current; - if (!minder) return; - minder.execCommand('camera'); - }, []); - - // 布局 - const setTemplate = useCallback( - (template) => { - const minder = $mind.current; - if (!minder) return; - minder.execCommand('template', template); - isEditable && updateAttributes({ template }); - }, - [updateAttributes, isEditable] - ); - - // 主题 - const setTheme = useCallback( - (theme) => { - const minder = $mind.current; - if (!minder) return; - minder.execCommand('theme', theme); - isEditable && updateAttributes({ theme }); - }, - [updateAttributes, isEditable] - ); - - const saveData = useCallback(() => { - const minder = $mind.current; - if (!minder) return; - isEditable && updateAttributes({ data: minder.exportJson() }); - }, [updateAttributes, isEditable]); - // 加载依赖 useEffect(() => { - loadKityMinder() - .then(() => { + import('./mind-elixir') + .then((module) => { toggleLoading(false); + window.MindElixir = module.default; }) .catch((e) => { setError(e); @@ -125,104 +74,45 @@ export const MindWrapper = ({ editor, node, updateAttributes }) => { if (loading || !$container.current) return; const onChange = () => { - saveData(); + updateAttributes({ data: mind.getAllData() }); }; + let mind = null; + try { - const Editor = window.kityminder.Editor; - const minder = new Editor($container.current).minder; - minder.importJson(data); - minder.execCommand('template', template); - minder.execCommand('theme', theme); - minder.execCommand('zoom', parseInt(zoom)); - - if (!isEditable) { - minder.preventEdit = true; - } else { - minder.preventEdit = false; - minder.enable(); - } - - $mind.current = minder; - minder.on('contentChange', onChange); + mind = new window.MindElixir({ + el: `#${containerId.current}`, + direction: window.MindElixir.SIDE, + data: JSON.parse(JSON.stringify(data)), + editable: editor.isEditable, + draggable: editor.isEditable, + contextMenu: editor.isEditable, + toolBar: true, + keypress: editor.isEditable, + nodeMenu: true, + locale: 'zh_CN', + }); + mind.shouldPreventDefault = () => editor.isActive('mind'); + mind.init(); + mind.bus.addListener('operation', onChange); + $mind.current = mind; toggleLoading(false); } catch (e) { setError(e); } return () => { - if ($mind.current) { - $mind.current.off('contentChange', onChange); - $mind.current.destroy(); + if (mind) { + mind.bus.removeListener('operation', onChange); } }; - }, [loading]); - - // 数据同步渲染 - useEffect(() => { - const minder = $mind.current; - if (!minder) return; - - const currentData = minder.exportJson(); - const isEqual = deepEqual(currentData, data); - if (isEqual) return; - // TODO: 也许刷新更好些 - minder.importJson(data); - }, [data]); - - // 启用/禁用 - useEffect(() => { - const minder = $mind.current; - if (!minder) return; - - if (!isEditable) { - minder.preventEdit = true; - } else { - minder.preventEdit = false; - minder.enable(); - } - }, [isEditable]); - - // 缩放 - useEffect(() => { - const minder = $mind.current; - if (!minder) return; - minder.execCommand('zoom', parseInt(zoom)); - }, [zoom]); - - // 布局 - useEffect(() => { - const minder = $mind.current; - if (!minder) return; - minder.execCommand('template', template); - }, [template]); - - // 主题 - useEffect(() => { - const minder = $mind.current; - if (!minder) return; - minder.execCommand('theme', theme); - }, [theme]); + }, [loading, editor, updateAttributes]); return ( {content} -
- -
); };