mirror of https://github.com/fantasticit/think.git
tiptap: add createUserId
parent
acd266acc0
commit
3bd5d1180c
|
@ -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() };
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
|
|
|
@ -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() };
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
|
|
|
@ -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() };
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
|
|
|
@ -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]);
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -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}>
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Reference in New Issue