@uigraph/sdk 1.2.11 → 1.2.13

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/index.cjs CHANGED
@@ -2743,7 +2743,7 @@ function convertC4ToReactFlow(data) {
2743
2743
  sourceHandle: `source-${side.source}`,
2744
2744
  targetHandle: `target-${side.target}`,
2745
2745
  label,
2746
- type: "simplebezier",
2746
+ type: "smoothstep",
2747
2747
  style: {
2748
2748
  stroke: lineColor,
2749
2749
  strokeWidth: (_style$lineWidth = style === null || style === void 0 ? void 0 : style.lineWidth) !== null && _style$lineWidth !== void 0 ? _style$lineWidth : 1.5
@@ -2780,16 +2780,19 @@ const LAYOUT_SPACING = {
2780
2780
  SUBGRAPH_HEADER_HEIGHT: 35,
2781
2781
  SUBGRAPH_PADDING: 8,
2782
2782
  SUBGRAPH_CONTENT_TOP_MARGIN: 10,
2783
- NODE_SEPARATION_HORIZONTAL: 80,
2784
- NODE_SEPARATION_VERTICAL: 100,
2785
- CONTAINER_SEPARATION_HORIZONTAL: 120,
2786
- CONTAINER_SEPARATION_VERTICAL: 160,
2787
- NESTED_SUBGRAPH_SEPARATION_HORIZONTAL: 120,
2788
- NESTED_SUBGRAPH_SEPARATION_VERTICAL: 140,
2783
+ NODE_SEPARATION_HORIZONTAL: 120,
2784
+ NODE_SEPARATION_VERTICAL: 180,
2785
+ CONTAINER_SEPARATION_HORIZONTAL: 180,
2786
+ CONTAINER_SEPARATION_VERTICAL: 280,
2787
+ NESTED_SUBGRAPH_SEPARATION_HORIZONTAL: 160,
2788
+ NESTED_SUBGRAPH_SEPARATION_VERTICAL: 220,
2789
+ MIN_SUBGRAPH_WIDTH_HORIZONTAL: 600,
2790
+ MIN_SUBGRAPH_WIDTH_VERTICAL: 240,
2791
+ MIN_SUBGRAPH_HEIGHT: 200,
2789
2792
  META_GRAPH_MARGIN: 100,
2790
2793
  NESTED_CONTENT_MARGIN: 40,
2791
- MIXED_CONTENT_VERTICAL_SPACING: 100,
2792
- MIXED_CONTENT_HORIZONTAL_SPACING: 120
2794
+ MIXED_CONTENT_VERTICAL_SPACING: 180,
2795
+ MIXED_CONTENT_HORIZONTAL_SPACING: 160
2793
2796
  };
2794
2797
  const LAYOUT_RANKERS = {
2795
2798
  NETWORK_SIMPLEX: "network-simplex",
@@ -2853,10 +2856,27 @@ function resolvePortalNodeType(hasImageUrl, tag) {
2853
2856
  if (tag && TAG_TO_NODE_TYPE[tag]) return TAG_TO_NODE_TYPE[tag];
2854
2857
  return "shape";
2855
2858
  }
2859
+ const COMPOUND_SHAPE_DELIMITERS = {
2860
+ circle: {
2861
+ open: "((",
2862
+ close: "))"
2863
+ },
2864
+ stadium: {
2865
+ open: "([",
2866
+ close: "])"
2867
+ },
2868
+ cylinder: {
2869
+ open: "[(",
2870
+ close: ")]"
2871
+ },
2872
+ subroutine: {
2873
+ open: "[[",
2874
+ close: "]]"
2875
+ }
2876
+ };
2856
2877
  function getNodeShape(nodeDefinition) {
2857
2878
  if (nodeDefinition.includes("{") && nodeDefinition.includes("}")) return "diamond";
2858
- if (nodeDefinition.includes("((") && nodeDefinition.includes("))")) return "circle";
2859
- if (nodeDefinition.includes("([") && nodeDefinition.includes("])")) return "stadium";
2879
+ for (const [shape, { open, close }] of Object.entries(COMPOUND_SHAPE_DELIMITERS)) if (nodeDefinition.includes(open) && nodeDefinition.includes(close)) return shape;
2860
2880
  if (nodeDefinition.includes("[") && nodeDefinition.includes("]")) return "rect";
2861
2881
  if (nodeDefinition.includes("(") && nodeDefinition.includes(")")) return "round";
2862
2882
  return "rect";
@@ -2906,15 +2926,35 @@ function parseMermaidCode(code) {
2906
2926
  }
2907
2927
  const lines = cleanCode.split("\n");
2908
2928
  const subgraphStack = [];
2929
+ const SHAPE_DELIMITER_PAIRS = [
2930
+ ["[", "]"],
2931
+ ["(", ")"],
2932
+ ["{", "}"]
2933
+ ];
2934
+ function stripWrappingShapeDelimiters(label) {
2935
+ let result = label;
2936
+ let changed = true;
2937
+ while (changed && result.length >= 2) {
2938
+ changed = false;
2939
+ for (const [open, close] of SHAPE_DELIMITER_PAIRS) if (result[0] === open && result[result.length - 1] === close) {
2940
+ const stripped = result.slice(1, -1).trim().replace(new RegExp("^\"(.*)\"$", "s"), "$1").replace(new RegExp("^'(.*)'$", "s"), "$1").trim();
2941
+ if (!stripped) break;
2942
+ result = stripped;
2943
+ changed = true;
2944
+ break;
2945
+ }
2946
+ }
2947
+ return result;
2948
+ }
2909
2949
  function enhancedCleanLabel(label) {
2910
- return label.replace(/<br\s*\/?>/gi, "\n").replace(/<[^>]*>/g, "").replace(/\\u([0-9a-fA-F]{4})/g, (match, code$1) => {
2950
+ return stripWrappingShapeDelimiters(label.replace(/<br\s*\/?>/gi, "\n").replace(/<[^>]*>/g, "").replace(/\\u([0-9a-fA-F]{4})/g, (match, code$1) => {
2911
2951
  try {
2912
2952
  return String.fromCharCode(parseInt(code$1, 16));
2913
2953
  } catch (_unused) {
2914
2954
  debugLog(`Warning: Could not parse unicode character: ${match}`);
2915
2955
  return match;
2916
2956
  }
2917
- }).replace(/\\n/g, "\n").replace(/\s*\n\s*/g, "\n").trim();
2957
+ }).replace(/\\n/g, "\n").replace(/\s*\n\s*/g, "\n").trim());
2918
2958
  }
2919
2959
  debugLog("Pre-scanning for node definitions...");
2920
2960
  lines.forEach((line, lineIndex) => {
@@ -2960,11 +3000,13 @@ function parseMermaidCode(code) {
2960
3000
  if (shapeDef) {
2961
3001
  const shape = getNodeShape(fullDef);
2962
3002
  let rawLabel = nodeId;
2963
- const labelContentMatch = shapeDef.match(new RegExp("^[\\[\\(\\{](.*)[\\]\\)\\}]$", "s"));
2964
- if (labelContentMatch) {
2965
- rawLabel = labelContentMatch[1];
2966
- rawLabel = rawLabel.replace(/^"(.*)"$/, "$1").replace(/^'(.*)'$/, "$1");
3003
+ const compoundDelimiters = COMPOUND_SHAPE_DELIMITERS[shape];
3004
+ if (compoundDelimiters && shapeDef.startsWith(compoundDelimiters.open) && shapeDef.endsWith(compoundDelimiters.close)) rawLabel = shapeDef.slice(compoundDelimiters.open.length, shapeDef.length - compoundDelimiters.close.length);
3005
+ else {
3006
+ const labelContentMatch = shapeDef.match(new RegExp("^[\\[\\(\\{](.*)[\\]\\)\\}]$", "s"));
3007
+ if (labelContentMatch) rawLabel = labelContentMatch[1];
2967
3008
  }
3009
+ rawLabel = rawLabel.replace(new RegExp("^\"(.*)\"$", "s"), "$1").replace(new RegExp("^'(.*)'$", "s"), "$1");
2968
3010
  const label = enhancedCleanLabel(rawLabel);
2969
3011
  nodeDefinitions.set(nodeId, {
2970
3012
  label,
@@ -3121,7 +3163,16 @@ function parseMermaidCode(code) {
3121
3163
  const openChar = openCharMatch[1];
3122
3164
  const openPos = idx + rest.indexOf(openChar);
3123
3165
  const closeChar = openChar === "[" ? "]" : openChar === "(" ? ")" : "}";
3124
- const closePos = str.indexOf(closeChar, openPos + 1);
3166
+ let depth = 0;
3167
+ let closePos = -1;
3168
+ for (let pos = openPos; pos < str.length; pos++) if (str[pos] === openChar) depth++;
3169
+ else if (str[pos] === closeChar) {
3170
+ depth--;
3171
+ if (depth === 0) {
3172
+ closePos = pos;
3173
+ break;
3174
+ }
3175
+ }
3125
3176
  if (closePos !== -1) return {
3126
3177
  id,
3127
3178
  full: str.slice(startIndex + idMatch[0].search(/\S/), closePos + 1).trim(),
@@ -3134,101 +3185,106 @@ function parseMermaidCode(code) {
3134
3185
  endIndex: idx
3135
3186
  };
3136
3187
  }
3188
+ const arrowHeads = [
3189
+ "-.->",
3190
+ "-->",
3191
+ "==>",
3192
+ "->>",
3193
+ "<->",
3194
+ "-<>",
3195
+ "<-",
3196
+ "->"
3197
+ ];
3137
3198
  function parseEdge(str) {
3138
3199
  try {
3200
+ const hops = [];
3139
3201
  let i$2 = 0;
3140
- const src = extractToken(str, i$2);
3202
+ let src = extractToken(str, i$2);
3141
3203
  if (!src) return null;
3142
3204
  i$2 = src.endIndex;
3143
- while (i$2 < str.length && /\s/.test(str[i$2])) i$2++;
3144
- const arrowHeads = [
3145
- "-.->",
3146
- "-->",
3147
- "==>",
3148
- "->>",
3149
- "<->",
3150
- "-<>",
3151
- "<-",
3152
- "->"
3153
- ];
3154
- let foundArrowIndex = -1;
3155
- let foundArrow = "";
3156
- for (const ah of arrowHeads) {
3157
- const idx = str.indexOf(ah, i$2);
3158
- if (idx !== -1 && (foundArrowIndex === -1 || idx < foundArrowIndex)) {
3159
- foundArrowIndex = idx;
3160
- foundArrow = ah;
3161
- }
3162
- }
3163
- let op = null;
3164
- let edgeLabel = "";
3165
- if (foundArrowIndex !== -1) {
3166
- const between = str.slice(i$2, foundArrowIndex);
3167
- const prePipeMatch = between.match(/\|(.*?)\|/);
3168
- if (prePipeMatch) edgeLabel = prePipeMatch[1];
3169
- else {
3170
- const inline = between.replace(/^\s*[\-\.=:\~]+\s*/g, "").replace(/\s*[\-\.=:\~]+\s*$/g, "").trim();
3171
- if (inline) edgeLabel = inline;
3172
- }
3173
- op = foundArrow;
3174
- i$2 = foundArrowIndex + foundArrow.length;
3205
+ while (true) {
3175
3206
  while (i$2 < str.length && /\s/.test(str[i$2])) i$2++;
3176
- if (str[i$2] === "|") {
3177
- const next = str.indexOf("|", i$2 + 1);
3178
- if (next !== -1) {
3179
- edgeLabel = str.slice(i$2 + 1, next);
3180
- i$2 = next + 1;
3207
+ let foundArrowIndex = -1;
3208
+ let foundArrow = "";
3209
+ for (const ah of arrowHeads) {
3210
+ const idx = str.indexOf(ah, i$2);
3211
+ if (idx !== -1 && (foundArrowIndex === -1 || idx < foundArrowIndex)) {
3212
+ foundArrowIndex = idx;
3213
+ foundArrow = ah;
3181
3214
  }
3182
3215
  }
3183
- } else {
3184
- for (const o of [
3185
- "---",
3186
- "-.-",
3187
- "::",
3188
- ":-:",
3189
- "...",
3190
- "~",
3191
- "==="
3192
- ].sort((a, b) => b.length - a.length)) if (str.startsWith(o, i$2)) {
3193
- op = o;
3194
- i$2 += o.length;
3195
- break;
3196
- }
3197
- if (!op) return null;
3198
- while (i$2 < str.length && /\s/.test(str[i$2])) i$2++;
3199
- if (str[i$2] === "|") {
3200
- const next = str.indexOf("|", i$2 + 1);
3201
- if (next !== -1) {
3202
- edgeLabel = str.slice(i$2 + 1, next);
3203
- i$2 = next + 1;
3216
+ let op = null;
3217
+ let edgeLabel = "";
3218
+ if (foundArrowIndex !== -1) {
3219
+ const between = str.slice(i$2, foundArrowIndex);
3220
+ const prePipeMatch = between.match(/\|(.*?)\|/);
3221
+ if (prePipeMatch) edgeLabel = prePipeMatch[1];
3222
+ else {
3223
+ const inline = between.replace(/^\s*[\-\.=:\~]+\s*/g, "").replace(/\s*[\-\.=:\~]+\s*$/g, "").trim();
3224
+ if (inline) edgeLabel = inline;
3204
3225
  }
3226
+ op = foundArrow;
3227
+ i$2 = foundArrowIndex + foundArrow.length;
3228
+ while (i$2 < str.length && /\s/.test(str[i$2])) i$2++;
3229
+ if (str[i$2] === "|") {
3230
+ const next = str.indexOf("|", i$2 + 1);
3231
+ if (next !== -1) {
3232
+ edgeLabel = str.slice(i$2 + 1, next);
3233
+ i$2 = next + 1;
3234
+ }
3235
+ }
3236
+ } else if (hops.length === 0) {
3237
+ for (const o of [
3238
+ "---",
3239
+ "-.-",
3240
+ "::",
3241
+ ":-:",
3242
+ "...",
3243
+ "~",
3244
+ "==="
3245
+ ].sort((a, b) => b.length - a.length)) if (str.startsWith(o, i$2)) {
3246
+ op = o;
3247
+ i$2 += o.length;
3248
+ break;
3249
+ }
3250
+ if (!op) return null;
3251
+ while (i$2 < str.length && /\s/.test(str[i$2])) i$2++;
3252
+ if (str[i$2] === "|") {
3253
+ const next = str.indexOf("|", i$2 + 1);
3254
+ if (next !== -1) {
3255
+ edgeLabel = str.slice(i$2 + 1, next);
3256
+ i$2 = next + 1;
3257
+ }
3258
+ }
3259
+ } else break;
3260
+ while (i$2 < str.length && /\s/.test(str[i$2])) i$2++;
3261
+ const tgt = extractToken(str, i$2);
3262
+ if (!tgt) break;
3263
+ const trailing = str.slice(tgt.endIndex).trimStart();
3264
+ if (!edgeLabel && !trailing.startsWith(":::") && !arrowHeads.some((ah) => trailing.includes(ah))) {
3265
+ const colonLabelMatch = trailing.match(/^:\s*(.+)$/);
3266
+ if (colonLabelMatch) edgeLabel = colonLabelMatch[1].trim();
3205
3267
  }
3268
+ const isReverseArrow = op === "<-";
3269
+ hops.push({
3270
+ sourceId: isReverseArrow ? tgt.id : src.id,
3271
+ sourceFull: isReverseArrow ? tgt.full : src.full,
3272
+ targetId: isReverseArrow ? src.id : tgt.id,
3273
+ targetFull: isReverseArrow ? src.full : tgt.full,
3274
+ edgeType: isReverseArrow ? "->" : op,
3275
+ edgeLabel
3276
+ });
3277
+ src = tgt;
3278
+ i$2 = tgt.endIndex;
3206
3279
  }
3207
- while (i$2 < str.length && /\s/.test(str[i$2])) i$2++;
3208
- const tgt = extractToken(str, i$2);
3209
- if (!tgt) return null;
3210
- const trailing = str.slice(tgt.endIndex).trimStart();
3211
- if (!edgeLabel && !trailing.startsWith(":::")) {
3212
- const colonLabelMatch = trailing.match(/^:\s*(.+)$/);
3213
- if (colonLabelMatch) edgeLabel = colonLabelMatch[1].trim();
3214
- }
3215
- const isReverseArrow = op === "<-";
3216
- return {
3217
- sourceId: isReverseArrow ? tgt.id : src.id,
3218
- sourceFull: isReverseArrow ? tgt.full : src.full,
3219
- targetId: isReverseArrow ? src.id : tgt.id,
3220
- targetFull: isReverseArrow ? src.full : tgt.full,
3221
- edgeType: isReverseArrow ? "->" : op,
3222
- edgeLabel
3223
- };
3280
+ return hops.length > 0 ? hops : null;
3224
3281
  } catch (_unused2) {
3225
3282
  return null;
3226
3283
  }
3227
3284
  }
3228
- const parsedEdge = parseEdge(line);
3229
- if (!parsedEdge) debugLog(`Line "${line}" did not match edge pattern - checking for standalone nodes`);
3230
- if (parsedEdge) try {
3231
- const { sourceId, targetId, edgeType, edgeLabel } = parsedEdge;
3285
+ const parsedEdges = parseEdge(line);
3286
+ if (!parsedEdges) debugLog(`Line "${line}" did not match edge pattern - checking for standalone nodes`);
3287
+ if (parsedEdges) for (const { sourceId, targetId, edgeType, edgeLabel } of parsedEdges) try {
3232
3288
  debugLog(`Found edge: ${sourceId} ${edgeType} ${targetId} with label: "${edgeLabel}" in context: ${currentSubgraph || "global"}`);
3233
3289
  const isSourceSubgraph = subgraphMap.has(sourceId);
3234
3290
  const isTargetSubgraph = subgraphMap.has(targetId);
@@ -3248,10 +3304,11 @@ function parseMermaidCode(code) {
3248
3304
  createOrGetNode(targetId, targetSubgraph);
3249
3305
  }
3250
3306
  }
3307
+ const unquotedEdgeLabel = edgeLabel.replace(new RegExp("^\"(.*)\"$", "s"), "$1").replace(new RegExp("^'(.*)'$", "s"), "$1");
3251
3308
  edges.push({
3252
3309
  source: sourceId,
3253
3310
  target: targetId,
3254
- label: enhancedCleanLabel(edgeLabel),
3311
+ label: enhancedCleanLabel(unquotedEdgeLabel),
3255
3312
  type: edgeType,
3256
3313
  isSourceSubgraph,
3257
3314
  isTargetSubgraph
@@ -3307,7 +3364,9 @@ const MERMAID_TO_PORTAL_SHAPE = {
3307
3364
  round: "rounded-rect",
3308
3365
  stadium: "terminator",
3309
3366
  circle: "ellipse",
3310
- diamond: "diamond"
3367
+ diamond: "diamond",
3368
+ cylinder: "cylinder",
3369
+ subroutine: "subroutine"
3311
3370
  };
3312
3371
  const SUBGRAPH_HEADER_HEIGHT = LAYOUT_SPACING.SUBGRAPH_HEADER_HEIGHT;
3313
3372
  const SUBGRAPH_PADDING = LAYOUT_SPACING.SUBGRAPH_PADDING;
@@ -3318,6 +3377,9 @@ const CONTAINER_SEPARATION_HORIZONTAL = LAYOUT_SPACING.CONTAINER_SEPARATION_HORI
3318
3377
  const CONTAINER_SEPARATION_VERTICAL = LAYOUT_SPACING.CONTAINER_SEPARATION_VERTICAL;
3319
3378
  const NESTED_SUBGRAPH_SEPARATION_HORIZONTAL = LAYOUT_SPACING.NESTED_SUBGRAPH_SEPARATION_HORIZONTAL;
3320
3379
  const NESTED_SUBGRAPH_SEPARATION_VERTICAL = LAYOUT_SPACING.NESTED_SUBGRAPH_SEPARATION_VERTICAL;
3380
+ const MIN_SUBGRAPH_WIDTH_HORIZONTAL = LAYOUT_SPACING.MIN_SUBGRAPH_WIDTH_HORIZONTAL;
3381
+ const MIN_SUBGRAPH_WIDTH_VERTICAL = LAYOUT_SPACING.MIN_SUBGRAPH_WIDTH_VERTICAL;
3382
+ const MIN_SUBGRAPH_HEIGHT = LAYOUT_SPACING.MIN_SUBGRAPH_HEIGHT;
3321
3383
  const META_GRAPH_MARGIN = LAYOUT_SPACING.META_GRAPH_MARGIN;
3322
3384
  const NESTED_CONTENT_MARGIN = LAYOUT_SPACING.NESTED_CONTENT_MARGIN;
3323
3385
  const MIXED_CONTENT_VERTICAL_SPACING = LAYOUT_SPACING.MIXED_CONTENT_VERTICAL_SPACING;
@@ -3341,7 +3403,8 @@ function calculateNodeSize(label, shape, isImageNode = false) {
3341
3403
  } catch (_unused) {}
3342
3404
  return text.length * 8;
3343
3405
  }
3344
- const baseWidth = Math.max(...lines.map((line) => Math.ceil(measureLineWidth(line)))) + 30;
3406
+ const maxLineWidth = Math.max(...lines.map((line) => Math.ceil(measureLineWidth(line))));
3407
+ const baseWidth = maxLineWidth + 30;
3345
3408
  const baseHeight = lines.length * 18 + 20;
3346
3409
  const width = Math.max(80, baseWidth + 30);
3347
3410
  const height = Math.max(40, baseHeight + 20);
@@ -3356,6 +3419,27 @@ function calculateNodeSize(label, shape, isImageNode = false) {
3356
3419
  height: size
3357
3420
  };
3358
3421
  }
3422
+ if (shape === "stadium") {
3423
+ const sideInset = Math.max(12, height / 2) * 2;
3424
+ return {
3425
+ width: Math.max(width, maxLineWidth + sideInset + 20),
3426
+ height
3427
+ };
3428
+ }
3429
+ if (shape === "cylinder") {
3430
+ const capInset = Math.max(12, Math.min(height * .18, width * .5) + 8) * 2;
3431
+ return {
3432
+ width,
3433
+ height: Math.max(height, lines.length * 18 + capInset + 10)
3434
+ };
3435
+ }
3436
+ if (shape === "subroutine") {
3437
+ const sideInset = Math.max(24, width * .2);
3438
+ return {
3439
+ width: Math.max(width, maxLineWidth + sideInset + 20),
3440
+ height
3441
+ };
3442
+ }
3359
3443
  return {
3360
3444
  width,
3361
3445
  height
@@ -3404,6 +3488,7 @@ function processSubgraphsInHierarchicalOrder(subgraphs) {
3404
3488
  }
3405
3489
  function layoutSubgraphs(nodes, edges, subgraphs, direction) {
3406
3490
  const subgraphLayouts = /* @__PURE__ */ new Map();
3491
+ const isHorizontal = direction === "LR" || direction === "RL";
3407
3492
  const orderedSubgraphs = processSubgraphsInHierarchicalOrder(subgraphs);
3408
3493
  debugLog(`Laying out ${orderedSubgraphs.length} subgraphs in hierarchical order`);
3409
3494
  orderedSubgraphs.forEach((subgraph) => {
@@ -3476,8 +3561,8 @@ function layoutSubgraphs(nodes, edges, subgraphs, direction) {
3476
3561
  validateNodeSpacing(nodePositions, subgraph.id);
3477
3562
  const baseWidth = maxX - minX + SUBGRAPH_PADDING * 2;
3478
3563
  const baseHeight = maxY - minY + SUBGRAPH_PADDING * 2 + SUBGRAPH_HEADER_HEIGHT + SUBGRAPH_CONTENT_TOP_MARGIN;
3479
- const width = baseWidth + 4;
3480
- const height = baseHeight + 4;
3564
+ const width = Math.max(baseWidth + SUBGRAPH_PADDING * 3, isHorizontal ? MIN_SUBGRAPH_WIDTH_HORIZONTAL : MIN_SUBGRAPH_WIDTH_VERTICAL);
3565
+ const height = Math.max(baseHeight + SUBGRAPH_PADDING * 2, MIN_SUBGRAPH_HEIGHT);
3481
3566
  subgraphLayouts.set(subgraph.id, {
3482
3567
  id: subgraph.id,
3483
3568
  title: subgraph.title,
@@ -3587,8 +3672,8 @@ function adjustParentSizesAfterPositioning(subgraphLayouts, subgraphPositions, o
3587
3672
  const contentMaxBottom = Math.max(maxNodeBottom, maxChildBottom);
3588
3673
  const requiredWidth = contentMaxRight + (isHorizontal ? SUBGRAPH_PADDING * 4 : SUBGRAPH_PADDING * 3);
3589
3674
  const requiredHeight = contentMaxBottom + SUBGRAPH_PADDING * 3;
3590
- const newWidth = Math.max(layout.width, requiredWidth, isHorizontal ? 600 : 240);
3591
- const newHeight = Math.max(layout.height, requiredHeight, 200);
3675
+ const newWidth = Math.max(layout.width, requiredWidth, isHorizontal ? MIN_SUBGRAPH_WIDTH_HORIZONTAL : MIN_SUBGRAPH_WIDTH_VERTICAL);
3676
+ const newHeight = Math.max(layout.height, requiredHeight, MIN_SUBGRAPH_HEIGHT);
3592
3677
  if (newWidth > layout.width || newHeight > layout.height) {
3593
3678
  debugLog(`Post-positioning resize (iter ${iterations}): ${subgraph.id} ${layout.width}x${layout.height} → ${newWidth}x${newHeight}`);
3594
3679
  layout.width = newWidth;
@@ -3623,11 +3708,12 @@ function validateNodeSpacing(nodePositions, subgraphId) {
3623
3708
  if (!hasOverlap) debugLog(`✓ Node spacing validated for subgraph ${subgraphId} - no overlaps detected`);
3624
3709
  }
3625
3710
  function layoutMetaGraph(nodes, edges, subgraphLayouts, direction) {
3711
+ const hasTopLevelSubgraphs = Array.from(subgraphLayouts.values()).some((layout) => !layout.parentId);
3626
3712
  const g = new dagre.default.graphlib.Graph();
3627
3713
  g.setGraph({
3628
3714
  rankdir: direction,
3629
- nodesep: CONTAINER_SEPARATION_HORIZONTAL,
3630
- ranksep: CONTAINER_SEPARATION_VERTICAL,
3715
+ nodesep: hasTopLevelSubgraphs ? CONTAINER_SEPARATION_HORIZONTAL : NODE_SEPARATION_HORIZONTAL,
3716
+ ranksep: hasTopLevelSubgraphs ? CONTAINER_SEPARATION_VERTICAL : NODE_SEPARATION_VERTICAL,
3631
3717
  marginx: META_GRAPH_MARGIN,
3632
3718
  marginy: META_GRAPH_MARGIN,
3633
3719
  ranker: DAGRE_RANKER
@@ -3872,7 +3958,8 @@ function createReactFlowElements(nodes, edges, subgraphs, subgraphLayouts, subgr
3872
3958
  ];
3873
3959
  return subgraphColors[index % subgraphColors.length];
3874
3960
  }
3875
- processSubgraphsInHierarchicalOrder(subgraphs).forEach((subgraph, index) => {
3961
+ const orderedSubgraphs = processSubgraphsInHierarchicalOrder(subgraphs);
3962
+ orderedSubgraphs.forEach((subgraph, index) => {
3876
3963
  const layout = subgraphLayouts.get(subgraph.id);
3877
3964
  const position = subgraphPositions.get(subgraph.id);
3878
3965
  if (layout && position) {
@@ -4067,11 +4154,42 @@ function createReactFlowElements(nodes, edges, subgraphs, subgraphLayouts, subgr
4067
4154
  zIndex: 1
4068
4155
  });
4069
4156
  });
4157
+ const nodeSubgraphById = new Map(nodes.map((n) => [n.id, n.subgraph]));
4158
+ const meaningfulEdges = edges.filter((edge) => {
4159
+ if (edge.isTargetSubgraph && nodeSubgraphById.get(edge.source) === edge.target) {
4160
+ debugLog(`Dropping edge ${edge.source} -> ${edge.target}: source already lives inside this subgraph`);
4161
+ return false;
4162
+ }
4163
+ if (edge.isSourceSubgraph && nodeSubgraphById.get(edge.target) === edge.source) {
4164
+ debugLog(`Dropping edge ${edge.source} -> ${edge.target}: target already lives inside this subgraph`);
4165
+ return false;
4166
+ }
4167
+ return true;
4168
+ });
4169
+ const nodeAxisPosition = /* @__PURE__ */ new Map();
4170
+ orderedSubgraphs.forEach((subgraph) => {
4171
+ const position = subgraphPositions.get(subgraph.id);
4172
+ if (position) nodeAxisPosition.set(`subgraph-${subgraph.id}`, position);
4173
+ });
4174
+ nodes.forEach((node) => {
4175
+ if (node.subgraph) {
4176
+ const subgraphLayout = subgraphLayouts.get(node.subgraph);
4177
+ const subgraphPosition = subgraphPositions.get(node.subgraph);
4178
+ const nodeLayout = subgraphLayout === null || subgraphLayout === void 0 ? void 0 : subgraphLayout.nodes.get(node.id);
4179
+ if (nodeLayout && subgraphPosition) nodeAxisPosition.set(node.id, {
4180
+ x: subgraphPosition.x + nodeLayout.x,
4181
+ y: subgraphPosition.y + nodeLayout.y
4182
+ });
4183
+ } else {
4184
+ const standalonePos = standalonePositions.get(node.id);
4185
+ if (standalonePos) nodeAxisPosition.set(node.id, standalonePos);
4186
+ }
4187
+ });
4070
4188
  return {
4071
4189
  nodes: reactFlowNodes,
4072
- edges: edges.map((edge, index) => {
4190
+ edges: meaningfulEdges.map((edge, index) => {
4073
4191
  const edgeStyle = { strokeWidth: 2.5 };
4074
- const edgeType = "default";
4192
+ const edgeType = "smoothstep";
4075
4193
  switch (edge.type) {
4076
4194
  case "-->":
4077
4195
  case "->": break;
@@ -4088,6 +4206,22 @@ function createReactFlowElements(nodes, edges, subgraphs, subgraphLayouts, subgr
4088
4206
  }
4089
4207
  const sourceId = edge.isSourceSubgraph ? `subgraph-${edge.source}` : edge.source;
4090
4208
  const targetId = edge.isTargetSubgraph ? `subgraph-${edge.target}` : edge.target;
4209
+ const isHorizontalLayout = direction === "LR" || direction === "RL";
4210
+ let sourceHandle = isHorizontalLayout ? "source-right" : "source-bottom";
4211
+ let targetHandle = isHorizontalLayout ? "target-left" : "target-top";
4212
+ const sourcePoint = nodeAxisPosition.get(sourceId);
4213
+ const targetPoint = nodeAxisPosition.get(targetId);
4214
+ if (sourcePoint && targetPoint) {
4215
+ if (isHorizontalLayout) {
4216
+ if (targetPoint.x < sourcePoint.x) {
4217
+ sourceHandle = "source-left";
4218
+ targetHandle = "target-right";
4219
+ }
4220
+ } else if (targetPoint.y < sourcePoint.y) {
4221
+ sourceHandle = "source-top";
4222
+ targetHandle = "target-bottom";
4223
+ }
4224
+ }
4091
4225
  return {
4092
4226
  id: `edge-${edge.source}-${edge.target}-${index}`,
4093
4227
  source: sourceId,
@@ -4107,8 +4241,8 @@ function createReactFlowElements(nodes, edges, subgraphs, subgraphLayouts, subgr
4107
4241
  width: 20,
4108
4242
  height: 20
4109
4243
  },
4110
- sourceHandle: direction === "LR" || direction === "RL" ? "source-right" : "source-bottom",
4111
- targetHandle: direction === "LR" || direction === "RL" ? "target-left" : "target-top",
4244
+ sourceHandle,
4245
+ targetHandle,
4112
4246
  zIndex: 0
4113
4247
  };
4114
4248
  })
@@ -6895,12 +7029,503 @@ function convertUiGraphToMermaid(input, options) {
6895
7029
  context
6896
7030
  };
6897
7031
  }
7032
+ const SHAPE_IDS = [
7033
+ "rectangle",
7034
+ "rounded-rect",
7035
+ "ellipse",
7036
+ "diamond",
7037
+ "triangle",
7038
+ "parallelogram",
7039
+ "trapezoid",
7040
+ "hexagon",
7041
+ "document",
7042
+ "cylinder",
7043
+ "delay",
7044
+ "off-page-connector",
7045
+ "display",
7046
+ "collate",
7047
+ "sort",
7048
+ "terminator",
7049
+ "or",
7050
+ "database",
7051
+ "multiple-documents",
7052
+ "subroutine",
7053
+ "manual-input",
7054
+ "summing-junction",
7055
+ "internal-storage"
7056
+ ];
7057
+ const STROKE_STYLES = [
7058
+ "solid",
7059
+ "dashed",
7060
+ "dotted"
7061
+ ];
7062
+ function clampNum(value, min, max) {
7063
+ if (value === void 0 || !Number.isFinite(value)) return void 0;
7064
+ return Math.min(max, Math.max(min, value));
7065
+ }
7066
+ function dropUndefined(input) {
7067
+ const output = {};
7068
+ for (const [key, value] of Object.entries(input)) {
7069
+ if (value === void 0) continue;
7070
+ output[key] = value;
7071
+ }
7072
+ return output;
7073
+ }
7074
+ function mapShapeStylePatch(patch) {
7075
+ return dropUndefined({
7076
+ fill: patch.fill,
7077
+ stroke: patch.stroke,
7078
+ strokeWidth: clampNum(patch.strokeWidth, 0, 10),
7079
+ strokeStyle: patch.strokeStyle,
7080
+ cornerRadius: clampNum(patch.cornerRadius, 0, 64),
7081
+ textColor: patch.textColor,
7082
+ textFontSize: clampNum(patch.textFontSize, 8, 48),
7083
+ shape: patch.shape
7084
+ });
7085
+ }
7086
+ function mapCloudStylePatch(patch) {
7087
+ return dropUndefined({
7088
+ fill: patch.fill,
7089
+ stroke: patch.stroke,
7090
+ strokeWidth: clampNum(patch.strokeWidth, 0, 10),
7091
+ strokeStyle: patch.strokeStyle
7092
+ });
7093
+ }
7094
+ function mapTextStylePatch(patch) {
7095
+ return dropUndefined({
7096
+ fill: patch.fill,
7097
+ stroke: patch.stroke,
7098
+ strokeWidth: clampNum(patch.strokeWidth, 0, 10),
7099
+ strokeStyle: patch.strokeStyle,
7100
+ borderRadius: clampNum(patch.cornerRadius, 0, 64),
7101
+ color: patch.textColor,
7102
+ fontSize: clampNum(patch.textFontSize, 8, 48)
7103
+ });
7104
+ }
7105
+ function mapGroupStylePatch(patch) {
7106
+ return dropUndefined({
7107
+ backgroundColor: patch.fill,
7108
+ borderColor: patch.stroke
7109
+ });
7110
+ }
7111
+ function mapC4StylePatch(patch) {
7112
+ return dropUndefined({
7113
+ fill: patch.fill,
7114
+ stroke: patch.stroke,
7115
+ fontColor: patch.textColor
7116
+ });
7117
+ }
7118
+ function mapC4BoundaryStylePatch(patch) {
7119
+ return dropUndefined({
7120
+ backgroundColor: patch.fill,
7121
+ borderColor: patch.stroke,
7122
+ fontColor: patch.textColor
7123
+ });
7124
+ }
7125
+ function mapSequenceParticipantStylePatch(patch) {
7126
+ return dropUndefined({
7127
+ color: patch.stroke,
7128
+ textColor: patch.textColor
7129
+ });
7130
+ }
7131
+ const NODE_TYPE_REGISTRY = {
7132
+ shape: {
7133
+ tag: "shape",
7134
+ diagramTypes: ["flowchart"],
7135
+ isContainer: false,
7136
+ geometryEditable: true,
7137
+ shapes: SHAPE_IDS,
7138
+ mapStylePatch: mapShapeStylePatch
7139
+ },
7140
+ default: {
7141
+ tag: "default",
7142
+ diagramTypes: ["flowchart"],
7143
+ isContainer: false,
7144
+ geometryEditable: true,
7145
+ shapes: SHAPE_IDS,
7146
+ mapStylePatch: mapShapeStylePatch
7147
+ },
7148
+ cloud: {
7149
+ tag: "cloud",
7150
+ diagramTypes: ["flowchart"],
7151
+ isContainer: false,
7152
+ geometryEditable: true,
7153
+ mapStylePatch: mapCloudStylePatch
7154
+ },
7155
+ text: {
7156
+ tag: "text",
7157
+ diagramTypes: ["flowchart"],
7158
+ isContainer: false,
7159
+ geometryEditable: true,
7160
+ mapStylePatch: mapTextStylePatch
7161
+ },
7162
+ group: {
7163
+ tag: "group",
7164
+ diagramTypes: ["flowchart"],
7165
+ isContainer: true,
7166
+ geometryEditable: false,
7167
+ mapStylePatch: mapGroupStylePatch
7168
+ },
7169
+ c4: {
7170
+ tag: "c4",
7171
+ diagramTypes: ["c4"],
7172
+ isContainer: false,
7173
+ geometryEditable: true,
7174
+ mapStylePatch: mapC4StylePatch
7175
+ },
7176
+ c4Boundary: {
7177
+ tag: "c4Boundary",
7178
+ diagramTypes: ["c4"],
7179
+ isContainer: true,
7180
+ geometryEditable: false,
7181
+ mapStylePatch: mapC4BoundaryStylePatch
7182
+ },
7183
+ sequenceParticipant: {
7184
+ tag: "sequenceParticipant",
7185
+ diagramTypes: ["sequence"],
7186
+ isContainer: false,
7187
+ geometryEditable: false,
7188
+ mapStylePatch: mapSequenceParticipantStylePatch
7189
+ }
7190
+ };
7191
+ function getNodeTypeSpec(type) {
7192
+ if (type === void 0) return void 0;
7193
+ return NODE_TYPE_REGISTRY[type];
7194
+ }
7195
+ function buildNodeStyleDataPatch(type, patch) {
7196
+ var _getNodeTypeSpec$mapS, _getNodeTypeSpec;
7197
+ return (_getNodeTypeSpec$mapS = (_getNodeTypeSpec = getNodeTypeSpec(type)) === null || _getNodeTypeSpec === void 0 ? void 0 : _getNodeTypeSpec.mapStylePatch(patch)) !== null && _getNodeTypeSpec$mapS !== void 0 ? _getNodeTypeSpec$mapS : {};
7198
+ }
7199
+ function isGeometryEditableNodeType(type) {
7200
+ var _getNodeTypeSpec$geom, _getNodeTypeSpec2;
7201
+ return (_getNodeTypeSpec$geom = (_getNodeTypeSpec2 = getNodeTypeSpec(type)) === null || _getNodeTypeSpec2 === void 0 ? void 0 : _getNodeTypeSpec2.geometryEditable) !== null && _getNodeTypeSpec$geom !== void 0 ? _getNodeTypeSpec$geom : false;
7202
+ }
7203
+ const THEME_ROLES = [
7204
+ "boundary",
7205
+ "client",
7206
+ "service",
7207
+ "data",
7208
+ "messaging",
7209
+ "neutral"
7210
+ ];
7211
+ const DEFAULT_THEME_ID = "professional";
7212
+ const THEME_REGISTRY = {
7213
+ professional: {
7214
+ id: "professional",
7215
+ label: "Professional",
7216
+ description: "Calm slate-navy palette, the default look",
7217
+ mode: "dark",
7218
+ promptHint: "clean, modern, professional, calm, corporate, default, no specific style requested",
7219
+ nodeText: "#F8FAFC",
7220
+ canvasText: "#93B4E8",
7221
+ roles: {
7222
+ boundary: {
7223
+ fill: "#171B26",
7224
+ stroke: "#3D4759"
7225
+ },
7226
+ client: {
7227
+ fill: "#1C2336",
7228
+ stroke: "#3D5EA8"
7229
+ },
7230
+ service: {
7231
+ fill: "#1C2336",
7232
+ stroke: "#3D5EA8"
7233
+ },
7234
+ data: {
7235
+ fill: "#18242F",
7236
+ stroke: "#3D8A7A"
7237
+ },
7238
+ messaging: {
7239
+ fill: "#241F30",
7240
+ stroke: "#6B5CA8"
7241
+ },
7242
+ neutral: {
7243
+ fill: "#1C2336",
7244
+ stroke: "#3D5EA8"
7245
+ }
7246
+ },
7247
+ edge: {
7248
+ stroke: "#828DA3",
7249
+ strokeWidth: 1.5,
7250
+ labelBackground: "#1E293B",
7251
+ labelText: "#E2E8F0",
7252
+ emphasizedStroke: "#5B9BFF",
7253
+ emphasizedStrokeWidth: 3
7254
+ }
7255
+ },
7256
+ "midnight-bold": {
7257
+ id: "midnight-bold",
7258
+ label: "Midnight Bold",
7259
+ description: "Dark background, saturated high-contrast accents",
7260
+ mode: "dark",
7261
+ promptHint: "dark, bold, saturated, high contrast, vivid, striking",
7262
+ nodeText: "#F8FAFC",
7263
+ canvasText: "#7FB2FF",
7264
+ roles: {
7265
+ boundary: {
7266
+ fill: "#12151F",
7267
+ stroke: "#3D4759"
7268
+ },
7269
+ client: {
7270
+ fill: "#1C2336",
7271
+ stroke: "#5B9BFF"
7272
+ },
7273
+ service: {
7274
+ fill: "#1C2336",
7275
+ stroke: "#38BDF8"
7276
+ },
7277
+ data: {
7278
+ fill: "#0F2D3A",
7279
+ stroke: "#2AD4B3"
7280
+ },
7281
+ messaging: {
7282
+ fill: "#2A2410",
7283
+ stroke: "#E8B93E"
7284
+ },
7285
+ neutral: {
7286
+ fill: "#1C2336",
7287
+ stroke: "#5B9BFF"
7288
+ }
7289
+ },
7290
+ edge: {
7291
+ stroke: "#5B9BFF",
7292
+ strokeWidth: 2.5,
7293
+ labelBackground: "#1E293B",
7294
+ labelText: "#E2E8F0",
7295
+ emphasizedStroke: "#5B9BFF",
7296
+ emphasizedStrokeWidth: 4
7297
+ }
7298
+ },
7299
+ "soft-pastel": {
7300
+ id: "soft-pastel",
7301
+ label: "Soft Pastel",
7302
+ description: "Dark cards, soft muted pastel-hued borders",
7303
+ mode: "dark",
7304
+ promptHint: "soft, pastel, gentle, muted, airy, whimsical",
7305
+ nodeText: "#F1F5F9",
7306
+ canvasText: "#A8C8E8",
7307
+ roles: {
7308
+ boundary: {
7309
+ fill: "#171B24",
7310
+ stroke: "#7C93B8"
7311
+ },
7312
+ client: {
7313
+ fill: "#1A2233",
7314
+ stroke: "#8FD9C4"
7315
+ },
7316
+ service: {
7317
+ fill: "#1A2233",
7318
+ stroke: "#93B8F0"
7319
+ },
7320
+ data: {
7321
+ fill: "#1F1A2E",
7322
+ stroke: "#E3A98C"
7323
+ },
7324
+ messaging: {
7325
+ fill: "#241F14",
7326
+ stroke: "#E8D48A"
7327
+ },
7328
+ neutral: {
7329
+ fill: "#1C2029",
7330
+ stroke: "#A8B3C4"
7331
+ }
7332
+ },
7333
+ edge: {
7334
+ stroke: "#8FA3C4",
7335
+ strokeWidth: 2,
7336
+ labelBackground: "#1E293B",
7337
+ labelText: "#E8EDF5",
7338
+ emphasizedStroke: "#8FD9C4",
7339
+ emphasizedStrokeWidth: 3.5
7340
+ }
7341
+ },
7342
+ monochrome: {
7343
+ id: "monochrome",
7344
+ label: "Monochrome",
7345
+ description: "Grayscale, roles differ by shade rather than hue",
7346
+ mode: "dark",
7347
+ promptHint: "monochrome, grayscale, black and white, minimal, neutral",
7348
+ nodeText: "#F3F4F6",
7349
+ canvasText: "#D1D5DB",
7350
+ roles: {
7351
+ boundary: {
7352
+ fill: "#17191D",
7353
+ stroke: "#4B5563"
7354
+ },
7355
+ client: {
7356
+ fill: "#23262B",
7357
+ stroke: "#9CA3AF"
7358
+ },
7359
+ service: {
7360
+ fill: "#1D2024",
7361
+ stroke: "#6B7280"
7362
+ },
7363
+ data: {
7364
+ fill: "#26292E",
7365
+ stroke: "#D1D5DB"
7366
+ },
7367
+ messaging: {
7368
+ fill: "#202225",
7369
+ stroke: "#4B5563"
7370
+ },
7371
+ neutral: {
7372
+ fill: "#1F2226",
7373
+ stroke: "#6B7280"
7374
+ }
7375
+ },
7376
+ edge: {
7377
+ stroke: "#9CA3AF",
7378
+ strokeWidth: 2,
7379
+ labelBackground: "#111318",
7380
+ labelText: "#E5E7EB",
7381
+ emphasizedStroke: "#F3F4F6",
7382
+ emphasizedStrokeWidth: 3.5
7383
+ }
7384
+ },
7385
+ "high-contrast": {
7386
+ id: "high-contrast",
7387
+ label: "High Contrast",
7388
+ description: "Maximum-contrast palette for accessibility or emphasis",
7389
+ mode: "dark",
7390
+ promptHint: "high contrast, accessible, accessibility, maximum contrast, bright neon",
7391
+ nodeText: "#000000",
7392
+ canvasText: "#FFFFFF",
7393
+ roles: {
7394
+ boundary: {
7395
+ fill: "#000000",
7396
+ stroke: "#FFFFFF"
7397
+ },
7398
+ client: {
7399
+ fill: "#FFD400",
7400
+ stroke: "#000000"
7401
+ },
7402
+ service: {
7403
+ fill: "#00E5FF",
7404
+ stroke: "#000000"
7405
+ },
7406
+ data: {
7407
+ fill: "#00FF85",
7408
+ stroke: "#000000"
7409
+ },
7410
+ messaging: {
7411
+ fill: "#FF6EC7",
7412
+ stroke: "#000000"
7413
+ },
7414
+ neutral: {
7415
+ fill: "#FFFFFF",
7416
+ stroke: "#000000"
7417
+ }
7418
+ },
7419
+ edge: {
7420
+ stroke: "#FFFFFF",
7421
+ strokeWidth: 2.5,
7422
+ labelBackground: "#000000",
7423
+ labelText: "#FFFFFF",
7424
+ emphasizedStroke: "#FFD400",
7425
+ emphasizedStrokeWidth: 4.5
7426
+ }
7427
+ },
7428
+ blueprint: {
7429
+ id: "blueprint",
7430
+ label: "Blueprint",
7431
+ description: "Monochrome technical blueprint — one blue hue, thin uniform lines, near-transparent fills",
7432
+ mode: "dark",
7433
+ promptHint: "blueprint, technical, monochrome blue, schematic, precise, no decorative color, engineering drawing",
7434
+ nodeText: "#CFE3F5",
7435
+ canvasText: "#5B8FBF",
7436
+ roles: {
7437
+ boundary: {
7438
+ fill: "#0B1929",
7439
+ stroke: "#3D6A94"
7440
+ },
7441
+ client: {
7442
+ fill: "#0E1D30",
7443
+ stroke: "#5B8FBF"
7444
+ },
7445
+ service: {
7446
+ fill: "#0E1D30",
7447
+ stroke: "#4A7BAA"
7448
+ },
7449
+ data: {
7450
+ fill: "#0E1D30",
7451
+ stroke: "#6FA8D6"
7452
+ },
7453
+ messaging: {
7454
+ fill: "#0E1D30",
7455
+ stroke: "#3D6A94"
7456
+ },
7457
+ neutral: {
7458
+ fill: "#0E1D30",
7459
+ stroke: "#4A7BAA"
7460
+ }
7461
+ },
7462
+ edge: {
7463
+ stroke: "#3D6A94",
7464
+ strokeWidth: 1,
7465
+ labelBackground: "#0B1929",
7466
+ labelText: "#CFE3F5",
7467
+ emphasizedStroke: "#6FA8D6",
7468
+ emphasizedStrokeWidth: 2
7469
+ }
7470
+ },
7471
+ ocean: {
7472
+ id: "ocean",
7473
+ label: "Ocean",
7474
+ description: "Cool dark blues and teals",
7475
+ mode: "dark",
7476
+ promptHint: "ocean, cool, blue, teal, calm water, deep sea",
7477
+ nodeText: "#EAF6FA",
7478
+ canvasText: "#7FD9EE",
7479
+ roles: {
7480
+ boundary: {
7481
+ fill: "#0B1F2A",
7482
+ stroke: "#2E5A6E"
7483
+ },
7484
+ client: {
7485
+ fill: "#0F2E3D",
7486
+ stroke: "#4FB8D6"
7487
+ },
7488
+ service: {
7489
+ fill: "#0F3A3A",
7490
+ stroke: "#35C7B0"
7491
+ },
7492
+ data: {
7493
+ fill: "#10293F",
7494
+ stroke: "#3B7DD8"
7495
+ },
7496
+ messaging: {
7497
+ fill: "#172B3D",
7498
+ stroke: "#6E93C7"
7499
+ },
7500
+ neutral: {
7501
+ fill: "#10222C",
7502
+ stroke: "#4FB8D6"
7503
+ }
7504
+ },
7505
+ edge: {
7506
+ stroke: "#4FB8D6",
7507
+ strokeWidth: 2,
7508
+ labelBackground: "#0B1F2A",
7509
+ labelText: "#DCEEF5",
7510
+ emphasizedStroke: "#35C7B0",
7511
+ emphasizedStrokeWidth: 3.5
7512
+ }
7513
+ }
7514
+ };
7515
+ function getTheme(themeId) {
7516
+ if (themeId && THEME_REGISTRY[themeId]) return THEME_REGISTRY[themeId];
7517
+ return THEME_REGISTRY[DEFAULT_THEME_ID];
7518
+ }
7519
+ function buildThemeCatalogPromptContext() {
7520
+ return Object.values(THEME_REGISTRY).map((t) => `- "${t.id}" (${t.mode}): ${t.description}. Matches requests like: ${t.promptHint}.`).join("\n");
7521
+ }
6898
7522
  exports.AstToSqlGenerator = AstToSqlGenerator;
6899
7523
  exports.AstToUiConverter = AstToUiConverter;
6900
7524
  exports.BasicDetailsSchema = BasicDetailsSchema;
6901
7525
  exports.C4_COLORS = C4_COLORS;
6902
7526
  exports.C4_LAYOUT = C4_LAYOUT;
6903
7527
  exports.ComponentInputType = require_component_type.ComponentInputType;
7528
+ exports.DEFAULT_THEME_ID = DEFAULT_THEME_ID;
6904
7529
  exports.DialectIdSchema = DialectIdSchema;
6905
7530
  exports.DocumentCollectionSchema = DocumentCollectionSchema;
6906
7531
  exports.DocumentIndexSchema = DocumentIndexSchema;
@@ -6914,11 +7539,18 @@ exports.MongoEditorSchema = MongoEditorSchema;
6914
7539
  exports.MongoIndexFieldSchema = MongoIndexFieldSchema;
6915
7540
  exports.MongoIndexSchema = MongoIndexSchema;
6916
7541
  exports.MongoNestedFieldSchema = MongoNestedFieldSchema;
7542
+ exports.NODE_TYPE_REGISTRY = NODE_TYPE_REGISTRY;
6917
7543
  exports.NestedFieldSchema = NestedFieldSchema;
6918
7544
  exports.NoSqlFieldSchema = NoSqlFieldSchema;
6919
7545
  exports.SEQUENCE_LAYOUT = SEQUENCE_LAYOUT;
7546
+ exports.SHAPE_IDS = SHAPE_IDS;
7547
+ exports.STROKE_STYLES = STROKE_STYLES;
6920
7548
  exports.SqlToAstParser = SqlToAstParser;
7549
+ exports.THEME_REGISTRY = THEME_REGISTRY;
7550
+ exports.THEME_ROLES = THEME_ROLES;
6921
7551
  exports.buildMetaData = buildMetaData;
7552
+ exports.buildNodeStyleDataPatch = buildNodeStyleDataPatch;
7553
+ exports.buildThemeCatalogPromptContext = buildThemeCatalogPromptContext;
6922
7554
  exports.computeDiagramSyncHash = computeDiagramSyncHash;
6923
7555
  exports.contextSchema = require_headless.contextSchema;
6924
7556
  exports.convertC4MermaidToReactFlow = convertC4MermaidToReactFlow;
@@ -6939,8 +7571,11 @@ exports.flattenMetaData = flattenMetaData;
6939
7571
  exports.generateTableNodeId = generateTableNodeId;
6940
7572
  exports.generateUUID = generateUUID;
6941
7573
  exports.getC4ElementColors = getC4ElementColors;
7574
+ exports.getNodeTypeSpec = getNodeTypeSpec;
7575
+ exports.getTheme = getTheme;
6942
7576
  exports.isC4Diagram = isC4Diagram;
6943
7577
  exports.isC4ReactFlowDiagram = isC4ReactFlowDiagram;
7578
+ exports.isGeometryEditableNodeType = isGeometryEditableNodeType;
6944
7579
  exports.isSequenceDiagram = isSequenceDiagram;
6945
7580
  exports.parseC4Diagram = parseC4Diagram;
6946
7581
  exports.sanitizeMermaidLabels = sanitizeMermaidLabels;