UNPKG

ranui

Version:

A framework-agnostic Web Components UI library built on native custom elements, with TypeScript types, light/dark theming, SSR and PWA support.

307 lines (306 loc) 10.5 kB
import { T as N, _ as f, i as g, m as b, n as $ } from "./factory-WDxu11V0.js"; import "./builder-EH76YCFS.js"; import { escapeHtml as I } from "ranuts/utils"; import { Marked as _ } from "marked"; import S from "dompurify"; import he from "remend"; var u = null, T = (t) => { if (typeof document > "u") return !1; u || (u = document.createElement("template")), u.innerHTML = `${t}<i data-ran-probe=""></i>`; const e = u.content.querySelector("[data-ran-probe]"), r = e !== null && e.parentNode !== u.content; return u.innerHTML = "", r; }, O = (t) => { const e = []; let r = ""; for (const n of t) { const a = e[e.length - 1]; if (r) { a.push(n), n.type === "html" && (r += n.raw, T(r) || (r = "")); continue; } if (n.type === "space" || n.type === "def") { a && a.push(n); continue; } e.push([n]), n.type === "html" && n.block && T(n.raw) && (r = n.raw); } return e; }, P = /^[ \t]{0,3}(`{3,}|~{3,})/, H = (t) => { let e = null, r = 0; for (const n of t.split(` `)) { const a = P.exec(n); e === null ? a && (e = a[1][0], r = a[1].length) : a && a[1][0] === e && a[1].length >= r && (e = null, r = 0); } return e !== null; }, v = null, w = null, h = null, k = /* @__PURE__ */ new Set(), M = /* @__PURE__ */ new Set(), p = /* @__PURE__ */ new Map(), D = () => h || (h = Promise.all([import("shiki"), import("shiki/engine/javascript")]).then(async ([t, e]) => { v = t; const r = await t.createHighlighter({ themes: [], langs: [], engine: e.createJavaScriptRegexEngine({ forgiving: !0 }) }); return w = r, r; }), h), E = (t) => { const e = (t || "").trim().toLowerCase(); return !e || e === "text" || e === "plain" || e === "plaintext" || e === "txt" ? "text" : v ? e in v.bundledLanguages ? e : "text" : e; }, m = (t, e) => { const r = `${t}:${e}`, n = t === "theme" ? k : M; if (n.has(e)) return Promise.resolve(); const a = p.get(r); if (a) return a; const s = D().then(async (o) => { t === "theme" ? await o.loadTheme(e) : e !== "text" && await o.loadLanguage(e), n.add(e); }).finally(() => p.delete(r)); return p.set(r, s), s; }, B = (t, e) => !!w && k.has(e.light) && k.has(e.dark) && (t === "text" || M.has(t)), A = (t, e, r) => w.codeToHtml(t, { lang: e, themes: { light: r.light, dark: r.dark }, defaultColor: !1 }), W = (t, e, r) => { const n = E(e); return B(n, r) ? A(t, n, r) : Promise.all([m("theme", r.light), m("theme", r.dark)]).then(() => { const a = E(e); return m("lang", a).then(() => A(t, a, r)); }).catch(() => null); }, F = { light: "github-light", dark: "github-dark" }, pe = (t) => { const e = t.trim().split(/\s+/).filter(Boolean); return e.length === 0 ? F : e.length === 1 ? { light: e[0], dark: e[0] } : { light: e[0], dark: e[1] }; }, L = (t, e) => `<span class="ran-md-math" data-ran-math="${I(t)}" data-display="${e}"></span>`, y = (t, e, r, n) => { if (!t.startsWith(e)) return null; const a = e.length, s = t.indexOf(r, a); if (s === -1 || s === a) return null; let o = s + r.length; if (n) { if (o !== t.length && t[o] !== ` `) return null; for (; t[o] === ` `; ) o += 1; } return { raw: t.slice(0, o), text: t.slice(a, s).trim() }; }, U = { name: "ranMathBlock", level: "block", start(t) { const e = t.indexOf("$$"), r = t.indexOf("\\["); return e === -1 ? r === -1 ? void 0 : r : r === -1 ? e : Math.min(e, r); }, tokenizer(t) { const e = y(t, "$$", "$$", !0) || y(t, "\\[", "\\]", !0); if (e) return { type: "ranMathBlock", raw: e.raw, text: e.text }; }, renderer(t) { return `<p class="ran-md-math-block">${L(t.text, "block")}</p> `; } }, G = (t) => { for (let e = 0; e < t.length; e += 1) if (t[e] === "$") { if (t[e + 1] === "$") { e += 1; continue; } if (!(e > 0 && t[e - 1] === "$")) return e; } return -1; }, z = /^\$(?!\s)((?:\\.|[^$\\\n])+?)(?<!\s)\$(?!\d)/, J = (t) => ({ name: "ranMathInline", level: "inline", start(e) { const r = e.indexOf("\\("), n = t ? G(e) : -1; return r === -1 ? n === -1 ? void 0 : n : n === -1 ? r : Math.min(r, n); }, tokenizer(e) { const r = y(e, "\\(", "\\)", !1); if (r) return { type: "ranMathInline", raw: r.raw, text: r.text }; const n = t ? z.exec(e) : null; if (n) return { type: "ranMathInline", raw: n[0], text: n[1].trim() }; }, renderer(e) { return L(e.text, "inline"); } }), x = /* @__PURE__ */ new Map(), Y = (t) => { const e = t ? "dollar" : "default"; let r = x.get(e); return r || (r = new _({ gfm: !0, breaks: !1, async: !1 }), r.use({ extensions: [U, J(t)] }), x.set(e, r)), r; }, q = { USE_PROFILES: { html: !0 }, FORBID_TAGS: [ "style", "form", "textarea", "select", "button", "iframe", "object", "embed" ], FORBID_ATTR: ["style"], ADD_ATTR: ["target"], RETURN_DOM_FRAGMENT: !0 }, K = "\0", j = (t, e) => { let r = "", n = !1; for (const s of t) r += s.raw, s.type === "table" && (n = !0); const a = t[t.length - 1]; return { tokens: t, raw: r, key: e ? `${r}${K}${e}` : r, hasTable: n, incompleteCode: a?.type === "code" && H(a.raw) }; }, me = (t, e = {}) => { const r = Y(!!e.inlineMath), n = (o) => S.sanitize(r.parser(o.tokens), q); if (!t.trim()) return { blocks: [], render: n }; const a = r.lexer(t); let s = ""; for (const o of a) o.type === "def" && (s += o.raw); return { blocks: (e.split === !1 ? [Array.from(a)] : O(a)).map((o) => j(o, s)), render: n }; }, V = "language-", X = (t) => { const e = Array.from(t.classList).find((n) => n.startsWith(V)), r = t.textContent || ""; return { lang: e ? e.slice(9).toLowerCase() : "", code: r.endsWith(` `) ? r.slice(0, -1) : r }; }, C = (t, e, r, n) => { const a = N(); return $().class("ran-md-btn").part("button").attr("type", "button").data("md-action", t).aria("label", r).attr("title", r).children(f("r-icon").attr("name", e).attr("size", "16").attr("color", "currentColor").ref(a)).on("click", () => n(a.current)).build(); }, Q = (t) => { const e = t.split(` `); return e.length > 1 && e[e.length - 1] === "" && e.pop(), e.flatMap((r, n) => { const a = b().class("line").text(r).build(); return n === 0 ? [a] : [document.createTextNode(` `), a]; }); }, Z = (t) => f("pre").class("ran-md-pre").children(f("code").children(...Q(t))).build(), ee = (t, e, r, n, a, s) => { const o = W(r, n, a), d = (c) => { if (!c || !t.isConnected || Number(t.dataset.renderToken) !== s) return; const l = document.createElement("template"); l.innerHTML = c; const i = l.content.firstElementChild; !i || i.tagName !== "PRE" || (i.classList.add("ran-md-pre"), i.removeAttribute("style"), i.removeAttribute("tabindex"), e.pre.replaceWith(i), e.pre = i); }; typeof o == "string" ? d(o) : o.then(d); }, te = 0, re = (t, e) => f("r-mermaid").class("ran-md-mermaid").attr("code", encodeURIComponent(t.trim())).attr("theme", e.theme).boolAttr("copy", e.copy).boolAttr("download", e.download).boolAttr("fullscreen", !0).build(), R = (t, e) => f("r-math").attr("latex", encodeURIComponent(t)).attr("display", e).build(), ne = (t, e) => { const r = t.firstElementChild; if (!r || r.tagName !== "CODE") return null; const { lang: n, code: a } = X(r); if (n === "mermaid" && !e.incomplete) { import("./mermaid.js"); const i = re(a, e); return t.replaceWith(i), i; } if ((n === "math" || n === "latex") && !e.incomplete) return import("./math.js"), t.replaceWith(R(a.trim(), "block")), null; const s = ++te, o = []; e.copy && o.push(C("copy", "copy", e.labels.copy, (i) => e.onCopy(i, a, n))), e.download && o.push(C("download", "download", e.labels.download, () => e.onDownload(a, n))); const d = n || o.length ? g().class("ran-md-code-header").part("code-header").children(b().class("ran-md-code-lang").part("code-lang").text(n), b().class("ran-md-code-actions").part("code-actions").children(...o)) : null, c = { pre: Z(a) }, l = g().class("ran-md-code").part("code").data("render-token", String(s)).children(d, c.pre).build(); return n && (l.dataset.language = n), e.incomplete && (l.dataset.incomplete = ""), e.lineNumbers && (l.dataset.lineNumbers = ""), t.replaceWith(l), e.highlight && ee(l, c, a, n, e.highlight, s), null; }, ae = /[\u3000-\u303f\u3040-\u30ff\u3400-\u4dbf\u4e00-\u9fff\uac00-\ud7af\uf900-\ufaff\uff00-\uffef]/u, oe = /^(https?:\/\/|www\.)([^/?#]*)/, le = (t) => { const e = t.textContent ?? "", r = t.getAttribute("href") ?? ""; let n = r; try { n = decodeURI(r); } catch { } if (e !== n) return; const a = oe.exec(e); if (a === null) return; const s = a[2].search(ae); if (s < 0) return; const o = e.slice(0, a[1].length + s); t.textContent = o, t.setAttribute("href", o), t.after(document.createTextNode(e.slice(o.length))); }, ge = (t, e) => { const r = [], n = [], a = [], s = [], o = [], d = document.createTreeWalker(t, NodeFilter.SHOW_ELEMENT); for (let l = d.nextNode(); l; l = d.nextNode()) { const i = l; switch (i.tagName) { case "PRE": r.push(i); break; case "A": n.push(i); break; case "TABLE": a.push(i); break; case "IMG": s.push(i); break; case "SPAN": i.dataset.ranMath !== void 0 && o.push(i); } } const c = []; for (const l of r) { const i = ne(l, e); i && c.push(i); } if (o.length > 0) { import("./math.js"); for (const l of o) l.replaceWith(R(l.dataset.ranMath || "", l.dataset.display === "inline" ? "inline" : "block")); } for (const l of n) { const i = l.getAttribute("href"); if (!i) { l.dataset.incomplete = ""; continue; } i.startsWith("#") || (le(l), e.linkTarget && e.linkTarget !== "_self" && (l.setAttribute("target", e.linkTarget), l.setAttribute("rel", "noopener noreferrer"))); } for (const l of a) { const i = g().class("ran-md-table-wrap").part("table").build(); l.replaceWith(i), i.appendChild(l); } for (const l of s) l.hasAttribute("loading") || l.setAttribute("loading", "lazy"); return { themed: c }; }; export { ge as enhance, me as parseDocument, pe as parseThemes, he as remend };