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.5 kB
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 };