@tiptap/extension-collaboration
Version:
collaboration extension for tiptap
150 lines (148 loc) • 4.81 kB
JavaScript
// src/collaboration.ts
import { Extension } from "@tiptap/core";
import { Plugin, PluginKey } from "@tiptap/pm/state";
import { redo, undo, ySyncPlugin, yUndoPlugin, yUndoPluginKey, yXmlFragmentToProsemirrorJSON } from "@tiptap/y-tiptap";
var Collaboration = Extension.create({
name: "collaboration",
priority: 1e3,
addOptions() {
return {
document: null,
field: "default",
fragment: null,
provider: null
};
},
addStorage() {
return {
isDisabled: false
};
},
onCreate() {
if (this.editor.extensionManager.extensions.find((extension) => extension.name === "undoRedo")) {
console.warn(
'[tiptap warn]: "@tiptap/extension-collaboration" comes with its own history support and is not compatible with "@tiptap/extension-undo-redo".'
);
}
},
addCommands() {
return {
undo: () => ({ tr, state, dispatch }) => {
tr.setMeta("preventDispatch", true);
const 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 = 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() {
var _a;
const fragment = this.options.fragment ? this.options.fragment : this.options.document.getXmlFragment(this.options.field);
const yUndoPluginInstance = yUndoPlugin(this.options.yUndoOptions);
const originalUndoPluginView = yUndoPluginInstance.spec.view;
yUndoPluginInstance.spec.view = (view) => {
const { undoManager } = yUndoPluginKey.getState(view.state);
if (undoManager.restore) {
undoManager.restore();
undoManager.restore = () => {
};
}
const viewRet = originalUndoPluginView ? originalUndoPluginView(view) : void 0;
return {
destroy: () => {
const hasUndoManSelf = undoManager.trackedOrigins.has(undoManager);
const observers = undoManager._observers;
undoManager.restore = () => {
if (hasUndoManSelf) {
undoManager.trackedOrigins.add(undoManager);
}
undoManager.doc.on("afterTransaction", undoManager.afterTransactionHandler);
undoManager._observers = observers;
};
if (viewRet == null ? void 0 : viewRet.destroy) {
viewRet.destroy();
}
}
};
};
const ySyncPluginOptions = {
...this.options.ySyncOptions,
onFirstRender: this.options.onFirstRender
};
const ySyncPluginInstance = ySyncPlugin(fragment, ySyncPluginOptions);
if (this.editor.options.enableContentCheck) {
(_a = fragment.doc) == null ? void 0 : _a.on("beforeTransaction", () => {
try {
const jsonContent = yXmlFragmentToProsemirrorJSON(fragment);
if (jsonContent.content.length === 0) {
return;
}
this.editor.schema.nodeFromJSON(jsonContent).check();
} catch (error) {
this.editor.emit("contentError", {
error,
editor: this.editor,
disableCollaboration: () => {
var _a2;
(_a2 = fragment.doc) == null ? void 0 : _a2.destroy();
this.storage.isDisabled = true;
}
});
return false;
}
});
}
return [
ySyncPluginInstance,
yUndoPluginInstance,
// Only add the filterInvalidContent plugin if content checking is enabled
this.editor.options.enableContentCheck && new Plugin({
key: new PluginKey("filterInvalidContent"),
filterTransaction: () => {
var _a2;
if (this.storage.isDisabled !== false) {
(_a2 = fragment.doc) == null ? void 0 : _a2.destroy();
return true;
}
return true;
}
})
].filter(Boolean);
}
});
// src/helpers/isChangeOrigin.ts
import { ySyncPluginKey } from "@tiptap/y-tiptap";
function isChangeOrigin(transaction) {
return !!transaction.getMeta(ySyncPluginKey);
}
// src/index.ts
var index_default = Collaboration;
export {
Collaboration,
index_default as default,
isChangeOrigin
};
//# sourceMappingURL=index.js.map