@aranzatech/diagrams-bpmn 0.1.3 → 0.2.0

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 (42) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +121 -0
  3. package/dist/{chunk-4AX573IV.js → chunk-5GRCJ5X6.js} +2 -2
  4. package/dist/{chunk-4AX573IV.js.map → chunk-5GRCJ5X6.js.map} +1 -1
  5. package/dist/chunk-G5S4ASP3.js +277 -0
  6. package/dist/chunk-G5S4ASP3.js.map +1 -0
  7. package/dist/{chunk-W3ROOC6E.js → chunk-MF2WE3OM.js} +145 -36
  8. package/dist/chunk-MF2WE3OM.js.map +1 -0
  9. package/dist/chunk-OZKTOILD.js +3 -0
  10. package/dist/chunk-OZKTOILD.js.map +1 -0
  11. package/dist/{chunk-NXMUX67A.js → chunk-S3GGEEA5.js} +31 -8
  12. package/dist/chunk-S3GGEEA5.js.map +1 -0
  13. package/dist/elements/index.d.cts +2 -2
  14. package/dist/elements/index.d.ts +2 -2
  15. package/dist/elements/index.js +2 -1
  16. package/dist/index.cjs +454 -66
  17. package/dist/index.cjs.map +1 -1
  18. package/dist/index.d.cts +7 -62
  19. package/dist/index.d.ts +7 -62
  20. package/dist/index.js +6 -40
  21. package/dist/index.js.map +1 -1
  22. package/dist/modeling/index.cjs +894 -0
  23. package/dist/modeling/index.cjs.map +1 -0
  24. package/dist/modeling/index.d.cts +88 -0
  25. package/dist/modeling/index.d.ts +88 -0
  26. package/dist/modeling/index.js +5 -0
  27. package/dist/modeling/index.js.map +1 -0
  28. package/dist/nodes/index.cjs +29 -6
  29. package/dist/nodes/index.cjs.map +1 -1
  30. package/dist/nodes/index.js +1 -1
  31. package/dist/{types-C78d_Kdh.d.cts → types-BKA0GZz5.d.cts} +6 -18
  32. package/dist/{types-C78d_Kdh.d.ts → types-BKA0GZz5.d.ts} +6 -18
  33. package/dist/types-CCkHqtC_.d.cts +20 -0
  34. package/dist/types-hj621ZRJ.d.ts +20 -0
  35. package/dist/xml/index.cjs +143 -34
  36. package/dist/xml/index.cjs.map +1 -1
  37. package/dist/xml/index.d.cts +4 -19
  38. package/dist/xml/index.d.ts +4 -19
  39. package/dist/xml/index.js +1 -1
  40. package/package.json +10 -3
  41. package/dist/chunk-NXMUX67A.js.map +0 -1
  42. package/dist/chunk-W3ROOC6E.js.map +0 -1
package/dist/index.cjs CHANGED
@@ -4,6 +4,8 @@ var react = require('@xyflow/react');
4
4
  var jsxRuntime = require('react/jsx-runtime');
5
5
  var routing = require('@aranzatech/diagrams-core/routing');
6
6
  var bpmnModdle = require('bpmn-moddle');
7
+ var diagramsCore = require('@aranzatech/diagrams-core');
8
+ var serialization = require('@aranzatech/diagrams-core/serialization');
7
9
 
8
10
  // src/elements/catalog.ts
9
11
  var BPMN_ELEMENT_CATALOG = {
@@ -1238,11 +1240,24 @@ function GatewayNode({ data, selected }) {
1238
1240
  /* @__PURE__ */ jsxRuntime.jsx(BpmnLabel, { external: true, children: d.label })
1239
1241
  ] });
1240
1242
  }
1243
+ function resolveVariant(d) {
1244
+ if (d.subProcessVariant) return d.subProcessVariant;
1245
+ switch (d.elementType) {
1246
+ case "Transaction":
1247
+ return "transaction";
1248
+ case "EventSubProcess":
1249
+ return "event";
1250
+ case "AdHocSubProcess":
1251
+ return "adhoc";
1252
+ default:
1253
+ return "embedded";
1254
+ }
1255
+ }
1241
1256
  function SubProcessNode({ data, selected }) {
1242
1257
  const d = data;
1243
1258
  const stroke = resolveStroke(selected, d.color?.stroke);
1244
1259
  const sw = resolveStrokeWidth(selected);
1245
- const variant = d.subProcessVariant ?? "embedded";
1260
+ const variant = resolveVariant(d);
1246
1261
  const isExpanded = d.isExpanded ?? true;
1247
1262
  const hasMarkers = d.markers && d.markers.length > 0;
1248
1263
  const borderStyle = variant === "event" ? "dashed" : "solid";
@@ -1334,6 +1349,7 @@ function PoolNode({ data, selected }) {
1334
1349
  "div",
1335
1350
  {
1336
1351
  "aria-label": "pool-header",
1352
+ className: "pool-drag-handle",
1337
1353
  style: {
1338
1354
  height: HEADER_HEIGHT,
1339
1355
  minHeight: HEADER_HEIGHT,
@@ -1342,7 +1358,8 @@ function PoolNode({ data, selected }) {
1342
1358
  alignItems: "center",
1343
1359
  justifyContent: "center",
1344
1360
  background: headerFill,
1345
- padding: "0 8px"
1361
+ padding: "0 8px",
1362
+ cursor: "grab"
1346
1363
  },
1347
1364
  children: /* @__PURE__ */ jsxRuntime.jsx(
1348
1365
  "span",
@@ -1391,7 +1408,8 @@ function PoolNode({ data, selected }) {
1391
1408
  display: "flex",
1392
1409
  alignItems: "center",
1393
1410
  justifyContent: "center",
1394
- background: headerFill
1411
+ background: headerFill,
1412
+ cursor: "grab"
1395
1413
  },
1396
1414
  children: /* @__PURE__ */ jsxRuntime.jsx(
1397
1415
  "span",
@@ -1446,6 +1464,7 @@ function LaneNode({ data, selected }) {
1446
1464
  "div",
1447
1465
  {
1448
1466
  "aria-label": "lane-header",
1467
+ className: "lane-drag-handle",
1449
1468
  style: {
1450
1469
  width: HEADER_WIDTH2,
1451
1470
  minWidth: HEADER_WIDTH2,
@@ -1454,7 +1473,8 @@ function LaneNode({ data, selected }) {
1454
1473
  alignItems: "center",
1455
1474
  justifyContent: "center",
1456
1475
  background: headerFill,
1457
- padding: "6px 0"
1476
+ padding: "6px 0",
1477
+ cursor: "grab"
1458
1478
  },
1459
1479
  children: /* @__PURE__ */ jsxRuntime.jsx(
1460
1480
  "span",
@@ -1500,6 +1520,7 @@ function LaneNode({ data, selected }) {
1500
1520
  "div",
1501
1521
  {
1502
1522
  "aria-label": "lane-header",
1523
+ className: "lane-drag-handle",
1503
1524
  style: {
1504
1525
  height: HEADER_HEIGHT2,
1505
1526
  minHeight: HEADER_HEIGHT2,
@@ -1510,7 +1531,8 @@ function LaneNode({ data, selected }) {
1510
1531
  background: headerFill,
1511
1532
  fontSize: BPMN_THEME.fontSize,
1512
1533
  fontWeight: 500,
1513
- color: BPMN_THEME.labelColor
1534
+ color: BPMN_THEME.labelColor,
1535
+ cursor: "grab"
1514
1536
  },
1515
1537
  children: d.label
1516
1538
  }
@@ -2084,8 +2106,11 @@ var BPMN_NODE_TYPES = {
2084
2106
  ParallelGateway: GatewayNode,
2085
2107
  EventBasedGateway: GatewayNode,
2086
2108
  ComplexGateway: GatewayNode,
2087
- // Containers
2109
+ // Containers — Transaction, EventSubProcess, AdHocSubProcess derive their visual variant from elementType
2088
2110
  SubProcess: SubProcessNode,
2111
+ Transaction: SubProcessNode,
2112
+ EventSubProcess: SubProcessNode,
2113
+ AdHocSubProcess: SubProcessNode,
2089
2114
  Pool: PoolNode,
2090
2115
  Lane: LaneNode,
2091
2116
  // Artifacts
@@ -2408,8 +2433,8 @@ var MODDLE_TO_ELEMENT_TYPE = {
2408
2433
  "bpmn:EventBasedGateway": "EventBasedGateway",
2409
2434
  "bpmn:ComplexGateway": "ComplexGateway",
2410
2435
  "bpmn:SubProcess": "SubProcess",
2411
- "bpmn:AdHocSubProcess": "SubProcess",
2412
- "bpmn:Transaction": "SubProcess",
2436
+ "bpmn:AdHocSubProcess": "AdHocSubProcess",
2437
+ "bpmn:Transaction": "Transaction",
2413
2438
  "bpmn:TextAnnotation": "Annotation",
2414
2439
  "bpmn:Group": "Group",
2415
2440
  "bpmn:DataObject": "DataObject",
@@ -2447,6 +2472,9 @@ var ELEMENT_TYPE_TO_MODDLE = {
2447
2472
  EventBasedGateway: "bpmn:EventBasedGateway",
2448
2473
  ComplexGateway: "bpmn:ComplexGateway",
2449
2474
  SubProcess: "bpmn:SubProcess",
2475
+ Transaction: "bpmn:Transaction",
2476
+ EventSubProcess: "bpmn:SubProcess",
2477
+ AdHocSubProcess: "bpmn:AdHocSubProcess",
2450
2478
  Pool: "bpmn:Participant",
2451
2479
  Lane: "bpmn:Lane",
2452
2480
  Annotation: "bpmn:TextAnnotation",
@@ -2511,6 +2539,10 @@ function asElements(v) {
2511
2539
  function asString(v) {
2512
2540
  return typeof v === "string" && v.trim() ? v.trim() : void 0;
2513
2541
  }
2542
+ function extractDocumentation(el) {
2543
+ const [doc] = asElements(el.documentation);
2544
+ return asString(doc?.text);
2545
+ }
2514
2546
  function extractDiagramInfo(definitions) {
2515
2547
  const shapes = /* @__PURE__ */ new Map();
2516
2548
  const waypoints = /* @__PURE__ */ new Map();
@@ -2566,6 +2598,7 @@ function extractTrigger(el) {
2566
2598
  function extractSubProcessVariant(el) {
2567
2599
  if (el.$type === "bpmn:Transaction") return "transaction";
2568
2600
  if (el.$type === "bpmn:AdHocSubProcess") return "adhoc";
2601
+ if (el.$type === "bpmn:SubProcess" && el.triggeredByEvent === true) return "event";
2569
2602
  if (el.triggeredByEvent === true) return "event";
2570
2603
  return "embedded";
2571
2604
  }
@@ -2579,7 +2612,7 @@ function walkFlowElements(elements, parentId, ctx, nodes, edges) {
2579
2612
  continue;
2580
2613
  }
2581
2614
  if ($type === "bpmn:LaneSet") continue;
2582
- const elementType = MODDLE_TO_ELEMENT_TYPE[$type];
2615
+ const elementType = $type === "bpmn:SubProcess" && el.triggeredByEvent === true ? "EventSubProcess" : MODDLE_TO_ELEMENT_TYPE[$type];
2583
2616
  if (!elementType) {
2584
2617
  ctx.warnings.push(`Unknown element type "${$type}" (id=${id}) \u2014 skipped.`);
2585
2618
  continue;
@@ -2600,22 +2633,26 @@ function buildNode(el, elementType, parentId, ctx, nodes) {
2600
2633
  const y = shape?.y ?? 100;
2601
2634
  if (!shape) ctx.autoX.value += (meta?.defaultWidth ?? 120) + 20;
2602
2635
  const label = asString(el.name);
2636
+ const documentation = extractDocumentation(el);
2603
2637
  const trigger = extractTrigger(el);
2604
2638
  const isNonInterrupting = el.cancelActivity === false;
2639
+ const attachedToRef = el.attachedToRef?.id;
2605
2640
  const data = {
2606
2641
  elementType,
2607
2642
  ...label ? { label } : {},
2643
+ ...documentation ? { documentation } : {},
2608
2644
  ...trigger ? { trigger } : {},
2609
- ...isNonInterrupting ? { isNonInterrupting: true } : {}
2645
+ ...isNonInterrupting ? { isNonInterrupting: true } : {},
2646
+ ...attachedToRef ? { attachedToRef } : {}
2610
2647
  };
2611
- if (elementType === "SubProcess") {
2648
+ if (elementType === "SubProcess" || elementType === "Transaction" || elementType === "EventSubProcess" || elementType === "AdHocSubProcess") {
2612
2649
  const variant = extractSubProcessVariant(el);
2613
2650
  if (variant) data.subProcessVariant = variant;
2614
2651
  const isExpanded = shape?.isExpanded ?? true;
2615
2652
  data.isExpanded = isExpanded;
2616
2653
  }
2617
2654
  const laneId = ctx.laneMembership.get(id);
2618
- const effectiveParentId = laneId ?? parentId;
2655
+ const effectiveParentId = attachedToRef ?? laneId ?? parentId;
2619
2656
  const node = {
2620
2657
  id,
2621
2658
  type: elementType,
@@ -2636,10 +2673,12 @@ function buildEdge(el, edgeType, ctx, edges) {
2636
2673
  return;
2637
2674
  }
2638
2675
  const label = asString(el.name);
2676
+ const documentation = extractDocumentation(el);
2639
2677
  const condExpr = el.conditionExpression;
2640
2678
  const data = {
2641
2679
  edgeType,
2642
2680
  ...label ? { label } : {},
2681
+ ...documentation ? { documentation } : {},
2643
2682
  ...condExpr?.body ? { conditionExpression: condExpr.body } : {}
2644
2683
  };
2645
2684
  const waypoints = ctx.waypoints.get(id);
@@ -2740,7 +2779,46 @@ async function parseBpmnXml(xml) {
2740
2779
  );
2741
2780
  }
2742
2781
  }
2743
- return { nodes, edges, warnings };
2782
+ const defaultFlowById = /* @__PURE__ */ new Set();
2783
+ const nodeIds = new Set(nodes.map((node) => node.id));
2784
+ for (const rootEl of asElements(rootElement.rootElements)) {
2785
+ collectDefaultFlows(rootEl, defaultFlowById);
2786
+ }
2787
+ const normalizedEdges = edges.map((edge) => {
2788
+ if (!defaultFlowById.has(edge.id)) return edge;
2789
+ const data = {
2790
+ edgeType: edge.data?.edgeType ?? edge.type,
2791
+ ...edge.data ?? {},
2792
+ isDefault: true
2793
+ };
2794
+ return { ...edge, data };
2795
+ });
2796
+ return {
2797
+ nodes: normalizeChildPositions(nodes, nodeIds),
2798
+ edges: normalizedEdges,
2799
+ warnings
2800
+ };
2801
+ }
2802
+ function collectDefaultFlows(el, defaultFlowById) {
2803
+ const defaultRef = el.default;
2804
+ if (defaultRef?.id) defaultFlowById.add(defaultRef.id);
2805
+ for (const child of asElements(el.rootElements)) collectDefaultFlows(child, defaultFlowById);
2806
+ for (const child of asElements(el.flowElements)) collectDefaultFlows(child, defaultFlowById);
2807
+ }
2808
+ function normalizeChildPositions(nodes, nodeIds) {
2809
+ const absoluteById = new Map(nodes.map((node) => [node.id, node.position]));
2810
+ return nodes.map((node) => {
2811
+ if (!node.parentId || !nodeIds.has(node.parentId)) return node;
2812
+ const parentPosition = absoluteById.get(node.parentId);
2813
+ if (!parentPosition) return node;
2814
+ return {
2815
+ ...node,
2816
+ position: {
2817
+ x: node.position.x - parentPosition.x,
2818
+ y: node.position.y - parentPosition.y
2819
+ }
2820
+ };
2821
+ });
2744
2822
  }
2745
2823
  function uid(prefix, id) {
2746
2824
  return `${prefix}_${id}`;
@@ -2748,19 +2826,6 @@ function uid(prefix, id) {
2748
2826
  function asNodes(nodes, types) {
2749
2827
  return nodes.filter((n) => types.includes(n.data.elementType));
2750
2828
  }
2751
- function buildFlowableAttrs(data) {
2752
- const attrs = {};
2753
- if (data.flowableAssignee) attrs["flowable:assignee"] = data.flowableAssignee;
2754
- if (data.flowableCandidateGroups) attrs["flowable:candidateGroups"] = data.flowableCandidateGroups;
2755
- if (data.flowableCandidateUsers) attrs["flowable:candidateUsers"] = data.flowableCandidateUsers;
2756
- if (data.flowableFormKey) attrs["flowable:formKey"] = data.flowableFormKey;
2757
- if (data.flowableDueDate) attrs["flowable:dueDate"] = data.flowableDueDate;
2758
- if (data.flowableType) attrs["flowable:type"] = data.flowableType;
2759
- if (data.flowableExpression) attrs["flowable:expression"] = data.flowableExpression;
2760
- if (data.flowableClass) attrs["flowable:class"] = data.flowableClass;
2761
- if (data.flowableDelegateExpression) attrs["flowable:delegateExpression"] = data.flowableDelegateExpression;
2762
- return attrs;
2763
- }
2764
2829
  function buildSemanticModel(moddle, nodes, edges, opts) {
2765
2830
  const defId = opts.id ?? "Definitions_1";
2766
2831
  const defName = opts.name;
@@ -2819,13 +2884,26 @@ function buildSemanticModel(moddle, nodes, edges, opts) {
2819
2884
  return definitions;
2820
2885
  }
2821
2886
  function buildProcess(moddle, allNodes, allEdges, poolId, laneNodes, processId) {
2822
- const myNodes = poolId ? allNodes.filter(
2887
+ const subProcessIds = new Set(
2888
+ allNodes.filter(
2889
+ (n) => n.data.elementType === "SubProcess" || n.data.elementType === "Transaction" || n.data.elementType === "EventSubProcess" || n.data.elementType === "AdHocSubProcess"
2890
+ ).map((n) => n.id)
2891
+ );
2892
+ const isInsideSubProcess = (node) => {
2893
+ let parentId = node.parentId;
2894
+ while (parentId) {
2895
+ if (subProcessIds.has(parentId)) return true;
2896
+ parentId = allNodes.find((candidate) => candidate.id === parentId)?.parentId;
2897
+ }
2898
+ return false;
2899
+ };
2900
+ const myNodes = (poolId ? allNodes.filter(
2823
2901
  (n) => n.parentId === poolId || laneNodes.some((l) => l.id === n.parentId && l.parentId === poolId)
2824
- ) : allNodes.filter((n) => n.data.elementType !== "Pool" && n.data.elementType !== "Lane");
2902
+ ) : allNodes.filter((n) => n.data.elementType !== "Pool" && n.data.elementType !== "Lane")).filter((n) => !isInsideSubProcess(n));
2825
2903
  const myLanes = laneNodes.filter((l) => poolId ? l.parentId === poolId : true);
2826
2904
  const flowElements = [];
2827
2905
  for (const node of myNodes) {
2828
- const el = buildFlowElement(moddle, node);
2906
+ const el = buildFlowElement(moddle, node, allNodes, allEdges);
2829
2907
  if (el) flowElements.push(el);
2830
2908
  }
2831
2909
  const myNodeIds = new Set(myNodes.map((n) => n.id));
@@ -2836,6 +2914,17 @@ function buildProcess(moddle, allNodes, allEdges, poolId, laneNodes, processId)
2836
2914
  const edgeMeta = buildEdgeElement(moddle, edge);
2837
2915
  if (edgeMeta) flowElements.push(edgeMeta);
2838
2916
  }
2917
+ const elementById = new Map(
2918
+ flowElements.filter((element) => typeof element.id === "string").map((element) => [element.id, element])
2919
+ );
2920
+ for (const edge of myEdges) {
2921
+ if (!edge.data?.isDefault) continue;
2922
+ const sourceElement = elementById.get(edge.source);
2923
+ const edgeElement = elementById.get(edge.id);
2924
+ if (sourceElement && edgeElement) {
2925
+ sourceElement.default = edgeElement;
2926
+ }
2927
+ }
2839
2928
  const process = moddle.create("bpmn:Process", {
2840
2929
  id: processId,
2841
2930
  isExecutable: true,
@@ -2856,7 +2945,7 @@ function buildProcess(moddle, allNodes, allEdges, poolId, laneNodes, processId)
2856
2945
  }
2857
2946
  return process;
2858
2947
  }
2859
- function buildFlowElement(moddle, node, _allNodes, _allEdges) {
2948
+ function buildFlowElement(moddle, node, allNodes, allEdges) {
2860
2949
  const { elementType, label, trigger } = node.data;
2861
2950
  if (elementType === "Pool" || elementType === "Lane") return null;
2862
2951
  const moddleType = ELEMENT_TYPE_TO_MODDLE[elementType];
@@ -2865,25 +2954,46 @@ function buildFlowElement(moddle, node, _allNodes, _allEdges) {
2865
2954
  id: node.id,
2866
2955
  name: label ?? ""
2867
2956
  };
2957
+ if (node.data.documentation) {
2958
+ attrs.documentation = [
2959
+ moddle.create("bpmn:Documentation", { text: node.data.documentation })
2960
+ ];
2961
+ }
2868
2962
  if (trigger && trigger !== "none") {
2869
2963
  const defType = TRIGGER_TO_EVENT_DEF[trigger];
2870
2964
  if (defType) {
2871
2965
  attrs.eventDefinitions = [moddle.create(defType, { id: uid("EventDef", node.id) })];
2872
2966
  }
2873
2967
  }
2874
- if (elementType === "SubProcess" && node.data.subProcessVariant === "transaction") {
2875
- return moddle.create("bpmn:Transaction", attrs);
2968
+ if (elementType === "BoundaryEvent") {
2969
+ attrs.attachedToRef = { id: node.data.attachedToRef ?? node.parentId };
2970
+ attrs.cancelActivity = node.data.isNonInterrupting ? false : true;
2876
2971
  }
2877
- if (elementType === "SubProcess" && node.data.subProcessVariant === "adhoc") {
2878
- return moddle.create("bpmn:AdHocSubProcess", attrs);
2972
+ const isSubProcess2 = elementType === "SubProcess" || elementType === "Transaction" || elementType === "EventSubProcess" || elementType === "AdHocSubProcess";
2973
+ if (isSubProcess2) {
2974
+ attrs.flowElements = buildNestedFlowElements(moddle, node, allNodes, allEdges);
2975
+ if (elementType === "EventSubProcess" || node.data.subProcessVariant === "event") {
2976
+ attrs.triggeredByEvent = true;
2977
+ }
2879
2978
  }
2880
2979
  const element = moddle.create(moddleType, attrs);
2881
- const flowableAttrs = buildFlowableAttrs(node.data);
2882
- if (Object.keys(flowableAttrs).length > 0) {
2883
- element.$attrs = flowableAttrs;
2884
- }
2885
2980
  return element;
2886
2981
  }
2982
+ function buildNestedFlowElements(moddle, parent, allNodes, allEdges) {
2983
+ const childNodes = allNodes.filter((node) => node.parentId === parent.id);
2984
+ const childNodeIds = new Set(childNodes.map((node) => node.id));
2985
+ const flowElements = [];
2986
+ for (const child of childNodes) {
2987
+ const element = buildFlowElement(moddle, child, allNodes, allEdges);
2988
+ if (element) flowElements.push(element);
2989
+ }
2990
+ for (const edge of allEdges) {
2991
+ if (!childNodeIds.has(edge.source) || !childNodeIds.has(edge.target)) continue;
2992
+ const element = buildEdgeElement(moddle, edge);
2993
+ if (element) flowElements.push(element);
2994
+ }
2995
+ return flowElements;
2996
+ }
2887
2997
  function buildEdgeElement(moddle, edge) {
2888
2998
  if (!edge.data) return null;
2889
2999
  const moddleType = EDGE_TYPE_TO_MODDLE[edge.data.edgeType];
@@ -2894,6 +3004,11 @@ function buildEdgeElement(moddle, edge) {
2894
3004
  sourceRef: { id: edge.source },
2895
3005
  targetRef: { id: edge.target }
2896
3006
  };
3007
+ if (edge.data.documentation) {
3008
+ attrs.documentation = [
3009
+ moddle.create("bpmn:Documentation", { text: edge.data.documentation })
3010
+ ];
3011
+ }
2897
3012
  if (edge.data.conditionExpression) {
2898
3013
  attrs.conditionExpression = moddle.create("bpmn:FormalExpression", {
2899
3014
  body: edge.data.conditionExpression
@@ -2904,13 +3019,14 @@ function buildEdgeElement(moddle, edge) {
2904
3019
  function buildBpmnDI(moddle, definitions, nodes, edges) {
2905
3020
  const shapes = [];
2906
3021
  const edgeShapes = [];
3022
+ const absolutePositionById = buildAbsolutePositionMap(nodes);
2907
3023
  for (const node of nodes) {
2908
3024
  const meta = BPMN_ELEMENT_CATALOG[node.data.elementType];
2909
3025
  const w = node.width ?? meta?.defaultWidth ?? 120;
2910
3026
  const h = node.height ?? meta?.defaultHeight ?? 60;
2911
3027
  const bounds = moddle.create("dc:Bounds", {
2912
- x: node.position.x,
2913
- y: node.position.y,
3028
+ x: absolutePositionById.get(node.id)?.x ?? node.position.x,
3029
+ y: absolutePositionById.get(node.id)?.y ?? node.position.y,
2914
3030
  width: w,
2915
3031
  height: h
2916
3032
  });
@@ -2949,6 +3065,24 @@ function buildBpmnDI(moddle, definitions, nodes, edges) {
2949
3065
  });
2950
3066
  definitions.diagrams = [diagram];
2951
3067
  }
3068
+ function buildAbsolutePositionMap(nodes) {
3069
+ const nodeById2 = new Map(nodes.map((node) => [node.id, node]));
3070
+ const absoluteById = /* @__PURE__ */ new Map();
3071
+ function resolve(node) {
3072
+ const cached = absoluteById.get(node.id);
3073
+ if (cached) return cached;
3074
+ const parent = node.parentId ? nodeById2.get(node.parentId) : void 0;
3075
+ const parentPosition = parent ? resolve(parent) : { x: 0, y: 0 };
3076
+ const absolute = {
3077
+ x: parentPosition.x + node.position.x,
3078
+ y: parentPosition.y + node.position.y
3079
+ };
3080
+ absoluteById.set(node.id, absolute);
3081
+ return absolute;
3082
+ }
3083
+ for (const node of nodes) resolve(node);
3084
+ return absoluteById;
3085
+ }
2952
3086
  async function serializeBpmnXml(nodes, edges, opts = {}) {
2953
3087
  const moddle = new bpmnModdle.BpmnModdle();
2954
3088
  const definitions = buildSemanticModel(moddle, nodes, edges, opts);
@@ -3431,44 +3565,280 @@ function isCompleted(state) {
3431
3565
  function setVariable(state, key, value) {
3432
3566
  return { ...state, variables: { ...state.variables, [key]: value } };
3433
3567
  }
3434
-
3435
- // src/flowable/adapter.ts
3436
- var PreviewAdapter = class {
3437
- constructor(diagram, initialVariables = {}) {
3438
- this.diagram = diagram;
3439
- this.mode = "preview";
3440
- this.state = createSimulation(diagram, initialVariables);
3568
+ function createBpmnNode(options) {
3569
+ const meta = BPMN_ELEMENT_CATALOG[options.elementType];
3570
+ return {
3571
+ id: options.id,
3572
+ type: options.elementType,
3573
+ position: options.position,
3574
+ data: {
3575
+ elementType: options.elementType,
3576
+ ...options.label ? { label: options.label } : {},
3577
+ ...options.data ?? {}
3578
+ },
3579
+ width: options.width ?? meta.defaultWidth,
3580
+ height: options.height ?? meta.defaultHeight,
3581
+ ...options.parentId ? { parentId: options.parentId } : {}
3582
+ };
3583
+ }
3584
+ function inferBpmnEdgeType(state, sourceId, targetId) {
3585
+ const source = diagramsCore.getNode(state, sourceId);
3586
+ const target = diagramsCore.getNode(state, targetId);
3587
+ if (!source || !target) return "sequenceFlow";
3588
+ if (isDataType(source.data.elementType) || isDataType(target.data.elementType)) {
3589
+ return "dataAssociation";
3441
3590
  }
3442
- async start(variables) {
3443
- this.state = tick(this.diagram, createSimulation(this.diagram, variables ?? {}));
3444
- return this.state;
3591
+ if (source.data.elementType === "Annotation" || target.data.elementType === "Annotation" || source.data.elementType === "Group" || target.data.elementType === "Group") {
3592
+ return "association";
3445
3593
  }
3446
- async tick() {
3447
- this.state = tick(this.diagram, this.state);
3448
- return this.state;
3594
+ if (source.data.elementType === "Conversation" || source.data.elementType === "SubConversation" || source.data.elementType === "CallConversation" || target.data.elementType === "Conversation" || target.data.elementType === "SubConversation" || target.data.elementType === "CallConversation") {
3595
+ return "conversationLink";
3449
3596
  }
3450
- async fire(elementId, variables) {
3451
- this.state = fire(this.diagram, this.state, elementId, variables);
3452
- return this.state;
3597
+ if (source.parentId && target.parentId && source.parentId !== target.parentId) {
3598
+ return "messageFlow";
3453
3599
  }
3454
- async getFireable() {
3455
- return getFireable(this.diagram, this.state);
3600
+ return "sequenceFlow";
3601
+ }
3602
+ function canUseSequenceFlow(type) {
3603
+ const meta = BPMN_ELEMENT_CATALOG[type];
3604
+ return meta.handlePolicy !== "none" && !isDataType(type) && type !== "Annotation" && type !== "Group" && meta.category !== "conversation";
3605
+ }
3606
+ function validateEdgeCardinality(state, edgeType, source, target) {
3607
+ if (edgeType !== "sequenceFlow") return true;
3608
+ const sourceMax = BPMN_ELEMENT_CATALOG[source.data.elementType].maxOutgoing;
3609
+ const targetMax = BPMN_ELEMENT_CATALOG[target.data.elementType].maxIncoming;
3610
+ const outgoing = diagramsCore.getOutgoingEdges(state, source.id).filter(
3611
+ (edge) => edge.data?.edgeType === "sequenceFlow"
3612
+ );
3613
+ const incoming = diagramsCore.getIncomingEdges(state, target.id).filter(
3614
+ (edge) => edge.data?.edgeType === "sequenceFlow"
3615
+ );
3616
+ if (sourceMax !== void 0 && outgoing.length >= sourceMax) {
3617
+ return `${source.data.elementType} cannot have more than ${sourceMax} outgoing sequence flow(s).`;
3456
3618
  }
3457
- getState() {
3458
- return this.state;
3619
+ if (targetMax !== void 0 && incoming.length >= targetMax) {
3620
+ return `${target.data.elementType} cannot have more than ${targetMax} incoming sequence flow(s).`;
3459
3621
  }
3460
- isCompleted() {
3461
- return isCompleted(this.state);
3622
+ return true;
3623
+ }
3624
+ var bpmnConnectionValidators = [
3625
+ ({ state, source, target }) => {
3626
+ if (source.id === target.id) return "BPMN self-connections are not allowed.";
3627
+ const edgeType = inferBpmnEdgeType(state, source.id, target.id);
3628
+ if (getHandlePolicy(source.data.elementType) === "none" || getHandlePolicy(target.data.elementType) === "none") {
3629
+ return "Elements without BPMN connection handles cannot be directly connected.";
3630
+ }
3631
+ if (edgeType === "sequenceFlow") {
3632
+ if (!canUseSequenceFlow(source.data.elementType) || !canUseSequenceFlow(target.data.elementType)) {
3633
+ return "Sequence flows can only connect BPMN flow nodes.";
3634
+ }
3635
+ if (source.data.elementType === "EndEvent") return "End events cannot have outgoing sequence flows.";
3636
+ if (target.data.elementType === "StartEvent") return "Start events cannot have incoming sequence flows.";
3637
+ return validateEdgeCardinality(state, edgeType, source, target);
3638
+ }
3639
+ return true;
3462
3640
  }
3463
- };
3464
- function createPreviewAdapter(diagram, initialVariables) {
3465
- return new PreviewAdapter(diagram, initialVariables);
3641
+ ];
3642
+ var BPMN_MODELING_RULES = diagramsCore.createModelingRules({
3643
+ connect: [
3644
+ ({ state, source, target }) => {
3645
+ if (!source || !target) return false;
3646
+ for (const validator of bpmnConnectionValidators) {
3647
+ const result = validator({
3648
+ state,
3649
+ source,
3650
+ target,
3651
+ existingEdges: state.edges
3652
+ });
3653
+ if (result !== true) return result;
3654
+ }
3655
+ return true;
3656
+ }
3657
+ ],
3658
+ drop: [
3659
+ ({ node, parent }) => {
3660
+ if (!node || !parent) return true;
3661
+ if (node.data.elementType === "BoundaryEvent") {
3662
+ return acceptsBoundaryEvents(parent.data.elementType) ? true : "Boundary events can only be attached to tasks or subprocesses.";
3663
+ }
3664
+ if (parent.data.elementType === "Pool" || parent.data.elementType === "Lane") {
3665
+ return isEventType(node.data.elementType) || node.data.elementType.includes("Task") || node.data.elementType.includes("Gateway") || node.data.elementType.includes("SubProcess") ? true : "Only flow nodes can be dropped into pools or lanes.";
3666
+ }
3667
+ return true;
3668
+ }
3669
+ ],
3670
+ reparent: [
3671
+ ({ node, parent }) => {
3672
+ if (!node || !parent) return true;
3673
+ if (node.data.elementType === "BoundaryEvent") {
3674
+ return acceptsBoundaryEvents(parent.data.elementType) ? true : "Boundary events can only be reparented to tasks or subprocesses.";
3675
+ }
3676
+ return true;
3677
+ }
3678
+ ],
3679
+ delete: [() => true],
3680
+ resize: [() => true]
3681
+ });
3682
+ function createBpmnNodeCommand(options) {
3683
+ return {
3684
+ id: `bpmn.createNode.${options.id}`,
3685
+ label: `Create ${options.elementType}`,
3686
+ execute: (state) => diagramsCore.addNode(state, createBpmnNode(options))
3687
+ };
3688
+ }
3689
+ function connectBpmnCommand(options) {
3690
+ return {
3691
+ id: `bpmn.connect.${options.id ?? `${options.source}-${options.target}`}`,
3692
+ label: "Connect BPMN elements",
3693
+ execute: (state) => {
3694
+ const edgeType = options.edgeType ?? inferBpmnEdgeType(state, options.source, options.target);
3695
+ return diagramsCore.connectNodes(
3696
+ state,
3697
+ {
3698
+ source: options.source,
3699
+ target: options.target,
3700
+ type: edgeType,
3701
+ ...options.sourceHandle !== void 0 ? { sourceHandle: options.sourceHandle } : {},
3702
+ ...options.targetHandle !== void 0 ? { targetHandle: options.targetHandle } : {},
3703
+ ...options.id ? { id: options.id } : {},
3704
+ data: {
3705
+ edgeType,
3706
+ ...options.label ? { label: options.label } : {},
3707
+ ...options.data ?? {}
3708
+ }
3709
+ },
3710
+ bpmnConnectionValidators
3711
+ );
3712
+ }
3713
+ };
3714
+ }
3715
+ function attachBoundaryEventCommand(boundaryId, hostId) {
3716
+ return {
3717
+ id: `bpmn.attachBoundary.${boundaryId}.${hostId}`,
3718
+ label: "Attach boundary event",
3719
+ execute: (state) => {
3720
+ const host = diagramsCore.getNode(state, hostId);
3721
+ if (!host || !acceptsBoundaryEvents(host.data.elementType)) {
3722
+ throw new Error(`Element "${hostId}" cannot host boundary events.`);
3723
+ }
3724
+ const boundary = diagramsCore.getNode(state, boundaryId);
3725
+ if (!boundary || boundary.data.elementType !== "BoundaryEvent") {
3726
+ throw new Error(`Element "${boundaryId}" is not a boundary event.`);
3727
+ }
3728
+ const reparented = diagramsCore.reparentNode(state, boundaryId, { parentId: hostId });
3729
+ return diagramsCore.patchNode(reparented, boundaryId, {
3730
+ data: { attachedToRef: hostId }
3731
+ });
3732
+ }
3733
+ };
3734
+ }
3735
+ function replaceBpmnNodeCommand(options) {
3736
+ return {
3737
+ id: `bpmn.replaceNode.${options.id}.${options.elementType}`,
3738
+ label: `Replace with ${options.elementType}`,
3739
+ execute: (state) => {
3740
+ const current = diagramsCore.getNode(state, options.id);
3741
+ if (!current) throw new Error(`Element "${options.id}" does not exist.`);
3742
+ const meta = BPMN_ELEMENT_CATALOG[options.elementType];
3743
+ return diagramsCore.replaceNode(state, options.id, {
3744
+ ...current,
3745
+ type: options.elementType,
3746
+ width: options.width ?? current.width ?? meta.defaultWidth,
3747
+ height: options.height ?? current.height ?? meta.defaultHeight,
3748
+ data: {
3749
+ ...current.data,
3750
+ elementType: options.elementType,
3751
+ ...options.label ? { label: options.label } : {},
3752
+ ...options.data ?? {}
3753
+ }
3754
+ });
3755
+ }
3756
+ };
3757
+ }
3758
+ function reparentBpmnNodeCommand(options) {
3759
+ return {
3760
+ id: `bpmn.reparent.${options.id}.${options.parentId ?? "root"}`,
3761
+ label: "Reparent BPMN element",
3762
+ execute: (state) => {
3763
+ const node = diagramsCore.getNode(state, options.id);
3764
+ const parent = options.parentId ? diagramsCore.getNode(state, options.parentId) : void 0;
3765
+ if (!node) throw new Error(`Element "${options.id}" does not exist.`);
3766
+ if (parent && node.data.elementType === "BoundaryEvent" && !acceptsBoundaryEvents(parent.data.elementType)) {
3767
+ throw new Error("Boundary events can only be reparented to tasks or subprocesses.");
3768
+ }
3769
+ return diagramsCore.reparentNode(state, options.id, {
3770
+ ...options.parentId !== void 0 ? { parentId: options.parentId } : {},
3771
+ ...options.position ? { position: options.position } : {}
3772
+ });
3773
+ }
3774
+ };
3775
+ }
3776
+ function resizeBpmnNodeCommand(options) {
3777
+ return {
3778
+ id: `bpmn.resize.${options.id}`,
3779
+ label: "Resize BPMN element",
3780
+ execute: (state) => diagramsCore.resizeNode(state, options.id, options)
3781
+ };
3782
+ }
3783
+ function deleteBpmnElementsCommand(ids) {
3784
+ return {
3785
+ id: `bpmn.delete.${ids.join(".")}`,
3786
+ label: "Delete BPMN elements",
3787
+ execute: (state) => diagramsCore.removeElements(state, ids)
3788
+ };
3789
+ }
3790
+ function copyBpmnElements(state, selection) {
3791
+ return diagramsCore.copyElements(state, selection);
3792
+ }
3793
+ function pasteBpmnElementsCommand(clipboard, options = {}) {
3794
+ return {
3795
+ id: "bpmn.paste",
3796
+ label: "Paste BPMN elements",
3797
+ execute: (state) => diagramsCore.pasteElements(state, clipboard, options)
3798
+ };
3799
+ }
3800
+ function selectBpmnElementsCommand(selection) {
3801
+ return {
3802
+ id: "bpmn.select",
3803
+ label: "Select BPMN elements",
3804
+ execute: (state) => diagramsCore.setSelection(state, diagramsCore.createSelectionState(selection.nodeIds, selection.edgeIds))
3805
+ };
3806
+ }
3807
+ function createBpmnDiagramDocument(state, options = {}) {
3808
+ return serialization.createDiagramDocument(diagramsCore.normalizeDiagramState(state), {
3809
+ ...options,
3810
+ diagramType: "bpmn"
3811
+ });
3812
+ }
3813
+ function serializeBpmnDiagram(state, options = {}) {
3814
+ return serialization.serializeDiagram(diagramsCore.normalizeDiagramState(state), {
3815
+ ...options,
3816
+ diagramType: "bpmn"
3817
+ });
3818
+ }
3819
+ function parseBpmnDiagramDocument(json) {
3820
+ const document = serialization.parseDiagramDocument(json);
3821
+ if (document.diagramType && document.diagramType !== "bpmn") {
3822
+ throw new Error(`Expected a BPMN diagram document, received "${document.diagramType}".`);
3823
+ }
3824
+ return document;
3825
+ }
3826
+ function deserializeBpmnDiagram(json) {
3827
+ const document = parseBpmnDiagramDocument(json);
3828
+ return serialization.deserializeDiagram(JSON.stringify(document));
3829
+ }
3830
+ function runBpmnCommand(stack, command) {
3831
+ return diagramsCore.executeCommand(stack, command);
3832
+ }
3833
+ function runBpmnCommands(stack, commands, options = {}) {
3834
+ return diagramsCore.executeCommands(stack, commands, options);
3466
3835
  }
3467
3836
 
3468
3837
  exports.AnnotationNode = AnnotationNode;
3469
3838
  exports.AssociationEdge = AssociationEdge;
3470
3839
  exports.BPMN_EDGE_TYPES = BPMN_EDGE_TYPES;
3471
3840
  exports.BPMN_ELEMENT_CATALOG = BPMN_ELEMENT_CATALOG;
3841
+ exports.BPMN_MODELING_RULES = BPMN_MODELING_RULES;
3472
3842
  exports.BPMN_NODE_TYPES = BPMN_NODE_TYPES;
3473
3843
  exports.BoundaryEventNode = BoundaryEventNode;
3474
3844
  exports.CallChoreographyNode = CallChoreographyNode;
@@ -3498,13 +3868,22 @@ exports.SubConversationNode = SubConversationNode;
3498
3868
  exports.SubProcessNode = SubProcessNode;
3499
3869
  exports.TaskNode = TaskNode;
3500
3870
  exports.acceptsBoundaryEvents = acceptsBoundaryEvents;
3501
- exports.createPreviewAdapter = createPreviewAdapter;
3871
+ exports.attachBoundaryEventCommand = attachBoundaryEventCommand;
3872
+ exports.bpmnConnectionValidators = bpmnConnectionValidators;
3873
+ exports.connectBpmnCommand = connectBpmnCommand;
3874
+ exports.copyBpmnElements = copyBpmnElements;
3875
+ exports.createBpmnDiagramDocument = createBpmnDiagramDocument;
3876
+ exports.createBpmnNode = createBpmnNode;
3877
+ exports.createBpmnNodeCommand = createBpmnNodeCommand;
3502
3878
  exports.createSimulation = createSimulation;
3879
+ exports.deleteBpmnElementsCommand = deleteBpmnElementsCommand;
3880
+ exports.deserializeBpmnDiagram = deserializeBpmnDiagram;
3503
3881
  exports.fire = fire;
3504
3882
  exports.getElementMeta = getElementMeta;
3505
3883
  exports.getFireable = getFireable;
3506
3884
  exports.getHandlePolicy = getHandlePolicy;
3507
3885
  exports.getOrientation = getOrientation;
3886
+ exports.inferBpmnEdgeType = inferBpmnEdgeType;
3508
3887
  exports.isChoreographyType = isChoreographyType;
3509
3888
  exports.isCompleted = isCompleted;
3510
3889
  exports.isContainerType = isContainerType;
@@ -3513,7 +3892,16 @@ exports.isDataType = isDataType;
3513
3892
  exports.isEventType = isEventType;
3514
3893
  exports.isGatewayType = isGatewayType;
3515
3894
  exports.isTaskType = isTaskType;
3895
+ exports.parseBpmnDiagramDocument = parseBpmnDiagramDocument;
3516
3896
  exports.parseBpmnXml = parseBpmnXml;
3897
+ exports.pasteBpmnElementsCommand = pasteBpmnElementsCommand;
3898
+ exports.reparentBpmnNodeCommand = reparentBpmnNodeCommand;
3899
+ exports.replaceBpmnNodeCommand = replaceBpmnNodeCommand;
3900
+ exports.resizeBpmnNodeCommand = resizeBpmnNodeCommand;
3901
+ exports.runBpmnCommand = runBpmnCommand;
3902
+ exports.runBpmnCommands = runBpmnCommands;
3903
+ exports.selectBpmnElementsCommand = selectBpmnElementsCommand;
3904
+ exports.serializeBpmnDiagram = serializeBpmnDiagram;
3517
3905
  exports.serializeBpmnXml = serializeBpmnXml;
3518
3906
  exports.setVariable = setVariable;
3519
3907
  exports.supportsCollapse = supportsCollapse;