@aranzatech/diagrams-bpmn 0.3.5 → 0.3.7

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 +1190 -874
  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 +604 -91
  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;
@@ -1845,15 +1928,113 @@ function routeMidX(sAbs, sW, tAbs, tW) {
1845
1928
  const rightEdge = Math.max(sAbs.x, tAbs.x);
1846
1929
  return leftEdge < rightEdge ? leftEdge + (rightEdge - leftEdge) * 0.35 : sAbs.x + sW / 2;
1847
1930
  }
1931
+ var HANDLE_SIDES = ["right", "left", "top", "bottom"];
1932
+ function borderHandle(point, rect, kind) {
1933
+ const dist = {
1934
+ right: Math.abs(point.x - (rect.x + rect.w)),
1935
+ left: Math.abs(point.x - rect.x),
1936
+ top: Math.abs(point.y - rect.y),
1937
+ bottom: Math.abs(point.y - (rect.y + rect.h))
1938
+ };
1939
+ let side = "right";
1940
+ let best = Infinity;
1941
+ for (const s of HANDLE_SIDES) {
1942
+ if (dist[s] < best) {
1943
+ best = dist[s];
1944
+ side = s;
1945
+ }
1946
+ }
1947
+ return `${kind}-${side}`;
1948
+ }
1848
1949
  var SAME_ROW_THRESHOLD = 15;
1849
1950
  function routeEdges(edges, layoutNodes, backEdgeIds, laneIds, poolIds) {
1850
1951
  const byId = new Map(layoutNodes.map((n) => [n.id, n]));
1851
1952
  const cache = /* @__PURE__ */ new Map();
1852
1953
  const abs = (id) => absolutePos(id, byId, cache);
1954
+ const handlesFor = (srcId, tgtId, pts) => {
1955
+ if (pts.length < 2) return {};
1956
+ const s = byId.get(srcId), t = byId.get(tgtId);
1957
+ if (!s || !t) return {};
1958
+ const sa = abs(srcId), ta = abs(tgtId);
1959
+ return {
1960
+ sourceHandle: borderHandle(pts[0], { x: sa.x, y: sa.y, w: nW(s), h: nH(s) }, "source"),
1961
+ targetHandle: borderHandle(pts[pts.length - 1], { x: ta.x, y: ta.y, w: nW(t), h: nH(t) }, "target")
1962
+ };
1963
+ };
1853
1964
  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) => {
1965
+ const contentInfos = layoutNodes.filter((n) => !poolIds.has(n.id) && !laneIds.has(n.id)).map((n) => {
1966
+ const p = abs(n.id);
1967
+ return { id: n.id, x: p.x, y: p.y, w: nW(n), h: nH(n), poolId: poolOf(n, poolIds, byId) ?? null };
1968
+ });
1969
+ const findClearX = (desiredX, y0, y1, minX, maxX, excludeA, excludeB, poolId) => {
1970
+ if (minX > maxX) return desiredX;
1971
+ const clampX = (x) => Math.min(maxX, Math.max(minX, x));
1972
+ const blockers = contentInfos.filter(
1973
+ (c) => c.poolId === poolId && c.id !== excludeA && c.id !== excludeB && c.y < y1 && c.y + c.h > y0
1974
+ );
1975
+ const isFree = (x) => blockers.every((c) => x < c.x - 4 || x > c.x + c.w + 4);
1976
+ const clamped = clampX(desiredX);
1977
+ if (isFree(clamped)) return clamped;
1978
+ const candidates = [];
1979
+ for (const c of blockers) candidates.push(c.x - 8, c.x + c.w + 8);
1980
+ const free = candidates.map(clampX).filter(isFree).sort((a, b) => Math.abs(a - desiredX) - Math.abs(b - desiredX));
1981
+ return free.length > 0 ? free[0] : clamped;
1982
+ };
1983
+ const backEdgeOrder = /* @__PURE__ */ new Map();
1984
+ for (const edge of [...edges].sort((a, b) => a.id < b.id ? -1 : a.id > b.id ? 1 : 0)) {
1985
+ if (backEdgeIds.has(edge.id)) backEdgeOrder.set(edge.id, backEdgeOrder.size);
1986
+ }
1987
+ const routeMessageFlow = (edge) => {
1988
+ const src = byId.get(edge.source);
1989
+ const tgt = byId.get(edge.target);
1990
+ if (!src || !tgt) return null;
1991
+ const srcPoolId = poolOf(src, poolIds, byId);
1992
+ const tgtPoolId = poolOf(tgt, poolIds, byId);
1993
+ if (!srcPoolId || !tgtPoolId || srcPoolId === tgtPoolId) return null;
1994
+ const srcPoolNode = byId.get(srcPoolId);
1995
+ const tgtPoolNode = byId.get(tgtPoolId);
1996
+ if (!srcPoolNode || !tgtPoolNode) return null;
1997
+ const sAbs = abs(src.id);
1998
+ const tAbs = abs(tgt.id);
1999
+ const sCX = sAbs.x + nW(src) / 2;
2000
+ const tCX = tAbs.x + nW(tgt) / 2;
2001
+ const srcPoolAbs = abs(srcPoolId);
2002
+ const tgtPoolAbs = abs(tgtPoolId);
2003
+ const srcPoolBottom = srcPoolAbs.y + nH(srcPoolNode);
2004
+ const tgtPoolBottom = tgtPoolAbs.y + nH(tgtPoolNode);
2005
+ if (tgtPoolAbs.y >= srcPoolBottom) {
2006
+ const corridorY = (srcPoolBottom + tgtPoolAbs.y) / 2;
2007
+ return [
2008
+ { x: sCX, y: sAbs.y + nH(src) },
2009
+ { x: sCX, y: corridorY },
2010
+ { x: tCX, y: corridorY },
2011
+ { x: tCX, y: tAbs.y }
2012
+ ];
2013
+ }
2014
+ if (srcPoolAbs.y >= tgtPoolBottom) {
2015
+ const corridorY = (tgtPoolBottom + srcPoolAbs.y) / 2;
2016
+ return [
2017
+ { x: sCX, y: sAbs.y },
2018
+ { x: sCX, y: corridorY },
2019
+ { x: tCX, y: corridorY },
2020
+ { x: tCX, y: tAbs.y + nH(tgt) }
2021
+ ];
2022
+ }
2023
+ return null;
2024
+ };
2025
+ const routed = edges.map((edge) => {
1855
2026
  const edgeType = edge.data?.edgeType ?? edge.type;
1856
2027
  if (edgeType !== "sequenceFlow") {
2028
+ if (edgeType === "messageFlow") {
2029
+ const pts = routeMessageFlow(edge);
2030
+ if (pts) {
2031
+ return {
2032
+ ...edge,
2033
+ ...handlesFor(edge.source, edge.target, pts),
2034
+ data: { ...edge.data, routingPoints: pts }
2035
+ };
2036
+ }
2037
+ }
1857
2038
  const d = { ...edge.data };
1858
2039
  delete d.routingPoints;
1859
2040
  return { ...edge, data: d };
@@ -1878,7 +2059,16 @@ function routeEdges(edges, layoutNodes, backEdgeIds, laneIds, poolIds) {
1878
2059
  }
1879
2060
  let routingPoints;
1880
2061
  if (backEdgeIds.has(edge.id)) {
1881
- const topY = Math.min(sAbs.y, tAbs.y) - BACK_EDGE_CLEARANCE;
2062
+ const spanMinX = Math.min(tAbs.x, sAbs.x) - EDGE_ROUTE_PAD;
2063
+ const spanMaxX = Math.max(tAbs.x + tW, sAbs.x + sW) + EDGE_ROUTE_PAD;
2064
+ let topMost = Math.min(sAbs.y, tAbs.y);
2065
+ for (const cand of contentInfos) {
2066
+ if (cand.poolId !== srcPool) continue;
2067
+ if (cand.x + cand.w < spanMinX || cand.x > spanMaxX) continue;
2068
+ topMost = Math.min(topMost, cand.y);
2069
+ }
2070
+ const stagger = (backEdgeOrder.get(edge.id) ?? 0) * 14;
2071
+ const topY = topMost - BACK_EDGE_CLEARANCE - stagger;
1882
2072
  routingPoints = [
1883
2073
  { x: sAbs.x + sW, y: sCY },
1884
2074
  { x: sAbs.x + sW + EDGE_ROUTE_PAD, y: sCY },
@@ -1892,7 +2082,16 @@ function routeEdges(edges, layoutNodes, backEdgeIds, laneIds, poolIds) {
1892
2082
  const tgtLane = byId.get(laneOf(tgt, laneIds, byId) ?? "");
1893
2083
  if (srcLane && tgtLane && laneIds.has(srcLane.id) && laneIds.has(tgtLane.id)) {
1894
2084
  const goingDown = tAbs.y > sAbs.y;
1895
- const sharedX = gapMidX(sAbs, sW, tAbs, tW);
2085
+ const sharedX = findClearX(
2086
+ gapMidX(sAbs, sW, tAbs, tW),
2087
+ Math.min(sCY, tCY),
2088
+ Math.max(sCY, tCY),
2089
+ sAbs.x + sW + 6,
2090
+ tAbs.x - EDGE_ROUTE_PAD - 4,
2091
+ src.id,
2092
+ tgt.id,
2093
+ srcPool
2094
+ );
1896
2095
  const srcLaneIdx = sortedLanes.findIndex((l) => l.id === srcLane.id);
1897
2096
  const tgtLaneIdx = sortedLanes.findIndex((l) => l.id === tgtLane.id);
1898
2097
  const pts = [];
@@ -1927,7 +2126,16 @@ function routeEdges(edges, layoutNodes, backEdgeIds, laneIds, poolIds) {
1927
2126
  }
1928
2127
  routingPoints = pts;
1929
2128
  } else {
1930
- const sharedX = gapMidX(sAbs, sW, tAbs, tW);
2129
+ const sharedX = findClearX(
2130
+ gapMidX(sAbs, sW, tAbs, tW),
2131
+ Math.min(sCY, tCY),
2132
+ Math.max(sCY, tCY),
2133
+ sAbs.x + sW + 6,
2134
+ tAbs.x - 6,
2135
+ src.id,
2136
+ tgt.id,
2137
+ srcPool
2138
+ );
1931
2139
  routingPoints = [
1932
2140
  { x: sAbs.x + sW, y: sCY },
1933
2141
  { x: sharedX, y: sCY },
@@ -1938,7 +2146,13 @@ function routeEdges(edges, layoutNodes, backEdgeIds, laneIds, poolIds) {
1938
2146
  } else if (Math.abs(sCY - tCY) <= SAME_ROW_THRESHOLD) {
1939
2147
  const d = { ...edge.data };
1940
2148
  delete d.routingPoints;
1941
- return { ...edge, data: d };
2149
+ const goesRight = tCX >= sCX;
2150
+ return {
2151
+ ...edge,
2152
+ sourceHandle: goesRight ? "source-right" : "source-left",
2153
+ targetHandle: goesRight ? "target-left" : "target-right",
2154
+ data: d
2155
+ };
1942
2156
  } else {
1943
2157
  const handle = edge.sourceHandle ?? "";
1944
2158
  const exitsTop = handle.includes("top");
@@ -1957,7 +2171,16 @@ function routeEdges(edges, layoutNodes, backEdgeIds, laneIds, poolIds) {
1957
2171
  const midX = routeMidX(sAbs, sW, tAbs, tW);
1958
2172
  const exitX = sAbs.x + sW;
1959
2173
  const entryX = tAbs.x;
1960
- const corridorX = Math.max(midX, exitX + EDGE_ROUTE_PAD);
2174
+ const corridorX = findClearX(
2175
+ Math.max(midX, exitX + EDGE_ROUTE_PAD),
2176
+ Math.min(sCY, tCY),
2177
+ Math.max(sCY, tCY),
2178
+ exitX + 6,
2179
+ entryX - 6,
2180
+ src.id,
2181
+ tgt.id,
2182
+ srcPool
2183
+ );
1961
2184
  routingPoints = [
1962
2185
  { x: exitX, y: sCY },
1963
2186
  { x: corridorX, y: sCY },
@@ -1966,11 +2189,87 @@ function routeEdges(edges, layoutNodes, backEdgeIds, laneIds, poolIds) {
1966
2189
  ];
1967
2190
  }
1968
2191
  }
1969
- return { ...edge, data: { ...edge.data, routingPoints } };
2192
+ return {
2193
+ ...edge,
2194
+ ...handlesFor(edge.source, edge.target, routingPoints),
2195
+ data: { ...edge.data, routingPoints }
2196
+ };
2197
+ });
2198
+ return spreadVerticalChannels(routed);
2199
+ }
2200
+ var CHANNEL_GAP = 10;
2201
+ var CHANNEL_CLUSTER_TOL = 8;
2202
+ function spreadVerticalChannels(edges) {
2203
+ const runs = [];
2204
+ edges.forEach((edge, edgeIdx) => {
2205
+ const pts = edge.data?.routingPoints;
2206
+ if (!pts || pts.length < 4) return;
2207
+ let i = 1;
2208
+ while (i < pts.length) {
2209
+ let j = i;
2210
+ while (j < pts.length && Math.abs(pts[j].x - pts[j - 1].x) <= 0.5) j++;
2211
+ if (j > i) {
2212
+ const fromIdx = i - 1;
2213
+ const toIdx = j - 1;
2214
+ if (fromIdx > 0 && toIdx < pts.length - 1) {
2215
+ const ys = pts.slice(fromIdx, toIdx + 1).map((p) => p.y);
2216
+ const y0 = Math.min(...ys);
2217
+ const y1 = Math.max(...ys);
2218
+ if (y1 - y0 >= 4) {
2219
+ runs.push({ edgeIdx, fromIdx, toIdx, x: pts[fromIdx].x, y0, y1 });
2220
+ }
2221
+ }
2222
+ i = j + 1;
2223
+ } else {
2224
+ i++;
2225
+ }
2226
+ }
2227
+ });
2228
+ if (runs.length < 2) return edges;
2229
+ runs.sort((a, b) => a.x - b.x);
2230
+ const clusters = [];
2231
+ for (const run of runs) {
2232
+ const last = clusters[clusters.length - 1];
2233
+ if (last && run.x - last[0].x <= CHANNEL_CLUSTER_TOL) last.push(run);
2234
+ else clusters.push([run]);
2235
+ }
2236
+ const offsets = /* @__PURE__ */ new Map();
2237
+ for (const cluster of clusters) {
2238
+ if (cluster.length < 2) continue;
2239
+ const colliding = cluster.filter(
2240
+ (run) => cluster.some((other) => other !== run && run.y0 < other.y1 && other.y0 < run.y1)
2241
+ );
2242
+ if (colliding.length < 2) continue;
2243
+ const ordered = [...colliding].sort((a, b) => {
2244
+ const idA = edges[a.edgeIdx].id;
2245
+ const idB = edges[b.edgeIdx].id;
2246
+ return idA < idB ? -1 : idA > idB ? 1 : a.fromIdx - b.fromIdx;
2247
+ });
2248
+ ordered.forEach((run, k) => {
2249
+ const off = Math.round((k - (ordered.length - 1) / 2) * CHANNEL_GAP);
2250
+ if (off !== 0) offsets.set(run, off);
2251
+ });
2252
+ }
2253
+ if (offsets.size === 0) return edges;
2254
+ const runsByEdge = /* @__PURE__ */ new Map();
2255
+ for (const [run, off] of offsets) {
2256
+ if (!runsByEdge.has(run.edgeIdx)) runsByEdge.set(run.edgeIdx, []);
2257
+ runsByEdge.get(run.edgeIdx).push(run);
2258
+ }
2259
+ return edges.map((edge, edgeIdx) => {
2260
+ const edgeRuns = runsByEdge.get(edgeIdx);
2261
+ if (!edgeRuns) return edge;
2262
+ const pts = (edge.data?.routingPoints).map((p) => ({ ...p }));
2263
+ for (const run of edgeRuns) {
2264
+ const off = offsets.get(run);
2265
+ for (let p = run.fromIdx; p <= run.toIdx; p++) pts[p].x += off;
2266
+ }
2267
+ return { ...edge, data: { ...edge.data, routingPoints: pts } };
1970
2268
  });
1971
2269
  }
1972
2270
  var ARTIFACT_ABOVE_GAP = 16;
1973
2271
  var ARTIFACT_H_SPACING = 12;
2272
+ var ARTIFACT_EDGE_PAD = 4;
1974
2273
  function positionArtifacts(artifacts, resultNodes, edges, originalNodes) {
1975
2274
  if (artifacts.length === 0) return [];
1976
2275
  const byId = new Map(resultNodes.map((n) => [n.id, n]));
@@ -2011,11 +2310,21 @@ function positionArtifacts(artifacts, resultNodes, edges, originalNodes) {
2011
2310
  let desiredAbsX = connAbsP.x + nW(connNode) / 2 - totalW / 2;
2012
2311
  for (const artifact of arts) {
2013
2312
  const parentAbsP = artifact.parentId ? absPos(artifact.parentId) : { x: 0, y: 0 };
2313
+ let relY = desiredAbsY - parentAbsP.y;
2314
+ const parentNode = artifact.parentId ? byId.get(artifact.parentId) : void 0;
2315
+ if (parentNode) {
2316
+ if (relY < ARTIFACT_EDGE_PAD) {
2317
+ const belowAbsY = connAbsP.y + nH(connNode) + ARTIFACT_ABOVE_GAP;
2318
+ relY = belowAbsY - parentAbsP.y;
2319
+ }
2320
+ relY = Math.min(relY, nH(parentNode) - nH(artifact) - ARTIFACT_EDGE_PAD);
2321
+ relY = Math.max(relY, ARTIFACT_EDGE_PAD);
2322
+ }
2014
2323
  positioned.push({
2015
2324
  ...artifact,
2016
2325
  position: {
2017
2326
  x: desiredAbsX - parentAbsP.x,
2018
- y: desiredAbsY - parentAbsP.y
2327
+ y: relY
2019
2328
  }
2020
2329
  });
2021
2330
  desiredAbsX += nW(artifact) + ARTIFACT_H_SPACING;
@@ -2080,9 +2389,17 @@ async function bpmnCustomLayout(nodes, edges) {
2080
2389
  const mainNodes = nodes.filter((n) => !LAYOUT_ARTIFACT_TYPES.has(n.data.elementType));
2081
2390
  const pools = mainNodes.filter((n) => n.data.elementType === "Pool");
2082
2391
  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
- );
2392
+ const nodeDepthById = /* @__PURE__ */ new Map();
2393
+ const mainById = new Map(mainNodes.map((n) => [n.id, n]));
2394
+ const depthOf = (node) => {
2395
+ const cached = nodeDepthById.get(node.id);
2396
+ if (cached != null) return cached;
2397
+ const parent = node.parentId ? mainById.get(node.parentId) : void 0;
2398
+ const depth = parent ? depthOf(parent) + 1 : 0;
2399
+ nodeDepthById.set(node.id, depth);
2400
+ return depth;
2401
+ };
2402
+ const expandedSubProcesses = mainNodes.filter((n) => COLLAPSED_SUBPROCESS_TYPES.has(n.data.elementType) && n.data.isExpanded).sort((a, b) => depthOf(b) - depthOf(a));
2086
2403
  const subProcessLayouts = /* @__PURE__ */ new Map();
2087
2404
  const workingMainNodes = [...mainNodes];
2088
2405
  for (const sp of expandedSubProcesses) {
@@ -2100,15 +2417,30 @@ async function bpmnCustomLayout(nodes, edges) {
2100
2417
  }
2101
2418
  }
2102
2419
  const content = workingMainNodes.filter((n) => {
2420
+ if (n.data.elementType === "BoundaryEvent") return false;
2103
2421
  if (!LAYOUT_CONTAINER_TYPES.has(n.data.elementType)) return true;
2104
2422
  if (COLLAPSED_SUBPROCESS_TYPES.has(n.data.elementType)) return true;
2105
2423
  return false;
2106
2424
  });
2107
2425
  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 };
2426
+ const isSpChild = (n) => !!n.parentId && subProcessLayouts.has(n.parentId);
2427
+ const freeContent = content.filter((n) => !isSpChild(n));
2428
+ const freeBoundaries = workingMainNodes.filter(
2429
+ (n) => n.data.elementType === "BoundaryEvent" && !isSpChild(n)
2430
+ );
2431
+ const resultNodes2 = layoutVirtualContext([...freeContent, ...freeBoundaries], edges, 0);
2432
+ for (const [, spLayout] of subProcessLayouts) {
2433
+ for (const child of spLayout.children) resultNodes2.push(child);
2434
+ }
2435
+ const contentIds = new Set(freeContent.map((n) => n.id));
2436
+ const seqEdges = extractSeqEdges(edges, contentIds);
2437
+ const backIds = detectBackEdges([...contentIds], seqEdges);
2438
+ const routedEdges2 = routeEdges(edges, resultNodes2, backIds, /* @__PURE__ */ new Set(), /* @__PURE__ */ new Set());
2439
+ const posArtifacts = positionArtifacts(artifacts, resultNodes2, edges, nodes);
2440
+ return {
2441
+ nodes: sortNodesParentFirst([...resultNodes2, ...posArtifacts]),
2442
+ edges: routedEdges2
2443
+ };
2112
2444
  }
2113
2445
  const poolIds = new Set(pools.map((p) => p.id));
2114
2446
  const allLaneIds = new Set(lanes.map((l) => l.id));
@@ -2151,30 +2483,14 @@ async function bpmnCustomLayout(nodes, edges) {
2151
2483
  const layoutted = new Set(resultNodes.map((n) => n.id));
2152
2484
  const freeNodes = workingMainNodes.filter((n) => !layoutted.has(n.id));
2153
2485
  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)
2486
+ const freeFlow = freeNodes.filter(
2487
+ (n) => n.data.elementType === "BoundaryEvent" || !LAYOUT_CONTAINER_TYPES.has(n.data.elementType) || COLLAPSED_SUBPROCESS_TYPES.has(n.data.elementType)
2157
2488
  );
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);
2489
+ const freeRest = freeNodes.filter((n) => !freeFlow.includes(n));
2490
+ for (const node of layoutVirtualContext(freeFlow, edges, stackY)) {
2491
+ resultNodes.push(node);
2177
2492
  }
2493
+ for (const node of freeRest) resultNodes.push(node);
2178
2494
  }
2179
2495
  const routedEdges = routeEdges(edges, resultNodes, allBackEdgeIds, allLaneIds, poolIds);
2180
2496
  const positionedArtifacts = positionArtifacts(artifacts, resultNodes, edges, nodes);