UNPKG

@blocknote/core

Version:

A "Notion-style" block-based extensible text editor built on top of Prosemirror and Tiptap.

1,817 lines 321 kB
var co = Object.defineProperty; var lo = (e, n, t) => n in e ? co(e, n, { enumerable: !0, configurable: !0, writable: !0, value: t }) : e[n] = t; var p = (e, n, t) => lo(e, typeof n != "symbol" ? n + "" : n, t); import { Slice as X, Fragment as R, DOMSerializer as ln, DOMParser as Ee, Node as uo } from "prosemirror-model"; import { ReplaceStep as dn, ReplaceAroundStep as st, Mapping as ho } from "prosemirror-transform"; import { Extension as _, combineTransactionSteps as un, getChangedRanges as po, findChildrenInRange as fo, Node as oe, Mark as re, isTextSelection as hn, InputRule as le, callOrReturn as mo, getExtensionField as go, mergeAttributes as kt, selectionToInsertionEnd as bo, isNodeSelection as it, posToDOMRect as Ue, getMarkRange as Nt, findChildren as Ht, findParentNode as ko, extensions as we, Editor as wo, createDocument as yo, getSchema as Co } from "@tiptap/core"; import { Plugin as N, PluginKey as U, TextSelection as L, NodeSelection as be, Selection as Ve, EditorState as vo } from "prosemirror-state"; import { v4 as pn } from "uuid"; import { TableMap as $e, goToNextCell as Dt, columnResizing as So, tableEditing as Eo, TableView as Bo, CellSelection as Be, addRowBefore as xo, addRowAfter as Mo, addColumnBefore as Po, addColumnAfter as To, deleteRow as Io, deleteColumn as Lo, mergeCells as Ao, splitCell as No } from "prosemirror-tables"; import Ho from "fast-deep-equal"; import { createHighlightPlugin as Do } from "prosemirror-highlight"; import { createParser as Oo } from "prosemirror-highlight/shiki"; import Ro from "@tiptap/extension-bold"; import Vo from "@tiptap/extension-code"; import _o from "@tiptap/extension-italic"; import Uo from "@tiptap/extension-strike"; import $o from "@tiptap/extension-underline"; import { TableCell as Fo } from "@tiptap/extension-table-cell"; import { TableHeader as zo } from "@tiptap/extension-table-header"; import { Gapcursor as Wo } from "@tiptap/extension-gapcursor"; import { History as jo } from "@tiptap/extension-history"; import { Link as Go } from "@tiptap/extension-link"; import { Text as qo } from "@tiptap/extension-text"; import { yCursorPlugin as Ko, defaultSelectionBuilder as Yo, ySyncPlugin as Xo, yUndoPlugin as Jo, ySyncPluginKey as de, getRelativeSelection as Zo, absolutePositionToRelativePosition as Qo, relativePositionToAbsolutePosition as er, yUndoPluginKey as Ae, yCursorPluginKey as tr, undoCommand as nr, redoCommand as or } from "y-prosemirror"; import { DecorationSet as j, Decoration as J, EditorView as rr } from "prosemirror-view"; import * as ie from "yjs"; import { undo as sr, redo as ir } from "prosemirror-history"; import { dropCursor as ar } from "prosemirror-dropcursor"; import { e as cr } from "./en-CvDoFvhc.js"; function lr(e, n = JSON.stringify) { const t = {}; return e.filter((o) => { const r = n(o); return Object.prototype.hasOwnProperty.call(t, r) ? !1 : t[r] = !0; }); } function dr(e) { const n = e.filter( (o, r) => e.indexOf(o) !== r ); return lr(n); } const Ge = _.create({ name: "uniqueID", // we’ll set a very high priority to make sure this runs first // and is compatible with `appendTransaction` hooks of other extensions priority: 1e4, addOptions() { return { attributeName: "id", types: [], setIdAttribute: !1, generateID: () => { if (typeof window < "u" && window.__TEST_OPTIONS) { const e = window.__TEST_OPTIONS; return e.mockID === void 0 ? e.mockID = 0 : e.mockID++, e.mockID.toString(); } return pn(); }, filterTransaction: null }; }, addGlobalAttributes() { return [ { types: this.options.types, attributes: { [this.options.attributeName]: { default: null, parseHTML: (e) => e.getAttribute(`data-${this.options.attributeName}`), renderHTML: (e) => { const n = { [`data-${this.options.attributeName}`]: e[this.options.attributeName] }; return this.options.setIdAttribute ? { ...n, id: e[this.options.attributeName] } : n; } } } } ]; }, // check initial content for missing ids // onCreate() { // // Don’t do this when the collaboration extension is active // // because this may update the content, so Y.js tries to merge these changes. // // This leads to empty block nodes. // // See: https://github.com/ueberdosis/tiptap/issues/2400 // if ( // this.editor.extensionManager.extensions.find( // (extension) => extension.name === "collaboration" // ) // ) { // return; // } // const { view, state } = this.editor; // const { tr, doc } = state; // const { types, attributeName, generateID } = this.options; // const nodesWithoutId = findChildren(doc, (node) => { // return ( // types.includes(node.type.name) && node.attrs[attributeName] === null // ); // }); // nodesWithoutId.forEach(({ node, pos }) => { // tr.setNodeMarkup(pos, undefined, { // ...node.attrs, // [attributeName]: generateID(), // }); // }); // tr.setMeta("addToHistory", false); // view.dispatch(tr); // }, addProseMirrorPlugins() { let e = null, n = !1; return [ new N({ key: new U("uniqueID"), appendTransaction: (t, o, r) => { const s = t.some((m) => m.docChanged) && !o.doc.eq(r.doc), i = this.options.filterTransaction && t.some((m) => { let g, b; return !(!((b = (g = this.options).filterTransaction) === null || b === void 0) && b.call(g, m)); }); if (!s || i) return; const { tr: a } = r, { types: c, attributeName: l, generateID: d } = this.options, u = un( o.doc, t ), { mapping: h } = u; if (po(u).forEach(({ newRange: m }) => { const g = fo( r.doc, m, (w) => c.includes(w.type.name) ), b = g.map(({ node: w }) => w.attrs[l]).filter((w) => w !== null), k = dr(b); g.forEach(({ node: w, pos: C }) => { let y; const B = (y = a.doc.nodeAt(C)) === null || y === void 0 ? void 0 : y.attrs[l]; if (B === null) { const v = o.doc.type.createAndFill().content; if (o.doc.content.findDiffStart(v) === null) { const M = JSON.parse( JSON.stringify(r.doc.toJSON()) ); if (M.content[0].content[0].attrs.id = "initialBlockId", JSON.stringify(M.content) === JSON.stringify(v.toJSON())) { a.setNodeMarkup(C, void 0, { ...w.attrs, [l]: "initialBlockId" }); return; } } a.setNodeMarkup(C, void 0, { ...w.attrs, [l]: d() }); return; } const { deleted: K } = h.invert().mapResult(C); K && k.includes(B) && a.setNodeMarkup(C, void 0, { ...w.attrs, [l]: d() }); }); }), !!a.steps.length) return a; }, // we register a global drag handler to track the current drag source element view(t) { const o = (r) => { let s; e = !((s = t.dom.parentElement) === null || s === void 0) && s.contains(r.target) ? t.dom.parentElement : null; }; return window.addEventListener("dragstart", o), { destroy() { window.removeEventListener("dragstart", o); } }; }, props: { // `handleDOMEvents` is called before `transformPasted` so we can do // some checks before. However, `transformPasted` only runs when // editor content is pasted - not external content. handleDOMEvents: { // only create new ids for dropped content while holding `alt` // or content is dragged from another editor drop: (t, o) => { let r; return e !== t.dom.parentElement || ((r = o.dataTransfer) === null || r === void 0 ? void 0 : r.effectAllowed) === "copy" ? n = !0 : n = !1, e = null, !1; }, // always create new ids on pasted content paste: () => (n = !0, !1) }, // we’ll remove ids for every pasted node // so we can create a new one within `appendTransaction` transformPasted: (t) => { if (!n) return t; const { types: o, attributeName: r } = this.options, s = (i) => { const a = []; return i.forEach((c) => { if (c.isText) { a.push(c); return; } if (!o.includes(c.type.name)) { a.push(c.copy(s(c.content))); return; } const l = c.type.create( { ...c.attrs, [r]: null }, s(c.content), c.marks ); a.push(l); }), R.from(a); }; return n = !1, new X( s(t.content), t.openStart, t.openEnd ); } } }) ]; } }); function Ot(e) { return e.type === "link"; } function fn(e) { return typeof e != "string" && e.type === "link"; } function ue(e) { return typeof e != "string" && e.type === "text"; } function at(e) { var n, t, o, r, s; return wt(e) ? { ...e } : Ce(e) ? { type: "tableCell", content: [].concat(e.content), props: { backgroundColor: ((n = e.props) == null ? void 0 : n.backgroundColor) ?? "default", textColor: ((t = e.props) == null ? void 0 : t.textColor) ?? "default", textAlignment: ((o = e.props) == null ? void 0 : o.textAlignment) ?? "left", colspan: ((r = e.props) == null ? void 0 : r.colspan) ?? 1, rowspan: ((s = e.props) == null ? void 0 : s.rowspan) ?? 1 } } : { type: "tableCell", content: [].concat(e), props: { backgroundColor: "default", textColor: "default", textAlignment: "left", colspan: 1, rowspan: 1 } }; } function Ce(e) { return e != null && typeof e != "string" && !Array.isArray(e) && e.type === "tableCell"; } function wt(e) { return Ce(e) && e.props !== void 0 && e.content !== void 0; } function ve(e) { return wt(e) ? e.props.colspan ?? 1 : 1; } function ct(e) { return wt(e) ? e.props.rowspan ?? 1 : 1; } class G extends Error { constructor(n) { super(`Unreachable case: ${n}`); } } function Fc(e, n = !0) { const { "data-test": t, ...o } = e; if (Object.keys(o).length > 0 && n) throw new Error("Object must be empty " + JSON.stringify(e)); } const ur = () => typeof navigator < "u" && (/Mac/.test(navigator.platform) || /AppleWebKit/.test(navigator.userAgent) && /Mobile\/\w+/.test(navigator.userAgent)); function Y(e, n = "Ctrl") { return ur() ? e.replace("Mod", "⌘") : e.replace("Mod", n); } function te(...e) { return [ // Converts to & from set to remove duplicates. ...new Set( e.filter((n) => n).join(" ").split(" ") ) ].join(" "); } const zc = () => /^((?!chrome|android).)*safari/i.test(navigator.userAgent); function $(e, n, t, o) { const r = document.createElement("div"); r.className = te( "bn-block-content", t.class ), r.setAttribute("data-content-type", e); for (const [i, a] of Object.entries(t)) i !== "class" && r.setAttribute(i, a); const s = document.createElement(n); s.className = te( "bn-inline-content", o.class ); for (const [i, a] of Object.entries( o )) i !== "class" && s.setAttribute(i, a); return r.appendChild(s), { dom: r, contentDOM: s }; } const Rt = (e, n) => { let t = pe(e, n.pmSchema); t.type.name === "blockContainer" && (t = t.firstChild); const o = n.pmSchema.nodes[t.type.name].spec.toDOM; if (o === void 0) throw new Error( "This block has no default HTML serialization as its corresponding TipTap node doesn't implement `renderHTML`." ); const r = o(t); if (typeof r != "object" || !("dom" in r)) throw new Error( "Cannot use this block's default HTML serialization as its corresponding TipTap node's `renderHTML` function does not return an object with the `dom` property." ); return r; }; function hr(e) { const n = e.querySelectorAll("p"); if (n.length > 1) { const t = n[0]; for (let o = 1; o < n.length; o++) { const r = n[o]; t.innerHTML += "<br>" + r.innerHTML, r.remove(); } } } const T = { backgroundColor: { default: "default" }, textColor: { default: "default" }, textAlignment: { default: "left", values: ["left", "center", "right", "justify"] } }, mn = ["backgroundColor", "textColor"]; function Fe(e) { return "data-" + e.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase(); } function Wc(e) { const n = e.split("/"); return !n.length || // invalid? n[n.length - 1] === "" ? e : n[n.length - 1]; } function xe(e) { const n = {}; return Object.entries(e).filter(([t, o]) => !mn.includes(t)).forEach(([t, o]) => { n[t] = { default: o.default, keepOnSplit: !0, // Props are displayed in kebab-case as HTML attributes. If a prop's // value is the same as its default, we don't display an HTML // attribute for it. parseHTML: (r) => { const s = r.getAttribute(Fe(t)); if (s === null) return null; if (o.default === void 0 && o.type === "boolean" || o.default !== void 0 && typeof o.default == "boolean") return s === "true" ? !0 : s === "false" ? !1 : null; if (o.default === void 0 && o.type === "number" || o.default !== void 0 && typeof o.default == "number") { const i = parseFloat(s); return !Number.isNaN(i) && Number.isFinite(i) ? i : null; } return s; }, renderHTML: (r) => r[t] !== o.default ? { [Fe(t)]: r[t] } : {} }; }), n; } function yt(e, n, t, o) { if (typeof e == "boolean") throw new Error( "Cannot find node position as getPos is a boolean, not a function." ); const r = e(), i = t.state.doc.resolve(r).node().attrs.id; if (!i) throw new Error("Block doesn't have id"); const a = n.getBlock(i); if (a.type !== o) throw new Error("Block type does not match"); return a; } function Ne(e, n, t, o, r = !1, s) { const i = document.createElement("div"); if (s !== void 0) for (const [a, c] of Object.entries(s)) a !== "class" && i.setAttribute(a, c); i.className = te( "bn-block-content", (s == null ? void 0 : s.class) || "" ), i.setAttribute("data-content-type", n); for (const [a, c] of Object.entries(t)) { const d = o[a].default; !mn.includes(a) && c !== d && i.setAttribute(Fe(a), c); } return r && i.setAttribute("data-file-block", ""), i.appendChild(e.dom), e.contentDOM !== void 0 && (e.contentDOM.className = te( "bn-inline-content", e.contentDOM.className )), { ...e, dom: i }; } function q(e) { return oe.create(e); } function gn(e, n) { return { config: e, implementation: n }; } function Q(e, n, t) { return gn( { type: e.name, content: e.config.content === "inline*" ? "inline" : e.config.content === "tableRow+" ? "table" : "none", propSchema: n }, { node: e, requiredExtensions: t, toInternalHTML: Rt, toExternalHTML: Rt // parse: () => undefined, // parse rules are in node already } ); } function bn(e) { return Object.fromEntries( Object.entries(e).map(([n, t]) => [n, t.config]) ); } function pr(e, n) { e.stopEvent = (t) => (t.type === "mousedown" && setTimeout(() => { n.view.dom.blur(); }, 10), !0); } function fr(e, n) { const t = [ { tag: "[data-content-type=" + e.type + "]", contentElement: ".bn-inline-content" } ]; return n && t.push({ tag: "*", getAttrs(o) { if (typeof o == "string") return !1; const r = n == null ? void 0 : n(o); return r === void 0 ? !1 : r; } }), t; } function Me(e, n) { const t = q({ name: e.type, content: e.content === "inline" ? "inline*" : "", group: "blockContent", selectable: e.isSelectable ?? !0, isolating: !0, addAttributes() { return xe(e.propSchema); }, parseHTML() { return fr(e, n.parse); }, renderHTML({ HTMLAttributes: o }) { const r = document.createElement("div"); return Ne( { dom: r, contentDOM: e.content === "inline" ? r : void 0 }, e.type, {}, e.propSchema, e.isFileBlock, o ); }, addNodeView() { return ({ getPos: o }) => { var l; const r = this.options.editor, s = yt( o, r, this.editor, e.type ), i = ((l = this.options.domAttributes) == null ? void 0 : l.blockContent) || {}, a = n.render(s, r), c = Ne( a, s.type, s.props, e.propSchema, e.isFileBlock, i ); return e.isSelectable === !1 && pr(c, this.editor), c; }; } }); if (t.name !== e.type) throw new Error( "Node name does not match block type. This is a bug in BlockNote." ); return gn(e, { node: t, toInternalHTML: (o, r) => { var a; const s = ((a = t.options.domAttributes) == null ? void 0 : a.blockContent) || {}, i = n.render(o, r); return Ne( i, o.type, o.props, e.propSchema, e.isFileBlock, s ); }, // TODO: this should not have wrapInBlockStructure and generally be a lot simpler // post-processing in externalHTMLExporter should not be necessary toExternalHTML: (o, r) => { var a, c; const s = ((a = t.options.domAttributes) == null ? void 0 : a.blockContent) || {}; let i = (c = n.toExternalHTML) == null ? void 0 : c.call( n, o, r ); return i === void 0 && (i = n.render(o, r)), Ne( i, o.type, o.props, e.propSchema, s ); } }); } function Z(e, n) { const t = e.resolve(n); if (t.nodeAfter && t.nodeAfter.type.isInGroup("bnBlock")) return { posBeforeNode: t.pos, node: t.nodeAfter }; let o = t.depth, r = t.node(o); for (; o > 0; ) { if (r.type.isInGroup("bnBlock")) return { posBeforeNode: t.before(o), node: r }; o--, r = t.node(o); } const s = []; e.descendants((a, c) => { a.type.isInGroup("bnBlock") && s.push(c); }), console.warn(`Position ${n} is not within a blockContainer node.`); const i = e.resolve( s.find((a) => a >= n) || s[s.length - 1] ); return { posBeforeNode: i.pos, node: i.nodeAfter }; } function Ct(e, n) { if (!e.type.isInGroup("bnBlock")) throw new Error( `Attempted to get bnBlock node at position but found node of different type ${e.type.name}` ); const t = e, o = n, r = o + t.nodeSize, s = { node: t, beforePos: o, afterPos: r }; if (t.type.name === "blockContainer") { let i, a; if (t.forEach((c, l) => { if (c.type.spec.group === "blockContent") { const d = c, u = o + l + 1, h = u + c.nodeSize; i = { node: d, beforePos: u, afterPos: h }; } else if (c.type.name === "blockGroup") { const d = c, u = o + l + 1, h = u + c.nodeSize; a = { node: d, beforePos: u, afterPos: h }; } }), !i) throw new Error( `blockContainer node does not contain a blockContent node in its children: ${t}` ); return { isBlockContainer: !0, bnBlock: s, blockContent: i, childContainer: a, blockNoteType: i.node.type.name }; } else { if (!s.node.type.isInGroup("childContainer")) throw new Error( `bnBlock node is not in the childContainer group: ${s.node}` ); return { isBlockContainer: !1, bnBlock: s, childContainer: s, blockNoteType: s.node.type.name }; } } function ne(e) { return Ct(e.node, e.posBeforeNode); } function Pe(e) { if (!e.nodeAfter) throw new Error( `Attempted to get blockContainer node at position ${e.pos} but a node at this position does not exist` ); return Ct(e.nodeAfter, e.pos); } function S(e) { const n = Z(e.doc, e.selection.anchor); return ne(n); } function qe(e) { const n = Z(e.doc, e.selection.anchor); return ne(n); } function H(e) { return "doc" in e ? e.doc.type.schema : e.type.schema; } function kn(e) { return e.cached.blockNoteEditor; } function Te(e) { return kn(e).schema; } function vt(e) { return Te(e).blockSchema; } function St(e) { return Te(e).inlineContentSchema; } function ke(e) { return Te(e).styleSchema; } function Et(e) { return kn(e).blockCache; } function wn(e, n, t) { var s, i; const o = { type: "tableContent", columnWidths: [], headerRows: void 0, headerCols: void 0, rows: [] }, r = []; e.content.forEach((a, c, l) => { const d = { cells: [] }; l === 0 && a.content.forEach((u) => { let h = u.attrs.colwidth; h == null && (h = new Array(u.attrs.colspan ?? 1).fill(void 0)), o.columnWidths.push(...h); }), d.cells = a.content.content.map((u, h) => (r[l] || (r[l] = []), r[l][h] = u.type.name === "tableHeader", { type: "tableCell", content: u.content.content.map( (m) => Ke(m, n, t) ).reduce( (m, g) => { if (!m.length) return g; const b = m[m.length - 1], k = g[0]; return k && ue(b) && ue(k) && JSON.stringify(b.styles) === JSON.stringify(k.styles) ? (b.text += ` ` + k.text, m.push(...g.slice(1)), m) : (m.push(...g), m); }, [] ), props: { colspan: u.attrs.colspan, rowspan: u.attrs.rowspan, backgroundColor: u.attrs.backgroundColor, textColor: u.attrs.textColor, textAlignment: u.attrs.textAlignment } })), o.rows.push(d); }); for (let a = 0; a < r.length; a++) (s = r[a]) != null && s.every((c) => c) && (o.headerRows = (o.headerRows ?? 0) + 1); for (let a = 0; a < ((i = r[0]) == null ? void 0 : i.length); a++) r != null && r.every((c) => c[a]) && (o.headerCols = (o.headerCols ?? 0) + 1); return o; } function Ke(e, n, t) { const o = []; let r; return e.content.forEach((s) => { if (s.type.name === "hardBreak") { if (r) if (ue(r)) r.text += ` `; else if (Ot(r)) r.content[r.content.length - 1].text += ` `; else throw new Error("unexpected"); else r = { type: "text", text: ` `, styles: {} }; return; } if (s.type.name !== "link" && s.type.name !== "text") { if (!n[s.type.name]) { console.warn("unrecognized inline content type", s.type.name); return; } r && (o.push(r), r = void 0), o.push( lt(s, n, t) ); return; } const i = {}; let a; for (const c of s.marks) if (c.type.name === "link") a = c; else { const l = t[c.type.name]; if (!l) { if (c.type.spec.blocknoteIgnore) continue; throw new Error(`style ${c.type.name} not found in styleSchema`); } if (l.propSchema === "boolean") i[l.type] = !0; else if (l.propSchema === "string") i[l.type] = c.attrs.stringValue; else throw new G(l.propSchema); } r ? ue(r) ? a ? (o.push(r), r = { type: "link", href: a.attrs.href, content: [ { type: "text", text: s.textContent, styles: i } ] }) : JSON.stringify(r.styles) === JSON.stringify(i) ? r.text += s.textContent : (o.push(r), r = { type: "text", text: s.textContent, styles: i }) : Ot(r) && (a ? r.href === a.attrs.href ? JSON.stringify( r.content[r.content.length - 1].styles ) === JSON.stringify(i) ? r.content[r.content.length - 1].text += s.textContent : r.content.push({ type: "text", text: s.textContent, styles: i }) : (o.push(r), r = { type: "link", href: a.attrs.href, content: [ { type: "text", text: s.textContent, styles: i } ] }) : (o.push(r), r = { type: "text", text: s.textContent, styles: i })) : a ? r = { type: "link", href: a.attrs.href, content: [ { type: "text", text: s.textContent, styles: i } ] } : r = { type: "text", text: s.textContent, styles: i }; }), r && o.push(r), o; } function lt(e, n, t) { if (e.type.name === "text" || e.type.name === "link") throw new Error("unexpected"); const o = {}, r = n[e.type.name]; for (const [a, c] of Object.entries(e.attrs)) { if (!r) throw Error("ic node is of an unrecognized type: " + e.type.name); const l = r.propSchema; a in l && (o[a] = c); } let s; return r.content === "styled" ? s = Ke( e, n, t ) : s = void 0, { type: e.type.name, props: o, content: s }; } function E(e, n, t = vt(n), o = St(n), r = ke(n), s = Et(n)) { var g; if (!e.type.isInGroup("bnBlock")) throw Error("Node should be a bnBlock, but is instead: " + e.type.name); const i = s == null ? void 0 : s.get(e); if (i) return i; const a = Ct(e, 0); let c = a.bnBlock.node.attrs.id; c === null && (c = Ge.options.generateID()); const l = t[a.blockNoteType]; if (!l) throw Error("Block is of an unrecognized type: " + a.blockNoteType); const d = {}; for (const [b, k] of Object.entries({ ...e.attrs, ...a.isBlockContainer ? a.blockContent.node.attrs : {} })) { const w = l.propSchema; b in w && !(w[b].default === void 0 && k === void 0) && (d[b] = k); } const u = t[a.blockNoteType], h = []; (g = a.childContainer) == null || g.node.forEach((b) => { h.push( E( b, n, t, o, r, s ) ); }); let f; if (u.content === "inline") { if (!a.isBlockContainer) throw new Error("impossible"); f = Ke( a.blockContent.node, o, r ); } else if (u.content === "table") { if (!a.isBlockContainer) throw new Error("impossible"); f = wn( a.blockContent.node, o, r ); } else if (u.content === "none") f = void 0; else throw new G(u.content); const m = { id: c, type: u.type, props: d, content: f, children: h }; return s == null || s.set(e, m), m; } function mr(e, n, t = vt(n), o = St(n), r = ke(n), s = Et(n)) { const i = []; return e.firstChild.descendants((a) => (i.push( E( a, n, t, o, r, s ) ), !1)), i; } function gr(e, n, t = vt(n), o = St(n), r = ke(n), s = Et(n)) { function i(a, c, l) { if (a.type.name !== "blockGroup") throw new Error("unexpected"); const d = []; let u, h; return a.forEach((f, m, g) => { if (f.type.name !== "blockContainer") throw new Error("unexpected"); if (f.childCount === 0) return; if (f.childCount === 0 || f.childCount > 2) throw new Error( "unexpected, blockContainer.childCount: " + f.childCount ); const b = g === 0, k = g === a.childCount - 1; if (f.firstChild.type.name === "blockGroup") { if (!b) throw new Error("unexpected"); const B = i( f.firstChild, Math.max(0, c - 1), k ? Math.max(0, l - 1) : 0 ); u = B.blockCutAtStart, k && (h = B.blockCutAtEnd), d.push(...B.blocks); return; } const w = E( f, n, t, o, r, s ), C = f.childCount > 1 ? f.child(1) : void 0; let y = []; if (C) { const B = i( C, 0, // TODO: can this be anything other than 0? k ? Math.max(0, l - 1) : 0 ); y = B.blocks, k && (h = B.blockCutAtEnd); } k && !C && l > 1 && (h = w.id), b && c > 1 && (u = w.id), d.push({ ...w, children: y }); }), { blocks: d, blockCutAtStart: u, blockCutAtEnd: h }; } if (e.content.childCount === 0) return { blocks: [], blockCutAtStart: void 0, blockCutAtEnd: void 0 }; if (e.content.childCount !== 1) throw new Error( "slice must be a single block, did you forget includeParents=true?" ); return i( e.content.firstChild, Math.max(e.openStart - 1, 0), Math.max(e.openEnd - 1, 0) ); } function Vt(e, n, t, o) { return e.dom.setAttribute("data-inline-content-type", n), Object.entries(t).filter(([r, s]) => { const i = o[r]; return s !== i.default; }).map(([r, s]) => [Fe(r), s]).forEach(([r, s]) => e.dom.setAttribute(r, s)), e.contentDOM !== void 0 && e.contentDOM.setAttribute("data-editable", ""), e; } function br(e) { return { Backspace: ({ editor: n }) => { const t = n.state.selection.$from; return n.state.selection.empty && t.node().type.name === e.type && t.parentOffset === 0; } }; } function kr(e, n) { return { config: e, implementation: n }; } function wr(e, n) { return kr( { type: e.name, propSchema: n, content: e.config.content === "inline*" ? "styled" : "none" }, { node: e } ); } function yn(e) { return Object.fromEntries( Object.entries(e).map(([n, t]) => [n, t.config]) ); } function yr(e) { return [ { tag: `[data-inline-content-type="${e.type}"]`, contentElement: (n) => { const t = n; return t.matches("[data-editable]") ? t : t.querySelector("[data-editable]") || t; } } ]; } function jc(e, n) { const t = oe.create({ name: e.type, inline: !0, group: "inline", selectable: e.content === "styled", atom: e.content === "none", content: e.content === "styled" ? "inline*" : "", addAttributes() { return xe(e.propSchema); }, addKeyboardShortcuts() { return br(e); }, parseHTML() { return yr(e); }, renderHTML({ node: o }) { const r = this.options.editor, s = n.render( lt( o, r.schema.inlineContentSchema, r.schema.styleSchema ), // TODO: fix cast () => { }, r ); return Vt( s, e.type, o.attrs, e.propSchema ); }, addNodeView() { return ({ node: o, getPos: r }) => { const s = this.options.editor, i = n.render( lt( o, s.schema.inlineContentSchema, s.schema.styleSchema ), // TODO: fix cast (a) => { if (typeof r == "boolean") return; const c = z([a], s.pmSchema); s.transact( (l) => l.replaceWith(r(), r() + o.nodeSize, c) ); }, s ); return Vt( i, e.type, o.attrs, e.propSchema ); }; } }); return wr( t, e.propSchema ); } function Cr(e) { return e === "boolean" ? {} : { stringValue: { default: void 0, keepOnSplit: !0, parseHTML: (n) => n.getAttribute("data-value"), renderHTML: (n) => n.stringValue !== void 0 ? { "data-value": n.stringValue } : {} } }; } function vr(e, n, t, o) { return e.dom.setAttribute("data-style-type", n), o === "string" && e.dom.setAttribute("data-value", t), e.contentDOM !== void 0 && e.contentDOM.setAttribute("data-editable", ""), e; } function Cn(e, n) { return { config: e, implementation: n }; } function ae(e, n) { return Cn( { type: e.name, propSchema: n }, { mark: e } ); } function vn(e) { return Object.fromEntries( Object.entries(e).map(([n, t]) => [n, t.config]) ); } function Sr(e) { return [ { tag: `[data-style-type="${e.type}"]`, contentElement: (n) => { const t = n; return t.matches("[data-editable]") ? t : t.querySelector("[data-editable]") || t; } } ]; } function Gc(e, n) { const t = re.create({ name: e.type, addAttributes() { return Cr(e.propSchema); }, parseHTML() { return Sr(e); }, renderHTML({ mark: o }) { let r; if (e.propSchema === "boolean") r = n.render(); else if (e.propSchema === "string") r = n.render(o.attrs.stringValue); else throw new G(e.propSchema); return vr( r, e.type, o.attrs.stringValue, e.propSchema ); } }); return Cn(e, { mark: t }); } function se(e) { const { height: n, width: t } = Bt(e), o = new Array(n).fill(!1).map(() => new Array(t).fill(null)), r = (s, i) => { for (let a = s; a < n; a++) for (let c = i; c < t; c++) if (!o[a][c]) return { row: a, col: c }; throw new Error( "Unable to create occupancy grid for table, no more available cells" ); }; for (let s = 0; s < e.content.rows.length; s++) for (let i = 0; i < e.content.rows[s].cells.length; i++) { const a = at(e.content.rows[s].cells[i]), c = ct(a), l = ve(a), { row: d, col: u } = r(s, i); for (let h = d; h < d + c; h++) for (let f = u; f < u + l; f++) { if (o[h][f]) throw new Error( `Unable to create occupancy grid for table, cell at ${h},${f} is already occupied` ); o[h][f] = { row: s, col: i, rowspan: c, colspan: l, cell: a }; } } return o; } function Se(e) { const n = /* @__PURE__ */ new Set(); return e.map((t) => ({ cells: t.map((o) => n.has(o.row + ":" + o.col) ? !1 : (n.add(o.row + ":" + o.col), o.cell)).filter((o) => o !== !1) })); } function he(e, n, t = se(n)) { for (let o = 0; o < t.length; o++) for (let r = 0; r < t[o].length; r++) { const s = t[o][r]; if (s.row === e.row && s.col === e.col) return { row: o, col: r, cell: s.cell }; } throw new Error( `Unable to resolve relative table cell indices for table, cell at ${e.row},${e.col} is not occupied` ); } function Bt(e) { const n = e.content.rows.length; let t = 0; return e.content.rows.forEach((o) => { let r = 0; o.cells.forEach((s) => { r += ve(s); }), t = Math.max(t, r); }), { height: n, width: t }; } function Sn(e, n, t = se(n)) { var r; const o = (r = t[e.row]) == null ? void 0 : r[e.col]; if (o) return { row: o.row, col: o.col, cell: o.cell }; } function dt(e, n) { var s; const t = se(e); if (n < 0 || n >= t.length) return []; let o = 0; for (let i = 0; i < n; i++) { const a = (s = t[o]) == null ? void 0 : s[0]; if (!a) return []; o += a.rowspan; } const r = new Array(t[0].length).fill(!1).map((i, a) => Sn( { row: o, col: a }, e, t )).filter( (i) => i !== void 0 ); return r.filter((i, a) => r.findIndex((c) => c.row === i.row && c.col === i.col) === a); } function ut(e, n) { var s; const t = se(e); if (n < 0 || n >= t[0].length) return []; let o = 0; for (let i = 0; i < n; i++) { const a = (s = t[0]) == null ? void 0 : s[o]; if (!a) return []; o += a.colspan; } const r = new Array(t.length).fill(!1).map((i, a) => Sn( { row: a, col: o }, e, t )).filter( (i) => i !== void 0 ); return r.filter((i, a) => r.findIndex((c) => c.row === i.row && c.col === i.col) === a); } function Er(e, n, t, o = se(e)) { const { col: r } = he( { row: 0, col: n }, e, o ), { col: s } = he( { row: 0, col: t }, e, o ); return o.forEach((i) => { const [a] = i.splice(r, 1); i.splice(s, 0, a); }), Se(o); } function Br(e, n, t, o = se(e)) { const { row: r } = he( { row: n, col: 0 }, e, o ), { row: s } = he( { row: t, col: 0 }, e, o ), [i] = o.splice(r, 1); return o.splice(s, 0, i), Se(o); } function ht(e) { return e ? Ce(e) ? ht(e.content) : typeof e == "string" ? e.length === 0 : Array.isArray(e) ? e.every( (n) => typeof n == "string" ? n.length === 0 : ue(n) ? n.text.length === 0 : fn(n) ? typeof n.content == "string" ? n.content.length === 0 : n.content.every((t) => t.text.length === 0) : !1 ) : !1 : !0; } function xr(e, n, t = se(e)) { if (n === "columns") { let s = 0; for (let i = t[0].length - 1; i >= 0 && t.every( (c) => ht(c[i].cell) && c[i].colspan === 1 ); i--) s++; for (let i = t.length - 1; i >= 0; i--) { const a = Math.max( t[i].length - s, 1 ); t[i] = t[i].slice(0, a); } return Se(t); } let o = 0; for (let s = t.length - 1; s >= 0 && t[s].every( (a) => ht(a.cell) && a.rowspan === 1 ); s--) o++; const r = Math.min(o, t.length - 1); return t.splice(t.length - r, r), Se(t); } function Mr(e, n, t, o = se(e)) { const { width: r, height: s } = Bt(e); if (n === "columns") o.forEach((i, a) => { if (t >= 0) for (let c = 0; c < t; c++) i.push({ row: a, col: Math.max(...i.map((l) => l.col)) + 1, rowspan: 1, colspan: 1, cell: at("") }); else i.splice(r + t, -1 * t); }); else if (t > 0) for (let i = 0; i < t; i++) { const a = new Array(r).fill(null).map((c, l) => ({ row: s + i, col: l, rowspan: 1, colspan: 1, cell: at("") })); o.push(a); } else t < 0 && o.splice(s + t, -1 * t); return Se(o); } function En(e, n, t) { const o = dt(e, t); if (!o.some((c) => ct(c.cell) > 1)) return !0; let s = t, i = t; return o.forEach((c) => { const l = ct(c.cell); s = Math.max(s, c.row + l - 1), i = Math.min(i, c.row); }), n < t ? t === s : t === i; } function Bn(e, n, t) { const o = ut(e, t); if (!o.some((c) => ve(c.cell) > 1)) return !0; let s = t, i = t; return o.forEach((c) => { const l = ve(c.cell); s = Math.max(s, c.col + l - 1), i = Math.min(i, c.col); }), n < t ? t === s : t === i; } function Pr(e, n, t) { const o = he(e, t), r = he(n, t); return o.col === r.col; } function _t(e, n, t, o) { const r = []; for (const [i, a] of Object.entries(e.styles || {})) { const c = t[i]; if (!c) throw new Error(`style ${i} not found in styleSchema`); if (c.propSchema === "boolean") a && r.push(n.mark(i)); else if (c.propSchema === "string") a && r.push(n.mark(i, { stringValue: a })); else throw new G(c.propSchema); } return !o || !n.nodes[o].spec.code ? e.text.split(/(\n)/g).filter((i) => i.length > 0).map((i) => i === ` ` ? n.nodes.hardBreak.createChecked() : n.text(i, r)) : e.text.length > 0 ? [n.text(e.text, r)] : []; } function Tr(e, n, t) { const o = n.marks.link.create({ href: e.href }); return pt(e.content, n, t).map( (r) => { if (r.type.name === "text") return r.mark([...r.marks, o]); if (r.type.name === "hardBreak") return r; throw new Error("unexpected node type"); } ); } function pt(e, n, t, o) { const r = []; if (typeof e == "string") return r.push( ..._t( { text: e, styles: {} }, n, t, o ) ), r; for (const s of e) r.push( ..._t(s, n, t, o) ); return r; } function z(e, n, t, o = ke(n)) { const r = []; for (const s of e) typeof s == "string" ? r.push( ...pt(s, n, o, t) ) : fn(s) ? r.push(...Tr(s, n, o)) : ue(s) ? r.push( ...pt([s], n, o, t) ) : r.push( xn(s, n, o) ); return r; } function Ye(e, n, t = ke(n)) { const o = [], r = new Array(e.headerRows ?? 0).fill(!0), s = new Array(e.headerCols ?? 0).fill(!0), i = e.columnWidths ?? []; for (let a = 0; a < e.rows.length; a++) { const c = e.rows[a], l = [], d = r[a]; for (let h = 0; h < c.cells.length; h++) { const f = c.cells[h], m = s[h], g = void 0; let b = null; const k = he( { row: a, col: h }, { content: e } ); let w = i[k.col] ? [i[k.col]] : null; if (f) if (typeof f == "string") b = n.text(f); else if (Ce(f)) { f.content && (b = z( f.content, n, "tableParagraph", t )); const y = ve(f); y > 1 && (w = new Array(y).fill(!1).map((B, K) => i[k.col + K] ?? void 0)); } else b = z( f, n, "tableParagraph", t ); const C = n.nodes[m || d ? "tableHeader" : "tableCell"].createChecked( { ...Ce(f) ? f.props : {}, colwidth: w }, n.nodes.tableParagraph.createChecked(g, b) ); l.push(C); } const u = n.nodes.tableRow.createChecked({}, l); o.push(u); } return o; } function xn(e, n, t) { let o, r = e.type; if (r === void 0 && (r = "paragraph"), !n.nodes[r]) throw new Error(`node type ${r} not found in schema`); if (!e.content) o = n.nodes[r].createChecked(e.props); else if (typeof e.content == "string") { const s = z( [e.content], n, r, t ); o = n.nodes[r].createChecked(e.props, s); } else if (Array.isArray(e.content)) { const s = z( e.content, n, r, t ); o = n.nodes[r].createChecked(e.props, s); } else if (e.content.type === "tableContent") { const s = Ye(e.content, n, t); o = n.nodes[r].createChecked(e.props, s); } else throw new G(e.content.type); return o; } function pe(e, n, t = ke(n)) { let o = e.id; o === void 0 && (o = Ge.options.generateID()); const r = []; if (e.children) for (const i of e.children) r.push(pe(i, n, t)); if (!e.type || // can happen if block.type is not defined (this should create the default node) n.nodes[e.type].isInGroup("blockContent")) { const i = xn( e, n, t ), a = r.length > 0 ? n.nodes.blockGroup.createChecked({}, r) : void 0; return n.nodes.blockContainer.createChecked( { id: o, ...e.props }, a ? [i, a] : i ); } else { if (n.nodes[e.type].isInGroup("bnBlock")) return n.nodes[e.type].createChecked( { id: o, ...e.props }, r ); throw new Error( `block type ${e.type} doesn't match blockContent or bnBlock group` ); } } function F(e, n) { let t, o; if (n.firstChild.descendants((r, s) => t ? !1 : !xt(r) || r.attrs.id !== e ? !0 : (t = r, o = s + 1, !1)), !(t === void 0 || o === void 0)) return { node: t, posBeforeNode: o }; } function xt(e) { return e.type.isInGroup("bnBlock"); } function Ir(e, n, t, o = "before") { const r = typeof t == "string" ? t : t.id, s = H(e), i = n.map( (d) => pe(d, s) ), a = F(r, e.doc); if (!a) throw new Error(`Block with ID ${r} not found`); let c = a.posBeforeNode; return o === "after" && (c += a.node.nodeSize), e.step( new dn(c, c, new X(R.from(i), 0, 0)) ), i.map( (d) => E(d, s) ); } function Ut(e, n, t) { const o = H(e), r = t.map( (d) => pe(d, o) ), s = new Set( n.map( (d) => typeof d == "string" ? d : d.id ) ), i = [], a = typeof n[0] == "string" ? n[0] : n[0].id; let c = 0; if (e.doc.descendants((d, u) => { if (s.size === 0) return !1; if (!d.type.isInGroup("bnBlock") || !s.has(d.attrs.id)) return !0; if (i.push(E(d, o)), s.delete(d.attrs.id), t.length > 0 && d.attrs.id === a) { const g = e.doc.nodeSize; e.insert(u, r); const b = e.doc.nodeSize; c += g - b; } const h = e.doc.nodeSize, f = e.doc.resolve(u - c); f.node().type.name === "blockGroup" && f.node(f.depth - 1).type.name !== "doc" && f.node().childCount === 1 ? e.delete(f.before(), f.after()) : e.delete(u - c, u - c + d.nodeSize); const m = e.doc.nodeSize; return c += h - m, !1; }), s.size > 0) { const d = [...s].join(` `); throw Error( "Blocks with the following IDs could not be found in the editor: " + d ); } return { insertedBlocks: r.map( (d) => E(d, o) ), removedBlocks: i }; } const O = (e, n) => ({ tr: t, dispatch: o }) => (o && Mn(t, e, n), !0); function Mn(e, n, t, o, r) { const s = Pe(e.doc.resolve(n)); let i = null; s.blockNoteType === "table" && (i = Nr(e)); const a = H(e); if (o !== void 0 && r !== void 0 && o > r) throw new Error("Invalid replaceFromPos or replaceToPos"); const c = a.nodes[s.blockNoteType], l = a.nodes[t.type || s.blockNoteType], d = l.isInGroup("bnBlock") ? l : a.nodes.blockContainer; if (s.isBlockContainer && l.isInGroup("blockContent")) { const u = o !== void 0 && o > s.blockContent.beforePos && o < s.blockContent.afterPos ? o - s.blockContent.beforePos - 1 : void 0, h = r !== void 0 && r > s.blockContent.beforePos && r < s.blockContent.afterPos ? r - s.blockContent.beforePos - 1 : void 0; $t(t, e, s), Lr( t, e, c, l, s, u, h ); } else if (!s.isBlockContainer && l.isInGroup("bnBlock")) $t(t, e, s); else { const u = E(s.bnBlock.node, a); e.replaceWith( s.bnBlock.beforePos, s.bnBlock.afterPos, pe( { children: u.children, // if no children are passed in, use existing children ...t }, a ) ); return; } e.setNodeMarkup(s.bnBlock.beforePos, d, { ...s.bnBlock.node.attrs, ...t.props }), i && Hr(e, s, i); } function Lr(e, n, t, o, r, s, i) { const a = H(n); let c = "keep"; if (e.content) if (typeof e.content == "string") c = z( [e.content], a, o.name ); else if (Array.isArray(e.content)) c = z(e.content, a, o.name); else if (e.content.type === "tableContent") c = Ye(e.content, a); else throw new G(e.content.type); else t.spec.content === "" || o.spec.content !== t.spec.content && (c = []); if (c === "keep") n.setNodeMarkup(r.blockContent.beforePos, o, { ...r.blockContent.node.attrs, ...e.props }); else if (s !== void 0 || i !== void 0) { n.setNodeMarkup(r.blockContent.beforePos, o, { ...r.blockContent.node.attrs, ...e.props }); const l = r.blockContent.beforePos + 1 + (s ?? 0), d = r.blockContent.beforePos + 1 + (i ?? r.blockContent.node.content.size), u = n.doc.resolve(r.blockContent.beforePos).depth, h = n.doc.resolve(l).depth, f = n.doc.resolve(d).depth; n.replace( l, d, new X( R.from(c), h - u - 1, f - u - 1 ) ); } else n.replaceWith( r.blockContent.beforePos, r.blockContent.afterPos, o.createChecked( { ...r.blockContent.node.attrs, ...e.props }, c ) ); } function $t(e, n, t) { const o = H(n); if (e.children !== void 0 && e.children.length > 0) { const r = e.children.map((s) => pe(s, o)); if (t.childContainer) n.step( new dn( t.childContainer.beforePos + 1, t.childContainer.afterPos - 1, new X(R.from(r), 0, 0) ) ); else { if (!t.isBlockContainer) throw new Error("impossible"); n.insert( t.blockContent.afterPos, o.nodes.blockGroup.createChecked({}, r) ); } } } function Ar(e, n, t, o, r) { const s = typeof n == "string" ? n : n.id, i = F(s, e.doc); if (!i) throw new Error(`Block with ID ${s} not found`); Mn( e, i.posBeforeNode, t, o, r ); const a = e.doc.resolve(i.posBeforeNode + 1).node(), c = H(e); return E(a, c); } function Nr(e) { const n = "selection" in e ? e.selection : null; if (!(n instanceof L)) return null; const t = e.doc.resolve(n.head); let o = -1, r = -1; for (let b = t.depth; b >= 0; b--) { const k = t.node(b).type.name; if (o < 0 && (k === "tableCell" || k === "tableHeader") && (o = b), k === "table") { r = b; break; } } if (o < 0 || r < 0) return null; const s = t.before(o), i = t.before(r), a = e.doc.nodeAt(i); if (!a || a.type.name !== "table") return null; const c = $e.get(a), l = s - (i + 1), d = c.map.indexOf(l); if (d < 0) return null; const u = Math.floor(d / c.width), h = d % c.width, m = s + 1 + 1, g = Math.max(0, n.head - m); return { row: u, col: h, offset: g }; } function Hr(e, n, t) { var b; if (n.blockNoteType !== "table") return !1; let o = -1; if (n.isBlockContainer) o = e.mapping.map(n.blockContent.beforePos); else { const k = e.mapping