UNPKG

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
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 };