{"version":3,"file":"index.cjs","sources":["../src/collaboration.ts","../src/helpers/isChangeOrigin.ts"],"sourcesContent":["import { Extension } from '@tiptap/core'\nimport { Plugin, PluginKey } from '@tiptap/pm/state'\nimport { EditorView } from '@tiptap/pm/view'\nimport {\n  redo,\n  undo,\n  ySyncPlugin,\n  yUndoPlugin,\n  yUndoPluginKey,\n  yXmlFragmentToProsemirrorJSON,\n} from 'y-prosemirror'\nimport { Doc, UndoManager, XmlFragment } from 'yjs'\n\ntype YSyncOpts = Parameters<typeof ySyncPlugin>[1];\ntype YUndoOpts = Parameters<typeof yUndoPlugin>[0];\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\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\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   * 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    }\n  },\n\n  addStorage() {\n    return {\n      isDisabled: false,\n    }\n  },\n\n  onCreate() {\n    if (this.editor.extensionManager.extensions.find(extension => extension.name === 'history')) {\n      console.warn(\n        '[tiptap warn]: \"@tiptap/extension-collaboration\" comes with its own history support and is not compatible with \"@tiptap/extension-history\".',\n      )\n    }\n  },\n\n  addCommands() {\n    return {\n      undo:\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        () => ({ 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) {\n              // Destroy the Yjs document to prevent any further sync transactions\n              fragment.doc?.destroy()\n\n              return true\n            }\n\n            return true\n          },\n        }),\n    ].filter(Boolean)\n  },\n})\n","import { Transaction } from '@tiptap/pm/state'\nimport { ySyncPluginKey } from 'y-prosemirror'\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"],"names":["Extension","yUndoPluginKey","undo","redo","yUndoPlugin","ySyncPlugin","yXmlFragmentToProsemirrorJSON","Plugin","PluginKey","ySyncPluginKey"],"mappings":"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"}