@diagrammo/dgmo 0.36.0 → 0.38.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/.cursorrules +3 -0
  2. package/.github/copilot-instructions.md +3 -0
  3. package/.windsurfrules +3 -0
  4. package/SKILL.md +3 -0
  5. package/dist/advanced.cjs +1058 -135
  6. package/dist/advanced.d.cts +122 -8
  7. package/dist/advanced.d.ts +122 -8
  8. package/dist/advanced.js +1055 -133
  9. package/dist/auto.cjs +1047 -132
  10. package/dist/auto.js +96 -95
  11. package/dist/auto.mjs +1048 -130
  12. package/dist/cli.cjs +117 -116
  13. package/dist/editor.cjs +4 -1
  14. package/dist/editor.js +4 -1
  15. package/dist/highlight.cjs +3 -0
  16. package/dist/highlight.js +3 -0
  17. package/dist/index.cjs +1043 -131
  18. package/dist/index.js +1044 -129
  19. package/docs/ai-integration.md +3 -0
  20. package/docs/language-reference.md +106 -7
  21. package/gallery/fixtures/map-coastline.dgmo +2 -2
  22. package/gallery/fixtures/map-route.dgmo +5 -5
  23. package/gallery/fixtures/treemap-branch.dgmo +15 -0
  24. package/gallery/fixtures/treemap-heat.dgmo +12 -0
  25. package/gallery/fixtures/treemap-tag-heat.dgmo +21 -0
  26. package/gallery/fixtures/treemap-tags.dgmo +18 -0
  27. package/package.json +1 -1
  28. package/src/advanced.ts +11 -0
  29. package/src/boxes-and-lines/layout-search.ts +19 -1
  30. package/src/chart-type-registry.ts +4 -0
  31. package/src/chart-types.ts +5 -0
  32. package/src/completion.ts +64 -0
  33. package/src/d3.ts +30 -18
  34. package/src/editor/highlight-api.ts +2 -0
  35. package/src/editor/keywords.ts +3 -0
  36. package/src/infra/parser.ts +95 -38
  37. package/src/map/dimensions.ts +19 -2
  38. package/src/map/layout.ts +91 -7
  39. package/src/map/parser.ts +51 -29
  40. package/src/map/renderer.ts +10 -0
  41. package/src/map/types.ts +9 -8
  42. package/src/treemap/layout.ts +189 -0
  43. package/src/treemap/parser.ts +475 -0
  44. package/src/treemap/renderer.ts +698 -0
  45. package/src/treemap/types.ts +57 -0
  46. package/src/utils/parsing.ts +1 -0
  47. package/src/utils/reserved-key-registry.ts +5 -0
package/dist/advanced.cjs CHANGED
@@ -699,7 +699,7 @@ function withTagAliases(base, aliases) {
699
699
  function isReservedKey(registry, key) {
700
700
  return registry.keys.has(key) || registry.tagAliases.has(key);
701
701
  }
702
- var SEQUENCE_REGISTRY, INFRA_REGISTRY, MAP_REGISTRY, ORG_REGISTRY, C4_REGISTRY, ER_REGISTRY, KANBAN_REGISTRY, SITEMAP_REGISTRY, GANTT_REGISTRY, PERT_REGISTRY, BOXES_AND_LINES_REGISTRY, TIMELINE_REGISTRY, MINDMAP_REGISTRY, TECH_RADAR_REGISTRY, CYCLE_REGISTRY, JOURNEY_MAP_REGISTRY, PYRAMID_REGISTRY, RING_REGISTRY, RACI_REGISTRY;
702
+ var SEQUENCE_REGISTRY, INFRA_REGISTRY, MAP_REGISTRY, ORG_REGISTRY, C4_REGISTRY, ER_REGISTRY, KANBAN_REGISTRY, SITEMAP_REGISTRY, GANTT_REGISTRY, PERT_REGISTRY, BOXES_AND_LINES_REGISTRY, TIMELINE_REGISTRY, MINDMAP_REGISTRY, TECH_RADAR_REGISTRY, CYCLE_REGISTRY, JOURNEY_MAP_REGISTRY, PYRAMID_REGISTRY, RING_REGISTRY, TREEMAP_REGISTRY, RACI_REGISTRY;
703
703
  var init_reserved_key_registry = __esm({
704
704
  "src/utils/reserved-key-registry.ts"() {
705
705
  "use strict";
@@ -818,6 +818,7 @@ var init_reserved_key_registry = __esm({
818
818
  "color",
819
819
  "description"
820
820
  ]);
821
+ TREEMAP_REGISTRY = staticRegistry(["heat"]);
821
822
  RACI_REGISTRY = staticRegistry([
822
823
  "color",
823
824
  "description"
@@ -1247,6 +1248,7 @@ var init_parsing = __esm({
1247
1248
  "journey-map",
1248
1249
  "pyramid",
1249
1250
  "ring",
1251
+ "treemap",
1250
1252
  "raci",
1251
1253
  "rasci",
1252
1254
  "daci",
@@ -11845,6 +11847,10 @@ var init_chart_types = __esm({
11845
11847
  id: "ring",
11846
11848
  description: "Concentric rings showing nested or hierarchical categories (read core-out)"
11847
11849
  },
11850
+ {
11851
+ id: "treemap",
11852
+ description: "Nested rectangles sized by value \u2014 show a hierarchy\u2019s proportions (budgets, disk usage, portfolios) with color by category, value heatmap, or branch"
11853
+ },
11848
11854
  {
11849
11855
  id: "map",
11850
11856
  description: "Geographic concept map: highlight/score regions, drop points of interest, connect with routes or edges"
@@ -16714,6 +16720,7 @@ function parseInfra(content) {
16714
16720
  let currentGroup = null;
16715
16721
  let currentTagGroup = null;
16716
16722
  let baseIndent = 0;
16723
+ let firstLineConsumed = false;
16717
16724
  function finishCurrentNode() {
16718
16725
  if (!currentNode) return;
16719
16726
  const key = currentNode.id;
@@ -16721,7 +16728,8 @@ function parseInfra(content) {
16721
16728
  if (existing) {
16722
16729
  const incomingDisplay = displayName(currentNode.label);
16723
16730
  const existingDisplay = displayName(existing.label);
16724
- if (incomingDisplay !== existingDisplay) {
16731
+ const isAliasRef = nameAliasMap.get(currentNode.label) === key;
16732
+ if (incomingDisplay !== existingDisplay && !isAliasRef) {
16725
16733
  result.diagnostics.push(
16726
16734
  makeDgmoError(
16727
16735
  currentNode.lineNumber,
@@ -16787,19 +16795,22 @@ function parseInfra(content) {
16787
16795
  if (indent === 0 && currentNode && !trimmed.startsWith("-")) {
16788
16796
  finishCurrentNode();
16789
16797
  }
16790
- const firstLineResult = parseFirstLine(trimmed);
16791
- if (firstLineResult) {
16792
- if (firstLineResult.chartType !== "infra") {
16793
- setError(
16794
- lineNumber,
16795
- `Expected chart type 'infra', got '${firstLineResult.chartType}'`
16796
- );
16797
- }
16798
- if (firstLineResult.title) {
16799
- result.title = firstLineResult.title;
16800
- result.titleLineNumber = lineNumber;
16798
+ if (!firstLineConsumed) {
16799
+ firstLineConsumed = true;
16800
+ const firstLineResult = parseFirstLine(trimmed);
16801
+ if (firstLineResult) {
16802
+ if (firstLineResult.chartType !== "infra") {
16803
+ setError(
16804
+ lineNumber,
16805
+ `Expected chart type 'infra', got '${firstLineResult.chartType}'`
16806
+ );
16807
+ }
16808
+ if (firstLineResult.title) {
16809
+ result.title = firstLineResult.title;
16810
+ result.titleLineNumber = lineNumber;
16811
+ }
16812
+ continue;
16801
16813
  }
16802
- continue;
16803
16814
  }
16804
16815
  if (/^direction-tb$/i.test(trimmed)) {
16805
16816
  result.direction = "TB";
@@ -16865,18 +16876,20 @@ function parseInfra(content) {
16865
16876
  if (compMatch) {
16866
16877
  finishCurrentNode();
16867
16878
  finishCurrentTagGroup();
16868
- const rawName = (compMatch[1] ?? compMatch[2] ?? "").trim();
16879
+ const { qname, uname, alias: asAlias, meta } = compMatch.groups;
16880
+ const rawName = (qname ?? uname ?? "").trim();
16869
16881
  const peeled = peelInfraDecorations(rawName, lineNumber);
16870
16882
  const name = peeled.label;
16871
- const rest = compMatch[3] || "";
16883
+ const alias = asAlias ?? peeled.alias;
16884
+ const rest = meta ?? "";
16872
16885
  const { tags } = extractPipeMetadata(rest);
16873
16886
  warnUnknownMetaKeys(
16874
16887
  tags,
16875
16888
  withTagAliases(INFRA_REGISTRY, tagAliasSet),
16876
16889
  (msg) => warn(lineNumber, msg)
16877
16890
  );
16878
- const id = nodeId2(name);
16879
- if (peeled.alias) nameAliasMap.set(peeled.alias, id);
16891
+ const id = nameAliasMap.get(name) ?? nodeId2(name);
16892
+ if (alias) nameAliasMap.set(alias, id);
16880
16893
  const isEdge = EDGE_NODE_NAMES.has(id.toLowerCase());
16881
16894
  currentNode = {
16882
16895
  id,
@@ -16960,18 +16973,20 @@ function parseInfra(content) {
16960
16973
  const compMatch = trimmed.match(COMPONENT_RE);
16961
16974
  if (compMatch) {
16962
16975
  finishCurrentTagGroup();
16963
- const rawName = (compMatch[1] ?? compMatch[2] ?? "").trim();
16976
+ const { qname, uname, alias: asAlias, meta } = compMatch.groups;
16977
+ const rawName = (qname ?? uname ?? "").trim();
16964
16978
  const peeled = peelInfraDecorations(rawName, lineNumber);
16965
16979
  const name = peeled.label;
16966
- const rest = compMatch[3] || "";
16980
+ const alias = asAlias ?? peeled.alias;
16981
+ const rest = meta ?? "";
16967
16982
  const { tags: nodeTags } = extractPipeMetadata(rest);
16968
16983
  warnUnknownMetaKeys(
16969
16984
  nodeTags,
16970
16985
  withTagAliases(INFRA_REGISTRY, tagAliasSet),
16971
16986
  (msg) => warn(lineNumber, msg)
16972
16987
  );
16973
- const id = nodeId2(name);
16974
- if (peeled.alias) nameAliasMap.set(peeled.alias, id);
16988
+ const id = nameAliasMap.get(name) ?? nodeId2(name);
16989
+ if (alias) nameAliasMap.set(alias, id);
16975
16990
  const tags = currentGroup.metadata ? { ...currentGroup.metadata, ...nodeTags } : nodeTags;
16976
16991
  currentNode = {
16977
16992
  id,
@@ -17162,6 +17177,11 @@ function parseInfra(content) {
17162
17177
  }
17163
17178
  continue;
17164
17179
  }
17180
+ if (currentNode && tagAliasSet.has(normalizeName(key))) {
17181
+ const mut = nodeMutableTags.get(currentNode.id);
17182
+ if (mut) mut[tagAttrKey(key)] = rawVal;
17183
+ continue;
17184
+ }
17165
17185
  if (!INFRA_BEHAVIOR_KEYS.has(key) && !EDGE_ONLY_KEYS.has(key)) {
17166
17186
  const allKeys = [...INFRA_BEHAVIOR_KEYS, ...EDGE_ONLY_KEYS];
17167
17187
  const hint = suggest(key, allKeys);
@@ -17227,18 +17247,20 @@ function parseInfra(content) {
17227
17247
  finishCurrentNode();
17228
17248
  const compMatch = trimmed.match(COMPONENT_RE);
17229
17249
  if (compMatch) {
17230
- const rawName = (compMatch[1] ?? compMatch[2] ?? "").trim();
17250
+ const { qname, uname, alias: asAlias, meta } = compMatch.groups;
17251
+ const rawName = (qname ?? uname ?? "").trim();
17231
17252
  const peeled = peelInfraDecorations(rawName, lineNumber);
17232
17253
  const name = peeled.label;
17233
- const rest = compMatch[3] || "";
17254
+ const alias = asAlias ?? peeled.alias;
17255
+ const rest = meta ?? "";
17234
17256
  const { tags: nodeTags } = extractPipeMetadata(rest);
17235
17257
  warnUnknownMetaKeys(
17236
17258
  nodeTags,
17237
17259
  withTagAliases(INFRA_REGISTRY, tagAliasSet),
17238
17260
  (msg) => warn(lineNumber, msg)
17239
17261
  );
17240
- const id = nodeId2(name);
17241
- if (peeled.alias) nameAliasMap.set(peeled.alias, id);
17262
+ const id = nameAliasMap.get(name) ?? nodeId2(name);
17263
+ if (alias) nameAliasMap.set(alias, id);
17242
17264
  const tags = currentGroup.metadata ? { ...currentGroup.metadata, ...nodeTags } : nodeTags;
17243
17265
  currentNode = {
17244
17266
  id,
@@ -17260,18 +17282,20 @@ function parseInfra(content) {
17260
17282
  finishCurrentNode();
17261
17283
  finishCurrentTagGroup();
17262
17284
  currentGroup = null;
17263
- const rawName = (compMatch[1] ?? compMatch[2] ?? "").trim();
17285
+ const { qname, uname, alias: asAlias, meta } = compMatch.groups;
17286
+ const rawName = (qname ?? uname ?? "").trim();
17264
17287
  const peeled = peelInfraDecorations(rawName, lineNumber);
17265
17288
  const name = peeled.label;
17266
- const rest = compMatch[3] || "";
17289
+ const alias = asAlias ?? peeled.alias;
17290
+ const rest = meta ?? "";
17267
17291
  const { tags } = extractPipeMetadata(rest);
17268
17292
  warnUnknownMetaKeys(
17269
17293
  tags,
17270
17294
  withTagAliases(INFRA_REGISTRY, tagAliasSet),
17271
17295
  (msg) => warn(lineNumber, msg)
17272
17296
  );
17273
- const id = nodeId2(name);
17274
- if (peeled.alias) nameAliasMap.set(peeled.alias, id);
17297
+ const id = nameAliasMap.get(name) ?? nodeId2(name);
17298
+ if (alias) nameAliasMap.set(alias, id);
17275
17299
  currentNode = {
17276
17300
  id,
17277
17301
  label: name,
@@ -17471,7 +17495,7 @@ var init_parser15 = __esm({
17471
17495
  DEPRECATED_FANOUT_RE = /\bx(\d+)\s*$/;
17472
17496
  GROUP_RE = /^\[([^\]]+)\]\s*(?:as\s+([A-Za-z][A-Za-z0-9_]{0,11})\s*)?((?:\|.*)|(?:[a-zA-Z_]\w*\s*:.*))?$/;
17473
17497
  TAG_VALUE_RE = /^(\w[\w\s]+?)\s*$/;
17474
- COMPONENT_RE = /^(?:"([^"]+)"|([a-zA-Z_][\w -]*?))\s*((?:\|.*)|(?:[a-zA-Z_]\w*\s*:.*))?$/;
17498
+ COMPONENT_RE = /^(?:"(?<qname>[^"]+)"|(?<uname>[a-zA-Z_][\w -]*?))(?:\s+as\s+(?<alias>[A-Za-z][A-Za-z0-9_]{0,11}))?\s*(?<meta>(?:\|.*)|(?:[a-zA-Z_]\w*\s*:.*))?$/;
17475
17499
  PIPE_META_RE = /[|,]\s*(\w+)\s*:\s*([^|,]+)/g;
17476
17500
  SAMELINE_META_RE = /(?:^|[\s,])(\w+)\s*:\s*([^,]+?)(?=\s*,|\s*$)/g;
17477
17501
  PROPERTY_RE = /^([\w-]+):\s*(.+)$/;
@@ -18955,8 +18979,8 @@ function parseMap(content, palette) {
18955
18979
  continue;
18956
18980
  }
18957
18981
  if (open.route && indent > open.route.indent) {
18958
- const leg = parseLeg(trimmed, lineNumber, open.route.route.style);
18959
- open.route.route.legs.push(leg);
18982
+ const leg = parseLeg(trimmed, lineNumber);
18983
+ if (leg) open.route.route.legs.push(leg);
18960
18984
  continue;
18961
18985
  }
18962
18986
  if (open.poi && indent > open.poi.indent) {
@@ -18985,6 +19009,14 @@ function parseMap(content, palette) {
18985
19009
  Object.assign(open.poi.poi.meta, split.meta);
18986
19010
  continue;
18987
19011
  }
19012
+ if (split.name) {
19013
+ const src = open.poi.poi.alias ?? poiName(open.poi.poi.pos) ?? "the poi";
19014
+ pushError(
19015
+ lineNumber,
19016
+ `Malformed hub edge: "${trimmed}" \u2014 an indented line under a poi is an edge from "${src}" and needs an arrow glyph (\`-> dest\`, \`~> dest\`, or labeled \`-label-> dest\`). For a standalone place, declare it at the top level. (\xA724B.5)`
19017
+ );
19018
+ continue;
19019
+ }
18988
19020
  }
18989
19021
  closeBlocks();
18990
19022
  const firstWord = trimmed.split(/\s+/)[0];
@@ -18993,7 +19025,7 @@ function parseMap(content, palette) {
18993
19025
  continue;
18994
19026
  }
18995
19027
  if (DIRECTIVE_SET.has(firstWord) && !trimmed.slice(firstWord.length).trimStart().startsWith(":")) {
18996
- handleDirective(
19028
+ handleDirective2(
18997
19029
  firstWord,
18998
19030
  trimmed.slice(firstWord.length).trim(),
18999
19031
  lineNumber
@@ -19032,7 +19064,7 @@ function parseMap(content, palette) {
19032
19064
  }
19033
19065
  }
19034
19066
  return result;
19035
- function handleDirective(key, value, line11) {
19067
+ function handleDirective2(key, value, line11) {
19036
19068
  const d = result.directives;
19037
19069
  const dup = (have) => {
19038
19070
  if (have !== void 0)
@@ -19233,31 +19265,44 @@ function parseMap(content, palette) {
19233
19265
  const { tags, meta } = partitionMeta(split.meta, tagGroupNames());
19234
19266
  const originLabel = meta["label"];
19235
19267
  const originValue = meta["value"];
19236
- const style = meta["style"] === "arc" ? "arc" : "straight";
19268
+ if (meta["style"] !== void 0) {
19269
+ pushError(
19270
+ line11,
19271
+ "route header no longer takes `style:` \u2014 set leg shape with the arrow glyph instead (`~\u2026~>` for an arc leg, `-\u2026->` for a straight one). (\xA724B.6)"
19272
+ );
19273
+ }
19237
19274
  const route = {
19238
19275
  origin: pos,
19239
19276
  ...split.alias !== void 0 && { originAlias: split.alias },
19240
19277
  ...originLabel !== void 0 && { originLabel },
19241
19278
  ...originValue !== void 0 && { originValue },
19242
19279
  originTags: tags,
19243
- style,
19244
19280
  legs: [],
19245
19281
  lineNumber: line11
19246
19282
  };
19247
19283
  routes.push(route);
19248
19284
  open.route = { route, indent };
19249
19285
  }
19250
- function parseLeg(trimmed, line11, headerStyle) {
19251
- let arrowStyle = "straight";
19252
- let label;
19253
- let rest = trimmed;
19286
+ function parseLeg(trimmed, line11) {
19254
19287
  const m = trimmed.match(LEG_ARROW_RE);
19255
- if (m) {
19256
- const arr = classifyArrow(m[1], line11);
19257
- arrowStyle = arr.style;
19258
- label = arr.label;
19259
- rest = m[2];
19288
+ if (!m) {
19289
+ pushError(
19290
+ line11,
19291
+ `Malformed route leg: "${trimmed}" \u2014 a leg needs an arrow glyph (\`-> dest\`, \`~> dest\`, or labeled \`-label-> dest\` / \`~label~> dest\`). (\xA724B.6)`
19292
+ );
19293
+ return null;
19260
19294
  }
19295
+ const arr = classifyArrow(m[1], line11);
19296
+ if (!arr.directed) {
19297
+ pushError(
19298
+ line11,
19299
+ `A route leg is directional \u2014 "${trimmed}" uses an undirected glyph; use \`-> \` (straight) or \`~> \` (arc). (\xA724B.6)`
19300
+ );
19301
+ return null;
19302
+ }
19303
+ const arrowStyle = arr.style;
19304
+ const label = arr.label;
19305
+ const rest = m[2];
19261
19306
  const split = splitNameAndMeta(
19262
19307
  rest,
19263
19308
  registry(),
@@ -19273,10 +19318,9 @@ function parseMap(content, palette) {
19273
19318
  const { tags, meta } = partitionMeta(split.meta, tagGroupNames());
19274
19319
  const value = meta["value"];
19275
19320
  const destLabel = meta["label"];
19276
- const style = arrowStyle === "arc" || headerStyle === "arc" ? "arc" : "straight";
19277
19321
  return {
19278
19322
  ...label !== void 0 && { label },
19279
- style,
19323
+ style: arrowStyle,
19280
19324
  ...value !== void 0 && { value },
19281
19325
  dest: pos,
19282
19326
  ...split.alias !== void 0 && { destAlias: split.alias },
@@ -22890,6 +22934,344 @@ var init_parser25 = __esm({
22890
22934
  }
22891
22935
  });
22892
22936
 
22937
+ // src/treemap/parser.ts
22938
+ var parser_exports20 = {};
22939
+ __export(parser_exports20, {
22940
+ TREEMAP_DIAGNOSTIC_CODES: () => TREEMAP_DIAGNOSTIC_CODES,
22941
+ parseTreemap: () => parseTreemap
22942
+ });
22943
+ function isFullyQuoted(s) {
22944
+ return s.length >= 2 && (s.startsWith('"') && s.endsWith('"') || s.startsWith("'") && s.endsWith("'"));
22945
+ }
22946
+ function parseTreemap(content, palette) {
22947
+ const options = {
22948
+ heatColors: [],
22949
+ noValues: false,
22950
+ noPercent: false,
22951
+ noHeaders: false,
22952
+ noLegend: false
22953
+ };
22954
+ const result = {
22955
+ type: "treemap",
22956
+ title: null,
22957
+ titleLineNumber: null,
22958
+ roots: [],
22959
+ tagGroups: [],
22960
+ hasHeat: false,
22961
+ defaultColorMode: "branch",
22962
+ options,
22963
+ diagnostics: [],
22964
+ error: null
22965
+ };
22966
+ const fail = makeFail(result);
22967
+ const pushError = (line11, message, code) => {
22968
+ const diag = makeDgmoError(line11, message, "error", code);
22969
+ result.diagnostics.push(diag);
22970
+ if (!result.error) result.error = formatDgmoError(diag);
22971
+ };
22972
+ const pushWarning = (line11, message, code) => {
22973
+ result.diagnostics.push(makeDgmoError(line11, message, "warning", code));
22974
+ };
22975
+ if (!content?.trim()) {
22976
+ return fail(0, "No content provided");
22977
+ }
22978
+ const lines = content.split("\n");
22979
+ let contentStarted = false;
22980
+ let nodeCounter = 0;
22981
+ let currentTagGroup = null;
22982
+ const aliasMap = /* @__PURE__ */ new Map();
22983
+ const indentStack = [];
22984
+ for (let i = 0; i < lines.length; i++) {
22985
+ const line11 = lines[i];
22986
+ const lineNumber = i + 1;
22987
+ const trimmed = line11.trim();
22988
+ if (!trimmed) {
22989
+ currentTagGroup = null;
22990
+ continue;
22991
+ }
22992
+ if (trimmed.startsWith("//")) continue;
22993
+ if (!contentStarted) {
22994
+ const firstLine = parseFirstLine(trimmed);
22995
+ if (firstLine && result.titleLineNumber === null && i === 0) {
22996
+ if (firstLine.chartType !== "treemap") {
22997
+ let msg = `Expected chart type "treemap", got "${firstLine.chartType}"`;
22998
+ const hint = suggest(firstLine.chartType, ["treemap"]);
22999
+ if (hint) msg += `. ${hint}`;
23000
+ return fail(lineNumber, msg);
23001
+ }
23002
+ result.title = firstLine.title ?? null;
23003
+ result.titleLineNumber = lineNumber;
23004
+ continue;
23005
+ }
23006
+ }
23007
+ const tagBlockMatch = matchTagBlockHeading(trimmed);
23008
+ if (tagBlockMatch) {
23009
+ emitTagLegacyDiagnostic(tagBlockMatch, lineNumber, result.diagnostics);
23010
+ if (contentStarted) {
23011
+ pushError(
23012
+ lineNumber,
23013
+ "Tag groups must appear before treemap content",
23014
+ "E_TAG_DECLARED_AFTER_CONTENT"
23015
+ );
23016
+ continue;
23017
+ }
23018
+ currentTagGroup = {
23019
+ name: tagBlockMatch.name,
23020
+ ...tagBlockMatch.alias !== void 0 && {
23021
+ alias: tagBlockMatch.alias
23022
+ },
23023
+ entries: [],
23024
+ lineNumber
23025
+ };
23026
+ if (tagBlockMatch.alias) {
23027
+ aliasMap.set(
23028
+ tagBlockMatch.alias.toLowerCase(),
23029
+ tagAttrKey(tagBlockMatch.name)
23030
+ );
23031
+ }
23032
+ aliasMap.set(
23033
+ tagAttrKey(tagBlockMatch.name),
23034
+ tagAttrKey(tagBlockMatch.name)
23035
+ );
23036
+ result.tagGroups.push(currentTagGroup);
23037
+ continue;
23038
+ }
23039
+ if (currentTagGroup && !contentStarted) {
23040
+ const indent2 = measureIndent(line11);
23041
+ if (indent2 > 0) {
23042
+ const { text: cleanEntry, isDefault } = stripDefaultModifier(trimmed);
23043
+ const { label, color } = extractColor(
23044
+ cleanEntry,
23045
+ palette,
23046
+ result.diagnostics,
23047
+ lineNumber
23048
+ );
23049
+ if (isDefault) {
23050
+ currentTagGroup.defaultValue = label;
23051
+ } else if (currentTagGroup.entries.length === 0) {
23052
+ currentTagGroup.defaultValue = label;
23053
+ }
23054
+ currentTagGroup.entries.push({
23055
+ value: label,
23056
+ color: color ?? AUTO_TAG_COLOR_SENTINEL,
23057
+ lineNumber
23058
+ });
23059
+ continue;
23060
+ }
23061
+ currentTagGroup = null;
23062
+ }
23063
+ if (!contentStarted && measureIndent(line11) === 0) {
23064
+ if (handleDirective(trimmed, options, result, pushWarning, lineNumber)) {
23065
+ continue;
23066
+ }
23067
+ }
23068
+ contentStarted = true;
23069
+ currentTagGroup = null;
23070
+ const indent = measureIndent(line11);
23071
+ const node = parseNodeLine3(
23072
+ trimmed,
23073
+ lineNumber,
23074
+ ++nodeCounter,
23075
+ aliasMap,
23076
+ result.diagnostics,
23077
+ pushWarning
23078
+ );
23079
+ if (node.heat !== void 0) result.hasHeat = true;
23080
+ attachNode4(node, indent, indentStack, result);
23081
+ }
23082
+ finalizeAutoTagColors(result.tagGroups, palette);
23083
+ const allNodes = [];
23084
+ const collectAll = (nodes) => {
23085
+ for (const n of nodes) {
23086
+ allNodes.push(n);
23087
+ collectAll(n.children);
23088
+ }
23089
+ };
23090
+ collectAll(result.roots);
23091
+ for (const n of allNodes) {
23092
+ const node = n;
23093
+ const isBranch = node.children.length > 0;
23094
+ if (isBranch) {
23095
+ if (node.value !== void 0) {
23096
+ pushWarning(
23097
+ node.lineNumber,
23098
+ `"${node.label}" is a branch \u2014 its trailing number is ignored; the area is the auto-sum of its children`,
23099
+ TREEMAP_DIAGNOSTIC_CODES.BRANCH_VALUE_IGNORED
23100
+ );
23101
+ delete node.value;
23102
+ }
23103
+ } else if (node.value === void 0) {
23104
+ pushWarning(
23105
+ node.lineNumber,
23106
+ `Leaf "${node.label}" has no value \u2014 it renders with zero area`,
23107
+ TREEMAP_DIAGNOSTIC_CODES.LEAF_NO_VALUE
23108
+ );
23109
+ node.value = 0;
23110
+ } else if (node.value < 0) {
23111
+ pushError(
23112
+ node.lineNumber,
23113
+ `Leaf "${node.label}" has a negative value (${node.value}) \u2014 treemap sizes must be \u2265 0`,
23114
+ TREEMAP_DIAGNOSTIC_CODES.NEGATIVE_VALUE
23115
+ );
23116
+ }
23117
+ }
23118
+ if (result.hasHeat || options.heatLabel !== void 0) {
23119
+ result.hasHeat = true;
23120
+ }
23121
+ if (result.tagGroups.length > 0) {
23122
+ validateTagValues(allNodes, result.tagGroups, pushWarning, suggest);
23123
+ validateTagGroupNames(result.tagGroups, pushWarning);
23124
+ cascadeTagMetadata(result.roots, result.tagGroups);
23125
+ }
23126
+ result.defaultColorMode = resolveDefaultColorMode(result);
23127
+ if (result.roots.length === 0 && !result.error) {
23128
+ const diag = makeDgmoError(1, "No nodes found in treemap");
23129
+ result.diagnostics.push(diag);
23130
+ result.error = formatDgmoError(diag);
23131
+ }
23132
+ return result;
23133
+ }
23134
+ function handleDirective(trimmed, options, result, pushWarning, lineNumber) {
23135
+ const depthMatch = trimmed.match(/^depth\s+(-?\d+)\s*$/i);
23136
+ if (depthMatch) {
23137
+ const n = parseInt(depthMatch[1], 10);
23138
+ if (n >= 1) options.maxDepth = n;
23139
+ else pushWarning(lineNumber, '"depth" must be \u2265 1 \u2014 ignored');
23140
+ return true;
23141
+ }
23142
+ if (/^other-below\b/i.test(trimmed)) {
23143
+ pushWarning(
23144
+ lineNumber,
23145
+ '"other-below" is no longer supported \u2014 remove this line'
23146
+ );
23147
+ return true;
23148
+ }
23149
+ const heatMatch = trimmed.match(/^heat\s+(.+)$/i);
23150
+ if (heatMatch) {
23151
+ const { label, low, high } = peelRampColors(heatMatch[1].trim());
23152
+ options.heatLabel = label || "Value";
23153
+ const colors = [];
23154
+ if (low !== void 0) colors.push(low);
23155
+ if (high !== void 0) colors.push(high);
23156
+ options.heatColors = colors;
23157
+ result.hasHeat = true;
23158
+ return true;
23159
+ }
23160
+ const noMatch = trimmed.match(/^no-(values|percent|headers|legend)\s*$/i);
23161
+ if (noMatch) {
23162
+ const key = noMatch[1].toLowerCase();
23163
+ if (key === "values") options.noValues = true;
23164
+ else if (key === "percent") options.noPercent = true;
23165
+ else if (key === "headers") options.noHeaders = true;
23166
+ else if (key === "legend") options.noLegend = true;
23167
+ return true;
23168
+ }
23169
+ return false;
23170
+ }
23171
+ function resolveDefaultColorMode(result) {
23172
+ if (result.tagGroups.length > 0) return "tag";
23173
+ if (result.hasHeat) return "heat";
23174
+ return "branch";
23175
+ }
23176
+ function parseNodeLine3(trimmed, lineNumber, counter, aliasMap, diagnostics, pushWarning) {
23177
+ if (trimmed.includes("|")) {
23178
+ diagnostics.push(
23179
+ makeDgmoError(
23180
+ lineNumber,
23181
+ pipeOperatorRemovedMessage(),
23182
+ "error",
23183
+ METADATA_DIAGNOSTIC_CODES.PIPE_OPERATOR_REMOVED
23184
+ )
23185
+ );
23186
+ }
23187
+ const registry = withTagAliases(TREEMAP_REGISTRY, new Set(aliasMap.keys()));
23188
+ const split = splitNameAndMeta(
23189
+ trimmed,
23190
+ registry,
23191
+ aliasMap,
23192
+ void 0,
23193
+ diagnostics,
23194
+ lineNumber
23195
+ );
23196
+ warnUnknownMetaKeys(
23197
+ split.meta,
23198
+ registry,
23199
+ (msg) => diagnostics.push(makeDgmoError(lineNumber, msg, "warning")),
23200
+ split.name
23201
+ );
23202
+ const metadata = { ...split.meta };
23203
+ let heat;
23204
+ if ("heat" in metadata) {
23205
+ const h = parseFloat(metadata["heat"].replace(/_/g, ""));
23206
+ if (Number.isFinite(h)) heat = h;
23207
+ delete metadata["heat"];
23208
+ }
23209
+ const rawName = split.name;
23210
+ let label;
23211
+ let value;
23212
+ if (isFullyQuoted(rawName)) {
23213
+ label = stripQuotes(rawName);
23214
+ } else {
23215
+ const vm = rawName.match(VALUE_TOKEN_RE);
23216
+ if (vm) {
23217
+ const labelPart = vm[1].trim();
23218
+ const token = vm[2];
23219
+ if (token.includes(",")) {
23220
+ pushWarning(lineNumber, dataCommaRemovedMessage(labelPart));
23221
+ }
23222
+ const cleaned = token.replace(/[_,]/g, "");
23223
+ const parsed = parseFloat(cleaned);
23224
+ if (Number.isFinite(parsed)) {
23225
+ value = parsed;
23226
+ label = isFullyQuoted(labelPart) ? stripQuotes(labelPart) : labelPart;
23227
+ } else {
23228
+ label = rawName;
23229
+ }
23230
+ } else {
23231
+ label = rawName;
23232
+ }
23233
+ }
23234
+ return {
23235
+ id: `treemap-node-${counter}`,
23236
+ label,
23237
+ ...value !== void 0 && { value },
23238
+ ...heat !== void 0 && { heat },
23239
+ metadata,
23240
+ children: [],
23241
+ lineNumber
23242
+ };
23243
+ }
23244
+ function attachNode4(node, indent, indentStack, result) {
23245
+ while (indentStack.length > 0) {
23246
+ const top = indentStack[indentStack.length - 1];
23247
+ if (top.indent < indent) break;
23248
+ indentStack.pop();
23249
+ }
23250
+ if (indentStack.length > 0) {
23251
+ const parent = indentStack[indentStack.length - 1].node;
23252
+ parent.children.push(node);
23253
+ } else {
23254
+ result.roots.push(node);
23255
+ }
23256
+ indentStack.push({ node, indent });
23257
+ }
23258
+ var TREEMAP_DIAGNOSTIC_CODES, VALUE_TOKEN_RE;
23259
+ var init_parser26 = __esm({
23260
+ "src/treemap/parser.ts"() {
23261
+ "use strict";
23262
+ init_diagnostics();
23263
+ init_tag_groups();
23264
+ init_parsing();
23265
+ init_reserved_key_registry();
23266
+ TREEMAP_DIAGNOSTIC_CODES = {
23267
+ NEGATIVE_VALUE: "E_TREEMAP_NEGATIVE_VALUE",
23268
+ LEAF_NO_VALUE: "W_TREEMAP_LEAF_NO_VALUE",
23269
+ BRANCH_VALUE_IGNORED: "W_TREEMAP_BRANCH_VALUE_IGNORED"
23270
+ };
23271
+ VALUE_TOKEN_RE = /^(.+?)\s+(-?\d[\d_,.]*)$/;
23272
+ }
23273
+ });
23274
+
22893
23275
  // src/raci/variants.ts
22894
23276
  function inferVariant(markers) {
22895
23277
  let hasD = false;
@@ -23144,8 +23526,8 @@ var init_variants = __esm({
23144
23526
  });
23145
23527
 
23146
23528
  // src/raci/parser.ts
23147
- var parser_exports20 = {};
23148
- __export(parser_exports20, {
23529
+ var parser_exports21 = {};
23530
+ __export(parser_exports21, {
23149
23531
  allTasks: () => allTasks,
23150
23532
  parseRaci: () => parseRaci
23151
23533
  });
@@ -23666,7 +24048,7 @@ function* allTasks(parsed) {
23666
24048
  }
23667
24049
  }
23668
24050
  var RACI_CHART_TYPE_IDS, CHART_TYPE_VARIANT_LOCK, VARIANT_LOCK_DIRECTIVES, KNOWN_OPTIONS10, KNOWN_BOOLEANS7, REMOVED_BOOLEANS3, PHASE_RE2, PHASE_PALETTE_COLOR_RE, ROLE_ASSIGNMENT_RE;
23669
- var init_parser26 = __esm({
24051
+ var init_parser27 = __esm({
23670
24052
  "src/raci/parser.ts"() {
23671
24053
  "use strict";
23672
24054
  init_diagnostics();
@@ -23912,6 +24294,7 @@ var init_chart_type_registry = __esm({
23912
24294
  init_parser24();
23913
24295
  init_parser25();
23914
24296
  init_parser26();
24297
+ init_parser27();
23915
24298
  CHART_TYPE_REGISTRY = [
23916
24299
  // ── Structured diagrams ───────────────────────────────────
23917
24300
  {
@@ -24052,6 +24435,9 @@ var init_chart_type_registry = __esm({
24052
24435
  { id: "cycle", category: "visualization", parse: parseCycle },
24053
24436
  { id: "pyramid", category: "visualization", parse: parsePyramid },
24054
24437
  { id: "ring", category: "visualization", parse: parseRing },
24438
+ // Treemap: squarified hierarchy. No measure/minDims — a treemap fills whatever
24439
+ // rectangle it's given and has no intrinsic aspect/size (F11).
24440
+ { id: "treemap", category: "visualization", parse: parseTreemap },
24055
24441
  // ── Geographic map (own parser → resolver → layout → renderer) ──
24056
24442
  { id: "map", category: "visualization", parse: parseMap }
24057
24443
  ];
@@ -26784,10 +27170,10 @@ async function renderSitemapForExport(content, theme, palette) {
26784
27170
  const parsed = parseSitemap2(content, effectivePalette);
26785
27171
  if (parsed.error || parsed.roots.length === 0) return "";
26786
27172
  const sitemapLayout = layoutSitemap2(parsed, void 0, null, void 0, true);
26787
- const PADDING3 = 20;
27173
+ const PADDING4 = 20;
26788
27174
  const titleOffset = parsed.title ? 30 : 0;
26789
- const exportWidth = sitemapLayout.width + PADDING3 * 2;
26790
- const exportHeight = sitemapLayout.height + PADDING3 * 2 + titleOffset;
27175
+ const exportWidth = sitemapLayout.width + PADDING4 * 2;
27176
+ const exportHeight = sitemapLayout.height + PADDING4 * 2 + titleOffset;
26791
27177
  const container = document.createElement("div");
26792
27178
  container.style.width = `${exportWidth}px`;
26793
27179
  container.style.height = `${exportHeight}px`;
@@ -31905,6 +32291,10 @@ async function layoutBoxesAndLinesSearch(parsed, collapseInfo, opts) {
31905
32291
  const reserveEdgeLabels = opts?.reserveEdgeLabels ?? false;
31906
32292
  const onProgress = opts?.onProgress;
31907
32293
  const tick = onProgress ? () => new Promise((r) => setTimeout(r)) : () => void 0;
32294
+ const YIELD_AFTER_MS = 150;
32295
+ const YIELD_EVERY_MS = 30;
32296
+ const searchStart = performance.now();
32297
+ let lastYield = searchStart;
31908
32298
  const collapsedGroupLabels = /* @__PURE__ */ new Set();
31909
32299
  if (collapseInfo) {
31910
32300
  const missing = /* @__PURE__ */ new Set();
@@ -32334,7 +32724,11 @@ async function layoutBoxesAndLinesSearch(parsed, collapseInfo, opts) {
32334
32724
  const step = async (phase) => {
32335
32725
  if (!onProgress) return;
32336
32726
  onProgress(++progressDone, progressTotal, phase);
32337
- await tick();
32727
+ const now = performance.now();
32728
+ if (now - searchStart > YIELD_AFTER_MS && now - lastYield > YIELD_EVERY_MS) {
32729
+ lastYield = now;
32730
+ await tick();
32731
+ }
32338
32732
  };
32339
32733
  const pool = [];
32340
32734
  for (const cfg of configs) {
@@ -50947,7 +51341,7 @@ function computeEdgeLabelPosition(midAngle, radius, cx, cy, lineCount, labelPxW,
50947
51341
  };
50948
51342
  }
50949
51343
  function fitToCanvas(nodes, edges, parsed, _cx, _cy, radius, width, height, _isClockwise) {
50950
- const PADDING3 = 30;
51344
+ const PADDING4 = 30;
50951
51345
  let contentMinX = Infinity, contentMaxX = -Infinity;
50952
51346
  let contentMinY = Infinity, contentMaxY = -Infinity;
50953
51347
  for (const n of nodes) {
@@ -50989,13 +51383,13 @@ function fitToCanvas(nodes, edges, parsed, _cx, _cy, radius, width, height, _isC
50989
51383
  contentMinY = Math.min(contentMinY, le.labelY - 12);
50990
51384
  contentMaxY = Math.max(contentMaxY, le.labelY + (lineCount - 1) * 15);
50991
51385
  }
50992
- const overflowX = Math.max(0, PADDING3 - contentMinX) + Math.max(0, contentMaxX - (width - PADDING3));
50993
- const overflowY = Math.max(0, PADDING3 - contentMinY) + Math.max(0, contentMaxY - (height - PADDING3));
51386
+ const overflowX = Math.max(0, PADDING4 - contentMinX) + Math.max(0, contentMaxX - (width - PADDING4));
51387
+ const overflowY = Math.max(0, PADDING4 - contentMinY) + Math.max(0, contentMaxY - (height - PADDING4));
50994
51388
  if (overflowX <= 0 && overflowY <= 0) return null;
50995
51389
  const contentW = contentMaxX - contentMinX;
50996
51390
  const contentH = contentMaxY - contentMinY;
50997
- const availW = width - 2 * PADDING3;
50998
- const availH = height - 2 * PADDING3;
51391
+ const availW = width - 2 * PADDING4;
51392
+ const availH = height - 2 * PADDING4;
50999
51393
  const shrink = Math.min(availW / contentW, availH / contentH);
51000
51394
  const newRadius = Math.max(80, radius * shrink);
51001
51395
  return { radius: newRadius };
@@ -51193,7 +51587,7 @@ function renderCycle(container, parsed, palette, isDark, onClickItem, exportDims
51193
51587
  }
51194
51588
  edgeLabelInfo.push({ le, edge });
51195
51589
  }
51196
- const HEADER_H = 36 * layout.scale;
51590
+ const HEADER_H2 = 36 * layout.scale;
51197
51591
  const scaledNodeFont = Math.max(6, Math.round(NODE_FONT_SIZE7 * layout.scale));
51198
51592
  const scaledEdgeLabelFont = Math.max(
51199
51593
  6,
@@ -51257,10 +51651,10 @@ function renderCycle(container, parsed, palette, isDark, onClickItem, exportDims
51257
51651
  const rx = 6;
51258
51652
  nodeG.append("rect").attr("x", ln.x - nodeW / 2).attr("y", ln.y - nodeH / 2).attr("width", nodeW).attr("height", nodeH).attr("rx", rx).attr("ry", rx).attr("fill", fillColor).attr("stroke", solidColor).attr("stroke-width", 2);
51259
51653
  if (hasDesc) {
51260
- const headerCenterY = ln.y - nodeH / 2 + HEADER_H / 2;
51654
+ const headerCenterY = ln.y - nodeH / 2 + HEADER_H2 / 2;
51261
51655
  const labelText = nodeG.append("text").attr("x", ln.x).attr("y", headerCenterY + scaledNodeFont / 3).attr("text-anchor", "middle").attr("fill", textColor).attr("font-family", FONT_FAMILY).attr("font-size", scaledNodeFont).attr("font-weight", "600");
51262
51656
  renderInlineText(labelText, node.label, palette, scaledNodeFont);
51263
- const sepY = ln.y - nodeH / 2 + HEADER_H;
51657
+ const sepY = ln.y - nodeH / 2 + HEADER_H2;
51264
51658
  nodeG.append("line").attr("x1", ln.x - nodeW / 2).attr("y1", sepY).attr("x2", ln.x + nodeW / 2).attr("y2", sepY).attr("stroke", solid ? descColor : solidColor).attr("stroke-opacity", 0.3).attr("stroke-width", 1);
51265
51659
  const descStartY = sepY + 4 + scaledDescFont;
51266
51660
  const descPadX = Math.max(8, 12 * layout.scale);
@@ -54080,13 +54474,15 @@ function layoutMap(resolvedIn, data, size, opts) {
54080
54474
  labelY: lp.y
54081
54475
  };
54082
54476
  const routeLabelStyle = leg.label !== void 0 ? labelOnFill(fillAt(bow.labelX, bow.labelY)) : void 0;
54477
+ const routeVal = Number(leg.value);
54083
54478
  legs.push({
54084
54479
  d: legPath(a, b, bow.curved, bow.offset),
54085
- width: routeWidthFor(Number(leg.value)),
54480
+ width: routeWidthFor(routeVal),
54086
54481
  color: lineColor(leg.tags) ?? mix(palette.text, palette.bg, 72),
54087
54482
  arrow: true,
54088
54483
  fromId: leg.fromId,
54089
54484
  toId: leg.toId,
54485
+ ...Number.isFinite(routeVal) && routeVal > 0 && { value: routeVal },
54090
54486
  ...Object.keys(leg.tags).length > 0 && { tags: leg.tags },
54091
54487
  lineNumber: leg.lineNumber,
54092
54488
  ...leg.label !== void 0 && {
@@ -54133,6 +54529,7 @@ function layoutMap(resolvedIn, data, size, opts) {
54133
54529
  labelY: lp.y
54134
54530
  };
54135
54531
  const edgeLabelStyle = e.label !== void 0 ? labelOnFill(fillAt(bow.labelX, bow.labelY)) : void 0;
54532
+ const edgeVal = Number(e.meta["value"]);
54136
54533
  legs.push({
54137
54534
  d: legPath(a, b, bow.curved, bow.offset),
54138
54535
  width: widthFor(e),
@@ -54140,6 +54537,7 @@ function layoutMap(resolvedIn, data, size, opts) {
54140
54537
  arrow: e.directed,
54141
54538
  fromId: e.fromId,
54142
54539
  toId: e.toId,
54540
+ ...Number.isFinite(edgeVal) && edgeVal > 0 && { value: edgeVal },
54143
54541
  ...Object.keys(e.tags).length > 0 && { tags: e.tags },
54144
54542
  lineNumber: e.lineNumber,
54145
54543
  ...e.label !== void 0 && {
@@ -54297,18 +54695,49 @@ function layoutMap(resolvedIn, data, size, opts) {
54297
54695
  const SHORT_HOP_MAX = Math.max(46, Math.min(width, height) * 0.11);
54298
54696
  const STEP = 4;
54299
54697
  const HOP_GAP = 9;
54698
+ const CLEAR_STEP = 6;
54699
+ const CLEAR_MAX = SHORT_HOP_MAX * 3;
54700
+ const CLEAR_TOL = CLEAR_STEP;
54701
+ const clearanceAt = (px, py, ox, oy) => {
54702
+ const baseAng = Math.atan2(oy, ox);
54703
+ let minClear = CLEAR_MAX;
54704
+ for (let k = -2; k <= 2; k++) {
54705
+ const a = baseAng + k * Math.PI / 4;
54706
+ const rx = Math.cos(a);
54707
+ const ry = Math.sin(a);
54708
+ let d = CLEAR_STEP;
54709
+ for (; d <= CLEAR_MAX; d += CLEAR_STEP) {
54710
+ const qx = px + rx * d;
54711
+ const qy = py + ry * d;
54712
+ if (qx < FIT_PAD || qy < topPad || qx > width - FIT_PAD || qy > height - FIT_PAD)
54713
+ break;
54714
+ if (fillAt(qx, qy) !== water) break;
54715
+ }
54716
+ if (d < minClear) minClear = d;
54717
+ }
54718
+ return minClear;
54719
+ };
54300
54720
  const tryShortHopCallout = (cx, cy, fill2, name, value, font = FONT2, gap = HOP_GAP, maxLen = SHORT_HOP_MAX) => {
54301
54721
  const chipW = stackW(name, value, font);
54302
54722
  const chipH = stackH(value !== void 0, font);
54723
+ const D = Math.SQRT1_2;
54303
54724
  const dirs = [
54304
54725
  [0, -1],
54305
- // north (over Canada)
54726
+ // north
54306
54727
  [0, 1],
54307
- // south (over Mexico / Gulf)
54728
+ // south
54308
54729
  [1, 0],
54309
- // east (Atlantic)
54310
- [-1, 0]
54311
- // west (Pacific)
54730
+ // east
54731
+ [-1, 0],
54732
+ // west
54733
+ [D, -D],
54734
+ // NE
54735
+ [D, D],
54736
+ // SE
54737
+ [-D, -D],
54738
+ // NW
54739
+ [-D, D]
54740
+ // SW
54312
54741
  ];
54313
54742
  let best = null;
54314
54743
  for (const [dx, dy] of dirs) {
@@ -54358,13 +54787,16 @@ function layoutMap(resolvedIn, data, size, opts) {
54358
54787
  (p) => segmentRectOverlap(cx, cy, innerX, innerY, p)
54359
54788
  ))
54360
54789
  continue;
54361
- if (best === null || len < best.len)
54790
+ const clear = clearanceAt(ccx, ccy, dx, dy);
54791
+ const better = best === null || clear > best.clear + CLEAR_TOL || clear >= best.clear - CLEAR_TOL && len < best.len;
54792
+ if (better)
54362
54793
  best = {
54363
54794
  x: ccx,
54364
54795
  y: ccy,
54365
54796
  rect,
54366
54797
  leader: [cx, cy, innerX, innerY],
54367
- len
54798
+ len,
54799
+ clear
54368
54800
  };
54369
54801
  }
54370
54802
  return best ? { x: best.x, y: best.y, rect: best.rect, leader: best.leader } : null;
@@ -55025,6 +55457,9 @@ function layoutMap(resolvedIn, data, size, opts) {
55025
55457
  const nx = -dy / len;
55026
55458
  const ny = dx / len;
55027
55459
  const perp = labelH + 2;
55460
+ const stroke2 = lg.width ?? W_MIN;
55461
+ const clearW = stroke2 / 2 + labelH / 2 + 3;
55462
+ const offList = stroke2 >= 4 ? [clearW, -clearW, clearW + perp, -(clearW + perp), 0] : [0, perp, -perp, 2 * perp, -2 * perp];
55028
55463
  const pm = /^M(-?[\d.]+),(-?[\d.]+)(?:L(-?[\d.]+),(-?[\d.]+)|Q(-?[\d.]+),(-?[\d.]+) (-?[\d.]+),(-?[\d.]+))$/.exec(
55029
55464
  lg.d
55030
55465
  );
@@ -55044,7 +55479,7 @@ function layoutMap(resolvedIn, data, size, opts) {
55044
55479
  return [a.cx + dx * t, a.cy + dy * t];
55045
55480
  };
55046
55481
  const candidates = [];
55047
- for (const off of [0, perp, -perp, 2 * perp, -2 * perp])
55482
+ for (const off of offList)
55048
55483
  for (const t of T_LIST) {
55049
55484
  const [bx, by] = pointAt(t);
55050
55485
  candidates.push([bx + nx * off, by + ny * off - 4]);
@@ -55796,6 +56231,12 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
55796
56231
  }
55797
56232
  }
55798
56233
  wireSync(p, leg.lineNumber);
56234
+ if (leg.value !== void 0) {
56235
+ p.attr("data-value", leg.value);
56236
+ p.append("title").text(
56237
+ leg.label !== void 0 ? `${leg.label}: ${leg.value}` : `${leg.value}`
56238
+ );
56239
+ }
55799
56240
  if (arrowTri) {
55800
56241
  gLegs.append("path").attr("d", arrowTri).attr("fill", leg.color).attr("stroke", leg.color).attr("stroke-width", 1).attr("stroke-linejoin", "round").attr("data-from-id", leg.fromId).attr("data-to-id", leg.toId);
55801
56242
  }
@@ -56025,7 +56466,9 @@ function mapContentAspect(resolved, data, ref = REF) {
56025
56466
  function mapExportDimensions(resolved, data, baseWidth = 1200, aspectOverride) {
56026
56467
  const useOverride = aspectOverride !== void 0 && Number.isFinite(aspectOverride) && aspectOverride > 0;
56027
56468
  const raw = useOverride ? aspectOverride : mapContentAspect(resolved, data);
56028
- const clamped = useOverride ? raw : Math.max(ASPECT_MIN, Math.min(ASPECT_MAX, raw));
56469
+ const isGlobal = !useOverride && buildMapProjection(resolved, data).fitIsGlobal;
56470
+ const target = isGlobal ? raw / GLOBAL_HEIGHT_BOOST : raw;
56471
+ const clamped = useOverride ? raw : Math.max(ASPECT_MIN, Math.min(ASPECT_MAX, target));
56029
56472
  const width = baseWidth;
56030
56473
  let height = Math.round(width / clamped);
56031
56474
  let chromeReserve = 0;
@@ -56038,10 +56481,10 @@ function mapExportDimensions(resolved, data, baseWidth = 1200, aspectOverride) {
56038
56481
  height = Math.round(chromeReserve + MIN_MAP_BAND);
56039
56482
  floored = true;
56040
56483
  }
56041
- const preferContain = useOverride ? floored : clamped !== raw || floored;
56484
+ const preferContain = useOverride ? floored : clamped !== target || floored;
56042
56485
  return { width, height, preferContain };
56043
56486
  }
56044
- var import_d3_geo3, FIT_PAD2, TITLE_GAP, ASPECT_MAX, ASPECT_MIN, MIN_MAP_BAND, FALLBACK_ASPECT, REF;
56487
+ var import_d3_geo3, FIT_PAD2, TITLE_GAP, ASPECT_MAX, ASPECT_MIN, GLOBAL_HEIGHT_BOOST, MIN_MAP_BAND, FALLBACK_ASPECT, REF;
56045
56488
  var init_dimensions = __esm({
56046
56489
  "src/map/dimensions.ts"() {
56047
56490
  "use strict";
@@ -56052,6 +56495,7 @@ var init_dimensions = __esm({
56052
56495
  TITLE_GAP = 16;
56053
56496
  ASPECT_MAX = 3;
56054
56497
  ASPECT_MIN = 0.9;
56498
+ GLOBAL_HEIGHT_BOOST = 1.12;
56055
56499
  MIN_MAP_BAND = 200;
56056
56500
  FALLBACK_ASPECT = 1.5;
56057
56501
  REF = 1e3;
@@ -56841,9 +57285,469 @@ var init_renderer18 = __esm({
56841
57285
  }
56842
57286
  });
56843
57287
 
56844
- // src/raci/renderer.ts
57288
+ // src/treemap/layout.ts
57289
+ function toDatum(node) {
57290
+ if (node.children.length === 0) {
57291
+ return {
57292
+ ref: node,
57293
+ label: node.label,
57294
+ value: node.value ?? 0,
57295
+ ...node.heat !== void 0 && { heat: node.heat },
57296
+ lineNumber: node.lineNumber
57297
+ };
57298
+ }
57299
+ return {
57300
+ ref: node,
57301
+ label: node.label,
57302
+ ...node.heat !== void 0 && { heat: node.heat },
57303
+ lineNumber: node.lineNumber,
57304
+ children: node.children.map((c) => toDatum(c))
57305
+ };
57306
+ }
57307
+ function datumHeat(node) {
57308
+ if (node.data.heat !== void 0) return node.data.heat;
57309
+ const xs = [];
57310
+ for (const l of node.leaves()) {
57311
+ if (l.data.heat !== void 0) xs.push(l.data.heat);
57312
+ }
57313
+ if (xs.length === 0) return void 0;
57314
+ return xs.reduce((a, b) => a + b, 0) / xs.length;
57315
+ }
57316
+ function layoutTreemap(roots, opts) {
57317
+ const maxDepth = opts.maxDepth ?? Infinity;
57318
+ const rootDatum = {
57319
+ label: "__root",
57320
+ children: roots.map((r) => toDatum(r))
57321
+ };
57322
+ const h = (0, import_d3_hierarchy2.hierarchy)(rootDatum).sum((d) => d.children?.length ? 0 : d.value ?? 0).sort((a, b) => (b.value ?? 0) - (a.value ?? 0));
57323
+ const hroot = (0, import_d3_hierarchy2.treemap)().tile(import_d3_hierarchy2.treemapSquarify).size([opts.width, opts.height]).paddingOuter(opts.paddingOuter ?? 3).paddingTop(opts.headerH > 0 ? opts.headerH : opts.paddingInner ?? 2).paddingInner(opts.paddingInner ?? 2).round(true)(h);
57324
+ const total = hroot.value ?? 0;
57325
+ (hroot.children ?? []).forEach((top, i) => {
57326
+ top.each((d) => {
57327
+ d._topIndex = i;
57328
+ });
57329
+ });
57330
+ const cells = [];
57331
+ for (const d of hroot.descendants()) {
57332
+ if (d.depth === 0) continue;
57333
+ if (d.depth > maxDepth) continue;
57334
+ const hasChildren = !!d.children && d.children.length > 0;
57335
+ const isCollapsed = hasChildren && d.depth >= maxDepth;
57336
+ const isContainer = hasChildren && !isCollapsed;
57337
+ const path = [];
57338
+ let p = d;
57339
+ while (p && p.depth > 0) {
57340
+ path.unshift(p.data.label);
57341
+ p = p.parent;
57342
+ }
57343
+ const heatVal = datumHeat(d);
57344
+ cells.push({
57345
+ node: d.data.ref ?? null,
57346
+ label: d.data.label,
57347
+ x0: d.x0,
57348
+ y0: d.y0,
57349
+ x1: d.x1,
57350
+ y1: d.y1,
57351
+ depth: d.depth,
57352
+ value: d.value ?? 0,
57353
+ isContainer,
57354
+ isCollapsed,
57355
+ topIndex: d._topIndex ?? 0,
57356
+ pctOfRoot: total > 0 ? (d.value ?? 0) / total : 0,
57357
+ pctOfParent: d.parent && (d.parent.value ?? 0) > 0 ? (d.value ?? 0) / (d.parent.value ?? 1) : 1,
57358
+ ...heatVal !== void 0 && { heat: heatVal },
57359
+ path,
57360
+ ...d.data.lineNumber !== void 0 && { lineNumber: d.data.lineNumber }
57361
+ });
57362
+ }
57363
+ return { cells, total };
57364
+ }
57365
+ var import_d3_hierarchy2;
57366
+ var init_layout16 = __esm({
57367
+ "src/treemap/layout.ts"() {
57368
+ "use strict";
57369
+ import_d3_hierarchy2 = require("d3-hierarchy");
57370
+ }
57371
+ });
57372
+
57373
+ // src/treemap/renderer.ts
56845
57374
  var renderer_exports19 = {};
56846
57375
  __export(renderer_exports19, {
57376
+ compactNumber: () => compactNumber2,
57377
+ renderTreemap: () => renderTreemap,
57378
+ renderTreemapForExport: () => renderTreemapForExport
57379
+ });
57380
+ function renderTreemapForExport(container, parsed, palette, isDark, exportDims, options) {
57381
+ renderTreemap(container, parsed, palette, isDark, exportDims, {
57382
+ exportMode: true,
57383
+ ...options
57384
+ });
57385
+ }
57386
+ function renderTreemap(container, parsed, palette, isDark, exportDims, options = {}) {
57387
+ if (parsed.error || parsed.roots.length === 0) return;
57388
+ void isDark;
57389
+ d3Selection26.select(container).selectAll(":not([data-d3-tooltip])").remove();
57390
+ const width = exportDims?.width ?? container.clientWidth;
57391
+ const height = exportDims?.height ?? container.clientHeight;
57392
+ if (width <= 0 || height <= 0) return;
57393
+ const mode = resolveColorMode(parsed, options.colorMode);
57394
+ const opts = parsed.options;
57395
+ const exportMode = options.exportMode ?? false;
57396
+ const seriesColorsTop = getSeriesColors(palette);
57397
+ const showTitle = !!parsed.title;
57398
+ const titleH = showTitle ? TITLE_BAND : 0;
57399
+ const heat = buildHeatScale(parsed, palette);
57400
+ const legend = !opts.noLegend ? buildLegend(mode, parsed, heat, seriesColorsTop, options.colorOffset ?? 0) : null;
57401
+ const legendReserve = legend ? getMaxLegendReservedHeight(
57402
+ { groups: legend.groups, position: LEGEND_POSITION, mode: "preview" },
57403
+ width
57404
+ ) + LEGEND_GROUP_GAP : 0;
57405
+ const headerH = opts.noHeaders ? 0 : HEADER_H;
57406
+ const areaX = PADDING3;
57407
+ const areaY = titleH + legendReserve + PADDING3;
57408
+ const areaW = Math.max(1, width - PADDING3 * 2);
57409
+ const areaH = Math.max(1, height - areaY - PADDING3);
57410
+ const layout = layoutTreemap(parsed.roots, {
57411
+ width: areaW,
57412
+ height: areaH,
57413
+ headerH,
57414
+ ...options.maxDepth !== void 0 && { maxDepth: options.maxDepth }
57415
+ });
57416
+ const svg = d3Selection26.select(container).append("svg").attr("width", width).attr("height", height).attr("viewBox", `0 0 ${width} ${height}`).attr("preserveAspectRatio", "xMidYMin meet").attr("xmlns", "http://www.w3.org/2000/svg").attr("class", "dgmo-treemap").style("font-family", FONT_FAMILY);
57417
+ svg.append("style").text(
57418
+ ".dgmo-treemap-focus{opacity:.3;transition:opacity .12s}.dgmo-treemap-cell:hover .dgmo-treemap-focus{opacity:.7}"
57419
+ );
57420
+ svg.append("rect").attr("width", width).attr("height", height).attr("fill", palette.bg);
57421
+ if (showTitle) {
57422
+ const title = svg.append("text").attr("class", "chart-title").attr("x", width / 2).attr("y", TITLE_Y).attr("text-anchor", "middle").attr("fill", palette.text).attr("font-family", FONT_FAMILY).attr("font-size", TITLE_FONT_SIZE).attr("font-weight", TITLE_FONT_WEIGHT).text(parsed.title);
57423
+ if (parsed.titleLineNumber !== null) {
57424
+ title.attr("data-line-number", parsed.titleLineNumber);
57425
+ }
57426
+ }
57427
+ const root = svg.append("g").attr("class", "dgmo-treemap-cells").attr("transform", `translate(${areaX},${areaY})`);
57428
+ const seriesColors2 = seriesColorsTop;
57429
+ const colorOffset = options.colorOffset ?? 0;
57430
+ const activeGroup = parsed.tagGroups.length > 0 ? parsed.tagGroups[0].name : null;
57431
+ const rootIndexByLabel = new Map(parsed.roots.map((r, i) => [r.label, i]));
57432
+ const colorOf = (cell) => {
57433
+ if (mode === "heat") {
57434
+ return cell.heat !== void 0 && heat ? heat.scale(cell.heat) : MUTED_FILL;
57435
+ }
57436
+ if (mode === "tag") {
57437
+ if (!cell.node) return MUTED_FILL;
57438
+ return resolveTagColor(cell.node.metadata, parsed.tagGroups, activeGroup) ?? MUTED_FILL;
57439
+ }
57440
+ const topLabel = cell.path[0] ?? cell.label;
57441
+ const idx = (rootIndexByLabel.get(topLabel) ?? cell.topIndex) + colorOffset;
57442
+ const hue = seriesColors2[idx % seriesColors2.length];
57443
+ if (cell.depth <= 1) return hue;
57444
+ const keepPct = Math.max(55, 100 - (cell.depth - 1) * 18);
57445
+ return mix(hue, palette.bg, keepPct);
57446
+ };
57447
+ for (const cell of layout.cells) {
57448
+ const w = Math.max(0, cell.x1 - cell.x0);
57449
+ const h = Math.max(0, cell.y1 - cell.y0);
57450
+ if (w <= 0 || h <= 0) continue;
57451
+ const baseColor = colorOf(cell);
57452
+ const fill2 = cell.isContainer ? baseColor : mix(baseColor, palette.bg, LEAF_MUTE_PCT);
57453
+ const drillable = cell.isContainer || cell.isCollapsed;
57454
+ const g = root.append("g").attr("class", "dgmo-treemap-cell").attr("transform", `translate(${cell.x0},${cell.y0})`).attr("data-node-path", cell.path.join(" / "));
57455
+ if (cell.lineNumber !== void 0) {
57456
+ g.attr("data-line-number", cell.lineNumber);
57457
+ }
57458
+ if (cell.heat !== void 0) g.attr("data-heat", cell.heat);
57459
+ if (cell.node && activeGroup) {
57460
+ const key = tagAttrKey(activeGroup);
57461
+ const tagVal = cell.node.metadata[key];
57462
+ if (tagVal) g.attr(`data-tag-${key}`, tagVal);
57463
+ }
57464
+ const rect = g.append("rect").attr(
57465
+ "class",
57466
+ cell.isContainer ? "dgmo-treemap-rect branch" : "dgmo-treemap-rect"
57467
+ ).attr("width", w).attr("height", h).attr("rx", 2).attr("fill", fill2).attr("fill-opacity", 1).attr("stroke", palette.bg).attr("stroke-width", cell.isContainer ? 1 : 0);
57468
+ if (drillable && options.onClickItem && cell.lineNumber !== void 0) {
57469
+ const ln = cell.lineNumber;
57470
+ rect.style("cursor", "pointer").on("click", () => options.onClickItem(ln));
57471
+ }
57472
+ const ink = contrastText(
57473
+ fill2,
57474
+ palette.textOnFillLight,
57475
+ palette.textOnFillDark
57476
+ );
57477
+ if (cell.isContainer && headerH > 0 && w > 34 && h > headerH) {
57478
+ const valParts = [];
57479
+ if (!opts.noValues) valParts.push(compactNumber2(cell.value));
57480
+ if (!opts.noPercent) valParts.push(formatPct(cell.pctOfRoot));
57481
+ const valStr = valParts.join(" \xB7 ");
57482
+ const ICON_RESERVE = drillable ? 16 : 4;
57483
+ const showVal = valStr.length > 0 && w > 110;
57484
+ const valW = showVal ? measureText(valStr, 10.5) : 0;
57485
+ const labelMax = w - 8 - ICON_RESERVE - (showVal ? valW + 10 : 0);
57486
+ g.append("text").attr("class", "dgmo-treemap-header").attr("x", 6).attr("y", 13).attr("font-size", 11).attr("font-weight", 700).attr("fill", ink).text(clipLabel(cell.label, Math.max(0, labelMax), 11));
57487
+ if (showVal) {
57488
+ g.append("text").attr("class", "dgmo-treemap-header-value").attr("x", w - ICON_RESERVE - 4).attr("y", 13).attr("text-anchor", "end").attr("font-size", 10.5).attr("fill", ink).attr("opacity", 0.75).text(valStr);
57489
+ }
57490
+ }
57491
+ const PAD = Math.max(4, Math.min(14, Math.floor(Math.min(w, h) / 5)));
57492
+ const MIN_FS = 7;
57493
+ if (!cell.isContainer && w >= 2 * PAD + 8 && h >= 2 * PAD + 8) {
57494
+ const maxW = w - 2 * PAD;
57495
+ let fs = clamp3(Math.round(Math.min(w / 3.6, h / 3.4)), MIN_FS, 72);
57496
+ const nameW = measureText(cell.label, fs) * 1.06;
57497
+ if (nameW > maxW) fs = Math.max(MIN_FS, Math.floor(fs * maxW / nameW));
57498
+ const tg = clamp3((fs - MIN_FS) / (72 - MIN_FS), 0, 1);
57499
+ const nameOpacity = 0.95 - tg * 0.5;
57500
+ const vfs = clamp3(Math.round(fs * 0.42), 11, 28);
57501
+ const valOpacity = Math.max(0.45, nameOpacity - 0.1);
57502
+ let y = PAD + Math.round(fs * 0.78);
57503
+ g.append("text").attr("class", "dgmo-treemap-label").attr("x", PAD).attr("y", y).attr("font-size", fs).attr("font-weight", 600).attr("fill", ink).attr("opacity", nameOpacity).text(clipLabel(cell.label, maxW, fs));
57504
+ const valParts = [
57505
+ opts.noValues ? "" : compactNumber2(cell.value),
57506
+ opts.noPercent ? "" : formatPct(cell.pctOfRoot)
57507
+ ].filter(Boolean);
57508
+ const combined = valParts.join(" \xB7 ");
57509
+ const nameBaseY = y;
57510
+ const addLineAt = (text, yy, size, opacity) => {
57511
+ g.append("text").attr("class", "dgmo-treemap-value").attr("x", PAD).attr("y", yy).attr("font-size", size).attr("fill", ink).attr("opacity", opacity).text(text);
57512
+ };
57513
+ if (combined) {
57514
+ const fitsW = measureText(combined, vfs) <= maxW;
57515
+ const roomBelow = h - PAD > y + vfs + 6;
57516
+ if (fitsW && roomBelow) {
57517
+ addLineAt(combined, y + vfs + 6, vfs, valOpacity);
57518
+ } else if (fitsW) {
57519
+ const ivfs = clamp3(Math.round(fs * 0.5), 11, Math.max(11, vfs));
57520
+ const rendered = clipLabel(cell.label, maxW, fs);
57521
+ const nW = measureText(rendered, fs) * 1.12;
57522
+ const gap = Math.max(12, Math.round(fs * 0.25));
57523
+ if (PAD + nW + gap + measureText(combined, ivfs) <= w - PAD) {
57524
+ g.append("text").attr("class", "dgmo-treemap-value").attr("x", PAD + nW + gap).attr("y", nameBaseY).attr("font-size", ivfs).attr("fill", ink).attr("opacity", valOpacity).text(combined);
57525
+ }
57526
+ } else if (valParts.length === 2) {
57527
+ if (h - PAD > y + vfs + 6) {
57528
+ y += vfs + 6;
57529
+ addLineAt(valParts[0], y, vfs, valOpacity);
57530
+ }
57531
+ const pfs = Math.max(10, Math.round(vfs * 0.9));
57532
+ if (h - PAD > y + pfs + 4) {
57533
+ y += pfs + 4;
57534
+ addLineAt(valParts[1], y, pfs, valOpacity);
57535
+ }
57536
+ } else if (h - PAD > y + vfs + 6) {
57537
+ addLineAt(combined, y + vfs + 6, vfs, valOpacity);
57538
+ }
57539
+ }
57540
+ }
57541
+ if (drillable && w > 30 && h > 22) {
57542
+ drawFocusIcon(g, w, ink, 9);
57543
+ }
57544
+ }
57545
+ if (legend) {
57546
+ const legendG = svg.append("g").attr("class", "dgmo-treemap-legend").attr("transform", `translate(0, ${titleH})`);
57547
+ renderIntegratedLegend(legendG, {
57548
+ groups: legend.groups,
57549
+ palette: {
57550
+ bg: palette.bg,
57551
+ surface: palette.surface,
57552
+ text: palette.text,
57553
+ textMuted: palette.textMuted,
57554
+ primary: palette.primary
57555
+ },
57556
+ isDark,
57557
+ width,
57558
+ mode: exportMode ? "export" : "preview",
57559
+ position: LEGEND_POSITION,
57560
+ activeGroup: legend.activeGroup,
57561
+ // The color-mode switcher is the legend itself: each applicable mode is a
57562
+ // group pill; the active one is the open capsule, the rest are clickable
57563
+ // pills that switch mode. Export shows only the active group.
57564
+ showInactivePills: !exportMode,
57565
+ showEmptyGroups: !exportMode,
57566
+ ...options.onSelectMode !== void 0 && {
57567
+ callbacks: {
57568
+ onGroupToggle: (name) => {
57569
+ const m = legend.modeByName.get(name);
57570
+ if (m) options.onSelectMode(m);
57571
+ }
57572
+ }
57573
+ }
57574
+ });
57575
+ }
57576
+ }
57577
+ function buildLegend(activeMode, parsed, heat, seriesColors2, colorOffset) {
57578
+ const groups = [];
57579
+ const modeByName = /* @__PURE__ */ new Map();
57580
+ let activeGroup = null;
57581
+ if (parsed.tagGroups.length > 0) {
57582
+ const tg = parsed.tagGroups[0];
57583
+ const used = /* @__PURE__ */ new Set();
57584
+ const collect = (nodes) => {
57585
+ for (const n of nodes) {
57586
+ const v = n.metadata[tagAttrKey(tg.name)];
57587
+ if (v) used.add(v.toLowerCase());
57588
+ collect(n.children);
57589
+ }
57590
+ };
57591
+ collect(parsed.roots);
57592
+ groups.push({
57593
+ name: tg.name,
57594
+ entries: tg.entries.filter((e) => used.has(e.value.toLowerCase())).map((e) => ({ value: e.value, color: e.color }))
57595
+ });
57596
+ modeByName.set(tg.name, "tag");
57597
+ if (activeMode === "tag") activeGroup = tg.name;
57598
+ }
57599
+ if (heat) {
57600
+ const name = parsed.options.heatLabel ?? "Value";
57601
+ groups.push({
57602
+ name,
57603
+ entries: [],
57604
+ gradient: {
57605
+ min: heat.min,
57606
+ max: heat.max,
57607
+ low: heat.stops[0],
57608
+ high: heat.stops[heat.stops.length - 1]
57609
+ }
57610
+ });
57611
+ modeByName.set(name, "heat");
57612
+ if (activeMode === "heat") activeGroup = name;
57613
+ }
57614
+ groups.push({
57615
+ name: "Branch",
57616
+ entries: parsed.roots.map((r, i) => ({
57617
+ value: r.label,
57618
+ color: seriesColors2[(i + colorOffset) % seriesColors2.length]
57619
+ }))
57620
+ });
57621
+ modeByName.set("Branch", "branch");
57622
+ if (activeMode === "branch" || activeGroup === null) activeGroup = "Branch";
57623
+ return { groups, activeGroup, modeByName };
57624
+ }
57625
+ function buildHeatScale(parsed, palette) {
57626
+ if (!parsed.hasHeat) return null;
57627
+ const values = [];
57628
+ const collect = (nodes) => {
57629
+ for (const n of nodes) {
57630
+ if (typeof n.heat === "number") values.push(n.heat);
57631
+ collect(n.children);
57632
+ }
57633
+ };
57634
+ collect(parsed.roots);
57635
+ if (values.length === 0) return null;
57636
+ const min = Math.min(...values);
57637
+ const max = Math.max(...values);
57638
+ const signed = min < 0 && max > 0;
57639
+ const neutral = palette.surface;
57640
+ const explicit = parsed.options.heatColors.map((c) => resolveColor(c, palette) ?? c).filter((c) => !!c);
57641
+ let stops;
57642
+ let domain;
57643
+ if (explicit.length >= 2) {
57644
+ stops = [explicit[0], neutral, explicit[1]];
57645
+ const mid = signed ? 0 : (min + max) / 2;
57646
+ domain = [min, mid, max];
57647
+ } else if (explicit.length === 1) {
57648
+ stops = [neutral, explicit[0]];
57649
+ domain = [min, max];
57650
+ } else if (signed) {
57651
+ stops = [palette.colors.red, neutral, palette.colors.green];
57652
+ domain = [min, 0, max];
57653
+ } else {
57654
+ stops = [neutral, palette.primary];
57655
+ domain = [min, max];
57656
+ }
57657
+ if (domain[0] === domain[domain.length - 1]) {
57658
+ const last = stops[stops.length - 1];
57659
+ return { scale: () => last, min, max, stops, signed };
57660
+ }
57661
+ const linear = (0, import_d3_scale.scaleLinear)().domain(domain).range(stops).clamp(true);
57662
+ return { scale: (v) => toHex(linear(v)), min, max, stops, signed };
57663
+ }
57664
+ function toHex(c) {
57665
+ if (c.startsWith("#")) return c;
57666
+ const m = c.match(/rgba?\(([^)]+)\)/);
57667
+ if (!m) return c;
57668
+ const parts = m[1].split(",").map((s) => Math.round(parseFloat(s)));
57669
+ const h = (n) => Math.max(0, Math.min(255, n || 0)).toString(16).padStart(2, "0");
57670
+ return `#${h(parts[0] ?? 0)}${h(parts[1] ?? 0)}${h(parts[2] ?? 0)}`;
57671
+ }
57672
+ function resolveColorMode(parsed, override) {
57673
+ let mode = override ?? parsed.defaultColorMode;
57674
+ if (mode === "tag" && parsed.tagGroups.length === 0) {
57675
+ mode = parsed.hasHeat ? "heat" : "branch";
57676
+ }
57677
+ if (mode === "heat" && !parsed.hasHeat) mode = "branch";
57678
+ return mode;
57679
+ }
57680
+ function drawFocusIcon(g, w, ink, cy) {
57681
+ const r = 4.5;
57682
+ const cx = w - r - 5;
57683
+ const fi = g.append("g").attr("class", "dgmo-treemap-focus").attr("data-export-ignore", "true");
57684
+ fi.append("rect").attr("x", cx - 9).attr("y", cy - 9).attr("width", 18).attr("height", 18).attr("fill", "transparent");
57685
+ fi.append("circle").attr("cx", cx).attr("cy", cy).attr("r", r).attr("fill", "none").attr("stroke", ink).attr("stroke-width", 1.25);
57686
+ fi.append("circle").attr("cx", cx).attr("cy", cy).attr("r", 1.4).attr("fill", ink);
57687
+ }
57688
+ function clamp3(x, lo, hi) {
57689
+ return Math.max(lo, Math.min(hi, x));
57690
+ }
57691
+ function clipLabel(s, maxWidth, fs) {
57692
+ if (measureText(s, fs) <= maxWidth) return s;
57693
+ let lo = 0;
57694
+ let hi = s.length;
57695
+ while (lo < hi) {
57696
+ const mid = Math.ceil((lo + hi) / 2);
57697
+ if (measureText(s.slice(0, mid) + "\u2026", fs) <= maxWidth) lo = mid;
57698
+ else hi = mid - 1;
57699
+ }
57700
+ return lo <= 0 ? "" : s.slice(0, lo) + "\u2026";
57701
+ }
57702
+ function compactNumber2(v) {
57703
+ const abs = Math.abs(v);
57704
+ if (abs >= 1e9) return strip(v / 1e9) + "B";
57705
+ if (abs >= 1e6) return strip(v / 1e6) + "M";
57706
+ if (abs >= 1e3) return strip(v / 1e3) + "k";
57707
+ return strip(Math.round(v * 100) / 100);
57708
+ }
57709
+ function strip(n) {
57710
+ return parseFloat(
57711
+ n.toFixed(n < 10 && !Number.isInteger(n) ? 1 : 0)
57712
+ ).toString();
57713
+ }
57714
+ function formatPct(frac) {
57715
+ const pct = frac * 100;
57716
+ if (pct >= 10) return `${Math.round(pct)}%`;
57717
+ if (pct >= 1) return `${pct.toFixed(0)}%`;
57718
+ return `${pct.toFixed(1)}%`;
57719
+ }
57720
+ var d3Selection26, import_d3_scale, PADDING3, HEADER_H, TITLE_BAND, MUTED_FILL, LEAF_MUTE_PCT, LEGEND_POSITION;
57721
+ var init_renderer19 = __esm({
57722
+ "src/treemap/renderer.ts"() {
57723
+ "use strict";
57724
+ d3Selection26 = __toESM(require("d3-selection"), 1);
57725
+ import_d3_scale = require("d3-scale");
57726
+ init_fonts();
57727
+ init_colors();
57728
+ init_color_utils();
57729
+ init_tag_groups();
57730
+ init_text_measure();
57731
+ init_legend_integration();
57732
+ init_legend_layout();
57733
+ init_legend_constants();
57734
+ init_title_constants();
57735
+ init_layout16();
57736
+ PADDING3 = 12;
57737
+ HEADER_H = 18;
57738
+ TITLE_BAND = 36;
57739
+ MUTED_FILL = "#cbd5e1";
57740
+ LEAF_MUTE_PCT = 50;
57741
+ LEGEND_POSITION = {
57742
+ placement: "top-center",
57743
+ titleRelation: "below-title"
57744
+ };
57745
+ }
57746
+ });
57747
+
57748
+ // src/raci/renderer.ts
57749
+ var renderer_exports20 = {};
57750
+ __export(renderer_exports20, {
56847
57751
  MARKER_LABELS: () => MARKER_LABELS,
56848
57752
  renderRaci: () => renderRaci,
56849
57753
  renderRaciForExport: () => renderRaciForExport
@@ -56919,7 +57823,7 @@ function renderRaci(container, parsed, palette, isDark, handlers, exportDims) {
56919
57823
  const hideLegend = opts.hideLegend ?? false;
56920
57824
  const collapsedPhases = opts.collapsedPhases ?? /* @__PURE__ */ new Set();
56921
57825
  const hideTitle = (opts.hideTitle ?? false) || parsed.options["no-title"] === "on";
56922
- d3Selection26.select(container).selectAll(":not([data-d3-tooltip])").remove();
57826
+ d3Selection27.select(container).selectAll(":not([data-d3-tooltip])").remove();
56923
57827
  const width = exportDims?.width ?? container.clientWidth;
56924
57828
  const height = exportDims?.height ?? container.clientHeight;
56925
57829
  if (width <= 0 || height <= 0) return;
@@ -57026,7 +57930,7 @@ function renderRaci(container, parsed, palette, isDark, handlers, exportDims) {
57026
57930
  const colBottomY = cursorY + sColumnBottomPad;
57027
57931
  const totalHeight = colBottomY + sVMargin;
57028
57932
  const svgHeight = exportDims ? totalHeight : Math.max(height, totalHeight);
57029
- const svg = d3Selection26.select(container).append("svg").attr("xmlns", "http://www.w3.org/2000/svg").attr("width", width).attr("height", svgHeight).attr("viewBox", `0 0 ${width} ${svgHeight}`).attr("preserveAspectRatio", "xMidYMin meet").attr("font-family", FONT_FAMILY).style("background", "transparent");
57933
+ const svg = d3Selection27.select(container).append("svg").attr("xmlns", "http://www.w3.org/2000/svg").attr("width", width).attr("height", svgHeight).attr("viewBox", `0 0 ${width} ${svgHeight}`).attr("preserveAspectRatio", "xMidYMin meet").attr("font-family", FONT_FAMILY).style("background", "transparent");
57030
57934
  if (ctx.isBelowFloor) {
57031
57935
  svg.attr("width", "100%");
57032
57936
  }
@@ -57506,15 +58410,15 @@ function parseQuotedSegments(message) {
57506
58410
  out.push({ text: message.slice(last), bold: false });
57507
58411
  return out;
57508
58412
  }
57509
- var d3Selection26, MARKER_LABELS, TITLE_AREA_HEIGHT4, H_MARGIN, V_MARGIN3, LEGEND_HEIGHT2, LEGEND_CHIP_GAP, LEGEND_CHIP_LABEL_MIN, LEGEND_LETTER_CHIP_W, TITLE_LEGEND_GAP, LEGEND_LABEL_FONT, LEGEND_LETTER_FONT, HEADER_HEIGHT5, ROW_HEIGHT, PHASE_HEIGHT, TASK_LABEL_MIN, TASK_LABEL_MAX, ROLE_COL_MIN, ROLE_COL_MAX, CELL_PAD, VIOLATION_LINE_HEIGHT, STACK_TOP_GAP, DESC_FONT, COLUMN_RADIUS3, COLUMN_INSET, COLUMN_BOTTOM_PAD, MARKER_FONT, MARKER_FONT_WEIGHT, LABEL_FONT2, ROLE_HEADER_FONT, PHASE_FONT, TINT_PCT, NODE_RADIUS3, AUTO_ACCENTS, SLICE_GAP, NAME_LINE_HEIGHT, DESC_LINE_HEIGHT9;
57510
- var init_renderer19 = __esm({
58413
+ var d3Selection27, MARKER_LABELS, TITLE_AREA_HEIGHT4, H_MARGIN, V_MARGIN3, LEGEND_HEIGHT2, LEGEND_CHIP_GAP, LEGEND_CHIP_LABEL_MIN, LEGEND_LETTER_CHIP_W, TITLE_LEGEND_GAP, LEGEND_LABEL_FONT, LEGEND_LETTER_FONT, HEADER_HEIGHT5, ROW_HEIGHT, PHASE_HEIGHT, TASK_LABEL_MIN, TASK_LABEL_MAX, ROLE_COL_MIN, ROLE_COL_MAX, CELL_PAD, VIOLATION_LINE_HEIGHT, STACK_TOP_GAP, DESC_FONT, COLUMN_RADIUS3, COLUMN_INSET, COLUMN_BOTTOM_PAD, MARKER_FONT, MARKER_FONT_WEIGHT, LABEL_FONT2, ROLE_HEADER_FONT, PHASE_FONT, TINT_PCT, NODE_RADIUS3, AUTO_ACCENTS, SLICE_GAP, NAME_LINE_HEIGHT, DESC_LINE_HEIGHT9;
58414
+ var init_renderer20 = __esm({
57511
58415
  "src/raci/renderer.ts"() {
57512
58416
  "use strict";
57513
- d3Selection26 = __toESM(require("d3-selection"), 1);
58417
+ d3Selection27 = __toESM(require("d3-selection"), 1);
57514
58418
  init_fonts();
57515
58419
  init_title_constants();
57516
58420
  init_color_utils();
57517
- init_parser26();
58421
+ init_parser27();
57518
58422
  init_variants();
57519
58423
  init_scaling();
57520
58424
  init_text_measure();
@@ -57771,8 +58675,8 @@ var init_tag_resolution = __esm({
57771
58675
  });
57772
58676
 
57773
58677
  // src/sequence/renderer.ts
57774
- var renderer_exports20 = {};
57775
- __export(renderer_exports20, {
58678
+ var renderer_exports21 = {};
58679
+ __export(renderer_exports21, {
57776
58680
  applyGroupOrdering: () => applyGroupOrdering,
57777
58681
  applyPositionOverrides: () => applyPositionOverrides,
57778
58682
  buildNoteMessageMap: () => buildNoteMessageMap,
@@ -58112,7 +59016,7 @@ function applyGroupOrdering(participants, groups, messages = []) {
58112
59016
  return result;
58113
59017
  }
58114
59018
  function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateToLine, options) {
58115
- d3Selection27.select(container).selectAll("*").remove();
59019
+ d3Selection28.select(container).selectAll("*").remove();
58116
59020
  const { title, options: parsedOptions } = parsed;
58117
59021
  const solid = parsedOptions["solid-fill"] === "on";
58118
59022
  const effectiveCollapsedGroups = /* @__PURE__ */ new Set();
@@ -58763,7 +59667,7 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
58763
59667
  offsetX = leftMargin + Math.max(0, (svgWidth - totalWidth) / 2);
58764
59668
  buildParticipantX();
58765
59669
  }
58766
- const svg = d3Selection27.select(container).append("svg").attr("width", "100%").attr("height", totalHeight).attr("viewBox", `0 0 ${svgWidth} ${totalHeight}`).attr("preserveAspectRatio", "xMidYMin meet").attr("class", "sequence-diagram").style("font-family", FONT_FAMILY);
59670
+ const svg = d3Selection28.select(container).append("svg").attr("width", "100%").attr("height", totalHeight).attr("viewBox", `0 0 ${svgWidth} ${totalHeight}`).attr("preserveAspectRatio", "xMidYMin meet").attr("class", "sequence-diagram").style("font-family", FONT_FAMILY);
58767
59671
  const defs = svg.append("defs");
58768
59672
  defs.append("marker").attr("id", "seq-arrowhead").attr("viewBox", `0 0 ${sArrowheadSize} ${sArrowheadSize}`).attr("refX", sArrowheadSize).attr("refY", sArrowheadSize / 2).attr("markerWidth", sArrowheadSize).attr("markerHeight", sArrowheadSize).attr("orient", "auto").append("polygon").attr(
58769
59673
  "points",
@@ -59375,12 +60279,12 @@ function renderParticipant(svg, participant, cx, cy, palette, isDark, color, tag
59375
60279
  });
59376
60280
  }
59377
60281
  }
59378
- var d3Selection27, PARTICIPANT_GAP, PARTICIPANT_BOX_WIDTH, PARTICIPANT_BOX_HEIGHT, LABEL_FONT_SIZE5, TOP_MARGIN, TITLE_HEIGHT8, PARTICIPANT_Y_OFFSET, MESSAGE_START_OFFSET, LIFELINE_TAIL, ARROWHEAD_SIZE, NOTE_MAX_W2, NOTE_FOLD2, NOTE_PAD_H2, NOTE_PAD_V2, NOTE_FONT_SIZE2, NOTE_LINE_H2, NOTE_GAP2, ACTIVATION_WIDTH, SELF_CALL_HEIGHT, SELF_CALL_WIDTH, ACTOR_LABEL_CLEARANCE, labelTextWidth, fill, stroke, SW, W, H;
59379
- var init_renderer20 = __esm({
60282
+ var d3Selection28, PARTICIPANT_GAP, PARTICIPANT_BOX_WIDTH, PARTICIPANT_BOX_HEIGHT, LABEL_FONT_SIZE5, TOP_MARGIN, TITLE_HEIGHT8, PARTICIPANT_Y_OFFSET, MESSAGE_START_OFFSET, LIFELINE_TAIL, ARROWHEAD_SIZE, NOTE_MAX_W2, NOTE_FOLD2, NOTE_PAD_H2, NOTE_PAD_V2, NOTE_FONT_SIZE2, NOTE_LINE_H2, NOTE_GAP2, ACTIVATION_WIDTH, SELF_CALL_HEIGHT, SELF_CALL_WIDTH, ACTOR_LABEL_CLEARANCE, labelTextWidth, fill, stroke, SW, W, H;
60283
+ var init_renderer21 = __esm({
59380
60284
  "src/sequence/renderer.ts"() {
59381
60285
  "use strict";
59382
60286
  init_tag_groups();
59383
- d3Selection27 = __toESM(require("d3-selection"), 1);
60287
+ d3Selection28 = __toESM(require("d3-selection"), 1);
59384
60288
  init_color_utils();
59385
60289
  init_inline_markdown();
59386
60290
  init_fonts();
@@ -59997,6 +60901,7 @@ __export(advanced_exports, {
59997
60901
  layoutOrg: () => layoutOrg,
59998
60902
  layoutPert: () => layoutPert,
59999
60903
  layoutSitemap: () => layoutSitemap,
60904
+ layoutTreemap: () => layoutTreemap,
60000
60905
  layoutWireframe: () => layoutWireframe,
60001
60906
  loadMapData: () => loadMapData,
60002
60907
  looksLikeClassDiagram: () => looksLikeClassDiagram,
@@ -60054,6 +60959,7 @@ __export(advanced_exports, {
60054
60959
  parseState: () => parseState,
60055
60960
  parseTechRadar: () => parseTechRadar,
60056
60961
  parseTimelineDate: () => parseTimelineDate,
60962
+ parseTreemap: () => parseTreemap,
60057
60963
  parseVisualization: () => parseVisualization,
60058
60964
  parseWireframe: () => parseWireframe,
60059
60965
  raciCellAppendMarker: () => cellAppendMarker,
@@ -60119,6 +61025,8 @@ __export(advanced_exports, {
60119
61025
  renderTechRadar: () => renderTechRadar,
60120
61026
  renderTechRadarForExport: () => renderTechRadarForExport,
60121
61027
  renderTimeline: () => renderTimeline,
61028
+ renderTreemap: () => renderTreemap,
61029
+ renderTreemapForExport: () => renderTreemapForExport,
60122
61030
  renderVenn: () => renderVenn,
60123
61031
  renderWireframe: () => renderWireframe,
60124
61032
  renderWordCloud: () => renderWordCloud,
@@ -63584,6 +64492,7 @@ var DIAGRAM_EXPORT_HANDLERS = {
63584
64492
  map: exportMap,
63585
64493
  pyramid: exportPyramid,
63586
64494
  ring: exportRing,
64495
+ treemap: exportTreemap,
63587
64496
  raci: exportRaci,
63588
64497
  rasci: exportRaci,
63589
64498
  daci: exportRaci,
@@ -63641,10 +64550,10 @@ async function exportOrg(ctx) {
63641
64550
  false
63642
64551
  // expandAllLegend off — collapsed-by-default per §1.3
63643
64552
  );
63644
- const PADDING3 = 20;
64553
+ const PADDING4 = 20;
63645
64554
  const titleOffset = effectiveParsed.title ? 30 : 0;
63646
- const exportWidth = orgLayout.width + PADDING3 * 2;
63647
- const exportHeight = orgLayout.height + PADDING3 * 2 + titleOffset;
64555
+ const exportWidth = orgLayout.width + PADDING4 * 2;
64556
+ const exportHeight = orgLayout.height + PADDING4 * 2 + titleOffset;
63648
64557
  const container = createExportContainer(exportWidth, exportHeight);
63649
64558
  renderOrg2(
63650
64559
  container,
@@ -63686,10 +64595,10 @@ async function exportSitemap(ctx) {
63686
64595
  hiddenAttributes,
63687
64596
  true
63688
64597
  );
63689
- const PADDING3 = 20;
64598
+ const PADDING4 = 20;
63690
64599
  const titleOffset = effectiveParsed.title ? 30 : 0;
63691
- const exportWidth = sitemapLayout.width + PADDING3 * 2;
63692
- const exportHeight = sitemapLayout.height + PADDING3 * 2 + titleOffset;
64600
+ const exportWidth = sitemapLayout.width + PADDING4 * 2;
64601
+ const exportHeight = sitemapLayout.height + PADDING4 * 2 + titleOffset;
63693
64602
  const container = createExportContainer(exportWidth, exportHeight);
63694
64603
  renderSitemap2(
63695
64604
  container,
@@ -63745,10 +64654,10 @@ async function exportClass(ctx) {
63745
64654
  const classParsed = parseClassDiagram2(content, effectivePalette);
63746
64655
  if (classParsed.error || classParsed.classes.length === 0) return "";
63747
64656
  const classLayout = layoutClassDiagram2(classParsed);
63748
- const PADDING3 = 20;
64657
+ const PADDING4 = 20;
63749
64658
  const titleOffset = classParsed.title ? 40 : 0;
63750
- const exportWidth = classLayout.width + PADDING3 * 2;
63751
- const exportHeight = classLayout.height + PADDING3 * 2 + titleOffset;
64659
+ const exportWidth = classLayout.width + PADDING4 * 2;
64660
+ const exportHeight = classLayout.height + PADDING4 * 2 + titleOffset;
63752
64661
  const container = createExportContainer(exportWidth, exportHeight);
63753
64662
  renderClassDiagram2(
63754
64663
  container,
@@ -63772,10 +64681,10 @@ async function exportEr(ctx) {
63772
64681
  const erParsed = parseERDiagram2(content, effectivePalette);
63773
64682
  if (erParsed.error || erParsed.tables.length === 0) return "";
63774
64683
  const erLayout = layoutERDiagram2(erParsed);
63775
- const PADDING3 = 20;
64684
+ const PADDING4 = 20;
63776
64685
  const titleOffset = erParsed.title ? 40 : 0;
63777
- const exportWidth = erLayout.width + PADDING3 * 2;
63778
- const exportHeight = erLayout.height + PADDING3 * 2 + titleOffset;
64686
+ const exportWidth = erLayout.width + PADDING4 * 2;
64687
+ const exportHeight = erLayout.height + PADDING4 * 2 + titleOffset;
63779
64688
  const container = createExportContainer(exportWidth, exportHeight);
63780
64689
  renderERDiagram2(
63781
64690
  container,
@@ -63811,10 +64720,10 @@ async function exportBoxesAndLines(ctx) {
63811
64720
  const { renderBoxesAndLinesForExport: renderBoxesAndLinesForExport2 } = await Promise.resolve().then(() => (init_renderer6(), renderer_exports6));
63812
64721
  const { layoutBoxesAndLines: layoutBoxesAndLines2 } = await Promise.resolve().then(() => (init_layout5(), layout_exports5));
63813
64722
  const blLayout = await layoutBoxesAndLines2(blParsed);
63814
- const PADDING3 = 20;
64723
+ const PADDING4 = 20;
63815
64724
  const titleOffset = blParsed.title ? 40 : 0;
63816
- const exportWidth = blLayout.width + PADDING3 * 2;
63817
- const exportHeight = blLayout.height + PADDING3 * 2 + titleOffset;
64725
+ const exportWidth = blLayout.width + PADDING4 * 2;
64726
+ const exportHeight = blLayout.height + PADDING4 * 2 + titleOffset;
63818
64727
  const container = createExportContainer(exportWidth, exportHeight);
63819
64728
  const blActiveTagGroup = ctxTagOverride(ctx);
63820
64729
  renderBoxesAndLinesForExport2(
@@ -63861,10 +64770,10 @@ async function exportMindmap(ctx) {
63861
64770
  activeTagGroup,
63862
64771
  hideDescriptions
63863
64772
  });
63864
- const PADDING3 = 20;
64773
+ const PADDING4 = 20;
63865
64774
  const titleOffset = effectiveParsed.title ? 30 : 0;
63866
- const exportWidth = mmLayout.width + PADDING3 * 2;
63867
- const exportHeight = mmLayout.height + PADDING3 * 2 + titleOffset;
64775
+ const exportWidth = mmLayout.width + PADDING4 * 2;
64776
+ const exportHeight = mmLayout.height + PADDING4 * 2 + titleOffset;
63868
64777
  const container = createExportContainer(exportWidth, exportHeight);
63869
64778
  const colorByDepth = viewState?.cbd === true;
63870
64779
  renderMindmap2(
@@ -63925,10 +64834,10 @@ async function exportC4(ctx) {
63925
64834
  const c4Container = ctx.options?.c4Container ?? viewState?.c4c;
63926
64835
  const c4Layout = c4Level === "deployment" ? layoutC4Deployment2(c4Parsed) : c4Level === "components" && c4System && c4Container ? layoutC4Components2(c4Parsed, c4System, c4Container) : c4Level === "containers" && c4System ? layoutC4Containers2(c4Parsed, c4System) : layoutC4Context2(c4Parsed);
63927
64836
  if (c4Layout.nodes.length === 0) return "";
63928
- const PADDING3 = 20;
64837
+ const PADDING4 = 20;
63929
64838
  const titleOffset = c4Parsed.title ? 40 : 0;
63930
- const exportWidth = c4Layout.width + PADDING3 * 2;
63931
- const exportHeight = c4Layout.height + PADDING3 * 2 + titleOffset;
64839
+ const exportWidth = c4Layout.width + PADDING4 * 2;
64840
+ const exportHeight = c4Layout.height + PADDING4 * 2 + titleOffset;
63932
64841
  const container = createExportContainer(exportWidth, exportHeight);
63933
64842
  const renderFn = c4Level === "deployment" || c4Level === "components" && c4System && c4Container || c4Level === "containers" && c4System ? renderC4Containers2 : renderC4Context2;
63934
64843
  renderFn(
@@ -64244,30 +65153,44 @@ async function exportRing(ctx) {
64244
65153
  const ringParsed = parseRing2(content);
64245
65154
  if (ringParsed.error || ringParsed.layers.length === 0) return "";
64246
65155
  const container = createExportContainer(EXPORT_WIDTH, EXPORT_HEIGHT);
64247
- renderRingForExport2(
65156
+ renderRingForExport2(container, ringParsed, effectivePalette, ctx.isDark, {
65157
+ width: EXPORT_WIDTH,
65158
+ height: EXPORT_HEIGHT
65159
+ });
65160
+ return finalizeSvgExport(container, theme, effectivePalette);
65161
+ }
65162
+ async function exportTreemap(ctx) {
65163
+ const { content, theme, palette } = ctx;
65164
+ const { parseTreemap: parseTreemap2 } = await Promise.resolve().then(() => (init_parser26(), parser_exports20));
65165
+ const { renderTreemapForExport: renderTreemapForExport2 } = await Promise.resolve().then(() => (init_renderer19(), renderer_exports19));
65166
+ const effectivePalette = await resolveExportPalette(theme, palette);
65167
+ const treemapParsed = parseTreemap2(content, effectivePalette);
65168
+ if (treemapParsed.error || treemapParsed.roots.length === 0) return "";
65169
+ const container = createExportContainer(EXPORT_WIDTH, EXPORT_HEIGHT);
65170
+ renderTreemapForExport2(
64248
65171
  container,
64249
- ringParsed,
65172
+ treemapParsed,
64250
65173
  effectivePalette,
64251
65174
  ctx.isDark,
64252
- { width: EXPORT_WIDTH, height: EXPORT_HEIGHT }
65175
+ {
65176
+ width: EXPORT_WIDTH,
65177
+ height: EXPORT_HEIGHT
65178
+ }
64253
65179
  );
64254
65180
  return finalizeSvgExport(container, theme, effectivePalette);
64255
65181
  }
64256
65182
  async function exportRaci(ctx) {
64257
65183
  const { content, theme, palette } = ctx;
64258
- const { parseRaci: parseRaci2 } = await Promise.resolve().then(() => (init_parser26(), parser_exports20));
64259
- const { renderRaciForExport: renderRaciForExport2 } = await Promise.resolve().then(() => (init_renderer19(), renderer_exports19));
65184
+ const { parseRaci: parseRaci2 } = await Promise.resolve().then(() => (init_parser27(), parser_exports21));
65185
+ const { renderRaciForExport: renderRaciForExport2 } = await Promise.resolve().then(() => (init_renderer20(), renderer_exports20));
64260
65186
  const effectivePalette = await resolveExportPalette(theme, palette);
64261
65187
  const raciParsed = parseRaci2(content, effectivePalette);
64262
65188
  if (raciParsed.error) return "";
64263
65189
  const container = createExportContainer(EXPORT_WIDTH, EXPORT_HEIGHT);
64264
- renderRaciForExport2(
64265
- container,
64266
- raciParsed,
64267
- effectivePalette,
64268
- ctx.isDark,
64269
- { width: EXPORT_WIDTH, height: EXPORT_HEIGHT }
64270
- );
65190
+ renderRaciForExport2(container, raciParsed, effectivePalette, ctx.isDark, {
65191
+ width: EXPORT_WIDTH,
65192
+ height: EXPORT_HEIGHT
65193
+ });
64271
65194
  return finalizeSvgExport(container, theme, effectivePalette);
64272
65195
  }
64273
65196
  function beginVizExport() {
@@ -64356,14 +65279,7 @@ async function exportVenn(ctx) {
64356
65279
  if (parsed.error || parsed.vennSets.length < 2) return "";
64357
65280
  const effectivePalette = await resolveExportPalette(theme, palette);
64358
65281
  const { container, dims } = beginVizExport();
64359
- renderVenn(
64360
- container,
64361
- parsed,
64362
- effectivePalette,
64363
- ctx.isDark,
64364
- void 0,
64365
- dims
64366
- );
65282
+ renderVenn(container, parsed, effectivePalette, ctx.isDark, void 0, dims);
64367
65283
  return finalizeSvgExport(container, theme, effectivePalette);
64368
65284
  }
64369
65285
  async function exportQuadrant(ctx) {
@@ -64397,7 +65313,7 @@ async function exportVisualization(ctx) {
64397
65313
  const isDark = ctx.isDark;
64398
65314
  const container = createExportContainer(EXPORT_WIDTH, EXPORT_HEIGHT);
64399
65315
  const { parseSequenceDgmo: parseSequenceDgmo2 } = await Promise.resolve().then(() => (init_parser7(), parser_exports));
64400
- const { renderSequenceDiagram: renderSequenceDiagram2 } = await Promise.resolve().then(() => (init_renderer20(), renderer_exports20));
65316
+ const { renderSequenceDiagram: renderSequenceDiagram2 } = await Promise.resolve().then(() => (init_renderer21(), renderer_exports21));
64401
65317
  const seqParsed = parseSequenceDgmo2(content, effectivePalette);
64402
65318
  if (seqParsed.error || seqParsed.participants.length === 0) return "";
64403
65319
  const collapsedSections = viewState?.cs ? new Set(viewState.cs) : void 0;
@@ -65028,6 +65944,9 @@ init_parser24();
65028
65944
  init_renderer17();
65029
65945
  init_parser25();
65030
65946
  init_renderer18();
65947
+ init_parser26();
65948
+ init_renderer19();
65949
+ init_layout16();
65031
65950
  init_parser17();
65032
65951
  init_resolver2();
65033
65952
  init_load_data();
@@ -65339,12 +66258,12 @@ function completeMapRegions(query, regions, opts) {
65339
66258
  }
65340
66259
 
65341
66260
  // src/raci/index.ts
65342
- init_parser26();
65343
- init_renderer19();
66261
+ init_parser27();
66262
+ init_renderer20();
65344
66263
 
65345
66264
  // src/raci/mutations.ts
65346
66265
  init_parsing();
65347
- init_parser26();
66266
+ init_parser27();
65348
66267
  function cellReplace(content, parsed, taskId, roleId, marker) {
65349
66268
  const task = findTask(parsed, taskId);
65350
66269
  if (!task) return null;
@@ -65857,7 +66776,7 @@ init_legend_svg();
65857
66776
  init_legend_constants();
65858
66777
  init_legend_d3();
65859
66778
  init_legend_layout();
65860
- init_renderer20();
66779
+ init_renderer21();
65861
66780
  init_collapse4();
65862
66781
  init_colors();
65863
66782
  init_palettes();
@@ -66090,6 +67009,7 @@ init_dgmo_router();
66090
67009
  layoutOrg,
66091
67010
  layoutPert,
66092
67011
  layoutSitemap,
67012
+ layoutTreemap,
66093
67013
  layoutWireframe,
66094
67014
  loadMapData,
66095
67015
  looksLikeClassDiagram,
@@ -66147,6 +67067,7 @@ init_dgmo_router();
66147
67067
  parseState,
66148
67068
  parseTechRadar,
66149
67069
  parseTimelineDate,
67070
+ parseTreemap,
66150
67071
  parseVisualization,
66151
67072
  parseWireframe,
66152
67073
  raciCellAppendMarker,
@@ -66212,6 +67133,8 @@ init_dgmo_router();
66212
67133
  renderTechRadar,
66213
67134
  renderTechRadarForExport,
66214
67135
  renderTimeline,
67136
+ renderTreemap,
67137
+ renderTreemapForExport,
66215
67138
  renderVenn,
66216
67139
  renderWireframe,
66217
67140
  renderWordCloud,