tiptap: add createUserId

fix/tiptap
fantasticit 2022-08-19 18:39:48 +08:00
parent acd266acc0
commit 3bd5d1180c
7 changed files with 70 additions and 32 deletions

View File

@ -12,6 +12,11 @@ export interface IFlowAttrs {
createUser?: IUser['id']; createUser?: IUser['id'];
} }
interface IFlowOptions {
HTMLAttributes: Record<string, any>;
getCreateUserId: () => string | number;
}
declare module '@tiptap/core' { declare module '@tiptap/core' {
interface Commands<ReturnType> { interface Commands<ReturnType> {
flow: { flow: {
@ -20,7 +25,7 @@ declare module '@tiptap/core' {
} }
} }
export const Flow = Node.create({ export const Flow = Node.create<IFlowOptions>({
name: 'flow', name: 'flow',
group: 'block', group: 'block',
selectable: true, selectable: true,
@ -55,6 +60,7 @@ export const Flow = Node.create({
HTMLAttributes: { HTMLAttributes: {
class: 'flow', class: 'flow',
}, },
getCreateUserId: () => null,
}; };
}, },
@ -105,7 +111,7 @@ export const Flow = Node.create({
find: /^\$flow $/, find: /^\$flow $/,
type: this.type, type: this.type,
getAttributes: () => { getAttributes: () => {
return { width: '100%' }; return { width: '100%', defaultShowPicker: true, createUser: this.options.getCreateUserId() };
}, },
}), }),
]; ];

View File

@ -10,6 +10,11 @@ export type IKatexAttrs = {
createUser?: IUser['id']; createUser?: IUser['id'];
}; };
interface IKatexOptions {
HTMLAttributes: Record<string, any>;
getCreateUserId: () => string | number;
}
declare module '@tiptap/core' { declare module '@tiptap/core' {
interface Commands<ReturnType> { interface Commands<ReturnType> {
katex: { katex: {
@ -18,7 +23,7 @@ declare module '@tiptap/core' {
} }
} }
export const Katex = Node.create({ export const Katex = Node.create<IKatexOptions>({
name: 'katex', name: 'katex',
group: 'block', group: 'block',
selectable: true, selectable: true,
@ -30,6 +35,7 @@ export const Katex = Node.create({
HTMLAttributes: { HTMLAttributes: {
class: 'katex', class: 'katex',
}, },
getCreateUserId: () => null,
}; };
}, },
@ -74,6 +80,9 @@ export const Katex = Node.create({
nodeInputRule({ nodeInputRule({
find: /^\$katex $/, find: /^\$katex $/,
type: this.type, type: this.type,
getAttributes: () => {
return { defaultShowPicker: true, createUser: this.options.getCreateUserId() };
},
}), }),
]; ];
}, },

View File

@ -22,6 +22,11 @@ export interface IMindAttrs {
zoom?: number; zoom?: number;
} }
interface IMindOptions {
HTMLAttributes: Record<string, any>;
getCreateUserId: () => string | number;
}
declare module '@tiptap/core' { declare module '@tiptap/core' {
interface Commands<ReturnType> { interface Commands<ReturnType> {
mind: { mind: {
@ -30,7 +35,7 @@ declare module '@tiptap/core' {
} }
} }
export const Mind = Node.create({ export const Mind = Node.create<IMindOptions>({
name: 'mind', name: 'mind',
group: 'block', group: 'block',
selectable: true, selectable: true,
@ -66,6 +71,7 @@ export const Mind = Node.create({
HTMLAttributes: { HTMLAttributes: {
class: 'mind', class: 'mind',
}, },
getCreateUserId: () => null,
}; };
}, },
@ -113,10 +119,10 @@ export const Mind = Node.create({
addInputRules() { addInputRules() {
return [ return [
nodeInputRule({ nodeInputRule({
find: /^\$mind $/, find: /^\$mind\$$/,
type: this.type, type: this.type,
getAttributes: () => { getAttributes: () => {
return { width: '100%' }; return { width: '100%', defaultShowPicker: true, createUser: this.options.getCreateUserId() };
}, },
}), }),
]; ];

View File

@ -43,7 +43,7 @@ export const KatexBubbleMenu: React.FC<{ editor: Editor }> = ({ editor }) => {
useEffect(() => { useEffect(() => {
if (visible) { if (visible) {
setTimeout(() => ref.current?.focus(), 100); setTimeout(() => ref.current?.focus(), 200);
} }
}, [visible]); }, [visible]);

View File

@ -81,7 +81,7 @@ export const FlowWrapper = ({ editor, node, updateAttributes }) => {
const onViewportChange = useCallback( const onViewportChange = useCallback(
(visible) => { (visible) => {
if (visible) { if (visible && !$graph.current) {
toggleVisible(true); toggleVisible(true);
} }
}, },

View File

@ -6,7 +6,7 @@ import { Resizeable } from 'components/resizeable';
import { Tooltip } from 'components/tooltip'; import { Tooltip } from 'components/tooltip';
import deepEqual from 'deep-equal'; import deepEqual from 'deep-equal';
import { useToggle } from 'hooks/use-toggle'; import { useToggle } from 'hooks/use-toggle';
import { useCallback, useEffect, useRef, useState } from 'react'; import React, { useCallback, useEffect, useRef, useState } from 'react';
import VisibilitySensor from 'react-visibility-sensor'; import VisibilitySensor from 'react-visibility-sensor';
import { load, renderMind } from 'thirtypart/kityminder'; import { load, renderMind } from 'thirtypart/kityminder';
import { Mind } from 'tiptap/core/extensions/mind'; import { Mind } from 'tiptap/core/extensions/mind';
@ -20,10 +20,8 @@ const { Text } = Typography;
const INHERIT_SIZE_STYLE = { width: '100%', height: '100%', maxWidth: '100%' }; const INHERIT_SIZE_STYLE = { width: '100%', height: '100%', maxWidth: '100%' };
export const MindWrapper = ({ editor, node, updateAttributes }) => { export const MindWrapper = ({ editor, node, updateAttributes }) => {
const $div = useRef(null);
const $mind = useRef(null); const $mind = useRef(null);
const isEditable = editor.isEditable; const isEditable = editor.isEditable;
const isActive = editor.isActive(Mind.name);
const { width: maxWidth } = getEditorContainerDOMSize(editor); const { width: maxWidth } = getEditorContainerDOMSize(editor);
const { data, width, height } = node.attrs; const { data, width, height } = node.attrs;
const [visible, toggleVisible] = useToggle(false); const [visible, toggleVisible] = useToggle(false);
@ -33,7 +31,7 @@ export const MindWrapper = ({ editor, node, updateAttributes }) => {
const setCenter = useCallback(() => { const setCenter = useCallback(() => {
const mind = $mind.current; const mind = $mind.current;
if (!mind) return; if (!mind) return;
mind.execCommand('camera', mind.getRoot(), 600); mind.execCommand('camera');
}, []); }, []);
const setZoom = useCallback((type: 'minus' | 'plus') => { const setZoom = useCallback((type: 'minus' | 'plus') => {
@ -56,9 +54,32 @@ export const MindWrapper = ({ editor, node, updateAttributes }) => {
[updateAttributes, setCenter] [updateAttributes, setCenter]
); );
const render = useCallback(
(div) => {
if (!div) return;
if (!$mind.current) {
const graph = renderMind({
container: div,
data,
isEditable: false,
});
$mind.current = graph;
}
},
[data]
);
const setMind = useCallback(
(div) => {
render(div);
},
[render]
);
const onViewportChange = useCallback( const onViewportChange = useCallback(
(visible) => { (visible) => {
if (visible) { if (visible && !$mind.current) {
toggleVisible(true); toggleVisible(true);
} }
}, },
@ -85,21 +106,8 @@ export const MindWrapper = ({ editor, node, updateAttributes }) => {
setCenter(); setCenter();
}, [width, height, setCenter]); }, [width, height, setCenter]);
useEffect(() => {
if (visible && !loading && !error) {
if (!$mind.current) {
const graph = renderMind({
container: $div.current,
data,
isEditable: false,
});
$mind.current = graph;
}
}
}, [visible, data, loading, error]);
return ( return (
<NodeViewWrapper className={cls(styles.wrap, isActive && styles.isActive)}> <NodeViewWrapper className={cls(styles.wrap)}>
<VisibilitySensor onChange={onViewportChange}> <VisibilitySensor onChange={onViewportChange}>
<Resizeable isEditable={isEditable} width={width} height={height} maxWidth={maxWidth} onChangeEnd={onResize}> <Resizeable isEditable={isEditable} width={width} height={height} maxWidth={maxWidth} onChangeEnd={onResize}>
<div <div
@ -114,8 +122,8 @@ export const MindWrapper = ({ editor, node, updateAttributes }) => {
{loading && <Spin spinning style={INHERIT_SIZE_STYLE}></Spin>} {loading && <Spin spinning style={INHERIT_SIZE_STYLE}></Spin>}
{!loading && !error && ( {!loading && !error && visible && (
<div style={{ height: '100%', maxHeight: '100%', overflow: 'hidden' }} ref={$div}></div> <div style={{ height: '100%', maxHeight: '100%', overflow: 'hidden' }} ref={setMind}></div>
)} )}
<div className={styles.title}> <div className={styles.title}>

View File

@ -1,4 +1,5 @@
import { Toast } from '@douyinfe/semi-ui'; import { Toast } from '@douyinfe/semi-ui';
import { safeJSONParse } from 'helpers/json';
// 自定义节点扩展 // 自定义节点扩展
import { Attachment } from 'tiptap/core/extensions/attachment'; import { Attachment } from 'tiptap/core/extensions/attachment';
import { BackgroundColor } from 'tiptap/core/extensions/background-color'; import { BackgroundColor } from 'tiptap/core/extensions/background-color';
@ -85,6 +86,8 @@ const placeholders = [
'你知道吗?输入 $katex 然后按一下空格就可以快速插入数学公式,其他节点操作类似哦', '你知道吗?输入 $katex 然后按一下空格就可以快速插入数学公式,其他节点操作类似哦',
]; ];
const getCreateUserId = () => safeJSONParse(window.localStorage.getItem('user')).id;
export const CollaborationKit = [ export const CollaborationKit = [
Paragraph, Paragraph,
Placeholder.configure({ Placeholder.configure({
@ -159,11 +162,17 @@ export const CollaborationKit = [
DocumentChildren, DocumentChildren,
DocumentReference, DocumentReference,
Emoji, Emoji,
Flow, Flow.configure({
getCreateUserId,
}),
Iframe, Iframe,
Katex, Katex.configure({
getCreateUserId,
}),
Mention, Mention,
Mind, Mind.configure({
getCreateUserId,
}),
QuickInsert, QuickInsert,
SearchNReplace, SearchNReplace,
Status, Status,