edix
Version:
An experimental, type-safe, framework agnostic and small (5kB+) contenteditable state manager.
814 lines (791 loc) • 28.5 kB
JavaScript
const t = Math.min, {keys: e, is: n} = Object, r = t => "string" == typeof t, o = t => "function" == typeof t, s = o(queueMicrotask) ? queueMicrotask : t => {
Promise.resolve().then(t);
}, i = (e, n) => {
const r = t(e.length, n.length);
for (let t = 0; t < r; t++) {
const r = e[t], o = n[t];
if (r < o) return -1;
if (r > o) return 1;
}
return 0;
}, c = ([t, e], [n, r]) => {
const o = i(t, n);
return 0 === o ? e === r ? 0 : e < r ? -1 : 1 : o;
}, l = ([t, e]) => 1 === c(t, e) ? [ e, t ] : [ t, e ], u = (t, e = t => k(t) ? t.text : "") => t.children.reduce((t, n, r) => {
const o = w(n);
return 0 !== r && o && (t += "\n"), t + (o ? n.children.reduce((t, n) => t + e(n), "") : "");
}, ""), f = (t, e, n) => t.split("\n").map(t => ({
...n,
children: [ {
...e,
text: t
} ]
})), a = "delete", d = "insert_text", h = "insert_node", p = "set_attr", y = "set_node_attr", g = ({type: t}) => t === h || t === p || t === y;
class m {
t;
constructor(t) {
this.t = t ? t.slice() : [];
}
get ops() {
return this.t;
}
insertText(t, e) {
return this.t.push({
type: d,
at: t,
text: e
}), this;
}
insertFragment(t, e) {
return this.t.push({
type: h,
at: t,
fragment: e
}), this;
}
delete(t, e) {
return this.t.push({
type: a,
start: t,
end: e
}), this;
}
format(t, e, n, r) {
return this.t.push({
type: p,
start: t,
end: e,
key: n,
value: r
}), this;
}
attr(t, e, n) {
return this.t.push({
type: y,
path: t,
key: e,
value: n
}), this;
}
transform(t) {
return this.t.reduce((t, e) => B(t, e), t);
}
}
const k = t => "text" in t, w = t => "children" in t, b = (t, r) => {
const o = e(t);
return o.length === e(r).length && o.every(e => e in r && ("text" === e || n(t[e], r[e])));
}, x = t => w(t) ? t.children.reduce((t, e) => t + x(e), 0) : k(t) ? t.text.length : 1, _ = (t, e = 0, n = t.length - 1) => {
let r = e + 1;
for (;r <= n; ) {
const e = t[r - 1], o = t[r];
k(e) && k(o) && b(e, o) ? (t[r - 1] = {
...e,
text: e.text + o.text
}, t.splice(r, 1), n--) : r++;
}
for (r = e; r <= n; ) {
const e = t[r];
k(e) && !e.text && t.length > 1 ? (t.splice(r, 1), n--) : r++;
}
}, v = (t, e = 0, n = t.length - 1) => {
let r = e + 1;
for (;r <= n; ) {
const e = t[r - 1], o = t[r];
t[r - 1] = E(e, o), t.splice(r, 1), n--;
}
}, D = (t, e, n) => {
if (e.length) {
const r = t.length;
t.push(...e), r && n(t, r - 1, r);
}
}, E = (...t) => ({
...t[0],
children: t.reduce((t, e) => (D(t, e.children, _), t), [])
}), M = ({children: t}, e) => {
for (let n = 0; n < t.length; n++) {
const r = t[n], o = x(r);
if (o > e) return {
o: r,
i: n,
l: e
};
e -= o;
}
return null;
}, O = (t, e, n = 0) => {
const r = t.children, o = e[0];
if (n < o.length) {
const s = o[n], [i, c] = O(r[s], e, n + 1), l = r.slice(0, s), u = r.slice(s + 1);
return l.push(i), u.unshift(c), [ {
...t,
children: l
}, {
...t,
children: u
} ];
}
{
const n = M(t, e[1]);
if (n) {
const {o: e, l: o, i: s} = n, i = r.slice(0, s), c = r.slice(s + 1);
if (k(e)) {
const t = e.text.slice(0, o), n = e.text.slice(o);
!t && i.length || i.push({
...e,
text: t
}), !n && c.length || c.unshift({
...e,
text: n
});
} else c.unshift(e);
return [ {
...t,
children: i
}, {
...t,
children: c
} ];
}
return [ t, {
...t,
children: []
} ];
}
}, S = t => t.length ? t[0] : 0, C = (t, e) => {
for (let n = 0; n < e.length; n++) t = t.children[e[n]];
return t;
}, I = (t, e, n, r) => [ [ S(t[0]) + e ], t[1] + (r ? n : 0) ], A = (t, e, n, r = 0) => {
if (r < e.length) {
const o = e[r];
return ((t, e, n, r) => {
const o = t.children.slice();
return o.splice(e, n - e + 1, ...r), {
...t,
children: o
};
})(t, o, o, [ A(t.children[o], e, n, r + 1) ]);
}
return n;
}, H = (t, e, n, r) => {
const [o, s] = O(t, e), i = -1 === c(e, n) ? O(t, n)[1] : s, l = o.children.slice();
return D(l, r, v), D(l, i.children, v), {
...t,
children: l
};
}, P = (t, e, n) => -1 !== c(e, n) ? [] : O(O(t, n)[0], e)[1].children, R = (t, [e, n]) => {
const r = C(t, e);
return !!(r && n >= 0 && n <= x(r));
}, B = (t, e) => {
switch (e.type) {
case a:
{
const {start: n, end: r} = e;
if (-1 !== c(t, n)) return -1 !== c(r, t) ? n : I(t, S(n[0]) - S(r[0]), n[1] - r[1], 0 === i(r[0], t[0]));
break;
}
case d:
case h:
{
const n = e.at;
if (-1 !== c(t, n)) {
const r = e.type === d ? f(e.text) : e.fragment, o = r.length, s = o - 1;
return I(t, s, x(r[o - 1]) - (0 === s ? 0 : n[1]), 0 === i(n[0], t[0]));
}
break;
}
}
return t;
}, F = (t, e) => [ B(t[0], e), B(t[1], e) ], T = (t, e, n) => {
switch (n.type) {
case a:
{
const {start: r, end: o} = n;
R(t, r) && R(t, o) && -1 === c(r, o) && (t = H(t, r, o, []), e = F(e, n));
break;
}
case d:
{
const {at: r, text: o} = n;
if (R(t, r) && o) {
const s = C(t, r[0]), i = M(s, r[1] - 1);
let c;
if (i) {
const t = i.o;
k(t) && (c = t);
}
t = H(t, r, r, f(o, c, s)), e = F(e, n);
}
break;
}
case h:
{
const {at: r, fragment: o} = n;
R(t, r) && o.length && (t = H(t, r, r, o), e = F(e, n));
break;
}
case p:
{
const {start: e, end: r, key: o, value: s} = n;
R(t, e) && R(t, r) && -1 === c(e, r) && (t = H(t, e, r, P(t, e, r).map(t => ({
...t,
children: t.children.map(t => k(t) ? {
...t,
[o]: s
} : t)
}))));
break;
}
case y:
{
const {path: e, key: r, value: o} = n, s = C(t, e);
s && (t = A(t, e, {
...s,
[r]: o
}));
break;
}
}
return [ t, e ];
};
function V(t = l(this.selection)) {
this.apply((new m).delete(...t));
}
function L(t, e = this.selection[0]) {
this.apply((new m).insertText(e, t));
}
function N(t, e = this.selection[0]) {
this.apply((new m).insertFragment(e, [ {
children: [ t ]
} ]));
}
function q(t) {
const [e, n] = l(this.selection);
this.apply((new m).delete(e, n).insertText(e, t));
}
function z(t) {
const e = this.doc;
this.apply((new m).delete([ [], 0 ], [ [ e.children.length - 1 ], x(e.children[e.children.length - 1]) ]).insertText([ [], 0 ], t));
}
function J(t, e, n = l(this.selection)) {
this.apply((new m).format(...n, t, e));
}
function U(t, e = l(this.selection)) {
const n = P(this.doc, ...e).flatMap(t => t.children.filter(k));
n.length && this.apply((new m).format(...e, t, !!n.some(e => !e[t])));
}
function G(t, e, n = this.selection[0][0]) {
this.apply((new m).attr(n, t, e));
}
function j(t, e, n, r = this.selection[0][0]) {
const o = C(this.doc, r);
this.apply((new m).attr(r, t, o[t] === e ? n : e));
}
let W = null, X = null, Y = null, K = null, Q = null;
const Z = t => 1 === t.nodeType, $ = t => 8 === t.nodeType, tt = () => X, et = () => {
const t = nt();
return 1 === t ? X.data.length : 2 === t ? 1 : 0;
}, nt = () => {
if (null != Y) return Y;
if (X) if ((t => 3 === t.nodeType)(X)) {
const t = X.data;
if (t) return Y = "\n" === t ? it() ? 3 : 6 : 1;
} else if (Z(X)) {
if ("BR" === X.tagName) return Y = it() ? 3 : 5;
if (K.u(X)) return Y = 2;
if (K.h(X)) return Y = 4;
}
return Y = 0;
}, rt = () => (Y = null, X = W.nextNode()), ot = () => {
for (;(Y = null) || (X = W.nextSibling()); ) if (4 === nt()) return;
}, st = () => {
for (;(Y = null) || (X = W.parentNode()); ) if (4 === nt()) return;
}, it = () => {
const t = X.parentNode;
return Q(() => {
for (;rt(); ) {
if (nt()) return !0;
if (!t.contains(X)) break;
}
return !1;
});
}, ct = () => {
for (;;) {
if (2 === nt()) {
const t = X;
for (;rt() && t.contains(X); ) ;
} else rt();
if (!X) break;
const t = nt();
if (t) return t;
}
}, lt = new Set([ "DIV", "H1", "H2", "H3", "H4", "H5", "H6", "P", "PRE", "LI", "DT", "DD", "TR" ]), ut = t => lt.has(t.tagName), ft = new Set([ "EMBED", "IMG", "PICTURE", "AUDIO", "VIDEO", "SVG", "CANVAS", "MATH", "IFRAME", "OBJECT" ]), at = t => "false" === t.contentEditable || ft.has(t.tagName), dt = (t, e) => t.compareDocumentPosition(e), ht = t => t.ownerDocument, pt = t => ht(t).getSelection(), yt = (t, e) => {
if (t.rangeCount) {
const n = t.getRangeAt(0);
if (e.contains(n.commonAncestorContainer)) return n;
}
}, gt = (t, e, n, r) => {
const o = pt(t);
(n || yt(o, t)) && (o.removeAllRanges(), o.addRange(e), r && (o.collapseToEnd(),
o.extend(e.startContainer, e.startOffset)));
}, mt = (t, e, [n, r], o, s) => {
const i = c(n, r), l = 0 === i, u = 1 === i, f = u ? r : n, a = u ? n : r;
if (0 === f[0].length && 0 === f[1] && l && !e.hasChildNodes()) {
const n = t.createRange();
return n.setStart(e, 0), n.setEnd(e, 0), gt(e, n, s);
}
const d = kt(e, f, o);
if (!d) return;
const h = l ? d : kt(e, a, o);
if (!h) return;
const p = t.createRange(), [y, g] = d, [m, k] = h;
Z(y) ? g < 1 ? p.setStartBefore(y) : p.setStartAfter(y) : p.setStart(y, g), Z(m) ? k < 1 ? p.setEndBefore(m) : p.setEndAfter(m) : p.setEnd(m, k),
gt(e, p, s, u);
}, kt = (t, [e, n], r) => r(() => {
let t, r = 0;
for (;t = ct(); ) if (4 === t) {
if (r < e.length) for (let t = e[r++]; t > 0; t--) ot();
} else {
const t = et();
if (n <= t) return [ tt(), n ];
n -= t;
}
}, t), wt = (e, n, r, o) => {
let s = !0;
if (e === n && !n.hasChildNodes()) return [ [ 0 ], 0 ];
if (Z(n) && n.hasChildNodes()) {
const e = t(r, n.childNodes.length - 1);
n = n.childNodes[e], s = e === r, r = 0;
}
return o(() => {
4 !== nt() && st();
const t = o(() => {
const t = [];
let n;
for (;(n = tt()) && n !== e; ) t.unshift(n), st();
if (!t.length) return [ 0 ];
let r = 0, o = t[t.length - 1];
for (;o = o.previousElementSibling; ) r++;
return [ r ];
});
let i = 0;
for (;ct(); ) {
const t = dt(n, tt());
if (0 === t || 16 & t) {
if (s) break;
} else if (4 & t) break;
i += et();
}
return [ t, i + r ];
}, e, n);
}, bt = (t, e, {startOffset: n, startContainer: r, endOffset: o, endContainer: s}) => {
const i = wt(t, r, n, e);
return [ i, r === s && n === o ? i : wt(t, s, o, e) ];
}, xt = t => (e, n) => {
e.setData("text/plain", u({
children: n
}, t));
}, _t = () => (t, e, n) => {
const r = document.createElement("div");
r.appendChild(yt(pt(n), n).cloneContents()), t.setData("text/html", r.innerHTML);
}, vt = "application/x-edix-editor", Dt = ({key: t = vt} = {}) => (e, n) => {
e.setData(t, JSON.stringify(n));
}, Et = t => e => {
for (const n of e.items) if ("file" === n.kind) {
const e = t[n.type];
if (e) {
const t = n.getAsFile();
if (t) return [ {
children: [ e(t) ]
} ];
}
}
return null;
}, Mt = () => t => t.getData("text/plain"), Ot = (t, e = []) => (n, r) => {
const o = n.getData("text/html");
if (o) {
let n = (new DOMParser).parseFromString(o, "text/html").body, s = !1;
for (const t of [ ...n.childNodes ]) $(t) ? "StartFragment" === t.data ? (s = !0,
n = new DocumentFragment) : "EndFragment" === t.data && (s = !1) : s && n.appendChild(t);
return ((t, e, n, r) => e(() => {
let t, e = null, o = "", s = !1;
const i = [], c = () => {
o && (e || (e = []), e.push(n(o)), o = "");
}, l = () => {
c(), !e && s && (e = []), e && i.push({
children: e
}), e = null, s = !1;
};
for (;t = ct(); ) if (4 === t) l(); else if (s = !0, 1 === t) o += tt().data; else if (2 === t) {
c();
const t = r(tt());
t && e.push(t);
} else 3 === t && l();
return l(), i.length || i.push({
children: []
}), i;
}, t))(n, r, t, t => {
for (const n of e) {
const e = n(t);
if (e) return e;
}
});
}
return null;
}, St = ({key: t = vt} = {}) => e => {
try {
return JSON.parse(e.getData(t));
} catch (t) {
return null;
}
}, Ct = (t, e, {mod: n, shift: r = !1, alt: o = !1} = {}) => (t = t.toLowerCase(),
s => {
if (s.key.toLowerCase() === t && (!n || s.ctrlKey || s.metaKey) && r === s.shiftKey && o === s.altKey) return e(s),
!0;
}), It = [], At = () => {}, Ht = ({doc: t, readonly: e = !1, schema: i, keyboard: u, copy: f = [ xt() ], paste: a = [ t => t.getData("text/plain") ], isBlock: d = ut, onChange: h, onError: p = console.error}) => {
let y = [ [ [ 0 ], 0 ], [ [ 0 ], 0 ] ];
const k = (t, e) => {
if (!i) return e("An unsafe operation was detected. We recommend using schema option."),
!0;
const n = i["~standard"].validate(t);
if (n instanceof Promise) e("async validate is not supported."); else {
if (!n.issues) return !0;
e(n.issues.map(t => t.message).join("\n"));
}
return !1;
};
let w;
if (!k(t, t => {
w = t;
}) && w) throw Error(w);
const b = new Map, x = t => b.get(t) || It, _ = new Map, v = t => {
const e = _.get(t);
e && !e[1] && (e[1] = !0, s(() => {
e[1] = !1, e[0].forEach(t => {
t();
});
}));
}, D = r => {
if (!e) {
const e = t, o = x("apply"), s = o.length;
for (let e of r.ops) {
let n = 0;
const r = () => {
if (n < s) {
const t = n;
o[n](e, i), t === n && i();
} else if (n === s) {
n++;
try {
const [n, r] = T(t, y, e);
g(e) && !k(n, p) || (t = n, y = r);
} catch (t) {
p("rollback operation: " + t);
}
}
}, i = t => {
t && (e = t), n++, r();
};
r();
}
n(e, t) || v("change");
}
}, E = e => {
((t, [e, n]) => R(t, e) && R(t, n))(t, e) && (c(y[0], e[0]) || c(y[1], e[1])) && (y = e,
v("selectionchange"));
}, M = {
get doc() {
return t;
},
get selection() {
return y;
},
get readonly() {
return e;
},
set readonly(t) {
e = t, v("readonly");
},
apply: (t, ...e) => (o(t) ? t.call(M, ...e) : D(t), M),
on: (t, e) => {
let n = _.get(t);
n || _.set(t, n = [ new Set, !1 ]);
const r = n[0];
return r.add(e), () => {
r.delete(e);
};
},
hook: (t, e) => {
let n = b.get(t);
return n || b.set(t, n = []), n.push(e), () => {
const t = n.indexOf(e);
-1 !== t && n.splice(t, 1);
};
},
use: (t, ...e) => (t.call(M, ...e), M),
input: n => {
if (!window.InputEvent || !o(InputEvent.prototype.getTargetRanges)) return p("beforeinput event is not supported."),
At;
const {contentEditable: s, role: i, ariaMultiLine: u, ariaReadOnly: h} = n, g = n.style.whiteSpace;
n.role = "textbox", n.style.whiteSpace = "pre-wrap", n.ariaMultiLine = "true";
let k = !1, w = null, b = !1, _ = !1, v = !1;
const O = ht(n), S = (t => {
const e = (n, r, o) => {
const s = K, i = Q, c = W, l = X, u = Y;
try {
return W || (K = t, Q = e, W = K.p.createTreeWalker(r, 5)), o && (W.currentNode = X = o),
n();
} finally {
K = s, Q = i, W = c, X = l, Y = u, W && l && (W.currentNode = l);
}
};
return e;
})({
p: O,
h: d,
u: at
}), C = () => {
n.contentEditable = e ? "false" : "true", n.ariaReadOnly = e ? "true" : null;
};
C();
const I = M.on("change", () => {
_ || requestAnimationFrame(() => {
_ || n.focus({
preventScroll: !0
});
});
}), A = M.on("readonly", C), H = t => {
for (const e of a) {
const n = e(t, S);
if (n) return n;
}
p("failed to serialize pasted data");
}, R = ((t, e) => {
let n = !1;
const r = [], o = t => {
n && r.push(...t);
}, s = new MutationObserver(t => {
o(t), n || e();
}), i = () => {
o(s.takeRecords());
}, c = () => (i(), r.splice(0));
return s.observe(t, {
characterData: !0,
characterDataOldValue: !0,
childList: !0,
subtree: !0
}), {
m: t => {
let e;
for (;e = t.pop(); ) if ("childList" === e.type) {
const {target: t, removedNodes: n, addedNodes: r, nextSibling: o} = e;
for (let e = n.length - 1; e >= 0; e--) t.insertBefore(n[e], o);
for (let e = r.length - 1; e >= 0; e--) t.removeChild(r[e]);
} else e.target.data = e.oldValue;
c();
},
k: t => {
!n && t && i(), n = t;
},
_: c,
v: () => {
r.splice(0), s.disconnect();
}
};
})(n, () => {
mt(O, n, y, S);
}), B = () => {
E(((t, e) => {
const n = pt(t), r = yt(n, t);
if (!r) return [ [ [ 0 ], 0 ], [ [ 0 ], 0 ] ];
const o = bt(t, e, r), s = dt(n.anchorNode, n.focusNode);
return (0 === s ? n.anchorOffset > n.focusOffset : 2 & s) ? [ o[1], o[0] ] : o;
})(n, S));
}, F = () => {
const t = R._();
R.k(!1), t.length && (R.m(t), O.removeEventListener("selectionchange", U), mt(O, n, y, S, !0),
O.addEventListener("selectionchange", U)), w && (E(w[1]), D(w[0]), w = null), b = !1;
}, T = t => {
if (!b) for (const e of x("keyboard")) if (e(t)) return t.preventDefault(), void R.k(!1);
}, V = () => {
b || F();
}, L = t => {
t.preventDefault();
const e = t.inputType;
if (e.startsWith("format")) return;
if ("historyUndo" === e || "historyRedo" === e) return;
b ? R.k(!0) : B();
const r = t.getTargetRanges()[0];
if (r) {
const o = bt(n, S, r);
let s, i = "insertParagraph" === e || "insertLineBreak" === e ? "\n" : t.data;
if (null == i) {
const e = t.dataTransfer;
e && (i = e.getData("text/plain"));
}
w || (w = [ new m, y ]), s = w[0], 0 !== c(...o) && s.delete(...o), i && s.insertText(o[0], i);
}
b || F();
}, N = () => {
b || B(), b = !0;
}, q = () => {
F();
}, z = () => {
_ = !0, B();
}, J = () => {
_ = !1;
}, U = () => {
!_ || b || v || B();
}, G = e => {
if (B(), 0 !== c(...y)) {
const r = P(t, ...l(y));
for (const t of f) t(e, r, n);
}
}, j = t => {
t.preventDefault(), G(t.clipboardData);
}, Z = t => {
t.preventDefault(), e || (G(t.clipboardData), D((new m).delete(...l(y))));
}, $ = t => {
t.preventDefault();
const e = H(t.clipboardData);
if (e) {
const [t, n] = l(y), o = (new m).delete(t, n);
r(e) ? o.insertText(t, e) : o.insertFragment(t, e), D(o);
}
}, tt = t => {
t.preventDefault();
const e = t.dataTransfer, o = ((t, e, {clientX: n, clientY: r}, o) => {
if (t.caretPositionFromPoint) {
const s = t.caretPositionFromPoint(n, r);
if (s) return wt(e, s.offsetNode, s.offset, o);
} else if (t.caretRangeFromPoint) {
const s = t.caretRangeFromPoint(n, r);
if (s) return wt(e, s.startContainer, s.startOffset, o);
}
})(O, n, t, S);
if (e && o) {
let t;
const n = new m;
v && n.delete(...l(y));
const s = H(e);
if (s) {
const e = n.transform(o);
r(s) ? n.insertText(e, s) : n.insertFragment(e, s), t = [ e, n.transform(o) ];
}
D(n), t && E(t);
}
}, et = t => {
v = !0, G(t.dataTransfer);
}, nt = () => {
v = !1;
};
O.addEventListener("selectionchange", U), n.addEventListener("keydown", T), n.addEventListener("input", V),
n.addEventListener("beforeinput", L), n.addEventListener("compositionstart", N),
n.addEventListener("compositionend", q), n.addEventListener("focus", z), n.addEventListener("blur", J),
n.addEventListener("copy", j), n.addEventListener("cut", Z), n.addEventListener("paste", $),
n.addEventListener("drop", tt), n.addEventListener("dragstart", et), n.addEventListener("dragend", nt);
const rt = x("mount"), ot = [];
return rt.forEach(t => {
const e = t(n);
e && ot.push(e);
}), () => {
k || (k = !0, I(), A(), n.contentEditable = s, n.role = i, n.ariaMultiLine = u,
n.ariaReadOnly = h, n.style.whiteSpace = g, R.v(), O.removeEventListener("selectionchange", U),
n.removeEventListener("keydown", T), n.removeEventListener("input", V), n.removeEventListener("beforeinput", L),
n.removeEventListener("compositionstart", N), n.removeEventListener("compositionend", q),
n.removeEventListener("focus", z), n.removeEventListener("blur", J), n.removeEventListener("copy", j),
n.removeEventListener("cut", Z), n.removeEventListener("paste", $), n.removeEventListener("drop", tt),
n.removeEventListener("dragstart", et), n.removeEventListener("dragend", nt), ot.forEach(t => {
t();
}));
};
}
}, O = (t => {
let e = 0, r = 0;
const o = Date.now, s = [ [ t.doc, t.selection, [] ] ], i = () => s[e];
return t.hook("apply", (i, c) => {
const l = t.doc, u = t.selection;
c(i);
const f = t.doc;
if (!n(l, f)) {
const t = o();
if (0 === e || t - r >= 500) {
e++;
const t = [ l, u, [] ];
e >= s.length ? s.push(t) : s[e] = t;
}
r = t, s[e][0] = f, s[e][2].push(i), s.splice(e + 1), e > 500 && (e--, s.shift());
}
}), {
undo: () => {
if (e > 0) {
const t = i()[1];
return e--, [ i()[0], t ];
}
},
redo: () => {
if (e < s.length - 1) {
e++;
const t = i()[0], n = i()[1];
return [ t, i()[2].reduce((t, e) => F(t, e), n) ];
}
}
};
})(M);
return M.on("change", () => {
h(t);
}), M.hook("keyboard", Ct("z", () => {
if (!e) {
const e = O.undo();
e && (t = e[0], E(e[1]), v("change"));
}
}, {
mod: !0
})), M.hook("keyboard", Ct("z", () => {
if (!e) {
const e = O.redo();
e && (t = e[0], E(e[1]), v("change"));
}
}, {
mod: !0,
shift: !0
})), u && u.forEach(t => {
M.hook("keyboard", t);
}), M;
};
function Pt() {
const t = this;
t.hook("apply", t => {
console.log("apply", t);
}), t.on("change", () => {
console.log("change", t.doc);
}), t.on("selectionchange", () => {
console.log("selectionchange", t.selection);
});
}
function Rt() {
this.hook("mount", t => {
t.ariaMultiLine = null;
}), this.hook("apply", (t, e) => {
"insert_text" === t.type ? t = {
...t,
text: t.text.replaceAll("\n", "")
} : "insert_node" === t.type && (t = {
...t,
fragment: [ E(...t.fragment) ]
}), e(t);
});
}
const Bt = ({text: t, singleline: e, onChange: n, ...r}) => {
const o = Ht({
...r,
doc: {
children: f(t)
},
onChange: t => {
n(u(t));
}
});
return e && o.use(Rt), o;
};
export { V as Delete, J as Format, N as InsertNode, L as InsertText, z as ReplaceAll, q as ReplaceText, G as SetBlockAttr, j as ToggleBlockAttr, U as ToggleFormat, m as Transaction, Ht as createEditor, Bt as createPlainEditor, Pt as debugPlugin, Et as filePaste, Ct as hotkey, _t as htmlCopy, Ot as htmlPaste, Dt as internalCopy, St as internalPaste, xt as plainCopy, Mt as plainPaste, Rt as singlelinePlugin };
//# sourceMappingURL=index.js.map