UNPKG

reactjs-tiptap-editor

Version:

A modern WYSIWYG rich text editor based on tiptap and shadcn ui for React

1,021 lines (1,020 loc) 38 kB
import { P as ue, a as ae, j as de, i as le, p as ce, E as he, k as fe, l as pe, o as me } from "./index-CXIIg9Sq.js"; import ve from "tippy.js"; import g, { useRef as Se, useState as F, useDebugValue as k, useEffect as K, forwardRef as ye, useLayoutEffect as Ee, useContext as ee, createContext as te, createRef as _e, memo as ge, createElement as be, version as q } from "react"; import Oe, { flushSync as we } from "react-dom"; class De { constructor({ editor: e, element: t, view: r, tippyOptions: i = {}, updateDelay: o = 250, shouldShow: h }) { this.preventHide = !1, this.shouldShow = ({ view: s, state: f, from: l, to: d }) => { const { doc: u, selection: p } = f, { empty: m } = p, y = !u.textBetween(l, d).length && de(f.selection), S = this.element.contains(document.activeElement); return !(!(s.hasFocus() || S) || m || y || !this.editor.isEditable); }, this.mousedownHandler = () => { this.preventHide = !0; }, this.dragstartHandler = () => { this.hide(); }, this.focusHandler = () => { setTimeout(() => this.update(this.editor.view)); }, this.blurHandler = ({ event: s }) => { var f; if (this.preventHide) { this.preventHide = !1; return; } s != null && s.relatedTarget && (!((f = this.element.parentNode) === null || f === void 0) && f.contains(s.relatedTarget)) || (s == null ? void 0 : s.relatedTarget) !== this.editor.view.dom && this.hide(); }, this.tippyBlurHandler = (s) => { this.blurHandler({ event: s }); }, this.handleDebouncedUpdate = (s, f) => { const l = !(f != null && f.selection.eq(s.state.selection)), d = !(f != null && f.doc.eq(s.state.doc)); !l && !d || (this.updateDebounceTimer && clearTimeout(this.updateDebounceTimer), this.updateDebounceTimer = window.setTimeout(() => { this.updateHandler(s, l, d, f); }, this.updateDelay)); }, this.updateHandler = (s, f, l, d) => { var u, p, m; const { state: y, composing: S } = s, { selection: E } = y; if (S || !f && !l) return; this.createTooltip(); const { ranges: D } = E, v = Math.min(...D.map((a) => a.$from.pos)), c = Math.max(...D.map((a) => a.$to.pos)); if (!((u = this.shouldShow) === null || u === void 0 ? void 0 : u.call(this, { editor: this.editor, element: this.element, view: s, state: y, oldState: d, from: v, to: c }))) { this.hide(); return; } (p = this.tippy) === null || p === void 0 || p.setProps({ getReferenceClientRect: ((m = this.tippyOptions) === null || m === void 0 ? void 0 : m.getReferenceClientRect) || (() => { if (le(y.selection)) { let a = s.nodeDOM(v); if (a) { const _ = a.dataset.nodeViewWrapper ? a : a.querySelector("[data-node-view-wrapper]"); if (_ && (a = _.firstChild), a) return a.getBoundingClientRect(); } } return ce(s, v, c); }) }), this.show(); }, this.editor = e, this.element = t, this.view = r, this.updateDelay = o, h && (this.shouldShow = h), this.element.addEventListener("mousedown", this.mousedownHandler, { capture: !0 }), this.view.dom.addEventListener("dragstart", this.dragstartHandler), this.editor.on("focus", this.focusHandler), this.editor.on("blur", this.blurHandler), this.tippyOptions = i, this.element.remove(), this.element.style.visibility = "visible"; } createTooltip() { const { element: e } = this.editor.options, t = !!e.parentElement; this.tippy || !t || (this.tippy = ve(e, { duration: 0, getReferenceClientRect: null, content: this.element, interactive: !0, trigger: "manual", placement: "top", hideOnClick: "toggle", ...this.tippyOptions }), this.tippy.popper.firstChild && this.tippy.popper.firstChild.addEventListener("blur", this.tippyBlurHandler)); } update(e, t) { const { state: r } = e, i = r.selection.from !== r.selection.to; if (this.updateDelay > 0 && i) { this.handleDebouncedUpdate(e, t); return; } const o = !(t != null && t.selection.eq(e.state.selection)), h = !(t != null && t.doc.eq(e.state.doc)); this.updateHandler(e, o, h, t); } show() { var e; (e = this.tippy) === null || e === void 0 || e.show(); } hide() { var e; (e = this.tippy) === null || e === void 0 || e.hide(); } destroy() { var e, t; !((e = this.tippy) === null || e === void 0) && e.popper.firstChild && this.tippy.popper.firstChild.removeEventListener("blur", this.tippyBlurHandler), (t = this.tippy) === null || t === void 0 || t.destroy(), this.element.removeEventListener("mousedown", this.mousedownHandler, { capture: !0 }), this.view.dom.removeEventListener("dragstart", this.dragstartHandler), this.editor.off("focus", this.focusHandler), this.editor.off("blur", this.blurHandler); } } const ne = (n) => new ue({ key: typeof n.pluginKey == "string" ? new ae(n.pluginKey) : n.pluginKey, view: (e) => new De({ view: e, ...n }) }); he.create({ name: "bubbleMenu", addOptions() { return { element: null, tippyOptions: {}, pluginKey: "bubbleMenu", updateDelay: void 0, shouldShow: null }; }, addProseMirrorPlugins() { return this.options.element ? [ ne({ pluginKey: this.options.pluginKey, editor: this.editor, element: this.options.element, tippyOptions: this.options.tippyOptions, updateDelay: this.options.updateDelay, shouldShow: this.options.shouldShow }) ] : []; } }); function Ce(n) { return n && n.__esModule && Object.prototype.hasOwnProperty.call(n, "default") ? n.default : n; } var P = { exports: {} }, I = {}; /** * @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 z; function Re() { if (z) return I; z = 1; var n = g; function e(u, p) { return u === p && (u !== 0 || 1 / u === 1 / p) || u !== u && p !== p; } var t = typeof Object.is == "function" ? Object.is : e, r = n.useState, i = n.useEffect, o = n.useLayoutEffect, h = n.useDebugValue; function s(u, p) { var m = p(), y = r({ inst: { value: m, getSnapshot: p } }), S = y[0].inst, E = y[1]; return o(function() { S.value = m, S.getSnapshot = p, f(S) && E({ inst: S }); }, [u, m, p]), i(function() { return f(S) && E({ inst: S }), u(function() { f(S) && E({ inst: S }); }); }, [u]), h(m), m; } function f(u) { var p = u.getSnapshot; u = u.value; try { var m = p(); return !t(u, m); } catch { return !0; } } function l(u, p) { return p(); } var d = typeof window > "u" || typeof window.document > "u" || typeof window.document.createElement > "u" ? l : s; return I.useSyncExternalStore = n.useSyncExternalStore !== void 0 ? n.useSyncExternalStore : d, I; } var H = {}; /** * @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 G; function Te() { return G || (G = 1, process.env.NODE_ENV !== "production" && function() { typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ < "u" && typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart == "function" && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(new Error()); var n = g, e = n.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; function t(v) { { for (var c = arguments.length, b = new Array(c > 1 ? c - 1 : 0), a = 1; a < c; a++) b[a - 1] = arguments[a]; r("error", v, b); } } function r(v, c, b) { { var a = e.ReactDebugCurrentFrame, _ = a.getStackAddendum(); _ !== "" && (c += "%s", b = b.concat([_])); var w = b.map(function(O) { return String(O); }); w.unshift("Warning: " + c), Function.prototype.apply.call(console[v], console, w); } } function i(v, c) { return v === c && (v !== 0 || 1 / v === 1 / c) || v !== v && c !== c; } var o = typeof Object.is == "function" ? Object.is : i, h = n.useState, s = n.useEffect, f = n.useLayoutEffect, l = n.useDebugValue, d = !1, u = !1; function p(v, c, b) { d || n.startTransition !== void 0 && (d = !0, t("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.")); var a = c(); if (!u) { var _ = c(); o(a, _) || (t("The result of getSnapshot should be cached to avoid an infinite loop"), u = !0); } var w = h({ inst: { value: a, getSnapshot: c } }), O = w[0].inst, R = w[1]; return f(function() { O.value = a, O.getSnapshot = c, m(O) && R({ inst: O }); }, [v, a, c]), s(function() { m(O) && R({ inst: O }); var L = function() { m(O) && R({ inst: O }); }; return v(L); }, [v]), l(a), a; } function m(v) { var c = v.getSnapshot, b = v.value; try { var a = c(); return !o(b, a); } catch { return !0; } } function y(v, c, b) { return c(); } var S = typeof window < "u" && typeof window.document < "u" && typeof window.document.createElement < "u", E = !S, C = E ? y : p, D = n.useSyncExternalStore !== void 0 ? n.useSyncExternalStore : C; H.useSyncExternalStore = D, typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ < "u" && typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop == "function" && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop(new Error()); }()), H; } process.env.NODE_ENV === "production" ? P.exports = Re() : P.exports = Te(); var M = P.exports; const Me = (...n) => (e) => { n.forEach((t) => { typeof t == "function" ? t(e) : t && (t.current = e); }); }, Le = ({ contentComponent: n }) => { const e = M.useSyncExternalStore(n.subscribe, n.getSnapshot, n.getServerSnapshot); return g.createElement(g.Fragment, null, Object.values(e)); }; function Ae() { const n = /* @__PURE__ */ new Set(); let e = {}; return { /** * Subscribe to the editor instance's changes. */ subscribe(t) { return n.add(t), () => { n.delete(t); }; }, getSnapshot() { return e; }, getServerSnapshot() { return e; }, /** * Adds a new NodeView Renderer to the editor. */ setRenderer(t, r) { e = { ...e, [t]: Oe.createPortal(r.reactElement, r.element, t) }, n.forEach((i) => i()); }, /** * Removes a NodeView Renderer from the editor. */ removeRenderer(t) { const r = { ...e }; delete r[t], e = r, n.forEach((i) => i()); } }; } class Ne extends g.Component { constructor(e) { var t; super(e), this.editorContentRef = g.createRef(), this.initialized = !1, this.state = { hasContentComponentInitialized: !!(!((t = e.editor) === null || t === void 0) && t.contentComponent) }; } componentDidMount() { this.init(); } componentDidUpdate() { this.init(); } init() { const e = this.props.editor; if (e && !e.isDestroyed && e.options.element) { if (e.contentComponent) return; const t = this.editorContentRef.current; t.append(...e.options.element.childNodes), e.setOptions({ element: t }), e.contentComponent = Ae(), this.state.hasContentComponentInitialized || (this.unsubscribeToContentComponent = e.contentComponent.subscribe(() => { this.setState((r) => r.hasContentComponentInitialized ? r : { hasContentComponentInitialized: !0 }), this.unsubscribeToContentComponent && this.unsubscribeToContentComponent(); })), e.createNodeViews(), this.initialized = !0; } } componentWillUnmount() { const e = this.props.editor; if (!e || (this.initialized = !1, e.isDestroyed || e.view.setProps({ nodeViews: {} }), this.unsubscribeToContentComponent && this.unsubscribeToContentComponent(), e.contentComponent = null, !e.options.element.firstChild)) return; const t = document.createElement("div"); t.append(...e.options.element.childNodes), e.setOptions({ element: t }); } render() { const { editor: e, innerRef: t, ...r } = this.props; return g.createElement( g.Fragment, null, g.createElement("div", { ref: Me(t, this.editorContentRef), ...r }), (e == null ? void 0 : e.contentComponent) && g.createElement(Le, { contentComponent: e.contentComponent }) ); } } const xe = ye((n, e) => { const t = g.useMemo(() => Math.floor(Math.random() * 4294967295).toString(), [n.editor]); return g.createElement(Ne, { key: t, innerRef: e, ...n }); }), tt = g.memo(xe); var Ve = function n(e, t) { if (e === t) return !0; if (e && t && typeof e == "object" && typeof t == "object") { if (e.constructor !== t.constructor) return !1; var r, i, o; if (Array.isArray(e)) { if (r = e.length, r != t.length) return !1; for (i = r; i-- !== 0; ) if (!n(e[i], t[i])) return !1; return !0; } if (e instanceof Map && t instanceof Map) { if (e.size !== t.size) return !1; for (i of e.entries()) if (!t.has(i[0])) return !1; for (i of e.entries()) if (!n(i[1], t.get(i[0]))) return !1; return !0; } if (e instanceof Set && t instanceof Set) { if (e.size !== t.size) return !1; for (i of e.entries()) if (!t.has(i[0])) return !1; return !0; } if (ArrayBuffer.isView(e) && ArrayBuffer.isView(t)) { if (r = e.length, r != t.length) return !1; for (i = r; i-- !== 0; ) if (e[i] !== t[i]) return !1; return !0; } if (e.constructor === RegExp) return e.source === t.source && e.flags === t.flags; if (e.valueOf !== Object.prototype.valueOf) return e.valueOf() === t.valueOf(); if (e.toString !== Object.prototype.toString) return e.toString() === t.toString(); if (o = Object.keys(e), r = o.length, r !== Object.keys(t).length) return !1; for (i = r; i-- !== 0; ) if (!Object.prototype.hasOwnProperty.call(t, o[i])) return !1; for (i = r; i-- !== 0; ) { var h = o[i]; if (!(h === "_owner" && e.$$typeof) && !n(e[h], t[h])) return !1; } return !0; } return e !== e && t !== t; }, Ie = /* @__PURE__ */ Ce(Ve), U = { exports: {} }, B = {}; /** * @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 J; function He() { if (J) return B; J = 1; var n = g, e = M; function t(l, d) { return l === d && (l !== 0 || 1 / l === 1 / d) || l !== l && d !== d; } var r = typeof Object.is == "function" ? Object.is : t, i = e.useSyncExternalStore, o = n.useRef, h = n.useEffect, s = n.useMemo, f = n.useDebugValue; return B.useSyncExternalStoreWithSelector = function(l, d, u, p, m) { var y = o(null); if (y.current === null) { var S = { hasValue: !1, value: null }; y.current = S; } else S = y.current; y = s(function() { function C(a) { if (!D) { if (D = !0, v = a, a = p(a), m !== void 0 && S.hasValue) { var _ = S.value; if (m(_, a)) return c = _; } return c = a; } if (_ = c, r(v, a)) return _; var w = p(a); return m !== void 0 && m(_, w) ? _ : (v = a, c = w); } var D = !1, v, c, b = u === void 0 ? null : u; return [function() { return C(d()); }, b === null ? void 0 : function() { return C(b()); }]; }, [d, u, p, m]); var E = i(l, y[0], y[1]); return h(function() { S.hasValue = !0, S.value = E; }, [E]), f(E), E; }, B; } var j = {}; /** * @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 Y; function Be() { return Y || (Y = 1, process.env.NODE_ENV !== "production" && function() { typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ < "u" && typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart == "function" && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(new Error()); var n = g, e = M; function t(d, u) { return d === u && (d !== 0 || 1 / d === 1 / u) || d !== d && u !== u; } var r = typeof Object.is == "function" ? Object.is : t, i = e.useSyncExternalStore, o = n.useRef, h = n.useEffect, s = n.useMemo, f = n.useDebugValue; function l(d, u, p, m, y) { var S = o(null), E; S.current === null ? (E = { hasValue: !1, value: null }, S.current = E) : E = S.current; var C = s(function() { var b = !1, a, _, w = function(T) { if (!b) { b = !0, a = T; var A = m(T); if (y !== void 0 && E.hasValue) { var N = E.value; if (y(N, A)) return _ = N, N; } return _ = A, A; } var se = a, x = _; if (r(se, T)) return x; var V = m(T); return y !== void 0 && y(x, V) ? x : (a = T, _ = V, V); }, O = p === void 0 ? null : p, R = function() { return w(u()); }, L = O === null ? void 0 : function() { return w(O()); }; return [R, L]; }, [u, p, m, y]), D = C[0], v = C[1], c = i(d, D, v); return h(function() { E.hasValue = !0, E.value = c; }, [c]), f(c), c; } j.useSyncExternalStoreWithSelector = l, typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ < "u" && typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop == "function" && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop(new Error()); }()), j; } process.env.NODE_ENV === "production" ? U.exports = He() : U.exports = Be(); var je = U.exports; const Pe = typeof window < "u" ? Ee : K; class Ue { constructor(e) { this.transactionNumber = 0, this.lastTransactionNumber = 0, this.subscribers = /* @__PURE__ */ new Set(), this.editor = e, this.lastSnapshot = { editor: e, 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() { return this.transactionNumber === this.lastTransactionNumber ? this.lastSnapshot : (this.lastTransactionNumber = this.transactionNumber, this.lastSnapshot = { editor: this.editor, transactionNumber: this.transactionNumber }, this.lastSnapshot); } /** * Always disable the editor on the server-side. */ getServerSnapshot() { return { editor: null, transactionNumber: 0 }; } /** * Subscribe to the editor instance's changes. */ subscribe(e) { return this.subscribers.add(e), () => { this.subscribers.delete(e); }; } /** * Watch the editor instance for changes. */ watch(e) { if (this.editor = e, this.editor) { const t = () => { this.transactionNumber += 1, this.subscribers.forEach((i) => i()); }, r = this.editor; return r.on("transaction", t), () => { r.off("transaction", t); }; } } } function $e(n) { var e; const [t] = F(() => new Ue(n.editor)), r = je.useSyncExternalStoreWithSelector(t.subscribe, t.getSnapshot, t.getServerSnapshot, n.selector, (e = n.equalityFn) !== null && e !== void 0 ? e : Ie); return Pe(() => t.watch(n.editor), [n.editor, t]), k(r), r; } const Q = process.env.NODE_ENV !== "production", $ = typeof window > "u", Fe = $ || !!(typeof window < "u" && window.next); class W { constructor(e) { this.editor = null, this.subscriptions = /* @__PURE__ */ new Set(), this.isComponentMounted = !1, this.previousDeps = null, this.instanceId = "", this.options = e, 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(e) { this.editor = e, this.instanceId = Math.random().toString(36).slice(2, 9), this.subscriptions.forEach((t) => t()); } getInitialEditor() { if (this.options.current.immediatelyRender === void 0) return $ || Fe ? (Q && console.warn("Tiptap Error: SSR has been detected, please set `immediatelyRender` explicitly to `false` to avoid hydration mismatches."), null) : this.createEditor(); if (this.options.current.immediatelyRender && $ && Q) 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."); return this.options.current.immediatelyRender ? this.createEditor() : null; } /** * Create a new editor instance. And attach event listeners. */ createEditor() { const e = { ...this.options.current, // Always call the most recent version of the callback function by default onBeforeCreate: (...r) => { var i, o; return (o = (i = this.options.current).onBeforeCreate) === null || o === void 0 ? void 0 : o.call(i, ...r); }, onBlur: (...r) => { var i, o; return (o = (i = this.options.current).onBlur) === null || o === void 0 ? void 0 : o.call(i, ...r); }, onCreate: (...r) => { var i, o; return (o = (i = this.options.current).onCreate) === null || o === void 0 ? void 0 : o.call(i, ...r); }, onDestroy: (...r) => { var i, o; return (o = (i = this.options.current).onDestroy) === null || o === void 0 ? void 0 : o.call(i, ...r); }, onFocus: (...r) => { var i, o; return (o = (i = this.options.current).onFocus) === null || o === void 0 ? void 0 : o.call(i, ...r); }, onSelectionUpdate: (...r) => { var i, o; return (o = (i = this.options.current).onSelectionUpdate) === null || o === void 0 ? void 0 : o.call(i, ...r); }, onTransaction: (...r) => { var i, o; return (o = (i = this.options.current).onTransaction) === null || o === void 0 ? void 0 : o.call(i, ...r); }, onUpdate: (...r) => { var i, o; return (o = (i = this.options.current).onUpdate) === null || o === void 0 ? void 0 : o.call(i, ...r); }, onContentError: (...r) => { var i, o; return (o = (i = this.options.current).onContentError) === null || o === void 0 ? void 0 : o.call(i, ...r); }, onDrop: (...r) => { var i, o; return (o = (i = this.options.current).onDrop) === null || o === void 0 ? void 0 : o.call(i, ...r); }, onPaste: (...r) => { var i, o; return (o = (i = this.options.current).onPaste) === null || o === void 0 ? void 0 : o.call(i, ...r); } }; return new fe(e); } /** * 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(e) { return this.subscriptions.add(e), () => { this.subscriptions.delete(e); }; } static compareOptions(e, t) { return Object.keys(e).every((r) => ["onCreate", "onBeforeCreate", "onDestroy", "onUpdate", "onTransaction", "onFocus", "onBlur", "onSelectionUpdate", "onContentError", "onDrop", "onPaste"].includes(r) ? !0 : r === "extensions" && e.extensions && t.extensions ? e.extensions.length !== t.extensions.length ? !1 : e.extensions.every((i, o) => { var h; return i === ((h = t.extensions) === null || h === void 0 ? void 0 : h[o]); }) : e[r] === t[r]); } /** * 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(e) { return () => (this.isComponentMounted = !0, clearTimeout(this.scheduledDestructionTimeout), this.editor && !this.editor.isDestroyed && e.length === 0 ? W.compareOptions(this.options.current, this.editor.options) || this.editor.setOptions({ ...this.options.current, editable: this.editor.isEditable }) : this.refreshEditorInstance(e), () => { this.isComponentMounted = !1, this.scheduleDestroy(); }); } /** * Recreate the editor instance if the dependencies have changed. */ refreshEditorInstance(e) { if (this.editor && !this.editor.isDestroyed) { if (this.previousDeps === null) { this.previousDeps = e; return; } if (this.previousDeps.length === e.length && this.previousDeps.every((r, i) => r === e[i])) return; } this.editor && !this.editor.isDestroyed && this.editor.destroy(), this.setEditor(this.createEditor()), this.previousDeps = e; } /** * 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 e = this.instanceId, t = this.editor; this.scheduledDestructionTimeout = setTimeout(() => { if (this.isComponentMounted && this.instanceId === e) { t && t.setOptions(this.options.current); return; } t && !t.isDestroyed && (t.destroy(), this.instanceId === e && this.setEditor(null)); }, 1); } } function nt(n = {}, e = []) { const t = Se(n); t.current = n; const [r] = F(() => new W(t)), i = M.useSyncExternalStore(r.subscribe, r.getEditor, r.getServerSnapshot); return k(i), K(r.onRender(e)), $e({ editor: i, selector: ({ transactionNumber: o }) => n.shouldRerenderOnTransaction === !1 ? null : n.immediatelyRender && o === 0 ? 0 : o + 1 }), i; } const re = te({ editor: null }); re.Consumer; const Ke = () => ee(re), rt = (n) => { const [e, t] = F(null), { editor: r } = Ke(); return K(() => { var i; if (!e || !((i = n.editor) === null || i === void 0) && i.isDestroyed || r != null && r.isDestroyed) return; const { pluginKey: o = "bubbleMenu", editor: h, tippyOptions: s = {}, updateDelay: f, shouldShow: l = null } = n, d = h || r; if (!d) { console.warn("BubbleMenu component is not rendered inside of an editor component or does not have editor prop."); return; } const u = ne({ updateDelay: f, editor: d, element: e, pluginKey: o, shouldShow: l, tippyOptions: s }); return d.registerPlugin(u), () => { d.unregisterPlugin(o); }; }, [n.editor, r, e]), g.createElement("div", { ref: t, className: n.className, style: { visibility: "hidden" } }, n.children); }, ie = te({ onDragStart: void 0 }), We = () => ee(ie), it = g.forwardRef((n, e) => { const { onDragStart: t } = We(), r = n.as || "div"; return ( // @ts-ignore g.createElement(r, { ...n, ref: e, "data-node-view-wrapper": "", onDragStart: t, style: { whiteSpace: "normal", ...n.style } }) ); }); function X(n) { return !!(typeof n == "function" && n.prototype && n.prototype.isReactComponent); } function Z(n) { return !!(typeof n == "object" && n.$$typeof && (n.$$typeof.toString() === "Symbol(react.forward_ref)" || n.$$typeof.description === "react.forward_ref")); } function qe(n) { return !!(typeof n == "object" && n.$$typeof && (n.$$typeof.toString() === "Symbol(react.memo)" || n.$$typeof.description === "react.memo")); } function ze(n) { if (X(n) || Z(n)) return !0; if (qe(n)) { const e = n.type; if (e) return X(e) || Z(e); } return !1; } function Ge() { try { if (q) return parseInt(q.split(".")[0], 10) >= 19; } catch { } return !1; } class Je { /** * Immediately creates element and renders the provided React component. */ constructor(e, { editor: t, props: r = {}, as: i = "div", className: o = "" }) { this.ref = null, this.id = Math.floor(Math.random() * 4294967295).toString(), this.component = e, this.editor = t, this.props = r, this.element = document.createElement(i), this.element.classList.add("react-renderer"), o && this.element.classList.add(...o.split(" ")), this.editor.isInitialized ? we(() => { this.render(); }) : this.render(); } /** * Render the React component. */ render() { var e; const t = this.component, r = this.props, i = this.editor, o = Ge(), h = ze(t), s = { ...r }; s.ref && !(o || h) && delete s.ref, !s.ref && (o || h) && (s.ref = (f) => { this.ref = f; }), this.reactElement = g.createElement(t, { ...s }), (e = i == null ? void 0 : i.contentComponent) === null || e === void 0 || e.setRenderer(this.id, this); } /** * Re-renders the React component with new props. */ updateProps(e = {}) { this.props = { ...this.props, ...e }, this.render(); } /** * Destroy the React component. */ destroy() { var e; const t = this.editor; (e = t == null ? void 0 : t.contentComponent) === null || e === void 0 || e.removeRenderer(this.id); } /** * Update the attributes of the element that holds the React component. */ updateAttributes(e) { Object.keys(e).forEach((t) => { this.element.setAttribute(t, e[t]); }); } } class Ye extends pe { /** * Setup the React component. * Called on initialization. */ mount() { const e = { editor: this.editor, node: this.node, decorations: this.decorations, innerDecorations: this.innerDecorations, view: this.view, selected: !1, extension: this.extension, HTMLAttributes: this.HTMLAttributes, getPos: () => this.getPos(), updateAttributes: (l = {}) => this.updateAttributes(l), deleteNode: () => this.deleteNode(), ref: _e() }; if (!this.component.displayName) { const l = (d) => d.charAt(0).toUpperCase() + d.substring(1); this.component.displayName = l(this.extension.name); } const i = { onDragStart: this.onDragStart.bind(this), nodeViewContentRef: (l) => { l && this.contentDOMElement && l.firstChild !== this.contentDOMElement && l.appendChild(this.contentDOMElement); } }, o = this.component, h = ge((l) => g.createElement(ie.Provider, { value: i }, be(o, l))); h.displayName = "ReactNodeView", this.node.isLeaf ? this.contentDOMElement = null : this.options.contentDOMElementTag ? this.contentDOMElement = document.createElement(this.options.contentDOMElementTag) : this.contentDOMElement = document.createElement(this.node.isInline ? "span" : "div"), this.contentDOMElement && (this.contentDOMElement.dataset.nodeViewContentReact = "", this.contentDOMElement.style.whiteSpace = "inherit"); let s = this.node.isInline ? "span" : "div"; this.options.as && (s = this.options.as); const { className: f = "" } = this.options; this.handleSelectionUpdate = this.handleSelectionUpdate.bind(this), this.renderer = new Je(h, { editor: this.editor, props: e, as: s, className: `node-${this.node.type.name} ${f}`.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 e; if (this.renderer.element.firstElementChild && !(!((e = this.renderer.element.firstElementChild) === null || e === void 0) && e.hasAttribute("data-node-view-wrapper"))) throw Error("Please use the NodeViewWrapper component for your node view."); return this.renderer.element; } /** * Return the content DOM element. * This is the element that will be used to display the rich-text content of the node. */ get contentDOM() { return this.node.isLeaf ? null : this.contentDOMElement; } /** * On editor selection update, check if the node is selected. * If it is, call `selectNode`, otherwise call `deselectNode`. */ handleSelectionUpdate() { const { from: e, to: t } = this.editor.state.selection, r = this.getPos(); if (typeof r == "number") if (e <= r && t >= r + 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(e, t, r) { const i = (o) => { this.renderer.updateProps(o), typeof this.options.attrs == "function" && this.updateElementAttributes(); }; if (e.type !== this.node.type) return !1; if (typeof this.options.update == "function") { const o = this.node, h = this.decorations, s = this.innerDecorations; return this.node = e, this.decorations = t, this.innerDecorations = r, this.options.update({ oldNode: o, oldDecorations: h, newNode: e, newDecorations: t, oldInnerDecorations: s, innerDecorations: r, updateProps: () => i({ node: e, decorations: t, innerDecorations: r }) }); } return e === this.node && this.decorations === t && this.innerDecorations === r || (this.node = e, this.decorations = t, this.innerDecorations = r, i({ node: e, decorations: t, innerDecorations: r })), !0; } /** * Select the node. * Add the `selected` prop and the `ProseMirror-selectednode` class. */ selectNode() { this.renderer.updateProps({ selected: !0 }), this.renderer.element.classList.add("ProseMirror-selectednode"); } /** * Deselect the node. * Remove the `selected` prop and the `ProseMirror-selectednode` class. */ deselectNode() { this.renderer.updateProps({ selected: !1 }), this.renderer.element.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 e = {}; if (typeof this.options.attrs == "function") { const t = this.editor.extensionManager.attributes, r = me(this.node, t); e = this.options.attrs({ node: this.node, HTMLAttributes: r }); } else e = this.options.attrs; this.renderer.updateAttributes(e); } } } function ot(n, e) { return (t) => t.editor.contentComponent ? new Ye(n, t, e) : {}; } function oe(n) { var e, t, r = ""; if (typeof n == "string" || typeof n == "number") r += n; else if (typeof n == "object") if (Array.isArray(n)) { var i = n.length; for (e = 0; e < i; e++) n[e] && (t = oe(n[e])) && (r && (r += " "), r += t); } else for (t in n) n[t] && (r && (r += " "), r += t); return r; } function st() { for (var n, e, t = 0, r = "", i = arguments.length; t < i; t++) (n = arguments[t]) && (e = oe(n)) && (r && (r += " "), r += e); return r; } function Qe(n) { try { return JSON.stringify(n); } catch { return JSON.stringify({}); } } function ut(n, e = !1) { return (t) => { const r = n.startsWith("data-") ? n : `data-${n}`; let i = decodeURIComponent(t.getAttribute(r)); if (i == null || typeof i == "string" && i === "null") try { const s = t.outerHTML.match(/([\S\s])+?="([\S\s])+?"/g); s && s.length > 0 && (i = (s.map((l) => l.trim()).reduce((l, d) => { const u = d.indexOf("="), p = [d.slice(0, u), d.slice(u + 1).slice(1, -1)]; return l[p[0]] = p[1], l; }, {})[n.toLowerCase()] || "").replaceAll("&quot;", '"')); } catch (h) { console.error("Error getDatasetAttribute ", h.message, t); } if (e) try { return JSON.parse(i); } catch { return {}; } if (i.includes("%") || i.includes("auto")) return i; const o = Number.parseInt(i); return o !== o ? i : o; }; } function at(n) { const { attrs: e } = n; return Object.keys(e).reduce((t, r) => { const i = e[r]; if (i == null) return t; let o = ""; return typeof i == "object" ? o = Qe(i) : o = i, t[r] = o, t; }, /* @__PURE__ */ Object.create(null)); } export { rt as B, tt as E, it as N, ot as R, Je as a, st as c, ut as g, at as n, nt as u };