mirror of https://github.com/fantasticit/think.git
tiptap: enhance mind
parent
59b2965b79
commit
337c3d172a
|
@ -0,0 +1,14 @@
|
||||||
|
import { Icon } from '@douyinfe/semi-ui';
|
||||||
|
|
||||||
|
export const IconStructure: React.FC<{ style?: React.CSSProperties }> = ({ style = {} }) => {
|
||||||
|
return (
|
||||||
|
<Icon
|
||||||
|
style={style}
|
||||||
|
svg={
|
||||||
|
<svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" width="1em" height="1em">
|
||||||
|
<path d="M896 645.888V608C896 519.808 824.256 448 736 448H512V384h32c52.928 0 96-43.072 96-96v-128C640 107.072 596.928 64 544 64h-128C363.072 64 320 107.072 320 160v128C320 340.928 363.072 384 416 384H448v64H224A160.192 160.192 0 0 0 64 608v37.888c-37.184 13.248-64 48.448-64 90.112v128c0 52.928 43.072 96 96 96h64c52.928 0 96-43.072 96-96v-128c0-52.928-43.072-96-96-96H128v-32C128 555.072 171.072 512 224 512H448v128h-32c-52.928 0-96 43.072-96 96v128c0 52.928 43.072 96 96 96h128c52.928 0 96-43.072 96-96v-128c0-52.928-43.072-96-96-96H512V512h224c52.928 0 96 43.072 96 96v32h-32c-52.928 0-96 43.072-96 96v128c0 52.928 43.072 96 96 96h64c52.928 0 96-43.072 96-96v-128c0-41.664-26.816-76.864-64-90.112zM384 288v-128a32 32 0 0 1 32-32h128a32 32 0 0 1 32 32v128a32 32 0 0 1-32 32h-128a32 32 0 0 1-32-32z m-192 448v128a32 32 0 0 1-32 32h-64a32 32 0 0 1-32-32v-128a32 32 0 0 1 32-32h64a32 32 0 0 1 32 32z m384 0v128a32 32 0 0 1-32 32h-128a32 32 0 0 1-32-32v-128a32 32 0 0 1 32-32h128a32 32 0 0 1 32 32z m320 128c0 17.6-14.4 32-32 32h-64a32.064 32.064 0 0 1-32-32v-128c0-17.6 14.4-32 32-32h64c17.6 0 32 14.4 32 32v128z"></path>
|
||||||
|
</svg>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
|
@ -51,3 +51,4 @@ export * from './IconGlobe';
|
||||||
export * from './IconCountdown';
|
export * from './IconCountdown';
|
||||||
export * from './IconDrawBoard';
|
export * from './IconDrawBoard';
|
||||||
export * from './IconCallout';
|
export * from './IconCallout';
|
||||||
|
export * from './IconStructure';
|
||||||
|
|
|
@ -6,7 +6,7 @@ import { getDatasetAttribute } from '../utils/dataset';
|
||||||
const DEFAULT_MIND_DATA = {
|
const DEFAULT_MIND_DATA = {
|
||||||
root: { data: { text: '中心节点' }, children: [] },
|
root: { data: { text: '中心节点' }, children: [] },
|
||||||
template: 'default',
|
template: 'default',
|
||||||
theme: 'fresh-blue',
|
theme: 'classic',
|
||||||
version: '1.4.43',
|
version: '1.4.43',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -39,6 +39,18 @@ export const Mind = Node.create({
|
||||||
default: DEFAULT_MIND_DATA,
|
default: DEFAULT_MIND_DATA,
|
||||||
parseHTML: getDatasetAttribute('data', true),
|
parseHTML: getDatasetAttribute('data', true),
|
||||||
},
|
},
|
||||||
|
template: {
|
||||||
|
default: 'default',
|
||||||
|
parseHTML: getDatasetAttribute('template'),
|
||||||
|
},
|
||||||
|
theme: {
|
||||||
|
default: 'classic',
|
||||||
|
parseHTML: getDatasetAttribute('theme'),
|
||||||
|
},
|
||||||
|
zoom: {
|
||||||
|
default: 100,
|
||||||
|
parseHTML: getDatasetAttribute('zoom'),
|
||||||
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
.sectionWrap {
|
||||||
|
margin-top: 16px;
|
||||||
|
|
||||||
|
> div {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
margin-top: 8px;
|
||||||
|
width: 168px;
|
||||||
|
|
||||||
|
ul {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
list-style: none;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
|
||||||
|
li {
|
||||||
|
width: 80px;
|
||||||
|
height: 30px;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 30px;
|
||||||
|
padding: 0 5px;
|
||||||
|
font-size: 12px;
|
||||||
|
cursor: pointer;
|
||||||
|
text-decoration: none;
|
||||||
|
border: 1px solid rgb(28 31 35 / 8%);
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
border: 1px solid rgb(0 101 255);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:nth-of-type(2n) {
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:nth-of-type(n + 3) {
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,18 +1,63 @@
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
import { Space, Button, List, Popover, Typography } from '@douyinfe/semi-ui';
|
import cls from 'classnames';
|
||||||
|
import { Space, Button, List, Popover, Typography, RadioGroup, Radio } from '@douyinfe/semi-ui';
|
||||||
import { IconEdit, IconDelete } from '@douyinfe/semi-icons';
|
import { IconEdit, IconDelete } from '@douyinfe/semi-icons';
|
||||||
import { Tooltip } from 'components/tooltip';
|
import { Tooltip } from 'components/tooltip';
|
||||||
import { DataRender } from 'components/data-render';
|
import { IconStructure, IconDrawBoard, IconZoomIn, IconZoomOut } from 'components/icons';
|
||||||
import { IconDocument } from 'components/icons';
|
|
||||||
import { useWikiTocs } from 'data/wiki';
|
|
||||||
import { BubbleMenu } from '../../views/bubble-menu';
|
import { BubbleMenu } from '../../views/bubble-menu';
|
||||||
import { Mind } from '../../extensions/mind';
|
import { Mind } from '../../extensions/mind';
|
||||||
import { Divider } from '../../divider';
|
import { Divider } from '../../divider';
|
||||||
|
import { clamp } from '../../utils/clamp';
|
||||||
|
import { TEMPLATES, THEMES, MAX_ZOOM, MIN_ZOOM, ZOOM_STEP } from './constant';
|
||||||
|
import styles from './bubble.module.scss';
|
||||||
|
|
||||||
const { Text } = Typography;
|
const { Text } = Typography;
|
||||||
|
|
||||||
export const MindBubbleMenu = ({ editor }) => {
|
export const MindBubbleMenu = ({ editor }) => {
|
||||||
|
const { template, theme, zoom } = editor.getAttributes(Mind.name);
|
||||||
|
|
||||||
|
const setZoom = useCallback(
|
||||||
|
(type: 'minus' | 'plus') => {
|
||||||
|
return () => {
|
||||||
|
editor
|
||||||
|
.chain()
|
||||||
|
.updateAttributes(Mind.name, {
|
||||||
|
zoom: clamp(type === 'minus' ? parseInt(zoom) - ZOOM_STEP : parseInt(zoom) + ZOOM_STEP, MIN_ZOOM, MAX_ZOOM),
|
||||||
|
})
|
||||||
|
.focus()
|
||||||
|
.run();
|
||||||
|
};
|
||||||
|
},
|
||||||
|
[editor, zoom]
|
||||||
|
);
|
||||||
|
|
||||||
|
const setTemplate = useCallback(
|
||||||
|
(template) => {
|
||||||
|
editor
|
||||||
|
.chain()
|
||||||
|
.updateAttributes(Mind.name, {
|
||||||
|
template,
|
||||||
|
})
|
||||||
|
.focus()
|
||||||
|
.run();
|
||||||
|
},
|
||||||
|
[editor]
|
||||||
|
);
|
||||||
|
|
||||||
|
const setTheme = useCallback(
|
||||||
|
(theme) => {
|
||||||
|
editor
|
||||||
|
.chain()
|
||||||
|
.updateAttributes(Mind.name, {
|
||||||
|
theme,
|
||||||
|
})
|
||||||
|
.focus()
|
||||||
|
.run();
|
||||||
|
},
|
||||||
|
[editor]
|
||||||
|
);
|
||||||
|
|
||||||
const deleteNode = useCallback(() => editor.chain().deleteSelection().run(), [editor]);
|
const deleteNode = useCallback(() => editor.chain().deleteSelection().run(), [editor]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -24,6 +69,82 @@ export const MindBubbleMenu = ({ editor }) => {
|
||||||
tippyOptions={{ maxWidth: 'calc(100vw - 100px)' }}
|
tippyOptions={{ maxWidth: 'calc(100vw - 100px)' }}
|
||||||
>
|
>
|
||||||
<Space>
|
<Space>
|
||||||
|
<Tooltip content="缩小">
|
||||||
|
<Button
|
||||||
|
size="small"
|
||||||
|
type="tertiary"
|
||||||
|
theme="borderless"
|
||||||
|
disabled={+zoom <= MIN_ZOOM}
|
||||||
|
icon={<IconZoomOut />}
|
||||||
|
onClick={setZoom('minus')}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
<Text style={{ width: 20, textAlign: 'center' }}>{zoom}</Text>
|
||||||
|
<Tooltip content="放大">
|
||||||
|
<Button
|
||||||
|
size="small"
|
||||||
|
type="tertiary"
|
||||||
|
theme="borderless"
|
||||||
|
disabled={+zoom >= MAX_ZOOM}
|
||||||
|
icon={<IconZoomIn />}
|
||||||
|
onClick={setZoom('plus')}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
|
||||||
|
<Popover
|
||||||
|
zIndex={10000}
|
||||||
|
spacing={10}
|
||||||
|
style={{ padding: '0 12px 12px', overflow: 'hidden' }}
|
||||||
|
content={
|
||||||
|
<section className={styles.sectionWrap}>
|
||||||
|
<Text type="secondary">布局</Text>
|
||||||
|
<div>
|
||||||
|
<ul>
|
||||||
|
{TEMPLATES.map((item) => {
|
||||||
|
return (
|
||||||
|
<li
|
||||||
|
className={cls(template === item.value && styles.active)}
|
||||||
|
onClick={() => setTemplate(item.value)}
|
||||||
|
>
|
||||||
|
{item.label}
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Button icon={<IconStructure />} type="tertiary" theme="borderless" size="small" />
|
||||||
|
</Popover>
|
||||||
|
|
||||||
|
<Popover
|
||||||
|
zIndex={10000}
|
||||||
|
spacing={10}
|
||||||
|
style={{ padding: '0 12px 12px', overflow: 'hidden' }}
|
||||||
|
content={
|
||||||
|
<section className={styles.sectionWrap}>
|
||||||
|
<Text type="secondary">主题</Text>
|
||||||
|
<div>
|
||||||
|
<ul>
|
||||||
|
{THEMES.map((item) => {
|
||||||
|
return (
|
||||||
|
<li
|
||||||
|
className={cls(theme === item.value && styles.active)}
|
||||||
|
style={item.style || {}}
|
||||||
|
onClick={() => setTheme(item.value)}
|
||||||
|
>
|
||||||
|
{item.label}
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Button icon={<IconDrawBoard />} type="tertiary" theme="borderless" size="small" />
|
||||||
|
</Popover>
|
||||||
<Divider />
|
<Divider />
|
||||||
<Tooltip content="删除节点" hideOnClick>
|
<Tooltip content="删除节点" hideOnClick>
|
||||||
<Button onClick={deleteNode} icon={<IconDelete />} type="tertiary" theme="borderless" size="small" />
|
<Button onClick={deleteNode} icon={<IconDelete />} type="tertiary" theme="borderless" size="small" />
|
||||||
|
|
|
@ -0,0 +1,113 @@
|
||||||
|
export const TEMPLATES = [
|
||||||
|
{
|
||||||
|
label: '经典',
|
||||||
|
value: 'default',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '文件夹',
|
||||||
|
value: 'filetree',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '鱼骨图',
|
||||||
|
value: 'fish-bone',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '靠右',
|
||||||
|
value: 'right',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '组织',
|
||||||
|
value: 'structure',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '天盘',
|
||||||
|
value: 'tianpan',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export const THEMES = [
|
||||||
|
{
|
||||||
|
label: '经典',
|
||||||
|
value: 'classic',
|
||||||
|
style: {
|
||||||
|
color: 'rgb(68, 51, 0)',
|
||||||
|
background: ' rgb(233, 223, 152)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '紧凑',
|
||||||
|
value: 'classic-compact',
|
||||||
|
style: {
|
||||||
|
color: 'rgb(68, 51, 0)',
|
||||||
|
background: ' rgb(233, 223, 152)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '清新红',
|
||||||
|
value: 'fresh-red',
|
||||||
|
style: {
|
||||||
|
color: 'white',
|
||||||
|
background: ' rgb(191, 115, 115)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '泥土黄',
|
||||||
|
value: 'fresh-soil',
|
||||||
|
style: {
|
||||||
|
color: 'white',
|
||||||
|
background: 'rgb(191, 147, 115)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '文艺绿',
|
||||||
|
value: 'fresh-green',
|
||||||
|
style: {
|
||||||
|
color: 'white',
|
||||||
|
background: 'rgb(115, 191, 118)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '天空蓝',
|
||||||
|
value: 'fresh-blue',
|
||||||
|
style: {
|
||||||
|
color: 'white',
|
||||||
|
background: 'rgb(115, 161, 191)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '浪漫紫',
|
||||||
|
value: 'fresh-purple',
|
||||||
|
style: {
|
||||||
|
color: 'white',
|
||||||
|
background: 'rgb(123, 115, 191)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '胭脂粉',
|
||||||
|
value: 'fresh-pink',
|
||||||
|
style: {
|
||||||
|
color: 'white',
|
||||||
|
background: 'rgb(191, 115, 148)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '冷光',
|
||||||
|
value: 'snow',
|
||||||
|
style: {
|
||||||
|
color: '#fff',
|
||||||
|
background: 'rgb(164, 197, 192)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '鱼骨图',
|
||||||
|
value: 'fish',
|
||||||
|
style: {
|
||||||
|
color: '#fff',
|
||||||
|
background: 'rgb(58, 65, 68)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export const MIN_ZOOM = 10;
|
||||||
|
export const MAX_ZOOM = 200;
|
||||||
|
export const ZOOM_STEP = 15;
|
|
@ -3,11 +3,32 @@
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
line-height: 0;
|
line-height: 0;
|
||||||
outline: none;
|
|
||||||
|
|
||||||
.renderWrap {
|
.renderWrap {
|
||||||
|
border: 1px solid var(--node-border-color);
|
||||||
|
border-radius: var(--border-radius);
|
||||||
|
|
||||||
&::after {
|
&::after {
|
||||||
background-color: transparent !important;
|
background-color: transparent !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mindHandlerWrap {
|
||||||
|
position: absolute;
|
||||||
|
right: 20px;
|
||||||
|
bottom: 20px;
|
||||||
|
z-index: 1000;
|
||||||
|
padding: 4px 8px;
|
||||||
|
background-color: var(--semi-color-bg-2);
|
||||||
|
border: 1px solid var(--node-border-color);
|
||||||
|
border-radius: var(--border-radius);
|
||||||
|
opacity: 0;
|
||||||
|
box-shadow: var(--box-shadow);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.isActive {
|
||||||
|
.mindHandlerWrap {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
import { NodeViewWrapper } from '@tiptap/react';
|
import { NodeViewWrapper } from '@tiptap/react';
|
||||||
import cls from 'classnames';
|
import cls from 'classnames';
|
||||||
import { useCallback, useEffect, useRef } from 'react';
|
import { useCallback, useEffect, useRef } from 'react';
|
||||||
import { Button } from '@douyinfe/semi-ui';
|
import { Spin, Button } from '@douyinfe/semi-ui';
|
||||||
import { IconMinus, IconPlus } from '@douyinfe/semi-icons';
|
import { IconMinus, IconPlus } from '@douyinfe/semi-icons';
|
||||||
import { Resizeable } from 'components/resizeable';
|
import { Resizeable } from 'components/resizeable';
|
||||||
import deepEqual from 'deep-equal';
|
import deepEqual from 'deep-equal';
|
||||||
import { useToggle } from 'hooks/use-toggle';
|
import { useToggle } from 'hooks/use-toggle';
|
||||||
|
import { MIN_ZOOM, MAX_ZOOM, ZOOM_STEP } from '../../menus/mind/constant';
|
||||||
|
import { clamp } from '../../utils/clamp';
|
||||||
import { Mind } from '../../extensions/mind';
|
import { Mind } from '../../extensions/mind';
|
||||||
import { loadKityMinder } from './kityminder';
|
import { loadKityMinder } from './kityminder';
|
||||||
import styles from './index.module.scss';
|
import styles from './index.module.scss';
|
||||||
|
@ -15,7 +17,7 @@ export const MindWrapper = ({ editor, node, updateAttributes }) => {
|
||||||
const $mind = useRef<any>();
|
const $mind = useRef<any>();
|
||||||
const isMindActive = editor.isActive(Mind.name);
|
const isMindActive = editor.isActive(Mind.name);
|
||||||
const isEditable = editor.isEditable;
|
const isEditable = editor.isEditable;
|
||||||
const { data, width, height = 100 } = node.attrs;
|
const { data, template, theme, zoom, width, height = 100 } = node.attrs;
|
||||||
const [loading, toggleLoading] = useToggle(true);
|
const [loading, toggleLoading] = useToggle(true);
|
||||||
|
|
||||||
const onResize = useCallback(
|
const onResize = useCallback(
|
||||||
|
@ -25,6 +27,23 @@ export const MindWrapper = ({ editor, node, updateAttributes }) => {
|
||||||
[updateAttributes]
|
[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);
|
||||||
|
};
|
||||||
|
},
|
||||||
|
[editor, zoom]
|
||||||
|
);
|
||||||
|
|
||||||
const saveData = useCallback(() => {
|
const saveData = useCallback(() => {
|
||||||
const minder = $mind.current;
|
const minder = $mind.current;
|
||||||
if (!minder) return;
|
if (!minder) return;
|
||||||
|
@ -38,12 +57,15 @@ export const MindWrapper = ({ editor, node, updateAttributes }) => {
|
||||||
};
|
};
|
||||||
loadKityMinder().then((Editor) => {
|
loadKityMinder().then((Editor) => {
|
||||||
toggleLoading(false);
|
toggleLoading(false);
|
||||||
|
|
||||||
|
try {
|
||||||
const minder = new Editor($container.current).minder;
|
const minder = new Editor($container.current).minder;
|
||||||
minder.importJson(data);
|
minder.importJson(data);
|
||||||
$mind.current = minder;
|
$mind.current = minder;
|
||||||
minder.on('contentChange', onChange);
|
minder.on('contentChange', onChange);
|
||||||
// @ts-ignore
|
} catch (e) {
|
||||||
window.minder = minder;
|
//
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
|
@ -63,13 +85,42 @@ export const MindWrapper = ({ editor, node, updateAttributes }) => {
|
||||||
minder.importData(data);
|
minder.importData(data);
|
||||||
}, [data]);
|
}, [data]);
|
||||||
|
|
||||||
|
// 布局
|
||||||
|
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]);
|
||||||
|
|
||||||
|
// 缩放
|
||||||
|
useEffect(() => {
|
||||||
|
const minder = $mind.current;
|
||||||
|
if (!minder) return;
|
||||||
|
minder.execCommand('zoom', parseInt(zoom));
|
||||||
|
}, [zoom]);
|
||||||
|
|
||||||
// 启用/禁用
|
// 启用/禁用
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const minder = $mind.current;
|
const minder = $mind.current;
|
||||||
if (!minder) return;
|
if (!minder) return;
|
||||||
|
|
||||||
|
if (isEditable) {
|
||||||
|
minder.enable();
|
||||||
|
} else {
|
||||||
|
minder.disable();
|
||||||
|
}
|
||||||
}, [isEditable]);
|
}, [isEditable]);
|
||||||
|
|
||||||
const content = (
|
const content = loading ? (
|
||||||
|
<Spin spinning={loading} style={{ width: '100%', height: '100%' }}></Spin>
|
||||||
|
) : (
|
||||||
<div
|
<div
|
||||||
ref={$container}
|
ref={$container}
|
||||||
className={cls(styles.renderWrap, 'render-wrapper')}
|
className={cls(styles.renderWrap, 'render-wrapper')}
|
||||||
|
@ -87,6 +138,25 @@ export const MindWrapper = ({ editor, node, updateAttributes }) => {
|
||||||
) : (
|
) : (
|
||||||
<div style={{ display: 'inline-block', width, height, maxWidth: '100%' }}>{content}</div>
|
<div style={{ display: 'inline-block', width, height, maxWidth: '100%' }}>{content}</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{!isEditable && (
|
||||||
|
<div className={styles.mindHandlerWrap}>
|
||||||
|
<Button
|
||||||
|
size="small"
|
||||||
|
theme="borderless"
|
||||||
|
type="tertiary"
|
||||||
|
icon={<IconMinus style={{ fontSize: 14 }} />}
|
||||||
|
onClick={setZoom('minus')}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
size="small"
|
||||||
|
theme="borderless"
|
||||||
|
type="tertiary"
|
||||||
|
icon={<IconPlus style={{ fontSize: 14 }} />}
|
||||||
|
onClick={setZoom('plus')}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</NodeViewWrapper>
|
</NodeViewWrapper>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,7 +5,9 @@ define(function (require, exports, module) {
|
||||||
Minder.registerInitHook(function () {
|
Minder.registerInitHook(function () {
|
||||||
this.on('beforemousedown', function (e) {
|
this.on('beforemousedown', function (e) {
|
||||||
this.focus();
|
this.focus();
|
||||||
// e.preventDefault();
|
// FIXME:如果遇到事件触发问题,需要检查这里
|
||||||
|
if (e.kityEvent.targetShape.__KityClassName === 'Paper') return;
|
||||||
|
e.preventDefault();
|
||||||
});
|
});
|
||||||
this.on('paperrender', function () {
|
this.on('paperrender', function () {
|
||||||
this.focus();
|
this.focus();
|
||||||
|
|
Loading…
Reference in New Issue