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