tiptap-editor-react
Version:
A modern WYSIWYG rich text editor based on tiptap and shadcn ui for React
1,511 lines (1,510 loc) • 206 kB
JavaScript
var dn = Object.defineProperty;
var un = (e, t, n) => t in e ? dn(e, t, { enumerable: !0, configurable: !0, writable: !0, value: n }) : e[t] = n;
var it = (e, t, n) => un(e, typeof t != "symbol" ? t + "" : t, n);
import _e from "tippy.js";
import { E as pn, a as hn, P as $, b as _, S as W, k as fn, T as I, D as mn, c as He, F as K, N as gn, d as Lt, w as yn, e as vn, f as bn, g as ht, h as et, s as Mn, i as ie, j as Sn, l as wn, m as kn, n as En, o as Tn, A as Cn, p as xn, q as An, r as On, t as Ln, u as Pn, v as Rn, x as $n, y as De, z as _n, B as Hn, C as Dn, G as In, H as Nn, I as Bn, J as jn, K as Ut, R as Fn, L as zn, M as Vn, O as Wn, Q as ae, U as Kn, V as Ie, W as Un, X as qn, Y as Gn, Z as Jn, _ as Yn, $ as mt, a0 as qt, a1 as Xn, a2 as Qn, a3 as Zn, a4 as Ne, a5 as tr, a6 as le, a7 as er, a8 as ce, a9 as de, aa as nr, ab as ue, ac as rr, ad as sr, ae as or, af as ir, ag as ar, ah as lr, ai as cr, aj as dr, ak as ur, al as pr, am as hr } from "./vendor-DIvoV5tx.js";
import L, { useRef as fr, useState as Gt, useDebugValue as Be, useEffect as Jt, forwardRef as mr, useLayoutEffect as gr, useContext as je, createContext as Fe } from "react";
import yr, { flushSync as vr } from "react-dom";
function bt(e) {
const { state: t, transaction: n } = e;
let { selection: r } = n, { doc: s } = n, { storedMarks: o } = n;
return {
...t,
apply: t.apply.bind(t),
applyTransaction: t.applyTransaction.bind(t),
plugins: t.plugins,
schema: t.schema,
reconfigure: t.reconfigure.bind(t),
toJSON: t.toJSON.bind(t),
get storedMarks() {
return o;
},
get selection() {
return r;
},
get doc() {
return s;
},
get tr() {
return r = n.selection, s = n.doc, o = n.storedMarks, n;
}
};
}
class Mt {
constructor(t) {
this.editor = t.editor, this.rawCommands = this.editor.extensionManager.commands, this.customState = t.state;
}
get hasCustomState() {
return !!this.customState;
}
get state() {
return this.customState || this.editor.state;
}
get commands() {
const { rawCommands: t, editor: n, state: r } = this, { view: s } = n, { tr: o } = r, i = this.buildProps(o);
return Object.fromEntries(Object.entries(t).map(([a, c]) => [a, (...u) => {
const d = c(...u)(i);
return !o.getMeta("preventDispatch") && !this.hasCustomState && s.dispatch(o), d;
}]));
}
get chain() {
return () => this.createChain();
}
get can() {
return () => this.createCan();
}
createChain(t, n = !0) {
const { rawCommands: r, editor: s, state: o } = this, { view: i } = s, a = [], c = !!t, l = t || o.tr, u = () => (!c && n && !l.getMeta("preventDispatch") && !this.hasCustomState && i.dispatch(l), a.every((p) => p === !0)), d = {
...Object.fromEntries(Object.entries(r).map(([p, h]) => [p, (...f) => {
const g = this.buildProps(l, n), y = h(...f)(g);
return a.push(y), d;
}])),
run: u
};
return d;
}
createCan(t) {
const { rawCommands: n, state: r } = this, s = !1, o = t || r.tr, i = this.buildProps(o, s);
return {
...Object.fromEntries(Object.entries(n).map(([c, l]) => [c, (...u) => l(...u)({ ...i, dispatch: void 0 })])),
chain: () => this.createChain(o, s)
};
}
buildProps(t, n = !0) {
const { rawCommands: r, editor: s, state: o } = this, { view: i } = s, a = {
tr: t,
editor: s,
view: i,
state: bt({
state: o,
transaction: t
}),
dispatch: n ? () => {
} : void 0,
chain: () => this.createChain(t, n),
can: () => this.createCan(t),
get commands() {
return Object.fromEntries(Object.entries(r).map(([c, l]) => [c, (...u) => l(...u)(a)]));
}
};
return a;
}
}
class br {
constructor() {
this.callbacks = {};
}
on(t, n) {
return this.callbacks[t] || (this.callbacks[t] = []), this.callbacks[t].push(n), this;
}
emit(t, ...n) {
const r = this.callbacks[t];
return r && r.forEach((s) => s.apply(this, n)), this;
}
off(t, n) {
const r = this.callbacks[t];
return r && (n ? this.callbacks[t] = r.filter((s) => s !== n) : delete this.callbacks[t]), this;
}
once(t, n) {
const r = (...s) => {
this.off(t, r), n.apply(this, s);
};
return this.on(t, r);
}
removeAllListeners() {
this.callbacks = {};
}
}
function w(e, t, n) {
return e.config[t] === void 0 && e.parent ? w(e.parent, t, n) : typeof e.config[t] == "function" ? e.config[t].bind({
...n,
parent: e.parent ? w(e.parent, t, n) : null
}) : e.config[t];
}
function St(e) {
const t = e.filter((s) => s.type === "extension"), n = e.filter((s) => s.type === "node"), r = e.filter((s) => s.type === "mark");
return {
baseExtensions: t,
nodeExtensions: n,
markExtensions: r
};
}
function ze(e) {
const t = [], { nodeExtensions: n, markExtensions: r } = St(e), s = [...n, ...r], o = {
default: null,
rendered: !0,
renderHTML: null,
parseHTML: null,
keepOnSplit: !0,
isRequired: !1
};
return e.forEach((i) => {
const a = {
name: i.name,
options: i.options,
storage: i.storage,
extensions: s
}, c = w(i, "addGlobalAttributes", a);
if (!c)
return;
c().forEach((u) => {
u.types.forEach((d) => {
Object.entries(u.attributes).forEach(([p, h]) => {
t.push({
type: d,
name: p,
attribute: {
...o,
...h
}
});
});
});
});
}), s.forEach((i) => {
const a = {
name: i.name,
options: i.options,
storage: i.storage
}, c = w(i, "addAttributes", a);
if (!c)
return;
const l = c();
Object.entries(l).forEach(([u, d]) => {
const p = {
...o,
...d
};
typeof (p == null ? void 0 : p.default) == "function" && (p.default = p.default()), p != null && p.isRequired && (p == null ? void 0 : p.default) === void 0 && delete p.default, t.push({
type: i.name,
name: u,
attribute: p
});
});
}), t;
}
function H(e, t) {
if (typeof e == "string") {
if (!t.nodes[e])
throw Error(`There is no node type named '${e}'. Maybe you forgot to add the extension?`);
return t.nodes[e];
}
return e;
}
function x(...e) {
return e.filter((t) => !!t).reduce((t, n) => {
const r = { ...t };
return Object.entries(n).forEach(([s, o]) => {
if (!r[s]) {
r[s] = o;
return;
}
if (s === "class") {
const a = o ? String(o).split(" ") : [], c = r[s] ? r[s].split(" ") : [], l = a.filter((u) => !c.includes(u));
r[s] = [...c, ...l].join(" ");
} else if (s === "style") {
const a = o ? o.split(";").map((u) => u.trim()).filter(Boolean) : [], c = r[s] ? r[s].split(";").map((u) => u.trim()).filter(Boolean) : [], l = /* @__PURE__ */ new Map();
c.forEach((u) => {
const [d, p] = u.split(":").map((h) => h.trim());
l.set(d, p);
}), a.forEach((u) => {
const [d, p] = u.split(":").map((h) => h.trim());
l.set(d, p);
}), r[s] = Array.from(l.entries()).map(([u, d]) => `${u}: ${d}`).join("; ");
} else
r[s] = o;
}), r;
}, {});
}
function gt(e, t) {
return t.filter((n) => n.type === e.type.name).filter((n) => n.attribute.rendered).map((n) => n.attribute.renderHTML ? n.attribute.renderHTML(e.attrs) || {} : {
[n.name]: e.attrs[n.name]
}).reduce((n, r) => x(n, r), {});
}
function Ve(e) {
return typeof e == "function";
}
function E(e, t = void 0, ...n) {
return Ve(e) ? t ? e.bind(t)(...n) : e(...n) : e;
}
function Mr(e = {}) {
return Object.keys(e).length === 0 && e.constructor === Object;
}
function Sr(e) {
return typeof e != "string" ? e : e.match(/^[+-]?(?:\d*\.)?\d+$/) ? Number(e) : e === "true" ? !0 : e === "false" ? !1 : e;
}
function pe(e, t) {
return "style" in e ? e : {
...e,
getAttrs: (n) => {
const r = e.getAttrs ? e.getAttrs(n) : e.attrs;
if (r === !1)
return !1;
const s = t.reduce((o, i) => {
const a = i.attribute.parseHTML ? i.attribute.parseHTML(n) : Sr(n.getAttribute(i.name));
return a == null ? o : {
...o,
[i.name]: a
};
}, {});
return { ...r, ...s };
}
};
}
function he(e) {
return Object.fromEntries(
// @ts-ignore
Object.entries(e).filter(([t, n]) => t === "attrs" && Mr(n) ? !1 : n != null)
);
}
function wr(e, t) {
var n;
const r = ze(e), { nodeExtensions: s, markExtensions: o } = St(e), i = (n = s.find((l) => w(l, "topNode"))) === null || n === void 0 ? void 0 : n.name, a = Object.fromEntries(s.map((l) => {
const u = r.filter((y) => y.type === l.name), d = {
name: l.name,
options: l.options,
storage: l.storage,
editor: t
}, p = e.reduce((y, M) => {
const b = w(M, "extendNodeSchema", d);
return {
...y,
...b ? b(l) : {}
};
}, {}), h = he({
...p,
content: E(w(l, "content", d)),
marks: E(w(l, "marks", d)),
group: E(w(l, "group", d)),
inline: E(w(l, "inline", d)),
atom: E(w(l, "atom", d)),
selectable: E(w(l, "selectable", d)),
draggable: E(w(l, "draggable", d)),
code: E(w(l, "code", d)),
whitespace: E(w(l, "whitespace", d)),
linebreakReplacement: E(w(l, "linebreakReplacement", d)),
defining: E(w(l, "defining", d)),
isolating: E(w(l, "isolating", d)),
attrs: Object.fromEntries(u.map((y) => {
var M;
return [y.name, { default: (M = y == null ? void 0 : y.attribute) === null || M === void 0 ? void 0 : M.default }];
}))
}), m = E(w(l, "parseHTML", d));
m && (h.parseDOM = m.map((y) => pe(y, u)));
const f = w(l, "renderHTML", d);
f && (h.toDOM = (y) => f({
node: y,
HTMLAttributes: gt(y, u)
}));
const g = w(l, "renderText", d);
return g && (h.toText = g), [l.name, h];
})), c = Object.fromEntries(o.map((l) => {
const u = r.filter((g) => g.type === l.name), d = {
name: l.name,
options: l.options,
storage: l.storage,
editor: t
}, p = e.reduce((g, y) => {
const M = w(y, "extendMarkSchema", d);
return {
...g,
...M ? M(l) : {}
};
}, {}), h = he({
...p,
inclusive: E(w(l, "inclusive", d)),
excludes: E(w(l, "excludes", d)),
group: E(w(l, "group", d)),
spanning: E(w(l, "spanning", d)),
code: E(w(l, "code", d)),
attrs: Object.fromEntries(u.map((g) => {
var y;
return [g.name, { default: (y = g == null ? void 0 : g.attribute) === null || y === void 0 ? void 0 : y.default }];
}))
}), m = E(w(l, "parseHTML", d));
m && (h.parseDOM = m.map((g) => pe(g, u)));
const f = w(l, "renderHTML", d);
return f && (h.toDOM = (g) => f({
mark: g,
HTMLAttributes: gt(g, u)
})), [l.name, h];
}));
return new He({
topNode: i,
nodes: a,
marks: c
});
}
function Pt(e, t) {
return t.nodes[e] || t.marks[e] || null;
}
function fe(e, t) {
return Array.isArray(t) ? t.some((n) => (typeof n == "string" ? n : n.name) === e.name) : t;
}
function Yt(e, t) {
const n = mn.fromSchema(t).serializeFragment(e), s = document.implementation.createHTMLDocument().createElement("div");
return s.appendChild(n), s.innerHTML;
}
const kr = (e, t = 500) => {
let n = "";
const r = e.parentOffset;
return e.parent.nodesBetween(Math.max(0, r - t), r, (s, o, i, a) => {
var c, l;
const u = ((l = (c = s.type.spec).toText) === null || l === void 0 ? void 0 : l.call(c, {
node: s,
pos: o,
parent: i,
index: a
})) || s.textContent || "%leaf%";
n += s.isAtom && !s.isText ? u : u.slice(0, Math.max(0, r - o));
}), n;
};
function Xt(e) {
return Object.prototype.toString.call(e) === "[object RegExp]";
}
class wt {
constructor(t) {
this.find = t.find, this.handler = t.handler;
}
}
const Er = (e, t) => {
if (Xt(t))
return t.exec(e);
const n = t(e);
if (!n)
return null;
const r = [n.text];
return r.index = n.index, r.input = e, r.data = n.data, n.replaceWith && (n.text.includes(n.replaceWith) || console.warn('[tiptap warn]: "inputRuleMatch.replaceWith" must be part of "inputRuleMatch.text".'), r.push(n.replaceWith)), r;
};
function at(e) {
var t;
const { editor: n, from: r, to: s, text: o, rules: i, plugin: a } = e, { view: c } = n;
if (c.composing)
return !1;
const l = c.state.doc.resolve(r);
if (
// check for code node
l.parent.type.spec.code || !((t = l.nodeBefore || l.nodeAfter) === null || t === void 0) && t.marks.find((p) => p.type.spec.code)
)
return !1;
let u = !1;
const d = kr(l) + o;
return i.forEach((p) => {
if (u)
return;
const h = Er(d, p.find);
if (!h)
return;
const m = c.state.tr, f = bt({
state: c.state,
transaction: m
}), g = {
from: r - (h[0].length - o.length),
to: s
}, { commands: y, chain: M, can: b } = new Mt({
editor: n,
state: f
});
p.handler({
state: f,
range: g,
match: h,
commands: y,
chain: M,
can: b
}) === null || !m.steps.length || (m.setMeta(a, {
transform: m,
from: r,
to: s,
text: o
}), c.dispatch(m), u = !0);
}), u;
}
function Tr(e) {
const { editor: t, rules: n } = e, r = new $({
state: {
init() {
return null;
},
apply(s, o, i) {
const a = s.getMeta(r);
if (a)
return a;
const c = s.getMeta("applyInputRules");
return !!c && setTimeout(() => {
let { text: u } = c;
typeof u == "string" ? u = u : u = Yt(K.from(u), i.schema);
const { from: d } = c, p = d + u.length;
at({
editor: t,
from: d,
to: p,
text: u,
rules: n,
plugin: r
});
}), s.selectionSet || s.docChanged ? null : o;
}
},
props: {
handleTextInput(s, o, i, a) {
return at({
editor: t,
from: o,
to: i,
text: a,
rules: n,
plugin: r
});
},
handleDOMEvents: {
compositionend: (s) => (setTimeout(() => {
const { $cursor: o } = s.state.selection;
o && at({
editor: t,
from: o.pos,
to: o.pos,
text: "",
rules: n,
plugin: r
});
}), !1)
},
// add support for input rules to trigger on enter
// this is useful for example for code blocks
handleKeyDown(s, o) {
if (o.key !== "Enter")
return !1;
const { $cursor: i } = s.state.selection;
return i ? at({
editor: t,
from: i.pos,
to: i.pos,
text: `
`,
rules: n,
plugin: r
}) : !1;
}
},
// @ts-ignore
isInputRules: !0
});
return r;
}
function Cr(e) {
return Object.prototype.toString.call(e).slice(8, -1);
}
function lt(e) {
return Cr(e) !== "Object" ? !1 : e.constructor === Object && Object.getPrototypeOf(e) === Object.prototype;
}
function kt(e, t) {
const n = { ...e };
return lt(e) && lt(t) && Object.keys(t).forEach((r) => {
lt(t[r]) && lt(e[r]) ? n[r] = kt(e[r], t[r]) : n[r] = t[r];
}), n;
}
class N {
constructor(t = {}) {
this.type = "mark", this.name = "mark", this.parent = null, this.child = null, this.config = {
name: this.name,
defaultOptions: {}
}, this.config = {
...this.config,
...t
}, this.name = this.config.name, t.defaultOptions && Object.keys(t.defaultOptions).length > 0 && console.warn(`[tiptap warn]: BREAKING CHANGE: "defaultOptions" is deprecated. Please use "addOptions" instead. Found in extension: "${this.name}".`), this.options = this.config.defaultOptions, this.config.addOptions && (this.options = E(w(this, "addOptions", {
name: this.name
}))), this.storage = E(w(this, "addStorage", {
name: this.name,
options: this.options
})) || {};
}
static create(t = {}) {
return new N(t);
}
configure(t = {}) {
const n = this.extend({
...this.config,
addOptions: () => kt(this.options, t)
});
return n.name = this.name, n.parent = this.parent, n;
}
extend(t = {}) {
const n = new N(t);
return n.parent = this, this.child = n, n.name = t.name ? t.name : n.parent.name, t.defaultOptions && Object.keys(t.defaultOptions).length > 0 && console.warn(`[tiptap warn]: BREAKING CHANGE: "defaultOptions" is deprecated. Please use "addOptions" instead. Found in extension: "${n.name}".`), n.options = E(w(n, "addOptions", {
name: n.name
})), n.storage = E(w(n, "addStorage", {
name: n.name,
options: n.options
})), n;
}
static handleExit({ editor: t, mark: n }) {
const { tr: r } = t.state, s = t.state.selection.$from;
if (s.pos === s.end()) {
const i = s.marks();
if (!!!i.find((l) => (l == null ? void 0 : l.type.name) === n.name))
return !1;
const c = i.find((l) => (l == null ? void 0 : l.type.name) === n.name);
return c && r.removeStoredMark(c), r.insertText(" ", s.pos), t.view.dispatch(r), !0;
}
return !1;
}
}
function xr(e) {
return typeof e == "number";
}
class We {
constructor(t) {
this.find = t.find, this.handler = t.handler;
}
}
const Ar = (e, t, n) => {
if (Xt(t))
return [...e.matchAll(t)];
const r = t(e, n);
return r ? r.map((s) => {
const o = [s.text];
return o.index = s.index, o.input = e, o.data = s.data, s.replaceWith && (s.text.includes(s.replaceWith) || console.warn('[tiptap warn]: "pasteRuleMatch.replaceWith" must be part of "pasteRuleMatch.text".'), o.push(s.replaceWith)), o;
}) : [];
};
function Or(e) {
const { editor: t, state: n, from: r, to: s, rule: o, pasteEvent: i, dropEvent: a } = e, { commands: c, chain: l, can: u } = new Mt({
editor: t,
state: n
}), d = [];
return n.doc.nodesBetween(r, s, (h, m) => {
if (!h.isTextblock || h.type.spec.code)
return;
const f = Math.max(r, m), g = Math.min(s, m + h.content.size), y = h.textBetween(f - m, g - m, void 0, "");
Ar(y, o.find, i).forEach((b) => {
if (b.index === void 0)
return;
const v = f + b.index + 1, k = v + b[0].length, S = {
from: n.tr.mapping.map(v),
to: n.tr.mapping.map(k)
}, T = o.handler({
state: n,
range: S,
match: b,
commands: c,
chain: l,
can: u,
pasteEvent: i,
dropEvent: a
});
d.push(T);
});
}), d.every((h) => h !== null);
}
let ct = null;
const Lr = (e) => {
var t;
const n = new ClipboardEvent("paste", {
clipboardData: new DataTransfer()
});
return (t = n.clipboardData) === null || t === void 0 || t.setData("text/html", e), n;
};
function Pr(e) {
const { editor: t, rules: n } = e;
let r = null, s = !1, o = !1, i = typeof ClipboardEvent < "u" ? new ClipboardEvent("paste") : null, a;
try {
a = typeof DragEvent < "u" ? new DragEvent("drop") : null;
} catch {
a = null;
}
const c = ({ state: u, from: d, to: p, rule: h, pasteEvt: m }) => {
const f = u.tr, g = bt({
state: u,
transaction: f
});
if (!(!Or({
editor: t,
state: g,
from: Math.max(d - 1, 0),
to: p.b - 1,
rule: h,
pasteEvent: m,
dropEvent: a
}) || !f.steps.length)) {
try {
a = typeof DragEvent < "u" ? new DragEvent("drop") : null;
} catch {
a = null;
}
return i = typeof ClipboardEvent < "u" ? new ClipboardEvent("paste") : null, f;
}
};
return n.map((u) => new $({
// we register a global drag handler to track the current drag source element
view(d) {
const p = (m) => {
var f;
r = !((f = d.dom.parentElement) === null || f === void 0) && f.contains(m.target) ? d.dom.parentElement : null, r && (ct = t);
}, h = () => {
ct && (ct = null);
};
return window.addEventListener("dragstart", p), window.addEventListener("dragend", h), {
destroy() {
window.removeEventListener("dragstart", p), window.removeEventListener("dragend", h);
}
};
},
props: {
handleDOMEvents: {
drop: (d, p) => {
if (o = r === d.dom.parentElement, a = p, !o) {
const h = ct;
h && setTimeout(() => {
const m = h.state.selection;
m && h.commands.deleteRange({ from: m.from, to: m.to });
}, 10);
}
return !1;
},
paste: (d, p) => {
var h;
const m = (h = p.clipboardData) === null || h === void 0 ? void 0 : h.getData("text/html");
return i = p, s = !!(m != null && m.includes("data-pm-slice")), !1;
}
}
},
appendTransaction: (d, p, h) => {
const m = d[0], f = m.getMeta("uiEvent") === "paste" && !s, g = m.getMeta("uiEvent") === "drop" && !o, y = m.getMeta("applyPasteRules"), M = !!y;
if (!f && !g && !M)
return;
if (M) {
let { text: k } = y;
typeof k == "string" ? k = k : k = Yt(K.from(k), h.schema);
const { from: S } = y, T = S + k.length, A = Lr(k);
return c({
rule: u,
state: h,
from: S,
to: { b: T },
pasteEvt: A
});
}
const b = p.doc.content.findDiffStart(h.doc.content), v = p.doc.content.findDiffEnd(h.doc.content);
if (!(!xr(b) || !v || b === v.b))
return c({
rule: u,
state: h,
from: b,
to: v,
pasteEvt: i
});
}
}));
}
function Rr(e) {
const t = e.filter((n, r) => e.indexOf(n) !== r);
return Array.from(new Set(t));
}
class tt {
constructor(t, n) {
this.splittableMarks = [], this.editor = n, this.extensions = tt.resolve(t), this.schema = wr(this.extensions, n), this.setupExtensions();
}
/**
* Returns a flattened and sorted extension list while
* also checking for duplicated extensions and warns the user.
* @param extensions An array of Tiptap extensions
* @returns An flattened and sorted array of Tiptap extensions
*/
static resolve(t) {
const n = tt.sort(tt.flatten(t)), r = Rr(n.map((s) => s.name));
return r.length && console.warn(`[tiptap warn]: Duplicate extension names found: [${r.map((s) => `'${s}'`).join(", ")}]. This can lead to issues.`), n;
}
/**
* Create a flattened array of extensions by traversing the `addExtensions` field.
* @param extensions An array of Tiptap extensions
* @returns A flattened array of Tiptap extensions
*/
static flatten(t) {
return t.map((n) => {
const r = {
name: n.name,
options: n.options,
storage: n.storage
}, s = w(n, "addExtensions", r);
return s ? [n, ...this.flatten(s())] : n;
}).flat(10);
}
/**
* Sort extensions by priority.
* @param extensions An array of Tiptap extensions
* @returns A sorted array of Tiptap extensions by priority
*/
static sort(t) {
return t.sort((r, s) => {
const o = w(r, "priority") || 100, i = w(s, "priority") || 100;
return o > i ? -1 : o < i ? 1 : 0;
});
}
/**
* Get all commands from the extensions.
* @returns An object with all commands where the key is the command name and the value is the command function
*/
get commands() {
return this.extensions.reduce((t, n) => {
const r = {
name: n.name,
options: n.options,
storage: n.storage,
editor: this.editor,
type: Pt(n.name, this.schema)
}, s = w(n, "addCommands", r);
return s ? {
...t,
...s()
} : t;
}, {});
}
/**
* Get all registered Prosemirror plugins from the extensions.
* @returns An array of Prosemirror plugins
*/
get plugins() {
const { editor: t } = this, n = tt.sort([...this.extensions].reverse()), r = [], s = [], o = n.map((i) => {
const a = {
name: i.name,
options: i.options,
storage: i.storage,
editor: t,
type: Pt(i.name, this.schema)
}, c = [], l = w(i, "addKeyboardShortcuts", a);
let u = {};
if (i.type === "mark" && w(i, "exitable", a) && (u.ArrowRight = () => N.handleExit({ editor: t, mark: i })), l) {
const f = Object.fromEntries(Object.entries(l()).map(([g, y]) => [g, () => y({ editor: t })]));
u = { ...u, ...f };
}
const d = fn(u);
c.push(d);
const p = w(i, "addInputRules", a);
fe(i, t.options.enableInputRules) && p && r.push(...p());
const h = w(i, "addPasteRules", a);
fe(i, t.options.enablePasteRules) && h && s.push(...h());
const m = w(i, "addProseMirrorPlugins", a);
if (m) {
const f = m();
c.push(...f);
}
return c;
}).flat();
return [
Tr({
editor: t,
rules: r
}),
...Pr({
editor: t,
rules: s
}),
...o
];
}
/**
* Get all attributes from the extensions.
* @returns An array of attributes
*/
get attributes() {
return ze(this.extensions);
}
/**
* Get all node views from the extensions.
* @returns An object with all node views where the key is the node name and the value is the node view function
*/
get nodeViews() {
const { editor: t } = this, { nodeExtensions: n } = St(this.extensions);
return Object.fromEntries(n.filter((r) => !!w(r, "addNodeView")).map((r) => {
const s = this.attributes.filter((c) => c.type === r.name), o = {
name: r.name,
options: r.options,
storage: r.storage,
editor: t,
type: H(r.name, this.schema)
}, i = w(r, "addNodeView", o);
if (!i)
return [];
const a = (c, l, u, d, p) => {
const h = gt(c, s);
return i()({
// pass-through
node: c,
view: l,
getPos: u,
decorations: d,
innerDecorations: p,
// tiptap-specific
editor: t,
extension: r,
HTMLAttributes: h
});
};
return [r.name, a];
}));
}
/**
* Go through all extensions, create extension storages & setup marks
* & bind editor event listener.
*/
setupExtensions() {
this.extensions.forEach((t) => {
var n;
this.editor.extensionStorage[t.name] = t.storage;
const r = {
name: t.name,
options: t.options,
storage: t.storage,
editor: this.editor,
type: Pt(t.name, this.schema)
};
t.type === "mark" && (!((n = E(w(t, "keepOnSplit", r))) !== null && n !== void 0) || n) && this.splittableMarks.push(t.name);
const s = w(t, "onBeforeCreate", r), o = w(t, "onCreate", r), i = w(t, "onUpdate", r), a = w(t, "onSelectionUpdate", r), c = w(t, "onTransaction", r), l = w(t, "onFocus", r), u = w(t, "onBlur", r), d = w(t, "onDestroy", r);
s && this.editor.on("beforeCreate", s), o && this.editor.on("create", o), i && this.editor.on("update", i), a && this.editor.on("selectionUpdate", a), c && this.editor.on("transaction", c), l && this.editor.on("focus", l), u && this.editor.on("blur", u), d && this.editor.on("destroy", d);
});
}
}
class R {
constructor(t = {}) {
this.type = "extension", this.name = "extension", this.parent = null, this.child = null, this.config = {
name: this.name,
defaultOptions: {}
}, this.config = {
...this.config,
...t
}, this.name = this.config.name, t.defaultOptions && Object.keys(t.defaultOptions).length > 0 && console.warn(`[tiptap warn]: BREAKING CHANGE: "defaultOptions" is deprecated. Please use "addOptions" instead. Found in extension: "${this.name}".`), this.options = this.config.defaultOptions, this.config.addOptions && (this.options = E(w(this, "addOptions", {
name: this.name
}))), this.storage = E(w(this, "addStorage", {
name: this.name,
options: this.options
})) || {};
}
static create(t = {}) {
return new R(t);
}
configure(t = {}) {
const n = this.extend({
...this.config,
addOptions: () => kt(this.options, t)
});
return n.name = this.name, n.parent = this.parent, n;
}
extend(t = {}) {
const n = new R({ ...this.config, ...t });
return n.parent = this, this.child = n, n.name = t.name ? t.name : n.parent.name, t.defaultOptions && Object.keys(t.defaultOptions).length > 0 && console.warn(`[tiptap warn]: BREAKING CHANGE: "defaultOptions" is deprecated. Please use "addOptions" instead. Found in extension: "${n.name}".`), n.options = E(w(n, "addOptions", {
name: n.name
})), n.storage = E(w(n, "addStorage", {
name: n.name,
options: n.options
})), n;
}
}
function Ke(e, t, n) {
const { from: r, to: s } = t, { blockSeparator: o = `
`, textSerializers: i = {} } = n || {};
let a = "";
return e.nodesBetween(r, s, (c, l, u, d) => {
var p;
c.isBlock && l > r && (a += o);
const h = i == null ? void 0 : i[c.type.name];
if (h)
return u && (a += h({
node: c,
pos: l,
parent: u,
index: d,
range: t
})), !1;
c.isText && (a += (p = c == null ? void 0 : c.text) === null || p === void 0 ? void 0 : p.slice(Math.max(r, l) - l, s - l));
}), a;
}
function Ue(e) {
return Object.fromEntries(Object.entries(e.nodes).filter(([, t]) => t.spec.toText).map(([t, n]) => [t, n.spec.toText]));
}
const $r = R.create({
name: "clipboardTextSerializer",
addOptions() {
return {
blockSeparator: void 0
};
},
addProseMirrorPlugins() {
return [
new $({
key: new _("clipboardTextSerializer"),
props: {
clipboardTextSerializer: () => {
const { editor: e } = this, { state: t, schema: n } = e, { doc: r, selection: s } = t, { ranges: o } = s, i = Math.min(...o.map((u) => u.$from.pos)), a = Math.max(...o.map((u) => u.$to.pos)), c = Ue(n);
return Ke(r, { from: i, to: a }, {
...this.options.blockSeparator !== void 0 ? { blockSeparator: this.options.blockSeparator } : {},
textSerializers: c
});
}
}
})
];
}
}), _r = () => ({ editor: e, view: t }) => (requestAnimationFrame(() => {
var n;
e.isDestroyed || (t.dom.blur(), (n = window == null ? void 0 : window.getSelection()) === null || n === void 0 || n.removeAllRanges());
}), !0), Hr = (e = !1) => ({ commands: t }) => t.setContent("", e), Dr = () => ({ state: e, tr: t, dispatch: n }) => {
const { selection: r } = t, { ranges: s } = r;
return n && s.forEach(({ $from: o, $to: i }) => {
e.doc.nodesBetween(o.pos, i.pos, (a, c) => {
if (a.type.isText)
return;
const { doc: l, mapping: u } = t, d = l.resolve(u.map(c)), p = l.resolve(u.map(c + a.nodeSize)), h = d.blockRange(p);
if (!h)
return;
const m = jn(h);
if (a.type.isTextblock) {
const { defaultType: f } = d.parent.contentMatchAt(d.index());
t.setNodeMarkup(h.start, f);
}
(m || m === 0) && t.lift(h, m);
});
}), !0;
}, Ir = (e) => (t) => e(t), Nr = () => ({ state: e, dispatch: t }) => Bn(e, t), Br = (e, t) => ({ editor: n, tr: r }) => {
const { state: s } = n, o = s.doc.slice(e.from, e.to);
r.deleteRange(e.from, e.to);
const i = r.mapping.map(t);
return r.insert(i, o.content), r.setSelection(new I(r.doc.resolve(i - 1))), !0;
}, jr = () => ({ tr: e, dispatch: t }) => {
const { selection: n } = e, r = n.$anchor.node();
if (r.content.size > 0)
return !1;
const s = e.selection.$anchor;
for (let o = s.depth; o > 0; o -= 1)
if (s.node(o).type === r.type) {
if (t) {
const a = s.before(o), c = s.after(o);
e.delete(a, c).scrollIntoView();
}
return !0;
}
return !1;
}, Fr = (e) => ({ tr: t, state: n, dispatch: r }) => {
const s = H(e, n.schema), o = t.selection.$anchor;
for (let i = o.depth; i > 0; i -= 1)
if (o.node(i).type === s) {
if (r) {
const c = o.before(i), l = o.after(i);
t.delete(c, l).scrollIntoView();
}
return !0;
}
return !1;
}, zr = (e) => ({ tr: t, dispatch: n }) => {
const { from: r, to: s } = e;
return n && t.delete(r, s), !0;
}, Vr = () => ({ state: e, dispatch: t }) => Nn(e, t), Wr = () => ({ commands: e }) => e.keyboardShortcut("Enter"), Kr = () => ({ state: e, dispatch: t }) => In(e, t);
function yt(e, t, n = { strict: !0 }) {
const r = Object.keys(t);
return r.length ? r.every((s) => n.strict ? t[s] === e[s] : Xt(t[s]) ? t[s].test(e[s]) : t[s] === e[s]) : !0;
}
function qe(e, t, n = {}) {
return e.find((r) => r.type === t && yt(
// Only check equality for the attributes that are provided
Object.fromEntries(Object.keys(n).map((s) => [s, r.attrs[s]])),
n
));
}
function me(e, t, n = {}) {
return !!qe(e, t, n);
}
function Qt(e, t, n) {
var r;
if (!e || !t)
return;
let s = e.parent.childAfter(e.parentOffset);
if ((!s.node || !s.node.marks.some((u) => u.type === t)) && (s = e.parent.childBefore(e.parentOffset)), !s.node || !s.node.marks.some((u) => u.type === t) || (n = n || ((r = s.node.marks[0]) === null || r === void 0 ? void 0 : r.attrs), !qe([...s.node.marks], t, n)))
return;
let i = s.index, a = e.start() + s.offset, c = i + 1, l = a + s.node.nodeSize;
for (; i > 0 && me([...e.parent.child(i - 1).marks], t, n); )
i -= 1, a -= e.parent.child(i).nodeSize;
for (; c < e.parent.childCount && me([...e.parent.child(c).marks], t, n); )
l += e.parent.child(c).nodeSize, c += 1;
return {
from: a,
to: l
};
}
function q(e, t) {
if (typeof e == "string") {
if (!t.marks[e])
throw Error(`There is no mark type named '${e}'. Maybe you forgot to add the extension?`);
return t.marks[e];
}
return e;
}
const Ur = (e, t = {}) => ({ tr: n, state: r, dispatch: s }) => {
const o = q(e, r.schema), { doc: i, selection: a } = n, { $from: c, from: l, to: u } = a;
if (s) {
const d = Qt(c, o, t);
if (d && d.from <= l && d.to >= u) {
const p = I.create(i, d.from, d.to);
n.setSelection(p);
}
}
return !0;
}, qr = (e) => (t) => {
const n = typeof e == "function" ? e(t) : e;
for (let r = 0; r < n.length; r += 1)
if (n[r](t))
return !0;
return !1;
};
function Zt(e) {
return e instanceof I;
}
function z(e = 0, t = 0, n = 0) {
return Math.min(Math.max(e, t), n);
}
function Ge(e, t = null) {
if (!t)
return null;
const n = W.atStart(e), r = W.atEnd(e);
if (t === "start" || t === !0)
return n;
if (t === "end")
return r;
const s = n.from, o = r.to;
return t === "all" ? I.create(e, z(0, s, o), z(e.content.size, s, o)) : I.create(e, z(t, s, o), z(t, s, o));
}
function Je() {
return navigator.platform === "Android" || /android/i.test(navigator.userAgent);
}
function Et() {
return [
"iPad Simulator",
"iPhone Simulator",
"iPod Simulator",
"iPad",
"iPhone",
"iPod"
].includes(navigator.platform) || navigator.userAgent.includes("Mac") && "ontouchend" in document;
}
const Gr = (e = null, t = {}) => ({ editor: n, view: r, tr: s, dispatch: o }) => {
t = {
scrollIntoView: !0,
...t
};
const i = () => {
(Et() || Je()) && r.dom.focus(), requestAnimationFrame(() => {
n.isDestroyed || (r.focus(), t != null && t.scrollIntoView && n.commands.scrollIntoView());
});
};
if (r.hasFocus() && e === null || e === !1)
return !0;
if (o && e === null && !Zt(n.state.selection))
return i(), !0;
const a = Ge(s.doc, e) || n.state.selection, c = n.state.selection.eq(a);
return o && (c || s.setSelection(a), c && s.storedMarks && s.setStoredMarks(s.storedMarks), i()), !0;
}, Jr = (e, t) => (n) => e.every((r, s) => t(r, { ...n, index: s })), Yr = (e, t) => ({ tr: n, commands: r }) => r.insertContentAt({ from: n.selection.from, to: n.selection.to }, e, t), Ye = (e) => {
const t = e.childNodes;
for (let n = t.length - 1; n >= 0; n -= 1) {
const r = t[n];
r.nodeType === 3 && r.nodeValue && /^(\n\s\s|\n)$/.test(r.nodeValue) ? e.removeChild(r) : r.nodeType === 1 && Ye(r);
}
return e;
};
function dt(e) {
const t = `<body>${e}</body>`, n = new window.DOMParser().parseFromString(t, "text/html").body;
return Ye(n);
}
function vt(e, t, n) {
if (e instanceof gn || e instanceof K)
return e;
n = {
slice: !0,
parseOptions: {},
...n
};
const r = typeof e == "object" && e !== null, s = typeof e == "string";
if (r)
try {
if (Array.isArray(e) && e.length > 0)
return K.fromArray(e.map((a) => t.nodeFromJSON(a)));
const i = t.nodeFromJSON(e);
return n.errorOnInvalidContent && i.check(), i;
} catch (o) {
if (n.errorOnInvalidContent)
throw new Error("[tiptap error]: Invalid JSON content", { cause: o });
return console.warn("[tiptap warn]: Invalid content.", "Passed value:", e, "Error:", o), vt("", t, n);
}
if (s) {
if (n.errorOnInvalidContent) {
let i = !1, a = "";
const c = new He({
topNode: t.spec.topNode,
marks: t.spec.marks,
// Prosemirror's schemas are executed such that: the last to execute, matches last
// This means that we can add a catch-all node at the end of the schema to catch any content that we don't know how to handle
nodes: t.spec.nodes.append({
__tiptap__private__unknown__catch__all__node: {
content: "inline*",
group: "block",
parseDOM: [
{
tag: "*",
getAttrs: (l) => (i = !0, a = typeof l == "string" ? l : l.outerHTML, null)
}
]
}
})
});
if (n.slice ? Lt.fromSchema(c).parseSlice(dt(e), n.parseOptions) : Lt.fromSchema(c).parse(dt(e), n.parseOptions), n.errorOnInvalidContent && i)
throw new Error("[tiptap error]: Invalid HTML content", { cause: new Error(`Invalid element found: ${a}`) });
}
const o = Lt.fromSchema(t);
return n.slice ? o.parseSlice(dt(e), n.parseOptions).content : o.parse(dt(e), n.parseOptions);
}
return vt("", t, n);
}
function Xr(e, t, n) {
const r = e.steps.length - 1;
if (r < t)
return;
const s = e.steps[r];
if (!(s instanceof Fn || s instanceof zn))
return;
const o = e.mapping.maps[r];
let i = 0;
o.forEach((a, c, l, u) => {
i === 0 && (i = u);
}), e.setSelection(W.near(e.doc.resolve(i), n));
}
const Qr = (e) => !("type" in e), Zr = (e, t, n) => ({ tr: r, dispatch: s, editor: o }) => {
var i;
if (s) {
n = {
parseOptions: o.options.parseOptions,
updateSelection: !0,
applyInputRules: !1,
applyPasteRules: !1,
...n
};
let a;
try {
a = vt(t, o.schema, {
parseOptions: {
preserveWhitespace: "full",
...n.parseOptions
},
errorOnInvalidContent: (i = n.errorOnInvalidContent) !== null && i !== void 0 ? i : o.options.enableContentCheck
});
} catch (m) {
return o.emit("contentError", {
editor: o,
error: m,
disableCollaboration: () => {
o.storage.collaboration && (o.storage.collaboration.isDisabled = !0);
}
}), !1;
}
let { from: c, to: l } = typeof e == "number" ? { from: e, to: e } : { from: e.from, to: e.to }, u = !0, d = !0;
if ((Qr(a) ? a : [a]).forEach((m) => {
m.check(), u = u ? m.isText && m.marks.length === 0 : !1, d = d ? m.isBlock : !1;
}), c === l && d) {
const { parent: m } = r.doc.resolve(c);
m.isTextblock && !m.type.spec.code && !m.childCount && (c -= 1, l += 1);
}
let h;
if (u) {
if (Array.isArray(t))
h = t.map((m) => m.text || "").join("");
else if (t instanceof K) {
let m = "";
t.forEach((f) => {
f.text && (m += f.text);
}), h = m;
} else typeof t == "object" && t && t.text ? h = t.text : h = t;
r.insertText(h, c, l);
} else
h = a, r.replaceWith(c, l, h);
n.updateSelection && Xr(r, r.steps.length - 1, -1), n.applyInputRules && r.setMeta("applyInputRules", { from: c, text: h }), n.applyPasteRules && r.setMeta("applyPasteRules", { from: c, text: h });
}
return !0;
}, ts = () => ({ state: e, dispatch: t }) => Pn(e, t), es = () => ({ state: e, dispatch: t }) => Hn(e, t), ns = () => ({ state: e, dispatch: t }) => Dn(e, t), rs = () => ({ state: e, dispatch: t }) => _n(e, t), ss = () => ({ state: e, dispatch: t, tr: n }) => {
try {
const r = De(e.doc, e.selection.$from.pos, -1);
return r == null ? !1 : (n.join(r, 2), t && t(n), !0);
} catch {
return !1;
}
}, os = () => ({ state: e, dispatch: t, tr: n }) => {
try {
const r = De(e.doc, e.selection.$from.pos, 1);
return r == null ? !1 : (n.join(r, 2), t && t(n), !0);
} catch {
return !1;
}
}, is = () => ({ state: e, dispatch: t }) => $n(e, t), as = () => ({ state: e, dispatch: t }) => Rn(e, t);
function Xe() {
return typeof navigator < "u" ? /Mac/.test(navigator.platform) : !1;
}
function ls(e) {
const t = e.split(/-(?!$)/);
let n = t[t.length - 1];
n === "Space" && (n = " ");
let r, s, o, i;
for (let a = 0; a < t.length - 1; a += 1) {
const c = t[a];
if (/^(cmd|meta|m)$/i.test(c))
i = !0;
else if (/^a(lt)?$/i.test(c))
r = !0;
else if (/^(c|ctrl|control)$/i.test(c))
s = !0;
else if (/^s(hift)?$/i.test(c))
o = !0;
else if (/^mod$/i.test(c))
Et() || Xe() ? i = !0 : s = !0;
else
throw new Error(`Unrecognized modifier name: ${c}`);
}
return r && (n = `Alt-${n}`), s && (n = `Ctrl-${n}`), i && (n = `Meta-${n}`), o && (n = `Shift-${n}`), n;
}
const cs = (e) => ({ editor: t, view: n, tr: r, dispatch: s }) => {
const o = ls(e).split(/-(?!$)/), i = o.find((l) => !["Alt", "Ctrl", "Meta", "Shift"].includes(l)), a = new KeyboardEvent("keydown", {
key: i === "Space" ? " " : i,
altKey: o.includes("Alt"),
ctrlKey: o.includes("Ctrl"),
metaKey: o.includes("Meta"),
shiftKey: o.includes("Shift"),
bubbles: !0,
cancelable: !0
}), c = t.captureTransaction(() => {
n.someProp("handleKeyDown", (l) => l(n, a));
});
return c == null || c.steps.forEach((l) => {
const u = l.map(r.mapping);
u && s && r.maybeStep(u);
}), !0;
};
function ot(e, t, n = {}) {
const { from: r, to: s, empty: o } = e.selection, i = t ? H(t, e.schema) : null, a = [];
e.doc.nodesBetween(r, s, (d, p) => {
if (d.isText)
return;
const h = Math.max(r, p), m = Math.min(s, p + d.nodeSize);
a.push({
node: d,
from: h,
to: m
});
});
const c = s - r, l = a.filter((d) => i ? i.name === d.node.type.name : !0).filter((d) => yt(d.node.attrs, n, { strict: !1 }));
return o ? !!l.length : l.reduce((d, p) => d + p.to - p.from, 0) >= c;
}
const ds = (e, t = {}) => ({ state: n, dispatch: r }) => {
const s = H(e, n.schema);
return ot(n, s, t) ? Ln(n, r) : !1;
}, us = () => ({ state: e, dispatch: t }) => On(e, t), ps = (e) => ({ state: t, dispatch: n }) => {
const r = H(e, t.schema);
return An(r)(t, n);
}, hs = () => ({ state: e, dispatch: t }) => xn(e, t);
function Tt(e, t) {
return t.nodes[e] ? "node" : t.marks[e] ? "mark" : null;
}
function ge(e, t) {
const n = typeof t == "string" ? [t] : t;
return Object.keys(e).reduce((r, s) => (n.includes(s) || (r[s] = e[s]), r), {});
}
const fs = (e, t) => ({ tr: n, state: r, dispatch: s }) => {
let o = null, i = null;
const a = Tt(typeof e == "string" ? e : e.name, r.schema);
return a ? (a === "node" && (o = H(e, r.schema)), a === "mark" && (i = q(e, r.schema)), s && n.selection.ranges.forEach((c) => {
r.doc.nodesBetween(c.$from.pos, c.$to.pos, (l, u) => {
o && o === l.type && n.setNodeMarkup(u, void 0, ge(l.attrs, t)), i && l.marks.length && l.marks.forEach((d) => {
i === d.type && n.addMark(u, u + l.nodeSize, i.create(ge(d.attrs, t)));
});
});
}), !0) : !1;
}, ms = () => ({ tr: e, dispatch: t }) => (t && e.scrollIntoView(), !0), gs = () => ({ tr: e, dispatch: t }) => {
if (t) {
const n = new Cn(e.doc);
e.setSelection(n);
}
return !0;
}, ys = () => ({ state: e, dispatch: t }) => Tn(e, t), vs = () => ({ state: e, dispatch: t }) => En(e, t), bs = () => ({ state: e, dispatch: t }) => kn(e, t), Ms = () => ({ state: e, dispatch: t }) => wn(e, t), Ss = () => ({ state: e, dispatch: t }) => Sn(e, t);
function Bt(e, t, n = {}, r = {}) {
return vt(e, t, {
slice: !1,
parseOptions: n,
errorOnInvalidContent: r.errorOnInvalidContent
});
}
const ws = (e, t = !1, n = {}, r = {}) => ({ editor: s, tr: o, dispatch: i, commands: a }) => {
var c, l;
const { doc: u } = o;
if (n.preserveWhitespace !== "full") {
const d = Bt(e, s.schema, n, {
errorOnInvalidContent: (c = r.errorOnInvalidContent) !== null && c !== void 0 ? c : s.options.enableContentCheck
});
return i && o.replaceWith(0, u.content.size, d).setMeta("preventUpdate", !t), !0;
}
return i && o.setMeta("preventUpdate", !t), a.insertContentAt({ from: 0, to: u.content.size }, e, {
parseOptions: n,
errorOnInvalidContent: (l = r.errorOnInvalidContent) !== null && l !== void 0 ? l : s.options.enableContentCheck
});
};
function Qe(e, t) {
const n = q(t, e.schema), { from: r, to: s, empty: o } = e.selection, i = [];
o ? (e.storedMarks && i.push(...e.storedMarks), i.push(...e.selection.$head.marks())) : e.doc.nodesBetween(r, s, (c) => {
i.push(...c.marks);
});
const a = i.find((c) => c.type.name === n.name);
return a ? { ...a.attrs } : {};
}
function ks(e, t) {
const n = new Wn(e);
return t.forEach((r) => {
r.steps.forEach((s) => {
n.step(s);
});
}), n;
}
function Es(e) {
for (let t = 0; t < e.edgeCount; t += 1) {
const { type: n } = e.edge(t);
if (n.isTextblock && !n.hasRequiredAttrs())
return n;
}
return null;
}
function Ci(e, t) {
const n = [];
return e.descendants((r, s) => {
t(r) && n.push({
node: r,
pos: s
});
}), n;
}
function Ts(e, t, n) {
const r = [];
return e.nodesBetween(t.from, t.to, (s, o) => {
n(s) && r.push({
node: s,
pos: o
});
}), r;
}
function Ze(e, t) {
for (let n = e.depth; n > 0; n -= 1) {
const r = e.node(n);
if (t(r))
return {
pos: n > 0 ? e.before(n) : 0,
start: e.start(n),
depth: n,
node: r
};
}
}
function te(e) {
return (t) => Ze(t.$from, e);
}
function Cs(e, t) {
const n = {
from: 0,
to: e.content.size
};
return Ke(e, n, t);
}
function xs(e, t) {
const n = H(t, e.schema), { from: r, to: s } = e.selection, o = [];
e.doc.nodesBetween(r, s, (a) => {
o.push(a);
});
const i = o.reverse().find((a) => a.type.name === n.name);
return i ? { ...i.attrs } : {};
}
function tn(e, t) {
const n = Tt(typeof t == "string" ? t : t.name, e.schema);
return n === "node" ? xs(e, t) : n === "mark" ? Qe(e, t) : {};
}
function As(e, t = JSON.stringify) {
const n = {};
return e.filter((r) => {
const s = t(r);
return Object.prototype.hasOwnProperty.call(n, s) ? !1 : n[s] = !0;
});
}
function Os(e) {
const t = As(e);
return t.length === 1 ? t : t.filter((n, r) => !t.filter((o, i) => i !== r).some((o) => n.oldRange.from >= o.oldRange.from && n.oldRange.to <= o.oldRange.to && n.newRange.from >= o.newRange.from && n.newRange.to <= o.newRange.to));
}
function Ls(e) {
const { mapping: t, steps: n } = e, r = [];
return t.maps.forEach((s, o) => {
const i = [];
if (s.ranges.length)
s.forEach((a, c) => {
i.push({ from: a, to: c });
});
else {
const { from: a, to: c } = n[o];
if (a === void 0 || c === void 0)
return;
i.push({ from: a, to: c });
}
i.forEach(({ from: a, to: c }) => {
const l = t.slice(o).map(a, -1), u = t.slice(o).map(c), d = t.invert().map(l, -1), p = t.invert().map(u);
r.push({
oldRange: {
from: d,
to: p
},
newRange: {
from: l,
to: u
}
});
});
}), Os(r);
}
function ee(e, t, n) {
const r = [];
return e === t ? n.resolve(e).marks().forEach((s) => {
const o = n.resolve(e), i = Qt(o, s.type);
i && r.push({
mark: s,
...i
});
}) : n.nodesBetween(e, t, (s, o) => {
!s || (s == null ? void 0 : s.nodeSize) === void 0 || r.push(...s.marks.map((i) => ({
from: o,
to: o + s.nodeSize,
mark: i
})));
}), r;
}
function ft(e, t, n) {
return Object.fromEntries(Object.entries(n).filter(([r]) => {
const s = e.find((o) => o.type === t && o.name === r);
return s ? s.attribute.keepOnSplit : !1;
}));
}
function jt(e, t, n = {}) {
const { empty: r, ranges: s } = e.selection, o = t ? q(t, e.schema) : null;
if (r)
return !!(e.storedMarks || e.selection.$from.marks()).filter((d) => o ? o.name === d.type.name : !0).find((d) => yt(d.attrs, n, { strict: !1 }));
let i = 0;
const a = [];
if (s.forEach(({ $from: d, $to: p }) => {
const h = d.pos, m = p.pos;
e.doc.nodesBetween(h, m, (f, g) => {
if (!f.isText && !f.marks.length)
return;
const y = Math.max(h, g), M = Math.min(m, g + f.nodeSize), b = M - y;
i += b, a.push(...f.marks.map((v) => ({
mark: v,
from: y,
to: M
})));
});
}), i === 0)
return !1;
const c = a.filter((d) => o ? o.name === d.mark.type.name : !0).filter((d) => yt(d.mark.attrs, n, { strict: !1 })).reduce((d, p) => d + p.to - p.from, 0), l = a.filter((d) => o ? d.mark.type !== o &