@aranzatech/diagrams-bpmn 0.3.5 → 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-JFYWN6QH.js → chunk-EMTO53AN.js} +52 -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 +73 -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 +194 -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 +1146 -872
  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 +560 -89
  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-FFWJA5BV.js +0 -163
  50. package/dist/chunk-FFWJA5BV.js.map +0 -1
  51. package/dist/chunk-JFYWN6QH.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,28 +1586,67 @@ 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
1652
  const laneColumnLayouts = /* @__PURE__ */ new Map();
@@ -1586,7 +1659,7 @@ function layoutPool(pool, lanes, content, allEdges) {
1586
1659
  for (const col of usedCols) colW.set(col, 0);
1587
1660
  for (const node of laneNodes) {
1588
1661
  const col = columns.get(node.id) ?? 0;
1589
- colW.set(col, Math.max(colW.get(col) ?? 0, layoutW(node)));
1662
+ colW.set(col, Math.max(colW.get(col) ?? 0, columnW(node)));
1590
1663
  }
1591
1664
  const colX = /* @__PURE__ */ new Map();
1592
1665
  let laneCumX = 0;
@@ -1633,9 +1706,8 @@ function layoutPool(pool, lanes, content, allEdges) {
1633
1706
  const lw = layoutW(node);
1634
1707
  const lh = layoutH(node);
1635
1708
  const colOffset = (laneLayout?.colX.get(c) ?? 0) + (laneLayout?.colW.get(c) ?? 120) / 2 - lw / 2;
1636
- const rowOffset = (r - stat.minRow) * (ROW_HEIGHT + ROW_GAP) + ROW_HEIGHT / 2 - lh / 2;
1637
- const contentH_stat = stat.rowCount * ROW_HEIGHT + Math.max(0, stat.rowCount - 1) * ROW_GAP;
1638
- const vertTopOffset = Math.max(LANE_V_PAD, (stat.height - contentH_stat) / 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);
1639
1711
  const isLaneChild = hasLanes && !!node.parentId && node.parentId !== pool.id;
1640
1712
  const x = isLaneChild ? LANE_LABEL_W + LANE_H_PAD + colOffset : POOL_H_PAD + colOffset;
1641
1713
  const y = isLaneChild ? vertTopOffset + rowOffset : lYOff + vertTopOffset + rowOffset;
@@ -1771,6 +1843,17 @@ function layoutPool(pool, lanes, content, allEdges) {
1771
1843
  height: poolH
1772
1844
  };
1773
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
+ }
1774
1857
  function absolutePos(nodeId, byId, cache) {
1775
1858
  const cached = cache.get(nodeId);
1776
1859
  if (cached) return cached;
@@ -1851,9 +1934,75 @@ function routeEdges(edges, layoutNodes, backEdgeIds, laneIds, poolIds) {
1851
1934
  const cache = /* @__PURE__ */ new Map();
1852
1935
  const abs = (id) => absolutePos(id, byId, cache);
1853
1936
  const sortedLanes = [...laneIds].map((id) => byId.get(id)).filter((n) => !!n).sort((a, b) => abs(a.id).y - abs(b.id).y);
1854
- 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) => {
1855
1998
  const edgeType = edge.data?.edgeType ?? edge.type;
1856
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
+ }
1857
2006
  const d = { ...edge.data };
1858
2007
  delete d.routingPoints;
1859
2008
  return { ...edge, data: d };
@@ -1878,7 +2027,16 @@ function routeEdges(edges, layoutNodes, backEdgeIds, laneIds, poolIds) {
1878
2027
  }
1879
2028
  let routingPoints;
1880
2029
  if (backEdgeIds.has(edge.id)) {
1881
- 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;
1882
2040
  routingPoints = [
1883
2041
  { x: sAbs.x + sW, y: sCY },
1884
2042
  { x: sAbs.x + sW + EDGE_ROUTE_PAD, y: sCY },
@@ -1892,7 +2050,16 @@ function routeEdges(edges, layoutNodes, backEdgeIds, laneIds, poolIds) {
1892
2050
  const tgtLane = byId.get(laneOf(tgt, laneIds, byId) ?? "");
1893
2051
  if (srcLane && tgtLane && laneIds.has(srcLane.id) && laneIds.has(tgtLane.id)) {
1894
2052
  const goingDown = tAbs.y > sAbs.y;
1895
- 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
+ );
1896
2063
  const srcLaneIdx = sortedLanes.findIndex((l) => l.id === srcLane.id);
1897
2064
  const tgtLaneIdx = sortedLanes.findIndex((l) => l.id === tgtLane.id);
1898
2065
  const pts = [];
@@ -1927,7 +2094,16 @@ function routeEdges(edges, layoutNodes, backEdgeIds, laneIds, poolIds) {
1927
2094
  }
1928
2095
  routingPoints = pts;
1929
2096
  } else {
1930
- 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
+ );
1931
2107
  routingPoints = [
1932
2108
  { x: sAbs.x + sW, y: sCY },
1933
2109
  { x: sharedX, y: sCY },
@@ -1957,7 +2133,16 @@ function routeEdges(edges, layoutNodes, backEdgeIds, laneIds, poolIds) {
1957
2133
  const midX = routeMidX(sAbs, sW, tAbs, tW);
1958
2134
  const exitX = sAbs.x + sW;
1959
2135
  const entryX = tAbs.x;
1960
- 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
+ );
1961
2146
  routingPoints = [
1962
2147
  { x: exitX, y: sCY },
1963
2148
  { x: corridorX, y: sCY },
@@ -1968,9 +2153,81 @@ function routeEdges(edges, layoutNodes, backEdgeIds, laneIds, poolIds) {
1968
2153
  }
1969
2154
  return { ...edge, data: { ...edge.data, routingPoints } };
1970
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
+ });
1971
2227
  }
1972
2228
  var ARTIFACT_ABOVE_GAP = 16;
1973
2229
  var ARTIFACT_H_SPACING = 12;
2230
+ var ARTIFACT_EDGE_PAD = 4;
1974
2231
  function positionArtifacts(artifacts, resultNodes, edges, originalNodes) {
1975
2232
  if (artifacts.length === 0) return [];
1976
2233
  const byId = new Map(resultNodes.map((n) => [n.id, n]));
@@ -2011,11 +2268,21 @@ function positionArtifacts(artifacts, resultNodes, edges, originalNodes) {
2011
2268
  let desiredAbsX = connAbsP.x + nW(connNode) / 2 - totalW / 2;
2012
2269
  for (const artifact of arts) {
2013
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
+ }
2014
2281
  positioned.push({
2015
2282
  ...artifact,
2016
2283
  position: {
2017
2284
  x: desiredAbsX - parentAbsP.x,
2018
- y: desiredAbsY - parentAbsP.y
2285
+ y: relY
2019
2286
  }
2020
2287
  });
2021
2288
  desiredAbsX += nW(artifact) + ARTIFACT_H_SPACING;
@@ -2080,9 +2347,17 @@ async function bpmnCustomLayout(nodes, edges) {
2080
2347
  const mainNodes = nodes.filter((n) => !LAYOUT_ARTIFACT_TYPES.has(n.data.elementType));
2081
2348
  const pools = mainNodes.filter((n) => n.data.elementType === "Pool");
2082
2349
  const lanes = mainNodes.filter((n) => n.data.elementType === "Lane");
2083
- const expandedSubProcesses = mainNodes.filter(
2084
- (n) => COLLAPSED_SUBPROCESS_TYPES.has(n.data.elementType) && n.data.isExpanded
2085
- );
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));
2086
2361
  const subProcessLayouts = /* @__PURE__ */ new Map();
2087
2362
  const workingMainNodes = [...mainNodes];
2088
2363
  for (const sp of expandedSubProcesses) {
@@ -2100,15 +2375,30 @@ async function bpmnCustomLayout(nodes, edges) {
2100
2375
  }
2101
2376
  }
2102
2377
  const content = workingMainNodes.filter((n) => {
2378
+ if (n.data.elementType === "BoundaryEvent") return false;
2103
2379
  if (!LAYOUT_CONTAINER_TYPES.has(n.data.elementType)) return true;
2104
2380
  if (COLLAPSED_SUBPROCESS_TYPES.has(n.data.elementType)) return true;
2105
2381
  return false;
2106
2382
  });
2107
2383
  if (pools.length === 0) {
2108
- const { bpmnElkLayout: bpmnElkLayout2 } = await Promise.resolve().then(() => (init_elk(), elk_exports));
2109
- const elkResult = await bpmnElkLayout2(nodes.filter((n) => !LAYOUT_ARTIFACT_TYPES.has(n.data.elementType)), edges);
2110
- const posArtifacts = positionArtifacts(artifacts, elkResult.nodes, edges, nodes);
2111
- 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
+ };
2112
2402
  }
2113
2403
  const poolIds = new Set(pools.map((p) => p.id));
2114
2404
  const allLaneIds = new Set(lanes.map((l) => l.id));
@@ -2151,30 +2441,14 @@ async function bpmnCustomLayout(nodes, edges) {
2151
2441
  const layoutted = new Set(resultNodes.map((n) => n.id));
2152
2442
  const freeNodes = workingMainNodes.filter((n) => !layoutted.has(n.id));
2153
2443
  if (freeNodes.length > 0) {
2154
- const freeNodeIds = new Set(freeNodes.map((n) => n.id));
2155
- const freeEdges = edges.filter(
2156
- (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)
2157
2446
  );
2158
- try {
2159
- const { bpmnElkLayout: bpmnElkLayout2 } = await Promise.resolve().then(() => (init_elk(), elk_exports));
2160
- const elkFree = await bpmnElkLayout2(freeNodes, freeEdges);
2161
- const offsetY = stackY;
2162
- for (const node of elkFree.nodes) {
2163
- resultNodes.push({
2164
- ...node,
2165
- position: { x: node.position.x, y: node.position.y + offsetY }
2166
- });
2167
- }
2168
- const freeEdgeIds = new Set(freeEdges.map((e) => e.id));
2169
- const elkEdgeMap = new Map(elkFree.edges.map((e) => [e.id, e]));
2170
- for (let i = 0; i < edges.length; i++) {
2171
- if (freeEdgeIds.has(edges[i].id) && elkEdgeMap.has(edges[i].id)) {
2172
- edges[i] = elkEdgeMap.get(edges[i].id);
2173
- }
2174
- }
2175
- } catch {
2176
- 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);
2177
2450
  }
2451
+ for (const node of freeRest) resultNodes.push(node);
2178
2452
  }
2179
2453
  const routedEdges = routeEdges(edges, resultNodes, allBackEdgeIds, allLaneIds, poolIds);
2180
2454
  const positionedArtifacts = positionArtifacts(artifacts, resultNodes, edges, nodes);