mirror of https://github.com/fantasticit/think.git
tiptap: fix isEditable
parent
578753c1f6
commit
b5172a8861
|
@ -92,21 +92,28 @@ export const Editor: React.FC<IProps> = ({ user: currentUser, documentId, author
|
|||
const [mentionUsers, setMentionUsers] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
const indexdbProvider = getIndexdbProvider(documentId, provider.document);
|
||||
|
||||
indexdbProvider.on('synced', () => {
|
||||
setStatus('loadCacheSuccess');
|
||||
});
|
||||
|
||||
provider.on('status', async ({ status }) => {
|
||||
setStatus(status);
|
||||
});
|
||||
|
||||
return () => {
|
||||
destoryProvider(provider, 'EDITOR');
|
||||
};
|
||||
}, [documentId, provider, authority]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!authority || !authority.editable) return;
|
||||
|
||||
const indexdbProvider = getIndexdbProvider(documentId, provider.document);
|
||||
|
||||
indexdbProvider.on('synced', () => {
|
||||
setStatus('loadCacheSuccess');
|
||||
});
|
||||
|
||||
return () => {
|
||||
destoryIndexdbProvider(documentId);
|
||||
};
|
||||
}, [documentId, provider]);
|
||||
}, [documentId, provider, authority]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!editor) return;
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
import { useState, useEffect, DependencyList } from 'react';
|
||||
import { EditorOptions } from '@tiptap/core';
|
||||
import { Editor } from '@tiptap/react';
|
||||
|
||||
function useForceUpdate() {
|
||||
const [, setValue] = useState(0);
|
||||
|
||||
return () => setValue((value) => value + 1);
|
||||
}
|
||||
|
||||
export const useEditor = (options: Partial<EditorOptions> = {}, deps: DependencyList = []) => {
|
||||
const [editor, setEditor] = useState<Editor | null>(null);
|
||||
const forceUpdate = useForceUpdate();
|
||||
|
||||
useEffect(() => {
|
||||
const instance = new Editor(options);
|
||||
|
||||
setEditor(instance);
|
||||
|
||||
// instance.on('transaction', () => {
|
||||
// requestAnimationFrame(() => {
|
||||
// requestAnimationFrame(() => {
|
||||
// console.log('update');
|
||||
// forceUpdate();
|
||||
// });
|
||||
// });
|
||||
// });
|
||||
|
||||
return () => {
|
||||
instance.destroy();
|
||||
};
|
||||
}, deps);
|
||||
|
||||
return editor;
|
||||
};
|
|
@ -101,7 +101,8 @@ export const createDecorations = (state, awareness, createCursor) => {
|
|||
export const yCursorPlugin = (
|
||||
awareness,
|
||||
{ cursorBuilder = defaultCursorBuilder, getSelection = (state) => state.selection } = {},
|
||||
cursorStateField = 'cursor'
|
||||
cursorStateField = 'cursor',
|
||||
isEditable = false
|
||||
) =>
|
||||
new Plugin({
|
||||
key: yCursorPluginKey,
|
||||
|
@ -131,6 +132,8 @@ export const yCursorPlugin = (
|
|||
}
|
||||
};
|
||||
const updateCursorInfo = () => {
|
||||
if (!isEditable) return;
|
||||
|
||||
const ystate = ySyncPluginKey.getState(view.state);
|
||||
// @note We make implicit checks when checking for the cursor property
|
||||
const current = awareness.getLocalState() || {};
|
||||
|
|
|
@ -165,6 +165,7 @@ export const CollaborationCursor = Extension.create<CollaborationCursorOptions,
|
|||
|
||||
addProseMirrorPlugins() {
|
||||
const extensionThis = this;
|
||||
const { isEditable } = this.editor;
|
||||
|
||||
return [
|
||||
yCursorPlugin(
|
||||
|
@ -184,7 +185,9 @@ export const CollaborationCursor = Extension.create<CollaborationCursorOptions,
|
|||
// @ts-ignore
|
||||
{
|
||||
cursorBuilder: this.options.render,
|
||||
}
|
||||
},
|
||||
'cursor',
|
||||
isEditable
|
||||
),
|
||||
];
|
||||
},
|
||||
|
|
|
@ -45,6 +45,7 @@ export const SelectionExtension = Extension.create({
|
|||
name: 'selection',
|
||||
priority: EXTENSION_PRIORITY_HIGHEST,
|
||||
addProseMirrorPlugins() {
|
||||
const { isEditable } = this.editor;
|
||||
return [
|
||||
new Plugin({
|
||||
key: selectionPluginKey,
|
||||
|
@ -103,6 +104,30 @@ export const SelectionExtension = Extension.create({
|
|||
},
|
||||
},
|
||||
}),
|
||||
new Plugin({
|
||||
key: new PluginKey('preventSelection'),
|
||||
props: {
|
||||
// 禁止非可编辑用户选中
|
||||
handleClick(_, __, event) {
|
||||
if (!isEditable) {
|
||||
event.preventDefault();
|
||||
return true;
|
||||
}
|
||||
},
|
||||
handleKeyPress(_, event) {
|
||||
if (!isEditable) {
|
||||
event.preventDefault();
|
||||
return true;
|
||||
}
|
||||
},
|
||||
handleKeyDown(_, event) {
|
||||
if (!isEditable) {
|
||||
event.preventDefault();
|
||||
return true;
|
||||
}
|
||||
},
|
||||
},
|
||||
}),
|
||||
];
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React from 'react';
|
||||
import React, { useMemo } from 'react';
|
||||
import { Editor } from '@tiptap/core';
|
||||
import { Space } from '@douyinfe/semi-ui';
|
||||
import { Divider } from './divider';
|
||||
|
||||
|
@ -43,11 +44,18 @@ import { Iframe } from './menus/iframe';
|
|||
import { Table } from './menus/table';
|
||||
import { Mind } from './menus/mind';
|
||||
|
||||
const _MenuBar: React.FC<{ editor: any }> = ({ editor }) => {
|
||||
const _MenuBar: React.FC<{ editor: Editor }> = ({ editor }) => {
|
||||
const isEditable = useMemo(() => editor.isEditable, [editor]);
|
||||
|
||||
if (!editor) return null;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div
|
||||
style={{
|
||||
opacity: isEditable ? 1 : 0.65,
|
||||
pointerEvents: isEditable ? 'auto' : 'none',
|
||||
}}
|
||||
>
|
||||
<Space spacing={2}>
|
||||
<Insert editor={editor} />
|
||||
|
||||
|
@ -109,7 +117,7 @@ export const MenuBar = React.memo(_MenuBar, (prevProps, nextProps) => {
|
|||
return prevProps.editor === nextProps.editor;
|
||||
});
|
||||
|
||||
const _CommentMenuBar: React.FC<{ editor: any }> = ({ editor }) => {
|
||||
const _CommentMenuBar: React.FC<{ editor: Editor }> = ({ editor }) => {
|
||||
return (
|
||||
<>
|
||||
<Space spacing={2}>
|
||||
|
|
|
@ -20,7 +20,6 @@ export const useEditor = (options: Partial<EditorOptions> = {}, deps: Dependency
|
|||
// instance.on('transaction', () => {
|
||||
// requestAnimationFrame(() => {
|
||||
// requestAnimationFrame(() => {
|
||||
// console.log('update');
|
||||
// forceUpdate();
|
||||
// });
|
||||
// });
|
||||
|
|
|
@ -133,7 +133,7 @@ export class BubbleMenuView {
|
|||
trigger: 'manual',
|
||||
placement: 'top',
|
||||
hideOnClick: 'toggle',
|
||||
...Object.assign({ zIndex: 99 }, this.tippyOptions),
|
||||
...Object.assign({ zIndex: 999 }, this.tippyOptions),
|
||||
});
|
||||
|
||||
// maybe we have to hide tippy on its own blur event as well
|
||||
|
@ -160,7 +160,9 @@ export class BubbleMenuView {
|
|||
const from = Math.min(...ranges.map((range) => range.$from.pos));
|
||||
const to = Math.max(...ranges.map((range) => range.$to.pos));
|
||||
|
||||
const shouldShow = this.shouldShow?.({
|
||||
const shouldShow =
|
||||
this.editor.isEditable &&
|
||||
this.shouldShow?.({
|
||||
editor: this.editor,
|
||||
view,
|
||||
state,
|
||||
|
|
Loading…
Reference in New Issue