"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);

// src/index.ts
var index_exports = {};
__export(index_exports, {
  Editor: () => Editor,
  EditorContent: () => EditorContent,
  MarkViewContent: () => MarkViewContent,
  NodeViewContent: () => NodeViewContent,
  NodeViewWrapper: () => NodeViewWrapper,
  VueMarkView: () => VueMarkView,
  VueMarkViewRenderer: () => VueMarkViewRenderer,
  VueNodeViewRenderer: () => VueNodeViewRenderer,
  VueRenderer: () => VueRenderer,
  markViewProps: () => markViewProps,
  nodeViewProps: () => nodeViewProps,
  useEditor: () => useEditor
});
module.exports = __toCommonJS(index_exports);

// src/Editor.ts
var import_core = require("@tiptap/core");
var import_vue = require("vue");
function useDebouncedRef(value) {
  return (0, import_vue.customRef)((track, trigger) => {
    return {
      get() {
        track();
        return value;
      },
      set(newValue) {
        value = newValue;
        requestAnimationFrame(() => {
          requestAnimationFrame(() => {
            trigger();
          });
        });
      }
    };
  });
}
var Editor = class extends import_core.Editor {
  constructor(options = {}) {
    super(options);
    this.contentComponent = null;
    this.appContext = null;
    this.reactiveState = useDebouncedRef(this.view.state);
    this.reactiveExtensionStorage = useDebouncedRef(this.extensionStorage);
    this.on("beforeTransaction", ({ nextState }) => {
      this.reactiveState.value = nextState;
      this.reactiveExtensionStorage.value = this.extensionStorage;
    });
    return (0, import_vue.markRaw)(this);
  }
  get state() {
    return this.reactiveState ? this.reactiveState.value : this.view.state;
  }
  get storage() {
    return this.reactiveExtensionStorage ? this.reactiveExtensionStorage.value : super.storage;
  }
  /**
   * Register a ProseMirror plugin.
   */
  registerPlugin(plugin, handlePlugins) {
    const nextState = super.registerPlugin(plugin, handlePlugins);
    if (this.reactiveState) {
      this.reactiveState.value = nextState;
    }
    return nextState;
  }
  /**
   * Unregister a ProseMirror plugin.
   */
  unregisterPlugin(nameOrPluginKey) {
    const nextState = super.unregisterPlugin(nameOrPluginKey);
    if (this.reactiveState && nextState) {
      this.reactiveState.value = nextState;
    }
    return nextState;
  }
};

// src/EditorContent.ts
var import_vue2 = require("vue");
var EditorContent = (0, import_vue2.defineComponent)({
  name: "EditorContent",
  props: {
    editor: {
      default: null,
      type: Object
    }
  },
  setup(props) {
    const rootEl = (0, import_vue2.ref)();
    const instance = (0, import_vue2.getCurrentInstance)();
    (0, import_vue2.watchEffect)(() => {
      const editor = props.editor;
      if (editor && editor.options.element && rootEl.value) {
        (0, import_vue2.nextTick)(() => {
          var _a;
          if (!rootEl.value || !((_a = editor.view.dom) == null ? void 0 : _a.parentNode)) {
            return;
          }
          const element = (0, import_vue2.unref)(rootEl.value);
          rootEl.value.append(...editor.view.dom.parentNode.childNodes);
          editor.contentComponent = instance.ctx._;
          if (instance) {
            editor.appContext = {
              ...instance.appContext,
              // Vue internally uses prototype chain to forward/shadow injects across the entire component chain
              // so don't use object spread operator or 'Object.assign' and just set `provides` as is on editor's appContext
              // @ts-expect-error forward instance's 'provides' into appContext
              provides: instance.provides
            };
          }
          editor.setOptions({
            element
          });
          editor.createNodeViews();
        });
      }
    });
    (0, import_vue2.onBeforeUnmount)(() => {
      const editor = props.editor;
      if (!editor) {
        return;
      }
      editor.contentComponent = null;
      editor.appContext = null;
    });
    return { rootEl };
  },
  render() {
    return (0, import_vue2.h)("div", {
      ref: (el) => {
        this.rootEl = el;
      }
    });
  }
});

// src/NodeViewContent.ts
var import_vue3 = require("vue");
var NodeViewContent = (0, import_vue3.defineComponent)({
  name: "NodeViewContent",
  props: {
    as: {
      type: String,
      default: "div"
    }
  },
  render() {
    return (0, import_vue3.h)(this.as, {
      style: {
        whiteSpace: "pre-wrap"
      },
      "data-node-view-content": ""
    });
  }
});

// src/NodeViewWrapper.ts
var import_vue4 = require("vue");
var NodeViewWrapper = (0, import_vue4.defineComponent)({
  name: "NodeViewWrapper",
  props: {
    as: {
      type: String,
      default: "div"
    }
  },
  inject: ["onDragStart", "decorationClasses"],
  render() {
    var _a, _b;
    return (0, import_vue4.h)(
      this.as,
      {
        // @ts-ignore
        class: this.decorationClasses,
        style: {
          whiteSpace: "normal"
        },
        "data-node-view-wrapper": "",
        // @ts-ignore (https://github.com/vuejs/vue-next/issues/3031)
        onDragstart: this.onDragStart
      },
      (_b = (_a = this.$slots).default) == null ? void 0 : _b.call(_a)
    );
  }
});

// src/useEditor.ts
var import_vue5 = require("vue");
var useEditor = (options = {}) => {
  const editor = (0, import_vue5.shallowRef)();
  (0, import_vue5.onMounted)(() => {
    editor.value = new Editor(options);
  });
  (0, import_vue5.onBeforeUnmount)(() => {
    var _a, _b, _c, _d;
    const nodes = (_b = (_a = editor.value) == null ? void 0 : _a.view.dom) == null ? void 0 : _b.parentNode;
    const newEl = nodes == null ? void 0 : nodes.cloneNode(true);
    (_c = nodes == null ? void 0 : nodes.parentNode) == null ? void 0 : _c.replaceChild(newEl, nodes);
    (_d = editor.value) == null ? void 0 : _d.destroy();
  });
  return editor;
};

// src/VueMarkViewRenderer.ts
var import_core2 = require("@tiptap/core");
var import_vue7 = require("vue");

// src/VueRenderer.ts
var import_vue6 = require("vue");
var VueRenderer = class {
  constructor(component, { props = {}, editor }) {
    /**
     * Flag to track if the renderer has been destroyed, preventing queued or asynchronous renders from executing after teardown.
     */
    this.destroyed = false;
    this.editor = editor;
    this.component = (0, import_vue6.markRaw)(component);
    this.el = document.createElement("div");
    this.props = (0, import_vue6.reactive)(props);
    this.renderedComponent = this.renderComponent();
  }
  get element() {
    return this.renderedComponent.el;
  }
  get ref() {
    var _a, _b, _c, _d;
    if ((_b = (_a = this.renderedComponent.vNode) == null ? void 0 : _a.component) == null ? void 0 : _b.exposed) {
      return this.renderedComponent.vNode.component.exposed;
    }
    return (_d = (_c = this.renderedComponent.vNode) == null ? void 0 : _c.component) == null ? void 0 : _d.proxy;
  }
  renderComponent() {
    if (this.destroyed) {
      return this.renderedComponent;
    }
    let vNode = (0, import_vue6.h)(this.component, this.props);
    if (this.editor.appContext) {
      vNode.appContext = this.editor.appContext;
    }
    if (typeof document !== "undefined" && this.el) {
      (0, import_vue6.render)(vNode, this.el);
    }
    const destroy = () => {
      if (this.el) {
        (0, import_vue6.render)(null, this.el);
      }
      this.el = null;
      vNode = null;
    };
    return { vNode, destroy, el: this.el ? this.el.firstElementChild : null };
  }
  updateProps(props = {}) {
    if (this.destroyed) {
      return;
    }
    Object.entries(props).forEach(([key, value]) => {
      this.props[key] = value;
    });
    this.renderComponent();
  }
  destroy() {
    if (this.destroyed) {
      return;
    }
    this.destroyed = true;
    this.renderedComponent.destroy();
  }
};

// src/VueMarkViewRenderer.ts
var markViewProps = {
  editor: {
    type: Object,
    required: true
  },
  mark: {
    type: Object,
    required: true
  },
  extension: {
    type: Object,
    required: true
  },
  inline: {
    type: Boolean,
    required: true
  },
  view: {
    type: Object,
    required: true
  },
  updateAttributes: {
    type: Function,
    required: true
  },
  HTMLAttributes: {
    type: Object,
    required: true
  }
};
var MarkViewContent = (0, import_vue7.defineComponent)({
  name: "MarkViewContent",
  props: {
    as: {
      type: String,
      default: "span"
    }
  },
  render() {
    return (0, import_vue7.h)(this.as, {
      style: {
        whiteSpace: "inherit"
      },
      "data-mark-view-content": ""
    });
  }
});
var VueMarkView = class extends import_core2.MarkView {
  constructor(component, props, options) {
    super(component, props, options);
    const componentProps = { ...props, updateAttributes: this.updateAttributes.bind(this) };
    const extendedComponent = (0, import_vue7.defineComponent)({
      extends: { ...component },
      props: Object.keys(componentProps),
      template: this.component.template,
      setup: (reactiveProps) => {
        var _a;
        return (_a = component.setup) == null ? void 0 : _a.call(component, reactiveProps, {
          expose: () => void 0
        });
      },
      // Add support for scoped styles
      __scopeId: component.__scopeId,
      __cssModules: component.__cssModules,
      __name: component.__name,
      __file: component.__file
    });
    this.renderer = new VueRenderer(extendedComponent, {
      editor: this.editor,
      props: componentProps
    });
  }
  get dom() {
    return this.renderer.element;
  }
  get contentDOM() {
    return this.dom.querySelector("[data-mark-view-content]");
  }
  updateAttributes(attrs) {
    const unproxiedMark = (0, import_vue7.toRaw)(this.mark);
    super.updateAttributes(attrs, unproxiedMark);
  }
  destroy() {
    this.renderer.destroy();
  }
};
function VueMarkViewRenderer(component, options = {}) {
  return (props) => {
    if (!props.editor.contentComponent) {
      return {};
    }
    return new VueMarkView(component, props, options);
  };
}

// src/VueNodeViewRenderer.ts
var import_core3 = require("@tiptap/core");
var import_vue8 = require("vue");
var nodeViewProps = {
  editor: {
    type: Object,
    required: true
  },
  node: {
    type: Object,
    required: true
  },
  decorations: {
    type: Object,
    required: true
  },
  selected: {
    type: Boolean,
    required: true
  },
  extension: {
    type: Object,
    required: true
  },
  getPos: {
    type: Function,
    required: true
  },
  updateAttributes: {
    type: Function,
    required: true
  },
  deleteNode: {
    type: Function,
    required: true
  },
  view: {
    type: Object,
    required: true
  },
  innerDecorations: {
    type: Object,
    required: true
  },
  HTMLAttributes: {
    type: Object,
    required: true
  }
};
var VueNodeView = class extends import_core3.NodeView {
  constructor() {
    super(...arguments);
    this.cachedExtensionWithSyncedStorage = null;
  }
  /**
   * Returns a proxy of the extension that redirects storage access to the editor's mutable storage.
   * This preserves the original prototype chain (instanceof checks, methods like configure/extend work).
   * Cached to avoid proxy creation on every update.
   */
  get extensionWithSyncedStorage() {
    if (!this.cachedExtensionWithSyncedStorage) {
      const editor = this.editor;
      const extension = this.extension;
      this.cachedExtensionWithSyncedStorage = new Proxy(extension, {
        get(target, prop, receiver) {
          var _a;
          if (prop === "storage") {
            return (_a = editor.storage[extension.name]) != null ? _a : {};
          }
          return Reflect.get(target, prop, receiver);
        }
      });
    }
    return this.cachedExtensionWithSyncedStorage;
  }
  mount() {
    const props = {
      editor: this.editor,
      node: this.node,
      decorations: this.decorations,
      innerDecorations: this.innerDecorations,
      view: this.view,
      selected: false,
      extension: this.extensionWithSyncedStorage,
      HTMLAttributes: this.HTMLAttributes,
      getPos: () => this.getPos(),
      updateAttributes: (attributes = {}) => this.updateAttributes(attributes),
      deleteNode: () => this.deleteNode()
    };
    const onDragStart = this.onDragStart.bind(this);
    this.decorationClasses = (0, import_vue8.ref)(this.getDecorationClasses());
    const extendedComponent = (0, import_vue8.defineComponent)({
      extends: { ...this.component },
      props: Object.keys(props),
      template: this.component.template,
      setup: (reactiveProps) => {
        var _a, _b;
        (0, import_vue8.provide)("onDragStart", onDragStart);
        (0, import_vue8.provide)("decorationClasses", this.decorationClasses);
        return (_b = (_a = this.component).setup) == null ? void 0 : _b.call(_a, reactiveProps, {
          expose: () => void 0
        });
      },
      // add support for scoped styles
      // @ts-ignore
      // eslint-disable-next-line
      __scopeId: this.component.__scopeId,
      // add support for CSS Modules
      // @ts-ignore
      // eslint-disable-next-line
      __cssModules: this.component.__cssModules,
      // add support for vue devtools
      // @ts-ignore
      // eslint-disable-next-line
      __name: this.component.__name,
      // @ts-ignore
      // eslint-disable-next-line
      __file: this.component.__file
    });
    this.handleSelectionUpdate = this.handleSelectionUpdate.bind(this);
    this.editor.on("selectionUpdate", this.handleSelectionUpdate);
    this.renderer = new VueRenderer(extendedComponent, {
      editor: this.editor,
      props
    });
  }
  /**
   * Return the DOM element.
   * This is the element that will be used to display the node view.
   */
  get dom() {
    if (!this.renderer.element || !this.renderer.element.hasAttribute("data-node-view-wrapper")) {
      throw Error("Please use the NodeViewWrapper component for your node view.");
    }
    return this.renderer.element;
  }
  /**
   * Return the content DOM element.
   * This is the element that will be used to display the rich-text content of the node.
   */
  get contentDOM() {
    if (this.node.isLeaf) {
      return null;
    }
    return this.dom.querySelector("[data-node-view-content]");
  }
  /**
   * On editor selection update, check if the node is selected.
   * If it is, call `selectNode`, otherwise call `deselectNode`.
   */
  handleSelectionUpdate() {
    const { from, to } = this.editor.state.selection;
    const pos = this.getPos();
    if (typeof pos !== "number") {
      return;
    }
    if (from <= pos && to >= pos + this.node.nodeSize) {
      if (this.renderer.props.selected) {
        return;
      }
      this.selectNode();
    } else {
      if (!this.renderer.props.selected) {
        return;
      }
      this.deselectNode();
    }
  }
  /**
   * On update, update the React component.
   * To prevent unnecessary updates, the `update` option can be used.
   */
  update(node, decorations, innerDecorations) {
    const rerenderComponent = (props) => {
      this.decorationClasses.value = this.getDecorationClasses();
      this.renderer.updateProps(props);
    };
    if (typeof this.options.update === "function") {
      const oldNode = this.node;
      const oldDecorations = this.decorations;
      const oldInnerDecorations = this.innerDecorations;
      this.node = node;
      this.decorations = decorations;
      this.innerDecorations = innerDecorations;
      return this.options.update({
        oldNode,
        oldDecorations,
        newNode: node,
        newDecorations: decorations,
        oldInnerDecorations,
        innerDecorations,
        updateProps: () => rerenderComponent({ node, decorations, innerDecorations, extension: this.extensionWithSyncedStorage })
      });
    }
    if (node.type !== this.node.type) {
      return false;
    }
    if (node === this.node && this.decorations === decorations && this.innerDecorations === innerDecorations) {
      return true;
    }
    this.node = node;
    this.decorations = decorations;
    this.innerDecorations = innerDecorations;
    rerenderComponent({ node, decorations, innerDecorations, extension: this.extensionWithSyncedStorage });
    return true;
  }
  /**
   * Select the node.
   * Add the `selected` prop and the `ProseMirror-selectednode` class.
   */
  selectNode() {
    this.renderer.updateProps({
      selected: true
    });
    if (this.renderer.element) {
      this.renderer.element.classList.add("ProseMirror-selectednode");
    }
  }
  /**
   * Deselect the node.
   * Remove the `selected` prop and the `ProseMirror-selectednode` class.
   */
  deselectNode() {
    this.renderer.updateProps({
      selected: false
    });
    if (this.renderer.element) {
      this.renderer.element.classList.remove("ProseMirror-selectednode");
    }
  }
  getDecorationClasses() {
    return this.decorations.flatMap((item) => item.type.attrs.class).join(" ");
  }
  destroy() {
    this.renderer.destroy();
    this.editor.off("selectionUpdate", this.handleSelectionUpdate);
  }
};
function VueNodeViewRenderer(component, options) {
  return (props) => {
    if (!props.editor.contentComponent) {
      return {};
    }
    const normalizedComponent = typeof component === "function" && "__vccOpts" in component ? component.__vccOpts : component;
    return new VueNodeView(normalizedComponent, props, options);
  };
}

// src/index.ts
__reExport(index_exports, require("@tiptap/core"), module.exports);
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  Editor,
  EditorContent,
  MarkViewContent,
  NodeViewContent,
  NodeViewWrapper,
  VueMarkView,
  VueMarkViewRenderer,
  VueNodeViewRenderer,
  VueRenderer,
  markViewProps,
  nodeViewProps,
  useEditor,
  ...require("@tiptap/core")
});
//# sourceMappingURL=index.cjs.map