@diagrammo/dgmo 0.8.10 → 0.8.12

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 (43) hide show
  1. package/dist/cli.cjs +245 -672
  2. package/dist/editor.cjs.map +1 -1
  3. package/dist/editor.d.cts +2 -3
  4. package/dist/editor.d.ts +2 -3
  5. package/dist/editor.js.map +1 -1
  6. package/dist/index.cjs +491 -125
  7. package/dist/index.cjs.map +1 -1
  8. package/dist/index.d.cts +9 -1
  9. package/dist/index.d.ts +9 -1
  10. package/dist/index.js +489 -125
  11. package/dist/index.js.map +1 -1
  12. package/gallery/fixtures/er.dgmo +36 -0
  13. package/gallery/fixtures/kanban.dgmo +27 -0
  14. package/package.json +14 -17
  15. package/src/boxes-and-lines/parser.ts +2 -0
  16. package/src/boxes-and-lines/renderer.ts +13 -5
  17. package/src/c4/layout.ts +31 -10
  18. package/src/c4/parser.ts +5 -1
  19. package/src/completion.ts +17 -2
  20. package/src/d3.ts +220 -102
  21. package/src/echarts.ts +57 -58
  22. package/src/editor/index.ts +1 -2
  23. package/src/er/parser.ts +5 -1
  24. package/src/gantt/parser.ts +8 -0
  25. package/src/gantt/renderer.ts +6 -7
  26. package/src/gantt/resolver.ts +19 -14
  27. package/src/gantt/types.ts +1 -0
  28. package/src/index.ts +2 -0
  29. package/src/infra/parser.ts +4 -0
  30. package/src/kanban/parser.ts +4 -1
  31. package/src/kanban/renderer.ts +11 -8
  32. package/src/label-layout.ts +286 -0
  33. package/src/org/parser.ts +3 -0
  34. package/src/sequence/parser.ts +6 -0
  35. package/src/sequence/renderer.ts +24 -9
  36. package/src/sharing.ts +15 -5
  37. package/src/sitemap/parser.ts +2 -0
  38. package/src/utils/arrows.ts +1 -1
  39. package/src/utils/legend-layout.ts +8 -8
  40. package/src/utils/legend-svg.ts +2 -2
  41. package/src/utils/legend-types.ts +0 -3
  42. package/src/utils/parsing.ts +1 -1
  43. package/src/utils/tag-groups.ts +65 -1
package/dist/index.js CHANGED
@@ -122,6 +122,183 @@ var init_branding = __esm({
122
122
  }
123
123
  });
124
124
 
125
+ // src/label-layout.ts
126
+ function rectsOverlap(a, b) {
127
+ return a.x < b.x + b.w && a.x + a.w > b.x && a.y < b.y + b.h && a.y + a.h > b.y;
128
+ }
129
+ function rectCircleOverlap(rect, circle) {
130
+ const nearestX = Math.max(rect.x, Math.min(circle.cx, rect.x + rect.w));
131
+ const nearestY = Math.max(rect.y, Math.min(circle.cy, rect.y + rect.h));
132
+ const dx = nearestX - circle.cx;
133
+ const dy = nearestY - circle.cy;
134
+ return dx * dx + dy * dy < circle.r * circle.r;
135
+ }
136
+ function computeQuadrantPointLabels(points, chartBounds, obstacles, pointRadius, fontSize) {
137
+ const labelHeight = fontSize + 4;
138
+ const stepSize = labelHeight + 2;
139
+ const minGap = pointRadius + 4;
140
+ const pointCircles = points.map((p) => ({
141
+ cx: p.cx,
142
+ cy: p.cy,
143
+ r: pointRadius
144
+ }));
145
+ const placedLabels = [];
146
+ const results = [];
147
+ for (let i = 0; i < points.length; i++) {
148
+ const pt = points[i];
149
+ const labelWidth = pt.label.length * fontSize * CHAR_WIDTH_RATIO + 8;
150
+ let best = null;
151
+ const directions = [
152
+ {
153
+ // Above
154
+ gen: (offset) => {
155
+ const lx = pt.cx - labelWidth / 2;
156
+ const ly = pt.cy - offset - labelHeight;
157
+ if (ly < chartBounds.top || lx < chartBounds.left || lx + labelWidth > chartBounds.right)
158
+ return null;
159
+ return {
160
+ rect: { x: lx, y: ly, w: labelWidth, h: labelHeight },
161
+ textX: pt.cx,
162
+ textY: ly + labelHeight / 2,
163
+ anchor: "middle"
164
+ };
165
+ }
166
+ },
167
+ {
168
+ // Below
169
+ gen: (offset) => {
170
+ const lx = pt.cx - labelWidth / 2;
171
+ const ly = pt.cy + offset;
172
+ if (ly + labelHeight > chartBounds.bottom || lx < chartBounds.left || lx + labelWidth > chartBounds.right)
173
+ return null;
174
+ return {
175
+ rect: { x: lx, y: ly, w: labelWidth, h: labelHeight },
176
+ textX: pt.cx,
177
+ textY: ly + labelHeight / 2,
178
+ anchor: "middle"
179
+ };
180
+ }
181
+ },
182
+ {
183
+ // Right
184
+ gen: (offset) => {
185
+ const lx = pt.cx + offset;
186
+ const ly = pt.cy - labelHeight / 2;
187
+ if (lx + labelWidth > chartBounds.right || ly < chartBounds.top || ly + labelHeight > chartBounds.bottom)
188
+ return null;
189
+ return {
190
+ rect: { x: lx, y: ly, w: labelWidth, h: labelHeight },
191
+ textX: lx,
192
+ textY: pt.cy,
193
+ anchor: "start"
194
+ };
195
+ }
196
+ },
197
+ {
198
+ // Left
199
+ gen: (offset) => {
200
+ const lx = pt.cx - offset - labelWidth;
201
+ const ly = pt.cy - labelHeight / 2;
202
+ if (lx < chartBounds.left || ly < chartBounds.top || ly + labelHeight > chartBounds.bottom)
203
+ return null;
204
+ return {
205
+ rect: { x: lx, y: ly, w: labelWidth, h: labelHeight },
206
+ textX: lx + labelWidth,
207
+ textY: pt.cy,
208
+ anchor: "end"
209
+ };
210
+ }
211
+ }
212
+ ];
213
+ for (const { gen } of directions) {
214
+ for (let offset = minGap; ; offset += stepSize) {
215
+ const cand = gen(offset);
216
+ if (!cand) break;
217
+ let collision = false;
218
+ for (const pl of placedLabels) {
219
+ if (rectsOverlap(cand.rect, pl)) {
220
+ collision = true;
221
+ break;
222
+ }
223
+ }
224
+ if (!collision) {
225
+ for (const circle of pointCircles) {
226
+ if (rectCircleOverlap(cand.rect, circle)) {
227
+ collision = true;
228
+ break;
229
+ }
230
+ }
231
+ }
232
+ if (!collision) {
233
+ for (const obs of obstacles) {
234
+ if (rectsOverlap(cand.rect, obs)) {
235
+ collision = true;
236
+ break;
237
+ }
238
+ }
239
+ }
240
+ if (!collision) {
241
+ const dist = offset;
242
+ if (!best || dist < best.dist) {
243
+ best = {
244
+ rect: cand.rect,
245
+ textX: cand.textX,
246
+ textY: cand.textY,
247
+ anchor: cand.anchor,
248
+ dist
249
+ };
250
+ }
251
+ break;
252
+ }
253
+ }
254
+ }
255
+ if (!best) {
256
+ const lx = pt.cx - labelWidth / 2;
257
+ const ly = pt.cy - minGap - labelHeight;
258
+ best = {
259
+ rect: { x: lx, y: ly, w: labelWidth, h: labelHeight },
260
+ textX: pt.cx,
261
+ textY: ly + labelHeight / 2,
262
+ anchor: "middle",
263
+ dist: minGap
264
+ };
265
+ }
266
+ placedLabels.push(best.rect);
267
+ let connectorLine;
268
+ if (best.dist > minGap + stepSize) {
269
+ const dx = best.textX - pt.cx;
270
+ const dy = best.textY - pt.cy;
271
+ const angle = Math.atan2(dy, dx);
272
+ const x1 = pt.cx + Math.cos(angle) * pointRadius;
273
+ const y1 = pt.cy + Math.sin(angle) * pointRadius;
274
+ const x2 = Math.max(
275
+ best.rect.x,
276
+ Math.min(pt.cx, best.rect.x + best.rect.w)
277
+ );
278
+ const y2 = Math.max(
279
+ best.rect.y,
280
+ Math.min(pt.cy, best.rect.y + best.rect.h)
281
+ );
282
+ connectorLine = { x1, y1, x2, y2 };
283
+ }
284
+ results.push({
285
+ label: pt.label,
286
+ x: best.textX,
287
+ y: best.textY,
288
+ anchor: best.anchor,
289
+ connectorLine
290
+ });
291
+ }
292
+ return results;
293
+ }
294
+ var CHAR_WIDTH_RATIO;
295
+ var init_label_layout = __esm({
296
+ "src/label-layout.ts"() {
297
+ "use strict";
298
+ CHAR_WIDTH_RATIO = 0.6;
299
+ }
300
+ });
301
+
125
302
  // src/colors.ts
126
303
  function resolveColor(color, palette) {
127
304
  if (color.startsWith("#")) return null;
@@ -1752,6 +1929,16 @@ function validateTagValues(entities, tagGroups, pushWarning, suggestFn) {
1752
1929
  }
1753
1930
  }
1754
1931
  }
1932
+ function validateTagGroupNames(tagGroups, pushWarning) {
1933
+ for (const group of tagGroups) {
1934
+ if (group.name.toLowerCase() === "none") {
1935
+ pushWarning(
1936
+ group.lineNumber,
1937
+ `'none' is a reserved keyword and cannot be used as a tag group name`
1938
+ );
1939
+ }
1940
+ }
1941
+ }
1755
1942
  function injectDefaultTagMetadata(entities, tagGroups, skip) {
1756
1943
  const defaults = [];
1757
1944
  for (const group of tagGroups) {
@@ -1772,6 +1959,19 @@ function injectDefaultTagMetadata(entities, tagGroups, skip) {
1772
1959
  }
1773
1960
  }
1774
1961
  }
1962
+ function resolveActiveTagGroup(tagGroups, explicitActiveTag, programmaticOverride) {
1963
+ if (programmaticOverride !== void 0) {
1964
+ if (!programmaticOverride) return null;
1965
+ if (programmaticOverride.toLowerCase() === "none") return null;
1966
+ return programmaticOverride;
1967
+ }
1968
+ if (explicitActiveTag) {
1969
+ if (explicitActiveTag.toLowerCase() === "none") return null;
1970
+ return explicitActiveTag;
1971
+ }
1972
+ if (tagGroups.length > 0) return tagGroups[0].name;
1973
+ return null;
1974
+ }
1775
1975
  function matchTagBlockHeading(trimmed) {
1776
1976
  return parseTagDeclaration(trimmed);
1777
1977
  }
@@ -1792,7 +1992,7 @@ function measureLegendText(text, fontSize) {
1792
1992
  }
1793
1993
  return w;
1794
1994
  }
1795
- var LEGEND_HEIGHT, LEGEND_PILL_PAD, LEGEND_PILL_FONT_SIZE, LEGEND_CAPSULE_PAD, LEGEND_DOT_R, LEGEND_ENTRY_FONT_SIZE, LEGEND_ENTRY_DOT_GAP, LEGEND_ENTRY_TRAIL, LEGEND_GROUP_GAP, LEGEND_EYE_SIZE, LEGEND_EYE_GAP, LEGEND_ICON_W, CHAR_W, DEFAULT_W, EYE_OPEN_PATH, EYE_CLOSED_PATH;
1995
+ var LEGEND_HEIGHT, LEGEND_PILL_PAD, LEGEND_PILL_FONT_SIZE, LEGEND_CAPSULE_PAD, LEGEND_DOT_R, LEGEND_ENTRY_FONT_SIZE, LEGEND_ENTRY_DOT_GAP, LEGEND_ENTRY_TRAIL, LEGEND_GROUP_GAP, LEGEND_EYE_SIZE, LEGEND_EYE_GAP, LEGEND_ICON_W, LEGEND_MAX_ENTRY_ROWS, CHAR_W, DEFAULT_W, EYE_OPEN_PATH, EYE_CLOSED_PATH;
1796
1996
  var init_legend_constants = __esm({
1797
1997
  "src/utils/legend-constants.ts"() {
1798
1998
  "use strict";
@@ -1808,6 +2008,7 @@ var init_legend_constants = __esm({
1808
2008
  LEGEND_EYE_SIZE = 14;
1809
2009
  LEGEND_EYE_GAP = 6;
1810
2010
  LEGEND_ICON_W = 20;
2011
+ LEGEND_MAX_ENTRY_ROWS = 3;
1811
2012
  CHAR_W = {
1812
2013
  " ": 0.28,
1813
2014
  "!": 0.28,
@@ -2074,13 +2275,15 @@ function computeLegendLayout(config, state, containerWidth) {
2074
2275
  });
2075
2276
  }
2076
2277
  }
2278
+ const alignLeft = config.position.titleRelation === "inline-with-title";
2077
2279
  const rows = layoutRows(
2078
2280
  activeCapsule,
2079
2281
  pills,
2080
2282
  controlLayouts,
2081
2283
  groupAvailW,
2082
2284
  containerWidth,
2083
- totalControlsW
2285
+ totalControlsW,
2286
+ alignLeft
2084
2287
  );
2085
2288
  const height = rows.length * LEGEND_HEIGHT;
2086
2289
  const width = containerWidth;
@@ -2154,7 +2357,7 @@ function buildCapsuleLayout(group, containerWidth, addonWidth = 0) {
2154
2357
  addonX: addonWidth > 0 ? LEGEND_CAPSULE_PAD + pw + 4 : void 0
2155
2358
  };
2156
2359
  }
2157
- function layoutRows(activeCapsule, pills, controls, groupAvailW, containerWidth, totalControlsW) {
2360
+ function layoutRows(activeCapsule, pills, controls, groupAvailW, containerWidth, totalControlsW, alignLeft = false) {
2158
2361
  const rows = [];
2159
2362
  const groupItems = [];
2160
2363
  if (activeCapsule) groupItems.push(activeCapsule);
@@ -2165,7 +2368,8 @@ function layoutRows(activeCapsule, pills, controls, groupAvailW, containerWidth,
2165
2368
  for (const item of groupItems) {
2166
2369
  const itemW = item.width + LEGEND_GROUP_GAP;
2167
2370
  if (currentRowW + item.width > groupAvailW && currentRowItems.length > 0) {
2168
- centerRowItems(currentRowItems, containerWidth, totalControlsW);
2371
+ if (!alignLeft)
2372
+ centerRowItems(currentRowItems, containerWidth, totalControlsW);
2169
2373
  rows.push({ y: rowY, items: currentRowItems });
2170
2374
  rowY += LEGEND_HEIGHT;
2171
2375
  currentRowItems = [];
@@ -2217,12 +2421,11 @@ function getLegendReservedHeight(config, state, containerWidth) {
2217
2421
  const layout = computeLegendLayout(config, state, containerWidth);
2218
2422
  return layout.height;
2219
2423
  }
2220
- var LEGEND_MAX_ENTRY_ROWS, CONTROL_PILL_PAD, CONTROL_FONT_SIZE, CONTROL_ICON_GAP, CONTROL_GAP;
2424
+ var CONTROL_PILL_PAD, CONTROL_FONT_SIZE, CONTROL_ICON_GAP, CONTROL_GAP;
2221
2425
  var init_legend_layout = __esm({
2222
2426
  "src/utils/legend-layout.ts"() {
2223
2427
  "use strict";
2224
2428
  init_legend_constants();
2225
- LEGEND_MAX_ENTRY_ROWS = 3;
2226
2429
  CONTROL_PILL_PAD = 16;
2227
2430
  CONTROL_FONT_SIZE = 11;
2228
2431
  CONTROL_ICON_GAP = 4;
@@ -3433,7 +3636,8 @@ function parseSequenceDgmo(content) {
3433
3636
  if (top.block.type === "if") {
3434
3637
  const branch = {
3435
3638
  label: elseIfMatch[1].trim(),
3436
- children: []
3639
+ children: [],
3640
+ lineNumber
3437
3641
  };
3438
3642
  if (!top.block.elseIfBranches) top.block.elseIfBranches = [];
3439
3643
  top.block.elseIfBranches.push(branch);
@@ -3456,6 +3660,7 @@ function parseSequenceDgmo(content) {
3456
3660
  if (top.block.type === "if") {
3457
3661
  top.inElse = true;
3458
3662
  top.activeElseIfBranch = void 0;
3663
+ top.block.elseLineNumber = lineNumber;
3459
3664
  }
3460
3665
  }
3461
3666
  continue;
@@ -3568,6 +3773,7 @@ function parseSequenceDgmo(content) {
3568
3773
  entities.push({ metadata: g.metadata, lineNumber: g.lineNumber });
3569
3774
  }
3570
3775
  validateTagValues(entities, result.tagGroups, pushWarning, suggest);
3776
+ validateTagGroupNames(result.tagGroups, pushWarning);
3571
3777
  }
3572
3778
  return result;
3573
3779
  }
@@ -4844,6 +5050,10 @@ function parseERDiagram(content, palette) {
4844
5050
  (line10, msg) => result.diagnostics.push(makeDgmoError(line10, msg, "warning")),
4845
5051
  suggest
4846
5052
  );
5053
+ validateTagGroupNames(
5054
+ result.tagGroups,
5055
+ (line10, msg) => result.diagnostics.push(makeDgmoError(line10, msg, "warning"))
5056
+ );
4847
5057
  for (const group of result.tagGroups) {
4848
5058
  if (!group.defaultValue) continue;
4849
5059
  const key = group.name.toLowerCase();
@@ -4939,7 +5149,7 @@ var init_parser3 = __esm({
4939
5149
  unique: "unique",
4940
5150
  nullable: "nullable"
4941
5151
  };
4942
- KNOWN_OPTIONS = /* @__PURE__ */ new Set(["notation"]);
5152
+ KNOWN_OPTIONS = /* @__PURE__ */ new Set(["notation", "active-tag"]);
4943
5153
  REL_SYMBOLIC_RE = /^([a-zA-Z_]\w*)\s+([1*?])\s*-{1,2}\s*([1*?])\s+([a-zA-Z_]\w*)(?:\s+(.+))?$/;
4944
5154
  REL_KEYWORD_RE = /^([a-zA-Z_]\w*)\s+(one|many|zero)[- ]to[- ](one|many|zero)\s+([a-zA-Z_]\w*)(?:\s+(.+))?$/i;
4945
5155
  KEYWORD_TO_SYMBOL = {
@@ -5849,7 +6059,8 @@ function buildExtendedChartOption(parsed, palette, isDark) {
5849
6059
  }
5850
6060
  const { textColor, axisLineColor, gridOpacity, colors, titleConfig } = buildChartCommons(parsed, palette, isDark);
5851
6061
  if (parsed.type === "sankey") {
5852
- return buildSankeyOption(parsed, textColor, colors, titleConfig);
6062
+ const bg = isDark ? palette.surface : palette.bg;
6063
+ return buildSankeyOption(parsed, textColor, colors, bg, titleConfig);
5853
6064
  }
5854
6065
  if (parsed.type === "chord") {
5855
6066
  const bg = isDark ? palette.surface : palette.bg;
@@ -5892,7 +6103,7 @@ function buildExtendedChartOption(parsed, palette, isDark) {
5892
6103
  titleConfig
5893
6104
  );
5894
6105
  }
5895
- function buildSankeyOption(parsed, textColor, colors, titleConfig) {
6106
+ function buildSankeyOption(parsed, textColor, colors, bg, titleConfig) {
5896
6107
  const nodeSet = /* @__PURE__ */ new Set();
5897
6108
  if (parsed.links) {
5898
6109
  for (const link of parsed.links) {
@@ -5900,12 +6111,15 @@ function buildSankeyOption(parsed, textColor, colors, titleConfig) {
5900
6111
  nodeSet.add(link.target);
5901
6112
  }
5902
6113
  }
5903
- const nodes = Array.from(nodeSet).map((name, index) => ({
5904
- name,
5905
- itemStyle: {
5906
- color: parsed.nodeColors?.[name] ?? colors[index % colors.length]
5907
- }
5908
- }));
6114
+ const tintNode = (c) => mix(c, bg, 75);
6115
+ const tintLink = (c) => mix(c, bg, 45);
6116
+ const nodeColorMap = /* @__PURE__ */ new Map();
6117
+ const nodes = Array.from(nodeSet).map((name, index) => {
6118
+ const raw = parsed.nodeColors?.[name] ?? colors[index % colors.length];
6119
+ const tinted = tintNode(raw);
6120
+ nodeColorMap.set(name, tintLink(raw));
6121
+ return { name, itemStyle: { color: tinted } };
6122
+ });
5909
6123
  return {
5910
6124
  ...CHART_BASE,
5911
6125
  title: titleConfig,
@@ -5928,11 +6142,13 @@ function buildSankeyOption(parsed, textColor, colors, titleConfig) {
5928
6142
  source: link.source,
5929
6143
  target: link.target,
5930
6144
  value: link.value,
5931
- ...link.color && { lineStyle: { color: link.color } }
6145
+ lineStyle: {
6146
+ color: link.color ? tintLink(link.color) : nodeColorMap.get(link.source)
6147
+ }
5932
6148
  })),
5933
6149
  lineStyle: {
5934
- color: "gradient",
5935
- curveness: 0.5
6150
+ curveness: 0.5,
6151
+ opacity: 0.6
5936
6152
  },
5937
6153
  label: {
5938
6154
  color: textColor,
@@ -6027,7 +6243,7 @@ function buildChordOption(parsed, textColor, colors, bg, titleConfig) {
6027
6243
  };
6028
6244
  });
6029
6245
  })(),
6030
- roam: true,
6246
+ roam: false,
6031
6247
  label: {
6032
6248
  position: "right",
6033
6249
  formatter: "{b}"
@@ -6189,16 +6405,6 @@ function getExtendedChartLegendGroups(parsed, colors) {
6189
6405
  }
6190
6406
  return [];
6191
6407
  }
6192
- function rectsOverlap(a, b) {
6193
- return a.x < b.x + b.w && a.x + a.w > b.x && a.y < b.y + b.h && a.y + a.h > b.y;
6194
- }
6195
- function rectCircleOverlap(rect, circle) {
6196
- const nearestX = Math.max(rect.x, Math.min(circle.cx, rect.x + rect.w));
6197
- const nearestY = Math.max(rect.y, Math.min(circle.cy, rect.y + rect.h));
6198
- const dx = nearestX - circle.cx;
6199
- const dy = nearestY - circle.cy;
6200
- return dx * dx + dy * dy < circle.r * circle.r;
6201
- }
6202
6408
  function computeScatterLabelGraphics(points, chartBounds, fontSize, symbolSize, bg) {
6203
6409
  const labelHeight = fontSize + 4;
6204
6410
  const stepSize = labelHeight + 2;
@@ -6575,12 +6781,17 @@ function buildHeatmapOption(parsed, palette, isDark, textColor, axisLineColor, t
6575
6781
  maxValue = Math.max(maxValue, value);
6576
6782
  });
6577
6783
  });
6784
+ const CHAR_WIDTH7 = 7;
6785
+ const ESTIMATED_CHART_WIDTH = 900;
6786
+ const longestCol = Math.max(...columns.map((c) => c.length), 0);
6787
+ const slotWidth = columns.length > 0 ? ESTIMATED_CHART_WIDTH / columns.length : Infinity;
6788
+ const needsRotation = longestCol * CHAR_WIDTH7 > slotWidth * 0.85;
6578
6789
  return {
6579
6790
  ...CHART_BASE,
6580
6791
  title: titleConfig,
6581
6792
  grid: {
6582
6793
  left: "3%",
6583
- right: "10%",
6794
+ right: "3%",
6584
6795
  bottom: "3%",
6585
6796
  top: parsed.title ? "15%" : "5%",
6586
6797
  containLabel: true
@@ -6588,6 +6799,7 @@ function buildHeatmapOption(parsed, palette, isDark, textColor, axisLineColor, t
6588
6799
  xAxis: {
6589
6800
  type: "category",
6590
6801
  data: columns,
6802
+ position: "top",
6591
6803
  splitArea: {
6592
6804
  show: true
6593
6805
  },
@@ -6596,12 +6808,19 @@ function buildHeatmapOption(parsed, palette, isDark, textColor, axisLineColor, t
6596
6808
  },
6597
6809
  axisLabel: {
6598
6810
  color: textColor,
6599
- fontSize: 16
6811
+ fontSize: 12,
6812
+ interval: 0,
6813
+ ...needsRotation && {
6814
+ rotate: -45,
6815
+ width: 200,
6816
+ overflow: "none"
6817
+ }
6600
6818
  }
6601
6819
  },
6602
6820
  yAxis: {
6603
6821
  type: "category",
6604
6822
  data: rowLabels,
6823
+ inverse: true,
6605
6824
  splitArea: {
6606
6825
  show: true
6607
6826
  },
@@ -6610,16 +6829,14 @@ function buildHeatmapOption(parsed, palette, isDark, textColor, axisLineColor, t
6610
6829
  },
6611
6830
  axisLabel: {
6612
6831
  color: textColor,
6613
- fontSize: 16
6832
+ fontSize: 12,
6833
+ interval: 0
6614
6834
  }
6615
6835
  },
6616
6836
  visualMap: {
6837
+ show: false,
6617
6838
  min: minValue,
6618
6839
  max: maxValue,
6619
- calculable: true,
6620
- orient: "vertical",
6621
- right: "2%",
6622
- top: "center",
6623
6840
  inRange: {
6624
6841
  color: [
6625
6842
  mix(palette.primary, bg, 30),
@@ -6627,9 +6844,6 @@ function buildHeatmapOption(parsed, palette, isDark, textColor, axisLineColor, t
6627
6844
  mix(palette.colors.yellow, bg, 30),
6628
6845
  mix(palette.colors.orange, bg, 30)
6629
6846
  ]
6630
- },
6631
- textStyle: {
6632
- color: textColor
6633
6847
  }
6634
6848
  },
6635
6849
  series: [
@@ -6647,9 +6861,8 @@ function buildHeatmapOption(parsed, palette, isDark, textColor, axisLineColor, t
6647
6861
  fontWeight: "bold"
6648
6862
  },
6649
6863
  emphasis: {
6650
- ...EMPHASIS_SELF
6651
- },
6652
- blur: BLUR_DIM
6864
+ disabled: true
6865
+ }
6653
6866
  }
6654
6867
  ]
6655
6868
  };
@@ -7503,6 +7716,7 @@ var init_echarts = __esm({
7503
7716
  init_fonts();
7504
7717
  init_branding();
7505
7718
  init_legend_svg();
7719
+ init_label_layout();
7506
7720
  init_palettes();
7507
7721
  init_color_utils();
7508
7722
  init_chart();
@@ -7784,6 +7998,7 @@ function parseOrg(content, palette) {
7784
7998
  };
7785
7999
  collectAll(result.roots);
7786
8000
  validateTagValues(allNodes, result.tagGroups, pushWarning, suggest);
8001
+ validateTagGroupNames(result.tagGroups, pushWarning);
7787
8002
  }
7788
8003
  if (result.roots.length === 0 && result.tagGroups.length === 0 && !result.error) {
7789
8004
  const diag = makeDgmoError(1, "No nodes found in org chart");
@@ -7850,7 +8065,8 @@ var init_parser4 = __esm({
7850
8065
  KNOWN_OPTIONS3 = /* @__PURE__ */ new Set([
7851
8066
  "sub-node-label",
7852
8067
  "hide",
7853
- "show-sub-node-count"
8068
+ "show-sub-node-count",
8069
+ "active-tag"
7854
8070
  ]);
7855
8071
  KNOWN_BOOLEANS2 = /* @__PURE__ */ new Set(["show-sub-node-count", "direction-tb"]);
7856
8072
  }
@@ -8111,6 +8327,7 @@ function parseKanban(content, palette) {
8111
8327
  if (result.columns.length === 0 && !result.error) {
8112
8328
  return fail(1, "No columns found. Use [Column Name] to define columns");
8113
8329
  }
8330
+ validateTagGroupNames(result.tagGroups, warn);
8114
8331
  return result;
8115
8332
  }
8116
8333
  function parseCardLine(trimmed, lineNumber, counter, aliasMap, palette) {
@@ -8156,7 +8373,7 @@ var init_parser5 = __esm({
8156
8373
  init_parsing();
8157
8374
  COLUMN_RE = /^\[(.+?)\](?:\s*\(([^)]+)\))?\s*(?:\|\s*(.+))?$/;
8158
8375
  LEGACY_COLUMN_RE = /^==\s+(.+?)\s*(?:\[wip:\s*(\d+)\])?\s*==$/;
8159
- KNOWN_OPTIONS4 = /* @__PURE__ */ new Set(["hide"]);
8376
+ KNOWN_OPTIONS4 = /* @__PURE__ */ new Set(["hide", "active-tag"]);
8160
8377
  KNOWN_BOOLEANS3 = /* @__PURE__ */ new Set(["no-auto-color"]);
8161
8378
  }
8162
8379
  });
@@ -8699,6 +8916,10 @@ function parseC4(content, palette) {
8699
8916
  }
8700
8917
  validateRelationshipTargets(result, knownNames, pushError);
8701
8918
  validateDeploymentRefs(result, knownNames, pushError);
8919
+ validateTagGroupNames(
8920
+ result.tagGroups,
8921
+ (line10, msg) => pushError(line10, msg, "warning")
8922
+ );
8702
8923
  return result;
8703
8924
  }
8704
8925
  function findParentElement(indent, stack) {
@@ -8825,7 +9046,7 @@ var init_parser6 = __esm({
8825
9046
  "cloud",
8826
9047
  "external"
8827
9048
  ]);
8828
- KNOWN_C4_OPTIONS = /* @__PURE__ */ new Set(["layout"]);
9049
+ KNOWN_C4_OPTIONS = /* @__PURE__ */ new Set(["layout", "active-tag"]);
8829
9050
  KNOWN_C4_BOOLEANS = /* @__PURE__ */ new Set(["direction-tb"]);
8830
9051
  ALL_CHART_TYPES2 = [
8831
9052
  "c4",
@@ -9163,6 +9384,7 @@ function parseSitemap(content, palette) {
9163
9384
  };
9164
9385
  collectAll(result.roots);
9165
9386
  validateTagValues(allNodes, result.tagGroups, pushWarning, suggest);
9387
+ validateTagGroupNames(result.tagGroups, pushWarning);
9166
9388
  }
9167
9389
  if (result.roots.length === 0 && result.tagGroups.length === 0 && !result.error) {
9168
9390
  const diag = makeDgmoError(1, "No pages found in sitemap");
@@ -9763,6 +9985,7 @@ function parseInfra(content) {
9763
9985
  }
9764
9986
  }
9765
9987
  }
9988
+ validateTagGroupNames(result.tagGroups, warn);
9766
9989
  return result;
9767
9990
  }
9768
9991
  function extractSymbols4(docText) {
@@ -9841,7 +10064,8 @@ var init_parser8 = __esm({
9841
10064
  "slo-warning-margin",
9842
10065
  "default-latency-ms",
9843
10066
  "default-uptime",
9844
- "default-rps"
10067
+ "default-rps",
10068
+ "active-tag"
9845
10069
  ]);
9846
10070
  UNPARSED_SPLIT_RE = /\bsplit\s+(\d+)%/;
9847
10071
  }
@@ -10039,6 +10263,7 @@ function parseGantt(content, palette) {
10039
10263
  dependencies: true,
10040
10264
  sort: "default",
10041
10265
  defaultSwimlaneGroup: null,
10266
+ activeTag: null,
10042
10267
  optionLineNumbers: {},
10043
10268
  holidaysLineNumber: null
10044
10269
  },
@@ -10453,6 +10678,9 @@ function parseGantt(content, palette) {
10453
10678
  );
10454
10679
  }
10455
10680
  break;
10681
+ case "active-tag":
10682
+ result.options.activeTag = value;
10683
+ break;
10456
10684
  }
10457
10685
  continue;
10458
10686
  }
@@ -10632,6 +10860,7 @@ function parseGantt(content, palette) {
10632
10860
  warn(0, "sort tag has no effect \u2014 no tag groups defined.");
10633
10861
  result.options.sort = "default";
10634
10862
  }
10863
+ validateTagGroupNames(result.tagGroups, warn);
10635
10864
  return result;
10636
10865
  function makeTask(labelRaw, duration, uncertain, ln, explicitStart) {
10637
10866
  const segments = labelRaw.split("|");
@@ -10794,7 +11023,8 @@ var init_parser9 = __esm({
10794
11023
  "critical-path",
10795
11024
  "dependencies",
10796
11025
  "chart",
10797
- "sort"
11026
+ "sort",
11027
+ "active-tag"
10798
11028
  ]);
10799
11029
  KNOWN_BOOLEANS4 = /* @__PURE__ */ new Set([
10800
11030
  "critical-path",
@@ -11214,6 +11444,7 @@ function parseBoxesAndLines(content) {
11214
11444
  if (result.tagGroups.length > 0) {
11215
11445
  injectDefaultTagMetadata(result.nodes, result.tagGroups);
11216
11446
  validateTagValues(result.nodes, result.tagGroups, pushWarning, suggest);
11447
+ validateTagGroupNames(result.tagGroups, pushWarning);
11217
11448
  }
11218
11449
  return result;
11219
11450
  }
@@ -14071,8 +14302,7 @@ function computeLayout(parsed, _palette) {
14071
14302
  currentX += cl.width + COLUMN_GAP;
14072
14303
  }
14073
14304
  const totalWidth = currentX - COLUMN_GAP + DIAGRAM_PADDING3;
14074
- const legendSpace = parsed.tagGroups.length > 0 ? LEGEND_HEIGHT : 0;
14075
- const totalHeight = startY + maxColumnHeight + DIAGRAM_PADDING3 + legendSpace;
14305
+ const totalHeight = startY + maxColumnHeight + DIAGRAM_PADDING3;
14076
14306
  return { columns: columnLayouts, totalWidth, totalHeight };
14077
14307
  }
14078
14308
  function renderKanban(container, parsed, palette, isDark, _onNavigateToLine, exportDims, activeTagGroup) {
@@ -14085,14 +14315,16 @@ function renderKanban(container, parsed, palette, isDark, _onNavigateToLine, exp
14085
14315
  svg.append("text").attr("class", "chart-title").attr("data-line-number", parsed.titleLineNumber ?? 0).attr("x", DIAGRAM_PADDING3).attr("y", DIAGRAM_PADDING3 + TITLE_FONT_SIZE).attr("font-size", TITLE_FONT_SIZE).attr("font-weight", TITLE_FONT_WEIGHT).attr("fill", palette.text).text(parsed.title);
14086
14316
  }
14087
14317
  if (parsed.tagGroups.length > 0) {
14088
- const legendY = height - LEGEND_HEIGHT;
14318
+ const titleTextWidth = parsed.title ? measureLegendText(parsed.title, TITLE_FONT_SIZE) + 16 : 0;
14319
+ const legendX = DIAGRAM_PADDING3 + titleTextWidth;
14320
+ const legendY = DIAGRAM_PADDING3 + (TITLE_FONT_SIZE - LEGEND_HEIGHT) / 2;
14089
14321
  const legendConfig = {
14090
14322
  groups: parsed.tagGroups,
14091
- position: { placement: "top-center", titleRelation: "below-title" },
14323
+ position: { placement: "top-center", titleRelation: "inline-with-title" },
14092
14324
  mode: exportDims ? "inline" : "fixed"
14093
14325
  };
14094
14326
  const legendState = { activeGroup: activeTagGroup ?? null };
14095
- const legendG = svg.append("g").attr("class", "kanban-legend").attr("transform", `translate(${DIAGRAM_PADDING3},${legendY})`);
14327
+ const legendG = svg.append("g").attr("class", "kanban-legend").attr("transform", `translate(${legendX},${legendY})`);
14096
14328
  renderLegendD3(
14097
14329
  legendG,
14098
14330
  legendConfig,
@@ -14100,7 +14332,7 @@ function renderKanban(container, parsed, palette, isDark, _onNavigateToLine, exp
14100
14332
  palette,
14101
14333
  isDark,
14102
14334
  void 0,
14103
- width - DIAGRAM_PADDING3 * 2
14335
+ width - legendX - DIAGRAM_PADDING3
14104
14336
  );
14105
14337
  }
14106
14338
  const defaultColBg = isDark ? mix(palette.surface, palette.bg, 50) : mix(palette.surface, palette.bg, 30);
@@ -15642,7 +15874,7 @@ function fitTextToNode(label, nodeWidth, nodeHeight) {
15642
15874
  const maxTextWidth = nodeWidth - NODE_TEXT_PADDING * 2;
15643
15875
  const lineHeight = 1.3;
15644
15876
  for (let fontSize = NODE_FONT_SIZE; fontSize >= MIN_NODE_FONT_SIZE; fontSize--) {
15645
- const charWidth2 = fontSize * CHAR_WIDTH_RATIO;
15877
+ const charWidth2 = fontSize * CHAR_WIDTH_RATIO2;
15646
15878
  const maxCharsPerLine = Math.floor(maxTextWidth / charWidth2);
15647
15879
  const maxLines = Math.floor((nodeHeight - 8) / (fontSize * lineHeight));
15648
15880
  if (maxCharsPerLine < 2 || maxLines < 1) continue;
@@ -15694,7 +15926,7 @@ function fitTextToNode(label, nodeWidth, nodeHeight) {
15694
15926
  }
15695
15927
  if (hardLines.length <= maxLines) return { lines: hardLines, fontSize };
15696
15928
  }
15697
- const charWidth = MIN_NODE_FONT_SIZE * CHAR_WIDTH_RATIO;
15929
+ const charWidth = MIN_NODE_FONT_SIZE * CHAR_WIDTH_RATIO2;
15698
15930
  const maxChars = Math.floor((nodeWidth - NODE_TEXT_PADDING * 2) / charWidth);
15699
15931
  const truncated = label.length > maxChars ? label.slice(0, maxChars - 1) + "\u2026" : label;
15700
15932
  return { lines: [truncated], fontSize: MIN_NODE_FONT_SIZE };
@@ -15771,7 +16003,11 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
15771
16003
  const width = exportDims?.width ?? container.clientWidth;
15772
16004
  const height = exportDims?.height ?? container.clientHeight;
15773
16005
  if (width <= 0 || height <= 0) return;
15774
- const activeGroup = activeTagGroup ?? parsed.options["active-tag"] ?? null;
16006
+ const activeGroup = resolveActiveTagGroup(
16007
+ parsed.tagGroups,
16008
+ parsed.options["active-tag"],
16009
+ activeTagGroup
16010
+ );
15775
16011
  const hidden = hiddenTagValues ?? parsed.initialHiddenTagValues;
15776
16012
  const nodeMap = /* @__PURE__ */ new Map();
15777
16013
  for (const node of parsed.nodes) nodeMap.set(node.label, node);
@@ -15853,7 +16089,7 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
15853
16089
  path.attr("marker-start", `url(#${revId})`);
15854
16090
  }
15855
16091
  if (le.label && le.labelX != null && le.labelY != null) {
15856
- const lw = le.label.length * EDGE_LABEL_FONT_SIZE4 * CHAR_WIDTH_RATIO;
16092
+ const lw = le.label.length * EDGE_LABEL_FONT_SIZE4 * CHAR_WIDTH_RATIO2;
15857
16093
  labelPositions.push({
15858
16094
  x: le.labelX,
15859
16095
  y: le.labelY + le.yOffset,
@@ -15911,7 +16147,7 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
15911
16147
  const descY = labelY + lineH / 2 + gap + META_FONT_SIZE3 / 2;
15912
16148
  nodeG.append("text").attr("x", 0).attr("y", labelY).attr("text-anchor", "middle").attr("dominant-baseline", "central").attr("font-size", NODE_FONT_SIZE).attr("font-weight", "600").attr("fill", colors.text).text(node.label);
15913
16149
  const maxChars = Math.floor(
15914
- (ln.width - NODE_TEXT_PADDING * 2) / (META_FONT_SIZE3 * CHAR_WIDTH_RATIO)
16150
+ (ln.width - NODE_TEXT_PADDING * 2) / (META_FONT_SIZE3 * CHAR_WIDTH_RATIO2)
15915
16151
  );
15916
16152
  const desc = node.description.length > maxChars ? node.description.slice(0, maxChars - 1) + "\u2026" : node.description;
15917
16153
  const descEl = nodeG.append("text").attr("x", 0).attr("y", descY).attr("text-anchor", "middle").attr("dominant-baseline", "central").attr("font-size", META_FONT_SIZE3).attr("fill", palette.textMuted).text(desc);
@@ -15949,10 +16185,11 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
15949
16185
  }
15950
16186
  function renderBoxesAndLinesForExport(container, parsed, layout, palette, isDark, options) {
15951
16187
  renderBoxesAndLines(container, parsed, layout, palette, isDark, {
15952
- exportDims: options?.exportDims
16188
+ exportDims: options?.exportDims,
16189
+ activeTagGroup: options?.activeTagGroup
15953
16190
  });
15954
16191
  }
15955
- var DIAGRAM_PADDING6, NODE_FONT_SIZE, MIN_NODE_FONT_SIZE, META_FONT_SIZE3, EDGE_LABEL_FONT_SIZE4, EDGE_STROKE_WIDTH5, NODE_STROKE_WIDTH5, NODE_RX, COLLAPSE_BAR_HEIGHT3, ARROWHEAD_W2, ARROWHEAD_H2, CHAR_WIDTH_RATIO, NODE_TEXT_PADDING, GROUP_RX, GROUP_LABEL_FONT_SIZE, lineGeneratorLR, lineGeneratorTB, lineGeneratorLinear2;
16192
+ var DIAGRAM_PADDING6, NODE_FONT_SIZE, MIN_NODE_FONT_SIZE, META_FONT_SIZE3, EDGE_LABEL_FONT_SIZE4, EDGE_STROKE_WIDTH5, NODE_STROKE_WIDTH5, NODE_RX, COLLAPSE_BAR_HEIGHT3, ARROWHEAD_W2, ARROWHEAD_H2, CHAR_WIDTH_RATIO2, NODE_TEXT_PADDING, GROUP_RX, GROUP_LABEL_FONT_SIZE, lineGeneratorLR, lineGeneratorTB, lineGeneratorLinear2;
15956
16193
  var init_renderer6 = __esm({
15957
16194
  "src/boxes-and-lines/renderer.ts"() {
15958
16195
  "use strict";
@@ -15973,7 +16210,7 @@ var init_renderer6 = __esm({
15973
16210
  COLLAPSE_BAR_HEIGHT3 = 4;
15974
16211
  ARROWHEAD_W2 = 5;
15975
16212
  ARROWHEAD_H2 = 4;
15976
- CHAR_WIDTH_RATIO = 0.6;
16213
+ CHAR_WIDTH_RATIO2 = 0.6;
15977
16214
  NODE_TEXT_PADDING = 12;
15978
16215
  GROUP_RX = 8;
15979
16216
  GROUP_LABEL_FONT_SIZE = 14;
@@ -16045,7 +16282,7 @@ function reduceCrossings(g, edgeList, nodeGroupMap) {
16045
16282
  }
16046
16283
  const nodeGeometry = /* @__PURE__ */ new Map();
16047
16284
  for (const name of g.nodes()) {
16048
- const pos = g.node(name);
16285
+ const pos = gNode(g, name);
16049
16286
  if (pos)
16050
16287
  nodeGeometry.set(name, {
16051
16288
  y: pos.y,
@@ -16055,14 +16292,14 @@ function reduceCrossings(g, edgeList, nodeGroupMap) {
16055
16292
  }
16056
16293
  const rankMap = /* @__PURE__ */ new Map();
16057
16294
  for (const name of g.nodes()) {
16058
- const pos = g.node(name);
16295
+ const pos = gNode(g, name);
16059
16296
  if (!pos) continue;
16060
16297
  const rankY = Math.round(pos.y);
16061
16298
  if (!rankMap.has(rankY)) rankMap.set(rankY, []);
16062
16299
  rankMap.get(rankY).push(name);
16063
16300
  }
16064
16301
  for (const [, rankNodes] of rankMap) {
16065
- rankNodes.sort((a, b) => g.node(a).x - g.node(b).x);
16302
+ rankNodes.sort((a, b) => gNode(g, a).x - gNode(g, b).x);
16066
16303
  }
16067
16304
  let anyMoved = false;
16068
16305
  for (const [, rankNodes] of rankMap) {
@@ -16089,10 +16326,10 @@ function reduceCrossings(g, edgeList, nodeGroupMap) {
16089
16326
  }
16090
16327
  for (const partition of partitions) {
16091
16328
  if (partition.length < 2) continue;
16092
- const xSlots = partition.map((name) => g.node(name).x).sort((a, b) => a - b);
16329
+ const xSlots = partition.map((name) => gNode(g, name).x).sort((a, b) => a - b);
16093
16330
  const basePositions = /* @__PURE__ */ new Map();
16094
16331
  for (const name of g.nodes()) {
16095
- const pos = g.node(name);
16332
+ const pos = gNode(g, name);
16096
16333
  if (pos) basePositions.set(name, pos.x);
16097
16334
  }
16098
16335
  const currentPenalty = computeEdgePenalty(
@@ -16170,7 +16407,7 @@ function reduceCrossings(g, edgeList, nodeGroupMap) {
16170
16407
  }
16171
16408
  if (bestPerm.some((name, i) => name !== partition[i])) {
16172
16409
  for (let i = 0; i < bestPerm.length; i++) {
16173
- g.node(bestPerm[i]).x = xSlots[i];
16410
+ gNode(g, bestPerm[i]).x = xSlots[i];
16174
16411
  const rankIdx = rankNodes.indexOf(partition[i]);
16175
16412
  if (rankIdx >= 0) rankNodes[rankIdx] = bestPerm[i];
16176
16413
  }
@@ -16180,10 +16417,10 @@ function reduceCrossings(g, edgeList, nodeGroupMap) {
16180
16417
  }
16181
16418
  if (anyMoved) {
16182
16419
  for (const edge of edgeList) {
16183
- const edgeData = g.edge(edge.source, edge.target);
16420
+ const edgeData = gEdge(g, edge.source, edge.target);
16184
16421
  if (!edgeData) continue;
16185
- const srcPos = g.node(edge.source);
16186
- const tgtPos = g.node(edge.target);
16422
+ const srcPos = gNode(g, edge.source);
16423
+ const tgtPos = gNode(g, edge.target);
16187
16424
  if (!srcPos || !tgtPos) continue;
16188
16425
  const srcBottom = { x: srcPos.x, y: srcPos.y + srcPos.height / 2 };
16189
16426
  const tgtTop = { x: tgtPos.x, y: tgtPos.y - tgtPos.height / 2 };
@@ -17627,11 +17864,13 @@ function layoutC4Deployment(parsed, activeTagGroup) {
17627
17864
  height: totalHeight
17628
17865
  };
17629
17866
  }
17630
- var CHAR_WIDTH5, MIN_NODE_WIDTH, MAX_NODE_WIDTH, TYPE_LABEL_HEIGHT, DIVIDER_GAP, NAME_HEIGHT, DESC_LINE_HEIGHT, DESC_CHAR_WIDTH, CARD_V_PAD3, CARD_H_PAD3, META_LINE_HEIGHT5, META_CHAR_WIDTH, MARGIN4, BOUNDARY_PAD, GROUP_BOUNDARY_PAD, LEGEND_HEIGHT4, LEGEND_PILL_PAD4, LEGEND_DOT_R4, LEGEND_ENTRY_DOT_GAP4, LEGEND_ENTRY_TRAIL4, LEGEND_CAPSULE_PAD4, EDGE_NODE_COLLISION_WEIGHT, META_EXCLUDE_KEYS;
17867
+ var gNode, gEdge, CHAR_WIDTH5, MIN_NODE_WIDTH, MAX_NODE_WIDTH, TYPE_LABEL_HEIGHT, DIVIDER_GAP, NAME_HEIGHT, DESC_LINE_HEIGHT, DESC_CHAR_WIDTH, CARD_V_PAD3, CARD_H_PAD3, META_LINE_HEIGHT5, META_CHAR_WIDTH, MARGIN4, BOUNDARY_PAD, GROUP_BOUNDARY_PAD, LEGEND_HEIGHT4, LEGEND_PILL_PAD4, LEGEND_DOT_R4, LEGEND_ENTRY_DOT_GAP4, LEGEND_ENTRY_TRAIL4, LEGEND_CAPSULE_PAD4, EDGE_NODE_COLLISION_WEIGHT, META_EXCLUDE_KEYS;
17631
17868
  var init_layout6 = __esm({
17632
17869
  "src/c4/layout.ts"() {
17633
17870
  "use strict";
17634
17871
  init_legend_constants();
17872
+ gNode = (g, name) => g.node(name);
17873
+ gEdge = (g, v, w) => g.edge(v, w);
17635
17874
  CHAR_WIDTH5 = 8;
17636
17875
  MIN_NODE_WIDTH = 160;
17637
17876
  MAX_NODE_WIDTH = 260;
@@ -22563,7 +22802,11 @@ function renderGantt(container, resolved, palette, isDark, options, exportDims)
22563
22802
  const collapsedLanes = options?.collapsedLanes;
22564
22803
  const onToggleLane = options?.onToggleLane;
22565
22804
  const seriesColors2 = getSeriesColors(palette);
22566
- let currentActiveGroup = options?.currentActiveGroup !== void 0 ? options.currentActiveGroup : resolved.tagGroups.length > 0 ? resolved.tagGroups[0].name : null;
22805
+ let currentActiveGroup = resolveActiveTagGroup(
22806
+ resolved.tagGroups,
22807
+ resolved.options.activeTag ?? void 0,
22808
+ options?.currentActiveGroup
22809
+ );
22567
22810
  let criticalPathActive = false;
22568
22811
  const tagRows = currentSwimlaneGroup ? buildTagLaneRowList(resolved, currentSwimlaneGroup, collapsedLanes) : null;
22569
22812
  const rows = tagRows ?? buildRowList(resolved, collapsedGroups);
@@ -24921,7 +25164,11 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
24921
25164
  );
24922
25165
  if (participants.length === 0) return;
24923
25166
  const activationsOff = parsedOptions.activations?.toLowerCase() === "off";
24924
- const activeTagGroup = options?.activeTagGroup !== void 0 ? options.activeTagGroup || void 0 : parsedOptions["active-tag"] || void 0;
25167
+ const activeTagGroup = resolveActiveTagGroup(
25168
+ parsed.tagGroups,
25169
+ parsedOptions["active-tag"],
25170
+ options?.activeTagGroup
25171
+ ) ?? void 0;
24925
25172
  let tagMap;
24926
25173
  const tagValueToColor = /* @__PURE__ */ new Map();
24927
25174
  if (activeTagGroup) {
@@ -25435,7 +25682,8 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
25435
25682
  for (const branch of el.elseIfBranches) {
25436
25683
  elseIfBranchData.push({
25437
25684
  label: branch.label,
25438
- indices: collectMsgIndices(branch.children)
25685
+ indices: collectMsgIndices(branch.children),
25686
+ lineNumber: branch.lineNumber
25439
25687
  });
25440
25688
  }
25441
25689
  }
@@ -25496,14 +25744,16 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
25496
25744
  x1: frameX,
25497
25745
  y1: dividerY,
25498
25746
  x2: frameX + frameW,
25499
- y2: dividerY
25747
+ y2: dividerY,
25748
+ blockLine: branchData.lineNumber
25500
25749
  });
25501
25750
  deferredLabels.push({
25502
25751
  x: frameX + 6,
25503
25752
  y: dividerY + 14,
25504
25753
  text: `else if ${branchData.label}`,
25505
25754
  bold: false,
25506
- italic: true
25755
+ italic: true,
25756
+ blockLine: branchData.lineNumber
25507
25757
  });
25508
25758
  }
25509
25759
  }
@@ -25521,14 +25771,16 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
25521
25771
  x1: frameX,
25522
25772
  y1: dividerY,
25523
25773
  x2: frameX + frameW,
25524
- y2: dividerY
25774
+ y2: dividerY,
25775
+ blockLine: el.elseLineNumber
25525
25776
  });
25526
25777
  deferredLabels.push({
25527
25778
  x: frameX + 6,
25528
25779
  y: dividerY + 14,
25529
25780
  text: "else",
25530
25781
  bold: false,
25531
- italic: true
25782
+ italic: true,
25783
+ blockLine: el.elseLineNumber
25532
25784
  });
25533
25785
  }
25534
25786
  }
@@ -25574,7 +25826,9 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
25574
25826
  }
25575
25827
  });
25576
25828
  for (const ln of deferredLines) {
25577
- svg.append("line").attr("x1", ln.x1).attr("y1", ln.y1).attr("x2", ln.x2).attr("y2", ln.y2).attr("stroke", palette.textMuted).attr("stroke-width", 1).attr("stroke-dasharray", "2 3");
25829
+ const line10 = svg.append("line").attr("x1", ln.x1).attr("y1", ln.y1).attr("x2", ln.x2).attr("y2", ln.y2).attr("stroke", palette.textMuted).attr("stroke-width", 1).attr("stroke-dasharray", "2 3").attr("class", "block-divider");
25830
+ if (ln.blockLine !== void 0)
25831
+ line10.attr("data-block-line", String(ln.blockLine));
25578
25832
  }
25579
25833
  for (const lbl of deferredLabels) {
25580
25834
  const t = svg.append("text").attr("x", lbl.x).attr("y", lbl.y).attr("fill", palette.text).attr("font-size", 11).attr("class", "block-label").text(lbl.text);
@@ -25916,6 +26170,7 @@ var init_renderer10 = __esm({
25916
26170
  init_colors();
25917
26171
  init_parser();
25918
26172
  init_tag_resolution();
26173
+ init_tag_groups();
25919
26174
  init_legend_constants();
25920
26175
  init_legend_d3();
25921
26176
  init_title_constants();
@@ -26876,6 +27131,10 @@ function parseVisualization(content, palette) {
26876
27131
  (line10, msg) => result.diagnostics.push(makeDgmoError(line10, msg, "warning")),
26877
27132
  suggest
26878
27133
  );
27134
+ validateTagGroupNames(
27135
+ result.timelineTagGroups,
27136
+ (line10, msg) => result.diagnostics.push(makeDgmoError(line10, msg, "warning"))
27137
+ );
26879
27138
  for (const group of result.timelineTagGroups) {
26880
27139
  if (!group.defaultValue) continue;
26881
27140
  const key = group.name.toLowerCase();
@@ -27772,6 +28031,26 @@ function buildEventTooltipHtml(ev) {
27772
28031
  function buildEraTooltipHtml(era) {
27773
28032
  return `<strong>${era.label}</strong><br>${formatDateLabel(era.startDate)} \u2192 ${formatDateLabel(era.endDate)}`;
27774
28033
  }
28034
+ function renderTimelineGroupLegend(g, groups, groupColorMap, textColor, palette, isDark, legendY, onHover, onLeave) {
28035
+ const PILL_H = 22;
28036
+ const DOT_R = 4;
28037
+ const DOT_GAP = 4;
28038
+ const PAD_X = 10;
28039
+ const FONT_SIZE = 11;
28040
+ const GAP = 8;
28041
+ const pillBg = isDark ? mix(palette.surface, palette.bg, 50) : mix(palette.surface, palette.bg, 30);
28042
+ let legendX = 0;
28043
+ for (const grp of groups) {
28044
+ const color = groupColorMap.get(grp.name) ?? textColor;
28045
+ const textW = measureLegendText(grp.name, FONT_SIZE);
28046
+ const pillW = PAD_X + DOT_R * 2 + DOT_GAP + textW + PAD_X;
28047
+ const itemG = g.append("g").attr("class", "tl-legend-item").attr("data-group", grp.name).style("cursor", "pointer").on("mouseenter", () => onHover(grp.name)).on("mouseleave", () => onLeave());
28048
+ itemG.append("rect").attr("x", legendX).attr("y", legendY - PILL_H / 2).attr("width", pillW).attr("height", PILL_H).attr("rx", PILL_H / 2).attr("fill", pillBg);
28049
+ itemG.append("circle").attr("cx", legendX + PAD_X + DOT_R).attr("cy", legendY).attr("r", DOT_R).attr("fill", color);
28050
+ itemG.append("text").attr("x", legendX + PAD_X + DOT_R * 2 + DOT_GAP).attr("y", legendY).attr("dy", "0.35em").attr("fill", textColor).attr("font-size", `${FONT_SIZE}px`).attr("font-family", FONT_FAMILY).text(grp.name);
28051
+ legendX += pillW + GAP;
28052
+ }
28053
+ }
27775
28054
  function renderTimeline(container, parsed, palette, isDark, onClickItem, exportDims, activeTagGroup, swimlaneTagGroup, onTagStateChange, viewMode) {
27776
28055
  d3Selection13.select(container).selectAll(":not([data-d3-tooltip])").remove();
27777
28056
  const {
@@ -28163,15 +28442,17 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
28163
28442
  );
28164
28443
  }
28165
28444
  if (timelineGroups.length > 0) {
28166
- let legendX = 0;
28167
- const legendY = -55;
28168
- for (const grp of timelineGroups) {
28169
- const color = groupColorMap.get(grp.name) ?? textColor;
28170
- const itemG = g.append("g").attr("class", "tl-legend-item").attr("data-group", grp.name).style("cursor", "pointer").on("mouseenter", () => fadeToGroup(g, grp.name)).on("mouseleave", () => fadeReset(g));
28171
- itemG.append("circle").attr("cx", legendX).attr("cy", legendY).attr("r", 5).attr("fill", color);
28172
- itemG.append("text").attr("x", legendX + 10).attr("y", legendY).attr("dy", "0.35em").attr("fill", textColor).attr("font-size", "11px").text(grp.name);
28173
- legendX += grp.name.length * 7 + 30;
28174
- }
28445
+ renderTimelineGroupLegend(
28446
+ g,
28447
+ timelineGroups,
28448
+ groupColorMap,
28449
+ textColor,
28450
+ palette,
28451
+ isDark,
28452
+ -55,
28453
+ (name) => fadeToGroup(g, name),
28454
+ () => fadeReset(g)
28455
+ );
28175
28456
  }
28176
28457
  g.append("line").attr("x1", axisX).attr("y1", 0).attr("x2", axisX).attr("y2", innerHeight).attr("stroke", mutedColor).attr("stroke-width", 1).attr("stroke-dasharray", "4,4");
28177
28458
  for (const ev of sorted) {
@@ -28398,7 +28679,7 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
28398
28679
  }
28399
28680
  evG.append("rect").attr("x", x).attr("y", y - BAR_H2 / 2).attr("width", rectW).attr("height", BAR_H2).attr("rx", 4).attr("fill", fill2).attr("stroke", stroke2).attr("stroke-width", 2);
28400
28681
  if (labelFitsInside) {
28401
- evG.append("text").attr("x", x + 8).attr("y", y).attr("dy", "0.35em").attr("text-anchor", "start").attr("fill", textColor).attr("font-size", "14px").attr("font-weight", "700").text(ev.label);
28682
+ evG.append("text").attr("x", x + 8).attr("y", y).attr("dy", "0.35em").attr("text-anchor", "start").attr("fill", textColor).attr("font-size", "13px").text(ev.label);
28402
28683
  } else {
28403
28684
  const wouldFlipLeft = x + rectW > innerWidth * 0.6;
28404
28685
  const labelFitsLeft = x - 6 - estLabelWidth > 0;
@@ -28479,15 +28760,18 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
28479
28760
  );
28480
28761
  }
28481
28762
  if (timelineGroups.length > 0) {
28482
- let legendX = 0;
28483
28763
  const legendY = timelineScale ? -75 : -55;
28484
- for (const grp of timelineGroups) {
28485
- const color = groupColorMap.get(grp.name) ?? textColor;
28486
- const itemG = g.append("g").attr("class", "tl-legend-item").attr("data-group", grp.name).style("cursor", "pointer").on("mouseenter", () => fadeToGroup(g, grp.name)).on("mouseleave", () => fadeReset(g));
28487
- itemG.append("circle").attr("cx", legendX).attr("cy", legendY).attr("r", 5).attr("fill", color);
28488
- itemG.append("text").attr("x", legendX + 10).attr("y", legendY).attr("dy", "0.35em").attr("fill", textColor).attr("font-size", "11px").text(grp.name);
28489
- legendX += grp.name.length * 7 + 30;
28490
- }
28764
+ renderTimelineGroupLegend(
28765
+ g,
28766
+ timelineGroups,
28767
+ groupColorMap,
28768
+ textColor,
28769
+ palette,
28770
+ isDark,
28771
+ legendY,
28772
+ (name) => fadeToGroup(g, name),
28773
+ () => fadeReset(g)
28774
+ );
28491
28775
  }
28492
28776
  sorted.forEach((ev, i) => {
28493
28777
  const y = markerMargin + i * rowH + rowH / 2;
@@ -28552,7 +28836,7 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
28552
28836
  }
28553
28837
  evG.append("rect").attr("x", x).attr("y", y - BAR_H2 / 2).attr("width", rectW).attr("height", BAR_H2).attr("rx", 4).attr("fill", fill2).attr("stroke", stroke2).attr("stroke-width", 2);
28554
28838
  if (labelFitsInside) {
28555
- evG.append("text").attr("x", x + 8).attr("y", y).attr("dy", "0.35em").attr("text-anchor", "start").attr("fill", textColor).attr("font-size", "14px").attr("font-weight", "700").text(ev.label);
28839
+ evG.append("text").attr("x", x + 8).attr("y", y).attr("dy", "0.35em").attr("text-anchor", "start").attr("fill", textColor).attr("font-size", "13px").text(ev.label);
28556
28840
  } else {
28557
28841
  const wouldFlipLeft = x + rectW > innerWidth * 0.6;
28558
28842
  const labelFitsLeft = x - 6 - estLabelWidth > 0;
@@ -28920,7 +29204,7 @@ function regionCentroid(circles, inside) {
28920
29204
  }
28921
29205
  function renderVenn(container, parsed, palette, isDark, onClickItem, exportDims) {
28922
29206
  const { vennSets, vennOverlaps, title } = parsed;
28923
- if (vennSets.length < 2) return;
29207
+ if (vennSets.length < 2 || vennSets.length > 3) return;
28924
29208
  const init2 = initD3Chart(container, palette, exportDims);
28925
29209
  if (!init2) return;
28926
29210
  const { svg, width, height, textColor, colors } = init2;
@@ -28976,7 +29260,9 @@ function renderVenn(container, parsed, palette, isDark, onClickItem, exportDims)
28976
29260
  marginBottom
28977
29261
  ).map((c) => ({ ...c, y: c.y + titleHeight }));
28978
29262
  const scaledR = circles[0].r;
28979
- svg.append("style").text("circle:focus, circle:focus-visible { outline: none !important; }");
29263
+ svg.append("style").text(
29264
+ "circle:focus, circle:focus-visible { outline-solid: none !important; }"
29265
+ );
28980
29266
  renderChartTitle(
28981
29267
  svg,
28982
29268
  title,
@@ -29158,7 +29444,7 @@ function renderVenn(container, parsed, palette, isDark, onClickItem, exportDims)
29158
29444
  }
29159
29445
  const hoverGroup = svg.append("g");
29160
29446
  circles.forEach((c, i) => {
29161
- hoverGroup.append("circle").attr("cx", c.x).attr("cy", c.y).attr("r", c.r).attr("fill", "transparent").attr("stroke", "none").attr("class", "venn-hit-target").attr("data-line-number", String(vennSets[i].lineNumber)).style("cursor", onClickItem ? "pointer" : "default").style("outline", "none").on("mouseenter", () => {
29447
+ hoverGroup.append("circle").attr("cx", c.x).attr("cy", c.y).attr("r", c.r).attr("fill", "transparent").attr("stroke", "none").attr("class", "venn-hit-target").attr("data-line-number", String(vennSets[i].lineNumber)).style("cursor", onClickItem ? "pointer" : "default").style("outline-solid", "none").on("mouseenter", () => {
29162
29448
  showRegionOverlay([i]);
29163
29449
  }).on("mouseleave", () => {
29164
29450
  hideAllOverlays();
@@ -29196,7 +29482,7 @@ function renderVenn(container, parsed, palette, isDark, onClickItem, exportDims)
29196
29482
  const declaredOv = vennOverlaps.find(
29197
29483
  (ov) => ov.sets.length === sets.length && ov.sets.every((s, k) => s === sets[k])
29198
29484
  );
29199
- hoverGroup.append("circle").attr("cx", centroid.x).attr("cy", centroid.y).attr("r", overlayR).attr("fill", "transparent").attr("stroke", "none").attr("class", "venn-hit-target").attr("data-line-number", declaredOv ? String(declaredOv.lineNumber) : "").style("cursor", onClickItem && declaredOv ? "pointer" : "default").style("outline", "none").on("mouseenter", () => {
29485
+ hoverGroup.append("circle").attr("cx", centroid.x).attr("cy", centroid.y).attr("r", overlayR).attr("fill", "transparent").attr("stroke", "none").attr("class", "venn-hit-target").attr("data-line-number", declaredOv ? String(declaredOv.lineNumber) : "").style("cursor", onClickItem && declaredOv ? "pointer" : "default").style("outline-solid", "none").on("mouseenter", () => {
29200
29486
  showRegionOverlay(idxs);
29201
29487
  }).on("mouseleave", () => {
29202
29488
  hideAllOverlays();
@@ -29330,8 +29616,8 @@ function renderQuadrant(container, parsed, palette, isDark, onClickItem, exportD
29330
29616
  const LABEL_MAX_FONT = 48;
29331
29617
  const LABEL_MIN_FONT = 14;
29332
29618
  const LABEL_PAD2 = 40;
29333
- const CHAR_WIDTH_RATIO2 = 0.6;
29334
- const estTextWidth = (text, fontSize) => text.length * fontSize * CHAR_WIDTH_RATIO2;
29619
+ const CHAR_WIDTH_RATIO3 = 0.6;
29620
+ const estTextWidth = (text, fontSize) => text.length * fontSize * CHAR_WIDTH_RATIO3;
29335
29621
  const quadrantLabelLayout = (text, qw2, qh2) => {
29336
29622
  const availW = qw2 - LABEL_PAD2;
29337
29623
  const availH = qh2 - LABEL_PAD2;
@@ -29475,16 +29761,45 @@ function renderQuadrant(container, parsed, palette, isDark, onClickItem, exportD
29475
29761
  if (x < 0.5 && y < 0.5) return "bottom-left";
29476
29762
  return "bottom-right";
29477
29763
  };
29764
+ const POINT_RADIUS = 6;
29765
+ const POINT_LABEL_FONT_SIZE = 12;
29766
+ const quadrantLabelObstacles = quadrantDefsWithLabel.map((d) => {
29767
+ const layout = labelLayouts.get(d.label.text);
29768
+ const totalW = Math.max(...layout.lines.map((l) => l.length)) * layout.fontSize * CHAR_WIDTH_RATIO3;
29769
+ const totalH = layout.lines.length * layout.fontSize * 1.2;
29770
+ return {
29771
+ x: d.labelX - totalW / 2,
29772
+ y: d.labelY - totalH / 2,
29773
+ w: totalW,
29774
+ h: totalH
29775
+ };
29776
+ });
29777
+ const pointPixels = quadrantPoints.map((point) => ({
29778
+ label: point.label,
29779
+ cx: xScale(point.x),
29780
+ cy: yScale(point.y)
29781
+ }));
29782
+ const placedPointLabels = computeQuadrantPointLabels(
29783
+ pointPixels,
29784
+ { left: 0, top: 0, right: chartWidth, bottom: chartHeight },
29785
+ quadrantLabelObstacles,
29786
+ POINT_RADIUS,
29787
+ POINT_LABEL_FONT_SIZE
29788
+ );
29478
29789
  const pointsG = chartG.append("g").attr("class", "points");
29479
- quadrantPoints.forEach((point) => {
29790
+ quadrantPoints.forEach((point, i) => {
29480
29791
  const cx = xScale(point.x);
29481
29792
  const cy = yScale(point.y);
29482
29793
  const quadrant = getPointQuadrant(point.x, point.y);
29483
29794
  const quadDef = quadrantDefs.find((d) => d.position === quadrant);
29484
29795
  const pointColor = quadDef?.label?.color ?? defaultColors[quadDef?.colorIdx ?? 0];
29796
+ const placed = placedPointLabels[i];
29485
29797
  const pointG = pointsG.append("g").attr("class", "point-group").attr("data-line-number", String(point.lineNumber));
29486
- pointG.append("circle").attr("cx", cx).attr("cy", cy).attr("r", 6).attr("fill", "#ffffff").attr("stroke", pointColor).attr("stroke-width", 2);
29487
- pointG.append("text").attr("x", cx).attr("y", cy - 10).attr("text-anchor", "middle").attr("fill", textColor).attr("font-size", "12px").attr("font-weight", "700").style("text-shadow", `0 1px 2px ${shadowColor}`).text(point.label);
29798
+ if (placed.connectorLine) {
29799
+ pointG.append("line").attr("x1", placed.connectorLine.x1).attr("y1", placed.connectorLine.y1).attr("x2", placed.connectorLine.x2).attr("y2", placed.connectorLine.y2).attr("stroke", pointColor).attr("stroke-width", 1).attr("opacity", 0.5);
29800
+ }
29801
+ pointG.append("circle").attr("cx", cx).attr("cy", cy).attr("r", POINT_RADIUS).attr("fill", "#ffffff").attr("stroke", pointColor).attr("stroke-width", 2);
29802
+ pointG.append("text").attr("x", placed.x).attr("y", placed.y).attr("text-anchor", placed.anchor).attr("dominant-baseline", "central").attr("fill", textColor).attr("font-size", `${POINT_LABEL_FONT_SIZE}px`).attr("font-weight", "700").style("text-shadow", `0 1px 2px ${shadowColor}`).text(point.label);
29488
29803
  const tipHtml = `<strong>${point.label}</strong><br>x: ${point.x.toFixed(2)}, y: ${point.y.toFixed(2)}`;
29489
29804
  pointG.style("cursor", onClickItem ? "pointer" : "default").on("mouseenter", (event) => {
29490
29805
  showTooltip(tooltip, tipHtml, event);
@@ -29493,7 +29808,7 @@ function renderQuadrant(container, parsed, palette, isDark, onClickItem, exportD
29493
29808
  showTooltip(tooltip, tipHtml, event);
29494
29809
  }).on("mouseleave", () => {
29495
29810
  hideTooltip(tooltip);
29496
- pointG.select("circle").attr("r", 6);
29811
+ pointG.select("circle").attr("r", POINT_RADIUS);
29497
29812
  }).on("click", () => {
29498
29813
  if (onClickItem && point.lineNumber) onClickItem(point.lineNumber);
29499
29814
  });
@@ -29568,7 +29883,11 @@ async function renderForExport(content, theme, palette, orgExportState, options)
29568
29883
  const orgParsed = parseOrg2(content, effectivePalette2);
29569
29884
  if (orgParsed.error) return "";
29570
29885
  const collapsedNodes = orgExportState?.collapsedNodes;
29571
- const activeTagGroup = orgExportState?.activeTagGroup ?? options?.tagGroup ?? null;
29886
+ const activeTagGroup = resolveActiveTagGroup(
29887
+ orgParsed.tagGroups,
29888
+ orgParsed.options["active-tag"],
29889
+ orgExportState?.activeTagGroup ?? options?.tagGroup
29890
+ );
29572
29891
  const hiddenAttributes = orgExportState?.hiddenAttributes;
29573
29892
  const { parsed: effectiveParsed, hiddenCounts } = collapsedNodes && collapsedNodes.size > 0 ? collapseOrgTree2(orgParsed, collapsedNodes) : { parsed: orgParsed, hiddenCounts: /* @__PURE__ */ new Map() };
29574
29893
  const orgLayout = layoutOrg2(
@@ -29607,7 +29926,11 @@ async function renderForExport(content, theme, palette, orgExportState, options)
29607
29926
  const sitemapParsed = parseSitemap2(content, effectivePalette2);
29608
29927
  if (sitemapParsed.error || sitemapParsed.roots.length === 0) return "";
29609
29928
  const collapsedNodes = orgExportState?.collapsedNodes;
29610
- const activeTagGroup = orgExportState?.activeTagGroup ?? options?.tagGroup ?? null;
29929
+ const activeTagGroup = resolveActiveTagGroup(
29930
+ sitemapParsed.tagGroups,
29931
+ sitemapParsed.options["active-tag"],
29932
+ orgExportState?.activeTagGroup ?? options?.tagGroup
29933
+ );
29611
29934
  const hiddenAttributes = orgExportState?.hiddenAttributes;
29612
29935
  const { parsed: effectiveParsed, hiddenCounts } = collapsedNodes && collapsedNodes.size > 0 ? collapseSitemapTree2(sitemapParsed, collapsedNodes) : { parsed: sitemapParsed, hiddenCounts: /* @__PURE__ */ new Map() };
29613
29936
  const sitemapLayout = layoutSitemap2(
@@ -29652,7 +29975,11 @@ async function renderForExport(content, theme, palette, orgExportState, options)
29652
29975
  theme === "dark",
29653
29976
  void 0,
29654
29977
  void 0,
29655
- options?.tagGroup
29978
+ resolveActiveTagGroup(
29979
+ kanbanParsed.tagGroups,
29980
+ kanbanParsed.options["active-tag"],
29981
+ options?.tagGroup
29982
+ )
29656
29983
  );
29657
29984
  return finalizeSvgExport(container2, theme, effectivePalette2, options);
29658
29985
  }
@@ -29701,7 +30028,11 @@ async function renderForExport(content, theme, palette, orgExportState, options)
29701
30028
  theme === "dark",
29702
30029
  void 0,
29703
30030
  { width: exportWidth, height: exportHeight },
29704
- options?.tagGroup
30031
+ resolveActiveTagGroup(
30032
+ erParsed.tagGroups,
30033
+ erParsed.options["active-tag"],
30034
+ options?.tagGroup
30035
+ )
29705
30036
  );
29706
30037
  return finalizeSvgExport(container2, theme, effectivePalette2, options);
29707
30038
  }
@@ -29724,7 +30055,10 @@ async function renderForExport(content, theme, palette, orgExportState, options)
29724
30055
  blLayout,
29725
30056
  effectivePalette2,
29726
30057
  theme === "dark",
29727
- { exportDims: { width: exportWidth, height: exportHeight } }
30058
+ {
30059
+ exportDims: { width: exportWidth, height: exportHeight },
30060
+ activeTagGroup: options?.tagGroup
30061
+ }
29728
30062
  );
29729
30063
  return finalizeSvgExport(container2, theme, effectivePalette2, options);
29730
30064
  }
@@ -29759,7 +30093,11 @@ async function renderForExport(content, theme, palette, orgExportState, options)
29759
30093
  theme === "dark",
29760
30094
  void 0,
29761
30095
  { width: exportWidth, height: exportHeight },
29762
- options?.tagGroup
30096
+ resolveActiveTagGroup(
30097
+ c4Parsed.tagGroups,
30098
+ c4Parsed.options["active-tag"],
30099
+ options?.tagGroup
30100
+ )
29763
30101
  );
29764
30102
  return finalizeSvgExport(container2, theme, effectivePalette2, options);
29765
30103
  }
@@ -29793,7 +30131,11 @@ async function renderForExport(content, theme, palette, orgExportState, options)
29793
30131
  if (infraParsed.error || infraParsed.nodes.length === 0) return "";
29794
30132
  const infraComputed = computeInfra2(infraParsed);
29795
30133
  const infraLayout = layoutInfra2(infraComputed);
29796
- const activeTagGroup = options?.tagGroup ?? null;
30134
+ const activeTagGroup = resolveActiveTagGroup(
30135
+ infraParsed.tagGroups,
30136
+ infraParsed.options["active-tag"],
30137
+ options?.tagGroup
30138
+ );
29797
30139
  const titleOffset = infraParsed.title ? 40 : 0;
29798
30140
  const legendGroups = computeInfraLegendGroups2(
29799
30141
  infraLayout.nodes,
@@ -29928,7 +30270,11 @@ async function renderForExport(content, theme, palette, orgExportState, options)
29928
30270
  isDark,
29929
30271
  void 0,
29930
30272
  dims,
29931
- orgExportState?.activeTagGroup ?? options?.tagGroup,
30273
+ resolveActiveTagGroup(
30274
+ parsed.timelineTagGroups,
30275
+ void 0,
30276
+ orgExportState?.activeTagGroup ?? options?.tagGroup
30277
+ ),
29932
30278
  orgExportState?.swimlaneTagGroup
29933
30279
  );
29934
30280
  } else if (parsed.type === "venn") {
@@ -29960,6 +30306,7 @@ var init_d3 = __esm({
29960
30306
  "use strict";
29961
30307
  init_fonts();
29962
30308
  init_branding();
30309
+ init_label_layout();
29963
30310
  init_colors();
29964
30311
  init_palettes();
29965
30312
  init_color_utils();
@@ -30895,7 +31242,7 @@ import {
30895
31242
  compressToEncodedURIComponent,
30896
31243
  decompressFromEncodedURIComponent
30897
31244
  } from "lz-string";
30898
- var DEFAULT_BASE_URL = "https://diagrammo.app/view";
31245
+ var DEFAULT_BASE_URL = "https://online.diagrammo.app";
30899
31246
  var COMPRESSED_SIZE_LIMIT = 8192;
30900
31247
  function encodeDiagramUrl(dsl, options) {
30901
31248
  const baseUrl = options?.baseUrl ?? DEFAULT_BASE_URL;
@@ -31167,21 +31514,33 @@ var COMPLETION_REGISTRY = /* @__PURE__ */ new Map([
31167
31514
  }
31168
31515
  })
31169
31516
  ],
31170
- ["er", withGlobals()],
31517
+ [
31518
+ "er",
31519
+ withGlobals({
31520
+ "active-tag": { description: "Active tag group name" }
31521
+ })
31522
+ ],
31171
31523
  [
31172
31524
  "org",
31173
31525
  withGlobals({
31174
31526
  "sub-node-label": { description: "Label for sub-nodes" },
31175
- "show-sub-node-count": { description: "Show sub-node counts" }
31527
+ "show-sub-node-count": { description: "Show sub-node counts" },
31528
+ "active-tag": { description: "Active tag group name" }
31176
31529
  })
31177
31530
  ],
31178
31531
  [
31179
31532
  "kanban",
31180
31533
  withGlobals({
31181
- "no-auto-color": { description: "Disable automatic card coloring" }
31534
+ "no-auto-color": { description: "Disable automatic card coloring" },
31535
+ "active-tag": { description: "Active tag group name" }
31536
+ })
31537
+ ],
31538
+ [
31539
+ "c4",
31540
+ withGlobals({
31541
+ "active-tag": { description: "Active tag group name" }
31182
31542
  })
31183
31543
  ],
31184
- ["c4", withGlobals()],
31185
31544
  [
31186
31545
  "state",
31187
31546
  withGlobals({
@@ -31192,7 +31551,8 @@ var COMPLETION_REGISTRY = /* @__PURE__ */ new Map([
31192
31551
  [
31193
31552
  "sitemap",
31194
31553
  withGlobals({
31195
- "direction-tb": { description: "Switch to top-to-bottom layout" }
31554
+ "direction-tb": { description: "Switch to top-to-bottom layout" },
31555
+ "active-tag": { description: "Active tag group name" }
31196
31556
  })
31197
31557
  ],
31198
31558
  [
@@ -31206,7 +31566,8 @@ var COMPLETION_REGISTRY = /* @__PURE__ */ new Map([
31206
31566
  "default-rps": { description: "Default RPS capacity for all nodes" },
31207
31567
  "slo-availability": { description: "SLO availability target (0-1)" },
31208
31568
  "slo-p90-latency-ms": { description: "SLO p90 latency target in ms" },
31209
- "slo-warning-margin": { description: "SLO warning margin percentage" }
31569
+ "slo-warning-margin": { description: "SLO warning margin percentage" },
31570
+ "active-tag": { description: "Active tag group name" }
31210
31571
  })
31211
31572
  ],
31212
31573
  [
@@ -31218,7 +31579,8 @@ var COMPLETION_REGISTRY = /* @__PURE__ */ new Map([
31218
31579
  },
31219
31580
  sort: { description: "Sort order", values: ["time", "group", "tag"] },
31220
31581
  "critical-path": { description: "Show critical path" },
31221
- dependencies: { description: "Show dependencies" }
31582
+ dependencies: { description: "Show dependencies" },
31583
+ "active-tag": { description: "Active tag group name" }
31222
31584
  })
31223
31585
  ],
31224
31586
  [
@@ -31736,6 +32098,7 @@ export {
31736
32098
  computeTimeTicks,
31737
32099
  contrastText,
31738
32100
  decodeDiagramUrl,
32101
+ draculaPalette,
31739
32102
  encodeDiagramUrl,
31740
32103
  extractDiagramSymbols,
31741
32104
  extractTagDeclarations,
@@ -31779,6 +32142,7 @@ export {
31779
32142
  looksLikeSitemap,
31780
32143
  looksLikeState,
31781
32144
  makeDgmoError,
32145
+ monokaiPalette,
31782
32146
  mute,
31783
32147
  nord,
31784
32148
  nordPalette,