schematex 0.2.3 → 0.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/dist/ai/ai-sdk.cjs +9 -9
  2. package/dist/ai/ai-sdk.js +4 -4
  3. package/dist/ai/index.cjs +12 -12
  4. package/dist/ai/index.js +4 -4
  5. package/dist/browser.cjs +6 -6
  6. package/dist/browser.js +4 -4
  7. package/dist/{chunk-MOU5QRZY.cjs → chunk-DPQYGWCT.cjs} +5 -5
  8. package/dist/{chunk-MOU5QRZY.cjs.map → chunk-DPQYGWCT.cjs.map} +1 -1
  9. package/dist/{chunk-2BM3HJSK.js → chunk-H2OEUBPO.js} +5 -3
  10. package/dist/chunk-H2OEUBPO.js.map +1 -0
  11. package/dist/{chunk-SN7NTZI6.js → chunk-J2LVOWVY.js} +171 -20
  12. package/dist/chunk-J2LVOWVY.js.map +1 -0
  13. package/dist/{chunk-6LZJTAA3.cjs → chunk-MJGDP3CS.cjs} +5 -3
  14. package/dist/chunk-MJGDP3CS.cjs.map +1 -0
  15. package/dist/{chunk-4QP37LD3.js → chunk-MR5HU5WU.js} +3 -3
  16. package/dist/{chunk-4QP37LD3.js.map → chunk-MR5HU5WU.js.map} +1 -1
  17. package/dist/{chunk-QXIGHMH2.cjs → chunk-MSYBSOU2.cjs} +6 -6
  18. package/dist/{chunk-QXIGHMH2.cjs.map → chunk-MSYBSOU2.cjs.map} +1 -1
  19. package/dist/{chunk-Z3DE6S64.cjs → chunk-UAGSCTYI.cjs} +171 -20
  20. package/dist/chunk-UAGSCTYI.cjs.map +1 -0
  21. package/dist/{chunk-S3RBKJM5.js → chunk-VPKCW4PB.js} +4 -4
  22. package/dist/{chunk-S3RBKJM5.js.map → chunk-VPKCW4PB.js.map} +1 -1
  23. package/dist/diagrams/flowchart/index.cjs +7 -7
  24. package/dist/diagrams/flowchart/index.d.cts +1 -1
  25. package/dist/diagrams/flowchart/index.d.ts +1 -1
  26. package/dist/diagrams/flowchart/index.js +1 -1
  27. package/dist/diagrams/genogram/index.cjs +8 -8
  28. package/dist/diagrams/genogram/index.js +1 -1
  29. package/dist/{index-lsSaw3E0.d.cts → index-BTZEka65.d.cts} +10 -1
  30. package/dist/{index-C97K-kuw.d.ts → index-DcU88F9i.d.ts} +10 -1
  31. package/dist/index.cjs +9 -9
  32. package/dist/index.d.cts +1 -1
  33. package/dist/index.d.ts +1 -1
  34. package/dist/index.js +3 -3
  35. package/dist/react.cjs +4 -4
  36. package/dist/react.js +3 -3
  37. package/package.json +1 -1
  38. package/dist/chunk-2BM3HJSK.js.map +0 -1
  39. package/dist/chunk-6LZJTAA3.cjs.map +0 -1
  40. package/dist/chunk-SN7NTZI6.js.map +0 -1
  41. package/dist/chunk-Z3DE6S64.cjs.map +0 -1
@@ -713,13 +713,53 @@ var FC_CONST = {
713
713
  // flow-direction gap between layers
714
714
  dummyWidth: 1,
715
715
  padding: 24,
716
+ /** Latin/digit avg width at 12px font. CJK uses cjkCharWidth instead. */
716
717
  charWidth: 6.8,
717
- // approx font-size 12 proportional width
718
+ /** Full-width glyph width at 12px (CJK ideograph, kana, hangul, fullwidth). */
719
+ cjkCharWidth: 12.5,
718
720
  labelHPad: 16,
719
721
  minNodeWidth: 72,
720
- maxLabelWidth: 220,
722
+ /**
723
+ * Cap on per-line label width. Until line-wrapping lands, this clamp is
724
+ * a soft contract: nodes never grow past this, and any overflow becomes
725
+ * the caller's problem. Set generously so common CJK sentences (≤30
726
+ * full-width chars) still fit without truncation or text overflow.
727
+ */
728
+ maxLabelWidth: 420,
721
729
  crossingSweepIters: 24
722
730
  };
731
+ var SHAPE_SLANT = {
732
+ parallelogram: 20,
733
+ trapezoid: 16
734
+ };
735
+ var CLUSTER_GEO = {
736
+ pad: 24,
737
+ titleH: 20,
738
+ /** Extra visible separation between two sequential cluster bboxes. */
739
+ gap: 12
740
+ };
741
+ function isFullWidth(code) {
742
+ if (code >= 12288 && code <= 12351) return true;
743
+ if (code >= 12352 && code <= 12447) return true;
744
+ if (code >= 12448 && code <= 12543) return true;
745
+ if (code >= 13312 && code <= 19903) return true;
746
+ if (code >= 19968 && code <= 40959) return true;
747
+ if (code >= 44032 && code <= 55215) return true;
748
+ if (code >= 63744 && code <= 64255) return true;
749
+ if (code >= 65280 && code <= 65376) return true;
750
+ if (code >= 65504 && code <= 65510) return true;
751
+ if (code >= 131072 && code <= 196607) return true;
752
+ return false;
753
+ }
754
+ function measureLabelWidth(label) {
755
+ let w = 0;
756
+ for (const ch of label) {
757
+ const code = ch.codePointAt(0) ?? 0;
758
+ if (isFullWidth(code)) w += FC_CONST.cjkCharWidth;
759
+ else w += FC_CONST.charWidth;
760
+ }
761
+ return w;
762
+ }
723
763
  function greedyFAS(nodeIds, edges) {
724
764
  const outAdj = /* @__PURE__ */ new Map();
725
765
  const inAdj = /* @__PURE__ */ new Map();
@@ -1038,6 +1078,46 @@ function laneBasedXCoords(layerNodes, pathOf, nodeSpacingX, segments) {
1038
1078
  }
1039
1079
  }
1040
1080
  }
1081
+ const clusterLanes = laneOrder.filter((l) => l !== null);
1082
+ if (clusterLanes.length >= 2 && laneOrder.includes(null)) {
1083
+ const tmpPartition = layerNodes.map(
1084
+ (layer) => {
1085
+ const m = /* @__PURE__ */ new Map();
1086
+ for (const n of layer) {
1087
+ if (n.isDummy) continue;
1088
+ const lane = laneOf(n.id);
1089
+ if (!m.has(lane)) m.set(lane, []);
1090
+ m.get(lane).push(n);
1091
+ }
1092
+ return m;
1093
+ }
1094
+ );
1095
+ const clusterOccupiedLayers = /* @__PURE__ */ new Set();
1096
+ for (let li = 0; li < tmpPartition.length; li++) {
1097
+ for (const lane of clusterLanes) {
1098
+ if ((tmpPartition[li].get(lane) ?? []).length > 0) {
1099
+ clusterOccupiedLayers.add(li);
1100
+ }
1101
+ }
1102
+ }
1103
+ let nullIsBoundary = true;
1104
+ for (let li = 0; li < tmpPartition.length; li++) {
1105
+ const nm = tmpPartition[li].get(null) ?? [];
1106
+ if (nm.length > 0 && clusterOccupiedLayers.has(li)) {
1107
+ nullIsBoundary = false;
1108
+ break;
1109
+ }
1110
+ }
1111
+ if (nullIsBoundary) {
1112
+ const mid = Math.floor(clusterLanes.length / 2);
1113
+ laneOrder.length = 0;
1114
+ laneOrder.push(
1115
+ ...clusterLanes.slice(0, mid),
1116
+ null,
1117
+ ...clusterLanes.slice(mid)
1118
+ );
1119
+ }
1120
+ }
1041
1121
  const lanesPerLayer = layerNodes.map(
1042
1122
  (layer) => {
1043
1123
  const m = /* @__PURE__ */ new Map();
@@ -1112,22 +1192,52 @@ function laneBasedXCoords(layerNodes, pathOf, nodeSpacingX, segments) {
1112
1192
  }
1113
1193
  return result;
1114
1194
  }
1195
+ function hasOverlappingTopLevelClusters(ast, layerMap, sgParent) {
1196
+ const topLevel = ast.subgraphs.filter((sg) => !sgParent.get(sg.id));
1197
+ if (topLevel.length < 2) return false;
1198
+ const collect = (sgId) => {
1199
+ const sg = ast.subgraphs.find((s) => s.id === sgId);
1200
+ if (!sg) return [];
1201
+ const ids = [...sg.children];
1202
+ for (const childSgId of sg.subgraphs) ids.push(...collect(childSgId));
1203
+ return ids;
1204
+ };
1205
+ const ranges = topLevel.map((sg) => {
1206
+ const ids = collect(sg.id);
1207
+ if (ids.length === 0) return { min: 0, max: -1 };
1208
+ const layers = ids.map((id) => layerMap.get(id) ?? 0);
1209
+ return { min: Math.min(...layers), max: Math.max(...layers) };
1210
+ });
1211
+ for (let i = 0; i < ranges.length; i++) {
1212
+ for (let j = i + 1; j < ranges.length; j++) {
1213
+ const a = ranges[i];
1214
+ const b = ranges[j];
1215
+ if (a.max < a.min || b.max < b.min) continue;
1216
+ if (a.min <= b.max && b.min <= a.max) return true;
1217
+ }
1218
+ }
1219
+ return false;
1220
+ }
1115
1221
  function layoutFlowchart(ast) {
1116
1222
  const dir = ast.direction;
1117
1223
  const isHorizontalDir = dir === "LR" || dir === "RL";
1118
1224
  const sizeOf = (n) => {
1225
+ const rawTextW = measureLabelWidth(n.label);
1119
1226
  const labelW = Math.min(
1120
1227
  FC_CONST.maxLabelWidth,
1121
- Math.ceil(n.label.length * FC_CONST.charWidth) + FC_CONST.labelHPad * 2
1228
+ Math.ceil(rawTextW) + FC_CONST.labelHPad * 2
1122
1229
  );
1123
1230
  let shapeW = Math.max(FC_CONST.minNodeWidth, labelW);
1124
1231
  let shapeH = FC_CONST.nodeHeight;
1125
1232
  if (n.shape === "diamond") {
1126
- shapeW = Math.max(shapeW, labelW * 1.25);
1233
+ shapeW = Math.max(shapeW, labelW * 1.4);
1127
1234
  shapeH = Math.max(shapeH, 52);
1128
1235
  }
1129
- if (n.shape === "parallelogram" || n.shape === "parallelogram-alt" || n.shape === "trapezoid" || n.shape === "trapezoid-alt") {
1130
- shapeW += 20;
1236
+ if (n.shape === "parallelogram" || n.shape === "parallelogram-alt") {
1237
+ shapeW += 2 * SHAPE_SLANT.parallelogram + 8;
1238
+ }
1239
+ if (n.shape === "trapezoid" || n.shape === "trapezoid-alt") {
1240
+ shapeW += 2 * SHAPE_SLANT.trapezoid + 8;
1131
1241
  }
1132
1242
  if (n.shape === "stadium" || n.shape === "round") {
1133
1243
  shapeW = Math.max(shapeW, shapeH + 20);
@@ -1138,7 +1248,10 @@ function layoutFlowchart(ast) {
1138
1248
  shapeH = side;
1139
1249
  }
1140
1250
  if (n.shape === "hexagon") {
1141
- shapeW = Math.max(shapeW, labelW + 44);
1251
+ shapeW = Math.max(shapeW, labelW + 48);
1252
+ }
1253
+ if (n.shape === "asymmetric") {
1254
+ shapeW += 24;
1142
1255
  }
1143
1256
  if (n.shape === "cylinder") {
1144
1257
  shapeH = Math.max(shapeH, 52);
@@ -1275,8 +1388,9 @@ function layoutFlowchart(ast) {
1275
1388
  const layerNodes = ordered.map(
1276
1389
  (layer) => layer.map((id) => lnodes.get(id))
1277
1390
  );
1391
+ const useLane = ast.subgraphs.length > 0 && hasOverlappingTopLevelClusters(ast, layerMap, sgParent);
1278
1392
  let xMap;
1279
- if (ast.subgraphs.length > 0) {
1393
+ if (useLane) {
1280
1394
  xMap = laneBasedXCoords(
1281
1395
  layerNodes,
1282
1396
  pathOf,
@@ -1290,7 +1404,6 @@ function layoutFlowchart(ast) {
1290
1404
  xMap = bkXCoords(bkLayers, segments, FC_CONST.nodeSpacingX);
1291
1405
  }
1292
1406
  const isHorizontal = dir === "LR" || dir === "RL";
1293
- const layerGap = FC_CONST.layerSpacingY;
1294
1407
  const layerHeights = layerNodes.map((layer) => {
1295
1408
  let maxH = 0;
1296
1409
  for (const n of layer) {
@@ -1300,17 +1413,56 @@ function layoutFlowchart(ast) {
1300
1413
  return maxH > 0 ? maxH : FC_CONST.nodeHeight;
1301
1414
  });
1302
1415
  const hasClusters = ast.subgraphs.length > 0;
1303
- const CLUSTER_OVERHEAD_TITLE = hasClusters ? 44 : 0;
1304
- const CLUSTER_OVERHEAD_SIDE = hasClusters ? 24 : 0;
1416
+ const CLUSTER_OVERHEAD_TITLE = hasClusters ? CLUSTER_GEO.pad + CLUSTER_GEO.titleH : 0;
1417
+ const CLUSTER_OVERHEAD_SIDE = hasClusters ? CLUSTER_GEO.pad : 0;
1305
1418
  const extraTopPad = isHorizontal ? CLUSTER_OVERHEAD_SIDE : CLUSTER_OVERHEAD_TITLE;
1306
1419
  const extraLeftPad = isHorizontal ? CLUSTER_OVERHEAD_TITLE : CLUSTER_OVERHEAD_SIDE;
1420
+ const topLevelOf = (sgId) => {
1421
+ let cur = sgId;
1422
+ let safety = 32;
1423
+ while (safety-- > 0) {
1424
+ const p = sgParent.get(cur);
1425
+ if (!p) return cur;
1426
+ cur = p;
1427
+ }
1428
+ return cur;
1429
+ };
1430
+ const clustersAtLayer = layerNodes.map(() => /* @__PURE__ */ new Set());
1431
+ for (let li = 0; li < layerNodes.length; li++) {
1432
+ for (const n of layerNodes[li]) {
1433
+ if (n.isDummy) continue;
1434
+ const parent = parentOf.get(n.id);
1435
+ if (!parent) continue;
1436
+ clustersAtLayer[li].add(topLevelOf(parent));
1437
+ }
1438
+ }
1439
+ const layerGapAt = (li) => {
1440
+ const a = clustersAtLayer[li] ?? /* @__PURE__ */ new Set();
1441
+ const b = clustersAtLayer[li + 1] ?? /* @__PURE__ */ new Set();
1442
+ let hasExit = false;
1443
+ for (const c of a) if (!b.has(c)) {
1444
+ hasExit = true;
1445
+ break;
1446
+ }
1447
+ let hasEntry = false;
1448
+ for (const c of b) if (!a.has(c)) {
1449
+ hasEntry = true;
1450
+ break;
1451
+ }
1452
+ let required = 0;
1453
+ if (hasExit) required += CLUSTER_GEO.pad;
1454
+ if (hasEntry) required += CLUSTER_GEO.pad + CLUSTER_GEO.titleH;
1455
+ if (hasExit && hasEntry) required += CLUSTER_GEO.gap;
1456
+ return Math.max(FC_CONST.layerSpacingY, required);
1457
+ };
1307
1458
  const layerCenterY = [];
1308
1459
  {
1309
1460
  let y = FC_CONST.padding + extraTopPad;
1310
1461
  for (let li = 0; li < layerHeights.length; li++) {
1311
1462
  y += layerHeights[li] / 2;
1312
1463
  layerCenterY.push(y);
1313
- y += layerHeights[li] / 2 + layerGap;
1464
+ y += layerHeights[li] / 2;
1465
+ if (li < layerHeights.length - 1) y += layerGapAt(li);
1314
1466
  }
1315
1467
  }
1316
1468
  let minX = Infinity;
@@ -1454,8 +1606,7 @@ function layoutFlowchart(ast) {
1454
1606
  }
1455
1607
  return 0;
1456
1608
  }
1457
- const CLUSTER_PAD = 24;
1458
- const CLUSTER_TITLE_H = 20;
1609
+ const { pad: CLUSTER_PAD, titleH: CLUSTER_TITLE_H } = CLUSTER_GEO;
1459
1610
  const clusters = ast.subgraphs.map((sg) => {
1460
1611
  const memberIds = collectDescendantNodeIds(sg.id);
1461
1612
  const members = outNodes.filter((n) => memberIds.includes(n.node.id));
@@ -1556,23 +1707,23 @@ function shapeSVG(shape, w, h) {
1556
1707
  return polygon({ points, class: "sx-fc-node sx-fc-node-diamond" });
1557
1708
  }
1558
1709
  case "parallelogram": {
1559
- const slant = 20;
1710
+ const slant = SHAPE_SLANT.parallelogram;
1560
1711
  const points = `${slant},0 ${w},0 ${w - slant},${h} 0,${h}`;
1561
1712
  return polygon({ points, class: "sx-fc-node" });
1562
1713
  }
1563
1714
  // ── M2 additional shapes ────────────────────────────────────
1564
1715
  case "parallelogram-alt": {
1565
- const slant = 20;
1716
+ const slant = SHAPE_SLANT.parallelogram;
1566
1717
  const points = `0,0 ${w - slant},0 ${w},${h} ${slant},${h}`;
1567
1718
  return polygon({ points, class: "sx-fc-node" });
1568
1719
  }
1569
1720
  case "trapezoid": {
1570
- const slant = 16;
1721
+ const slant = SHAPE_SLANT.trapezoid;
1571
1722
  const points = `0,0 ${w},0 ${w - slant},${h} ${slant},${h}`;
1572
1723
  return polygon({ points, class: "sx-fc-node" });
1573
1724
  }
1574
1725
  case "trapezoid-alt": {
1575
- const slant = 16;
1726
+ const slant = SHAPE_SLANT.trapezoid;
1576
1727
  const points = `${slant},0 ${w - slant},0 ${w},${h} 0,${h}`;
1577
1728
  return polygon({ points, class: "sx-fc-node" });
1578
1729
  }
@@ -1871,5 +2022,5 @@ var flowchart = {
1871
2022
  };
1872
2023
 
1873
2024
  export { FC_CONST, flowchart, layoutFlowchart, parseFlowchart, renderFlowchart, renderFlowchartAST };
1874
- //# sourceMappingURL=chunk-SN7NTZI6.js.map
1875
- //# sourceMappingURL=chunk-SN7NTZI6.js.map
2025
+ //# sourceMappingURL=chunk-J2LVOWVY.js.map
2026
+ //# sourceMappingURL=chunk-J2LVOWVY.js.map