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
JavaScript
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(""", '"'));
} 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
};