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...

372 lines (371 loc) 12.1 kB
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 };