@aranzatech/diagrams-bpmn 0.3.0 → 0.3.2

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 (36) hide show
  1. package/dist/{catalog-DAGDhO-D.d.cts → catalog-DG-sz0VM.d.cts} +1 -1
  2. package/dist/{catalog-Q1QmKLDD.d.ts → catalog-DNIyjHbl.d.ts} +1 -1
  3. package/dist/{chunk-334WN4JZ.js → chunk-NYIYQUGX.js} +104 -23
  4. package/dist/chunk-NYIYQUGX.js.map +1 -0
  5. package/dist/elements/index.d.cts +3 -3
  6. package/dist/elements/index.d.ts +3 -3
  7. package/dist/extensions/index.d.cts +2 -2
  8. package/dist/extensions/index.d.ts +2 -2
  9. package/dist/index.cjs +102 -21
  10. package/dist/index.cjs.map +1 -1
  11. package/dist/index.d.cts +4 -4
  12. package/dist/index.d.ts +4 -4
  13. package/dist/index.js +1 -1
  14. package/dist/layout/index.cjs +392 -95
  15. package/dist/layout/index.cjs.map +1 -1
  16. package/dist/layout/index.d.cts +4 -4
  17. package/dist/layout/index.d.ts +4 -4
  18. package/dist/layout/index.js +392 -95
  19. package/dist/layout/index.js.map +1 -1
  20. package/dist/modeling/index.d.cts +4 -4
  21. package/dist/modeling/index.d.ts +4 -4
  22. package/dist/{types-CggktCqr.d.cts → types-CDp9kWQ4.d.cts} +2 -2
  23. package/dist/{types-DmDODKlh.d.ts → types-CuDL2YGL.d.ts} +2 -2
  24. package/dist/{types-D7zel9dq.d.ts → types-X5FyP8oS.d.ts} +1 -1
  25. package/dist/{types-BX_o95GC.d.cts → types-dQUuSnV5.d.cts} +1 -1
  26. package/dist/{types-BYN4Zuee.d.cts → types-nvF59RGF.d.cts} +12 -0
  27. package/dist/{types-BYN4Zuee.d.ts → types-nvF59RGF.d.ts} +12 -0
  28. package/dist/validation/index.d.cts +3 -3
  29. package/dist/validation/index.d.ts +3 -3
  30. package/dist/xml/index.cjs +102 -21
  31. package/dist/xml/index.cjs.map +1 -1
  32. package/dist/xml/index.d.cts +4 -4
  33. package/dist/xml/index.d.ts +4 -4
  34. package/dist/xml/index.js +1 -1
  35. package/package.json +1 -1
  36. package/dist/chunk-334WN4JZ.js.map +0 -1
@@ -1311,63 +1311,221 @@ function assignRows(nodes, forwardEdges, columns, gatewayPairs) {
1311
1311
 
1312
1312
  // src/layout/bpmn-custom-layout.ts
1313
1313
  var LANE_LABEL_W = 28;
1314
- var LANE_H_PAD = 20;
1315
- var COL_GAP = 80;
1316
- var ROW_HEIGHT = 80;
1317
- var ROW_GAP = 60;
1318
- var LANE_V_PAD = 50;
1319
- var POOL_H_PAD = 60;
1320
- var POOL_V_GAP = 50;
1321
- var LANE_MIN_H = 160;
1314
+ var LANE_H_PAD = 32;
1315
+ var COL_GAP = 60;
1316
+ var ROW_HEIGHT = 90;
1317
+ var ROW_GAP = 50;
1318
+ var LANE_V_PAD = 48;
1319
+ var POOL_H_PAD = 64;
1320
+ var POOL_V_GAP = 48;
1321
+ var LANE_MIN_H = 180;
1322
1322
  var POOL_MIN_W = 720;
1323
- var POOL_INNER_PAD = 8;
1323
+ var POOL_INNER_PAD = 10;
1324
+ var BACK_EDGE_CLEARANCE = 56;
1325
+ var LAYOUT_ARTIFACT_TYPES = /* @__PURE__ */ new Set([
1326
+ "DataObject",
1327
+ "DataObjectReference",
1328
+ "DataInput",
1329
+ "DataOutput",
1330
+ "DataStore",
1331
+ "DataStoreReference",
1332
+ "Annotation",
1333
+ "Group"
1334
+ ]);
1335
+ var COLLAPSED_SUBPROCESS_TYPES = /* @__PURE__ */ new Set([
1336
+ "SubProcess",
1337
+ "Transaction",
1338
+ "EventSubProcess",
1339
+ "AdHocSubProcess"
1340
+ ]);
1341
+ var LAYOUT_TASK_TYPES = /* @__PURE__ */ new Set([
1342
+ "Task",
1343
+ "UserTask",
1344
+ "ServiceTask",
1345
+ "ScriptTask",
1346
+ "ManualTask",
1347
+ "BusinessRuleTask",
1348
+ "ReceiveTask",
1349
+ "SendTask",
1350
+ "CallActivity"
1351
+ ]);
1352
+ var TASK_LAYOUT_MIN_W = 130;
1353
+ var TASK_LAYOUT_MIN_H = 80;
1324
1354
  function nW(node) {
1325
1355
  return node.width ?? node.measured?.width ?? 120;
1326
1356
  }
1327
1357
  function nH(node) {
1328
1358
  return node.height ?? node.measured?.height ?? 60;
1329
1359
  }
1360
+ function layoutW(node) {
1361
+ return LAYOUT_TASK_TYPES.has(node.data.elementType) ? Math.max(nW(node), TASK_LAYOUT_MIN_W) : nW(node);
1362
+ }
1363
+ function layoutH(node) {
1364
+ return LAYOUT_TASK_TYPES.has(node.data.elementType) ? Math.max(nH(node), TASK_LAYOUT_MIN_H) : nH(node);
1365
+ }
1366
+ function applyLayoutMinSize(node) {
1367
+ if (!LAYOUT_TASK_TYPES.has(node.data.elementType)) return node;
1368
+ const w = layoutW(node);
1369
+ const h = layoutH(node);
1370
+ if (w === nW(node) && h === nH(node)) return node;
1371
+ return { ...node, width: w, height: h, measured: { width: w, height: h } };
1372
+ }
1373
+ var BOUNDARY_SPACING = 10;
1374
+ function repositionBoundaryEvents(boundaryEvents, positionedContent) {
1375
+ if (boundaryEvents.length === 0) return [];
1376
+ const hostById = new Map(positionedContent.map((n) => [n.id, n]));
1377
+ const byHost = /* @__PURE__ */ new Map();
1378
+ for (const be of boundaryEvents) {
1379
+ const hostId = be.data.attachedToRef;
1380
+ if (!hostId) continue;
1381
+ if (!byHost.has(hostId)) byHost.set(hostId, []);
1382
+ byHost.get(hostId).push(be);
1383
+ }
1384
+ const result = [];
1385
+ for (const be of boundaryEvents) {
1386
+ const hostId = be.data.attachedToRef;
1387
+ if (!hostId) {
1388
+ result.push(be);
1389
+ continue;
1390
+ }
1391
+ const host = hostById.get(hostId);
1392
+ if (!host) {
1393
+ result.push(be);
1394
+ continue;
1395
+ }
1396
+ const hostGroup = byHost.get(hostId);
1397
+ const siblingIdx = hostGroup.findIndex((n) => n.id === be.id);
1398
+ const hostW = layoutW(host);
1399
+ const hostH = layoutH(host);
1400
+ const beH = nH(be);
1401
+ const totalGroupW = hostGroup.reduce((s, b) => s + nW(b), 0) + (hostGroup.length - 1) * BOUNDARY_SPACING;
1402
+ const groupStartX = host.position.x + hostW / 2 - totalGroupW / 2;
1403
+ const offsetX = hostGroup.slice(0, siblingIdx).reduce((s, b) => s + nW(b) + BOUNDARY_SPACING, 0);
1404
+ result.push({
1405
+ ...be,
1406
+ position: {
1407
+ x: groupStartX + offsetX,
1408
+ y: host.position.y + hostH - beH / 2
1409
+ }
1410
+ });
1411
+ }
1412
+ return result;
1413
+ }
1414
+ var SP_PAD = 48;
1415
+ function layoutSubProcess(children, edges) {
1416
+ if (children.length === 0) {
1417
+ return { children: [], width: 280, height: 160 };
1418
+ }
1419
+ const boundaryEvents = children.filter((n) => n.data.elementType === "BoundaryEvent");
1420
+ const mainChildren = children.filter((n) => n.data.elementType !== "BoundaryEvent");
1421
+ if (mainChildren.length === 0) {
1422
+ return {
1423
+ children: repositionBoundaryEvents(boundaryEvents, []),
1424
+ width: 280,
1425
+ height: 160
1426
+ };
1427
+ }
1428
+ const contentIds = new Set(mainChildren.map((n) => n.id));
1429
+ const seqEdges = extractSeqEdges(edges, contentIds);
1430
+ const backIds = detectBackEdges([...contentIds], seqEdges);
1431
+ const fwdEdges = seqEdges.filter((e) => !backIds.has(e.id));
1432
+ const columns = assignColumns([...contentIds], fwdEdges);
1433
+ const pairs = detectGatewayPairs(mainChildren, fwdEdges);
1434
+ const rows = assignRows(mainChildren, fwdEdges, columns, pairs);
1435
+ const maxCol = Math.max(0, ...[...columns.values()]);
1436
+ const colW = /* @__PURE__ */ new Map();
1437
+ for (let c = 0; c <= maxCol; c++) colW.set(c, 0);
1438
+ for (const node of mainChildren) {
1439
+ const c = columns.get(node.id) ?? 0;
1440
+ colW.set(c, Math.max(colW.get(c) ?? 0, layoutW(node)));
1441
+ }
1442
+ const colX = /* @__PURE__ */ new Map();
1443
+ let cumX = 0;
1444
+ for (let c = 0; c <= maxCol; c++) {
1445
+ colX.set(c, cumX);
1446
+ cumX += (colW.get(c) ?? 120) + COL_GAP;
1447
+ }
1448
+ const contentW = cumX - COL_GAP;
1449
+ const rowVals = [...rows.values()];
1450
+ const minRow = Math.min(0, ...rowVals);
1451
+ const maxRow = Math.max(0, ...rowVals);
1452
+ const rowCount = maxRow - minRow + 1;
1453
+ const contentH = rowCount * ROW_HEIGHT + Math.max(0, rowCount - 1) * ROW_GAP;
1454
+ const spW = Math.max(280, SP_PAD * 2 + contentW);
1455
+ const spH = Math.max(160, SP_PAD * 2 + contentH);
1456
+ const positionedChildren = mainChildren.map((node) => {
1457
+ const c = columns.get(node.id) ?? 0;
1458
+ const r = rows.get(node.id) ?? 0;
1459
+ const lw = layoutW(node);
1460
+ const lh = layoutH(node);
1461
+ const colOffset = (colX.get(c) ?? 0) + (colW.get(c) ?? 120) / 2 - lw / 2;
1462
+ const rowOffset = (r - minRow) * (ROW_HEIGHT + ROW_GAP) + ROW_HEIGHT / 2 - lh / 2;
1463
+ return applyLayoutMinSize({ ...node, position: { x: SP_PAD + colOffset, y: SP_PAD + rowOffset } });
1464
+ });
1465
+ const positionedBoundaries = repositionBoundaryEvents(boundaryEvents, positionedChildren);
1466
+ return {
1467
+ children: [...positionedChildren, ...positionedBoundaries],
1468
+ width: spW,
1469
+ height: spH
1470
+ };
1471
+ }
1330
1472
  function layoutPool(pool, lanes, content, allEdges) {
1331
- if (content.length === 0) {
1473
+ const boundaryEvents = content.filter((n) => n.data.elementType === "BoundaryEvent");
1474
+ const mainContent = content.filter((n) => n.data.elementType !== "BoundaryEvent");
1475
+ if (mainContent.length === 0) {
1476
+ const positionedBoundaries2 = repositionBoundaryEvents(boundaryEvents, []);
1332
1477
  if (lanes.length === 0) {
1333
- return { nodes: [], width: 240, height: 120 };
1478
+ return { nodes: positionedBoundaries2, width: 300, height: 140 };
1334
1479
  }
1335
1480
  const laneH = LANE_MIN_H;
1336
1481
  const h = POOL_INNER_PAD * 2 + lanes.length * laneH + Math.max(0, lanes.length - 1) * POOL_INNER_PAD;
1337
- const w = POOL_MIN_W;
1338
1482
  return {
1339
- nodes: lanes.map((lane, i) => ({
1340
- ...lane,
1341
- position: { x: POOL_INNER_PAD, y: POOL_INNER_PAD + i * (laneH + POOL_INNER_PAD) },
1342
- width: w - POOL_INNER_PAD * 2,
1343
- height: laneH
1344
- })),
1345
- width: w,
1483
+ nodes: [
1484
+ ...positionedBoundaries2,
1485
+ ...lanes.map((lane, i) => ({
1486
+ ...lane,
1487
+ position: { x: POOL_INNER_PAD, y: POOL_INNER_PAD + i * (laneH + POOL_INNER_PAD) },
1488
+ width: POOL_MIN_W - POOL_INNER_PAD * 2,
1489
+ height: laneH
1490
+ }))
1491
+ ],
1492
+ width: POOL_MIN_W,
1346
1493
  height: h
1347
1494
  };
1348
1495
  }
1349
- const contentIds = new Set(content.map((n) => n.id));
1496
+ const sortedLanes = [...lanes].sort((a, b) => a.position.y - b.position.y);
1497
+ const hasLanes = sortedLanes.length > 0;
1498
+ const laneIdSet = new Set(sortedLanes.map((l) => l.id));
1499
+ const nodeLaneId = /* @__PURE__ */ new Map();
1500
+ for (const node of mainContent) {
1501
+ const lId = hasLanes && node.parentId && laneIdSet.has(node.parentId) ? node.parentId : "_pool_";
1502
+ nodeLaneId.set(node.id, lId);
1503
+ }
1504
+ const contentIds = new Set(mainContent.map((n) => n.id));
1350
1505
  const seqEdges = extractSeqEdges(allEdges, contentIds);
1351
1506
  const backIds = detectBackEdges([...contentIds], seqEdges);
1352
1507
  const fwdEdges = seqEdges.filter((e) => !backIds.has(e.id));
1353
1508
  const columns = assignColumns([...contentIds], fwdEdges);
1354
- const pairs = detectGatewayPairs(content, fwdEdges);
1355
- const rows = assignRows(content, fwdEdges, columns, pairs);
1356
- const lanePositionsDistinct = lanes.some((l) => Math.abs(l.position.y) > 10);
1357
- const sortedLanes = lanePositionsDistinct ? [...lanes].sort((a, b) => a.position.y - b.position.y) : [...lanes];
1358
- const hasLanes = sortedLanes.length > 0;
1359
- const nodeLaneId = /* @__PURE__ */ new Map();
1360
- for (const node of content) {
1361
- if (hasLanes && node.parentId && node.parentId !== pool.id) {
1362
- nodeLaneId.set(node.id, node.parentId);
1363
- } else {
1364
- nodeLaneId.set(node.id, "_pool_");
1365
- }
1509
+ const rows = /* @__PURE__ */ new Map();
1510
+ const contentByLane = /* @__PURE__ */ new Map();
1511
+ for (const node of mainContent) {
1512
+ const lId = nodeLaneId.get(node.id) ?? "_pool_";
1513
+ if (!contentByLane.has(lId)) contentByLane.set(lId, []);
1514
+ contentByLane.get(lId).push(node);
1515
+ }
1516
+ for (const [, laneNodes] of contentByLane) {
1517
+ const laneNodeIds = new Set(laneNodes.map((n) => n.id));
1518
+ const intraEdges = fwdEdges.filter(
1519
+ (e) => laneNodeIds.has(e.source) && laneNodeIds.has(e.target)
1520
+ );
1521
+ const lanePairs = detectGatewayPairs(laneNodes, intraEdges);
1522
+ const laneRows = assignRows(laneNodes, intraEdges, columns, lanePairs);
1523
+ for (const [id, row] of laneRows) rows.set(id, row);
1366
1524
  }
1367
1525
  const laneIds = hasLanes ? sortedLanes.map((l) => l.id) : ["_pool_"];
1368
1526
  const laneStats = /* @__PURE__ */ new Map();
1369
1527
  for (const laneId of laneIds) {
1370
- const laneRows = content.filter((n) => nodeLaneId.get(n.id) === laneId).map((n) => rows.get(n.id) ?? 0);
1528
+ const laneRows = mainContent.filter((n) => nodeLaneId.get(n.id) === laneId).map((n) => rows.get(n.id) ?? 0);
1371
1529
  if (laneRows.length === 0) {
1372
1530
  laneStats.set(laneId, { minRow: 0, maxRow: 0, rowCount: 1, height: LANE_MIN_H });
1373
1531
  } else {
@@ -1382,9 +1540,9 @@ function layoutPool(pool, lanes, content, allEdges) {
1382
1540
  const maxCol = Math.max(0, ...[...columns.values()]);
1383
1541
  const colW = /* @__PURE__ */ new Map();
1384
1542
  for (let c = 0; c <= maxCol; c++) colW.set(c, 0);
1385
- for (const node of content) {
1543
+ for (const node of mainContent) {
1386
1544
  const c = columns.get(node.id) ?? 0;
1387
- colW.set(c, Math.max(colW.get(c) ?? 0, nW(node)));
1545
+ colW.set(c, Math.max(colW.get(c) ?? 0, layoutW(node)));
1388
1546
  }
1389
1547
  const colX = /* @__PURE__ */ new Map();
1390
1548
  let cumX = 0;
@@ -1405,62 +1563,58 @@ function layoutPool(pool, lanes, content, allEdges) {
1405
1563
  if (i < laneIds.length - 1) cumY += POOL_INNER_PAD;
1406
1564
  }
1407
1565
  const poolH = cumY + POOL_INNER_PAD;
1408
- const positionedContent = content.map((node) => {
1566
+ const positionedContent = mainContent.map((node) => {
1409
1567
  const c = columns.get(node.id) ?? 0;
1410
1568
  const r = rows.get(node.id) ?? 0;
1411
1569
  const laneId = nodeLaneId.get(node.id) ?? "_pool_";
1412
1570
  const stat = laneStats.get(laneId);
1413
1571
  const lYOff = laneY.get(laneId) ?? 0;
1414
- const colOffset = (colX.get(c) ?? 0) + (colW.get(c) ?? 120) / 2 - nW(node) / 2;
1415
- const rowOffset = (r - stat.minRow) * (ROW_HEIGHT + ROW_GAP) + ROW_HEIGHT / 2 - nH(node) / 2;
1416
- const isLaneChild = hasLanes && !!node.parentId && node.parentId !== pool.id;
1572
+ const lw = layoutW(node);
1573
+ const lh = layoutH(node);
1574
+ const colOffset = (colX.get(c) ?? 0) + (colW.get(c) ?? 120) / 2 - lw / 2;
1575
+ const rowOffset = (r - stat.minRow) * (ROW_HEIGHT + ROW_GAP) + ROW_HEIGHT / 2 - lh / 2;
1417
1576
  const contentH_stat = stat.rowCount * ROW_HEIGHT + Math.max(0, stat.rowCount - 1) * ROW_GAP;
1418
1577
  const vertTopOffset = Math.max(LANE_V_PAD, (stat.height - contentH_stat) / 2);
1578
+ const isLaneChild = hasLanes && !!node.parentId && node.parentId !== pool.id;
1419
1579
  const x = isLaneChild ? LANE_LABEL_W + LANE_H_PAD + colOffset : POOL_H_PAD + colOffset;
1420
1580
  const y = isLaneChild ? vertTopOffset + rowOffset : lYOff + vertTopOffset + rowOffset;
1421
- return { ...node, position: { x, y } };
1581
+ return applyLayoutMinSize({ ...node, position: { x, y } });
1422
1582
  });
1423
- const NODE_MIN_GAP = 20;
1583
+ const NODE_MIN_GAP = 24;
1424
1584
  const resolvedContent = [...positionedContent];
1425
1585
  for (const laneId of laneIds) {
1426
1586
  const laneNodeIndices = resolvedContent.map((n, i) => ({ n, i })).filter(({ n }) => (nodeLaneId.get(n.id) ?? "_pool_") === laneId).sort((a, b) => a.n.position.x - b.n.position.x);
1427
1587
  for (let k = 1; k < laneNodeIndices.length; k++) {
1428
1588
  const prev = resolvedContent[laneNodeIndices[k - 1].i];
1429
1589
  const curr = resolvedContent[laneNodeIndices[k].i];
1430
- const prevBottom = prev.position.y + nH(prev);
1590
+ const prevBottom = prev.position.y + layoutH(prev);
1431
1591
  const currTop = curr.position.y;
1432
1592
  const prevTop = prev.position.y;
1433
- const currBottom = curr.position.y + nH(curr);
1593
+ const currBottom = curr.position.y + layoutH(curr);
1434
1594
  const yOverlap = prevBottom + NODE_MIN_GAP > currTop && currBottom + NODE_MIN_GAP > prevTop;
1435
1595
  if (!yOverlap) continue;
1436
- const prevRight = prev.position.x + nW(prev);
1596
+ const prevRight = prev.position.x + layoutW(prev);
1437
1597
  if (prevRight + NODE_MIN_GAP > curr.position.x) {
1438
1598
  resolvedContent[laneNodeIndices[k].i] = {
1439
1599
  ...curr,
1440
- position: {
1441
- x: prevRight + NODE_MIN_GAP,
1442
- y: curr.position.y
1443
- }
1600
+ position: { x: prevRight + NODE_MIN_GAP, y: curr.position.y }
1444
1601
  };
1445
1602
  }
1446
1603
  }
1447
1604
  }
1605
+ const positionedBoundaries = repositionBoundaryEvents(boundaryEvents, resolvedContent);
1448
1606
  const positionedLanes = hasLanes ? sortedLanes.map((lane) => ({
1449
1607
  ...lane,
1450
- // x: after pool label strip + left inner padding
1451
- // y: laneY already includes top POOL_INNER_PAD offset
1452
1608
  position: { x: POOL_INNER_PAD, y: laneY.get(lane.id) ?? POOL_INNER_PAD },
1453
1609
  width: laneW,
1454
1610
  height: laneStats.get(lane.id)?.height ?? LANE_MIN_H
1455
1611
  })) : [];
1456
1612
  return {
1457
- nodes: [...resolvedContent, ...positionedLanes],
1613
+ nodes: [...resolvedContent, ...positionedBoundaries, ...positionedLanes],
1458
1614
  width: poolW,
1459
1615
  height: poolH
1460
1616
  };
1461
1617
  }
1462
- var BACK_EDGE_CLEARANCE = 50;
1463
- var SAME_ROW_THRESHOLD = 15;
1464
1618
  function absolutePos(nodeId, byId, cache) {
1465
1619
  const cached = cache.get(nodeId);
1466
1620
  if (cached) return cached;
@@ -1479,10 +1633,22 @@ function absolutePos(nodeId, byId, cache) {
1479
1633
  function laneOf(node, laneIds) {
1480
1634
  return node.parentId && laneIds.has(node.parentId) ? node.parentId : void 0;
1481
1635
  }
1636
+ function gapMidX(sAbs, sW, tAbs, tW) {
1637
+ const leftRightEdge = Math.min(sAbs.x + sW, tAbs.x + tW);
1638
+ const rightLeftEdge = Math.max(sAbs.x, tAbs.x);
1639
+ return leftRightEdge < rightLeftEdge ? (leftRightEdge + rightLeftEdge) / 2 : sAbs.x + sW / 2;
1640
+ }
1641
+ function routeMidX(sAbs, sW, tAbs, tW) {
1642
+ const leftEdge = Math.min(sAbs.x + sW, tAbs.x + tW);
1643
+ const rightEdge = Math.max(sAbs.x, tAbs.x);
1644
+ return leftEdge < rightEdge ? leftEdge + (rightEdge - leftEdge) * 0.35 : sAbs.x + sW / 2;
1645
+ }
1646
+ var SAME_ROW_THRESHOLD = 15;
1482
1647
  function routeEdges(edges, layoutNodes, backEdgeIds, laneIds, poolIds) {
1483
1648
  const byId = new Map(layoutNodes.map((n) => [n.id, n]));
1484
1649
  const cache = /* @__PURE__ */ new Map();
1485
1650
  const abs = (id) => absolutePos(id, byId, cache);
1651
+ const sortedLanes = [...laneIds].map((id) => byId.get(id)).filter((n) => !!n).sort((a, b) => abs(a.id).y - abs(b.id).y);
1486
1652
  return edges.map((edge) => {
1487
1653
  const edgeType = edge.data?.edgeType ?? edge.type;
1488
1654
  if (edgeType !== "sequenceFlow") {
@@ -1497,11 +1663,22 @@ function routeEdges(edges, layoutNodes, backEdgeIds, laneIds, poolIds) {
1497
1663
  const tAbs = abs(tgt.id);
1498
1664
  const sW = nW(src), sH = nH(src);
1499
1665
  const tW = nW(tgt), tH = nH(tgt);
1500
- const sCX = sAbs.x + sW / 2, sCY = sAbs.y + sH / 2;
1501
- const tCX = tAbs.x + tW / 2, tCY = tAbs.y + tH / 2;
1502
- const srcPool = poolIds.has(src.parentId ?? "") ? src.parentId : poolIds.has(byId.get(src.parentId ?? "")?.parentId ?? "") ? byId.get(src.parentId ?? "")?.parentId : src.parentId;
1503
- const tgtPool = poolIds.has(tgt.parentId ?? "") ? tgt.parentId : poolIds.has(byId.get(tgt.parentId ?? "")?.parentId ?? "") ? byId.get(tgt.parentId ?? "")?.parentId : tgt.parentId;
1504
- if (srcPool !== tgtPool) {
1666
+ const sCX = sAbs.x + sW / 2;
1667
+ const tCX = tAbs.x + tW / 2;
1668
+ const sCY = sAbs.y + sH / 2;
1669
+ const tCY = tAbs.y + tH / 2;
1670
+ const getPool = (nodeId) => {
1671
+ const node = byId.get(nodeId);
1672
+ if (!node) return null;
1673
+ if (poolIds.has(nodeId)) return nodeId;
1674
+ if (node.parentId && poolIds.has(node.parentId)) return node.parentId;
1675
+ if (node.parentId) {
1676
+ const gp = byId.get(node.parentId)?.parentId ?? null;
1677
+ if (gp && poolIds.has(gp)) return gp;
1678
+ }
1679
+ return node.parentId ?? null;
1680
+ };
1681
+ if (getPool(edge.source) !== getPool(edge.target)) {
1505
1682
  const d = { ...edge.data };
1506
1683
  delete d.routingPoints;
1507
1684
  return { ...edge, data: d };
@@ -1511,33 +1688,49 @@ function routeEdges(edges, layoutNodes, backEdgeIds, laneIds, poolIds) {
1511
1688
  const topY = Math.min(sAbs.y, tAbs.y) - BACK_EDGE_CLEARANCE;
1512
1689
  routingPoints = [
1513
1690
  { x: sCX, y: sAbs.y },
1514
- // [0] discarded
1515
1691
  { x: sCX, y: topY },
1516
- // [1] go up
1517
1692
  { x: tCX, y: topY },
1518
- // [2] go left/right
1519
- { x: tCX, y: tAbs.y }
1520
- // [3] discarded
1693
+ { x: tCX, y: tAbs.y + tH }
1521
1694
  ];
1522
1695
  } else if (laneOf(src, laneIds) !== laneOf(tgt, laneIds)) {
1523
- const goingDown = tAbs.y > sAbs.y;
1524
- const sharedX = Math.abs(sCX - tCX) < 10 ? sCX : (sCX + tCX) / 2;
1525
1696
  const srcLane = byId.get(src.parentId ?? "");
1526
1697
  const tgtLane = byId.get(tgt.parentId ?? "");
1527
1698
  if (srcLane && tgtLane && laneIds.has(srcLane.id) && laneIds.has(tgtLane.id)) {
1528
- const srcLaneAbs = abs(srcLane.id);
1529
- const borderY = goingDown ? srcLaneAbs.y + (srcLane.height ?? 160) : srcLaneAbs.y;
1530
- routingPoints = [
1531
- { x: sCX, y: goingDown ? sAbs.y + sH : sAbs.y },
1532
- // [0] discarded
1533
- { x: sharedX, y: goingDown ? sAbs.y + sH : sAbs.y },
1534
- // [1] bend: horizontal exit
1535
- { x: sharedX, y: borderY },
1536
- // [2] bend: lane border
1537
- { x: sharedX, y: goingDown ? tAbs.y : tAbs.y + tH }
1538
- // [3] discarded
1539
- ];
1699
+ const goingDown = tAbs.y > sAbs.y;
1700
+ const sharedX = gapMidX(sAbs, sW, tAbs, tW);
1701
+ const srcLaneIdx = sortedLanes.findIndex((l) => l.id === srcLane.id);
1702
+ const tgtLaneIdx = sortedLanes.findIndex((l) => l.id === tgtLane.id);
1703
+ const pts = [];
1704
+ if (goingDown) {
1705
+ pts.push({ x: sCX, y: sAbs.y + sH });
1706
+ pts.push({ x: sharedX, y: sAbs.y + sH });
1707
+ const fromIdx = Math.min(srcLaneIdx, tgtLaneIdx);
1708
+ const toIdx = Math.max(srcLaneIdx, tgtLaneIdx);
1709
+ for (let i = fromIdx; i < toIdx; i++) {
1710
+ const lane = sortedLanes[i];
1711
+ const laneBot = abs(lane.id).y + (lane.height ?? LANE_MIN_H);
1712
+ pts.push({ x: sharedX, y: laneBot });
1713
+ }
1714
+ const lastY = pts[pts.length - 1].y;
1715
+ pts.push({ x: tCX, y: lastY });
1716
+ pts.push({ x: tCX, y: tAbs.y + tH });
1717
+ } else {
1718
+ pts.push({ x: sCX, y: sAbs.y });
1719
+ pts.push({ x: sharedX, y: sAbs.y });
1720
+ const fromIdx = Math.min(srcLaneIdx, tgtLaneIdx);
1721
+ const toIdx = Math.max(srcLaneIdx, tgtLaneIdx);
1722
+ for (let i = toIdx; i > fromIdx; i--) {
1723
+ const lane = sortedLanes[i];
1724
+ const laneTop = abs(lane.id).y;
1725
+ pts.push({ x: sharedX, y: laneTop });
1726
+ }
1727
+ const lastY = pts[pts.length - 1].y;
1728
+ pts.push({ x: tCX, y: lastY });
1729
+ pts.push({ x: tCX, y: tAbs.y });
1730
+ }
1731
+ routingPoints = pts;
1540
1732
  } else {
1733
+ const sharedX = gapMidX(sAbs, sW, tAbs, tW);
1541
1734
  routingPoints = [
1542
1735
  { x: sCX, y: sCY },
1543
1736
  { x: sharedX, y: sCY },
@@ -1556,39 +1749,108 @@ function routeEdges(edges, layoutNodes, backEdgeIds, laneIds, poolIds) {
1556
1749
  if (exitsTop || exitsBottom) {
1557
1750
  routingPoints = [
1558
1751
  { x: sCX, y: exitsTop ? sAbs.y : sAbs.y + sH },
1559
- // [0] discarded
1560
1752
  { x: sCX, y: tCY },
1561
- // [1] vertical to target row
1562
1753
  { x: tCX, y: tCY },
1563
- // [2] horizontal to target
1564
1754
  { x: tCX, y: exitsTop ? tAbs.y + tH : tAbs.y }
1565
- // [3] discarded
1566
1755
  ];
1567
1756
  } else {
1568
- const goingRight = tAbs.x >= sAbs.x;
1569
- const midX = goingRight ? sAbs.x + sW + COL_GAP / 2 : sAbs.x - COL_GAP / 2;
1757
+ const midX = routeMidX(sAbs, sW, tAbs, tW);
1570
1758
  routingPoints = [
1571
1759
  { x: sAbs.x + sW, y: sCY },
1572
- // [0] discarded
1573
1760
  { x: midX, y: sCY },
1574
- // [1] horizontal exit
1575
1761
  { x: midX, y: tCY },
1576
- // [2] vertical to target row
1577
1762
  { x: tAbs.x, y: tCY }
1578
- // [3] discarded
1579
1763
  ];
1580
1764
  }
1581
1765
  }
1582
1766
  return { ...edge, data: { ...edge.data, routingPoints } };
1583
1767
  });
1584
1768
  }
1769
+ var ARTIFACT_ABOVE_GAP = 16;
1770
+ var ARTIFACT_H_SPACING = 12;
1771
+ function positionArtifacts(artifacts, resultNodes, edges) {
1772
+ if (artifacts.length === 0) return [];
1773
+ const byId = new Map(resultNodes.map((n) => [n.id, n]));
1774
+ const cache = /* @__PURE__ */ new Map();
1775
+ const absPos = (id) => absolutePos(id, byId, cache);
1776
+ const artifactsByNode = /* @__PURE__ */ new Map();
1777
+ const ungrouped = [];
1778
+ for (const artifact of artifacts) {
1779
+ if (artifact.data.elementType === "Group") {
1780
+ ungrouped.push(artifact);
1781
+ continue;
1782
+ }
1783
+ const connEdge = edges.find((e) => {
1784
+ const t = e.data?.edgeType ?? e.type;
1785
+ return (t === "association" || t === "dataAssociation") && (e.source === artifact.id || e.target === artifact.id);
1786
+ });
1787
+ if (!connEdge) {
1788
+ ungrouped.push(artifact);
1789
+ continue;
1790
+ }
1791
+ const connId = connEdge.source === artifact.id ? connEdge.target : connEdge.source;
1792
+ if (!byId.has(connId)) {
1793
+ ungrouped.push(artifact);
1794
+ continue;
1795
+ }
1796
+ if (!artifactsByNode.has(connId)) artifactsByNode.set(connId, []);
1797
+ artifactsByNode.get(connId).push(artifact);
1798
+ }
1799
+ const positioned = [...ungrouped];
1800
+ for (const [connId, arts] of artifactsByNode) {
1801
+ const connNode = byId.get(connId);
1802
+ const connAbsP = absPos(connId);
1803
+ const totalW = arts.reduce((s, a) => s + nW(a), 0) + (arts.length - 1) * ARTIFACT_H_SPACING;
1804
+ const desiredAbsY = connAbsP.y - ARTIFACT_ABOVE_GAP - Math.max(...arts.map(nH));
1805
+ let desiredAbsX = connAbsP.x + nW(connNode) / 2 - totalW / 2;
1806
+ for (const artifact of arts) {
1807
+ const parentAbsP = artifact.parentId ? absPos(artifact.parentId) : { x: 0, y: 0 };
1808
+ positioned.push({
1809
+ ...artifact,
1810
+ position: {
1811
+ x: desiredAbsX - parentAbsP.x,
1812
+ y: desiredAbsY - parentAbsP.y
1813
+ }
1814
+ });
1815
+ desiredAbsX += nW(artifact) + ARTIFACT_H_SPACING;
1816
+ }
1817
+ }
1818
+ return positioned;
1819
+ }
1585
1820
  async function bpmnCustomLayout(nodes, edges) {
1586
- const pools = nodes.filter((n) => n.data.elementType === "Pool");
1587
- const lanes = nodes.filter((n) => n.data.elementType === "Lane");
1588
- const content = nodes.filter((n) => !LAYOUT_CONTAINER_TYPES.has(n.data.elementType));
1821
+ const artifacts = nodes.filter((n) => LAYOUT_ARTIFACT_TYPES.has(n.data.elementType));
1822
+ const mainNodes = nodes.filter((n) => !LAYOUT_ARTIFACT_TYPES.has(n.data.elementType));
1823
+ const pools = mainNodes.filter((n) => n.data.elementType === "Pool");
1824
+ const lanes = mainNodes.filter((n) => n.data.elementType === "Lane");
1825
+ const expandedSubProcesses = mainNodes.filter(
1826
+ (n) => COLLAPSED_SUBPROCESS_TYPES.has(n.data.elementType) && n.data.isExpanded
1827
+ );
1828
+ const subProcessLayouts = /* @__PURE__ */ new Map();
1829
+ const workingMainNodes = [...mainNodes];
1830
+ for (const sp of expandedSubProcesses) {
1831
+ const spChildren = workingMainNodes.filter((n) => n.parentId === sp.id);
1832
+ const result = layoutSubProcess(spChildren, edges);
1833
+ subProcessLayouts.set(sp.id, result);
1834
+ const spIdx = workingMainNodes.findIndex((n) => n.id === sp.id);
1835
+ if (spIdx >= 0) {
1836
+ workingMainNodes[spIdx] = {
1837
+ ...workingMainNodes[spIdx],
1838
+ width: result.width,
1839
+ height: result.height,
1840
+ measured: { width: result.width, height: result.height }
1841
+ };
1842
+ }
1843
+ }
1844
+ const content = workingMainNodes.filter((n) => {
1845
+ if (!LAYOUT_CONTAINER_TYPES.has(n.data.elementType)) return true;
1846
+ if (COLLAPSED_SUBPROCESS_TYPES.has(n.data.elementType)) return true;
1847
+ return false;
1848
+ });
1589
1849
  if (pools.length === 0) {
1590
1850
  const { bpmnElkLayout: bpmnElkLayout2 } = await Promise.resolve().then(() => (init_elk(), elk_exports));
1591
- return bpmnElkLayout2(nodes, edges);
1851
+ const elkResult = await bpmnElkLayout2(nodes.filter((n) => !LAYOUT_ARTIFACT_TYPES.has(n.data.elementType)), edges);
1852
+ const posArtifacts = positionArtifacts(artifacts, elkResult.nodes, edges);
1853
+ return { nodes: [...elkResult.nodes, ...posArtifacts], edges: elkResult.edges };
1592
1854
  }
1593
1855
  const poolIds = new Set(pools.map((p) => p.id));
1594
1856
  const allLaneIds = new Set(lanes.map((l) => l.id));
@@ -1608,7 +1870,10 @@ async function bpmnCustomLayout(nodes, edges) {
1608
1870
  const poolContent = content.filter(
1609
1871
  (n) => n.parentId === pool.id || n.parentId != null && laneIds.has(n.parentId)
1610
1872
  );
1611
- const result = layoutPool(pool, poolLanes, poolContent, edges);
1873
+ const poolBoundaries = workingMainNodes.filter(
1874
+ (n) => n.data.elementType === "BoundaryEvent" && (n.parentId === pool.id || n.parentId != null && laneIds.has(n.parentId))
1875
+ );
1876
+ const result = layoutPool(pool, poolLanes, [...poolContent, ...poolBoundaries], edges);
1612
1877
  resultNodes.push({
1613
1878
  ...pool,
1614
1879
  position: { x: 0, y: stackY },
@@ -1620,12 +1885,44 @@ async function bpmnCustomLayout(nodes, edges) {
1620
1885
  }
1621
1886
  stackY += result.height + POOL_V_GAP;
1622
1887
  }
1888
+ for (const [, spLayout] of subProcessLayouts) {
1889
+ for (const child of spLayout.children) {
1890
+ resultNodes.push(child);
1891
+ }
1892
+ }
1623
1893
  const layoutted = new Set(resultNodes.map((n) => n.id));
1624
- for (const node of nodes) {
1625
- if (!layoutted.has(node.id)) resultNodes.push(node);
1894
+ const freeNodes = workingMainNodes.filter((n) => !layoutted.has(n.id));
1895
+ if (freeNodes.length > 0) {
1896
+ const freeEdges = edges.filter(
1897
+ (e) => freeNodes.some((n) => n.id === e.source || n.id === e.target)
1898
+ );
1899
+ try {
1900
+ const { bpmnElkLayout: bpmnElkLayout2 } = await Promise.resolve().then(() => (init_elk(), elk_exports));
1901
+ const elkFree = await bpmnElkLayout2(freeNodes, freeEdges);
1902
+ const offsetY = stackY;
1903
+ for (const node of elkFree.nodes) {
1904
+ resultNodes.push({
1905
+ ...node,
1906
+ position: { x: node.position.x, y: node.position.y + offsetY }
1907
+ });
1908
+ }
1909
+ const freeEdgeIds = new Set(freeEdges.map((e) => e.id));
1910
+ const elkEdgeMap = new Map(elkFree.edges.map((e) => [e.id, e]));
1911
+ for (let i = 0; i < edges.length; i++) {
1912
+ if (freeEdgeIds.has(edges[i].id) && elkEdgeMap.has(edges[i].id)) {
1913
+ edges[i] = elkEdgeMap.get(edges[i].id);
1914
+ }
1915
+ }
1916
+ } catch {
1917
+ for (const node of freeNodes) resultNodes.push(node);
1918
+ }
1626
1919
  }
1627
1920
  const routedEdges = routeEdges(edges, resultNodes, allBackEdgeIds, allLaneIds, poolIds);
1628
- return { nodes: resultNodes, edges: routedEdges };
1921
+ const positionedArtifacts = positionArtifacts(artifacts, resultNodes, edges);
1922
+ return {
1923
+ nodes: [...resultNodes, ...positionedArtifacts],
1924
+ edges: routedEdges
1925
+ };
1629
1926
  }
1630
1927
 
1631
1928
  // src/layout/index.ts