@diagrammo/dgmo 0.14.1 → 0.15.1

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 (71) hide show
  1. package/README.md +14 -1
  2. package/dist/advanced.cjs +53069 -0
  3. package/dist/advanced.d.cts +4691 -0
  4. package/dist/advanced.d.ts +4691 -0
  5. package/dist/advanced.js +52823 -0
  6. package/dist/auto.cjs +1557 -1295
  7. package/dist/auto.js +132 -713
  8. package/dist/auto.mjs +1553 -1291
  9. package/dist/cli.cjs +173 -150
  10. package/dist/editor.cjs +1 -0
  11. package/dist/editor.js +1 -0
  12. package/dist/highlight.cjs +1 -0
  13. package/dist/highlight.js +1 -0
  14. package/dist/index.cjs +2031 -4722
  15. package/dist/index.d.cts +96 -4464
  16. package/dist/index.d.ts +96 -4464
  17. package/dist/index.js +2024 -4475
  18. package/dist/internal.cjs +51930 -553
  19. package/dist/internal.d.cts +4526 -102
  20. package/dist/internal.d.ts +4526 -102
  21. package/dist/internal.js +51721 -548
  22. package/dist/pert.cjs +1 -1
  23. package/dist/pert.js +1 -1
  24. package/docs/language-reference.md +67 -17
  25. package/package.json +18 -3
  26. package/src/advanced.ts +731 -0
  27. package/src/auto/index.ts +14 -13
  28. package/src/boxes-and-lines/layout.ts +481 -445
  29. package/src/c4/parser.ts +7 -7
  30. package/src/chart-types.ts +0 -5
  31. package/src/class/parser.ts +1 -9
  32. package/src/cli.ts +9 -7
  33. package/src/completion-types.ts +28 -0
  34. package/src/completion.ts +15 -18
  35. package/src/cycle/layout.ts +2 -2
  36. package/src/d3.ts +1455 -1122
  37. package/src/echarts.ts +11 -11
  38. package/src/editor/keywords.ts +1 -0
  39. package/src/er/parser.ts +1 -9
  40. package/src/er/renderer.ts +1 -1
  41. package/src/gantt/calculator.ts +1 -11
  42. package/src/gantt/parser.ts +16 -16
  43. package/src/gantt/renderer.ts +2 -2
  44. package/src/graph/flowchart-parser.ts +1 -1
  45. package/src/graph/flowchart-renderer.ts +1 -1
  46. package/src/graph/state-renderer.ts +1 -1
  47. package/src/index.ts +213 -690
  48. package/src/infra/parser.ts +57 -25
  49. package/src/infra/renderer.ts +2 -2
  50. package/src/internal.ts +11 -17
  51. package/src/kanban/parser.ts +2 -2
  52. package/src/mindmap/layout.ts +1 -1
  53. package/src/mindmap/parser.ts +1 -1
  54. package/src/org/parser.ts +1 -1
  55. package/src/org/renderer.ts +1 -1
  56. package/src/palettes/index.ts +39 -0
  57. package/src/pert/layout.ts +1 -1
  58. package/src/pert/monte-carlo.ts +2 -2
  59. package/src/pert/parser.ts +3 -3
  60. package/src/raci/parser.ts +4 -4
  61. package/src/raci/renderer.ts +1 -1
  62. package/src/render.ts +17 -1
  63. package/src/sequence/renderer.ts +1 -4
  64. package/src/sitemap/parser.ts +1 -1
  65. package/src/tech-radar/interactive.ts +1 -1
  66. package/src/tech-radar/renderer.ts +1 -1
  67. package/src/themes.ts +22 -0
  68. package/src/utils/tag-groups.ts +11 -12
  69. package/src/wireframe/layout.ts +11 -7
  70. package/src/wireframe/parser.ts +2 -2
  71. package/src/wireframe/renderer.ts +5 -2
package/dist/auto.cjs CHANGED
@@ -1761,6 +1761,7 @@ __export(palettes_exports, {
1761
1761
  monokaiPalette: () => monokaiPalette,
1762
1762
  nordPalette: () => nordPalette,
1763
1763
  oneDarkPalette: () => oneDarkPalette,
1764
+ palettes: () => palettes,
1764
1765
  registerPalette: () => registerPalette,
1765
1766
  rosePinePalette: () => rosePinePalette,
1766
1767
  shade: () => shade,
@@ -1769,6 +1770,7 @@ __export(palettes_exports, {
1769
1770
  tint: () => tint,
1770
1771
  tokyoNightPalette: () => tokyoNightPalette
1771
1772
  });
1773
+ var palettes;
1772
1774
  var init_palettes = __esm({
1773
1775
  "src/palettes/index.ts"() {
1774
1776
  "use strict";
@@ -1784,6 +1786,28 @@ var init_palettes = __esm({
1784
1786
  init_tokyo_night();
1785
1787
  init_dracula();
1786
1788
  init_monokai();
1789
+ init_bold();
1790
+ init_catppuccin();
1791
+ init_dracula();
1792
+ init_gruvbox();
1793
+ init_monokai();
1794
+ init_nord();
1795
+ init_one_dark();
1796
+ init_rose_pine();
1797
+ init_solarized();
1798
+ init_tokyo_night();
1799
+ palettes = {
1800
+ nord: nordPalette,
1801
+ catppuccin: catppuccinPalette,
1802
+ solarized: solarizedPalette,
1803
+ gruvbox: gruvboxPalette,
1804
+ tokyoNight: tokyoNightPalette,
1805
+ oneDark: oneDarkPalette,
1806
+ rosePine: rosePinePalette,
1807
+ dracula: draculaPalette,
1808
+ monokai: monokaiPalette,
1809
+ bold: boldPalette
1810
+ };
1787
1811
  }
1788
1812
  });
1789
1813
 
@@ -2214,7 +2238,7 @@ function injectDefaultTagMetadata(entities, tagGroups, skip) {
2214
2238
  }
2215
2239
  }
2216
2240
  }
2217
- function resolveActiveTagGroup(_tagGroups, explicitActiveTag, programmaticOverride) {
2241
+ function resolveActiveTagGroup(tagGroups, explicitActiveTag, programmaticOverride) {
2218
2242
  if (programmaticOverride !== void 0) {
2219
2243
  if (!programmaticOverride) return null;
2220
2244
  if (programmaticOverride.toLowerCase() === "none") return null;
@@ -2224,6 +2248,7 @@ function resolveActiveTagGroup(_tagGroups, explicitActiveTag, programmaticOverri
2224
2248
  if (explicitActiveTag.toLowerCase() === "none") return null;
2225
2249
  return explicitActiveTag;
2226
2250
  }
2251
+ if (tagGroups.length > 0) return tagGroups[0].name;
2227
2252
  return null;
2228
2253
  }
2229
2254
  function matchTagBlockHeading(trimmed) {
@@ -5304,12 +5329,6 @@ function parseClassDiagram(content, palette) {
5304
5329
  diagnostics: [],
5305
5330
  error: null
5306
5331
  };
5307
- const _fail = (line12, message) => {
5308
- const diag = makeDgmoError(line12, message);
5309
- result.diagnostics.push(diag);
5310
- result.error = formatDgmoError(diag);
5311
- return result;
5312
- };
5313
5332
  const classMap = /* @__PURE__ */ new Map();
5314
5333
  const nameAliasMap = /* @__PURE__ */ new Map();
5315
5334
  function resolveAliasName(token) {
@@ -5704,12 +5723,6 @@ function parseERDiagram(content, palette) {
5704
5723
  diagnostics: [],
5705
5724
  error: null
5706
5725
  };
5707
- const _fail = (line12, message) => {
5708
- const diag = makeDgmoError(line12, message);
5709
- result.diagnostics.push(diag);
5710
- result.error = formatDgmoError(diag);
5711
- return result;
5712
- };
5713
5726
  const pushError = (line12, message) => {
5714
5727
  const diag = makeDgmoError(line12, message);
5715
5728
  result.diagnostics.push(diag);
@@ -7146,7 +7159,7 @@ function buildSankeyOption(parsed, textColor, colors, bg, titleConfig) {
7146
7159
  ]
7147
7160
  };
7148
7161
  }
7149
- function buildChordOption(parsed, palette, isDark, textColor, colors, bg, titleConfig) {
7162
+ function buildChordOption(parsed, palette, isDark, textColor, colors, _bg, titleConfig) {
7150
7163
  const nodeSet = /* @__PURE__ */ new Set();
7151
7164
  if (parsed.links) {
7152
7165
  for (const link of parsed.links) {
@@ -7260,7 +7273,7 @@ function evaluateExpression(expr, x) {
7260
7273
  return NaN;
7261
7274
  }
7262
7275
  }
7263
- function buildFunctionOption(parsed, palette, isDark, textColor, axisLineColor, gridOpacity, colors, titleConfig) {
7276
+ function buildFunctionOption(parsed, palette, _isDark, textColor, axisLineColor, gridOpacity, colors, titleConfig) {
7264
7277
  const xRange = parsed.xRange ?? { min: -10, max: 10 };
7265
7278
  const samples = 200;
7266
7279
  const step = (xRange.max - xRange.min) / samples;
@@ -7933,7 +7946,7 @@ function buildHeatmapOption(parsed, palette, isDark, textColor, axisLineColor, t
7933
7946
  ]
7934
7947
  };
7935
7948
  }
7936
- function buildFunnelOption(parsed, palette, isDark, textColor, colors, bg, titleConfig) {
7949
+ function buildFunnelOption(parsed, palette, isDark, textColor, colors, _bg, titleConfig) {
7937
7950
  const sorted = [...parsed.data].sort((a, b) => b.value - a.value);
7938
7951
  const data = sorted.map((d) => {
7939
7952
  const stroke2 = d.color ?? colors[parsed.data.indexOf(d) % colors.length];
@@ -8216,7 +8229,7 @@ function wrapLabel(text, maxChars) {
8216
8229
  if (current) lines.push(current);
8217
8230
  return lines.join("\n");
8218
8231
  }
8219
- function buildBarOption(parsed, palette, isDark, textColor, axisLineColor, splitLineColor, gridOpacity, colors, bg, titleConfig, chartWidth) {
8232
+ function buildBarOption(parsed, palette, isDark, textColor, axisLineColor, splitLineColor, gridOpacity, colors, _bg, titleConfig, chartWidth) {
8220
8233
  const { xLabel, yLabel } = resolveAxisLabels(parsed);
8221
8234
  const isHorizontal = parsed.orientation === "horizontal";
8222
8235
  const labels = parsed.data.map((d) => d.label);
@@ -8543,7 +8556,7 @@ function pieLabelLayout(parsed) {
8543
8556
  if (maxLen > 18) return { outerRadius: 55, fontSize: 13 };
8544
8557
  return { outerRadius: 70, fontSize: 14 };
8545
8558
  }
8546
- function buildPieOption(parsed, palette, isDark, textColor, colors, bg, titleConfig, isDoughnut) {
8559
+ function buildPieOption(parsed, palette, isDark, textColor, colors, _bg, titleConfig, isDoughnut) {
8547
8560
  const HIDE_AXES = { xAxis: { show: false }, yAxis: { show: false } };
8548
8561
  const data = parsed.data.map((d, i) => {
8549
8562
  const stroke2 = d.color ?? colors[i % colors.length];
@@ -8642,7 +8655,7 @@ function buildRadarOption(parsed, palette, isDark, textColor, gridOpacity, title
8642
8655
  ]
8643
8656
  };
8644
8657
  }
8645
- function buildPolarAreaOption(parsed, palette, isDark, textColor, colors, bg, titleConfig) {
8658
+ function buildPolarAreaOption(parsed, palette, isDark, textColor, colors, _bg, titleConfig) {
8646
8659
  const data = parsed.data.map((d, i) => {
8647
8660
  const stroke2 = d.color ?? colors[i % colors.length];
8648
8661
  return {
@@ -8685,7 +8698,7 @@ function buildPolarAreaOption(parsed, palette, isDark, textColor, colors, bg, ti
8685
8698
  ]
8686
8699
  };
8687
8700
  }
8688
- function buildBarStackedOption(parsed, palette, isDark, textColor, axisLineColor, splitLineColor, gridOpacity, colors, bg, titleConfig, chartWidth) {
8701
+ function buildBarStackedOption(parsed, palette, isDark, textColor, axisLineColor, splitLineColor, gridOpacity, colors, _bg, titleConfig, chartWidth) {
8689
8702
  const { xLabel, yLabel } = resolveAxisLabels(parsed);
8690
8703
  const isHorizontal = parsed.orientation === "horizontal";
8691
8704
  const seriesNames = parsed.seriesNames ?? [];
@@ -8825,8 +8838,8 @@ async function renderExtendedChartForExport(content, theme, palette) {
8825
8838
  const titleHeight = option.title && option.title.text ? 40 : 0;
8826
8839
  const legendY = 8 + titleHeight;
8827
8840
  const grid = option.grid;
8828
- const gridLeftPct = grid?.left ? parseFloat(String(grid.left)) : void 0;
8829
- const gridRightPct = grid?.right ? parseFloat(String(grid.right)) : void 0;
8841
+ const gridLeftPct = grid?.["left"] ? parseFloat(String(grid["left"])) : void 0;
8842
+ const gridRightPct = grid?.["right"] ? parseFloat(String(grid["right"])) : void 0;
8830
8843
  const { svg: legendSvgStr } = renderLegendSvg(legendGroups, {
8831
8844
  palette: effectivePalette,
8832
8845
  isDark,
@@ -9176,7 +9189,7 @@ function parseOrg(content, palette) {
9176
9189
  }
9177
9190
  return result;
9178
9191
  }
9179
- function parseNodeLabel(trimmed, _indent, lineNumber, palette, counter, metaAliasMap = /* @__PURE__ */ new Map(), warnFn, nameAliasMap) {
9192
+ function parseNodeLabel(trimmed, _indent, lineNumber, _palette, counter, metaAliasMap = /* @__PURE__ */ new Map(), warnFn, nameAliasMap) {
9180
9193
  const segments = trimmed.split("|").map((s) => s.trim());
9181
9194
  let label = segments[0];
9182
9195
  const asMatch = label.match(/^(.*?)\s+as\s+([A-Za-z][A-Za-z0-9_]{0,11})\s*$/);
@@ -9425,8 +9438,8 @@ function parseKanban(content, palette) {
9425
9438
  columnMetadata,
9426
9439
  parsePipeMetadata(pipeSegments, metaAliasMap)
9427
9440
  );
9428
- if (columnMetadata.wip) {
9429
- const wipVal = parseInt(columnMetadata.wip, 10);
9441
+ if (columnMetadata["wip"]) {
9442
+ const wipVal = parseInt(columnMetadata["wip"], 10);
9430
9443
  if (!isNaN(wipVal)) {
9431
9444
  wipLimit = wipVal;
9432
9445
  }
@@ -9805,7 +9818,7 @@ function parseC4(content, palette) {
9805
9818
  );
9806
9819
  const shape = inferC4Shape(
9807
9820
  nodeName,
9808
- metadata.tech ?? metadata.technology
9821
+ metadata["tech"] ?? metadata["technology"]
9809
9822
  );
9810
9823
  const dNode = {
9811
9824
  name: nodeName,
@@ -9908,11 +9921,11 @@ function parseC4(content, palette) {
9908
9921
  target = targetBody.substring(0, pipeIdx).trim();
9909
9922
  const metaPart = targetBody.substring(pipeIdx + 1).trim();
9910
9923
  const meta = parsePipeMetadata(["", metaPart], metaAliasMap);
9911
- if (meta.tech) {
9912
- technology = meta.tech;
9924
+ if (meta["tech"]) {
9925
+ technology = meta["tech"];
9913
9926
  }
9914
- if (meta.technology) {
9915
- technology = meta.technology;
9927
+ if (meta["technology"]) {
9928
+ technology = meta["technology"];
9916
9929
  }
9917
9930
  }
9918
9931
  const rel = {
@@ -10046,7 +10059,7 @@ function parseC4(content, palette) {
10046
10059
  metaAliasMap,
10047
10060
  () => pushError(lineNumber, MULTIPLE_PIPE_ERROR)
10048
10061
  );
10049
- const shape = explicitShape ?? inferC4Shape(namePart, metadata.tech ?? metadata.technology);
10062
+ const shape = explicitShape ?? inferC4Shape(namePart, metadata["tech"] ?? metadata["technology"]);
10050
10063
  let isADescription;
10051
10064
  if ("description" in metadata) {
10052
10065
  const descVal = metadata["description"].trim();
@@ -10106,7 +10119,7 @@ function parseC4(content, palette) {
10106
10119
  metaAliasMap,
10107
10120
  () => pushError(lineNumber, MULTIPLE_PIPE_ERROR)
10108
10121
  );
10109
- const shape = explicitShape ?? inferC4Shape(namePart, metadata.tech ?? metadata.technology);
10122
+ const shape = explicitShape ?? inferC4Shape(namePart, metadata["tech"] ?? metadata["technology"]);
10110
10123
  let prefixDescription;
10111
10124
  if ("description" in metadata) {
10112
10125
  const descVal = metadata["description"].trim();
@@ -10715,7 +10728,7 @@ function parseSitemap(content, palette) {
10715
10728
  }
10716
10729
  return result;
10717
10730
  }
10718
- function parseNodeLabel2(trimmed, lineNumber, palette, counter, metaAliasMap = /* @__PURE__ */ new Map(), warnFn, _diagnostics, nameAliasMap) {
10731
+ function parseNodeLabel2(trimmed, lineNumber, _palette, counter, metaAliasMap = /* @__PURE__ */ new Map(), warnFn, _diagnostics, nameAliasMap) {
10719
10732
  const segments = trimmed.split("|").map((s) => s.trim());
10720
10733
  let label = segments[0];
10721
10734
  const asMatch = label.match(/^(.*?)\s+as\s+([A-Za-z][A-Za-z0-9_]{0,11})\s*$/);
@@ -10892,6 +10905,17 @@ function parseInfra(content) {
10892
10905
  if (!m) return { label: trimmed };
10893
10906
  return { label: m[1].trim(), alias: m[2] };
10894
10907
  }
10908
+ const IS_A_SUFFIX = /^(.*?)\s+is\s+an?\s+[A-Za-z][\w-]*\s*$/i;
10909
+ function peelInfraDecorations(rawName, lineNumber) {
10910
+ const peeled = peelAlias2(rawName);
10911
+ const m = peeled.label.match(IS_A_SUFFIX);
10912
+ if (!m) return peeled;
10913
+ warn2(
10914
+ lineNumber,
10915
+ `Infra nodes don't use 'is a <type>' \u2014 types are inferred from properties (cache-hit, buffer, drain-rate, \u2026). Drop the 'is a' suffix.`
10916
+ );
10917
+ return { label: m[1].trim(), alias: peeled.alias };
10918
+ }
10895
10919
  function resolveTargetId(rawName) {
10896
10920
  const aliasResolved = nameAliasMap.get(rawName.trim());
10897
10921
  if (aliasResolved !== void 0) return aliasResolved;
@@ -10995,11 +11019,11 @@ function parseInfra(content) {
10995
11019
  continue;
10996
11020
  }
10997
11021
  if (trimmed === "animate") {
10998
- result.options.animate = "on";
11022
+ result.options["animate"] = "on";
10999
11023
  continue;
11000
11024
  }
11001
11025
  if (trimmed === "no-animate") {
11002
- result.options.animate = "off";
11026
+ result.options["animate"] = "off";
11003
11027
  continue;
11004
11028
  }
11005
11029
  if (tryParseSharedOption(trimmed, result.options)) {
@@ -11046,7 +11070,7 @@ function parseInfra(content) {
11046
11070
  finishCurrentNode();
11047
11071
  finishCurrentTagGroup();
11048
11072
  const rawName = (compMatch[1] ?? compMatch[2] ?? "").trim();
11049
- const peeled = peelAlias2(rawName);
11073
+ const peeled = peelInfraDecorations(rawName, lineNumber);
11050
11074
  const name = peeled.label;
11051
11075
  const rest = compMatch[3] || "";
11052
11076
  const { tags } = extractPipeMetadata(rest);
@@ -11117,7 +11141,7 @@ function parseInfra(content) {
11117
11141
  if (compMatch) {
11118
11142
  finishCurrentTagGroup();
11119
11143
  const rawName = (compMatch[1] ?? compMatch[2] ?? "").trim();
11120
- const peeled = peelAlias2(rawName);
11144
+ const peeled = peelInfraDecorations(rawName, lineNumber);
11121
11145
  const name = peeled.label;
11122
11146
  const rest = compMatch[3] || "";
11123
11147
  const { tags: nodeTags } = extractPipeMetadata(rest);
@@ -11153,8 +11177,8 @@ function parseInfra(content) {
11153
11177
  const pipeMeta = extractPipeMetadata(targetRaw);
11154
11178
  const targetName = pipeMeta.clean || targetRaw;
11155
11179
  warnUnparsedPipeMeta(targetName, lineNumber, warn2);
11156
- const split = pipeMeta.tags.split ? parseFloat(pipeMeta.tags.split) : null;
11157
- const fanoutRaw = pipeMeta.tags.fanout ? parseInt(pipeMeta.tags.fanout, 10) : null;
11180
+ const split = pipeMeta.tags["split"] ? parseFloat(pipeMeta.tags["split"]) : null;
11181
+ const fanoutRaw = pipeMeta.tags["fanout"] ? parseInt(pipeMeta.tags["fanout"], 10) : null;
11158
11182
  if (fanoutRaw !== null && fanoutRaw < 1) {
11159
11183
  warn2(
11160
11184
  lineNumber,
@@ -11185,8 +11209,8 @@ function parseInfra(content) {
11185
11209
  const pipeMeta = extractPipeMetadata(targetRaw);
11186
11210
  const targetName = pipeMeta.clean || targetRaw;
11187
11211
  warnUnparsedPipeMeta(targetName, lineNumber, warn2);
11188
- const split = pipeMeta.tags.split ? parseFloat(pipeMeta.tags.split) : null;
11189
- const fanoutRaw = pipeMeta.tags.fanout ? parseInt(pipeMeta.tags.fanout, 10) : null;
11212
+ const split = pipeMeta.tags["split"] ? parseFloat(pipeMeta.tags["split"]) : null;
11213
+ const fanoutRaw = pipeMeta.tags["fanout"] ? parseInt(pipeMeta.tags["fanout"], 10) : null;
11190
11214
  if (fanoutRaw !== null && fanoutRaw < 1) {
11191
11215
  warn2(
11192
11216
  lineNumber,
@@ -11220,8 +11244,8 @@ function parseInfra(content) {
11220
11244
  const pipeMeta = extractPipeMetadata(targetRaw);
11221
11245
  const targetName = pipeMeta.clean || targetRaw;
11222
11246
  warnUnparsedPipeMeta(targetName, lineNumber, warn2);
11223
- const split = pipeMeta.tags.split ? parseFloat(pipeMeta.tags.split) : null;
11224
- const fanoutRaw = pipeMeta.tags.fanout ? parseInt(pipeMeta.tags.fanout, 10) : null;
11247
+ const split = pipeMeta.tags["split"] ? parseFloat(pipeMeta.tags["split"]) : null;
11248
+ const fanoutRaw = pipeMeta.tags["fanout"] ? parseInt(pipeMeta.tags["fanout"], 10) : null;
11225
11249
  if (fanoutRaw !== null && fanoutRaw < 1) {
11226
11250
  warn2(
11227
11251
  lineNumber,
@@ -11252,8 +11276,8 @@ function parseInfra(content) {
11252
11276
  const pipeMeta = extractPipeMetadata(targetRaw);
11253
11277
  const targetName = pipeMeta.clean || targetRaw;
11254
11278
  warnUnparsedPipeMeta(targetName, lineNumber, warn2);
11255
- const split = pipeMeta.tags.split ? parseFloat(pipeMeta.tags.split) : null;
11256
- const fanoutRaw = pipeMeta.tags.fanout ? parseInt(pipeMeta.tags.fanout, 10) : null;
11279
+ const split = pipeMeta.tags["split"] ? parseFloat(pipeMeta.tags["split"]) : null;
11280
+ const fanoutRaw = pipeMeta.tags["fanout"] ? parseInt(pipeMeta.tags["fanout"], 10) : null;
11257
11281
  if (fanoutRaw !== null && fanoutRaw < 1) {
11258
11282
  warn2(
11259
11283
  lineNumber,
@@ -11336,7 +11360,7 @@ function parseInfra(content) {
11336
11360
  const compMatch = trimmed.match(COMPONENT_RE);
11337
11361
  if (compMatch) {
11338
11362
  const rawName = (compMatch[1] ?? compMatch[2] ?? "").trim();
11339
- const peeled = peelAlias2(rawName);
11363
+ const peeled = peelInfraDecorations(rawName, lineNumber);
11340
11364
  const name = peeled.label;
11341
11365
  const rest = compMatch[3] || "";
11342
11366
  const { tags: nodeTags } = extractPipeMetadata(rest);
@@ -11362,10 +11386,13 @@ function parseInfra(content) {
11362
11386
  finishCurrentNode();
11363
11387
  finishCurrentTagGroup();
11364
11388
  currentGroup = null;
11365
- const name = (compMatch[1] ?? compMatch[2] ?? "").trim();
11389
+ const rawName = (compMatch[1] ?? compMatch[2] ?? "").trim();
11390
+ const peeled = peelInfraDecorations(rawName, lineNumber);
11391
+ const name = peeled.label;
11366
11392
  const rest = compMatch[3] || "";
11367
11393
  const { tags } = extractPipeMetadata(rest);
11368
11394
  const id = nodeId2(name);
11395
+ if (peeled.alias) nameAliasMap.set(peeled.alias, id);
11369
11396
  currentNode = {
11370
11397
  id,
11371
11398
  label: name,
@@ -11415,6 +11442,14 @@ function parseInfra(content) {
11415
11442
  validateTagGroupNames(result.tagGroups, warn2, setError);
11416
11443
  return result;
11417
11444
  }
11445
+ function stripNodeDecorations(name) {
11446
+ let s = name.trim();
11447
+ const aliasMatch = s.match(/^(.*?)\s+as\s+[A-Za-z][A-Za-z0-9_]{0,11}\s*$/);
11448
+ if (aliasMatch) s = aliasMatch[1].trim();
11449
+ const isAMatch = s.match(/^(.*?)\s+is\s+an?\s+[A-Za-z][\w-]*\s*$/i);
11450
+ if (isAMatch) s = isAMatch[1].trim();
11451
+ return s;
11452
+ }
11418
11453
  function extractSymbols4(docText) {
11419
11454
  const entities = [];
11420
11455
  let inMetadata = true;
@@ -11448,7 +11483,7 @@ function extractSymbols4(docText) {
11448
11483
  if (/^\[/.test(line12)) continue;
11449
11484
  const m = COMPONENT_RE.exec(line12);
11450
11485
  if (m) {
11451
- const name = (m[1] ?? m[2] ?? "").trim();
11486
+ const name = stripNodeDecorations((m[1] ?? m[2] ?? "").trim());
11452
11487
  if (name && !entities.includes(name)) entities.push(name);
11453
11488
  }
11454
11489
  } else {
@@ -11463,7 +11498,7 @@ function extractSymbols4(docText) {
11463
11498
  continue;
11464
11499
  const m = COMPONENT_RE.exec(line12);
11465
11500
  if (m) {
11466
- const name = (m[1] ?? m[2] ?? "").trim();
11501
+ const name = stripNodeDecorations((m[1] ?? m[2] ?? "").trim());
11467
11502
  if (name && !entities.includes(name)) entities.push(name);
11468
11503
  }
11469
11504
  }
@@ -11949,15 +11984,15 @@ function parseGantt(content, palette) {
11949
11984
  metaAliasMap,
11950
11985
  () => warn2(lineNumber, MULTIPLE_PIPE_ERROR)
11951
11986
  );
11952
- if (meta.lag || meta.lead) {
11953
- const key = meta.lag ? "lag" : "lead";
11987
+ if (meta["lag"] || meta["lead"]) {
11988
+ const key = meta["lag"] ? "lag" : "lead";
11954
11989
  softError(
11955
11990
  lineNumber,
11956
11991
  `"${key}" is no longer supported \u2014 use "offset: ${meta[key]}" instead.${key === "lead" ? ' Negate the value for lead behavior: "offset: -...".' : ""}`
11957
11992
  );
11958
11993
  }
11959
- if (meta.offset) {
11960
- const raw = meta.offset;
11994
+ if (meta["offset"]) {
11995
+ const raw = meta["offset"];
11961
11996
  if (raw.trim().startsWith("+")) {
11962
11997
  warn2(
11963
11998
  lineNumber,
@@ -12344,15 +12379,15 @@ function parseGantt(content, palette) {
12344
12379
  metaAliasMap,
12345
12380
  () => warn2(lineNumber, MULTIPLE_PIPE_ERROR)
12346
12381
  );
12347
- if (meta.lag || meta.lead) {
12348
- const key = meta.lag ? "lag" : "lead";
12382
+ if (meta["lag"] || meta["lead"]) {
12383
+ const key = meta["lag"] ? "lag" : "lead";
12349
12384
  softError(
12350
12385
  lineNumber,
12351
12386
  `"${key}" is no longer supported \u2014 use "offset: ${meta[key]}" instead.${key === "lead" ? ' Negate the value for lead behavior: "offset: -...".' : ""}`
12352
12387
  );
12353
12388
  }
12354
- if (meta.offset) {
12355
- const raw = meta.offset;
12389
+ if (meta["offset"]) {
12390
+ const raw = meta["offset"];
12356
12391
  if (raw.trim().startsWith("+")) {
12357
12392
  warn2(
12358
12393
  lineNumber,
@@ -12423,9 +12458,9 @@ function parseGantt(content, palette) {
12423
12458
  () => warn2(ln, MULTIPLE_PIPE_ERROR)
12424
12459
  ) : {};
12425
12460
  let progress = null;
12426
- if (metadata.progress) {
12427
- progress = parseFloat(metadata.progress);
12428
- delete metadata.progress;
12461
+ if (metadata["progress"]) {
12462
+ progress = parseFloat(metadata["progress"]);
12463
+ delete metadata["progress"];
12429
12464
  }
12430
12465
  for (const part of segments.slice(1).join(",").split(",")) {
12431
12466
  const seg = part.trim();
@@ -12434,16 +12469,16 @@ function parseGantt(content, palette) {
12434
12469
  progress = parseInt(progressMatch[1], 10);
12435
12470
  }
12436
12471
  }
12437
- if (metadata.lag || metadata.lead) {
12438
- const key = metadata.lag ? "lag" : "lead";
12472
+ if (metadata["lag"] || metadata["lead"]) {
12473
+ const key = metadata["lag"] ? "lag" : "lead";
12439
12474
  softError(
12440
12475
  ln,
12441
12476
  `"${key}" is no longer supported \u2014 use "offset: ${metadata[key]}" instead.${key === "lead" ? ' Negate the value for lead behavior: "offset: -...".' : ""}`
12442
12477
  );
12443
12478
  }
12444
12479
  let taskOffset;
12445
- if (metadata.offset) {
12446
- const raw = metadata.offset;
12480
+ if (metadata["offset"]) {
12481
+ const raw = metadata["offset"];
12447
12482
  if (raw.trim().startsWith("+")) {
12448
12483
  warn2(
12449
12484
  ln,
@@ -12458,7 +12493,7 @@ function parseGantt(content, palette) {
12458
12493
  );
12459
12494
  }
12460
12495
  }
12461
- delete metadata.offset;
12496
+ delete metadata["offset"];
12462
12497
  }
12463
12498
  const groupPath = currentGroupPath();
12464
12499
  const inheritedMeta = {};
@@ -12981,7 +13016,7 @@ function parsePert(content, parseOpts = {}) {
12981
13016
  id,
12982
13017
  name,
12983
13018
  activityIds: [],
12984
- collapsed: meta.collapsed === "true",
13019
+ collapsed: meta["collapsed"] === "true",
12985
13020
  lineNumber,
12986
13021
  ...Object.keys(tags).length > 0 && { tags }
12987
13022
  });
@@ -13243,7 +13278,7 @@ function parsePert(content, parseOpts = {}) {
13243
13278
  name: decl.name,
13244
13279
  ...decl.alias !== void 0 && { alias: decl.alias },
13245
13280
  duration: estimate,
13246
- ...meta.confidence && { confidence: meta.confidence },
13281
+ ...meta["confidence"] && { confidence: meta["confidence"] },
13247
13282
  ...decl.groupHint !== void 0 && { groupId: decl.groupHint },
13248
13283
  lineNumber: decl.lineNumber,
13249
13284
  isMilestone,
@@ -14574,7 +14609,7 @@ function parseMindmap(content, palette) {
14574
14609
  }
14575
14610
  return result;
14576
14611
  }
14577
- function parseNodeLine2(trimmed, lineNumber, palette, counter, aliasMap, warnFn) {
14612
+ function parseNodeLine2(trimmed, lineNumber, _palette, counter, aliasMap, warnFn) {
14578
14613
  const segments = trimmed.split("|").map((s) => s.trim());
14579
14614
  const label = segments[0];
14580
14615
  const metadata = parsePipeMetadata(
@@ -15018,7 +15053,7 @@ function parseWireframe(content) {
15018
15053
  wrapper.isContainer = true;
15019
15054
  wrapper.orientation = "horizontal";
15020
15055
  wrapper.children = children;
15021
- wrapper.metadata._inlineRow = "true";
15056
+ wrapper.metadata["_inlineRow"] = "true";
15022
15057
  pushElement(wrapper);
15023
15058
  }
15024
15059
  for (let i = 0; i < lines.length; i++) {
@@ -15169,7 +15204,7 @@ function parseWireframe(content) {
15169
15204
  wrapper.isContainer = true;
15170
15205
  wrapper.orientation = "horizontal";
15171
15206
  wrapper.children.push(labelEl, fieldEl);
15172
- wrapper.metadata._labelField = "true";
15207
+ wrapper.metadata["_labelField"] = "true";
15173
15208
  pushElement(wrapper);
15174
15209
  }
15175
15210
  } else {
@@ -16990,9 +17025,9 @@ function parseRaci(content, palette) {
16990
17025
  let roleColor;
16991
17026
  if (segments.length > 1) {
16992
17027
  const meta = parsePipeMetadata(segments);
16993
- if (meta.color) {
17028
+ if (meta["color"]) {
16994
17029
  roleColor = resolveColorWithDiagnostic(
16995
- meta.color,
17030
+ meta["color"],
16996
17031
  j + 1,
16997
17032
  result.diagnostics,
16998
17033
  palette
@@ -17059,9 +17094,9 @@ function parseRaci(content, palette) {
17059
17094
  let phaseColor;
17060
17095
  if (phaseMatch[2]) {
17061
17096
  const meta = parsePipeMetadata(["", phaseMatch[2]]);
17062
- if (meta.color) {
17097
+ if (meta["color"]) {
17063
17098
  phaseColor = resolveColorWithDiagnostic(
17064
- meta.color,
17099
+ meta["color"],
17065
17100
  lineNumber,
17066
17101
  result.diagnostics,
17067
17102
  palette
@@ -19070,7 +19105,7 @@ function renderOrg(container, parsed, layout, palette, isDark, onClickItem, expo
19070
19105
  displayNames.set(group.name.toLowerCase(), group.name);
19071
19106
  }
19072
19107
  const rootNodeIds = new Set(parsed.roots.map((r) => r.id));
19073
- const colorOff = parsed.options?.color === "off";
19108
+ const colorOff = parsed.options?.["color"] === "off";
19074
19109
  for (const c of layout.containers) {
19075
19110
  const cG = contentG.append("g").attr("transform", `translate(${c.x}, ${c.y})`).attr("class", "org-container").attr("data-line-number", String(c.lineNumber));
19076
19111
  if (activeTagGroup) {
@@ -22170,7 +22205,7 @@ function renderERDiagram(container, parsed, layout, palette, isDark, onClickItem
22170
22205
  const seriesColors2 = getSeriesColors(palette);
22171
22206
  const semanticRoles = useSemanticColors ? classifyEREntities(parsed.tables, parsed.relationships) : null;
22172
22207
  const semanticActive = semanticRoles !== null && (semanticColorsActive ?? true);
22173
- const useLabels = parsed.options.notation === "labels";
22208
+ const useLabels = parsed.options["notation"] === "labels";
22174
22209
  for (const edge of layout.edges) {
22175
22210
  if (edge.points.length < 2) continue;
22176
22211
  const edgeG = contentG.append("g").attr("class", "er-edge-group").attr("data-line-number", String(edge.lineNumber));
@@ -22385,495 +22420,6 @@ var init_renderer5 = __esm({
22385
22420
  }
22386
22421
  });
22387
22422
 
22388
- // src/boxes-and-lines/layout.ts
22389
- var layout_exports5 = {};
22390
- __export(layout_exports5, {
22391
- layoutBoxesAndLines: () => layoutBoxesAndLines
22392
- });
22393
- function clipToRectBorder2(cx, cy, w, h, tx, ty) {
22394
- const dx = tx - cx;
22395
- const dy = ty - cy;
22396
- if (dx === 0 && dy === 0) return { x: cx, y: cy };
22397
- const hw = w / 2;
22398
- const hh = h / 2;
22399
- const sx = dx !== 0 ? hw / Math.abs(dx) : Infinity;
22400
- const sy = dy !== 0 ? hh / Math.abs(dy) : Infinity;
22401
- const s = Math.min(sx, sy);
22402
- return { x: cx + dx * s, y: cy + dy * s };
22403
- }
22404
- function splitCamelCase(word) {
22405
- const parts = [];
22406
- let start = 0;
22407
- for (let i = 1; i < word.length; i++) {
22408
- const prev = word[i - 1];
22409
- const curr = word[i];
22410
- const next = i + 1 < word.length ? word[i + 1] : "";
22411
- const lowerToUpper = prev >= "a" && prev <= "z" && curr >= "A" && curr <= "Z";
22412
- const upperRunEnd = prev >= "A" && prev <= "Z" && curr >= "A" && curr <= "Z" && next >= "a" && next <= "z";
22413
- if (lowerToUpper || upperRunEnd) {
22414
- parts.push(word.slice(start, i));
22415
- start = i;
22416
- }
22417
- }
22418
- parts.push(word.slice(start));
22419
- return parts.length > 1 ? parts : [word];
22420
- }
22421
- function estimateLabelLines(label, nodeWidth2 = NODE_WIDTH) {
22422
- const rawParts = label.split(/[\s-]+/);
22423
- const words = [];
22424
- for (const part of rawParts) {
22425
- if (!part) continue;
22426
- words.push(...splitCamelCase(part));
22427
- }
22428
- for (let fontSize = 13; fontSize >= 9; fontSize--) {
22429
- const charWidth = fontSize * 0.6;
22430
- const maxChars = Math.floor((nodeWidth2 - 24) / charWidth);
22431
- if (maxChars < 2) continue;
22432
- let lines = 1;
22433
- let current = "";
22434
- for (const word of words) {
22435
- const test = current ? `${current} ${word}` : word;
22436
- if (test.length <= maxChars) {
22437
- current = test;
22438
- } else {
22439
- lines++;
22440
- current = word;
22441
- }
22442
- }
22443
- if (lines <= MAX_LABEL_LINES) return Math.min(lines, MAX_LABEL_LINES);
22444
- }
22445
- return MAX_LABEL_LINES;
22446
- }
22447
- function computeNodeSize(node) {
22448
- if (!node.description || node.description.length === 0) {
22449
- return { width: NODE_WIDTH, height: NODE_HEIGHT };
22450
- }
22451
- const w = DESC_NODE_WIDTH;
22452
- const labelLines = estimateLabelLines(node.label, w);
22453
- const labelHeight = labelLines * 13 * LABEL_LINE_HEIGHT + LABEL_PAD;
22454
- const charsPerLine = Math.floor((w - 24) / (DESC_FONT_SIZE * 0.6));
22455
- let totalRenderedLines = 0;
22456
- for (const line12 of node.description) {
22457
- if (line12.length <= charsPerLine) {
22458
- totalRenderedLines += 1;
22459
- } else {
22460
- const words = line12.split(/\s+/);
22461
- let current = "";
22462
- let lineCount = 0;
22463
- for (const word of words) {
22464
- const fitted = word.length > charsPerLine ? word.slice(0, charsPerLine) : word;
22465
- const test = current ? `${current} ${fitted}` : fitted;
22466
- if (test.length <= charsPerLine) {
22467
- current = test;
22468
- } else {
22469
- if (current) lineCount++;
22470
- current = fitted;
22471
- }
22472
- }
22473
- if (current) lineCount++;
22474
- totalRenderedLines += lineCount;
22475
- }
22476
- }
22477
- totalRenderedLines = Math.min(totalRenderedLines, MAX_DESC_LINES);
22478
- const descriptionHeight = totalRenderedLines * DESC_FONT_SIZE * DESC_LINE_HEIGHT;
22479
- const totalHeight = labelHeight + SEPARATOR_GAP5 + DESC_PADDING + descriptionHeight + DESC_PADDING;
22480
- return { width: w, height: Math.max(NODE_HEIGHT, totalHeight) };
22481
- }
22482
- function layoutBoxesAndLines(parsed, collapseInfo, layoutOptions) {
22483
- const hideDescriptions = layoutOptions?.hideDescriptions ?? false;
22484
- const g = new import_dagre4.default.graphlib.Graph({ compound: true, multigraph: true });
22485
- g.setGraph({
22486
- rankdir: parsed.direction,
22487
- nodesep: NODESEP,
22488
- ranksep: RANKSEP,
22489
- marginx: MARGIN3,
22490
- marginy: MARGIN3
22491
- });
22492
- g.setDefaultEdgeLabel(() => ({}));
22493
- const collapsedGroupLabels = /* @__PURE__ */ new Set();
22494
- if (collapseInfo) {
22495
- const missingGroups = /* @__PURE__ */ new Set();
22496
- for (const og of collapseInfo.originalGroups) {
22497
- if (!parsed.groups.some((g2) => g2.label === og.label)) {
22498
- missingGroups.add(og.label);
22499
- }
22500
- }
22501
- for (const label of missingGroups) {
22502
- const og = collapseInfo.originalGroups.find((g2) => g2.label === label);
22503
- const parentLabel = og?.parentGroup;
22504
- if (!parentLabel || !missingGroups.has(parentLabel)) {
22505
- collapsedGroupLabels.add(label);
22506
- }
22507
- }
22508
- }
22509
- for (const label of collapsedGroupLabels) {
22510
- const gid = `__group_${label}`;
22511
- g.setNode(gid, { label, width: NODE_WIDTH, height: NODE_HEIGHT });
22512
- }
22513
- for (const group of parsed.groups) {
22514
- const gid = `__group_${group.label}`;
22515
- g.setNode(gid, {
22516
- label: group.label,
22517
- paddingLeft: CONTAINER_PAD_X3,
22518
- paddingRight: CONTAINER_PAD_X3,
22519
- paddingTop: CONTAINER_PAD_TOP2,
22520
- paddingBottom: CONTAINER_PAD_BOTTOM3
22521
- });
22522
- }
22523
- const originalGroupByLabel = /* @__PURE__ */ new Map();
22524
- if (collapseInfo) {
22525
- for (const og of collapseInfo.originalGroups) {
22526
- originalGroupByLabel.set(og.label, og);
22527
- }
22528
- }
22529
- for (const label of collapsedGroupLabels) {
22530
- const og = originalGroupByLabel.get(label);
22531
- if (og?.parentGroup && !collapsedGroupLabels.has(og.parentGroup)) {
22532
- const gid = `__group_${label}`;
22533
- const parentGid = `__group_${og.parentGroup}`;
22534
- if (g.hasNode(parentGid)) {
22535
- g.setParent(gid, parentGid);
22536
- }
22537
- }
22538
- }
22539
- const nodeSizes = /* @__PURE__ */ new Map();
22540
- let maxDescHeight = 0;
22541
- for (const node of parsed.nodes) {
22542
- const size = hideDescriptions ? { width: NODE_WIDTH, height: NODE_HEIGHT } : computeNodeSize(node);
22543
- nodeSizes.set(node.label, size);
22544
- if (!hideDescriptions && node.description && node.description.length > 0) {
22545
- maxDescHeight = Math.max(maxDescHeight, size.height);
22546
- }
22547
- }
22548
- if (maxDescHeight > 0) {
22549
- for (const node of parsed.nodes) {
22550
- if (node.description && node.description.length > 0) {
22551
- const size = nodeSizes.get(node.label);
22552
- nodeSizes.set(node.label, { width: size.width, height: maxDescHeight });
22553
- }
22554
- }
22555
- }
22556
- for (const node of parsed.nodes) {
22557
- const size = nodeSizes.get(node.label);
22558
- g.setNode(node.label, {
22559
- label: node.label,
22560
- width: size.width,
22561
- height: size.height
22562
- });
22563
- }
22564
- for (const group of parsed.groups) {
22565
- if (group.parentGroup) {
22566
- const childGid = `__group_${group.label}`;
22567
- const parentGid = `__group_${group.parentGroup}`;
22568
- if (g.hasNode(childGid) && g.hasNode(parentGid)) {
22569
- g.setParent(childGid, parentGid);
22570
- }
22571
- }
22572
- }
22573
- const groupLabelSet = new Set(parsed.groups.map((gr) => gr.label));
22574
- for (const group of parsed.groups) {
22575
- const gid = `__group_${group.label}`;
22576
- for (const child of group.children) {
22577
- if (groupLabelSet.has(child)) continue;
22578
- if (g.hasNode(child)) {
22579
- g.setParent(child, gid);
22580
- }
22581
- }
22582
- }
22583
- const expandedGroupIds = /* @__PURE__ */ new Set();
22584
- for (const group of parsed.groups) {
22585
- expandedGroupIds.add(`__group_${group.label}`);
22586
- }
22587
- const groupFirstChild = /* @__PURE__ */ new Map();
22588
- for (const group of parsed.groups) {
22589
- const gid = `__group_${group.label}`;
22590
- const firstChild = group.children.find(
22591
- (c) => !groupLabelSet.has(c) && g.hasNode(c)
22592
- );
22593
- if (firstChild) {
22594
- groupFirstChild.set(gid, firstChild);
22595
- }
22596
- }
22597
- const deferredEdgeIndices = [];
22598
- let proxyIdx = 0;
22599
- for (let i = 0; i < parsed.edges.length; i++) {
22600
- const edge = parsed.edges[i];
22601
- const src = edge.source;
22602
- const tgt = edge.target;
22603
- if (!g.hasNode(src) || !g.hasNode(tgt)) continue;
22604
- if (expandedGroupIds.has(src) || expandedGroupIds.has(tgt)) {
22605
- deferredEdgeIndices.push(i);
22606
- const proxySrc = expandedGroupIds.has(src) ? groupFirstChild.get(src) : src;
22607
- const proxyTgt = expandedGroupIds.has(tgt) ? groupFirstChild.get(tgt) : tgt;
22608
- if (proxySrc && proxyTgt && proxySrc !== proxyTgt) {
22609
- g.setEdge(
22610
- proxySrc,
22611
- proxyTgt,
22612
- { label: "", minlen: 1 },
22613
- `proxy${proxyIdx++}`
22614
- );
22615
- }
22616
- continue;
22617
- }
22618
- g.setEdge(src, tgt, { label: edge.label ?? "", minlen: 1 }, `e${i}`);
22619
- }
22620
- import_dagre4.default.layout(g);
22621
- const layoutNodes = [];
22622
- for (const node of parsed.nodes) {
22623
- const dagreNode = g.node(node.label);
22624
- if (!dagreNode) continue;
22625
- layoutNodes.push({
22626
- label: node.label,
22627
- x: dagreNode.x,
22628
- y: dagreNode.y,
22629
- width: dagreNode.width,
22630
- height: dagreNode.height
22631
- });
22632
- }
22633
- const layoutGroups = [];
22634
- for (const group of parsed.groups) {
22635
- const gid = `__group_${group.label}`;
22636
- const dagreNode = g.node(gid);
22637
- if (!dagreNode) continue;
22638
- layoutGroups.push({
22639
- label: group.label,
22640
- lineNumber: group.lineNumber,
22641
- x: dagreNode.x,
22642
- y: dagreNode.y,
22643
- width: dagreNode.width,
22644
- height: dagreNode.height,
22645
- collapsed: false
22646
- });
22647
- }
22648
- for (const label of collapsedGroupLabels) {
22649
- const gid = `__group_${label}`;
22650
- const dagreNode = g.node(gid);
22651
- if (!dagreNode) continue;
22652
- const og = collapseInfo?.originalGroups.find((g2) => g2.label === label);
22653
- layoutGroups.push({
22654
- label,
22655
- lineNumber: og?.lineNumber ?? 0,
22656
- x: dagreNode.x,
22657
- y: dagreNode.y,
22658
- width: dagreNode.width,
22659
- height: dagreNode.height,
22660
- collapsed: true,
22661
- childCount: collapseInfo?.collapsedChildCounts.get(label) ?? 0
22662
- });
22663
- }
22664
- const groupAlignShifts = /* @__PURE__ */ new Map();
22665
- {
22666
- const groupEdges = [];
22667
- for (const edge of parsed.edges) {
22668
- if (edge.source.startsWith("__group_") && edge.target.startsWith("__group_")) {
22669
- groupEdges.push(edge);
22670
- }
22671
- }
22672
- if (groupEdges.length > 0) {
22673
- const groupParent = /* @__PURE__ */ new Map();
22674
- const find = (x) => {
22675
- while (groupParent.has(x) && groupParent.get(x) !== x) {
22676
- groupParent.set(x, groupParent.get(groupParent.get(x)));
22677
- x = groupParent.get(x);
22678
- }
22679
- return x;
22680
- };
22681
- const union = (a, b) => {
22682
- const ra = find(a), rb = find(b);
22683
- if (ra !== rb) groupParent.set(ra, rb);
22684
- };
22685
- for (const edge of groupEdges) {
22686
- if (!groupParent.has(edge.source))
22687
- groupParent.set(edge.source, edge.source);
22688
- if (!groupParent.has(edge.target))
22689
- groupParent.set(edge.target, edge.target);
22690
- union(edge.source, edge.target);
22691
- }
22692
- const components = /* @__PURE__ */ new Map();
22693
- for (const lg of layoutGroups) {
22694
- const gid = `__group_${lg.label}`;
22695
- if (!groupParent.has(gid)) continue;
22696
- const root = find(gid);
22697
- if (!components.has(root)) components.set(root, []);
22698
- components.get(root).push(lg);
22699
- }
22700
- const axis = parsed.direction === "TB" ? "x" : "y";
22701
- for (const groups of components.values()) {
22702
- if (groups.length < 2) continue;
22703
- const dim = axis === "x" ? "width" : "height";
22704
- let widest = groups[0];
22705
- for (const g2 of groups) {
22706
- if (g2[dim] > widest[dim]) widest = g2;
22707
- }
22708
- const targetCenter = widest[axis];
22709
- for (const grp of groups) {
22710
- const dx = targetCenter - grp[axis];
22711
- if (dx === 0) continue;
22712
- grp[axis] += dx;
22713
- groupAlignShifts.set(`__group_${grp.label}`, dx);
22714
- const parsedGroup = parsed.groups.find(
22715
- (pg) => pg.label === grp.label
22716
- );
22717
- if (parsedGroup) {
22718
- for (const childLabel of parsedGroup.children) {
22719
- const childNode = layoutNodes.find((n) => n.label === childLabel);
22720
- if (childNode) childNode[axis] += dx;
22721
- }
22722
- }
22723
- }
22724
- }
22725
- }
22726
- }
22727
- const edgeYOffsets = new Array(parsed.edges.length).fill(0);
22728
- const edgeParallelCounts = new Array(parsed.edges.length).fill(1);
22729
- const parallelGroups = /* @__PURE__ */ new Map();
22730
- for (let i = 0; i < parsed.edges.length; i++) {
22731
- const edge = parsed.edges[i];
22732
- const [a, b] = edge.source < edge.target ? [edge.source, edge.target] : [edge.target, edge.source];
22733
- const key = `${a}\0${b}`;
22734
- if (!parallelGroups.has(key)) parallelGroups.set(key, []);
22735
- parallelGroups.get(key).push(i);
22736
- }
22737
- for (const group of parallelGroups.values()) {
22738
- const capped = group.slice(0, MAX_PARALLEL_EDGES);
22739
- for (const idx of group.slice(MAX_PARALLEL_EDGES)) {
22740
- edgeParallelCounts[idx] = 0;
22741
- }
22742
- if (capped.length < 2) continue;
22743
- const effectiveSpacing = PARALLEL_SPACING;
22744
- for (let j = 0; j < capped.length; j++) {
22745
- edgeYOffsets[capped[j]] = (j - (capped.length - 1) / 2) * effectiveSpacing;
22746
- edgeParallelCounts[capped[j]] = capped.length;
22747
- }
22748
- }
22749
- const deferredSet = new Set(deferredEdgeIndices);
22750
- const layoutEdges = [];
22751
- for (let i = 0; i < parsed.edges.length; i++) {
22752
- const edge = parsed.edges[i];
22753
- if (edgeParallelCounts[i] === 0) continue;
22754
- let points;
22755
- if (deferredSet.has(i)) {
22756
- const srcLayout = layoutGroups.find(
22757
- (lg) => `__group_${lg.label}` === edge.source
22758
- );
22759
- const tgtLayout = layoutGroups.find(
22760
- (lg) => `__group_${lg.label}` === edge.target
22761
- );
22762
- if (!srcLayout || !tgtLayout) {
22763
- const srcNode = g.node(edge.source);
22764
- const tgtNode = g.node(edge.target);
22765
- if (!srcNode || !tgtNode) continue;
22766
- const srcPt = clipToRectBorder2(
22767
- srcNode.x,
22768
- srcNode.y,
22769
- srcNode.width,
22770
- srcNode.height,
22771
- tgtNode.x,
22772
- tgtNode.y
22773
- );
22774
- const tgtPt = clipToRectBorder2(
22775
- tgtNode.x,
22776
- tgtNode.y,
22777
- tgtNode.width,
22778
- tgtNode.height,
22779
- srcNode.x,
22780
- srcNode.y
22781
- );
22782
- const midX = (srcPt.x + tgtPt.x) / 2;
22783
- const midY = (srcPt.y + tgtPt.y) / 2;
22784
- points = [srcPt, { x: midX, y: midY }, tgtPt];
22785
- } else if (parsed.direction === "TB") {
22786
- const cx = (srcLayout.x + tgtLayout.x) / 2;
22787
- const srcPt = { x: cx, y: srcLayout.y + srcLayout.height / 2 };
22788
- const tgtPt = { x: cx, y: tgtLayout.y - tgtLayout.height / 2 };
22789
- const midY = (srcPt.y + tgtPt.y) / 2;
22790
- points = [srcPt, { x: cx, y: midY }, tgtPt];
22791
- } else {
22792
- const cy = (srcLayout.y + tgtLayout.y) / 2;
22793
- const srcPt = { x: srcLayout.x + srcLayout.width / 2, y: cy };
22794
- const tgtPt = { x: tgtLayout.x - tgtLayout.width / 2, y: cy };
22795
- const midX = (srcPt.x + tgtPt.x) / 2;
22796
- points = [srcPt, { x: midX, y: cy }, tgtPt];
22797
- }
22798
- } else {
22799
- const dagreEdge = g.edge(edge.source, edge.target, `e${i}`);
22800
- points = dagreEdge?.points ?? [];
22801
- const srcShift = groupAlignShifts.get(edge.source) ?? 0;
22802
- const tgtShift = groupAlignShifts.get(edge.target) ?? 0;
22803
- if (srcShift !== 0 || tgtShift !== 0) {
22804
- const avgShift = (srcShift + tgtShift) / 2;
22805
- const prop = parsed.direction === "TB" ? "x" : "y";
22806
- points = points.map((p) => ({ ...p, [prop]: p[prop] + avgShift }));
22807
- }
22808
- }
22809
- let labelX;
22810
- let labelY;
22811
- if (edge.label && points.length >= 2) {
22812
- const mid = Math.floor(points.length / 2);
22813
- labelX = points[mid].x;
22814
- labelY = points[mid].y - 10;
22815
- }
22816
- layoutEdges.push({
22817
- source: edge.source,
22818
- target: edge.target,
22819
- label: edge.label,
22820
- bidirectional: edge.bidirectional,
22821
- lineNumber: edge.lineNumber,
22822
- points,
22823
- labelX,
22824
- labelY,
22825
- yOffset: edgeYOffsets[i],
22826
- parallelCount: edgeParallelCounts[i],
22827
- metadata: edge.metadata,
22828
- deferred: deferredSet.has(i) || void 0
22829
- });
22830
- }
22831
- let maxX = 0;
22832
- let maxY = 0;
22833
- for (const node of layoutNodes) {
22834
- maxX = Math.max(maxX, node.x + node.width / 2);
22835
- maxY = Math.max(maxY, node.y + node.height / 2);
22836
- }
22837
- for (const group of layoutGroups) {
22838
- maxX = Math.max(maxX, group.x + group.width / 2);
22839
- maxY = Math.max(maxY, group.y + group.height / 2);
22840
- }
22841
- return {
22842
- nodes: layoutNodes,
22843
- edges: layoutEdges,
22844
- groups: layoutGroups,
22845
- width: maxX + MARGIN3,
22846
- height: maxY + MARGIN3
22847
- };
22848
- }
22849
- var import_dagre4, NODESEP, RANKSEP, MARGIN3, CONTAINER_PAD_X3, CONTAINER_PAD_TOP2, CONTAINER_PAD_BOTTOM3, MAX_PARALLEL_EDGES, PARALLEL_SPACING, PHI, NODE_HEIGHT, NODE_WIDTH, DESC_NODE_WIDTH, DESC_FONT_SIZE, DESC_LINE_HEIGHT, DESC_PADDING, SEPARATOR_GAP5, MAX_DESC_LINES, MAX_LABEL_LINES, LABEL_LINE_HEIGHT, LABEL_PAD;
22850
- var init_layout5 = __esm({
22851
- "src/boxes-and-lines/layout.ts"() {
22852
- "use strict";
22853
- import_dagre4 = __toESM(require("@dagrejs/dagre"), 1);
22854
- NODESEP = 60;
22855
- RANKSEP = 100;
22856
- MARGIN3 = 40;
22857
- CONTAINER_PAD_X3 = 30;
22858
- CONTAINER_PAD_TOP2 = 40;
22859
- CONTAINER_PAD_BOTTOM3 = 24;
22860
- MAX_PARALLEL_EDGES = 5;
22861
- PARALLEL_SPACING = 22;
22862
- PHI = 1.618;
22863
- NODE_HEIGHT = 60;
22864
- NODE_WIDTH = Math.round(NODE_HEIGHT * PHI);
22865
- DESC_NODE_WIDTH = 140;
22866
- DESC_FONT_SIZE = 10;
22867
- DESC_LINE_HEIGHT = 1.4;
22868
- DESC_PADDING = 8;
22869
- SEPARATOR_GAP5 = 4;
22870
- MAX_DESC_LINES = 6;
22871
- MAX_LABEL_LINES = 3;
22872
- LABEL_LINE_HEIGHT = 1.3;
22873
- LABEL_PAD = 12;
22874
- }
22875
- });
22876
-
22877
22423
  // src/utils/wrapped-desc.ts
22878
22424
  function wrapDescriptionLines(lines, charsPerLine, lengthFn = (s) => s.length) {
22879
22425
  const result = [];
@@ -22923,7 +22469,7 @@ __export(renderer_exports6, {
22923
22469
  renderBoxesAndLines: () => renderBoxesAndLines,
22924
22470
  renderBoxesAndLinesForExport: () => renderBoxesAndLinesForExport
22925
22471
  });
22926
- function splitCamelCase2(word) {
22472
+ function splitCamelCase(word) {
22927
22473
  const parts = [];
22928
22474
  let start = 0;
22929
22475
  for (let i = 1; i < word.length; i++) {
@@ -22946,7 +22492,7 @@ function fitLabelToHeader(label, nodeWidth2, maxLines) {
22946
22492
  const words = [];
22947
22493
  for (const part of rawParts) {
22948
22494
  if (!part || /^\s+$/.test(part) || part === "-") continue;
22949
- words.push(...splitCamelCase2(part));
22495
+ words.push(...splitCamelCase(part));
22950
22496
  }
22951
22497
  for (let fontSize = NODE_FONT_SIZE; fontSize >= MIN_NODE_FONT_SIZE; fontSize--) {
22952
22498
  const charWidth2 = fontSize * CHAR_WIDTH_RATIO2;
@@ -23322,12 +22868,12 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
23322
22868
  }
23323
22869
  const sepY = -ln.height / 2 + headerH;
23324
22870
  nodeG.append("line").attr("x1", -ln.width / 2).attr("y1", sepY).attr("x2", ln.width / 2).attr("y2", sepY).attr("stroke", colors.stroke).attr("stroke-opacity", 0.3).attr("stroke-width", 1);
23325
- const descStartY = sepY + 4 + DESC_FONT_SIZE2;
22871
+ const descStartY = sepY + 4 + DESC_FONT_SIZE;
23326
22872
  const maxTextWidth = ln.width - NODE_TEXT_PADDING * 2;
23327
22873
  const charsPerLine = Math.floor(
23328
- maxTextWidth / (DESC_FONT_SIZE2 * CHAR_WIDTH_RATIO2)
22874
+ maxTextWidth / (DESC_FONT_SIZE * CHAR_WIDTH_RATIO2)
23329
22875
  );
23330
- const descLineH = DESC_FONT_SIZE2 * DESC_LINE_HEIGHT2;
22876
+ const descLineH = DESC_FONT_SIZE * DESC_LINE_HEIGHT;
23331
22877
  const displayLen = (text) => text.replace(/\[([^\]]+)\]\([^)]+\)/g, "$1").replace(/\*\*(.+?)\*\*/g, "$1").replace(/\*(.+?)\*/g, "$1").replace(/`(.+?)`/g, "$1").replace(/https?:\/\/\S+/g, (u) => u.slice(0, 20)).length;
23332
22878
  const normalizedLines = [];
23333
22879
  for (const descLine of desc) {
@@ -23343,8 +22889,8 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
23343
22889
  charsPerLine,
23344
22890
  displayLen
23345
22891
  );
23346
- const truncated = wrappedLinesShared.length > MAX_DESC_LINES2;
23347
- const visibleLines = truncated ? wrappedLinesShared.slice(0, MAX_DESC_LINES2) : wrappedLinesShared;
22892
+ const truncated = wrappedLinesShared.length > MAX_DESC_LINES;
22893
+ const visibleLines = truncated ? wrappedLinesShared.slice(0, MAX_DESC_LINES) : wrappedLinesShared;
23348
22894
  const BULLET_GLYPH_X = -ln.width / 2 + 6;
23349
22895
  const BULLET_BODY_X = BULLET_GLYPH_X + 10;
23350
22896
  for (let li = 0; li < visibleLines.length; li++) {
@@ -23355,11 +22901,11 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
23355
22901
  }
23356
22902
  const y2 = descStartY + li * descLineH;
23357
22903
  if (line12.kind === "bullet-first") {
23358
- nodeG.append("text").attr("x", BULLET_GLYPH_X).attr("y", y2).attr("text-anchor", "start").attr("dominant-baseline", "central").attr("font-size", DESC_FONT_SIZE2).attr("fill", palette.textMuted).text("\u2022");
22904
+ nodeG.append("text").attr("x", BULLET_GLYPH_X).attr("y", y2).attr("text-anchor", "start").attr("dominant-baseline", "central").attr("font-size", DESC_FONT_SIZE).attr("fill", palette.textMuted).text("\u2022");
23359
22905
  }
23360
22906
  const isBullet = line12.kind === "bullet-first" || line12.kind === "bullet-cont";
23361
- const textEl = nodeG.append("text").attr("x", isBullet ? BULLET_BODY_X : 0).attr("y", y2).attr("text-anchor", isBullet ? "start" : "middle").attr("dominant-baseline", "central").attr("font-size", DESC_FONT_SIZE2).attr("fill", palette.textMuted);
23362
- renderInlineText(textEl, lineText, palette, DESC_FONT_SIZE2);
22907
+ const textEl = nodeG.append("text").attr("x", isBullet ? BULLET_BODY_X : 0).attr("y", y2).attr("text-anchor", isBullet ? "start" : "middle").attr("dominant-baseline", "central").attr("font-size", DESC_FONT_SIZE).attr("fill", palette.textMuted);
22908
+ renderInlineText(textEl, lineText, palette, DESC_FONT_SIZE);
23363
22909
  }
23364
22910
  if (truncated) {
23365
22911
  const fullText = desc.join(" ");
@@ -23437,7 +22983,7 @@ function renderBoxesAndLinesForExport(container, parsed, layout, palette, isDark
23437
22983
  hiddenTagValues: options?.hiddenTagValues
23438
22984
  });
23439
22985
  }
23440
- var d3Selection6, d3Shape4, DIAGRAM_PADDING6, NODE_FONT_SIZE, MIN_NODE_FONT_SIZE, EDGE_LABEL_FONT_SIZE4, EDGE_STROKE_WIDTH5, NODE_STROKE_WIDTH5, NODE_RX, COLLAPSE_BAR_HEIGHT3, ARROWHEAD_W2, ARROWHEAD_H2, DESC_FONT_SIZE2, DESC_LINE_HEIGHT2, MAX_DESC_LINES2, CHAR_WIDTH_RATIO2, NODE_TEXT_PADDING, GROUP_RX, GROUP_LABEL_FONT_SIZE, GROUP_LABEL_ZONE, lineGeneratorLR, lineGeneratorTB;
22986
+ var d3Selection6, d3Shape4, DIAGRAM_PADDING6, NODE_FONT_SIZE, MIN_NODE_FONT_SIZE, EDGE_LABEL_FONT_SIZE4, EDGE_STROKE_WIDTH5, NODE_STROKE_WIDTH5, NODE_RX, COLLAPSE_BAR_HEIGHT3, ARROWHEAD_W2, ARROWHEAD_H2, DESC_FONT_SIZE, DESC_LINE_HEIGHT, MAX_DESC_LINES, CHAR_WIDTH_RATIO2, NODE_TEXT_PADDING, GROUP_RX, GROUP_LABEL_FONT_SIZE, GROUP_LABEL_ZONE, lineGeneratorLR, lineGeneratorTB;
23441
22987
  var init_renderer6 = __esm({
23442
22988
  "src/boxes-and-lines/renderer.ts"() {
23443
22989
  "use strict";
@@ -23461,9 +23007,9 @@ var init_renderer6 = __esm({
23461
23007
  COLLAPSE_BAR_HEIGHT3 = 4;
23462
23008
  ARROWHEAD_W2 = 5;
23463
23009
  ARROWHEAD_H2 = 4;
23464
- DESC_FONT_SIZE2 = 10;
23465
- DESC_LINE_HEIGHT2 = 1.4;
23466
- MAX_DESC_LINES2 = 6;
23010
+ DESC_FONT_SIZE = 10;
23011
+ DESC_LINE_HEIGHT = 1.4;
23012
+ MAX_DESC_LINES = 6;
23467
23013
  CHAR_WIDTH_RATIO2 = 0.6;
23468
23014
  NODE_TEXT_PADDING = 12;
23469
23015
  GROUP_RX = 8;
@@ -23474,6 +23020,523 @@ var init_renderer6 = __esm({
23474
23020
  }
23475
23021
  });
23476
23022
 
23023
+ // src/boxes-and-lines/layout.ts
23024
+ var layout_exports5 = {};
23025
+ __export(layout_exports5, {
23026
+ layoutBoxesAndLines: () => layoutBoxesAndLines
23027
+ });
23028
+ function splitCamelCase2(word) {
23029
+ const parts = [];
23030
+ let start = 0;
23031
+ for (let i = 1; i < word.length; i++) {
23032
+ const prev = word[i - 1];
23033
+ const curr = word[i];
23034
+ const next = i + 1 < word.length ? word[i + 1] : "";
23035
+ const lowerToUpper = prev >= "a" && prev <= "z" && curr >= "A" && curr <= "Z";
23036
+ const upperRunEnd = prev >= "A" && prev <= "Z" && curr >= "A" && curr <= "Z" && next >= "a" && next <= "z";
23037
+ if (lowerToUpper || upperRunEnd) {
23038
+ parts.push(word.slice(start, i));
23039
+ start = i;
23040
+ }
23041
+ }
23042
+ parts.push(word.slice(start));
23043
+ return parts.length > 1 ? parts : [word];
23044
+ }
23045
+ function estimateLabelLines(label, nodeWidth2 = NODE_WIDTH) {
23046
+ const rawParts = label.split(/[\s-]+/);
23047
+ const words = [];
23048
+ for (const part of rawParts) {
23049
+ if (!part) continue;
23050
+ words.push(...splitCamelCase2(part));
23051
+ }
23052
+ for (let fontSize = 13; fontSize >= 9; fontSize--) {
23053
+ const charWidth = fontSize * 0.6;
23054
+ const maxChars = Math.floor((nodeWidth2 - 24) / charWidth);
23055
+ if (maxChars < 2) continue;
23056
+ let lines = 1;
23057
+ let current = "";
23058
+ for (const word of words) {
23059
+ const test = current ? `${current} ${word}` : word;
23060
+ if (test.length <= maxChars) {
23061
+ current = test;
23062
+ } else {
23063
+ lines++;
23064
+ current = word;
23065
+ }
23066
+ }
23067
+ if (lines <= MAX_LABEL_LINES) return Math.min(lines, MAX_LABEL_LINES);
23068
+ }
23069
+ return MAX_LABEL_LINES;
23070
+ }
23071
+ function computeNodeSize(node) {
23072
+ if (!node.description || node.description.length === 0) {
23073
+ return { width: NODE_WIDTH, height: NODE_HEIGHT };
23074
+ }
23075
+ const w = DESC_NODE_WIDTH;
23076
+ const labelLines = estimateLabelLines(node.label, w);
23077
+ const labelHeight = labelLines * 13 * LABEL_LINE_HEIGHT + LABEL_PAD;
23078
+ const charsPerLine = Math.floor((w - 24) / (DESC_FONT_SIZE2 * 0.6));
23079
+ let totalRenderedLines = 0;
23080
+ for (const line12 of node.description) {
23081
+ if (line12.length <= charsPerLine) {
23082
+ totalRenderedLines += 1;
23083
+ } else {
23084
+ const words = line12.split(/\s+/);
23085
+ let current = "";
23086
+ let lineCount = 0;
23087
+ for (const word of words) {
23088
+ const fitted = word.length > charsPerLine ? word.slice(0, charsPerLine) : word;
23089
+ const test = current ? `${current} ${fitted}` : fitted;
23090
+ if (test.length <= charsPerLine) {
23091
+ current = test;
23092
+ } else {
23093
+ if (current) lineCount++;
23094
+ current = fitted;
23095
+ }
23096
+ }
23097
+ if (current) lineCount++;
23098
+ totalRenderedLines += lineCount;
23099
+ }
23100
+ }
23101
+ totalRenderedLines = Math.min(totalRenderedLines, MAX_DESC_LINES2);
23102
+ const descriptionHeight = totalRenderedLines * DESC_FONT_SIZE2 * DESC_LINE_HEIGHT2;
23103
+ const totalHeight = labelHeight + SEPARATOR_GAP5 + DESC_PADDING + descriptionHeight + DESC_PADDING;
23104
+ return { width: w, height: Math.max(NODE_HEIGHT, totalHeight) };
23105
+ }
23106
+ function getElk() {
23107
+ if (!elkInstance) elkInstance = new import_elk_bundled.default();
23108
+ return elkInstance;
23109
+ }
23110
+ function baseOptions() {
23111
+ return {
23112
+ "elk.algorithm": "layered",
23113
+ // INCLUDE_CHILDREN lets ELK route edges across container boundaries.
23114
+ "elk.hierarchyHandling": "INCLUDE_CHILDREN",
23115
+ "elk.edgeRouting": "ORTHOGONAL",
23116
+ "elk.layered.unnecessaryBendpoints": "true",
23117
+ // Let edges leave from top/bottom of nodes (not just the flow-direction
23118
+ // sides) when it reduces crossings.
23119
+ "elk.layered.allowNonFlowPortsToSwitchSides": "true"
23120
+ };
23121
+ }
23122
+ function bkBaseline() {
23123
+ return {
23124
+ ...baseOptions(),
23125
+ "elk.layered.nodePlacement.strategy": "BRANDES_KOEPF",
23126
+ "elk.layered.nodePlacement.bk.fixedAlignment": "BALANCED",
23127
+ "elk.layered.nodePlacement.bk.edgeStraightening": "IMPROVE_STRAIGHTNESS",
23128
+ "elk.layered.compaction.connectedComponents": "true",
23129
+ "elk.layered.spacing.nodeNodeBetweenLayers": "90",
23130
+ "elk.spacing.nodeNode": "55",
23131
+ "elk.spacing.edgeNode": "55",
23132
+ "elk.spacing.edgeEdge": "18"
23133
+ };
23134
+ }
23135
+ function getVariants() {
23136
+ const bk = bkBaseline();
23137
+ return [
23138
+ {
23139
+ name: "bk-baseline",
23140
+ options: {
23141
+ ...bk,
23142
+ "elk.layered.crossingMinimization.greedySwitch.type": "ONE_SIDED"
23143
+ }
23144
+ },
23145
+ {
23146
+ name: "bk-aggressive",
23147
+ options: {
23148
+ ...bk,
23149
+ "elk.layered.crossingMinimization.greedySwitch.type": "TWO_SIDED",
23150
+ "elk.layered.thoroughness": "50"
23151
+ }
23152
+ },
23153
+ {
23154
+ name: "bk-wide",
23155
+ options: {
23156
+ ...bk,
23157
+ "elk.layered.crossingMinimization.greedySwitch.type": "TWO_SIDED",
23158
+ "elk.layered.thoroughness": "50",
23159
+ "elk.spacing.nodeNode": "70",
23160
+ "elk.spacing.edgeNode": "75",
23161
+ "elk.spacing.edgeEdge": "22",
23162
+ "elk.layered.spacing.nodeNodeBetweenLayers": "120"
23163
+ }
23164
+ },
23165
+ {
23166
+ name: "longest-path",
23167
+ options: {
23168
+ ...bk,
23169
+ "elk.layered.layering.strategy": "LONGEST_PATH",
23170
+ "elk.layered.crossingMinimization.greedySwitch.type": "TWO_SIDED",
23171
+ "elk.layered.thoroughness": "50"
23172
+ }
23173
+ },
23174
+ {
23175
+ name: "bounded-width",
23176
+ options: {
23177
+ ...bk,
23178
+ "elk.layered.layering.strategy": "COFFMAN_GRAHAM",
23179
+ "elk.layered.layering.coffmanGraham.layerBound": "3",
23180
+ "elk.layered.crossingMinimization.greedySwitch.type": "TWO_SIDED",
23181
+ "elk.layered.thoroughness": "50"
23182
+ }
23183
+ }
23184
+ ];
23185
+ }
23186
+ function countCrossings(edges) {
23187
+ let count = 0;
23188
+ for (let i = 0; i < edges.length; i++) {
23189
+ const a = edges[i].points;
23190
+ if (a.length < 2) continue;
23191
+ for (let j = i + 1; j < edges.length; j++) {
23192
+ const b = edges[j].points;
23193
+ if (b.length < 2) continue;
23194
+ if (edges[i].source === edges[j].source) continue;
23195
+ if (edges[i].source === edges[j].target) continue;
23196
+ if (edges[i].target === edges[j].source) continue;
23197
+ if (edges[i].target === edges[j].target) continue;
23198
+ for (let ai = 0; ai < a.length - 1; ai++) {
23199
+ for (let bi = 0; bi < b.length - 1; bi++) {
23200
+ if (segmentsCross(a[ai], a[ai + 1], b[bi], b[bi + 1])) count++;
23201
+ }
23202
+ }
23203
+ }
23204
+ }
23205
+ return count;
23206
+ }
23207
+ function segmentsCross(p1, p2, p3, p4) {
23208
+ const d1x = p2.x - p1.x;
23209
+ const d1y = p2.y - p1.y;
23210
+ const d2x = p4.x - p3.x;
23211
+ const d2y = p4.y - p3.y;
23212
+ const denom = d1x * d2y - d1y * d2x;
23213
+ if (Math.abs(denom) < 1e-9) return false;
23214
+ const t = ((p3.x - p1.x) * d2y - (p3.y - p1.y) * d2x) / denom;
23215
+ const s = ((p3.x - p1.x) * d1y - (p3.y - p1.y) * d1x) / denom;
23216
+ const EPS = 1e-3;
23217
+ return t > EPS && t < 1 - EPS && s > EPS && s < 1 - EPS;
23218
+ }
23219
+ function countTotalBends(edges) {
23220
+ let bends = 0;
23221
+ for (const e of edges) bends += Math.max(0, e.points.length - 2);
23222
+ return bends;
23223
+ }
23224
+ function scoreLayout(layout) {
23225
+ return {
23226
+ crossings: countCrossings(layout.edges),
23227
+ bends: countTotalBends(layout.edges),
23228
+ area: layout.width * layout.height
23229
+ };
23230
+ }
23231
+ function cmpScore(a, b) {
23232
+ const aBucket = a.crossings <= CROSSINGS_FORGIVENESS ? 0 : a.crossings;
23233
+ const bBucket = b.crossings <= CROSSINGS_FORGIVENESS ? 0 : b.crossings;
23234
+ if (aBucket !== bBucket) return aBucket - bBucket;
23235
+ if (a.area !== b.area) return a.area - b.area;
23236
+ return a.bends - b.bends;
23237
+ }
23238
+ async function layoutBoxesAndLines(parsed, collapseInfo, layoutOptions) {
23239
+ const hideDescriptions = layoutOptions?.hideDescriptions ?? false;
23240
+ const direction = parsed.direction === "TB" ? "DOWN" : "RIGHT";
23241
+ const collapsedGroupLabels = /* @__PURE__ */ new Set();
23242
+ if (collapseInfo) {
23243
+ const missingGroups = /* @__PURE__ */ new Set();
23244
+ for (const og of collapseInfo.originalGroups) {
23245
+ if (!parsed.groups.some((g) => g.label === og.label)) {
23246
+ missingGroups.add(og.label);
23247
+ }
23248
+ }
23249
+ for (const label of missingGroups) {
23250
+ const og = collapseInfo.originalGroups.find((g) => g.label === label);
23251
+ const parentLabel = og?.parentGroup;
23252
+ if (!parentLabel || !missingGroups.has(parentLabel)) {
23253
+ collapsedGroupLabels.add(label);
23254
+ }
23255
+ }
23256
+ }
23257
+ const nodeSizes = /* @__PURE__ */ new Map();
23258
+ let maxDescHeight = 0;
23259
+ for (const node of parsed.nodes) {
23260
+ const size = hideDescriptions ? { width: NODE_WIDTH, height: NODE_HEIGHT } : computeNodeSize(node);
23261
+ nodeSizes.set(node.label, size);
23262
+ if (!hideDescriptions && node.description && node.description.length > 0) {
23263
+ maxDescHeight = Math.max(maxDescHeight, size.height);
23264
+ }
23265
+ }
23266
+ if (maxDescHeight > 0) {
23267
+ for (const node of parsed.nodes) {
23268
+ if (node.description && node.description.length > 0) {
23269
+ const size = nodeSizes.get(node.label);
23270
+ nodeSizes.set(node.label, { width: size.width, height: maxDescHeight });
23271
+ }
23272
+ }
23273
+ }
23274
+ const expandedGroupSet = new Set(parsed.groups.map((g) => g.label));
23275
+ const gid = (label) => `__group_${label}`;
23276
+ function buildGraph() {
23277
+ const nodeById = /* @__PURE__ */ new Map();
23278
+ const parentOf = /* @__PURE__ */ new Map();
23279
+ for (const node of parsed.nodes) {
23280
+ const size = nodeSizes.get(node.label);
23281
+ nodeById.set(node.label, {
23282
+ id: node.label,
23283
+ width: size.width,
23284
+ height: size.height,
23285
+ labels: [{ text: node.label }]
23286
+ });
23287
+ }
23288
+ for (const group of parsed.groups) {
23289
+ nodeById.set(gid(group.label), {
23290
+ id: gid(group.label),
23291
+ labels: [{ text: group.label }],
23292
+ layoutOptions: {
23293
+ "elk.padding": `[top=${CONTAINER_PAD_TOP2},left=${CONTAINER_PAD_X3},bottom=${CONTAINER_PAD_BOTTOM3},right=${CONTAINER_PAD_X3}]`,
23294
+ // Suggest square-ish containers — has limited effect with
23295
+ // INCLUDE_CHILDREN but doesn't hurt.
23296
+ "elk.aspectRatio": "1.4"
23297
+ },
23298
+ children: [],
23299
+ edges: []
23300
+ });
23301
+ }
23302
+ for (const label of collapsedGroupLabels) {
23303
+ nodeById.set(gid(label), {
23304
+ id: gid(label),
23305
+ width: NODE_WIDTH,
23306
+ height: NODE_HEIGHT,
23307
+ labels: [{ text: label }]
23308
+ });
23309
+ }
23310
+ for (const group of parsed.groups) {
23311
+ if (group.parentGroup && nodeById.has(gid(group.parentGroup))) {
23312
+ parentOf.set(gid(group.label), gid(group.parentGroup));
23313
+ }
23314
+ }
23315
+ if (collapseInfo) {
23316
+ for (const label of collapsedGroupLabels) {
23317
+ const og = collapseInfo.originalGroups.find((g) => g.label === label);
23318
+ if (og?.parentGroup && !collapsedGroupLabels.has(og.parentGroup) && nodeById.has(gid(og.parentGroup))) {
23319
+ parentOf.set(gid(label), gid(og.parentGroup));
23320
+ }
23321
+ }
23322
+ }
23323
+ for (const group of parsed.groups) {
23324
+ for (const child of group.children) {
23325
+ if (expandedGroupSet.has(child)) continue;
23326
+ if (nodeById.has(child)) {
23327
+ parentOf.set(child, gid(group.label));
23328
+ }
23329
+ }
23330
+ }
23331
+ const roots = [];
23332
+ for (const [id, node] of nodeById) {
23333
+ const parentId = parentOf.get(id);
23334
+ if (parentId) {
23335
+ const parent = nodeById.get(parentId);
23336
+ parent.children = parent.children ?? [];
23337
+ parent.children.push(node);
23338
+ } else {
23339
+ roots.push(node);
23340
+ }
23341
+ }
23342
+ const rootEdges = [];
23343
+ for (let i = 0; i < parsed.edges.length; i++) {
23344
+ const edge = parsed.edges[i];
23345
+ if (!nodeById.has(edge.source) || !nodeById.has(edge.target)) continue;
23346
+ rootEdges.push({
23347
+ id: `e${i}`,
23348
+ sources: [edge.source],
23349
+ targets: [edge.target]
23350
+ });
23351
+ }
23352
+ return { roots, rootEdges };
23353
+ }
23354
+ async function runVariant(variant) {
23355
+ const { roots, rootEdges } = buildGraph();
23356
+ const elkRoot = {
23357
+ id: "root",
23358
+ layoutOptions: {
23359
+ ...variant.options,
23360
+ "elk.direction": direction,
23361
+ "elk.padding": `[top=${MARGIN3},left=${MARGIN3},bottom=${MARGIN3},right=${MARGIN3}]`
23362
+ },
23363
+ children: roots,
23364
+ edges: rootEdges
23365
+ };
23366
+ const result = await getElk().layout(elkRoot);
23367
+ return extractLayout(result);
23368
+ }
23369
+ function extractLayout(result) {
23370
+ const layoutNodes = [];
23371
+ const layoutGroups = [];
23372
+ const allEdges = [];
23373
+ const containerAbs = /* @__PURE__ */ new Map();
23374
+ function walk(n, offsetX, offsetY, isRoot) {
23375
+ const nx = (n.x ?? 0) + offsetX;
23376
+ const ny = (n.y ?? 0) + offsetY;
23377
+ const nw = n.width ?? 0;
23378
+ const nh = n.height ?? 0;
23379
+ if (isRoot) {
23380
+ containerAbs.set("root", { x: nx, y: ny });
23381
+ } else {
23382
+ const isGroup = n.id.startsWith("__group_");
23383
+ if (isGroup) {
23384
+ const label = n.id.slice("__group_".length);
23385
+ const collapsed = collapsedGroupLabels.has(label);
23386
+ const og = collapseInfo?.originalGroups.find(
23387
+ (g) => g.label === label
23388
+ );
23389
+ const pg = parsed.groups.find((g) => g.label === label);
23390
+ layoutGroups.push({
23391
+ label,
23392
+ lineNumber: pg?.lineNumber ?? og?.lineNumber ?? 0,
23393
+ x: nx + nw / 2,
23394
+ y: ny + nh / 2,
23395
+ width: nw,
23396
+ height: nh,
23397
+ collapsed,
23398
+ childCount: collapsed ? collapseInfo?.collapsedChildCounts.get(label) ?? 0 : void 0
23399
+ });
23400
+ if (!collapsed) containerAbs.set(n.id, { x: nx, y: ny });
23401
+ } else {
23402
+ layoutNodes.push({
23403
+ label: n.id,
23404
+ x: nx + nw / 2,
23405
+ y: ny + nh / 2,
23406
+ width: nw,
23407
+ height: nh
23408
+ });
23409
+ }
23410
+ }
23411
+ if (n.edges) for (const e of n.edges) allEdges.push(e);
23412
+ if (n.children) for (const c of n.children) walk(c, nx, ny, false);
23413
+ }
23414
+ walk(result, 0, 0, true);
23415
+ const edgeYOffsets = new Array(parsed.edges.length).fill(0);
23416
+ const edgeParallelCounts = new Array(parsed.edges.length).fill(1);
23417
+ const parallelGroups = /* @__PURE__ */ new Map();
23418
+ for (let i = 0; i < parsed.edges.length; i++) {
23419
+ const edge = parsed.edges[i];
23420
+ const [a, b] = edge.source < edge.target ? [edge.source, edge.target] : [edge.target, edge.source];
23421
+ const key = `${a}\0${b}`;
23422
+ if (!parallelGroups.has(key)) parallelGroups.set(key, []);
23423
+ parallelGroups.get(key).push(i);
23424
+ }
23425
+ for (const group of parallelGroups.values()) {
23426
+ const capped = group.slice(0, MAX_PARALLEL_EDGES);
23427
+ for (const idx of group.slice(MAX_PARALLEL_EDGES)) {
23428
+ edgeParallelCounts[idx] = 0;
23429
+ }
23430
+ if (capped.length < 2) continue;
23431
+ for (let j = 0; j < capped.length; j++) {
23432
+ edgeYOffsets[capped[j]] = (j - (capped.length - 1) / 2) * PARALLEL_SPACING;
23433
+ edgeParallelCounts[capped[j]] = capped.length;
23434
+ }
23435
+ }
23436
+ const edgeById = /* @__PURE__ */ new Map();
23437
+ for (const e of allEdges) edgeById.set(e.id, e);
23438
+ const layoutEdges = [];
23439
+ for (let i = 0; i < parsed.edges.length; i++) {
23440
+ const edge = parsed.edges[i];
23441
+ if (edgeParallelCounts[i] === 0) continue;
23442
+ const elkEdge = edgeById.get(`e${i}`);
23443
+ if (!elkEdge || !elkEdge.sections || elkEdge.sections.length === 0)
23444
+ continue;
23445
+ const container = elkEdge.container ?? "root";
23446
+ const off = containerAbs.get(container) ?? { x: 0, y: 0 };
23447
+ const s = elkEdge.sections[0];
23448
+ const points = [
23449
+ { x: s.startPoint.x + off.x, y: s.startPoint.y + off.y },
23450
+ ...(s.bendPoints ?? []).map((p) => ({
23451
+ x: p.x + off.x,
23452
+ y: p.y + off.y
23453
+ })),
23454
+ { x: s.endPoint.x + off.x, y: s.endPoint.y + off.y }
23455
+ ];
23456
+ let labelX;
23457
+ let labelY;
23458
+ if (edge.label && points.length >= 2) {
23459
+ const mid = Math.floor(points.length / 2);
23460
+ labelX = points[mid].x;
23461
+ labelY = points[mid].y - 10;
23462
+ }
23463
+ layoutEdges.push({
23464
+ source: edge.source,
23465
+ target: edge.target,
23466
+ label: edge.label,
23467
+ bidirectional: edge.bidirectional,
23468
+ lineNumber: edge.lineNumber,
23469
+ points,
23470
+ labelX,
23471
+ labelY,
23472
+ yOffset: edgeYOffsets[i],
23473
+ parallelCount: edgeParallelCounts[i],
23474
+ metadata: edge.metadata,
23475
+ deferred: true
23476
+ });
23477
+ }
23478
+ let maxX = 0;
23479
+ let maxY = 0;
23480
+ for (const node of layoutNodes) {
23481
+ maxX = Math.max(maxX, node.x + node.width / 2);
23482
+ maxY = Math.max(maxY, node.y + node.height / 2);
23483
+ }
23484
+ for (const group of layoutGroups) {
23485
+ maxX = Math.max(maxX, group.x + group.width / 2);
23486
+ maxY = Math.max(maxY, group.y + group.height / 2);
23487
+ }
23488
+ return {
23489
+ nodes: layoutNodes,
23490
+ edges: layoutEdges,
23491
+ groups: layoutGroups,
23492
+ width: maxX + MARGIN3,
23493
+ height: maxY + MARGIN3
23494
+ };
23495
+ }
23496
+ const N = parsed.nodes.length + parsed.groups.length;
23497
+ const E = parsed.edges.length;
23498
+ const trivial = N < 8 && E < 10;
23499
+ const variants = trivial ? [getVariants()[1]] : getVariants();
23500
+ const results = await Promise.all(variants.map((v) => runVariant(v)));
23501
+ let best = results[0];
23502
+ let bestScore = scoreLayout(best);
23503
+ for (let i = 1; i < results.length; i++) {
23504
+ const s = scoreLayout(results[i]);
23505
+ if (cmpScore(s, bestScore) < 0) {
23506
+ best = results[i];
23507
+ bestScore = s;
23508
+ }
23509
+ }
23510
+ return best;
23511
+ }
23512
+ var import_elk_bundled, MARGIN3, CONTAINER_PAD_X3, CONTAINER_PAD_TOP2, CONTAINER_PAD_BOTTOM3, MAX_PARALLEL_EDGES, PARALLEL_SPACING, PHI, NODE_HEIGHT, NODE_WIDTH, DESC_NODE_WIDTH, DESC_FONT_SIZE2, DESC_LINE_HEIGHT2, DESC_PADDING, SEPARATOR_GAP5, MAX_DESC_LINES2, MAX_LABEL_LINES, LABEL_LINE_HEIGHT, LABEL_PAD, elkInstance, CROSSINGS_FORGIVENESS;
23513
+ var init_layout5 = __esm({
23514
+ "src/boxes-and-lines/layout.ts"() {
23515
+ "use strict";
23516
+ import_elk_bundled = __toESM(require("elkjs/lib/elk.bundled.js"), 1);
23517
+ MARGIN3 = 40;
23518
+ CONTAINER_PAD_X3 = 30;
23519
+ CONTAINER_PAD_TOP2 = 40;
23520
+ CONTAINER_PAD_BOTTOM3 = 24;
23521
+ MAX_PARALLEL_EDGES = 5;
23522
+ PARALLEL_SPACING = 22;
23523
+ PHI = 1.618;
23524
+ NODE_HEIGHT = 60;
23525
+ NODE_WIDTH = Math.round(NODE_HEIGHT * PHI);
23526
+ DESC_NODE_WIDTH = 140;
23527
+ DESC_FONT_SIZE2 = 10;
23528
+ DESC_LINE_HEIGHT2 = 1.4;
23529
+ DESC_PADDING = 8;
23530
+ SEPARATOR_GAP5 = 4;
23531
+ MAX_DESC_LINES2 = 6;
23532
+ MAX_LABEL_LINES = 3;
23533
+ LABEL_LINE_HEIGHT = 1.3;
23534
+ LABEL_PAD = 12;
23535
+ elkInstance = null;
23536
+ CROSSINGS_FORGIVENESS = 1;
23537
+ }
23538
+ });
23539
+
23477
23540
  // src/mindmap/text-wrap.ts
23478
23541
  function tokenize(text) {
23479
23542
  const tokens = [];
@@ -23612,7 +23675,7 @@ var layout_exports6 = {};
23612
23675
  __export(layout_exports6, {
23613
23676
  layoutMindmap: () => layoutMindmap
23614
23677
  });
23615
- function layoutMindmap(parsed, palette, options) {
23678
+ function layoutMindmap(parsed, _palette, options) {
23616
23679
  const roots = parsed.roots;
23617
23680
  if (roots.length === 0) {
23618
23681
  return { nodes: [], edges: [], width: 0, height: 0 };
@@ -24508,7 +24571,7 @@ function layoutElement(el, x, y, width) {
24508
24571
  node.height = getElementHeight(el);
24509
24572
  return node;
24510
24573
  }
24511
- const isInlineRow = el.metadata._inlineRow === "true" || el.metadata._labelField === "true";
24574
+ const isInlineRow = el.metadata["_inlineRow"] === "true" || el.metadata["_labelField"] === "true";
24512
24575
  const padTop = isInlineRow ? 0 : GROUP_PADDING_TOP;
24513
24576
  const padBottom = isInlineRow ? 0 : GROUP_PADDING_BOTTOM;
24514
24577
  const padX = isInlineRow ? 0 : GROUP_PADDING_X;
@@ -24557,7 +24620,7 @@ function allocateEqualWidths(children, totalWidth) {
24557
24620
  }
24558
24621
  function getElementHeight(el) {
24559
24622
  if (el.type === "heading") {
24560
- return el.headingLevel === 2 ? ELEMENT_HEIGHTS.subheading ?? 36 : ELEMENT_HEIGHTS.heading ?? 48;
24623
+ return el.headingLevel === 2 ? ELEMENT_HEIGHTS["subheading"] ?? 36 : ELEMENT_HEIGHTS["heading"] ?? 48;
24561
24624
  }
24562
24625
  if (el.type === "textInput" && el.fieldVariant === "textarea") {
24563
24626
  return 80;
@@ -24571,16 +24634,16 @@ function getElementHeight(el) {
24571
24634
  if (el.type === "image") {
24572
24635
  if (el.imageHint === "round") return 80;
24573
24636
  if (el.imageHint === "wide") return 80;
24574
- return ELEMENT_HEIGHTS.image ?? 120;
24637
+ return ELEMENT_HEIGHTS["image"] ?? 120;
24575
24638
  }
24576
- if (el.metadata._labelField === "true") {
24639
+ if (el.metadata["_labelField"] === "true") {
24577
24640
  return 36;
24578
24641
  }
24579
24642
  return ELEMENT_HEIGHTS[el.type] ?? 24;
24580
24643
  }
24581
24644
  function getSpacingAfter(el) {
24582
24645
  if (el.type === "heading" && el.headingLevel === 2) {
24583
- return SPACING_AFTER.subheading ?? 12;
24646
+ return SPACING_AFTER["subheading"] ?? 12;
24584
24647
  }
24585
24648
  return SPACING_AFTER[el.type] ?? 8;
24586
24649
  }
@@ -24588,7 +24651,7 @@ function computeFieldAlignX(children) {
24588
24651
  let maxLabelWidth = 0;
24589
24652
  let labelFieldCount = 0;
24590
24653
  for (const child of children) {
24591
- if (child.metadata._labelField === "true" && child.children.length >= 2) {
24654
+ if (child.metadata["_labelField"] === "true" && child.children.length >= 2) {
24592
24655
  const labelEl = child.children[0];
24593
24656
  const labelWidth = labelEl.label.length * CHAR_WIDTH5;
24594
24657
  maxLabelWidth = Math.max(maxLabelWidth, labelWidth);
@@ -24799,7 +24862,7 @@ function renderNode(parent, node, ctx, depth) {
24799
24862
  function renderGroup(g, node, ctx, depth) {
24800
24863
  const { palette, isTransparent } = ctx;
24801
24864
  const el = node.element;
24802
- if (el.metadata._inlineRow === "true" || el.metadata._labelField === "true") {
24865
+ if (el.metadata["_inlineRow"] === "true" || el.metadata["_labelField"] === "true") {
24803
24866
  for (const child of node.children) {
24804
24867
  renderNode(g, child, ctx, depth);
24805
24868
  }
@@ -24927,7 +24990,7 @@ function renderDivider(g, node, ctx) {
24927
24990
  function renderText(g, node, ctx) {
24928
24991
  const { palette } = ctx;
24929
24992
  const el = node.element;
24930
- if (el.metadata._labelField === "true" && el.children.length >= 2) {
24993
+ if (el.metadata["_labelField"] === "true" && el.children.length >= 2) {
24931
24994
  for (const child of node.children) {
24932
24995
  renderNode(g, child, ctx, 0);
24933
24996
  }
@@ -25662,7 +25725,7 @@ function layoutC4Context(parsed, activeTagGroup) {
25662
25725
  }
25663
25726
  const contextRels = rollUpContextRelationships(parsed);
25664
25727
  const spacing = computeAdaptiveSpacing(contextRels);
25665
- const g = new import_dagre5.default.graphlib.Graph();
25728
+ const g = new import_dagre4.default.graphlib.Graph();
25666
25729
  g.setGraph({
25667
25730
  rankdir: "TB",
25668
25731
  nodesep: spacing.nodesep,
@@ -25683,7 +25746,7 @@ function layoutC4Context(parsed, activeTagGroup) {
25683
25746
  g.setEdge(rel.sourceName, rel.targetName, { label: rel.label ?? "" });
25684
25747
  }
25685
25748
  }
25686
- import_dagre5.default.layout(g);
25749
+ import_dagre4.default.layout(g);
25687
25750
  reduceCrossings(
25688
25751
  g,
25689
25752
  validRels.map((r) => ({ source: r.sourceName, target: r.targetName }))
@@ -25855,7 +25918,7 @@ function layoutC4Containers(parsed, systemName, activeTagGroup) {
25855
25918
  }
25856
25919
  }
25857
25920
  const hasGroups = elementToGroup.size > 0;
25858
- const g = hasGroups ? new import_dagre5.default.graphlib.Graph({ compound: true }) : new import_dagre5.default.graphlib.Graph();
25921
+ const g = hasGroups ? new import_dagre4.default.graphlib.Graph({ compound: true }) : new import_dagre4.default.graphlib.Graph();
25859
25922
  g.setDefaultEdgeLabel(() => ({}));
25860
25923
  if (hasGroups) {
25861
25924
  const seenGroups = /* @__PURE__ */ new Set();
@@ -25933,7 +25996,7 @@ function layoutC4Containers(parsed, systemName, activeTagGroup) {
25933
25996
  g.setEdge(rel.sourceName, rel.targetName, { label: rel.label ?? "" });
25934
25997
  }
25935
25998
  }
25936
- import_dagre5.default.layout(g);
25999
+ import_dagre4.default.layout(g);
25937
26000
  const nodeGroupMap = hasGroups ? new Map([...elementToGroup.entries()].map(([k, v]) => [k, v.name])) : void 0;
25938
26001
  reduceCrossings(
25939
26002
  g,
@@ -26259,7 +26322,7 @@ function layoutC4Components(parsed, systemName, containerName, activeTagGroup) {
26259
26322
  }
26260
26323
  }
26261
26324
  const hasGroups = elementToGroup.size > 0;
26262
- const g = hasGroups ? new import_dagre5.default.graphlib.Graph({ compound: true }) : new import_dagre5.default.graphlib.Graph();
26325
+ const g = hasGroups ? new import_dagre4.default.graphlib.Graph({ compound: true }) : new import_dagre4.default.graphlib.Graph();
26263
26326
  g.setDefaultEdgeLabel(() => ({}));
26264
26327
  if (hasGroups) {
26265
26328
  const seenGroups = /* @__PURE__ */ new Set();
@@ -26343,7 +26406,7 @@ function layoutC4Components(parsed, systemName, containerName, activeTagGroup) {
26343
26406
  g.setEdge(rel.sourceName, rel.targetName, { label: rel.label ?? "" });
26344
26407
  }
26345
26408
  }
26346
- import_dagre5.default.layout(g);
26409
+ import_dagre4.default.layout(g);
26347
26410
  const nodeGroupMap = hasGroups ? new Map([...elementToGroup.entries()].map(([k, v]) => [k, v.name])) : void 0;
26348
26411
  reduceCrossings(
26349
26412
  g,
@@ -26632,7 +26695,7 @@ function layoutC4Deployment(parsed, activeTagGroup) {
26632
26695
  for (const r of refEntries) {
26633
26696
  nameToElement.set(r.element.name, r.element);
26634
26697
  }
26635
- const g = new import_dagre5.default.graphlib.Graph({ compound: true });
26698
+ const g = new import_dagre4.default.graphlib.Graph({ compound: true });
26636
26699
  g.setDefaultEdgeLabel(() => ({}));
26637
26700
  for (const [infraId] of infraIds) {
26638
26701
  g.setNode(infraId, {});
@@ -26676,7 +26739,7 @@ function layoutC4Deployment(parsed, activeTagGroup) {
26676
26739
  g.setEdge(rel.sourceName, rel.targetName, { label: rel.label ?? "" });
26677
26740
  }
26678
26741
  }
26679
- import_dagre5.default.layout(g);
26742
+ import_dagre4.default.layout(g);
26680
26743
  const nodeInfraMap = /* @__PURE__ */ new Map();
26681
26744
  for (const r of refEntries) nodeInfraMap.set(r.element.name, r.infraId);
26682
26745
  reduceCrossings(
@@ -26854,11 +26917,11 @@ function layoutC4Deployment(parsed, activeTagGroup) {
26854
26917
  height: totalHeight
26855
26918
  };
26856
26919
  }
26857
- var import_dagre5, gNode, gEdge, CHAR_WIDTH6, MIN_NODE_WIDTH, MAX_NODE_WIDTH, TYPE_LABEL_HEIGHT, DIVIDER_GAP, NAME_HEIGHT, DESC_LINE_HEIGHT5, DESC_CHAR_WIDTH, CARD_V_PAD3, CARD_H_PAD3, META_LINE_HEIGHT5, META_CHAR_WIDTH, MARGIN5, 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;
26920
+ var import_dagre4, gNode, gEdge, CHAR_WIDTH6, MIN_NODE_WIDTH, MAX_NODE_WIDTH, TYPE_LABEL_HEIGHT, DIVIDER_GAP, NAME_HEIGHT, DESC_LINE_HEIGHT5, DESC_CHAR_WIDTH, CARD_V_PAD3, CARD_H_PAD3, META_LINE_HEIGHT5, META_CHAR_WIDTH, MARGIN5, 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;
26858
26921
  var init_layout8 = __esm({
26859
26922
  "src/c4/layout.ts"() {
26860
26923
  "use strict";
26861
- import_dagre5 = __toESM(require("@dagrejs/dagre"), 1);
26924
+ import_dagre4 = __toESM(require("@dagrejs/dagre"), 1);
26862
26925
  init_legend_constants();
26863
26926
  gNode = (g, name) => g.node(name);
26864
26927
  gEdge = (g, v, w) => g.edge(v, w);
@@ -27941,7 +28004,7 @@ function layoutGraph(graph, options) {
27941
28004
  if (allNodes.length === 0) {
27942
28005
  return { nodes: [], edges: [], groups: [], width: 0, height: 0 };
27943
28006
  }
27944
- const g = new import_dagre6.default.graphlib.Graph({ compound: true });
28007
+ const g = new import_dagre5.default.graphlib.Graph({ compound: true });
27945
28008
  g.setGraph({
27946
28009
  rankdir: graph.direction,
27947
28010
  nodesep: 50,
@@ -27977,7 +28040,7 @@ function layoutGraph(graph, options) {
27977
28040
  label: edge.label ?? ""
27978
28041
  });
27979
28042
  }
27980
- import_dagre6.default.layout(g);
28043
+ import_dagre5.default.layout(g);
27981
28044
  const collapsedGroupIds = collapsedChildCounts ? new Set(collapsedChildCounts.keys()) : /* @__PURE__ */ new Set();
27982
28045
  const layoutNodes = allNodes.map((node) => {
27983
28046
  const pos = g.node(node.id);
@@ -28094,11 +28157,11 @@ function layoutGraph(graph, options) {
28094
28157
  height: totalHeight
28095
28158
  };
28096
28159
  }
28097
- var import_dagre6, GROUP_PADDING;
28160
+ var import_dagre5, GROUP_PADDING;
28098
28161
  var init_layout9 = __esm({
28099
28162
  "src/graph/layout.ts"() {
28100
28163
  "use strict";
28101
- import_dagre6 = __toESM(require("@dagrejs/dagre"), 1);
28164
+ import_dagre5 = __toESM(require("@dagrejs/dagre"), 1);
28102
28165
  GROUP_PADDING = 20;
28103
28166
  }
28104
28167
  });
@@ -28410,7 +28473,7 @@ function renderFlowchart(container, graph, layout, palette, isDark, onClickItem,
28410
28473
  endTerminalIds.add(node.id);
28411
28474
  }
28412
28475
  }
28413
- const colorOff = graph.options?.color === "off";
28476
+ const colorOff = graph.options?.["color"] === "off";
28414
28477
  const solid = graph.options?.["solid-fill"] === "on";
28415
28478
  for (const node of layout.nodes) {
28416
28479
  const nodeG = contentG.append("g").attr("transform", `translate(${node.x}, ${node.y})`).attr("class", "fc-node").attr("data-line-number", String(node.lineNumber)).attr("data-node-id", node.id);
@@ -29643,7 +29706,7 @@ function layoutInfra(computed, expandedNodeIds, collapsedNodes) {
29643
29706
  };
29644
29707
  }
29645
29708
  const isLR = computed.direction !== "TB";
29646
- const g = new import_dagre7.default.graphlib.Graph();
29709
+ const g = new import_dagre6.default.graphlib.Graph();
29647
29710
  g.setGraph({
29648
29711
  rankdir: computed.direction === "TB" ? "TB" : "LR",
29649
29712
  nodesep: isLR ? 70 : 60,
@@ -29694,7 +29757,7 @@ function layoutInfra(computed, expandedNodeIds, collapsedNodes) {
29694
29757
  g.setEdge(edge.sourceId, edge.targetId, { label: edge.label });
29695
29758
  }
29696
29759
  }
29697
- import_dagre7.default.layout(g);
29760
+ import_dagre6.default.layout(g);
29698
29761
  const layoutNodes = computed.nodes.map((node) => {
29699
29762
  const pos = g.node(node.id);
29700
29763
  return {
@@ -29856,11 +29919,11 @@ function layoutInfra(computed, expandedNodeIds, collapsedNodes) {
29856
29919
  height: totalHeight
29857
29920
  };
29858
29921
  }
29859
- var import_dagre7, MIN_NODE_WIDTH2, NODE_HEADER_HEIGHT, META_LINE_HEIGHT7, NODE_SEPARATOR_GAP, NODE_PAD_BOTTOM, ROLE_DOT_ROW, COLLAPSE_BAR_HEIGHT5, CHAR_WIDTH7, META_CHAR_WIDTH3, PADDING_X3, GROUP_PADDING2, GROUP_HEADER_HEIGHT, EDGE_MARGIN, DISPLAY_KEYS, DISPLAY_NAMES, GROUP_GAP;
29922
+ var import_dagre6, MIN_NODE_WIDTH2, NODE_HEADER_HEIGHT, META_LINE_HEIGHT7, NODE_SEPARATOR_GAP, NODE_PAD_BOTTOM, ROLE_DOT_ROW, COLLAPSE_BAR_HEIGHT5, CHAR_WIDTH7, META_CHAR_WIDTH3, PADDING_X3, GROUP_PADDING2, GROUP_HEADER_HEIGHT, EDGE_MARGIN, DISPLAY_KEYS, DISPLAY_NAMES, GROUP_GAP;
29860
29923
  var init_layout10 = __esm({
29861
29924
  "src/infra/layout.ts"() {
29862
29925
  "use strict";
29863
- import_dagre7 = __toESM(require("@dagrejs/dagre"), 1);
29926
+ import_dagre6 = __toESM(require("@dagrejs/dagre"), 1);
29864
29927
  MIN_NODE_WIDTH2 = 140;
29865
29928
  NODE_HEADER_HEIGHT = 28;
29866
29929
  META_LINE_HEIGHT7 = 14;
@@ -30602,7 +30665,7 @@ function renderGroups(svg, groups, palette, _isDark) {
30602
30665
  }
30603
30666
  }
30604
30667
  }
30605
- function renderEdgePaths(svg, edges, nodes, groups, palette, isDark, animate, direction, speedMultiplier = 1) {
30668
+ function renderEdgePaths(svg, edges, nodes, groups, palette, _isDark, animate, direction, speedMultiplier = 1) {
30606
30669
  const nodeMap = new Map(nodes.map((n) => [n.id, n]));
30607
30670
  const maxRps = Math.max(...edges.map((e) => e.computedRps), 1);
30608
30671
  const { srcPts, tgtPts } = computePortPts(edges, nodeMap, direction);
@@ -30643,7 +30706,7 @@ function renderEdgePaths(svg, edges, nodes, groups, palette, isDark, animate, di
30643
30706
  }
30644
30707
  }
30645
30708
  }
30646
- function renderEdgeLabels(svg, edges, nodes, groups, palette, isDark, animate, direction) {
30709
+ function renderEdgeLabels(svg, edges, nodes, groups, palette, _isDark, animate, direction) {
30647
30710
  const nodeMap = new Map(nodes.map((n) => [n.id, n]));
30648
30711
  const { srcPts, tgtPts } = computePortPts(edges, nodeMap, direction);
30649
30712
  for (const edge of edges) {
@@ -31384,7 +31447,7 @@ function sampleBetaPert(o, m, p, rng) {
31384
31447
  const beta = 1 + 4 * (p - m) / range;
31385
31448
  return o + sampleBeta(alpha, beta, rng) * range;
31386
31449
  }
31387
- function simulate(resolved, expanded, predecessors, successors, topo, terminals, poisoned, opts) {
31450
+ function simulate(resolved, expanded, _predecessors, _successors, topo, terminals, poisoned, opts) {
31388
31451
  const rng = mulberry32(opts.seed);
31389
31452
  const expById = /* @__PURE__ */ new Map();
31390
31453
  for (const e of expanded) expById.set(e.id, e);
@@ -32504,7 +32567,7 @@ function relayoutPert(resolved, overrides, collapsedGroupIds = /* @__PURE__ */ n
32504
32567
  }
32505
32568
  }
32506
32569
  const dagreId = (id) => memberToGroup.get(id) ?? id;
32507
- const g = new import_dagre8.default.graphlib.Graph();
32570
+ const g = new import_dagre7.default.graphlib.Graph();
32508
32571
  g.setGraph({
32509
32572
  rankdir: resolved.options.direction,
32510
32573
  nodesep: 50,
@@ -32543,7 +32606,7 @@ function relayoutPert(resolved, overrides, collapsedGroupIds = /* @__PURE__ */ n
32543
32606
  seenEdges.add(k);
32544
32607
  g.setEdge(src, tgt, {});
32545
32608
  }
32546
- import_dagre8.default.layout(g);
32609
+ import_dagre7.default.layout(g);
32547
32610
  const swimApplied = applySwimLanes(
32548
32611
  g,
32549
32612
  resolved,
@@ -32663,7 +32726,7 @@ function relayoutPert(resolved, overrides, collapsedGroupIds = /* @__PURE__ */ n
32663
32726
  height: totalH + DIAGRAM_PADDING10
32664
32727
  };
32665
32728
  }
32666
- function applySwimLanes(g, resolved, memberToGroup, collapsedGroupIds) {
32729
+ function applySwimLanes(g, resolved, _memberToGroup, collapsedGroupIds) {
32667
32730
  const expanded = resolved.groups.filter(
32668
32731
  (rg) => !collapsedGroupIds.has(rg.group.id)
32669
32732
  );
@@ -32889,7 +32952,7 @@ function reduceCrossings2(g, direction) {
32889
32952
  buckets.get(key).push(id);
32890
32953
  }
32891
32954
  const edges = g.edges().map((e) => ({ v: e.v, w: e.w }));
32892
- const countCrossings = () => {
32955
+ const countCrossings2 = () => {
32893
32956
  let total = 0;
32894
32957
  for (let i = 0; i < edges.length; i++) {
32895
32958
  const a = edges[i];
@@ -32902,13 +32965,13 @@ function reduceCrossings2(g, direction) {
32902
32965
  const b1 = g.node(b.v);
32903
32966
  const b2 = g.node(b.w);
32904
32967
  if (!b1 || !b2) continue;
32905
- if (segmentsCross(a1, a2, b1, b2)) total++;
32968
+ if (segmentsCross2(a1, a2, b1, b2)) total++;
32906
32969
  }
32907
32970
  }
32908
32971
  return total;
32909
32972
  };
32910
32973
  const MAX_ITER = 8;
32911
- let baseline = countCrossings();
32974
+ let baseline = countCrossings2();
32912
32975
  if (baseline === 0) return;
32913
32976
  for (let iter = 0; iter < MAX_ITER; iter++) {
32914
32977
  let improved = false;
@@ -32926,7 +32989,7 @@ function reduceCrossings2(g, direction) {
32926
32989
  const bv = bn[slotAxis];
32927
32990
  an[slotAxis] = bv;
32928
32991
  bn[slotAxis] = av;
32929
- const after = countCrossings();
32992
+ const after = countCrossings2();
32930
32993
  if (after < baseline) {
32931
32994
  baseline = after;
32932
32995
  improved = true;
@@ -32947,7 +33010,7 @@ function reduceCrossings2(g, direction) {
32947
33010
  data.points = smoothEdge(src, tgt, direction);
32948
33011
  }
32949
33012
  }
32950
- function segmentsCross(a1, a2, b1, b2) {
33013
+ function segmentsCross2(a1, a2, b1, b2) {
32951
33014
  const ccw = (p, q, r) => (q.x - p.x) * (r.y - p.y) - (q.y - p.y) * (r.x - p.x);
32952
33015
  const d1 = ccw(b1, b2, a1);
32953
33016
  const d2 = ccw(b1, b2, a2);
@@ -32955,11 +33018,11 @@ function segmentsCross(a1, a2, b1, b2) {
32955
33018
  const d4 = ccw(a1, a2, b2);
32956
33019
  return (d1 > 0 && d2 < 0 || d1 < 0 && d2 > 0) && (d32 > 0 && d4 < 0 || d32 < 0 && d4 > 0);
32957
33020
  }
32958
- var import_dagre8, DEFAULT_NODE_HEIGHT, MILESTONE_NODE_HEIGHT, COLLAPSED_GROUP_HEIGHT, DIAGRAM_PADDING10, GROUP_PADDING3, GROUP_TOP_PADDING, SWIMLANE_SLOT_SEP, SWIMLANE_GAP, NODE_CELL_FONT_SIZE, NODE_NAME_FONT_SIZE, CELL_CHAR_WIDTH_RATIO, CELL_PAD_X, NAME_PAD_X, NAME_PIN_WIDTH, MIN_CELL_WIDTH, MIN_NODE_WIDTH3, MAX_NODE_WIDTH2, MIN_MILESTONE_WIDTH, MAX_MILESTONE_WIDTH;
33021
+ var import_dagre7, DEFAULT_NODE_HEIGHT, MILESTONE_NODE_HEIGHT, COLLAPSED_GROUP_HEIGHT, DIAGRAM_PADDING10, GROUP_PADDING3, GROUP_TOP_PADDING, SWIMLANE_SLOT_SEP, SWIMLANE_GAP, NODE_CELL_FONT_SIZE, NODE_NAME_FONT_SIZE, CELL_CHAR_WIDTH_RATIO, CELL_PAD_X, NAME_PAD_X, NAME_PIN_WIDTH, MIN_CELL_WIDTH, MIN_NODE_WIDTH3, MAX_NODE_WIDTH2, MIN_MILESTONE_WIDTH, MAX_MILESTONE_WIDTH;
32959
33022
  var init_layout11 = __esm({
32960
33023
  "src/pert/layout.ts"() {
32961
33024
  "use strict";
32962
- import_dagre8 = __toESM(require("@dagrejs/dagre"), 1);
33025
+ import_dagre7 = __toESM(require("@dagrejs/dagre"), 1);
32963
33026
  init_internal();
32964
33027
  DEFAULT_NODE_HEIGHT = 90;
32965
33028
  MILESTONE_NODE_HEIGHT = DEFAULT_NODE_HEIGHT;
@@ -34956,12 +35019,6 @@ function calculateSchedule(parsed) {
34956
35019
  const warn2 = (line12, message) => {
34957
35020
  diagnostics.push(makeDgmoError(line12, message, "warning"));
34958
35021
  };
34959
- const _fail = (line12, message) => {
34960
- const diag = makeDgmoError(line12, message);
34961
- diagnostics.push(diag);
34962
- result.error = formatDgmoError(diag);
34963
- return result;
34964
- };
34965
35022
  const holidaySet = buildHolidaySet(parsed.holidays);
34966
35023
  let projectStart;
34967
35024
  if (parsed.options.start) {
@@ -34986,7 +35043,6 @@ function calculateSchedule(parsed) {
34986
35043
  }
34987
35044
  buildImplicitDeps(parsed.nodes, taskMap);
34988
35045
  for (const task of allTasks2) {
34989
- const _node = taskMap.get(task.id);
34990
35046
  for (const dep of task.dependencies) {
34991
35047
  const resolved = resolveTaskName(dep.targetName, allTasks2);
34992
35048
  if (isResolverError(resolved)) {
@@ -36525,7 +36581,7 @@ function buildControlsToggles(hasCriticalPath, criticalPathActive, hasDependenci
36525
36581
  }
36526
36582
  return toggles;
36527
36583
  }
36528
- function renderTagLegend(svg, chartG, tagGroups, activeGroupName, chartLeftMargin, chartInnerWidth, legendY, palette, isDark, hasCriticalPath, criticalPathActive, optionLineNumbers, onToggle, onToggleControlsExpand, currentSwimlaneGroup, onSwimlaneChange, legendViewMode, resolvedTasks, controlsExpanded = false, hasDependencies = false, dependenciesActive = false, onControlsToggle) {
36584
+ function renderTagLegend(svg, chartG, tagGroups, activeGroupName, chartLeftMargin, chartInnerWidth, legendY, palette, isDark, hasCriticalPath, criticalPathActive, _optionLineNumbers, onToggle, onToggleControlsExpand, currentSwimlaneGroup, onSwimlaneChange, legendViewMode, resolvedTasks, controlsExpanded = false, hasDependencies = false, dependenciesActive = false, onControlsToggle) {
36529
36585
  let visibleGroups;
36530
36586
  if (activeGroupName) {
36531
36587
  const activeGroup = tagGroups.filter(
@@ -37488,7 +37544,7 @@ function resolveTaskColor(rt, activeTagGroup, resolved, seriesColors2, palette)
37488
37544
  }
37489
37545
  return palette.accent || seriesColors2[0] || "#4a90d9";
37490
37546
  }
37491
- function renderTimeScaleHorizontal(g, scale, innerWidth, innerHeight, textColor) {
37547
+ function renderTimeScaleHorizontal(g, scale, _innerWidth, innerHeight, textColor) {
37492
37548
  const [domainMin, domainMax] = scale.domain();
37493
37549
  const ticks = computeTimeTicks(domainMin, domainMax, scale);
37494
37550
  if (ticks.length < 2) return;
@@ -37735,7 +37791,7 @@ function renderState(container, graph, layout, palette, isDark, onClickItem, exp
37735
37791
  for (const group of layout.groups) {
37736
37792
  if (group.collapsed) collapsedGroupIds.add(group.id);
37737
37793
  }
37738
- const colorOff = graph.options?.color === "off";
37794
+ const colorOff = graph.options?.["color"] === "off";
37739
37795
  const solid = graph.options?.["solid-fill"] === "on";
37740
37796
  for (const node of layout.nodes) {
37741
37797
  const isCollapsedGroup = collapsedGroupIds.has(node.id);
@@ -38135,7 +38191,7 @@ function renderQuadrantFocus(container, parsed, quadrantPosition, palette, isDar
38135
38191
  }
38136
38192
  }
38137
38193
  }
38138
- function renderQuarterCircle(svg, parsed, quadrant, qColor, palette, isDark, width, height, mutedColor, tooltip, rootContainer, onClickItem) {
38194
+ function renderQuarterCircle(svg, parsed, quadrant, qColor, palette, isDark, width, height, mutedColor, _tooltip, rootContainer, onClickItem) {
38139
38195
  const padding = 8;
38140
38196
  const size = Math.min(width - padding, height - padding);
38141
38197
  const maxRadius = size * 0.95;
@@ -39005,7 +39061,7 @@ function estimateListingHeight(parsed) {
39005
39061
  );
39006
39062
  return LISTING_LINE_HEIGHT * (maxBlipsInQuadrant + 1) + LISTING_LINE_HEIGHT + LISTING_TOP_MARGIN;
39007
39063
  }
39008
- function createBlipPopover(container, palette, isDark) {
39064
+ function createBlipPopover(container, _palette, isDark) {
39009
39065
  container.style.position = "relative";
39010
39066
  const existing = container.querySelector(
39011
39067
  "[data-blip-popover]"
@@ -40873,7 +40929,7 @@ function computeEdgeLabelPosition(midAngle, radius, cx, cy, lineCount, maxCharLe
40873
40929
  labelAngle: best.labelAngle
40874
40930
  };
40875
40931
  }
40876
- function fitToCanvas(nodes, edges, parsed, cx, cy, radius, width, height, _isClockwise) {
40932
+ function fitToCanvas(nodes, edges, parsed, _cx, _cy, radius, width, height, _isClockwise) {
40877
40933
  const PADDING3 = 30;
40878
40934
  let contentMinX = Infinity, contentMaxX = -Infinity;
40879
40935
  let contentMinY = Infinity, contentMaxY = -Infinity;
@@ -42382,7 +42438,7 @@ function renderPhaseBar(svg, phase, x, y, width, palette, collapsed, autoColor,
42382
42438
  });
42383
42439
  }
42384
42440
  }
42385
- function renderTaskRow(svg, task, parsed, x, y, labelW, roleX, roleColW, palette, surfaceBg, solid, taskDiagnostics, hasAnyDiagnostic, rowContent, onClickLine, _onMarkerDragStart) {
42441
+ function renderTaskRow(svg, task, parsed, x, y, labelW, roleX, roleColW, palette, surfaceBg, solid, taskDiagnostics, _hasAnyDiagnostic, rowContent, onClickLine, _onMarkerDragStart) {
42386
42442
  const rowG = svg.append("g").attr("class", "raci-task-row").attr("data-task-id", task.id).attr("data-line-number", String(task.lineNumber));
42387
42443
  const labelX = x + 8;
42388
42444
  const labelMaxW = labelW - 16;
@@ -43188,7 +43244,6 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
43188
43244
  const messages = collapsed ? collapsed.messages : parsed.messages;
43189
43245
  const elements = collapsed ? collapsed.elements : parsed.elements;
43190
43246
  const groups = collapsed ? collapsed.groups : parsed.groups;
43191
- const collapsedGroupIds = collapsed?.collapsedGroupIds ?? /* @__PURE__ */ new Map();
43192
43247
  const collapsedSections = options?.collapsedSections;
43193
43248
  const sourceParticipants = collapsed ? collapsed.participants : parsed.participants;
43194
43249
  const participants = applyPositionOverrides(
@@ -43216,7 +43271,7 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
43216
43271
  return Math.min(NOTE_MAX_W, laneMax);
43217
43272
  };
43218
43273
  const charsForWidth = (maxW) => Math.floor((maxW - NOTE_PAD_H * 2 - NOTE_FOLD) / NOTE_CHAR_W);
43219
- const activationsOff = parsedOptions.activations?.toLowerCase() === "off";
43274
+ const activationsOff = parsedOptions["activations"]?.toLowerCase() === "off";
43220
43275
  const activeTagGroup = resolveActiveTagGroup(
43221
43276
  parsed.tagGroups,
43222
43277
  parsedOptions["active-tag"],
@@ -46168,7 +46223,7 @@ function renderTimelineGroupLegend(g, groups, groupColorMap, textColor, palette,
46168
46223
  legendX += pillW + GAP;
46169
46224
  }
46170
46225
  }
46171
- function renderTimeline(container, parsed, palette, isDark, onClickItem, exportDims, activeTagGroup, swimlaneTagGroup, onTagStateChange, viewMode) {
46226
+ function setupTimeline(container, parsed, palette, isDark, exportDims, activeTagGroup, swimlaneTagGroup) {
46172
46227
  d3Selection22.select(container).selectAll(":not([data-d3-tooltip])").remove();
46173
46228
  const solid = parsed.solidFill === true;
46174
46229
  const {
@@ -46177,19 +46232,17 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
46177
46232
  timelineEras,
46178
46233
  timelineMarkers,
46179
46234
  timelineSort,
46180
- timelineScale,
46181
- timelineSwimlanes,
46182
46235
  orientation
46183
46236
  } = parsed;
46184
- const title = parsed.noTitle ? null : parsed.title;
46185
- if (timelineEvents.length === 0) return;
46186
- if (swimlaneTagGroup == null && timelineSort === "tag" && parsed.timelineDefaultSwimlaneTG) {
46187
- swimlaneTagGroup = parsed.timelineDefaultSwimlaneTG;
46237
+ if (timelineEvents.length === 0) return null;
46238
+ let resolvedSwimlaneTG = swimlaneTagGroup ?? null;
46239
+ if (resolvedSwimlaneTG == null && timelineSort === "tag" && parsed.timelineDefaultSwimlaneTG) {
46240
+ resolvedSwimlaneTG = parsed.timelineDefaultSwimlaneTG;
46188
46241
  }
46189
46242
  const tooltip = createTooltip2(container, palette, isDark);
46190
46243
  const width = exportDims?.width ?? container.clientWidth;
46191
46244
  const height = exportDims?.height ?? container.clientHeight;
46192
- if (width <= 0 || height <= 0) return;
46245
+ if (width <= 0 || height <= 0) return null;
46193
46246
  const isVertical = orientation === "vertical";
46194
46247
  const textColor = palette.text;
46195
46248
  const mutedColor = palette.border;
@@ -46201,8 +46254,8 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
46201
46254
  groupColorMap.set(grp.name, grp.color ?? colors[i % colors.length]);
46202
46255
  });
46203
46256
  let tagLanes = null;
46204
- if (swimlaneTagGroup) {
46205
- const tagKey = swimlaneTagGroup.toLowerCase();
46257
+ if (resolvedSwimlaneTG) {
46258
+ const tagKey = resolvedSwimlaneTG.toLowerCase();
46206
46259
  const tagGroup = parsed.timelineTagGroups.find(
46207
46260
  (g) => g.name.toLowerCase() === tagKey
46208
46261
  );
@@ -46233,7 +46286,7 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
46233
46286
  }
46234
46287
  }
46235
46288
  }
46236
- const effectiveColorTG = activeTagGroup ?? swimlaneTagGroup ?? null;
46289
+ const effectiveColorTG = activeTagGroup ?? resolvedSwimlaneTG ?? null;
46237
46290
  function eventColor(ev) {
46238
46291
  if (effectiveColorTG) {
46239
46292
  const tagColor = resolveTagColor(
@@ -46289,6 +46342,30 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
46289
46342
  }
46290
46343
  }
46291
46344
  const datePadding = (maxDate - minDate) * 0.05 || 0.5;
46345
+ const tagLegendReserve = parsed.timelineTagGroups.length > 0 ? 36 : 0;
46346
+ return {
46347
+ width,
46348
+ height,
46349
+ isVertical,
46350
+ tooltip,
46351
+ solid,
46352
+ textColor,
46353
+ mutedColor,
46354
+ bgColor,
46355
+ bg,
46356
+ swimlaneTagGroup: resolvedSwimlaneTG,
46357
+ groupColorMap,
46358
+ tagLanes,
46359
+ eventColor,
46360
+ minDate,
46361
+ maxDate,
46362
+ datePadding,
46363
+ earliestStartDateStr,
46364
+ latestEndDateStr,
46365
+ tagLegendReserve
46366
+ };
46367
+ }
46368
+ function makeTimelineHoverHelpers() {
46292
46369
  const FADE_OPACITY3 = 0.1;
46293
46370
  function fadeToGroup(g, groupName) {
46294
46371
  g.selectAll(".tl-event").each(function() {
@@ -46388,337 +46465,683 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
46388
46465
  evG.attr(`data-tag-${key}`, value.toLowerCase());
46389
46466
  }
46390
46467
  }
46391
- const tagLegendReserve = parsed.timelineTagGroups.length > 0 ? 36 : 0;
46392
- if (isVertical) {
46393
- const useGroupedVertical = tagLanes != null || timelineSort === "group" && timelineGroups.length > 0;
46394
- if (useGroupedVertical) {
46395
- let laneNames;
46396
- let laneEventsByName;
46397
- if (tagLanes) {
46398
- laneNames = tagLanes.map((l) => l.name);
46399
- laneEventsByName = new Map(tagLanes.map((l) => [l.name, l.events]));
46400
- } else {
46401
- const groupNames = timelineGroups.map((gr) => gr.name);
46402
- const ungroupedEvents = timelineEvents.filter(
46403
- (ev) => ev.group === null || !groupNames.includes(ev.group)
46404
- );
46405
- laneNames = ungroupedEvents.length > 0 ? [...groupNames, "(Other)"] : groupNames;
46406
- laneEventsByName = new Map(
46407
- laneNames.map((name) => [
46408
- name,
46409
- timelineEvents.filter(
46410
- (ev) => name === "(Other)" ? ev.group === null || !groupNames.includes(ev.group) : ev.group === name
46411
- )
46412
- ])
46413
- );
46468
+ return {
46469
+ FADE_OPACITY: FADE_OPACITY3,
46470
+ fadeToGroup,
46471
+ fadeToEra,
46472
+ fadeToMarker,
46473
+ fadeReset,
46474
+ fadeToTagValue,
46475
+ setTagAttrs
46476
+ };
46477
+ }
46478
+ function renderTimelineTagLegendOverlay(container, parsed, palette, isDark, setup, hovers, onClickItem, exportDims, swimlaneTagGroup, activeTagGroup, onTagStateChange, viewMode) {
46479
+ if (parsed.timelineTagGroups.length === 0) return;
46480
+ const { width, textColor, groupColorMap, solid } = setup;
46481
+ const { FADE_OPACITY: FADE_OPACITY3, fadeReset, fadeToTagValue } = hovers;
46482
+ const title = parsed.noTitle ? null : parsed.title;
46483
+ const { timelineEvents } = parsed;
46484
+ const LG_HEIGHT = LEGEND_HEIGHT;
46485
+ const LG_PILL_PAD = LEGEND_PILL_PAD;
46486
+ const LG_PILL_FONT_SIZE = LEGEND_PILL_FONT_SIZE;
46487
+ const LG_CAPSULE_PAD = LEGEND_CAPSULE_PAD;
46488
+ const LG_DOT_R = LEGEND_DOT_R;
46489
+ const LG_ENTRY_FONT_SIZE = LEGEND_ENTRY_FONT_SIZE;
46490
+ const LG_ENTRY_DOT_GAP = LEGEND_ENTRY_DOT_GAP;
46491
+ const LG_ENTRY_TRAIL = LEGEND_ENTRY_TRAIL;
46492
+ const LG_ICON_W = 20;
46493
+ const mainSvg = d3Selection22.select(container).select("svg");
46494
+ const mainG = mainSvg.select("g");
46495
+ if (!mainSvg.empty() && !mainG.empty()) {
46496
+ let drawSwimlaneIcon4 = function(parent, x, y, isSwimActive) {
46497
+ const iconG = parent.append("g").attr("class", "tl-swimlane-icon").attr("transform", `translate(${x}, ${y})`).style("cursor", "pointer");
46498
+ const barColor = isSwimActive ? palette.primary : palette.textMuted;
46499
+ const barOpacity = isSwimActive ? 1 : 0.35;
46500
+ const bars = [
46501
+ { y: 0, w: 8 },
46502
+ { y: 4, w: 12 },
46503
+ { y: 8, w: 6 }
46504
+ ];
46505
+ for (const bar of bars) {
46506
+ iconG.append("rect").attr("x", 0).attr("y", bar.y).attr("width", bar.w).attr("height", 2).attr("rx", 1).attr("fill", barColor).attr("opacity", barOpacity);
46414
46507
  }
46415
- const laneCount = laneNames.length;
46416
- const scaleMargin = timelineScale ? 40 : 0;
46417
- const markerMargin = timelineMarkers.length > 0 ? 30 : 0;
46418
- const margin = {
46419
- top: 104 + markerMargin + tagLegendReserve,
46420
- right: 40 + scaleMargin,
46421
- bottom: 40,
46422
- left: 60 + scaleMargin
46423
- };
46424
- const innerWidth = width - margin.left - margin.right;
46425
- const innerHeight = height - margin.top - margin.bottom;
46426
- const laneWidth = innerWidth / laneCount;
46427
- const yScale = d3Scale2.scaleLinear().domain([minDate - datePadding, maxDate + datePadding]).range([0, innerHeight]);
46428
- const svg = d3Selection22.select(container).append("svg").attr("viewBox", `0 0 ${width} ${height}`).attr("width", exportDims ? width : "100%").attr("preserveAspectRatio", "xMidYMin meet").style("background", bgColor);
46429
- const g = svg.append("g").attr("transform", `translate(${margin.left},${margin.top})`);
46430
- renderChartTitle(
46431
- svg,
46432
- title,
46433
- parsed.titleLineNumber,
46434
- width,
46435
- textColor,
46436
- onClickItem
46437
- );
46438
- renderEras(
46439
- g,
46440
- timelineEras,
46441
- yScale,
46442
- true,
46443
- innerWidth,
46444
- innerHeight,
46445
- (s, e) => fadeToEra(g, s, e),
46446
- () => fadeReset(g),
46447
- timelineScale,
46448
- tooltip,
46449
- palette
46450
- );
46451
- renderMarkers(
46452
- g,
46453
- timelineMarkers,
46454
- yScale,
46455
- true,
46456
- innerWidth,
46457
- innerHeight,
46458
- (d) => fadeToMarker(g, d),
46459
- () => fadeReset(g),
46460
- timelineScale,
46461
- tooltip,
46462
- palette
46508
+ return iconG;
46509
+ }, relayout2 = function() {
46510
+ renderTimeline(
46511
+ container,
46512
+ parsed,
46513
+ palette,
46514
+ isDark,
46515
+ onClickItem,
46516
+ exportDims,
46517
+ currentActiveGroup,
46518
+ currentSwimlaneGroup,
46519
+ onTagStateChange,
46520
+ viewMode
46463
46521
  );
46464
- if (timelineScale) {
46465
- renderTimeScale(
46466
- g,
46467
- yScale,
46468
- true,
46469
- innerWidth,
46470
- innerHeight,
46471
- textColor,
46472
- minDate,
46473
- maxDate,
46474
- formatBoundaryLabel(earliestStartDateStr, latestEndDateStr),
46475
- formatBoundaryLabel(latestEndDateStr, earliestStartDateStr)
46522
+ }, drawLegend2 = function() {
46523
+ mainSvg.selectAll(".tl-tag-legend-group").remove();
46524
+ mainSvg.selectAll(".tl-tag-legend-container").remove();
46525
+ const effectiveColorKey = (currentActiveGroup ?? currentSwimlaneGroup)?.toLowerCase() ?? null;
46526
+ const visibleGroups = viewMode ? legendGroups.filter(
46527
+ (lg) => effectiveColorKey != null && lg.group.name.toLowerCase() === effectiveColorKey
46528
+ ) : legendGroups;
46529
+ if (visibleGroups.length === 0) return;
46530
+ const legendContainer = mainSvg.append("g").attr("class", "tl-tag-legend-container");
46531
+ if (currentActiveGroup) {
46532
+ legendContainer.attr(
46533
+ "data-legend-active",
46534
+ currentActiveGroup.toLowerCase()
46476
46535
  );
46477
46536
  }
46478
- if (timelineSwimlanes || tagLanes) {
46479
- laneNames.forEach((laneName, laneIdx) => {
46480
- const laneX = laneIdx * laneWidth;
46481
- const fillColor = laneIdx % 2 === 0 ? textColor : "transparent";
46482
- g.append("rect").attr("class", "tl-swimlane").attr("data-group", laneName).attr("x", laneX).attr("y", 0).attr("width", laneWidth).attr("height", innerHeight).attr("fill", fillColor).attr("opacity", 0.06);
46483
- });
46484
- }
46485
- laneNames.forEach((laneName, laneIdx) => {
46486
- const laneX = laneIdx * laneWidth;
46487
- const laneColor = groupColorMap.get(laneName) ?? textColor;
46488
- const laneCenter = laneX + laneWidth / 2;
46489
- const headerG = g.append("g").attr("class", "tl-lane-header").attr("data-group", laneName).style("cursor", "pointer").on("mouseenter", () => fadeToGroup(g, laneName)).on("mouseleave", () => fadeReset(g));
46490
- headerG.append("text").attr("x", laneCenter).attr("y", -15).attr("text-anchor", "middle").attr("fill", laneColor).attr("font-size", "12px").attr("font-weight", "600").text(laneName);
46491
- g.append("line").attr("x1", laneCenter).attr("y1", 0).attr("x2", laneCenter).attr("y2", innerHeight).attr("stroke", mutedColor).attr("stroke-width", 1).attr("stroke-dasharray", "4,4");
46492
- const laneEvents = laneEventsByName.get(laneName) ?? [];
46493
- for (const ev of laneEvents) {
46494
- const y = yScale(parseTimelineDate(ev.date));
46495
- const evG = g.append("g").attr("class", "tl-event").attr("data-group", laneName).attr("data-line-number", String(ev.lineNumber)).attr("data-date", String(parseTimelineDate(ev.date))).attr(
46496
- "data-end-date",
46497
- ev.endDate ? String(parseTimelineDate(ev.endDate)) : null
46498
- ).style("cursor", "pointer").on("mouseenter", function(event) {
46499
- fadeToGroup(g, laneName);
46500
- showTooltip(tooltip, buildEventTooltipHtml(ev), event);
46501
- }).on("mouseleave", function() {
46502
- fadeReset(g);
46503
- hideTooltip(tooltip);
46504
- }).on("mousemove", function(event) {
46505
- showTooltip(tooltip, buildEventTooltipHtml(ev), event);
46506
- }).on("click", () => {
46507
- if (onClickItem && ev.lineNumber) onClickItem(ev.lineNumber);
46508
- });
46509
- setTagAttrs(evG, ev);
46510
- const evColor = eventColor(ev);
46511
- if (ev.endDate) {
46512
- const y2 = yScale(parseTimelineDate(ev.endDate));
46513
- const rectH = Math.max(y2 - y, 4);
46514
- let fill2 = shapeFill(palette, evColor, isDark, { solid });
46515
- let stroke2 = evColor;
46516
- if (ev.uncertain) {
46517
- const gradientId = `uncertain-vg-${ev.lineNumber}`;
46518
- const strokeGradientId = `uncertain-vg-s-${ev.lineNumber}`;
46519
- const defs = svg.select("defs").node() || svg.append("defs").node();
46520
- const defsEl = d3Selection22.select(defs);
46521
- defsEl.append("linearGradient").attr("id", gradientId).attr("x1", "0%").attr("y1", "0%").attr("x2", "0%").attr("y2", "100%").selectAll("stop").data([
46522
- { offset: "0%", opacity: 1 },
46523
- { offset: "80%", opacity: 1 },
46524
- { offset: "100%", opacity: 0 }
46525
- ]).enter().append("stop").attr("offset", (d) => d.offset).attr("stop-color", mix(laneColor, bg, 30)).attr("stop-opacity", (d) => d.opacity);
46526
- defsEl.append("linearGradient").attr("id", strokeGradientId).attr("x1", "0%").attr("y1", "0%").attr("x2", "0%").attr("y2", "100%").selectAll("stop").data([
46527
- { offset: "0%", opacity: 1 },
46528
- { offset: "80%", opacity: 1 },
46529
- { offset: "100%", opacity: 0 }
46530
- ]).enter().append("stop").attr("offset", (d) => d.offset).attr("stop-color", evColor).attr("stop-opacity", (d) => d.opacity);
46531
- fill2 = `url(#${gradientId})`;
46532
- stroke2 = `url(#${strokeGradientId})`;
46533
- }
46534
- evG.append("rect").attr("x", laneCenter - 6).attr("y", y).attr("width", 12).attr("height", rectH).attr("rx", 4).attr("fill", fill2).attr("stroke", stroke2).attr("stroke-width", 2);
46535
- evG.append("text").attr("x", laneCenter + 14).attr("y", y + rectH / 2).attr("dy", "0.35em").attr("fill", textColor).attr("font-size", "10px").text(ev.label);
46537
+ const iconAddon = viewMode ? 0 : LG_ICON_W;
46538
+ const centralGroups = visibleGroups.map((lg) => ({
46539
+ name: lg.group.name,
46540
+ entries: lg.group.entries.map((e) => ({
46541
+ value: e.value,
46542
+ color: e.color
46543
+ }))
46544
+ }));
46545
+ const centralActive = viewMode ? effectiveColorKey : currentActiveGroup;
46546
+ const centralConfig = {
46547
+ groups: centralGroups,
46548
+ position: { placement: "top-center", titleRelation: "below-title" },
46549
+ mode: "fixed",
46550
+ capsulePillAddonWidth: iconAddon
46551
+ };
46552
+ const centralState = { activeGroup: centralActive };
46553
+ const centralCallbacks = viewMode ? {} : {
46554
+ onGroupToggle: (groupName) => {
46555
+ currentActiveGroup = currentActiveGroup === groupName.toLowerCase() ? null : groupName.toLowerCase();
46556
+ drawLegend2();
46557
+ recolorEvents2();
46558
+ onTagStateChange?.(currentActiveGroup, currentSwimlaneGroup);
46559
+ },
46560
+ onEntryHover: (groupName, entryValue) => {
46561
+ const tagKey = groupName.toLowerCase();
46562
+ if (entryValue) {
46563
+ const tagVal = entryValue.toLowerCase();
46564
+ fadeToTagValue(mainG, tagKey, tagVal);
46565
+ mainSvg.selectAll("[data-legend-entry]").each(function() {
46566
+ const el = d3Selection22.select(this);
46567
+ const ev = el.attr("data-legend-entry");
46568
+ const eg = el.attr("data-tag-group") ?? el.node()?.closest?.("[data-tag-group]")?.getAttribute("data-tag-group");
46569
+ el.attr(
46570
+ "opacity",
46571
+ eg === tagKey && ev === tagVal ? 1 : FADE_OPACITY3
46572
+ );
46573
+ });
46536
46574
  } else {
46537
- evG.append("circle").attr("cx", laneCenter).attr("cy", y).attr("r", 4).attr("fill", shapeFill(palette, evColor, isDark, { solid })).attr("stroke", evColor).attr("stroke-width", 2);
46538
- evG.append("text").attr("x", laneCenter + 10).attr("y", y).attr("dy", "0.35em").attr("fill", textColor).attr("font-size", "10px").text(ev.label);
46575
+ fadeReset(mainG);
46576
+ mainSvg.selectAll("[data-legend-entry]").attr("opacity", 1);
46577
+ }
46578
+ },
46579
+ onGroupRendered: (groupName, groupEl, isActive) => {
46580
+ const groupKey = groupName.toLowerCase();
46581
+ groupEl.attr("data-tag-group", groupKey);
46582
+ if (isActive && !viewMode) {
46583
+ const isSwimActive = currentSwimlaneGroup != null && currentSwimlaneGroup.toLowerCase() === groupKey;
46584
+ const pillWidth3 = measureLegendText(groupName, LG_PILL_FONT_SIZE) + LG_PILL_PAD;
46585
+ const pillXOff = LG_CAPSULE_PAD;
46586
+ const iconX = pillXOff + pillWidth3 + 5;
46587
+ const iconY = (LG_HEIGHT - 10) / 2;
46588
+ const iconEl = drawSwimlaneIcon4(
46589
+ groupEl,
46590
+ iconX,
46591
+ iconY,
46592
+ isSwimActive
46593
+ );
46594
+ iconEl.attr("data-swimlane-toggle", groupKey).on("click", (event) => {
46595
+ event.stopPropagation();
46596
+ currentSwimlaneGroup = currentSwimlaneGroup === groupKey ? null : groupKey;
46597
+ onTagStateChange?.(
46598
+ currentActiveGroup,
46599
+ currentSwimlaneGroup
46600
+ );
46601
+ relayout2();
46602
+ });
46539
46603
  }
46540
46604
  }
46541
- });
46542
- } else {
46543
- const scaleMargin = timelineScale ? 40 : 0;
46544
- const markerMargin = timelineMarkers.length > 0 ? 30 : 0;
46545
- const margin = {
46546
- top: 104 + markerMargin + tagLegendReserve,
46547
- right: 200,
46548
- bottom: 40,
46549
- left: 60 + scaleMargin
46550
46605
  };
46551
- const innerWidth = width - margin.left - margin.right;
46552
- const innerHeight = height - margin.top - margin.bottom;
46553
- const axisX = 20;
46554
- const yScale = d3Scale2.scaleLinear().domain([minDate - datePadding, maxDate + datePadding]).range([0, innerHeight]);
46555
- const sorted = timelineEvents.slice().sort((a, b) => parseTimelineDate(a.date) - parseTimelineDate(b.date));
46556
- const svg = d3Selection22.select(container).append("svg").attr("viewBox", `0 0 ${width} ${height}`).attr("width", exportDims ? width : "100%").attr("preserveAspectRatio", "xMidYMin meet").style("background", bgColor);
46557
- const g = svg.append("g").attr("transform", `translate(${margin.left},${margin.top})`);
46558
- renderChartTitle(
46559
- svg,
46560
- title,
46561
- parsed.titleLineNumber,
46562
- width,
46563
- textColor,
46564
- onClickItem
46565
- );
46566
- renderEras(
46567
- g,
46568
- timelineEras,
46569
- yScale,
46570
- true,
46571
- innerWidth,
46572
- innerHeight,
46573
- (s, e) => fadeToEra(g, s, e),
46574
- () => fadeReset(g),
46575
- timelineScale,
46576
- tooltip,
46577
- palette
46578
- );
46579
- renderMarkers(
46580
- g,
46581
- timelineMarkers,
46582
- yScale,
46583
- true,
46584
- innerWidth,
46585
- innerHeight,
46586
- (d) => fadeToMarker(g, d),
46587
- () => fadeReset(g),
46588
- timelineScale,
46589
- tooltip,
46590
- palette
46606
+ const legendInnerG = legendContainer.append("g").attr("transform", `translate(0, ${legendY})`);
46607
+ renderLegendD3(
46608
+ legendInnerG,
46609
+ centralConfig,
46610
+ centralState,
46611
+ palette,
46612
+ isDark,
46613
+ centralCallbacks,
46614
+ width
46591
46615
  );
46616
+ }, recolorEvents2 = function() {
46617
+ const colorTG = currentActiveGroup ?? swimlaneTagGroup ?? null;
46618
+ mainG.selectAll(".tl-event").each(function() {
46619
+ const el = d3Selection22.select(this);
46620
+ const lineNum = el.attr("data-line-number");
46621
+ const ev = lineNum ? eventByLine.get(lineNum) : void 0;
46622
+ if (!ev) return;
46623
+ let color;
46624
+ if (colorTG) {
46625
+ const tagColor = resolveTagColor(
46626
+ ev.metadata,
46627
+ parsed.timelineTagGroups,
46628
+ colorTG
46629
+ );
46630
+ color = tagColor ?? (ev.group && groupColorMap.has(ev.group) ? groupColorMap.get(ev.group) : textColor);
46631
+ } else {
46632
+ color = ev.group && groupColorMap.has(ev.group) ? groupColorMap.get(ev.group) : textColor;
46633
+ }
46634
+ el.selectAll("rect").attr("fill", shapeFill(palette, color, isDark, { solid })).attr("stroke", color);
46635
+ el.selectAll("circle:not(.tl-event-point-outline)").attr("fill", shapeFill(palette, color, isDark, { solid })).attr("stroke", color);
46636
+ });
46637
+ };
46638
+ var drawSwimlaneIcon3 = drawSwimlaneIcon4, relayout = relayout2, drawLegend = drawLegend2, recolorEvents = recolorEvents2;
46639
+ const legendY = title ? 50 : 10;
46640
+ const legendGroups = parsed.timelineTagGroups.map((g) => {
46641
+ const pillW = measureLegendText(g.name, LG_PILL_FONT_SIZE) + LG_PILL_PAD;
46642
+ const iconSpace = viewMode ? 8 : LG_ICON_W + 4;
46643
+ let entryX = LG_CAPSULE_PAD + pillW + iconSpace;
46644
+ for (const entry of g.entries) {
46645
+ const textX = entryX + LG_DOT_R * 2 + LG_ENTRY_DOT_GAP;
46646
+ entryX = textX + measureLegendText(entry.value, LG_ENTRY_FONT_SIZE) + LG_ENTRY_TRAIL;
46647
+ }
46648
+ return {
46649
+ group: g,
46650
+ minifiedWidth: pillW,
46651
+ expandedWidth: entryX + LG_CAPSULE_PAD
46652
+ };
46653
+ });
46654
+ let currentActiveGroup = activeTagGroup ?? null;
46655
+ let currentSwimlaneGroup = swimlaneTagGroup ?? null;
46656
+ const eventByLine = /* @__PURE__ */ new Map();
46657
+ for (const ev of timelineEvents) {
46658
+ eventByLine.set(String(ev.lineNumber), ev);
46659
+ }
46660
+ drawLegend2();
46661
+ }
46662
+ }
46663
+ function renderTimelineHorizontalTimeSort(container, parsed, palette, isDark, setup, hovers, onClickItem, _exportDims, _swimlaneTagGroup, _activeTagGroup, _onTagStateChange, _viewMode) {
46664
+ const {
46665
+ width,
46666
+ height,
46667
+ tooltip,
46668
+ solid,
46669
+ textColor,
46670
+ bgColor,
46671
+ bg,
46672
+ groupColorMap,
46673
+ eventColor,
46674
+ minDate,
46675
+ maxDate,
46676
+ datePadding,
46677
+ earliestStartDateStr,
46678
+ latestEndDateStr,
46679
+ tagLegendReserve
46680
+ } = setup;
46681
+ const { fadeToGroup, fadeToEra, fadeToMarker, fadeReset, setTagAttrs } = hovers;
46682
+ const {
46683
+ timelineEvents,
46684
+ timelineGroups,
46685
+ timelineEras,
46686
+ timelineMarkers,
46687
+ timelineScale
46688
+ } = parsed;
46689
+ const title = parsed.noTitle ? null : parsed.title;
46690
+ const BAR_H2 = 22;
46691
+ const sorted = timelineEvents.slice().sort((a, b) => parseTimelineDate(a.date) - parseTimelineDate(b.date));
46692
+ const scaleMargin = timelineScale ? 24 : 0;
46693
+ const ERA_ROW_H = 22;
46694
+ const MARKER_ROW_H = 22;
46695
+ const eraReserve = timelineEras.length > 0 ? ERA_ROW_H : 0;
46696
+ const markerReserve = timelineMarkers.length > 0 ? MARKER_ROW_H : 0;
46697
+ const topScaleH = timelineScale ? 40 : 0;
46698
+ const margin = {
46699
+ top: 104 + topScaleH + eraReserve + markerReserve + tagLegendReserve,
46700
+ right: 40,
46701
+ bottom: 40 + scaleMargin,
46702
+ left: 60
46703
+ };
46704
+ const markerLabelY = markerReserve ? -(topScaleH + MARKER_ROW_H / 2) : 0;
46705
+ const eraLabelY = eraReserve ? -(topScaleH + markerReserve + ERA_ROW_H / 2) : 0;
46706
+ const innerWidth = width - margin.left - margin.right;
46707
+ const innerHeight = height - margin.top - margin.bottom;
46708
+ const rowH = Math.min(28, innerHeight / sorted.length);
46709
+ const xScale = d3Scale2.scaleLinear().domain([minDate - datePadding, maxDate + datePadding]).range([0, innerWidth]);
46710
+ const svg = d3Selection22.select(container).append("svg").attr("width", width).attr("height", height).style("background", bgColor);
46711
+ const g = svg.append("g").attr("transform", `translate(${margin.left},${margin.top})`);
46712
+ renderChartTitle(
46713
+ svg,
46714
+ title,
46715
+ parsed.titleLineNumber,
46716
+ width,
46717
+ textColor,
46718
+ onClickItem
46719
+ );
46720
+ renderEras(
46721
+ g,
46722
+ timelineEras,
46723
+ xScale,
46724
+ false,
46725
+ innerWidth,
46726
+ innerHeight,
46727
+ (s, e) => fadeToEra(g, s, e),
46728
+ () => fadeReset(g),
46729
+ timelineScale,
46730
+ tooltip,
46731
+ palette,
46732
+ eraReserve ? eraLabelY : void 0
46733
+ );
46734
+ renderMarkers(
46735
+ g,
46736
+ timelineMarkers,
46737
+ xScale,
46738
+ false,
46739
+ innerWidth,
46740
+ innerHeight,
46741
+ (d) => fadeToMarker(g, d),
46742
+ () => fadeReset(g),
46743
+ timelineScale,
46744
+ tooltip,
46745
+ palette,
46746
+ markerReserve ? markerLabelY : void 0
46747
+ );
46748
+ if (timelineScale) {
46749
+ renderTimeScale(
46750
+ g,
46751
+ xScale,
46752
+ false,
46753
+ innerWidth,
46754
+ innerHeight,
46755
+ textColor,
46756
+ minDate,
46757
+ maxDate,
46758
+ formatBoundaryLabel(earliestStartDateStr, latestEndDateStr),
46759
+ formatBoundaryLabel(latestEndDateStr, earliestStartDateStr)
46760
+ );
46761
+ }
46762
+ if (timelineGroups.length > 0) {
46763
+ const legendY = timelineScale ? -75 : -55;
46764
+ renderTimelineGroupLegend(
46765
+ g,
46766
+ timelineGroups,
46767
+ groupColorMap,
46768
+ textColor,
46769
+ palette,
46770
+ isDark,
46771
+ legendY,
46772
+ (name) => fadeToGroup(g, name),
46773
+ () => fadeReset(g)
46774
+ );
46775
+ }
46776
+ sorted.forEach((ev, i) => {
46777
+ const y = i * rowH + rowH / 2;
46778
+ const x = xScale(parseTimelineDate(ev.date));
46779
+ const color = eventColor(ev);
46780
+ const evG = g.append("g").attr("class", "tl-event").attr("data-group", ev.group || "").attr("data-line-number", String(ev.lineNumber)).attr("data-date", String(parseTimelineDate(ev.date))).attr(
46781
+ "data-end-date",
46782
+ ev.endDate ? String(parseTimelineDate(ev.endDate)) : null
46783
+ ).style("cursor", "pointer").on("mouseenter", function(event) {
46784
+ if (ev.group && timelineGroups.length > 0) fadeToGroup(g, ev.group);
46592
46785
  if (timelineScale) {
46593
- renderTimeScale(
46786
+ showEventDatesOnScale(
46594
46787
  g,
46595
- yScale,
46596
- true,
46597
- innerWidth,
46788
+ xScale,
46789
+ ev.date,
46790
+ ev.endDate,
46598
46791
  innerHeight,
46599
- textColor,
46600
- minDate,
46601
- maxDate,
46602
- formatBoundaryLabel(earliestStartDateStr, latestEndDateStr),
46603
- formatBoundaryLabel(latestEndDateStr, earliestStartDateStr)
46792
+ color
46604
46793
  );
46794
+ } else {
46795
+ showTooltip(tooltip, buildEventTooltipHtml(ev), event);
46605
46796
  }
46606
- if (timelineGroups.length > 0) {
46607
- renderTimelineGroupLegend(
46608
- g,
46609
- timelineGroups,
46610
- groupColorMap,
46611
- textColor,
46612
- palette,
46613
- isDark,
46614
- -55,
46615
- (name) => fadeToGroup(g, name),
46616
- () => fadeReset(g)
46617
- );
46797
+ }).on("mouseleave", function() {
46798
+ fadeReset(g);
46799
+ if (timelineScale) {
46800
+ hideEventDatesOnScale(g);
46801
+ } else {
46802
+ hideTooltip(tooltip);
46618
46803
  }
46619
- 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");
46620
- for (const ev of sorted) {
46621
- const y = yScale(parseTimelineDate(ev.date));
46622
- const color = eventColor(ev);
46623
- const evG = g.append("g").attr("class", "tl-event").attr("data-group", ev.group || "").attr("data-line-number", String(ev.lineNumber)).attr("data-date", String(parseTimelineDate(ev.date))).attr(
46624
- "data-end-date",
46625
- ev.endDate ? String(parseTimelineDate(ev.endDate)) : null
46626
- ).style("cursor", "pointer").on("mouseenter", function(event) {
46627
- if (ev.group && timelineGroups.length > 0) fadeToGroup(g, ev.group);
46804
+ }).on("mousemove", function(event) {
46805
+ if (!timelineScale) {
46806
+ showTooltip(tooltip, buildEventTooltipHtml(ev), event);
46807
+ }
46808
+ }).on("click", () => {
46809
+ if (onClickItem && ev.lineNumber) onClickItem(ev.lineNumber);
46810
+ });
46811
+ setTagAttrs(evG, ev);
46812
+ if (ev.endDate) {
46813
+ const x2 = xScale(parseTimelineDate(ev.endDate));
46814
+ const rectW = Math.max(x2 - x, 4);
46815
+ const estLabelWidth = ev.label.length * 7 + 16;
46816
+ const labelFitsInside = rectW >= estLabelWidth;
46817
+ let fill2 = shapeFill(palette, color, isDark, { solid });
46818
+ let stroke2 = color;
46819
+ if (ev.uncertain) {
46820
+ const gradientId = `uncertain-ts-${ev.lineNumber}`;
46821
+ const strokeGradientId = `uncertain-ts-s-${ev.lineNumber}`;
46822
+ const defs = svg.select("defs").node() || svg.append("defs").node();
46823
+ const defsEl = d3Selection22.select(defs);
46824
+ defsEl.append("linearGradient").attr("id", gradientId).attr("x1", "0%").attr("y1", "0%").attr("x2", "100%").attr("y2", "0%").selectAll("stop").data([
46825
+ { offset: "0%", opacity: 1 },
46826
+ { offset: "80%", opacity: 1 },
46827
+ { offset: "100%", opacity: 0 }
46828
+ ]).enter().append("stop").attr("offset", (d) => d.offset).attr("stop-color", mix(color, bg, 30)).attr("stop-opacity", (d) => d.opacity);
46829
+ defsEl.append("linearGradient").attr("id", strokeGradientId).attr("x1", "0%").attr("y1", "0%").attr("x2", "100%").attr("y2", "0%").selectAll("stop").data([
46830
+ { offset: "0%", opacity: 1 },
46831
+ { offset: "80%", opacity: 1 },
46832
+ { offset: "100%", opacity: 0 }
46833
+ ]).enter().append("stop").attr("offset", (d) => d.offset).attr("stop-color", color).attr("stop-opacity", (d) => d.opacity);
46834
+ fill2 = `url(#${gradientId})`;
46835
+ stroke2 = `url(#${strokeGradientId})`;
46836
+ }
46837
+ 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);
46838
+ if (labelFitsInside) {
46839
+ 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);
46840
+ } else {
46841
+ const wouldFlipLeft = x + rectW > innerWidth * 0.6;
46842
+ const labelFitsLeft = x - 6 - estLabelWidth > 0;
46843
+ const flipLeft = wouldFlipLeft && labelFitsLeft;
46844
+ evG.append("text").attr("x", flipLeft ? x - 6 : x + rectW + 6).attr("y", y).attr("dy", "0.35em").attr("text-anchor", flipLeft ? "end" : "start").attr("fill", textColor).attr("font-size", "13px").text(ev.label);
46845
+ }
46846
+ } else {
46847
+ const estLabelWidth = ev.label.length * 7;
46848
+ const wouldFlipLeft = x > innerWidth * 0.6;
46849
+ const labelFitsLeft = x - 10 - estLabelWidth > 0;
46850
+ const flipLeft = wouldFlipLeft && labelFitsLeft;
46851
+ evG.append("circle").attr("cx", x).attr("cy", y).attr("r", 5).attr("fill", shapeFill(palette, color, isDark, { solid })).attr("stroke", color).attr("stroke-width", 2);
46852
+ evG.append("text").attr("x", flipLeft ? x - 10 : x + 10).attr("y", y).attr("dy", "0.35em").attr("text-anchor", flipLeft ? "end" : "start").attr("fill", textColor).attr("font-size", "12px").text(ev.label);
46853
+ }
46854
+ });
46855
+ }
46856
+ function renderTimelineHorizontalGrouped(container, parsed, palette, isDark, setup, hovers, onClickItem, _exportDims, _swimlaneTagGroup, _activeTagGroup, _onTagStateChange, _viewMode) {
46857
+ const {
46858
+ width,
46859
+ height,
46860
+ tooltip,
46861
+ solid,
46862
+ textColor,
46863
+ bgColor,
46864
+ bg,
46865
+ groupColorMap,
46866
+ tagLanes,
46867
+ eventColor,
46868
+ minDate,
46869
+ maxDate,
46870
+ datePadding,
46871
+ earliestStartDateStr,
46872
+ latestEndDateStr,
46873
+ tagLegendReserve
46874
+ } = setup;
46875
+ const { fadeToGroup, fadeToEra, fadeToMarker, fadeReset, setTagAttrs } = hovers;
46876
+ const {
46877
+ timelineEvents,
46878
+ timelineGroups,
46879
+ timelineEras,
46880
+ timelineMarkers,
46881
+ timelineScale,
46882
+ timelineSwimlanes
46883
+ } = parsed;
46884
+ const title = parsed.noTitle ? null : parsed.title;
46885
+ const BAR_H2 = 22;
46886
+ const GROUP_GAP3 = 12;
46887
+ let lanes;
46888
+ if (tagLanes) {
46889
+ lanes = tagLanes;
46890
+ } else {
46891
+ const groupNames = timelineGroups.map((gr) => gr.name);
46892
+ const ungroupedEvents = timelineEvents.filter(
46893
+ (ev) => ev.group === null || !groupNames.includes(ev.group)
46894
+ );
46895
+ const laneNames = ungroupedEvents.length > 0 ? [...groupNames, "(Other)"] : groupNames;
46896
+ lanes = laneNames.map((name) => ({
46897
+ name,
46898
+ events: timelineEvents.filter(
46899
+ (ev) => name === "(Other)" ? ev.group === null || !groupNames.includes(ev.group) : ev.group === name
46900
+ )
46901
+ }));
46902
+ }
46903
+ const totalEventRows = lanes.reduce((s, l) => s + l.events.length, 0);
46904
+ const scaleMargin = timelineScale ? 24 : 0;
46905
+ const ERA_ROW_H = 22;
46906
+ const MARKER_ROW_H = 22;
46907
+ const eraReserve = timelineEras.length > 0 ? ERA_ROW_H : 0;
46908
+ const markerReserve = timelineMarkers.length > 0 ? MARKER_ROW_H : 0;
46909
+ const topScaleH = timelineScale ? 40 : 0;
46910
+ const maxGroupNameLen = Math.max(...lanes.map((l) => l.name.length));
46911
+ const dynamicLeftMargin = Math.max(120, maxGroupNameLen * 7 + 30);
46912
+ const baseTopMargin = title ? 50 : 20;
46913
+ const margin = {
46914
+ top: baseTopMargin + topScaleH + eraReserve + markerReserve + tagLegendReserve,
46915
+ right: 40,
46916
+ bottom: 40 + scaleMargin,
46917
+ left: dynamicLeftMargin
46918
+ };
46919
+ const markerLabelY = markerReserve ? -(topScaleH + MARKER_ROW_H / 2) : 0;
46920
+ const eraLabelY = eraReserve ? -(topScaleH + markerReserve + ERA_ROW_H / 2) : 0;
46921
+ const innerWidth = width - margin.left - margin.right;
46922
+ const innerHeight = height - margin.top - margin.bottom;
46923
+ const totalGaps = (lanes.length - 1) * GROUP_GAP3;
46924
+ const rowH = Math.min(28, (innerHeight - totalGaps) / totalEventRows);
46925
+ const xScale = d3Scale2.scaleLinear().domain([minDate - datePadding, maxDate + datePadding]).range([0, innerWidth]);
46926
+ const svg = d3Selection22.select(container).append("svg").attr("width", width).attr("height", height).style("background", bgColor);
46927
+ const g = svg.append("g").attr("transform", `translate(${margin.left},${margin.top})`);
46928
+ renderChartTitle(
46929
+ svg,
46930
+ title,
46931
+ parsed.titleLineNumber,
46932
+ width,
46933
+ textColor,
46934
+ onClickItem
46935
+ );
46936
+ renderEras(
46937
+ g,
46938
+ timelineEras,
46939
+ xScale,
46940
+ false,
46941
+ innerWidth,
46942
+ innerHeight,
46943
+ (s, e) => fadeToEra(g, s, e),
46944
+ () => fadeReset(g),
46945
+ timelineScale,
46946
+ tooltip,
46947
+ palette,
46948
+ eraReserve ? eraLabelY : void 0
46949
+ );
46950
+ renderMarkers(
46951
+ g,
46952
+ timelineMarkers,
46953
+ xScale,
46954
+ false,
46955
+ innerWidth,
46956
+ innerHeight,
46957
+ (d) => fadeToMarker(g, d),
46958
+ () => fadeReset(g),
46959
+ timelineScale,
46960
+ tooltip,
46961
+ palette,
46962
+ markerReserve ? markerLabelY : void 0
46963
+ );
46964
+ if (timelineScale) {
46965
+ renderTimeScale(
46966
+ g,
46967
+ xScale,
46968
+ false,
46969
+ innerWidth,
46970
+ innerHeight,
46971
+ textColor,
46972
+ minDate,
46973
+ maxDate,
46974
+ formatBoundaryLabel(earliestStartDateStr, latestEndDateStr),
46975
+ formatBoundaryLabel(latestEndDateStr, earliestStartDateStr)
46976
+ );
46977
+ }
46978
+ let curY = 0;
46979
+ if (timelineSwimlanes || tagLanes) {
46980
+ let swimY = 0;
46981
+ lanes.forEach((lane, idx) => {
46982
+ const laneSpan = lane.events.length * rowH;
46983
+ const fillColor = idx % 2 === 0 ? textColor : "transparent";
46984
+ g.append("rect").attr("class", "tl-swimlane").attr("data-group", lane.name).attr("x", -margin.left).attr("y", swimY).attr("width", innerWidth + margin.left).attr("height", laneSpan + (idx < lanes.length - 1 ? GROUP_GAP3 : 0)).attr("fill", fillColor).attr("opacity", 0.06);
46985
+ swimY += laneSpan + GROUP_GAP3;
46986
+ });
46987
+ }
46988
+ for (const lane of lanes) {
46989
+ const laneColor = groupColorMap.get(lane.name) ?? textColor;
46990
+ const laneSpan = lane.events.length * rowH;
46991
+ const group = timelineGroups.find((grp) => grp.name === lane.name);
46992
+ const headerG = g.append("g").attr("class", "tl-lane-header").attr("data-group", lane.name).style("cursor", "pointer").on("mouseenter", () => fadeToGroup(g, lane.name)).on("mouseleave", () => fadeReset(g)).on("click", () => {
46993
+ if (onClickItem && group?.lineNumber) onClickItem(group.lineNumber);
46994
+ });
46995
+ headerG.append("text").attr("x", -margin.left + 10).attr("y", curY + laneSpan / 2).attr("dy", "0.35em").attr("text-anchor", "start").attr("fill", laneColor).attr("font-size", "12px").attr("font-weight", "600").text(lane.name);
46996
+ lane.events.forEach((ev, i) => {
46997
+ const y = curY + i * rowH + rowH / 2;
46998
+ const x = xScale(parseTimelineDate(ev.date));
46999
+ const evG = g.append("g").attr("class", "tl-event").attr("data-group", lane.name).attr("data-line-number", String(ev.lineNumber)).attr("data-date", String(parseTimelineDate(ev.date))).attr(
47000
+ "data-end-date",
47001
+ ev.endDate ? String(parseTimelineDate(ev.endDate)) : null
47002
+ ).style("cursor", "pointer").on("mouseenter", function(event) {
47003
+ fadeToGroup(g, lane.name);
47004
+ if (timelineScale) {
47005
+ showEventDatesOnScale(
47006
+ g,
47007
+ xScale,
47008
+ ev.date,
47009
+ ev.endDate,
47010
+ innerHeight,
47011
+ laneColor
47012
+ );
47013
+ } else {
46628
47014
  showTooltip(tooltip, buildEventTooltipHtml(ev), event);
46629
- }).on("mouseleave", function() {
46630
- fadeReset(g);
47015
+ }
47016
+ }).on("mouseleave", function() {
47017
+ fadeReset(g);
47018
+ if (timelineScale) {
47019
+ hideEventDatesOnScale(g);
47020
+ } else {
46631
47021
  hideTooltip(tooltip);
46632
- }).on("mousemove", function(event) {
47022
+ }
47023
+ }).on("mousemove", function(event) {
47024
+ if (!timelineScale) {
46633
47025
  showTooltip(tooltip, buildEventTooltipHtml(ev), event);
46634
- }).on("click", () => {
46635
- if (onClickItem && ev.lineNumber) onClickItem(ev.lineNumber);
46636
- });
46637
- setTagAttrs(evG, ev);
46638
- if (ev.endDate) {
46639
- const y2 = yScale(parseTimelineDate(ev.endDate));
46640
- const rectH = Math.max(y2 - y, 4);
46641
- let fill2 = shapeFill(palette, color, isDark, { solid });
46642
- let stroke2 = color;
46643
- if (ev.uncertain) {
46644
- const gradientId = `uncertain-v-${ev.lineNumber}`;
46645
- const strokeGradientId = `uncertain-v-s-${ev.lineNumber}`;
46646
- const defs = svg.select("defs").node() || svg.append("defs").node();
46647
- const defsEl = d3Selection22.select(defs);
46648
- defsEl.append("linearGradient").attr("id", gradientId).attr("x1", "0%").attr("y1", "0%").attr("x2", "0%").attr("y2", "100%").selectAll("stop").data([
46649
- { offset: "0%", opacity: 1 },
46650
- { offset: "80%", opacity: 1 },
46651
- { offset: "100%", opacity: 0 }
46652
- ]).enter().append("stop").attr("offset", (d) => d.offset).attr("stop-color", mix(color, bg, 30)).attr("stop-opacity", (d) => d.opacity);
46653
- defsEl.append("linearGradient").attr("id", strokeGradientId).attr("x1", "0%").attr("y1", "0%").attr("x2", "0%").attr("y2", "100%").selectAll("stop").data([
46654
- { offset: "0%", opacity: 1 },
46655
- { offset: "80%", opacity: 1 },
46656
- { offset: "100%", opacity: 0 }
46657
- ]).enter().append("stop").attr("offset", (d) => d.offset).attr("stop-color", color).attr("stop-opacity", (d) => d.opacity);
46658
- fill2 = `url(#${gradientId})`;
46659
- stroke2 = `url(#${strokeGradientId})`;
46660
- }
46661
- evG.append("rect").attr("x", axisX - 6).attr("y", y).attr("width", 12).attr("height", rectH).attr("rx", 4).attr("fill", fill2).attr("stroke", stroke2).attr("stroke-width", 2);
46662
- evG.append("text").attr("x", axisX + 16).attr("y", y + rectH / 2).attr("dy", "0.35em").attr("fill", textColor).attr("font-size", "11px").text(ev.label);
47026
+ }
47027
+ }).on("click", () => {
47028
+ if (onClickItem && ev.lineNumber) onClickItem(ev.lineNumber);
47029
+ });
47030
+ setTagAttrs(evG, ev);
47031
+ const evColor = eventColor(ev);
47032
+ if (ev.endDate) {
47033
+ const x2 = xScale(parseTimelineDate(ev.endDate));
47034
+ const rectW = Math.max(x2 - x, 4);
47035
+ const estLabelWidth = ev.label.length * 7 + 16;
47036
+ const labelFitsInside = rectW >= estLabelWidth;
47037
+ let fill2 = shapeFill(palette, evColor, isDark, { solid });
47038
+ let stroke2 = evColor;
47039
+ if (ev.uncertain) {
47040
+ const gradientId = `uncertain-${ev.lineNumber}`;
47041
+ const strokeGradientId = `uncertain-s-${ev.lineNumber}`;
47042
+ const defs = svg.select("defs").node() || svg.append("defs").node();
47043
+ const defsEl = d3Selection22.select(defs);
47044
+ defsEl.append("linearGradient").attr("id", gradientId).attr("x1", "0%").attr("y1", "0%").attr("x2", "100%").attr("y2", "0%").selectAll("stop").data([
47045
+ { offset: "0%", opacity: 1 },
47046
+ { offset: "80%", opacity: 1 },
47047
+ { offset: "100%", opacity: 0 }
47048
+ ]).enter().append("stop").attr("offset", (d) => d.offset).attr("stop-color", mix(evColor, bg, 30)).attr("stop-opacity", (d) => d.opacity);
47049
+ defsEl.append("linearGradient").attr("id", strokeGradientId).attr("x1", "0%").attr("y1", "0%").attr("x2", "100%").attr("y2", "0%").selectAll("stop").data([
47050
+ { offset: "0%", opacity: 1 },
47051
+ { offset: "80%", opacity: 1 },
47052
+ { offset: "100%", opacity: 0 }
47053
+ ]).enter().append("stop").attr("offset", (d) => d.offset).attr("stop-color", evColor).attr("stop-opacity", (d) => d.opacity);
47054
+ fill2 = `url(#${gradientId})`;
47055
+ stroke2 = `url(#${strokeGradientId})`;
47056
+ }
47057
+ 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);
47058
+ if (labelFitsInside) {
47059
+ 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);
46663
47060
  } else {
46664
- evG.append("circle").attr("cx", axisX).attr("cy", y).attr("r", 4).attr("fill", shapeFill(palette, color, isDark, { solid })).attr("stroke", color).attr("stroke-width", 2);
46665
- evG.append("text").attr("x", axisX + 16).attr("y", y).attr("dy", "0.35em").attr("fill", textColor).attr("font-size", "11px").text(ev.label);
47061
+ const wouldFlipLeft = x + rectW > innerWidth * 0.6;
47062
+ const labelFitsLeft = x - 6 - estLabelWidth > 0;
47063
+ const flipLeft = wouldFlipLeft && labelFitsLeft;
47064
+ evG.append("text").attr("x", flipLeft ? x - 6 : x + rectW + 6).attr("y", y).attr("dy", "0.35em").attr("text-anchor", flipLeft ? "end" : "start").attr("fill", textColor).attr("font-size", "13px").text(ev.label);
46666
47065
  }
46667
- evG.append("text").attr("x", axisX - 14).attr(
46668
- "y",
46669
- ev.endDate ? yScale(parseTimelineDate(ev.date)) + Math.max(
46670
- yScale(parseTimelineDate(ev.endDate)) - yScale(parseTimelineDate(ev.date)),
46671
- 4
46672
- ) / 2 : y
46673
- ).attr("dy", "0.35em").attr("text-anchor", "end").attr("fill", mutedColor).attr("font-size", "10px").text(ev.date + (ev.endDate ? `\u2192${ev.endDate}` : ""));
47066
+ } else {
47067
+ const estLabelWidth = ev.label.length * 7;
47068
+ const wouldFlipLeft = x > innerWidth * 0.6;
47069
+ const labelFitsLeft = x - 10 - estLabelWidth > 0;
47070
+ const flipLeft = wouldFlipLeft && labelFitsLeft;
47071
+ evG.append("circle").attr("cx", x).attr("cy", y).attr("r", 5).attr("fill", shapeFill(palette, evColor, isDark, { solid })).attr("stroke", evColor).attr("stroke-width", 2);
47072
+ evG.append("text").attr("x", flipLeft ? x - 10 : x + 10).attr("y", y).attr("dy", "0.35em").attr("text-anchor", flipLeft ? "end" : "start").attr("fill", textColor).attr("font-size", "12px").text(ev.label);
46674
47073
  }
46675
- }
46676
- return;
47074
+ });
47075
+ curY += laneSpan + GROUP_GAP3;
46677
47076
  }
46678
- const BAR_H2 = 22;
46679
- const GROUP_GAP3 = 12;
46680
- const useGroupedHorizontal = tagLanes != null || timelineSort === "group" && timelineGroups.length > 0;
46681
- if (useGroupedHorizontal) {
46682
- let lanes;
47077
+ }
47078
+ function renderTimelineVertical(container, parsed, palette, isDark, setup, hovers, onClickItem, exportDims, _swimlaneTagGroup, _activeTagGroup, _onTagStateChange, _viewMode) {
47079
+ const {
47080
+ width,
47081
+ height,
47082
+ tooltip,
47083
+ solid,
47084
+ textColor,
47085
+ mutedColor,
47086
+ bgColor,
47087
+ bg,
47088
+ groupColorMap,
47089
+ tagLanes,
47090
+ eventColor,
47091
+ minDate,
47092
+ maxDate,
47093
+ datePadding,
47094
+ earliestStartDateStr,
47095
+ latestEndDateStr,
47096
+ tagLegendReserve
47097
+ } = setup;
47098
+ const { fadeToGroup, fadeToEra, fadeToMarker, fadeReset, setTagAttrs } = hovers;
47099
+ const {
47100
+ timelineEvents,
47101
+ timelineGroups,
47102
+ timelineEras,
47103
+ timelineMarkers,
47104
+ timelineSort,
47105
+ timelineScale,
47106
+ timelineSwimlanes
47107
+ } = parsed;
47108
+ const title = parsed.noTitle ? null : parsed.title;
47109
+ const useGroupedVertical = tagLanes != null || timelineSort === "group" && timelineGroups.length > 0;
47110
+ if (useGroupedVertical) {
47111
+ let laneNames;
47112
+ let laneEventsByName;
46683
47113
  if (tagLanes) {
46684
- lanes = tagLanes;
47114
+ laneNames = tagLanes.map((l) => l.name);
47115
+ laneEventsByName = new Map(tagLanes.map((l) => [l.name, l.events]));
46685
47116
  } else {
46686
47117
  const groupNames = timelineGroups.map((gr) => gr.name);
46687
47118
  const ungroupedEvents = timelineEvents.filter(
46688
47119
  (ev) => ev.group === null || !groupNames.includes(ev.group)
46689
47120
  );
46690
- const laneNames = ungroupedEvents.length > 0 ? [...groupNames, "(Other)"] : groupNames;
46691
- lanes = laneNames.map((name) => ({
46692
- name,
46693
- events: timelineEvents.filter(
46694
- (ev) => name === "(Other)" ? ev.group === null || !groupNames.includes(ev.group) : ev.group === name
46695
- )
46696
- }));
47121
+ laneNames = ungroupedEvents.length > 0 ? [...groupNames, "(Other)"] : groupNames;
47122
+ laneEventsByName = new Map(
47123
+ laneNames.map((name) => [
47124
+ name,
47125
+ timelineEvents.filter(
47126
+ (ev) => name === "(Other)" ? ev.group === null || !groupNames.includes(ev.group) : ev.group === name
47127
+ )
47128
+ ])
47129
+ );
46697
47130
  }
46698
- const totalEventRows = lanes.reduce((s, l) => s + l.events.length, 0);
46699
- const scaleMargin = timelineScale ? 24 : 0;
46700
- const ERA_ROW_H = 22;
46701
- const MARKER_ROW_H = 22;
46702
- const eraReserve = timelineEras.length > 0 ? ERA_ROW_H : 0;
46703
- const markerReserve = timelineMarkers.length > 0 ? MARKER_ROW_H : 0;
46704
- const topScaleH = timelineScale ? 40 : 0;
46705
- const maxGroupNameLen = Math.max(...lanes.map((l) => l.name.length));
46706
- const dynamicLeftMargin = Math.max(120, maxGroupNameLen * 7 + 30);
46707
- const baseTopMargin = title ? 50 : 20;
47131
+ const laneCount = laneNames.length;
47132
+ const scaleMargin = timelineScale ? 40 : 0;
47133
+ const markerMargin = timelineMarkers.length > 0 ? 30 : 0;
46708
47134
  const margin = {
46709
- top: baseTopMargin + topScaleH + eraReserve + markerReserve + tagLegendReserve,
46710
- right: 40,
46711
- bottom: 40 + scaleMargin,
46712
- left: dynamicLeftMargin
47135
+ top: 104 + markerMargin + tagLegendReserve,
47136
+ right: 40 + scaleMargin,
47137
+ bottom: 40,
47138
+ left: 60 + scaleMargin
46713
47139
  };
46714
- const markerLabelY = markerReserve ? -(topScaleH + MARKER_ROW_H / 2) : 0;
46715
- const eraLabelY = eraReserve ? -(topScaleH + markerReserve + ERA_ROW_H / 2) : 0;
46716
47140
  const innerWidth = width - margin.left - margin.right;
46717
47141
  const innerHeight = height - margin.top - margin.bottom;
46718
- const totalGaps = (lanes.length - 1) * GROUP_GAP3;
46719
- const rowH = Math.min(28, (innerHeight - totalGaps) / totalEventRows);
46720
- const xScale = d3Scale2.scaleLinear().domain([minDate - datePadding, maxDate + datePadding]).range([0, innerWidth]);
46721
- const svg = d3Selection22.select(container).append("svg").attr("width", width).attr("height", height).style("background", bgColor);
47142
+ const laneWidth = innerWidth / laneCount;
47143
+ const yScale = d3Scale2.scaleLinear().domain([minDate - datePadding, maxDate + datePadding]).range([0, innerHeight]);
47144
+ const svg = d3Selection22.select(container).append("svg").attr("viewBox", `0 0 ${width} ${height}`).attr("width", exportDims ? width : "100%").attr("preserveAspectRatio", "xMidYMin meet").style("background", bgColor);
46722
47145
  const g = svg.append("g").attr("transform", `translate(${margin.left},${margin.top})`);
46723
47146
  renderChartTitle(
46724
47147
  svg,
@@ -46731,36 +47154,34 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
46731
47154
  renderEras(
46732
47155
  g,
46733
47156
  timelineEras,
46734
- xScale,
46735
- false,
47157
+ yScale,
47158
+ true,
46736
47159
  innerWidth,
46737
47160
  innerHeight,
46738
47161
  (s, e) => fadeToEra(g, s, e),
46739
47162
  () => fadeReset(g),
46740
47163
  timelineScale,
46741
47164
  tooltip,
46742
- palette,
46743
- eraReserve ? eraLabelY : void 0
47165
+ palette
46744
47166
  );
46745
47167
  renderMarkers(
46746
47168
  g,
46747
47169
  timelineMarkers,
46748
- xScale,
46749
- false,
47170
+ yScale,
47171
+ true,
46750
47172
  innerWidth,
46751
47173
  innerHeight,
46752
47174
  (d) => fadeToMarker(g, d),
46753
47175
  () => fadeReset(g),
46754
47176
  timelineScale,
46755
47177
  tooltip,
46756
- palette,
46757
- markerReserve ? markerLabelY : void 0
47178
+ palette
46758
47179
  );
46759
47180
  if (timelineScale) {
46760
47181
  renderTimeScale(
46761
47182
  g,
46762
- xScale,
46763
- false,
47183
+ yScale,
47184
+ true,
46764
47185
  innerWidth,
46765
47186
  innerHeight,
46766
47187
  textColor,
@@ -46770,78 +47191,55 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
46770
47191
  formatBoundaryLabel(latestEndDateStr, earliestStartDateStr)
46771
47192
  );
46772
47193
  }
46773
- let curY = 0;
46774
47194
  if (timelineSwimlanes || tagLanes) {
46775
- let swimY = 0;
46776
- lanes.forEach((lane, idx) => {
46777
- const laneSpan = lane.events.length * rowH;
46778
- const fillColor = idx % 2 === 0 ? textColor : "transparent";
46779
- g.append("rect").attr("class", "tl-swimlane").attr("data-group", lane.name).attr("x", -margin.left).attr("y", swimY).attr("width", innerWidth + margin.left).attr("height", laneSpan + (idx < lanes.length - 1 ? GROUP_GAP3 : 0)).attr("fill", fillColor).attr("opacity", 0.06);
46780
- swimY += laneSpan + GROUP_GAP3;
47195
+ laneNames.forEach((laneName, laneIdx) => {
47196
+ const laneX = laneIdx * laneWidth;
47197
+ const fillColor = laneIdx % 2 === 0 ? textColor : "transparent";
47198
+ g.append("rect").attr("class", "tl-swimlane").attr("data-group", laneName).attr("x", laneX).attr("y", 0).attr("width", laneWidth).attr("height", innerHeight).attr("fill", fillColor).attr("opacity", 0.06);
46781
47199
  });
46782
47200
  }
46783
- for (const lane of lanes) {
46784
- const laneColor = groupColorMap.get(lane.name) ?? textColor;
46785
- const laneSpan = lane.events.length * rowH;
46786
- const group = timelineGroups.find((grp) => grp.name === lane.name);
46787
- const headerG = g.append("g").attr("class", "tl-lane-header").attr("data-group", lane.name).style("cursor", "pointer").on("mouseenter", () => fadeToGroup(g, lane.name)).on("mouseleave", () => fadeReset(g)).on("click", () => {
46788
- if (onClickItem && group?.lineNumber) onClickItem(group.lineNumber);
46789
- });
46790
- headerG.append("text").attr("x", -margin.left + 10).attr("y", curY + laneSpan / 2).attr("dy", "0.35em").attr("text-anchor", "start").attr("fill", laneColor).attr("font-size", "12px").attr("font-weight", "600").text(lane.name);
46791
- lane.events.forEach((ev, i) => {
46792
- const y = curY + i * rowH + rowH / 2;
46793
- const x = xScale(parseTimelineDate(ev.date));
46794
- const evG = g.append("g").attr("class", "tl-event").attr("data-group", lane.name).attr("data-line-number", String(ev.lineNumber)).attr("data-date", String(parseTimelineDate(ev.date))).attr(
47201
+ laneNames.forEach((laneName, laneIdx) => {
47202
+ const laneX = laneIdx * laneWidth;
47203
+ const laneColor = groupColorMap.get(laneName) ?? textColor;
47204
+ const laneCenter = laneX + laneWidth / 2;
47205
+ const headerG = g.append("g").attr("class", "tl-lane-header").attr("data-group", laneName).style("cursor", "pointer").on("mouseenter", () => fadeToGroup(g, laneName)).on("mouseleave", () => fadeReset(g));
47206
+ headerG.append("text").attr("x", laneCenter).attr("y", -15).attr("text-anchor", "middle").attr("fill", laneColor).attr("font-size", "12px").attr("font-weight", "600").text(laneName);
47207
+ g.append("line").attr("x1", laneCenter).attr("y1", 0).attr("x2", laneCenter).attr("y2", innerHeight).attr("stroke", mutedColor).attr("stroke-width", 1).attr("stroke-dasharray", "4,4");
47208
+ const laneEvents = laneEventsByName.get(laneName) ?? [];
47209
+ for (const ev of laneEvents) {
47210
+ const y = yScale(parseTimelineDate(ev.date));
47211
+ const evG = g.append("g").attr("class", "tl-event").attr("data-group", laneName).attr("data-line-number", String(ev.lineNumber)).attr("data-date", String(parseTimelineDate(ev.date))).attr(
46795
47212
  "data-end-date",
46796
47213
  ev.endDate ? String(parseTimelineDate(ev.endDate)) : null
46797
47214
  ).style("cursor", "pointer").on("mouseenter", function(event) {
46798
- fadeToGroup(g, lane.name);
46799
- if (timelineScale) {
46800
- showEventDatesOnScale(
46801
- g,
46802
- xScale,
46803
- ev.date,
46804
- ev.endDate,
46805
- innerHeight,
46806
- laneColor
46807
- );
46808
- } else {
46809
- showTooltip(tooltip, buildEventTooltipHtml(ev), event);
46810
- }
47215
+ fadeToGroup(g, laneName);
47216
+ showTooltip(tooltip, buildEventTooltipHtml(ev), event);
46811
47217
  }).on("mouseleave", function() {
46812
47218
  fadeReset(g);
46813
- if (timelineScale) {
46814
- hideEventDatesOnScale(g);
46815
- } else {
46816
- hideTooltip(tooltip);
46817
- }
47219
+ hideTooltip(tooltip);
46818
47220
  }).on("mousemove", function(event) {
46819
- if (!timelineScale) {
46820
- showTooltip(tooltip, buildEventTooltipHtml(ev), event);
46821
- }
47221
+ showTooltip(tooltip, buildEventTooltipHtml(ev), event);
46822
47222
  }).on("click", () => {
46823
47223
  if (onClickItem && ev.lineNumber) onClickItem(ev.lineNumber);
46824
47224
  });
46825
47225
  setTagAttrs(evG, ev);
46826
47226
  const evColor = eventColor(ev);
46827
47227
  if (ev.endDate) {
46828
- const x2 = xScale(parseTimelineDate(ev.endDate));
46829
- const rectW = Math.max(x2 - x, 4);
46830
- const estLabelWidth = ev.label.length * 7 + 16;
46831
- const labelFitsInside = rectW >= estLabelWidth;
47228
+ const y2 = yScale(parseTimelineDate(ev.endDate));
47229
+ const rectH = Math.max(y2 - y, 4);
46832
47230
  let fill2 = shapeFill(palette, evColor, isDark, { solid });
46833
47231
  let stroke2 = evColor;
46834
47232
  if (ev.uncertain) {
46835
- const gradientId = `uncertain-${ev.lineNumber}`;
46836
- const strokeGradientId = `uncertain-s-${ev.lineNumber}`;
47233
+ const gradientId = `uncertain-vg-${ev.lineNumber}`;
47234
+ const strokeGradientId = `uncertain-vg-s-${ev.lineNumber}`;
46837
47235
  const defs = svg.select("defs").node() || svg.append("defs").node();
46838
47236
  const defsEl = d3Selection22.select(defs);
46839
- defsEl.append("linearGradient").attr("id", gradientId).attr("x1", "0%").attr("y1", "0%").attr("x2", "100%").attr("y2", "0%").selectAll("stop").data([
47237
+ defsEl.append("linearGradient").attr("id", gradientId).attr("x1", "0%").attr("y1", "0%").attr("x2", "0%").attr("y2", "100%").selectAll("stop").data([
46840
47238
  { offset: "0%", opacity: 1 },
46841
47239
  { offset: "80%", opacity: 1 },
46842
47240
  { offset: "100%", opacity: 0 }
46843
- ]).enter().append("stop").attr("offset", (d) => d.offset).attr("stop-color", mix(evColor, bg, 30)).attr("stop-opacity", (d) => d.opacity);
46844
- defsEl.append("linearGradient").attr("id", strokeGradientId).attr("x1", "0%").attr("y1", "0%").attr("x2", "100%").attr("y2", "0%").selectAll("stop").data([
47241
+ ]).enter().append("stop").attr("offset", (d) => d.offset).attr("stop-color", mix(laneColor, bg, 30)).attr("stop-opacity", (d) => d.opacity);
47242
+ defsEl.append("linearGradient").attr("id", strokeGradientId).attr("x1", "0%").attr("y1", "0%").attr("x2", "0%").attr("y2", "100%").selectAll("stop").data([
46845
47243
  { offset: "0%", opacity: 1 },
46846
47244
  { offset: "80%", opacity: 1 },
46847
47245
  { offset: "100%", opacity: 0 }
@@ -46849,47 +47247,29 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
46849
47247
  fill2 = `url(#${gradientId})`;
46850
47248
  stroke2 = `url(#${strokeGradientId})`;
46851
47249
  }
46852
- 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);
46853
- if (labelFitsInside) {
46854
- 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);
46855
- } else {
46856
- const wouldFlipLeft = x + rectW > innerWidth * 0.6;
46857
- const labelFitsLeft = x - 6 - estLabelWidth > 0;
46858
- const flipLeft = wouldFlipLeft && labelFitsLeft;
46859
- evG.append("text").attr("x", flipLeft ? x - 6 : x + rectW + 6).attr("y", y).attr("dy", "0.35em").attr("text-anchor", flipLeft ? "end" : "start").attr("fill", textColor).attr("font-size", "13px").text(ev.label);
46860
- }
47250
+ evG.append("rect").attr("x", laneCenter - 6).attr("y", y).attr("width", 12).attr("height", rectH).attr("rx", 4).attr("fill", fill2).attr("stroke", stroke2).attr("stroke-width", 2);
47251
+ evG.append("text").attr("x", laneCenter + 14).attr("y", y + rectH / 2).attr("dy", "0.35em").attr("fill", textColor).attr("font-size", "10px").text(ev.label);
46861
47252
  } else {
46862
- const estLabelWidth = ev.label.length * 7;
46863
- const wouldFlipLeft = x > innerWidth * 0.6;
46864
- const labelFitsLeft = x - 10 - estLabelWidth > 0;
46865
- const flipLeft = wouldFlipLeft && labelFitsLeft;
46866
- evG.append("circle").attr("cx", x).attr("cy", y).attr("r", 5).attr("fill", shapeFill(palette, evColor, isDark, { solid })).attr("stroke", evColor).attr("stroke-width", 2);
46867
- evG.append("text").attr("x", flipLeft ? x - 10 : x + 10).attr("y", y).attr("dy", "0.35em").attr("text-anchor", flipLeft ? "end" : "start").attr("fill", textColor).attr("font-size", "12px").text(ev.label);
47253
+ evG.append("circle").attr("cx", laneCenter).attr("cy", y).attr("r", 4).attr("fill", shapeFill(palette, evColor, isDark, { solid })).attr("stroke", evColor).attr("stroke-width", 2);
47254
+ evG.append("text").attr("x", laneCenter + 10).attr("y", y).attr("dy", "0.35em").attr("fill", textColor).attr("font-size", "10px").text(ev.label);
46868
47255
  }
46869
- });
46870
- curY += laneSpan + GROUP_GAP3;
46871
- }
47256
+ }
47257
+ });
46872
47258
  } else {
46873
- const sorted = timelineEvents.slice().sort((a, b) => parseTimelineDate(a.date) - parseTimelineDate(b.date));
46874
- const scaleMargin = timelineScale ? 24 : 0;
46875
- const ERA_ROW_H = 22;
46876
- const MARKER_ROW_H = 22;
46877
- const eraReserve = timelineEras.length > 0 ? ERA_ROW_H : 0;
46878
- const markerReserve = timelineMarkers.length > 0 ? MARKER_ROW_H : 0;
46879
- const topScaleH = timelineScale ? 40 : 0;
47259
+ const scaleMargin = timelineScale ? 40 : 0;
47260
+ const markerMargin = timelineMarkers.length > 0 ? 30 : 0;
46880
47261
  const margin = {
46881
- top: 104 + topScaleH + eraReserve + markerReserve + tagLegendReserve,
46882
- right: 40,
46883
- bottom: 40 + scaleMargin,
46884
- left: 60
47262
+ top: 104 + markerMargin + tagLegendReserve,
47263
+ right: 200,
47264
+ bottom: 40,
47265
+ left: 60 + scaleMargin
46885
47266
  };
46886
- const markerLabelY = markerReserve ? -(topScaleH + MARKER_ROW_H / 2) : 0;
46887
- const eraLabelY = eraReserve ? -(topScaleH + markerReserve + ERA_ROW_H / 2) : 0;
46888
47267
  const innerWidth = width - margin.left - margin.right;
46889
47268
  const innerHeight = height - margin.top - margin.bottom;
46890
- const rowH = Math.min(28, innerHeight / sorted.length);
46891
- const xScale = d3Scale2.scaleLinear().domain([minDate - datePadding, maxDate + datePadding]).range([0, innerWidth]);
46892
- const svg = d3Selection22.select(container).append("svg").attr("width", width).attr("height", height).style("background", bgColor);
47269
+ const axisX = 20;
47270
+ const yScale = d3Scale2.scaleLinear().domain([minDate - datePadding, maxDate + datePadding]).range([0, innerHeight]);
47271
+ const sorted = timelineEvents.slice().sort((a, b) => parseTimelineDate(a.date) - parseTimelineDate(b.date));
47272
+ const svg = d3Selection22.select(container).append("svg").attr("viewBox", `0 0 ${width} ${height}`).attr("width", exportDims ? width : "100%").attr("preserveAspectRatio", "xMidYMin meet").style("background", bgColor);
46893
47273
  const g = svg.append("g").attr("transform", `translate(${margin.left},${margin.top})`);
46894
47274
  renderChartTitle(
46895
47275
  svg,
@@ -46902,36 +47282,34 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
46902
47282
  renderEras(
46903
47283
  g,
46904
47284
  timelineEras,
46905
- xScale,
46906
- false,
47285
+ yScale,
47286
+ true,
46907
47287
  innerWidth,
46908
47288
  innerHeight,
46909
47289
  (s, e) => fadeToEra(g, s, e),
46910
47290
  () => fadeReset(g),
46911
47291
  timelineScale,
46912
47292
  tooltip,
46913
- palette,
46914
- eraReserve ? eraLabelY : void 0
47293
+ palette
46915
47294
  );
46916
47295
  renderMarkers(
46917
47296
  g,
46918
47297
  timelineMarkers,
46919
- xScale,
46920
- false,
47298
+ yScale,
47299
+ true,
46921
47300
  innerWidth,
46922
47301
  innerHeight,
46923
47302
  (d) => fadeToMarker(g, d),
46924
47303
  () => fadeReset(g),
46925
47304
  timelineScale,
46926
47305
  tooltip,
46927
- palette,
46928
- markerReserve ? markerLabelY : void 0
47306
+ palette
46929
47307
  );
46930
47308
  if (timelineScale) {
46931
47309
  renderTimeScale(
46932
47310
  g,
46933
- xScale,
46934
- false,
47311
+ yScale,
47312
+ true,
46935
47313
  innerWidth,
46936
47314
  innerHeight,
46937
47315
  textColor,
@@ -46942,7 +47320,6 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
46942
47320
  );
46943
47321
  }
46944
47322
  if (timelineGroups.length > 0) {
46945
- const legendY = timelineScale ? -75 : -55;
46946
47323
  renderTimelineGroupLegend(
46947
47324
  g,
46948
47325
  timelineGroups,
@@ -46950,65 +47327,46 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
46950
47327
  textColor,
46951
47328
  palette,
46952
47329
  isDark,
46953
- legendY,
47330
+ -55,
46954
47331
  (name) => fadeToGroup(g, name),
46955
47332
  () => fadeReset(g)
46956
47333
  );
46957
47334
  }
46958
- sorted.forEach((ev, i) => {
46959
- const y = i * rowH + rowH / 2;
46960
- const x = xScale(parseTimelineDate(ev.date));
47335
+ 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");
47336
+ for (const ev of sorted) {
47337
+ const y = yScale(parseTimelineDate(ev.date));
46961
47338
  const color = eventColor(ev);
46962
47339
  const evG = g.append("g").attr("class", "tl-event").attr("data-group", ev.group || "").attr("data-line-number", String(ev.lineNumber)).attr("data-date", String(parseTimelineDate(ev.date))).attr(
46963
47340
  "data-end-date",
46964
47341
  ev.endDate ? String(parseTimelineDate(ev.endDate)) : null
46965
47342
  ).style("cursor", "pointer").on("mouseenter", function(event) {
46966
47343
  if (ev.group && timelineGroups.length > 0) fadeToGroup(g, ev.group);
46967
- if (timelineScale) {
46968
- showEventDatesOnScale(
46969
- g,
46970
- xScale,
46971
- ev.date,
46972
- ev.endDate,
46973
- innerHeight,
46974
- color
46975
- );
46976
- } else {
46977
- showTooltip(tooltip, buildEventTooltipHtml(ev), event);
46978
- }
47344
+ showTooltip(tooltip, buildEventTooltipHtml(ev), event);
46979
47345
  }).on("mouseleave", function() {
46980
47346
  fadeReset(g);
46981
- if (timelineScale) {
46982
- hideEventDatesOnScale(g);
46983
- } else {
46984
- hideTooltip(tooltip);
46985
- }
47347
+ hideTooltip(tooltip);
46986
47348
  }).on("mousemove", function(event) {
46987
- if (!timelineScale) {
46988
- showTooltip(tooltip, buildEventTooltipHtml(ev), event);
46989
- }
47349
+ showTooltip(tooltip, buildEventTooltipHtml(ev), event);
46990
47350
  }).on("click", () => {
46991
47351
  if (onClickItem && ev.lineNumber) onClickItem(ev.lineNumber);
46992
47352
  });
46993
47353
  setTagAttrs(evG, ev);
46994
47354
  if (ev.endDate) {
46995
- const x2 = xScale(parseTimelineDate(ev.endDate));
46996
- const rectW = Math.max(x2 - x, 4);
46997
- const estLabelWidth = ev.label.length * 7 + 16;
46998
- const labelFitsInside = rectW >= estLabelWidth;
47355
+ const y2 = yScale(parseTimelineDate(ev.endDate));
47356
+ const rectH = Math.max(y2 - y, 4);
46999
47357
  let fill2 = shapeFill(palette, color, isDark, { solid });
47000
47358
  let stroke2 = color;
47001
47359
  if (ev.uncertain) {
47002
- const gradientId = `uncertain-ts-${ev.lineNumber}`;
47003
- const strokeGradientId = `uncertain-ts-s-${ev.lineNumber}`;
47360
+ const gradientId = `uncertain-v-${ev.lineNumber}`;
47361
+ const strokeGradientId = `uncertain-v-s-${ev.lineNumber}`;
47004
47362
  const defs = svg.select("defs").node() || svg.append("defs").node();
47005
47363
  const defsEl = d3Selection22.select(defs);
47006
- defsEl.append("linearGradient").attr("id", gradientId).attr("x1", "0%").attr("y1", "0%").attr("x2", "100%").attr("y2", "0%").selectAll("stop").data([
47364
+ defsEl.append("linearGradient").attr("id", gradientId).attr("x1", "0%").attr("y1", "0%").attr("x2", "0%").attr("y2", "100%").selectAll("stop").data([
47007
47365
  { offset: "0%", opacity: 1 },
47008
47366
  { offset: "80%", opacity: 1 },
47009
47367
  { offset: "100%", opacity: 0 }
47010
47368
  ]).enter().append("stop").attr("offset", (d) => d.offset).attr("stop-color", mix(color, bg, 30)).attr("stop-opacity", (d) => d.opacity);
47011
- defsEl.append("linearGradient").attr("id", strokeGradientId).attr("x1", "0%").attr("y1", "0%").attr("x2", "100%").attr("y2", "0%").selectAll("stop").data([
47369
+ defsEl.append("linearGradient").attr("id", strokeGradientId).attr("x1", "0%").attr("y1", "0%").attr("x2", "0%").attr("y2", "100%").selectAll("stop").data([
47012
47370
  { offset: "0%", opacity: 1 },
47013
47371
  { offset: "80%", opacity: 1 },
47014
47372
  { offset: "100%", opacity: 0 }
@@ -47016,206 +47374,100 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
47016
47374
  fill2 = `url(#${gradientId})`;
47017
47375
  stroke2 = `url(#${strokeGradientId})`;
47018
47376
  }
47019
- 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);
47020
- if (labelFitsInside) {
47021
- 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);
47022
- } else {
47023
- const wouldFlipLeft = x + rectW > innerWidth * 0.6;
47024
- const labelFitsLeft = x - 6 - estLabelWidth > 0;
47025
- const flipLeft = wouldFlipLeft && labelFitsLeft;
47026
- evG.append("text").attr("x", flipLeft ? x - 6 : x + rectW + 6).attr("y", y).attr("dy", "0.35em").attr("text-anchor", flipLeft ? "end" : "start").attr("fill", textColor).attr("font-size", "13px").text(ev.label);
47027
- }
47377
+ evG.append("rect").attr("x", axisX - 6).attr("y", y).attr("width", 12).attr("height", rectH).attr("rx", 4).attr("fill", fill2).attr("stroke", stroke2).attr("stroke-width", 2);
47378
+ evG.append("text").attr("x", axisX + 16).attr("y", y + rectH / 2).attr("dy", "0.35em").attr("fill", textColor).attr("font-size", "11px").text(ev.label);
47028
47379
  } else {
47029
- const estLabelWidth = ev.label.length * 7;
47030
- const wouldFlipLeft = x > innerWidth * 0.6;
47031
- const labelFitsLeft = x - 10 - estLabelWidth > 0;
47032
- const flipLeft = wouldFlipLeft && labelFitsLeft;
47033
- evG.append("circle").attr("cx", x).attr("cy", y).attr("r", 5).attr("fill", shapeFill(palette, color, isDark, { solid })).attr("stroke", color).attr("stroke-width", 2);
47034
- evG.append("text").attr("x", flipLeft ? x - 10 : x + 10).attr("y", y).attr("dy", "0.35em").attr("text-anchor", flipLeft ? "end" : "start").attr("fill", textColor).attr("font-size", "12px").text(ev.label);
47035
- }
47036
- });
47037
- }
47038
- if (parsed.timelineTagGroups.length > 0) {
47039
- const LG_HEIGHT = LEGEND_HEIGHT;
47040
- const LG_PILL_PAD = LEGEND_PILL_PAD;
47041
- const LG_PILL_FONT_SIZE = LEGEND_PILL_FONT_SIZE;
47042
- const LG_CAPSULE_PAD = LEGEND_CAPSULE_PAD;
47043
- const LG_DOT_R = LEGEND_DOT_R;
47044
- const LG_ENTRY_FONT_SIZE = LEGEND_ENTRY_FONT_SIZE;
47045
- const LG_ENTRY_DOT_GAP = LEGEND_ENTRY_DOT_GAP;
47046
- const LG_ENTRY_TRAIL = LEGEND_ENTRY_TRAIL;
47047
- const LG_ICON_W = 20;
47048
- const mainSvg = d3Selection22.select(container).select("svg");
47049
- const mainG = mainSvg.select("g");
47050
- if (!mainSvg.empty() && !mainG.empty()) {
47051
- let drawSwimlaneIcon4 = function(parent, x, y, isSwimActive) {
47052
- const iconG = parent.append("g").attr("class", "tl-swimlane-icon").attr("transform", `translate(${x}, ${y})`).style("cursor", "pointer");
47053
- const barColor = isSwimActive ? palette.primary : palette.textMuted;
47054
- const barOpacity = isSwimActive ? 1 : 0.35;
47055
- const bars = [
47056
- { y: 0, w: 8 },
47057
- { y: 4, w: 12 },
47058
- { y: 8, w: 6 }
47059
- ];
47060
- for (const bar of bars) {
47061
- iconG.append("rect").attr("x", 0).attr("y", bar.y).attr("width", bar.w).attr("height", 2).attr("rx", 1).attr("fill", barColor).attr("opacity", barOpacity);
47062
- }
47063
- return iconG;
47064
- }, relayout2 = function() {
47065
- renderTimeline(
47066
- container,
47067
- parsed,
47068
- palette,
47069
- isDark,
47070
- onClickItem,
47071
- exportDims,
47072
- currentActiveGroup,
47073
- currentSwimlaneGroup,
47074
- onTagStateChange,
47075
- viewMode
47076
- );
47077
- }, drawLegend2 = function() {
47078
- mainSvg.selectAll(".tl-tag-legend-group").remove();
47079
- mainSvg.selectAll(".tl-tag-legend-container").remove();
47080
- const effectiveColorKey = (currentActiveGroup ?? currentSwimlaneGroup)?.toLowerCase() ?? null;
47081
- const visibleGroups = viewMode ? legendGroups.filter(
47082
- (lg) => effectiveColorKey != null && lg.group.name.toLowerCase() === effectiveColorKey
47083
- ) : legendGroups;
47084
- if (visibleGroups.length === 0) return;
47085
- const legendContainer = mainSvg.append("g").attr("class", "tl-tag-legend-container");
47086
- if (currentActiveGroup) {
47087
- legendContainer.attr(
47088
- "data-legend-active",
47089
- currentActiveGroup.toLowerCase()
47090
- );
47091
- }
47092
- const iconAddon = viewMode ? 0 : LG_ICON_W;
47093
- const centralGroups = visibleGroups.map((lg) => ({
47094
- name: lg.group.name,
47095
- entries: lg.group.entries.map((e) => ({
47096
- value: e.value,
47097
- color: e.color
47098
- }))
47099
- }));
47100
- const centralActive = viewMode ? effectiveColorKey : currentActiveGroup;
47101
- const centralConfig = {
47102
- groups: centralGroups,
47103
- position: { placement: "top-center", titleRelation: "below-title" },
47104
- mode: "fixed",
47105
- capsulePillAddonWidth: iconAddon
47106
- };
47107
- const centralState = { activeGroup: centralActive };
47108
- const centralCallbacks = viewMode ? {} : {
47109
- onGroupToggle: (groupName) => {
47110
- currentActiveGroup = currentActiveGroup === groupName.toLowerCase() ? null : groupName.toLowerCase();
47111
- drawLegend2();
47112
- recolorEvents2();
47113
- onTagStateChange?.(currentActiveGroup, currentSwimlaneGroup);
47114
- },
47115
- onEntryHover: (groupName, entryValue) => {
47116
- const tagKey = groupName.toLowerCase();
47117
- if (entryValue) {
47118
- const tagVal = entryValue.toLowerCase();
47119
- fadeToTagValue(mainG, tagKey, tagVal);
47120
- mainSvg.selectAll("[data-legend-entry]").each(function() {
47121
- const el = d3Selection22.select(this);
47122
- const ev = el.attr("data-legend-entry");
47123
- const eg = el.attr("data-tag-group") ?? el.node()?.closest?.("[data-tag-group]")?.getAttribute("data-tag-group");
47124
- el.attr(
47125
- "opacity",
47126
- eg === tagKey && ev === tagVal ? 1 : FADE_OPACITY3
47127
- );
47128
- });
47129
- } else {
47130
- fadeReset(mainG);
47131
- mainSvg.selectAll("[data-legend-entry]").attr("opacity", 1);
47132
- }
47133
- },
47134
- onGroupRendered: (groupName, groupEl, isActive) => {
47135
- const groupKey = groupName.toLowerCase();
47136
- groupEl.attr("data-tag-group", groupKey);
47137
- if (isActive && !viewMode) {
47138
- const isSwimActive = currentSwimlaneGroup != null && currentSwimlaneGroup.toLowerCase() === groupKey;
47139
- const pillWidth3 = measureLegendText(groupName, LG_PILL_FONT_SIZE) + LG_PILL_PAD;
47140
- const pillXOff = LG_CAPSULE_PAD;
47141
- const iconX = pillXOff + pillWidth3 + 5;
47142
- const iconY = (LG_HEIGHT - 10) / 2;
47143
- const iconEl = drawSwimlaneIcon4(
47144
- groupEl,
47145
- iconX,
47146
- iconY,
47147
- isSwimActive
47148
- );
47149
- iconEl.attr("data-swimlane-toggle", groupKey).on("click", (event) => {
47150
- event.stopPropagation();
47151
- currentSwimlaneGroup = currentSwimlaneGroup === groupKey ? null : groupKey;
47152
- onTagStateChange?.(
47153
- currentActiveGroup,
47154
- currentSwimlaneGroup
47155
- );
47156
- relayout2();
47157
- });
47158
- }
47159
- }
47160
- };
47161
- const legendInnerG = legendContainer.append("g").attr("transform", `translate(0, ${legendY})`);
47162
- renderLegendD3(
47163
- legendInnerG,
47164
- centralConfig,
47165
- centralState,
47166
- palette,
47167
- isDark,
47168
- centralCallbacks,
47169
- width
47170
- );
47171
- }, recolorEvents2 = function() {
47172
- const colorTG = currentActiveGroup ?? swimlaneTagGroup ?? null;
47173
- mainG.selectAll(".tl-event").each(function() {
47174
- const el = d3Selection22.select(this);
47175
- const lineNum = el.attr("data-line-number");
47176
- const ev = lineNum ? eventByLine.get(lineNum) : void 0;
47177
- if (!ev) return;
47178
- let color;
47179
- if (colorTG) {
47180
- const tagColor = resolveTagColor(
47181
- ev.metadata,
47182
- parsed.timelineTagGroups,
47183
- colorTG
47184
- );
47185
- color = tagColor ?? (ev.group && groupColorMap.has(ev.group) ? groupColorMap.get(ev.group) : textColor);
47186
- } else {
47187
- color = ev.group && groupColorMap.has(ev.group) ? groupColorMap.get(ev.group) : textColor;
47188
- }
47189
- el.selectAll("rect").attr("fill", shapeFill(palette, color, isDark, { solid })).attr("stroke", color);
47190
- el.selectAll("circle:not(.tl-event-point-outline)").attr("fill", shapeFill(palette, color, isDark, { solid })).attr("stroke", color);
47191
- });
47192
- };
47193
- var drawSwimlaneIcon3 = drawSwimlaneIcon4, relayout = relayout2, drawLegend = drawLegend2, recolorEvents = recolorEvents2;
47194
- const legendY = title ? 50 : 10;
47195
- const legendGroups = parsed.timelineTagGroups.map((g) => {
47196
- const pillW = measureLegendText(g.name, LG_PILL_FONT_SIZE) + LG_PILL_PAD;
47197
- const iconSpace = viewMode ? 8 : LG_ICON_W + 4;
47198
- let entryX = LG_CAPSULE_PAD + pillW + iconSpace;
47199
- for (const entry of g.entries) {
47200
- const textX = entryX + LG_DOT_R * 2 + LG_ENTRY_DOT_GAP;
47201
- entryX = textX + measureLegendText(entry.value, LG_ENTRY_FONT_SIZE) + LG_ENTRY_TRAIL;
47202
- }
47203
- return {
47204
- group: g,
47205
- minifiedWidth: pillW,
47206
- expandedWidth: entryX + LG_CAPSULE_PAD
47207
- };
47208
- });
47209
- let currentActiveGroup = activeTagGroup ?? null;
47210
- let currentSwimlaneGroup = swimlaneTagGroup ?? null;
47211
- const eventByLine = /* @__PURE__ */ new Map();
47212
- for (const ev of timelineEvents) {
47213
- eventByLine.set(String(ev.lineNumber), ev);
47380
+ evG.append("circle").attr("cx", axisX).attr("cy", y).attr("r", 4).attr("fill", shapeFill(palette, color, isDark, { solid })).attr("stroke", color).attr("stroke-width", 2);
47381
+ evG.append("text").attr("x", axisX + 16).attr("y", y).attr("dy", "0.35em").attr("fill", textColor).attr("font-size", "11px").text(ev.label);
47214
47382
  }
47215
- drawLegend2();
47383
+ evG.append("text").attr("x", axisX - 14).attr(
47384
+ "y",
47385
+ ev.endDate ? yScale(parseTimelineDate(ev.date)) + Math.max(
47386
+ yScale(parseTimelineDate(ev.endDate)) - yScale(parseTimelineDate(ev.date)),
47387
+ 4
47388
+ ) / 2 : y
47389
+ ).attr("dy", "0.35em").attr("text-anchor", "end").attr("fill", mutedColor).attr("font-size", "10px").text(ev.date + (ev.endDate ? `\u2192${ev.endDate}` : ""));
47216
47390
  }
47217
47391
  }
47218
47392
  }
47393
+ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportDims, activeTagGroup, swimlaneTagGroup, onTagStateChange, viewMode) {
47394
+ const setup = setupTimeline(
47395
+ container,
47396
+ parsed,
47397
+ palette,
47398
+ isDark,
47399
+ exportDims,
47400
+ activeTagGroup,
47401
+ swimlaneTagGroup
47402
+ );
47403
+ if (!setup) return;
47404
+ swimlaneTagGroup = setup.swimlaneTagGroup;
47405
+ const { isVertical, tagLanes } = setup;
47406
+ const hovers = makeTimelineHoverHelpers();
47407
+ if (isVertical) {
47408
+ renderTimelineVertical(
47409
+ container,
47410
+ parsed,
47411
+ palette,
47412
+ isDark,
47413
+ setup,
47414
+ hovers,
47415
+ onClickItem,
47416
+ exportDims,
47417
+ swimlaneTagGroup,
47418
+ activeTagGroup,
47419
+ onTagStateChange,
47420
+ viewMode
47421
+ );
47422
+ return;
47423
+ }
47424
+ const useGroupedHorizontal = tagLanes != null || parsed.timelineSort === "group" && parsed.timelineGroups.length > 0;
47425
+ if (useGroupedHorizontal) {
47426
+ renderTimelineHorizontalGrouped(
47427
+ container,
47428
+ parsed,
47429
+ palette,
47430
+ isDark,
47431
+ setup,
47432
+ hovers,
47433
+ onClickItem,
47434
+ exportDims,
47435
+ swimlaneTagGroup,
47436
+ activeTagGroup,
47437
+ onTagStateChange,
47438
+ viewMode
47439
+ );
47440
+ } else {
47441
+ renderTimelineHorizontalTimeSort(
47442
+ container,
47443
+ parsed,
47444
+ palette,
47445
+ isDark,
47446
+ setup,
47447
+ hovers,
47448
+ onClickItem,
47449
+ exportDims,
47450
+ swimlaneTagGroup,
47451
+ activeTagGroup,
47452
+ onTagStateChange,
47453
+ viewMode
47454
+ );
47455
+ }
47456
+ renderTimelineTagLegendOverlay(
47457
+ container,
47458
+ parsed,
47459
+ palette,
47460
+ isDark,
47461
+ setup,
47462
+ hovers,
47463
+ onClickItem,
47464
+ exportDims,
47465
+ swimlaneTagGroup,
47466
+ activeTagGroup,
47467
+ onTagStateChange,
47468
+ viewMode
47469
+ );
47470
+ }
47219
47471
  function getRotateFn(mode) {
47220
47472
  if (mode === "mixed") return () => Math.random() > 0.5 ? 0 : 90;
47221
47473
  if (mode === "angled") return () => Math.round(Math.random() * 30 - 15);
@@ -47339,7 +47591,7 @@ function regionCentroid(circles, inside) {
47339
47591
  }
47340
47592
  return { x: sx / count, y: sy / count };
47341
47593
  }
47342
- function renderVenn(container, parsed, palette, isDark, onClickItem, exportDims) {
47594
+ function renderVenn(container, parsed, palette, _isDark, onClickItem, exportDims) {
47343
47595
  const { vennSets, vennOverlaps } = parsed;
47344
47596
  const title = parsed.noTitle ? null : parsed.title;
47345
47597
  if (vennSets.length < 2 || vennSets.length > 3) return;
@@ -47573,7 +47825,7 @@ function renderVenn(container, parsed, palette, isDark, onClickItem, exportDims)
47573
47825
  };
47574
47826
  const gcx = circles.reduce((s, c) => s + c.x, 0) / n;
47575
47827
  const gcy = circles.reduce((s, c) => s + c.y, 0) / n;
47576
- function exclusiveHSpan(px, py, ci) {
47828
+ function exclusiveHSpan(_px, py, ci) {
47577
47829
  const dy = py - circles[ci].y;
47578
47830
  const halfChord = Math.sqrt(
47579
47831
  Math.max(0, circles[ci].r * circles[ci].r - dy * dy)
@@ -48486,9 +48738,9 @@ async function renderForExport(content, theme, palette, viewState, options) {
48486
48738
  blHiddenTagValues.set(k, new Set(v));
48487
48739
  }
48488
48740
  }
48489
- const { layoutBoxesAndLines: layoutBoxesAndLines2 } = await Promise.resolve().then(() => (init_layout5(), layout_exports5));
48490
48741
  const { renderBoxesAndLinesForExport: renderBoxesAndLinesForExport2 } = await Promise.resolve().then(() => (init_renderer6(), renderer_exports6));
48491
- const blLayout = layoutBoxesAndLines2(blParsed);
48742
+ const { layoutBoxesAndLines: layoutBoxesAndLines2 } = await Promise.resolve().then(() => (init_layout5(), layout_exports5));
48743
+ const blLayout = await layoutBoxesAndLines2(blParsed);
48492
48744
  const PADDING3 = 20;
48493
48745
  const titleOffset = blParsed.title ? 40 : 0;
48494
48746
  const exportWidth = blLayout.width + PADDING3 * 2;
@@ -49595,7 +49847,7 @@ init_dgmo_router();
49595
49847
  init_registry();
49596
49848
  async function ensureDom() {
49597
49849
  if (typeof document !== "undefined") return;
49598
- const { JSDOM } = await import("jsdom");
49850
+ const { JSDOM } = await loadJsdom();
49599
49851
  const dom = new JSDOM("<!DOCTYPE html><html><body></body></html>");
49600
49852
  const win = dom.window;
49601
49853
  Object.defineProperty(globalThis, "document", {
@@ -49619,6 +49871,14 @@ async function ensureDom() {
49619
49871
  configurable: true
49620
49872
  });
49621
49873
  }
49874
+ async function loadJsdom() {
49875
+ const spec = ["js", "dom"].join("");
49876
+ return import(
49877
+ /* @vite-ignore */
49878
+ /* webpackIgnore: true */
49879
+ spec
49880
+ );
49881
+ }
49622
49882
  async function render(content, options) {
49623
49883
  const theme = options?.theme ?? "light";
49624
49884
  const paletteName = options?.palette ?? "nord";
@@ -49800,6 +50060,7 @@ var DIRECTIVE_KEYWORDS = /* @__PURE__ */ new Set([
49800
50060
  "split",
49801
50061
  "slo-p90-latency-ms",
49802
50062
  "slo-availability",
50063
+ "slo-warning-margin",
49803
50064
  "cache-hit",
49804
50065
  "concurrency",
49805
50066
  "duration-ms",
@@ -50423,7 +50684,7 @@ pre.dgmo, code.language-dgmo, pre > code.language-dgmo,
50423
50684
 
50424
50685
  // src/auto/index.ts
50425
50686
  init_safe_href();
50426
- var VERSION = "0.14.1";
50687
+ var VERSION = "0.15.1";
50427
50688
  var DEFAULTS = {
50428
50689
  theme: "auto",
50429
50690
  palette: "nord",
@@ -50740,8 +51001,8 @@ function determineReplaceTarget(matched) {
50740
51001
  }
50741
51002
  async function processElement(el) {
50742
51003
  if (!(el instanceof HTMLElement)) return {};
50743
- if (el.dataset.dgmoProcessed === "true") return {};
50744
- el.dataset.dgmoProcessed = "true";
51004
+ if (el.dataset["dgmoProcessed"] === "true") return {};
51005
+ el.dataset["dgmoProcessed"] = "true";
50745
51006
  const source = el.textContent || "";
50746
51007
  const sourceBytes = new TextEncoder().encode(source).byteLength;
50747
51008
  if (sourceBytes > SOURCE_BYTE_CAP) {
@@ -50758,7 +51019,7 @@ async function processElement(el) {
50758
51019
  const resolvedTheme = cfg.theme === "transparent" ? "transparent" : resolveTheme(cfg.theme);
50759
51020
  const renderTheme = resolvedTheme === "transparent" ? "transparent" : resolvedTheme;
50760
51021
  const ariaLabel = deriveAriaLabel(source);
50761
- const perElementShowSource = el.dataset.showSource;
51022
+ const perElementShowSource = el.dataset["showSource"];
50762
51023
  let showSource = cfg.showSource;
50763
51024
  if (perElementShowSource === "true") showSource = true;
50764
51025
  else if (perElementShowSource === "false") showSource = false;
@@ -50808,7 +51069,7 @@ async function processElement(el) {
50808
51069
  const wrapper = document.createElement("div");
50809
51070
  const themeClass = resolvedTheme === "dark" ? "dgmo-theme-dark" : resolvedTheme === "transparent" ? "dgmo-theme-transparent" : "dgmo-theme-light";
50810
51071
  wrapper.className = `dgmo-rendered ${themeClass}`;
50811
- wrapper.dataset.dgmoProcessed = "true";
51072
+ wrapper.dataset["dgmoProcessed"] = "true";
50812
51073
  const svgHolder = document.createElement("div");
50813
51074
  svgHolder.innerHTML = result.svg;
50814
51075
  const svgEl = svgHolder.querySelector("svg");
@@ -50877,15 +51138,16 @@ function initialize(opts = {}) {
50877
51138
  }
50878
51139
  }
50879
51140
  const next = { ...activeConfig };
50880
- if (isValidTheme(opts.theme)) {
50881
- next.theme = opts.theme;
51141
+ if (isValidTheme(opts["theme"])) {
51142
+ next.theme = opts["theme"];
50882
51143
  }
50883
- if (typeof opts.palette === "string" && paletteExists(opts.palette)) {
50884
- next.palette = opts.palette;
51144
+ if (typeof opts["palette"] === "string" && paletteExists(opts["palette"])) {
51145
+ next.palette = opts["palette"];
50885
51146
  }
50886
- if (typeof opts.showSource === "boolean") next.showSource = opts.showSource;
50887
- if (typeof opts.showEditorLink === "boolean")
50888
- next.showEditorLink = opts.showEditorLink;
51147
+ if (typeof opts["showSource"] === "boolean")
51148
+ next.showSource = opts["showSource"];
51149
+ if (typeof opts["showEditorLink"] === "boolean")
51150
+ next.showEditorLink = opts["showEditorLink"];
50889
51151
  activeConfig = next;
50890
51152
  }
50891
51153
  async function run(opts = {}) {
@@ -50924,7 +51186,7 @@ function rerenderAllForTheme() {
50924
51186
  placeholder.className = "dgmo";
50925
51187
  placeholder.textContent = t.source;
50926
51188
  if (t.perElementShowSource !== null) {
50927
- placeholder.dataset.showSource = String(t.perElementShowSource);
51189
+ placeholder.dataset["showSource"] = String(t.perElementShowSource);
50928
51190
  }
50929
51191
  t.wrapper.replaceWith(placeholder);
50930
51192
  wrappers.delete(t);
@@ -50951,7 +51213,7 @@ function unhideAllSources() {
50951
51213
  el.style.visibility = "visible";
50952
51214
  });
50953
51215
  if (document.documentElement && document.documentElement.dataset) {
50954
- document.documentElement.dataset.dgmoAutoFailed = "1";
51216
+ document.documentElement.dataset["dgmoAutoFailed"] = "1";
50955
51217
  }
50956
51218
  }
50957
51219
  function bootstrap() {