@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/auto.mjs CHANGED
@@ -600,7 +600,7 @@ function withTagAliases(base, aliases) {
600
600
  function isReservedKey(registry, key) {
601
601
  return registry.keys.has(key) || registry.tagAliases.has(key);
602
602
  }
603
- 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;
603
+ 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;
604
604
  var init_reserved_key_registry = __esm({
605
605
  "src/utils/reserved-key-registry.ts"() {
606
606
  "use strict";
@@ -719,6 +719,7 @@ var init_reserved_key_registry = __esm({
719
719
  "color",
720
720
  "description"
721
721
  ]);
722
+ TREEMAP_REGISTRY = staticRegistry(["heat"]);
722
723
  RACI_REGISTRY = staticRegistry([
723
724
  "color",
724
725
  "description"
@@ -1148,6 +1149,7 @@ var init_parsing = __esm({
1148
1149
  "journey-map",
1149
1150
  "pyramid",
1150
1151
  "ring",
1152
+ "treemap",
1151
1153
  "raci",
1152
1154
  "rasci",
1153
1155
  "daci",
@@ -11807,6 +11809,10 @@ var init_chart_types = __esm({
11807
11809
  id: "ring",
11808
11810
  description: "Concentric rings showing nested or hierarchical categories (read core-out)"
11809
11811
  },
11812
+ {
11813
+ id: "treemap",
11814
+ description: "Nested rectangles sized by value \u2014 show a hierarchy\u2019s proportions (budgets, disk usage, portfolios) with color by category, value heatmap, or branch"
11815
+ },
11810
11816
  {
11811
11817
  id: "map",
11812
11818
  description: "Geographic concept map: highlight/score regions, drop points of interest, connect with routes or edges"
@@ -16681,6 +16687,7 @@ function parseInfra(content) {
16681
16687
  let currentGroup = null;
16682
16688
  let currentTagGroup = null;
16683
16689
  let baseIndent = 0;
16690
+ let firstLineConsumed = false;
16684
16691
  function finishCurrentNode() {
16685
16692
  if (!currentNode) return;
16686
16693
  const key = currentNode.id;
@@ -16688,7 +16695,8 @@ function parseInfra(content) {
16688
16695
  if (existing) {
16689
16696
  const incomingDisplay = displayName(currentNode.label);
16690
16697
  const existingDisplay = displayName(existing.label);
16691
- if (incomingDisplay !== existingDisplay) {
16698
+ const isAliasRef = nameAliasMap.get(currentNode.label) === key;
16699
+ if (incomingDisplay !== existingDisplay && !isAliasRef) {
16692
16700
  result.diagnostics.push(
16693
16701
  makeDgmoError(
16694
16702
  currentNode.lineNumber,
@@ -16754,19 +16762,22 @@ function parseInfra(content) {
16754
16762
  if (indent === 0 && currentNode && !trimmed.startsWith("-")) {
16755
16763
  finishCurrentNode();
16756
16764
  }
16757
- const firstLineResult = parseFirstLine(trimmed);
16758
- if (firstLineResult) {
16759
- if (firstLineResult.chartType !== "infra") {
16760
- setError(
16761
- lineNumber,
16762
- `Expected chart type 'infra', got '${firstLineResult.chartType}'`
16763
- );
16764
- }
16765
- if (firstLineResult.title) {
16766
- result.title = firstLineResult.title;
16767
- result.titleLineNumber = lineNumber;
16765
+ if (!firstLineConsumed) {
16766
+ firstLineConsumed = true;
16767
+ const firstLineResult = parseFirstLine(trimmed);
16768
+ if (firstLineResult) {
16769
+ if (firstLineResult.chartType !== "infra") {
16770
+ setError(
16771
+ lineNumber,
16772
+ `Expected chart type 'infra', got '${firstLineResult.chartType}'`
16773
+ );
16774
+ }
16775
+ if (firstLineResult.title) {
16776
+ result.title = firstLineResult.title;
16777
+ result.titleLineNumber = lineNumber;
16778
+ }
16779
+ continue;
16768
16780
  }
16769
- continue;
16770
16781
  }
16771
16782
  if (/^direction-tb$/i.test(trimmed)) {
16772
16783
  result.direction = "TB";
@@ -16832,18 +16843,20 @@ function parseInfra(content) {
16832
16843
  if (compMatch) {
16833
16844
  finishCurrentNode();
16834
16845
  finishCurrentTagGroup();
16835
- const rawName = (compMatch[1] ?? compMatch[2] ?? "").trim();
16846
+ const { qname, uname, alias: asAlias, meta } = compMatch.groups;
16847
+ const rawName = (qname ?? uname ?? "").trim();
16836
16848
  const peeled = peelInfraDecorations(rawName, lineNumber);
16837
16849
  const name = peeled.label;
16838
- const rest = compMatch[3] || "";
16850
+ const alias = asAlias ?? peeled.alias;
16851
+ const rest = meta ?? "";
16839
16852
  const { tags } = extractPipeMetadata(rest);
16840
16853
  warnUnknownMetaKeys(
16841
16854
  tags,
16842
16855
  withTagAliases(INFRA_REGISTRY, tagAliasSet),
16843
16856
  (msg) => warn2(lineNumber, msg)
16844
16857
  );
16845
- const id = nodeId2(name);
16846
- if (peeled.alias) nameAliasMap.set(peeled.alias, id);
16858
+ const id = nameAliasMap.get(name) ?? nodeId2(name);
16859
+ if (alias) nameAliasMap.set(alias, id);
16847
16860
  const isEdge = EDGE_NODE_NAMES.has(id.toLowerCase());
16848
16861
  currentNode = {
16849
16862
  id,
@@ -16927,18 +16940,20 @@ function parseInfra(content) {
16927
16940
  const compMatch = trimmed.match(COMPONENT_RE);
16928
16941
  if (compMatch) {
16929
16942
  finishCurrentTagGroup();
16930
- const rawName = (compMatch[1] ?? compMatch[2] ?? "").trim();
16943
+ const { qname, uname, alias: asAlias, meta } = compMatch.groups;
16944
+ const rawName = (qname ?? uname ?? "").trim();
16931
16945
  const peeled = peelInfraDecorations(rawName, lineNumber);
16932
16946
  const name = peeled.label;
16933
- const rest = compMatch[3] || "";
16947
+ const alias = asAlias ?? peeled.alias;
16948
+ const rest = meta ?? "";
16934
16949
  const { tags: nodeTags } = extractPipeMetadata(rest);
16935
16950
  warnUnknownMetaKeys(
16936
16951
  nodeTags,
16937
16952
  withTagAliases(INFRA_REGISTRY, tagAliasSet),
16938
16953
  (msg) => warn2(lineNumber, msg)
16939
16954
  );
16940
- const id = nodeId2(name);
16941
- if (peeled.alias) nameAliasMap.set(peeled.alias, id);
16955
+ const id = nameAliasMap.get(name) ?? nodeId2(name);
16956
+ if (alias) nameAliasMap.set(alias, id);
16942
16957
  const tags = currentGroup.metadata ? { ...currentGroup.metadata, ...nodeTags } : nodeTags;
16943
16958
  currentNode = {
16944
16959
  id,
@@ -17129,6 +17144,11 @@ function parseInfra(content) {
17129
17144
  }
17130
17145
  continue;
17131
17146
  }
17147
+ if (currentNode && tagAliasSet.has(normalizeName(key))) {
17148
+ const mut = nodeMutableTags.get(currentNode.id);
17149
+ if (mut) mut[tagAttrKey(key)] = rawVal;
17150
+ continue;
17151
+ }
17132
17152
  if (!INFRA_BEHAVIOR_KEYS.has(key) && !EDGE_ONLY_KEYS.has(key)) {
17133
17153
  const allKeys = [...INFRA_BEHAVIOR_KEYS, ...EDGE_ONLY_KEYS];
17134
17154
  const hint = suggest(key, allKeys);
@@ -17194,18 +17214,20 @@ function parseInfra(content) {
17194
17214
  finishCurrentNode();
17195
17215
  const compMatch = trimmed.match(COMPONENT_RE);
17196
17216
  if (compMatch) {
17197
- const rawName = (compMatch[1] ?? compMatch[2] ?? "").trim();
17217
+ const { qname, uname, alias: asAlias, meta } = compMatch.groups;
17218
+ const rawName = (qname ?? uname ?? "").trim();
17198
17219
  const peeled = peelInfraDecorations(rawName, lineNumber);
17199
17220
  const name = peeled.label;
17200
- const rest = compMatch[3] || "";
17221
+ const alias = asAlias ?? peeled.alias;
17222
+ const rest = meta ?? "";
17201
17223
  const { tags: nodeTags } = extractPipeMetadata(rest);
17202
17224
  warnUnknownMetaKeys(
17203
17225
  nodeTags,
17204
17226
  withTagAliases(INFRA_REGISTRY, tagAliasSet),
17205
17227
  (msg) => warn2(lineNumber, msg)
17206
17228
  );
17207
- const id = nodeId2(name);
17208
- if (peeled.alias) nameAliasMap.set(peeled.alias, id);
17229
+ const id = nameAliasMap.get(name) ?? nodeId2(name);
17230
+ if (alias) nameAliasMap.set(alias, id);
17209
17231
  const tags = currentGroup.metadata ? { ...currentGroup.metadata, ...nodeTags } : nodeTags;
17210
17232
  currentNode = {
17211
17233
  id,
@@ -17227,18 +17249,20 @@ function parseInfra(content) {
17227
17249
  finishCurrentNode();
17228
17250
  finishCurrentTagGroup();
17229
17251
  currentGroup = null;
17230
- const rawName = (compMatch[1] ?? compMatch[2] ?? "").trim();
17252
+ const { qname, uname, alias: asAlias, meta } = compMatch.groups;
17253
+ const rawName = (qname ?? uname ?? "").trim();
17231
17254
  const peeled = peelInfraDecorations(rawName, lineNumber);
17232
17255
  const name = peeled.label;
17233
- const rest = compMatch[3] || "";
17256
+ const alias = asAlias ?? peeled.alias;
17257
+ const rest = meta ?? "";
17234
17258
  const { tags } = extractPipeMetadata(rest);
17235
17259
  warnUnknownMetaKeys(
17236
17260
  tags,
17237
17261
  withTagAliases(INFRA_REGISTRY, tagAliasSet),
17238
17262
  (msg) => warn2(lineNumber, msg)
17239
17263
  );
17240
- const id = nodeId2(name);
17241
- if (peeled.alias) nameAliasMap.set(peeled.alias, id);
17264
+ const id = nameAliasMap.get(name) ?? nodeId2(name);
17265
+ if (alias) nameAliasMap.set(alias, id);
17242
17266
  currentNode = {
17243
17267
  id,
17244
17268
  label: name,
@@ -17438,7 +17462,7 @@ var init_parser15 = __esm({
17438
17462
  DEPRECATED_FANOUT_RE = /\bx(\d+)\s*$/;
17439
17463
  GROUP_RE = /^\[([^\]]+)\]\s*(?:as\s+([A-Za-z][A-Za-z0-9_]{0,11})\s*)?((?:\|.*)|(?:[a-zA-Z_]\w*\s*:.*))?$/;
17440
17464
  TAG_VALUE_RE = /^(\w[\w\s]+?)\s*$/;
17441
- COMPONENT_RE = /^(?:"([^"]+)"|([a-zA-Z_][\w -]*?))\s*((?:\|.*)|(?:[a-zA-Z_]\w*\s*:.*))?$/;
17465
+ 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*:.*))?$/;
17442
17466
  PIPE_META_RE = /[|,]\s*(\w+)\s*:\s*([^|,]+)/g;
17443
17467
  SAMELINE_META_RE = /(?:^|[\s,])(\w+)\s*:\s*([^,]+?)(?=\s*,|\s*$)/g;
17444
17468
  PROPERTY_RE = /^([\w-]+):\s*(.+)$/;
@@ -18922,8 +18946,8 @@ function parseMap(content, palette) {
18922
18946
  continue;
18923
18947
  }
18924
18948
  if (open.route && indent > open.route.indent) {
18925
- const leg = parseLeg(trimmed, lineNumber, open.route.route.style);
18926
- open.route.route.legs.push(leg);
18949
+ const leg = parseLeg(trimmed, lineNumber);
18950
+ if (leg) open.route.route.legs.push(leg);
18927
18951
  continue;
18928
18952
  }
18929
18953
  if (open.poi && indent > open.poi.indent) {
@@ -18952,6 +18976,14 @@ function parseMap(content, palette) {
18952
18976
  Object.assign(open.poi.poi.meta, split.meta);
18953
18977
  continue;
18954
18978
  }
18979
+ if (split.name) {
18980
+ const src = open.poi.poi.alias ?? poiName(open.poi.poi.pos) ?? "the poi";
18981
+ pushError(
18982
+ lineNumber,
18983
+ `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)`
18984
+ );
18985
+ continue;
18986
+ }
18955
18987
  }
18956
18988
  closeBlocks();
18957
18989
  const firstWord = trimmed.split(/\s+/)[0];
@@ -18960,7 +18992,7 @@ function parseMap(content, palette) {
18960
18992
  continue;
18961
18993
  }
18962
18994
  if (DIRECTIVE_SET.has(firstWord) && !trimmed.slice(firstWord.length).trimStart().startsWith(":")) {
18963
- handleDirective(
18995
+ handleDirective2(
18964
18996
  firstWord,
18965
18997
  trimmed.slice(firstWord.length).trim(),
18966
18998
  lineNumber
@@ -18999,7 +19031,7 @@ function parseMap(content, palette) {
18999
19031
  }
19000
19032
  }
19001
19033
  return result;
19002
- function handleDirective(key, value, line11) {
19034
+ function handleDirective2(key, value, line11) {
19003
19035
  const d = result.directives;
19004
19036
  const dup = (have) => {
19005
19037
  if (have !== void 0)
@@ -19200,31 +19232,44 @@ function parseMap(content, palette) {
19200
19232
  const { tags, meta } = partitionMeta(split.meta, tagGroupNames());
19201
19233
  const originLabel = meta["label"];
19202
19234
  const originValue = meta["value"];
19203
- const style = meta["style"] === "arc" ? "arc" : "straight";
19235
+ if (meta["style"] !== void 0) {
19236
+ pushError(
19237
+ line11,
19238
+ "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)"
19239
+ );
19240
+ }
19204
19241
  const route = {
19205
19242
  origin: pos,
19206
19243
  ...split.alias !== void 0 && { originAlias: split.alias },
19207
19244
  ...originLabel !== void 0 && { originLabel },
19208
19245
  ...originValue !== void 0 && { originValue },
19209
19246
  originTags: tags,
19210
- style,
19211
19247
  legs: [],
19212
19248
  lineNumber: line11
19213
19249
  };
19214
19250
  routes.push(route);
19215
19251
  open.route = { route, indent };
19216
19252
  }
19217
- function parseLeg(trimmed, line11, headerStyle) {
19218
- let arrowStyle = "straight";
19219
- let label;
19220
- let rest = trimmed;
19253
+ function parseLeg(trimmed, line11) {
19221
19254
  const m = trimmed.match(LEG_ARROW_RE);
19222
- if (m) {
19223
- const arr = classifyArrow(m[1], line11);
19224
- arrowStyle = arr.style;
19225
- label = arr.label;
19226
- rest = m[2];
19255
+ if (!m) {
19256
+ pushError(
19257
+ line11,
19258
+ `Malformed route leg: "${trimmed}" \u2014 a leg needs an arrow glyph (\`-> dest\`, \`~> dest\`, or labeled \`-label-> dest\` / \`~label~> dest\`). (\xA724B.6)`
19259
+ );
19260
+ return null;
19227
19261
  }
19262
+ const arr = classifyArrow(m[1], line11);
19263
+ if (!arr.directed) {
19264
+ pushError(
19265
+ line11,
19266
+ `A route leg is directional \u2014 "${trimmed}" uses an undirected glyph; use \`-> \` (straight) or \`~> \` (arc). (\xA724B.6)`
19267
+ );
19268
+ return null;
19269
+ }
19270
+ const arrowStyle = arr.style;
19271
+ const label = arr.label;
19272
+ const rest = m[2];
19228
19273
  const split = splitNameAndMeta(
19229
19274
  rest,
19230
19275
  registry(),
@@ -19240,10 +19285,9 @@ function parseMap(content, palette) {
19240
19285
  const { tags, meta } = partitionMeta(split.meta, tagGroupNames());
19241
19286
  const value = meta["value"];
19242
19287
  const destLabel = meta["label"];
19243
- const style = arrowStyle === "arc" || headerStyle === "arc" ? "arc" : "straight";
19244
19288
  return {
19245
19289
  ...label !== void 0 && { label },
19246
- style,
19290
+ style: arrowStyle,
19247
19291
  ...value !== void 0 && { value },
19248
19292
  dest: pos,
19249
19293
  ...split.alias !== void 0 && { destAlias: split.alias },
@@ -22857,6 +22901,344 @@ var init_parser25 = __esm({
22857
22901
  }
22858
22902
  });
22859
22903
 
22904
+ // src/treemap/parser.ts
22905
+ var parser_exports20 = {};
22906
+ __export(parser_exports20, {
22907
+ TREEMAP_DIAGNOSTIC_CODES: () => TREEMAP_DIAGNOSTIC_CODES,
22908
+ parseTreemap: () => parseTreemap
22909
+ });
22910
+ function isFullyQuoted(s) {
22911
+ return s.length >= 2 && (s.startsWith('"') && s.endsWith('"') || s.startsWith("'") && s.endsWith("'"));
22912
+ }
22913
+ function parseTreemap(content, palette) {
22914
+ const options = {
22915
+ heatColors: [],
22916
+ noValues: false,
22917
+ noPercent: false,
22918
+ noHeaders: false,
22919
+ noLegend: false
22920
+ };
22921
+ const result = {
22922
+ type: "treemap",
22923
+ title: null,
22924
+ titleLineNumber: null,
22925
+ roots: [],
22926
+ tagGroups: [],
22927
+ hasHeat: false,
22928
+ defaultColorMode: "branch",
22929
+ options,
22930
+ diagnostics: [],
22931
+ error: null
22932
+ };
22933
+ const fail = makeFail(result);
22934
+ const pushError = (line11, message, code) => {
22935
+ const diag = makeDgmoError(line11, message, "error", code);
22936
+ result.diagnostics.push(diag);
22937
+ if (!result.error) result.error = formatDgmoError(diag);
22938
+ };
22939
+ const pushWarning = (line11, message, code) => {
22940
+ result.diagnostics.push(makeDgmoError(line11, message, "warning", code));
22941
+ };
22942
+ if (!content?.trim()) {
22943
+ return fail(0, "No content provided");
22944
+ }
22945
+ const lines = content.split("\n");
22946
+ let contentStarted = false;
22947
+ let nodeCounter = 0;
22948
+ let currentTagGroup = null;
22949
+ const aliasMap = /* @__PURE__ */ new Map();
22950
+ const indentStack = [];
22951
+ for (let i = 0; i < lines.length; i++) {
22952
+ const line11 = lines[i];
22953
+ const lineNumber = i + 1;
22954
+ const trimmed = line11.trim();
22955
+ if (!trimmed) {
22956
+ currentTagGroup = null;
22957
+ continue;
22958
+ }
22959
+ if (trimmed.startsWith("//")) continue;
22960
+ if (!contentStarted) {
22961
+ const firstLine = parseFirstLine(trimmed);
22962
+ if (firstLine && result.titleLineNumber === null && i === 0) {
22963
+ if (firstLine.chartType !== "treemap") {
22964
+ let msg = `Expected chart type "treemap", got "${firstLine.chartType}"`;
22965
+ const hint = suggest(firstLine.chartType, ["treemap"]);
22966
+ if (hint) msg += `. ${hint}`;
22967
+ return fail(lineNumber, msg);
22968
+ }
22969
+ result.title = firstLine.title ?? null;
22970
+ result.titleLineNumber = lineNumber;
22971
+ continue;
22972
+ }
22973
+ }
22974
+ const tagBlockMatch = matchTagBlockHeading(trimmed);
22975
+ if (tagBlockMatch) {
22976
+ emitTagLegacyDiagnostic(tagBlockMatch, lineNumber, result.diagnostics);
22977
+ if (contentStarted) {
22978
+ pushError(
22979
+ lineNumber,
22980
+ "Tag groups must appear before treemap content",
22981
+ "E_TAG_DECLARED_AFTER_CONTENT"
22982
+ );
22983
+ continue;
22984
+ }
22985
+ currentTagGroup = {
22986
+ name: tagBlockMatch.name,
22987
+ ...tagBlockMatch.alias !== void 0 && {
22988
+ alias: tagBlockMatch.alias
22989
+ },
22990
+ entries: [],
22991
+ lineNumber
22992
+ };
22993
+ if (tagBlockMatch.alias) {
22994
+ aliasMap.set(
22995
+ tagBlockMatch.alias.toLowerCase(),
22996
+ tagAttrKey(tagBlockMatch.name)
22997
+ );
22998
+ }
22999
+ aliasMap.set(
23000
+ tagAttrKey(tagBlockMatch.name),
23001
+ tagAttrKey(tagBlockMatch.name)
23002
+ );
23003
+ result.tagGroups.push(currentTagGroup);
23004
+ continue;
23005
+ }
23006
+ if (currentTagGroup && !contentStarted) {
23007
+ const indent2 = measureIndent(line11);
23008
+ if (indent2 > 0) {
23009
+ const { text: cleanEntry, isDefault } = stripDefaultModifier(trimmed);
23010
+ const { label, color } = extractColor(
23011
+ cleanEntry,
23012
+ palette,
23013
+ result.diagnostics,
23014
+ lineNumber
23015
+ );
23016
+ if (isDefault) {
23017
+ currentTagGroup.defaultValue = label;
23018
+ } else if (currentTagGroup.entries.length === 0) {
23019
+ currentTagGroup.defaultValue = label;
23020
+ }
23021
+ currentTagGroup.entries.push({
23022
+ value: label,
23023
+ color: color ?? AUTO_TAG_COLOR_SENTINEL,
23024
+ lineNumber
23025
+ });
23026
+ continue;
23027
+ }
23028
+ currentTagGroup = null;
23029
+ }
23030
+ if (!contentStarted && measureIndent(line11) === 0) {
23031
+ if (handleDirective(trimmed, options, result, pushWarning, lineNumber)) {
23032
+ continue;
23033
+ }
23034
+ }
23035
+ contentStarted = true;
23036
+ currentTagGroup = null;
23037
+ const indent = measureIndent(line11);
23038
+ const node = parseNodeLine3(
23039
+ trimmed,
23040
+ lineNumber,
23041
+ ++nodeCounter,
23042
+ aliasMap,
23043
+ result.diagnostics,
23044
+ pushWarning
23045
+ );
23046
+ if (node.heat !== void 0) result.hasHeat = true;
23047
+ attachNode4(node, indent, indentStack, result);
23048
+ }
23049
+ finalizeAutoTagColors(result.tagGroups, palette);
23050
+ const allNodes = [];
23051
+ const collectAll = (nodes) => {
23052
+ for (const n of nodes) {
23053
+ allNodes.push(n);
23054
+ collectAll(n.children);
23055
+ }
23056
+ };
23057
+ collectAll(result.roots);
23058
+ for (const n of allNodes) {
23059
+ const node = n;
23060
+ const isBranch = node.children.length > 0;
23061
+ if (isBranch) {
23062
+ if (node.value !== void 0) {
23063
+ pushWarning(
23064
+ node.lineNumber,
23065
+ `"${node.label}" is a branch \u2014 its trailing number is ignored; the area is the auto-sum of its children`,
23066
+ TREEMAP_DIAGNOSTIC_CODES.BRANCH_VALUE_IGNORED
23067
+ );
23068
+ delete node.value;
23069
+ }
23070
+ } else if (node.value === void 0) {
23071
+ pushWarning(
23072
+ node.lineNumber,
23073
+ `Leaf "${node.label}" has no value \u2014 it renders with zero area`,
23074
+ TREEMAP_DIAGNOSTIC_CODES.LEAF_NO_VALUE
23075
+ );
23076
+ node.value = 0;
23077
+ } else if (node.value < 0) {
23078
+ pushError(
23079
+ node.lineNumber,
23080
+ `Leaf "${node.label}" has a negative value (${node.value}) \u2014 treemap sizes must be \u2265 0`,
23081
+ TREEMAP_DIAGNOSTIC_CODES.NEGATIVE_VALUE
23082
+ );
23083
+ }
23084
+ }
23085
+ if (result.hasHeat || options.heatLabel !== void 0) {
23086
+ result.hasHeat = true;
23087
+ }
23088
+ if (result.tagGroups.length > 0) {
23089
+ validateTagValues(allNodes, result.tagGroups, pushWarning, suggest);
23090
+ validateTagGroupNames(result.tagGroups, pushWarning);
23091
+ cascadeTagMetadata(result.roots, result.tagGroups);
23092
+ }
23093
+ result.defaultColorMode = resolveDefaultColorMode(result);
23094
+ if (result.roots.length === 0 && !result.error) {
23095
+ const diag = makeDgmoError(1, "No nodes found in treemap");
23096
+ result.diagnostics.push(diag);
23097
+ result.error = formatDgmoError(diag);
23098
+ }
23099
+ return result;
23100
+ }
23101
+ function handleDirective(trimmed, options, result, pushWarning, lineNumber) {
23102
+ const depthMatch = trimmed.match(/^depth\s+(-?\d+)\s*$/i);
23103
+ if (depthMatch) {
23104
+ const n = parseInt(depthMatch[1], 10);
23105
+ if (n >= 1) options.maxDepth = n;
23106
+ else pushWarning(lineNumber, '"depth" must be \u2265 1 \u2014 ignored');
23107
+ return true;
23108
+ }
23109
+ if (/^other-below\b/i.test(trimmed)) {
23110
+ pushWarning(
23111
+ lineNumber,
23112
+ '"other-below" is no longer supported \u2014 remove this line'
23113
+ );
23114
+ return true;
23115
+ }
23116
+ const heatMatch = trimmed.match(/^heat\s+(.+)$/i);
23117
+ if (heatMatch) {
23118
+ const { label, low, high } = peelRampColors(heatMatch[1].trim());
23119
+ options.heatLabel = label || "Value";
23120
+ const colors = [];
23121
+ if (low !== void 0) colors.push(low);
23122
+ if (high !== void 0) colors.push(high);
23123
+ options.heatColors = colors;
23124
+ result.hasHeat = true;
23125
+ return true;
23126
+ }
23127
+ const noMatch = trimmed.match(/^no-(values|percent|headers|legend)\s*$/i);
23128
+ if (noMatch) {
23129
+ const key = noMatch[1].toLowerCase();
23130
+ if (key === "values") options.noValues = true;
23131
+ else if (key === "percent") options.noPercent = true;
23132
+ else if (key === "headers") options.noHeaders = true;
23133
+ else if (key === "legend") options.noLegend = true;
23134
+ return true;
23135
+ }
23136
+ return false;
23137
+ }
23138
+ function resolveDefaultColorMode(result) {
23139
+ if (result.tagGroups.length > 0) return "tag";
23140
+ if (result.hasHeat) return "heat";
23141
+ return "branch";
23142
+ }
23143
+ function parseNodeLine3(trimmed, lineNumber, counter, aliasMap, diagnostics, pushWarning) {
23144
+ if (trimmed.includes("|")) {
23145
+ diagnostics.push(
23146
+ makeDgmoError(
23147
+ lineNumber,
23148
+ pipeOperatorRemovedMessage(),
23149
+ "error",
23150
+ METADATA_DIAGNOSTIC_CODES.PIPE_OPERATOR_REMOVED
23151
+ )
23152
+ );
23153
+ }
23154
+ const registry = withTagAliases(TREEMAP_REGISTRY, new Set(aliasMap.keys()));
23155
+ const split = splitNameAndMeta(
23156
+ trimmed,
23157
+ registry,
23158
+ aliasMap,
23159
+ void 0,
23160
+ diagnostics,
23161
+ lineNumber
23162
+ );
23163
+ warnUnknownMetaKeys(
23164
+ split.meta,
23165
+ registry,
23166
+ (msg) => diagnostics.push(makeDgmoError(lineNumber, msg, "warning")),
23167
+ split.name
23168
+ );
23169
+ const metadata = { ...split.meta };
23170
+ let heat;
23171
+ if ("heat" in metadata) {
23172
+ const h = parseFloat(metadata["heat"].replace(/_/g, ""));
23173
+ if (Number.isFinite(h)) heat = h;
23174
+ delete metadata["heat"];
23175
+ }
23176
+ const rawName = split.name;
23177
+ let label;
23178
+ let value;
23179
+ if (isFullyQuoted(rawName)) {
23180
+ label = stripQuotes(rawName);
23181
+ } else {
23182
+ const vm = rawName.match(VALUE_TOKEN_RE);
23183
+ if (vm) {
23184
+ const labelPart = vm[1].trim();
23185
+ const token = vm[2];
23186
+ if (token.includes(",")) {
23187
+ pushWarning(lineNumber, dataCommaRemovedMessage(labelPart));
23188
+ }
23189
+ const cleaned = token.replace(/[_,]/g, "");
23190
+ const parsed = parseFloat(cleaned);
23191
+ if (Number.isFinite(parsed)) {
23192
+ value = parsed;
23193
+ label = isFullyQuoted(labelPart) ? stripQuotes(labelPart) : labelPart;
23194
+ } else {
23195
+ label = rawName;
23196
+ }
23197
+ } else {
23198
+ label = rawName;
23199
+ }
23200
+ }
23201
+ return {
23202
+ id: `treemap-node-${counter}`,
23203
+ label,
23204
+ ...value !== void 0 && { value },
23205
+ ...heat !== void 0 && { heat },
23206
+ metadata,
23207
+ children: [],
23208
+ lineNumber
23209
+ };
23210
+ }
23211
+ function attachNode4(node, indent, indentStack, result) {
23212
+ while (indentStack.length > 0) {
23213
+ const top = indentStack[indentStack.length - 1];
23214
+ if (top.indent < indent) break;
23215
+ indentStack.pop();
23216
+ }
23217
+ if (indentStack.length > 0) {
23218
+ const parent = indentStack[indentStack.length - 1].node;
23219
+ parent.children.push(node);
23220
+ } else {
23221
+ result.roots.push(node);
23222
+ }
23223
+ indentStack.push({ node, indent });
23224
+ }
23225
+ var TREEMAP_DIAGNOSTIC_CODES, VALUE_TOKEN_RE;
23226
+ var init_parser26 = __esm({
23227
+ "src/treemap/parser.ts"() {
23228
+ "use strict";
23229
+ init_diagnostics();
23230
+ init_tag_groups();
23231
+ init_parsing();
23232
+ init_reserved_key_registry();
23233
+ TREEMAP_DIAGNOSTIC_CODES = {
23234
+ NEGATIVE_VALUE: "E_TREEMAP_NEGATIVE_VALUE",
23235
+ LEAF_NO_VALUE: "W_TREEMAP_LEAF_NO_VALUE",
23236
+ BRANCH_VALUE_IGNORED: "W_TREEMAP_BRANCH_VALUE_IGNORED"
23237
+ };
23238
+ VALUE_TOKEN_RE = /^(.+?)\s+(-?\d[\d_,.]*)$/;
23239
+ }
23240
+ });
23241
+
22860
23242
  // src/raci/variants.ts
22861
23243
  function inferVariant(markers) {
22862
23244
  let hasD = false;
@@ -23111,8 +23493,8 @@ var init_variants = __esm({
23111
23493
  });
23112
23494
 
23113
23495
  // src/raci/parser.ts
23114
- var parser_exports20 = {};
23115
- __export(parser_exports20, {
23496
+ var parser_exports21 = {};
23497
+ __export(parser_exports21, {
23116
23498
  allTasks: () => allTasks,
23117
23499
  parseRaci: () => parseRaci
23118
23500
  });
@@ -23633,7 +24015,7 @@ function* allTasks(parsed) {
23633
24015
  }
23634
24016
  }
23635
24017
  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;
23636
- var init_parser26 = __esm({
24018
+ var init_parser27 = __esm({
23637
24019
  "src/raci/parser.ts"() {
23638
24020
  "use strict";
23639
24021
  init_diagnostics();
@@ -23879,6 +24261,7 @@ var init_chart_type_registry = __esm({
23879
24261
  init_parser24();
23880
24262
  init_parser25();
23881
24263
  init_parser26();
24264
+ init_parser27();
23882
24265
  CHART_TYPE_REGISTRY = [
23883
24266
  // ── Structured diagrams ───────────────────────────────────
23884
24267
  {
@@ -24019,6 +24402,9 @@ var init_chart_type_registry = __esm({
24019
24402
  { id: "cycle", category: "visualization", parse: parseCycle },
24020
24403
  { id: "pyramid", category: "visualization", parse: parsePyramid },
24021
24404
  { id: "ring", category: "visualization", parse: parseRing },
24405
+ // Treemap: squarified hierarchy. No measure/minDims — a treemap fills whatever
24406
+ // rectangle it's given and has no intrinsic aspect/size (F11).
24407
+ { id: "treemap", category: "visualization", parse: parseTreemap },
24022
24408
  // ── Geographic map (own parser → resolver → layout → renderer) ──
24023
24409
  { id: "map", category: "visualization", parse: parseMap }
24024
24410
  ];
@@ -26753,10 +27139,10 @@ async function renderSitemapForExport(content, theme, palette) {
26753
27139
  const parsed = parseSitemap2(content, effectivePalette);
26754
27140
  if (parsed.error || parsed.roots.length === 0) return "";
26755
27141
  const sitemapLayout = layoutSitemap2(parsed, void 0, null, void 0, true);
26756
- const PADDING3 = 20;
27142
+ const PADDING4 = 20;
26757
27143
  const titleOffset = parsed.title ? 30 : 0;
26758
- const exportWidth = sitemapLayout.width + PADDING3 * 2;
26759
- const exportHeight = sitemapLayout.height + PADDING3 * 2 + titleOffset;
27144
+ const exportWidth = sitemapLayout.width + PADDING4 * 2;
27145
+ const exportHeight = sitemapLayout.height + PADDING4 * 2 + titleOffset;
26760
27146
  const container = document.createElement("div");
26761
27147
  container.style.width = `${exportWidth}px`;
26762
27148
  container.style.height = `${exportHeight}px`;
@@ -31784,6 +32170,10 @@ async function layoutBoxesAndLinesSearch(parsed, collapseInfo, opts) {
31784
32170
  const reserveEdgeLabels = opts?.reserveEdgeLabels ?? false;
31785
32171
  const onProgress = opts?.onProgress;
31786
32172
  const tick = onProgress ? () => new Promise((r) => setTimeout(r)) : () => void 0;
32173
+ const YIELD_AFTER_MS = 150;
32174
+ const YIELD_EVERY_MS = 30;
32175
+ const searchStart = performance.now();
32176
+ let lastYield = searchStart;
31787
32177
  const collapsedGroupLabels = /* @__PURE__ */ new Set();
31788
32178
  if (collapseInfo) {
31789
32179
  const missing = /* @__PURE__ */ new Set();
@@ -32213,7 +32603,11 @@ async function layoutBoxesAndLinesSearch(parsed, collapseInfo, opts) {
32213
32603
  const step = async (phase) => {
32214
32604
  if (!onProgress) return;
32215
32605
  onProgress(++progressDone, progressTotal, phase);
32216
- await tick();
32606
+ const now = performance.now();
32607
+ if (now - searchStart > YIELD_AFTER_MS && now - lastYield > YIELD_EVERY_MS) {
32608
+ lastYield = now;
32609
+ await tick();
32610
+ }
32217
32611
  };
32218
32612
  const pool = [];
32219
32613
  for (const cfg of configs) {
@@ -50601,7 +50995,7 @@ function computeEdgeLabelPosition(midAngle, radius, cx, cy, lineCount, labelPxW,
50601
50995
  };
50602
50996
  }
50603
50997
  function fitToCanvas(nodes, edges, parsed, _cx, _cy, radius, width, height, _isClockwise) {
50604
- const PADDING3 = 30;
50998
+ const PADDING4 = 30;
50605
50999
  let contentMinX = Infinity, contentMaxX = -Infinity;
50606
51000
  let contentMinY = Infinity, contentMaxY = -Infinity;
50607
51001
  for (const n of nodes) {
@@ -50643,13 +51037,13 @@ function fitToCanvas(nodes, edges, parsed, _cx, _cy, radius, width, height, _isC
50643
51037
  contentMinY = Math.min(contentMinY, le.labelY - 12);
50644
51038
  contentMaxY = Math.max(contentMaxY, le.labelY + (lineCount - 1) * 15);
50645
51039
  }
50646
- const overflowX = Math.max(0, PADDING3 - contentMinX) + Math.max(0, contentMaxX - (width - PADDING3));
50647
- const overflowY = Math.max(0, PADDING3 - contentMinY) + Math.max(0, contentMaxY - (height - PADDING3));
51040
+ const overflowX = Math.max(0, PADDING4 - contentMinX) + Math.max(0, contentMaxX - (width - PADDING4));
51041
+ const overflowY = Math.max(0, PADDING4 - contentMinY) + Math.max(0, contentMaxY - (height - PADDING4));
50648
51042
  if (overflowX <= 0 && overflowY <= 0) return null;
50649
51043
  const contentW = contentMaxX - contentMinX;
50650
51044
  const contentH = contentMaxY - contentMinY;
50651
- const availW = width - 2 * PADDING3;
50652
- const availH = height - 2 * PADDING3;
51045
+ const availW = width - 2 * PADDING4;
51046
+ const availH = height - 2 * PADDING4;
50653
51047
  const shrink = Math.min(availW / contentW, availH / contentH);
50654
51048
  const newRadius = Math.max(80, radius * shrink);
50655
51049
  return { radius: newRadius };
@@ -50848,7 +51242,7 @@ function renderCycle(container, parsed, palette, isDark, onClickItem, exportDims
50848
51242
  }
50849
51243
  edgeLabelInfo.push({ le, edge });
50850
51244
  }
50851
- const HEADER_H = 36 * layout.scale;
51245
+ const HEADER_H2 = 36 * layout.scale;
50852
51246
  const scaledNodeFont = Math.max(6, Math.round(NODE_FONT_SIZE7 * layout.scale));
50853
51247
  const scaledEdgeLabelFont = Math.max(
50854
51248
  6,
@@ -50912,10 +51306,10 @@ function renderCycle(container, parsed, palette, isDark, onClickItem, exportDims
50912
51306
  const rx = 6;
50913
51307
  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);
50914
51308
  if (hasDesc) {
50915
- const headerCenterY = ln.y - nodeH / 2 + HEADER_H / 2;
51309
+ const headerCenterY = ln.y - nodeH / 2 + HEADER_H2 / 2;
50916
51310
  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");
50917
51311
  renderInlineText(labelText, node.label, palette, scaledNodeFont);
50918
- const sepY = ln.y - nodeH / 2 + HEADER_H;
51312
+ const sepY = ln.y - nodeH / 2 + HEADER_H2;
50919
51313
  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);
50920
51314
  const descStartY = sepY + 4 + scaledDescFont;
50921
51315
  const descPadX = Math.max(8, 12 * layout.scale);
@@ -53745,13 +54139,15 @@ function layoutMap(resolvedIn, data, size, opts) {
53745
54139
  labelY: lp.y
53746
54140
  };
53747
54141
  const routeLabelStyle = leg.label !== void 0 ? labelOnFill(fillAt(bow.labelX, bow.labelY)) : void 0;
54142
+ const routeVal = Number(leg.value);
53748
54143
  legs.push({
53749
54144
  d: legPath(a, b, bow.curved, bow.offset),
53750
- width: routeWidthFor(Number(leg.value)),
54145
+ width: routeWidthFor(routeVal),
53751
54146
  color: lineColor(leg.tags) ?? mix(palette.text, palette.bg, 72),
53752
54147
  arrow: true,
53753
54148
  fromId: leg.fromId,
53754
54149
  toId: leg.toId,
54150
+ ...Number.isFinite(routeVal) && routeVal > 0 && { value: routeVal },
53755
54151
  ...Object.keys(leg.tags).length > 0 && { tags: leg.tags },
53756
54152
  lineNumber: leg.lineNumber,
53757
54153
  ...leg.label !== void 0 && {
@@ -53798,6 +54194,7 @@ function layoutMap(resolvedIn, data, size, opts) {
53798
54194
  labelY: lp.y
53799
54195
  };
53800
54196
  const edgeLabelStyle = e.label !== void 0 ? labelOnFill(fillAt(bow.labelX, bow.labelY)) : void 0;
54197
+ const edgeVal = Number(e.meta["value"]);
53801
54198
  legs.push({
53802
54199
  d: legPath(a, b, bow.curved, bow.offset),
53803
54200
  width: widthFor(e),
@@ -53805,6 +54202,7 @@ function layoutMap(resolvedIn, data, size, opts) {
53805
54202
  arrow: e.directed,
53806
54203
  fromId: e.fromId,
53807
54204
  toId: e.toId,
54205
+ ...Number.isFinite(edgeVal) && edgeVal > 0 && { value: edgeVal },
53808
54206
  ...Object.keys(e.tags).length > 0 && { tags: e.tags },
53809
54207
  lineNumber: e.lineNumber,
53810
54208
  ...e.label !== void 0 && {
@@ -53962,18 +54360,49 @@ function layoutMap(resolvedIn, data, size, opts) {
53962
54360
  const SHORT_HOP_MAX = Math.max(46, Math.min(width, height) * 0.11);
53963
54361
  const STEP = 4;
53964
54362
  const HOP_GAP = 9;
54363
+ const CLEAR_STEP = 6;
54364
+ const CLEAR_MAX = SHORT_HOP_MAX * 3;
54365
+ const CLEAR_TOL = CLEAR_STEP;
54366
+ const clearanceAt = (px, py, ox, oy) => {
54367
+ const baseAng = Math.atan2(oy, ox);
54368
+ let minClear = CLEAR_MAX;
54369
+ for (let k = -2; k <= 2; k++) {
54370
+ const a = baseAng + k * Math.PI / 4;
54371
+ const rx = Math.cos(a);
54372
+ const ry = Math.sin(a);
54373
+ let d = CLEAR_STEP;
54374
+ for (; d <= CLEAR_MAX; d += CLEAR_STEP) {
54375
+ const qx = px + rx * d;
54376
+ const qy = py + ry * d;
54377
+ if (qx < FIT_PAD || qy < topPad || qx > width - FIT_PAD || qy > height - FIT_PAD)
54378
+ break;
54379
+ if (fillAt(qx, qy) !== water) break;
54380
+ }
54381
+ if (d < minClear) minClear = d;
54382
+ }
54383
+ return minClear;
54384
+ };
53965
54385
  const tryShortHopCallout = (cx, cy, fill2, name, value, font = FONT2, gap = HOP_GAP, maxLen = SHORT_HOP_MAX) => {
53966
54386
  const chipW = stackW(name, value, font);
53967
54387
  const chipH = stackH(value !== void 0, font);
54388
+ const D = Math.SQRT1_2;
53968
54389
  const dirs = [
53969
54390
  [0, -1],
53970
- // north (over Canada)
54391
+ // north
53971
54392
  [0, 1],
53972
- // south (over Mexico / Gulf)
54393
+ // south
53973
54394
  [1, 0],
53974
- // east (Atlantic)
53975
- [-1, 0]
53976
- // west (Pacific)
54395
+ // east
54396
+ [-1, 0],
54397
+ // west
54398
+ [D, -D],
54399
+ // NE
54400
+ [D, D],
54401
+ // SE
54402
+ [-D, -D],
54403
+ // NW
54404
+ [-D, D]
54405
+ // SW
53977
54406
  ];
53978
54407
  let best = null;
53979
54408
  for (const [dx, dy] of dirs) {
@@ -54023,13 +54452,16 @@ function layoutMap(resolvedIn, data, size, opts) {
54023
54452
  (p) => segmentRectOverlap(cx, cy, innerX, innerY, p)
54024
54453
  ))
54025
54454
  continue;
54026
- if (best === null || len < best.len)
54455
+ const clear = clearanceAt(ccx, ccy, dx, dy);
54456
+ const better = best === null || clear > best.clear + CLEAR_TOL || clear >= best.clear - CLEAR_TOL && len < best.len;
54457
+ if (better)
54027
54458
  best = {
54028
54459
  x: ccx,
54029
54460
  y: ccy,
54030
54461
  rect,
54031
54462
  leader: [cx, cy, innerX, innerY],
54032
- len
54463
+ len,
54464
+ clear
54033
54465
  };
54034
54466
  }
54035
54467
  return best ? { x: best.x, y: best.y, rect: best.rect, leader: best.leader } : null;
@@ -54690,6 +55122,9 @@ function layoutMap(resolvedIn, data, size, opts) {
54690
55122
  const nx = -dy / len;
54691
55123
  const ny = dx / len;
54692
55124
  const perp = labelH + 2;
55125
+ const stroke2 = lg.width ?? W_MIN;
55126
+ const clearW = stroke2 / 2 + labelH / 2 + 3;
55127
+ const offList = stroke2 >= 4 ? [clearW, -clearW, clearW + perp, -(clearW + perp), 0] : [0, perp, -perp, 2 * perp, -2 * perp];
54693
55128
  const pm = /^M(-?[\d.]+),(-?[\d.]+)(?:L(-?[\d.]+),(-?[\d.]+)|Q(-?[\d.]+),(-?[\d.]+) (-?[\d.]+),(-?[\d.]+))$/.exec(
54694
55129
  lg.d
54695
55130
  );
@@ -54709,7 +55144,7 @@ function layoutMap(resolvedIn, data, size, opts) {
54709
55144
  return [a.cx + dx * t, a.cy + dy * t];
54710
55145
  };
54711
55146
  const candidates = [];
54712
- for (const off of [0, perp, -perp, 2 * perp, -2 * perp])
55147
+ for (const off of offList)
54713
55148
  for (const t of T_LIST) {
54714
55149
  const [bx, by] = pointAt(t);
54715
55150
  candidates.push([bx + nx * off, by + ny * off - 4]);
@@ -55460,6 +55895,12 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
55460
55895
  }
55461
55896
  }
55462
55897
  wireSync(p, leg.lineNumber);
55898
+ if (leg.value !== void 0) {
55899
+ p.attr("data-value", leg.value);
55900
+ p.append("title").text(
55901
+ leg.label !== void 0 ? `${leg.label}: ${leg.value}` : `${leg.value}`
55902
+ );
55903
+ }
55463
55904
  if (arrowTri) {
55464
55905
  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);
55465
55906
  }
@@ -55689,7 +56130,9 @@ function mapContentAspect(resolved, data, ref = REF) {
55689
56130
  function mapExportDimensions(resolved, data, baseWidth = 1200, aspectOverride) {
55690
56131
  const useOverride = aspectOverride !== void 0 && Number.isFinite(aspectOverride) && aspectOverride > 0;
55691
56132
  const raw = useOverride ? aspectOverride : mapContentAspect(resolved, data);
55692
- const clamped = useOverride ? raw : Math.max(ASPECT_MIN, Math.min(ASPECT_MAX, raw));
56133
+ const isGlobal = !useOverride && buildMapProjection(resolved, data).fitIsGlobal;
56134
+ const target = isGlobal ? raw / GLOBAL_HEIGHT_BOOST : raw;
56135
+ const clamped = useOverride ? raw : Math.max(ASPECT_MIN, Math.min(ASPECT_MAX, target));
55693
56136
  const width = baseWidth;
55694
56137
  let height = Math.round(width / clamped);
55695
56138
  let chromeReserve = 0;
@@ -55702,10 +56145,10 @@ function mapExportDimensions(resolved, data, baseWidth = 1200, aspectOverride) {
55702
56145
  height = Math.round(chromeReserve + MIN_MAP_BAND);
55703
56146
  floored = true;
55704
56147
  }
55705
- const preferContain = useOverride ? floored : clamped !== raw || floored;
56148
+ const preferContain = useOverride ? floored : clamped !== target || floored;
55706
56149
  return { width, height, preferContain };
55707
56150
  }
55708
- var FIT_PAD2, TITLE_GAP, ASPECT_MAX, ASPECT_MIN, MIN_MAP_BAND, FALLBACK_ASPECT, REF;
56151
+ var FIT_PAD2, TITLE_GAP, ASPECT_MAX, ASPECT_MIN, GLOBAL_HEIGHT_BOOST, MIN_MAP_BAND, FALLBACK_ASPECT, REF;
55709
56152
  var init_dimensions = __esm({
55710
56153
  "src/map/dimensions.ts"() {
55711
56154
  "use strict";
@@ -55715,6 +56158,7 @@ var init_dimensions = __esm({
55715
56158
  TITLE_GAP = 16;
55716
56159
  ASPECT_MAX = 3;
55717
56160
  ASPECT_MIN = 0.9;
56161
+ GLOBAL_HEIGHT_BOOST = 1.12;
55718
56162
  MIN_MAP_BAND = 200;
55719
56163
  FALLBACK_ASPECT = 1.5;
55720
56164
  REF = 1e3;
@@ -56503,14 +56947,477 @@ var init_renderer18 = __esm({
56503
56947
  }
56504
56948
  });
56505
56949
 
56506
- // src/raci/renderer.ts
56950
+ // src/treemap/layout.ts
56951
+ import {
56952
+ hierarchy as hierarchy2,
56953
+ treemap,
56954
+ treemapSquarify
56955
+ } from "d3-hierarchy";
56956
+ function toDatum(node) {
56957
+ if (node.children.length === 0) {
56958
+ return {
56959
+ ref: node,
56960
+ label: node.label,
56961
+ value: node.value ?? 0,
56962
+ ...node.heat !== void 0 && { heat: node.heat },
56963
+ lineNumber: node.lineNumber
56964
+ };
56965
+ }
56966
+ return {
56967
+ ref: node,
56968
+ label: node.label,
56969
+ ...node.heat !== void 0 && { heat: node.heat },
56970
+ lineNumber: node.lineNumber,
56971
+ children: node.children.map((c) => toDatum(c))
56972
+ };
56973
+ }
56974
+ function datumHeat(node) {
56975
+ if (node.data.heat !== void 0) return node.data.heat;
56976
+ const xs = [];
56977
+ for (const l of node.leaves()) {
56978
+ if (l.data.heat !== void 0) xs.push(l.data.heat);
56979
+ }
56980
+ if (xs.length === 0) return void 0;
56981
+ return xs.reduce((a, b) => a + b, 0) / xs.length;
56982
+ }
56983
+ function layoutTreemap(roots, opts) {
56984
+ const maxDepth = opts.maxDepth ?? Infinity;
56985
+ const rootDatum = {
56986
+ label: "__root",
56987
+ children: roots.map((r) => toDatum(r))
56988
+ };
56989
+ const h = hierarchy2(rootDatum).sum((d) => d.children?.length ? 0 : d.value ?? 0).sort((a, b) => (b.value ?? 0) - (a.value ?? 0));
56990
+ const hroot = treemap().tile(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);
56991
+ const total = hroot.value ?? 0;
56992
+ (hroot.children ?? []).forEach((top, i) => {
56993
+ top.each((d) => {
56994
+ d._topIndex = i;
56995
+ });
56996
+ });
56997
+ const cells = [];
56998
+ for (const d of hroot.descendants()) {
56999
+ if (d.depth === 0) continue;
57000
+ if (d.depth > maxDepth) continue;
57001
+ const hasChildren = !!d.children && d.children.length > 0;
57002
+ const isCollapsed = hasChildren && d.depth >= maxDepth;
57003
+ const isContainer = hasChildren && !isCollapsed;
57004
+ const path = [];
57005
+ let p = d;
57006
+ while (p && p.depth > 0) {
57007
+ path.unshift(p.data.label);
57008
+ p = p.parent;
57009
+ }
57010
+ const heatVal = datumHeat(d);
57011
+ cells.push({
57012
+ node: d.data.ref ?? null,
57013
+ label: d.data.label,
57014
+ x0: d.x0,
57015
+ y0: d.y0,
57016
+ x1: d.x1,
57017
+ y1: d.y1,
57018
+ depth: d.depth,
57019
+ value: d.value ?? 0,
57020
+ isContainer,
57021
+ isCollapsed,
57022
+ topIndex: d._topIndex ?? 0,
57023
+ pctOfRoot: total > 0 ? (d.value ?? 0) / total : 0,
57024
+ pctOfParent: d.parent && (d.parent.value ?? 0) > 0 ? (d.value ?? 0) / (d.parent.value ?? 1) : 1,
57025
+ ...heatVal !== void 0 && { heat: heatVal },
57026
+ path,
57027
+ ...d.data.lineNumber !== void 0 && { lineNumber: d.data.lineNumber }
57028
+ });
57029
+ }
57030
+ return { cells, total };
57031
+ }
57032
+ var init_layout16 = __esm({
57033
+ "src/treemap/layout.ts"() {
57034
+ "use strict";
57035
+ }
57036
+ });
57037
+
57038
+ // src/treemap/renderer.ts
56507
57039
  var renderer_exports19 = {};
56508
57040
  __export(renderer_exports19, {
57041
+ compactNumber: () => compactNumber2,
57042
+ renderTreemap: () => renderTreemap,
57043
+ renderTreemapForExport: () => renderTreemapForExport
57044
+ });
57045
+ import * as d3Selection26 from "d3-selection";
57046
+ import { scaleLinear as scaleLinear6 } from "d3-scale";
57047
+ function renderTreemapForExport(container, parsed, palette, isDark, exportDims, options) {
57048
+ renderTreemap(container, parsed, palette, isDark, exportDims, {
57049
+ exportMode: true,
57050
+ ...options
57051
+ });
57052
+ }
57053
+ function renderTreemap(container, parsed, palette, isDark, exportDims, options = {}) {
57054
+ if (parsed.error || parsed.roots.length === 0) return;
57055
+ void isDark;
57056
+ d3Selection26.select(container).selectAll(":not([data-d3-tooltip])").remove();
57057
+ const width = exportDims?.width ?? container.clientWidth;
57058
+ const height = exportDims?.height ?? container.clientHeight;
57059
+ if (width <= 0 || height <= 0) return;
57060
+ const mode = resolveColorMode(parsed, options.colorMode);
57061
+ const opts = parsed.options;
57062
+ const exportMode = options.exportMode ?? false;
57063
+ const seriesColorsTop = getSeriesColors(palette);
57064
+ const showTitle = !!parsed.title;
57065
+ const titleH = showTitle ? TITLE_BAND : 0;
57066
+ const heat = buildHeatScale(parsed, palette);
57067
+ const legend = !opts.noLegend ? buildLegend(mode, parsed, heat, seriesColorsTop, options.colorOffset ?? 0) : null;
57068
+ const legendReserve = legend ? getMaxLegendReservedHeight(
57069
+ { groups: legend.groups, position: LEGEND_POSITION, mode: "preview" },
57070
+ width
57071
+ ) + LEGEND_GROUP_GAP : 0;
57072
+ const headerH = opts.noHeaders ? 0 : HEADER_H;
57073
+ const areaX = PADDING3;
57074
+ const areaY = titleH + legendReserve + PADDING3;
57075
+ const areaW = Math.max(1, width - PADDING3 * 2);
57076
+ const areaH = Math.max(1, height - areaY - PADDING3);
57077
+ const layout = layoutTreemap(parsed.roots, {
57078
+ width: areaW,
57079
+ height: areaH,
57080
+ headerH,
57081
+ ...options.maxDepth !== void 0 && { maxDepth: options.maxDepth }
57082
+ });
57083
+ 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);
57084
+ svg.append("style").text(
57085
+ ".dgmo-treemap-focus{opacity:.3;transition:opacity .12s}.dgmo-treemap-cell:hover .dgmo-treemap-focus{opacity:.7}"
57086
+ );
57087
+ svg.append("rect").attr("width", width).attr("height", height).attr("fill", palette.bg);
57088
+ if (showTitle) {
57089
+ 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);
57090
+ if (parsed.titleLineNumber !== null) {
57091
+ title.attr("data-line-number", parsed.titleLineNumber);
57092
+ }
57093
+ }
57094
+ const root = svg.append("g").attr("class", "dgmo-treemap-cells").attr("transform", `translate(${areaX},${areaY})`);
57095
+ const seriesColors2 = seriesColorsTop;
57096
+ const colorOffset = options.colorOffset ?? 0;
57097
+ const activeGroup = parsed.tagGroups.length > 0 ? parsed.tagGroups[0].name : null;
57098
+ const rootIndexByLabel = new Map(parsed.roots.map((r, i) => [r.label, i]));
57099
+ const colorOf = (cell) => {
57100
+ if (mode === "heat") {
57101
+ return cell.heat !== void 0 && heat ? heat.scale(cell.heat) : MUTED_FILL;
57102
+ }
57103
+ if (mode === "tag") {
57104
+ if (!cell.node) return MUTED_FILL;
57105
+ return resolveTagColor(cell.node.metadata, parsed.tagGroups, activeGroup) ?? MUTED_FILL;
57106
+ }
57107
+ const topLabel = cell.path[0] ?? cell.label;
57108
+ const idx = (rootIndexByLabel.get(topLabel) ?? cell.topIndex) + colorOffset;
57109
+ const hue = seriesColors2[idx % seriesColors2.length];
57110
+ if (cell.depth <= 1) return hue;
57111
+ const keepPct = Math.max(55, 100 - (cell.depth - 1) * 18);
57112
+ return mix(hue, palette.bg, keepPct);
57113
+ };
57114
+ for (const cell of layout.cells) {
57115
+ const w = Math.max(0, cell.x1 - cell.x0);
57116
+ const h = Math.max(0, cell.y1 - cell.y0);
57117
+ if (w <= 0 || h <= 0) continue;
57118
+ const baseColor = colorOf(cell);
57119
+ const fill2 = cell.isContainer ? baseColor : mix(baseColor, palette.bg, LEAF_MUTE_PCT);
57120
+ const drillable = cell.isContainer || cell.isCollapsed;
57121
+ const g = root.append("g").attr("class", "dgmo-treemap-cell").attr("transform", `translate(${cell.x0},${cell.y0})`).attr("data-node-path", cell.path.join(" / "));
57122
+ if (cell.lineNumber !== void 0) {
57123
+ g.attr("data-line-number", cell.lineNumber);
57124
+ }
57125
+ if (cell.heat !== void 0) g.attr("data-heat", cell.heat);
57126
+ if (cell.node && activeGroup) {
57127
+ const key = tagAttrKey(activeGroup);
57128
+ const tagVal = cell.node.metadata[key];
57129
+ if (tagVal) g.attr(`data-tag-${key}`, tagVal);
57130
+ }
57131
+ const rect = g.append("rect").attr(
57132
+ "class",
57133
+ cell.isContainer ? "dgmo-treemap-rect branch" : "dgmo-treemap-rect"
57134
+ ).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);
57135
+ if (drillable && options.onClickItem && cell.lineNumber !== void 0) {
57136
+ const ln = cell.lineNumber;
57137
+ rect.style("cursor", "pointer").on("click", () => options.onClickItem(ln));
57138
+ }
57139
+ const ink = contrastText(
57140
+ fill2,
57141
+ palette.textOnFillLight,
57142
+ palette.textOnFillDark
57143
+ );
57144
+ if (cell.isContainer && headerH > 0 && w > 34 && h > headerH) {
57145
+ const valParts = [];
57146
+ if (!opts.noValues) valParts.push(compactNumber2(cell.value));
57147
+ if (!opts.noPercent) valParts.push(formatPct(cell.pctOfRoot));
57148
+ const valStr = valParts.join(" \xB7 ");
57149
+ const ICON_RESERVE = drillable ? 16 : 4;
57150
+ const showVal = valStr.length > 0 && w > 110;
57151
+ const valW = showVal ? measureText(valStr, 10.5) : 0;
57152
+ const labelMax = w - 8 - ICON_RESERVE - (showVal ? valW + 10 : 0);
57153
+ 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));
57154
+ if (showVal) {
57155
+ 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);
57156
+ }
57157
+ }
57158
+ const PAD = Math.max(4, Math.min(14, Math.floor(Math.min(w, h) / 5)));
57159
+ const MIN_FS = 7;
57160
+ if (!cell.isContainer && w >= 2 * PAD + 8 && h >= 2 * PAD + 8) {
57161
+ const maxW = w - 2 * PAD;
57162
+ let fs = clamp3(Math.round(Math.min(w / 3.6, h / 3.4)), MIN_FS, 72);
57163
+ const nameW = measureText(cell.label, fs) * 1.06;
57164
+ if (nameW > maxW) fs = Math.max(MIN_FS, Math.floor(fs * maxW / nameW));
57165
+ const tg = clamp3((fs - MIN_FS) / (72 - MIN_FS), 0, 1);
57166
+ const nameOpacity = 0.95 - tg * 0.5;
57167
+ const vfs = clamp3(Math.round(fs * 0.42), 11, 28);
57168
+ const valOpacity = Math.max(0.45, nameOpacity - 0.1);
57169
+ let y = PAD + Math.round(fs * 0.78);
57170
+ 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));
57171
+ const valParts = [
57172
+ opts.noValues ? "" : compactNumber2(cell.value),
57173
+ opts.noPercent ? "" : formatPct(cell.pctOfRoot)
57174
+ ].filter(Boolean);
57175
+ const combined = valParts.join(" \xB7 ");
57176
+ const nameBaseY = y;
57177
+ const addLineAt = (text, yy, size, opacity) => {
57178
+ 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);
57179
+ };
57180
+ if (combined) {
57181
+ const fitsW = measureText(combined, vfs) <= maxW;
57182
+ const roomBelow = h - PAD > y + vfs + 6;
57183
+ if (fitsW && roomBelow) {
57184
+ addLineAt(combined, y + vfs + 6, vfs, valOpacity);
57185
+ } else if (fitsW) {
57186
+ const ivfs = clamp3(Math.round(fs * 0.5), 11, Math.max(11, vfs));
57187
+ const rendered = clipLabel(cell.label, maxW, fs);
57188
+ const nW = measureText(rendered, fs) * 1.12;
57189
+ const gap = Math.max(12, Math.round(fs * 0.25));
57190
+ if (PAD + nW + gap + measureText(combined, ivfs) <= w - PAD) {
57191
+ 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);
57192
+ }
57193
+ } else if (valParts.length === 2) {
57194
+ if (h - PAD > y + vfs + 6) {
57195
+ y += vfs + 6;
57196
+ addLineAt(valParts[0], y, vfs, valOpacity);
57197
+ }
57198
+ const pfs = Math.max(10, Math.round(vfs * 0.9));
57199
+ if (h - PAD > y + pfs + 4) {
57200
+ y += pfs + 4;
57201
+ addLineAt(valParts[1], y, pfs, valOpacity);
57202
+ }
57203
+ } else if (h - PAD > y + vfs + 6) {
57204
+ addLineAt(combined, y + vfs + 6, vfs, valOpacity);
57205
+ }
57206
+ }
57207
+ }
57208
+ if (drillable && w > 30 && h > 22) {
57209
+ drawFocusIcon(g, w, ink, 9);
57210
+ }
57211
+ }
57212
+ if (legend) {
57213
+ const legendG = svg.append("g").attr("class", "dgmo-treemap-legend").attr("transform", `translate(0, ${titleH})`);
57214
+ renderIntegratedLegend(legendG, {
57215
+ groups: legend.groups,
57216
+ palette: {
57217
+ bg: palette.bg,
57218
+ surface: palette.surface,
57219
+ text: palette.text,
57220
+ textMuted: palette.textMuted,
57221
+ primary: palette.primary
57222
+ },
57223
+ isDark,
57224
+ width,
57225
+ mode: exportMode ? "export" : "preview",
57226
+ position: LEGEND_POSITION,
57227
+ activeGroup: legend.activeGroup,
57228
+ // The color-mode switcher is the legend itself: each applicable mode is a
57229
+ // group pill; the active one is the open capsule, the rest are clickable
57230
+ // pills that switch mode. Export shows only the active group.
57231
+ showInactivePills: !exportMode,
57232
+ showEmptyGroups: !exportMode,
57233
+ ...options.onSelectMode !== void 0 && {
57234
+ callbacks: {
57235
+ onGroupToggle: (name) => {
57236
+ const m = legend.modeByName.get(name);
57237
+ if (m) options.onSelectMode(m);
57238
+ }
57239
+ }
57240
+ }
57241
+ });
57242
+ }
57243
+ }
57244
+ function buildLegend(activeMode, parsed, heat, seriesColors2, colorOffset) {
57245
+ const groups = [];
57246
+ const modeByName = /* @__PURE__ */ new Map();
57247
+ let activeGroup = null;
57248
+ if (parsed.tagGroups.length > 0) {
57249
+ const tg = parsed.tagGroups[0];
57250
+ const used = /* @__PURE__ */ new Set();
57251
+ const collect = (nodes) => {
57252
+ for (const n of nodes) {
57253
+ const v = n.metadata[tagAttrKey(tg.name)];
57254
+ if (v) used.add(v.toLowerCase());
57255
+ collect(n.children);
57256
+ }
57257
+ };
57258
+ collect(parsed.roots);
57259
+ groups.push({
57260
+ name: tg.name,
57261
+ entries: tg.entries.filter((e) => used.has(e.value.toLowerCase())).map((e) => ({ value: e.value, color: e.color }))
57262
+ });
57263
+ modeByName.set(tg.name, "tag");
57264
+ if (activeMode === "tag") activeGroup = tg.name;
57265
+ }
57266
+ if (heat) {
57267
+ const name = parsed.options.heatLabel ?? "Value";
57268
+ groups.push({
57269
+ name,
57270
+ entries: [],
57271
+ gradient: {
57272
+ min: heat.min,
57273
+ max: heat.max,
57274
+ low: heat.stops[0],
57275
+ high: heat.stops[heat.stops.length - 1]
57276
+ }
57277
+ });
57278
+ modeByName.set(name, "heat");
57279
+ if (activeMode === "heat") activeGroup = name;
57280
+ }
57281
+ groups.push({
57282
+ name: "Branch",
57283
+ entries: parsed.roots.map((r, i) => ({
57284
+ value: r.label,
57285
+ color: seriesColors2[(i + colorOffset) % seriesColors2.length]
57286
+ }))
57287
+ });
57288
+ modeByName.set("Branch", "branch");
57289
+ if (activeMode === "branch" || activeGroup === null) activeGroup = "Branch";
57290
+ return { groups, activeGroup, modeByName };
57291
+ }
57292
+ function buildHeatScale(parsed, palette) {
57293
+ if (!parsed.hasHeat) return null;
57294
+ const values = [];
57295
+ const collect = (nodes) => {
57296
+ for (const n of nodes) {
57297
+ if (typeof n.heat === "number") values.push(n.heat);
57298
+ collect(n.children);
57299
+ }
57300
+ };
57301
+ collect(parsed.roots);
57302
+ if (values.length === 0) return null;
57303
+ const min = Math.min(...values);
57304
+ const max = Math.max(...values);
57305
+ const signed = min < 0 && max > 0;
57306
+ const neutral = palette.surface;
57307
+ const explicit = parsed.options.heatColors.map((c) => resolveColor(c, palette) ?? c).filter((c) => !!c);
57308
+ let stops;
57309
+ let domain;
57310
+ if (explicit.length >= 2) {
57311
+ stops = [explicit[0], neutral, explicit[1]];
57312
+ const mid = signed ? 0 : (min + max) / 2;
57313
+ domain = [min, mid, max];
57314
+ } else if (explicit.length === 1) {
57315
+ stops = [neutral, explicit[0]];
57316
+ domain = [min, max];
57317
+ } else if (signed) {
57318
+ stops = [palette.colors.red, neutral, palette.colors.green];
57319
+ domain = [min, 0, max];
57320
+ } else {
57321
+ stops = [neutral, palette.primary];
57322
+ domain = [min, max];
57323
+ }
57324
+ if (domain[0] === domain[domain.length - 1]) {
57325
+ const last = stops[stops.length - 1];
57326
+ return { scale: () => last, min, max, stops, signed };
57327
+ }
57328
+ const linear = scaleLinear6().domain(domain).range(stops).clamp(true);
57329
+ return { scale: (v) => toHex(linear(v)), min, max, stops, signed };
57330
+ }
57331
+ function toHex(c) {
57332
+ if (c.startsWith("#")) return c;
57333
+ const m = c.match(/rgba?\(([^)]+)\)/);
57334
+ if (!m) return c;
57335
+ const parts = m[1].split(",").map((s) => Math.round(parseFloat(s)));
57336
+ const h = (n) => Math.max(0, Math.min(255, n || 0)).toString(16).padStart(2, "0");
57337
+ return `#${h(parts[0] ?? 0)}${h(parts[1] ?? 0)}${h(parts[2] ?? 0)}`;
57338
+ }
57339
+ function resolveColorMode(parsed, override) {
57340
+ let mode = override ?? parsed.defaultColorMode;
57341
+ if (mode === "tag" && parsed.tagGroups.length === 0) {
57342
+ mode = parsed.hasHeat ? "heat" : "branch";
57343
+ }
57344
+ if (mode === "heat" && !parsed.hasHeat) mode = "branch";
57345
+ return mode;
57346
+ }
57347
+ function drawFocusIcon(g, w, ink, cy) {
57348
+ const r = 4.5;
57349
+ const cx = w - r - 5;
57350
+ const fi = g.append("g").attr("class", "dgmo-treemap-focus").attr("data-export-ignore", "true");
57351
+ fi.append("rect").attr("x", cx - 9).attr("y", cy - 9).attr("width", 18).attr("height", 18).attr("fill", "transparent");
57352
+ fi.append("circle").attr("cx", cx).attr("cy", cy).attr("r", r).attr("fill", "none").attr("stroke", ink).attr("stroke-width", 1.25);
57353
+ fi.append("circle").attr("cx", cx).attr("cy", cy).attr("r", 1.4).attr("fill", ink);
57354
+ }
57355
+ function clamp3(x, lo, hi) {
57356
+ return Math.max(lo, Math.min(hi, x));
57357
+ }
57358
+ function clipLabel(s, maxWidth, fs) {
57359
+ if (measureText(s, fs) <= maxWidth) return s;
57360
+ let lo = 0;
57361
+ let hi = s.length;
57362
+ while (lo < hi) {
57363
+ const mid = Math.ceil((lo + hi) / 2);
57364
+ if (measureText(s.slice(0, mid) + "\u2026", fs) <= maxWidth) lo = mid;
57365
+ else hi = mid - 1;
57366
+ }
57367
+ return lo <= 0 ? "" : s.slice(0, lo) + "\u2026";
57368
+ }
57369
+ function compactNumber2(v) {
57370
+ const abs = Math.abs(v);
57371
+ if (abs >= 1e9) return strip(v / 1e9) + "B";
57372
+ if (abs >= 1e6) return strip(v / 1e6) + "M";
57373
+ if (abs >= 1e3) return strip(v / 1e3) + "k";
57374
+ return strip(Math.round(v * 100) / 100);
57375
+ }
57376
+ function strip(n) {
57377
+ return parseFloat(
57378
+ n.toFixed(n < 10 && !Number.isInteger(n) ? 1 : 0)
57379
+ ).toString();
57380
+ }
57381
+ function formatPct(frac) {
57382
+ const pct = frac * 100;
57383
+ if (pct >= 10) return `${Math.round(pct)}%`;
57384
+ if (pct >= 1) return `${pct.toFixed(0)}%`;
57385
+ return `${pct.toFixed(1)}%`;
57386
+ }
57387
+ var PADDING3, HEADER_H, TITLE_BAND, MUTED_FILL, LEAF_MUTE_PCT, LEGEND_POSITION;
57388
+ var init_renderer19 = __esm({
57389
+ "src/treemap/renderer.ts"() {
57390
+ "use strict";
57391
+ init_fonts();
57392
+ init_colors();
57393
+ init_color_utils();
57394
+ init_tag_groups();
57395
+ init_text_measure();
57396
+ init_legend_integration();
57397
+ init_legend_layout();
57398
+ init_legend_constants();
57399
+ init_title_constants();
57400
+ init_layout16();
57401
+ PADDING3 = 12;
57402
+ HEADER_H = 18;
57403
+ TITLE_BAND = 36;
57404
+ MUTED_FILL = "#cbd5e1";
57405
+ LEAF_MUTE_PCT = 50;
57406
+ LEGEND_POSITION = {
57407
+ placement: "top-center",
57408
+ titleRelation: "below-title"
57409
+ };
57410
+ }
57411
+ });
57412
+
57413
+ // src/raci/renderer.ts
57414
+ var renderer_exports20 = {};
57415
+ __export(renderer_exports20, {
56509
57416
  MARKER_LABELS: () => MARKER_LABELS,
56510
57417
  renderRaci: () => renderRaci,
56511
57418
  renderRaciForExport: () => renderRaciForExport
56512
57419
  });
56513
- import * as d3Selection26 from "d3-selection";
57420
+ import * as d3Selection27 from "d3-selection";
56514
57421
  function groupDiagnosticsByTask(parsed) {
56515
57422
  const map = /* @__PURE__ */ new Map();
56516
57423
  if (parsed.diagnostics.length === 0) return map;
@@ -56582,7 +57489,7 @@ function renderRaci(container, parsed, palette, isDark, handlers, exportDims) {
56582
57489
  const hideLegend = opts.hideLegend ?? false;
56583
57490
  const collapsedPhases = opts.collapsedPhases ?? /* @__PURE__ */ new Set();
56584
57491
  const hideTitle = (opts.hideTitle ?? false) || parsed.options["no-title"] === "on";
56585
- d3Selection26.select(container).selectAll(":not([data-d3-tooltip])").remove();
57492
+ d3Selection27.select(container).selectAll(":not([data-d3-tooltip])").remove();
56586
57493
  const width = exportDims?.width ?? container.clientWidth;
56587
57494
  const height = exportDims?.height ?? container.clientHeight;
56588
57495
  if (width <= 0 || height <= 0) return;
@@ -56689,7 +57596,7 @@ function renderRaci(container, parsed, palette, isDark, handlers, exportDims) {
56689
57596
  const colBottomY = cursorY + sColumnBottomPad;
56690
57597
  const totalHeight = colBottomY + sVMargin;
56691
57598
  const svgHeight = exportDims ? totalHeight : Math.max(height, totalHeight);
56692
- 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");
57599
+ 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");
56693
57600
  if (ctx.isBelowFloor) {
56694
57601
  svg.attr("width", "100%");
56695
57602
  }
@@ -57170,13 +58077,13 @@ function parseQuotedSegments(message) {
57170
58077
  return out;
57171
58078
  }
57172
58079
  var 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;
57173
- var init_renderer19 = __esm({
58080
+ var init_renderer20 = __esm({
57174
58081
  "src/raci/renderer.ts"() {
57175
58082
  "use strict";
57176
58083
  init_fonts();
57177
58084
  init_title_constants();
57178
58085
  init_color_utils();
57179
- init_parser26();
58086
+ init_parser27();
57180
58087
  init_variants();
57181
58088
  init_scaling();
57182
58089
  init_text_measure();
@@ -57433,8 +58340,8 @@ var init_tag_resolution = __esm({
57433
58340
  });
57434
58341
 
57435
58342
  // src/sequence/renderer.ts
57436
- var renderer_exports20 = {};
57437
- __export(renderer_exports20, {
58343
+ var renderer_exports21 = {};
58344
+ __export(renderer_exports21, {
57438
58345
  applyGroupOrdering: () => applyGroupOrdering,
57439
58346
  applyPositionOverrides: () => applyPositionOverrides,
57440
58347
  buildNoteMessageMap: () => buildNoteMessageMap,
@@ -57445,7 +58352,7 @@ __export(renderer_exports20, {
57445
58352
  renderSequenceDiagram: () => renderSequenceDiagram,
57446
58353
  truncateBareUrl: () => truncateBareUrl
57447
58354
  });
57448
- import * as d3Selection27 from "d3-selection";
58355
+ import * as d3Selection28 from "d3-selection";
57449
58356
  function wrapTextLines(text, maxWidth, fontSize) {
57450
58357
  const rawLines = text.split("\n").map((l) => l.startsWith("- ") ? "\u2022 " + l.slice(2) : l);
57451
58358
  return wrapDescriptionLines(
@@ -57775,7 +58682,7 @@ function applyGroupOrdering(participants, groups, messages = []) {
57775
58682
  return result;
57776
58683
  }
57777
58684
  function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateToLine, options) {
57778
- d3Selection27.select(container).selectAll("*").remove();
58685
+ d3Selection28.select(container).selectAll("*").remove();
57779
58686
  const { title, options: parsedOptions } = parsed;
57780
58687
  const solid = parsedOptions["solid-fill"] === "on";
57781
58688
  const effectiveCollapsedGroups = /* @__PURE__ */ new Set();
@@ -58426,7 +59333,7 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
58426
59333
  offsetX = leftMargin + Math.max(0, (svgWidth - totalWidth) / 2);
58427
59334
  buildParticipantX();
58428
59335
  }
58429
- 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);
59336
+ 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);
58430
59337
  const defs = svg.append("defs");
58431
59338
  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(
58432
59339
  "points",
@@ -59039,7 +59946,7 @@ function renderParticipant(svg, participant, cx, cy, palette, isDark, color, tag
59039
59946
  }
59040
59947
  }
59041
59948
  var 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;
59042
- var init_renderer20 = __esm({
59949
+ var init_renderer21 = __esm({
59043
59950
  "src/sequence/renderer.ts"() {
59044
59951
  "use strict";
59045
59952
  init_tag_groups();
@@ -62917,6 +63824,7 @@ var DIAGRAM_EXPORT_HANDLERS = {
62917
63824
  map: exportMap,
62918
63825
  pyramid: exportPyramid,
62919
63826
  ring: exportRing,
63827
+ treemap: exportTreemap,
62920
63828
  raci: exportRaci,
62921
63829
  rasci: exportRaci,
62922
63830
  daci: exportRaci,
@@ -62974,10 +63882,10 @@ async function exportOrg(ctx) {
62974
63882
  false
62975
63883
  // expandAllLegend off — collapsed-by-default per §1.3
62976
63884
  );
62977
- const PADDING3 = 20;
63885
+ const PADDING4 = 20;
62978
63886
  const titleOffset = effectiveParsed.title ? 30 : 0;
62979
- const exportWidth = orgLayout.width + PADDING3 * 2;
62980
- const exportHeight = orgLayout.height + PADDING3 * 2 + titleOffset;
63887
+ const exportWidth = orgLayout.width + PADDING4 * 2;
63888
+ const exportHeight = orgLayout.height + PADDING4 * 2 + titleOffset;
62981
63889
  const container = createExportContainer(exportWidth, exportHeight);
62982
63890
  renderOrg2(
62983
63891
  container,
@@ -63019,10 +63927,10 @@ async function exportSitemap(ctx) {
63019
63927
  hiddenAttributes,
63020
63928
  true
63021
63929
  );
63022
- const PADDING3 = 20;
63930
+ const PADDING4 = 20;
63023
63931
  const titleOffset = effectiveParsed.title ? 30 : 0;
63024
- const exportWidth = sitemapLayout.width + PADDING3 * 2;
63025
- const exportHeight = sitemapLayout.height + PADDING3 * 2 + titleOffset;
63932
+ const exportWidth = sitemapLayout.width + PADDING4 * 2;
63933
+ const exportHeight = sitemapLayout.height + PADDING4 * 2 + titleOffset;
63026
63934
  const container = createExportContainer(exportWidth, exportHeight);
63027
63935
  renderSitemap2(
63028
63936
  container,
@@ -63078,10 +63986,10 @@ async function exportClass(ctx) {
63078
63986
  const classParsed = parseClassDiagram2(content, effectivePalette);
63079
63987
  if (classParsed.error || classParsed.classes.length === 0) return "";
63080
63988
  const classLayout = layoutClassDiagram2(classParsed);
63081
- const PADDING3 = 20;
63989
+ const PADDING4 = 20;
63082
63990
  const titleOffset = classParsed.title ? 40 : 0;
63083
- const exportWidth = classLayout.width + PADDING3 * 2;
63084
- const exportHeight = classLayout.height + PADDING3 * 2 + titleOffset;
63991
+ const exportWidth = classLayout.width + PADDING4 * 2;
63992
+ const exportHeight = classLayout.height + PADDING4 * 2 + titleOffset;
63085
63993
  const container = createExportContainer(exportWidth, exportHeight);
63086
63994
  renderClassDiagram2(
63087
63995
  container,
@@ -63105,10 +64013,10 @@ async function exportEr(ctx) {
63105
64013
  const erParsed = parseERDiagram2(content, effectivePalette);
63106
64014
  if (erParsed.error || erParsed.tables.length === 0) return "";
63107
64015
  const erLayout = layoutERDiagram2(erParsed);
63108
- const PADDING3 = 20;
64016
+ const PADDING4 = 20;
63109
64017
  const titleOffset = erParsed.title ? 40 : 0;
63110
- const exportWidth = erLayout.width + PADDING3 * 2;
63111
- const exportHeight = erLayout.height + PADDING3 * 2 + titleOffset;
64018
+ const exportWidth = erLayout.width + PADDING4 * 2;
64019
+ const exportHeight = erLayout.height + PADDING4 * 2 + titleOffset;
63112
64020
  const container = createExportContainer(exportWidth, exportHeight);
63113
64021
  renderERDiagram2(
63114
64022
  container,
@@ -63144,10 +64052,10 @@ async function exportBoxesAndLines(ctx) {
63144
64052
  const { renderBoxesAndLinesForExport: renderBoxesAndLinesForExport2 } = await Promise.resolve().then(() => (init_renderer6(), renderer_exports6));
63145
64053
  const { layoutBoxesAndLines: layoutBoxesAndLines2 } = await Promise.resolve().then(() => (init_layout5(), layout_exports5));
63146
64054
  const blLayout = await layoutBoxesAndLines2(blParsed);
63147
- const PADDING3 = 20;
64055
+ const PADDING4 = 20;
63148
64056
  const titleOffset = blParsed.title ? 40 : 0;
63149
- const exportWidth = blLayout.width + PADDING3 * 2;
63150
- const exportHeight = blLayout.height + PADDING3 * 2 + titleOffset;
64057
+ const exportWidth = blLayout.width + PADDING4 * 2;
64058
+ const exportHeight = blLayout.height + PADDING4 * 2 + titleOffset;
63151
64059
  const container = createExportContainer(exportWidth, exportHeight);
63152
64060
  const blActiveTagGroup = ctxTagOverride(ctx);
63153
64061
  renderBoxesAndLinesForExport2(
@@ -63194,10 +64102,10 @@ async function exportMindmap(ctx) {
63194
64102
  activeTagGroup,
63195
64103
  hideDescriptions
63196
64104
  });
63197
- const PADDING3 = 20;
64105
+ const PADDING4 = 20;
63198
64106
  const titleOffset = effectiveParsed.title ? 30 : 0;
63199
- const exportWidth = mmLayout.width + PADDING3 * 2;
63200
- const exportHeight = mmLayout.height + PADDING3 * 2 + titleOffset;
64107
+ const exportWidth = mmLayout.width + PADDING4 * 2;
64108
+ const exportHeight = mmLayout.height + PADDING4 * 2 + titleOffset;
63201
64109
  const container = createExportContainer(exportWidth, exportHeight);
63202
64110
  const colorByDepth = viewState?.cbd === true;
63203
64111
  renderMindmap2(
@@ -63258,10 +64166,10 @@ async function exportC4(ctx) {
63258
64166
  const c4Container = ctx.options?.c4Container ?? viewState?.c4c;
63259
64167
  const c4Layout = c4Level === "deployment" ? layoutC4Deployment2(c4Parsed) : c4Level === "components" && c4System && c4Container ? layoutC4Components2(c4Parsed, c4System, c4Container) : c4Level === "containers" && c4System ? layoutC4Containers2(c4Parsed, c4System) : layoutC4Context2(c4Parsed);
63260
64168
  if (c4Layout.nodes.length === 0) return "";
63261
- const PADDING3 = 20;
64169
+ const PADDING4 = 20;
63262
64170
  const titleOffset = c4Parsed.title ? 40 : 0;
63263
- const exportWidth = c4Layout.width + PADDING3 * 2;
63264
- const exportHeight = c4Layout.height + PADDING3 * 2 + titleOffset;
64171
+ const exportWidth = c4Layout.width + PADDING4 * 2;
64172
+ const exportHeight = c4Layout.height + PADDING4 * 2 + titleOffset;
63265
64173
  const container = createExportContainer(exportWidth, exportHeight);
63266
64174
  const renderFn = c4Level === "deployment" || c4Level === "components" && c4System && c4Container || c4Level === "containers" && c4System ? renderC4Containers2 : renderC4Context2;
63267
64175
  renderFn(
@@ -63577,30 +64485,44 @@ async function exportRing(ctx) {
63577
64485
  const ringParsed = parseRing2(content);
63578
64486
  if (ringParsed.error || ringParsed.layers.length === 0) return "";
63579
64487
  const container = createExportContainer(EXPORT_WIDTH, EXPORT_HEIGHT);
63580
- renderRingForExport2(
64488
+ renderRingForExport2(container, ringParsed, effectivePalette, ctx.isDark, {
64489
+ width: EXPORT_WIDTH,
64490
+ height: EXPORT_HEIGHT
64491
+ });
64492
+ return finalizeSvgExport(container, theme, effectivePalette);
64493
+ }
64494
+ async function exportTreemap(ctx) {
64495
+ const { content, theme, palette } = ctx;
64496
+ const { parseTreemap: parseTreemap2 } = await Promise.resolve().then(() => (init_parser26(), parser_exports20));
64497
+ const { renderTreemapForExport: renderTreemapForExport2 } = await Promise.resolve().then(() => (init_renderer19(), renderer_exports19));
64498
+ const effectivePalette = await resolveExportPalette(theme, palette);
64499
+ const treemapParsed = parseTreemap2(content, effectivePalette);
64500
+ if (treemapParsed.error || treemapParsed.roots.length === 0) return "";
64501
+ const container = createExportContainer(EXPORT_WIDTH, EXPORT_HEIGHT);
64502
+ renderTreemapForExport2(
63581
64503
  container,
63582
- ringParsed,
64504
+ treemapParsed,
63583
64505
  effectivePalette,
63584
64506
  ctx.isDark,
63585
- { width: EXPORT_WIDTH, height: EXPORT_HEIGHT }
64507
+ {
64508
+ width: EXPORT_WIDTH,
64509
+ height: EXPORT_HEIGHT
64510
+ }
63586
64511
  );
63587
64512
  return finalizeSvgExport(container, theme, effectivePalette);
63588
64513
  }
63589
64514
  async function exportRaci(ctx) {
63590
64515
  const { content, theme, palette } = ctx;
63591
- const { parseRaci: parseRaci2 } = await Promise.resolve().then(() => (init_parser26(), parser_exports20));
63592
- const { renderRaciForExport: renderRaciForExport2 } = await Promise.resolve().then(() => (init_renderer19(), renderer_exports19));
64516
+ const { parseRaci: parseRaci2 } = await Promise.resolve().then(() => (init_parser27(), parser_exports21));
64517
+ const { renderRaciForExport: renderRaciForExport2 } = await Promise.resolve().then(() => (init_renderer20(), renderer_exports20));
63593
64518
  const effectivePalette = await resolveExportPalette(theme, palette);
63594
64519
  const raciParsed = parseRaci2(content, effectivePalette);
63595
64520
  if (raciParsed.error) return "";
63596
64521
  const container = createExportContainer(EXPORT_WIDTH, EXPORT_HEIGHT);
63597
- renderRaciForExport2(
63598
- container,
63599
- raciParsed,
63600
- effectivePalette,
63601
- ctx.isDark,
63602
- { width: EXPORT_WIDTH, height: EXPORT_HEIGHT }
63603
- );
64522
+ renderRaciForExport2(container, raciParsed, effectivePalette, ctx.isDark, {
64523
+ width: EXPORT_WIDTH,
64524
+ height: EXPORT_HEIGHT
64525
+ });
63604
64526
  return finalizeSvgExport(container, theme, effectivePalette);
63605
64527
  }
63606
64528
  function beginVizExport() {
@@ -63689,14 +64611,7 @@ async function exportVenn(ctx) {
63689
64611
  if (parsed.error || parsed.vennSets.length < 2) return "";
63690
64612
  const effectivePalette = await resolveExportPalette(theme, palette);
63691
64613
  const { container, dims } = beginVizExport();
63692
- renderVenn(
63693
- container,
63694
- parsed,
63695
- effectivePalette,
63696
- ctx.isDark,
63697
- void 0,
63698
- dims
63699
- );
64614
+ renderVenn(container, parsed, effectivePalette, ctx.isDark, void 0, dims);
63700
64615
  return finalizeSvgExport(container, theme, effectivePalette);
63701
64616
  }
63702
64617
  async function exportQuadrant(ctx) {
@@ -63730,7 +64645,7 @@ async function exportVisualization(ctx) {
63730
64645
  const isDark = ctx.isDark;
63731
64646
  const container = createExportContainer(EXPORT_WIDTH, EXPORT_HEIGHT);
63732
64647
  const { parseSequenceDgmo: parseSequenceDgmo2 } = await Promise.resolve().then(() => (init_parser7(), parser_exports));
63733
- const { renderSequenceDiagram: renderSequenceDiagram2 } = await Promise.resolve().then(() => (init_renderer20(), renderer_exports20));
64648
+ const { renderSequenceDiagram: renderSequenceDiagram2 } = await Promise.resolve().then(() => (init_renderer21(), renderer_exports21));
63734
64649
  const seqParsed = parseSequenceDgmo2(content, effectivePalette);
63735
64650
  if (seqParsed.error || seqParsed.participants.length === 0) return "";
63736
64651
  const collapsedSections = viewState?.cs ? new Set(viewState.cs) : void 0;
@@ -63941,6 +64856,7 @@ var CHART_TYPES = /* @__PURE__ */ new Set([
63941
64856
  "journey-map",
63942
64857
  "pyramid",
63943
64858
  "ring",
64859
+ "treemap",
63944
64860
  "raci",
63945
64861
  "rasci",
63946
64862
  "daci",
@@ -64132,6 +65048,8 @@ var ATTRIBUTE_KEYS = /* @__PURE__ */ new Set([
64132
65048
  "value",
64133
65049
  "label",
64134
65050
  "style",
65051
+ // Treemap color-by-value metric key
65052
+ "heat",
64135
65053
  // Infra node behavior + edge colon-keys (§4) come from the single-source
64136
65054
  // directives registry — the parser accepts them only as `key: value` node
64137
65055
  // properties, so they render as `propertyName`. The dual-use top-level SLO
@@ -64509,7 +65427,7 @@ pre.dgmo, code.language-dgmo, pre > code.language-dgmo,
64509
65427
 
64510
65428
  // src/auto/index.ts
64511
65429
  init_safe_href();
64512
- var VERSION = "0.36.0";
65430
+ var VERSION = "0.38.0";
64513
65431
  var DEFAULTS = {
64514
65432
  theme: "auto",
64515
65433
  palette: "slate",