@aranzatech/diagrams-bpmn 0.3.1 → 0.3.3

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 +241 -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 +241 -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
@@ -1,13 +1,13 @@
1
1
  import { LayoutResult, LayoutOptions } from '@aranzatech/diagrams-core/types';
2
2
  export { applyLayoutResultToDiagram } from '@aranzatech/diagrams-core/layout';
3
- import { d as BpmnRFNode, c as BpmnRFEdge } from '../types-CggktCqr.cjs';
3
+ import { d as BpmnRFNode, c as BpmnRFEdge } from '../types-CDp9kWQ4.cjs';
4
4
  import { BpmnDiagramState } from '../modeling/index.cjs';
5
5
  import '@xyflow/react';
6
- import '../types-BYN4Zuee.cjs';
7
- import '../types-BX_o95GC.cjs';
6
+ import '../types-nvF59RGF.cjs';
7
+ import '../types-dQUuSnV5.cjs';
8
8
  import '@aranzatech/diagrams-core';
9
9
  import '@aranzatech/diagrams-core/serialization';
10
- import '../catalog-DAGDhO-D.cjs';
10
+ import '../catalog-DG-sz0VM.cjs';
11
11
 
12
12
  /**
13
13
  * ELK-based auto-layout for BPMN diagrams.
@@ -1,13 +1,13 @@
1
1
  import { LayoutResult, LayoutOptions } from '@aranzatech/diagrams-core/types';
2
2
  export { applyLayoutResultToDiagram } from '@aranzatech/diagrams-core/layout';
3
- import { d as BpmnRFNode, c as BpmnRFEdge } from '../types-DmDODKlh.js';
3
+ import { d as BpmnRFNode, c as BpmnRFEdge } from '../types-CuDL2YGL.js';
4
4
  import { BpmnDiagramState } from '../modeling/index.js';
5
5
  import '@xyflow/react';
6
- import '../types-BYN4Zuee.js';
7
- import '../types-D7zel9dq.js';
6
+ import '../types-nvF59RGF.js';
7
+ import '../types-X5FyP8oS.js';
8
8
  import '@aranzatech/diagrams-core';
9
9
  import '@aranzatech/diagrams-core/serialization';
10
- import '../catalog-Q1QmKLDD.js';
10
+ import '../catalog-DNIyjHbl.js';
11
11
 
12
12
  /**
13
13
  * ELK-based auto-layout for BPMN diagrams.
@@ -135,6 +135,17 @@ function detectGatewayPairs(nodes, forwardEdges) {
135
135
  }
136
136
  return pairs;
137
137
  }
138
+ function createSecondaryOffsets(count) {
139
+ if (count <= 0) return [];
140
+ const offsets = [];
141
+ let step = 1;
142
+ while (offsets.length < count) {
143
+ offsets.push(-step);
144
+ if (offsets.length < count) offsets.push(step);
145
+ step++;
146
+ }
147
+ return offsets;
148
+ }
138
149
  function handleToRowBias(handle) {
139
150
  if (!handle) return null;
140
151
  if (handle.includes("top")) return -1;
@@ -150,6 +161,52 @@ function buildHandleMap(edges) {
150
161
  }
151
162
  return map;
152
163
  }
164
+ function pickMainBranch(branchData) {
165
+ if (branchData.length === 0) return void 0;
166
+ return [...branchData].sort((a, b) => {
167
+ const aRight = a.bias === 0 ? 1 : 0;
168
+ const bRight = b.bias === 0 ? 1 : 0;
169
+ if (aRight !== bRight) return bRight - aRight;
170
+ if (a.nodeIds.length !== b.nodeIds.length) return b.nodeIds.length - a.nodeIds.length;
171
+ return a.start.localeCompare(b.start);
172
+ })[0]?.start;
173
+ }
174
+ function resolveDirectionalRow(splitRow, preferredOffset, usedRows) {
175
+ if (preferredOffset === 0 && !usedRows.has(splitRow)) return splitRow;
176
+ const direction = preferredOffset < 0 ? -1 : 1;
177
+ let distance = Math.max(1, Math.abs(preferredOffset));
178
+ while (usedRows.has(splitRow + direction * distance)) distance++;
179
+ return splitRow + direction * distance;
180
+ }
181
+ function assignBranchRowsAroundMain(branchData, splitRow) {
182
+ const assigned = /* @__PURE__ */ new Map();
183
+ const mainBranchStart = pickMainBranch(branchData);
184
+ if (mainBranchStart) assigned.set(mainBranchStart, splitRow);
185
+ const usedRows = new Set(assigned.values());
186
+ const remaining = branchData.filter((branch) => branch.start !== mainBranchStart);
187
+ const withBias = remaining.filter((branch) => branch.bias !== null && branch.bias !== 0).sort((a, b) => {
188
+ const aMag = Math.abs(a.bias ?? 0);
189
+ const bMag = Math.abs(b.bias ?? 0);
190
+ if (aMag !== bMag) return aMag - bMag;
191
+ return a.start.localeCompare(b.start);
192
+ });
193
+ const withoutBias = remaining.filter((branch) => branch.bias === null || branch.bias === 0).sort((a, b) => b.nodeIds.length - a.nodeIds.length || a.start.localeCompare(b.start));
194
+ for (const branch of withBias) {
195
+ const row = resolveDirectionalRow(splitRow, branch.bias ?? 0, usedRows);
196
+ assigned.set(branch.start, row);
197
+ usedRows.add(row);
198
+ }
199
+ const preferredOffsets = createSecondaryOffsets(withoutBias.length);
200
+ for (let i = 0; i < withoutBias.length; i++) {
201
+ let row = splitRow + preferredOffsets[i];
202
+ if (usedRows.has(row)) {
203
+ row = resolveDirectionalRow(splitRow, preferredOffsets[i], usedRows);
204
+ }
205
+ assigned.set(withoutBias[i].start, row);
206
+ usedRows.add(row);
207
+ }
208
+ return assigned;
209
+ }
153
210
  function assignRows(nodes, forwardEdges, columns, gatewayPairs) {
154
211
  const rows = new Map(nodes.map((n) => [n.id, 0]));
155
212
  const succs = new Map(nodes.map((n) => [n.id, []]));
@@ -183,24 +240,14 @@ function assignRows(nodes, forwardEdges, columns, gatewayPairs) {
183
240
  nodeIds: getBranchNodes(start),
184
241
  bias: handleToRowBias(splitHandles?.get(start) ?? null)
185
242
  }));
186
- const withBias = branchData.filter((b) => b.bias !== null && b.bias !== 0);
187
- const withoutBias = branchData.filter((b) => b.bias === null || b.bias === 0).sort((a, b) => b.nodeIds.length - a.nodeIds.length);
188
- const assigned = /* @__PURE__ */ new Map();
189
- for (const b of withBias) {
190
- assigned.set(b.start, splitRow + b.bias);
191
- }
192
- let nextOffset = 0;
193
- for (const b of withoutBias) {
194
- while ([...assigned.values()].includes(splitRow + nextOffset)) nextOffset++;
195
- assigned.set(b.start, splitRow + nextOffset);
196
- nextOffset++;
197
- }
243
+ const assigned = assignBranchRowsAroundMain(branchData, splitRow);
198
244
  for (const b of branchData) {
199
245
  const row = assigned.get(b.start) ?? splitRow;
200
246
  for (const id of b.nodeIds) {
201
247
  rows.set(id, row);
202
248
  }
203
249
  }
250
+ rows.set(mergeId, splitRow);
204
251
  }
205
252
  const pairedSplits = new Set(gatewayPairs.keys());
206
253
  const unpairedSplits = nodes.filter(
@@ -229,16 +276,7 @@ function assignRows(nodes, forwardEdges, columns, gatewayPairs) {
229
276
  nodeIds: getAllReachable(start),
230
277
  bias: handleToRowBias(splitHandles2?.get(start) ?? null)
231
278
  }));
232
- const withBias2 = branchData.filter((b) => b.bias !== null && b.bias !== 0);
233
- const withoutBias2 = branchData.filter((b) => b.bias === null || b.bias === 0).sort((a, b) => b.nodeIds.length - a.nodeIds.length);
234
- const assigned2 = /* @__PURE__ */ new Map();
235
- for (const b of withBias2) assigned2.set(b.start, splitRow + b.bias);
236
- let nextOff = 0;
237
- for (const b of withoutBias2) {
238
- while ([...assigned2.values()].includes(splitRow + nextOff)) nextOff++;
239
- assigned2.set(b.start, splitRow + nextOff);
240
- nextOff++;
241
- }
279
+ const assigned2 = assignBranchRowsAroundMain(branchData, splitRow);
242
280
  for (const b of branchData) {
243
281
  const row = assigned2.get(b.start) ?? splitRow;
244
282
  for (const id of b.nodeIds) rows.set(id, row);
@@ -249,17 +287,18 @@ function assignRows(nodes, forwardEdges, columns, gatewayPairs) {
249
287
 
250
288
  // src/layout/bpmn-custom-layout.ts
251
289
  var LANE_LABEL_W = 28;
252
- var LANE_H_PAD = 40;
253
- var COL_GAP = 100;
254
- var ROW_HEIGHT = 100;
255
- var ROW_GAP = 80;
256
- var LANE_V_PAD = 60;
257
- var POOL_H_PAD = 80;
258
- var POOL_V_GAP = 60;
259
- var LANE_MIN_H = 200;
260
- var POOL_MIN_W = 840;
290
+ var LANE_H_PAD = 32;
291
+ var COL_GAP = 60;
292
+ var ROW_HEIGHT = 90;
293
+ var ROW_GAP = 50;
294
+ var LANE_V_PAD = 48;
295
+ var POOL_H_PAD = 64;
296
+ var POOL_V_GAP = 48;
297
+ var LANE_MIN_H = 180;
298
+ var POOL_MIN_W = 720;
261
299
  var POOL_INNER_PAD = 10;
262
- var BACK_EDGE_CLEARANCE = 70;
300
+ var BACK_EDGE_CLEARANCE = 56;
301
+ var EDGE_ROUTE_PAD = 28;
263
302
  var LAYOUT_ARTIFACT_TYPES = /* @__PURE__ */ new Set([
264
303
  "DataObject",
265
304
  "DataObjectReference",
@@ -276,12 +315,38 @@ var COLLAPSED_SUBPROCESS_TYPES = /* @__PURE__ */ new Set([
276
315
  "EventSubProcess",
277
316
  "AdHocSubProcess"
278
317
  ]);
318
+ var LAYOUT_TASK_TYPES = /* @__PURE__ */ new Set([
319
+ "Task",
320
+ "UserTask",
321
+ "ServiceTask",
322
+ "ScriptTask",
323
+ "ManualTask",
324
+ "BusinessRuleTask",
325
+ "ReceiveTask",
326
+ "SendTask",
327
+ "CallActivity"
328
+ ]);
329
+ var TASK_LAYOUT_MIN_W = 130;
330
+ var TASK_LAYOUT_MIN_H = 80;
279
331
  function nW(node) {
280
332
  return node.width ?? node.measured?.width ?? 120;
281
333
  }
282
334
  function nH(node) {
283
335
  return node.height ?? node.measured?.height ?? 60;
284
336
  }
337
+ function layoutW(node) {
338
+ return LAYOUT_TASK_TYPES.has(node.data.elementType) ? Math.max(nW(node), TASK_LAYOUT_MIN_W) : nW(node);
339
+ }
340
+ function layoutH(node) {
341
+ return LAYOUT_TASK_TYPES.has(node.data.elementType) ? Math.max(nH(node), TASK_LAYOUT_MIN_H) : nH(node);
342
+ }
343
+ function applyLayoutMinSize(node) {
344
+ if (!LAYOUT_TASK_TYPES.has(node.data.elementType)) return node;
345
+ const w = layoutW(node);
346
+ const h = layoutH(node);
347
+ if (w === nW(node) && h === nH(node)) return node;
348
+ return { ...node, width: w, height: h, measured: { width: w, height: h } };
349
+ }
285
350
  var BOUNDARY_SPACING = 10;
286
351
  function repositionBoundaryEvents(boundaryEvents, positionedContent) {
287
352
  if (boundaryEvents.length === 0) return [];
@@ -307,8 +372,8 @@ function repositionBoundaryEvents(boundaryEvents, positionedContent) {
307
372
  }
308
373
  const hostGroup = byHost.get(hostId);
309
374
  const siblingIdx = hostGroup.findIndex((n) => n.id === be.id);
310
- const hostW = nW(host);
311
- const hostH = nH(host);
375
+ const hostW = layoutW(host);
376
+ const hostH = layoutH(host);
312
377
  const beH = nH(be);
313
378
  const totalGroupW = hostGroup.reduce((s, b) => s + nW(b), 0) + (hostGroup.length - 1) * BOUNDARY_SPACING;
314
379
  const groupStartX = host.position.x + hostW / 2 - totalGroupW / 2;
@@ -349,7 +414,7 @@ function layoutSubProcess(children, edges) {
349
414
  for (let c = 0; c <= maxCol; c++) colW.set(c, 0);
350
415
  for (const node of mainChildren) {
351
416
  const c = columns.get(node.id) ?? 0;
352
- colW.set(c, Math.max(colW.get(c) ?? 0, nW(node)));
417
+ colW.set(c, Math.max(colW.get(c) ?? 0, layoutW(node)));
353
418
  }
354
419
  const colX = /* @__PURE__ */ new Map();
355
420
  let cumX = 0;
@@ -368,12 +433,11 @@ function layoutSubProcess(children, edges) {
368
433
  const positionedChildren = mainChildren.map((node) => {
369
434
  const c = columns.get(node.id) ?? 0;
370
435
  const r = rows.get(node.id) ?? 0;
371
- const colOffset = (colX.get(c) ?? 0) + (colW.get(c) ?? 120) / 2 - nW(node) / 2;
372
- const rowOffset = (r - minRow) * (ROW_HEIGHT + ROW_GAP) + ROW_HEIGHT / 2 - nH(node) / 2;
373
- return {
374
- ...node,
375
- position: { x: SP_PAD + colOffset, y: SP_PAD + rowOffset }
376
- };
436
+ const lw = layoutW(node);
437
+ const lh = layoutH(node);
438
+ const colOffset = (colX.get(c) ?? 0) + (colW.get(c) ?? 120) / 2 - lw / 2;
439
+ const rowOffset = (r - minRow) * (ROW_HEIGHT + ROW_GAP) + ROW_HEIGHT / 2 - lh / 2;
440
+ return applyLayoutMinSize({ ...node, position: { x: SP_PAD + colOffset, y: SP_PAD + rowOffset } });
377
441
  });
378
442
  const positionedBoundaries = repositionBoundaryEvents(boundaryEvents, positionedChildren);
379
443
  return {
@@ -406,8 +470,7 @@ function layoutPool(pool, lanes, content, allEdges) {
406
470
  height: h
407
471
  };
408
472
  }
409
- const lanePositionsDistinct = lanes.some((l) => Math.abs(l.position.y) > 10);
410
- const sortedLanes = lanePositionsDistinct ? [...lanes].sort((a, b) => a.position.y - b.position.y) : [...lanes];
473
+ const sortedLanes = [...lanes].sort((a, b) => a.position.y - b.position.y);
411
474
  const hasLanes = sortedLanes.length > 0;
412
475
  const laneIdSet = new Set(sortedLanes.map((l) => l.id));
413
476
  const nodeLaneId = /* @__PURE__ */ new Map();
@@ -456,7 +519,7 @@ function layoutPool(pool, lanes, content, allEdges) {
456
519
  for (let c = 0; c <= maxCol; c++) colW.set(c, 0);
457
520
  for (const node of mainContent) {
458
521
  const c = columns.get(node.id) ?? 0;
459
- colW.set(c, Math.max(colW.get(c) ?? 0, nW(node)));
522
+ colW.set(c, Math.max(colW.get(c) ?? 0, layoutW(node)));
460
523
  }
461
524
  const colX = /* @__PURE__ */ new Map();
462
525
  let cumX = 0;
@@ -483,14 +546,16 @@ function layoutPool(pool, lanes, content, allEdges) {
483
546
  const laneId = nodeLaneId.get(node.id) ?? "_pool_";
484
547
  const stat = laneStats.get(laneId);
485
548
  const lYOff = laneY.get(laneId) ?? 0;
486
- const colOffset = (colX.get(c) ?? 0) + (colW.get(c) ?? 120) / 2 - nW(node) / 2;
487
- const rowOffset = (r - stat.minRow) * (ROW_HEIGHT + ROW_GAP) + ROW_HEIGHT / 2 - nH(node) / 2;
549
+ const lw = layoutW(node);
550
+ const lh = layoutH(node);
551
+ const colOffset = (colX.get(c) ?? 0) + (colW.get(c) ?? 120) / 2 - lw / 2;
552
+ const rowOffset = (r - stat.minRow) * (ROW_HEIGHT + ROW_GAP) + ROW_HEIGHT / 2 - lh / 2;
488
553
  const contentH_stat = stat.rowCount * ROW_HEIGHT + Math.max(0, stat.rowCount - 1) * ROW_GAP;
489
554
  const vertTopOffset = Math.max(LANE_V_PAD, (stat.height - contentH_stat) / 2);
490
555
  const isLaneChild = hasLanes && !!node.parentId && node.parentId !== pool.id;
491
556
  const x = isLaneChild ? LANE_LABEL_W + LANE_H_PAD + colOffset : POOL_H_PAD + colOffset;
492
557
  const y = isLaneChild ? vertTopOffset + rowOffset : lYOff + vertTopOffset + rowOffset;
493
- return { ...node, position: { x, y } };
558
+ return applyLayoutMinSize({ ...node, position: { x, y } });
494
559
  });
495
560
  const NODE_MIN_GAP = 24;
496
561
  const resolvedContent = [...positionedContent];
@@ -499,13 +564,13 @@ function layoutPool(pool, lanes, content, allEdges) {
499
564
  for (let k = 1; k < laneNodeIndices.length; k++) {
500
565
  const prev = resolvedContent[laneNodeIndices[k - 1].i];
501
566
  const curr = resolvedContent[laneNodeIndices[k].i];
502
- const prevBottom = prev.position.y + nH(prev);
567
+ const prevBottom = prev.position.y + layoutH(prev);
503
568
  const currTop = curr.position.y;
504
569
  const prevTop = prev.position.y;
505
- const currBottom = curr.position.y + nH(curr);
570
+ const currBottom = curr.position.y + layoutH(curr);
506
571
  const yOverlap = prevBottom + NODE_MIN_GAP > currTop && currBottom + NODE_MIN_GAP > prevTop;
507
572
  if (!yOverlap) continue;
508
- const prevRight = prev.position.x + nW(prev);
573
+ const prevRight = prev.position.x + layoutW(prev);
509
574
  if (prevRight + NODE_MIN_GAP > curr.position.x) {
510
575
  resolvedContent[laneNodeIndices[k].i] = {
511
576
  ...curr,
@@ -542,14 +607,38 @@ function absolutePos(nodeId, byId, cache) {
542
607
  cache.set(nodeId, abs);
543
608
  return abs;
544
609
  }
545
- function laneOf(node, laneIds) {
546
- return node.parentId && laneIds.has(node.parentId) ? node.parentId : void 0;
610
+ function findAncestorNodeId(node, candidateIds, byId) {
611
+ let current = node;
612
+ while (current?.parentId) {
613
+ if (candidateIds.has(current.parentId)) return current.parentId;
614
+ current = byId.get(current.parentId);
615
+ }
616
+ return void 0;
617
+ }
618
+ function laneOf(node, laneIds, byId) {
619
+ return findAncestorNodeId(node, laneIds, byId);
620
+ }
621
+ function poolOf(node, poolIds, byId) {
622
+ if (poolIds.has(node.id)) return node.id;
623
+ return findAncestorNodeId(node, poolIds, byId);
624
+ }
625
+ function nodeRect(node, byId, cache) {
626
+ const pos = absolutePos(node.id, byId, cache);
627
+ return { x: pos.x, y: pos.y, width: nW(node), height: nH(node) };
628
+ }
629
+ function rectContainsRect(outer, inner) {
630
+ return inner.x >= outer.x && inner.y >= outer.y && inner.x + inner.width <= outer.x + outer.width && inner.y + inner.height <= outer.y + outer.height;
547
631
  }
548
632
  function gapMidX(sAbs, sW, tAbs, tW) {
549
633
  const leftRightEdge = Math.min(sAbs.x + sW, tAbs.x + tW);
550
634
  const rightLeftEdge = Math.max(sAbs.x, tAbs.x);
551
635
  return leftRightEdge < rightLeftEdge ? (leftRightEdge + rightLeftEdge) / 2 : sAbs.x + sW / 2;
552
636
  }
637
+ function routeMidX(sAbs, sW, tAbs, tW) {
638
+ const leftEdge = Math.min(sAbs.x + sW, tAbs.x + tW);
639
+ const rightEdge = Math.max(sAbs.x, tAbs.x);
640
+ return leftEdge < rightEdge ? leftEdge + (rightEdge - leftEdge) * 0.35 : sAbs.x + sW / 2;
641
+ }
553
642
  var SAME_ROW_THRESHOLD = 15;
554
643
  function routeEdges(edges, layoutNodes, backEdgeIds, laneIds, poolIds) {
555
644
  const byId = new Map(layoutNodes.map((n) => [n.id, n]));
@@ -574,18 +663,9 @@ function routeEdges(edges, layoutNodes, backEdgeIds, laneIds, poolIds) {
574
663
  const tCX = tAbs.x + tW / 2;
575
664
  const sCY = sAbs.y + sH / 2;
576
665
  const tCY = tAbs.y + tH / 2;
577
- const getPool = (nodeId) => {
578
- const node = byId.get(nodeId);
579
- if (!node) return null;
580
- if (poolIds.has(nodeId)) return nodeId;
581
- if (node.parentId && poolIds.has(node.parentId)) return node.parentId;
582
- if (node.parentId) {
583
- const gp = byId.get(node.parentId)?.parentId ?? null;
584
- if (gp && poolIds.has(gp)) return gp;
585
- }
586
- return node.parentId ?? null;
587
- };
588
- if (getPool(edge.source) !== getPool(edge.target)) {
666
+ const srcPool = poolOf(src, poolIds, byId) ?? null;
667
+ const tgtPool = poolOf(tgt, poolIds, byId) ?? null;
668
+ if (srcPool !== tgtPool) {
589
669
  const d = { ...edge.data };
590
670
  delete d.routingPoints;
591
671
  return { ...edge, data: d };
@@ -594,14 +674,16 @@ function routeEdges(edges, layoutNodes, backEdgeIds, laneIds, poolIds) {
594
674
  if (backEdgeIds.has(edge.id)) {
595
675
  const topY = Math.min(sAbs.y, tAbs.y) - BACK_EDGE_CLEARANCE;
596
676
  routingPoints = [
597
- { x: sCX, y: sAbs.y },
598
- { x: sCX, y: topY },
599
- { x: tCX, y: topY },
600
- { x: tCX, y: tAbs.y + tH }
677
+ { x: sAbs.x + sW, y: sCY },
678
+ { x: sAbs.x + sW + EDGE_ROUTE_PAD, y: sCY },
679
+ { x: sAbs.x + sW + EDGE_ROUTE_PAD, y: topY },
680
+ { x: tAbs.x - EDGE_ROUTE_PAD, y: topY },
681
+ { x: tAbs.x - EDGE_ROUTE_PAD, y: tCY },
682
+ { x: tAbs.x, y: tCY }
601
683
  ];
602
- } else if (laneOf(src, laneIds) !== laneOf(tgt, laneIds)) {
603
- const srcLane = byId.get(src.parentId ?? "");
604
- const tgtLane = byId.get(tgt.parentId ?? "");
684
+ } else if (laneOf(src, laneIds, byId) !== laneOf(tgt, laneIds, byId)) {
685
+ const srcLane = byId.get(laneOf(src, laneIds, byId) ?? "");
686
+ const tgtLane = byId.get(laneOf(tgt, laneIds, byId) ?? "");
605
687
  if (srcLane && tgtLane && laneIds.has(srcLane.id) && laneIds.has(tgtLane.id)) {
606
688
  const goingDown = tAbs.y > sAbs.y;
607
689
  const sharedX = gapMidX(sAbs, sW, tAbs, tW);
@@ -609,8 +691,8 @@ function routeEdges(edges, layoutNodes, backEdgeIds, laneIds, poolIds) {
609
691
  const tgtLaneIdx = sortedLanes.findIndex((l) => l.id === tgtLane.id);
610
692
  const pts = [];
611
693
  if (goingDown) {
612
- pts.push({ x: sCX, y: sAbs.y + sH });
613
- pts.push({ x: sharedX, y: sAbs.y + sH });
694
+ pts.push({ x: sAbs.x + sW, y: sCY });
695
+ pts.push({ x: sharedX, y: sCY });
614
696
  const fromIdx = Math.min(srcLaneIdx, tgtLaneIdx);
615
697
  const toIdx = Math.max(srcLaneIdx, tgtLaneIdx);
616
698
  for (let i = fromIdx; i < toIdx; i++) {
@@ -619,11 +701,12 @@ function routeEdges(edges, layoutNodes, backEdgeIds, laneIds, poolIds) {
619
701
  pts.push({ x: sharedX, y: laneBot });
620
702
  }
621
703
  const lastY = pts[pts.length - 1].y;
622
- pts.push({ x: tCX, y: lastY });
623
- pts.push({ x: tCX, y: tAbs.y + tH });
704
+ pts.push({ x: tAbs.x - EDGE_ROUTE_PAD, y: lastY });
705
+ pts.push({ x: tAbs.x - EDGE_ROUTE_PAD, y: tCY });
706
+ pts.push({ x: tAbs.x, y: tCY });
624
707
  } else {
625
- pts.push({ x: sCX, y: sAbs.y });
626
- pts.push({ x: sharedX, y: sAbs.y });
708
+ pts.push({ x: sAbs.x + sW, y: sCY });
709
+ pts.push({ x: sharedX, y: sCY });
627
710
  const fromIdx = Math.min(srcLaneIdx, tgtLaneIdx);
628
711
  const toIdx = Math.max(srcLaneIdx, tgtLaneIdx);
629
712
  for (let i = toIdx; i > fromIdx; i--) {
@@ -632,17 +715,18 @@ function routeEdges(edges, layoutNodes, backEdgeIds, laneIds, poolIds) {
632
715
  pts.push({ x: sharedX, y: laneTop });
633
716
  }
634
717
  const lastY = pts[pts.length - 1].y;
635
- pts.push({ x: tCX, y: lastY });
636
- pts.push({ x: tCX, y: tAbs.y });
718
+ pts.push({ x: tAbs.x - EDGE_ROUTE_PAD, y: lastY });
719
+ pts.push({ x: tAbs.x - EDGE_ROUTE_PAD, y: tCY });
720
+ pts.push({ x: tAbs.x, y: tCY });
637
721
  }
638
722
  routingPoints = pts;
639
723
  } else {
640
724
  const sharedX = gapMidX(sAbs, sW, tAbs, tW);
641
725
  routingPoints = [
642
- { x: sCX, y: sCY },
726
+ { x: sAbs.x + sW, y: sCY },
643
727
  { x: sharedX, y: sCY },
644
728
  { x: sharedX, y: tCY },
645
- { x: tCX, y: tCY }
729
+ { x: tAbs.x, y: tCY }
646
730
  ];
647
731
  }
648
732
  } else if (Math.abs(sCY - tCY) <= SAME_ROW_THRESHOLD) {
@@ -654,19 +738,25 @@ function routeEdges(edges, layoutNodes, backEdgeIds, laneIds, poolIds) {
654
738
  const exitsTop = handle.includes("top");
655
739
  const exitsBottom = handle.includes("bottom");
656
740
  if (exitsTop || exitsBottom) {
741
+ const exitY = exitsTop ? sAbs.y : sAbs.y + sH;
742
+ const entryY = exitsTop ? tAbs.y + tH : tAbs.y;
743
+ const corridorY = exitsTop ? Math.min(exitY, entryY) - EDGE_ROUTE_PAD : Math.max(exitY, entryY) + EDGE_ROUTE_PAD;
657
744
  routingPoints = [
658
- { x: sCX, y: exitsTop ? sAbs.y : sAbs.y + sH },
659
- { x: sCX, y: tCY },
660
- { x: tCX, y: tCY },
661
- { x: tCX, y: exitsTop ? tAbs.y + tH : tAbs.y }
745
+ { x: sCX, y: exitY },
746
+ { x: sCX, y: corridorY },
747
+ { x: tCX, y: corridorY },
748
+ { x: tCX, y: entryY }
662
749
  ];
663
750
  } else {
664
- const midX = gapMidX(sAbs, sW, tAbs, tW);
751
+ const midX = routeMidX(sAbs, sW, tAbs, tW);
752
+ const exitX = sAbs.x + sW;
753
+ const entryX = tAbs.x;
754
+ const corridorX = Math.max(midX, exitX + EDGE_ROUTE_PAD);
665
755
  routingPoints = [
666
- { x: sAbs.x + sW, y: sCY },
667
- { x: midX, y: sCY },
668
- { x: midX, y: tCY },
669
- { x: tAbs.x, y: tCY }
756
+ { x: exitX, y: sCY },
757
+ { x: corridorX, y: sCY },
758
+ { x: corridorX, y: tCY },
759
+ { x: entryX, y: tCY }
670
760
  ];
671
761
  }
672
762
  }
@@ -675,16 +765,19 @@ function routeEdges(edges, layoutNodes, backEdgeIds, laneIds, poolIds) {
675
765
  }
676
766
  var ARTIFACT_ABOVE_GAP = 16;
677
767
  var ARTIFACT_H_SPACING = 12;
678
- function positionArtifacts(artifacts, resultNodes, edges) {
768
+ function positionArtifacts(artifacts, resultNodes, edges, originalNodes) {
679
769
  if (artifacts.length === 0) return [];
680
770
  const byId = new Map(resultNodes.map((n) => [n.id, n]));
681
771
  const cache = /* @__PURE__ */ new Map();
682
772
  const absPos = (id) => absolutePos(id, byId, cache);
773
+ const originalById = new Map(originalNodes.map((n) => [n.id, n]));
774
+ const originalCache = /* @__PURE__ */ new Map();
683
775
  const artifactsByNode = /* @__PURE__ */ new Map();
684
776
  const ungrouped = [];
777
+ const groups = [];
685
778
  for (const artifact of artifacts) {
686
779
  if (artifact.data.elementType === "Group") {
687
- ungrouped.push(artifact);
780
+ groups.push(artifact);
688
781
  continue;
689
782
  }
690
783
  const connEdge = edges.find((e) => {
@@ -722,6 +815,58 @@ function positionArtifacts(artifacts, resultNodes, edges) {
722
815
  desiredAbsX += nW(artifact) + ARTIFACT_H_SPACING;
723
816
  }
724
817
  }
818
+ const nonArtifactOriginalNodes = originalNodes.filter(
819
+ (node) => !LAYOUT_ARTIFACT_TYPES.has(node.data.elementType)
820
+ );
821
+ for (const group of groups) {
822
+ const originalGroup = originalById.get(group.id);
823
+ if (!originalGroup) {
824
+ positioned.push(group);
825
+ continue;
826
+ }
827
+ const groupRect = nodeRect(originalGroup, originalById, originalCache);
828
+ const containedOriginalIds = nonArtifactOriginalNodes.filter((node) => node.id !== group.id).filter((node) => {
829
+ if (node.parentId !== group.parentId) return false;
830
+ return rectContainsRect(groupRect, nodeRect(node, originalById, originalCache));
831
+ }).map((node) => node.id);
832
+ if (containedOriginalIds.length === 0) {
833
+ positioned.push(group);
834
+ continue;
835
+ }
836
+ const containedLaidOut = containedOriginalIds.map((id) => byId.get(id)).filter((node) => !!node);
837
+ if (containedLaidOut.length === 0) {
838
+ positioned.push(group);
839
+ continue;
840
+ }
841
+ const GROUP_PAD_X = 24;
842
+ const GROUP_PAD_Y = 20;
843
+ const bounds = containedLaidOut.reduce(
844
+ (acc, node) => {
845
+ const rect = nodeRect(node, byId, cache);
846
+ return {
847
+ left: Math.min(acc.left, rect.x),
848
+ top: Math.min(acc.top, rect.y),
849
+ right: Math.max(acc.right, rect.x + rect.width),
850
+ bottom: Math.max(acc.bottom, rect.y + rect.height)
851
+ };
852
+ },
853
+ { left: Number.POSITIVE_INFINITY, top: Number.POSITIVE_INFINITY, right: Number.NEGATIVE_INFINITY, bottom: Number.NEGATIVE_INFINITY }
854
+ );
855
+ const parentAbsP = group.parentId ? absPos(group.parentId) : { x: 0, y: 0 };
856
+ positioned.push({
857
+ ...group,
858
+ position: {
859
+ x: bounds.left - GROUP_PAD_X - parentAbsP.x,
860
+ y: bounds.top - GROUP_PAD_Y - parentAbsP.y
861
+ },
862
+ width: bounds.right - bounds.left + GROUP_PAD_X * 2,
863
+ height: bounds.bottom - bounds.top + GROUP_PAD_Y * 2,
864
+ measured: {
865
+ width: bounds.right - bounds.left + GROUP_PAD_X * 2,
866
+ height: bounds.bottom - bounds.top + GROUP_PAD_Y * 2
867
+ }
868
+ });
869
+ }
725
870
  return positioned;
726
871
  }
727
872
  async function bpmnCustomLayout(nodes, edges) {
@@ -756,7 +901,7 @@ async function bpmnCustomLayout(nodes, edges) {
756
901
  if (pools.length === 0) {
757
902
  const { bpmnElkLayout: bpmnElkLayout2 } = await import('../elk-QT7H4252.js');
758
903
  const elkResult = await bpmnElkLayout2(nodes.filter((n) => !LAYOUT_ARTIFACT_TYPES.has(n.data.elementType)), edges);
759
- const posArtifacts = positionArtifacts(artifacts, elkResult.nodes, edges);
904
+ const posArtifacts = positionArtifacts(artifacts, elkResult.nodes, edges, nodes);
760
905
  return { nodes: [...elkResult.nodes, ...posArtifacts], edges: elkResult.edges };
761
906
  }
762
907
  const poolIds = new Set(pools.map((p) => p.id));
@@ -800,8 +945,9 @@ async function bpmnCustomLayout(nodes, edges) {
800
945
  const layoutted = new Set(resultNodes.map((n) => n.id));
801
946
  const freeNodes = workingMainNodes.filter((n) => !layoutted.has(n.id));
802
947
  if (freeNodes.length > 0) {
948
+ const freeNodeIds = new Set(freeNodes.map((n) => n.id));
803
949
  const freeEdges = edges.filter(
804
- (e) => freeNodes.some((n) => n.id === e.source || n.id === e.target)
950
+ (e) => freeNodeIds.has(e.source) && freeNodeIds.has(e.target)
805
951
  );
806
952
  try {
807
953
  const { bpmnElkLayout: bpmnElkLayout2 } = await import('../elk-QT7H4252.js');
@@ -825,7 +971,7 @@ async function bpmnCustomLayout(nodes, edges) {
825
971
  }
826
972
  }
827
973
  const routedEdges = routeEdges(edges, resultNodes, allBackEdgeIds, allLaneIds, poolIds);
828
- const positionedArtifacts = positionArtifacts(artifacts, resultNodes, edges);
974
+ const positionedArtifacts = positionArtifacts(artifacts, resultNodes, edges, nodes);
829
975
  return {
830
976
  nodes: [...resultNodes, ...positionedArtifacts],
831
977
  edges: routedEdges