{"version":3,"file":"index.cjs","names":["ySyncPluginKey","ySyncPluginKey","relativePositionToAbsolutePosition","absolutePositionToRelativePosition","MappablePosition","coreGetUpdatedPosition","Extension","yUndoPluginKey","undo","redo","yUndoPlugin","ySyncPlugin","Plugin","PluginKey"],"sources":["../src/helpers/isChangeOrigin.ts","../src/helpers/yRelativePosition.ts","../src/helpers/CollaborationMappablePosition.ts","../src/collaboration.ts","../src/index.ts"],"sourcesContent":["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 {\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 { 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<typeof ySyncPlugin>[1]\ntype YUndoOpts = Parameters<typeof yUndoPlugin>[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<ReturnType> {\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<CollaborationOptions, CollaborationStorage>({\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              // Allow the transaction so ProseMirror state stays in sync with Yjs\n              // (Yjs transactions cannot be cancelled). Returning false would cause\n              // a state mismatch and prevent onContentError from working properly.\n              return true\n            }\n          },\n        }),\n    ].filter(Boolean)\n  },\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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"}