md-editor-rt
Version:
Markdown editor for react, developed in jsx and typescript, dark theme、beautify content by prettier、render articles directly、paste or clip the picture and upload it...
397 lines (396 loc) • 12.5 kB
JavaScript
import { jsxs as K, jsx as P, Fragment as te } from "react/jsx-runtime";
import { createContext as le, memo as Q, useContext as oe, useRef as _, useEffect as j, useMemo as F, useState as G, useCallback as U } from "react";
import { p as B, d as ne } from "./config.mjs";
import { b as q, f as z, P as re, G as J, S as se } from "./event-bus.mjs";
import { c as X, g as ie } from "./index2.mjs";
import { createSmoothScroll as ce, debounce as ae } from "@vavt/util";
const fe = `.${B}-preview > [data-line]`, I = (t, e) => +getComputedStyle(t).getPropertyValue(e).replace("px", ""), Ee = (t, e) => {
const N = ae(() => {
t.removeEventListener("scroll", n), t.addEventListener("scroll", n), e.removeEventListener("scroll", n), e.addEventListener("scroll", n);
}, 50), n = ($) => {
const b = t.clientHeight, L = e.clientHeight, u = t.scrollHeight, a = e.scrollHeight, h = (u - b) / (a - L);
$.target === t ? (e.removeEventListener("scroll", n), e.scrollTo({
top: t.scrollTop / h
// behavior: 'smooth'
}), N()) : (t.removeEventListener("scroll", n), t.scrollTo({
top: e.scrollTop * h
// behavior: 'smooth'
}), N());
};
return [
() => {
N().finally(() => {
t.dispatchEvent(new Event("scroll"));
});
},
() => {
t.removeEventListener("scroll", n), e.removeEventListener("scroll", n);
}
];
}, He = (t, e, N) => {
const { view: n } = N, $ = ce(), b = (s) => n.lineBlockAt(n.state.doc.line(s + 1).from).top, L = (s) => n.lineBlockAt(n.state.doc.line(s + 1).from).bottom;
let u = [], a = [], h = [];
const A = () => {
u = [], a = Array.from(
e.querySelectorAll(fe)
), h = a.map((r) => Number(r.dataset.line));
const s = [...h], { lines: m } = n.state.doc;
s[0] !== 0 && s.unshift(0);
let p = s.shift() || 0, i = s.shift() || m;
for (let r = 0; r < m; r++)
r === i && (p = r, i = s.shift() || m), u.push({
start: p,
end: i - 1
});
}, w = (s, m) => {
let p = 1;
for (let i = a.length - 1; i - 1 >= 0; i--) {
const r = a[i];
if (r.offsetTop <= m) {
p = Number(r.dataset.line);
break;
}
}
for (let i = u.length - 1; i >= 0; i--)
if (b(u[i].start) <= s) {
p = p < u[i].start ? p : u[i].start;
break;
}
return p;
};
let x = 0, R = 0;
const O = () => {
if (R !== 0)
return !1;
x++;
const { scrollDOM: s } = n;
let m = I(e, "padding-block-start");
const p = n.lineBlockAtHeight(s.scrollTop), { number: i } = n.state.doc.lineAt(p.from), r = u[i - 1];
if (!r)
return !1;
let T = 1;
const g = e.querySelector(`[data-line="${r.start}"]`) || e.firstElementChild?.firstElementChild, E = e.querySelector(`[data-line="${r.end + 1}"]`) || e.lastElementChild?.lastElementChild, o = s.scrollHeight - s.clientHeight, d = e.scrollHeight - e.clientHeight;
let C = b(r.start), y = L(r.end), c = g.offsetTop, v = E.offsetTop - c;
C === 0 && (c = 0, g === E ? (m = 0, v = 0) : v = E.offsetTop), T = (s.scrollTop - C) / (y - C);
const H = E == e.lastElementChild?.lastElementChild ? E.offsetTop + E.clientHeight : E.offsetTop;
if (y >= o || H > d) {
const f = w(o, d);
C = b(f), T = (s.scrollTop - C) / (o - C);
const l = e.querySelector(`[data-line="${f}"]`);
C > 0 && l && (c = l.offsetTop), v = d - c + I(e, "padding-block-start");
}
const k = c - m + v * T;
$(e, k, () => {
x--;
});
}, D = () => {
if (x !== 0)
return;
R++;
const { scrollDOM: s } = n, m = e.scrollTop, p = e.scrollHeight, i = s.scrollHeight - s.clientHeight, r = e.scrollHeight - e.clientHeight;
let T = e.firstElementChild?.firstElementChild, g = e.firstElementChild?.lastElementChild;
if (h.length > 0) {
let f = Math.ceil(
h[h.length - 1] * (m / p)
), l = h.findLastIndex((S) => S <= f);
l = l === -1 ? 0 : l, f = h[l];
for (let S = l; S >= 0 && S < h.length; )
if (a[S].offsetTop > m) {
if (S - 1 >= 0) {
S--;
continue;
}
f = -1, l = -1;
break;
} else {
if (S + 1 < h.length && a[S + 1].offsetTop < m) {
S++;
continue;
}
f = h[S], l = S;
break;
}
switch (l) {
case -1: {
T = e.firstElementChild?.firstElementChild, g = a[0];
break;
}
case h.length - 1: {
T = a[l], g = e.firstElementChild?.lastElementChild;
break;
}
default:
T = a[l], g = a[l + 1];
}
}
let E = T === e.firstElementChild?.firstElementChild ? 0 : T.offsetTop - I(T, "margin-block-start"), o = g.offsetTop, d = 0;
const { start: C, end: y } = u[Number(T.dataset.line || 0)];
let c = b(C);
const v = b(
y + 1 === n.state.doc.lines ? y : y + 1
);
let H = 0;
const k = g == e.lastElementChild?.lastElementChild ? g.offsetTop + g.offsetHeight : g.offsetTop;
if (v > i || k > r) {
const f = w(i, r), l = e.querySelector(`[data-line="${f}"]`);
E = l ? l.offsetTop - I(l, "margin-block-start") : E, c = b(f), d = (m - E) / (r - E), H = i - c;
} else T === e.firstElementChild?.firstElementChild ? (T === g && (o = g.offsetTop + g.offsetHeight + I(g, "margin-block-end")), H = v, c = 0, d = Math.max(m / o, 0)) : (d = Math.max(
(m - E) / (o - E),
0
), H = v - c);
$(t, c + H * d, () => {
R--;
});
}, M = (s) => {
const { scrollDOM: m, contentHeight: p } = n, i = m.clientHeight;
if (p <= i || e.firstElementChild.clientHeight <= e.clientHeight || n.state.doc.lines <= u[u.length - 1]?.end)
return !1;
s.target === t ? O() : D();
};
return [
() => {
A(), t.addEventListener("scroll", M), e.addEventListener("scroll", M), t.dispatchEvent(new Event("scroll"));
},
() => {
t.removeEventListener("scroll", M), e.removeEventListener("scroll", M);
}
];
}, Y = le({
scrollElementRef: void 0,
rootNodeRef: void 0
}), Z = ({
tocItem: t,
mdHeadingId: e,
onActive: N,
onClick: n,
scrollElementOffsetTop: $ = 0
}) => {
const { scrollElementRef: b, rootNodeRef: L } = oe(Y), u = _(null);
return j(() => {
t.active && N(t, u.current);
}, [N, t, t.active]), /* @__PURE__ */ K(
"div",
{
ref: u,
className: X([
`${B}-catalog-link`,
t.active && `${B}-catalog-active`
]),
onClick: (a) => {
if (a.stopPropagation(), n?.(a, t), a.defaultPrevented)
return;
const h = e({
text: t.text,
level: t.level,
index: t.index,
currentToken: t.currentToken,
nextToken: t.nextToken
}), A = L?.current.getElementById(h), w = b?.current;
if (A && w) {
let x = A.offsetParent, R = A.offsetTop;
if (w.contains(x))
for (; x && w != x; )
R += x?.offsetTop, x = x?.offsetParent;
const O = A.previousElementSibling;
let D = 0;
O || (D = I(A, "margin-block-start")), w?.scrollTo({
top: R - $ - D,
behavior: "smooth"
});
}
},
children: [
/* @__PURE__ */ P("span", { title: t.text, children: t.text }),
t.children && t.children.length > 0 && /* @__PURE__ */ P("div", { className: `${B}-catalog-wrapper`, children: t.children.map((a) => /* @__PURE__ */ P(
Z,
{
mdHeadingId: e,
tocItem: a,
onActive: N,
onClick: n,
scrollElementOffsetTop: $
},
`${t.text}-link-${a.level}-${a.text}`
)) })
]
}
);
}, de = Q(Z), he = (t) => {
const {
editorId: e,
mdHeadingId: N = ne.mdHeadingId,
theme: n = "light",
offsetTop: $ = 20,
syncWith: b = "preview",
catalogMaxDepth: L
} = t, u = F(() => `#${e}-preview-wrapper`, [e]), [a, h] = G([]), [A, w] = G(), x = _(null), R = _(null), O = _(void 0), D = _(null), [M, s] = G(), [m, p] = G({}), i = F(() => {
const o = [];
return a.forEach((d, C) => {
if (L && d.level > L)
return;
const { text: y, level: c, line: v } = d, H = {
level: c,
text: y,
line: v,
index: C + 1,
active: A === d
};
if (o.length === 0)
o.push(H);
else {
let k = o[o.length - 1];
if (H.level > k.level)
for (let f = k.level + 1; f <= 6; f++) {
const { children: l } = k;
if (!l) {
k.children = [H];
break;
}
if (k = l[l.length - 1], H.level <= k.level) {
l.push(H);
break;
}
}
else
o.push(H);
}
}), o;
}, [A, a, L]), [r] = G(() => t.scrollElement || `#${e}-preview-wrapper`), T = U(() => {
if (r instanceof HTMLElement)
return r;
let o = document;
return (r === u || t.isScrollElementInShadow) && (o = x.current?.getRootNode()), o.querySelector(r);
}, [u, t.isScrollElementInShadow, r]), g = U(
(o, d) => {
p({
top: d.offsetTop + I(d, "padding-block-start") + "px"
}), t.onActive?.(o, d);
},
[t]
);
j(() => {
D.current = x.current.getRootNode();
}, []), j(() => {
let o = [];
const d = (c) => {
if (c.length === 0)
return w(void 0), h([]), o = c, !1;
const { activeHead: v, activeIndex: H } = c.reduce(
(f, l, S) => {
let V = 0;
if (b === "preview") {
const W = D.current?.getElementById(
N({
text: l.text,
level: l.level,
index: S + 1,
currentToken: l.currentToken,
nextToken: l.nextToken
})
);
W instanceof HTMLElement && (V = ie(W, R.current));
} else if (M) {
const W = M.lineBlockAt(
M.state.doc.line(l.line + 1).from
).top, ee = M.scrollDOM.scrollTop;
V = W - ee;
}
return V < $ && V > f.minTop ? {
activeHead: l,
activeIndex: S,
minTop: V
} : f;
},
{
activeHead: c[0],
activeIndex: 0,
minTop: Number.MIN_SAFE_INTEGER
}
);
let k = v;
if (L && k.level > L) {
for (let f = H; f >= 0; f--) {
const l = c[f];
if (l.level <= L) {
k = l;
break;
}
}
if (k.level > L) {
const f = c.find((l) => l.level <= L);
f && (k = f);
}
}
w(k), h(c), o = c;
}, C = () => {
d(o);
}, y = (c) => {
if (O.current?.removeEventListener("scroll", C), b === "editor")
O.current = M?.scrollDOM;
else {
const v = T();
R.current = v, O.current = v === document.documentElement ? document : v;
}
d(c), O.current?.addEventListener("scroll", C);
};
return q.on(e, {
name: z,
callback: y
}), q.emit(e, re), () => {
q.remove(e, z, y), O.current?.removeEventListener("scroll", C);
};
}, [
$,
N,
T,
e,
b,
M,
L
]);
const E = F(() => ({
scrollElementRef: R,
rootNodeRef: D
}), []);
return j(() => {
const o = (d) => {
s(d);
};
return q.on(e, {
name: J,
callback: o
}), q.emit(e, se), () => {
q.remove(e, J, o);
};
}, [e]), /* @__PURE__ */ P(Y.Provider, { value: E, children: /* @__PURE__ */ P(
"div",
{
className: X([
`${B}-catalog`,
n === "dark" && `${B}-catalog-dark`,
t.className || ""
]),
style: t.style,
ref: x,
children: i.length > 0 && /* @__PURE__ */ K(te, { children: [
/* @__PURE__ */ P("div", { className: `${B}-catalog-indicator`, style: m }),
/* @__PURE__ */ P("div", { className: `${B}-catalog-container`, children: i.map((o) => /* @__PURE__ */ P(
de,
{
mdHeadingId: N,
tocItem: o,
onActive: g,
onClick: t.onClick,
scrollElementOffsetTop: t.scrollElementOffsetTop
},
`link-${o.level}-${o.text}`
)) })
] })
}
) });
}, ke = Q(he);
export {
ke as M,
Ee as a,
He as s
};