@aranzatech/diagrams-bpmn 0.3.4 → 0.3.6

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 (55) hide show
  1. package/dist/{catalog-DNIyjHbl.d.ts → catalog-CYZHikuU.d.ts} +1 -1
  2. package/dist/{catalog-DG-sz0VM.d.cts → catalog-C_S9hyyn.d.cts} +1 -1
  3. package/dist/{chunk-CPFUQM6H.js → chunk-EMTO53AN.js} +54 -73
  4. package/dist/chunk-EMTO53AN.js.map +1 -0
  5. package/dist/chunk-G22XQD6H.js +64 -0
  6. package/dist/chunk-G22XQD6H.js.map +1 -0
  7. package/dist/{chunk-NYIYQUGX.js → chunk-OFOTX3LA.js} +124 -20
  8. package/dist/chunk-OFOTX3LA.js.map +1 -0
  9. package/dist/{chunk-YAYZW45I.js → chunk-SRUWPELT.js} +80 -3
  10. package/dist/chunk-SRUWPELT.js.map +1 -0
  11. package/dist/edges/index.cjs +75 -35
  12. package/dist/edges/index.cjs.map +1 -1
  13. package/dist/edges/index.js +2 -1
  14. package/dist/elements/index.d.cts +3 -3
  15. package/dist/elements/index.d.ts +3 -3
  16. package/dist/extensions/index.d.cts +2 -2
  17. package/dist/extensions/index.d.ts +2 -2
  18. package/dist/index.cjs +196 -53
  19. package/dist/index.cjs.map +1 -1
  20. package/dist/index.d.cts +4 -4
  21. package/dist/index.d.ts +4 -4
  22. package/dist/index.js +4 -3
  23. package/dist/index.js.map +1 -1
  24. package/dist/layout/index.cjs +1280 -889
  25. package/dist/layout/index.cjs.map +1 -1
  26. package/dist/layout/index.d.cts +4 -4
  27. package/dist/layout/index.d.ts +4 -4
  28. package/dist/layout/index.js +694 -106
  29. package/dist/layout/index.js.map +1 -1
  30. package/dist/modeling/index.cjs +78 -0
  31. package/dist/modeling/index.cjs.map +1 -1
  32. package/dist/modeling/index.d.cts +10 -5
  33. package/dist/modeling/index.d.ts +10 -5
  34. package/dist/modeling/index.js +1 -1
  35. package/dist/{types-nvF59RGF.d.cts → types--x9aoecw.d.cts} +5 -0
  36. package/dist/{types-nvF59RGF.d.ts → types--x9aoecw.d.ts} +5 -0
  37. package/dist/{types-dQUuSnV5.d.cts → types-CrFDTGo9.d.cts} +1 -1
  38. package/dist/{types-CuDL2YGL.d.ts → types-DoPv3m7u.d.ts} +2 -2
  39. package/dist/{types-X5FyP8oS.d.ts → types-DteJykQG.d.ts} +1 -1
  40. package/dist/{types-CDp9kWQ4.d.cts → types-YZ4sj3Ih.d.cts} +2 -2
  41. package/dist/validation/index.d.cts +3 -3
  42. package/dist/validation/index.d.ts +3 -3
  43. package/dist/xml/index.cjs +162 -18
  44. package/dist/xml/index.cjs.map +1 -1
  45. package/dist/xml/index.d.cts +4 -4
  46. package/dist/xml/index.d.ts +4 -4
  47. package/dist/xml/index.js +2 -1
  48. package/package.json +1 -1
  49. package/dist/chunk-CPFUQM6H.js.map +0 -1
  50. package/dist/chunk-FFWJA5BV.js +0 -163
  51. package/dist/chunk-FFWJA5BV.js.map +0 -1
  52. package/dist/chunk-NYIYQUGX.js.map +0 -1
  53. package/dist/chunk-YAYZW45I.js.map +0 -1
  54. package/dist/elk-QT7H4252.js +0 -6
  55. package/dist/elk-QT7H4252.js.map +0 -1
@@ -1,23 +1,626 @@
1
1
  'use strict';
2
2
 
3
+ var layout = require('@aranzatech/diagrams-core/layout');
3
4
  var diagramsCore = require('@aranzatech/diagrams-core');
4
5
  require('@aranzatech/diagrams-core/serialization');
5
- var layout = require('@aranzatech/diagrams-core/layout');
6
6
 
7
- var __defProp = Object.defineProperty;
8
- var __getOwnPropNames = Object.getOwnPropertyNames;
9
- var __esm = (fn, res) => function __init() {
10
- return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
11
- };
12
- var __export = (target, all) => {
13
- for (var name in all)
14
- __defProp(target, name, { get: all[name], enumerable: true });
15
- };
7
+ // src/layout/index.ts
16
8
 
17
9
  // src/elements/catalog.ts
10
+ var BPMN_ELEMENT_CATALOG = {
11
+ // ─── Events ──────────────────────────────────────────────────────────────────
12
+ StartEvent: {
13
+ label: "Start Event",
14
+ icon: "Circle",
15
+ category: "event",
16
+ defaultWidth: 36,
17
+ defaultHeight: 36,
18
+ handlePolicy: "source",
19
+ orientation: "free",
20
+ isContainer: false,
21
+ acceptsBoundaryEvents: false,
22
+ eventSemantics: "start",
23
+ canBeStart: true,
24
+ canBeEnd: false,
25
+ maxIncoming: 0,
26
+ maxOutgoing: 1
27
+ },
28
+ EndEvent: {
29
+ label: "End Event",
30
+ icon: "CircleDot",
31
+ category: "event",
32
+ defaultWidth: 36,
33
+ defaultHeight: 36,
34
+ handlePolicy: "target",
35
+ orientation: "free",
36
+ isContainer: false,
37
+ acceptsBoundaryEvents: false,
38
+ eventSemantics: "end",
39
+ canBeStart: false,
40
+ canBeEnd: true,
41
+ maxOutgoing: 0
42
+ },
43
+ IntermediateCatchEvent: {
44
+ label: "Intermediate Catch Event",
45
+ icon: "Clock3",
46
+ category: "event",
47
+ defaultWidth: 36,
48
+ defaultHeight: 36,
49
+ handlePolicy: "all",
50
+ orientation: "free",
51
+ isContainer: false,
52
+ acceptsBoundaryEvents: false,
53
+ eventSemantics: "intermediateCatch",
54
+ canBeStart: false,
55
+ canBeEnd: false
56
+ },
57
+ IntermediateThrowEvent: {
58
+ label: "Intermediate Throw Event",
59
+ icon: "Send",
60
+ category: "event",
61
+ defaultWidth: 36,
62
+ defaultHeight: 36,
63
+ handlePolicy: "all",
64
+ orientation: "free",
65
+ isContainer: false,
66
+ acceptsBoundaryEvents: false,
67
+ eventSemantics: "intermediateThrow",
68
+ canBeStart: false,
69
+ canBeEnd: false
70
+ },
71
+ BoundaryEvent: {
72
+ label: "Boundary Event",
73
+ icon: "AlarmClock",
74
+ category: "event",
75
+ defaultWidth: 36,
76
+ defaultHeight: 36,
77
+ handlePolicy: "source",
78
+ orientation: "free",
79
+ isContainer: false,
80
+ acceptsBoundaryEvents: false,
81
+ eventSemantics: "boundary",
82
+ canBeStart: false,
83
+ canBeEnd: false,
84
+ maxIncoming: 0
85
+ },
86
+ // ─── Tasks ───────────────────────────────────────────────────────────────────
87
+ Task: {
88
+ label: "Task",
89
+ icon: "CheckSquare",
90
+ category: "task",
91
+ defaultWidth: 120,
92
+ defaultHeight: 60,
93
+ handlePolicy: "all",
94
+ orientation: "free",
95
+ isContainer: false,
96
+ acceptsBoundaryEvents: true,
97
+ supportsMarkers: true,
98
+ canBeStart: false,
99
+ canBeEnd: false
100
+ },
101
+ UserTask: {
102
+ label: "User Task",
103
+ icon: "UserRound",
104
+ category: "task",
105
+ defaultWidth: 120,
106
+ defaultHeight: 60,
107
+ handlePolicy: "all",
108
+ orientation: "free",
109
+ isContainer: false,
110
+ acceptsBoundaryEvents: true,
111
+ supportsMarkers: true,
112
+ canBeStart: false,
113
+ canBeEnd: false
114
+ },
115
+ ServiceTask: {
116
+ label: "Service Task",
117
+ icon: "Cog",
118
+ category: "task",
119
+ defaultWidth: 120,
120
+ defaultHeight: 60,
121
+ handlePolicy: "all",
122
+ orientation: "free",
123
+ isContainer: false,
124
+ acceptsBoundaryEvents: true,
125
+ supportsMarkers: true,
126
+ canBeStart: false,
127
+ canBeEnd: false
128
+ },
129
+ ScriptTask: {
130
+ label: "Script Task",
131
+ icon: "FileCode",
132
+ category: "task",
133
+ defaultWidth: 120,
134
+ defaultHeight: 60,
135
+ handlePolicy: "all",
136
+ orientation: "free",
137
+ isContainer: false,
138
+ acceptsBoundaryEvents: true,
139
+ supportsMarkers: true,
140
+ canBeStart: false,
141
+ canBeEnd: false
142
+ },
143
+ ManualTask: {
144
+ label: "Manual Task",
145
+ icon: "Hand",
146
+ category: "task",
147
+ defaultWidth: 120,
148
+ defaultHeight: 60,
149
+ handlePolicy: "all",
150
+ orientation: "free",
151
+ isContainer: false,
152
+ acceptsBoundaryEvents: true,
153
+ supportsMarkers: true,
154
+ canBeStart: false,
155
+ canBeEnd: false
156
+ },
157
+ BusinessRuleTask: {
158
+ label: "Business Rule Task",
159
+ icon: "Table2",
160
+ category: "task",
161
+ defaultWidth: 120,
162
+ defaultHeight: 60,
163
+ handlePolicy: "all",
164
+ orientation: "free",
165
+ isContainer: false,
166
+ acceptsBoundaryEvents: true,
167
+ supportsMarkers: true,
168
+ canBeStart: false,
169
+ canBeEnd: false
170
+ },
171
+ ReceiveTask: {
172
+ label: "Receive Task",
173
+ icon: "Inbox",
174
+ category: "task",
175
+ defaultWidth: 120,
176
+ defaultHeight: 60,
177
+ handlePolicy: "all",
178
+ orientation: "free",
179
+ isContainer: false,
180
+ acceptsBoundaryEvents: true,
181
+ supportsMarkers: true,
182
+ canBeStart: false,
183
+ canBeEnd: false
184
+ },
185
+ SendTask: {
186
+ label: "Send Task",
187
+ icon: "Send",
188
+ category: "task",
189
+ defaultWidth: 120,
190
+ defaultHeight: 60,
191
+ handlePolicy: "all",
192
+ orientation: "free",
193
+ isContainer: false,
194
+ acceptsBoundaryEvents: true,
195
+ supportsMarkers: true,
196
+ canBeStart: false,
197
+ canBeEnd: false
198
+ },
199
+ CallActivity: {
200
+ label: "Call Activity",
201
+ icon: "ExternalLink",
202
+ category: "task",
203
+ defaultWidth: 120,
204
+ defaultHeight: 60,
205
+ handlePolicy: "all",
206
+ orientation: "free",
207
+ isContainer: false,
208
+ acceptsBoundaryEvents: true,
209
+ supportsMarkers: true,
210
+ canBeStart: false,
211
+ canBeEnd: false
212
+ },
213
+ // ─── Gateways ────────────────────────────────────────────────────────────────
214
+ ExclusiveGateway: {
215
+ label: "Exclusive Gateway",
216
+ icon: "X",
217
+ category: "gateway",
218
+ defaultWidth: 50,
219
+ defaultHeight: 50,
220
+ handlePolicy: "all",
221
+ orientation: "free",
222
+ isContainer: false,
223
+ acceptsBoundaryEvents: false,
224
+ canBeStart: false,
225
+ canBeEnd: false
226
+ },
227
+ InclusiveGateway: {
228
+ label: "Inclusive Gateway",
229
+ icon: "Circle",
230
+ category: "gateway",
231
+ defaultWidth: 50,
232
+ defaultHeight: 50,
233
+ handlePolicy: "all",
234
+ orientation: "free",
235
+ isContainer: false,
236
+ acceptsBoundaryEvents: false,
237
+ canBeStart: false,
238
+ canBeEnd: false
239
+ },
240
+ ParallelGateway: {
241
+ label: "Parallel Gateway",
242
+ icon: "Plus",
243
+ category: "gateway",
244
+ defaultWidth: 50,
245
+ defaultHeight: 50,
246
+ handlePolicy: "all",
247
+ orientation: "free",
248
+ isContainer: false,
249
+ acceptsBoundaryEvents: false,
250
+ canBeStart: false,
251
+ canBeEnd: false
252
+ },
253
+ EventBasedGateway: {
254
+ label: "Event-Based Gateway",
255
+ icon: "Radio",
256
+ category: "gateway",
257
+ defaultWidth: 50,
258
+ defaultHeight: 50,
259
+ handlePolicy: "all",
260
+ orientation: "free",
261
+ isContainer: false,
262
+ acceptsBoundaryEvents: false,
263
+ canBeStart: false,
264
+ canBeEnd: false,
265
+ maxIncoming: 1
266
+ },
267
+ ComplexGateway: {
268
+ label: "Complex Gateway",
269
+ icon: "Asterisk",
270
+ category: "gateway",
271
+ defaultWidth: 50,
272
+ defaultHeight: 50,
273
+ handlePolicy: "all",
274
+ orientation: "free",
275
+ isContainer: false,
276
+ acceptsBoundaryEvents: false,
277
+ canBeStart: false,
278
+ canBeEnd: false
279
+ },
280
+ // ─── Containers ───────────────────────────────────────────────────────────────
281
+ SubProcess: {
282
+ label: "Sub-Process",
283
+ icon: "PlusSquare",
284
+ category: "container",
285
+ defaultWidth: 350,
286
+ defaultHeight: 200,
287
+ handlePolicy: "all",
288
+ orientation: "horizontal",
289
+ isContainer: true,
290
+ acceptsBoundaryEvents: true,
291
+ supportsCollapse: true,
292
+ supportsMarkers: true,
293
+ canBeStart: false,
294
+ canBeEnd: false
295
+ },
296
+ Transaction: {
297
+ label: "Transaction",
298
+ icon: "Receipt",
299
+ category: "container",
300
+ defaultWidth: 350,
301
+ defaultHeight: 200,
302
+ handlePolicy: "all",
303
+ orientation: "horizontal",
304
+ isContainer: true,
305
+ acceptsBoundaryEvents: true,
306
+ supportsCollapse: true,
307
+ supportsMarkers: true,
308
+ canBeStart: false,
309
+ canBeEnd: false
310
+ },
311
+ EventSubProcess: {
312
+ label: "Event Sub-Process",
313
+ icon: "CircleDotDashed",
314
+ category: "container",
315
+ defaultWidth: 350,
316
+ defaultHeight: 200,
317
+ handlePolicy: "all",
318
+ orientation: "horizontal",
319
+ isContainer: true,
320
+ acceptsBoundaryEvents: false,
321
+ supportsCollapse: true,
322
+ supportsMarkers: true,
323
+ canBeStart: false,
324
+ canBeEnd: false
325
+ },
326
+ AdHocSubProcess: {
327
+ label: "Ad-Hoc Sub-Process",
328
+ icon: "Waves",
329
+ category: "container",
330
+ defaultWidth: 350,
331
+ defaultHeight: 200,
332
+ handlePolicy: "all",
333
+ orientation: "horizontal",
334
+ isContainer: true,
335
+ acceptsBoundaryEvents: true,
336
+ supportsCollapse: true,
337
+ supportsMarkers: true,
338
+ canBeStart: false,
339
+ canBeEnd: false
340
+ },
341
+ Pool: {
342
+ label: "Pool",
343
+ icon: "Rows3",
344
+ category: "container",
345
+ defaultWidth: 600,
346
+ defaultHeight: 200,
347
+ handlePolicy: "none",
348
+ orientation: "horizontal",
349
+ isContainer: true,
350
+ acceptsBoundaryEvents: false,
351
+ canBeStart: false,
352
+ canBeEnd: false,
353
+ maxIncoming: 0,
354
+ maxOutgoing: 0
355
+ },
356
+ Lane: {
357
+ label: "Lane",
358
+ icon: "PanelTop",
359
+ category: "container",
360
+ defaultWidth: 600,
361
+ defaultHeight: 120,
362
+ handlePolicy: "none",
363
+ orientation: "horizontal",
364
+ isContainer: true,
365
+ acceptsBoundaryEvents: false,
366
+ canBeStart: false,
367
+ canBeEnd: false,
368
+ maxIncoming: 0,
369
+ maxOutgoing: 0
370
+ },
371
+ // ─── Artifacts ────────────────────────────────────────────────────────────────
372
+ Annotation: {
373
+ label: "Text Annotation",
374
+ icon: "StickyNote",
375
+ category: "artifact",
376
+ defaultWidth: 100,
377
+ defaultHeight: 60,
378
+ handlePolicy: "none",
379
+ orientation: "free",
380
+ isContainer: false,
381
+ acceptsBoundaryEvents: false,
382
+ canBeStart: false,
383
+ canBeEnd: false,
384
+ maxIncoming: 0,
385
+ maxOutgoing: 0
386
+ },
387
+ Group: {
388
+ label: "Group",
389
+ icon: "Group",
390
+ category: "artifact",
391
+ defaultWidth: 300,
392
+ defaultHeight: 200,
393
+ handlePolicy: "none",
394
+ orientation: "free",
395
+ isContainer: false,
396
+ acceptsBoundaryEvents: false,
397
+ canBeStart: false,
398
+ canBeEnd: false,
399
+ maxIncoming: 0,
400
+ maxOutgoing: 0
401
+ },
402
+ // ─── Data (BPMN 2.0 §10.3) ───────────────────────────────────────────────────
403
+ DataObject: {
404
+ label: "Data Object",
405
+ icon: "File",
406
+ category: "data",
407
+ defaultWidth: 36,
408
+ defaultHeight: 50,
409
+ handlePolicy: "all",
410
+ orientation: "free",
411
+ isContainer: false,
412
+ acceptsBoundaryEvents: false,
413
+ canBeStart: false,
414
+ canBeEnd: false,
415
+ maxIncoming: 0,
416
+ maxOutgoing: 0
417
+ },
418
+ DataObjectReference: {
419
+ label: "Data Object Reference",
420
+ icon: "FileSymlink",
421
+ category: "data",
422
+ defaultWidth: 36,
423
+ defaultHeight: 50,
424
+ handlePolicy: "all",
425
+ orientation: "free",
426
+ isContainer: false,
427
+ acceptsBoundaryEvents: false,
428
+ canBeStart: false,
429
+ canBeEnd: false,
430
+ maxIncoming: 0,
431
+ maxOutgoing: 0
432
+ },
433
+ DataInput: {
434
+ label: "Data Input",
435
+ icon: "FileInput",
436
+ category: "data",
437
+ defaultWidth: 36,
438
+ defaultHeight: 50,
439
+ handlePolicy: "all",
440
+ orientation: "free",
441
+ isContainer: false,
442
+ acceptsBoundaryEvents: false,
443
+ canBeStart: false,
444
+ canBeEnd: false,
445
+ maxIncoming: 0
446
+ },
447
+ DataOutput: {
448
+ label: "Data Output",
449
+ icon: "FileOutput",
450
+ category: "data",
451
+ defaultWidth: 36,
452
+ defaultHeight: 50,
453
+ handlePolicy: "all",
454
+ orientation: "free",
455
+ isContainer: false,
456
+ acceptsBoundaryEvents: false,
457
+ canBeStart: false,
458
+ canBeEnd: false,
459
+ maxOutgoing: 0
460
+ },
461
+ DataStore: {
462
+ label: "Data Store",
463
+ icon: "Database",
464
+ category: "data",
465
+ defaultWidth: 50,
466
+ defaultHeight: 50,
467
+ handlePolicy: "all",
468
+ orientation: "free",
469
+ isContainer: false,
470
+ acceptsBoundaryEvents: false,
471
+ canBeStart: false,
472
+ canBeEnd: false,
473
+ maxIncoming: 0,
474
+ maxOutgoing: 0
475
+ },
476
+ DataStoreReference: {
477
+ label: "Data Store Reference",
478
+ icon: "DatabaseZap",
479
+ category: "data",
480
+ defaultWidth: 50,
481
+ defaultHeight: 50,
482
+ handlePolicy: "all",
483
+ orientation: "free",
484
+ isContainer: false,
485
+ acceptsBoundaryEvents: false,
486
+ canBeStart: false,
487
+ canBeEnd: false,
488
+ maxIncoming: 0,
489
+ maxOutgoing: 0
490
+ },
491
+ // ─── Conversation (BPMN 2.0 §12) ─────────────────────────────────────────────
492
+ Conversation: {
493
+ label: "Conversation",
494
+ icon: "MessageCircle",
495
+ category: "conversation",
496
+ defaultWidth: 60,
497
+ defaultHeight: 52,
498
+ handlePolicy: "all",
499
+ orientation: "free",
500
+ isContainer: false,
501
+ acceptsBoundaryEvents: false,
502
+ canBeStart: false,
503
+ canBeEnd: false
504
+ },
505
+ SubConversation: {
506
+ label: "Sub-Conversation",
507
+ icon: "MessagesSquare",
508
+ category: "conversation",
509
+ defaultWidth: 60,
510
+ defaultHeight: 52,
511
+ handlePolicy: "all",
512
+ orientation: "free",
513
+ isContainer: true,
514
+ acceptsBoundaryEvents: false,
515
+ supportsCollapse: true,
516
+ canBeStart: false,
517
+ canBeEnd: false
518
+ },
519
+ CallConversation: {
520
+ label: "Call Conversation",
521
+ icon: "PhoneCall",
522
+ category: "conversation",
523
+ defaultWidth: 60,
524
+ defaultHeight: 52,
525
+ handlePolicy: "all",
526
+ orientation: "free",
527
+ isContainer: false,
528
+ acceptsBoundaryEvents: false,
529
+ canBeStart: false,
530
+ canBeEnd: false
531
+ },
532
+ // ─── Choreography (BPMN 2.0 §11) ─────────────────────────────────────────────
533
+ ChoreographyTask: {
534
+ label: "Choreography Task",
535
+ icon: "ArrowLeftRight",
536
+ category: "choreography",
537
+ defaultWidth: 120,
538
+ defaultHeight: 80,
539
+ handlePolicy: "all",
540
+ orientation: "horizontal",
541
+ isContainer: false,
542
+ acceptsBoundaryEvents: false,
543
+ canBeStart: false,
544
+ canBeEnd: false
545
+ },
546
+ SubChoreography: {
547
+ label: "Sub-Choreography",
548
+ icon: "BoxSelect",
549
+ category: "choreography",
550
+ defaultWidth: 120,
551
+ defaultHeight: 80,
552
+ handlePolicy: "all",
553
+ orientation: "horizontal",
554
+ isContainer: true,
555
+ acceptsBoundaryEvents: false,
556
+ supportsCollapse: true,
557
+ canBeStart: false,
558
+ canBeEnd: false
559
+ },
560
+ CallChoreography: {
561
+ label: "Call Choreography",
562
+ icon: "Phone",
563
+ category: "choreography",
564
+ defaultWidth: 120,
565
+ defaultHeight: 80,
566
+ handlePolicy: "all",
567
+ orientation: "horizontal",
568
+ isContainer: false,
569
+ acceptsBoundaryEvents: false,
570
+ canBeStart: false,
571
+ canBeEnd: false
572
+ }
573
+ };
18
574
  function getElementMeta(type) {
19
575
  return BPMN_ELEMENT_CATALOG[type];
20
576
  }
577
+ var BPMN_RESIZABLE_ELEMENT_TYPES = [
578
+ "Task",
579
+ "UserTask",
580
+ "ServiceTask",
581
+ "ScriptTask",
582
+ "ManualTask",
583
+ "BusinessRuleTask",
584
+ "ReceiveTask",
585
+ "SendTask",
586
+ "CallActivity",
587
+ "SubProcess",
588
+ "Transaction",
589
+ "EventSubProcess",
590
+ "AdHocSubProcess",
591
+ "Pool",
592
+ "Lane",
593
+ "Annotation",
594
+ "Group",
595
+ "SubConversation",
596
+ "ChoreographyTask",
597
+ "SubChoreography",
598
+ "CallChoreography"
599
+ ];
600
+ var BPMN_MIN_SIZE_OVERRIDES = {
601
+ Task: { minWidth: 80, minHeight: 48 },
602
+ UserTask: { minWidth: 80, minHeight: 48 },
603
+ ServiceTask: { minWidth: 80, minHeight: 48 },
604
+ ScriptTask: { minWidth: 80, minHeight: 48 },
605
+ ManualTask: { minWidth: 80, minHeight: 48 },
606
+ BusinessRuleTask: { minWidth: 80, minHeight: 48 },
607
+ ReceiveTask: { minWidth: 80, minHeight: 48 },
608
+ SendTask: { minWidth: 80, minHeight: 48 },
609
+ CallActivity: { minWidth: 80, minHeight: 48 },
610
+ SubProcess: { minWidth: 160, minHeight: 100 },
611
+ Transaction: { minWidth: 160, minHeight: 100 },
612
+ EventSubProcess: { minWidth: 160, minHeight: 100 },
613
+ AdHocSubProcess: { minWidth: 160, minHeight: 100 },
614
+ Pool: { minWidth: 240, minHeight: 120 },
615
+ Lane: { minWidth: 240, minHeight: 80 },
616
+ Annotation: { minWidth: 80, minHeight: 40 },
617
+ Group: { minWidth: 120, minHeight: 80 },
618
+ SubConversation: { minWidth: 60, minHeight: 52 },
619
+ ChoreographyTask: { minWidth: 100, minHeight: 70 },
620
+ SubChoreography: { minWidth: 100, minHeight: 70 },
621
+ CallChoreography: { minWidth: 100, minHeight: 70 }
622
+ };
623
+ var resizableTypes = new Set(BPMN_RESIZABLE_ELEMENT_TYPES);
21
624
  function isBpmnElementResizable(type) {
22
625
  return resizableTypes.has(type);
23
626
  }
@@ -32,624 +635,30 @@ function getBpmnElementSize(type) {
32
635
  resizable: meta.resizable ?? isBpmnElementResizable(type)
33
636
  };
34
637
  }
35
- var BPMN_ELEMENT_CATALOG, BPMN_RESIZABLE_ELEMENT_TYPES, BPMN_MIN_SIZE_OVERRIDES, resizableTypes;
36
- var init_catalog = __esm({
37
- "src/elements/catalog.ts"() {
38
- BPMN_ELEMENT_CATALOG = {
39
- // ─── Events ──────────────────────────────────────────────────────────────────
40
- StartEvent: {
41
- label: "Start Event",
42
- icon: "Circle",
43
- category: "event",
44
- defaultWidth: 36,
45
- defaultHeight: 36,
46
- handlePolicy: "source",
47
- orientation: "free",
48
- isContainer: false,
49
- acceptsBoundaryEvents: false,
50
- eventSemantics: "start",
51
- canBeStart: true,
52
- canBeEnd: false,
53
- maxIncoming: 0,
54
- maxOutgoing: 1
55
- },
56
- EndEvent: {
57
- label: "End Event",
58
- icon: "CircleDot",
59
- category: "event",
60
- defaultWidth: 36,
61
- defaultHeight: 36,
62
- handlePolicy: "target",
63
- orientation: "free",
64
- isContainer: false,
65
- acceptsBoundaryEvents: false,
66
- eventSemantics: "end",
67
- canBeStart: false,
68
- canBeEnd: true,
69
- maxOutgoing: 0
70
- },
71
- IntermediateCatchEvent: {
72
- label: "Intermediate Catch Event",
73
- icon: "Clock3",
74
- category: "event",
75
- defaultWidth: 36,
76
- defaultHeight: 36,
77
- handlePolicy: "all",
78
- orientation: "free",
79
- isContainer: false,
80
- acceptsBoundaryEvents: false,
81
- eventSemantics: "intermediateCatch",
82
- canBeStart: false,
83
- canBeEnd: false
84
- },
85
- IntermediateThrowEvent: {
86
- label: "Intermediate Throw Event",
87
- icon: "Send",
88
- category: "event",
89
- defaultWidth: 36,
90
- defaultHeight: 36,
91
- handlePolicy: "all",
92
- orientation: "free",
93
- isContainer: false,
94
- acceptsBoundaryEvents: false,
95
- eventSemantics: "intermediateThrow",
96
- canBeStart: false,
97
- canBeEnd: false
98
- },
99
- BoundaryEvent: {
100
- label: "Boundary Event",
101
- icon: "AlarmClock",
102
- category: "event",
103
- defaultWidth: 36,
104
- defaultHeight: 36,
105
- handlePolicy: "source",
106
- orientation: "free",
107
- isContainer: false,
108
- acceptsBoundaryEvents: false,
109
- eventSemantics: "boundary",
110
- canBeStart: false,
111
- canBeEnd: false,
112
- maxIncoming: 0
113
- },
114
- // ─── Tasks ───────────────────────────────────────────────────────────────────
115
- Task: {
116
- label: "Task",
117
- icon: "CheckSquare",
118
- category: "task",
119
- defaultWidth: 120,
120
- defaultHeight: 60,
121
- handlePolicy: "all",
122
- orientation: "free",
123
- isContainer: false,
124
- acceptsBoundaryEvents: true,
125
- supportsMarkers: true,
126
- canBeStart: false,
127
- canBeEnd: false
128
- },
129
- UserTask: {
130
- label: "User Task",
131
- icon: "UserRound",
132
- category: "task",
133
- defaultWidth: 120,
134
- defaultHeight: 60,
135
- handlePolicy: "all",
136
- orientation: "free",
137
- isContainer: false,
138
- acceptsBoundaryEvents: true,
139
- supportsMarkers: true,
140
- canBeStart: false,
141
- canBeEnd: false
142
- },
143
- ServiceTask: {
144
- label: "Service Task",
145
- icon: "Cog",
146
- category: "task",
147
- defaultWidth: 120,
148
- defaultHeight: 60,
149
- handlePolicy: "all",
150
- orientation: "free",
151
- isContainer: false,
152
- acceptsBoundaryEvents: true,
153
- supportsMarkers: true,
154
- canBeStart: false,
155
- canBeEnd: false
156
- },
157
- ScriptTask: {
158
- label: "Script Task",
159
- icon: "FileCode",
160
- category: "task",
161
- defaultWidth: 120,
162
- defaultHeight: 60,
163
- handlePolicy: "all",
164
- orientation: "free",
165
- isContainer: false,
166
- acceptsBoundaryEvents: true,
167
- supportsMarkers: true,
168
- canBeStart: false,
169
- canBeEnd: false
170
- },
171
- ManualTask: {
172
- label: "Manual Task",
173
- icon: "Hand",
174
- category: "task",
175
- defaultWidth: 120,
176
- defaultHeight: 60,
177
- handlePolicy: "all",
178
- orientation: "free",
179
- isContainer: false,
180
- acceptsBoundaryEvents: true,
181
- supportsMarkers: true,
182
- canBeStart: false,
183
- canBeEnd: false
184
- },
185
- BusinessRuleTask: {
186
- label: "Business Rule Task",
187
- icon: "Table2",
188
- category: "task",
189
- defaultWidth: 120,
190
- defaultHeight: 60,
191
- handlePolicy: "all",
192
- orientation: "free",
193
- isContainer: false,
194
- acceptsBoundaryEvents: true,
195
- supportsMarkers: true,
196
- canBeStart: false,
197
- canBeEnd: false
198
- },
199
- ReceiveTask: {
200
- label: "Receive Task",
201
- icon: "Inbox",
202
- category: "task",
203
- defaultWidth: 120,
204
- defaultHeight: 60,
205
- handlePolicy: "all",
206
- orientation: "free",
207
- isContainer: false,
208
- acceptsBoundaryEvents: true,
209
- supportsMarkers: true,
210
- canBeStart: false,
211
- canBeEnd: false
212
- },
213
- SendTask: {
214
- label: "Send Task",
215
- icon: "Send",
216
- category: "task",
217
- defaultWidth: 120,
218
- defaultHeight: 60,
219
- handlePolicy: "all",
220
- orientation: "free",
221
- isContainer: false,
222
- acceptsBoundaryEvents: true,
223
- supportsMarkers: true,
224
- canBeStart: false,
225
- canBeEnd: false
226
- },
227
- CallActivity: {
228
- label: "Call Activity",
229
- icon: "ExternalLink",
230
- category: "task",
231
- defaultWidth: 120,
232
- defaultHeight: 60,
233
- handlePolicy: "all",
234
- orientation: "free",
235
- isContainer: false,
236
- acceptsBoundaryEvents: true,
237
- supportsMarkers: true,
238
- canBeStart: false,
239
- canBeEnd: false
240
- },
241
- // ─── Gateways ────────────────────────────────────────────────────────────────
242
- ExclusiveGateway: {
243
- label: "Exclusive Gateway",
244
- icon: "X",
245
- category: "gateway",
246
- defaultWidth: 50,
247
- defaultHeight: 50,
248
- handlePolicy: "all",
249
- orientation: "free",
250
- isContainer: false,
251
- acceptsBoundaryEvents: false,
252
- canBeStart: false,
253
- canBeEnd: false
254
- },
255
- InclusiveGateway: {
256
- label: "Inclusive Gateway",
257
- icon: "Circle",
258
- category: "gateway",
259
- defaultWidth: 50,
260
- defaultHeight: 50,
261
- handlePolicy: "all",
262
- orientation: "free",
263
- isContainer: false,
264
- acceptsBoundaryEvents: false,
265
- canBeStart: false,
266
- canBeEnd: false
267
- },
268
- ParallelGateway: {
269
- label: "Parallel Gateway",
270
- icon: "Plus",
271
- category: "gateway",
272
- defaultWidth: 50,
273
- defaultHeight: 50,
274
- handlePolicy: "all",
275
- orientation: "free",
276
- isContainer: false,
277
- acceptsBoundaryEvents: false,
278
- canBeStart: false,
279
- canBeEnd: false
280
- },
281
- EventBasedGateway: {
282
- label: "Event-Based Gateway",
283
- icon: "Radio",
284
- category: "gateway",
285
- defaultWidth: 50,
286
- defaultHeight: 50,
287
- handlePolicy: "all",
288
- orientation: "free",
289
- isContainer: false,
290
- acceptsBoundaryEvents: false,
291
- canBeStart: false,
292
- canBeEnd: false,
293
- maxIncoming: 1
294
- },
295
- ComplexGateway: {
296
- label: "Complex Gateway",
297
- icon: "Asterisk",
298
- category: "gateway",
299
- defaultWidth: 50,
300
- defaultHeight: 50,
301
- handlePolicy: "all",
302
- orientation: "free",
303
- isContainer: false,
304
- acceptsBoundaryEvents: false,
305
- canBeStart: false,
306
- canBeEnd: false
307
- },
308
- // ─── Containers ───────────────────────────────────────────────────────────────
309
- SubProcess: {
310
- label: "Sub-Process",
311
- icon: "PlusSquare",
312
- category: "container",
313
- defaultWidth: 350,
314
- defaultHeight: 200,
315
- handlePolicy: "all",
316
- orientation: "horizontal",
317
- isContainer: true,
318
- acceptsBoundaryEvents: true,
319
- supportsCollapse: true,
320
- supportsMarkers: true,
321
- canBeStart: false,
322
- canBeEnd: false
323
- },
324
- Transaction: {
325
- label: "Transaction",
326
- icon: "Receipt",
327
- category: "container",
328
- defaultWidth: 350,
329
- defaultHeight: 200,
330
- handlePolicy: "all",
331
- orientation: "horizontal",
332
- isContainer: true,
333
- acceptsBoundaryEvents: true,
334
- supportsCollapse: true,
335
- supportsMarkers: true,
336
- canBeStart: false,
337
- canBeEnd: false
338
- },
339
- EventSubProcess: {
340
- label: "Event Sub-Process",
341
- icon: "CircleDotDashed",
342
- category: "container",
343
- defaultWidth: 350,
344
- defaultHeight: 200,
345
- handlePolicy: "all",
346
- orientation: "horizontal",
347
- isContainer: true,
348
- acceptsBoundaryEvents: false,
349
- supportsCollapse: true,
350
- supportsMarkers: true,
351
- canBeStart: false,
352
- canBeEnd: false
353
- },
354
- AdHocSubProcess: {
355
- label: "Ad-Hoc Sub-Process",
356
- icon: "Waves",
357
- category: "container",
358
- defaultWidth: 350,
359
- defaultHeight: 200,
360
- handlePolicy: "all",
361
- orientation: "horizontal",
362
- isContainer: true,
363
- acceptsBoundaryEvents: true,
364
- supportsCollapse: true,
365
- supportsMarkers: true,
366
- canBeStart: false,
367
- canBeEnd: false
368
- },
369
- Pool: {
370
- label: "Pool",
371
- icon: "Rows3",
372
- category: "container",
373
- defaultWidth: 600,
374
- defaultHeight: 200,
375
- handlePolicy: "none",
376
- orientation: "horizontal",
377
- isContainer: true,
378
- acceptsBoundaryEvents: false,
379
- canBeStart: false,
380
- canBeEnd: false,
381
- maxIncoming: 0,
382
- maxOutgoing: 0
383
- },
384
- Lane: {
385
- label: "Lane",
386
- icon: "PanelTop",
387
- category: "container",
388
- defaultWidth: 600,
389
- defaultHeight: 120,
390
- handlePolicy: "none",
391
- orientation: "horizontal",
392
- isContainer: true,
393
- acceptsBoundaryEvents: false,
394
- canBeStart: false,
395
- canBeEnd: false,
396
- maxIncoming: 0,
397
- maxOutgoing: 0
398
- },
399
- // ─── Artifacts ────────────────────────────────────────────────────────────────
400
- Annotation: {
401
- label: "Text Annotation",
402
- icon: "StickyNote",
403
- category: "artifact",
404
- defaultWidth: 100,
405
- defaultHeight: 60,
406
- handlePolicy: "none",
407
- orientation: "free",
408
- isContainer: false,
409
- acceptsBoundaryEvents: false,
410
- canBeStart: false,
411
- canBeEnd: false,
412
- maxIncoming: 0,
413
- maxOutgoing: 0
414
- },
415
- Group: {
416
- label: "Group",
417
- icon: "Group",
418
- category: "artifact",
419
- defaultWidth: 300,
420
- defaultHeight: 200,
421
- handlePolicy: "none",
422
- orientation: "free",
423
- isContainer: false,
424
- acceptsBoundaryEvents: false,
425
- canBeStart: false,
426
- canBeEnd: false,
427
- maxIncoming: 0,
428
- maxOutgoing: 0
429
- },
430
- // ─── Data (BPMN 2.0 §10.3) ───────────────────────────────────────────────────
431
- DataObject: {
432
- label: "Data Object",
433
- icon: "File",
434
- category: "data",
435
- defaultWidth: 36,
436
- defaultHeight: 50,
437
- handlePolicy: "all",
438
- orientation: "free",
439
- isContainer: false,
440
- acceptsBoundaryEvents: false,
441
- canBeStart: false,
442
- canBeEnd: false,
443
- maxIncoming: 0,
444
- maxOutgoing: 0
445
- },
446
- DataObjectReference: {
447
- label: "Data Object Reference",
448
- icon: "FileSymlink",
449
- category: "data",
450
- defaultWidth: 36,
451
- defaultHeight: 50,
452
- handlePolicy: "all",
453
- orientation: "free",
454
- isContainer: false,
455
- acceptsBoundaryEvents: false,
456
- canBeStart: false,
457
- canBeEnd: false,
458
- maxIncoming: 0,
459
- maxOutgoing: 0
460
- },
461
- DataInput: {
462
- label: "Data Input",
463
- icon: "FileInput",
464
- category: "data",
465
- defaultWidth: 36,
466
- defaultHeight: 50,
467
- handlePolicy: "all",
468
- orientation: "free",
469
- isContainer: false,
470
- acceptsBoundaryEvents: false,
471
- canBeStart: false,
472
- canBeEnd: false,
473
- maxIncoming: 0
474
- },
475
- DataOutput: {
476
- label: "Data Output",
477
- icon: "FileOutput",
478
- category: "data",
479
- defaultWidth: 36,
480
- defaultHeight: 50,
481
- handlePolicy: "all",
482
- orientation: "free",
483
- isContainer: false,
484
- acceptsBoundaryEvents: false,
485
- canBeStart: false,
486
- canBeEnd: false,
487
- maxOutgoing: 0
488
- },
489
- DataStore: {
490
- label: "Data Store",
491
- icon: "Database",
492
- category: "data",
493
- defaultWidth: 50,
494
- defaultHeight: 50,
495
- handlePolicy: "all",
496
- orientation: "free",
497
- isContainer: false,
498
- acceptsBoundaryEvents: false,
499
- canBeStart: false,
500
- canBeEnd: false,
501
- maxIncoming: 0,
502
- maxOutgoing: 0
503
- },
504
- DataStoreReference: {
505
- label: "Data Store Reference",
506
- icon: "DatabaseZap",
507
- category: "data",
508
- defaultWidth: 50,
509
- defaultHeight: 50,
510
- handlePolicy: "all",
511
- orientation: "free",
512
- isContainer: false,
513
- acceptsBoundaryEvents: false,
514
- canBeStart: false,
515
- canBeEnd: false,
516
- maxIncoming: 0,
517
- maxOutgoing: 0
518
- },
519
- // ─── Conversation (BPMN 2.0 §12) ─────────────────────────────────────────────
520
- Conversation: {
521
- label: "Conversation",
522
- icon: "MessageCircle",
523
- category: "conversation",
524
- defaultWidth: 60,
525
- defaultHeight: 52,
526
- handlePolicy: "all",
527
- orientation: "free",
528
- isContainer: false,
529
- acceptsBoundaryEvents: false,
530
- canBeStart: false,
531
- canBeEnd: false
532
- },
533
- SubConversation: {
534
- label: "Sub-Conversation",
535
- icon: "MessagesSquare",
536
- category: "conversation",
537
- defaultWidth: 60,
538
- defaultHeight: 52,
539
- handlePolicy: "all",
540
- orientation: "free",
541
- isContainer: true,
542
- acceptsBoundaryEvents: false,
543
- supportsCollapse: true,
544
- canBeStart: false,
545
- canBeEnd: false
546
- },
547
- CallConversation: {
548
- label: "Call Conversation",
549
- icon: "PhoneCall",
550
- category: "conversation",
551
- defaultWidth: 60,
552
- defaultHeight: 52,
553
- handlePolicy: "all",
554
- orientation: "free",
555
- isContainer: false,
556
- acceptsBoundaryEvents: false,
557
- canBeStart: false,
558
- canBeEnd: false
559
- },
560
- // ─── Choreography (BPMN 2.0 §11) ─────────────────────────────────────────────
561
- ChoreographyTask: {
562
- label: "Choreography Task",
563
- icon: "ArrowLeftRight",
564
- category: "choreography",
565
- defaultWidth: 120,
566
- defaultHeight: 80,
567
- handlePolicy: "all",
568
- orientation: "horizontal",
569
- isContainer: false,
570
- acceptsBoundaryEvents: false,
571
- canBeStart: false,
572
- canBeEnd: false
573
- },
574
- SubChoreography: {
575
- label: "Sub-Choreography",
576
- icon: "BoxSelect",
577
- category: "choreography",
578
- defaultWidth: 120,
579
- defaultHeight: 80,
580
- handlePolicy: "all",
581
- orientation: "horizontal",
582
- isContainer: true,
583
- acceptsBoundaryEvents: false,
584
- supportsCollapse: true,
585
- canBeStart: false,
586
- canBeEnd: false
587
- },
588
- CallChoreography: {
589
- label: "Call Choreography",
590
- icon: "Phone",
591
- category: "choreography",
592
- defaultWidth: 120,
593
- defaultHeight: 80,
594
- handlePolicy: "all",
595
- orientation: "horizontal",
596
- isContainer: false,
597
- acceptsBoundaryEvents: false,
598
- canBeStart: false,
599
- canBeEnd: false
600
- }
601
- };
602
- BPMN_RESIZABLE_ELEMENT_TYPES = [
603
- "Task",
604
- "UserTask",
605
- "ServiceTask",
606
- "ScriptTask",
607
- "ManualTask",
608
- "BusinessRuleTask",
609
- "ReceiveTask",
610
- "SendTask",
611
- "CallActivity",
612
- "SubProcess",
613
- "Transaction",
614
- "EventSubProcess",
615
- "AdHocSubProcess",
616
- "Pool",
617
- "Lane",
618
- "Annotation",
619
- "Group",
620
- "SubConversation",
621
- "ChoreographyTask",
622
- "SubChoreography",
623
- "CallChoreography"
624
- ];
625
- BPMN_MIN_SIZE_OVERRIDES = {
626
- Task: { minWidth: 80, minHeight: 48 },
627
- UserTask: { minWidth: 80, minHeight: 48 },
628
- ServiceTask: { minWidth: 80, minHeight: 48 },
629
- ScriptTask: { minWidth: 80, minHeight: 48 },
630
- ManualTask: { minWidth: 80, minHeight: 48 },
631
- BusinessRuleTask: { minWidth: 80, minHeight: 48 },
632
- ReceiveTask: { minWidth: 80, minHeight: 48 },
633
- SendTask: { minWidth: 80, minHeight: 48 },
634
- CallActivity: { minWidth: 80, minHeight: 48 },
635
- SubProcess: { minWidth: 160, minHeight: 100 },
636
- Transaction: { minWidth: 160, minHeight: 100 },
637
- EventSubProcess: { minWidth: 160, minHeight: 100 },
638
- AdHocSubProcess: { minWidth: 160, minHeight: 100 },
639
- Pool: { minWidth: 240, minHeight: 120 },
640
- Lane: { minWidth: 240, minHeight: 80 },
641
- Annotation: { minWidth: 80, minHeight: 40 },
642
- Group: { minWidth: 120, minHeight: 80 },
643
- SubConversation: { minWidth: 60, minHeight: 52 },
644
- ChoreographyTask: { minWidth: 100, minHeight: 70 },
645
- SubChoreography: { minWidth: 100, minHeight: 70 },
646
- CallChoreography: { minWidth: 100, minHeight: 70 }
647
- };
648
- resizableTypes = new Set(BPMN_RESIZABLE_ELEMENT_TYPES);
649
- }
650
- });
651
638
 
652
639
  // src/elements/guards.ts
640
+ var GATEWAY_TYPES = /* @__PURE__ */ new Set([
641
+ "ExclusiveGateway",
642
+ "InclusiveGateway",
643
+ "ParallelGateway",
644
+ "EventBasedGateway",
645
+ "ComplexGateway"
646
+ ]);
647
+ var EVENT_TYPES = /* @__PURE__ */ new Set([
648
+ "StartEvent",
649
+ "EndEvent",
650
+ "IntermediateCatchEvent",
651
+ "IntermediateThrowEvent",
652
+ "BoundaryEvent"
653
+ ]);
654
+ var DATA_TYPES = /* @__PURE__ */ new Set([
655
+ "DataObject",
656
+ "DataObjectReference",
657
+ "DataInput",
658
+ "DataOutput",
659
+ "DataStore",
660
+ "DataStoreReference"
661
+ ]);
653
662
  function isGatewayType(type) {
654
663
  return GATEWAY_TYPES.has(type);
655
664
  }
@@ -665,34 +674,45 @@ function acceptsBoundaryEvents(type) {
665
674
  function getHandlePolicy(type) {
666
675
  return BPMN_ELEMENT_CATALOG[type].handlePolicy;
667
676
  }
668
- var GATEWAY_TYPES, EVENT_TYPES, DATA_TYPES;
669
- var init_guards = __esm({
670
- "src/elements/guards.ts"() {
671
- init_catalog();
672
- GATEWAY_TYPES = /* @__PURE__ */ new Set([
673
- "ExclusiveGateway",
674
- "InclusiveGateway",
675
- "ParallelGateway",
676
- "EventBasedGateway",
677
- "ComplexGateway"
678
- ]);
679
- EVENT_TYPES = /* @__PURE__ */ new Set([
680
- "StartEvent",
681
- "EndEvent",
682
- "IntermediateCatchEvent",
683
- "IntermediateThrowEvent",
684
- "BoundaryEvent"
685
- ]);
686
- DATA_TYPES = /* @__PURE__ */ new Set([
687
- "DataObject",
688
- "DataObjectReference",
689
- "DataInput",
690
- "DataOutput",
691
- "DataStore",
692
- "DataStoreReference"
693
- ]);
677
+
678
+ // src/modeling/index.ts
679
+ var BPMN_EDGE_CONNECTION_RULES = {
680
+ sequenceFlow: {
681
+ edgeType: "sequenceFlow",
682
+ sourceCategories: ["flowNode"],
683
+ targetCategories: ["flowNode"],
684
+ allowSameParent: true,
685
+ allowDifferentParent: false
686
+ },
687
+ messageFlow: {
688
+ edgeType: "messageFlow",
689
+ sourceCategories: ["flowNode"],
690
+ targetCategories: ["flowNode"],
691
+ allowSameParent: false,
692
+ allowDifferentParent: true
693
+ },
694
+ association: {
695
+ edgeType: "association",
696
+ sourceCategories: ["flowNode", "artifact", "data"],
697
+ targetCategories: ["flowNode", "artifact", "data"],
698
+ allowSameParent: true,
699
+ allowDifferentParent: true
700
+ },
701
+ dataAssociation: {
702
+ edgeType: "dataAssociation",
703
+ sourceCategories: ["flowNode", "data"],
704
+ targetCategories: ["flowNode", "data"],
705
+ allowSameParent: true,
706
+ allowDifferentParent: true
707
+ },
708
+ conversationLink: {
709
+ edgeType: "conversationLink",
710
+ sourceCategories: ["conversation", "flowNode"],
711
+ targetCategories: ["conversation", "flowNode"],
712
+ allowSameParent: true,
713
+ allowDifferentParent: true
694
714
  }
695
- });
715
+ };
696
716
  function inferBpmnEdgeType(state, sourceId, targetId) {
697
717
  const source = diagramsCore.getNode(state, sourceId);
698
718
  const target = diagramsCore.getNode(state, targetId);
@@ -797,109 +817,82 @@ function validateEdgeCardinality(state, edgeType, source, target) {
797
817
  }
798
818
  return true;
799
819
  }
800
- var BPMN_EDGE_CONNECTION_RULES, bpmnConnectionValidators;
801
- var init_modeling = __esm({
802
- "src/modeling/index.ts"() {
803
- init_catalog();
804
- init_guards();
805
- init_catalog();
806
- BPMN_EDGE_CONNECTION_RULES = {
807
- sequenceFlow: {
808
- edgeType: "sequenceFlow",
809
- sourceCategories: ["flowNode"],
810
- targetCategories: ["flowNode"],
811
- allowSameParent: true,
812
- allowDifferentParent: false
813
- },
814
- messageFlow: {
815
- edgeType: "messageFlow",
816
- sourceCategories: ["flowNode"],
817
- targetCategories: ["flowNode"],
818
- allowSameParent: false,
819
- allowDifferentParent: true
820
- },
821
- association: {
822
- edgeType: "association",
823
- sourceCategories: ["flowNode", "artifact", "data"],
824
- targetCategories: ["flowNode", "artifact", "data"],
825
- allowSameParent: true,
826
- allowDifferentParent: true
827
- },
828
- dataAssociation: {
829
- edgeType: "dataAssociation",
830
- sourceCategories: ["flowNode", "data"],
831
- targetCategories: ["flowNode", "data"],
832
- allowSameParent: true,
833
- allowDifferentParent: true
834
- },
835
- conversationLink: {
836
- edgeType: "conversationLink",
837
- sourceCategories: ["conversation", "flowNode"],
838
- targetCategories: ["conversation", "flowNode"],
839
- allowSameParent: true,
840
- allowDifferentParent: true
820
+ var bpmnConnectionValidators = [
821
+ ({ state, source, target }) => {
822
+ if (source.id === target.id) return "BPMN self-connections are not allowed.";
823
+ const edgeType = inferBpmnEdgeType(state, source.id, target.id);
824
+ if (getHandlePolicy(source.data.elementType) === "none" || getHandlePolicy(target.data.elementType) === "none") {
825
+ return "Elements without BPMN connection handles cannot be directly connected.";
826
+ }
827
+ if (edgeType === "sequenceFlow") {
828
+ return validateBpmnConnectionForEdgeType(state, edgeType, source, target);
829
+ }
830
+ return validateBpmnConnectionForEdgeType(state, edgeType, source, target);
831
+ }
832
+ ];
833
+ diagramsCore.createModelingRules({
834
+ connect: [
835
+ ({ state, source, target }) => {
836
+ if (!source || !target) return false;
837
+ for (const validator of bpmnConnectionValidators) {
838
+ const result = validator({
839
+ state,
840
+ source,
841
+ target,
842
+ existingEdges: state.edges
843
+ });
844
+ if (result !== true) return result;
841
845
  }
842
- };
843
- bpmnConnectionValidators = [
844
- ({ state, source, target }) => {
845
- if (source.id === target.id) return "BPMN self-connections are not allowed.";
846
- const edgeType = inferBpmnEdgeType(state, source.id, target.id);
847
- if (getHandlePolicy(source.data.elementType) === "none" || getHandlePolicy(target.data.elementType) === "none") {
848
- return "Elements without BPMN connection handles cannot be directly connected.";
849
- }
850
- if (edgeType === "sequenceFlow") {
851
- return validateBpmnConnectionForEdgeType(state, edgeType, source, target);
852
- }
853
- return validateBpmnConnectionForEdgeType(state, edgeType, source, target);
846
+ return true;
847
+ }
848
+ ],
849
+ drop: [
850
+ ({ node, parent }) => {
851
+ if (!node || !parent) return true;
852
+ if (node.data.elementType === "BoundaryEvent") {
853
+ return acceptsBoundaryEvents(parent.data.elementType) ? true : "Boundary events can only be attached to tasks or subprocesses.";
854
854
  }
855
- ];
856
- diagramsCore.createModelingRules({
857
- connect: [
858
- ({ state, source, target }) => {
859
- if (!source || !target) return false;
860
- for (const validator of bpmnConnectionValidators) {
861
- const result = validator({
862
- state,
863
- source,
864
- target,
865
- existingEdges: state.edges
866
- });
867
- if (result !== true) return result;
868
- }
869
- return true;
870
- }
871
- ],
872
- drop: [
873
- ({ node, parent }) => {
874
- if (!node || !parent) return true;
875
- if (node.data.elementType === "BoundaryEvent") {
876
- return acceptsBoundaryEvents(parent.data.elementType) ? true : "Boundary events can only be attached to tasks or subprocesses.";
877
- }
878
- return canContainBpmnElement(parent.data.elementType, node.data.elementType);
879
- }
880
- ],
881
- reparent: [
882
- ({ node, parent }) => {
883
- if (!node || !parent) return true;
884
- if (node.data.elementType === "BoundaryEvent") {
885
- return acceptsBoundaryEvents(parent.data.elementType) ? true : "Boundary events can only be reparented to tasks or subprocesses.";
886
- }
887
- return canContainBpmnElement(parent?.data.elementType, node.data.elementType);
888
- }
889
- ],
890
- delete: [() => true],
891
- resize: [
892
- ({ node }) => !node || isBpmnElementResizable(node.data.elementType) ? true : `${node.data.elementType} is not resizable in BPMN.`
893
- ]
894
- });
895
- }
896
- });
897
-
898
- // src/layout/elk.ts
899
- var elk_exports = {};
900
- __export(elk_exports, {
901
- bpmnElkLayout: () => bpmnElkLayout
855
+ return canContainBpmnElement(parent.data.elementType, node.data.elementType);
856
+ }
857
+ ],
858
+ reparent: [
859
+ ({ node, parent }) => {
860
+ if (!node || !parent) return true;
861
+ if (node.data.elementType === "BoundaryEvent") {
862
+ return acceptsBoundaryEvents(parent.data.elementType) ? true : "Boundary events can only be reparented to tasks or subprocesses.";
863
+ }
864
+ return canContainBpmnElement(parent?.data.elementType, node.data.elementType);
865
+ }
866
+ ],
867
+ delete: [() => true],
868
+ resize: [
869
+ ({ node }) => !node || isBpmnElementResizable(node.data.elementType) ? true : `${node.data.elementType} is not resizable in BPMN.`
870
+ ]
902
871
  });
872
+ var BPMN_CONTAINER_TYPES = /* @__PURE__ */ new Set([
873
+ "Pool",
874
+ "Lane",
875
+ "SubProcess",
876
+ "Transaction",
877
+ "EventSubProcess",
878
+ "AdHocSubProcess"
879
+ ]);
880
+ var CONTAINER_MIN_SIZE = {
881
+ Pool: { w: 720, h: 200 },
882
+ Lane: { w: 600, h: 160 },
883
+ SubProcess: { w: 240, h: 140 },
884
+ Transaction: { w: 240, h: 140 },
885
+ EventSubProcess: { w: 240, h: 140 },
886
+ AdHocSubProcess: { w: 240, h: 140 }
887
+ };
888
+ var CONTAINER_PADDING = {
889
+ Pool: "[top=30,left=60,bottom=30,right=50]",
890
+ Lane: "[top=40,left=70,bottom=40,right=50]",
891
+ SubProcess: "[top=30,left=40,bottom=30,right=40]",
892
+ Transaction: "[top=30,left=40,bottom=30,right=40]",
893
+ EventSubProcess: "[top=30,left=40,bottom=30,right=40]",
894
+ AdHocSubProcess: "[top=30,left=40,bottom=30,right=40]"
895
+ };
903
896
  async function bpmnElkLayout(nodes, edges) {
904
897
  const poolsWithLanes = /* @__PURE__ */ new Set();
905
898
  for (const node of nodes) {
@@ -1032,40 +1025,6 @@ async function bpmnElkLayout(nodes, edges) {
1032
1025
  });
1033
1026
  return { nodes: updatedNodes, edges: updatedEdges };
1034
1027
  }
1035
- var BPMN_CONTAINER_TYPES, CONTAINER_MIN_SIZE, CONTAINER_PADDING;
1036
- var init_elk = __esm({
1037
- "src/layout/elk.ts"() {
1038
- init_modeling();
1039
- BPMN_CONTAINER_TYPES = /* @__PURE__ */ new Set([
1040
- "Pool",
1041
- "Lane",
1042
- "SubProcess",
1043
- "Transaction",
1044
- "EventSubProcess",
1045
- "AdHocSubProcess"
1046
- ]);
1047
- CONTAINER_MIN_SIZE = {
1048
- Pool: { w: 720, h: 200 },
1049
- Lane: { w: 600, h: 160 },
1050
- SubProcess: { w: 240, h: 140 },
1051
- Transaction: { w: 240, h: 140 },
1052
- EventSubProcess: { w: 240, h: 140 },
1053
- AdHocSubProcess: { w: 240, h: 140 }
1054
- };
1055
- CONTAINER_PADDING = {
1056
- Pool: "[top=30,left=60,bottom=30,right=50]",
1057
- Lane: "[top=40,left=70,bottom=40,right=50]",
1058
- SubProcess: "[top=30,left=40,bottom=30,right=40]",
1059
- Transaction: "[top=30,left=40,bottom=30,right=40]",
1060
- EventSubProcess: "[top=30,left=40,bottom=30,right=40]",
1061
- AdHocSubProcess: "[top=30,left=40,bottom=30,right=40]"
1062
- };
1063
- }
1064
- });
1065
-
1066
- // src/layout/index.ts
1067
- init_modeling();
1068
- init_elk();
1069
1028
 
1070
1029
  // src/layout/bpmn-layout-graph.ts
1071
1030
  var LAYOUT_CONTAINER_TYPES = /* @__PURE__ */ new Set([
@@ -1084,15 +1043,21 @@ var LAYOUT_GATEWAY_TYPES = /* @__PURE__ */ new Set([
1084
1043
  "ComplexGateway"
1085
1044
  ]);
1086
1045
  function detectBackEdges(nodeIds, seqEdges) {
1046
+ const sortedIds = [...nodeIds].sort();
1087
1047
  const backEdgeIds = /* @__PURE__ */ new Set();
1088
1048
  const state = /* @__PURE__ */ new Map();
1089
- for (const id of nodeIds) state.set(id, 0);
1049
+ for (const id of sortedIds) state.set(id, 0);
1090
1050
  const adj = /* @__PURE__ */ new Map();
1091
- for (const id of nodeIds) adj.set(id, []);
1051
+ for (const id of sortedIds) adj.set(id, []);
1092
1052
  for (const e of seqEdges) {
1093
1053
  adj.get(e.source)?.push({ target: e.target, edgeId: e.id });
1094
1054
  }
1095
- for (const startId of nodeIds) {
1055
+ for (const list of adj.values()) {
1056
+ list.sort(
1057
+ (a, b) => a.target < b.target ? -1 : a.target > b.target ? 1 : a.edgeId < b.edgeId ? -1 : a.edgeId > b.edgeId ? 1 : 0
1058
+ );
1059
+ }
1060
+ for (const startId of sortedIds) {
1096
1061
  if (state.get(startId) !== 0) continue;
1097
1062
  const stack = [{ id: startId, idx: 0 }];
1098
1063
  state.set(startId, 1);
@@ -1169,9 +1134,7 @@ function detectGatewayPairs(nodes, forwardEdges) {
1169
1134
  }
1170
1135
  const order = topologicalSort(nodeIds, forwardEdges);
1171
1136
  const topoPos = new Map(order.map((id, i) => [id, i]));
1172
- const splits = nodes.filter(
1173
- (n) => LAYOUT_GATEWAY_TYPES.has(n.data.elementType) && (succs.get(n.id)?.length ?? 0) > 1
1174
- );
1137
+ const splits = nodes.filter((n) => (succs.get(n.id)?.length ?? 0) > 1);
1175
1138
  for (const split of splits) {
1176
1139
  const branches = succs.get(split.id) ?? [];
1177
1140
  if (branches.length < 2) continue;
@@ -1223,12 +1186,18 @@ function buildHandleMap(edges) {
1223
1186
  }
1224
1187
  return map;
1225
1188
  }
1189
+ function branchPullBias(nodeIds, nodeBias) {
1190
+ if (!nodeBias) return null;
1191
+ let sum = 0;
1192
+ for (const id of nodeIds) sum += nodeBias.get(id) ?? 0;
1193
+ if (sum === 0) return null;
1194
+ return sum > 0 ? 1 : -1;
1195
+ }
1226
1196
  function pickMainBranch(branchData) {
1227
1197
  if (branchData.length === 0) return void 0;
1228
1198
  return [...branchData].sort((a, b) => {
1229
- const aRight = a.bias === 0 ? 1 : 0;
1230
- const bRight = b.bias === 0 ? 1 : 0;
1231
- if (aRight !== bRight) return bRight - aRight;
1199
+ const rank = (branch) => branch.bias === 0 ? 2 : branch.bias === null ? 1 : 0;
1200
+ if (rank(a) !== rank(b)) return rank(b) - rank(a);
1232
1201
  if (a.nodeIds.length !== b.nodeIds.length) return b.nodeIds.length - a.nodeIds.length;
1233
1202
  return a.start.localeCompare(b.start);
1234
1203
  })[0]?.start;
@@ -1269,7 +1238,7 @@ function assignBranchRowsAroundMain(branchData, splitRow) {
1269
1238
  }
1270
1239
  return assigned;
1271
1240
  }
1272
- function assignRows(nodes, forwardEdges, columns, gatewayPairs) {
1241
+ function assignRows(nodes, forwardEdges, columns, gatewayPairs, nodeBias) {
1273
1242
  const rows = new Map(nodes.map((n) => [n.id, 0]));
1274
1243
  const succs = new Map(nodes.map((n) => [n.id, []]));
1275
1244
  for (const e of forwardEdges) {
@@ -1277,7 +1246,7 @@ function assignRows(nodes, forwardEdges, columns, gatewayPairs) {
1277
1246
  }
1278
1247
  const handleMap = buildHandleMap(forwardEdges);
1279
1248
  const sortedPairs = [...gatewayPairs.entries()].sort(
1280
- (a, b) => (columns.get(b[0]) ?? 0) - (columns.get(a[0]) ?? 0)
1249
+ (a, b) => (columns.get(a[0]) ?? 0) - (columns.get(b[0]) ?? 0)
1281
1250
  );
1282
1251
  for (const [splitId, mergeId] of sortedPairs) {
1283
1252
  const branches = succs.get(splitId) ?? [];
@@ -1297,11 +1266,14 @@ function assignRows(nodes, forwardEdges, columns, gatewayPairs) {
1297
1266
  return result;
1298
1267
  };
1299
1268
  const splitHandles = handleMap.get(splitId);
1300
- const branchData = branches.map((start) => ({
1301
- start,
1302
- nodeIds: getBranchNodes(start),
1303
- bias: handleToRowBias(splitHandles?.get(start) ?? null)
1304
- }));
1269
+ const branchData = branches.map((start) => {
1270
+ const nodeIds = getBranchNodes(start);
1271
+ return {
1272
+ start,
1273
+ nodeIds,
1274
+ bias: handleToRowBias(splitHandles?.get(start) ?? null) ?? branchPullBias(nodeIds, nodeBias)
1275
+ };
1276
+ });
1305
1277
  const assigned = assignBranchRowsAroundMain(branchData, splitRow);
1306
1278
  for (const b of branchData) {
1307
1279
  const row = assigned.get(b.start) ?? splitRow;
@@ -1313,7 +1285,7 @@ function assignRows(nodes, forwardEdges, columns, gatewayPairs) {
1313
1285
  }
1314
1286
  const pairedSplits = new Set(gatewayPairs.keys());
1315
1287
  const unpairedSplits = nodes.filter(
1316
- (n) => LAYOUT_GATEWAY_TYPES.has(n.data.elementType) && !pairedSplits.has(n.id) && (succs.get(n.id)?.length ?? 0) > 1
1288
+ (n) => !pairedSplits.has(n.id) && (succs.get(n.id)?.length ?? 0) > 1
1317
1289
  );
1318
1290
  for (const split of unpairedSplits) {
1319
1291
  const branches = succs.get(split.id) ?? [];
@@ -1333,11 +1305,14 @@ function assignRows(nodes, forwardEdges, columns, gatewayPairs) {
1333
1305
  return result;
1334
1306
  };
1335
1307
  const splitHandles2 = handleMap.get(split.id);
1336
- const branchData = branches.map((start) => ({
1337
- start,
1338
- nodeIds: getAllReachable(start),
1339
- bias: handleToRowBias(splitHandles2?.get(start) ?? null)
1340
- }));
1308
+ const branchData = branches.map((start) => {
1309
+ const nodeIds = getAllReachable(start);
1310
+ return {
1311
+ start,
1312
+ nodeIds,
1313
+ bias: handleToRowBias(splitHandles2?.get(start) ?? null) ?? branchPullBias(nodeIds, nodeBias)
1314
+ };
1315
+ });
1341
1316
  const assigned2 = assignBranchRowsAroundMain(branchData, splitRow);
1342
1317
  for (const b of branchData) {
1343
1318
  const row = assigned2.get(b.start) ?? splitRow;
@@ -1390,6 +1365,17 @@ var LAYOUT_TASK_TYPES = /* @__PURE__ */ new Set([
1390
1365
  ]);
1391
1366
  var TASK_LAYOUT_MIN_W = 130;
1392
1367
  var TASK_LAYOUT_MIN_H = 80;
1368
+ var SUBPROCESS_LAYOUT_MIN_W = 160;
1369
+ var SUBPROCESS_LAYOUT_MIN_H = 80;
1370
+ function layoutMinSize(node) {
1371
+ if (LAYOUT_TASK_TYPES.has(node.data.elementType)) {
1372
+ return { w: TASK_LAYOUT_MIN_W, h: TASK_LAYOUT_MIN_H };
1373
+ }
1374
+ if (COLLAPSED_SUBPROCESS_TYPES.has(node.data.elementType) && !node.data.isExpanded) {
1375
+ return { w: SUBPROCESS_LAYOUT_MIN_W, h: SUBPROCESS_LAYOUT_MIN_H };
1376
+ }
1377
+ return null;
1378
+ }
1393
1379
  function nW(node) {
1394
1380
  return node.width ?? node.measured?.width ?? 120;
1395
1381
  }
@@ -1397,18 +1383,68 @@ function nH(node) {
1397
1383
  return node.height ?? node.measured?.height ?? 60;
1398
1384
  }
1399
1385
  function layoutW(node) {
1400
- return LAYOUT_TASK_TYPES.has(node.data.elementType) ? Math.max(nW(node), TASK_LAYOUT_MIN_W) : nW(node);
1386
+ const min = layoutMinSize(node);
1387
+ return min ? Math.max(nW(node), min.w) : nW(node);
1401
1388
  }
1402
1389
  function layoutH(node) {
1403
- return LAYOUT_TASK_TYPES.has(node.data.elementType) ? Math.max(nH(node), TASK_LAYOUT_MIN_H) : nH(node);
1390
+ const min = layoutMinSize(node);
1391
+ return min ? Math.max(nH(node), min.h) : nH(node);
1392
+ }
1393
+ var LABEL_RESERVE_TYPES = /* @__PURE__ */ new Set([
1394
+ ...LAYOUT_GATEWAY_TYPES,
1395
+ "StartEvent",
1396
+ "EndEvent",
1397
+ "IntermediateCatchEvent",
1398
+ "IntermediateThrowEvent"
1399
+ ]);
1400
+ var LABEL_CHAR_W = 6.5;
1401
+ var LABEL_RESERVE_MAX = 150;
1402
+ function columnW(node) {
1403
+ const base = layoutW(node);
1404
+ if (!LABEL_RESERVE_TYPES.has(node.data.elementType)) return base;
1405
+ const label = typeof node.data.label === "string" ? node.data.label : "";
1406
+ if (!label) return base;
1407
+ const reserve = Math.min(Math.ceil(label.length * LABEL_CHAR_W), LABEL_RESERVE_MAX);
1408
+ return Math.max(base, reserve);
1404
1409
  }
1405
1410
  function applyLayoutMinSize(node) {
1406
- if (!LAYOUT_TASK_TYPES.has(node.data.elementType)) return node;
1411
+ if (!layoutMinSize(node)) return node;
1407
1412
  const w = layoutW(node);
1408
1413
  const h = layoutH(node);
1409
1414
  if (w === nW(node) && h === nH(node)) return node;
1410
1415
  return { ...node, width: w, height: h, measured: { width: w, height: h } };
1411
1416
  }
1417
+ function computeRowMetrics(contextNodes, rows, includeRowZero) {
1418
+ const vals = contextNodes.map((n) => rows.get(n.id) ?? 0);
1419
+ const base = includeRowZero ? [0, ...vals] : vals;
1420
+ const minRow = Math.min(...base);
1421
+ const maxRow = Math.max(...base);
1422
+ const rowH = /* @__PURE__ */ new Map();
1423
+ for (let r = minRow; r <= maxRow; r++) rowH.set(r, ROW_HEIGHT);
1424
+ for (const node of contextNodes) {
1425
+ const r = rows.get(node.id) ?? 0;
1426
+ rowH.set(r, Math.max(rowH.get(r) ?? ROW_HEIGHT, layoutH(node)));
1427
+ }
1428
+ const rowY = /* @__PURE__ */ new Map();
1429
+ let y = 0;
1430
+ for (let r = minRow; r <= maxRow; r++) {
1431
+ rowY.set(r, y);
1432
+ y += (rowH.get(r) ?? ROW_HEIGHT) + ROW_GAP;
1433
+ }
1434
+ return { minRow, maxRow, rowH, rowY, contentH: y - ROW_GAP };
1435
+ }
1436
+ function reanchorBoundaryEdges(edges, boundaryEvents, contentIds) {
1437
+ if (boundaryEvents.length === 0) return edges;
1438
+ const hostByBoundaryId = /* @__PURE__ */ new Map();
1439
+ for (const be of boundaryEvents) {
1440
+ if (be.data.attachedToRef) hostByBoundaryId.set(be.id, be.data.attachedToRef);
1441
+ }
1442
+ if (hostByBoundaryId.size === 0) return edges;
1443
+ return edges.map((edge) => {
1444
+ const host = hostByBoundaryId.get(edge.source);
1445
+ return host && contentIds.has(host) ? { ...edge, source: host, sourceHandle: "source-bottom" } : edge;
1446
+ });
1447
+ }
1412
1448
  var BOUNDARY_SPACING = 10;
1413
1449
  function repositionBoundaryEvents(boundaryEvents, positionedContent) {
1414
1450
  if (boundaryEvents.length === 0) return [];
@@ -1465,7 +1501,8 @@ function layoutSubProcess(children, edges) {
1465
1501
  };
1466
1502
  }
1467
1503
  const contentIds = new Set(mainChildren.map((n) => n.id));
1468
- const seqEdges = extractSeqEdges(edges, contentIds);
1504
+ const graphEdges = reanchorBoundaryEdges(edges, boundaryEvents, contentIds);
1505
+ const seqEdges = extractSeqEdges(graphEdges, contentIds);
1469
1506
  const backIds = detectBackEdges([...contentIds], seqEdges);
1470
1507
  const fwdEdges = seqEdges.filter((e) => !backIds.has(e.id));
1471
1508
  const columns = assignColumns([...contentIds], fwdEdges);
@@ -1476,7 +1513,7 @@ function layoutSubProcess(children, edges) {
1476
1513
  for (let c = 0; c <= maxCol; c++) colW.set(c, 0);
1477
1514
  for (const node of mainChildren) {
1478
1515
  const c = columns.get(node.id) ?? 0;
1479
- colW.set(c, Math.max(colW.get(c) ?? 0, layoutW(node)));
1516
+ colW.set(c, Math.max(colW.get(c) ?? 0, columnW(node)));
1480
1517
  }
1481
1518
  const colX = /* @__PURE__ */ new Map();
1482
1519
  let cumX = 0;
@@ -1485,20 +1522,16 @@ function layoutSubProcess(children, edges) {
1485
1522
  cumX += (colW.get(c) ?? 120) + COL_GAP;
1486
1523
  }
1487
1524
  const contentW = cumX - COL_GAP;
1488
- const rowVals = [...rows.values()];
1489
- const minRow = Math.min(0, ...rowVals);
1490
- const maxRow = Math.max(0, ...rowVals);
1491
- const rowCount = maxRow - minRow + 1;
1492
- const contentH = rowCount * ROW_HEIGHT + Math.max(0, rowCount - 1) * ROW_GAP;
1525
+ const rowMetrics = computeRowMetrics(mainChildren, rows, true);
1493
1526
  const spW = Math.max(280, SP_PAD * 2 + contentW);
1494
- const spH = Math.max(160, SP_PAD * 2 + contentH);
1527
+ const spH = Math.max(160, SP_PAD * 2 + rowMetrics.contentH);
1495
1528
  const positionedChildren = mainChildren.map((node) => {
1496
1529
  const c = columns.get(node.id) ?? 0;
1497
1530
  const r = rows.get(node.id) ?? 0;
1498
1531
  const lw = layoutW(node);
1499
1532
  const lh = layoutH(node);
1500
1533
  const colOffset = (colX.get(c) ?? 0) + (colW.get(c) ?? 120) / 2 - lw / 2;
1501
- const rowOffset = (r - minRow) * (ROW_HEIGHT + ROW_GAP) + ROW_HEIGHT / 2 - lh / 2;
1534
+ const rowOffset = (rowMetrics.rowY.get(r) ?? 0) + (rowMetrics.rowH.get(r) ?? ROW_HEIGHT) / 2 - lh / 2;
1502
1535
  return applyLayoutMinSize({ ...node, position: { x: SP_PAD + colOffset, y: SP_PAD + rowOffset } });
1503
1536
  });
1504
1537
  const positionedBoundaries = repositionBoundaryEvents(boundaryEvents, positionedChildren);
@@ -1541,7 +1574,8 @@ function layoutPool(pool, lanes, content, allEdges) {
1541
1574
  nodeLaneId.set(node.id, lId);
1542
1575
  }
1543
1576
  const contentIds = new Set(mainContent.map((n) => n.id));
1544
- const seqEdges = extractSeqEdges(allEdges, contentIds);
1577
+ const graphEdges = reanchorBoundaryEdges(allEdges, boundaryEvents, contentIds);
1578
+ const seqEdges = extractSeqEdges(graphEdges, contentIds);
1545
1579
  const backIds = detectBackEdges([...contentIds], seqEdges);
1546
1580
  const fwdEdges = seqEdges.filter((e) => !backIds.has(e.id));
1547
1581
  const columns = assignColumns([...contentIds], fwdEdges);
@@ -1552,47 +1586,107 @@ function layoutPool(pool, lanes, content, allEdges) {
1552
1586
  if (!contentByLane.has(lId)) contentByLane.set(lId, []);
1553
1587
  contentByLane.get(lId).push(node);
1554
1588
  }
1589
+ const laneStackIndex = /* @__PURE__ */ new Map();
1590
+ sortedLanes.forEach((laneNode, index) => laneStackIndex.set(laneNode.id, index));
1591
+ laneStackIndex.set("_pool_", sortedLanes.length);
1592
+ const crossLanePull = /* @__PURE__ */ new Map();
1593
+ for (const e of fwdEdges) {
1594
+ const sLane = nodeLaneId.get(e.source) ?? "_pool_";
1595
+ const tLane = nodeLaneId.get(e.target) ?? "_pool_";
1596
+ if (sLane === tLane) continue;
1597
+ const dir = Math.sign((laneStackIndex.get(tLane) ?? 0) - (laneStackIndex.get(sLane) ?? 0));
1598
+ crossLanePull.set(e.source, (crossLanePull.get(e.source) ?? 0) + dir);
1599
+ crossLanePull.set(e.target, (crossLanePull.get(e.target) ?? 0) - dir);
1600
+ }
1555
1601
  for (const [, laneNodes] of contentByLane) {
1556
1602
  const laneNodeIds = new Set(laneNodes.map((n) => n.id));
1557
1603
  const intraEdges = fwdEdges.filter(
1558
1604
  (e) => laneNodeIds.has(e.source) && laneNodeIds.has(e.target)
1559
1605
  );
1560
1606
  const lanePairs = detectGatewayPairs(laneNodes, intraEdges);
1561
- const laneRows = assignRows(laneNodes, intraEdges, columns, lanePairs);
1607
+ const laneRows = assignRows(laneNodes, intraEdges, columns, lanePairs, crossLanePull);
1562
1608
  for (const [id, row] of laneRows) rows.set(id, row);
1563
1609
  }
1564
- const laneIds = hasLanes ? sortedLanes.map((l) => l.id) : ["_pool_"];
1610
+ const seqTouched = /* @__PURE__ */ new Set();
1611
+ for (const e of seqEdges) {
1612
+ seqTouched.add(e.source);
1613
+ seqTouched.add(e.target);
1614
+ }
1615
+ for (const [, laneNodes] of contentByLane) {
1616
+ const eventSPs = laneNodes.filter(
1617
+ (n) => n.data.elementType === "EventSubProcess" && !seqTouched.has(n.id)
1618
+ );
1619
+ if (eventSPs.length === 0) continue;
1620
+ const eventSpIds = new Set(eventSPs.map((n) => n.id));
1621
+ const otherRows = laneNodes.filter((n) => !eventSpIds.has(n.id)).map((n) => rows.get(n.id) ?? 0);
1622
+ const laneMaxRow = otherRows.length > 0 ? Math.max(...otherRows) : -1;
1623
+ for (const sp of eventSPs) rows.set(sp.id, laneMaxRow + 1);
1624
+ }
1625
+ const hasPoolDirectContent = [...nodeLaneId.values()].includes("_pool_");
1626
+ const laneIds = hasLanes ? [...sortedLanes.map((l) => l.id), ...hasPoolDirectContent ? ["_pool_"] : []] : ["_pool_"];
1565
1627
  const laneStats = /* @__PURE__ */ new Map();
1566
1628
  for (const laneId of laneIds) {
1567
- const laneRows = mainContent.filter((n) => nodeLaneId.get(n.id) === laneId).map((n) => rows.get(n.id) ?? 0);
1568
- if (laneRows.length === 0) {
1569
- laneStats.set(laneId, { minRow: 0, maxRow: 0, rowCount: 1, height: LANE_MIN_H });
1629
+ const laneNodes = mainContent.filter((n) => nodeLaneId.get(n.id) === laneId);
1630
+ if (laneNodes.length === 0) {
1631
+ laneStats.set(laneId, {
1632
+ minRow: 0,
1633
+ maxRow: 0,
1634
+ height: LANE_MIN_H,
1635
+ contentH: ROW_HEIGHT,
1636
+ rowH: /* @__PURE__ */ new Map([[0, ROW_HEIGHT]]),
1637
+ rowY: /* @__PURE__ */ new Map([[0, 0]])
1638
+ });
1570
1639
  } else {
1571
- const minRow = Math.min(...laneRows);
1572
- const maxRow = Math.max(...laneRows);
1573
- const rowCount = maxRow - minRow + 1;
1574
- const contentH = rowCount * ROW_HEIGHT + Math.max(0, rowCount - 1) * ROW_GAP;
1575
- const height = Math.max(LANE_MIN_H, LANE_V_PAD * 2 + contentH);
1576
- laneStats.set(laneId, { minRow, maxRow, rowCount, height });
1640
+ const m = computeRowMetrics(laneNodes, rows, false);
1641
+ const height = Math.max(LANE_MIN_H, LANE_V_PAD * 2 + m.contentH);
1642
+ laneStats.set(laneId, {
1643
+ minRow: m.minRow,
1644
+ maxRow: m.maxRow,
1645
+ height,
1646
+ contentH: m.contentH,
1647
+ rowH: m.rowH,
1648
+ rowY: m.rowY
1649
+ });
1577
1650
  }
1578
1651
  }
1579
- const maxCol = Math.max(0, ...[...columns.values()]);
1580
- const colW = /* @__PURE__ */ new Map();
1581
- for (let c = 0; c <= maxCol; c++) colW.set(c, 0);
1582
- for (const node of mainContent) {
1583
- const c = columns.get(node.id) ?? 0;
1584
- colW.set(c, Math.max(colW.get(c) ?? 0, layoutW(node)));
1585
- }
1586
- const colX = /* @__PURE__ */ new Map();
1587
- let cumX = 0;
1588
- for (let c = 0; c <= maxCol; c++) {
1589
- colX.set(c, cumX);
1590
- cumX += (colW.get(c) ?? 120) + COL_GAP;
1652
+ const laneColumnLayouts = /* @__PURE__ */ new Map();
1653
+ for (const laneId of laneIds) {
1654
+ const laneNodes = mainContent.filter(
1655
+ (node) => (nodeLaneId.get(node.id) ?? "_pool_") === laneId
1656
+ );
1657
+ const usedCols = [...new Set(laneNodes.map((node) => columns.get(node.id) ?? 0))].sort((a, b) => a - b);
1658
+ const colW = /* @__PURE__ */ new Map();
1659
+ for (const col of usedCols) colW.set(col, 0);
1660
+ for (const node of laneNodes) {
1661
+ const col = columns.get(node.id) ?? 0;
1662
+ colW.set(col, Math.max(colW.get(col) ?? 0, columnW(node)));
1663
+ }
1664
+ const colX = /* @__PURE__ */ new Map();
1665
+ let laneCumX = 0;
1666
+ for (const col of usedCols) {
1667
+ colX.set(col, laneCumX);
1668
+ laneCumX += (colW.get(col) ?? 120) + COL_GAP;
1669
+ }
1670
+ laneColumnLayouts.set(laneId, {
1671
+ colW,
1672
+ colX,
1673
+ contentW: usedCols.length > 0 ? laneCumX - COL_GAP : 0
1674
+ });
1591
1675
  }
1592
- const contentW = cumX - COL_GAP;
1593
- const innerW = LANE_LABEL_W + LANE_H_PAD + contentW + LANE_H_PAD;
1676
+ const baseLaneInnerW = Math.max(
1677
+ 0,
1678
+ ...laneIds.filter((laneId) => laneId !== "_pool_").map((laneId) => {
1679
+ const contentW = laneColumnLayouts.get(laneId)?.contentW ?? 0;
1680
+ return LANE_LABEL_W + LANE_H_PAD + contentW + LANE_H_PAD;
1681
+ })
1682
+ );
1683
+ const basePoolInnerW = Math.max(
1684
+ 0,
1685
+ ...laneIds.filter((laneId) => laneId === "_pool_").map((laneId) => (laneColumnLayouts.get(laneId)?.contentW ?? 0) + POOL_H_PAD * 2)
1686
+ );
1687
+ const innerW = Math.max(baseLaneInnerW, basePoolInnerW);
1594
1688
  const poolW = Math.max(POOL_MIN_W, innerW + POOL_INNER_PAD * 2);
1595
- const laneW = poolW - POOL_INNER_PAD * 2;
1689
+ let laneW = poolW - POOL_INNER_PAD * 2;
1596
1690
  const laneY = /* @__PURE__ */ new Map();
1597
1691
  let cumY = POOL_INNER_PAD;
1598
1692
  for (let i = 0; i < laneIds.length; i++) {
@@ -1607,20 +1701,106 @@ function layoutPool(pool, lanes, content, allEdges) {
1607
1701
  const r = rows.get(node.id) ?? 0;
1608
1702
  const laneId = nodeLaneId.get(node.id) ?? "_pool_";
1609
1703
  const stat = laneStats.get(laneId);
1704
+ const laneLayout = laneColumnLayouts.get(laneId);
1610
1705
  const lYOff = laneY.get(laneId) ?? 0;
1611
1706
  const lw = layoutW(node);
1612
1707
  const lh = layoutH(node);
1613
- const colOffset = (colX.get(c) ?? 0) + (colW.get(c) ?? 120) / 2 - lw / 2;
1614
- const rowOffset = (r - stat.minRow) * (ROW_HEIGHT + ROW_GAP) + ROW_HEIGHT / 2 - lh / 2;
1615
- const contentH_stat = stat.rowCount * ROW_HEIGHT + Math.max(0, stat.rowCount - 1) * ROW_GAP;
1616
- const vertTopOffset = Math.max(LANE_V_PAD, (stat.height - contentH_stat) / 2);
1708
+ const colOffset = (laneLayout?.colX.get(c) ?? 0) + (laneLayout?.colW.get(c) ?? 120) / 2 - lw / 2;
1709
+ const rowOffset = (stat.rowY.get(r) ?? 0) + (stat.rowH.get(r) ?? ROW_HEIGHT) / 2 - lh / 2;
1710
+ const vertTopOffset = Math.max(LANE_V_PAD, (stat.height - stat.contentH) / 2);
1617
1711
  const isLaneChild = hasLanes && !!node.parentId && node.parentId !== pool.id;
1618
1712
  const x = isLaneChild ? LANE_LABEL_W + LANE_H_PAD + colOffset : POOL_H_PAD + colOffset;
1619
1713
  const y = isLaneChild ? vertTopOffset + rowOffset : lYOff + vertTopOffset + rowOffset;
1620
1714
  return applyLayoutMinSize({ ...node, position: { x, y } });
1621
1715
  });
1716
+ const handoffAdjustedContent = [...positionedContent];
1717
+ const nodeIndexById = new Map(handoffAdjustedContent.map((node, index) => [node.id, index]));
1718
+ const outgoingBySource = /* @__PURE__ */ new Map();
1719
+ for (const edge of fwdEdges) {
1720
+ if (!outgoingBySource.has(edge.source)) outgoingBySource.set(edge.source, []);
1721
+ outgoingBySource.get(edge.source).push(edge);
1722
+ }
1723
+ const crossLaneEdges = fwdEdges.filter((edge) => {
1724
+ const srcLane = nodeLaneId.get(edge.source) ?? "_pool_";
1725
+ const tgtLane = nodeLaneId.get(edge.target) ?? "_pool_";
1726
+ return srcLane !== tgtLane;
1727
+ }).sort(
1728
+ (a, b) => (columns.get(a.target) ?? 0) - (columns.get(b.target) ?? 0) || (columns.get(a.source) ?? 0) - (columns.get(b.source) ?? 0)
1729
+ );
1730
+ for (const edge of crossLaneEdges) {
1731
+ const srcIndex = nodeIndexById.get(edge.source);
1732
+ const tgtIndex = nodeIndexById.get(edge.target);
1733
+ if (srcIndex == null || tgtIndex == null) continue;
1734
+ const srcNode = handoffAdjustedContent[srcIndex];
1735
+ const tgtNode = handoffAdjustedContent[tgtIndex];
1736
+ const tgtLaneId = nodeLaneId.get(tgtNode.id) ?? "_pool_";
1737
+ const tgtCol = columns.get(tgtNode.id) ?? 0;
1738
+ const siblingTargets = (outgoingBySource.get(edge.source) ?? []).filter((candidate) => (columns.get(candidate.target) ?? 0) === tgtCol).map((candidate) => handoffAdjustedContent[nodeIndexById.get(candidate.target) ?? -1]).filter((node) => !!node);
1739
+ const siblingAlignedX = siblingTargets.reduce(
1740
+ (max, node) => Math.max(max, node.position.x),
1741
+ Number.NEGATIVE_INFINITY
1742
+ );
1743
+ const minTargetX = Math.max(
1744
+ siblingAlignedX,
1745
+ srcNode.position.x + layoutW(srcNode) / 2 + layoutW(tgtNode) / 2 + COL_GAP
1746
+ );
1747
+ if (tgtNode.position.x >= minTargetX) continue;
1748
+ const delta = minTargetX - tgtNode.position.x;
1749
+ for (let i = 0; i < handoffAdjustedContent.length; i++) {
1750
+ const candidate = handoffAdjustedContent[i];
1751
+ if ((nodeLaneId.get(candidate.id) ?? "_pool_") !== tgtLaneId) continue;
1752
+ if ((columns.get(candidate.id) ?? 0) < tgtCol) continue;
1753
+ handoffAdjustedContent[i] = {
1754
+ ...candidate,
1755
+ position: {
1756
+ x: candidate.position.x + delta,
1757
+ y: candidate.position.y
1758
+ }
1759
+ };
1760
+ }
1761
+ }
1762
+ for (const [sourceId, outgoing] of outgoingBySource) {
1763
+ if (outgoing.length < 2) continue;
1764
+ const hasCrossLaneSibling = outgoing.some((edge) => {
1765
+ const srcLane = nodeLaneId.get(edge.source) ?? "_pool_";
1766
+ const tgtLane = nodeLaneId.get(edge.target) ?? "_pool_";
1767
+ return srcLane !== tgtLane;
1768
+ });
1769
+ if (!hasCrossLaneSibling) continue;
1770
+ const siblingsByCol = /* @__PURE__ */ new Map();
1771
+ for (const edge of outgoing) {
1772
+ const col = columns.get(edge.target) ?? 0;
1773
+ const node = handoffAdjustedContent[nodeIndexById.get(edge.target) ?? -1];
1774
+ if (!node) continue;
1775
+ if (!siblingsByCol.has(col)) siblingsByCol.set(col, []);
1776
+ siblingsByCol.get(col).push(node);
1777
+ }
1778
+ for (const [col, siblings] of siblingsByCol) {
1779
+ if (siblings.length < 2) continue;
1780
+ const alignedX = Math.max(...siblings.map((node) => node.position.x));
1781
+ for (let i = 0; i < handoffAdjustedContent.length; i++) {
1782
+ const candidate = handoffAdjustedContent[i];
1783
+ if (!siblings.some((node) => node.id === candidate.id)) continue;
1784
+ const laneId = nodeLaneId.get(candidate.id) ?? "_pool_";
1785
+ for (let j = 0; j < handoffAdjustedContent.length; j++) {
1786
+ const maybeShift = handoffAdjustedContent[j];
1787
+ if ((nodeLaneId.get(maybeShift.id) ?? "_pool_") !== laneId) continue;
1788
+ if ((columns.get(maybeShift.id) ?? 0) < col) continue;
1789
+ const delta = alignedX - candidate.position.x;
1790
+ if (delta <= 0) continue;
1791
+ handoffAdjustedContent[j] = {
1792
+ ...maybeShift,
1793
+ position: {
1794
+ x: maybeShift.position.x + delta,
1795
+ y: maybeShift.position.y
1796
+ }
1797
+ };
1798
+ }
1799
+ }
1800
+ }
1801
+ }
1622
1802
  const NODE_MIN_GAP = 24;
1623
- const resolvedContent = [...positionedContent];
1803
+ const resolvedContent = [...handoffAdjustedContent];
1624
1804
  for (const laneId of laneIds) {
1625
1805
  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);
1626
1806
  for (let k = 1; k < laneNodeIndices.length; k++) {
@@ -1642,6 +1822,15 @@ function layoutPool(pool, lanes, content, allEdges) {
1642
1822
  }
1643
1823
  }
1644
1824
  const positionedBoundaries = repositionBoundaryEvents(boundaryEvents, resolvedContent);
1825
+ const laneChildRight = resolvedContent.filter((node) => hasLanes && !!node.parentId && node.parentId !== pool.id).reduce((max, node) => Math.max(max, node.position.x + nW(node) + LANE_H_PAD), 0);
1826
+ const poolChildRight = resolvedContent.filter((node) => !hasLanes || !node.parentId || node.parentId === pool.id).reduce((max, node) => Math.max(max, node.position.x + nW(node) + POOL_H_PAD), 0);
1827
+ const boundaryRight = positionedBoundaries.reduce(
1828
+ (max, node) => Math.max(max, node.position.x + nW(node) + (hasLanes ? LANE_H_PAD : POOL_H_PAD)),
1829
+ 0
1830
+ );
1831
+ const finalInnerW = Math.max(innerW, laneChildRight, poolChildRight, boundaryRight);
1832
+ const finalPoolW = Math.max(POOL_MIN_W, finalInnerW + POOL_INNER_PAD * 2);
1833
+ laneW = finalPoolW - POOL_INNER_PAD * 2;
1645
1834
  const positionedLanes = hasLanes ? sortedLanes.map((lane) => ({
1646
1835
  ...lane,
1647
1836
  position: { x: POOL_INNER_PAD, y: laneY.get(lane.id) ?? POOL_INNER_PAD },
@@ -1650,10 +1839,21 @@ function layoutPool(pool, lanes, content, allEdges) {
1650
1839
  })) : [];
1651
1840
  return {
1652
1841
  nodes: [...resolvedContent, ...positionedBoundaries, ...positionedLanes],
1653
- width: poolW,
1842
+ width: finalPoolW,
1654
1843
  height: poolH
1655
1844
  };
1656
1845
  }
1846
+ function layoutVirtualContext(contextNodes, allEdges, offsetY) {
1847
+ if (contextNodes.length === 0) return [];
1848
+ const virtualPool = {
1849
+ id: "__bpmn_virtual_pool__"};
1850
+ const result = layoutPool(virtualPool, [], contextNodes, allEdges);
1851
+ if (offsetY === 0) return result.nodes;
1852
+ return result.nodes.map((n) => ({
1853
+ ...n,
1854
+ position: { x: n.position.x, y: n.position.y + offsetY }
1855
+ }));
1856
+ }
1657
1857
  function absolutePos(nodeId, byId, cache) {
1658
1858
  const cached = cache.get(nodeId);
1659
1859
  if (cached) return cached;
@@ -1734,9 +1934,75 @@ function routeEdges(edges, layoutNodes, backEdgeIds, laneIds, poolIds) {
1734
1934
  const cache = /* @__PURE__ */ new Map();
1735
1935
  const abs = (id) => absolutePos(id, byId, cache);
1736
1936
  const sortedLanes = [...laneIds].map((id) => byId.get(id)).filter((n) => !!n).sort((a, b) => abs(a.id).y - abs(b.id).y);
1737
- return edges.map((edge) => {
1937
+ const contentInfos = layoutNodes.filter((n) => !poolIds.has(n.id) && !laneIds.has(n.id)).map((n) => {
1938
+ const p = abs(n.id);
1939
+ return { id: n.id, x: p.x, y: p.y, w: nW(n), h: nH(n), poolId: poolOf(n, poolIds, byId) ?? null };
1940
+ });
1941
+ const findClearX = (desiredX, y0, y1, minX, maxX, excludeA, excludeB, poolId) => {
1942
+ if (minX > maxX) return desiredX;
1943
+ const clampX = (x) => Math.min(maxX, Math.max(minX, x));
1944
+ const blockers = contentInfos.filter(
1945
+ (c) => c.poolId === poolId && c.id !== excludeA && c.id !== excludeB && c.y < y1 && c.y + c.h > y0
1946
+ );
1947
+ const isFree = (x) => blockers.every((c) => x < c.x - 4 || x > c.x + c.w + 4);
1948
+ const clamped = clampX(desiredX);
1949
+ if (isFree(clamped)) return clamped;
1950
+ const candidates = [];
1951
+ for (const c of blockers) candidates.push(c.x - 8, c.x + c.w + 8);
1952
+ const free = candidates.map(clampX).filter(isFree).sort((a, b) => Math.abs(a - desiredX) - Math.abs(b - desiredX));
1953
+ return free.length > 0 ? free[0] : clamped;
1954
+ };
1955
+ const backEdgeOrder = /* @__PURE__ */ new Map();
1956
+ for (const edge of [...edges].sort((a, b) => a.id < b.id ? -1 : a.id > b.id ? 1 : 0)) {
1957
+ if (backEdgeIds.has(edge.id)) backEdgeOrder.set(edge.id, backEdgeOrder.size);
1958
+ }
1959
+ const routeMessageFlow = (edge) => {
1960
+ const src = byId.get(edge.source);
1961
+ const tgt = byId.get(edge.target);
1962
+ if (!src || !tgt) return null;
1963
+ const srcPoolId = poolOf(src, poolIds, byId);
1964
+ const tgtPoolId = poolOf(tgt, poolIds, byId);
1965
+ if (!srcPoolId || !tgtPoolId || srcPoolId === tgtPoolId) return null;
1966
+ const srcPoolNode = byId.get(srcPoolId);
1967
+ const tgtPoolNode = byId.get(tgtPoolId);
1968
+ if (!srcPoolNode || !tgtPoolNode) return null;
1969
+ const sAbs = abs(src.id);
1970
+ const tAbs = abs(tgt.id);
1971
+ const sCX = sAbs.x + nW(src) / 2;
1972
+ const tCX = tAbs.x + nW(tgt) / 2;
1973
+ const srcPoolAbs = abs(srcPoolId);
1974
+ const tgtPoolAbs = abs(tgtPoolId);
1975
+ const srcPoolBottom = srcPoolAbs.y + nH(srcPoolNode);
1976
+ const tgtPoolBottom = tgtPoolAbs.y + nH(tgtPoolNode);
1977
+ if (tgtPoolAbs.y >= srcPoolBottom) {
1978
+ const corridorY = (srcPoolBottom + tgtPoolAbs.y) / 2;
1979
+ return [
1980
+ { x: sCX, y: sAbs.y + nH(src) },
1981
+ { x: sCX, y: corridorY },
1982
+ { x: tCX, y: corridorY },
1983
+ { x: tCX, y: tAbs.y }
1984
+ ];
1985
+ }
1986
+ if (srcPoolAbs.y >= tgtPoolBottom) {
1987
+ const corridorY = (tgtPoolBottom + srcPoolAbs.y) / 2;
1988
+ return [
1989
+ { x: sCX, y: sAbs.y },
1990
+ { x: sCX, y: corridorY },
1991
+ { x: tCX, y: corridorY },
1992
+ { x: tCX, y: tAbs.y + nH(tgt) }
1993
+ ];
1994
+ }
1995
+ return null;
1996
+ };
1997
+ const routed = edges.map((edge) => {
1738
1998
  const edgeType = edge.data?.edgeType ?? edge.type;
1739
1999
  if (edgeType !== "sequenceFlow") {
2000
+ if (edgeType === "messageFlow") {
2001
+ const pts = routeMessageFlow(edge);
2002
+ if (pts) {
2003
+ return { ...edge, data: { ...edge.data, routingPoints: pts } };
2004
+ }
2005
+ }
1740
2006
  const d = { ...edge.data };
1741
2007
  delete d.routingPoints;
1742
2008
  return { ...edge, data: d };
@@ -1761,7 +2027,16 @@ function routeEdges(edges, layoutNodes, backEdgeIds, laneIds, poolIds) {
1761
2027
  }
1762
2028
  let routingPoints;
1763
2029
  if (backEdgeIds.has(edge.id)) {
1764
- const topY = Math.min(sAbs.y, tAbs.y) - BACK_EDGE_CLEARANCE;
2030
+ const spanMinX = Math.min(tAbs.x, sAbs.x) - EDGE_ROUTE_PAD;
2031
+ const spanMaxX = Math.max(tAbs.x + tW, sAbs.x + sW) + EDGE_ROUTE_PAD;
2032
+ let topMost = Math.min(sAbs.y, tAbs.y);
2033
+ for (const cand of contentInfos) {
2034
+ if (cand.poolId !== srcPool) continue;
2035
+ if (cand.x + cand.w < spanMinX || cand.x > spanMaxX) continue;
2036
+ topMost = Math.min(topMost, cand.y);
2037
+ }
2038
+ const stagger = (backEdgeOrder.get(edge.id) ?? 0) * 14;
2039
+ const topY = topMost - BACK_EDGE_CLEARANCE - stagger;
1765
2040
  routingPoints = [
1766
2041
  { x: sAbs.x + sW, y: sCY },
1767
2042
  { x: sAbs.x + sW + EDGE_ROUTE_PAD, y: sCY },
@@ -1775,7 +2050,16 @@ function routeEdges(edges, layoutNodes, backEdgeIds, laneIds, poolIds) {
1775
2050
  const tgtLane = byId.get(laneOf(tgt, laneIds, byId) ?? "");
1776
2051
  if (srcLane && tgtLane && laneIds.has(srcLane.id) && laneIds.has(tgtLane.id)) {
1777
2052
  const goingDown = tAbs.y > sAbs.y;
1778
- const sharedX = gapMidX(sAbs, sW, tAbs, tW);
2053
+ const sharedX = findClearX(
2054
+ gapMidX(sAbs, sW, tAbs, tW),
2055
+ Math.min(sCY, tCY),
2056
+ Math.max(sCY, tCY),
2057
+ sAbs.x + sW + 6,
2058
+ tAbs.x - EDGE_ROUTE_PAD - 4,
2059
+ src.id,
2060
+ tgt.id,
2061
+ srcPool
2062
+ );
1779
2063
  const srcLaneIdx = sortedLanes.findIndex((l) => l.id === srcLane.id);
1780
2064
  const tgtLaneIdx = sortedLanes.findIndex((l) => l.id === tgtLane.id);
1781
2065
  const pts = [];
@@ -1810,7 +2094,16 @@ function routeEdges(edges, layoutNodes, backEdgeIds, laneIds, poolIds) {
1810
2094
  }
1811
2095
  routingPoints = pts;
1812
2096
  } else {
1813
- const sharedX = gapMidX(sAbs, sW, tAbs, tW);
2097
+ const sharedX = findClearX(
2098
+ gapMidX(sAbs, sW, tAbs, tW),
2099
+ Math.min(sCY, tCY),
2100
+ Math.max(sCY, tCY),
2101
+ sAbs.x + sW + 6,
2102
+ tAbs.x - 6,
2103
+ src.id,
2104
+ tgt.id,
2105
+ srcPool
2106
+ );
1814
2107
  routingPoints = [
1815
2108
  { x: sAbs.x + sW, y: sCY },
1816
2109
  { x: sharedX, y: sCY },
@@ -1840,7 +2133,16 @@ function routeEdges(edges, layoutNodes, backEdgeIds, laneIds, poolIds) {
1840
2133
  const midX = routeMidX(sAbs, sW, tAbs, tW);
1841
2134
  const exitX = sAbs.x + sW;
1842
2135
  const entryX = tAbs.x;
1843
- const corridorX = Math.max(midX, exitX + EDGE_ROUTE_PAD);
2136
+ const corridorX = findClearX(
2137
+ Math.max(midX, exitX + EDGE_ROUTE_PAD),
2138
+ Math.min(sCY, tCY),
2139
+ Math.max(sCY, tCY),
2140
+ exitX + 6,
2141
+ entryX - 6,
2142
+ src.id,
2143
+ tgt.id,
2144
+ srcPool
2145
+ );
1844
2146
  routingPoints = [
1845
2147
  { x: exitX, y: sCY },
1846
2148
  { x: corridorX, y: sCY },
@@ -1851,9 +2153,81 @@ function routeEdges(edges, layoutNodes, backEdgeIds, laneIds, poolIds) {
1851
2153
  }
1852
2154
  return { ...edge, data: { ...edge.data, routingPoints } };
1853
2155
  });
2156
+ return spreadVerticalChannels(routed);
2157
+ }
2158
+ var CHANNEL_GAP = 10;
2159
+ var CHANNEL_CLUSTER_TOL = 8;
2160
+ function spreadVerticalChannels(edges) {
2161
+ const runs = [];
2162
+ edges.forEach((edge, edgeIdx) => {
2163
+ const pts = edge.data?.routingPoints;
2164
+ if (!pts || pts.length < 4) return;
2165
+ let i = 1;
2166
+ while (i < pts.length) {
2167
+ let j = i;
2168
+ while (j < pts.length && Math.abs(pts[j].x - pts[j - 1].x) <= 0.5) j++;
2169
+ if (j > i) {
2170
+ const fromIdx = i - 1;
2171
+ const toIdx = j - 1;
2172
+ if (fromIdx > 0 && toIdx < pts.length - 1) {
2173
+ const ys = pts.slice(fromIdx, toIdx + 1).map((p) => p.y);
2174
+ const y0 = Math.min(...ys);
2175
+ const y1 = Math.max(...ys);
2176
+ if (y1 - y0 >= 4) {
2177
+ runs.push({ edgeIdx, fromIdx, toIdx, x: pts[fromIdx].x, y0, y1 });
2178
+ }
2179
+ }
2180
+ i = j + 1;
2181
+ } else {
2182
+ i++;
2183
+ }
2184
+ }
2185
+ });
2186
+ if (runs.length < 2) return edges;
2187
+ runs.sort((a, b) => a.x - b.x);
2188
+ const clusters = [];
2189
+ for (const run of runs) {
2190
+ const last = clusters[clusters.length - 1];
2191
+ if (last && run.x - last[0].x <= CHANNEL_CLUSTER_TOL) last.push(run);
2192
+ else clusters.push([run]);
2193
+ }
2194
+ const offsets = /* @__PURE__ */ new Map();
2195
+ for (const cluster of clusters) {
2196
+ if (cluster.length < 2) continue;
2197
+ const colliding = cluster.filter(
2198
+ (run) => cluster.some((other) => other !== run && run.y0 < other.y1 && other.y0 < run.y1)
2199
+ );
2200
+ if (colliding.length < 2) continue;
2201
+ const ordered = [...colliding].sort((a, b) => {
2202
+ const idA = edges[a.edgeIdx].id;
2203
+ const idB = edges[b.edgeIdx].id;
2204
+ return idA < idB ? -1 : idA > idB ? 1 : a.fromIdx - b.fromIdx;
2205
+ });
2206
+ ordered.forEach((run, k) => {
2207
+ const off = Math.round((k - (ordered.length - 1) / 2) * CHANNEL_GAP);
2208
+ if (off !== 0) offsets.set(run, off);
2209
+ });
2210
+ }
2211
+ if (offsets.size === 0) return edges;
2212
+ const runsByEdge = /* @__PURE__ */ new Map();
2213
+ for (const [run, off] of offsets) {
2214
+ if (!runsByEdge.has(run.edgeIdx)) runsByEdge.set(run.edgeIdx, []);
2215
+ runsByEdge.get(run.edgeIdx).push(run);
2216
+ }
2217
+ return edges.map((edge, edgeIdx) => {
2218
+ const edgeRuns = runsByEdge.get(edgeIdx);
2219
+ if (!edgeRuns) return edge;
2220
+ const pts = (edge.data?.routingPoints).map((p) => ({ ...p }));
2221
+ for (const run of edgeRuns) {
2222
+ const off = offsets.get(run);
2223
+ for (let p = run.fromIdx; p <= run.toIdx; p++) pts[p].x += off;
2224
+ }
2225
+ return { ...edge, data: { ...edge.data, routingPoints: pts } };
2226
+ });
1854
2227
  }
1855
2228
  var ARTIFACT_ABOVE_GAP = 16;
1856
2229
  var ARTIFACT_H_SPACING = 12;
2230
+ var ARTIFACT_EDGE_PAD = 4;
1857
2231
  function positionArtifacts(artifacts, resultNodes, edges, originalNodes) {
1858
2232
  if (artifacts.length === 0) return [];
1859
2233
  const byId = new Map(resultNodes.map((n) => [n.id, n]));
@@ -1894,11 +2268,21 @@ function positionArtifacts(artifacts, resultNodes, edges, originalNodes) {
1894
2268
  let desiredAbsX = connAbsP.x + nW(connNode) / 2 - totalW / 2;
1895
2269
  for (const artifact of arts) {
1896
2270
  const parentAbsP = artifact.parentId ? absPos(artifact.parentId) : { x: 0, y: 0 };
2271
+ let relY = desiredAbsY - parentAbsP.y;
2272
+ const parentNode = artifact.parentId ? byId.get(artifact.parentId) : void 0;
2273
+ if (parentNode) {
2274
+ if (relY < ARTIFACT_EDGE_PAD) {
2275
+ const belowAbsY = connAbsP.y + nH(connNode) + ARTIFACT_ABOVE_GAP;
2276
+ relY = belowAbsY - parentAbsP.y;
2277
+ }
2278
+ relY = Math.min(relY, nH(parentNode) - nH(artifact) - ARTIFACT_EDGE_PAD);
2279
+ relY = Math.max(relY, ARTIFACT_EDGE_PAD);
2280
+ }
1897
2281
  positioned.push({
1898
2282
  ...artifact,
1899
2283
  position: {
1900
2284
  x: desiredAbsX - parentAbsP.x,
1901
- y: desiredAbsY - parentAbsP.y
2285
+ y: relY
1902
2286
  }
1903
2287
  });
1904
2288
  desiredAbsX += nW(artifact) + ARTIFACT_H_SPACING;
@@ -1963,9 +2347,17 @@ async function bpmnCustomLayout(nodes, edges) {
1963
2347
  const mainNodes = nodes.filter((n) => !LAYOUT_ARTIFACT_TYPES.has(n.data.elementType));
1964
2348
  const pools = mainNodes.filter((n) => n.data.elementType === "Pool");
1965
2349
  const lanes = mainNodes.filter((n) => n.data.elementType === "Lane");
1966
- const expandedSubProcesses = mainNodes.filter(
1967
- (n) => COLLAPSED_SUBPROCESS_TYPES.has(n.data.elementType) && n.data.isExpanded
1968
- );
2350
+ const nodeDepthById = /* @__PURE__ */ new Map();
2351
+ const mainById = new Map(mainNodes.map((n) => [n.id, n]));
2352
+ const depthOf = (node) => {
2353
+ const cached = nodeDepthById.get(node.id);
2354
+ if (cached != null) return cached;
2355
+ const parent = node.parentId ? mainById.get(node.parentId) : void 0;
2356
+ const depth = parent ? depthOf(parent) + 1 : 0;
2357
+ nodeDepthById.set(node.id, depth);
2358
+ return depth;
2359
+ };
2360
+ const expandedSubProcesses = mainNodes.filter((n) => COLLAPSED_SUBPROCESS_TYPES.has(n.data.elementType) && n.data.isExpanded).sort((a, b) => depthOf(b) - depthOf(a));
1969
2361
  const subProcessLayouts = /* @__PURE__ */ new Map();
1970
2362
  const workingMainNodes = [...mainNodes];
1971
2363
  for (const sp of expandedSubProcesses) {
@@ -1983,15 +2375,30 @@ async function bpmnCustomLayout(nodes, edges) {
1983
2375
  }
1984
2376
  }
1985
2377
  const content = workingMainNodes.filter((n) => {
2378
+ if (n.data.elementType === "BoundaryEvent") return false;
1986
2379
  if (!LAYOUT_CONTAINER_TYPES.has(n.data.elementType)) return true;
1987
2380
  if (COLLAPSED_SUBPROCESS_TYPES.has(n.data.elementType)) return true;
1988
2381
  return false;
1989
2382
  });
1990
2383
  if (pools.length === 0) {
1991
- const { bpmnElkLayout: bpmnElkLayout2 } = await Promise.resolve().then(() => (init_elk(), elk_exports));
1992
- const elkResult = await bpmnElkLayout2(nodes.filter((n) => !LAYOUT_ARTIFACT_TYPES.has(n.data.elementType)), edges);
1993
- const posArtifacts = positionArtifacts(artifacts, elkResult.nodes, edges, nodes);
1994
- return { nodes: sortNodesParentFirst([...elkResult.nodes, ...posArtifacts]), edges: elkResult.edges };
2384
+ const isSpChild = (n) => !!n.parentId && subProcessLayouts.has(n.parentId);
2385
+ const freeContent = content.filter((n) => !isSpChild(n));
2386
+ const freeBoundaries = workingMainNodes.filter(
2387
+ (n) => n.data.elementType === "BoundaryEvent" && !isSpChild(n)
2388
+ );
2389
+ const resultNodes2 = layoutVirtualContext([...freeContent, ...freeBoundaries], edges, 0);
2390
+ for (const [, spLayout] of subProcessLayouts) {
2391
+ for (const child of spLayout.children) resultNodes2.push(child);
2392
+ }
2393
+ const contentIds = new Set(freeContent.map((n) => n.id));
2394
+ const seqEdges = extractSeqEdges(edges, contentIds);
2395
+ const backIds = detectBackEdges([...contentIds], seqEdges);
2396
+ const routedEdges2 = routeEdges(edges, resultNodes2, backIds, /* @__PURE__ */ new Set(), /* @__PURE__ */ new Set());
2397
+ const posArtifacts = positionArtifacts(artifacts, resultNodes2, edges, nodes);
2398
+ return {
2399
+ nodes: sortNodesParentFirst([...resultNodes2, ...posArtifacts]),
2400
+ edges: routedEdges2
2401
+ };
1995
2402
  }
1996
2403
  const poolIds = new Set(pools.map((p) => p.id));
1997
2404
  const allLaneIds = new Set(lanes.map((l) => l.id));
@@ -2034,30 +2441,14 @@ async function bpmnCustomLayout(nodes, edges) {
2034
2441
  const layoutted = new Set(resultNodes.map((n) => n.id));
2035
2442
  const freeNodes = workingMainNodes.filter((n) => !layoutted.has(n.id));
2036
2443
  if (freeNodes.length > 0) {
2037
- const freeNodeIds = new Set(freeNodes.map((n) => n.id));
2038
- const freeEdges = edges.filter(
2039
- (e) => freeNodeIds.has(e.source) && freeNodeIds.has(e.target)
2444
+ const freeFlow = freeNodes.filter(
2445
+ (n) => n.data.elementType === "BoundaryEvent" || !LAYOUT_CONTAINER_TYPES.has(n.data.elementType) || COLLAPSED_SUBPROCESS_TYPES.has(n.data.elementType)
2040
2446
  );
2041
- try {
2042
- const { bpmnElkLayout: bpmnElkLayout2 } = await Promise.resolve().then(() => (init_elk(), elk_exports));
2043
- const elkFree = await bpmnElkLayout2(freeNodes, freeEdges);
2044
- const offsetY = stackY;
2045
- for (const node of elkFree.nodes) {
2046
- resultNodes.push({
2047
- ...node,
2048
- position: { x: node.position.x, y: node.position.y + offsetY }
2049
- });
2050
- }
2051
- const freeEdgeIds = new Set(freeEdges.map((e) => e.id));
2052
- const elkEdgeMap = new Map(elkFree.edges.map((e) => [e.id, e]));
2053
- for (let i = 0; i < edges.length; i++) {
2054
- if (freeEdgeIds.has(edges[i].id) && elkEdgeMap.has(edges[i].id)) {
2055
- edges[i] = elkEdgeMap.get(edges[i].id);
2056
- }
2057
- }
2058
- } catch {
2059
- for (const node of freeNodes) resultNodes.push(node);
2447
+ const freeRest = freeNodes.filter((n) => !freeFlow.includes(n));
2448
+ for (const node of layoutVirtualContext(freeFlow, edges, stackY)) {
2449
+ resultNodes.push(node);
2060
2450
  }
2451
+ for (const node of freeRest) resultNodes.push(node);
2061
2452
  }
2062
2453
  const routedEdges = routeEdges(edges, resultNodes, allBackEdgeIds, allLaneIds, poolIds);
2063
2454
  const positionedArtifacts = positionArtifacts(artifacts, resultNodes, edges, nodes);