@blocknote/core
Version:
A "Notion-style" block-based extensible text editor built on top of Prosemirror and Tiptap.
1,573 lines • 126 kB
JavaScript
var Oe = Object.defineProperty;
var Fe = (o, e, t) => e in o ? Oe(o, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : o[e] = t;
var h = (o, e, t) => Fe(o, typeof e != "symbol" ? e + "" : e, t);
import { Slice as N, Fragment as A, DOMSerializer as he, DOMParser as $e, Node as He } from "prosemirror-model";
import { ReplaceStep as Ve, ReplaceAroundStep as V } from "prosemirror-transform";
import { n as U, i as O, g as C, b as q, a as b, t as Ue, U as F, q as _, r as $, d as ze, s as Ge, u as Re, v as Y, w as B, x as me, y as je, z as ke, A as z } from "./blockToNode-BNoNIXU7.js";
import { B as ns, G as ss, C as rs, D as is, N as as, E as cs, O as ls, F as ds, H as us, I as ps, L as fs, J as hs, M as ms, K as ks } from "./blockToNode-BNoNIXU7.js";
import { ak as H, al as We, am as Ke, an as Je, aj as x, ao as qe, ap as Ye, a5 as Qe, a8 as G, aq as Xe, ar as Ze, a6 as et, as as Q, a9 as ge, at as tt } from "./defaultBlocks-DvCGYzqu.js";
import { aw as bs, av as ys, E as Ss, a as Bs, F as Cs, r as xs, N as Es, a4 as Ms, ad as ws, aG as Ts, ax as Ps, b as vs, d as Is, e as As, a0 as _s, aM as Ds, au as Ls, c as Ns, f as Os, ag as Fs, ah as $s, aB as Hs, x as Vs, y as Us, A as zs, z as Gs, g as Rs, h as js, T as Ws, j as Ks, k as Js, l as qs, n as Ys, o as Qs, q as Xs, s as Zs, w as er, aC as tr, aH as or, B as nr, C as sr, H as rr, I as ir, J as ar, K as cr, aE as lr, aI as dr, M as ur, D as pr, G as fr, S as hr, O as mr, Q as kr, W as gr, U as br, _ as yr, Z as Sr, a2 as Br, Y as Cr, X as xr, R as Er, $ as Mr, m as wr, aN as Tr, aK as Pr, az as vr, af as Ir, i as Ar, ay as _r, aD as Dr, ae as Lr, a7 as Nr, t as Or, u as Fr, v as $r, aJ as Hr, ai as Vr, aL as Ur, a1 as zr, V as Gr, p as Rr, a3 as jr, aF as Wr, L as Kr, aO as Jr, P as qr, aA as Yr } from "./defaultBlocks-DvCGYzqu.js";
import { j as ot, k as be, l as nt, m as st, n as rt, c as R, F as it, Y as at, a as ct, b as lt, S as dt, B as ye, D as ut, L as pt, N as ft, P as ht, g as mt, i as kt, H as gt, h as bt, e as yt, V as St, d as Bt } from "./TrailingNode-8cXFaQUm.js";
import { s as Ct, B as xt } from "./BlockNoteSchema-BOW16JHv.js";
import { C as Xr, b as Zr, c as ei, a as ti, g as oi, u as ni, w as si } from "./BlockNoteSchema-BOW16JHv.js";
import { Node as D, Extension as E, mergeAttributes as Et, Mark as X, extensions as I, isNodeSelection as Mt, posToDOMRect as wt, selectionToInsertionEnd as Tt, getSchema as Pt, createDocument as vt, Editor as It } from "@tiptap/core";
import { E as Se } from "./EventEmitter-CjSwpTbz.js";
import { Fragment as Z, Slice as ne } from "@tiptap/pm/model";
import { e as At } from "./en-njEqD7AG.js";
import { inputRules as _t, InputRule as Dt } from "@handlewithcare/prosemirror-inputrules";
import { keymap as Lt } from "@tiptap/pm/keymap";
import { c as Nt, o as Ot } from "./BlockNoteExtension-C2X7LW-V.js";
import { a as ii } from "./BlockNoteExtension-C2X7LW-V.js";
import { Gapcursor as Ft } from "@tiptap/extension-gapcursor";
import { Link as $t } from "@tiptap/extension-link";
import { Text as Ht } from "@tiptap/extension-text";
import { NodeSelection as L, TextSelection as M, Plugin as ee } from "prosemirror-state";
import { CellSelection as te, TableMap as se } from "prosemirror-tables";
import { S as Vt } from "./ShowSelection-Dz-NEase.js";
import Ut from "remark-gfm";
import zt from "remark-parse";
import Gt, { defaultHandlers as re } from "remark-rehype";
import Rt from "rehype-stringify";
import { unified as jt } from "unified";
import { TextSelection as Wt } from "@tiptap/pm/state";
function Kt(o, e) {
const t = [
{
tag: `[data-inline-content-type="${o.type}"]`,
contentElement: (n) => {
const s = n;
return s.matches("[data-editable]") ? s : s.querySelector("[data-editable]") || s;
}
}
];
return e && t.push({
tag: "*",
getAttrs(n) {
if (typeof n == "string")
return !1;
const s = e == null ? void 0 : e(n);
return s === void 0 ? !1 : s;
}
}), t;
}
function Qn(o, e) {
var n;
const t = D.create({
name: o.type,
inline: !0,
group: "inline",
draggable: (n = e.meta) == null ? void 0 : n.draggable,
selectable: o.content === "styled",
atom: o.content === "none",
content: o.content === "styled" ? "inline*" : "",
addAttributes() {
return Ke(o.propSchema);
},
addKeyboardShortcuts() {
return We(o);
},
parseHTML() {
return Kt(
o,
e.parse
);
},
renderHTML({ node: s }) {
const r = this.options.editor, i = e.render.call(
{ renderType: "dom", props: void 0 },
U(
s,
r.schema.inlineContentSchema,
r.schema.styleSchema
),
// TODO: fix cast
() => {
},
r
);
return H(
i,
o.type,
s.attrs,
o.propSchema
);
},
addNodeView() {
return (s) => {
const { node: r, getPos: i } = s, c = this.options.editor, a = e.render.call(
{ renderType: "nodeView", props: s },
U(
r,
c.schema.inlineContentSchema,
c.schema.styleSchema
),
// TODO: fix cast
(l) => {
const d = O([l], c.pmSchema), u = i();
u && c.transact(
(p) => p.replaceWith(u, u + r.nodeSize, d)
);
},
c
);
return H(
a,
o.type,
r.attrs,
o.propSchema
);
};
}
});
return Je(
t,
o.propSchema,
{
...e,
toExternalHTML: e.toExternalHTML,
render(s, r, i) {
const c = e.render(
s,
r,
i
);
return H(
c,
o.type,
s.props,
o.propSchema
);
}
}
);
}
function Jt(o, e, t, n = "before") {
const s = typeof t == "string" ? t : t.id, r = C(o), i = e.map(
(d) => q(d, r)
), c = x(s, o.doc);
if (!c)
throw new Error(`Block with ID ${s} not found`);
let a = c.posBeforeNode;
return n === "after" && (a += c.node.nodeSize), o.step(
new Ve(a, a, new N(A.from(i), 0, 0))
), i.map(
(d) => b(d, r)
);
}
function j(o) {
if (!o || o.type.name !== "column")
throw new Error("Invalid columnPos: does not point to column node.");
const e = o.firstChild;
if (!e)
throw new Error("Invalid column: does not have child node.");
const t = e.firstChild;
if (!t)
throw new Error("Invalid blockContainer: does not have child node.");
return o.childCount === 1 && e.childCount === 1 && t.type.name === "paragraph" && t.content.content.length === 0;
}
function qt(o, e) {
const t = o.doc.resolve(e), n = t.nodeAfter;
if (!n || n.type.name !== "columnList")
throw new Error(
"Invalid columnListPos: does not point to columnList node."
);
for (let s = n.childCount - 1; s >= 0; s--) {
const r = o.doc.resolve(t.pos + 1).posAtIndex(s), c = o.doc.resolve(r).nodeAfter;
if (!c || c.type.name !== "column")
throw new Error("Invalid columnPos: does not point to column node.");
j(c) && o.delete(r, r + c.nodeSize);
}
}
function W(o, e) {
qt(o, e);
const n = o.doc.resolve(e).nodeAfter;
if (!n || n.type.name !== "columnList")
throw new Error(
"Invalid columnListPos: does not point to columnList node."
);
if (n.childCount > 2)
return;
if (n.childCount < 2)
throw new Error("Invalid columnList: contains fewer than two children.");
const s = e + 1, i = o.doc.resolve(s).nodeAfter, c = e + n.nodeSize - 1, l = o.doc.resolve(c).nodeBefore;
if (!i || !l)
throw new Error("Invalid columnList: does not contain children.");
const d = j(i), u = j(l);
if (d && u) {
o.delete(e, e + n.nodeSize);
return;
}
if (d) {
o.step(
new V(
// Replaces `columnList`.
e,
e + n.nodeSize,
// Replaces with content of last `column`.
c - l.nodeSize + 1,
c - 1,
// Doesn't append anything.
N.empty,
0,
!1
)
);
return;
}
if (u) {
o.step(
new V(
// Replaces `columnList`.
e,
e + n.nodeSize,
// Replaces with content of first `column`.
s + 1,
s + i.nodeSize - 1,
// Doesn't append anything.
N.empty,
0,
!1
)
);
return;
}
}
function ie(o, e, t) {
const n = C(o), s = t.map(
(u) => q(u, n)
), r = new Set(
e.map(
(u) => typeof u == "string" ? u : u.id
)
), i = [], c = /* @__PURE__ */ new Set(), a = typeof e[0] == "string" ? e[0] : e[0].id;
let l = 0;
if (o.doc.descendants((u, p) => {
if (r.size === 0)
return !1;
if (!u.type.isInGroup("bnBlock") || !r.has(u.attrs.id))
return !0;
if (i.push(b(u, n)), r.delete(u.attrs.id), t.length > 0 && u.attrs.id === a) {
const g = o.doc.nodeSize;
o.insert(p, s);
const y = o.doc.nodeSize;
l += g - y;
}
const m = o.doc.nodeSize, f = o.doc.resolve(p - l);
f.node().type.name === "column" ? c.add(f.before(-1)) : f.node().type.name === "columnList" && c.add(f.before()), f.node().type.name === "blockGroup" && f.node(f.depth - 1).type.name !== "doc" && f.node().childCount === 1 ? o.delete(f.before(), f.after()) : o.delete(p - l, p - l + u.nodeSize);
const k = o.doc.nodeSize;
return l += m - k, !1;
}), r.size > 0) {
const u = [...r].join(`
`);
throw Error(
"Blocks with the following IDs could not be found in the editor: " + u
);
}
return c.forEach((u) => W(o, u)), { insertedBlocks: s.map(
(u) => b(u, n)
), removedBlocks: i };
}
function Yt(o, e, t, n, s) {
let r;
if (e)
if (typeof e == "string")
r = O([e], o.pmSchema, n);
else if (Array.isArray(e))
r = O(e, o.pmSchema, n);
else if (e.type === "tableContent")
r = Ue(e, o.pmSchema);
else
throw new F(e.type);
else throw new Error("blockContent is required");
const c = ((s == null ? void 0 : s.document) ?? document).createDocumentFragment();
for (const a of r)
if (a.type.name !== "text" && o.schema.inlineContentSchema[a.type.name]) {
const l = o.schema.inlineContentSpecs[a.type.name].implementation;
if (l) {
const d = U(
a,
o.schema.inlineContentSchema,
o.schema.styleSchema
), u = l.render.call(
{
renderType: "dom",
props: void 0
},
d,
() => {
},
o
);
if (u) {
if (c.appendChild(u.dom), u.contentDOM) {
const p = t.serializeFragment(
a.content,
s
);
u.contentDOM.dataset.editable = "", u.contentDOM.appendChild(p);
}
continue;
}
}
} else if (a.type.name === "text") {
let l = document.createTextNode(
a.textContent
);
for (const d of a.marks.toReversed())
if (d.type.name in o.schema.styleSpecs) {
const u = o.schema.styleSpecs[d.type.name].implementation.render(d.attrs.stringValue, o);
u.contentDOM.appendChild(l), l = u.dom;
} else {
const u = d.type.spec.toDOM(d, !0), p = he.renderSpec(document, u);
p.contentDOM.appendChild(l), l = p.dom;
}
c.appendChild(l);
} else {
const l = t.serializeFragment(
A.from([a]),
s
);
c.appendChild(l);
}
return c;
}
function Qt(o, e, t, n) {
var u, p, m, f, k;
const s = o.pmSchema.nodes.blockContainer, r = e.props || {};
for (const [g, y] of Object.entries(
o.schema.blockSchema[e.type].propSchema
))
!(g in r) && y.default !== void 0 && (r[g] = y.default);
const i = e.children || [], a = o.blockImplementations[e.type].implementation.render.call(
{
renderType: "dom",
props: void 0
},
{ ...e, props: r, children: i },
o
);
if (a.contentDOM && e.content) {
const g = Yt(
o,
e.content,
// TODO
t,
e.type,
n
);
a.contentDOM.appendChild(g);
}
if (o.pmSchema.nodes[e.type].isInGroup("bnBlock")) {
if (e.children && e.children.length > 0) {
const g = Be(
o,
e.children,
t,
n
);
(u = a.contentDOM) == null || u.append(g);
}
return a.dom;
}
const d = (m = (p = s.spec) == null ? void 0 : p.toDOM) == null ? void 0 : m.call(
p,
s.create({
id: e.id,
...r
})
);
return (f = d.contentDOM) == null || f.appendChild(a.dom), e.children && e.children.length > 0 && ((k = d.contentDOM) == null || k.appendChild(
Ce(o, e.children, t, n)
)), d.dom;
}
function Be(o, e, t, n) {
const r = ((n == null ? void 0 : n.document) ?? document).createDocumentFragment();
for (const i of e) {
const c = Qt(o, i, t, n);
r.appendChild(c);
}
return r;
}
const Ce = (o, e, t, n) => {
var c;
const s = o.pmSchema.nodes.blockGroup, r = s.spec.toDOM(s.create({})), i = Be(o, e, t, n);
return (c = r.contentDOM) == null || c.appendChild(i), r.dom;
}, Xt = (o, e) => {
const t = he.fromSchema(o);
return {
serializeBlocks: (n, s) => Ce(e, n, t, s).outerHTML
};
};
function Zt(o) {
return o.transact((e) => {
const t = _(e.doc, e.selection.anchor);
if (e.selection instanceof te)
return {
type: "cell",
anchorBlockId: t.node.attrs.id,
anchorCellOffset: e.selection.$anchorCell.pos - t.posBeforeNode,
headCellOffset: e.selection.$headCell.pos - t.posBeforeNode
};
if (e.selection instanceof L)
return {
type: "node",
anchorBlockId: t.node.attrs.id
};
{
const n = _(e.doc, e.selection.head);
return {
type: "text",
anchorBlockId: t.node.attrs.id,
headBlockId: n.node.attrs.id,
anchorOffset: e.selection.anchor - t.posBeforeNode,
headOffset: e.selection.head - n.posBeforeNode
};
}
});
}
function eo(o, e) {
var s, r;
const t = (s = x(e.anchorBlockId, o.doc)) == null ? void 0 : s.posBeforeNode;
if (t === void 0)
throw new Error(
`Could not find block with ID ${e.anchorBlockId} to update selection`
);
let n;
if (e.type === "cell")
n = te.create(
o.doc,
t + e.anchorCellOffset,
t + e.headCellOffset
);
else if (e.type === "node")
n = L.create(o.doc, t + 1);
else {
const i = (r = x(e.headBlockId, o.doc)) == null ? void 0 : r.posBeforeNode;
if (i === void 0)
throw new Error(
`Could not find block with ID ${e.headBlockId} to update selection`
);
n = M.create(
o.doc,
t + e.anchorOffset,
i + e.headOffset
);
}
o.setSelection(n);
}
function K(o) {
return o.map((e) => e.type === "columnList" ? e.children.map((t) => K(t.children)).flat() : {
...e,
children: K(e.children)
}).flat();
}
function xe(o, e, t) {
o.transact((n) => {
var i;
const s = ((i = o.getSelection()) == null ? void 0 : i.blocks) || [
o.getTextCursorPosition().block
], r = Zt(o);
o.removeBlocks(s), o.insertBlocks(K(s), e, t), eo(n, r);
});
}
function Ee(o) {
return !o || o.type !== "columnList";
}
function Me(o, e, t) {
let n, s;
if (e ? e.children.length > 0 ? (n = e.children[e.children.length - 1], s = "after") : (n = e, s = "before") : t && (n = t, s = "before"), !n || !s)
return;
const r = o.getParentBlock(n);
return Ee(r) ? { referenceBlock: n, placement: s } : Me(
o,
s === "after" ? n : o.getPrevBlock(n),
r
);
}
function we(o, e, t) {
let n, s;
if (e ? e.children.length > 0 ? (n = e.children[0], s = "before") : (n = e, s = "after") : t && (n = t, s = "after"), !n || !s)
return;
const r = o.getParentBlock(n);
return Ee(r) ? { referenceBlock: n, placement: s } : we(
o,
s === "before" ? n : o.getNextBlock(n),
r
);
}
function to(o) {
o.transact(() => {
const e = o.getSelection(), t = (e == null ? void 0 : e.blocks[0]) || o.getTextCursorPosition().block, n = Me(
o,
o.getPrevBlock(t),
o.getParentBlock(t)
);
n && xe(
o,
n.referenceBlock,
n.placement
);
});
}
function oo(o) {
o.transact(() => {
const e = o.getSelection(), t = (e == null ? void 0 : e.blocks[(e == null ? void 0 : e.blocks.length) - 1]) || o.getTextCursorPosition().block, n = we(
o,
o.getNextBlock(t),
o.getParentBlock(t)
);
n && xe(
o,
n.referenceBlock,
n.placement
);
});
}
function no(o, e, t) {
const { $from: n, $to: s } = o.selection, r = n.blockRange(
s,
(f) => f.childCount > 0 && (f.type.name === "blockGroup" || f.type.name === "column")
// change necessary to not look at first item child type
);
if (!r)
return !1;
const i = r.startIndex;
if (i === 0)
return !1;
const a = r.parent.child(i - 1);
if (a.type !== e)
return !1;
const l = a.lastChild && a.lastChild.type === t, d = A.from(l ? e.create() : null), u = new N(
A.from(
e.create(null, A.from(t.create(null, d)))
// change necessary to create "groupType" instead of parent.type
),
l ? 3 : 1,
0
), p = r.start, m = r.end;
return o.step(
new V(
p - (l ? 3 : 1),
m,
p,
m,
u,
1,
!0
)
).scrollIntoView(), !0;
}
function Te(o) {
return o.transact((e) => no(
e,
o.pmSchema.nodes.blockContainer,
o.pmSchema.nodes.blockGroup
));
}
function so(o) {
o._tiptapEditor.commands.liftListItem("blockContainer");
}
function ro(o) {
return o.transact((e) => {
const { bnBlock: t } = $(e);
return e.doc.resolve(t.beforePos).nodeBefore !== null;
});
}
function io(o) {
return o.transact((e) => {
const { bnBlock: t } = $(e);
return e.doc.resolve(t.beforePos).depth > 1;
});
}
function ao(o, e) {
const t = typeof e == "string" ? e : e.id, n = C(o), s = x(t, o);
if (s)
return b(s.node, n);
}
function co(o, e) {
const t = typeof e == "string" ? e : e.id, n = x(t, o), s = C(o);
if (!n)
return;
const i = o.resolve(n.posBeforeNode).nodeBefore;
if (i)
return b(i, s);
}
function lo(o, e) {
const t = typeof e == "string" ? e : e.id, n = x(t, o), s = C(o);
if (!n)
return;
const i = o.resolve(
n.posBeforeNode + n.node.nodeSize
).nodeAfter;
if (i)
return b(i, s);
}
function uo(o, e) {
const t = typeof e == "string" ? e : e.id, n = C(o), s = x(t, o);
if (!s)
return;
const r = o.resolve(s.posBeforeNode), i = r.node(), c = r.node(-1), a = c.type.name !== "doc" ? i.type.name === "blockGroup" ? c : i : void 0;
if (a)
return b(a, n);
}
class po {
constructor(e) {
this.editor = e;
}
/**
* Gets a snapshot of all top-level (non-nested) blocks in the editor.
* @returns A snapshot of all top-level (non-nested) blocks in the editor.
*/
get document() {
return this.editor.transact((e) => ze(e.doc, this.editor.pmSchema));
}
/**
* Gets a snapshot of an existing block from the editor.
* @param blockIdentifier The identifier of an existing block that should be
* retrieved.
* @returns The block that matches the identifier, or `undefined` if no
* matching block was found.
*/
getBlock(e) {
return this.editor.transact((t) => ao(t.doc, e));
}
/**
* Gets a snapshot of the previous sibling of an existing block from the
* editor.
* @param blockIdentifier The identifier of an existing block for which the
* previous sibling should be retrieved.
* @returns The previous sibling of the block that matches the identifier.
* `undefined` if no matching block was found, or it's the first child/block
* in the document.
*/
getPrevBlock(e) {
return this.editor.transact((t) => co(t.doc, e));
}
/**
* Gets a snapshot of the next sibling of an existing block from the editor.
* @param blockIdentifier The identifier of an existing block for which the
* next sibling should be retrieved.
* @returns The next sibling of the block that matches the identifier.
* `undefined` if no matching block was found, or it's the last child/block in
* the document.
*/
getNextBlock(e) {
return this.editor.transact((t) => lo(t.doc, e));
}
/**
* Gets a snapshot of the parent of an existing block from the editor.
* @param blockIdentifier The identifier of an existing block for which the
* parent should be retrieved.
* @returns The parent of the block that matches the identifier. `undefined`
* if no matching block was found, or the block isn't nested.
*/
getParentBlock(e) {
return this.editor.transact(
(t) => uo(t.doc, e)
);
}
/**
* Traverses all blocks in the editor depth-first, and executes a callback for each.
* @param callback The callback to execute for each block. Returning `false` stops the traversal.
* @param reverse Whether the blocks should be traversed in reverse order.
*/
forEachBlock(e, t = !1) {
const n = this.document.slice();
t && n.reverse();
function s(r) {
for (const i of r) {
if (e(i) === !1)
return !1;
const c = t ? i.children.slice().reverse() : i.children;
if (!s(c))
return !1;
}
return !0;
}
s(n);
}
/**
* Inserts new blocks into the editor. If a block's `id` is undefined, BlockNote generates one automatically. Throws an
* error if the reference block could not be found.
* @param blocksToInsert An array of partial blocks that should be inserted.
* @param referenceBlock An identifier for an existing block, at which the new blocks should be inserted.
* @param placement Whether the blocks should be inserted just before, just after, or nested inside the
* `referenceBlock`.
*/
insertBlocks(e, t, n = "before") {
return this.editor.transact(
(s) => Jt(s, e, t, n)
);
}
/**
* Updates an existing block in the editor. Since updatedBlock is a PartialBlock object, some fields might not be
* defined. These undefined fields are kept as-is from the existing block. Throws an error if the block to update could
* not be found.
* @param blockToUpdate The block that should be updated.
* @param update A partial block which defines how the existing block should be changed.
*/
updateBlock(e, t) {
return this.editor.transact((n) => qe(n, e, t));
}
/**
* Removes existing blocks from the editor. Throws an error if any of the blocks could not be found.
* @param blocksToRemove An array of identifiers for existing blocks that should be removed.
*/
removeBlocks(e) {
return this.editor.transact(
(t) => ie(t, e, []).removedBlocks
);
}
/**
* Replaces existing blocks in the editor with new blocks. If the blocks that should be removed are not adjacent or
* are at different nesting levels, `blocksToInsert` will be inserted at the position of the first block in
* `blocksToRemove`. Throws an error if any of the blocks to remove could not be found.
* @param blocksToRemove An array of blocks that should be replaced.
* @param blocksToInsert An array of partial blocks to replace the old ones with.
*/
replaceBlocks(e, t) {
return this.editor.transact(
(n) => ie(n, e, t)
);
}
/**
* Checks if the block containing the text cursor can be nested.
*/
canNestBlock() {
return ro(this.editor);
}
/**
* Nests the block containing the text cursor into the block above it.
*/
nestBlock() {
Te(this.editor);
}
/**
* Checks if the block containing the text cursor is nested.
*/
canUnnestBlock() {
return io(this.editor);
}
/**
* Lifts the block containing the text cursor out of its parent.
*/
unnestBlock() {
so(this.editor);
}
/**
* Moves the selected blocks up. If the previous block has children, moves
* them to the end of its children. If there is no previous block, but the
* current blocks share a common parent, moves them out of & before it.
*/
moveBlocksUp() {
return to(this.editor);
}
/**
* Moves the selected blocks down. If the next block has children, moves
* them to the start of its children. If there is no next block, but the
* current blocks share a common parent, moves them out of & after it.
*/
moveBlocksDown() {
return oo(this.editor);
}
}
class fo extends Se {
constructor(e) {
super(), this.editor = e, e.on("create", () => {
e._tiptapEditor.on(
"update",
({ transaction: t, appendedTransactions: n }) => {
this.emit("onChange", { editor: e, transaction: t, appendedTransactions: n });
}
), e._tiptapEditor.on("selectionUpdate", ({ transaction: t }) => {
this.emit("onSelectionChange", { editor: e, transaction: t });
}), e._tiptapEditor.on("mount", () => {
this.emit("onMount", { editor: e });
}), e._tiptapEditor.on("unmount", () => {
this.emit("onUnmount", { editor: e });
});
});
}
/**
* Register a callback that will be called when the editor changes.
*/
onChange(e, t = !0) {
const n = ({
transaction: s,
appendedTransactions: r
}) => {
!t && ae(s) || e(this.editor, {
getChanges() {
return ot(
s,
r
);
}
});
};
return this.on("onChange", n), () => {
this.off("onChange", n);
};
}
/**
* Register a callback that will be called when the selection changes.
*/
onSelectionChange(e, t = !1) {
const n = (s) => {
!t && ae(s.transaction) || e(this.editor);
};
return this.on("onSelectionChange", n), () => {
this.off("onSelectionChange", n);
};
}
/**
* Register a callback that will be called when the editor is mounted.
*/
onMount(e) {
return this.on("onMount", e), () => {
this.off("onMount", e);
};
}
/**
* Register a callback that will be called when the editor is unmounted.
*/
onUnmount(e) {
return this.on("onUnmount", e), () => {
this.off("onUnmount", e);
};
}
}
function ae(o) {
return !!o.getMeta("y-sync$");
}
function ho(o) {
return Array.prototype.indexOf.call(o.parentElement.childNodes, o);
}
function mo(o) {
return o.nodeType === 3 && !/\S/.test(o.nodeValue || "");
}
function ko(o) {
o.querySelectorAll("li > ul, li > ol").forEach((e) => {
const t = ho(e), n = e.parentElement, s = Array.from(n.childNodes).slice(
t + 1
);
e.remove(), s.forEach((r) => {
r.remove();
}), n.insertAdjacentElement("afterend", e), s.reverse().forEach((r) => {
if (mo(r))
return;
const i = document.createElement("li");
i.append(r), e.insertAdjacentElement("afterend", i);
}), n.childNodes.length === 0 && n.remove();
});
}
function go(o) {
o.querySelectorAll("li + ul, li + ol").forEach((e) => {
var r, i;
const t = e.previousElementSibling, n = document.createElement("div");
t.insertAdjacentElement("afterend", n), n.append(t);
const s = document.createElement("div");
for (s.setAttribute("data-node-type", "blockGroup"), n.append(s); ((r = n.nextElementSibling) == null ? void 0 : r.nodeName) === "UL" || ((i = n.nextElementSibling) == null ? void 0 : i.nodeName) === "OL"; )
s.append(n.nextElementSibling);
});
}
let ce = null;
function bo() {
return ce || (ce = document.implementation.createHTMLDocument("title"));
}
function yo(o) {
if (typeof o == "string") {
const e = bo().createElement("div");
e.innerHTML = o, o = e;
}
return ko(o), go(o), o;
}
function Pe(o, e) {
const t = yo(o), s = $e.fromSchema(e).parse(t, {
topNode: e.nodes.blockGroup.create()
}), r = [];
for (let i = 0; i < s.childCount; i++)
r.push(b(s.child(i), e));
return r;
}
function So(o, e) {
const t = e.value ? e.value : "", n = {};
e.lang && (n["data-language"] = e.lang);
let s = {
type: "element",
tagName: "code",
properties: n,
children: [{ type: "text", value: t }]
};
return e.meta && (s.data = { meta: e.meta }), o.patch(e, s), s = o.applyData(e, s), s = {
type: "element",
tagName: "pre",
properties: {},
children: [s]
}, o.patch(e, s), s;
}
function Bo(o, e) {
var r;
const t = String((e == null ? void 0 : e.url) || ""), n = e != null && e.title ? String(e.title) : void 0;
let s = {
type: "element",
tagName: "video",
properties: {
src: t,
"data-name": n,
"data-url": t,
controls: !0
},
children: []
};
return (r = o.patch) == null || r.call(o, e, s), s = o.applyData ? o.applyData(e, s) : s, s;
}
function ve(o) {
return jt().use(zt).use(Ut).use(Gt, {
handlers: {
...re,
image: (t, n) => {
const s = String((n == null ? void 0 : n.url) || "");
return Ye(s) ? Bo(t, n) : re.image(t, n);
},
code: So,
blockquote: (t, n) => {
const s = {
type: "element",
tagName: "blockquote",
properties: {},
// The only difference from the original is that we don't wrap the children with line endings
children: t.wrap(t.all(n), !1)
};
return t.patch(n, s), t.applyData(n, s);
}
}
}).use(Rt).processSync(o).value;
}
function Co(o, e) {
const t = ve(o);
return Pe(t, e);
}
class xo {
constructor(e) {
this.editor = e;
}
/**
* Exports blocks into a simplified HTML string. To better conform to HTML standards, children of blocks which aren't list
* items are un-nested in the output HTML.
*
* @param blocks An array of blocks that should be serialized into HTML.
* @returns The blocks, serialized as an HTML string.
*/
blocksToHTMLLossy(e = this.editor.document) {
return be(
this.editor.pmSchema,
this.editor
).exportBlocks(e, {});
}
/**
* Serializes blocks into an HTML string in the format that would normally be rendered by the editor.
*
* Use this method if you want to server-side render HTML (for example, a blog post that has been edited in BlockNote)
* and serve it to users without loading the editor on the client (i.e.: displaying the blog post)
*
* @param blocks An array of blocks that should be serialized into HTML.
* @returns The blocks, serialized as an HTML string.
*/
blocksToFullHTML(e = this.editor.document) {
return Xt(
this.editor.pmSchema,
this.editor
).serializeBlocks(e, {});
}
/**
* Parses blocks from an HTML string. Tries to create `Block` objects out of any HTML block-level elements, and
* `InlineNode` objects from any HTML inline elements, though not all element types are recognized. If BlockNote
* doesn't recognize an HTML element's tag, it will parse it as a paragraph or plain text.
* @param html The HTML string to parse blocks from.
* @returns The blocks parsed from the HTML string.
*/
tryParseHTMLToBlocks(e) {
return Pe(e, this.editor.pmSchema);
}
/**
* Serializes blocks into a Markdown string. The output is simplified as Markdown does not support all features of
* BlockNote - children of blocks which aren't list items are un-nested and certain styles are removed.
* @param blocks An array of blocks that should be serialized into Markdown.
* @returns The blocks, serialized as a Markdown string.
*/
blocksToMarkdownLossy(e = this.editor.document) {
return nt(e, this.editor.pmSchema, this.editor, {});
}
/**
* Creates a list of blocks from a Markdown string. Tries to create `Block` and `InlineNode` objects based on
* Markdown syntax, though not all symbols are recognized. If BlockNote doesn't recognize a symbol, it will parse it
* as text.
* @param markdown The Markdown string to parse blocks from.
* @returns The blocks parsed from the Markdown string.
*/
tryParseMarkdownToBlocks(e) {
return Co(e, this.editor.pmSchema);
}
/**
* Paste HTML into the editor. Defaults to converting HTML to BlockNote HTML.
* @param html The HTML to paste.
* @param raw Whether to paste the HTML as is, or to convert it to BlockNote HTML.
*/
pasteHTML(e, t = !1) {
var s;
let n = e;
if (!t) {
const r = this.tryParseHTMLToBlocks(e);
n = this.blocksToFullHTML(r);
}
n && ((s = this.editor.prosemirrorView) == null || s.pasteHTML(n));
}
/**
* Paste text into the editor. Defaults to interpreting text as markdown.
* @param text The text to paste.
*/
pasteText(e) {
var t;
return (t = this.editor.prosemirrorView) == null ? void 0 : t.pasteText(e);
}
/**
* Paste markdown into the editor.
* @param markdown The markdown to paste.
*/
pasteMarkdown(e) {
const t = ve(e);
return this.pasteHTML(t);
}
}
const oe = [
"vscode-editor-data",
"blocknote/html",
"text/markdown",
"text/html",
"text/plain",
"Files"
];
function Eo(o, e) {
if (!o.startsWith(".") || !e.startsWith("."))
throw new Error("The strings provided are not valid file extensions.");
return o === e;
}
function Mo(o, e) {
const t = o.split("/"), n = e.split("/");
if (t.length !== 2)
throw new Error(`The string ${o} is not a valid MIME type.`);
if (n.length !== 2)
throw new Error(`The string ${e} is not a valid MIME type.`);
return t[1] === "*" || n[1] === "*" ? t[0] === n[0] : (t[0] === "*" || n[0] === "*" || t[0] === n[0]) && t[1] === n[1];
}
function le(o, e, t, n = "after") {
let s;
return Array.isArray(e.content) && e.content.length === 0 ? s = o.updateBlock(e, t).id : s = o.insertBlocks(
[t],
e,
n
)[0].id, s;
}
async function Ie(o, e) {
var r;
if (!e.uploadFile) {
console.warn(
"Attempted ot insert file, but uploadFile is not set in the BlockNote editor options"
);
return;
}
const t = "dataTransfer" in o ? o.dataTransfer : o.clipboardData;
if (t === null)
return;
let n = null;
for (const i of oe)
if (t.types.includes(i)) {
n = i;
break;
}
if (n !== "Files")
return;
const s = t.items;
if (s) {
o.preventDefault();
for (let i = 0; i < s.length; i++) {
let c = "file";
for (const l of Object.values(e.schema.blockSpecs))
for (const d of ((r = l.implementation.meta) == null ? void 0 : r.fileBlockAccept) || []) {
const u = d.startsWith("."), p = s[i].getAsFile();
if (p && (!u && p.type && Mo(s[i].type, d) || u && Eo(
"." + p.name.split(".").pop(),
d
))) {
c = l.config.type;
break;
}
}
const a = s[i].getAsFile();
if (a) {
const l = {
type: c,
props: {
name: a.name
}
};
let d;
if (o.type === "paste") {
const m = e.getTextCursorPosition().block;
d = le(e, m, l);
} else if (o.type === "drop") {
const m = {
left: o.clientX,
top: o.clientY
}, f = e.prosemirrorView.posAtCoords(m);
if (!f)
return;
d = e.transact((k) => {
var S;
const g = _(k.doc, f.pos), y = (S = e.domElement) == null ? void 0 : S.querySelector(
`[data-id="${g.node.attrs.id}"]`
), T = y == null ? void 0 : y.getBoundingClientRect();
return le(
e,
e.getBlock(g.node.attrs.id),
l,
T && (T.top + T.bottom) / 2 > m.top ? "before" : "after"
);
});
} else
return;
const u = await e.uploadFile(a, d), p = typeof u == "string" ? {
props: {
url: u
}
} : { ...u };
e.updateBlock(d, p);
}
}
}
}
const wo = (o) => E.create({
name: "dropFile",
addProseMirrorPlugins() {
return [
new ee({
props: {
handleDOMEvents: {
drop(e, t) {
if (!o.isEditable)
return;
let n = null;
for (const s of oe)
if (t.dataTransfer.types.includes(s)) {
n = s;
break;
}
return n === null ? !0 : n === "Files" ? (Ie(t, o), !0) : !1;
}
}
}
})
];
}
}), To = /(^|\n) {0,3}#{1,6} {1,8}[^\n]{1,64}\r?\n\r?\n\s{0,32}\S/, Po = /(_|__|\*|\*\*|~~|==|\+\+)(?!\s)(?:[^\s](?:.{0,62}[^\s])?|\S)(?=\1)/, vo = /\[[^\]]{1,128}\]\(https?:\/\/\S{1,999}\)/, Io = /(?:\s|^)`(?!\s)(?:[^\s`](?:[^`]{0,46}[^\s`])?|[^\s`])`([^\w]|$)/, Ao = /(?:^|\n)\s{0,5}-\s{1}[^\n]+\n\s{0,15}-\s/, _o = /(?:^|\n)\s{0,5}\d+\.\s{1}[^\n]+\n\s{0,15}\d+\.\s/, Do = /\n{2} {0,3}-{2,48}\n{2}/, Lo = /(?:\n|^)(```|~~~|\$\$)(?!`|~)[^\s]{0,64} {0,64}[^\n]{0,64}\n[\s\S]{0,9999}?\s*\1 {0,64}(?:\n+|$)/, No = /(?:\n|^)(?!\s)\w[^\n]{0,64}\r?\n(-|=)\1{0,64}\n\n\s{0,64}(\w|$)/, Oo = /(?:^|(\r?\n\r?\n))( {0,3}>[^\n]{1,333}\n){1,999}($|(\r?\n))/, Fo = /^\s*\|(.+\|)+\s*$/m, $o = /^\s*\|(\s*[-:]+[-:]\s*\|)+\s*$/m, Ho = /^\s*\|(.+\|)+\s*$/m, Vo = (o) => To.test(o) || Po.test(o) || vo.test(o) || Io.test(o) || Ao.test(o) || _o.test(o) || Do.test(o) || Lo.test(o) || No.test(o) || Oo.test(o) || Fo.test(o) || $o.test(o) || Ho.test(o);
async function Uo(o, e) {
const { schema: t } = e.state;
if (!o.clipboardData)
return !1;
const n = o.clipboardData.getData("text/plain");
if (!n)
return !1;
if (!t.nodes.codeBlock)
return e.pasteText(n), !0;
const s = o.clipboardData.getData("vscode-editor-data"), r = s ? JSON.parse(s) : void 0, i = r == null ? void 0 : r.mode;
return i ? (e.pasteHTML(
`<pre><code class="language-${i}">${n.replace(
/\r\n?/g,
`
`
)}</code></pre>`
), !0) : !1;
}
function zo({
event: o,
editor: e,
prioritizeMarkdownOverHTML: t,
plainTextAsMarkdown: n
}) {
var c;
if (e.transact(
(a) => a.selection.$from.parent.type.spec.code && a.selection.$to.parent.type.spec.code
)) {
const a = (c = o.clipboardData) == null ? void 0 : c.getData("text/plain");
if (a)
return e.pasteText(a), !0;
}
let r;
for (const a of oe)
if (o.clipboardData.types.includes(a)) {
r = a;
break;
}
if (!r)
return !0;
if (r === "vscode-editor-data")
return Uo(o, e.prosemirrorView), !0;
if (r === "Files")
return Ie(o, e), !0;
const i = o.clipboardData.getData(r);
if (r === "blocknote/html")
return e.pasteHTML(i, !0), !0;
if (r === "text/markdown")
return e.pasteMarkdown(i), !0;
if (t) {
const a = o.clipboardData.getData("text/plain");
if (Vo(a))
return e.pasteMarkdown(a), !0;
}
return r === "text/html" ? (e.pasteHTML(i), !0) : n ? (e.pasteMarkdown(i), !0) : (e.pasteText(i), !0);
}
const Go = (o, e) => E.create({
name: "pasteFromClipboard",
addProseMirrorPlugins() {
return [
new ee({
props: {
handleDOMEvents: {
paste(t, n) {
if (n.preventDefault(), !!o.isEditable)
return e({
event: n,
editor: o,
defaultPasteHandler: ({
prioritizeMarkdownOverHTML: s = !0,
plainTextAsMarkdown: r = !0
} = {}) => zo({
event: n,
editor: o,
prioritizeMarkdownOverHTML: s,
plainTextAsMarkdown: r
})
});
}
}
}
})
];
}
});
function Ro(o, e, t) {
var c;
let n = !1;
const s = o.state.selection instanceof te;
if (!s) {
const a = o.state.doc.slice(
o.state.selection.from,
o.state.selection.to,
!1
).content, l = [];
for (let d = 0; d < a.childCount; d++)
l.push(a.child(d));
n = l.find(
(d) => d.type.isInGroup("bnBlock") || d.type.name === "blockGroup" || d.type.spec.group === "blockContent"
) === void 0, n && (e = a);
}
let r;
const i = be(
o.state.schema,
t
);
if (s) {
((c = e.firstChild) == null ? void 0 : c.type.name) === "table" && (e = e.firstChild.content);
const a = Ge(
e,
t.schema.inlineContentSchema,
t.schema.styleSchema
);
r = `<table>${i.exportInlineContent(
a,
{}
)}</table>`;
} else if (n) {
const a = Re(
e,
t.schema.inlineContentSchema,
t.schema.styleSchema
);
r = i.exportInlineContent(a, {});
} else {
const a = rt(e);
r = i.exportBlocks(a, {});
}
return r;
}
function Ae(o, e) {
"node" in o.state.selection && o.state.selection.node.type.spec.group === "blockContent" && e.transact(
(i) => i.setSelection(
new L(i.doc.resolve(o.state.selection.from - 1))
)
);
const t = o.serializeForClipboard(
o.state.selection.content()
).dom.innerHTML, n = o.state.selection.content().content, s = Ro(
o,
n,
e
), r = st(s);
return { clipboardHTML: t, externalHTML: s, markdown: r };
}
const de = () => {
const o = window.getSelection();
if (!o || o.isCollapsed)
return !0;
let e = o.focusNode;
for (; e; ) {
if (e instanceof HTMLElement && e.getAttribute("contenteditable") === "false")
return !0;
e = e.parentElement;
}
return !1;
}, ue = (o, e, t) => {
t.preventDefault(), t.clipboardData.clearData();
const { clipboardHTML: n, externalHTML: s, markdown: r } = Ae(
e,
o
);
t.clipboardData.setData("blocknote/html", n), t.clipboardData.setData("text/html", s), t.clipboardData.setData("text/plain", r);
}, jo = (o) => E.create({
name: "copyToClipboard",
addProseMirrorPlugins() {
return [
new ee({
props: {
handleDOMEvents: {
copy(e, t) {
return de() || ue(o, e, t), !0;
},
cut(e, t) {
return de() || (ue(o, e, t), e.editable && e.dispatch(e.state.tr.deleteSelection())), !0;
},
// This is for the use-case in which only a block without content
// is selected, e.g. an image block, and dragged (not using the
// drag handle).
dragstart(e, t) {
if (!("node" in e.state.selection) || e.state.selection.node.type.spec.group !== "blockContent")
return;
o.transact(
(i) => i.setSelection(
new L(
i.doc.resolve(e.state.selection.from - 1)
)
)
), t.preventDefault(), t.dataTransfer.clearData();
const { clipboardHTML: n, externalHTML: s, markdown: r } = Ae(e, o);
return t.dataTransfer.setData("blocknote/html", n), t.dataTransfer.setData("text/html", s), t.dataTransfer.setData("text/plain", r), !0;
}
}
}
})
];
}
}), Wo = E.create({
name: "blockBackgroundColor",
addGlobalAttributes() {
return [
{
types: ["tableCell", "tableHeader"],
attributes: {
backgroundColor: Qe()
}
}
];
}
}), Ko = D.create({
name: "hardBreak",
inline: !0,
group: "inline",
selectable: !1,
linebreakReplacement: !0,
priority: 10,
parseHTML() {
return [{ tag: "br" }];
},
renderHTML({ HTMLAttributes: o }) {
return ["br", Et(this.options.HTMLAttributes, o)];
},
renderText() {
return `
`;
}
}), J = (o, e) => {
const t = o.resolve(e), n = t.index();
if (n === 0)
return;
const s = t.posAtIndex(n - 1);
return Y(
o.resolve(s)
);
}, _e = (o, e) => {
for (; e.childContainer; ) {
const t = e.childContainer.node, n = o.resolve(e.childContainer.beforePos + 1).posAtIndex(t.childCount - 1);
e = Y(o.resolve(n));
}
return e;
}, Jo = (o, e) => o.isBlockContainer && o.blockContent.node.type.spec.content === "inline*" && o.blockContent.node.childCount > 0 && e.isBlockContainer && e.blockContent.node.type.spec.content === "inline*", qo = (o, e, t, n) => {
if (!n.isBlockContainer)
throw new Error(
`Attempted to merge block at position ${n.bnBlock.beforePos} into previous block at position ${t.bnBlock.beforePos}, but next block is not a block container`
);
if (n.childContainer) {
const s = o.doc.resolve(
n.childContainer.beforePos + 1
), r = o.doc.resolve(
n.childContainer.afterPos - 1
), i = s.blockRange(r);
if (e) {
const c = o.doc.resolve(n.bnBlock.beforePos);
o.tr.lift(i, c.depth);
}
}
if (e) {
if (!t.isBlockContainer)
throw new Error(
`Attempted to merge block at position ${n.bnBlock.beforePos} into previous block at position ${t.bnBlock.beforePos}, but previous block is not a block container`
);
e(
o.tr.delete(
t.blockContent.afterPos - 1,
n.blockContent.beforePos + 1
)
);
}
return !0;
}, pe = (o) => ({
state: e,
dispatch: t
}) => {
const n = e.doc.resolve(o), s = Y(n), r = J(
e.doc,
s.bnBlock.beforePos
);
if (!r)
return !1;
const i = _e(
e.doc,
r
);
return Jo(i, s) ? qo(e, t, i, s) : !1;
}, Yo = E.create({
priority: 50,
// TODO: The shortcuts need a refactor. Do we want to use a command priority
// design as there is now, or clump the logic into a single function?
addKeyboardShortcuts() {
const o = () => this.editor.commands.first(({ chain: n, commands: s }) => [
// Deletes the selection if it's not empty.
() => s.deleteSelection(),
// Undoes an input rule if one was triggered in the last editor state change.
() => s.undoInputRule(),
// Reverts block content type to a paragraph if the selection is at the start of the block.
() => s.command(({ state: r }) => {
const i = B(r);
if (!i.isBlockContainer)
return !1;
const c = r.selection.from === i.blockContent.beforePos + 1, a = i.blockContent.node.type.name === "paragraph";
return c && !a ? s.command(
Ze(i.bnBlock.beforePos, {
type: "paragraph",
props: {}
})
) : !1;
}),
// Removes a level of nesting if the block is indented if the selection is at the start of the block.
() => s.command(({ state: r }) => {
const i = B(r);
if (!i.isBlockContainer)
return !1;
const { blockContent: c } = i;
return r.selection.from === c.beforePos + 1 ? s.liftListItem("blockContainer") : !1;
}),
// Merges block with the previous one if it isn't indented, and the selection is at the start of the
// block. The target block for merging must contain inline content.
() => s.command(({ state: r }) => {
const i = B(r);
if (!i.isBlockContainer)
return !1;
const { bnBlock: c, blockContent: a } = i, l = r.selection.from === a.beforePos + 1, d = r.selection.empty, u = c.beforePos;
return l && d ? n().command(pe(u)).scrollIntoView().run() : !1;
}),
() => s.command(({ state: r, tr: i, dispatch: c }) => {
const a = B(r);
if (!a.isBlockContainer || !(i.selection.from === a.blockContent.beforePos + 1))
return !1;
const d = i.doc.resolve(a.bnBlock.beforePos);
if (d.nodeBefore || d.node().type.name !== "column")
return !1;
const m = i.doc.resolve(a.bnBlock.beforePos), f = i.doc.resolve(m.before()), k = f.before();
if (c) {
const g = i.doc.slice(
a.bnBlock.beforePos,
a.bnBlock.afterPos
).content;
i.delete(
a.bnBlock.beforePos,
a.bnBlock.afterPos
), f.index() === 0 ? (W(i, k), i.insert(k, g), i.setSelection(
M.near(i.doc.resolve(k))
)) : (i.insert(f.pos - 1, g), i.setSelection(
M.near(i.doc.resolve(f.pos - 1))
), W(i, k));
}
return !0;
}),
// Deletes the current block if it's an empty block with inline content,
// and moves the selection to the previous block.
() => s.command(({ state: r }) => {
const i = B(r);
if (!i.isBlockContainer)
return !1;
if (i.blockContent.node.childCount === 0 && i.blockContent.node.type.spec.content === "inline*") {
const a = J(
r.doc,
i.bnBlock.beforePos
);
if (!a || !a.isBlockContainer)
return !1;
let l = n();
if (a.blockContent.node.type.spec.content === "tableRow+") {
const f = i.bnBlock.beforePos - 1 - 1 - 1 - 1 - 1;
l = l.setTextSelection(
f
);
} else if (a.blockContent.node.type.spec.content === "") {
const d = a.blockContent.afterPos - a.blockContent.node.nodeSize;
l = l.setNodeSelection(
d
);
} else {
const d = a.blockContent.afterPos - a.blockContent.node.nodeSize;
l = l.setTextSelection(d);
}
return l.deleteRange({
from: i.bnBlock.beforePos,
to: i.bnBlock.afterPos
}).scrollIntoView().run();
}
return !1;
}),
// Deletes previous block if it contains no content and isn't a table,
// when the selection is empty and at the start of the block. Moves the
// current block into the deleted block's place.
() => s.command(({ state: r }) => {
const i = B(r);
if (!i.isBlockContainer)
throw new Error("todo");
const c = r.selection.from === i.blockContent.beforePos + 1, a = r.selection.empty, l = J(
r.doc,
i.bnBlock.beforePos
);
if (l && c && a) {
const d = _e(
r.doc,
l
);
if (!d.isBlockC