@diagrammo/dgmo 0.85.0 → 0.87.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.
Files changed (122) hide show
  1. package/dist/advanced.d.ts +45 -9
  2. package/dist/advanced.js +83 -64
  3. package/dist/block.js +11 -23
  4. package/dist/chart-meta.js +3 -3
  5. package/dist/{chunk-FAV4RDVT.js → chunk-2A4DQAXG.js} +1 -1
  6. package/dist/{chunk-LRNIYQ6Y.js → chunk-33FQ6HNV.js} +1 -1
  7. package/dist/{chunk-JIPUBFAM.js → chunk-5KGM44TG.js} +2 -2
  8. package/dist/{chunk-23RWHHI5.js → chunk-5NU7NII2.js} +14 -2
  9. package/dist/{chunk-QJ2JOLFN.js → chunk-6I5UN4FD.js} +2 -2
  10. package/dist/{chunk-HMWZQ53A.js → chunk-7WGCQE2E.js} +1 -1
  11. package/dist/{chunk-NSS2EF5B.js → chunk-AAMCXQPP.js} +1 -1
  12. package/dist/{chunk-XD7XL3SF.js → chunk-AGO3PFGS.js} +1 -1
  13. package/dist/{chunk-JVRDKR5R.js → chunk-AQIBKTPG.js} +1 -1
  14. package/dist/{chunk-RYZNNXUV.js → chunk-AUS7V54P.js} +1 -1
  15. package/dist/{chunk-ITLPDLBH.js → chunk-B7CU2HW5.js} +3 -3
  16. package/dist/{chunk-X2VEJ5NT.js → chunk-BMUWF77V.js} +2 -2
  17. package/dist/{chunk-6HOVLE3H.js → chunk-BT2WH2XT.js} +1 -1
  18. package/dist/{chunk-3MXJMZAN.js → chunk-BV6PKJUS.js} +105 -28
  19. package/dist/{chunk-7256EOAE.js → chunk-CFBY77QJ.js} +129 -10
  20. package/dist/{chunk-BP4BT5TH.js → chunk-CLQIXD2C.js} +1 -1
  21. package/dist/{chunk-OZTDXMRQ.js → chunk-D4M25W6R.js} +1 -1
  22. package/dist/{chunk-A4PHPKNR.js → chunk-DAX42XVH.js} +1 -1
  23. package/dist/{chunk-C5FEPGSJ.js → chunk-DSG6GBUQ.js} +3 -3
  24. package/dist/{chunk-JLGN6S4B.js → chunk-EJS3K44P.js} +148 -80
  25. package/dist/{chunk-YWHGWLY6.js → chunk-FBKPSU3A.js} +5 -5
  26. package/dist/{chunk-5JO443MB.js → chunk-HAH5X345.js} +1 -1
  27. package/dist/{chunk-HBCAY3KR.js → chunk-HTNLLT34.js} +1 -1
  28. package/dist/{chunk-PEFPTQ3Z.js → chunk-HTPZDZKQ.js} +3 -3
  29. package/dist/{chunk-XXAZ5C4K.js → chunk-IJ27L3R4.js} +1 -1
  30. package/dist/{chunk-OGKP2XGJ.js → chunk-J7Q4VPBJ.js} +2 -2
  31. package/dist/{chunk-VDMG3MM4.js → chunk-JD4RHBNX.js} +1 -1
  32. package/dist/{chunk-HATTVAWX.js → chunk-LJFXC3IP.js} +1 -1
  33. package/dist/{chunk-REUEU5PU.js → chunk-LL6D3MES.js} +3 -3
  34. package/dist/{chunk-ULCB4BLF.js → chunk-LPXC4I4R.js} +19 -2
  35. package/dist/{chunk-BIQYWWJ2.js → chunk-LSQGJN5H.js} +2 -2
  36. package/dist/{chunk-T327J6CE.js → chunk-MSXRNVHB.js} +2 -2
  37. package/dist/{chunk-V3LJIPS4.js → chunk-N7XRBWXA.js} +3 -3
  38. package/dist/{chunk-UJRMARNX.js → chunk-NJIGYGZS.js} +19 -1
  39. package/dist/{chunk-WMIKC5XO.js → chunk-NPWVOFB3.js} +1 -1
  40. package/dist/{chunk-2QIGN7KL.js → chunk-O6MMQQLF.js} +9 -5
  41. package/dist/{chunk-MIZ46MOF.js → chunk-P5V63L35.js} +2 -2
  42. package/dist/{chunk-ADAGWVWJ.js → chunk-PJQZWJ5I.js} +70 -48
  43. package/dist/{chunk-RMAJIB6S.js → chunk-PUVTFUNH.js} +4 -4
  44. package/dist/{chunk-ETBXIKK6.js → chunk-Q2U5635V.js} +1 -1
  45. package/dist/chunk-QT3KDDXK.js +436 -0
  46. package/dist/{chunk-UNSN56OJ.js → chunk-R2K5L4UA.js} +1 -1
  47. package/dist/{chunk-SLMAAJPE.js → chunk-RGI64U3A.js} +1 -1
  48. package/dist/{chunk-ZGHV4QLK.js → chunk-RJNZHFNG.js} +1 -1
  49. package/dist/{chunk-FWNJDD4U.js → chunk-S7W75MIM.js} +3 -20
  50. package/dist/{chunk-ZUUNTOMG.js → chunk-UIUXIDBX.js} +1 -1
  51. package/dist/{chunk-XIYVGO24.js → chunk-UMRZPRAN.js} +3 -3
  52. package/dist/{chunk-67USWFFE.js → chunk-UY6TEJJH.js} +1 -1
  53. package/dist/{chunk-UGYZ5Q5Y.js → chunk-VJ2KROJ5.js} +1 -1
  54. package/dist/{chunk-PSH5DT26.js → chunk-WZ23JJ7U.js} +3 -3
  55. package/dist/{chunk-IIEI7VK5.js → chunk-XCKNFFKM.js} +2 -0
  56. package/dist/{chunk-Y7FTHOMD.js → chunk-XIFK423U.js} +129 -225
  57. package/dist/{chunk-LQSNWE3W.js → chunk-XUDGZJTJ.js} +3 -3
  58. package/dist/{chunk-D7D5YK4J.js → chunk-XVSJYAK7.js} +15 -3
  59. package/dist/{chunk-J2ICADUM.js → chunk-XWYR5T52.js} +3 -3
  60. package/dist/{chunk-QNKHJ5CK.js → chunk-YK4N6TBN.js} +4 -2
  61. package/dist/{chunk-NJS62BAG.js → chunk-YMG7JDEY.js} +17 -7
  62. package/dist/chunk-Z6DXWULM.js +23 -0
  63. package/dist/{chunk-PBEH52A2.js → chunk-ZNNVI5SR.js} +1 -1
  64. package/dist/cloud-reference.d.ts +11 -1
  65. package/dist/cloud-reference.js +1 -1
  66. package/dist/{dgmo-router-VILEOWQ2.js → dgmo-router-F2DSURTR.js} +4 -4
  67. package/dist/{dimensions-F3Y5T54V.js → dimensions-6QAWEGIR.js} +2 -2
  68. package/dist/{flowchart-renderer-TGQL4S4L.js → flowchart-renderer-THC6Y7EH.js} +8 -7
  69. package/dist/index.d.ts +68 -1
  70. package/dist/index.js +81 -13
  71. package/dist/{layout-WZCXK7DF.js → layout-5NPBHV5F.js} +2 -2
  72. package/dist/{layout-WXVGMSI3.js → layout-5VSMZPMG.js} +2 -2
  73. package/dist/{layout-CFTB7GKV.js → layout-BOVTLAOT.js} +7 -6
  74. package/dist/{layout-K6NI4VCS.js → layout-CUFA7XJD.js} +2 -2
  75. package/dist/{layout-6JARW64V.js → layout-EHTYSMV4.js} +6 -5
  76. package/dist/{layout-NB7TKAWN.js → layout-LUQKAGGT.js} +2 -2
  77. package/dist/{layout-YELNBVPC.js → layout-P6DTD4RT.js} +6 -5
  78. package/dist/{layout-PT7IKVCV.js → layout-QX5T6ZNE.js} +2 -2
  79. package/dist/layout-RANVNAKI.js +10 -0
  80. package/dist/{layout-FMKSENGL.js → layout-XUW444O5.js} +5 -4
  81. package/dist/{layout-search-GRJEBAUF.js → layout-search-VKSBUCDM.js} +67 -33
  82. package/dist/live-link-resolve.d.ts +21 -3
  83. package/dist/live-link-resolve.js +47 -17
  84. package/dist/{parser-6TXNMXNB.js → parser-XYY5NHP4.js} +2 -2
  85. package/dist/{renderer-YSH5EX54.js → renderer-222OTVQV.js} +3 -2
  86. package/dist/{renderer-DRLLZZ6P.js → renderer-2KVQGGTT.js} +5 -4
  87. package/dist/{renderer-E5EKGIX2.js → renderer-2OOPQ4CH.js} +4 -3
  88. package/dist/{renderer-OV3GUJRR.js → renderer-36JH4OMC.js} +4 -4
  89. package/dist/{renderer-G72GMBKA.js → renderer-3CTUWCO7.js} +7 -6
  90. package/dist/{renderer-XS42HEXW.js → renderer-3FF4QVGW.js} +4 -3
  91. package/dist/{renderer-R6VJDZFO.js → renderer-4BHOELCE.js} +4 -3
  92. package/dist/{renderer-EU27D4S6.js → renderer-4BIMRO4X.js} +5 -4
  93. package/dist/{renderer-HV6ZYJMC.js → renderer-4NZZ5J2F.js} +2 -2
  94. package/dist/{renderer-UGA5DGKR.js → renderer-A4LMOBZL.js} +9 -8
  95. package/dist/{renderer-3AOOLHJU.js → renderer-A6ACVK4X.js} +3 -2
  96. package/dist/{renderer-HWEGM72C.js → renderer-BICLPGAH.js} +2 -2
  97. package/dist/{renderer-ML2CLU25.js → renderer-DCFQDBGJ.js} +4 -3
  98. package/dist/{renderer-ADX4DWRJ.js → renderer-ELYPDPNF.js} +3 -2
  99. package/dist/{renderer-OXSLLQQC.js → renderer-KVAQE7PQ.js} +2 -2
  100. package/dist/{renderer-X4KFEKUK.js → renderer-LODEVN3V.js} +5 -4
  101. package/dist/{renderer-WUDVV363.js → renderer-NHPKNNBD.js} +6 -5
  102. package/dist/{renderer-TF3NTKP3.js → renderer-NX4YKWCJ.js} +2 -2
  103. package/dist/{renderer-P7LQBDU2.js → renderer-QM23SWAM.js} +2 -2
  104. package/dist/{renderer-5YOF2AHJ.js → renderer-R34GJL7U.js} +9 -8
  105. package/dist/{renderer-FBAFYSIQ.js → renderer-RAATRF6W.js} +3 -3
  106. package/dist/{renderer-FXX3XSNW.js → renderer-RENDISO5.js} +2 -2
  107. package/dist/{renderer-3F4K2X57.js → renderer-RMGN3Q7D.js} +2 -2
  108. package/dist/{renderer-FQAZ3KNU.js → renderer-SDUSBCJI.js} +4 -3
  109. package/dist/{renderer-OVDVFPAI.js → renderer-WH2HWE5Z.js} +5 -4
  110. package/dist/{renderer-J3O2KVTL.js → renderer-X5A5VIRD.js} +6 -5
  111. package/dist/{renderer-WRWVFEX7.js → renderer-XRALFCIN.js} +6 -4
  112. package/dist/{renderer-3XRDFNYF.js → renderer-YDAVCRTP.js} +5 -4
  113. package/dist/{renderer-5A6VWIVX.js → renderer-YIZ7G4HU.js} +5 -5
  114. package/dist/{state-renderer-B4ZF6ESS.js → state-renderer-5IQ4OJUI.js} +8 -7
  115. package/docs/language-reference.md +12 -12
  116. package/gallery/fixtures/journey-map.dgmo +28 -0
  117. package/gallery/fixtures/mindmap.dgmo +31 -0
  118. package/gallery/fixtures/pert.dgmo +27 -0
  119. package/gallery/fixtures/wireframe.dgmo +30 -0
  120. package/package.json +3 -3
  121. package/dist/chunk-WTTIODDV.js +0 -9
  122. package/dist/layout-JQ3IPJYR.js +0 -9
@@ -0,0 +1,436 @@
1
+ import {
2
+ measureText,
3
+ truncateText,
4
+ wrapTextToWidth
5
+ } from "./chunk-KAO7JL4I.js";
6
+
7
+ // src/boxes-and-lines/node-metrics.ts
8
+ var PHI = 1.618;
9
+ var NODE_HEIGHT = 60;
10
+ var NODE_WIDTH = Math.round(NODE_HEIGHT * PHI);
11
+
12
+ // src/boxes-and-lines/label-placement.ts
13
+ import { curveBasis } from "d3-shape";
14
+ var EDGE_LABEL_FONT_SIZE = 11;
15
+ var LABEL_MAX_WIDTH = 160;
16
+ var MAX_LABEL_LINES = 3;
17
+ var LABEL_LINE_HEIGHT = 1.3;
18
+ var H_PAD = 6;
19
+ var V_PAD = 3;
20
+ var BOX_CLEAR_PAD = 4;
21
+ var PERP_STEP = 8;
22
+ var LABEL_REACH_NEAR = 40;
23
+ var LABEL_REACH_WIDE = 56;
24
+ var SLIDE_SAMPLES = 9;
25
+ var CURVE_STEP = 4;
26
+ var EDGE_CLEAR_PAD = 2;
27
+ var GROUP_BORDER_BAND = 4;
28
+ var GROUP_TITLE_FONT_SIZE = 14;
29
+ var GROUP_TITLE_DEPTH = 24;
30
+ var GROUP_LABEL_ZONE = 32;
31
+ function measureEdgeLabel(label, fontSize = EDGE_LABEL_FONT_SIZE, maxWidth = LABEL_MAX_WIDTH) {
32
+ let lines = wrapTextToWidth(label, fontSize, maxWidth, { hardBreak: true });
33
+ if (lines.length > MAX_LABEL_LINES) {
34
+ const kept = lines.slice(0, MAX_LABEL_LINES - 1);
35
+ const rest = lines.slice(MAX_LABEL_LINES - 1).join(" ");
36
+ kept.push(truncateText(rest, fontSize, maxWidth));
37
+ lines = kept;
38
+ }
39
+ let textW = 0;
40
+ for (const ln of lines) {
41
+ const w = measureText(ln, fontSize);
42
+ if (w > textW) textW = w;
43
+ }
44
+ return {
45
+ lines,
46
+ width: textW + 2 * H_PAD,
47
+ height: lines.length * fontSize * LABEL_LINE_HEIGHT + 2 * V_PAD
48
+ };
49
+ }
50
+ function edgePolylineMidpoint(points) {
51
+ return pointAtArcFraction(points, 0.5).p;
52
+ }
53
+ function pointAtArcFraction(points, t) {
54
+ if (points.length === 0) return { p: { x: 0, y: 0 }, nx: 0, ny: 1 };
55
+ if (points.length === 1)
56
+ return { p: { x: points[0].x, y: points[0].y }, nx: 0, ny: 1 };
57
+ const segLen = [];
58
+ let total = 0;
59
+ for (let k = 1; k < points.length; k++) {
60
+ const len = Math.hypot(
61
+ points[k].x - points[k - 1].x,
62
+ points[k].y - points[k - 1].y
63
+ );
64
+ segLen.push(len);
65
+ total += len;
66
+ }
67
+ let want = total * Math.max(0, Math.min(1, t));
68
+ for (let k = 1; k < points.length; k++) {
69
+ const len = segLen[k - 1];
70
+ if (want <= len || k === points.length - 1) {
71
+ const f = len === 0 ? 0 : Math.min(1, want / len);
72
+ const ax = points[k - 1].x;
73
+ const ay = points[k - 1].y;
74
+ const bx = points[k].x;
75
+ const by = points[k].y;
76
+ const dx = bx - ax;
77
+ const dy = by - ay;
78
+ const dlen = Math.hypot(dx, dy) || 1;
79
+ return {
80
+ p: { x: ax + dx * f, y: ay + dy * f },
81
+ nx: -dy / dlen,
82
+ ny: dx / dlen
83
+ };
84
+ }
85
+ want -= len;
86
+ }
87
+ const last = points[points.length - 1];
88
+ return { p: { x: last.x, y: last.y }, nx: 0, ny: 1 };
89
+ }
90
+ function rectFromCenter(cx, cy, w, h) {
91
+ return {
92
+ minX: cx - w / 2,
93
+ minY: cy - h / 2,
94
+ maxX: cx + w / 2,
95
+ maxY: cy + h / 2
96
+ };
97
+ }
98
+ function overlapsAny(cx, cy, w, h, obstacles, pad) {
99
+ const minX = cx - w / 2 - pad;
100
+ const minY = cy - h / 2 - pad;
101
+ const maxX = cx + w / 2 + pad;
102
+ const maxY = cy + h / 2 + pad;
103
+ for (const o of obstacles) {
104
+ if (minX < o.maxX && maxX > o.minX && minY < o.maxY && maxY > o.minY)
105
+ return true;
106
+ }
107
+ return false;
108
+ }
109
+ function slideFractions() {
110
+ const out = [0.5];
111
+ for (let k = 1; k <= SLIDE_SAMPLES; k++) {
112
+ const off = k * 0.08;
113
+ if (0.5 - off >= 0.12) out.push(0.5 - off);
114
+ if (0.5 + off <= 0.88) out.push(0.5 + off);
115
+ }
116
+ return out;
117
+ }
118
+ function findClearPosition(points, blocked, perpMax, firstSide = -1) {
119
+ const ts = slideFractions();
120
+ for (const t of ts) {
121
+ const { p } = pointAtArcFraction(points, t);
122
+ if (!blocked(p.x, p.y)) return p;
123
+ }
124
+ for (let mag = PERP_STEP; mag <= perpMax; mag += PERP_STEP) {
125
+ for (const t of ts) {
126
+ const { p, nx, ny } = pointAtArcFraction(points, t);
127
+ for (const sign of [firstSide, -firstSide]) {
128
+ const x = p.x + nx * mag * sign;
129
+ const y = p.y + ny * mag * sign;
130
+ if (!blocked(x, y)) return { x, y };
131
+ }
132
+ }
133
+ }
134
+ return null;
135
+ }
136
+ function sampleDrawnCurve(points) {
137
+ const out = [];
138
+ if (points.length < 2) return out;
139
+ let cx = 0;
140
+ let cy = 0;
141
+ const ctx = {
142
+ moveTo(x, y) {
143
+ out.push({ x, y });
144
+ cx = x;
145
+ cy = y;
146
+ },
147
+ lineTo(x, y) {
148
+ const n = Math.max(1, Math.ceil(Math.hypot(x - cx, y - cy) / CURVE_STEP));
149
+ for (let k = 1; k <= n; k++)
150
+ out.push({ x: cx + (x - cx) * k / n, y: cy + (y - cy) * k / n });
151
+ cx = x;
152
+ cy = y;
153
+ },
154
+ bezierCurveTo(x1, y1, x2, y2, x, y) {
155
+ const n = Math.max(
156
+ 1,
157
+ Math.ceil(
158
+ (Math.hypot(x1 - cx, y1 - cy) + Math.hypot(x2 - x1, y2 - y1) + Math.hypot(x - x2, y - y2)) / CURVE_STEP
159
+ )
160
+ );
161
+ for (let k = 1; k <= n; k++) {
162
+ const t = k / n;
163
+ const u = 1 - t;
164
+ out.push({
165
+ x: u * u * u * cx + 3 * u * u * t * x1 + 3 * u * t * t * x2 + t * t * t * x,
166
+ y: u * u * u * cy + 3 * u * u * t * y1 + 3 * u * t * t * y2 + t * t * t * y
167
+ });
168
+ }
169
+ cx = x;
170
+ cy = y;
171
+ },
172
+ closePath() {
173
+ }
174
+ };
175
+ const curve = curveBasis(ctx);
176
+ curve.lineStart();
177
+ for (const p of points) curve.point(p.x, p.y);
178
+ curve.lineEnd();
179
+ return out;
180
+ }
181
+ function buildGroupContainers(groups) {
182
+ const byLabel = new Map(groups.map((g) => [g.label, g]));
183
+ const parent = /* @__PURE__ */ new Map();
184
+ for (const g of groups)
185
+ for (const c of g.children) if (byLabel.has(c)) parent.set(c, g.label);
186
+ for (const g of groups) if (g.parentGroup) parent.set(g.label, g.parentGroup);
187
+ const chainOf = (label) => {
188
+ const out = [];
189
+ const seen = /* @__PURE__ */ new Set();
190
+ let cur = label;
191
+ while (cur !== void 0 && byLabel.has(cur) && !seen.has(cur)) {
192
+ seen.add(cur);
193
+ out.push(cur);
194
+ cur = parent.get(cur);
195
+ }
196
+ return out;
197
+ };
198
+ const containers = /* @__PURE__ */ new Map();
199
+ for (const g of groups) containers.set(g.label, new Set(chainOf(g.label)));
200
+ for (const g of groups) {
201
+ const chain = chainOf(g.label);
202
+ for (const c of g.children) {
203
+ if (byLabel.has(c)) continue;
204
+ let set = containers.get(c);
205
+ if (!set) {
206
+ set = /* @__PURE__ */ new Set();
207
+ containers.set(c, set);
208
+ }
209
+ for (const a of chain) set.add(a);
210
+ }
211
+ }
212
+ return containers;
213
+ }
214
+ function resolveLabelOverlaps(boxes) {
215
+ const MAX_PASSES = 8;
216
+ const PAD = 4;
217
+ for (let pass = 0; pass < MAX_PASSES; pass++) {
218
+ let moved = false;
219
+ for (let i = 0; i < boxes.length; i++) {
220
+ for (let j = i + 1; j < boxes.length; j++) {
221
+ const a = boxes[i];
222
+ const b = boxes[j];
223
+ const dx = Math.abs(a.cx - b.cx);
224
+ const dy = Math.abs(a.cy - b.cy);
225
+ const overlapX = (a.w + b.w) / 2 + PAD - dx;
226
+ const overlapY = (a.h + b.h) / 2 + PAD - dy;
227
+ if (overlapX > 0 && overlapY > 0) {
228
+ const shift = overlapY / 2 + 1;
229
+ if (a.cy < b.cy) {
230
+ a.cy -= shift;
231
+ b.cy += shift;
232
+ } else {
233
+ a.cy += shift;
234
+ b.cy -= shift;
235
+ }
236
+ moved = true;
237
+ }
238
+ }
239
+ }
240
+ if (!moved) break;
241
+ }
242
+ }
243
+ function placeEdgeLabels(layout, opts) {
244
+ const fontSize = opts?.fontSize ?? EDGE_LABEL_FONT_SIZE;
245
+ const maxWidth = opts?.maxWidth ?? LABEL_MAX_WIDTH;
246
+ const perpMax = opts?.perpMax ?? LABEL_REACH_NEAR;
247
+ const baseObstacles = [];
248
+ for (const n of layout.nodes)
249
+ baseObstacles.push(rectFromCenter(n.x, n.y, n.width, n.height));
250
+ const expandedGroups = [];
251
+ for (const g of layout.groups) {
252
+ const r = rectFromCenter(g.x, g.y, g.width, g.height);
253
+ if (g.collapsed) baseObstacles.push(r);
254
+ else expandedGroups.push({ label: g.label, rect: r });
255
+ }
256
+ const containers = buildGroupContainers(opts?.groups ?? []);
257
+ const noContainers = /* @__PURE__ */ new Set();
258
+ const obstacleCache = /* @__PURE__ */ new Map();
259
+ const obstaclesFor = (edgeIdx) => {
260
+ const cached = obstacleCache.get(edgeIdx);
261
+ if (cached !== void 0) return cached;
262
+ let out = baseObstacles;
263
+ if (expandedGroups.length > 0) {
264
+ const e = layout.edges[edgeIdx];
265
+ const src = containers.get(e.source) ?? noContainers;
266
+ const tgt = containers.get(e.target) ?? noContainers;
267
+ const foreign = expandedGroups.filter((g) => !(src.has(g.label) && tgt.has(g.label))).map((g) => g.rect);
268
+ if (foreign.length > 0) out = [...baseObstacles, ...foreign];
269
+ }
270
+ obstacleCache.set(edgeIdx, out);
271
+ return out;
272
+ };
273
+ const curves = layout.edges.map((e) => {
274
+ const pts = sampleDrawnCurve(e.points);
275
+ let minX = Infinity;
276
+ let minY = Infinity;
277
+ let maxX = -Infinity;
278
+ let maxY = -Infinity;
279
+ for (const p of pts) {
280
+ if (p.x < minX) minX = p.x;
281
+ if (p.y < minY) minY = p.y;
282
+ if (p.x > maxX) maxX = p.x;
283
+ if (p.y > maxY) maxY = p.y;
284
+ }
285
+ return { pts, minX, minY, maxX, maxY };
286
+ });
287
+ const crossesOtherEdge = (edgeIdx, cx, cy, w, h) => {
288
+ const minX = cx - w / 2 - EDGE_CLEAR_PAD;
289
+ const minY = cy - h / 2 - EDGE_CLEAR_PAD;
290
+ const maxX = cx + w / 2 + EDGE_CLEAR_PAD;
291
+ const maxY = cy + h / 2 + EDGE_CLEAR_PAD;
292
+ for (let j = 0; j < curves.length; j++) {
293
+ if (j === edgeIdx) continue;
294
+ const c = curves[j];
295
+ if (c.maxX < minX || c.minX > maxX || c.maxY < minY || c.minY > maxY)
296
+ continue;
297
+ for (const p of c.pts)
298
+ if (p.x > minX && p.x < maxX && p.y > minY && p.y < maxY) return true;
299
+ }
300
+ return false;
301
+ };
302
+ const hasSubGroup = new Set(
303
+ (opts?.groups ?? []).flatMap((g) => g.parentGroup ? [g.parentGroup] : [])
304
+ );
305
+ const drawnTop = (g) => g.y - g.height / 2 - (hasSubGroup.has(g.label) ? GROUP_LABEL_ZONE : 0);
306
+ const titleRects = layout.groups.filter((g) => !g.collapsed).map((g) => {
307
+ const tw = measureText(g.label, GROUP_TITLE_FONT_SIZE, { bold: true });
308
+ const top = drawnTop(g);
309
+ return {
310
+ minX: g.x - tw / 2,
311
+ minY: top,
312
+ maxX: g.x + tw / 2,
313
+ maxY: top + GROUP_TITLE_DEPTH
314
+ };
315
+ });
316
+ const borderBands = (g) => {
317
+ const B = GROUP_BORDER_BAND;
318
+ const l = g.x - g.width / 2;
319
+ const r = g.x + g.width / 2;
320
+ const t = drawnTop(g);
321
+ const b = g.y + g.height / 2;
322
+ return [
323
+ { minX: l - B, minY: t - B, maxX: r + B, maxY: t + B },
324
+ { minX: l - B, minY: b - B, maxX: r + B, maxY: b + B },
325
+ { minX: l - B, minY: t - B, maxX: l + B, maxY: b + B },
326
+ { minX: r - B, minY: t - B, maxX: r + B, maxY: b + B }
327
+ ];
328
+ };
329
+ const preferredCache = /* @__PURE__ */ new Map();
330
+ const preferredFor = (edgeIdx) => {
331
+ const cached = preferredCache.get(edgeIdx);
332
+ if (cached !== void 0) return cached;
333
+ const e = layout.edges[edgeIdx];
334
+ const src = containers.get(e.source) ?? noContainers;
335
+ const tgt = containers.get(e.target) ?? noContainers;
336
+ const own = layout.groups.filter(
337
+ (g) => !g.collapsed && src.has(g.label) && tgt.has(g.label)
338
+ );
339
+ const out = [
340
+ ...obstaclesFor(edgeIdx),
341
+ ...titleRects,
342
+ ...own.flatMap(borderBands)
343
+ ];
344
+ preferredCache.set(edgeIdx, out);
345
+ return out;
346
+ };
347
+ const clearOfAll = (edgeIdx, cx, cy, w, h) => !overlapsAny(cx, cy, w, h, preferredFor(edgeIdx), BOX_CLEAR_PAD) && !crossesOtherEdge(edgeIdx, cx, cy, w, h);
348
+ const boxes = [];
349
+ layout.edges.forEach((e, idx) => {
350
+ if (!e.label || e.points.length < 2) return;
351
+ const m = measureEdgeLabel(e.label, fontSize, maxWidth);
352
+ const mid = edgePolylineMidpoint(e.points);
353
+ let cy = mid.y;
354
+ if (e.parallelCount > 1 && e.yOffset !== 0)
355
+ cy += (e.yOffset < 0 ? -1 : 1) * (m.height / 2);
356
+ boxes.push({
357
+ edgeIdx: idx,
358
+ cx: mid.x,
359
+ cy,
360
+ w: m.width,
361
+ h: m.height,
362
+ lines: m.lines,
363
+ resolved: true
364
+ });
365
+ });
366
+ for (const box of boxes) {
367
+ const obstacles = obstaclesFor(box.edgeIdx);
368
+ if (clearOfAll(box.edgeIdx, box.cx, box.cy, box.w, box.h)) continue;
369
+ const e = layout.edges[box.edgeIdx];
370
+ const { w, h } = box;
371
+ const mid = pointAtArcFraction(e.points, 0.5);
372
+ const side = (box.cx - mid.p.x) * mid.nx + (box.cy - mid.p.y) * mid.ny > 0 ? 1 : -1;
373
+ const ideal = findClearPosition(
374
+ e.points,
375
+ (x, y) => !clearOfAll(box.edgeIdx, x, y, w, h),
376
+ perpMax,
377
+ side
378
+ );
379
+ if (ideal) {
380
+ box.cx = ideal.x;
381
+ box.cy = ideal.y;
382
+ continue;
383
+ }
384
+ if (!overlapsAny(box.cx, box.cy, w, h, obstacles, BOX_CLEAR_PAD)) continue;
385
+ const clear = findClearPosition(
386
+ e.points,
387
+ (x, y) => overlapsAny(x, y, w, h, obstacles, BOX_CLEAR_PAD),
388
+ perpMax
389
+ ) ?? findClearPosition(
390
+ e.points,
391
+ (x, y) => overlapsAny(x, y, w, h, baseObstacles, BOX_CLEAR_PAD),
392
+ perpMax
393
+ );
394
+ if (clear) {
395
+ box.cx = clear.x;
396
+ box.cy = clear.y;
397
+ }
398
+ if (overlapsAny(box.cx, box.cy, box.w, box.h, obstacles, BOX_CLEAR_PAD))
399
+ box.resolved = false;
400
+ }
401
+ resolveLabelOverlaps(boxes);
402
+ for (const box of boxes) {
403
+ const obstacles = obstaclesFor(box.edgeIdx);
404
+ if (overlapsAny(box.cx, box.cy, box.w, box.h, obstacles, BOX_CLEAR_PAD))
405
+ box.resolved = false;
406
+ }
407
+ const boxByIdx = /* @__PURE__ */ new Map();
408
+ for (const b of boxes) boxByIdx.set(b.edgeIdx, b);
409
+ const edges = layout.edges.map((e, idx) => {
410
+ const b = boxByIdx.get(idx);
411
+ if (!b) return e;
412
+ return {
413
+ ...e,
414
+ labelX: b.cx,
415
+ labelY: b.cy,
416
+ labelWidth: b.w,
417
+ labelHeight: b.h,
418
+ labelLines: b.lines,
419
+ labelResolved: b.resolved
420
+ };
421
+ });
422
+ return {
423
+ layout: { ...layout, edges },
424
+ unresolved: boxes.filter((b) => !b.resolved).map((b) => b.edgeIdx)
425
+ };
426
+ }
427
+
428
+ export {
429
+ NODE_HEIGHT,
430
+ NODE_WIDTH,
431
+ EDGE_LABEL_FONT_SIZE,
432
+ BOX_CLEAR_PAD,
433
+ LABEL_REACH_WIDE,
434
+ measureEdgeLabel,
435
+ placeEdgeLabels
436
+ };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  EDGE_DASH
3
- } from "./chunk-IIEI7VK5.js";
3
+ } from "./chunk-XCKNFFKM.js";
4
4
  import {
5
5
  measureText
6
6
  } from "./chunk-KAO7JL4I.js";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  EDGE_DASH
3
- } from "./chunk-IIEI7VK5.js";
3
+ } from "./chunk-XCKNFFKM.js";
4
4
  import {
5
5
  layoutInlineHeader
6
6
  } from "./chunk-3DOQOXXI.js";
@@ -9,7 +9,7 @@ import {
9
9
  } from "./chunk-5DH3KYFH.js";
10
10
  import {
11
11
  wrapDescriptionLines
12
- } from "./chunk-WMIKC5XO.js";
12
+ } from "./chunk-NPWVOFB3.js";
13
13
  import {
14
14
  measureText
15
15
  } from "./chunk-KAO7JL4I.js";
@@ -1,26 +1,10 @@
1
+ import {
2
+ safeHref
3
+ } from "./chunk-Z6DXWULM.js";
1
4
  import {
2
5
  MONO_FAMILY
3
6
  } from "./chunk-ICLB27PZ.js";
4
7
 
5
- // src/utils/safe-href.ts
6
- var ALLOWED_SCHEMES = ["http", "https", "mailto"];
7
- var SCHEME_RE = /^([a-z][a-z0-9+.-]*):/i;
8
- var LEADING_TRIM_RE = /^[\x00-\x20]+/;
9
- function safeHref(url) {
10
- if (typeof url !== "string") return null;
11
- const trimmed = url.replace(LEADING_TRIM_RE, "");
12
- if (trimmed.length === 0) return null;
13
- const match = SCHEME_RE.exec(trimmed);
14
- if (!match) {
15
- return url;
16
- }
17
- const scheme = match[1].toLowerCase();
18
- if (ALLOWED_SCHEMES.includes(scheme)) {
19
- return url;
20
- }
21
- return null;
22
- }
23
-
24
8
  // src/utils/inline-markdown.ts
25
9
  function parseInlineMarkdown(text) {
26
10
  const spans = [];
@@ -88,7 +72,6 @@ function renderInlineText(textEl, text, palette, fontSize) {
88
72
  }
89
73
 
90
74
  export {
91
- safeHref,
92
75
  parseInlineMarkdown,
93
76
  truncateBareUrl,
94
77
  stripInlineMarkdown,
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-24YPR5EH.js";
4
4
  import {
5
5
  HEADER_HEIGHT
6
- } from "./chunk-IIEI7VK5.js";
6
+ } from "./chunk-XCKNFFKM.js";
7
7
  import {
8
8
  measureText,
9
9
  truncateText
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  layoutOrg
3
- } from "./chunk-LRNIYQ6Y.js";
3
+ } from "./chunk-33FQ6HNV.js";
4
4
  import {
5
5
  renderCollapseBar,
6
6
  renderNodeCard
7
- } from "./chunk-UNSN56OJ.js";
7
+ } from "./chunk-R2K5L4UA.js";
8
8
  import {
9
9
  ScaleContext
10
10
  } from "./chunk-24YPR5EH.js";
@@ -24,7 +24,7 @@ import {
24
24
  META_LINE_HEIGHT,
25
25
  NODE_STROKE_WIDTH,
26
26
  SEPARATOR_GAP
27
- } from "./chunk-IIEI7VK5.js";
27
+ } from "./chunk-XCKNFFKM.js";
28
28
  import {
29
29
  extractExportSvg,
30
30
  runInExportContainer
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  EDGE_DASH,
3
3
  HAIRLINE_DASH
4
- } from "./chunk-IIEI7VK5.js";
4
+ } from "./chunk-XCKNFFKM.js";
5
5
  import {
6
6
  TITLE_FONT_SIZE,
7
7
  TITLE_FONT_WEIGHT,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  buildMapProjection
3
- } from "./chunk-3MXJMZAN.js";
3
+ } from "./chunk-BV6PKJUS.js";
4
4
  import {
5
5
  TITLE_FONT_SIZE,
6
6
  TITLE_Y
@@ -4,14 +4,14 @@ import {
4
4
  layoutC4Containers,
5
5
  layoutC4Context,
6
6
  layoutC4Deployment
7
- } from "./chunk-A4PHPKNR.js";
7
+ } from "./chunk-DAX42XVH.js";
8
8
  import {
9
9
  appendArrowheadMarkers,
10
10
  appendReverseArrowheadMarkers
11
11
  } from "./chunk-XBJJP2HN.js";
12
12
  import {
13
13
  renderInlineText
14
- } from "./chunk-FWNJDD4U.js";
14
+ } from "./chunk-S7W75MIM.js";
15
15
  import {
16
16
  ARROWHEAD_HEIGHT,
17
17
  ARROWHEAD_WIDTH,
@@ -25,7 +25,7 @@ import {
25
25
  META_FONT_SIZE,
26
26
  META_LINE_HEIGHT,
27
27
  NODE_STROKE_WIDTH
28
- } from "./chunk-IIEI7VK5.js";
28
+ } from "./chunk-XCKNFFKM.js";
29
29
  import {
30
30
  serializeSvg
31
31
  } from "./chunk-LD2JSKU3.js";
@@ -5,6 +5,7 @@ var CARD_RADIUS = 6;
5
5
  var CONTAINER_RADIUS = 8;
6
6
  var COLLAPSE_BAR_INSET = 0;
7
7
  var EDGE_LABEL_KNOCKOUT_OPACITY = 0.9;
8
+ var EDGE_LABEL_UNRESOLVED_KNOCKOUT_OPACITY = 1;
8
9
  var ARROWHEAD_WIDTH = 10;
9
10
  var ARROWHEAD_HEIGHT = 7;
10
11
  var EDGE_DASH = "6 3";
@@ -31,6 +32,7 @@ export {
31
32
  CONTAINER_RADIUS,
32
33
  COLLAPSE_BAR_INSET,
33
34
  EDGE_LABEL_KNOCKOUT_OPACITY,
35
+ EDGE_LABEL_UNRESOLVED_KNOCKOUT_OPACITY,
34
36
  ARROWHEAD_WIDTH,
35
37
  ARROWHEAD_HEIGHT,
36
38
  EDGE_DASH,