tiptap: add toolbar for flow

This commit is contained in:
fantasticit 2022-05-11 21:15:20 +08:00
parent cd894ef446
commit 9cd1a06f53
2 changed files with 69 additions and 9 deletions

View File

@ -71370,8 +71370,11 @@ GraphViewer.prototype.init = function (b, c, e) {
null != c && null != c &&
((this.xmlDocument = c.ownerDocument), (this.xmlNode = c), (this.xml = mxUtils.getXml(c)), null != b) ((this.xmlDocument = c.ownerDocument), (this.xmlNode = c), (this.xml = mxUtils.getXml(c)), null != b)
) { ) {
var self = this;
var f = mxUtils.bind(this, function () { var f = mxUtils.bind(this, function () {
this.graph = new Graph(b); const graph = new Graph(b);
this.graph = graph;
self.graph = graph;
this.graph.enableFlowAnimation = !0; this.graph.enableFlowAnimation = !0;
this.graph.defaultPageBackgroundColor = 'transparent'; this.graph.defaultPageBackgroundColor = 'transparent';
this.graph.transparentBackground = !1; this.graph.transparentBackground = !1;

View File

@ -1,5 +1,7 @@
import { NodeViewWrapper } from '@tiptap/react'; import { NodeViewWrapper } from '@tiptap/react';
import cls from 'classnames'; import cls from 'classnames';
import { Button, Space } from '@douyinfe/semi-ui';
import { IconMindCenter, IconZoomOut, IconZoomIn } from 'components/icons';
import { useCallback, useEffect, useMemo, useRef } from 'react'; import { useCallback, useEffect, useMemo, useRef } from 'react';
import { Resizeable } from 'components/resizeable'; import { Resizeable } from 'components/resizeable';
import { getEditorContainerDOMSize } from 'tiptap/prose-utils'; import { getEditorContainerDOMSize } from 'tiptap/prose-utils';
@ -7,27 +9,51 @@ import { Flow } from 'tiptap/core/extensions/flow';
import styles from './index.module.scss'; import styles from './index.module.scss';
const INHERIT_SIZE_STYLE = { width: '100%', height: '100%', maxWidth: '100%', overflow: 'hidden', padding: '1rem' }; const INHERIT_SIZE_STYLE = { width: '100%', height: '100%', maxWidth: '100%', overflow: 'hidden', padding: '1rem' };
const ICON_STYLE = { fontSize: '0.85em' };
export const FlowWrapper = ({ editor, node, updateAttributes }) => { export const FlowWrapper = ({ editor, node, updateAttributes }) => {
const isEditable = editor.isEditable; const isEditable = editor.isEditable;
const isActive = editor.isActive(Flow.name); const isActive = editor.isActive(Flow.name);
const { width: maxWidth } = getEditorContainerDOMSize(editor); const { width: maxWidth } = getEditorContainerDOMSize(editor);
const { data, width, height } = node.attrs; const { data, width, height } = node.attrs;
const $viewer = useRef(null);
const $container = useRef<HTMLElement>(); const $container = useRef<HTMLElement>();
const graphData = useMemo(() => { const graphData = useMemo(() => {
const content = data.replace(/<!--.*?-->/gs, '').trim(); const content = data.replace(/<!--.*?-->/gs, '').trim();
const config = JSON.stringify({ const config = JSON.stringify({
highlight: '#00afff', 'lightbox': false,
lightbox: false, 'nav': false,
nav: false, 'resize': true,
resize: true, 'xml': content,
xml: content, 'zoom': 1,
zoom: 0.8, 'auto-fit': true,
'allow-zoom-in': true,
'allow-zoom-out': true,
'forceCenter': true,
}); });
return config; return config;
}, [data]); }, [data]);
const center = useCallback(() => {
const graph = $viewer.current && $viewer.current.graph;
if (!graph) return;
graph.fit();
graph.center(true, false);
}, []);
const zoomOut = useCallback(() => {
const graph = $viewer.current && $viewer.current.graph;
if (!graph) return;
graph.zoomOut();
}, []);
const zoomIn = useCallback(() => {
const graph = $viewer.current && $viewer.current.graph;
if (!graph) return;
graph.zoomIn();
}, []);
const onResize = useCallback( const onResize = useCallback(
(size) => { (size) => {
updateAttributes({ width: size.width, height: size.height }); updateAttributes({ width: size.width, height: size.height });
@ -37,11 +63,14 @@ export const FlowWrapper = ({ editor, node, updateAttributes }) => {
const render = useCallback((div) => { const render = useCallback((div) => {
if (!div) return; if (!div) return;
// @ts-ignore // @ts-ignore
const DrawioViewer = window.GraphViewer; const DrawioViewer = window.GraphViewer;
if (DrawioViewer) { if (DrawioViewer) {
div.innerHTML = ''; div.innerHTML = '';
DrawioViewer.createViewerForElement(div); DrawioViewer.createViewerForElement(div, (viewer) => {
$viewer.current = viewer;
});
} }
}, []); }, []);
@ -61,7 +90,35 @@ export const FlowWrapper = ({ editor, node, updateAttributes }) => {
<NodeViewWrapper className={cls(styles.wrap, isActive && styles.isActive)}> <NodeViewWrapper className={cls(styles.wrap, isActive && styles.isActive)}>
<Resizeable isEditable={isEditable} width={width} height={height} maxWidth={maxWidth} onChangeEnd={onResize}> <Resizeable isEditable={isEditable} width={width} height={height} maxWidth={maxWidth} onChangeEnd={onResize}>
<div className={cls(styles.renderWrap, 'render-wrapper')} style={INHERIT_SIZE_STYLE}> <div className={cls(styles.renderWrap, 'render-wrapper')} style={INHERIT_SIZE_STYLE}>
<div className="mxgraph" ref={setMxgraph} data-mxgraph={graphData}></div> <div className="mxgraph" style={{ width, height }} ref={setMxgraph} data-mxgraph={graphData}></div>
</div>
<div className={styles.toolbarWrap}>
<Space spacing={2}>
<Button
type="tertiary"
theme="borderless"
size="small"
onClick={center}
icon={<IconMindCenter style={ICON_STYLE} />}
/>
<Button
type="tertiary"
theme="borderless"
size="small"
onClick={zoomOut}
icon={<IconZoomOut style={ICON_STYLE} />}
/>
<Button
type="tertiary"
theme="borderless"
size="small"
onClick={zoomIn}
icon={<IconZoomIn style={ICON_STYLE} />}
/>
</Space>
</div> </div>
</Resizeable> </Resizeable>
</NodeViewWrapper> </NodeViewWrapper>