mirror of https://github.com/fantasticit/think.git
Merge pull request #7 from fantasticit/collobration
commit
c0533bb8f8
|
@ -23,8 +23,6 @@
|
||||||
"@tiptap/extension-code": "^2.0.0-beta.26",
|
"@tiptap/extension-code": "^2.0.0-beta.26",
|
||||||
"@tiptap/extension-code-block": "^2.0.0-beta.37",
|
"@tiptap/extension-code-block": "^2.0.0-beta.37",
|
||||||
"@tiptap/extension-code-block-lowlight": "^2.0.0-beta.68",
|
"@tiptap/extension-code-block-lowlight": "^2.0.0-beta.68",
|
||||||
"@tiptap/extension-collaboration": "^2.0.0-beta.33",
|
|
||||||
"@tiptap/extension-collaboration-cursor": "^2.0.0-beta.34",
|
|
||||||
"@tiptap/extension-color": "^2.0.0-beta.9",
|
"@tiptap/extension-color": "^2.0.0-beta.9",
|
||||||
"@tiptap/extension-document": "^2.0.0-beta.15",
|
"@tiptap/extension-document": "^2.0.0-beta.15",
|
||||||
"@tiptap/extension-dropcursor": "^2.0.0-beta.25",
|
"@tiptap/extension-dropcursor": "^2.0.0-beta.25",
|
||||||
|
@ -60,6 +58,7 @@
|
||||||
"dompurify": "^2.3.5",
|
"dompurify": "^2.3.5",
|
||||||
"interactjs": "^1.10.11",
|
"interactjs": "^1.10.11",
|
||||||
"katex": "^0.15.2",
|
"katex": "^0.15.2",
|
||||||
|
"lib0": "^0.2.47",
|
||||||
"lowlight": "^2.5.0",
|
"lowlight": "^2.5.0",
|
||||||
"markdown-it": "^12.3.2",
|
"markdown-it": "^12.3.2",
|
||||||
"markdown-it-anchor": "^8.4.1",
|
"markdown-it-anchor": "^8.4.1",
|
||||||
|
@ -78,7 +77,9 @@
|
||||||
"react-split-pane": "^0.1.92",
|
"react-split-pane": "^0.1.92",
|
||||||
"scroll-into-view-if-needed": "^2.2.29",
|
"scroll-into-view-if-needed": "^2.2.29",
|
||||||
"swr": "^1.2.0",
|
"swr": "^1.2.0",
|
||||||
"tippy.js": "^6.3.7"
|
"tippy.js": "^6.3.7",
|
||||||
|
"y-prosemirror": "^1.0.14",
|
||||||
|
"yjs": "^13.5.24"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "17.0.13",
|
"@types/node": "17.0.13",
|
||||||
|
|
|
@ -0,0 +1,110 @@
|
||||||
|
import { Extension } from '@tiptap/core';
|
||||||
|
import { UndoManager } from 'yjs';
|
||||||
|
import { redo, undo, ySyncPlugin, yUndoPlugin, yUndoPluginKey } from 'y-prosemirror';
|
||||||
|
|
||||||
|
declare module '@tiptap/core' {
|
||||||
|
interface Commands<ReturnType> {
|
||||||
|
collaboration: {
|
||||||
|
/**
|
||||||
|
* Undo recent changes
|
||||||
|
*/
|
||||||
|
undo: () => ReturnType;
|
||||||
|
/**
|
||||||
|
* Reapply reverted changes
|
||||||
|
*/
|
||||||
|
redo: () => ReturnType;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CollaborationOptions {
|
||||||
|
/**
|
||||||
|
* An initialized Y.js document.
|
||||||
|
*/
|
||||||
|
document: any;
|
||||||
|
/**
|
||||||
|
* Name of a Y.js fragment, can be changed to sync multiple fields with one Y.js document.
|
||||||
|
*/
|
||||||
|
field: string;
|
||||||
|
/**
|
||||||
|
* A raw Y.js fragment, can be used instead of `document` and `field`.
|
||||||
|
*/
|
||||||
|
fragment: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Collaboration = Extension.create<CollaborationOptions>({
|
||||||
|
name: 'collaboration',
|
||||||
|
|
||||||
|
priority: 1000,
|
||||||
|
|
||||||
|
addOptions() {
|
||||||
|
return {
|
||||||
|
document: null,
|
||||||
|
field: 'default',
|
||||||
|
fragment: null,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
onCreate() {
|
||||||
|
if (this.editor.extensionManager.extensions.find((extension) => extension.name === 'history')) {
|
||||||
|
console.warn(
|
||||||
|
'[tiptap warn]: "@tiptap/extension-collaboration" comes with its own history support and is not compatible with "@tiptap/extension-history".'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
addCommands() {
|
||||||
|
return {
|
||||||
|
undo:
|
||||||
|
() =>
|
||||||
|
({ tr, state, dispatch }) => {
|
||||||
|
tr.setMeta('preventDispatch', true);
|
||||||
|
|
||||||
|
const undoManager: UndoManager = yUndoPluginKey.getState(state).undoManager;
|
||||||
|
|
||||||
|
if (undoManager.undoStack.length === 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dispatch) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return undo(state);
|
||||||
|
},
|
||||||
|
redo:
|
||||||
|
() =>
|
||||||
|
({ tr, state, dispatch }) => {
|
||||||
|
tr.setMeta('preventDispatch', true);
|
||||||
|
|
||||||
|
const undoManager: UndoManager = yUndoPluginKey.getState(state).undoManager;
|
||||||
|
|
||||||
|
if (undoManager.redoStack.length === 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dispatch) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return redo(state);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
addKeyboardShortcuts() {
|
||||||
|
return {
|
||||||
|
'Mod-z': () => this.editor.commands.undo(),
|
||||||
|
'Mod-y': () => this.editor.commands.redo(),
|
||||||
|
'Shift-Mod-z': () => this.editor.commands.redo(),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
addProseMirrorPlugins() {
|
||||||
|
const fragment = this.options.fragment
|
||||||
|
? this.options.fragment
|
||||||
|
: this.options.document.getXmlFragment(this.options.field);
|
||||||
|
|
||||||
|
return [ySyncPlugin(fragment), yUndoPlugin()];
|
||||||
|
},
|
||||||
|
});
|
|
@ -0,0 +1,6 @@
|
||||||
|
import { ySyncPluginKey } from 'y-prosemirror';
|
||||||
|
import { Transaction } from 'prosemirror-state';
|
||||||
|
|
||||||
|
export function isChangeOrigin(transaction: Transaction): boolean {
|
||||||
|
return !!transaction.getMeta(ySyncPluginKey);
|
||||||
|
}
|
|
@ -0,0 +1,2 @@
|
||||||
|
export * from './collaboration';
|
||||||
|
export * from './helpers/isChangeOrigin';
|
|
@ -0,0 +1,131 @@
|
||||||
|
import { Extension } from '@tiptap/core';
|
||||||
|
import { yCursorPlugin } from 'y-prosemirror';
|
||||||
|
|
||||||
|
type CollaborationCursorStorage = {
|
||||||
|
users: { clientId: number; [key: string]: any }[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface CollaborationCursorOptions {
|
||||||
|
provider: any;
|
||||||
|
user: Record<string, any>;
|
||||||
|
render(user: Record<string, any>): HTMLElement;
|
||||||
|
/**
|
||||||
|
* @deprecated The "onUpdate" option is deprecated. Please use `editor.storage.collaborationCursor.users` instead. Read more: https://tiptap.dev/api/extensions/collaboration-cursor
|
||||||
|
*/
|
||||||
|
onUpdate: (users: { clientId: number; [key: string]: any }[]) => null;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module '@tiptap/core' {
|
||||||
|
interface Commands<ReturnType> {
|
||||||
|
collaborationCursor: {
|
||||||
|
/**
|
||||||
|
* Update details of the current user
|
||||||
|
*/
|
||||||
|
updateUser: (attributes: Record<string, any>) => ReturnType;
|
||||||
|
/**
|
||||||
|
* Update details of the current user
|
||||||
|
*
|
||||||
|
* @deprecated The "user" command is deprecated. Please use "updateUser" instead. Read more: https://tiptap.dev/api/extensions/collaboration-cursor
|
||||||
|
*/
|
||||||
|
user: (attributes: Record<string, any>) => ReturnType;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const awarenessStatesToArray = (states: Map<number, Record<string, any>>) => {
|
||||||
|
return Array.from(states.entries()).map(([key, value]) => {
|
||||||
|
return {
|
||||||
|
clientId: key,
|
||||||
|
...value.user,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const defaultOnUpdate = () => null;
|
||||||
|
|
||||||
|
export const CollaborationCursor = Extension.create<CollaborationCursorOptions, CollaborationCursorStorage>({
|
||||||
|
name: 'collaborationCursor',
|
||||||
|
|
||||||
|
addOptions() {
|
||||||
|
return {
|
||||||
|
provider: null,
|
||||||
|
user: {
|
||||||
|
name: null,
|
||||||
|
color: null,
|
||||||
|
},
|
||||||
|
render: (user) => {
|
||||||
|
const cursor = document.createElement('span');
|
||||||
|
|
||||||
|
cursor.classList.add('collaboration-cursor__caret');
|
||||||
|
cursor.setAttribute('style', `border-color: ${user.color}`);
|
||||||
|
|
||||||
|
const label = document.createElement('div');
|
||||||
|
|
||||||
|
label.classList.add('collaboration-cursor__label');
|
||||||
|
label.setAttribute('style', `background-color: ${user.color}`);
|
||||||
|
label.insertBefore(document.createTextNode(user.name), null);
|
||||||
|
cursor.insertBefore(label, null);
|
||||||
|
|
||||||
|
return cursor;
|
||||||
|
},
|
||||||
|
onUpdate: defaultOnUpdate,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
onCreate() {
|
||||||
|
if (this.options.onUpdate !== defaultOnUpdate) {
|
||||||
|
console.warn(
|
||||||
|
'[tiptap warn]: DEPRECATED: The "onUpdate" option is deprecated. Please use `editor.storage.collaborationCursor.users` instead. Read more: https://tiptap.dev/api/extensions/collaboration-cursor'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
addStorage() {
|
||||||
|
return {
|
||||||
|
users: [],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
addCommands() {
|
||||||
|
return {
|
||||||
|
updateUser: (attributes) => () => {
|
||||||
|
this.options.user = attributes;
|
||||||
|
|
||||||
|
this.options.provider.awareness.setLocalStateField('user', this.options.user);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
user:
|
||||||
|
(attributes) =>
|
||||||
|
({ editor }) => {
|
||||||
|
console.warn(
|
||||||
|
'[tiptap warn]: DEPRECATED: The "user" command is deprecated. Please use "updateUser" instead. Read more: https://tiptap.dev/api/extensions/collaboration-cursor'
|
||||||
|
);
|
||||||
|
|
||||||
|
return editor.commands.updateUser(attributes);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
addProseMirrorPlugins() {
|
||||||
|
return [
|
||||||
|
yCursorPlugin(
|
||||||
|
(() => {
|
||||||
|
this.options.provider.awareness.setLocalStateField('user', this.options.user);
|
||||||
|
|
||||||
|
this.storage.users = awarenessStatesToArray(this.options.provider.awareness.states);
|
||||||
|
|
||||||
|
this.options.provider.awareness.on('update', () => {
|
||||||
|
this.storage.users = awarenessStatesToArray(this.options.provider.awareness.states);
|
||||||
|
});
|
||||||
|
|
||||||
|
return this.options.provider.awareness;
|
||||||
|
})(),
|
||||||
|
// @ts-ignore
|
||||||
|
{
|
||||||
|
cursorBuilder: this.options.render,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
];
|
||||||
|
},
|
||||||
|
});
|
|
@ -0,0 +1,187 @@
|
||||||
|
import * as Y from 'yjs';
|
||||||
|
import { Decoration, DecorationSet } from 'prosemirror-view'; // eslint-disable-line
|
||||||
|
import { Plugin } from 'prosemirror-state'; // eslint-disable-line
|
||||||
|
import * as math from 'lib0/math';
|
||||||
|
import {
|
||||||
|
absolutePositionToRelativePosition,
|
||||||
|
relativePositionToAbsolutePosition,
|
||||||
|
setMeta,
|
||||||
|
yCursorPluginKey,
|
||||||
|
ySyncPluginKey,
|
||||||
|
} from 'y-prosemirror';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default generator for a cursor element
|
||||||
|
*
|
||||||
|
* @param {any} user user data
|
||||||
|
* @return HTMLElement
|
||||||
|
*/
|
||||||
|
export const defaultCursorBuilder = (user) => {
|
||||||
|
const cursor = document.createElement('span');
|
||||||
|
cursor.classList.add('ProseMirror-yjs-cursor');
|
||||||
|
cursor.setAttribute('style', `border-color: ${user.color}`);
|
||||||
|
const userDiv = document.createElement('div');
|
||||||
|
userDiv.setAttribute('style', `background-color: ${user.color}`);
|
||||||
|
userDiv.insertBefore(document.createTextNode(user.name), null);
|
||||||
|
cursor.insertBefore(userDiv, null);
|
||||||
|
return cursor;
|
||||||
|
};
|
||||||
|
|
||||||
|
const rxValidColor = /^#[0-9a-fA-F]{6}$/;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {any} state
|
||||||
|
* @param {Awareness} awareness
|
||||||
|
* @return {any} DecorationSet
|
||||||
|
*/
|
||||||
|
export const createDecorations = (state, awareness, createCursor) => {
|
||||||
|
const ystate = ySyncPluginKey.getState(state) || state['y-sync$'];
|
||||||
|
const y = ystate.doc;
|
||||||
|
const decorations = [];
|
||||||
|
if (ystate.snapshot != null || ystate.prevSnapshot != null || ystate.binding === null) {
|
||||||
|
// do not render cursors while snapshot is active
|
||||||
|
return DecorationSet.create(state.doc, []);
|
||||||
|
}
|
||||||
|
awareness.getStates().forEach((aw, clientId) => {
|
||||||
|
if (clientId === y.clientID) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (aw.cursor != null) {
|
||||||
|
const user = aw.user || {};
|
||||||
|
if (user.color == null) {
|
||||||
|
user.color = '#ffa500';
|
||||||
|
} else if (!rxValidColor.test(user.color)) {
|
||||||
|
// We only support 6-digit RGB colors in y-prosemirror
|
||||||
|
console.warn('A user uses an unsupported color format', user);
|
||||||
|
}
|
||||||
|
if (user.name == null) {
|
||||||
|
user.name = `User: ${clientId}`;
|
||||||
|
}
|
||||||
|
let anchor = relativePositionToAbsolutePosition(
|
||||||
|
y,
|
||||||
|
ystate.type,
|
||||||
|
Y.createRelativePositionFromJSON(aw.cursor.anchor),
|
||||||
|
ystate.binding.mapping
|
||||||
|
);
|
||||||
|
let head = relativePositionToAbsolutePosition(
|
||||||
|
y,
|
||||||
|
ystate.type,
|
||||||
|
Y.createRelativePositionFromJSON(aw.cursor.head),
|
||||||
|
ystate.binding.mapping
|
||||||
|
);
|
||||||
|
if (anchor !== null && head !== null) {
|
||||||
|
const maxsize = math.max(state.doc.content.size - 1, 0);
|
||||||
|
anchor = math.min(anchor, maxsize);
|
||||||
|
head = math.min(head, maxsize);
|
||||||
|
decorations.push(Decoration.widget(head, () => createCursor(user), { key: clientId + '', side: 10 }));
|
||||||
|
const from = math.min(anchor, head);
|
||||||
|
const to = math.max(anchor, head);
|
||||||
|
decorations.push(
|
||||||
|
Decoration.inline(
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
{ style: `background-color: ${user.color}70` },
|
||||||
|
{ inclusiveEnd: true, inclusiveStart: false }
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return DecorationSet.create(state.doc, decorations);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A prosemirror plugin that listens to awareness information on Yjs.
|
||||||
|
* This requires that a `prosemirrorPlugin` is also bound to the prosemirror.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @param {Awareness} awareness
|
||||||
|
* @param {object} [opts]
|
||||||
|
* @param {function(any):HTMLElement} [opts.cursorBuilder]
|
||||||
|
* @param {function(any):any} [opts.getSelection]
|
||||||
|
* @param {string} [opts.cursorStateField] By default all editor bindings use the awareness 'cursor' field to propagate cursor information.
|
||||||
|
* @return {any}
|
||||||
|
*/
|
||||||
|
export const yCursorPlugin = (
|
||||||
|
awareness,
|
||||||
|
{ cursorBuilder = defaultCursorBuilder, getSelection = (state) => state.selection } = {},
|
||||||
|
cursorStateField = 'cursor'
|
||||||
|
) =>
|
||||||
|
new Plugin({
|
||||||
|
key: yCursorPluginKey,
|
||||||
|
state: {
|
||||||
|
init(_, state) {
|
||||||
|
return createDecorations(state, awareness, cursorBuilder);
|
||||||
|
},
|
||||||
|
apply(tr, prevState, oldState, newState) {
|
||||||
|
const ystate = ySyncPluginKey.getState(newState);
|
||||||
|
const yCursorState = tr.getMeta(yCursorPluginKey);
|
||||||
|
if ((ystate && ystate.isChangeOrigin) || (yCursorState && yCursorState.awarenessUpdated)) {
|
||||||
|
return createDecorations(newState, awareness, cursorBuilder);
|
||||||
|
}
|
||||||
|
return prevState.map(tr.mapping, tr.doc);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
decorations: (state) => {
|
||||||
|
return yCursorPluginKey.getState(state);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
view: (view) => {
|
||||||
|
const awarenessListener = () => {
|
||||||
|
// @ts-ignore
|
||||||
|
if (view.docView) {
|
||||||
|
setMeta(view, yCursorPluginKey, { awarenessUpdated: true });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const updateCursorInfo = () => {
|
||||||
|
const ystate = ySyncPluginKey.getState(view.state) || view.state['y-sync$'];
|
||||||
|
// @note We make implicit checks when checking for the cursor property
|
||||||
|
const current = awareness.getLocalState() || {};
|
||||||
|
if (view.hasFocus() && ystate.binding !== null) {
|
||||||
|
const selection = getSelection(view.state);
|
||||||
|
/**
|
||||||
|
* @type {Y.RelativePosition}
|
||||||
|
*/
|
||||||
|
const anchor = absolutePositionToRelativePosition(selection.anchor, ystate.type, ystate.binding.mapping);
|
||||||
|
/**
|
||||||
|
* @type {Y.RelativePosition}
|
||||||
|
*/
|
||||||
|
const head = absolutePositionToRelativePosition(selection.head, ystate.type, ystate.binding.mapping);
|
||||||
|
if (
|
||||||
|
current.cursor == null ||
|
||||||
|
!Y.compareRelativePositions(Y.createRelativePositionFromJSON(current.cursor.anchor), anchor) ||
|
||||||
|
!Y.compareRelativePositions(Y.createRelativePositionFromJSON(current.cursor.head), head)
|
||||||
|
) {
|
||||||
|
awareness.setLocalStateField(cursorStateField, {
|
||||||
|
anchor,
|
||||||
|
head,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if (
|
||||||
|
current.cursor != null &&
|
||||||
|
relativePositionToAbsolutePosition(
|
||||||
|
ystate.doc,
|
||||||
|
ystate.type,
|
||||||
|
Y.createRelativePositionFromJSON(current.cursor.anchor),
|
||||||
|
ystate.binding.mapping
|
||||||
|
) !== null
|
||||||
|
) {
|
||||||
|
// delete cursor information if current cursor information is owned by this editor binding
|
||||||
|
awareness.setLocalStateField(cursorStateField, null);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
awareness.on('change', awarenessListener);
|
||||||
|
view.dom.addEventListener('focusin', updateCursorInfo);
|
||||||
|
view.dom.addEventListener('focusout', updateCursorInfo);
|
||||||
|
return {
|
||||||
|
update: updateCursorInfo,
|
||||||
|
destroy: () => {
|
||||||
|
view.dom.removeEventListener('focusin', updateCursorInfo);
|
||||||
|
view.dom.removeEventListener('focusout', updateCursorInfo);
|
||||||
|
awareness.off('change', awarenessListener);
|
||||||
|
awareness.setLocalStateField(cursorStateField, null);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
|
@ -1,6 +1,6 @@
|
||||||
import { HocuspocusProvider } from '@hocuspocus/provider';
|
import { HocuspocusProvider } from '@hocuspocus/provider';
|
||||||
import Collaboration from '@tiptap/extension-collaboration';
|
import { Collaboration } from './collaboration';
|
||||||
import CollaborationCursor from '@tiptap/extension-collaboration-cursor';
|
import { CollaborationCursor } from './collaborationCursor';
|
||||||
import History from '@tiptap/extension-history';
|
import History from '@tiptap/extension-history';
|
||||||
import { getRandomColor } from 'helpers/color';
|
import { getRandomColor } from 'helpers/color';
|
||||||
import { Document } from './extensions/document';
|
import { Document } from './extensions/document';
|
||||||
|
|
|
@ -57,8 +57,6 @@ importers:
|
||||||
'@tiptap/extension-code': ^2.0.0-beta.26
|
'@tiptap/extension-code': ^2.0.0-beta.26
|
||||||
'@tiptap/extension-code-block': ^2.0.0-beta.37
|
'@tiptap/extension-code-block': ^2.0.0-beta.37
|
||||||
'@tiptap/extension-code-block-lowlight': ^2.0.0-beta.68
|
'@tiptap/extension-code-block-lowlight': ^2.0.0-beta.68
|
||||||
'@tiptap/extension-collaboration': ^2.0.0-beta.33
|
|
||||||
'@tiptap/extension-collaboration-cursor': ^2.0.0-beta.34
|
|
||||||
'@tiptap/extension-color': ^2.0.0-beta.9
|
'@tiptap/extension-color': ^2.0.0-beta.9
|
||||||
'@tiptap/extension-document': ^2.0.0-beta.15
|
'@tiptap/extension-document': ^2.0.0-beta.15
|
||||||
'@tiptap/extension-dropcursor': ^2.0.0-beta.25
|
'@tiptap/extension-dropcursor': ^2.0.0-beta.25
|
||||||
|
@ -96,6 +94,7 @@ importers:
|
||||||
dompurify: ^2.3.5
|
dompurify: ^2.3.5
|
||||||
interactjs: ^1.10.11
|
interactjs: ^1.10.11
|
||||||
katex: ^0.15.2
|
katex: ^0.15.2
|
||||||
|
lib0: ^0.2.47
|
||||||
lowlight: ^2.5.0
|
lowlight: ^2.5.0
|
||||||
markdown-it: ^12.3.2
|
markdown-it: ^12.3.2
|
||||||
markdown-it-anchor: ^8.4.1
|
markdown-it-anchor: ^8.4.1
|
||||||
|
@ -117,6 +116,8 @@ importers:
|
||||||
tippy.js: ^6.3.7
|
tippy.js: ^6.3.7
|
||||||
tsconfig-paths-webpack-plugin: ^3.5.2
|
tsconfig-paths-webpack-plugin: ^3.5.2
|
||||||
typescript: 4.5.5
|
typescript: 4.5.5
|
||||||
|
y-prosemirror: ^1.0.14
|
||||||
|
yjs: ^13.5.24
|
||||||
dependencies:
|
dependencies:
|
||||||
'@douyinfe/semi-icons': 2.3.1_react@17.0.2
|
'@douyinfe/semi-icons': 2.3.1_react@17.0.2
|
||||||
'@douyinfe/semi-next': 2.3.1
|
'@douyinfe/semi-next': 2.3.1
|
||||||
|
@ -132,8 +133,6 @@ importers:
|
||||||
'@tiptap/extension-code': 2.0.0-beta.26_@tiptap+core@2.0.0-beta.171
|
'@tiptap/extension-code': 2.0.0-beta.26_@tiptap+core@2.0.0-beta.171
|
||||||
'@tiptap/extension-code-block': 2.0.0-beta.37_@tiptap+core@2.0.0-beta.171
|
'@tiptap/extension-code-block': 2.0.0-beta.37_@tiptap+core@2.0.0-beta.171
|
||||||
'@tiptap/extension-code-block-lowlight': 2.0.0-beta.68_@tiptap+core@2.0.0-beta.171
|
'@tiptap/extension-code-block-lowlight': 2.0.0-beta.68_@tiptap+core@2.0.0-beta.171
|
||||||
'@tiptap/extension-collaboration': 2.0.0-beta.33_24052c2d57881e244a8dbd08d556b4fc
|
|
||||||
'@tiptap/extension-collaboration-cursor': 2.0.0-beta.34_24052c2d57881e244a8dbd08d556b4fc
|
|
||||||
'@tiptap/extension-color': 2.0.0-beta.9_e32f4205d0966701340db1456434a591
|
'@tiptap/extension-color': 2.0.0-beta.9_e32f4205d0966701340db1456434a591
|
||||||
'@tiptap/extension-document': 2.0.0-beta.15_@tiptap+core@2.0.0-beta.171
|
'@tiptap/extension-document': 2.0.0-beta.15_@tiptap+core@2.0.0-beta.171
|
||||||
'@tiptap/extension-dropcursor': 2.0.0-beta.25_@tiptap+core@2.0.0-beta.171
|
'@tiptap/extension-dropcursor': 2.0.0-beta.25_@tiptap+core@2.0.0-beta.171
|
||||||
|
@ -169,6 +168,7 @@ importers:
|
||||||
dompurify: 2.3.5
|
dompurify: 2.3.5
|
||||||
interactjs: 1.10.11
|
interactjs: 1.10.11
|
||||||
katex: 0.15.2
|
katex: 0.15.2
|
||||||
|
lib0: 0.2.47
|
||||||
lowlight: 2.5.0
|
lowlight: 2.5.0
|
||||||
markdown-it: 12.3.2
|
markdown-it: 12.3.2
|
||||||
markdown-it-anchor: 8.4.1_markdown-it@12.3.2
|
markdown-it-anchor: 8.4.1_markdown-it@12.3.2
|
||||||
|
@ -188,6 +188,8 @@ importers:
|
||||||
scroll-into-view-if-needed: 2.2.29
|
scroll-into-view-if-needed: 2.2.29
|
||||||
swr: 1.2.0_react@17.0.2
|
swr: 1.2.0_react@17.0.2
|
||||||
tippy.js: 6.3.7
|
tippy.js: 6.3.7
|
||||||
|
y-prosemirror: 1.0.14_0fedec857d2fb730ad5b02a71124bf2a
|
||||||
|
yjs: 13.5.24
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@types/node': 17.0.13
|
'@types/node': 17.0.13
|
||||||
'@types/react': 17.0.38
|
'@types/react': 17.0.38
|
||||||
|
@ -917,7 +919,7 @@ packages:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@hocuspocus/common': 1.0.0-alpha.4
|
'@hocuspocus/common': 1.0.0-alpha.4
|
||||||
'@lifeomic/attempt': 3.0.2
|
'@lifeomic/attempt': 3.0.2
|
||||||
lib0: 0.2.43
|
lib0: 0.2.47
|
||||||
y-protocols: 1.0.5
|
y-protocols: 1.0.5
|
||||||
yjs: 13.5.24
|
yjs: 13.5.24
|
||||||
dev: false
|
dev: false
|
||||||
|
@ -1650,36 +1652,6 @@ packages:
|
||||||
'@tiptap/core': 2.0.0-beta.171
|
'@tiptap/core': 2.0.0-beta.171
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@tiptap/extension-collaboration-cursor/2.0.0-beta.34_24052c2d57881e244a8dbd08d556b4fc:
|
|
||||||
resolution: {integrity: sha512-6jxM8jxOXEwRHv7rkWsacC8Q3km83opEK/2udiMEC7a/yFeMKpYjOP+sAvzdGBposlIof/VgjXhbIUBRBqmqLw==}
|
|
||||||
peerDependencies:
|
|
||||||
'@tiptap/core': ^2.0.0-beta.1
|
|
||||||
dependencies:
|
|
||||||
'@tiptap/core': 2.0.0-beta.171
|
|
||||||
y-prosemirror: 1.0.14_prosemirror-view@1.23.6
|
|
||||||
transitivePeerDependencies:
|
|
||||||
- prosemirror-model
|
|
||||||
- prosemirror-state
|
|
||||||
- prosemirror-view
|
|
||||||
- y-protocols
|
|
||||||
- yjs
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/@tiptap/extension-collaboration/2.0.0-beta.33_24052c2d57881e244a8dbd08d556b4fc:
|
|
||||||
resolution: {integrity: sha512-KMHJxsS/FSVyum2ds3gfu0WFU1Zu7xQ5YmsSCLXyBxkhDtBGWBZTcpcSh9siWfs26+Fk1ZvcEssNyRYMEummpQ==}
|
|
||||||
peerDependencies:
|
|
||||||
'@tiptap/core': ^2.0.0-beta.1
|
|
||||||
dependencies:
|
|
||||||
'@tiptap/core': 2.0.0-beta.171
|
|
||||||
prosemirror-state: 1.3.4
|
|
||||||
y-prosemirror: 1.0.14_fb8440a343abf572e136ee4e217d51fa
|
|
||||||
transitivePeerDependencies:
|
|
||||||
- prosemirror-model
|
|
||||||
- prosemirror-view
|
|
||||||
- y-protocols
|
|
||||||
- yjs
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/@tiptap/extension-color/2.0.0-beta.9_e32f4205d0966701340db1456434a591:
|
/@tiptap/extension-color/2.0.0-beta.9_e32f4205d0966701340db1456434a591:
|
||||||
resolution: {integrity: sha512-c8zcaNCdwUwbgrutfsG7LD9KH7ZvDVwKOZHbOL4gMSwdH9s+6r1ThRFLEbKgHIJlTa2jd96qoo+lVfj1Qwp7ww==}
|
resolution: {integrity: sha512-c8zcaNCdwUwbgrutfsG7LD9KH7ZvDVwKOZHbOL4gMSwdH9s+6r1ThRFLEbKgHIJlTa2jd96qoo+lVfj1Qwp7ww==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
@ -5811,6 +5783,13 @@ packages:
|
||||||
isomorphic.js: 0.2.4
|
isomorphic.js: 0.2.4
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/lib0/0.2.47:
|
||||||
|
resolution: {integrity: sha512-RXprIyaflw7OmFNMpb8HmvDhuRVUFXYCXrmynQN8OGbGevgMx9u6tjQG/yB0dOoDcuB1XXgqFn8Oy3RlKF/Qhg==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
dependencies:
|
||||||
|
isomorphic.js: 0.2.4
|
||||||
|
dev: false
|
||||||
|
|
||||||
/libphonenumber-js/1.9.46:
|
/libphonenumber-js/1.9.46:
|
||||||
resolution: {integrity: sha512-QqTX4UVsGy24njtCgLRspiKpxfRniRBZE/P+d0vQXuYWQ+hwDS6X0ouo0O/SRyf7bhhMCE71b6vAvLMtY5PfEw==}
|
resolution: {integrity: sha512-QqTX4UVsGy24njtCgLRspiKpxfRniRBZE/P+d0vQXuYWQ+hwDS6X0ouo0O/SRyf7bhhMCE71b6vAvLMtY5PfEw==}
|
||||||
dev: false
|
dev: false
|
||||||
|
@ -8521,6 +8500,20 @@ packages:
|
||||||
engines: {node: '>=0.4'}
|
engines: {node: '>=0.4'}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/y-prosemirror/1.0.14_0fedec857d2fb730ad5b02a71124bf2a:
|
||||||
|
resolution: {integrity: sha512-fJQn/XT+z/gks9sd64eB+Mf1UQP0d5SHQ8RwbrzIwYFW+FgU/nx8/hJm+nrBAoO9azHOY5aDeoffeLmOFXLD9w==}
|
||||||
|
peerDependencies:
|
||||||
|
prosemirror-model: ^1.7.1
|
||||||
|
prosemirror-state: ^1.2.3
|
||||||
|
prosemirror-view: ^1.9.10
|
||||||
|
y-protocols: ^1.0.1
|
||||||
|
yjs: ^13.3.2
|
||||||
|
dependencies:
|
||||||
|
lib0: 0.2.47
|
||||||
|
prosemirror-view: 1.23.6
|
||||||
|
yjs: 13.5.24
|
||||||
|
dev: false
|
||||||
|
|
||||||
/y-prosemirror/1.0.14_8fd72c89aecefb95d86a797b5207d945:
|
/y-prosemirror/1.0.14_8fd72c89aecefb95d86a797b5207d945:
|
||||||
resolution: {integrity: sha512-fJQn/XT+z/gks9sd64eB+Mf1UQP0d5SHQ8RwbrzIwYFW+FgU/nx8/hJm+nrBAoO9azHOY5aDeoffeLmOFXLD9w==}
|
resolution: {integrity: sha512-fJQn/XT+z/gks9sd64eB+Mf1UQP0d5SHQ8RwbrzIwYFW+FgU/nx8/hJm+nrBAoO9azHOY5aDeoffeLmOFXLD9w==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
@ -8535,37 +8528,10 @@ packages:
|
||||||
yjs: 13.5.24
|
yjs: 13.5.24
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/y-prosemirror/1.0.14_fb8440a343abf572e136ee4e217d51fa:
|
|
||||||
resolution: {integrity: sha512-fJQn/XT+z/gks9sd64eB+Mf1UQP0d5SHQ8RwbrzIwYFW+FgU/nx8/hJm+nrBAoO9azHOY5aDeoffeLmOFXLD9w==}
|
|
||||||
peerDependencies:
|
|
||||||
prosemirror-model: ^1.7.1
|
|
||||||
prosemirror-state: ^1.2.3
|
|
||||||
prosemirror-view: ^1.9.10
|
|
||||||
y-protocols: ^1.0.1
|
|
||||||
yjs: ^13.3.2
|
|
||||||
dependencies:
|
|
||||||
lib0: 0.2.43
|
|
||||||
prosemirror-state: 1.3.4
|
|
||||||
prosemirror-view: 1.23.6
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/y-prosemirror/1.0.14_prosemirror-view@1.23.6:
|
|
||||||
resolution: {integrity: sha512-fJQn/XT+z/gks9sd64eB+Mf1UQP0d5SHQ8RwbrzIwYFW+FgU/nx8/hJm+nrBAoO9azHOY5aDeoffeLmOFXLD9w==}
|
|
||||||
peerDependencies:
|
|
||||||
prosemirror-model: ^1.7.1
|
|
||||||
prosemirror-state: ^1.2.3
|
|
||||||
prosemirror-view: ^1.9.10
|
|
||||||
y-protocols: ^1.0.1
|
|
||||||
yjs: ^13.3.2
|
|
||||||
dependencies:
|
|
||||||
lib0: 0.2.43
|
|
||||||
prosemirror-view: 1.23.6
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/y-protocols/1.0.5:
|
/y-protocols/1.0.5:
|
||||||
resolution: {integrity: sha512-Wil92b7cGk712lRHDqS4T90IczF6RkcvCwAD0A2OPg+adKmOe+nOiT/N2hvpQIWS3zfjmtL4CPaH5sIW1Hkm/A==}
|
resolution: {integrity: sha512-Wil92b7cGk712lRHDqS4T90IczF6RkcvCwAD0A2OPg+adKmOe+nOiT/N2hvpQIWS3zfjmtL4CPaH5sIW1Hkm/A==}
|
||||||
dependencies:
|
dependencies:
|
||||||
lib0: 0.2.43
|
lib0: 0.2.47
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/y18n/5.0.8:
|
/y18n/5.0.8:
|
||||||
|
@ -8626,7 +8592,7 @@ packages:
|
||||||
resolution: {integrity: sha512-f6DqRfnhjihj4+iQv5zjhsYqOpkcM9SGroqluq6J6eEUTq7ipbgECKf+h5W4P+LU4fKawWFdQH8mxgJ7baZPJw==}
|
resolution: {integrity: sha512-f6DqRfnhjihj4+iQv5zjhsYqOpkcM9SGroqluq6J6eEUTq7ipbgECKf+h5W4P+LU4fKawWFdQH8mxgJ7baZPJw==}
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
dependencies:
|
dependencies:
|
||||||
lib0: 0.2.43
|
lib0: 0.2.47
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/yn/3.1.1:
|
/yn/3.1.1:
|
||||||
|
|
Loading…
Reference in New Issue