UNPKG

velaris-richtext-editor

Version:

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

1,000 lines (999 loc) 37.4 kB
import { P as ie, a as oe, h as se, i as ue, p as ae, E as de, j as le, k as ce, l as he } from "./index-Drmyqk9P.js"; import fe from "tippy.js"; import y, { useRef as pe, useState as K, useDebugValue as Q, useEffect as W, forwardRef as me, useLayoutEffect as ve, useContext as X, createContext as Z } from "react"; import Se, { flushSync as Ee } from "react-dom"; class ye { constructor({ editor: e, element: t, view: n, tippyOptions: r = {}, updateDelay: o = 250, shouldShow: p }) { this.preventHide = !1, this.shouldShow = ({ view: a, state: f, from: l, to: d }) => { const { doc: s, selection: h } = f, { empty: m } = h, E = !s.textBetween(l, d).length && se(f.selection), S = this.element.contains(document.activeElement); return !(!(a.hasFocus() || S) || m || E || !this.editor.isEditable); }, this.mousedownHandler = () => { this.preventHide = !0; }, this.dragstartHandler = () => { this.hide(); }, this.focusHandler = () => { setTimeout(() => this.update(this.editor.view)); }, this.blurHandler = ({ event: a }) => { var f; if (this.preventHide) { this.preventHide = !1; return; } a != null && a.relatedTarget && (!((f = this.element.parentNode) === null || f === void 0) && f.contains(a.relatedTarget)) || (a == null ? void 0 : a.relatedTarget) !== this.editor.view.dom && this.hide(); }, this.tippyBlurHandler = (a) => { this.blurHandler({ event: a }); }, this.handleDebouncedUpdate = (a, f) => { const l = !(f != null && f.selection.eq(a.state.selection)), d = !(f != null && f.doc.eq(a.state.doc)); !l && !d || (this.updateDebounceTimer && clearTimeout(this.updateDebounceTimer), this.updateDebounceTimer = window.setTimeout(() => { this.updateHandler(a, l, d, f); }, this.updateDelay)); }, this.updateHandler = (a, f, l, d) => { var s, h, m; const { state: E, composing: S } = a, { selection: _ } = E; if (S || !f && !l) return; this.createTooltip(); const { ranges: C } = _, v = Math.min(...C.map((u) => u.$from.pos)), c = Math.max(...C.map((u) => u.$to.pos)); if (!((s = this.shouldShow) === null || s === void 0 ? void 0 : s.call(this, { editor: this.editor, element: this.element, view: a, state: E, oldState: d, from: v, to: c }))) { this.hide(); return; } (h = this.tippy) === null || h === void 0 || h.setProps({ getReferenceClientRect: ((m = this.tippyOptions) === null || m === void 0 ? void 0 : m.getReferenceClientRect) || (() => { if (ue(E.selection)) { let u = a.nodeDOM(v); if (u) { const g = u.dataset.nodeViewWrapper ? u : u.querySelector("[data-node-view-wrapper]"); if (g && (u = g.firstChild), u) return u.getBoundingClientRect(); } } return ae(a, v, c); }) }), this.show(); }, this.editor = e, this.element = t, this.view = n, this.updateDelay = o, p && (this.shouldShow = p), 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 = r, this.element.remove(), this.element.style.visibility = "visible"; } createTooltip() { const { element: e } = this.editor.options, t = !!e.parentElement; this.tippy || !t || (this.tippy = fe(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: n } = e, r = n.selection.from !== n.selection.to; if (this.updateDelay > 0 && r) { this.handleDebouncedUpdate(e, t); return; } const o = !(t != null && t.selection.eq(e.state.selection)), p = !(t != null && t.doc.eq(e.state.doc)); this.updateHandler(e, o, p, 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 k = (i) => new ie({ key: typeof i.pluginKey == "string" ? new oe(i.pluginKey) : i.pluginKey, view: (e) => new ye({ view: e, ...i }) }); de.create({ name: "bubbleMenu", addOptions() { return { element: null, tippyOptions: {}, pluginKey: "bubbleMenu", updateDelay: void 0, shouldShow: null }; }, addProseMirrorPlugins() { return this.options.element ? [ k({ pluginKey: this.options.pluginKey, editor: this.editor, element: this.options.element, tippyOptions: this.options.tippyOptions, updateDelay: this.options.updateDelay, shouldShow: this.options.shouldShow }) ] : []; } }); function _e(i) { return i && i.__esModule && Object.prototype.hasOwnProperty.call(i, "default") ? i.default : i; } var j = { 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 ge() { if (z) return I; z = 1; var i = y; function e(s, h) { return s === h && (s !== 0 || 1 / s === 1 / h) || s !== s && h !== h; } var t = typeof Object.is == "function" ? Object.is : e, n = i.useState, r = i.useEffect, o = i.useLayoutEffect, p = i.useDebugValue; function a(s, h) { var m = h(), E = n({ inst: { value: m, getSnapshot: h } }), S = E[0].inst, _ = E[1]; return o(function() { S.value = m, S.getSnapshot = h, f(S) && _({ inst: S }); }, [s, m, h]), r(function() { return f(S) && _({ inst: S }), s(function() { f(S) && _({ inst: S }); }); }, [s]), p(m), m; } function f(s) { var h = s.getSnapshot; s = s.value; try { var m = h(); return !t(s, m); } catch { return !0; } } function l(s, h) { return h(); } var d = typeof window > "u" || typeof window.document > "u" || typeof window.document.createElement > "u" ? l : a; return I.useSyncExternalStore = i.useSyncExternalStore !== void 0 ? i.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 Oe() { 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 i = y, e = i.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; function t(v) { { for (var c = arguments.length, O = new Array(c > 1 ? c - 1 : 0), u = 1; u < c; u++) O[u - 1] = arguments[u]; n("error", v, O); } } function n(v, c, O) { { var u = e.ReactDebugCurrentFrame, g = u.getStackAddendum(); g !== "" && (c += "%s", O = O.concat([g])); var w = O.map(function(b) { return String(b); }); w.unshift("Warning: " + c), Function.prototype.apply.call(console[v], console, w); } } function r(v, c) { return v === c && (v !== 0 || 1 / v === 1 / c) || v !== v && c !== c; } var o = typeof Object.is == "function" ? Object.is : r, p = i.useState, a = i.useEffect, f = i.useLayoutEffect, l = i.useDebugValue, d = !1, s = !1; function h(v, c, O) { d || i.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 u = c(); if (!s) { var g = c(); o(u, g) || (t("The result of getSnapshot should be cached to avoid an infinite loop"), s = !0); } var w = p({ inst: { value: u, getSnapshot: c } }), b = w[0].inst, R = w[1]; return f(function() { b.value = u, b.getSnapshot = c, m(b) && R({ inst: b }); }, [v, u, c]), a(function() { m(b) && R({ inst: b }); var L = function() { m(b) && R({ inst: b }); }; return v(L); }, [v]), l(u), u; } function m(v) { var c = v.getSnapshot, O = v.value; try { var u = c(); return !o(O, u); } catch { return !0; } } function E(v, c, O) { return c(); } var S = typeof window < "u" && typeof window.document < "u" && typeof window.document.createElement < "u", _ = !S, D = _ ? E : h, C = i.useSyncExternalStore !== void 0 ? i.useSyncExternalStore : D; H.useSyncExternalStore = C, 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" ? j.exports = ge() : j.exports = Oe(); var M = j.exports; const be = (...i) => (e) => { i.forEach((t) => { typeof t == "function" ? t(e) : t && (t.current = e); }); }, we = ({ contentComponent: i }) => { const e = M.useSyncExternalStore(i.subscribe, i.getSnapshot, i.getServerSnapshot); return y.createElement(y.Fragment, null, Object.values(e)); }; function Ce() { const i = /* @__PURE__ */ new Set(); let e = {}; return { /** * Subscribe to the editor instance's changes. */ subscribe(t) { return i.add(t), () => { i.delete(t); }; }, getSnapshot() { return e; }, getServerSnapshot() { return e; }, /** * Adds a new NodeView Renderer to the editor. */ setRenderer(t, n) { e = { ...e, [t]: Se.createPortal(n.reactElement, n.element, t) }, i.forEach((r) => r()); }, /** * Removes a NodeView Renderer from the editor. */ removeRenderer(t) { const n = { ...e }; delete n[t], e = n, i.forEach((r) => r()); } }; } class De extends y.Component { constructor(e) { var t; super(e), this.editorContentRef = y.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 = Ce(), this.state.hasContentComponentInitialized || (this.unsubscribeToContentComponent = e.contentComponent.subscribe(() => { this.setState((n) => n.hasContentComponentInitialized ? n : { 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, ...n } = this.props; return y.createElement( y.Fragment, null, y.createElement("div", { ref: be(t, this.editorContentRef), ...n }), (e == null ? void 0 : e.contentComponent) && y.createElement(we, { contentComponent: e.contentComponent }) ); } } const Re = me((i, e) => { const t = y.useMemo(() => Math.floor(Math.random() * 4294967295).toString(), [i.editor]); return y.createElement(De, { key: t, innerRef: e, ...i }); }), Je = y.memo(Re); var Te = function i(e, t) { if (e === t) return !0; if (e && t && typeof e == "object" && typeof t == "object") { if (e.constructor !== t.constructor) return !1; var n, r, o; if (Array.isArray(e)) { if (n = e.length, n != t.length) return !1; for (r = n; r-- !== 0; ) if (!i(e[r], t[r])) return !1; return !0; } if (e instanceof Map && t instanceof Map) { if (e.size !== t.size) return !1; for (r of e.entries()) if (!t.has(r[0])) return !1; for (r of e.entries()) if (!i(r[1], t.get(r[0]))) return !1; return !0; } if (e instanceof Set && t instanceof Set) { if (e.size !== t.size) return !1; for (r of e.entries()) if (!t.has(r[0])) return !1; return !0; } if (ArrayBuffer.isView(e) && ArrayBuffer.isView(t)) { if (n = e.length, n != t.length) return !1; for (r = n; r-- !== 0; ) if (e[r] !== t[r]) 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), n = o.length, n !== Object.keys(t).length) return !1; for (r = n; r-- !== 0; ) if (!Object.prototype.hasOwnProperty.call(t, o[r])) return !1; for (r = n; r-- !== 0; ) { var p = o[r]; if (!(p === "_owner" && e.$$typeof) && !i(e[p], t[p])) return !1; } return !0; } return e !== e && t !== t; }, Me = /* @__PURE__ */ _e(Te), 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 $; function Le() { if ($) return B; $ = 1; var i = y, e = M; function t(l, d) { return l === d && (l !== 0 || 1 / l === 1 / d) || l !== l && d !== d; } var n = typeof Object.is == "function" ? Object.is : t, r = e.useSyncExternalStore, o = i.useRef, p = i.useEffect, a = i.useMemo, f = i.useDebugValue; return B.useSyncExternalStoreWithSelector = function(l, d, s, h, m) { var E = o(null); if (E.current === null) { var S = { hasValue: !1, value: null }; E.current = S; } else S = E.current; E = a(function() { function D(u) { if (!C) { if (C = !0, v = u, u = h(u), m !== void 0 && S.hasValue) { var g = S.value; if (m(g, u)) return c = g; } return c = u; } if (g = c, n(v, u)) return g; var w = h(u); return m !== void 0 && m(g, w) ? g : (v = u, c = w); } var C = !1, v, c, O = s === void 0 ? null : s; return [function() { return D(d()); }, O === null ? void 0 : function() { return D(O()); }]; }, [d, s, h, m]); var _ = r(l, E[0], E[1]); return p(function() { S.hasValue = !0, S.value = _; }, [_]), f(_), _; }, B; } var P = {}; /** * @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 J; function Ae() { return J || (J = 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 i = y, e = M; function t(d, s) { return d === s && (d !== 0 || 1 / d === 1 / s) || d !== d && s !== s; } var n = typeof Object.is == "function" ? Object.is : t, r = e.useSyncExternalStore, o = i.useRef, p = i.useEffect, a = i.useMemo, f = i.useDebugValue; function l(d, s, h, m, E) { var S = o(null), _; S.current === null ? (_ = { hasValue: !1, value: null }, S.current = _) : _ = S.current; var D = a(function() { var O = !1, u, g, w = function(T) { if (!O) { O = !0, u = T; var A = m(T); if (E !== void 0 && _.hasValue) { var N = _.value; if (E(N, A)) return g = N, N; } return g = A, A; } var re = u, x = g; if (n(re, T)) return x; var V = m(T); return E !== void 0 && E(x, V) ? x : (u = T, g = V, V); }, b = h === void 0 ? null : h, R = function() { return w(s()); }, L = b === null ? void 0 : function() { return w(b()); }; return [R, L]; }, [s, h, m, E]), C = D[0], v = D[1], c = r(d, C, v); return p(function() { _.hasValue = !0, _.value = c; }, [c]), f(c), c; } P.useSyncExternalStoreWithSelector = l, typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ < "u" && typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop == "function" && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop(new Error()); }()), P; } process.env.NODE_ENV === "production" ? U.exports = Le() : U.exports = Ae(); var Ne = U.exports; const xe = typeof window < "u" ? ve : W; class Ve { 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((r) => r()); }, n = this.editor; return n.on("transaction", t), () => { n.off("transaction", t); }; } } } function Ie(i) { var e; const [t] = K(() => new Ve(i.editor)), n = Ne.useSyncExternalStoreWithSelector(t.subscribe, t.getSnapshot, t.getServerSnapshot, i.selector, (e = i.equalityFn) !== null && e !== void 0 ? e : Me); return xe(() => t.watch(i.editor), [i.editor, t]), Q(n), n; } const Y = process.env.NODE_ENV !== "production", F = typeof window > "u", He = F || !!(typeof window < "u" && window.next); class q { 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 F || He ? (Y && 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 && F && Y) 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: (...n) => { var r, o; return (o = (r = this.options.current).onBeforeCreate) === null || o === void 0 ? void 0 : o.call(r, ...n); }, onBlur: (...n) => { var r, o; return (o = (r = this.options.current).onBlur) === null || o === void 0 ? void 0 : o.call(r, ...n); }, onCreate: (...n) => { var r, o; return (o = (r = this.options.current).onCreate) === null || o === void 0 ? void 0 : o.call(r, ...n); }, onDestroy: (...n) => { var r, o; return (o = (r = this.options.current).onDestroy) === null || o === void 0 ? void 0 : o.call(r, ...n); }, onFocus: (...n) => { var r, o; return (o = (r = this.options.current).onFocus) === null || o === void 0 ? void 0 : o.call(r, ...n); }, onSelectionUpdate: (...n) => { var r, o; return (o = (r = this.options.current).onSelectionUpdate) === null || o === void 0 ? void 0 : o.call(r, ...n); }, onTransaction: (...n) => { var r, o; return (o = (r = this.options.current).onTransaction) === null || o === void 0 ? void 0 : o.call(r, ...n); }, onUpdate: (...n) => { var r, o; return (o = (r = this.options.current).onUpdate) === null || o === void 0 ? void 0 : o.call(r, ...n); }, onContentError: (...n) => { var r, o; return (o = (r = this.options.current).onContentError) === null || o === void 0 ? void 0 : o.call(r, ...n); }, onDrop: (...n) => { var r, o; return (o = (r = this.options.current).onDrop) === null || o === void 0 ? void 0 : o.call(r, ...n); }, onPaste: (...n) => { var r, o; return (o = (r = this.options.current).onPaste) === null || o === void 0 ? void 0 : o.call(r, ...n); } }; return new le(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((n) => ["onCreate", "onBeforeCreate", "onDestroy", "onUpdate", "onTransaction", "onFocus", "onBlur", "onSelectionUpdate", "onContentError", "onDrop", "onPaste"].includes(n) ? !0 : n === "extensions" && e.extensions && t.extensions ? e.extensions.length !== t.extensions.length ? !1 : e.extensions.every((r, o) => { var p; return r === ((p = t.extensions) === null || p === void 0 ? void 0 : p[o]); }) : e[n] === t[n]); } /** * 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 ? q.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((n, r) => n === e[r])) 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 Ye(i = {}, e = []) { const t = pe(i); t.current = i; const [n] = K(() => new q(t)), r = M.useSyncExternalStore(n.subscribe, n.getEditor, n.getServerSnapshot); return Q(r), W(n.onRender(e)), Ie({ editor: r, selector: ({ transactionNumber: o }) => i.shouldRerenderOnTransaction === !1 ? null : i.immediatelyRender && o === 0 ? 0 : o + 1 }), r; } const ee = Z({ editor: null }); ee.Consumer; const Be = () => X(ee), Qe = (i) => { const [e, t] = K(null), { editor: n } = Be(); return W(() => { var r; if (!e || !((r = i.editor) === null || r === void 0) && r.isDestroyed || n != null && n.isDestroyed) return; const { pluginKey: o = "bubbleMenu", editor: p, tippyOptions: a = {}, updateDelay: f, shouldShow: l = null } = i, d = p || n; if (!d) { console.warn("BubbleMenu component is not rendered inside of an editor component or does not have editor prop."); return; } const s = k({ updateDelay: f, editor: d, element: e, pluginKey: o, shouldShow: l, tippyOptions: a }); return d.registerPlugin(s), () => { d.unregisterPlugin(o); }; }, [i.editor, n, e]), y.createElement("div", { ref: t, className: i.className, style: { visibility: "hidden" } }, i.children); }, te = Z({ onDragStart: void 0 }), Pe = () => X(te), Xe = y.forwardRef((i, e) => { const { onDragStart: t } = Pe(), n = i.as || "div"; return ( // @ts-ignore y.createElement(n, { ...i, ref: e, "data-node-view-wrapper": "", onDragStart: t, style: { whiteSpace: "normal", ...i.style } }) ); }); function je(i) { return !!(typeof i == "function" && i.prototype && i.prototype.isReactComponent); } function Ue(i) { var e; return typeof i == "object" && ((e = i.$$typeof) === null || e === void 0 ? void 0 : e.toString()) === "Symbol(react.forward_ref)"; } class Fe { /** * Immediately creates element and renders the provided React component. */ constructor(e, { editor: t, props: n = {}, as: r = "div", className: o = "" }) { this.ref = null, this.id = Math.floor(Math.random() * 4294967295).toString(), this.component = e, this.editor = t, this.props = n, this.element = document.createElement(r), this.element.classList.add("react-renderer"), o && this.element.classList.add(...o.split(" ")), this.editor.isInitialized ? Ee(() => { this.render(); }) : this.render(); } /** * Render the React component. */ render() { var e; const t = this.component, n = this.props, r = this.editor; (je(t) || Ue(t)) && (n.ref = (o) => { this.ref = o; }), this.reactElement = y.createElement(t, { ...n }), (e = r == null ? void 0 : r.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 Ke extends ce { /** * 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() }; if (!this.component.displayName) { const l = (d) => d.charAt(0).toUpperCase() + d.substring(1); this.component.displayName = l(this.extension.name); } const r = { onDragStart: this.onDragStart.bind(this), nodeViewContentRef: (l) => { l && this.contentDOMElement && l.firstChild !== this.contentDOMElement && l.appendChild(this.contentDOMElement); } }, o = this.component, p = y.memo((l) => y.createElement(te.Provider, { value: r }, y.createElement(o, l))); p.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 a = this.node.isInline ? "span" : "div"; this.options.as && (a = this.options.as); const { className: f = "" } = this.options; this.handleSelectionUpdate = this.handleSelectionUpdate.bind(this), this.renderer = new Fe(p, { editor: this.editor, props: e, as: a, 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, n = this.getPos(); if (typeof n == "number") if (e <= n && t >= n + 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, n) { const r = (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, p = this.decorations, a = this.innerDecorations; return this.node = e, this.decorations = t, this.innerDecorations = n, this.options.update({ oldNode: o, oldDecorations: p, newNode: e, newDecorations: t, oldInnerDecorations: a, innerDecorations: n, updateProps: () => r({ node: e, decorations: t, innerDecorations: n }) }); } return e === this.node && this.decorations === t && this.innerDecorations === n || (this.node = e, this.decorations = t, this.innerDecorations = n, r({ node: e, decorations: t, innerDecorations: n })), !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, n = he(this.node, t); e = this.options.attrs({ node: this.node, HTMLAttributes: n }); } else e = this.options.attrs; this.renderer.updateAttributes(e); } } } function Ze(i, e) { return (t) => t.editor.contentComponent ? new Ke(i, t, e) : {}; } function ne(i) { var e, t, n = ""; if (typeof i == "string" || typeof i == "number") n += i; else if (typeof i == "object") if (Array.isArray(i)) { var r = i.length; for (e = 0; e < r; e++) i[e] && (t = ne(i[e])) && (n && (n += " "), n += t); } else for (t in i) i[t] && (n && (n += " "), n += t); return n; } function ke() { for (var i, e, t = 0, n = "", r = arguments.length; t < r; t++) (i = arguments[t]) && (e = ne(i)) && (n && (n += " "), n += e); return n; } function We(i) { try { return JSON.stringify(i); } catch { return JSON.stringify({}); } } function et(i, e = !1) { return (t) => { const n = i.startsWith("data-") ? i : `data-${i}`; let r = decodeURIComponent(t.getAttribute(n)); if (r == null || typeof r == "string" && r === "null") try { const a = t.outerHTML.match(/([\S\s])+?="([\S\s])+?"/g); a && a.length > 0 && (r = (a.map((l) => l.trim()).reduce((l, d) => { const s = d.indexOf("="), h = [d.slice(0, s), d.slice(s + 1).slice(1, -1)]; return l[h[0]] = h[1], l; }, {})[i.toLowerCase()] || "").replaceAll("&quot;", '"')); } catch (p) { console.error("Error getDatasetAttribute ", p.message, t); } if (e) try { return JSON.parse(r); } catch { return {}; } if (r.includes("%") || r.includes("auto")) return r; const o = Number.parseInt(r); return o !== o ? r : o; }; } function tt(i) { const { attrs: e } = i; return Object.keys(e).reduce((t, n) => { const r = e[n]; if (r == null) return t; let o = ""; return typeof r == "object" ? o = We(r) : o = r, t[n] = o, t; }, /* @__PURE__ */ Object.create(null)); } export { Qe as B, Je as E, Xe as N, Ze as R, Fe as a, ke as c, et as g, tt as n, Ye as u };