UNPKG

@blocknote/core

Version:

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

1,810 lines 316 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 J, Fragment as R, DOMSerializer as ln, DOMParser as Se, Node as uo } from "prosemirror-model"; import { ReplaceStep as dn, ReplaceAroundStep as ot, Mapping as po } from "prosemirror-transform"; import { Extension as _, combineTransactionSteps as un, getChangedRanges as ho, findChildrenInRange as fo, Node as oe, Mark as re, isTextSelection as pn, InputRule as le, callOrReturn as mo, getExtensionField as go, mergeAttributes as gt, selectionToInsertionEnd as bo, isNodeSelection as rt, posToDOMRect as Ue, getMarkRange as At, findChildren as Nt, findParentNode as ko, extensions as we, Editor as wo, createDocument as yo, getSchema as Co } from "@tiptap/core"; import { Plugin as L, PluginKey as U, TextSelection as O, NodeSelection as be, Selection as Ve, EditorState as vo } from "prosemirror-state"; import { v4 as hn } from "uuid"; import { createHighlightPlugin as Eo } from "prosemirror-highlight"; import { createParser as So } from "prosemirror-highlight/shiki"; import Bo from "@tiptap/extension-bold"; import xo from "@tiptap/extension-code"; import To from "@tiptap/extension-italic"; import Mo from "@tiptap/extension-strike"; import Po from "@tiptap/extension-underline"; import { TableCell as Io } from "@tiptap/extension-table-cell"; import { TableHeader as Lo } from "@tiptap/extension-table-header"; import { goToNextCell as Ht, columnResizing as Ao, tableEditing as No, TableView as Ho, CellSelection as Be, TableMap as Dt, addRowBefore as Do, addRowAfter as Oo, addColumnBefore as Ro, addColumnAfter as Vo, deleteRow as _o, deleteColumn as Uo, mergeCells as $o, splitCell as Fo } from "prosemirror-tables"; import { Gapcursor as zo } from "@tiptap/extension-gapcursor"; import { History as Wo } from "@tiptap/extension-history"; import { Link as jo } from "@tiptap/extension-link"; import { Text as Go } from "@tiptap/extension-text"; import { yCursorPlugin as qo, defaultSelectionBuilder as Ko, ySyncPlugin as Yo, yUndoPlugin as Jo, ySyncPluginKey as de, getRelativeSelection as Xo, absolutePositionToRelativePosition as Zo, relativePositionToAbsolutePosition as Qo, yUndoPluginKey as Ae, yCursorPluginKey as er, undoCommand as tr, redoCommand as nr } from "y-prosemirror"; import { DecorationSet as G, Decoration as X, EditorView as or } from "prosemirror-view"; import * as ie from "yjs"; import { undo as rr, redo as sr } from "prosemirror-history"; import { dropCursor as ir } from "prosemirror-dropcursor"; import { e as ar } from "./en-Dx9fwHD4.js"; function cr(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 lr(e) { const n = e.filter( (o, r) => e.indexOf(o) !== r ); return cr(n); } const je = _.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 hn(); }, 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 L({ 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 (ho(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 = lr(b); g.forEach(({ node: w, pos: y }) => { let v; const N = (v = a.doc.nodeAt(y)) === null || v === void 0 ? void 0 : v.attrs[l]; if (N === null) { const E = o.doc.type.createAndFill().content; if (o.doc.content.findDiffStart(E) === null) { const x = JSON.parse( JSON.stringify(r.doc.toJSON()) ); if (x.content[0].content[0].attrs.id = "initialBlockId", JSON.stringify(x.content) === JSON.stringify(E.toJSON())) { a.setNodeMarkup(y, void 0, { ...w.attrs, [l]: "initialBlockId" }); return; } } a.setNodeMarkup(y, void 0, { ...w.attrs, [l]: d() }); return; } const { deleted: z } = h.invert().mapResult(y); z && k.includes(N) && a.setNodeMarkup(y, 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 J( 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 st(e) { var n, t, o, r, s; return bt(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 bt(e) { return Ce(e) && e.props !== void 0 && e.content !== void 0; } function ve(e) { return bt(e) ? e.props.colspan ?? 1 : 1; } function it(e) { return bt(e) ? e.props.rowspan ?? 1 : 1; } class q extends Error { constructor(n) { super(`Unreachable case: ${n}`); } } function Vc(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 dr = () => typeof navigator < "u" && (/Mac/.test(navigator.platform) || /AppleWebKit/.test(navigator.userAgent) && /Mobile\/\w+/.test(navigator.userAgent)); function Y(e, n = "Ctrl") { return dr() ? 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 _c = () => /^((?!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 = he(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 ur(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 M = { backgroundColor: { default: "default" }, textColor: { default: "default" }, textAlignment: { default: "left", values: ["left", "center", "right", "justify"] } }, mn = ["backgroundColor", "textColor"]; function $e(e) { return "data-" + e.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase(); } function Uc(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($e(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 ? { [$e(t)]: r[t] } : {} }; }), n; } function kt(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($e(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 K(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 hr(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 Te(e, n) { const t = K({ name: e.type, content: e.content === "inline" ? "inline*" : "", group: "blockContent", selectable: e.isSelectable ?? !0, isolating: !0, addAttributes() { return xe(e.propSchema); }, parseHTML() { return hr(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 = kt( 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 wt(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 wt(e.node, e.posBeforeNode); } function Me(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 wt(e.nodeAfter, e.pos); } function C(e) { const n = Z(e.doc, e.selection.anchor); return ne(n); } function Ge(e) { const n = Z(e.doc, e.selection.anchor); return ne(n); } function A(e) { return "doc" in e ? e.doc.type.schema : e.type.schema; } function kn(e) { return e.cached.blockNoteEditor; } function Pe(e) { return kn(e).schema; } function yt(e) { return Pe(e).blockSchema; } function Ct(e) { return Pe(e).inlineContentSchema; } function ke(e) { return Pe(e).styleSchema; } function vt(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) => qe(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 qe(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( at(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 q(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 at(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 = qe( e, n, t ) : s = void 0, { type: e.type.name, props: o, content: s }; } function S(e, n, t = yt(n), o = Ct(n), r = ke(n), s = vt(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 = wt(e, 0); let c = a.bnBlock.node.attrs.id; c === null && (c = je.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( S( b, n, t, o, r, s ) ); }); let f; if (u.content === "inline") { if (!a.isBlockContainer) throw new Error("impossible"); f = qe( 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 q(u.content); const m = { id: c, type: u.type, props: d, content: f, children: h }; return s == null || s.set(e, m), m; } function fr(e, n, t = yt(n), o = Ct(n), r = ke(n), s = vt(n)) { const i = []; return e.firstChild.descendants((a) => (i.push( S( a, n, t, o, r, s ) ), !1)), i; } function mr(e, n, t = yt(n), o = Ct(n), r = ke(n), s = vt(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 N = i( f.firstChild, Math.max(0, c - 1), k ? Math.max(0, l - 1) : 0 ); u = N.blockCutAtStart, k && (h = N.blockCutAtEnd), d.push(...N.blocks); return; } const w = S( f, n, t, o, r, s ), y = f.childCount > 1 ? f.child(1) : void 0; let v = []; if (y) { const N = i( y, 0, // TODO: can this be anything other than 0? k ? Math.max(0, l - 1) : 0 ); v = N.blocks, k && (h = N.blockCutAtEnd); } k && !y && l > 1 && (h = w.id), b && c > 1 && (u = w.id), d.push({ ...w, children: v }); }), { 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]) => [$e(r), s]).forEach(([r, s]) => e.dom.setAttribute(r, s)), e.contentDOM !== void 0 && e.contentDOM.setAttribute("data-editable", ""), e; } function gr(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 br(e, n) { return { config: e, implementation: n }; } function kr(e, n) { return br( { 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 wr(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 $c(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 gr(e); }, parseHTML() { return wr(e); }, renderHTML({ node: o }) { const r = this.options.editor, s = n.render( at( 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( at( o, s.schema.inlineContentSchema, s.schema.styleSchema ), // TODO: fix cast (a) => { if (typeof r == "boolean") return; const c = W([a], s.pmSchema); s.transact( (l) => l.replaceWith(r(), r() + o.nodeSize, c) ); }, s ); return Vt( i, e.type, o.attrs, e.propSchema ); }; } }); return kr( t, e.propSchema ); } function yr(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 Cr(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 vr(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 Fc(e, n) { const t = re.create({ name: e.type, addAttributes() { return yr(e.propSchema); }, parseHTML() { return vr(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 q(e.propSchema); return Cr( r, e.type, o.attrs.stringValue, e.propSchema ); } }); return Cn(e, { mark: t }); } function se(e) { const { height: n, width: t } = Et(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 = st(e.content.rows[s].cells[i]), c = it(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 Ee(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 pe(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 Et(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 En(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 ct(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) => En( { 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 lt(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) => En( { 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 } = pe( { row: 0, col: n }, e, o ), { col: s } = pe( { row: 0, col: t }, e, o ); return o.forEach((i) => { const [a] = i.splice(r, 1); i.splice(s, 0, a); }), Ee(o); } function Sr(e, n, t, o = se(e)) { const { row: r } = pe( { row: n, col: 0 }, e, o ), { row: s } = pe( { row: t, col: 0 }, e, o ), [i] = o.splice(r, 1); return o.splice(s, 0, i), Ee(o); } function dt(e) { return e ? Ce(e) ? dt(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 Br(e, n, t = se(e)) { if (n === "columns") { let s = 0; for (let i = t[0].length - 1; i >= 0 && t.every( (c) => dt(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 Ee(t); } let o = 0; for (let s = t.length - 1; s >= 0 && t[s].every( (a) => dt(a.cell) && a.rowspan === 1 ); s--) o++; const r = Math.min(o, t.length - 1); return t.splice(t.length - r, r), Ee(t); } function xr(e, n, t, o = se(e)) { const { width: r, height: s } = Et(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: st("") }); 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: st("") })); o.push(a); } else t < 0 && o.splice(s + t, -1 * t); return Ee(o); } function Sn(e, n, t) { const o = ct(e, t); if (!o.some((c) => it(c.cell) > 1)) return !0; let s = t, i = t; return o.forEach((c) => { const l = it(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 = lt(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 Tr(e, n, t) { const o = pe(e, t), r = pe(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 q(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 Mr(e, n, t) { const o = n.marks.link.create({ href: e.href }); return ut(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 ut(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 W(e, n, t, o = ke(n)) { const r = []; for (const s of e) typeof s == "string" ? r.push( ...ut(s, n, o, t) ) : fn(s) ? r.push(...Mr(s, n, o)) : ue(s) ? r.push( ...ut([s], n, o, t) ) : r.push( xn(s, n, o) ); return r; } function Ke(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 = pe( { 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 = W( f.content, n, "tableParagraph", t )); const v = ve(f); v > 1 && (w = new Array(v).fill(!1).map((N, z) => i[k.col + z] ?? void 0)); } else b = W( f, n, "tableParagraph", t ); const y = n.nodes[m || d ? "tableHeader" : "tableCell"].createChecked( { ...Ce(f) ? f.props : {}, colwidth: w }, n.nodes.tableParagraph.createChecked(g, b) ); l.push(y); } 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 = W( [e.content], n, r, t ); o = n.nodes[r].createChecked(e.props, s); } else if (Array.isArray(e.content)) { const s = W( e.content, n, r, t ); o = n.nodes[r].createChecked(e.props, s); } else if (e.content.type === "tableContent") { const s = Ke(e.content, n, t); o = n.nodes[r].createChecked(e.props, s); } else throw new q(e.content.type); return o; } function he(e, n, t = ke(n)) { let o = e.id; o === void 0 && (o = je.options.generateID()); const r = []; if (e.children) for (const i of e.children) r.push(he(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 Pr(e, n) { if (n === 0) return; const t = e.resolve(n); for (let o = t.depth; o > 0; o--) { const r = t.node(o); if (St(r)) return r.attrs.id; } } function F(e, n) { let t, o; if (n.firstChild.descendants((r, s) => t ? !1 : !St(r) || r.attrs.id !== e ? !0 : (t = r, o = s + 1, !1)), !(t === void 0 || o === void 0)) return { node: t, posBeforeNode: o }; } function St(e) { return e.type.isInGroup("bnBlock"); } function Ir(e, n) { return e.id !== n.id || e.type !== n.type || JSON.stringify(e.props) !== JSON.stringify(n.props) || JSON.stringify(e.content) !== JSON.stringify(n.content); } function Lr(e) { return e.getMeta("paste") ? { type: "paste" } : e.getMeta("uiEvent") === "drop" ? { type: "drop" } : e.getMeta("history$") ? { type: e.getMeta("history$").redo ? "redo" : "undo" } : e.getMeta("y-sync$") ? e.getMeta("y-sync$").isUndoRedoOperation ? { type: "undo-redo" } : { type: "yjs-remote" } : { type: "local" }; } function Ut(e) { const n = {}, t = A(e); return e.descendants((o, r) => { if (St(o)) { const s = Pr(e, r); n[o.attrs.id] = { block: S(o, t), parentId: s }; } return !0; }), n; } function Tn(e, n = []) { const t = Lr(e), o = un(e.before, [ e, ...n ]), r = Ut( o.before ), s = Ut( o.doc ), i = []; return Object.keys(s).filter((a) => !(a in r)).forEach((a) => { i.push({ type: "insert", block: s[a].block, source: t, prevBlock: void 0 }); }), Object.keys(r).filter((a) => !(a in s)).forEach((a) => { i.push({ type: "delete", block: r[a].block, source: t, prevBlock: void 0 }); }), Object.keys(s).filter((a) => a in r).forEach((a) => { var u, h; const c = r[a], l = s[a]; c.parentId !== l.parentId ? i.push({ type: "move", block: l.block, prevBlock: c.block, source: t, prevParent: c.parentId ? (u = r[c.parentId]) == null ? void 0 : u.block : void 0, currentParent: l.parentId ? (h = s[l.parentId]) == null ? void 0 : h.block : void 0 }) : Ir(c.block, l.block) && i.push({ type: "update", block: l.block, prevBlock: c.block, source: t }); }), i; } function Ar(e, n, t, o = "before") { const r = typeof t == "string" ? t : t.id, s = A(e), i = n.map( (d) => he(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 J(R.from(i), 0, 0)) ), i.map( (d) => S(d, s) ); } function $t(e, n, t) { const o = A(e), r = t.map( (d) => he(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(S(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) => S(d, o) ), removedBlocks: i }; } const D = (e, n) => ({ tr: t, dispatch: o }) => (o && Mn(t, e, n), !0); function Mn(e, n, t, o, r) { const s = Me(e.doc.resolve(n)), i = A(e); if (o !== void 0 && r !== void 0 && o > r) throw new Error("Invalid replaceFromPos or replaceToPos"); const a = i.nodes[s.blockNoteType], c = i.nodes[t.type || s.blockNoteType], l = c.isInGroup("bnBlock") ? c : i.nodes.blockContainer; if (s.isBlockContainer && c.isInGroup("blockContent")) { const d = o !== void 0 && o > s.blockContent.beforePos && o < s.blockContent.afterPos ? o - s.blockContent.beforePos - 1 : void 0, u = r !== void 0 && r > s.blockContent.beforePos && r < s.blockContent.afterPos ? r - s.blockContent.beforePos - 1 : void 0; Ft(t, e, s), Nr( t, e, a, c, s, d, u ); } else if (!s.isBlockContainer && c.isInGroup("bnBlock")) Ft(t, e, s); else { const d = S(s.bnBlock.node, i); e.replaceWith( s.bnBlock.beforePos, s.bnBlock.afterPos, he( { children: d.children, // if no children are passed in, use existing children ...t }, i ) ); return; } e.setNodeMarkup(s.bnBlock.beforePos, l, { ...s.bnBlock.node.attrs, ...t.props }); } function Nr(e, n, t, o, r, s, i) { const a = A(n); let c = "keep"; if (e.content) if (typeof e.content == "string") c = W( [e.content], a, o.name ); else if (Array.isArray(e.content)) c = W(e.content, a, o.name); else if (e.content.type === "tableContent") c = Ke(e.content, a); else throw new q(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 J( R.from(c), h - u - 1, f - u - 1 ) ); } else n.replaceWith( r.blockContent.beforePos, r.blockContent.afterPos, o.createChecked( { ...r.blockContent.no