@avodado/render 0.1.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -2124,11 +2124,12 @@ function renderErd(data) {
2124
2124
  const lo = Math.min(sx, tx) + 10;
2125
2125
  const hi = Math.max(sx, tx) - 10;
2126
2126
  const midX = hi > lo ? clamp((sx + tx) / 2, lo, hi) : (sx + tx) / 2;
2127
- s += `<path d="M${round(sx)},${round(fkY)} H${round(midX)} V${round(pkY)} H${round(tx)}" fill="none" stroke="var(--gray)" stroke-width="1.5"/><circle cx="${round(sx)}" cy="${round(fkY)}" r="2.6" fill="var(--gray)"/>` + arrowHeadH(tx, pkY, rightward);
2128
- if (r.card !== void 0) {
2129
- const w2 = 30;
2127
+ const card = parseCard(r.card);
2128
+ s += `<path d="M${round(sx)},${round(fkY)} H${round(midX)} V${round(pkY)} H${round(tx)}" fill="none" stroke="var(--gray)" stroke-width="1.5"/>` + crowFoot(sx, fkY, rightward ? 1 : -1, card.fromMany) + crowFoot(tx, pkY, rightward ? -1 : 1, card.toMany);
2129
+ if (r.label !== void 0 && r.label !== "") {
2130
+ const w2 = Math.max(30, r.label.length * 6.4);
2130
2131
  const cy = (fkY + pkY) / 2;
2131
- s += `<rect x="${round(midX - w2 / 2)}" y="${round(cy - 9)}" width="${w2}" height="18" rx="9" fill="var(--white)" stroke="var(--rule)"/><text x="${round(midX)}" y="${round(cy + 3)}" class="edge-label">${escapeHtml(r.card)}</text>`;
2132
+ s += `<rect x="${round(midX - w2 / 2)}" y="${round(cy - 9)}" width="${round(w2)}" height="18" rx="9" fill="var(--white)" stroke="var(--rule)"/><text x="${round(midX)}" y="${round(cy + 3)}" class="edge-label">${escapeHtml(r.label)}</text>`;
2132
2133
  }
2133
2134
  });
2134
2135
  for (const b of boxes) {
@@ -2180,9 +2181,19 @@ function pickFkIndex(columns, toName) {
2180
2181
  });
2181
2182
  return (match ?? first).i;
2182
2183
  }
2183
- function arrowHeadH(x2, y, pointRight) {
2184
- const dx = pointRight ? -10 : 10;
2185
- return `<path d="M${round(x2 + dx)},${round(y - 5)} L${round(x2)},${round(y)} L${round(x2 + dx)},${round(y + 5)}" fill="none" stroke="var(--navy)" stroke-width="1.6" stroke-linejoin="round" stroke-linecap="round"/>`;
2184
+ function parseCard(card) {
2185
+ if (card === void 0) return { fromMany: true, toMany: false };
2186
+ const parts = card.split(":");
2187
+ const many = (p2) => p2 !== void 0 && p2.trim().toUpperCase() !== "1";
2188
+ return { fromMany: many(parts[0]), toMany: many(parts[1]) };
2189
+ }
2190
+ function crowFoot(bx, y, outward, many) {
2191
+ if (many) {
2192
+ const ax = bx + outward * 14;
2193
+ return `<path d="M${round(ax)},${round(y)} L${round(bx)},${round(y - 7)} M${round(ax)},${round(y)} L${round(bx)},${round(y)} M${round(ax)},${round(y)} L${round(bx)},${round(y + 7)}" fill="none" stroke="var(--navy)" stroke-width="1.4" stroke-linecap="round"/>`;
2194
+ }
2195
+ const tx = bx + outward * 9;
2196
+ return `<line x1="${round(tx)}" y1="${round(y - 6)}" x2="${round(tx)}" y2="${round(y + 6)}" stroke="var(--navy)" stroke-width="1.4" stroke-linecap="round"/>`;
2186
2197
  }
2187
2198
  var clamp = (n, lo, hi) => Math.max(lo, Math.min(hi, n));
2188
2199
  var round = (n) => Math.round(n * 10) / 10;
@@ -2721,6 +2732,51 @@ function edgePill(p2, label, err = false) {
2721
2732
  return `<g><rect x="${p2.lx - w2 / 2}" y="${p2.ly - 9}" width="${w2}" height="18" rx="9" fill="#fff" stroke="#d1d5db"/><text x="${p2.lx}" y="${p2.ly + 3}" class="edge-label${errClass}">${escapeHtml(label)}</text></g>`;
2722
2733
  }
2723
2734
 
2735
+ // src/blocks/autoLayout.ts
2736
+ function ensureGrid(items, edges, rankdir) {
2737
+ const allPlaced = items.length > 0 && items.every((n) => n.col !== void 0 && n.row !== void 0);
2738
+ if (allPlaced) {
2739
+ return items.map((n) => ({ ...n, col: n.col, row: n.row }));
2740
+ }
2741
+ const grid = autoGrid(
2742
+ items.map((n) => n.id),
2743
+ edges,
2744
+ rankdir
2745
+ );
2746
+ return items.map((n) => {
2747
+ const g = grid.get(n.id) ?? { col: 1, row: 1 };
2748
+ return { ...n, col: g.col, row: g.row };
2749
+ });
2750
+ }
2751
+ function autoGrid(ids, edges, rankdir) {
2752
+ const idSet = new Set(ids);
2753
+ const g = new To.graphlib.Graph();
2754
+ g.setGraph({ rankdir, nodesep: 16, ranksep: 16, marginx: 0, marginy: 0 });
2755
+ g.setDefaultEdgeLabel(() => ({}));
2756
+ for (const id of ids) g.setNode(id, { width: 10, height: 10 });
2757
+ for (const e of edges) {
2758
+ if (e.from !== e.to && idSet.has(e.from) && idSet.has(e.to)) g.setEdge(e.from, e.to);
2759
+ }
2760
+ To.layout(g);
2761
+ const pos = ids.map((id) => {
2762
+ const n = g.node(id);
2763
+ return { id, x: Math.round(n?.x ?? 0), y: Math.round(n?.y ?? 0) };
2764
+ });
2765
+ const out = /* @__PURE__ */ new Map();
2766
+ if (rankdir === "TB") {
2767
+ const ranks = [...new Set(pos.map((p2) => p2.y))].sort((a, b) => a - b);
2768
+ ranks.forEach((yv, ri) => {
2769
+ pos.filter((p2) => p2.y === yv).sort((a, b) => a.x - b.x).forEach((p2, ci) => out.set(p2.id, { col: ci + 1, row: ri + 1 }));
2770
+ });
2771
+ } else {
2772
+ const ranks = [...new Set(pos.map((p2) => p2.x))].sort((a, b) => a - b);
2773
+ ranks.forEach((xv, ci) => {
2774
+ pos.filter((p2) => p2.x === xv).sort((a, b) => a.y - b.y).forEach((p2, ri) => out.set(p2.id, { col: ci + 1, row: ri + 1 }));
2775
+ });
2776
+ }
2777
+ return out;
2778
+ }
2779
+
2724
2780
  // src/blocks/flow.ts
2725
2781
  function flowStyle(kind) {
2726
2782
  switch (kind ?? "process") {
@@ -2736,8 +2792,8 @@ function flowStyle(kind) {
2736
2792
  }
2737
2793
  var ERR_LABEL_RE = /^(no|fail|error|reject)/i;
2738
2794
  function renderFlowSvg(data) {
2739
- const nodes = data.nodes ?? [];
2740
2795
  const edges = data.edges ?? [];
2796
+ const nodes = ensureGrid(data.nodes ?? [], edges, "TB");
2741
2797
  const cellW = 176;
2742
2798
  const cellH = 70;
2743
2799
  const gapX = 60;
@@ -2828,8 +2884,8 @@ function pillCls(kind) {
2828
2884
  return "pill pill-active";
2829
2885
  }
2830
2886
  function renderState(data) {
2831
- const states = data.states ?? [];
2832
2887
  const trans = data.transitions ?? [];
2888
+ const states = ensureGrid(data.states ?? [], trans, "LR");
2833
2889
  const cellW = 168;
2834
2890
  const cellH = 64;
2835
2891
  const gapX = 74;
@@ -2901,8 +2957,8 @@ function dfdStyle(kind) {
2901
2957
  }
2902
2958
  }
2903
2959
  function renderDfd(data) {
2904
- const nodes = data.nodes ?? [];
2905
2960
  const edges = data.edges ?? [];
2961
+ const nodes = ensureGrid(data.nodes ?? [], edges, "LR");
2906
2962
  const cellW = 168;
2907
2963
  const cellH = 76;
2908
2964
  const gapX = 60;
@@ -3424,8 +3480,8 @@ var LEGEND = [
3424
3480
  { sw: "#f3f4f6", label: "External" }
3425
3481
  ];
3426
3482
  function renderC4(data) {
3427
- const nodes = data.nodes ?? [];
3428
3483
  const edges = data.edges ?? [];
3484
+ const nodes = ensureGrid(data.nodes ?? [], edges, "TB");
3429
3485
  const byId = new Map(nodes.map((n) => [n.id, n]));
3430
3486
  const cellW = 212;
3431
3487
  const cellH = 102;
@@ -3524,8 +3580,8 @@ function umlRel(kind) {
3524
3580
  }
3525
3581
  }
3526
3582
  function renderUml(data) {
3527
- const classes = data.classes ?? [];
3528
3583
  const rels = data.rels ?? [];
3584
+ const classes = ensureGrid(data.classes ?? [], rels, "TB");
3529
3585
  const colW = 204;
3530
3586
  const gapX = 64;
3531
3587
  const gapY = 50;