@aranzatech/diagrams-bpmn 0.2.15 → 0.3.1

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 (75) hide show
  1. package/README.md +34 -4
  2. package/dist/{catalog-xOMF2ifW.d.cts → catalog-DAGDhO-D.d.cts} +1 -1
  3. package/dist/{catalog-CK3_4cOb.d.ts → catalog-Q1QmKLDD.d.ts} +1 -1
  4. package/dist/{chunk-YUE5EM3W.js → chunk-334WN4JZ.js} +276 -107
  5. package/dist/chunk-334WN4JZ.js.map +1 -0
  6. package/dist/chunk-77L6O76M.js +3 -0
  7. package/dist/chunk-77L6O76M.js.map +1 -0
  8. package/dist/{chunk-QSMP34CT.js → chunk-CPFUQM6H.js} +80 -44
  9. package/dist/chunk-CPFUQM6H.js.map +1 -0
  10. package/dist/{chunk-XMVV7FRZ.js → chunk-FFWJA5BV.js} +3 -3
  11. package/dist/{chunk-XMVV7FRZ.js.map → chunk-FFWJA5BV.js.map} +1 -1
  12. package/dist/{chunk-FBTGIYZS.js → chunk-JEGYVEJO.js} +80 -3
  13. package/dist/{chunk-FBTGIYZS.js.map → chunk-JEGYVEJO.js.map} +1 -1
  14. package/dist/chunk-TB6V4S5N.js +104 -0
  15. package/dist/chunk-TB6V4S5N.js.map +1 -0
  16. package/dist/{chunk-HOWK3ZOO.js → chunk-YAYZW45I.js} +379 -16
  17. package/dist/chunk-YAYZW45I.js.map +1 -0
  18. package/dist/edges/index.cjs +78 -42
  19. package/dist/edges/index.cjs.map +1 -1
  20. package/dist/edges/index.js +1 -1
  21. package/dist/elements/index.cjs +78 -0
  22. package/dist/elements/index.cjs.map +1 -1
  23. package/dist/elements/index.d.cts +24 -5
  24. package/dist/elements/index.d.ts +24 -5
  25. package/dist/elements/index.js +1 -1
  26. package/dist/elk-QT7H4252.js +6 -0
  27. package/dist/elk-QT7H4252.js.map +1 -0
  28. package/dist/extensions/index.cjs +108 -0
  29. package/dist/extensions/index.cjs.map +1 -0
  30. package/dist/extensions/index.d.cts +145 -0
  31. package/dist/extensions/index.d.ts +145 -0
  32. package/dist/extensions/index.js +4 -0
  33. package/dist/extensions/index.js.map +1 -0
  34. package/dist/index.cjs +922 -160
  35. package/dist/index.cjs.map +1 -1
  36. package/dist/index.d.cts +7 -5
  37. package/dist/index.d.ts +7 -5
  38. package/dist/index.js +6 -4
  39. package/dist/index.js.map +1 -1
  40. package/dist/layout/index.cjs +366 -90
  41. package/dist/layout/index.cjs.map +1 -1
  42. package/dist/layout/index.d.cts +4 -3
  43. package/dist/layout/index.d.ts +4 -3
  44. package/dist/layout/index.js +358 -92
  45. package/dist/layout/index.js.map +1 -1
  46. package/dist/modeling/index.cjs +387 -13
  47. package/dist/modeling/index.cjs.map +1 -1
  48. package/dist/modeling/index.d.cts +62 -4
  49. package/dist/modeling/index.d.ts +62 -4
  50. package/dist/modeling/index.js +1 -1
  51. package/dist/types-BX_o95GC.d.cts +40 -0
  52. package/dist/{types-y-ZbX-ff.d.ts → types-BYN4Zuee.d.cts} +15 -1
  53. package/dist/{types-y-ZbX-ff.d.cts → types-BYN4Zuee.d.ts} +15 -1
  54. package/dist/{types-jIDz306Y.d.cts → types-CggktCqr.d.cts} +4 -1
  55. package/dist/types-D7zel9dq.d.ts +40 -0
  56. package/dist/{types-DG5yPKld.d.ts → types-DmDODKlh.d.ts} +4 -1
  57. package/dist/validation/index.cjs +81 -125
  58. package/dist/validation/index.cjs.map +1 -1
  59. package/dist/validation/index.d.cts +22 -5
  60. package/dist/validation/index.d.ts +22 -5
  61. package/dist/validation/index.js +82 -126
  62. package/dist/validation/index.js.map +1 -1
  63. package/dist/xml/index.cjs +319 -49
  64. package/dist/xml/index.cjs.map +1 -1
  65. package/dist/xml/index.d.cts +5 -3
  66. package/dist/xml/index.d.ts +5 -3
  67. package/dist/xml/index.js +2 -1
  68. package/package.json +6 -1
  69. package/dist/chunk-HOWK3ZOO.js.map +0 -1
  70. package/dist/chunk-QSMP34CT.js.map +0 -1
  71. package/dist/chunk-YUE5EM3W.js.map +0 -1
  72. package/dist/elk-FSFIEL6O.js +0 -6
  73. package/dist/elk-FSFIEL6O.js.map +0 -1
  74. package/dist/guards-C70uIY_O.d.cts +0 -16
  75. package/dist/guards-foB6XIfZ.d.ts +0 -16
@@ -1,12 +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-jIDz306Y.cjs';
3
+ import { d as BpmnRFNode, c as BpmnRFEdge } from '../types-CggktCqr.cjs';
4
4
  import { BpmnDiagramState } from '../modeling/index.cjs';
5
5
  import '@xyflow/react';
6
- import '../types-y-ZbX-ff.cjs';
6
+ import '../types-BYN4Zuee.cjs';
7
+ import '../types-BX_o95GC.cjs';
7
8
  import '@aranzatech/diagrams-core';
8
9
  import '@aranzatech/diagrams-core/serialization';
9
- import '../catalog-xOMF2ifW.cjs';
10
+ import '../catalog-DAGDhO-D.cjs';
10
11
 
11
12
  /**
12
13
  * ELK-based auto-layout for BPMN diagrams.
@@ -1,12 +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-DG5yPKld.js';
3
+ import { d as BpmnRFNode, c as BpmnRFEdge } from '../types-DmDODKlh.js';
4
4
  import { BpmnDiagramState } from '../modeling/index.js';
5
5
  import '@xyflow/react';
6
- import '../types-y-ZbX-ff.js';
6
+ import '../types-BYN4Zuee.js';
7
+ import '../types-D7zel9dq.js';
7
8
  import '@aranzatech/diagrams-core';
8
9
  import '@aranzatech/diagrams-core/serialization';
9
- import '../catalog-CK3_4cOb.js';
10
+ import '../catalog-Q1QmKLDD.js';
10
11
 
11
12
  /**
12
13
  * ELK-based auto-layout for BPMN diagrams.
@@ -1,5 +1,5 @@
1
- export { bpmnElkLayout } from '../chunk-XMVV7FRZ.js';
2
- import { getBpmnNodeSize } from '../chunk-HOWK3ZOO.js';
1
+ export { bpmnElkLayout } from '../chunk-FFWJA5BV.js';
2
+ import { getBpmnNodeSize } from '../chunk-YAYZW45I.js';
3
3
  import '../chunk-RLAJNRF2.js';
4
4
  import '../chunk-L5Z22RLX.js';
5
5
  import { dagreLayout, applyLayoutResultToDiagram } from '@aranzatech/diagrams-core/layout';
@@ -249,63 +249,197 @@ function assignRows(nodes, forwardEdges, columns, gatewayPairs) {
249
249
 
250
250
  // src/layout/bpmn-custom-layout.ts
251
251
  var LANE_LABEL_W = 28;
252
- var LANE_H_PAD = 20;
253
- var COL_GAP = 80;
254
- var ROW_HEIGHT = 80;
255
- var ROW_GAP = 60;
256
- var LANE_V_PAD = 50;
257
- var POOL_H_PAD = 60;
258
- var POOL_V_GAP = 50;
259
- var LANE_MIN_H = 160;
260
- var POOL_MIN_W = 720;
261
- var POOL_INNER_PAD = 8;
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;
261
+ var POOL_INNER_PAD = 10;
262
+ var BACK_EDGE_CLEARANCE = 70;
263
+ var LAYOUT_ARTIFACT_TYPES = /* @__PURE__ */ new Set([
264
+ "DataObject",
265
+ "DataObjectReference",
266
+ "DataInput",
267
+ "DataOutput",
268
+ "DataStore",
269
+ "DataStoreReference",
270
+ "Annotation",
271
+ "Group"
272
+ ]);
273
+ var COLLAPSED_SUBPROCESS_TYPES = /* @__PURE__ */ new Set([
274
+ "SubProcess",
275
+ "Transaction",
276
+ "EventSubProcess",
277
+ "AdHocSubProcess"
278
+ ]);
262
279
  function nW(node) {
263
280
  return node.width ?? node.measured?.width ?? 120;
264
281
  }
265
282
  function nH(node) {
266
283
  return node.height ?? node.measured?.height ?? 60;
267
284
  }
285
+ var BOUNDARY_SPACING = 10;
286
+ function repositionBoundaryEvents(boundaryEvents, positionedContent) {
287
+ if (boundaryEvents.length === 0) return [];
288
+ const hostById = new Map(positionedContent.map((n) => [n.id, n]));
289
+ const byHost = /* @__PURE__ */ new Map();
290
+ for (const be of boundaryEvents) {
291
+ const hostId = be.data.attachedToRef;
292
+ if (!hostId) continue;
293
+ if (!byHost.has(hostId)) byHost.set(hostId, []);
294
+ byHost.get(hostId).push(be);
295
+ }
296
+ const result = [];
297
+ for (const be of boundaryEvents) {
298
+ const hostId = be.data.attachedToRef;
299
+ if (!hostId) {
300
+ result.push(be);
301
+ continue;
302
+ }
303
+ const host = hostById.get(hostId);
304
+ if (!host) {
305
+ result.push(be);
306
+ continue;
307
+ }
308
+ const hostGroup = byHost.get(hostId);
309
+ const siblingIdx = hostGroup.findIndex((n) => n.id === be.id);
310
+ const hostW = nW(host);
311
+ const hostH = nH(host);
312
+ const beH = nH(be);
313
+ const totalGroupW = hostGroup.reduce((s, b) => s + nW(b), 0) + (hostGroup.length - 1) * BOUNDARY_SPACING;
314
+ const groupStartX = host.position.x + hostW / 2 - totalGroupW / 2;
315
+ const offsetX = hostGroup.slice(0, siblingIdx).reduce((s, b) => s + nW(b) + BOUNDARY_SPACING, 0);
316
+ result.push({
317
+ ...be,
318
+ position: {
319
+ x: groupStartX + offsetX,
320
+ y: host.position.y + hostH - beH / 2
321
+ }
322
+ });
323
+ }
324
+ return result;
325
+ }
326
+ var SP_PAD = 48;
327
+ function layoutSubProcess(children, edges) {
328
+ if (children.length === 0) {
329
+ return { children: [], width: 280, height: 160 };
330
+ }
331
+ const boundaryEvents = children.filter((n) => n.data.elementType === "BoundaryEvent");
332
+ const mainChildren = children.filter((n) => n.data.elementType !== "BoundaryEvent");
333
+ if (mainChildren.length === 0) {
334
+ return {
335
+ children: repositionBoundaryEvents(boundaryEvents, []),
336
+ width: 280,
337
+ height: 160
338
+ };
339
+ }
340
+ const contentIds = new Set(mainChildren.map((n) => n.id));
341
+ const seqEdges = extractSeqEdges(edges, contentIds);
342
+ const backIds = detectBackEdges([...contentIds], seqEdges);
343
+ const fwdEdges = seqEdges.filter((e) => !backIds.has(e.id));
344
+ const columns = assignColumns([...contentIds], fwdEdges);
345
+ const pairs = detectGatewayPairs(mainChildren, fwdEdges);
346
+ const rows = assignRows(mainChildren, fwdEdges, columns, pairs);
347
+ const maxCol = Math.max(0, ...[...columns.values()]);
348
+ const colW = /* @__PURE__ */ new Map();
349
+ for (let c = 0; c <= maxCol; c++) colW.set(c, 0);
350
+ for (const node of mainChildren) {
351
+ const c = columns.get(node.id) ?? 0;
352
+ colW.set(c, Math.max(colW.get(c) ?? 0, nW(node)));
353
+ }
354
+ const colX = /* @__PURE__ */ new Map();
355
+ let cumX = 0;
356
+ for (let c = 0; c <= maxCol; c++) {
357
+ colX.set(c, cumX);
358
+ cumX += (colW.get(c) ?? 120) + COL_GAP;
359
+ }
360
+ const contentW = cumX - COL_GAP;
361
+ const rowVals = [...rows.values()];
362
+ const minRow = Math.min(0, ...rowVals);
363
+ const maxRow = Math.max(0, ...rowVals);
364
+ const rowCount = maxRow - minRow + 1;
365
+ const contentH = rowCount * ROW_HEIGHT + Math.max(0, rowCount - 1) * ROW_GAP;
366
+ const spW = Math.max(280, SP_PAD * 2 + contentW);
367
+ const spH = Math.max(160, SP_PAD * 2 + contentH);
368
+ const positionedChildren = mainChildren.map((node) => {
369
+ const c = columns.get(node.id) ?? 0;
370
+ 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
+ };
377
+ });
378
+ const positionedBoundaries = repositionBoundaryEvents(boundaryEvents, positionedChildren);
379
+ return {
380
+ children: [...positionedChildren, ...positionedBoundaries],
381
+ width: spW,
382
+ height: spH
383
+ };
384
+ }
268
385
  function layoutPool(pool, lanes, content, allEdges) {
269
- if (content.length === 0) {
386
+ const boundaryEvents = content.filter((n) => n.data.elementType === "BoundaryEvent");
387
+ const mainContent = content.filter((n) => n.data.elementType !== "BoundaryEvent");
388
+ if (mainContent.length === 0) {
389
+ const positionedBoundaries2 = repositionBoundaryEvents(boundaryEvents, []);
270
390
  if (lanes.length === 0) {
271
- return { nodes: [], width: 240, height: 120 };
391
+ return { nodes: positionedBoundaries2, width: 300, height: 140 };
272
392
  }
273
393
  const laneH = LANE_MIN_H;
274
394
  const h = POOL_INNER_PAD * 2 + lanes.length * laneH + Math.max(0, lanes.length - 1) * POOL_INNER_PAD;
275
- const w = POOL_MIN_W;
276
395
  return {
277
- nodes: lanes.map((lane, i) => ({
278
- ...lane,
279
- position: { x: POOL_INNER_PAD, y: POOL_INNER_PAD + i * (laneH + POOL_INNER_PAD) },
280
- width: w - POOL_INNER_PAD * 2,
281
- height: laneH
282
- })),
283
- width: w,
396
+ nodes: [
397
+ ...positionedBoundaries2,
398
+ ...lanes.map((lane, i) => ({
399
+ ...lane,
400
+ position: { x: POOL_INNER_PAD, y: POOL_INNER_PAD + i * (laneH + POOL_INNER_PAD) },
401
+ width: POOL_MIN_W - POOL_INNER_PAD * 2,
402
+ height: laneH
403
+ }))
404
+ ],
405
+ width: POOL_MIN_W,
284
406
  height: h
285
407
  };
286
408
  }
287
- const contentIds = new Set(content.map((n) => n.id));
288
- const seqEdges = extractSeqEdges(allEdges, contentIds);
289
- const backIds = detectBackEdges([...contentIds], seqEdges);
290
- const fwdEdges = seqEdges.filter((e) => !backIds.has(e.id));
291
- const columns = assignColumns([...contentIds], fwdEdges);
292
- const pairs = detectGatewayPairs(content, fwdEdges);
293
- const rows = assignRows(content, fwdEdges, columns, pairs);
294
409
  const lanePositionsDistinct = lanes.some((l) => Math.abs(l.position.y) > 10);
295
410
  const sortedLanes = lanePositionsDistinct ? [...lanes].sort((a, b) => a.position.y - b.position.y) : [...lanes];
296
411
  const hasLanes = sortedLanes.length > 0;
412
+ const laneIdSet = new Set(sortedLanes.map((l) => l.id));
297
413
  const nodeLaneId = /* @__PURE__ */ new Map();
298
- for (const node of content) {
299
- if (hasLanes && node.parentId && node.parentId !== pool.id) {
300
- nodeLaneId.set(node.id, node.parentId);
301
- } else {
302
- nodeLaneId.set(node.id, "_pool_");
303
- }
414
+ for (const node of mainContent) {
415
+ const lId = hasLanes && node.parentId && laneIdSet.has(node.parentId) ? node.parentId : "_pool_";
416
+ nodeLaneId.set(node.id, lId);
417
+ }
418
+ const contentIds = new Set(mainContent.map((n) => n.id));
419
+ const seqEdges = extractSeqEdges(allEdges, contentIds);
420
+ const backIds = detectBackEdges([...contentIds], seqEdges);
421
+ const fwdEdges = seqEdges.filter((e) => !backIds.has(e.id));
422
+ const columns = assignColumns([...contentIds], fwdEdges);
423
+ const rows = /* @__PURE__ */ new Map();
424
+ const contentByLane = /* @__PURE__ */ new Map();
425
+ for (const node of mainContent) {
426
+ const lId = nodeLaneId.get(node.id) ?? "_pool_";
427
+ if (!contentByLane.has(lId)) contentByLane.set(lId, []);
428
+ contentByLane.get(lId).push(node);
429
+ }
430
+ for (const [, laneNodes] of contentByLane) {
431
+ const laneNodeIds = new Set(laneNodes.map((n) => n.id));
432
+ const intraEdges = fwdEdges.filter(
433
+ (e) => laneNodeIds.has(e.source) && laneNodeIds.has(e.target)
434
+ );
435
+ const lanePairs = detectGatewayPairs(laneNodes, intraEdges);
436
+ const laneRows = assignRows(laneNodes, intraEdges, columns, lanePairs);
437
+ for (const [id, row] of laneRows) rows.set(id, row);
304
438
  }
305
439
  const laneIds = hasLanes ? sortedLanes.map((l) => l.id) : ["_pool_"];
306
440
  const laneStats = /* @__PURE__ */ new Map();
307
441
  for (const laneId of laneIds) {
308
- const laneRows = content.filter((n) => nodeLaneId.get(n.id) === laneId).map((n) => rows.get(n.id) ?? 0);
442
+ const laneRows = mainContent.filter((n) => nodeLaneId.get(n.id) === laneId).map((n) => rows.get(n.id) ?? 0);
309
443
  if (laneRows.length === 0) {
310
444
  laneStats.set(laneId, { minRow: 0, maxRow: 0, rowCount: 1, height: LANE_MIN_H });
311
445
  } else {
@@ -320,7 +454,7 @@ function layoutPool(pool, lanes, content, allEdges) {
320
454
  const maxCol = Math.max(0, ...[...columns.values()]);
321
455
  const colW = /* @__PURE__ */ new Map();
322
456
  for (let c = 0; c <= maxCol; c++) colW.set(c, 0);
323
- for (const node of content) {
457
+ for (const node of mainContent) {
324
458
  const c = columns.get(node.id) ?? 0;
325
459
  colW.set(c, Math.max(colW.get(c) ?? 0, nW(node)));
326
460
  }
@@ -343,7 +477,7 @@ function layoutPool(pool, lanes, content, allEdges) {
343
477
  if (i < laneIds.length - 1) cumY += POOL_INNER_PAD;
344
478
  }
345
479
  const poolH = cumY + POOL_INNER_PAD;
346
- const positionedContent = content.map((node) => {
480
+ const positionedContent = mainContent.map((node) => {
347
481
  const c = columns.get(node.id) ?? 0;
348
482
  const r = rows.get(node.id) ?? 0;
349
483
  const laneId = nodeLaneId.get(node.id) ?? "_pool_";
@@ -351,14 +485,14 @@ function layoutPool(pool, lanes, content, allEdges) {
351
485
  const lYOff = laneY.get(laneId) ?? 0;
352
486
  const colOffset = (colX.get(c) ?? 0) + (colW.get(c) ?? 120) / 2 - nW(node) / 2;
353
487
  const rowOffset = (r - stat.minRow) * (ROW_HEIGHT + ROW_GAP) + ROW_HEIGHT / 2 - nH(node) / 2;
354
- const isLaneChild = hasLanes && !!node.parentId && node.parentId !== pool.id;
355
488
  const contentH_stat = stat.rowCount * ROW_HEIGHT + Math.max(0, stat.rowCount - 1) * ROW_GAP;
356
489
  const vertTopOffset = Math.max(LANE_V_PAD, (stat.height - contentH_stat) / 2);
490
+ const isLaneChild = hasLanes && !!node.parentId && node.parentId !== pool.id;
357
491
  const x = isLaneChild ? LANE_LABEL_W + LANE_H_PAD + colOffset : POOL_H_PAD + colOffset;
358
492
  const y = isLaneChild ? vertTopOffset + rowOffset : lYOff + vertTopOffset + rowOffset;
359
493
  return { ...node, position: { x, y } };
360
494
  });
361
- const NODE_MIN_GAP = 20;
495
+ const NODE_MIN_GAP = 24;
362
496
  const resolvedContent = [...positionedContent];
363
497
  for (const laneId of laneIds) {
364
498
  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);
@@ -375,30 +509,24 @@ function layoutPool(pool, lanes, content, allEdges) {
375
509
  if (prevRight + NODE_MIN_GAP > curr.position.x) {
376
510
  resolvedContent[laneNodeIndices[k].i] = {
377
511
  ...curr,
378
- position: {
379
- x: prevRight + NODE_MIN_GAP,
380
- y: curr.position.y
381
- }
512
+ position: { x: prevRight + NODE_MIN_GAP, y: curr.position.y }
382
513
  };
383
514
  }
384
515
  }
385
516
  }
517
+ const positionedBoundaries = repositionBoundaryEvents(boundaryEvents, resolvedContent);
386
518
  const positionedLanes = hasLanes ? sortedLanes.map((lane) => ({
387
519
  ...lane,
388
- // x: after pool label strip + left inner padding
389
- // y: laneY already includes top POOL_INNER_PAD offset
390
520
  position: { x: POOL_INNER_PAD, y: laneY.get(lane.id) ?? POOL_INNER_PAD },
391
521
  width: laneW,
392
522
  height: laneStats.get(lane.id)?.height ?? LANE_MIN_H
393
523
  })) : [];
394
524
  return {
395
- nodes: [...resolvedContent, ...positionedLanes],
525
+ nodes: [...resolvedContent, ...positionedBoundaries, ...positionedLanes],
396
526
  width: poolW,
397
527
  height: poolH
398
528
  };
399
529
  }
400
- var BACK_EDGE_CLEARANCE = 50;
401
- var SAME_ROW_THRESHOLD = 15;
402
530
  function absolutePos(nodeId, byId, cache) {
403
531
  const cached = cache.get(nodeId);
404
532
  if (cached) return cached;
@@ -417,10 +545,17 @@ function absolutePos(nodeId, byId, cache) {
417
545
  function laneOf(node, laneIds) {
418
546
  return node.parentId && laneIds.has(node.parentId) ? node.parentId : void 0;
419
547
  }
548
+ function gapMidX(sAbs, sW, tAbs, tW) {
549
+ const leftRightEdge = Math.min(sAbs.x + sW, tAbs.x + tW);
550
+ const rightLeftEdge = Math.max(sAbs.x, tAbs.x);
551
+ return leftRightEdge < rightLeftEdge ? (leftRightEdge + rightLeftEdge) / 2 : sAbs.x + sW / 2;
552
+ }
553
+ var SAME_ROW_THRESHOLD = 15;
420
554
  function routeEdges(edges, layoutNodes, backEdgeIds, laneIds, poolIds) {
421
555
  const byId = new Map(layoutNodes.map((n) => [n.id, n]));
422
556
  const cache = /* @__PURE__ */ new Map();
423
557
  const abs = (id) => absolutePos(id, byId, cache);
558
+ const sortedLanes = [...laneIds].map((id) => byId.get(id)).filter((n) => !!n).sort((a, b) => abs(a.id).y - abs(b.id).y);
424
559
  return edges.map((edge) => {
425
560
  const edgeType = edge.data?.edgeType ?? edge.type;
426
561
  if (edgeType !== "sequenceFlow") {
@@ -435,11 +570,22 @@ function routeEdges(edges, layoutNodes, backEdgeIds, laneIds, poolIds) {
435
570
  const tAbs = abs(tgt.id);
436
571
  const sW = nW(src), sH = nH(src);
437
572
  const tW = nW(tgt), tH = nH(tgt);
438
- const sCX = sAbs.x + sW / 2, sCY = sAbs.y + sH / 2;
439
- const tCX = tAbs.x + tW / 2, tCY = tAbs.y + tH / 2;
440
- const srcPool = poolIds.has(src.parentId ?? "") ? src.parentId : poolIds.has(byId.get(src.parentId ?? "")?.parentId ?? "") ? byId.get(src.parentId ?? "")?.parentId : src.parentId;
441
- const tgtPool = poolIds.has(tgt.parentId ?? "") ? tgt.parentId : poolIds.has(byId.get(tgt.parentId ?? "")?.parentId ?? "") ? byId.get(tgt.parentId ?? "")?.parentId : tgt.parentId;
442
- if (srcPool !== tgtPool) {
573
+ const sCX = sAbs.x + sW / 2;
574
+ const tCX = tAbs.x + tW / 2;
575
+ const sCY = sAbs.y + sH / 2;
576
+ 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)) {
443
589
  const d = { ...edge.data };
444
590
  delete d.routingPoints;
445
591
  return { ...edge, data: d };
@@ -449,33 +595,49 @@ function routeEdges(edges, layoutNodes, backEdgeIds, laneIds, poolIds) {
449
595
  const topY = Math.min(sAbs.y, tAbs.y) - BACK_EDGE_CLEARANCE;
450
596
  routingPoints = [
451
597
  { x: sCX, y: sAbs.y },
452
- // [0] discarded
453
598
  { x: sCX, y: topY },
454
- // [1] go up
455
599
  { x: tCX, y: topY },
456
- // [2] go left/right
457
- { x: tCX, y: tAbs.y }
458
- // [3] discarded
600
+ { x: tCX, y: tAbs.y + tH }
459
601
  ];
460
602
  } else if (laneOf(src, laneIds) !== laneOf(tgt, laneIds)) {
461
- const goingDown = tAbs.y > sAbs.y;
462
- const sharedX = Math.abs(sCX - tCX) < 10 ? sCX : (sCX + tCX) / 2;
463
603
  const srcLane = byId.get(src.parentId ?? "");
464
604
  const tgtLane = byId.get(tgt.parentId ?? "");
465
605
  if (srcLane && tgtLane && laneIds.has(srcLane.id) && laneIds.has(tgtLane.id)) {
466
- const srcLaneAbs = abs(srcLane.id);
467
- const borderY = goingDown ? srcLaneAbs.y + (srcLane.height ?? 160) : srcLaneAbs.y;
468
- routingPoints = [
469
- { x: sCX, y: goingDown ? sAbs.y + sH : sAbs.y },
470
- // [0] discarded
471
- { x: sharedX, y: goingDown ? sAbs.y + sH : sAbs.y },
472
- // [1] bend: horizontal exit
473
- { x: sharedX, y: borderY },
474
- // [2] bend: lane border
475
- { x: sharedX, y: goingDown ? tAbs.y : tAbs.y + tH }
476
- // [3] discarded
477
- ];
606
+ const goingDown = tAbs.y > sAbs.y;
607
+ const sharedX = gapMidX(sAbs, sW, tAbs, tW);
608
+ const srcLaneIdx = sortedLanes.findIndex((l) => l.id === srcLane.id);
609
+ const tgtLaneIdx = sortedLanes.findIndex((l) => l.id === tgtLane.id);
610
+ const pts = [];
611
+ if (goingDown) {
612
+ pts.push({ x: sCX, y: sAbs.y + sH });
613
+ pts.push({ x: sharedX, y: sAbs.y + sH });
614
+ const fromIdx = Math.min(srcLaneIdx, tgtLaneIdx);
615
+ const toIdx = Math.max(srcLaneIdx, tgtLaneIdx);
616
+ for (let i = fromIdx; i < toIdx; i++) {
617
+ const lane = sortedLanes[i];
618
+ const laneBot = abs(lane.id).y + (lane.height ?? LANE_MIN_H);
619
+ pts.push({ x: sharedX, y: laneBot });
620
+ }
621
+ const lastY = pts[pts.length - 1].y;
622
+ pts.push({ x: tCX, y: lastY });
623
+ pts.push({ x: tCX, y: tAbs.y + tH });
624
+ } else {
625
+ pts.push({ x: sCX, y: sAbs.y });
626
+ pts.push({ x: sharedX, y: sAbs.y });
627
+ const fromIdx = Math.min(srcLaneIdx, tgtLaneIdx);
628
+ const toIdx = Math.max(srcLaneIdx, tgtLaneIdx);
629
+ for (let i = toIdx; i > fromIdx; i--) {
630
+ const lane = sortedLanes[i];
631
+ const laneTop = abs(lane.id).y;
632
+ pts.push({ x: sharedX, y: laneTop });
633
+ }
634
+ const lastY = pts[pts.length - 1].y;
635
+ pts.push({ x: tCX, y: lastY });
636
+ pts.push({ x: tCX, y: tAbs.y });
637
+ }
638
+ routingPoints = pts;
478
639
  } else {
640
+ const sharedX = gapMidX(sAbs, sW, tAbs, tW);
479
641
  routingPoints = [
480
642
  { x: sCX, y: sCY },
481
643
  { x: sharedX, y: sCY },
@@ -494,39 +656,108 @@ function routeEdges(edges, layoutNodes, backEdgeIds, laneIds, poolIds) {
494
656
  if (exitsTop || exitsBottom) {
495
657
  routingPoints = [
496
658
  { x: sCX, y: exitsTop ? sAbs.y : sAbs.y + sH },
497
- // [0] discarded
498
659
  { x: sCX, y: tCY },
499
- // [1] vertical to target row
500
660
  { x: tCX, y: tCY },
501
- // [2] horizontal to target
502
661
  { x: tCX, y: exitsTop ? tAbs.y + tH : tAbs.y }
503
- // [3] discarded
504
662
  ];
505
663
  } else {
506
- const goingRight = tAbs.x >= sAbs.x;
507
- const midX = goingRight ? sAbs.x + sW + COL_GAP / 2 : sAbs.x - COL_GAP / 2;
664
+ const midX = gapMidX(sAbs, sW, tAbs, tW);
508
665
  routingPoints = [
509
666
  { x: sAbs.x + sW, y: sCY },
510
- // [0] discarded
511
667
  { x: midX, y: sCY },
512
- // [1] horizontal exit
513
668
  { x: midX, y: tCY },
514
- // [2] vertical to target row
515
669
  { x: tAbs.x, y: tCY }
516
- // [3] discarded
517
670
  ];
518
671
  }
519
672
  }
520
673
  return { ...edge, data: { ...edge.data, routingPoints } };
521
674
  });
522
675
  }
676
+ var ARTIFACT_ABOVE_GAP = 16;
677
+ var ARTIFACT_H_SPACING = 12;
678
+ function positionArtifacts(artifacts, resultNodes, edges) {
679
+ if (artifacts.length === 0) return [];
680
+ const byId = new Map(resultNodes.map((n) => [n.id, n]));
681
+ const cache = /* @__PURE__ */ new Map();
682
+ const absPos = (id) => absolutePos(id, byId, cache);
683
+ const artifactsByNode = /* @__PURE__ */ new Map();
684
+ const ungrouped = [];
685
+ for (const artifact of artifacts) {
686
+ if (artifact.data.elementType === "Group") {
687
+ ungrouped.push(artifact);
688
+ continue;
689
+ }
690
+ const connEdge = edges.find((e) => {
691
+ const t = e.data?.edgeType ?? e.type;
692
+ return (t === "association" || t === "dataAssociation") && (e.source === artifact.id || e.target === artifact.id);
693
+ });
694
+ if (!connEdge) {
695
+ ungrouped.push(artifact);
696
+ continue;
697
+ }
698
+ const connId = connEdge.source === artifact.id ? connEdge.target : connEdge.source;
699
+ if (!byId.has(connId)) {
700
+ ungrouped.push(artifact);
701
+ continue;
702
+ }
703
+ if (!artifactsByNode.has(connId)) artifactsByNode.set(connId, []);
704
+ artifactsByNode.get(connId).push(artifact);
705
+ }
706
+ const positioned = [...ungrouped];
707
+ for (const [connId, arts] of artifactsByNode) {
708
+ const connNode = byId.get(connId);
709
+ const connAbsP = absPos(connId);
710
+ const totalW = arts.reduce((s, a) => s + nW(a), 0) + (arts.length - 1) * ARTIFACT_H_SPACING;
711
+ const desiredAbsY = connAbsP.y - ARTIFACT_ABOVE_GAP - Math.max(...arts.map(nH));
712
+ let desiredAbsX = connAbsP.x + nW(connNode) / 2 - totalW / 2;
713
+ for (const artifact of arts) {
714
+ const parentAbsP = artifact.parentId ? absPos(artifact.parentId) : { x: 0, y: 0 };
715
+ positioned.push({
716
+ ...artifact,
717
+ position: {
718
+ x: desiredAbsX - parentAbsP.x,
719
+ y: desiredAbsY - parentAbsP.y
720
+ }
721
+ });
722
+ desiredAbsX += nW(artifact) + ARTIFACT_H_SPACING;
723
+ }
724
+ }
725
+ return positioned;
726
+ }
523
727
  async function bpmnCustomLayout(nodes, edges) {
524
- const pools = nodes.filter((n) => n.data.elementType === "Pool");
525
- const lanes = nodes.filter((n) => n.data.elementType === "Lane");
526
- const content = nodes.filter((n) => !LAYOUT_CONTAINER_TYPES.has(n.data.elementType));
728
+ const artifacts = nodes.filter((n) => LAYOUT_ARTIFACT_TYPES.has(n.data.elementType));
729
+ const mainNodes = nodes.filter((n) => !LAYOUT_ARTIFACT_TYPES.has(n.data.elementType));
730
+ const pools = mainNodes.filter((n) => n.data.elementType === "Pool");
731
+ const lanes = mainNodes.filter((n) => n.data.elementType === "Lane");
732
+ const expandedSubProcesses = mainNodes.filter(
733
+ (n) => COLLAPSED_SUBPROCESS_TYPES.has(n.data.elementType) && n.data.isExpanded
734
+ );
735
+ const subProcessLayouts = /* @__PURE__ */ new Map();
736
+ const workingMainNodes = [...mainNodes];
737
+ for (const sp of expandedSubProcesses) {
738
+ const spChildren = workingMainNodes.filter((n) => n.parentId === sp.id);
739
+ const result = layoutSubProcess(spChildren, edges);
740
+ subProcessLayouts.set(sp.id, result);
741
+ const spIdx = workingMainNodes.findIndex((n) => n.id === sp.id);
742
+ if (spIdx >= 0) {
743
+ workingMainNodes[spIdx] = {
744
+ ...workingMainNodes[spIdx],
745
+ width: result.width,
746
+ height: result.height,
747
+ measured: { width: result.width, height: result.height }
748
+ };
749
+ }
750
+ }
751
+ const content = workingMainNodes.filter((n) => {
752
+ if (!LAYOUT_CONTAINER_TYPES.has(n.data.elementType)) return true;
753
+ if (COLLAPSED_SUBPROCESS_TYPES.has(n.data.elementType)) return true;
754
+ return false;
755
+ });
527
756
  if (pools.length === 0) {
528
- const { bpmnElkLayout: bpmnElkLayout2 } = await import('../elk-FSFIEL6O.js');
529
- return bpmnElkLayout2(nodes, edges);
757
+ const { bpmnElkLayout: bpmnElkLayout2 } = await import('../elk-QT7H4252.js');
758
+ const elkResult = await bpmnElkLayout2(nodes.filter((n) => !LAYOUT_ARTIFACT_TYPES.has(n.data.elementType)), edges);
759
+ const posArtifacts = positionArtifacts(artifacts, elkResult.nodes, edges);
760
+ return { nodes: [...elkResult.nodes, ...posArtifacts], edges: elkResult.edges };
530
761
  }
531
762
  const poolIds = new Set(pools.map((p) => p.id));
532
763
  const allLaneIds = new Set(lanes.map((l) => l.id));
@@ -546,7 +777,10 @@ async function bpmnCustomLayout(nodes, edges) {
546
777
  const poolContent = content.filter(
547
778
  (n) => n.parentId === pool.id || n.parentId != null && laneIds.has(n.parentId)
548
779
  );
549
- const result = layoutPool(pool, poolLanes, poolContent, edges);
780
+ const poolBoundaries = workingMainNodes.filter(
781
+ (n) => n.data.elementType === "BoundaryEvent" && (n.parentId === pool.id || n.parentId != null && laneIds.has(n.parentId))
782
+ );
783
+ const result = layoutPool(pool, poolLanes, [...poolContent, ...poolBoundaries], edges);
550
784
  resultNodes.push({
551
785
  ...pool,
552
786
  position: { x: 0, y: stackY },
@@ -558,12 +792,44 @@ async function bpmnCustomLayout(nodes, edges) {
558
792
  }
559
793
  stackY += result.height + POOL_V_GAP;
560
794
  }
795
+ for (const [, spLayout] of subProcessLayouts) {
796
+ for (const child of spLayout.children) {
797
+ resultNodes.push(child);
798
+ }
799
+ }
561
800
  const layoutted = new Set(resultNodes.map((n) => n.id));
562
- for (const node of nodes) {
563
- if (!layoutted.has(node.id)) resultNodes.push(node);
801
+ const freeNodes = workingMainNodes.filter((n) => !layoutted.has(n.id));
802
+ if (freeNodes.length > 0) {
803
+ const freeEdges = edges.filter(
804
+ (e) => freeNodes.some((n) => n.id === e.source || n.id === e.target)
805
+ );
806
+ try {
807
+ const { bpmnElkLayout: bpmnElkLayout2 } = await import('../elk-QT7H4252.js');
808
+ const elkFree = await bpmnElkLayout2(freeNodes, freeEdges);
809
+ const offsetY = stackY;
810
+ for (const node of elkFree.nodes) {
811
+ resultNodes.push({
812
+ ...node,
813
+ position: { x: node.position.x, y: node.position.y + offsetY }
814
+ });
815
+ }
816
+ const freeEdgeIds = new Set(freeEdges.map((e) => e.id));
817
+ const elkEdgeMap = new Map(elkFree.edges.map((e) => [e.id, e]));
818
+ for (let i = 0; i < edges.length; i++) {
819
+ if (freeEdgeIds.has(edges[i].id) && elkEdgeMap.has(edges[i].id)) {
820
+ edges[i] = elkEdgeMap.get(edges[i].id);
821
+ }
822
+ }
823
+ } catch {
824
+ for (const node of freeNodes) resultNodes.push(node);
825
+ }
564
826
  }
565
827
  const routedEdges = routeEdges(edges, resultNodes, allBackEdgeIds, allLaneIds, poolIds);
566
- return { nodes: resultNodes, edges: routedEdges };
828
+ const positionedArtifacts = positionArtifacts(artifacts, resultNodes, edges);
829
+ return {
830
+ nodes: [...resultNodes, ...positionedArtifacts],
831
+ edges: routedEdges
832
+ };
567
833
  }
568
834
 
569
835
  // src/layout/index.ts