"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default")); var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var index_exports = {}; __export(index_exports, { EditorConsumer: () => EditorConsumer, EditorContent: () => EditorContent, EditorContext: () => EditorContext, EditorProvider: () => EditorProvider, MarkViewContent: () => MarkViewContent, NodeViewContent: () => NodeViewContent, NodeViewWrapper: () => NodeViewWrapper, PureEditorContent: () => PureEditorContent, ReactMarkView: () => ReactMarkView, ReactMarkViewContext: () => ReactMarkViewContext, ReactMarkViewRenderer: () => ReactMarkViewRenderer, ReactNodeView: () => ReactNodeView, ReactNodeViewContentProvider: () => ReactNodeViewContentProvider, ReactNodeViewContext: () => ReactNodeViewContext, ReactNodeViewRenderer: () => ReactNodeViewRenderer, ReactRenderer: () => ReactRenderer, Tiptap: () => Tiptap, TiptapContent: () => TiptapContent, TiptapContext: () => TiptapContext, TiptapWrapper: () => TiptapWrapper, useCurrentEditor: () => useCurrentEditor, useEditor: () => useEditor, useEditorState: () => useEditorState, useReactNodeView: () => useReactNodeView, useTiptap: () => useTiptap, useTiptapState: () => useTiptapState }); module.exports = __toCommonJS(index_exports); // src/Context.tsx var import_react4 = require("react"); // src/EditorContent.tsx var import_react = __toESM(require("react"), 1); var import_react_dom = __toESM(require("react-dom"), 1); var import_shim = require("use-sync-external-store/shim/index.js"); var import_jsx_runtime = require("react/jsx-runtime"); var mergeRefs = (...refs) => { return (node) => { refs.forEach((ref) => { if (typeof ref === "function") { ref(node); } else if (ref) { ; ref.current = node; } }); }; }; var Portals = ({ contentComponent }) => { const renderers = (0, import_shim.useSyncExternalStore)( contentComponent.subscribe, contentComponent.getSnapshot, contentComponent.getServerSnapshot ); return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: Object.values(renderers) }); }; function getInstance() { const subscribers = /* @__PURE__ */ 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]: import_react_dom.default.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()); } }; } var PureEditorContent = class extends import_react.default.Component { constructor(props) { var _a; super(props); this.editorContentRef = import_react.default.createRef(); this.initialized = false; this.state = { hasContentComponentInitialized: Boolean((_a = props.editor) == null ? void 0 : _a.contentComponent) }; } componentDidMount() { this.init(); } componentDidUpdate() { this.init(); } init() { var _a; const editor = this.props.editor; if (editor && !editor.isDestroyed && ((_a = editor.view.dom) == null ? void 0 : _a.parentNode)) { if (editor.contentComponent) { return; } const element = this.editorContentRef.current; element.append(...editor.view.dom.parentNode.childNodes); editor.setOptions({ element }); editor.contentComponent = getInstance(); if (!this.state.hasContentComponentInitialized) { this.unsubscribeToContentComponent = editor.contentComponent.subscribe(() => { this.setState((prevState) => { if (!prevState.hasContentComponentInitialized) { return { hasContentComponentInitialized: true }; } return prevState; }); if (this.unsubscribeToContentComponent) { this.unsubscribeToContentComponent(); } }); } editor.createNodeViews(); this.initialized = true; } } componentWillUnmount() { var _a; 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; try { if (!((_a = editor.view.dom) == null ? void 0 : _a.parentNode)) { return; } const newElement = document.createElement("div"); newElement.append(...editor.view.dom.parentNode.childNodes); editor.setOptions({ element: newElement }); } catch { } } render() { const { editor, innerRef, ...rest } = this.props; return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { ref: mergeRefs(innerRef, this.editorContentRef), ...rest }), (editor == null ? void 0 : editor.contentComponent) && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Portals, { contentComponent: editor.contentComponent }) ] }); } }; var EditorContentWithKey = (0, import_react.forwardRef)( (props, ref) => { const key = import_react.default.useMemo(() => { return Math.floor(Math.random() * 4294967295).toString(); }, [props.editor]); return import_react.default.createElement(PureEditorContent, { key, innerRef: ref, ...props }); } ); var EditorContent = import_react.default.memo(EditorContentWithKey); // src/useEditor.ts var import_core = require("@tiptap/core"); var import_react3 = require("react"); var import_shim2 = require("use-sync-external-store/shim/index.js"); // src/useEditorState.ts var import_fast_equals = require("fast-equals"); var import_react2 = require("react"); var import_with_selector = require("use-sync-external-store/shim/with-selector.js"); var useIsomorphicLayoutEffect = typeof window !== "undefined" ? import_react2.useLayoutEffect : import_react2.useEffect; var EditorStateManager = class { constructor(initialEditor) { this.transactionNumber = 0; this.lastTransactionNumber = 0; this.subscribers = /* @__PURE__ */ 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) { const fn = () => { this.transactionNumber += 1; this.subscribers.forEach((callback) => callback()); }; const currentEditor = this.editor; currentEditor.on("transaction", fn); return () => { currentEditor.off("transaction", fn); }; } return void 0; } }; function useEditorState(options) { var _a; const [editorStateManager] = (0, import_react2.useState)(() => new EditorStateManager(options.editor)); const selectedState = (0, import_with_selector.useSyncExternalStoreWithSelector)( editorStateManager.subscribe, editorStateManager.getSnapshot, editorStateManager.getServerSnapshot, options.selector, (_a = options.equalityFn) != null ? _a : import_fast_equals.deepEqual ); useIsomorphicLayoutEffect(() => { return editorStateManager.watch(options.editor); }, [options.editor, editorStateManager]); (0, import_react2.useDebugValue)(selectedState); return selectedState; } // src/useEditor.ts var isDev = process.env.NODE_ENV !== "production"; var isSSR = typeof window === "undefined"; var isNext = isSSR || Boolean(typeof window !== "undefined" && window.next); var EditorInstanceManager = 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 = /* @__PURE__ */ 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 = /* @__PURE__ */ 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); this.subscriptions.forEach((cb) => cb()); } getInitialEditor() { if (this.options.current.immediatelyRender === void 0) { if (isSSR || isNext) { if (isDev) { throw new Error( "Tiptap Error: SSR has been detected, please set `immediatelyRender` explicitly to `false` to avoid hydration mismatches." ); } return null; } return this.createEditor(); } if (this.options.current.immediatelyRender && isSSR && isDev) { 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 ? void 0 : _b.call(_a, ...args); }, onBlur: (...args) => { var _a, _b; return (_b = (_a = this.options.current).onBlur) == null ? void 0 : _b.call(_a, ...args); }, onCreate: (...args) => { var _a, _b; return (_b = (_a = this.options.current).onCreate) == null ? void 0 : _b.call(_a, ...args); }, onDestroy: (...args) => { var _a, _b; return (_b = (_a = this.options.current).onDestroy) == null ? void 0 : _b.call(_a, ...args); }, onFocus: (...args) => { var _a, _b; return (_b = (_a = this.options.current).onFocus) == null ? void 0 : _b.call(_a, ...args); }, onSelectionUpdate: (...args) => { var _a, _b; return (_b = (_a = this.options.current).onSelectionUpdate) == null ? void 0 : _b.call(_a, ...args); }, onTransaction: (...args) => { var _a, _b; return (_b = (_a = this.options.current).onTransaction) == null ? void 0 : _b.call(_a, ...args); }, onUpdate: (...args) => { var _a, _b; return (_b = (_a = this.options.current).onUpdate) == null ? void 0 : _b.call(_a, ...args); }, onContentError: (...args) => { var _a, _b; return (_b = (_a = this.options.current).onContentError) == null ? void 0 : _b.call(_a, ...args); }, onDrop: (...args) => { var _a, _b; return (_b = (_a = this.options.current).onDrop) == null ? void 0 : _b.call(_a, ...args); }, onPaste: (...args) => { var _a, _b; return (_b = (_a = this.options.current).onPaste) == null ? void 0 : _b.call(_a, ...args); }, onDelete: (...args) => { var _a, _b; return (_b = (_a = this.options.current).onDelete) == null ? void 0 : _b.call(_a, ...args); } }; const editor = new import_core.Editor(optionsToApply); 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)) { return true; } 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 ? void 0 : _a[index])) { return false; } return true; }); } if (a[key] !== b[key]) { 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) { return () => { this.isComponentMounted = true; clearTimeout(this.scheduledDestructionTimeout); if (this.editor && !this.editor.isDestroyed && deps.length === 0) { if (!_EditorInstanceManager.compareOptions(this.options.current, this.editor.options)) { this.editor.setOptions({ ...this.options.current, editable: this.editor.isEditable }); } } else { 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) { if (this.previousDeps === null) { this.previousDeps = deps; return; } const depsAreEqual = this.previousDeps.length === deps.length && this.previousDeps.every((dep, index) => dep === deps[index]); if (depsAreEqual) { return; } } if (this.editor && !this.editor.isDestroyed) { this.editor.destroy(); } this.setEditor(this.createEditor()); 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; this.scheduledDestructionTimeout = setTimeout(() => { if (this.isComponentMounted && this.instanceId === currentInstanceId) { if (currentEditor) { currentEditor.setOptions(this.options.current); } return; } if (currentEditor && !currentEditor.isDestroyed) { currentEditor.destroy(); if (this.instanceId === currentInstanceId) { this.setEditor(null); } } }, 1); } }; function useEditor(options = {}, deps = []) { const mostRecentOptions = (0, import_react3.useRef)(options); mostRecentOptions.current = options; const [instanceManager] = (0, import_react3.useState)(() => new EditorInstanceManager(mostRecentOptions)); const editor = (0, import_shim2.useSyncExternalStore)( instanceManager.subscribe, instanceManager.getEditor, instanceManager.getServerSnapshot ); (0, import_react3.useDebugValue)(editor); (0, import_react3.useEffect)(instanceManager.onRender(deps)); useEditorState({ editor, selector: ({ transactionNumber }) => { if (options.shouldRerenderOnTransaction === false || options.shouldRerenderOnTransaction === void 0) { return null; } if (options.immediatelyRender && transactionNumber === 0) { return 0; } return transactionNumber + 1; } }); return editor; } // src/Context.tsx var import_jsx_runtime2 = require("react/jsx-runtime"); var EditorContext = (0, import_react4.createContext)({ editor: null }); var EditorConsumer = EditorContext.Consumer; var useCurrentEditor = () => (0, import_react4.useContext)(EditorContext); function EditorProvider({ children, slotAfter, slotBefore, editorContainerProps = {}, ...editorOptions }) { const editor = useEditor(editorOptions); const contextValue = (0, import_react4.useMemo)(() => ({ editor }), [editor]); if (!editor) { return null; } return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(EditorContext.Provider, { value: contextValue, children: [ slotBefore, /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(EditorConsumer, { children: ({ editor: currentEditor }) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(EditorContent, { editor: currentEditor, ...editorContainerProps }) }), children, slotAfter ] }); } // src/useReactNodeView.ts var import_react5 = require("react"); var ReactNodeViewContext = (0, import_react5.createContext)({ onDragStart: () => { }, nodeViewContentChildren: void 0, nodeViewContentRef: () => { } }); var ReactNodeViewContentProvider = ({ children, content }) => { return (0, import_react5.createElement)(ReactNodeViewContext.Provider, { value: { nodeViewContentChildren: content } }, children); }; var useReactNodeView = () => (0, import_react5.useContext)(ReactNodeViewContext); // src/NodeViewContent.tsx var import_jsx_runtime3 = ( // @ts-ignore require("react/jsx-runtime") ); function NodeViewContent({ as: Tag = "div", ...props }) { const { nodeViewContentRef, nodeViewContentChildren } = useReactNodeView(); return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)( Tag, { ...props, ref: nodeViewContentRef, "data-node-view-content": "", style: { whiteSpace: "pre-wrap", ...props.style }, children: nodeViewContentChildren } ); } // src/NodeViewWrapper.tsx var import_react6 = __toESM(require("react"), 1); var import_jsx_runtime4 = ( // @ts-ignore require("react/jsx-runtime") ); var NodeViewWrapper = import_react6.default.forwardRef((props, ref) => { const { onDragStart } = useReactNodeView(); const Tag = props.as || "div"; return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)( Tag, { ...props, ref, "data-node-view-wrapper": "", onDragStart, style: { whiteSpace: "normal", ...props.style } } ); }); // src/ReactMarkViewRenderer.tsx var import_core2 = require("@tiptap/core"); var import_react8 = __toESM(require("react"), 1); // src/ReactRenderer.tsx var import_react7 = require("react"); var import_react_dom2 = require("react-dom"); var import_jsx_runtime5 = require("react/jsx-runtime"); function isClassComponent(Component) { return !!(typeof Component === "function" && Component.prototype && Component.prototype.isReactComponent); } function isForwardRefComponent(Component) { return !!(typeof Component === "object" && Component.$$typeof && (Component.$$typeof.toString() === "Symbol(react.forward_ref)" || Component.$$typeof.description === "react.forward_ref")); } function isMemoComponent(Component) { return !!(typeof Component === "object" && Component.$$typeof && (Component.$$typeof.toString() === "Symbol(react.memo)" || Component.$$typeof.description === "react.memo")); } function canReceiveRef(Component) { if (isClassComponent(Component)) { return true; } if (isForwardRefComponent(Component)) { return true; } if (isMemoComponent(Component)) { const wrappedComponent = Component.type; if (wrappedComponent) { return isClassComponent(wrappedComponent) || isForwardRefComponent(wrappedComponent); } } return false; } function isReact19Plus() { try { if (import_react7.version) { const majorVersion = parseInt(import_react7.version.split(".")[0], 10); return majorVersion >= 19; } } catch { } return false; } var ReactRenderer = class { /** * Immediately creates element and renders the provided React component. */ constructor(component, { editor, props = {}, as = "div", className = "" }) { this.ref = null; /** * Flag to track if the renderer has been destroyed, preventing queued or asynchronous renders from executing after teardown. */ this.destroyed = false; this.id = Math.floor(Math.random() * 4294967295).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) { (0, import_react_dom2.flushSync)(() => { this.render(); }); } else { queueMicrotask(() => { if (this.destroyed) { return; } this.render(); }); } } /** * Render the React component. */ render() { var _a; if (this.destroyed) { return; } const Component = this.component; const props = this.props; const editor = this.editor; const isReact19 = isReact19Plus(); const componentCanReceiveRef = canReceiveRef(Component); const elementProps = { ...props }; if (elementProps.ref && !(isReact19 || componentCanReceiveRef)) { delete elementProps.ref; } if (!elementProps.ref && (isReact19 || componentCanReceiveRef)) { elementProps.ref = (ref) => { this.ref = ref; }; } this.reactElement = /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Component, { ...elementProps }); (_a = editor == null ? void 0 : editor.contentComponent) == null ? void 0 : _a.setRenderer(this.id, this); } /** * Re-renders the React component with new props. */ updateProps(props = {}) { if (this.destroyed) { return; } this.props = { ...this.props, ...props }; this.render(); } /** * Destroy the React component. */ destroy() { var _a; this.destroyed = true; const editor = this.editor; (_a = editor == null ? void 0 : editor.contentComponent) == null ? void 0 : _a.removeRenderer(this.id); try { if (this.element && this.element.parentNode) { this.element.parentNode.removeChild(this.element); } } catch { } } /** * Update the attributes of the element that holds the React component. */ updateAttributes(attributes) { Object.keys(attributes).forEach((key) => { this.element.setAttribute(key, attributes[key]); }); } }; // src/ReactMarkViewRenderer.tsx var import_jsx_runtime6 = ( // @ts-ignore require("react/jsx-runtime") ); var ReactMarkViewContext = import_react8.default.createContext({ markViewContentRef: () => { } }); var MarkViewContent = (props) => { const { as: Tag = "span", ...rest } = props; const { markViewContentRef } = import_react8.default.useContext(ReactMarkViewContext); return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Tag, { ...rest, ref: markViewContentRef, "data-mark-view-content": "" }); }; var ReactMarkView = class extends import_core2.MarkView { constructor(component, props, options) { super(component, props, options); const { as = "span", attrs, className = "" } = options || {}; const componentProps = { ...props, updateAttributes: this.updateAttributes.bind(this) }; this.contentDOMElement = document.createElement("span"); const markViewContentRef = (el) => { if (el && !el.contains(this.contentDOMElement)) { el.appendChild(this.contentDOMElement); } }; const context = { markViewContentRef }; const ReactMarkViewProvider = import_react8.default.memo((componentProps2) => { return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ReactMarkViewContext.Provider, { value: context, children: import_react8.default.createElement(component, componentProps2) }); }); ReactMarkViewProvider.displayName = "ReactMarkView"; this.renderer = new ReactRenderer(ReactMarkViewProvider, { editor: props.editor, props: componentProps, as, className: `mark-${props.mark.type.name} ${className}`.trim() }); if (attrs) { this.renderer.updateAttributes(attrs); } } get dom() { return this.renderer.element; } get contentDOM() { return this.contentDOMElement; } }; function ReactMarkViewRenderer(component, options = {}) { return (props) => new ReactMarkView(component, props, options); } // src/ReactNodeViewRenderer.tsx var import_core3 = require("@tiptap/core"); var import_react9 = require("react"); var import_jsx_runtime7 = require("react/jsx-runtime"); var ReactNodeView = class extends import_core3.NodeView { constructor(component, props, options) { super(component, props, options); /** * The requestAnimationFrame ID used for selection updates. */ this.selectionRafId = null; this.cachedExtensionWithSyncedStorage = null; 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 = ""; this.contentDOMElement.style.whiteSpace = "inherit"; const contentTarget = this.dom.querySelector("[data-node-view-content]"); if (!contentTarget) { return; } contentTarget.appendChild(this.contentDOMElement); } } /** * Returns a proxy of the extension that redirects storage access to the editor's mutable storage. * This preserves the original prototype chain (instanceof checks, methods like configure/extend work). * Cached to avoid proxy creation on every update. */ get extensionWithSyncedStorage() { if (!this.cachedExtensionWithSyncedStorage) { const editor = this.editor; const extension = this.extension; this.cachedExtensionWithSyncedStorage = new Proxy(extension, { get(target, prop, receiver) { var _a; if (prop === "storage") { return (_a = editor.storage[extension.name]) != null ? _a : {}; } return Reflect.get(target, prop, receiver); } }); } return this.cachedExtensionWithSyncedStorage; } /** * 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.extensionWithSyncedStorage, HTMLAttributes: this.HTMLAttributes, getPos: () => this.getPos(), updateAttributes: (attributes = {}) => this.updateAttributes(attributes), deleteNode: () => this.deleteNode(), ref: (0, import_react9.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) { 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; const ReactNodeViewProvider = (0, import_react9.memo)((componentProps) => { return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ReactNodeViewContext.Provider, { value: context, children: (0, import_react9.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 ? 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() { if (this.selectionRafId) { cancelAnimationFrame(this.selectionRafId); this.selectionRafId = null; } this.selectionRafId = requestAnimationFrame(() => { this.selectionRafId = null; 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, extension: this.extensionWithSyncedStorage }) }); } if (node === this.node && this.decorations === decorations && this.innerDecorations === innerDecorations) { return true; } this.node = node; this.decorations = decorations; this.innerDecorations = innerDecorations; rerenderComponent({ node, decorations, innerDecorations, extension: this.extensionWithSyncedStorage }); return true; } /** * Select the node. * Add the `selected` prop and the `ProseMirror-selectednode` class. */ selectNode() { this.renderer.updateProps({ selected: true }); 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; if (this.selectionRafId) { cancelAnimationFrame(this.selectionRafId); this.selectionRafId = 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 = (0, import_core3.getRenderedAttributes)(this.node, extensionAttributes); attrsObj = this.options.attrs({ node: this.node, HTMLAttributes }); } else { attrsObj = this.options.attrs; } this.renderer.updateAttributes(attrsObj); } } }; function ReactNodeViewRenderer(component, options) { return (props) => { if (!props.editor.contentComponent) { return {}; } return new ReactNodeView(component, props, options); }; } // src/Tiptap.tsx var import_react10 = require("react"); var import_jsx_runtime8 = require("react/jsx-runtime"); var TiptapContext = (0, import_react10.createContext)({ get editor() { throw new Error("useTiptap must be used within a provider"); } }); TiptapContext.displayName = "TiptapContext"; var useTiptap = () => (0, import_react10.useContext)(TiptapContext); function useTiptapState(selector, equalityFn) { const { editor } = useTiptap(); return useEditorState({ editor, selector, equalityFn }); } function TiptapWrapper({ editor, instance, children }) { const resolvedEditor = editor != null ? editor : instance; if (!resolvedEditor) { throw new Error("Tiptap: An editor instance is required. Pass a non-null `editor` prop."); } const tiptapContextValue = (0, import_react10.useMemo)(() => ({ editor: resolvedEditor }), [resolvedEditor]); const legacyContextValue = (0, import_react10.useMemo)(() => ({ editor: resolvedEditor }), [resolvedEditor]); return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(EditorContext.Provider, { value: legacyContextValue, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(TiptapContext.Provider, { value: tiptapContextValue, children }) }); } TiptapWrapper.displayName = "Tiptap"; function TiptapContent({ ...rest }) { const { editor } = useTiptap(); return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(EditorContent, { editor, ...rest }); } TiptapContent.displayName = "Tiptap.Content"; var Tiptap = Object.assign(TiptapWrapper, { /** * The Tiptap Content component that renders the EditorContent with the editor instance from the context. * @see TiptapContent */ Content: TiptapContent }); // src/index.ts __reExport(index_exports, require("@tiptap/core"), module.exports); // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { EditorConsumer, EditorContent, EditorContext, EditorProvider, MarkViewContent, NodeViewContent, NodeViewWrapper, PureEditorContent, ReactMarkView, ReactMarkViewContext, ReactMarkViewRenderer, ReactNodeView, ReactNodeViewContentProvider, ReactNodeViewContext, ReactNodeViewRenderer, ReactRenderer, Tiptap, TiptapContent, TiptapContext, TiptapWrapper, useCurrentEditor, useEditor, useEditorState, useReactNodeView, useTiptap, useTiptapState, ...require("@tiptap/core") }); //# sourceMappingURL=index.cjs.map