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.

517 lines (504 loc) 20 kB
import { n as c } from "./chunk-Y2CYZVJY-0JxdZxki.js"; import { m as x } from "./src-DtRLxcYO.js"; import { D as P, a as L, b as W, c as I, x as X, z as H } from "./chunk-WYO6CB5R-DDHkKowO.js"; import { t as q } from "./chunk-VAUOI2AC-izt0o4id.js"; var N = "", $ = "", z = "", b = [], R = /* @__PURE__ */ new Map(), S = /* @__PURE__ */ c((e) => H(e, X()), "sanitizeText"), v = /* @__PURE__ */ c((e) => { switch (e.type) { case "terminal": return { ...e, value: S(e.value) }; case "nonterminal": return { ...e, name: S(e.name) }; case "sequence": return { ...e, elements: e.elements.map(v) }; case "choice": return { ...e, alternatives: e.alternatives.map(v) }; case "optional": return { ...e, element: v(e.element) }; case "repetition": return { ...e, element: v(e.element), separator: e.separator ? v(e.separator) : void 0 }; case "special": return { ...e, text: S(e.text) }; } }, "sanitizeAstNode"), U = /* @__PURE__ */ c(() => { N = "", $ = "", z = "", b.length = 0, R.clear(), L(), x.debug("[Railroad] Database cleared"); }, "clear"), O = /* @__PURE__ */ c((e) => { N = S(e), x.debug("[Railroad] Title set:", e); }, "setTitle"), D = /* @__PURE__ */ c(() => N, "getTitle"), G = { clear: U, setTitle: O, getTitle: D, addRule: /* @__PURE__ */ c((e) => { const n = { ...e, name: S(e.name), definition: v(e.definition), comment: e.comment ? S(e.comment) : void 0 }; x.debug("[Railroad] Adding rule:", n.name), R.has(n.name) && x.warn(`[Railroad] Rule '${n.name}' is already defined. Overwriting.`), b.push(n), R.set(n.name, n); }, "addRule"), getRules: /* @__PURE__ */ c(() => b, "getRules"), getRule: /* @__PURE__ */ c((e) => R.get(e), "getRule"), setAccTitle: /* @__PURE__ */ c((e) => { $ = S(e).replace(/^\s+/g, ""), x.debug("[Railroad] Accessibility title set:", e); }, "setAccTitle"), getAccTitle: /* @__PURE__ */ c(() => $, "getAccTitle"), setAccDescription: /* @__PURE__ */ c((e) => { z = S(e).replace(/\n\s+/g, ` `), x.debug("[Railroad] Accessibility description set:", e); }, "setAccDescription"), getAccDescription: /* @__PURE__ */ c(() => z, "getAccDescription"), setDiagramTitle: O, getDiagramTitle: D }, f = { compactMode: !1, padding: 10, verticalSeparation: 8, horizontalSeparation: 10, arcRadius: 10, fontSize: 14, fontFamily: "monospace", terminalFill: "#FFFFC0", terminalStroke: "#000000", terminalTextColor: "#000000", nonTerminalFill: "#FFFFFF", nonTerminalStroke: "#000000", nonTerminalTextColor: "#000000", lineColor: "#000000", strokeWidth: 2, markerFill: "#000000", commentFill: "#E8E8E8", commentStroke: "#888888", commentTextColor: "#666666", specialFill: "#F0E0FF", specialStroke: "#8800CC", ruleNameColor: "#000066", showMarkers: !0, markerRadius: 5 }, j = /^#(?:[\da-f]{3,4}|[\da-f]{6}|[\da-f]{8})$|^(?:rgb|rgba|hsl|hsla|hwb|lab|lch|oklab|oklch)\([\d\s%+,./-]+\)$|^[a-z]+$/i, K = /^[\w "',.-]+$/, J = /* @__PURE__ */ new Set([ "compactMode", "padding", "verticalSeparation", "horizontalSeparation", "arcRadius", "fontSize", "fontFamily", "terminalFill", "terminalStroke", "terminalTextColor", "nonTerminalFill", "nonTerminalStroke", "nonTerminalTextColor", "lineColor", "strokeWidth", "markerFill", "commentFill", "commentStroke", "commentTextColor", "specialFill", "specialStroke", "ruleNameColor", "showMarkers", "markerRadius" ]), _ = /* @__PURE__ */ c((e) => e ? Object.keys(e).every((n) => n === "railroad" || J.has(n)) : !1, "isRailroadStyleOptions"), Q = /* @__PURE__ */ c((e) => e ? "railroad" in e && e.railroad ? e.railroad : _(e) ? e : {} : {}, "extractRailroadOverrides"), Z = /* @__PURE__ */ c((e) => { if (!e || _(e)) return {}; const { railroad: n, svgId: r, theme: t, look: i, ...a } = e; return a; }, "extractThemeOverrides"), d = /* @__PURE__ */ c((e, n) => { if (typeof e != "string") return n; const r = e.trim(); return j.test(r) ? r : n; }, "sanitizeColorValue"), B = /* @__PURE__ */ c((e, n) => { if (typeof e != "string") return n; const r = e.trim(); return K.test(r) ? r : n; }, "sanitizeFontFamilyValue"), F = /* @__PURE__ */ c((e, n) => { const r = typeof e == "number" ? e : typeof e == "string" ? Number.parseFloat(e) : NaN; return Number.isFinite(r) && r >= 0 ? r : n; }, "sanitizeNumberValue"), V = /* @__PURE__ */ c((e) => { const n = typeof e == "number" ? e : typeof e == "string" ? Number.parseFloat(e) : NaN; return Number.isFinite(n) && n > 0 ? n : void 0; }, "parseThemeFontSize"), ee = /* @__PURE__ */ c((e) => { const n = B(e.fontFamily, f.fontFamily), r = V(e.fontSize) ?? f.fontSize; return { ...f, fontFamily: n, fontSize: r, terminalFill: d(e.secondBkg ?? e.secondaryColor, f.terminalFill), terminalStroke: d(e.secondaryBorderColor ?? e.lineColor, f.terminalStroke), terminalTextColor: d(e.secondaryTextColor ?? e.textColor, f.terminalTextColor), nonTerminalFill: d(e.mainBkg ?? e.background, f.nonTerminalFill), nonTerminalStroke: d(e.primaryBorderColor ?? e.lineColor, f.nonTerminalStroke), nonTerminalTextColor: d(e.primaryTextColor ?? e.textColor, f.nonTerminalTextColor), lineColor: d(e.lineColor, f.lineColor), markerFill: d(e.lineColor, f.markerFill), commentFill: d(e.labelBackground ?? e.tertiaryColor, f.commentFill), commentStroke: d(e.tertiaryBorderColor ?? e.lineColor, f.commentStroke), commentTextColor: d(e.tertiaryTextColor ?? e.textColor, f.commentTextColor), specialFill: d(e.tertiaryColor ?? e.secondaryColor, f.specialFill), specialStroke: d(e.tertiaryBorderColor ?? e.secondaryBorderColor, f.specialStroke), ruleNameColor: d(e.titleColor ?? e.textColor, f.ruleNameColor) }; }, "buildThemeDefaults"), A = /* @__PURE__ */ c((e) => { const n = W(), r = ee({ ...P(), ...n.themeVariables ?? {}, ...Z(e) }), t = { ...n.railroad ?? {}, ...Q(e) }; return { compactMode: t.compactMode ?? r.compactMode, padding: F(t.padding, r.padding), verticalSeparation: F(t.verticalSeparation, r.verticalSeparation), horizontalSeparation: F(t.horizontalSeparation, r.horizontalSeparation), arcRadius: F(t.arcRadius, r.arcRadius), fontSize: F(t.fontSize, r.fontSize), fontFamily: B(t.fontFamily, r.fontFamily), terminalFill: d(t.terminalFill, r.terminalFill), terminalStroke: d(t.terminalStroke, r.terminalStroke), terminalTextColor: d(t.terminalTextColor, r.terminalTextColor), nonTerminalFill: d(t.nonTerminalFill, r.nonTerminalFill), nonTerminalStroke: d(t.nonTerminalStroke, r.nonTerminalStroke), nonTerminalTextColor: d(t.nonTerminalTextColor, r.nonTerminalTextColor), lineColor: d(t.lineColor, r.lineColor), strokeWidth: F(t.strokeWidth, r.strokeWidth), markerFill: d(t.markerFill, r.markerFill), commentFill: d(t.commentFill, r.commentFill), commentStroke: d(t.commentStroke, r.commentStroke), commentTextColor: d(t.commentTextColor, r.commentTextColor), specialFill: d(t.specialFill, r.specialFill), specialStroke: d(t.specialStroke, r.specialStroke), ruleNameColor: d(t.ruleNameColor, r.ruleNameColor), showMarkers: t.showMarkers ?? r.showMarkers, markerRadius: F(t.markerRadius, r.markerRadius) }; }, "buildRailroadStyleOptions"), oe = /* @__PURE__ */ c((e) => { const { fontFamily: n, fontSize: r, terminalFill: t, terminalStroke: i, terminalTextColor: a, nonTerminalFill: p, nonTerminalStroke: s, nonTerminalTextColor: l, lineColor: u, strokeWidth: o, markerFill: g, commentFill: m, commentStroke: h, commentTextColor: C, specialFill: k, specialStroke: w, ruleNameColor: y } = A(e); return ` .railroad-diagram { font-family: ${n}; font-size: ${r}px; } .railroad-terminal rect { fill: ${t}; stroke: ${i}; stroke-width: ${o}px; } .railroad-terminal text { fill: ${a}; font-family: ${n}; font-size: ${r}px; text-anchor: middle; dominant-baseline: middle; } .railroad-nonterminal rect { fill: ${p}; stroke: ${s}; stroke-width: ${o}px; } .railroad-nonterminal text { fill: ${l}; font-family: ${n}; font-size: ${r}px; text-anchor: middle; dominant-baseline: middle; } .railroad-line { stroke: ${u}; stroke-width: ${o}px; fill: none; } .railroad-start circle, .railroad-end circle { fill: ${g}; } .railroad-comment ellipse { fill: ${m}; stroke: ${h}; stroke-width: ${o}px; } .railroad-comment text { fill: ${C}; font-style: italic; font-family: ${n}; font-size: ${r}px; text-anchor: middle; dominant-baseline: middle; } .railroad-special rect { fill: ${k}; stroke: ${w}; stroke-width: ${o}px; stroke-dasharray: 5,3; } .railroad-special text { fill: ${l}; font-family: ${n}; font-size: ${r}px; text-anchor: middle; dominant-baseline: middle; } .railroad-rule-name { font-weight: bold; fill: ${y}; font-family: ${n}; font-size: ${r}px; } .railroad-group { /* Grouping container, no specific styles */ } `; }, "getStyles"), T = class { constructor() { this.d = ""; } static { c(this, "PathBuilder"); } moveTo(e, n) { return this.d += `M ${e} ${n} `, this; } lineTo(e, n) { return this.d += `L ${e} ${n} `, this; } horizontalTo(e) { return this.d += `H ${e} `, this; } verticalTo(e) { return this.d += `V ${e} `, this; } arcTo(e, n, r, t, i, a, p) { return this.d += `A ${e} ${n} ${r} ${t ? 1 : 0} ${i ? 1 : 0} ${a} ${p} `, this; } build() { return this.d.trim(); } }, te = class { constructor(e, n = A()) { this.textCache = /* @__PURE__ */ new Map(), this.svg = e, this.config = n; } static { c(this, "RailroadRenderer"); } measureText(e) { if (this.textCache.has(e)) return this.textCache.get(e); const n = this.svg.append("text").attr("font-family", this.config.fontFamily).attr("font-size", this.config.fontSize).text(e), r = n.node().getBBox(), t = { width: r.width, height: r.height }; return n.remove(), this.textCache.set(e, t), t; } renderTerminal(e, n) { const r = this.measureText(n), t = r.width + this.config.padding * 2, i = r.height + this.config.padding * 2, a = e.append("g").attr("class", "railroad-terminal"); return a.append("rect").attr("x", 0).attr("y", 0).attr("width", t).attr("height", i).attr("rx", 10).attr("ry", 10), a.append("text").attr("x", t / 2).attr("y", i / 2).text(n), { element: a.node(), dimensions: { width: t, height: i, up: i / 2, down: i / 2 } }; } renderNonTerminal(e, n) { const r = this.measureText(n), t = r.width + this.config.padding * 2, i = r.height + this.config.padding * 2, a = e.append("g").attr("class", "railroad-nonterminal"); return a.append("rect").attr("x", 0).attr("y", 0).attr("width", t).attr("height", i), a.append("text").attr("x", t / 2).attr("y", i / 2).text(n), { element: a.node(), dimensions: { width: t, height: i, up: i / 2, down: i / 2 } }; } renderSequence(e, n) { const r = n.map((l) => this.renderExpression(e, l)); let t = 0, i = 0, a = 0; for (const l of r) t += l.dimensions.width, i = Math.max(i, l.dimensions.up), a = Math.max(a, l.dimensions.down); t += (r.length - 1) * this.config.horizontalSeparation; const p = e.append("g").attr("class", "railroad-sequence"); let s = 0; for (let l = 0; l < r.length; l++) { const u = r[l], o = i - u.dimensions.up; if (p.node().appendChild(u.element).setAttribute("transform", `translate(${s}, ${o})`), l < r.length - 1) { const g = s + u.dimensions.width, m = g + this.config.horizontalSeparation, h = i; p.append("path").attr("class", "railroad-line").attr("d", new T().moveTo(g, h).lineTo(m, h).build()); } s += u.dimensions.width + this.config.horizontalSeparation; } return { element: p.node(), dimensions: { width: t, height: i + a, up: i, down: a } }; } renderChoice(e, n) { const r = n.map((g) => this.renderExpression(e, g)); let t = 0, i = 0; for (const g of r) t = Math.max(t, g.dimensions.width), i += g.dimensions.height; i += (r.length - 1) * this.config.verticalSeparation; const a = this.config.arcRadius, p = a * 4, s = t + p, l = e.append("g").attr("class", "railroad-choice"); let u = 0; const o = i / 2; for (const g of r) { const m = u, h = m + g.dimensions.up, C = a * 2 + (t - g.dimensions.width) / 2; l.node().appendChild(g.element).setAttribute("transform", `translate(${C}, ${m})`); const k = new T(), w = h > o; h === o ? k.moveTo(0, o).lineTo(C, h) : k.moveTo(0, o).arcTo(a, a, 0, !1, w, a, o + (w ? a : -a)).lineTo(a, h - (w ? a : -a)).arcTo(a, a, 0, !1, !w, a * 2, h).lineTo(C, h), l.append("path").attr("class", "railroad-line").attr("d", k.build()); const y = new T(), M = C + g.dimensions.width, Y = s - a * 2; h === o ? y.moveTo(M, h).lineTo(s, o) : y.moveTo(M, h).lineTo(Y, h).arcTo(a, a, 0, !1, !w, s - a, h + (w ? -a : a)).lineTo(s - a, o + (w ? a : -a)).arcTo(a, a, 0, !1, w, s, o), l.append("path").attr("class", "railroad-line").attr("d", y.build()), u += g.dimensions.height + this.config.verticalSeparation; } return { element: l.node(), dimensions: { width: s, height: i, up: o, down: i - o } }; } renderOptional(e, n) { const r = this.renderExpression(e, n), t = this.config.arcRadius, i = t * 2, a = r.dimensions.width + t * 4, p = r.dimensions.height + i, s = e.append("g").attr("class", "railroad-optional"), l = t * 2, u = i; s.node().appendChild(r.element).setAttribute("transform", `translate(${l}, ${u})`); const o = u + r.dimensions.up, g = new T().moveTo(0, o).lineTo(t * 2, o); s.append("path").attr("class", "railroad-line").attr("d", g.build()); const m = new T().moveTo(l + r.dimensions.width, o).lineTo(a, o); s.append("path").attr("class", "railroad-line").attr("d", m.build()); const h = new T().moveTo(0, o).arcTo(t, t, 0, !1, !1, t, o - t).lineTo(t, t).arcTo(t, t, 0, !1, !0, t * 2, 0).lineTo(a - t * 2, 0).arcTo(t, t, 0, !1, !0, a - t, t).lineTo(a - t, o - t).arcTo(t, t, 0, !1, !1, a, o); return s.append("path").attr("class", "railroad-line").attr("d", h.build()), { element: s.node(), dimensions: { width: a, height: p, up: o, down: p - o } }; } renderRepetition(e, n, r) { const t = this.renderExpression(e, n), i = this.config.arcRadius, a = i * 2, p = t.dimensions.width + i * 4, s = r === 0, l = t.dimensions.height + a + (s ? a : 0), u = e.append("g").attr("class", "railroad-repetition"), o = i * 2, g = s ? a : 0; u.node().appendChild(t.element).setAttribute("transform", `translate(${o}, ${g})`); const m = g + t.dimensions.up; u.append("path").attr("class", "railroad-line").attr("d", new T().moveTo(0, m).lineTo(i * 2, m).build()), u.append("path").attr("class", "railroad-line").attr("d", new T().moveTo(o + t.dimensions.width, m).lineTo(p, m).build()); const h = g + t.dimensions.height + i, C = new T().moveTo(o + t.dimensions.width, m).arcTo(i, i, 0, !1, !0, o + t.dimensions.width + i, m + i).lineTo(o + t.dimensions.width + i, h).arcTo(i, i, 0, !1, !0, o + t.dimensions.width, h + i).lineTo(i * 2, h + i).arcTo(i, i, 0, !1, !0, i, h).lineTo(i, m + i).arcTo(i, i, 0, !1, !0, i * 2, m); if (u.append("path").attr("class", "railroad-line").attr("d", C.build()), s) { const k = new T().moveTo(0, m).arcTo(i, i, 0, !1, !1, i, m - i).lineTo(i, i).arcTo(i, i, 0, !1, !0, i * 2, 0).lineTo(p - i * 2, 0).arcTo(i, i, 0, !1, !0, p - i, i).lineTo(p - i, m - i).arcTo(i, i, 0, !1, !1, p, m); u.append("path").attr("class", "railroad-line").attr("d", k.build()); } return { element: u.node(), dimensions: { width: p, height: l, up: m, down: l - m } }; } renderSpecial(e, n) { const r = this.measureText("? " + n + " ?"), t = r.width + this.config.padding * 2, i = r.height + this.config.padding * 2, a = e.append("g").attr("class", "railroad-special"); return a.append("rect").attr("x", 0).attr("y", 0).attr("width", t).attr("height", i), a.append("text").attr("x", t / 2).attr("y", i / 2).text("? " + n + " ?"), { element: a.node(), dimensions: { width: t, height: i, up: i / 2, down: i / 2 } }; } renderExpression(e, n) { switch (n.type) { case "terminal": return this.renderTerminal(e, n.value); case "nonterminal": return this.renderNonTerminal(e, n.name); case "sequence": return this.renderSequence(e, n.elements); case "choice": return this.renderChoice(e, n.alternatives); case "optional": return this.renderOptional(e, n.element); case "repetition": return this.renderRepetition(e, n.element, n.min); case "special": return this.renderSpecial(e, n.text); default: throw new Error(`Unknown node type: ${n.type}`); } } renderRule(e, n) { const r = this.svg.append("g").attr("class", "railroad-rule").attr("transform", `translate(0, ${n})`), t = e.name + " =", i = this.measureText(t).width + 20, a = i + 20, p = r.append("g"), s = this.renderExpression(p, e.definition), l = Math.max(20, s.dimensions.up), u = l - s.dimensions.up; return p.attr("transform", `translate(${a}, ${u})`), r.append("g").attr("class", "railroad-rule-name-group").append("text").attr("class", "railroad-rule-name").attr("x", 0).attr("y", l).text(t), r.append("g").attr("class", "railroad-start").append("circle").attr("cx", i).attr("cy", l).attr("r", this.config.markerRadius), r.append("g").attr("class", "railroad-end").append("circle").attr("cx", a + s.dimensions.width + 10).attr("cy", l).attr("r", this.config.markerRadius), r.append("path").attr("class", "railroad-line").attr("d", new T().moveTo(i + this.config.markerRadius, l).lineTo(a, l).build()), r.append("path").attr("class", "railroad-line").attr("d", new T().moveTo(a + s.dimensions.width, l).lineTo(a + s.dimensions.width + 10 - this.config.markerRadius, l).build()), { height: Math.max(40, u + s.dimensions.height + this.config.padding * 2), width: a + s.dimensions.width + 10 + this.config.markerRadius }; } renderDiagram(e) { let n = this.config.padding, r = 0; for (const t of e) { const i = this.renderRule(t, n); n += i.height + this.config.verticalSeparation, r = Math.max(r, i.width); } return { width: r + this.config.padding * 2, height: n + this.config.padding }; } }, E = /* @__PURE__ */ c((e, n, r) => { I(e, n.height, n.width, r), e.attr("viewBox", `0 0 ${n.width} ${n.height}`); }, "configureRailroadSvgSize"), le = { draw: /* @__PURE__ */ c((e, n, r) => { x.debug(`[Railroad] Rendering diagram ` + e); try { const t = q(n); t.attr("class", "railroad-diagram"); const i = W().railroad?.useMaxWidth ?? !0, a = G.getRules(); if (x.debug(`[Railroad] Rendering ${a.length} rules`), a.length === 0) { x.warn("[Railroad] No rules to render"), E(t, { height: 100, width: 200 }, i); return; } E(t, new te(t, A()).renderDiagram(a), i), x.debug("[Railroad] Render complete"); } catch (t) { throw x.error("[Railroad] Render error:", t), t; } }, "draw") }; export { oe as n, le as r, G as t };