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