import { BubbleMenuPlugin as g } from "@tiptap/extension-bubble-menu";
import { defineComponent as d, ref as l, onMounted as c, onBeforeUnmount as a, h as u, getCurrentInstance as y, watchEffect as b, nextTick as C, unref as w, markRaw as f, shallowRef as S, reactive as _, render as h, customRef as x, provide as v } from "vue";
import { Editor as N, NodeView as O } from "@tiptap/core";
export * from "@tiptap/core";
import { FloatingMenuPlugin as P } from "@tiptap/extension-floating-menu";
const A = d({
  name: "BubbleMenu",
  props: {
    pluginKey: {
      type: [String, Object],
      default: "bubbleMenu"
    },
    editor: {
      type: Object,
      required: !0
    },
    updateDelay: {
      type: Number,
      default: void 0
    },
    tippyOptions: {
      type: Object,
      default: () => ({})
    },
    shouldShow: {
      type: Function,
      default: null
    }
  },
  setup(r, { slots: t }) {
    const n = l(null);
    return c(() => {
      const { updateDelay: e, editor: o, pluginKey: i, shouldShow: s, tippyOptions: p } = r;
      o.registerPlugin(g({
        updateDelay: e,
        editor: o,
        element: n.value,
        pluginKey: i,
        shouldShow: s,
        tippyOptions: p
      }));
    }), a(() => {
      const { pluginKey: e, editor: o } = r;
      o.unregisterPlugin(e);
    }), () => {
      var e;
      return u("div", { ref: n }, (e = t.default) === null || e === void 0 ? void 0 : e.call(t));
    };
  }
});
function m(r) {
  return x((t, n) => ({
    get() {
      return t(), r;
    },
    set(e) {
      r = e, requestAnimationFrame(() => {
        requestAnimationFrame(() => {
          n();
        });
      });
    }
  }));
}
class D extends N {
  constructor(t = {}) {
    return super(t), this.contentComponent = null, this.appContext = null, this.reactiveState = m(this.view.state), this.reactiveExtensionStorage = m(this.extensionStorage), this.on("beforeTransaction", ({ nextState: n }) => {
      this.reactiveState.value = n, this.reactiveExtensionStorage.value = this.extensionStorage;
    }), f(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(t, n) {
    const e = super.registerPlugin(t, n);
    return this.reactiveState && (this.reactiveState.value = e), e;
  }
  /**
   * Unregister a ProseMirror plugin.
   */
  unregisterPlugin(t) {
    const n = super.unregisterPlugin(t);
    return this.reactiveState && n && (this.reactiveState.value = n), n;
  }
}
const U = d({
  name: "EditorContent",
  props: {
    editor: {
      default: null,
      type: Object
    }
  },
  setup(r) {
    const t = l(), n = y();
    return b(() => {
      const e = r.editor;
      e && e.options.element && t.value && C(() => {
        if (!t.value || !e.options.element.firstChild)
          return;
        const o = w(t.value);
        t.value.append(...e.options.element.childNodes), e.contentComponent = n.ctx._, n && (e.appContext = {
          ...n.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: n.provides
        }), e.setOptions({
          element: o
        }), e.createNodeViews();
      });
    }), a(() => {
      const e = r.editor;
      e && (e.contentComponent = null, e.appContext = null);
    }), { rootEl: t };
  },
  render() {
    return u("div", {
      ref: (r) => {
        this.rootEl = r;
      }
    });
  }
}), K = d({
  name: "FloatingMenu",
  props: {
    pluginKey: {
      // TODO: TypeScript breaks :(
      // type: [String, Object as PropType<Exclude<FloatingMenuPluginProps['pluginKey'], string>>],
      type: null,
      default: "floatingMenu"
    },
    editor: {
      type: Object,
      required: !0
    },
    tippyOptions: {
      type: Object,
      default: () => ({})
    },
    shouldShow: {
      type: Function,
      default: null
    }
  },
  setup(r, { slots: t }) {
    const n = l(null);
    return c(() => {
      const { pluginKey: e, editor: o, tippyOptions: i, shouldShow: s } = r;
      o.registerPlugin(P({
        pluginKey: e,
        editor: o,
        element: n.value,
        tippyOptions: i,
        shouldShow: s
      }));
    }), a(() => {
      const { pluginKey: e, editor: o } = r;
      o.unregisterPlugin(e);
    }), () => {
      var e;
      return u("div", { ref: n }, (e = t.default) === null || e === void 0 ? void 0 : e.call(t));
    };
  }
}), L = d({
  name: "NodeViewContent",
  props: {
    as: {
      type: String,
      default: "div"
    }
  },
  render() {
    return u(this.as, {
      style: {
        whiteSpace: "pre-wrap"
      },
      "data-node-view-content": ""
    });
  }
}), R = d({
  name: "NodeViewWrapper",
  props: {
    as: {
      type: String,
      default: "div"
    }
  },
  inject: ["onDragStart", "decorationClasses"],
  render() {
    var r, t;
    return u(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
    }, (t = (r = this.$slots).default) === null || t === void 0 ? void 0 : t.call(r));
  }
}), B = (r = {}) => {
  const t = S();
  return c(() => {
    t.value = new D(r);
  }), a(() => {
    var n, e, o;
    const i = (n = t.value) === null || n === void 0 ? void 0 : n.options.element, s = i == null ? void 0 : i.cloneNode(!0);
    (e = i == null ? void 0 : i.parentNode) === null || e === void 0 || e.replaceChild(s, i), (o = t.value) === null || o === void 0 || o.destroy();
  }), t;
};
class E {
  constructor(t, { props: n = {}, editor: e }) {
    this.editor = e, this.component = f(t), this.el = document.createElement("div"), this.props = _(n), this.renderedComponent = this.renderComponent();
  }
  get element() {
    return this.renderedComponent.el;
  }
  get ref() {
    var t, n, e, o;
    return !((n = (t = this.renderedComponent.vNode) === null || t === void 0 ? void 0 : t.component) === null || n === void 0) && n.exposed ? this.renderedComponent.vNode.component.exposed : (o = (e = this.renderedComponent.vNode) === null || e === void 0 ? void 0 : e.component) === null || o === void 0 ? void 0 : o.proxy;
  }
  renderComponent() {
    let t = u(this.component, this.props);
    return this.editor.appContext && (t.appContext = this.editor.appContext), typeof document < "u" && this.el && h(t, this.el), { vNode: t, destroy: () => {
      this.el && h(null, this.el), this.el = null, t = null;
    }, el: this.el ? this.el.firstElementChild : null };
  }
  updateProps(t = {}) {
    Object.entries(t).forEach(([n, e]) => {
      this.props[n] = e;
    }), this.renderComponent();
  }
  destroy() {
    this.renderedComponent.destroy();
  }
}
const T = {
  editor: {
    type: Object,
    required: !0
  },
  node: {
    type: Object,
    required: !0
  },
  decorations: {
    type: Object,
    required: !0
  },
  selected: {
    type: Boolean,
    required: !0
  },
  extension: {
    type: Object,
    required: !0
  },
  getPos: {
    type: Function,
    required: !0
  },
  updateAttributes: {
    type: Function,
    required: !0
  },
  deleteNode: {
    type: Function,
    required: !0
  },
  view: {
    type: Object,
    required: !0
  },
  innerDecorations: {
    type: Object,
    required: !0
  },
  HTMLAttributes: {
    type: Object,
    required: !0
  }
};
class j extends O {
  mount() {
    const t = {
      editor: this.editor,
      node: this.node,
      decorations: this.decorations,
      innerDecorations: this.innerDecorations,
      view: this.view,
      selected: !1,
      extension: this.extension,
      HTMLAttributes: this.HTMLAttributes,
      getPos: () => this.getPos(),
      updateAttributes: (o = {}) => this.updateAttributes(o),
      deleteNode: () => this.deleteNode()
    }, n = this.onDragStart.bind(this);
    this.decorationClasses = l(this.getDecorationClasses());
    const e = d({
      extends: { ...this.component },
      props: Object.keys(t),
      template: this.component.template,
      setup: (o) => {
        var i, s;
        return v("onDragStart", n), v("decorationClasses", this.decorationClasses), (s = (i = this.component).setup) === null || s === void 0 ? void 0 : s.call(i, o, {
          expose: () => {
          }
        });
      },
      // 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 E(e, {
      editor: this.editor,
      props: t
    });
  }
  /**
   * 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() {
    return this.node.isLeaf ? null : 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: t, to: n } = this.editor.state.selection, e = this.getPos();
    if (typeof e == "number")
      if (t <= e && n >= e + 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(t, n, e) {
    const o = (i) => {
      this.decorationClasses.value = this.getDecorationClasses(), this.renderer.updateProps(i);
    };
    if (typeof this.options.update == "function") {
      const i = this.node, s = this.decorations, p = this.innerDecorations;
      return this.node = t, this.decorations = n, this.innerDecorations = e, this.options.update({
        oldNode: i,
        oldDecorations: s,
        newNode: t,
        newDecorations: n,
        oldInnerDecorations: p,
        innerDecorations: e,
        updateProps: () => o({ node: t, decorations: n, innerDecorations: e })
      });
    }
    return t.type !== this.node.type ? !1 : (t === this.node && this.decorations === n && this.innerDecorations === e || (this.node = t, this.decorations = n, this.innerDecorations = e, o({ node: t, decorations: n, innerDecorations: e })), !0);
  }
  /**
   * Select the node.
   * Add the `selected` prop and the `ProseMirror-selectednode` class.
   */
  selectNode() {
    this.renderer.updateProps({
      selected: !0
    }), 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: !1
    }), this.renderer.element && this.renderer.element.classList.remove("ProseMirror-selectednode");
  }
  getDecorationClasses() {
    return this.decorations.map((t) => t.type.attrs.class).flat().join(" ");
  }
  destroy() {
    this.renderer.destroy(), this.editor.off("selectionUpdate", this.handleSelectionUpdate);
  }
}
function I(r, t) {
  return (n) => {
    if (!n.editor.contentComponent)
      return {};
    const e = typeof r == "function" && "__vccOpts" in r ? r.__vccOpts : r;
    return new j(e, n, t);
  };
}
export {
  A as BubbleMenu,
  D as Editor,
  U as EditorContent,
  K as FloatingMenu,
  L as NodeViewContent,
  R as NodeViewWrapper,
  I as VueNodeViewRenderer,
  E as VueRenderer,
  T as nodeViewProps,
  B as useEditor
};
//# sourceMappingURL=vue-3.js.map
