{"version":3,"sources":["../src/collaboration.ts","../src/helpers/CollaborationMappablePosition.ts","../src/helpers/isChangeOrigin.ts","../src/helpers/yRelativePosition.ts","../src/index.ts"],"sourcesContent":["import { Extension } from '@tiptap/core'\nimport { Plugin, PluginKey } from '@tiptap/pm/state'\nimport type { EditorView } from '@tiptap/pm/view'\nimport { redo, undo, ySyncPlugin, yUndoPlugin, yUndoPluginKey } from '@tiptap/y-tiptap'\nimport type { Doc, UndoManager, XmlFragment } from 'yjs'\n\nimport {\n createMappablePosition,\n getUpdatedPosition,\n} from './helpers/CollaborationMappablePosition.js'\nimport { isChangeOrigin } from './helpers/isChangeOrigin.js'\n\ntype YSyncOpts = Parameters[1]\ntype YUndoOpts = Parameters[0]\n\nexport interface CollaborationStorage {\n /**\n * Whether collaboration is currently disabled.\n * Disabling collaboration will prevent any changes from being synced with other users.\n */\n isDisabled: boolean\n}\n\ndeclare module '@tiptap/core' {\n interface Commands {\n collaboration: {\n /**\n * Undo recent changes\n * @example editor.commands.undo()\n */\n undo: () => ReturnType\n /**\n * Reapply reverted changes\n * @example editor.commands.redo()\n */\n redo: () => ReturnType\n }\n }\n\n interface Storage {\n collaboration: CollaborationStorage\n }\n}\n\nexport interface CollaborationOptions {\n /**\n * An initialized Y.js document.\n * @example new Y.Doc()\n */\n document?: Doc | null\n\n /**\n * Name of a Y.js fragment, can be changed to sync multiple fields with one Y.js document.\n * @default 'default'\n * @example 'my-custom-field'\n */\n field?: string\n\n /**\n * A raw Y.js fragment, can be used instead of `document` and `field`.\n * @example new Y.Doc().getXmlFragment('body')\n */\n fragment?: XmlFragment | null\n\n /**\n * The collaboration provider.\n * @default null\n */\n provider?: any | null\n\n /**\n * Fired when the content from Yjs is initially rendered to Tiptap.\n */\n onFirstRender?: () => void\n\n /**\n * Options for the Yjs sync plugin.\n */\n ySyncOptions?: YSyncOpts\n\n /**\n * Options for the Yjs undo plugin.\n */\n yUndoOptions?: YUndoOpts\n}\n\n/**\n * This extension allows you to collaborate with others in real-time.\n * @see https://tiptap.dev/api/extensions/collaboration\n */\nexport const Collaboration = Extension.create({\n name: 'collaboration',\n\n priority: 1000,\n\n addOptions() {\n return {\n document: null,\n field: 'default',\n fragment: null,\n provider: null,\n }\n },\n\n addStorage() {\n return {\n isDisabled: false,\n }\n },\n\n onCreate() {\n if (this.editor.extensionManager.extensions.find(extension => extension.name === 'undoRedo')) {\n console.warn(\n '[tiptap warn]: \"@tiptap/extension-collaboration\" comes with its own history support and is not compatible with \"@tiptap/extension-undo-redo\".',\n )\n }\n },\n\n onBeforeCreate() {\n this.editor.utils.getUpdatedPosition = (position, transaction) =>\n getUpdatedPosition(position, transaction, this.editor.state)\n this.editor.utils.createMappablePosition = position =>\n createMappablePosition(position, this.editor.state)\n },\n\n addCommands() {\n return {\n undo:\n () =>\n ({ tr, state, dispatch }) => {\n tr.setMeta('preventDispatch', true)\n\n const undoManager: UndoManager = yUndoPluginKey.getState(state).undoManager\n\n if (undoManager.undoStack.length === 0) {\n return false\n }\n\n if (!dispatch) {\n return true\n }\n\n return undo(state)\n },\n redo:\n () =>\n ({ tr, state, dispatch }) => {\n tr.setMeta('preventDispatch', true)\n\n const undoManager: UndoManager = yUndoPluginKey.getState(state).undoManager\n\n if (undoManager.redoStack.length === 0) {\n return false\n }\n\n if (!dispatch) {\n return true\n }\n\n return redo(state)\n },\n }\n },\n\n addKeyboardShortcuts() {\n return {\n 'Mod-z': () => this.editor.commands.undo(),\n 'Mod-y': () => this.editor.commands.redo(),\n 'Shift-Mod-z': () => this.editor.commands.redo(),\n }\n },\n\n addProseMirrorPlugins() {\n const fragment = this.options.fragment\n ? this.options.fragment\n : (this.options.document as Doc).getXmlFragment(this.options.field)\n\n // Quick fix until there is an official implementation (thanks to @hamflx).\n // See https://github.com/yjs/y-prosemirror/issues/114 and https://github.com/yjs/y-prosemirror/issues/102\n const yUndoPluginInstance = yUndoPlugin(this.options.yUndoOptions)\n const originalUndoPluginView = yUndoPluginInstance.spec.view\n\n yUndoPluginInstance.spec.view = (view: EditorView) => {\n const { undoManager } = yUndoPluginKey.getState(view.state)\n\n if (undoManager.restore) {\n undoManager.restore()\n undoManager.restore = () => {\n // noop\n }\n }\n\n const viewRet = originalUndoPluginView ? originalUndoPluginView(view) : undefined\n\n return {\n destroy: () => {\n const hasUndoManSelf = undoManager.trackedOrigins.has(undoManager)\n // oxlint-disable-next-line no-underscore-dangle\n const observers = undoManager._observers\n\n undoManager.restore = () => {\n if (hasUndoManSelf) {\n undoManager.trackedOrigins.add(undoManager)\n }\n\n undoManager.doc.on('afterTransaction', undoManager.afterTransactionHandler)\n // oxlint-disable-next-line no-underscore-dangle\n undoManager._observers = observers\n }\n\n if (viewRet?.destroy) {\n viewRet.destroy()\n }\n },\n }\n }\n\n const ySyncPluginOptions: YSyncOpts = {\n ...this.options.ySyncOptions,\n onFirstRender: this.options.onFirstRender,\n }\n\n const ySyncPluginInstance = ySyncPlugin(fragment, ySyncPluginOptions)\n\n return [\n ySyncPluginInstance,\n yUndoPluginInstance,\n // Only add the filterInvalidContent plugin if content checking is enabled\n this.editor.options.enableContentCheck &&\n new Plugin({\n key: new PluginKey('filterInvalidContent'),\n filterTransaction: transaction => {\n if (!isChangeOrigin(transaction)) {\n return true\n }\n if (this.storage.isDisabled) {\n return false\n }\n if (!transaction.docChanged) {\n return true\n }\n try {\n transaction.doc.check()\n return true\n } catch (error) {\n this.storage.isDisabled = true\n this.editor.emit('contentError', {\n error: error as Error,\n editor: this.editor,\n disableCollaboration: () => {\n fragment.doc?.destroy()\n },\n })\n return false\n }\n },\n }),\n ].filter(Boolean)\n },\n})\n","import {\n type GetUpdatedPositionResult,\n getUpdatedPosition as coreGetUpdatedPosition,\n MappablePosition,\n} from '@tiptap/core'\nimport type { EditorState, Transaction } from '@tiptap/pm/state'\n\nimport { isChangeOrigin } from './isChangeOrigin.js'\nimport {\n type YRelativePosition,\n getYAbsolutePosition,\n getYRelativePosition,\n} from './yRelativePosition.js'\n\n/**\n * A MappablePosition subclass that includes Y.js relative position information\n * to track positions in collaborative transactions.\n */\nexport class CollaborationMappablePosition extends MappablePosition {\n /**\n * The Y.js relative position used for mapping positions in collaborative editing.\n */\n public yRelativePosition: YRelativePosition\n\n constructor(position: number, yRelativePosition: YRelativePosition) {\n super(position)\n this.yRelativePosition = yRelativePosition\n }\n\n /**\n * Creates a CollaborationMappablePosition from a JSON object.\n */\n static fromJSON(json: any): CollaborationMappablePosition {\n return new CollaborationMappablePosition(json.position, json.yRelativePosition)\n }\n\n /**\n * Converts the CollaborationMappablePosition to a JSON object.\n */\n toJSON(): any {\n return {\n position: this.position,\n yRelativePosition: this.yRelativePosition,\n }\n }\n}\n\n/**\n * Creates a MappablePosition from a position number.\n * This is the collaboration implementation that returns a CollaborationMappablePosition.\n */\nexport function createMappablePosition(\n position: number,\n state: EditorState,\n): CollaborationMappablePosition {\n const yRelativePosition = getYRelativePosition(state, position)\n return new CollaborationMappablePosition(position, yRelativePosition)\n}\n\n/**\n * Returns the new position after applying a transaction. Handles both Y.js\n * transactions and regular transactions.\n */\nexport function getUpdatedPosition(\n position: MappablePosition,\n transaction: Transaction,\n state: EditorState,\n): GetUpdatedPositionResult {\n const yRelativePosition =\n position instanceof CollaborationMappablePosition ? position.yRelativePosition : null\n\n if (isChangeOrigin(transaction) && yRelativePosition) {\n const absolutePosition = getYAbsolutePosition(state, yRelativePosition)\n\n return {\n position: new CollaborationMappablePosition(absolutePosition, yRelativePosition),\n mapResult: null,\n }\n }\n\n const result = coreGetUpdatedPosition(position, transaction)\n\n const absolutePosition = result.position.position\n\n return {\n position: new CollaborationMappablePosition(\n absolutePosition,\n yRelativePosition ?? getYRelativePosition(state, absolutePosition),\n ),\n mapResult: result.mapResult,\n }\n}\n","import type { Transaction } from '@tiptap/pm/state'\nimport { ySyncPluginKey } from '@tiptap/y-tiptap'\n\n/**\n * Checks if a transaction was originated from a Yjs change.\n * @param {Transaction} transaction - The transaction to check.\n * @returns {boolean} - True if the transaction was originated from a Yjs change, false otherwise.\n * @example\n * const transaction = new Transaction(doc)\n * const isOrigin = isChangeOrigin(transaction) // returns false\n */\nexport function isChangeOrigin(transaction: Transaction): boolean {\n return !!transaction.getMeta(ySyncPluginKey)\n}\n","import type { EditorState } from '@tiptap/pm/state'\nimport {\n absolutePositionToRelativePosition,\n relativePositionToAbsolutePosition,\n ySyncPluginKey,\n} from '@tiptap/y-tiptap'\n\n/**\n * A type that represents a Y.js relative position. Used to map a position from\n * a transaction, handling both Yjs changes and regular transactions.\n *\n * If the editor is not collaborative, the value can be `null`.\n */\nexport type YRelativePosition = any\n\n/**\n * Converts a Y.js relative position to a position in the Tiptap document.\n */\nexport function getYAbsolutePosition(state: EditorState, relativePos: YRelativePosition): number {\n // ystate is never null because we've checked it before calling this function\n const ystate = ySyncPluginKey.getState(state)\n return (\n relativePositionToAbsolutePosition(\n ystate.doc,\n ystate.type,\n relativePos,\n ystate.binding.mapping,\n ) || 0\n )\n}\n\n/**\n * Converts a position in the Tiptap document to a Y.js relative position.\n */\nexport function getYRelativePosition(state: EditorState, absolutePos: number): YRelativePosition {\n // ystate is never null because we've checked it before calling this function\n const ystate = ySyncPluginKey.getState(state)\n return absolutePositionToRelativePosition(absolutePos, ystate.type, ystate.binding.mapping)\n}\n","import { Collaboration } from './collaboration.js'\n\nexport * from './collaboration.js'\nexport * from './helpers/CollaborationMappablePosition.js'\nexport * from './helpers/isChangeOrigin.js'\n\nexport default Collaboration\n"],"mappings":"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","names":["ySyncPluginKey","absolutePosition"]}