@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.cjs CHANGED
@@ -144,6 +144,183 @@ var init_branding = __esm({
144
144
  }
145
145
  });
146
146
 
147
+ // src/label-layout.ts
148
+ function rectsOverlap(a, b) {
149
+ 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;
150
+ }
151
+ function rectCircleOverlap(rect, circle) {
152
+ const nearestX = Math.max(rect.x, Math.min(circle.cx, rect.x + rect.w));
153
+ const nearestY = Math.max(rect.y, Math.min(circle.cy, rect.y + rect.h));
154
+ const dx = nearestX - circle.cx;
155
+ const dy = nearestY - circle.cy;
156
+ return dx * dx + dy * dy < circle.r * circle.r;
157
+ }
158
+ function computeQuadrantPointLabels(points, chartBounds, obstacles, pointRadius, fontSize) {
159
+ const labelHeight = fontSize + 4;
160
+ const stepSize = labelHeight + 2;
161
+ const minGap = pointRadius + 4;
162
+ const pointCircles = points.map((p) => ({
163
+ cx: p.cx,
164
+ cy: p.cy,
165
+ r: pointRadius
166
+ }));
167
+ const placedLabels = [];
168
+ const results = [];
169
+ for (let i = 0; i < points.length; i++) {
170
+ const pt = points[i];
171
+ const labelWidth = pt.label.length * fontSize * CHAR_WIDTH_RATIO + 8;
172
+ let best = null;
173
+ const directions = [
174
+ {
175
+ // Above
176
+ gen: (offset) => {
177
+ const lx = pt.cx - labelWidth / 2;
178
+ const ly = pt.cy - offset - labelHeight;
179
+ if (ly < chartBounds.top || lx < chartBounds.left || lx + labelWidth > chartBounds.right)
180
+ return null;
181
+ return {
182
+ rect: { x: lx, y: ly, w: labelWidth, h: labelHeight },
183
+ textX: pt.cx,
184
+ textY: ly + labelHeight / 2,
185
+ anchor: "middle"
186
+ };
187
+ }
188
+ },
189
+ {
190
+ // Below
191
+ gen: (offset) => {
192
+ const lx = pt.cx - labelWidth / 2;
193
+ const ly = pt.cy + offset;
194
+ if (ly + labelHeight > chartBounds.bottom || lx < chartBounds.left || lx + labelWidth > chartBounds.right)
195
+ return null;
196
+ return {
197
+ rect: { x: lx, y: ly, w: labelWidth, h: labelHeight },
198
+ textX: pt.cx,
199
+ textY: ly + labelHeight / 2,
200
+ anchor: "middle"
201
+ };
202
+ }
203
+ },
204
+ {
205
+ // Right
206
+ gen: (offset) => {
207
+ const lx = pt.cx + offset;
208
+ const ly = pt.cy - labelHeight / 2;
209
+ if (lx + labelWidth > chartBounds.right || ly < chartBounds.top || ly + labelHeight > chartBounds.bottom)
210
+ return null;
211
+ return {
212
+ rect: { x: lx, y: ly, w: labelWidth, h: labelHeight },
213
+ textX: lx,
214
+ textY: pt.cy,
215
+ anchor: "start"
216
+ };
217
+ }
218
+ },
219
+ {
220
+ // Left
221
+ gen: (offset) => {
222
+ const lx = pt.cx - offset - labelWidth;
223
+ const ly = pt.cy - labelHeight / 2;
224
+ if (lx < chartBounds.left || ly < chartBounds.top || ly + labelHeight > chartBounds.bottom)
225
+ return null;
226
+ return {
227
+ rect: { x: lx, y: ly, w: labelWidth, h: labelHeight },
228
+ textX: lx + labelWidth,
229
+ textY: pt.cy,
230
+ anchor: "end"
231
+ };
232
+ }
233
+ }
234
+ ];
235
+ for (const { gen } of directions) {
236
+ for (let offset = minGap; ; offset += stepSize) {
237
+ const cand = gen(offset);
238
+ if (!cand) break;
239
+ let collision = false;
240
+ for (const pl of placedLabels) {
241
+ if (rectsOverlap(cand.rect, pl)) {
242
+ collision = true;
243
+ break;
244
+ }
245
+ }
246
+ if (!collision) {
247
+ for (const circle of pointCircles) {
248
+ if (rectCircleOverlap(cand.rect, circle)) {
249
+ collision = true;
250
+ break;
251
+ }
252
+ }
253
+ }
254
+ if (!collision) {
255
+ for (const obs of obstacles) {
256
+ if (rectsOverlap(cand.rect, obs)) {
257
+ collision = true;
258
+ break;
259
+ }
260
+ }
261
+ }
262
+ if (!collision) {
263
+ const dist = offset;
264
+ if (!best || dist < best.dist) {
265
+ best = {
266
+ rect: cand.rect,
267
+ textX: cand.textX,
268
+ textY: cand.textY,
269
+ anchor: cand.anchor,
270
+ dist
271
+ };
272
+ }
273
+ break;
274
+ }
275
+ }
276
+ }
277
+ if (!best) {
278
+ const lx = pt.cx - labelWidth / 2;
279
+ const ly = pt.cy - minGap - labelHeight;
280
+ best = {
281
+ rect: { x: lx, y: ly, w: labelWidth, h: labelHeight },
282
+ textX: pt.cx,
283
+ textY: ly + labelHeight / 2,
284
+ anchor: "middle",
285
+ dist: minGap
286
+ };
287
+ }
288
+ placedLabels.push(best.rect);
289
+ let connectorLine;
290
+ if (best.dist > minGap + stepSize) {
291
+ const dx = best.textX - pt.cx;
292
+ const dy = best.textY - pt.cy;
293
+ const angle = Math.atan2(dy, dx);
294
+ const x1 = pt.cx + Math.cos(angle) * pointRadius;
295
+ const y1 = pt.cy + Math.sin(angle) * pointRadius;
296
+ const x2 = Math.max(
297
+ best.rect.x,
298
+ Math.min(pt.cx, best.rect.x + best.rect.w)
299
+ );
300
+ const y2 = Math.max(
301
+ best.rect.y,
302
+ Math.min(pt.cy, best.rect.y + best.rect.h)
303
+ );
304
+ connectorLine = { x1, y1, x2, y2 };
305
+ }
306
+ results.push({
307
+ label: pt.label,
308
+ x: best.textX,
309
+ y: best.textY,
310
+ anchor: best.anchor,
311
+ connectorLine
312
+ });
313
+ }
314
+ return results;
315
+ }
316
+ var CHAR_WIDTH_RATIO;
317
+ var init_label_layout = __esm({
318
+ "src/label-layout.ts"() {
319
+ "use strict";
320
+ CHAR_WIDTH_RATIO = 0.6;
321
+ }
322
+ });
323
+
147
324
  // src/colors.ts
148
325
  function resolveColor(color, palette) {
149
326
  if (color.startsWith("#")) return null;
@@ -1774,6 +1951,16 @@ function validateTagValues(entities, tagGroups, pushWarning, suggestFn) {
1774
1951
  }
1775
1952
  }
1776
1953
  }
1954
+ function validateTagGroupNames(tagGroups, pushWarning) {
1955
+ for (const group of tagGroups) {
1956
+ if (group.name.toLowerCase() === "none") {
1957
+ pushWarning(
1958
+ group.lineNumber,
1959
+ `'none' is a reserved keyword and cannot be used as a tag group name`
1960
+ );
1961
+ }
1962
+ }
1963
+ }
1777
1964
  function injectDefaultTagMetadata(entities, tagGroups, skip) {
1778
1965
  const defaults = [];
1779
1966
  for (const group of tagGroups) {
@@ -1794,6 +1981,19 @@ function injectDefaultTagMetadata(entities, tagGroups, skip) {
1794
1981
  }
1795
1982
  }
1796
1983
  }
1984
+ function resolveActiveTagGroup(tagGroups, explicitActiveTag, programmaticOverride) {
1985
+ if (programmaticOverride !== void 0) {
1986
+ if (!programmaticOverride) return null;
1987
+ if (programmaticOverride.toLowerCase() === "none") return null;
1988
+ return programmaticOverride;
1989
+ }
1990
+ if (explicitActiveTag) {
1991
+ if (explicitActiveTag.toLowerCase() === "none") return null;
1992
+ return explicitActiveTag;
1993
+ }
1994
+ if (tagGroups.length > 0) return tagGroups[0].name;
1995
+ return null;
1996
+ }
1797
1997
  function matchTagBlockHeading(trimmed) {
1798
1998
  return parseTagDeclaration(trimmed);
1799
1999
  }
@@ -1814,7 +2014,7 @@ function measureLegendText(text, fontSize) {
1814
2014
  }
1815
2015
  return w;
1816
2016
  }
1817
- 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;
2017
+ 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;
1818
2018
  var init_legend_constants = __esm({
1819
2019
  "src/utils/legend-constants.ts"() {
1820
2020
  "use strict";
@@ -1830,6 +2030,7 @@ var init_legend_constants = __esm({
1830
2030
  LEGEND_EYE_SIZE = 14;
1831
2031
  LEGEND_EYE_GAP = 6;
1832
2032
  LEGEND_ICON_W = 20;
2033
+ LEGEND_MAX_ENTRY_ROWS = 3;
1833
2034
  CHAR_W = {
1834
2035
  " ": 0.28,
1835
2036
  "!": 0.28,
@@ -2096,13 +2297,15 @@ function computeLegendLayout(config, state, containerWidth) {
2096
2297
  });
2097
2298
  }
2098
2299
  }
2300
+ const alignLeft = config.position.titleRelation === "inline-with-title";
2099
2301
  const rows = layoutRows(
2100
2302
  activeCapsule,
2101
2303
  pills,
2102
2304
  controlLayouts,
2103
2305
  groupAvailW,
2104
2306
  containerWidth,
2105
- totalControlsW
2307
+ totalControlsW,
2308
+ alignLeft
2106
2309
  );
2107
2310
  const height = rows.length * LEGEND_HEIGHT;
2108
2311
  const width = containerWidth;
@@ -2176,7 +2379,7 @@ function buildCapsuleLayout(group, containerWidth, addonWidth = 0) {
2176
2379
  addonX: addonWidth > 0 ? LEGEND_CAPSULE_PAD + pw + 4 : void 0
2177
2380
  };
2178
2381
  }
2179
- function layoutRows(activeCapsule, pills, controls, groupAvailW, containerWidth, totalControlsW) {
2382
+ function layoutRows(activeCapsule, pills, controls, groupAvailW, containerWidth, totalControlsW, alignLeft = false) {
2180
2383
  const rows = [];
2181
2384
  const groupItems = [];
2182
2385
  if (activeCapsule) groupItems.push(activeCapsule);
@@ -2187,7 +2390,8 @@ function layoutRows(activeCapsule, pills, controls, groupAvailW, containerWidth,
2187
2390
  for (const item of groupItems) {
2188
2391
  const itemW = item.width + LEGEND_GROUP_GAP;
2189
2392
  if (currentRowW + item.width > groupAvailW && currentRowItems.length > 0) {
2190
- centerRowItems(currentRowItems, containerWidth, totalControlsW);
2393
+ if (!alignLeft)
2394
+ centerRowItems(currentRowItems, containerWidth, totalControlsW);
2191
2395
  rows.push({ y: rowY, items: currentRowItems });
2192
2396
  rowY += LEGEND_HEIGHT;
2193
2397
  currentRowItems = [];
@@ -2239,12 +2443,11 @@ function getLegendReservedHeight(config, state, containerWidth) {
2239
2443
  const layout = computeLegendLayout(config, state, containerWidth);
2240
2444
  return layout.height;
2241
2445
  }
2242
- var LEGEND_MAX_ENTRY_ROWS, CONTROL_PILL_PAD, CONTROL_FONT_SIZE, CONTROL_ICON_GAP, CONTROL_GAP;
2446
+ var CONTROL_PILL_PAD, CONTROL_FONT_SIZE, CONTROL_ICON_GAP, CONTROL_GAP;
2243
2447
  var init_legend_layout = __esm({
2244
2448
  "src/utils/legend-layout.ts"() {
2245
2449
  "use strict";
2246
2450
  init_legend_constants();
2247
- LEGEND_MAX_ENTRY_ROWS = 3;
2248
2451
  CONTROL_PILL_PAD = 16;
2249
2452
  CONTROL_FONT_SIZE = 11;
2250
2453
  CONTROL_ICON_GAP = 4;
@@ -3455,7 +3658,8 @@ function parseSequenceDgmo(content) {
3455
3658
  if (top.block.type === "if") {
3456
3659
  const branch = {
3457
3660
  label: elseIfMatch[1].trim(),
3458
- children: []
3661
+ children: [],
3662
+ lineNumber
3459
3663
  };
3460
3664
  if (!top.block.elseIfBranches) top.block.elseIfBranches = [];
3461
3665
  top.block.elseIfBranches.push(branch);
@@ -3478,6 +3682,7 @@ function parseSequenceDgmo(content) {
3478
3682
  if (top.block.type === "if") {
3479
3683
  top.inElse = true;
3480
3684
  top.activeElseIfBranch = void 0;
3685
+ top.block.elseLineNumber = lineNumber;
3481
3686
  }
3482
3687
  }
3483
3688
  continue;
@@ -3590,6 +3795,7 @@ function parseSequenceDgmo(content) {
3590
3795
  entities.push({ metadata: g.metadata, lineNumber: g.lineNumber });
3591
3796
  }
3592
3797
  validateTagValues(entities, result.tagGroups, pushWarning, suggest);
3798
+ validateTagGroupNames(result.tagGroups, pushWarning);
3593
3799
  }
3594
3800
  return result;
3595
3801
  }
@@ -4866,6 +5072,10 @@ function parseERDiagram(content, palette) {
4866
5072
  (line10, msg) => result.diagnostics.push(makeDgmoError(line10, msg, "warning")),
4867
5073
  suggest
4868
5074
  );
5075
+ validateTagGroupNames(
5076
+ result.tagGroups,
5077
+ (line10, msg) => result.diagnostics.push(makeDgmoError(line10, msg, "warning"))
5078
+ );
4869
5079
  for (const group of result.tagGroups) {
4870
5080
  if (!group.defaultValue) continue;
4871
5081
  const key = group.name.toLowerCase();
@@ -4961,7 +5171,7 @@ var init_parser3 = __esm({
4961
5171
  unique: "unique",
4962
5172
  nullable: "nullable"
4963
5173
  };
4964
- KNOWN_OPTIONS = /* @__PURE__ */ new Set(["notation"]);
5174
+ KNOWN_OPTIONS = /* @__PURE__ */ new Set(["notation", "active-tag"]);
4965
5175
  REL_SYMBOLIC_RE = /^([a-zA-Z_]\w*)\s+([1*?])\s*-{1,2}\s*([1*?])\s+([a-zA-Z_]\w*)(?:\s+(.+))?$/;
4966
5176
  REL_KEYWORD_RE = /^([a-zA-Z_]\w*)\s+(one|many|zero)[- ]to[- ](one|many|zero)\s+([a-zA-Z_]\w*)(?:\s+(.+))?$/i;
4967
5177
  KEYWORD_TO_SYMBOL = {
@@ -5870,7 +6080,8 @@ function buildExtendedChartOption(parsed, palette, isDark) {
5870
6080
  }
5871
6081
  const { textColor, axisLineColor, gridOpacity, colors, titleConfig } = buildChartCommons(parsed, palette, isDark);
5872
6082
  if (parsed.type === "sankey") {
5873
- return buildSankeyOption(parsed, textColor, colors, titleConfig);
6083
+ const bg = isDark ? palette.surface : palette.bg;
6084
+ return buildSankeyOption(parsed, textColor, colors, bg, titleConfig);
5874
6085
  }
5875
6086
  if (parsed.type === "chord") {
5876
6087
  const bg = isDark ? palette.surface : palette.bg;
@@ -5913,7 +6124,7 @@ function buildExtendedChartOption(parsed, palette, isDark) {
5913
6124
  titleConfig
5914
6125
  );
5915
6126
  }
5916
- function buildSankeyOption(parsed, textColor, colors, titleConfig) {
6127
+ function buildSankeyOption(parsed, textColor, colors, bg, titleConfig) {
5917
6128
  const nodeSet = /* @__PURE__ */ new Set();
5918
6129
  if (parsed.links) {
5919
6130
  for (const link of parsed.links) {
@@ -5921,12 +6132,15 @@ function buildSankeyOption(parsed, textColor, colors, titleConfig) {
5921
6132
  nodeSet.add(link.target);
5922
6133
  }
5923
6134
  }
5924
- const nodes = Array.from(nodeSet).map((name, index) => ({
5925
- name,
5926
- itemStyle: {
5927
- color: parsed.nodeColors?.[name] ?? colors[index % colors.length]
5928
- }
5929
- }));
6135
+ const tintNode = (c) => mix(c, bg, 75);
6136
+ const tintLink = (c) => mix(c, bg, 45);
6137
+ const nodeColorMap = /* @__PURE__ */ new Map();
6138
+ const nodes = Array.from(nodeSet).map((name, index) => {
6139
+ const raw = parsed.nodeColors?.[name] ?? colors[index % colors.length];
6140
+ const tinted = tintNode(raw);
6141
+ nodeColorMap.set(name, tintLink(raw));
6142
+ return { name, itemStyle: { color: tinted } };
6143
+ });
5930
6144
  return {
5931
6145
  ...CHART_BASE,
5932
6146
  title: titleConfig,
@@ -5949,11 +6163,13 @@ function buildSankeyOption(parsed, textColor, colors, titleConfig) {
5949
6163
  source: link.source,
5950
6164
  target: link.target,
5951
6165
  value: link.value,
5952
- ...link.color && { lineStyle: { color: link.color } }
6166
+ lineStyle: {
6167
+ color: link.color ? tintLink(link.color) : nodeColorMap.get(link.source)
6168
+ }
5953
6169
  })),
5954
6170
  lineStyle: {
5955
- color: "gradient",
5956
- curveness: 0.5
6171
+ curveness: 0.5,
6172
+ opacity: 0.6
5957
6173
  },
5958
6174
  label: {
5959
6175
  color: textColor,
@@ -6048,7 +6264,7 @@ function buildChordOption(parsed, textColor, colors, bg, titleConfig) {
6048
6264
  };
6049
6265
  });
6050
6266
  })(),
6051
- roam: true,
6267
+ roam: false,
6052
6268
  label: {
6053
6269
  position: "right",
6054
6270
  formatter: "{b}"
@@ -6210,16 +6426,6 @@ function getExtendedChartLegendGroups(parsed, colors) {
6210
6426
  }
6211
6427
  return [];
6212
6428
  }
6213
- function rectsOverlap(a, b) {
6214
- 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;
6215
- }
6216
- function rectCircleOverlap(rect, circle) {
6217
- const nearestX = Math.max(rect.x, Math.min(circle.cx, rect.x + rect.w));
6218
- const nearestY = Math.max(rect.y, Math.min(circle.cy, rect.y + rect.h));
6219
- const dx = nearestX - circle.cx;
6220
- const dy = nearestY - circle.cy;
6221
- return dx * dx + dy * dy < circle.r * circle.r;
6222
- }
6223
6429
  function computeScatterLabelGraphics(points, chartBounds, fontSize, symbolSize, bg) {
6224
6430
  const labelHeight = fontSize + 4;
6225
6431
  const stepSize = labelHeight + 2;
@@ -6596,12 +6802,17 @@ function buildHeatmapOption(parsed, palette, isDark, textColor, axisLineColor, t
6596
6802
  maxValue = Math.max(maxValue, value);
6597
6803
  });
6598
6804
  });
6805
+ const CHAR_WIDTH7 = 7;
6806
+ const ESTIMATED_CHART_WIDTH = 900;
6807
+ const longestCol = Math.max(...columns.map((c) => c.length), 0);
6808
+ const slotWidth = columns.length > 0 ? ESTIMATED_CHART_WIDTH / columns.length : Infinity;
6809
+ const needsRotation = longestCol * CHAR_WIDTH7 > slotWidth * 0.85;
6599
6810
  return {
6600
6811
  ...CHART_BASE,
6601
6812
  title: titleConfig,
6602
6813
  grid: {
6603
6814
  left: "3%",
6604
- right: "10%",
6815
+ right: "3%",
6605
6816
  bottom: "3%",
6606
6817
  top: parsed.title ? "15%" : "5%",
6607
6818
  containLabel: true
@@ -6609,6 +6820,7 @@ function buildHeatmapOption(parsed, palette, isDark, textColor, axisLineColor, t
6609
6820
  xAxis: {
6610
6821
  type: "category",
6611
6822
  data: columns,
6823
+ position: "top",
6612
6824
  splitArea: {
6613
6825
  show: true
6614
6826
  },
@@ -6617,12 +6829,19 @@ function buildHeatmapOption(parsed, palette, isDark, textColor, axisLineColor, t
6617
6829
  },
6618
6830
  axisLabel: {
6619
6831
  color: textColor,
6620
- fontSize: 16
6832
+ fontSize: 12,
6833
+ interval: 0,
6834
+ ...needsRotation && {
6835
+ rotate: -45,
6836
+ width: 200,
6837
+ overflow: "none"
6838
+ }
6621
6839
  }
6622
6840
  },
6623
6841
  yAxis: {
6624
6842
  type: "category",
6625
6843
  data: rowLabels,
6844
+ inverse: true,
6626
6845
  splitArea: {
6627
6846
  show: true
6628
6847
  },
@@ -6631,16 +6850,14 @@ function buildHeatmapOption(parsed, palette, isDark, textColor, axisLineColor, t
6631
6850
  },
6632
6851
  axisLabel: {
6633
6852
  color: textColor,
6634
- fontSize: 16
6853
+ fontSize: 12,
6854
+ interval: 0
6635
6855
  }
6636
6856
  },
6637
6857
  visualMap: {
6858
+ show: false,
6638
6859
  min: minValue,
6639
6860
  max: maxValue,
6640
- calculable: true,
6641
- orient: "vertical",
6642
- right: "2%",
6643
- top: "center",
6644
6861
  inRange: {
6645
6862
  color: [
6646
6863
  mix(palette.primary, bg, 30),
@@ -6648,9 +6865,6 @@ function buildHeatmapOption(parsed, palette, isDark, textColor, axisLineColor, t
6648
6865
  mix(palette.colors.yellow, bg, 30),
6649
6866
  mix(palette.colors.orange, bg, 30)
6650
6867
  ]
6651
- },
6652
- textStyle: {
6653
- color: textColor
6654
6868
  }
6655
6869
  },
6656
6870
  series: [
@@ -6668,9 +6882,8 @@ function buildHeatmapOption(parsed, palette, isDark, textColor, axisLineColor, t
6668
6882
  fontWeight: "bold"
6669
6883
  },
6670
6884
  emphasis: {
6671
- ...EMPHASIS_SELF
6672
- },
6673
- blur: BLUR_DIM
6885
+ disabled: true
6886
+ }
6674
6887
  }
6675
6888
  ]
6676
6889
  };
@@ -7525,6 +7738,7 @@ var init_echarts = __esm({
7525
7738
  init_fonts();
7526
7739
  init_branding();
7527
7740
  init_legend_svg();
7741
+ init_label_layout();
7528
7742
  init_palettes();
7529
7743
  init_color_utils();
7530
7744
  init_chart();
@@ -7806,6 +8020,7 @@ function parseOrg(content, palette) {
7806
8020
  };
7807
8021
  collectAll(result.roots);
7808
8022
  validateTagValues(allNodes, result.tagGroups, pushWarning, suggest);
8023
+ validateTagGroupNames(result.tagGroups, pushWarning);
7809
8024
  }
7810
8025
  if (result.roots.length === 0 && result.tagGroups.length === 0 && !result.error) {
7811
8026
  const diag = makeDgmoError(1, "No nodes found in org chart");
@@ -7872,7 +8087,8 @@ var init_parser4 = __esm({
7872
8087
  KNOWN_OPTIONS3 = /* @__PURE__ */ new Set([
7873
8088
  "sub-node-label",
7874
8089
  "hide",
7875
- "show-sub-node-count"
8090
+ "show-sub-node-count",
8091
+ "active-tag"
7876
8092
  ]);
7877
8093
  KNOWN_BOOLEANS2 = /* @__PURE__ */ new Set(["show-sub-node-count", "direction-tb"]);
7878
8094
  }
@@ -8133,6 +8349,7 @@ function parseKanban(content, palette) {
8133
8349
  if (result.columns.length === 0 && !result.error) {
8134
8350
  return fail(1, "No columns found. Use [Column Name] to define columns");
8135
8351
  }
8352
+ validateTagGroupNames(result.tagGroups, warn);
8136
8353
  return result;
8137
8354
  }
8138
8355
  function parseCardLine(trimmed, lineNumber, counter, aliasMap, palette) {
@@ -8178,7 +8395,7 @@ var init_parser5 = __esm({
8178
8395
  init_parsing();
8179
8396
  COLUMN_RE = /^\[(.+?)\](?:\s*\(([^)]+)\))?\s*(?:\|\s*(.+))?$/;
8180
8397
  LEGACY_COLUMN_RE = /^==\s+(.+?)\s*(?:\[wip:\s*(\d+)\])?\s*==$/;
8181
- KNOWN_OPTIONS4 = /* @__PURE__ */ new Set(["hide"]);
8398
+ KNOWN_OPTIONS4 = /* @__PURE__ */ new Set(["hide", "active-tag"]);
8182
8399
  KNOWN_BOOLEANS3 = /* @__PURE__ */ new Set(["no-auto-color"]);
8183
8400
  }
8184
8401
  });
@@ -8721,6 +8938,10 @@ function parseC4(content, palette) {
8721
8938
  }
8722
8939
  validateRelationshipTargets(result, knownNames, pushError);
8723
8940
  validateDeploymentRefs(result, knownNames, pushError);
8941
+ validateTagGroupNames(
8942
+ result.tagGroups,
8943
+ (line10, msg) => pushError(line10, msg, "warning")
8944
+ );
8724
8945
  return result;
8725
8946
  }
8726
8947
  function findParentElement(indent, stack) {
@@ -8847,7 +9068,7 @@ var init_parser6 = __esm({
8847
9068
  "cloud",
8848
9069
  "external"
8849
9070
  ]);
8850
- KNOWN_C4_OPTIONS = /* @__PURE__ */ new Set(["layout"]);
9071
+ KNOWN_C4_OPTIONS = /* @__PURE__ */ new Set(["layout", "active-tag"]);
8851
9072
  KNOWN_C4_BOOLEANS = /* @__PURE__ */ new Set(["direction-tb"]);
8852
9073
  ALL_CHART_TYPES2 = [
8853
9074
  "c4",
@@ -9185,6 +9406,7 @@ function parseSitemap(content, palette) {
9185
9406
  };
9186
9407
  collectAll(result.roots);
9187
9408
  validateTagValues(allNodes, result.tagGroups, pushWarning, suggest);
9409
+ validateTagGroupNames(result.tagGroups, pushWarning);
9188
9410
  }
9189
9411
  if (result.roots.length === 0 && result.tagGroups.length === 0 && !result.error) {
9190
9412
  const diag = makeDgmoError(1, "No pages found in sitemap");
@@ -9785,6 +10007,7 @@ function parseInfra(content) {
9785
10007
  }
9786
10008
  }
9787
10009
  }
10010
+ validateTagGroupNames(result.tagGroups, warn);
9788
10011
  return result;
9789
10012
  }
9790
10013
  function extractSymbols4(docText) {
@@ -9863,7 +10086,8 @@ var init_parser8 = __esm({
9863
10086
  "slo-warning-margin",
9864
10087
  "default-latency-ms",
9865
10088
  "default-uptime",
9866
- "default-rps"
10089
+ "default-rps",
10090
+ "active-tag"
9867
10091
  ]);
9868
10092
  UNPARSED_SPLIT_RE = /\bsplit\s+(\d+)%/;
9869
10093
  }
@@ -10061,6 +10285,7 @@ function parseGantt(content, palette) {
10061
10285
  dependencies: true,
10062
10286
  sort: "default",
10063
10287
  defaultSwimlaneGroup: null,
10288
+ activeTag: null,
10064
10289
  optionLineNumbers: {},
10065
10290
  holidaysLineNumber: null
10066
10291
  },
@@ -10475,6 +10700,9 @@ function parseGantt(content, palette) {
10475
10700
  );
10476
10701
  }
10477
10702
  break;
10703
+ case "active-tag":
10704
+ result.options.activeTag = value;
10705
+ break;
10478
10706
  }
10479
10707
  continue;
10480
10708
  }
@@ -10654,6 +10882,7 @@ function parseGantt(content, palette) {
10654
10882
  warn(0, "sort tag has no effect \u2014 no tag groups defined.");
10655
10883
  result.options.sort = "default";
10656
10884
  }
10885
+ validateTagGroupNames(result.tagGroups, warn);
10657
10886
  return result;
10658
10887
  function makeTask(labelRaw, duration, uncertain, ln, explicitStart) {
10659
10888
  const segments = labelRaw.split("|");
@@ -10816,7 +11045,8 @@ var init_parser9 = __esm({
10816
11045
  "critical-path",
10817
11046
  "dependencies",
10818
11047
  "chart",
10819
- "sort"
11048
+ "sort",
11049
+ "active-tag"
10820
11050
  ]);
10821
11051
  KNOWN_BOOLEANS4 = /* @__PURE__ */ new Set([
10822
11052
  "critical-path",
@@ -11236,6 +11466,7 @@ function parseBoxesAndLines(content) {
11236
11466
  if (result.tagGroups.length > 0) {
11237
11467
  injectDefaultTagMetadata(result.nodes, result.tagGroups);
11238
11468
  validateTagValues(result.nodes, result.tagGroups, pushWarning, suggest);
11469
+ validateTagGroupNames(result.tagGroups, pushWarning);
11239
11470
  }
11240
11471
  return result;
11241
11472
  }
@@ -14092,8 +14323,7 @@ function computeLayout(parsed, _palette) {
14092
14323
  currentX += cl.width + COLUMN_GAP;
14093
14324
  }
14094
14325
  const totalWidth = currentX - COLUMN_GAP + DIAGRAM_PADDING3;
14095
- const legendSpace = parsed.tagGroups.length > 0 ? LEGEND_HEIGHT : 0;
14096
- const totalHeight = startY + maxColumnHeight + DIAGRAM_PADDING3 + legendSpace;
14326
+ const totalHeight = startY + maxColumnHeight + DIAGRAM_PADDING3;
14097
14327
  return { columns: columnLayouts, totalWidth, totalHeight };
14098
14328
  }
14099
14329
  function renderKanban(container, parsed, palette, isDark, _onNavigateToLine, exportDims, activeTagGroup) {
@@ -14106,14 +14336,16 @@ function renderKanban(container, parsed, palette, isDark, _onNavigateToLine, exp
14106
14336
  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);
14107
14337
  }
14108
14338
  if (parsed.tagGroups.length > 0) {
14109
- const legendY = height - LEGEND_HEIGHT;
14339
+ const titleTextWidth = parsed.title ? measureLegendText(parsed.title, TITLE_FONT_SIZE) + 16 : 0;
14340
+ const legendX = DIAGRAM_PADDING3 + titleTextWidth;
14341
+ const legendY = DIAGRAM_PADDING3 + (TITLE_FONT_SIZE - LEGEND_HEIGHT) / 2;
14110
14342
  const legendConfig = {
14111
14343
  groups: parsed.tagGroups,
14112
- position: { placement: "top-center", titleRelation: "below-title" },
14344
+ position: { placement: "top-center", titleRelation: "inline-with-title" },
14113
14345
  mode: exportDims ? "inline" : "fixed"
14114
14346
  };
14115
14347
  const legendState = { activeGroup: activeTagGroup ?? null };
14116
- const legendG = svg.append("g").attr("class", "kanban-legend").attr("transform", `translate(${DIAGRAM_PADDING3},${legendY})`);
14348
+ const legendG = svg.append("g").attr("class", "kanban-legend").attr("transform", `translate(${legendX},${legendY})`);
14117
14349
  renderLegendD3(
14118
14350
  legendG,
14119
14351
  legendConfig,
@@ -14121,7 +14353,7 @@ function renderKanban(container, parsed, palette, isDark, _onNavigateToLine, exp
14121
14353
  palette,
14122
14354
  isDark,
14123
14355
  void 0,
14124
- width - DIAGRAM_PADDING3 * 2
14356
+ width - legendX - DIAGRAM_PADDING3
14125
14357
  );
14126
14358
  }
14127
14359
  const defaultColBg = isDark ? mix(palette.surface, palette.bg, 50) : mix(palette.surface, palette.bg, 30);
@@ -15662,7 +15894,7 @@ function fitTextToNode(label, nodeWidth, nodeHeight) {
15662
15894
  const maxTextWidth = nodeWidth - NODE_TEXT_PADDING * 2;
15663
15895
  const lineHeight = 1.3;
15664
15896
  for (let fontSize = NODE_FONT_SIZE; fontSize >= MIN_NODE_FONT_SIZE; fontSize--) {
15665
- const charWidth2 = fontSize * CHAR_WIDTH_RATIO;
15897
+ const charWidth2 = fontSize * CHAR_WIDTH_RATIO2;
15666
15898
  const maxCharsPerLine = Math.floor(maxTextWidth / charWidth2);
15667
15899
  const maxLines = Math.floor((nodeHeight - 8) / (fontSize * lineHeight));
15668
15900
  if (maxCharsPerLine < 2 || maxLines < 1) continue;
@@ -15714,7 +15946,7 @@ function fitTextToNode(label, nodeWidth, nodeHeight) {
15714
15946
  }
15715
15947
  if (hardLines.length <= maxLines) return { lines: hardLines, fontSize };
15716
15948
  }
15717
- const charWidth = MIN_NODE_FONT_SIZE * CHAR_WIDTH_RATIO;
15949
+ const charWidth = MIN_NODE_FONT_SIZE * CHAR_WIDTH_RATIO2;
15718
15950
  const maxChars = Math.floor((nodeWidth - NODE_TEXT_PADDING * 2) / charWidth);
15719
15951
  const truncated = label.length > maxChars ? label.slice(0, maxChars - 1) + "\u2026" : label;
15720
15952
  return { lines: [truncated], fontSize: MIN_NODE_FONT_SIZE };
@@ -15791,7 +16023,11 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
15791
16023
  const width = exportDims?.width ?? container.clientWidth;
15792
16024
  const height = exportDims?.height ?? container.clientHeight;
15793
16025
  if (width <= 0 || height <= 0) return;
15794
- const activeGroup = activeTagGroup ?? parsed.options["active-tag"] ?? null;
16026
+ const activeGroup = resolveActiveTagGroup(
16027
+ parsed.tagGroups,
16028
+ parsed.options["active-tag"],
16029
+ activeTagGroup
16030
+ );
15795
16031
  const hidden = hiddenTagValues ?? parsed.initialHiddenTagValues;
15796
16032
  const nodeMap = /* @__PURE__ */ new Map();
15797
16033
  for (const node of parsed.nodes) nodeMap.set(node.label, node);
@@ -15873,7 +16109,7 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
15873
16109
  path.attr("marker-start", `url(#${revId})`);
15874
16110
  }
15875
16111
  if (le.label && le.labelX != null && le.labelY != null) {
15876
- const lw = le.label.length * EDGE_LABEL_FONT_SIZE4 * CHAR_WIDTH_RATIO;
16112
+ const lw = le.label.length * EDGE_LABEL_FONT_SIZE4 * CHAR_WIDTH_RATIO2;
15877
16113
  labelPositions.push({
15878
16114
  x: le.labelX,
15879
16115
  y: le.labelY + le.yOffset,
@@ -15931,7 +16167,7 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
15931
16167
  const descY = labelY + lineH / 2 + gap + META_FONT_SIZE3 / 2;
15932
16168
  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);
15933
16169
  const maxChars = Math.floor(
15934
- (ln.width - NODE_TEXT_PADDING * 2) / (META_FONT_SIZE3 * CHAR_WIDTH_RATIO)
16170
+ (ln.width - NODE_TEXT_PADDING * 2) / (META_FONT_SIZE3 * CHAR_WIDTH_RATIO2)
15935
16171
  );
15936
16172
  const desc = node.description.length > maxChars ? node.description.slice(0, maxChars - 1) + "\u2026" : node.description;
15937
16173
  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);
@@ -15969,10 +16205,11 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
15969
16205
  }
15970
16206
  function renderBoxesAndLinesForExport(container, parsed, layout, palette, isDark, options) {
15971
16207
  renderBoxesAndLines(container, parsed, layout, palette, isDark, {
15972
- exportDims: options?.exportDims
16208
+ exportDims: options?.exportDims,
16209
+ activeTagGroup: options?.activeTagGroup
15973
16210
  });
15974
16211
  }
15975
- var d3Selection6, d3Shape4, 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;
16212
+ var d3Selection6, d3Shape4, 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;
15976
16213
  var init_renderer6 = __esm({
15977
16214
  "src/boxes-and-lines/renderer.ts"() {
15978
16215
  "use strict";
@@ -15995,7 +16232,7 @@ var init_renderer6 = __esm({
15995
16232
  COLLAPSE_BAR_HEIGHT3 = 4;
15996
16233
  ARROWHEAD_W2 = 5;
15997
16234
  ARROWHEAD_H2 = 4;
15998
- CHAR_WIDTH_RATIO = 0.6;
16235
+ CHAR_WIDTH_RATIO2 = 0.6;
15999
16236
  NODE_TEXT_PADDING = 12;
16000
16237
  GROUP_RX = 8;
16001
16238
  GROUP_LABEL_FONT_SIZE = 14;
@@ -16066,7 +16303,7 @@ function reduceCrossings(g, edgeList, nodeGroupMap) {
16066
16303
  }
16067
16304
  const nodeGeometry = /* @__PURE__ */ new Map();
16068
16305
  for (const name of g.nodes()) {
16069
- const pos = g.node(name);
16306
+ const pos = gNode(g, name);
16070
16307
  if (pos)
16071
16308
  nodeGeometry.set(name, {
16072
16309
  y: pos.y,
@@ -16076,14 +16313,14 @@ function reduceCrossings(g, edgeList, nodeGroupMap) {
16076
16313
  }
16077
16314
  const rankMap = /* @__PURE__ */ new Map();
16078
16315
  for (const name of g.nodes()) {
16079
- const pos = g.node(name);
16316
+ const pos = gNode(g, name);
16080
16317
  if (!pos) continue;
16081
16318
  const rankY = Math.round(pos.y);
16082
16319
  if (!rankMap.has(rankY)) rankMap.set(rankY, []);
16083
16320
  rankMap.get(rankY).push(name);
16084
16321
  }
16085
16322
  for (const [, rankNodes] of rankMap) {
16086
- rankNodes.sort((a, b) => g.node(a).x - g.node(b).x);
16323
+ rankNodes.sort((a, b) => gNode(g, a).x - gNode(g, b).x);
16087
16324
  }
16088
16325
  let anyMoved = false;
16089
16326
  for (const [, rankNodes] of rankMap) {
@@ -16110,10 +16347,10 @@ function reduceCrossings(g, edgeList, nodeGroupMap) {
16110
16347
  }
16111
16348
  for (const partition of partitions) {
16112
16349
  if (partition.length < 2) continue;
16113
- const xSlots = partition.map((name) => g.node(name).x).sort((a, b) => a - b);
16350
+ const xSlots = partition.map((name) => gNode(g, name).x).sort((a, b) => a - b);
16114
16351
  const basePositions = /* @__PURE__ */ new Map();
16115
16352
  for (const name of g.nodes()) {
16116
- const pos = g.node(name);
16353
+ const pos = gNode(g, name);
16117
16354
  if (pos) basePositions.set(name, pos.x);
16118
16355
  }
16119
16356
  const currentPenalty = computeEdgePenalty(
@@ -16191,7 +16428,7 @@ function reduceCrossings(g, edgeList, nodeGroupMap) {
16191
16428
  }
16192
16429
  if (bestPerm.some((name, i) => name !== partition[i])) {
16193
16430
  for (let i = 0; i < bestPerm.length; i++) {
16194
- g.node(bestPerm[i]).x = xSlots[i];
16431
+ gNode(g, bestPerm[i]).x = xSlots[i];
16195
16432
  const rankIdx = rankNodes.indexOf(partition[i]);
16196
16433
  if (rankIdx >= 0) rankNodes[rankIdx] = bestPerm[i];
16197
16434
  }
@@ -16201,10 +16438,10 @@ function reduceCrossings(g, edgeList, nodeGroupMap) {
16201
16438
  }
16202
16439
  if (anyMoved) {
16203
16440
  for (const edge of edgeList) {
16204
- const edgeData = g.edge(edge.source, edge.target);
16441
+ const edgeData = gEdge(g, edge.source, edge.target);
16205
16442
  if (!edgeData) continue;
16206
- const srcPos = g.node(edge.source);
16207
- const tgtPos = g.node(edge.target);
16443
+ const srcPos = gNode(g, edge.source);
16444
+ const tgtPos = gNode(g, edge.target);
16208
16445
  if (!srcPos || !tgtPos) continue;
16209
16446
  const srcBottom = { x: srcPos.x, y: srcPos.y + srcPos.height / 2 };
16210
16447
  const tgtTop = { x: tgtPos.x, y: tgtPos.y - tgtPos.height / 2 };
@@ -17648,12 +17885,14 @@ function layoutC4Deployment(parsed, activeTagGroup) {
17648
17885
  height: totalHeight
17649
17886
  };
17650
17887
  }
17651
- var import_dagre5, 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;
17888
+ var import_dagre5, 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;
17652
17889
  var init_layout6 = __esm({
17653
17890
  "src/c4/layout.ts"() {
17654
17891
  "use strict";
17655
17892
  import_dagre5 = __toESM(require("@dagrejs/dagre"), 1);
17656
17893
  init_legend_constants();
17894
+ gNode = (g, name) => g.node(name);
17895
+ gEdge = (g, v, w) => g.edge(v, w);
17657
17896
  CHAR_WIDTH5 = 8;
17658
17897
  MIN_NODE_WIDTH = 160;
17659
17898
  MAX_NODE_WIDTH = 260;
@@ -22583,7 +22822,11 @@ function renderGantt(container, resolved, palette, isDark, options, exportDims)
22583
22822
  const collapsedLanes = options?.collapsedLanes;
22584
22823
  const onToggleLane = options?.onToggleLane;
22585
22824
  const seriesColors2 = getSeriesColors(palette);
22586
- let currentActiveGroup = options?.currentActiveGroup !== void 0 ? options.currentActiveGroup : resolved.tagGroups.length > 0 ? resolved.tagGroups[0].name : null;
22825
+ let currentActiveGroup = resolveActiveTagGroup(
22826
+ resolved.tagGroups,
22827
+ resolved.options.activeTag ?? void 0,
22828
+ options?.currentActiveGroup
22829
+ );
22587
22830
  let criticalPathActive = false;
22588
22831
  const tagRows = currentSwimlaneGroup ? buildTagLaneRowList(resolved, currentSwimlaneGroup, collapsedLanes) : null;
22589
22832
  const rows = tagRows ?? buildRowList(resolved, collapsedGroups);
@@ -24942,7 +25185,11 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
24942
25185
  );
24943
25186
  if (participants.length === 0) return;
24944
25187
  const activationsOff = parsedOptions.activations?.toLowerCase() === "off";
24945
- const activeTagGroup = options?.activeTagGroup !== void 0 ? options.activeTagGroup || void 0 : parsedOptions["active-tag"] || void 0;
25188
+ const activeTagGroup = resolveActiveTagGroup(
25189
+ parsed.tagGroups,
25190
+ parsedOptions["active-tag"],
25191
+ options?.activeTagGroup
25192
+ ) ?? void 0;
24946
25193
  let tagMap;
24947
25194
  const tagValueToColor = /* @__PURE__ */ new Map();
24948
25195
  if (activeTagGroup) {
@@ -25456,7 +25703,8 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
25456
25703
  for (const branch of el.elseIfBranches) {
25457
25704
  elseIfBranchData.push({
25458
25705
  label: branch.label,
25459
- indices: collectMsgIndices(branch.children)
25706
+ indices: collectMsgIndices(branch.children),
25707
+ lineNumber: branch.lineNumber
25460
25708
  });
25461
25709
  }
25462
25710
  }
@@ -25517,14 +25765,16 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
25517
25765
  x1: frameX,
25518
25766
  y1: dividerY,
25519
25767
  x2: frameX + frameW,
25520
- y2: dividerY
25768
+ y2: dividerY,
25769
+ blockLine: branchData.lineNumber
25521
25770
  });
25522
25771
  deferredLabels.push({
25523
25772
  x: frameX + 6,
25524
25773
  y: dividerY + 14,
25525
25774
  text: `else if ${branchData.label}`,
25526
25775
  bold: false,
25527
- italic: true
25776
+ italic: true,
25777
+ blockLine: branchData.lineNumber
25528
25778
  });
25529
25779
  }
25530
25780
  }
@@ -25542,14 +25792,16 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
25542
25792
  x1: frameX,
25543
25793
  y1: dividerY,
25544
25794
  x2: frameX + frameW,
25545
- y2: dividerY
25795
+ y2: dividerY,
25796
+ blockLine: el.elseLineNumber
25546
25797
  });
25547
25798
  deferredLabels.push({
25548
25799
  x: frameX + 6,
25549
25800
  y: dividerY + 14,
25550
25801
  text: "else",
25551
25802
  bold: false,
25552
- italic: true
25803
+ italic: true,
25804
+ blockLine: el.elseLineNumber
25553
25805
  });
25554
25806
  }
25555
25807
  }
@@ -25595,7 +25847,9 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
25595
25847
  }
25596
25848
  });
25597
25849
  for (const ln of deferredLines) {
25598
- 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");
25850
+ 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");
25851
+ if (ln.blockLine !== void 0)
25852
+ line10.attr("data-block-line", String(ln.blockLine));
25599
25853
  }
25600
25854
  for (const lbl of deferredLabels) {
25601
25855
  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);
@@ -25938,6 +26192,7 @@ var init_renderer10 = __esm({
25938
26192
  init_colors();
25939
26193
  init_parser();
25940
26194
  init_tag_resolution();
26195
+ init_tag_groups();
25941
26196
  init_legend_constants();
25942
26197
  init_legend_d3();
25943
26198
  init_title_constants();
@@ -26893,6 +27148,10 @@ function parseVisualization(content, palette) {
26893
27148
  (line10, msg) => result.diagnostics.push(makeDgmoError(line10, msg, "warning")),
26894
27149
  suggest
26895
27150
  );
27151
+ validateTagGroupNames(
27152
+ result.timelineTagGroups,
27153
+ (line10, msg) => result.diagnostics.push(makeDgmoError(line10, msg, "warning"))
27154
+ );
26896
27155
  for (const group of result.timelineTagGroups) {
26897
27156
  if (!group.defaultValue) continue;
26898
27157
  const key = group.name.toLowerCase();
@@ -27789,6 +28048,26 @@ function buildEventTooltipHtml(ev) {
27789
28048
  function buildEraTooltipHtml(era) {
27790
28049
  return `<strong>${era.label}</strong><br>${formatDateLabel(era.startDate)} \u2192 ${formatDateLabel(era.endDate)}`;
27791
28050
  }
28051
+ function renderTimelineGroupLegend(g, groups, groupColorMap, textColor, palette, isDark, legendY, onHover, onLeave) {
28052
+ const PILL_H = 22;
28053
+ const DOT_R = 4;
28054
+ const DOT_GAP = 4;
28055
+ const PAD_X = 10;
28056
+ const FONT_SIZE = 11;
28057
+ const GAP = 8;
28058
+ const pillBg = isDark ? mix(palette.surface, palette.bg, 50) : mix(palette.surface, palette.bg, 30);
28059
+ let legendX = 0;
28060
+ for (const grp of groups) {
28061
+ const color = groupColorMap.get(grp.name) ?? textColor;
28062
+ const textW = measureLegendText(grp.name, FONT_SIZE);
28063
+ const pillW = PAD_X + DOT_R * 2 + DOT_GAP + textW + PAD_X;
28064
+ 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());
28065
+ 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);
28066
+ itemG.append("circle").attr("cx", legendX + PAD_X + DOT_R).attr("cy", legendY).attr("r", DOT_R).attr("fill", color);
28067
+ 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);
28068
+ legendX += pillW + GAP;
28069
+ }
28070
+ }
27792
28071
  function renderTimeline(container, parsed, palette, isDark, onClickItem, exportDims, activeTagGroup, swimlaneTagGroup, onTagStateChange, viewMode) {
27793
28072
  d3Selection13.select(container).selectAll(":not([data-d3-tooltip])").remove();
27794
28073
  const {
@@ -28180,15 +28459,17 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
28180
28459
  );
28181
28460
  }
28182
28461
  if (timelineGroups.length > 0) {
28183
- let legendX = 0;
28184
- const legendY = -55;
28185
- for (const grp of timelineGroups) {
28186
- const color = groupColorMap.get(grp.name) ?? textColor;
28187
- 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));
28188
- itemG.append("circle").attr("cx", legendX).attr("cy", legendY).attr("r", 5).attr("fill", color);
28189
- itemG.append("text").attr("x", legendX + 10).attr("y", legendY).attr("dy", "0.35em").attr("fill", textColor).attr("font-size", "11px").text(grp.name);
28190
- legendX += grp.name.length * 7 + 30;
28191
- }
28462
+ renderTimelineGroupLegend(
28463
+ g,
28464
+ timelineGroups,
28465
+ groupColorMap,
28466
+ textColor,
28467
+ palette,
28468
+ isDark,
28469
+ -55,
28470
+ (name) => fadeToGroup(g, name),
28471
+ () => fadeReset(g)
28472
+ );
28192
28473
  }
28193
28474
  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");
28194
28475
  for (const ev of sorted) {
@@ -28415,7 +28696,7 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
28415
28696
  }
28416
28697
  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);
28417
28698
  if (labelFitsInside) {
28418
- 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);
28699
+ 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);
28419
28700
  } else {
28420
28701
  const wouldFlipLeft = x + rectW > innerWidth * 0.6;
28421
28702
  const labelFitsLeft = x - 6 - estLabelWidth > 0;
@@ -28496,15 +28777,18 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
28496
28777
  );
28497
28778
  }
28498
28779
  if (timelineGroups.length > 0) {
28499
- let legendX = 0;
28500
28780
  const legendY = timelineScale ? -75 : -55;
28501
- for (const grp of timelineGroups) {
28502
- const color = groupColorMap.get(grp.name) ?? textColor;
28503
- 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));
28504
- itemG.append("circle").attr("cx", legendX).attr("cy", legendY).attr("r", 5).attr("fill", color);
28505
- itemG.append("text").attr("x", legendX + 10).attr("y", legendY).attr("dy", "0.35em").attr("fill", textColor).attr("font-size", "11px").text(grp.name);
28506
- legendX += grp.name.length * 7 + 30;
28507
- }
28781
+ renderTimelineGroupLegend(
28782
+ g,
28783
+ timelineGroups,
28784
+ groupColorMap,
28785
+ textColor,
28786
+ palette,
28787
+ isDark,
28788
+ legendY,
28789
+ (name) => fadeToGroup(g, name),
28790
+ () => fadeReset(g)
28791
+ );
28508
28792
  }
28509
28793
  sorted.forEach((ev, i) => {
28510
28794
  const y = markerMargin + i * rowH + rowH / 2;
@@ -28569,7 +28853,7 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
28569
28853
  }
28570
28854
  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);
28571
28855
  if (labelFitsInside) {
28572
- 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);
28856
+ 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);
28573
28857
  } else {
28574
28858
  const wouldFlipLeft = x + rectW > innerWidth * 0.6;
28575
28859
  const labelFitsLeft = x - 6 - estLabelWidth > 0;
@@ -28937,7 +29221,7 @@ function regionCentroid(circles, inside) {
28937
29221
  }
28938
29222
  function renderVenn(container, parsed, palette, isDark, onClickItem, exportDims) {
28939
29223
  const { vennSets, vennOverlaps, title } = parsed;
28940
- if (vennSets.length < 2) return;
29224
+ if (vennSets.length < 2 || vennSets.length > 3) return;
28941
29225
  const init2 = initD3Chart(container, palette, exportDims);
28942
29226
  if (!init2) return;
28943
29227
  const { svg, width, height, textColor, colors } = init2;
@@ -28993,7 +29277,9 @@ function renderVenn(container, parsed, palette, isDark, onClickItem, exportDims)
28993
29277
  marginBottom
28994
29278
  ).map((c) => ({ ...c, y: c.y + titleHeight }));
28995
29279
  const scaledR = circles[0].r;
28996
- svg.append("style").text("circle:focus, circle:focus-visible { outline: none !important; }");
29280
+ svg.append("style").text(
29281
+ "circle:focus, circle:focus-visible { outline-solid: none !important; }"
29282
+ );
28997
29283
  renderChartTitle(
28998
29284
  svg,
28999
29285
  title,
@@ -29175,7 +29461,7 @@ function renderVenn(container, parsed, palette, isDark, onClickItem, exportDims)
29175
29461
  }
29176
29462
  const hoverGroup = svg.append("g");
29177
29463
  circles.forEach((c, i) => {
29178
- 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", () => {
29464
+ 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", () => {
29179
29465
  showRegionOverlay([i]);
29180
29466
  }).on("mouseleave", () => {
29181
29467
  hideAllOverlays();
@@ -29213,7 +29499,7 @@ function renderVenn(container, parsed, palette, isDark, onClickItem, exportDims)
29213
29499
  const declaredOv = vennOverlaps.find(
29214
29500
  (ov) => ov.sets.length === sets.length && ov.sets.every((s, k) => s === sets[k])
29215
29501
  );
29216
- 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", () => {
29502
+ 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", () => {
29217
29503
  showRegionOverlay(idxs);
29218
29504
  }).on("mouseleave", () => {
29219
29505
  hideAllOverlays();
@@ -29347,8 +29633,8 @@ function renderQuadrant(container, parsed, palette, isDark, onClickItem, exportD
29347
29633
  const LABEL_MAX_FONT = 48;
29348
29634
  const LABEL_MIN_FONT = 14;
29349
29635
  const LABEL_PAD2 = 40;
29350
- const CHAR_WIDTH_RATIO2 = 0.6;
29351
- const estTextWidth = (text, fontSize) => text.length * fontSize * CHAR_WIDTH_RATIO2;
29636
+ const CHAR_WIDTH_RATIO3 = 0.6;
29637
+ const estTextWidth = (text, fontSize) => text.length * fontSize * CHAR_WIDTH_RATIO3;
29352
29638
  const quadrantLabelLayout = (text, qw2, qh2) => {
29353
29639
  const availW = qw2 - LABEL_PAD2;
29354
29640
  const availH = qh2 - LABEL_PAD2;
@@ -29492,16 +29778,45 @@ function renderQuadrant(container, parsed, palette, isDark, onClickItem, exportD
29492
29778
  if (x < 0.5 && y < 0.5) return "bottom-left";
29493
29779
  return "bottom-right";
29494
29780
  };
29781
+ const POINT_RADIUS = 6;
29782
+ const POINT_LABEL_FONT_SIZE = 12;
29783
+ const quadrantLabelObstacles = quadrantDefsWithLabel.map((d) => {
29784
+ const layout = labelLayouts.get(d.label.text);
29785
+ const totalW = Math.max(...layout.lines.map((l) => l.length)) * layout.fontSize * CHAR_WIDTH_RATIO3;
29786
+ const totalH = layout.lines.length * layout.fontSize * 1.2;
29787
+ return {
29788
+ x: d.labelX - totalW / 2,
29789
+ y: d.labelY - totalH / 2,
29790
+ w: totalW,
29791
+ h: totalH
29792
+ };
29793
+ });
29794
+ const pointPixels = quadrantPoints.map((point) => ({
29795
+ label: point.label,
29796
+ cx: xScale(point.x),
29797
+ cy: yScale(point.y)
29798
+ }));
29799
+ const placedPointLabels = computeQuadrantPointLabels(
29800
+ pointPixels,
29801
+ { left: 0, top: 0, right: chartWidth, bottom: chartHeight },
29802
+ quadrantLabelObstacles,
29803
+ POINT_RADIUS,
29804
+ POINT_LABEL_FONT_SIZE
29805
+ );
29495
29806
  const pointsG = chartG.append("g").attr("class", "points");
29496
- quadrantPoints.forEach((point) => {
29807
+ quadrantPoints.forEach((point, i) => {
29497
29808
  const cx = xScale(point.x);
29498
29809
  const cy = yScale(point.y);
29499
29810
  const quadrant = getPointQuadrant(point.x, point.y);
29500
29811
  const quadDef = quadrantDefs.find((d) => d.position === quadrant);
29501
29812
  const pointColor = quadDef?.label?.color ?? defaultColors[quadDef?.colorIdx ?? 0];
29813
+ const placed = placedPointLabels[i];
29502
29814
  const pointG = pointsG.append("g").attr("class", "point-group").attr("data-line-number", String(point.lineNumber));
29503
- pointG.append("circle").attr("cx", cx).attr("cy", cy).attr("r", 6).attr("fill", "#ffffff").attr("stroke", pointColor).attr("stroke-width", 2);
29504
- 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);
29815
+ if (placed.connectorLine) {
29816
+ 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);
29817
+ }
29818
+ pointG.append("circle").attr("cx", cx).attr("cy", cy).attr("r", POINT_RADIUS).attr("fill", "#ffffff").attr("stroke", pointColor).attr("stroke-width", 2);
29819
+ 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);
29505
29820
  const tipHtml = `<strong>${point.label}</strong><br>x: ${point.x.toFixed(2)}, y: ${point.y.toFixed(2)}`;
29506
29821
  pointG.style("cursor", onClickItem ? "pointer" : "default").on("mouseenter", (event) => {
29507
29822
  showTooltip(tooltip, tipHtml, event);
@@ -29510,7 +29825,7 @@ function renderQuadrant(container, parsed, palette, isDark, onClickItem, exportD
29510
29825
  showTooltip(tooltip, tipHtml, event);
29511
29826
  }).on("mouseleave", () => {
29512
29827
  hideTooltip(tooltip);
29513
- pointG.select("circle").attr("r", 6);
29828
+ pointG.select("circle").attr("r", POINT_RADIUS);
29514
29829
  }).on("click", () => {
29515
29830
  if (onClickItem && point.lineNumber) onClickItem(point.lineNumber);
29516
29831
  });
@@ -29585,7 +29900,11 @@ async function renderForExport(content, theme, palette, orgExportState, options)
29585
29900
  const orgParsed = parseOrg2(content, effectivePalette2);
29586
29901
  if (orgParsed.error) return "";
29587
29902
  const collapsedNodes = orgExportState?.collapsedNodes;
29588
- const activeTagGroup = orgExportState?.activeTagGroup ?? options?.tagGroup ?? null;
29903
+ const activeTagGroup = resolveActiveTagGroup(
29904
+ orgParsed.tagGroups,
29905
+ orgParsed.options["active-tag"],
29906
+ orgExportState?.activeTagGroup ?? options?.tagGroup
29907
+ );
29589
29908
  const hiddenAttributes = orgExportState?.hiddenAttributes;
29590
29909
  const { parsed: effectiveParsed, hiddenCounts } = collapsedNodes && collapsedNodes.size > 0 ? collapseOrgTree2(orgParsed, collapsedNodes) : { parsed: orgParsed, hiddenCounts: /* @__PURE__ */ new Map() };
29591
29910
  const orgLayout = layoutOrg2(
@@ -29624,7 +29943,11 @@ async function renderForExport(content, theme, palette, orgExportState, options)
29624
29943
  const sitemapParsed = parseSitemap2(content, effectivePalette2);
29625
29944
  if (sitemapParsed.error || sitemapParsed.roots.length === 0) return "";
29626
29945
  const collapsedNodes = orgExportState?.collapsedNodes;
29627
- const activeTagGroup = orgExportState?.activeTagGroup ?? options?.tagGroup ?? null;
29946
+ const activeTagGroup = resolveActiveTagGroup(
29947
+ sitemapParsed.tagGroups,
29948
+ sitemapParsed.options["active-tag"],
29949
+ orgExportState?.activeTagGroup ?? options?.tagGroup
29950
+ );
29628
29951
  const hiddenAttributes = orgExportState?.hiddenAttributes;
29629
29952
  const { parsed: effectiveParsed, hiddenCounts } = collapsedNodes && collapsedNodes.size > 0 ? collapseSitemapTree2(sitemapParsed, collapsedNodes) : { parsed: sitemapParsed, hiddenCounts: /* @__PURE__ */ new Map() };
29630
29953
  const sitemapLayout = layoutSitemap2(
@@ -29669,7 +29992,11 @@ async function renderForExport(content, theme, palette, orgExportState, options)
29669
29992
  theme === "dark",
29670
29993
  void 0,
29671
29994
  void 0,
29672
- options?.tagGroup
29995
+ resolveActiveTagGroup(
29996
+ kanbanParsed.tagGroups,
29997
+ kanbanParsed.options["active-tag"],
29998
+ options?.tagGroup
29999
+ )
29673
30000
  );
29674
30001
  return finalizeSvgExport(container2, theme, effectivePalette2, options);
29675
30002
  }
@@ -29718,7 +30045,11 @@ async function renderForExport(content, theme, palette, orgExportState, options)
29718
30045
  theme === "dark",
29719
30046
  void 0,
29720
30047
  { width: exportWidth, height: exportHeight },
29721
- options?.tagGroup
30048
+ resolveActiveTagGroup(
30049
+ erParsed.tagGroups,
30050
+ erParsed.options["active-tag"],
30051
+ options?.tagGroup
30052
+ )
29722
30053
  );
29723
30054
  return finalizeSvgExport(container2, theme, effectivePalette2, options);
29724
30055
  }
@@ -29741,7 +30072,10 @@ async function renderForExport(content, theme, palette, orgExportState, options)
29741
30072
  blLayout,
29742
30073
  effectivePalette2,
29743
30074
  theme === "dark",
29744
- { exportDims: { width: exportWidth, height: exportHeight } }
30075
+ {
30076
+ exportDims: { width: exportWidth, height: exportHeight },
30077
+ activeTagGroup: options?.tagGroup
30078
+ }
29745
30079
  );
29746
30080
  return finalizeSvgExport(container2, theme, effectivePalette2, options);
29747
30081
  }
@@ -29776,7 +30110,11 @@ async function renderForExport(content, theme, palette, orgExportState, options)
29776
30110
  theme === "dark",
29777
30111
  void 0,
29778
30112
  { width: exportWidth, height: exportHeight },
29779
- options?.tagGroup
30113
+ resolveActiveTagGroup(
30114
+ c4Parsed.tagGroups,
30115
+ c4Parsed.options["active-tag"],
30116
+ options?.tagGroup
30117
+ )
29780
30118
  );
29781
30119
  return finalizeSvgExport(container2, theme, effectivePalette2, options);
29782
30120
  }
@@ -29810,7 +30148,11 @@ async function renderForExport(content, theme, palette, orgExportState, options)
29810
30148
  if (infraParsed.error || infraParsed.nodes.length === 0) return "";
29811
30149
  const infraComputed = computeInfra2(infraParsed);
29812
30150
  const infraLayout = layoutInfra2(infraComputed);
29813
- const activeTagGroup = options?.tagGroup ?? null;
30151
+ const activeTagGroup = resolveActiveTagGroup(
30152
+ infraParsed.tagGroups,
30153
+ infraParsed.options["active-tag"],
30154
+ options?.tagGroup
30155
+ );
29814
30156
  const titleOffset = infraParsed.title ? 40 : 0;
29815
30157
  const legendGroups = computeInfraLegendGroups2(
29816
30158
  infraLayout.nodes,
@@ -29945,7 +30287,11 @@ async function renderForExport(content, theme, palette, orgExportState, options)
29945
30287
  isDark,
29946
30288
  void 0,
29947
30289
  dims,
29948
- orgExportState?.activeTagGroup ?? options?.tagGroup,
30290
+ resolveActiveTagGroup(
30291
+ parsed.timelineTagGroups,
30292
+ void 0,
30293
+ orgExportState?.activeTagGroup ?? options?.tagGroup
30294
+ ),
29949
30295
  orgExportState?.swimlaneTagGroup
29950
30296
  );
29951
30297
  } else if (parsed.type === "venn") {
@@ -29982,6 +30328,7 @@ var init_d3 = __esm({
29982
30328
  import_d3_cloud = __toESM(require("d3-cloud"), 1);
29983
30329
  init_fonts();
29984
30330
  init_branding();
30331
+ init_label_layout();
29985
30332
  init_colors();
29986
30333
  init_palettes();
29987
30334
  init_color_utils();
@@ -30173,6 +30520,7 @@ __export(index_exports, {
30173
30520
  computeTimeTicks: () => computeTimeTicks,
30174
30521
  contrastText: () => contrastText,
30175
30522
  decodeDiagramUrl: () => decodeDiagramUrl,
30523
+ draculaPalette: () => draculaPalette,
30176
30524
  encodeDiagramUrl: () => encodeDiagramUrl,
30177
30525
  extractDiagramSymbols: () => extractDiagramSymbols,
30178
30526
  extractTagDeclarations: () => extractTagDeclarations,
@@ -30216,6 +30564,7 @@ __export(index_exports, {
30216
30564
  looksLikeSitemap: () => looksLikeSitemap,
30217
30565
  looksLikeState: () => looksLikeState,
30218
30566
  makeDgmoError: () => makeDgmoError,
30567
+ monokaiPalette: () => monokaiPalette,
30219
30568
  mute: () => mute,
30220
30569
  nord: () => nord,
30221
30570
  nordPalette: () => nordPalette,
@@ -31081,7 +31430,7 @@ init_palettes();
31081
31430
 
31082
31431
  // src/sharing.ts
31083
31432
  var import_lz_string = require("lz-string");
31084
- var DEFAULT_BASE_URL = "https://diagrammo.app/view";
31433
+ var DEFAULT_BASE_URL = "https://online.diagrammo.app";
31085
31434
  var COMPRESSED_SIZE_LIMIT = 8192;
31086
31435
  function encodeDiagramUrl(dsl, options) {
31087
31436
  const baseUrl = options?.baseUrl ?? DEFAULT_BASE_URL;
@@ -31353,21 +31702,33 @@ var COMPLETION_REGISTRY = /* @__PURE__ */ new Map([
31353
31702
  }
31354
31703
  })
31355
31704
  ],
31356
- ["er", withGlobals()],
31705
+ [
31706
+ "er",
31707
+ withGlobals({
31708
+ "active-tag": { description: "Active tag group name" }
31709
+ })
31710
+ ],
31357
31711
  [
31358
31712
  "org",
31359
31713
  withGlobals({
31360
31714
  "sub-node-label": { description: "Label for sub-nodes" },
31361
- "show-sub-node-count": { description: "Show sub-node counts" }
31715
+ "show-sub-node-count": { description: "Show sub-node counts" },
31716
+ "active-tag": { description: "Active tag group name" }
31362
31717
  })
31363
31718
  ],
31364
31719
  [
31365
31720
  "kanban",
31366
31721
  withGlobals({
31367
- "no-auto-color": { description: "Disable automatic card coloring" }
31722
+ "no-auto-color": { description: "Disable automatic card coloring" },
31723
+ "active-tag": { description: "Active tag group name" }
31724
+ })
31725
+ ],
31726
+ [
31727
+ "c4",
31728
+ withGlobals({
31729
+ "active-tag": { description: "Active tag group name" }
31368
31730
  })
31369
31731
  ],
31370
- ["c4", withGlobals()],
31371
31732
  [
31372
31733
  "state",
31373
31734
  withGlobals({
@@ -31378,7 +31739,8 @@ var COMPLETION_REGISTRY = /* @__PURE__ */ new Map([
31378
31739
  [
31379
31740
  "sitemap",
31380
31741
  withGlobals({
31381
- "direction-tb": { description: "Switch to top-to-bottom layout" }
31742
+ "direction-tb": { description: "Switch to top-to-bottom layout" },
31743
+ "active-tag": { description: "Active tag group name" }
31382
31744
  })
31383
31745
  ],
31384
31746
  [
@@ -31392,7 +31754,8 @@ var COMPLETION_REGISTRY = /* @__PURE__ */ new Map([
31392
31754
  "default-rps": { description: "Default RPS capacity for all nodes" },
31393
31755
  "slo-availability": { description: "SLO availability target (0-1)" },
31394
31756
  "slo-p90-latency-ms": { description: "SLO p90 latency target in ms" },
31395
- "slo-warning-margin": { description: "SLO warning margin percentage" }
31757
+ "slo-warning-margin": { description: "SLO warning margin percentage" },
31758
+ "active-tag": { description: "Active tag group name" }
31396
31759
  })
31397
31760
  ],
31398
31761
  [
@@ -31404,7 +31767,8 @@ var COMPLETION_REGISTRY = /* @__PURE__ */ new Map([
31404
31767
  },
31405
31768
  sort: { description: "Sort order", values: ["time", "group", "tag"] },
31406
31769
  "critical-path": { description: "Show critical path" },
31407
- dependencies: { description: "Show dependencies" }
31770
+ dependencies: { description: "Show dependencies" },
31771
+ "active-tag": { description: "Active tag group name" }
31408
31772
  })
31409
31773
  ],
31410
31774
  [
@@ -31923,6 +32287,7 @@ init_branding();
31923
32287
  computeTimeTicks,
31924
32288
  contrastText,
31925
32289
  decodeDiagramUrl,
32290
+ draculaPalette,
31926
32291
  encodeDiagramUrl,
31927
32292
  extractDiagramSymbols,
31928
32293
  extractTagDeclarations,
@@ -31966,6 +32331,7 @@ init_branding();
31966
32331
  looksLikeSitemap,
31967
32332
  looksLikeState,
31968
32333
  makeDgmoError,
32334
+ monokaiPalette,
31969
32335
  mute,
31970
32336
  nord,
31971
32337
  nordPalette,