import { BubbleMenuPlugin } from '@tiptap/extension-bubble-menu';
import React, { forwardRef, useState, useDebugValue, useLayoutEffect, useEffect, useRef, createContext, useContext, version, createRef, memo, createElement } from 'react';
import ReactDOM, { flushSync } from 'react-dom';
import { Editor, NodeView, getRenderedAttributes } from '@tiptap/core';
export * from '@tiptap/core';
import { FloatingMenuPlugin } from '@tiptap/extension-floating-menu';

function getDefaultExportFromCjs (x) {
	return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
}

var shim = {exports: {}};

var useSyncExternalStoreShim_production_min = {};

/**
 * @license React
 * use-sync-external-store-shim.production.min.js
 *
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

var hasRequiredUseSyncExternalStoreShim_production_min;

function requireUseSyncExternalStoreShim_production_min () {
	if (hasRequiredUseSyncExternalStoreShim_production_min) return useSyncExternalStoreShim_production_min;
	hasRequiredUseSyncExternalStoreShim_production_min = 1;
var e=React;function h(a,b){return a===b&&(0!==a||1/a===1/b)||a!==a&&b!==b}var k="function"===typeof Object.is?Object.is:h,l=e.useState,m=e.useEffect,n=e.useLayoutEffect,p=e.useDebugValue;function q(a,b){var d=b(),f=l({inst:{value:d,getSnapshot:b}}),c=f[0].inst,g=f[1];n(function(){c.value=d;c.getSnapshot=b;r(c)&&g({inst:c});},[a,d,b]);m(function(){r(c)&&g({inst:c});return a(function(){r(c)&&g({inst:c});})},[a]);p(d);return d}
	function r(a){var b=a.getSnapshot;a=a.value;try{var d=b();return !k(a,d)}catch(f){return !0}}function t(a,b){return b()}var u="undefined"===typeof window||"undefined"===typeof window.document||"undefined"===typeof window.document.createElement?t:q;useSyncExternalStoreShim_production_min.useSyncExternalStore=void 0!==e.useSyncExternalStore?e.useSyncExternalStore:u;
	return useSyncExternalStoreShim_production_min;
}

var useSyncExternalStoreShim_development = {};

/**
 * @license React
 * use-sync-external-store-shim.development.js
 *
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

var hasRequiredUseSyncExternalStoreShim_development;

function requireUseSyncExternalStoreShim_development () {
	if (hasRequiredUseSyncExternalStoreShim_development) return useSyncExternalStoreShim_development;
	hasRequiredUseSyncExternalStoreShim_development = 1;

	if (process.env.NODE_ENV !== "production") {
	  (function() {

	/* global __REACT_DEVTOOLS_GLOBAL_HOOK__ */
	if (
	  typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== 'undefined' &&
	  typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart ===
	    'function'
	) {
	  __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(new Error());
	}
	          var React$1 = React;

	var ReactSharedInternals = React$1.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;

	function error(format) {
	  {
	    {
	      for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
	        args[_key2 - 1] = arguments[_key2];
	      }

	      printWarning('error', format, args);
	    }
	  }
	}

	function printWarning(level, format, args) {
	  // When changing this logic, you might want to also
	  // update consoleWithStackDev.www.js as well.
	  {
	    var ReactDebugCurrentFrame = ReactSharedInternals.ReactDebugCurrentFrame;
	    var stack = ReactDebugCurrentFrame.getStackAddendum();

	    if (stack !== '') {
	      format += '%s';
	      args = args.concat([stack]);
	    } // eslint-disable-next-line react-internal/safe-string-coercion


	    var argsWithFormat = args.map(function (item) {
	      return String(item);
	    }); // Careful: RN currently depends on this prefix

	    argsWithFormat.unshift('Warning: ' + format); // We intentionally don't use spread (or .apply) directly because it
	    // breaks IE9: https://github.com/facebook/react/issues/13610
	    // eslint-disable-next-line react-internal/no-production-logging

	    Function.prototype.apply.call(console[level], console, argsWithFormat);
	  }
	}

	/**
	 * inlined Object.is polyfill to avoid requiring consumers ship their own
	 * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
	 */
	function is(x, y) {
	  return x === y && (x !== 0 || 1 / x === 1 / y) || x !== x && y !== y // eslint-disable-line no-self-compare
	  ;
	}

	var objectIs = typeof Object.is === 'function' ? Object.is : is;

	// dispatch for CommonJS interop named imports.

	var useState = React$1.useState,
	    useEffect = React$1.useEffect,
	    useLayoutEffect = React$1.useLayoutEffect,
	    useDebugValue = React$1.useDebugValue;
	var didWarnOld18Alpha = false;
	var didWarnUncachedGetSnapshot = false; // Disclaimer: This shim breaks many of the rules of React, and only works
	// because of a very particular set of implementation details and assumptions
	// -- change any one of them and it will break. The most important assumption
	// is that updates are always synchronous, because concurrent rendering is
	// only available in versions of React that also have a built-in
	// useSyncExternalStore API. And we only use this shim when the built-in API
	// does not exist.
	//
	// Do not assume that the clever hacks used by this hook also work in general.
	// The point of this shim is to replace the need for hacks by other libraries.

	function useSyncExternalStore(subscribe, getSnapshot, // Note: The shim does not use getServerSnapshot, because pre-18 versions of
	// React do not expose a way to check if we're hydrating. So users of the shim
	// will need to track that themselves and return the correct value
	// from `getSnapshot`.
	getServerSnapshot) {
	  {
	    if (!didWarnOld18Alpha) {
	      if (React$1.startTransition !== undefined) {
	        didWarnOld18Alpha = true;

	        error('You are using an outdated, pre-release alpha of React 18 that ' + 'does not support useSyncExternalStore. The ' + 'use-sync-external-store shim will not work correctly. Upgrade ' + 'to a newer pre-release.');
	      }
	    }
	  } // Read the current snapshot from the store on every render. Again, this
	  // breaks the rules of React, and only works here because of specific
	  // implementation details, most importantly that updates are
	  // always synchronous.


	  var value = getSnapshot();

	  {
	    if (!didWarnUncachedGetSnapshot) {
	      var cachedValue = getSnapshot();

	      if (!objectIs(value, cachedValue)) {
	        error('The result of getSnapshot should be cached to avoid an infinite loop');

	        didWarnUncachedGetSnapshot = true;
	      }
	    }
	  } // Because updates are synchronous, we don't queue them. Instead we force a
	  // re-render whenever the subscribed state changes by updating an some
	  // arbitrary useState hook. Then, during render, we call getSnapshot to read
	  // the current value.
	  //
	  // Because we don't actually use the state returned by the useState hook, we
	  // can save a bit of memory by storing other stuff in that slot.
	  //
	  // To implement the early bailout, we need to track some things on a mutable
	  // object. Usually, we would put that in a useRef hook, but we can stash it in
	  // our useState hook instead.
	  //
	  // To force a re-render, we call forceUpdate({inst}). That works because the
	  // new object always fails an equality check.


	  var _useState = useState({
	    inst: {
	      value: value,
	      getSnapshot: getSnapshot
	    }
	  }),
	      inst = _useState[0].inst,
	      forceUpdate = _useState[1]; // Track the latest getSnapshot function with a ref. This needs to be updated
	  // in the layout phase so we can access it during the tearing check that
	  // happens on subscribe.


	  useLayoutEffect(function () {
	    inst.value = value;
	    inst.getSnapshot = getSnapshot; // Whenever getSnapshot or subscribe changes, we need to check in the
	    // commit phase if there was an interleaved mutation. In concurrent mode
	    // this can happen all the time, but even in synchronous mode, an earlier
	    // effect may have mutated the store.

	    if (checkIfSnapshotChanged(inst)) {
	      // Force a re-render.
	      forceUpdate({
	        inst: inst
	      });
	    }
	  }, [subscribe, value, getSnapshot]);
	  useEffect(function () {
	    // Check for changes right before subscribing. Subsequent changes will be
	    // detected in the subscription handler.
	    if (checkIfSnapshotChanged(inst)) {
	      // Force a re-render.
	      forceUpdate({
	        inst: inst
	      });
	    }

	    var handleStoreChange = function () {
	      // TODO: Because there is no cross-renderer API for batching updates, it's
	      // up to the consumer of this library to wrap their subscription event
	      // with unstable_batchedUpdates. Should we try to detect when this isn't
	      // the case and print a warning in development?
	      // The store changed. Check if the snapshot changed since the last time we
	      // read from the store.
	      if (checkIfSnapshotChanged(inst)) {
	        // Force a re-render.
	        forceUpdate({
	          inst: inst
	        });
	      }
	    }; // Subscribe to the store and return a clean-up function.


	    return subscribe(handleStoreChange);
	  }, [subscribe]);
	  useDebugValue(value);
	  return value;
	}

	function checkIfSnapshotChanged(inst) {
	  var latestGetSnapshot = inst.getSnapshot;
	  var prevValue = inst.value;

	  try {
	    var nextValue = latestGetSnapshot();
	    return !objectIs(prevValue, nextValue);
	  } catch (error) {
	    return true;
	  }
	}

	function useSyncExternalStore$1(subscribe, getSnapshot, getServerSnapshot) {
	  // Note: The shim does not use getServerSnapshot, because pre-18 versions of
	  // React do not expose a way to check if we're hydrating. So users of the shim
	  // will need to track that themselves and return the correct value
	  // from `getSnapshot`.
	  return getSnapshot();
	}

	var canUseDOM = !!(typeof window !== 'undefined' && typeof window.document !== 'undefined' && typeof window.document.createElement !== 'undefined');

	var isServerEnvironment = !canUseDOM;

	var shim = isServerEnvironment ? useSyncExternalStore$1 : useSyncExternalStore;
	var useSyncExternalStore$2 = React$1.useSyncExternalStore !== undefined ? React$1.useSyncExternalStore : shim;

	useSyncExternalStoreShim_development.useSyncExternalStore = useSyncExternalStore$2;
	          /* global __REACT_DEVTOOLS_GLOBAL_HOOK__ */
	if (
	  typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== 'undefined' &&
	  typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop ===
	    'function'
	) {
	  __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop(new Error());
	}
	        
	  })();
	}
	return useSyncExternalStoreShim_development;
}

if (process.env.NODE_ENV === 'production') {
  shim.exports = requireUseSyncExternalStoreShim_production_min();
} else {
  shim.exports = requireUseSyncExternalStoreShim_development();
}

var shimExports = shim.exports;

const mergeRefs = (...refs) => {
    return (node) => {
        refs.forEach(ref => {
            if (typeof ref === 'function') {
                ref(node);
            }
            else if (ref) {
                ref.current = node;
            }
        });
    };
};
/**
 * This component renders all of the editor's node views.
 */
const Portals = ({ contentComponent, }) => {
    // For performance reasons, we render the node view portals on state changes only
    const renderers = shimExports.useSyncExternalStore(contentComponent.subscribe, contentComponent.getSnapshot, contentComponent.getServerSnapshot);
    // This allows us to directly render the portals without any additional wrapper
    return (React.createElement(React.Fragment, null, Object.values(renderers)));
};
function getInstance() {
    const subscribers = new Set();
    let renderers = {};
    return {
        /**
         * Subscribe to the editor instance's changes.
         */
        subscribe(callback) {
            subscribers.add(callback);
            return () => {
                subscribers.delete(callback);
            };
        },
        getSnapshot() {
            return renderers;
        },
        getServerSnapshot() {
            return renderers;
        },
        /**
         * Adds a new NodeView Renderer to the editor.
         */
        setRenderer(id, renderer) {
            renderers = {
                ...renderers,
                [id]: ReactDOM.createPortal(renderer.reactElement, renderer.element, id),
            };
            subscribers.forEach(subscriber => subscriber());
        },
        /**
         * Removes a NodeView Renderer from the editor.
         */
        removeRenderer(id) {
            const nextRenderers = { ...renderers };
            delete nextRenderers[id];
            renderers = nextRenderers;
            subscribers.forEach(subscriber => subscriber());
        },
    };
}
class PureEditorContent extends React.Component {
    constructor(props) {
        var _a;
        super(props);
        this.editorContentRef = React.createRef();
        this.initialized = false;
        this.state = {
            hasContentComponentInitialized: Boolean((_a = props.editor) === null || _a === void 0 ? void 0 : _a.contentComponent),
        };
    }
    componentDidMount() {
        this.init();
    }
    componentDidUpdate() {
        this.init();
    }
    init() {
        const editor = this.props.editor;
        if (editor && !editor.isDestroyed && editor.options.element) {
            if (editor.contentComponent) {
                return;
            }
            const element = this.editorContentRef.current;
            element.append(...editor.options.element.childNodes);
            editor.setOptions({
                element,
            });
            editor.contentComponent = getInstance();
            // Has the content component been initialized?
            if (!this.state.hasContentComponentInitialized) {
                // Subscribe to the content component
                this.unsubscribeToContentComponent = editor.contentComponent.subscribe(() => {
                    this.setState(prevState => {
                        if (!prevState.hasContentComponentInitialized) {
                            return {
                                hasContentComponentInitialized: true,
                            };
                        }
                        return prevState;
                    });
                    // Unsubscribe to previous content component
                    if (this.unsubscribeToContentComponent) {
                        this.unsubscribeToContentComponent();
                    }
                });
            }
            editor.createNodeViews();
            this.initialized = true;
        }
    }
    componentWillUnmount() {
        const editor = this.props.editor;
        if (!editor) {
            return;
        }
        this.initialized = false;
        if (!editor.isDestroyed) {
            editor.view.setProps({
                nodeViews: {},
            });
        }
        if (this.unsubscribeToContentComponent) {
            this.unsubscribeToContentComponent();
        }
        editor.contentComponent = null;
        if (!editor.options.element.firstChild) {
            return;
        }
        const newElement = document.createElement('div');
        newElement.append(...editor.options.element.childNodes);
        editor.setOptions({
            element: newElement,
        });
    }
    render() {
        const { editor, innerRef, ...rest } = this.props;
        return (React.createElement(React.Fragment, null,
            React.createElement("div", { ref: mergeRefs(innerRef, this.editorContentRef), ...rest }),
            (editor === null || editor === void 0 ? void 0 : editor.contentComponent) && React.createElement(Portals, { contentComponent: editor.contentComponent })));
    }
}
// EditorContent should be re-created whenever the Editor instance changes
const EditorContentWithKey = forwardRef((props, ref) => {
    const key = React.useMemo(() => {
        return Math.floor(Math.random() * 0xffffffff).toString();
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [props.editor]);
    // Can't use JSX here because it conflicts with the type definition of Vue's JSX, so use createElement
    return React.createElement(PureEditorContent, {
        key,
        innerRef: ref,
        ...props,
    });
});
const EditorContent = React.memo(EditorContentWithKey);

var react = function equal(a, b) {
  if (a === b) return true;

  if (a && b && typeof a == 'object' && typeof b == 'object') {
    if (a.constructor !== b.constructor) return false;

    var length, i, keys;
    if (Array.isArray(a)) {
      length = a.length;
      if (length != b.length) return false;
      for (i = length; i-- !== 0;)
        if (!equal(a[i], b[i])) return false;
      return true;
    }


    if ((a instanceof Map) && (b instanceof Map)) {
      if (a.size !== b.size) return false;
      for (i of a.entries())
        if (!b.has(i[0])) return false;
      for (i of a.entries())
        if (!equal(i[1], b.get(i[0]))) return false;
      return true;
    }

    if ((a instanceof Set) && (b instanceof Set)) {
      if (a.size !== b.size) return false;
      for (i of a.entries())
        if (!b.has(i[0])) return false;
      return true;
    }

    if (ArrayBuffer.isView(a) && ArrayBuffer.isView(b)) {
      length = a.length;
      if (length != b.length) return false;
      for (i = length; i-- !== 0;)
        if (a[i] !== b[i]) return false;
      return true;
    }


    if (a.constructor === RegExp) return a.source === b.source && a.flags === b.flags;
    if (a.valueOf !== Object.prototype.valueOf) return a.valueOf() === b.valueOf();
    if (a.toString !== Object.prototype.toString) return a.toString() === b.toString();

    keys = Object.keys(a);
    length = keys.length;
    if (length !== Object.keys(b).length) return false;

    for (i = length; i-- !== 0;)
      if (!Object.prototype.hasOwnProperty.call(b, keys[i])) return false;

    for (i = length; i-- !== 0;) {
      var key = keys[i];

      if (key === '_owner' && a.$$typeof) {
        // React-specific: avoid traversing React elements' _owner.
        //  _owner contains circular references
        // and is not needed when comparing the actual elements (and not their owners)
        continue;
      }

      if (!equal(a[key], b[key])) return false;
    }

    return true;
  }

  // true if both NaN, false otherwise
  return a!==a && b!==b;
};

var deepEqual = /*@__PURE__*/getDefaultExportFromCjs(react);

var withSelector = {exports: {}};

var withSelector_production_min = {};

/**
 * @license React
 * use-sync-external-store-shim/with-selector.production.min.js
 *
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

var hasRequiredWithSelector_production_min;

function requireWithSelector_production_min () {
	if (hasRequiredWithSelector_production_min) return withSelector_production_min;
	hasRequiredWithSelector_production_min = 1;
var h=React,n=shimExports;function p(a,b){return a===b&&(0!==a||1/a===1/b)||a!==a&&b!==b}var q="function"===typeof Object.is?Object.is:p,r=n.useSyncExternalStore,t=h.useRef,u=h.useEffect,v=h.useMemo,w=h.useDebugValue;
	withSelector_production_min.useSyncExternalStoreWithSelector=function(a,b,e,l,g){var c=t(null);if(null===c.current){var f={hasValue:!1,value:null};c.current=f;}else f=c.current;c=v(function(){function a(a){if(!c){c=!0;d=a;a=l(a);if(void 0!==g&&f.hasValue){var b=f.value;if(g(b,a))return k=b}return k=a}b=k;if(q(d,a))return b;var e=l(a);if(void 0!==g&&g(b,e))return b;d=a;return k=e}var c=!1,d,k,m=void 0===e?null:e;return [function(){return a(b())},null===m?void 0:function(){return a(m())}]},[b,e,l,g]);var d=r(a,c[0],c[1]);
	u(function(){f.hasValue=!0;f.value=d;},[d]);w(d);return d};
	return withSelector_production_min;
}

var withSelector_development = {};

/**
 * @license React
 * use-sync-external-store-shim/with-selector.development.js
 *
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

var hasRequiredWithSelector_development;

function requireWithSelector_development () {
	if (hasRequiredWithSelector_development) return withSelector_development;
	hasRequiredWithSelector_development = 1;

	if (process.env.NODE_ENV !== "production") {
	  (function() {

	/* global __REACT_DEVTOOLS_GLOBAL_HOOK__ */
	if (
	  typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== 'undefined' &&
	  typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart ===
	    'function'
	) {
	  __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(new Error());
	}
	          var React$1 = React;
	var shim = shimExports;

	/**
	 * inlined Object.is polyfill to avoid requiring consumers ship their own
	 * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
	 */
	function is(x, y) {
	  return x === y && (x !== 0 || 1 / x === 1 / y) || x !== x && y !== y // eslint-disable-line no-self-compare
	  ;
	}

	var objectIs = typeof Object.is === 'function' ? Object.is : is;

	var useSyncExternalStore = shim.useSyncExternalStore;

	// for CommonJS interop.

	var useRef = React$1.useRef,
	    useEffect = React$1.useEffect,
	    useMemo = React$1.useMemo,
	    useDebugValue = React$1.useDebugValue; // Same as useSyncExternalStore, but supports selector and isEqual arguments.

	function useSyncExternalStoreWithSelector(subscribe, getSnapshot, getServerSnapshot, selector, isEqual) {
	  // Use this to track the rendered snapshot.
	  var instRef = useRef(null);
	  var inst;

	  if (instRef.current === null) {
	    inst = {
	      hasValue: false,
	      value: null
	    };
	    instRef.current = inst;
	  } else {
	    inst = instRef.current;
	  }

	  var _useMemo = useMemo(function () {
	    // Track the memoized state using closure variables that are local to this
	    // memoized instance of a getSnapshot function. Intentionally not using a
	    // useRef hook, because that state would be shared across all concurrent
	    // copies of the hook/component.
	    var hasMemo = false;
	    var memoizedSnapshot;
	    var memoizedSelection;

	    var memoizedSelector = function (nextSnapshot) {
	      if (!hasMemo) {
	        // The first time the hook is called, there is no memoized result.
	        hasMemo = true;
	        memoizedSnapshot = nextSnapshot;

	        var _nextSelection = selector(nextSnapshot);

	        if (isEqual !== undefined) {
	          // Even if the selector has changed, the currently rendered selection
	          // may be equal to the new selection. We should attempt to reuse the
	          // current value if possible, to preserve downstream memoizations.
	          if (inst.hasValue) {
	            var currentSelection = inst.value;

	            if (isEqual(currentSelection, _nextSelection)) {
	              memoizedSelection = currentSelection;
	              return currentSelection;
	            }
	          }
	        }

	        memoizedSelection = _nextSelection;
	        return _nextSelection;
	      } // We may be able to reuse the previous invocation's result.


	      // We may be able to reuse the previous invocation's result.
	      var prevSnapshot = memoizedSnapshot;
	      var prevSelection = memoizedSelection;

	      if (objectIs(prevSnapshot, nextSnapshot)) {
	        // The snapshot is the same as last time. Reuse the previous selection.
	        return prevSelection;
	      } // The snapshot has changed, so we need to compute a new selection.


	      // The snapshot has changed, so we need to compute a new selection.
	      var nextSelection = selector(nextSnapshot); // If a custom isEqual function is provided, use that to check if the data
	      // has changed. If it hasn't, return the previous selection. That signals
	      // to React that the selections are conceptually equal, and we can bail
	      // out of rendering.

	      // If a custom isEqual function is provided, use that to check if the data
	      // has changed. If it hasn't, return the previous selection. That signals
	      // to React that the selections are conceptually equal, and we can bail
	      // out of rendering.
	      if (isEqual !== undefined && isEqual(prevSelection, nextSelection)) {
	        return prevSelection;
	      }

	      memoizedSnapshot = nextSnapshot;
	      memoizedSelection = nextSelection;
	      return nextSelection;
	    }; // Assigning this to a constant so that Flow knows it can't change.


	    // Assigning this to a constant so that Flow knows it can't change.
	    var maybeGetServerSnapshot = getServerSnapshot === undefined ? null : getServerSnapshot;

	    var getSnapshotWithSelector = function () {
	      return memoizedSelector(getSnapshot());
	    };

	    var getServerSnapshotWithSelector = maybeGetServerSnapshot === null ? undefined : function () {
	      return memoizedSelector(maybeGetServerSnapshot());
	    };
	    return [getSnapshotWithSelector, getServerSnapshotWithSelector];
	  }, [getSnapshot, getServerSnapshot, selector, isEqual]),
	      getSelection = _useMemo[0],
	      getServerSelection = _useMemo[1];

	  var value = useSyncExternalStore(subscribe, getSelection, getServerSelection);
	  useEffect(function () {
	    inst.hasValue = true;
	    inst.value = value;
	  }, [value]);
	  useDebugValue(value);
	  return value;
	}

	withSelector_development.useSyncExternalStoreWithSelector = useSyncExternalStoreWithSelector;
	          /* global __REACT_DEVTOOLS_GLOBAL_HOOK__ */
	if (
	  typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== 'undefined' &&
	  typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop ===
	    'function'
	) {
	  __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop(new Error());
	}
	        
	  })();
	}
	return withSelector_development;
}

if (process.env.NODE_ENV === 'production') {
  withSelector.exports = requireWithSelector_production_min();
} else {
  withSelector.exports = requireWithSelector_development();
}

var withSelectorExports = withSelector.exports;

const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect;
/**
 * To synchronize the editor instance with the component state,
 * we need to create a separate instance that is not affected by the component re-renders.
 */
class EditorStateManager {
    constructor(initialEditor) {
        this.transactionNumber = 0;
        this.lastTransactionNumber = 0;
        this.subscribers = new Set();
        this.editor = initialEditor;
        this.lastSnapshot = { editor: initialEditor, transactionNumber: 0 };
        this.getSnapshot = this.getSnapshot.bind(this);
        this.getServerSnapshot = this.getServerSnapshot.bind(this);
        this.watch = this.watch.bind(this);
        this.subscribe = this.subscribe.bind(this);
    }
    /**
     * Get the current editor instance.
     */
    getSnapshot() {
        if (this.transactionNumber === this.lastTransactionNumber) {
            return this.lastSnapshot;
        }
        this.lastTransactionNumber = this.transactionNumber;
        this.lastSnapshot = { editor: this.editor, transactionNumber: this.transactionNumber };
        return this.lastSnapshot;
    }
    /**
     * Always disable the editor on the server-side.
     */
    getServerSnapshot() {
        return { editor: null, transactionNumber: 0 };
    }
    /**
     * Subscribe to the editor instance's changes.
     */
    subscribe(callback) {
        this.subscribers.add(callback);
        return () => {
            this.subscribers.delete(callback);
        };
    }
    /**
     * Watch the editor instance for changes.
     */
    watch(nextEditor) {
        this.editor = nextEditor;
        if (this.editor) {
            /**
             * This will force a re-render when the editor state changes.
             * This is to support things like `editor.can().toggleBold()` in components that `useEditor`.
             * This could be more efficient, but it's a good trade-off for now.
             */
            const fn = () => {
                this.transactionNumber += 1;
                this.subscribers.forEach(callback => callback());
            };
            const currentEditor = this.editor;
            currentEditor.on('transaction', fn);
            return () => {
                currentEditor.off('transaction', fn);
            };
        }
        return undefined;
    }
}
/**
 * This hook allows you to watch for changes on the editor instance.
 * It will allow you to select a part of the editor state and re-render the component when it changes.
 * @example
 * ```tsx
 * const editor = useEditor({...options})
 * const { currentSelection } = useEditorState({
 *  editor,
 *  selector: snapshot => ({ currentSelection: snapshot.editor.state.selection }),
 * })
 */
function useEditorState(options) {
    var _a;
    const [editorStateManager] = useState(() => new EditorStateManager(options.editor));
    // Using the `useSyncExternalStore` hook to sync the editor instance with the component state
    const selectedState = withSelectorExports.useSyncExternalStoreWithSelector(editorStateManager.subscribe, editorStateManager.getSnapshot, editorStateManager.getServerSnapshot, options.selector, (_a = options.equalityFn) !== null && _a !== void 0 ? _a : deepEqual);
    useIsomorphicLayoutEffect(() => {
        return editorStateManager.watch(options.editor);
    }, [options.editor, editorStateManager]);
    useDebugValue(selectedState);
    return selectedState;
}

const isDev = process.env.NODE_ENV !== 'production';
const isSSR = typeof window === 'undefined';
const isNext = isSSR || Boolean(typeof window !== 'undefined' && window.next);
/**
 * This class handles the creation, destruction, and re-creation of the editor instance.
 */
class EditorInstanceManager {
    constructor(options) {
        /**
         * The current editor instance.
         */
        this.editor = null;
        /**
         * The subscriptions to notify when the editor instance
         * has been created or destroyed.
         */
        this.subscriptions = new Set();
        /**
         * Whether the editor has been mounted.
         */
        this.isComponentMounted = false;
        /**
         * The most recent dependencies array.
         */
        this.previousDeps = null;
        /**
         * The unique instance ID. This is used to identify the editor instance. And will be re-generated for each new instance.
         */
        this.instanceId = '';
        this.options = options;
        this.subscriptions = new Set();
        this.setEditor(this.getInitialEditor());
        this.scheduleDestroy();
        this.getEditor = this.getEditor.bind(this);
        this.getServerSnapshot = this.getServerSnapshot.bind(this);
        this.subscribe = this.subscribe.bind(this);
        this.refreshEditorInstance = this.refreshEditorInstance.bind(this);
        this.scheduleDestroy = this.scheduleDestroy.bind(this);
        this.onRender = this.onRender.bind(this);
        this.createEditor = this.createEditor.bind(this);
    }
    setEditor(editor) {
        this.editor = editor;
        this.instanceId = Math.random().toString(36).slice(2, 9);
        // Notify all subscribers that the editor instance has been created
        this.subscriptions.forEach(cb => cb());
    }
    getInitialEditor() {
        if (this.options.current.immediatelyRender === undefined) {
            if (isSSR || isNext) {
                // TODO in the next major release, we should throw an error here
                if (isDev) {
                    /**
                     * Throw an error in development, to make sure the developer is aware that tiptap cannot be SSR'd
                     * and that they need to set `immediatelyRender` to `false` to avoid hydration mismatches.
                     */
                    console.warn('Tiptap Error: SSR has been detected, please set `immediatelyRender` explicitly to `false` to avoid hydration mismatches.');
                }
                // Best faith effort in production, run the code in the legacy mode to avoid hydration mismatches and errors in production
                return null;
            }
            // Default to immediately rendering when client-side rendering
            return this.createEditor();
        }
        if (this.options.current.immediatelyRender && isSSR && isDev) {
            // Warn in development, to make sure the developer is aware that tiptap cannot be SSR'd, set `immediatelyRender` to `false` to avoid hydration mismatches.
            throw new Error('Tiptap Error: SSR has been detected, and `immediatelyRender` has been set to `true` this is an unsupported configuration that may result in errors, explicitly set `immediatelyRender` to `false` to avoid hydration mismatches.');
        }
        if (this.options.current.immediatelyRender) {
            return this.createEditor();
        }
        return null;
    }
    /**
     * Create a new editor instance. And attach event listeners.
     */
    createEditor() {
        const optionsToApply = {
            ...this.options.current,
            // Always call the most recent version of the callback function by default
            onBeforeCreate: (...args) => { var _a, _b; return (_b = (_a = this.options.current).onBeforeCreate) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); },
            onBlur: (...args) => { var _a, _b; return (_b = (_a = this.options.current).onBlur) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); },
            onCreate: (...args) => { var _a, _b; return (_b = (_a = this.options.current).onCreate) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); },
            onDestroy: (...args) => { var _a, _b; return (_b = (_a = this.options.current).onDestroy) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); },
            onFocus: (...args) => { var _a, _b; return (_b = (_a = this.options.current).onFocus) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); },
            onSelectionUpdate: (...args) => { var _a, _b; return (_b = (_a = this.options.current).onSelectionUpdate) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); },
            onTransaction: (...args) => { var _a, _b; return (_b = (_a = this.options.current).onTransaction) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); },
            onUpdate: (...args) => { var _a, _b; return (_b = (_a = this.options.current).onUpdate) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); },
            onContentError: (...args) => { var _a, _b; return (_b = (_a = this.options.current).onContentError) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); },
            onDrop: (...args) => { var _a, _b; return (_b = (_a = this.options.current).onDrop) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); },
            onPaste: (...args) => { var _a, _b; return (_b = (_a = this.options.current).onPaste) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); },
        };
        const editor = new Editor(optionsToApply);
        // no need to keep track of the event listeners, they will be removed when the editor is destroyed
        return editor;
    }
    /**
     * Get the current editor instance.
     */
    getEditor() {
        return this.editor;
    }
    /**
     * Always disable the editor on the server-side.
     */
    getServerSnapshot() {
        return null;
    }
    /**
     * Subscribe to the editor instance's changes.
     */
    subscribe(onStoreChange) {
        this.subscriptions.add(onStoreChange);
        return () => {
            this.subscriptions.delete(onStoreChange);
        };
    }
    static compareOptions(a, b) {
        return Object.keys(a).every(key => {
            if (['onCreate', 'onBeforeCreate', 'onDestroy', 'onUpdate', 'onTransaction', 'onFocus', 'onBlur', 'onSelectionUpdate', 'onContentError', 'onDrop', 'onPaste'].includes(key)) {
                // we don't want to compare callbacks, they are always different and only registered once
                return true;
            }
            // We often encourage putting extensions inlined in the options object, so we will do a slightly deeper comparison here
            if (key === 'extensions' && a.extensions && b.extensions) {
                if (a.extensions.length !== b.extensions.length) {
                    return false;
                }
                return a.extensions.every((extension, index) => {
                    var _a;
                    if (extension !== ((_a = b.extensions) === null || _a === void 0 ? void 0 : _a[index])) {
                        return false;
                    }
                    return true;
                });
            }
            if (a[key] !== b[key]) {
                // if any of the options have changed, we should update the editor options
                return false;
            }
            return true;
        });
    }
    /**
     * On each render, we will create, update, or destroy the editor instance.
     * @param deps The dependencies to watch for changes
     * @returns A cleanup function
     */
    onRender(deps) {
        // The returned callback will run on each render
        return () => {
            this.isComponentMounted = true;
            // Cleanup any scheduled destructions, since we are currently rendering
            clearTimeout(this.scheduledDestructionTimeout);
            if (this.editor && !this.editor.isDestroyed && deps.length === 0) {
                // if the editor does exist & deps are empty, we don't need to re-initialize the editor generally
                if (!EditorInstanceManager.compareOptions(this.options.current, this.editor.options)) {
                    // But, the options are different, so we need to update the editor options
                    // Still, this is faster than re-creating the editor
                    this.editor.setOptions({
                        ...this.options.current,
                        editable: this.editor.isEditable,
                    });
                }
            }
            else {
                // When the editor:
                // - does not yet exist
                // - is destroyed
                // - the deps array changes
                // We need to destroy the editor instance and re-initialize it
                this.refreshEditorInstance(deps);
            }
            return () => {
                this.isComponentMounted = false;
                this.scheduleDestroy();
            };
        };
    }
    /**
     * Recreate the editor instance if the dependencies have changed.
     */
    refreshEditorInstance(deps) {
        if (this.editor && !this.editor.isDestroyed) {
            // Editor instance already exists
            if (this.previousDeps === null) {
                // If lastDeps has not yet been initialized, reuse the current editor instance
                this.previousDeps = deps;
                return;
            }
            const depsAreEqual = this.previousDeps.length === deps.length
                && this.previousDeps.every((dep, index) => dep === deps[index]);
            if (depsAreEqual) {
                // deps exist and are equal, no need to recreate
                return;
            }
        }
        if (this.editor && !this.editor.isDestroyed) {
            // Destroy the editor instance if it exists
            this.editor.destroy();
        }
        this.setEditor(this.createEditor());
        // Update the lastDeps to the current deps
        this.previousDeps = deps;
    }
    /**
     * Schedule the destruction of the editor instance.
     * This will only destroy the editor if it was not mounted on the next tick.
     * This is to avoid destroying the editor instance when it's actually still mounted.
     */
    scheduleDestroy() {
        const currentInstanceId = this.instanceId;
        const currentEditor = this.editor;
        // Wait two ticks to see if the component is still mounted
        this.scheduledDestructionTimeout = setTimeout(() => {
            if (this.isComponentMounted && this.instanceId === currentInstanceId) {
                // If still mounted on the following tick, with the same instanceId, do not destroy the editor
                if (currentEditor) {
                    // just re-apply options as they might have changed
                    currentEditor.setOptions(this.options.current);
                }
                return;
            }
            if (currentEditor && !currentEditor.isDestroyed) {
                currentEditor.destroy();
                if (this.instanceId === currentInstanceId) {
                    this.setEditor(null);
                }
            }
            // This allows the effect to run again between ticks
            // which may save us from having to re-create the editor
        }, 1);
    }
}
function useEditor(options = {}, deps = []) {
    const mostRecentOptions = useRef(options);
    mostRecentOptions.current = options;
    const [instanceManager] = useState(() => new EditorInstanceManager(mostRecentOptions));
    const editor = shimExports.useSyncExternalStore(instanceManager.subscribe, instanceManager.getEditor, instanceManager.getServerSnapshot);
    useDebugValue(editor);
    // This effect will handle creating/updating the editor instance
    // eslint-disable-next-line react-hooks/exhaustive-deps
    useEffect(instanceManager.onRender(deps));
    // The default behavior is to re-render on each transaction
    // This is legacy behavior that will be removed in future versions
    useEditorState({
        editor,
        selector: ({ transactionNumber }) => {
            if (options.shouldRerenderOnTransaction === false) {
                // This will prevent the editor from re-rendering on each transaction
                return null;
            }
            // This will avoid re-rendering on the first transaction when `immediatelyRender` is set to `true`
            if (options.immediatelyRender && transactionNumber === 0) {
                return 0;
            }
            return transactionNumber + 1;
        },
    });
    return editor;
}

const EditorContext = createContext({
    editor: null,
});
const EditorConsumer = EditorContext.Consumer;
/**
 * A hook to get the current editor instance.
 */
const useCurrentEditor = () => useContext(EditorContext);
/**
 * This is the provider component for the editor.
 * It allows the editor to be accessible across the entire component tree
 * with `useCurrentEditor`.
 */
function EditorProvider({ children, slotAfter, slotBefore, editorContainerProps = {}, ...editorOptions }) {
    const editor = useEditor(editorOptions);
    if (!editor) {
        return null;
    }
    return (React.createElement(EditorContext.Provider, { value: { editor } },
        slotBefore,
        React.createElement(EditorConsumer, null, ({ editor: currentEditor }) => (React.createElement(EditorContent, { editor: currentEditor, ...editorContainerProps }))),
        children,
        slotAfter));
}

const BubbleMenu = (props) => {
    const [element, setElement] = useState(null);
    const { editor: currentEditor } = useCurrentEditor();
    useEffect(() => {
        var _a;
        if (!element) {
            return;
        }
        if (((_a = props.editor) === null || _a === void 0 ? void 0 : _a.isDestroyed) || (currentEditor === null || currentEditor === void 0 ? void 0 : currentEditor.isDestroyed)) {
            return;
        }
        const { pluginKey = 'bubbleMenu', editor, tippyOptions = {}, updateDelay, shouldShow = null, } = props;
        const menuEditor = editor || currentEditor;
        if (!menuEditor) {
            console.warn('BubbleMenu component is not rendered inside of an editor component or does not have editor prop.');
            return;
        }
        const plugin = BubbleMenuPlugin({
            updateDelay,
            editor: menuEditor,
            element,
            pluginKey,
            shouldShow,
            tippyOptions,
        });
        menuEditor.registerPlugin(plugin);
        return () => { menuEditor.unregisterPlugin(pluginKey); };
    }, [props.editor, currentEditor, element]);
    return (React.createElement("div", { ref: setElement, className: props.className, style: { visibility: 'hidden' } }, props.children));
};

const FloatingMenu = (props) => {
    const [element, setElement] = useState(null);
    const { editor: currentEditor } = useCurrentEditor();
    useEffect(() => {
        var _a;
        if (!element) {
            return;
        }
        if (((_a = props.editor) === null || _a === void 0 ? void 0 : _a.isDestroyed) || (currentEditor === null || currentEditor === void 0 ? void 0 : currentEditor.isDestroyed)) {
            return;
        }
        const { pluginKey = 'floatingMenu', editor, tippyOptions = {}, shouldShow = null, } = props;
        const menuEditor = editor || currentEditor;
        if (!menuEditor) {
            console.warn('FloatingMenu component is not rendered inside of an editor component or does not have editor prop.');
            return;
        }
        const plugin = FloatingMenuPlugin({
            pluginKey,
            editor: menuEditor,
            element,
            tippyOptions,
            shouldShow,
        });
        menuEditor.registerPlugin(plugin);
        return () => { menuEditor.unregisterPlugin(pluginKey); };
    }, [
        props.editor,
        currentEditor,
        element,
    ]);
    return (React.createElement("div", { ref: setElement, className: props.className, style: { visibility: 'hidden' } }, props.children));
};

const ReactNodeViewContext = createContext({
    onDragStart: undefined,
});
const useReactNodeView = () => useContext(ReactNodeViewContext);

const NodeViewContent = props => {
    const Tag = props.as || 'div';
    const { nodeViewContentRef } = useReactNodeView();
    return (
    // @ts-ignore
    React.createElement(Tag, { ...props, ref: nodeViewContentRef, "data-node-view-content": "", style: {
            whiteSpace: 'pre-wrap',
            ...props.style,
        } }));
};

const NodeViewWrapper = React.forwardRef((props, ref) => {
    const { onDragStart } = useReactNodeView();
    const Tag = props.as || 'div';
    return (
    // @ts-ignore
    React.createElement(Tag, { ...props, ref: ref, "data-node-view-wrapper": "", onDragStart: onDragStart, style: {
            whiteSpace: 'normal',
            ...props.style,
        } }));
});

/**
 * Check if a component is a class component.
 * @param Component
 * @returns {boolean}
 */
function isClassComponent(Component) {
    return !!(typeof Component === 'function'
        && Component.prototype
        && Component.prototype.isReactComponent);
}
/**
 * Check if a component is a forward ref component.
 * @param Component
 * @returns {boolean}
 */
function isForwardRefComponent(Component) {
    return !!(typeof Component === 'object'
        && Component.$$typeof
        && (Component.$$typeof.toString() === 'Symbol(react.forward_ref)'
            || Component.$$typeof.description === 'react.forward_ref'));
}
/**
 * Check if a component is a memoized component.
 * @param Component
 * @returns {boolean}
 */
function isMemoComponent(Component) {
    return !!(typeof Component === 'object'
        && Component.$$typeof
        && (Component.$$typeof.toString() === 'Symbol(react.memo)' || Component.$$typeof.description === 'react.memo'));
}
/**
 * Check if a component can safely receive a ref prop.
 * This includes class components, forwardRef components, and memoized components
 * that wrap forwardRef or class components.
 * @param Component
 * @returns {boolean}
 */
function canReceiveRef(Component) {
    // Check if it's a class component
    if (isClassComponent(Component)) {
        return true;
    }
    // Check if it's a forwardRef component
    if (isForwardRefComponent(Component)) {
        return true;
    }
    // Check if it's a memoized component
    if (isMemoComponent(Component)) {
        // For memoized components, check the wrapped component
        const wrappedComponent = Component.type;
        if (wrappedComponent) {
            return isClassComponent(wrappedComponent) || isForwardRefComponent(wrappedComponent);
        }
    }
    return false;
}
/**
 * Check if we're running React 19+ by detecting if function components support ref props
 * @returns {boolean}
 */
function isReact19Plus() {
    // React 19 is detected by checking React version if available
    // In practice, we'll use a more conservative approach and assume React 18 behavior
    // unless we can definitively detect React 19
    try {
        // @ts-ignore
        if (version) {
            const majorVersion = parseInt(version.split('.')[0], 10);
            return majorVersion >= 19;
        }
    }
    catch {
        // Fallback to React 18 behavior if we can't determine version
    }
    return false;
}
/**
 * The ReactRenderer class. It's responsible for rendering React components inside the editor.
 * @example
 * new ReactRenderer(MyComponent, {
 *   editor,
 *   props: {
 *     foo: 'bar',
 *   },
 *   as: 'span',
 * })
*/
class ReactRenderer {
    /**
     * Immediately creates element and renders the provided React component.
     */
    constructor(component, { editor, props = {}, as = 'div', className = '', }) {
        this.ref = null;
        this.id = Math.floor(Math.random() * 0xFFFFFFFF).toString();
        this.component = component;
        this.editor = editor;
        this.props = props;
        this.element = document.createElement(as);
        this.element.classList.add('react-renderer');
        if (className) {
            this.element.classList.add(...className.split(' '));
        }
        if (this.editor.isInitialized) {
            // On first render, we need to flush the render synchronously
            // Renders afterwards can be async, but this fixes a cursor positioning issue
            flushSync(() => {
                this.render();
            });
        }
        else {
            this.render();
        }
    }
    /**
     * Render the React component.
     */
    render() {
        var _a;
        const Component = this.component;
        const props = this.props;
        const editor = this.editor;
        // Handle ref forwarding with React 18/19 compatibility
        const isReact19 = isReact19Plus();
        const componentCanReceiveRef = canReceiveRef(Component);
        const elementProps = { ...props };
        // Always remove ref if the component cannot receive it (unless React 19+)
        if (elementProps.ref && !(isReact19 || componentCanReceiveRef)) {
            delete elementProps.ref;
        }
        // Only assign our own ref if allowed
        if (!elementProps.ref && (isReact19 || componentCanReceiveRef)) {
            // @ts-ignore - Setting ref prop for compatible components
            elementProps.ref = (ref) => {
                this.ref = ref;
            };
        }
        this.reactElement = React.createElement(Component, { ...elementProps });
        (_a = editor === null || editor === void 0 ? void 0 : editor.contentComponent) === null || _a === void 0 ? void 0 : _a.setRenderer(this.id, this);
    }
    /**
     * Re-renders the React component with new props.
     */
    updateProps(props = {}) {
        this.props = {
            ...this.props,
            ...props,
        };
        this.render();
    }
    /**
     * Destroy the React component.
     */
    destroy() {
        var _a;
        const editor = this.editor;
        (_a = editor === null || editor === void 0 ? void 0 : editor.contentComponent) === null || _a === void 0 ? void 0 : _a.removeRenderer(this.id);
    }
    /**
     * Update the attributes of the element that holds the React component.
     */
    updateAttributes(attributes) {
        Object.keys(attributes).forEach(key => {
            this.element.setAttribute(key, attributes[key]);
        });
    }
}

class ReactNodeView extends NodeView {
    /**
     * Setup the React component.
     * Called on initialization.
     */
    mount() {
        const props = {
            editor: this.editor,
            node: this.node,
            decorations: this.decorations,
            innerDecorations: this.innerDecorations,
            view: this.view,
            selected: false,
            extension: this.extension,
            HTMLAttributes: this.HTMLAttributes,
            getPos: () => this.getPos(),
            updateAttributes: (attributes = {}) => this.updateAttributes(attributes),
            deleteNode: () => this.deleteNode(),
            ref: createRef(),
        };
        if (!this.component.displayName) {
            const capitalizeFirstChar = (string) => {
                return string.charAt(0).toUpperCase() + string.substring(1);
            };
            this.component.displayName = capitalizeFirstChar(this.extension.name);
        }
        const onDragStart = this.onDragStart.bind(this);
        const nodeViewContentRef = element => {
            if (element && this.contentDOMElement && element.firstChild !== this.contentDOMElement) {
                element.appendChild(this.contentDOMElement);
            }
        };
        const context = { onDragStart, nodeViewContentRef };
        const Component = this.component;
        // For performance reasons, we memoize the provider component
        // And all of the things it requires are declared outside of the component, so it doesn't need to re-render
        const ReactNodeViewProvider = memo(componentProps => {
            return (React.createElement(ReactNodeViewContext.Provider, { value: context }, createElement(Component, componentProps)));
        });
        ReactNodeViewProvider.displayName = 'ReactNodeView';
        if (this.node.isLeaf) {
            this.contentDOMElement = null;
        }
        else if (this.options.contentDOMElementTag) {
            this.contentDOMElement = document.createElement(this.options.contentDOMElementTag);
        }
        else {
            this.contentDOMElement = document.createElement(this.node.isInline ? 'span' : 'div');
        }
        if (this.contentDOMElement) {
            this.contentDOMElement.dataset.nodeViewContentReact = '';
            // For some reason the whiteSpace prop is not inherited properly in Chrome and Safari
            // With this fix it seems to work fine
            // See: https://github.com/ueberdosis/tiptap/issues/1197
            this.contentDOMElement.style.whiteSpace = 'inherit';
        }
        let as = this.node.isInline ? 'span' : 'div';
        if (this.options.as) {
            as = this.options.as;
        }
        const { className = '' } = this.options;
        this.handleSelectionUpdate = this.handleSelectionUpdate.bind(this);
        this.renderer = new ReactRenderer(ReactNodeViewProvider, {
            editor: this.editor,
            props,
            as,
            className: `node-${this.node.type.name} ${className}`.trim(),
        });
        this.editor.on('selectionUpdate', this.handleSelectionUpdate);
        this.updateElementAttributes();
    }
    /**
     * Return the DOM element.
     * This is the element that will be used to display the node view.
     */
    get dom() {
        var _a;
        if (this.renderer.element.firstElementChild
            && !((_a = this.renderer.element.firstElementChild) === null || _a === void 0 ? void 0 : _a.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.contentDOMElement;
    }
    /**
     * 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.renderer.updateProps(props);
            if (typeof this.options.attrs === 'function') {
                this.updateElementAttributes();
            }
        };
        if (node.type !== this.node.type) {
            return false;
        }
        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 }),
            });
        }
        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 });
        return true;
    }
    /**
     * Select the node.
     * Add the `selected` prop and the `ProseMirror-selectednode` class.
     */
    selectNode() {
        this.renderer.updateProps({
            selected: true,
        });
        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,
        });
        this.renderer.element.classList.remove('ProseMirror-selectednode');
    }
    /**
     * Destroy the React component instance.
     */
    destroy() {
        this.renderer.destroy();
        this.editor.off('selectionUpdate', this.handleSelectionUpdate);
        this.contentDOMElement = null;
    }
    /**
     * Update the attributes of the top-level element that holds the React component.
     * Applying the attributes defined in the `attrs` option.
     */
    updateElementAttributes() {
        if (this.options.attrs) {
            let attrsObj = {};
            if (typeof this.options.attrs === 'function') {
                const extensionAttributes = this.editor.extensionManager.attributes;
                const HTMLAttributes = getRenderedAttributes(this.node, extensionAttributes);
                attrsObj = this.options.attrs({ node: this.node, HTMLAttributes });
            }
            else {
                attrsObj = this.options.attrs;
            }
            this.renderer.updateAttributes(attrsObj);
        }
    }
}
/**
 * Create a React node view renderer.
 */
function ReactNodeViewRenderer(component, options) {
    return props => {
        // try to get the parent component
        // this is important for vue devtools to show the component hierarchy correctly
        // maybe it’s `undefined` because <editor-content> isn’t rendered yet
        if (!props.editor.contentComponent) {
            return {};
        }
        return new ReactNodeView(component, props, options);
    };
}

export { BubbleMenu, EditorConsumer, EditorContent, EditorContext, EditorProvider, FloatingMenu, NodeViewContent, NodeViewWrapper, PureEditorContent, ReactNodeView, ReactNodeViewContext, ReactNodeViewRenderer, ReactRenderer, useCurrentEditor, useEditor, useEditorState, useReactNodeView };
//# sourceMappingURL=index.js.map
