@diagrammo/dgmo 0.37.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.
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"
@@ -19019,7 +19025,7 @@ function parseMap(content, palette) {
19019
19025
  continue;
19020
19026
  }
19021
19027
  if (DIRECTIVE_SET.has(firstWord) && !trimmed.slice(firstWord.length).trimStart().startsWith(":")) {
19022
- handleDirective(
19028
+ handleDirective2(
19023
19029
  firstWord,
19024
19030
  trimmed.slice(firstWord.length).trim(),
19025
19031
  lineNumber
@@ -19058,7 +19064,7 @@ function parseMap(content, palette) {
19058
19064
  }
19059
19065
  }
19060
19066
  return result;
19061
- function handleDirective(key, value, line11) {
19067
+ function handleDirective2(key, value, line11) {
19062
19068
  const d = result.directives;
19063
19069
  const dup = (have) => {
19064
19070
  if (have !== void 0)
@@ -22928,6 +22934,344 @@ var init_parser25 = __esm({
22928
22934
  }
22929
22935
  });
22930
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
+
22931
23275
  // src/raci/variants.ts
22932
23276
  function inferVariant(markers) {
22933
23277
  let hasD = false;
@@ -23182,8 +23526,8 @@ var init_variants = __esm({
23182
23526
  });
23183
23527
 
23184
23528
  // src/raci/parser.ts
23185
- var parser_exports20 = {};
23186
- __export(parser_exports20, {
23529
+ var parser_exports21 = {};
23530
+ __export(parser_exports21, {
23187
23531
  allTasks: () => allTasks,
23188
23532
  parseRaci: () => parseRaci
23189
23533
  });
@@ -23704,7 +24048,7 @@ function* allTasks(parsed) {
23704
24048
  }
23705
24049
  }
23706
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;
23707
- var init_parser26 = __esm({
24051
+ var init_parser27 = __esm({
23708
24052
  "src/raci/parser.ts"() {
23709
24053
  "use strict";
23710
24054
  init_diagnostics();
@@ -23950,6 +24294,7 @@ var init_chart_type_registry = __esm({
23950
24294
  init_parser24();
23951
24295
  init_parser25();
23952
24296
  init_parser26();
24297
+ init_parser27();
23953
24298
  CHART_TYPE_REGISTRY = [
23954
24299
  // ── Structured diagrams ───────────────────────────────────
23955
24300
  {
@@ -24090,6 +24435,9 @@ var init_chart_type_registry = __esm({
24090
24435
  { id: "cycle", category: "visualization", parse: parseCycle },
24091
24436
  { id: "pyramid", category: "visualization", parse: parsePyramid },
24092
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 },
24093
24441
  // ── Geographic map (own parser → resolver → layout → renderer) ──
24094
24442
  { id: "map", category: "visualization", parse: parseMap }
24095
24443
  ];
@@ -26822,10 +27170,10 @@ async function renderSitemapForExport(content, theme, palette) {
26822
27170
  const parsed = parseSitemap2(content, effectivePalette);
26823
27171
  if (parsed.error || parsed.roots.length === 0) return "";
26824
27172
  const sitemapLayout = layoutSitemap2(parsed, void 0, null, void 0, true);
26825
- const PADDING3 = 20;
27173
+ const PADDING4 = 20;
26826
27174
  const titleOffset = parsed.title ? 30 : 0;
26827
- const exportWidth = sitemapLayout.width + PADDING3 * 2;
26828
- const exportHeight = sitemapLayout.height + PADDING3 * 2 + titleOffset;
27175
+ const exportWidth = sitemapLayout.width + PADDING4 * 2;
27176
+ const exportHeight = sitemapLayout.height + PADDING4 * 2 + titleOffset;
26829
27177
  const container = document.createElement("div");
26830
27178
  container.style.width = `${exportWidth}px`;
26831
27179
  container.style.height = `${exportHeight}px`;
@@ -31943,6 +32291,10 @@ async function layoutBoxesAndLinesSearch(parsed, collapseInfo, opts) {
31943
32291
  const reserveEdgeLabels = opts?.reserveEdgeLabels ?? false;
31944
32292
  const onProgress = opts?.onProgress;
31945
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;
31946
32298
  const collapsedGroupLabels = /* @__PURE__ */ new Set();
31947
32299
  if (collapseInfo) {
31948
32300
  const missing = /* @__PURE__ */ new Set();
@@ -32372,7 +32724,11 @@ async function layoutBoxesAndLinesSearch(parsed, collapseInfo, opts) {
32372
32724
  const step = async (phase) => {
32373
32725
  if (!onProgress) return;
32374
32726
  onProgress(++progressDone, progressTotal, phase);
32375
- 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
+ }
32376
32732
  };
32377
32733
  const pool = [];
32378
32734
  for (const cfg of configs) {
@@ -50985,7 +51341,7 @@ function computeEdgeLabelPosition(midAngle, radius, cx, cy, lineCount, labelPxW,
50985
51341
  };
50986
51342
  }
50987
51343
  function fitToCanvas(nodes, edges, parsed, _cx, _cy, radius, width, height, _isClockwise) {
50988
- const PADDING3 = 30;
51344
+ const PADDING4 = 30;
50989
51345
  let contentMinX = Infinity, contentMaxX = -Infinity;
50990
51346
  let contentMinY = Infinity, contentMaxY = -Infinity;
50991
51347
  for (const n of nodes) {
@@ -51027,13 +51383,13 @@ function fitToCanvas(nodes, edges, parsed, _cx, _cy, radius, width, height, _isC
51027
51383
  contentMinY = Math.min(contentMinY, le.labelY - 12);
51028
51384
  contentMaxY = Math.max(contentMaxY, le.labelY + (lineCount - 1) * 15);
51029
51385
  }
51030
- const overflowX = Math.max(0, PADDING3 - contentMinX) + Math.max(0, contentMaxX - (width - PADDING3));
51031
- 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));
51032
51388
  if (overflowX <= 0 && overflowY <= 0) return null;
51033
51389
  const contentW = contentMaxX - contentMinX;
51034
51390
  const contentH = contentMaxY - contentMinY;
51035
- const availW = width - 2 * PADDING3;
51036
- const availH = height - 2 * PADDING3;
51391
+ const availW = width - 2 * PADDING4;
51392
+ const availH = height - 2 * PADDING4;
51037
51393
  const shrink = Math.min(availW / contentW, availH / contentH);
51038
51394
  const newRadius = Math.max(80, radius * shrink);
51039
51395
  return { radius: newRadius };
@@ -51231,7 +51587,7 @@ function renderCycle(container, parsed, palette, isDark, onClickItem, exportDims
51231
51587
  }
51232
51588
  edgeLabelInfo.push({ le, edge });
51233
51589
  }
51234
- const HEADER_H = 36 * layout.scale;
51590
+ const HEADER_H2 = 36 * layout.scale;
51235
51591
  const scaledNodeFont = Math.max(6, Math.round(NODE_FONT_SIZE7 * layout.scale));
51236
51592
  const scaledEdgeLabelFont = Math.max(
51237
51593
  6,
@@ -51295,10 +51651,10 @@ function renderCycle(container, parsed, palette, isDark, onClickItem, exportDims
51295
51651
  const rx = 6;
51296
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);
51297
51653
  if (hasDesc) {
51298
- const headerCenterY = ln.y - nodeH / 2 + HEADER_H / 2;
51654
+ const headerCenterY = ln.y - nodeH / 2 + HEADER_H2 / 2;
51299
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");
51300
51656
  renderInlineText(labelText, node.label, palette, scaledNodeFont);
51301
- const sepY = ln.y - nodeH / 2 + HEADER_H;
51657
+ const sepY = ln.y - nodeH / 2 + HEADER_H2;
51302
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);
51303
51659
  const descStartY = sepY + 4 + scaledDescFont;
51304
51660
  const descPadX = Math.max(8, 12 * layout.scale);
@@ -56110,7 +56466,9 @@ function mapContentAspect(resolved, data, ref = REF) {
56110
56466
  function mapExportDimensions(resolved, data, baseWidth = 1200, aspectOverride) {
56111
56467
  const useOverride = aspectOverride !== void 0 && Number.isFinite(aspectOverride) && aspectOverride > 0;
56112
56468
  const raw = useOverride ? aspectOverride : mapContentAspect(resolved, data);
56113
- 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));
56114
56472
  const width = baseWidth;
56115
56473
  let height = Math.round(width / clamped);
56116
56474
  let chromeReserve = 0;
@@ -56123,10 +56481,10 @@ function mapExportDimensions(resolved, data, baseWidth = 1200, aspectOverride) {
56123
56481
  height = Math.round(chromeReserve + MIN_MAP_BAND);
56124
56482
  floored = true;
56125
56483
  }
56126
- const preferContain = useOverride ? floored : clamped !== raw || floored;
56484
+ const preferContain = useOverride ? floored : clamped !== target || floored;
56127
56485
  return { width, height, preferContain };
56128
56486
  }
56129
- 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;
56130
56488
  var init_dimensions = __esm({
56131
56489
  "src/map/dimensions.ts"() {
56132
56490
  "use strict";
@@ -56137,6 +56495,7 @@ var init_dimensions = __esm({
56137
56495
  TITLE_GAP = 16;
56138
56496
  ASPECT_MAX = 3;
56139
56497
  ASPECT_MIN = 0.9;
56498
+ GLOBAL_HEIGHT_BOOST = 1.12;
56140
56499
  MIN_MAP_BAND = 200;
56141
56500
  FALLBACK_ASPECT = 1.5;
56142
56501
  REF = 1e3;
@@ -56926,9 +57285,469 @@ var init_renderer18 = __esm({
56926
57285
  }
56927
57286
  });
56928
57287
 
56929
- // 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
56930
57374
  var renderer_exports19 = {};
56931
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, {
56932
57751
  MARKER_LABELS: () => MARKER_LABELS,
56933
57752
  renderRaci: () => renderRaci,
56934
57753
  renderRaciForExport: () => renderRaciForExport
@@ -57004,7 +57823,7 @@ function renderRaci(container, parsed, palette, isDark, handlers, exportDims) {
57004
57823
  const hideLegend = opts.hideLegend ?? false;
57005
57824
  const collapsedPhases = opts.collapsedPhases ?? /* @__PURE__ */ new Set();
57006
57825
  const hideTitle = (opts.hideTitle ?? false) || parsed.options["no-title"] === "on";
57007
- d3Selection26.select(container).selectAll(":not([data-d3-tooltip])").remove();
57826
+ d3Selection27.select(container).selectAll(":not([data-d3-tooltip])").remove();
57008
57827
  const width = exportDims?.width ?? container.clientWidth;
57009
57828
  const height = exportDims?.height ?? container.clientHeight;
57010
57829
  if (width <= 0 || height <= 0) return;
@@ -57111,7 +57930,7 @@ function renderRaci(container, parsed, palette, isDark, handlers, exportDims) {
57111
57930
  const colBottomY = cursorY + sColumnBottomPad;
57112
57931
  const totalHeight = colBottomY + sVMargin;
57113
57932
  const svgHeight = exportDims ? totalHeight : Math.max(height, totalHeight);
57114
- 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");
57115
57934
  if (ctx.isBelowFloor) {
57116
57935
  svg.attr("width", "100%");
57117
57936
  }
@@ -57591,15 +58410,15 @@ function parseQuotedSegments(message) {
57591
58410
  out.push({ text: message.slice(last), bold: false });
57592
58411
  return out;
57593
58412
  }
57594
- 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;
57595
- 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({
57596
58415
  "src/raci/renderer.ts"() {
57597
58416
  "use strict";
57598
- d3Selection26 = __toESM(require("d3-selection"), 1);
58417
+ d3Selection27 = __toESM(require("d3-selection"), 1);
57599
58418
  init_fonts();
57600
58419
  init_title_constants();
57601
58420
  init_color_utils();
57602
- init_parser26();
58421
+ init_parser27();
57603
58422
  init_variants();
57604
58423
  init_scaling();
57605
58424
  init_text_measure();
@@ -57856,8 +58675,8 @@ var init_tag_resolution = __esm({
57856
58675
  });
57857
58676
 
57858
58677
  // src/sequence/renderer.ts
57859
- var renderer_exports20 = {};
57860
- __export(renderer_exports20, {
58678
+ var renderer_exports21 = {};
58679
+ __export(renderer_exports21, {
57861
58680
  applyGroupOrdering: () => applyGroupOrdering,
57862
58681
  applyPositionOverrides: () => applyPositionOverrides,
57863
58682
  buildNoteMessageMap: () => buildNoteMessageMap,
@@ -58197,7 +59016,7 @@ function applyGroupOrdering(participants, groups, messages = []) {
58197
59016
  return result;
58198
59017
  }
58199
59018
  function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateToLine, options) {
58200
- d3Selection27.select(container).selectAll("*").remove();
59019
+ d3Selection28.select(container).selectAll("*").remove();
58201
59020
  const { title, options: parsedOptions } = parsed;
58202
59021
  const solid = parsedOptions["solid-fill"] === "on";
58203
59022
  const effectiveCollapsedGroups = /* @__PURE__ */ new Set();
@@ -58848,7 +59667,7 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
58848
59667
  offsetX = leftMargin + Math.max(0, (svgWidth - totalWidth) / 2);
58849
59668
  buildParticipantX();
58850
59669
  }
58851
- 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);
58852
59671
  const defs = svg.append("defs");
58853
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(
58854
59673
  "points",
@@ -59460,12 +60279,12 @@ function renderParticipant(svg, participant, cx, cy, palette, isDark, color, tag
59460
60279
  });
59461
60280
  }
59462
60281
  }
59463
- 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;
59464
- 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({
59465
60284
  "src/sequence/renderer.ts"() {
59466
60285
  "use strict";
59467
60286
  init_tag_groups();
59468
- d3Selection27 = __toESM(require("d3-selection"), 1);
60287
+ d3Selection28 = __toESM(require("d3-selection"), 1);
59469
60288
  init_color_utils();
59470
60289
  init_inline_markdown();
59471
60290
  init_fonts();
@@ -60082,6 +60901,7 @@ __export(advanced_exports, {
60082
60901
  layoutOrg: () => layoutOrg,
60083
60902
  layoutPert: () => layoutPert,
60084
60903
  layoutSitemap: () => layoutSitemap,
60904
+ layoutTreemap: () => layoutTreemap,
60085
60905
  layoutWireframe: () => layoutWireframe,
60086
60906
  loadMapData: () => loadMapData,
60087
60907
  looksLikeClassDiagram: () => looksLikeClassDiagram,
@@ -60139,6 +60959,7 @@ __export(advanced_exports, {
60139
60959
  parseState: () => parseState,
60140
60960
  parseTechRadar: () => parseTechRadar,
60141
60961
  parseTimelineDate: () => parseTimelineDate,
60962
+ parseTreemap: () => parseTreemap,
60142
60963
  parseVisualization: () => parseVisualization,
60143
60964
  parseWireframe: () => parseWireframe,
60144
60965
  raciCellAppendMarker: () => cellAppendMarker,
@@ -60204,6 +61025,8 @@ __export(advanced_exports, {
60204
61025
  renderTechRadar: () => renderTechRadar,
60205
61026
  renderTechRadarForExport: () => renderTechRadarForExport,
60206
61027
  renderTimeline: () => renderTimeline,
61028
+ renderTreemap: () => renderTreemap,
61029
+ renderTreemapForExport: () => renderTreemapForExport,
60207
61030
  renderVenn: () => renderVenn,
60208
61031
  renderWireframe: () => renderWireframe,
60209
61032
  renderWordCloud: () => renderWordCloud,
@@ -63669,6 +64492,7 @@ var DIAGRAM_EXPORT_HANDLERS = {
63669
64492
  map: exportMap,
63670
64493
  pyramid: exportPyramid,
63671
64494
  ring: exportRing,
64495
+ treemap: exportTreemap,
63672
64496
  raci: exportRaci,
63673
64497
  rasci: exportRaci,
63674
64498
  daci: exportRaci,
@@ -63726,10 +64550,10 @@ async function exportOrg(ctx) {
63726
64550
  false
63727
64551
  // expandAllLegend off — collapsed-by-default per §1.3
63728
64552
  );
63729
- const PADDING3 = 20;
64553
+ const PADDING4 = 20;
63730
64554
  const titleOffset = effectiveParsed.title ? 30 : 0;
63731
- const exportWidth = orgLayout.width + PADDING3 * 2;
63732
- const exportHeight = orgLayout.height + PADDING3 * 2 + titleOffset;
64555
+ const exportWidth = orgLayout.width + PADDING4 * 2;
64556
+ const exportHeight = orgLayout.height + PADDING4 * 2 + titleOffset;
63733
64557
  const container = createExportContainer(exportWidth, exportHeight);
63734
64558
  renderOrg2(
63735
64559
  container,
@@ -63771,10 +64595,10 @@ async function exportSitemap(ctx) {
63771
64595
  hiddenAttributes,
63772
64596
  true
63773
64597
  );
63774
- const PADDING3 = 20;
64598
+ const PADDING4 = 20;
63775
64599
  const titleOffset = effectiveParsed.title ? 30 : 0;
63776
- const exportWidth = sitemapLayout.width + PADDING3 * 2;
63777
- const exportHeight = sitemapLayout.height + PADDING3 * 2 + titleOffset;
64600
+ const exportWidth = sitemapLayout.width + PADDING4 * 2;
64601
+ const exportHeight = sitemapLayout.height + PADDING4 * 2 + titleOffset;
63778
64602
  const container = createExportContainer(exportWidth, exportHeight);
63779
64603
  renderSitemap2(
63780
64604
  container,
@@ -63830,10 +64654,10 @@ async function exportClass(ctx) {
63830
64654
  const classParsed = parseClassDiagram2(content, effectivePalette);
63831
64655
  if (classParsed.error || classParsed.classes.length === 0) return "";
63832
64656
  const classLayout = layoutClassDiagram2(classParsed);
63833
- const PADDING3 = 20;
64657
+ const PADDING4 = 20;
63834
64658
  const titleOffset = classParsed.title ? 40 : 0;
63835
- const exportWidth = classLayout.width + PADDING3 * 2;
63836
- const exportHeight = classLayout.height + PADDING3 * 2 + titleOffset;
64659
+ const exportWidth = classLayout.width + PADDING4 * 2;
64660
+ const exportHeight = classLayout.height + PADDING4 * 2 + titleOffset;
63837
64661
  const container = createExportContainer(exportWidth, exportHeight);
63838
64662
  renderClassDiagram2(
63839
64663
  container,
@@ -63857,10 +64681,10 @@ async function exportEr(ctx) {
63857
64681
  const erParsed = parseERDiagram2(content, effectivePalette);
63858
64682
  if (erParsed.error || erParsed.tables.length === 0) return "";
63859
64683
  const erLayout = layoutERDiagram2(erParsed);
63860
- const PADDING3 = 20;
64684
+ const PADDING4 = 20;
63861
64685
  const titleOffset = erParsed.title ? 40 : 0;
63862
- const exportWidth = erLayout.width + PADDING3 * 2;
63863
- const exportHeight = erLayout.height + PADDING3 * 2 + titleOffset;
64686
+ const exportWidth = erLayout.width + PADDING4 * 2;
64687
+ const exportHeight = erLayout.height + PADDING4 * 2 + titleOffset;
63864
64688
  const container = createExportContainer(exportWidth, exportHeight);
63865
64689
  renderERDiagram2(
63866
64690
  container,
@@ -63896,10 +64720,10 @@ async function exportBoxesAndLines(ctx) {
63896
64720
  const { renderBoxesAndLinesForExport: renderBoxesAndLinesForExport2 } = await Promise.resolve().then(() => (init_renderer6(), renderer_exports6));
63897
64721
  const { layoutBoxesAndLines: layoutBoxesAndLines2 } = await Promise.resolve().then(() => (init_layout5(), layout_exports5));
63898
64722
  const blLayout = await layoutBoxesAndLines2(blParsed);
63899
- const PADDING3 = 20;
64723
+ const PADDING4 = 20;
63900
64724
  const titleOffset = blParsed.title ? 40 : 0;
63901
- const exportWidth = blLayout.width + PADDING3 * 2;
63902
- const exportHeight = blLayout.height + PADDING3 * 2 + titleOffset;
64725
+ const exportWidth = blLayout.width + PADDING4 * 2;
64726
+ const exportHeight = blLayout.height + PADDING4 * 2 + titleOffset;
63903
64727
  const container = createExportContainer(exportWidth, exportHeight);
63904
64728
  const blActiveTagGroup = ctxTagOverride(ctx);
63905
64729
  renderBoxesAndLinesForExport2(
@@ -63946,10 +64770,10 @@ async function exportMindmap(ctx) {
63946
64770
  activeTagGroup,
63947
64771
  hideDescriptions
63948
64772
  });
63949
- const PADDING3 = 20;
64773
+ const PADDING4 = 20;
63950
64774
  const titleOffset = effectiveParsed.title ? 30 : 0;
63951
- const exportWidth = mmLayout.width + PADDING3 * 2;
63952
- const exportHeight = mmLayout.height + PADDING3 * 2 + titleOffset;
64775
+ const exportWidth = mmLayout.width + PADDING4 * 2;
64776
+ const exportHeight = mmLayout.height + PADDING4 * 2 + titleOffset;
63953
64777
  const container = createExportContainer(exportWidth, exportHeight);
63954
64778
  const colorByDepth = viewState?.cbd === true;
63955
64779
  renderMindmap2(
@@ -64010,10 +64834,10 @@ async function exportC4(ctx) {
64010
64834
  const c4Container = ctx.options?.c4Container ?? viewState?.c4c;
64011
64835
  const c4Layout = c4Level === "deployment" ? layoutC4Deployment2(c4Parsed) : c4Level === "components" && c4System && c4Container ? layoutC4Components2(c4Parsed, c4System, c4Container) : c4Level === "containers" && c4System ? layoutC4Containers2(c4Parsed, c4System) : layoutC4Context2(c4Parsed);
64012
64836
  if (c4Layout.nodes.length === 0) return "";
64013
- const PADDING3 = 20;
64837
+ const PADDING4 = 20;
64014
64838
  const titleOffset = c4Parsed.title ? 40 : 0;
64015
- const exportWidth = c4Layout.width + PADDING3 * 2;
64016
- const exportHeight = c4Layout.height + PADDING3 * 2 + titleOffset;
64839
+ const exportWidth = c4Layout.width + PADDING4 * 2;
64840
+ const exportHeight = c4Layout.height + PADDING4 * 2 + titleOffset;
64017
64841
  const container = createExportContainer(exportWidth, exportHeight);
64018
64842
  const renderFn = c4Level === "deployment" || c4Level === "components" && c4System && c4Container || c4Level === "containers" && c4System ? renderC4Containers2 : renderC4Context2;
64019
64843
  renderFn(
@@ -64329,30 +65153,44 @@ async function exportRing(ctx) {
64329
65153
  const ringParsed = parseRing2(content);
64330
65154
  if (ringParsed.error || ringParsed.layers.length === 0) return "";
64331
65155
  const container = createExportContainer(EXPORT_WIDTH, EXPORT_HEIGHT);
64332
- 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(
64333
65171
  container,
64334
- ringParsed,
65172
+ treemapParsed,
64335
65173
  effectivePalette,
64336
65174
  ctx.isDark,
64337
- { width: EXPORT_WIDTH, height: EXPORT_HEIGHT }
65175
+ {
65176
+ width: EXPORT_WIDTH,
65177
+ height: EXPORT_HEIGHT
65178
+ }
64338
65179
  );
64339
65180
  return finalizeSvgExport(container, theme, effectivePalette);
64340
65181
  }
64341
65182
  async function exportRaci(ctx) {
64342
65183
  const { content, theme, palette } = ctx;
64343
- const { parseRaci: parseRaci2 } = await Promise.resolve().then(() => (init_parser26(), parser_exports20));
64344
- 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));
64345
65186
  const effectivePalette = await resolveExportPalette(theme, palette);
64346
65187
  const raciParsed = parseRaci2(content, effectivePalette);
64347
65188
  if (raciParsed.error) return "";
64348
65189
  const container = createExportContainer(EXPORT_WIDTH, EXPORT_HEIGHT);
64349
- renderRaciForExport2(
64350
- container,
64351
- raciParsed,
64352
- effectivePalette,
64353
- ctx.isDark,
64354
- { width: EXPORT_WIDTH, height: EXPORT_HEIGHT }
64355
- );
65190
+ renderRaciForExport2(container, raciParsed, effectivePalette, ctx.isDark, {
65191
+ width: EXPORT_WIDTH,
65192
+ height: EXPORT_HEIGHT
65193
+ });
64356
65194
  return finalizeSvgExport(container, theme, effectivePalette);
64357
65195
  }
64358
65196
  function beginVizExport() {
@@ -64441,14 +65279,7 @@ async function exportVenn(ctx) {
64441
65279
  if (parsed.error || parsed.vennSets.length < 2) return "";
64442
65280
  const effectivePalette = await resolveExportPalette(theme, palette);
64443
65281
  const { container, dims } = beginVizExport();
64444
- renderVenn(
64445
- container,
64446
- parsed,
64447
- effectivePalette,
64448
- ctx.isDark,
64449
- void 0,
64450
- dims
64451
- );
65282
+ renderVenn(container, parsed, effectivePalette, ctx.isDark, void 0, dims);
64452
65283
  return finalizeSvgExport(container, theme, effectivePalette);
64453
65284
  }
64454
65285
  async function exportQuadrant(ctx) {
@@ -64482,7 +65313,7 @@ async function exportVisualization(ctx) {
64482
65313
  const isDark = ctx.isDark;
64483
65314
  const container = createExportContainer(EXPORT_WIDTH, EXPORT_HEIGHT);
64484
65315
  const { parseSequenceDgmo: parseSequenceDgmo2 } = await Promise.resolve().then(() => (init_parser7(), parser_exports));
64485
- const { renderSequenceDiagram: renderSequenceDiagram2 } = await Promise.resolve().then(() => (init_renderer20(), renderer_exports20));
65316
+ const { renderSequenceDiagram: renderSequenceDiagram2 } = await Promise.resolve().then(() => (init_renderer21(), renderer_exports21));
64486
65317
  const seqParsed = parseSequenceDgmo2(content, effectivePalette);
64487
65318
  if (seqParsed.error || seqParsed.participants.length === 0) return "";
64488
65319
  const collapsedSections = viewState?.cs ? new Set(viewState.cs) : void 0;
@@ -65113,6 +65944,9 @@ init_parser24();
65113
65944
  init_renderer17();
65114
65945
  init_parser25();
65115
65946
  init_renderer18();
65947
+ init_parser26();
65948
+ init_renderer19();
65949
+ init_layout16();
65116
65950
  init_parser17();
65117
65951
  init_resolver2();
65118
65952
  init_load_data();
@@ -65424,12 +66258,12 @@ function completeMapRegions(query, regions, opts) {
65424
66258
  }
65425
66259
 
65426
66260
  // src/raci/index.ts
65427
- init_parser26();
65428
- init_renderer19();
66261
+ init_parser27();
66262
+ init_renderer20();
65429
66263
 
65430
66264
  // src/raci/mutations.ts
65431
66265
  init_parsing();
65432
- init_parser26();
66266
+ init_parser27();
65433
66267
  function cellReplace(content, parsed, taskId, roleId, marker) {
65434
66268
  const task = findTask(parsed, taskId);
65435
66269
  if (!task) return null;
@@ -65942,7 +66776,7 @@ init_legend_svg();
65942
66776
  init_legend_constants();
65943
66777
  init_legend_d3();
65944
66778
  init_legend_layout();
65945
- init_renderer20();
66779
+ init_renderer21();
65946
66780
  init_collapse4();
65947
66781
  init_colors();
65948
66782
  init_palettes();
@@ -66175,6 +67009,7 @@ init_dgmo_router();
66175
67009
  layoutOrg,
66176
67010
  layoutPert,
66177
67011
  layoutSitemap,
67012
+ layoutTreemap,
66178
67013
  layoutWireframe,
66179
67014
  loadMapData,
66180
67015
  looksLikeClassDiagram,
@@ -66232,6 +67067,7 @@ init_dgmo_router();
66232
67067
  parseState,
66233
67068
  parseTechRadar,
66234
67069
  parseTimelineDate,
67070
+ parseTreemap,
66235
67071
  parseVisualization,
66236
67072
  parseWireframe,
66237
67073
  raciCellAppendMarker,
@@ -66297,6 +67133,8 @@ init_dgmo_router();
66297
67133
  renderTechRadar,
66298
67134
  renderTechRadarForExport,
66299
67135
  renderTimeline,
67136
+ renderTreemap,
67137
+ renderTreemapForExport,
66300
67138
  renderVenn,
66301
67139
  renderWireframe,
66302
67140
  renderWordCloud,