(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@tiptap/extension-bubble-menu'), require('react'), require('react-dom'), require('@tiptap/core'), require('@tiptap/extension-floating-menu')) : typeof define === 'function' && define.amd ? define(['exports', '@tiptap/extension-bubble-menu', 'react', 'react-dom', '@tiptap/core', '@tiptap/extension-floating-menu'], factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global["@tiptap/react"] = {}, global.extensionBubbleMenu, global.React, global.ReactDOM, global.core, global.extensionFloatingMenu)); })(this, (function (exports, extensionBubbleMenu, React, ReactDOM, core, extensionFloatingMenu) { 'use strict'; 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 = React.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' ? React.useLayoutEffect : React.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] = React.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]); React.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 core.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 = React.useRef(options); mostRecentOptions.current = options; const [instanceManager] = React.useState(() => new EditorInstanceManager(mostRecentOptions)); const editor = shimExports.useSyncExternalStore(instanceManager.subscribe, instanceManager.getEditor, instanceManager.getServerSnapshot); React.useDebugValue(editor); // This effect will handle creating/updating the editor instance // eslint-disable-next-line react-hooks/exhaustive-deps React.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 = React.createContext({ editor: null, }); const EditorConsumer = EditorContext.Consumer; /** * A hook to get the current editor instance. */ const useCurrentEditor = () => React.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] = React.useState(null); const { editor: currentEditor } = useCurrentEditor(); React.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 = extensionBubbleMenu.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] = React.useState(null); const { editor: currentEditor } = useCurrentEditor(); React.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 = extensionFloatingMenu.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 = React.createContext({ onDragStart: undefined, }); const useReactNodeView = () => React.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 (React.version) { const majorVersion = parseInt(React.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 the editor is already initialized, we will need to // synchronously render the component to ensure it renders // together with Prosemirror's rendering. if (this.editor.isInitialized) { ReactDOM.flushSync(() => { this.render(); }); } else { queueMicrotask(() => { 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 core.NodeView { constructor(component, props, options) { super(component, props, options); if (!this.node.isLeaf) { if (this.options.contentDOMElementTag) { this.contentDOMElement = document.createElement(this.options.contentDOMElementTag); } else { this.contentDOMElement = document.createElement(this.node.isInline ? 'span' : 'div'); } this.contentDOMElement.dataset.nodeViewContentReact = ''; this.contentDOMElement.dataset.nodeViewWrapper = ''; // 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'; const contentTarget = this.dom.querySelector('[data-node-view-content]'); if (!contentTarget) { return; } contentTarget.appendChild(this.contentDOMElement); } } /** * 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: React.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) { // remove the nodeViewWrapper attribute from the element if (element.hasAttribute('data-node-view-wrapper')) { element.removeAttribute('data-node-view-wrapper'); } 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 = React.memo(componentProps => { return (React.createElement(ReactNodeViewContext.Provider, { value: context }, React.createElement(Component, componentProps))); }); ReactNodeViewProvider.displayName = 'ReactNodeView'; 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 = core.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 isn’t rendered yet if (!props.editor.contentComponent) { return {}; } return new ReactNodeView(component, props, options); }; } exports.BubbleMenu = BubbleMenu; exports.EditorConsumer = EditorConsumer; exports.EditorContent = EditorContent; exports.EditorContext = EditorContext; exports.EditorProvider = EditorProvider; exports.FloatingMenu = FloatingMenu; exports.NodeViewContent = NodeViewContent; exports.NodeViewWrapper = NodeViewWrapper; exports.PureEditorContent = PureEditorContent; exports.ReactNodeView = ReactNodeView; exports.ReactNodeViewContext = ReactNodeViewContext; exports.ReactNodeViewRenderer = ReactNodeViewRenderer; exports.ReactRenderer = ReactRenderer; exports.useCurrentEditor = useCurrentEditor; exports.useEditor = useEditor; exports.useEditorState = useEditorState; exports.useReactNodeView = useReactNodeView; Object.keys(core).forEach(function (k) { if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, { enumerable: true, get: function () { return core[k]; } }); }); })); //# sourceMappingURL=index.umd.js.map