{"version":3,"sources":["../src/index.ts","../src/collaboration.ts","../src/helpers/isChangeOrigin.ts"],"sourcesContent":["import { Collaboration } from './collaboration.js'\n\nexport * from './collaboration.js'\nexport * from './helpers/isChangeOrigin.js'\n\nexport default Collaboration\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, yXmlFragmentToProsemirrorJSON } from '@tiptap/y-tiptap'\nimport type { Doc, UndoManager, XmlFragment } from 'yjs'\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  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          // eslint-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            // eslint-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    if (this.editor.options.enableContentCheck) {\n      fragment.doc?.on('beforeTransaction', () => {\n        try {\n          const jsonContent = yXmlFragmentToProsemirrorJSON(fragment)\n\n          if (jsonContent.content.length === 0) {\n            return\n          }\n\n          this.editor.schema.nodeFromJSON(jsonContent).check()\n        } catch (error) {\n          this.editor.emit('contentError', {\n            error: error as Error,\n            editor: this.editor,\n            disableCollaboration: () => {\n              fragment.doc?.destroy()\n              this.storage.isDisabled = true\n            },\n          })\n          // If the content is invalid, return false to prevent the transaction from being applied\n          return false\n        }\n      })\n    }\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: () => {\n            // When collaboration is disabled, prevent any sync transactions from being applied\n            if (this.storage.isDisabled !== false) {\n              // Destroy the Yjs document to prevent any further sync transactions\n              fragment.doc?.destroy()\n\n              return true\n            }\n            // TODO should we be returning false when the transaction is a collaboration transaction?\n\n            return true\n          },\n        }),\n    ].filter(Boolean)\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"],"mappings":"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","names":["_a","import_y_tiptap"]}