orcasvn-react-diagrams 0.2.2 → 0.2.4

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 (83) hide show
  1. package/CHANGELOG.md +69 -0
  2. package/README.md +15 -3
  3. package/dist/cjs/examples.js +2616 -291
  4. package/dist/cjs/index.js +1186 -153
  5. package/dist/cjs/types/api/createDiagramEditor.d.ts +19 -1
  6. package/dist/cjs/types/api/index.d.ts +1 -1
  7. package/dist/cjs/types/api/types.d.ts +41 -0
  8. package/dist/cjs/types/displaybox/DisplayBoxControls.d.ts +5 -1
  9. package/dist/cjs/types/displaybox/demos/AsymmetricPortMultiAnchorDemoTab.d.ts +3 -0
  10. package/dist/cjs/types/displaybox/demos/LayoutLabelReservedSpaceDemoTab.d.ts +3 -0
  11. package/dist/cjs/types/displaybox/demos/VertexControlLinkSessionDemoTab.d.ts +3 -0
  12. package/dist/cjs/types/displaybox/demos/asymmetricPortMultiAnchorDemo.d.ts +31 -0
  13. package/dist/cjs/types/displaybox/demos/labelStyleDemo.d.ts +2 -0
  14. package/dist/cjs/types/displaybox/demos/layoutLabelReservedSpaceDemo.d.ts +11 -0
  15. package/dist/cjs/types/displaybox/demos/portPositionLimitsDemo.d.ts +2 -0
  16. package/dist/cjs/types/displaybox/demos/vertexControlLinkSessionDemo.d.ts +12 -0
  17. package/dist/cjs/types/displaybox/useDemoControls.d.ts +4 -0
  18. package/dist/cjs/types/engine/AutoLayoutService.d.ts +2 -0
  19. package/dist/cjs/types/engine/DiagramEngine.d.ts +11 -0
  20. package/dist/cjs/types/engine/LinkRoutingService.d.ts +9 -1
  21. package/dist/cjs/types/models/PortModel.d.ts +5 -0
  22. package/dist/cjs/types/renderer/RenderTypes.d.ts +3 -1
  23. package/dist/cjs/types/renderer/konva/KonvaInteraction.d.ts +14 -0
  24. package/dist/cjs/types/renderer/konva/KonvaNodeFactory.d.ts +12 -0
  25. package/dist/cjs/types/renderer/konva/KonvaRenderer.d.ts +2 -1
  26. package/dist/cjs/types/shapes/BuiltInShapes.d.ts +3 -1
  27. package/dist/cjs/types/strategies/ObstacleRouter.d.ts +2 -0
  28. package/dist/cjs/types/utils/__tests__/portGeometry.test.d.ts +1 -0
  29. package/dist/cjs/types/utils/portGeometry.d.ts +44 -0
  30. package/dist/esm/examples.js +2617 -292
  31. package/dist/esm/examples.js.map +1 -1
  32. package/dist/esm/index.js +1186 -153
  33. package/dist/esm/index.js.map +1 -1
  34. package/dist/esm/types/api/createDiagramEditor.d.ts +19 -1
  35. package/dist/esm/types/api/index.d.ts +1 -1
  36. package/dist/esm/types/api/types.d.ts +41 -0
  37. package/dist/esm/types/displaybox/DisplayBoxControls.d.ts +5 -1
  38. package/dist/esm/types/displaybox/demos/AsymmetricPortMultiAnchorDemoTab.d.ts +3 -0
  39. package/dist/esm/types/displaybox/demos/LayoutLabelReservedSpaceDemoTab.d.ts +3 -0
  40. package/dist/esm/types/displaybox/demos/VertexControlLinkSessionDemoTab.d.ts +3 -0
  41. package/dist/esm/types/displaybox/demos/asymmetricPortMultiAnchorDemo.d.ts +31 -0
  42. package/dist/esm/types/displaybox/demos/labelStyleDemo.d.ts +2 -0
  43. package/dist/esm/types/displaybox/demos/layoutLabelReservedSpaceDemo.d.ts +11 -0
  44. package/dist/esm/types/displaybox/demos/portPositionLimitsDemo.d.ts +2 -0
  45. package/dist/esm/types/displaybox/demos/vertexControlLinkSessionDemo.d.ts +12 -0
  46. package/dist/esm/types/displaybox/useDemoControls.d.ts +4 -0
  47. package/dist/esm/types/engine/AutoLayoutService.d.ts +2 -0
  48. package/dist/esm/types/engine/DiagramEngine.d.ts +11 -0
  49. package/dist/esm/types/engine/LinkRoutingService.d.ts +9 -1
  50. package/dist/esm/types/models/PortModel.d.ts +5 -0
  51. package/dist/esm/types/renderer/RenderTypes.d.ts +3 -1
  52. package/dist/esm/types/renderer/konva/KonvaInteraction.d.ts +14 -0
  53. package/dist/esm/types/renderer/konva/KonvaNodeFactory.d.ts +12 -0
  54. package/dist/esm/types/renderer/konva/KonvaRenderer.d.ts +2 -1
  55. package/dist/esm/types/shapes/BuiltInShapes.d.ts +3 -1
  56. package/dist/esm/types/strategies/ObstacleRouter.d.ts +2 -0
  57. package/dist/esm/types/utils/__tests__/portGeometry.test.d.ts +1 -0
  58. package/dist/esm/types/utils/portGeometry.d.ts +44 -0
  59. package/dist/examples.d.ts +59 -0
  60. package/dist/index.d.ts +67 -1
  61. package/package.json +2 -1
  62. package/src/displaybox/demos/AsymmetricPortMultiAnchorDemoTab.tsx +269 -0
  63. package/src/displaybox/demos/AutoLayoutDemoTab.tsx +113 -11
  64. package/src/displaybox/demos/DeletionEventsDemoTab.tsx +6 -1
  65. package/src/displaybox/demos/EngineEventsDemoTab.tsx +5 -0
  66. package/src/displaybox/demos/EventHandlersDemoTab.tsx +5 -0
  67. package/src/displaybox/demos/ExternalDragDropDemoTab.tsx +5 -0
  68. package/src/displaybox/demos/LayoutLabelReservedSpaceDemoTab.tsx +291 -0
  69. package/src/displaybox/demos/LinkCancelDemoTab.tsx +5 -0
  70. package/src/displaybox/demos/ObstacleRoutingDemoTab.tsx +11 -10
  71. package/src/displaybox/demos/ShapeHoverControlsDemoTab.tsx +6 -1
  72. package/src/displaybox/demos/SimpleDemo.tsx +5 -0
  73. package/src/displaybox/demos/SvgPathDemoTab.tsx +5 -0
  74. package/src/displaybox/demos/TextLayoutDemoTab.tsx +6 -1
  75. package/src/displaybox/demos/VertexControlLinkSessionDemoTab.tsx +302 -0
  76. package/src/displaybox/demos/asymmetricPortMultiAnchorDemo.ts +357 -0
  77. package/src/displaybox/demos/autoLayoutDemo.ts +23 -5
  78. package/src/displaybox/demos/index.tsx +110 -80
  79. package/src/displaybox/demos/labelStyleDemo.ts +101 -0
  80. package/src/displaybox/demos/layoutLabelReservedSpaceDemo.ts +121 -0
  81. package/src/displaybox/demos/obstacleRoutingDemo.ts +212 -176
  82. package/src/displaybox/demos/portPositionLimitsDemo.ts +211 -0
  83. package/src/displaybox/demos/vertexControlLinkSessionDemo.ts +145 -0
package/dist/esm/index.js CHANGED
@@ -215,6 +215,11 @@ var PortModel = /** @class */ (function () {
215
215
  this.moveMode = data.moveMode;
216
216
  this.anchorCenter = (_a = data.anchorCenter) !== null && _a !== void 0 ? _a : true;
217
217
  this.orientToHostBorder = (_b = data.orientToHostBorder) !== null && _b !== void 0 ? _b : true;
218
+ this.placementPoint = data.placementPoint ? __assign({}, data.placementPoint) : undefined;
219
+ this.linkAttachPoint = data.linkAttachPoint ? __assign({}, data.linkAttachPoint) : undefined;
220
+ this.externalLinkAttachPoint = data.externalLinkAttachPoint ? __assign({}, data.externalLinkAttachPoint) : undefined;
221
+ this.internalLinkAttachPoint = data.internalLinkAttachPoint ? __assign({}, data.internalLinkAttachPoint) : undefined;
222
+ this.rotationPivot = data.rotationPivot ? __assign({}, data.rotationPivot) : undefined;
218
223
  this.currentAnchorId = data.currentAnchorId;
219
224
  }
220
225
  PortModel.prototype.setPosition = function (position) {
@@ -243,6 +248,11 @@ var PortModel = /** @class */ (function () {
243
248
  moveMode: this.moveMode,
244
249
  anchorCenter: this.anchorCenter,
245
250
  orientToHostBorder: this.orientToHostBorder,
251
+ placementPoint: this.placementPoint ? __assign({}, this.placementPoint) : undefined,
252
+ linkAttachPoint: this.linkAttachPoint ? __assign({}, this.linkAttachPoint) : undefined,
253
+ externalLinkAttachPoint: this.externalLinkAttachPoint ? __assign({}, this.externalLinkAttachPoint) : undefined,
254
+ internalLinkAttachPoint: this.internalLinkAttachPoint ? __assign({}, this.internalLinkAttachPoint) : undefined,
255
+ rotationPivot: this.rotationPivot ? __assign({}, this.rotationPivot) : undefined,
246
256
  currentAnchorId: this.currentAnchorId,
247
257
  };
248
258
  };
@@ -1271,21 +1281,42 @@ var ObstacleRouter = /** @class */ (function () {
1271
1281
  ObstacleRouter.prototype.computeStubEndpoint = function (point, endpoint, bounds, obstacles) {
1272
1282
  if (!(endpoint === null || endpoint === void 0 ? void 0 : endpoint.onEdgeSide) || !endpoint.rect)
1273
1283
  return null;
1274
- var normal = this.getNormal(endpoint.onEdgeSide);
1284
+ var outwardNormal = this.getNormal(endpoint.onEdgeSide);
1285
+ var selectedNormal = outwardNormal;
1286
+ var maxLength = this.computeAvailableStubLength(point, outwardNormal, bounds, obstacles, endpoint.elementId);
1287
+ // If the outward normal is fully blocked by route bounds on the endpoint host, fall back inward
1288
+ // to preserve a visible perpendicular stub for bounded parent-child routes.
1289
+ if (maxLength <= this.tolerance && bounds && this.rectsEqual(bounds, endpoint.rect)) {
1290
+ var inwardNormal = { x: -outwardNormal.x, y: -outwardNormal.y };
1291
+ var inwardLength = this.computeAvailableStubLength(point, inwardNormal, bounds, obstacles, endpoint.elementId);
1292
+ if (inwardLength > maxLength) {
1293
+ selectedNormal = inwardNormal;
1294
+ maxLength = inwardLength;
1295
+ }
1296
+ }
1297
+ if (maxLength <= 0)
1298
+ return null;
1299
+ return {
1300
+ x: point.x + selectedNormal.x * maxLength,
1301
+ y: point.y + selectedNormal.y * maxLength,
1302
+ };
1303
+ };
1304
+ ObstacleRouter.prototype.computeAvailableStubLength = function (point, normal, bounds, obstacles, ignoreId) {
1275
1305
  var maxLength = this.stubLength;
1276
1306
  if (bounds) {
1277
1307
  maxLength = Math.min(maxLength, this.distanceToBounds(point, normal, bounds));
1278
1308
  }
1279
- var obstacleLimit = this.distanceToObstacles(point, normal, obstacles, endpoint.elementId);
1309
+ var obstacleLimit = this.distanceToObstacles(point, normal, obstacles, ignoreId);
1280
1310
  if (obstacleLimit !== null) {
1281
1311
  maxLength = Math.min(maxLength, obstacleLimit);
1282
1312
  }
1283
- if (maxLength <= 0)
1284
- return null;
1285
- return {
1286
- x: point.x + normal.x * maxLength,
1287
- y: point.y + normal.y * maxLength,
1288
- };
1313
+ return maxLength;
1314
+ };
1315
+ ObstacleRouter.prototype.rectsEqual = function (a, b) {
1316
+ return (Math.abs(a.x - b.x) <= this.tolerance &&
1317
+ Math.abs(a.y - b.y) <= this.tolerance &&
1318
+ Math.abs(a.width - b.width) <= this.tolerance &&
1319
+ Math.abs(a.height - b.height) <= this.tolerance);
1289
1320
  };
1290
1321
  ObstacleRouter.prototype.getNormal = function (side) {
1291
1322
  switch (side) {
@@ -1582,7 +1613,7 @@ var borderSideToInwardRotation = function (side) {
1582
1613
  return 0;
1583
1614
  };
1584
1615
 
1585
- var POSITION_EPSILON$1 = 1e-6;
1616
+ var POSITION_EPSILON$2 = 1e-6;
1586
1617
  var MIN_TRUNCATION_WIDTH_SAFETY_EPSILON = 0.5;
1587
1618
  var FONT_SIZE_TRUNCATION_SAFETY_RATIO = 1.4;
1588
1619
  var FONT_SIZE_TRUNCATION_SAFETY_BASE = 2;
@@ -1608,7 +1639,7 @@ var TextLayoutService = /** @class */ (function () {
1608
1639
  var textRenderPadding = this.resolveTextRenderPadding(text.style);
1609
1640
  var horizontalRenderInset = textRenderPadding * 2;
1610
1641
  var verticalRenderInset = textRenderPadding * 2;
1611
- var zeroPaddingInset = padding <= POSITION_EPSILON$1 && this.shouldTrackOwnerBoundLayout(text) ? 0.5 : 0;
1642
+ var zeroPaddingInset = padding <= POSITION_EPSILON$2 && this.shouldTrackOwnerBoundLayout(text) ? 0.5 : 0;
1612
1643
  var drawableWidth = maxWidth !== undefined ? Math.max(0, maxWidth - zeroPaddingInset * 2 - horizontalRenderInset) : undefined;
1613
1644
  var drawableHeight = maxHeight !== undefined ? Math.max(0, maxHeight - zeroPaddingInset * 2 - verticalRenderInset) : undefined;
1614
1645
  var lineHeight = this.textMeasurer.measure(__assign(__assign({}, text), { content: 'M' })).height;
@@ -1925,6 +1956,7 @@ var AutoLayoutService = /** @class */ (function () {
1925
1956
  var childFitCrossAxis = (_e = layout.childFitCrossAxis) !== null && _e !== void 0 ? _e : 'none';
1926
1957
  var childFitMinSize = layout.childFitMinSize;
1927
1958
  var childFitMaxSize = layout.childFitMaxSize;
1959
+ var labelReservedTopLane = this.resolveLabelReservedTopLane(parentId, layout);
1928
1960
  var sorted = __spreadArray([], children, true).sort(function (a, b) {
1929
1961
  var aPos = axis === 'horizontal' ? a.position.x : a.position.y;
1930
1962
  var bPos = axis === 'horizontal' ? b.position.x : b.position.y;
@@ -1935,7 +1967,7 @@ var AutoLayoutService = /** @class */ (function () {
1935
1967
  var gapCount = Math.max(0, sorted.length - 1);
1936
1968
  var calculateFittedSizes = function (parentWidth, parentHeight) {
1937
1969
  var availableWidth = Math.max(0, parentWidth - padding.x * 2);
1938
- var availableHeight = Math.max(0, parentHeight - padding.y * 2);
1970
+ var availableHeight = Math.max(0, parentHeight - padding.y * 2 - labelReservedTopLane);
1939
1971
  var availableMain = axis === 'horizontal'
1940
1972
  ? Math.max(0, availableWidth - gap * gapCount)
1941
1973
  : Math.max(0, availableHeight - gap * gapCount);
@@ -1980,12 +2012,12 @@ var AutoLayoutService = /** @class */ (function () {
1980
2012
  if (axis === 'horizontal') {
1981
2013
  return {
1982
2014
  width: Math.max(parent.size.width, padding.x * 2 + totalWidth + gap * gapCount),
1983
- height: Math.max(parent.size.height, padding.y * 2 + maxHeight),
2015
+ height: Math.max(parent.size.height, padding.y * 2 + labelReservedTopLane + maxHeight),
1984
2016
  };
1985
2017
  }
1986
2018
  return {
1987
2019
  width: Math.max(parent.size.width, padding.x * 2 + maxWidth),
1988
- height: Math.max(parent.size.height, padding.y * 2 + totalHeight + gap * gapCount),
2020
+ height: Math.max(parent.size.height, padding.y * 2 + labelReservedTopLane + totalHeight + gap * gapCount),
1989
2021
  };
1990
2022
  };
1991
2023
  var fittedSizes = calculateFittedSizes(parent.size.width, parent.size.height);
@@ -1993,9 +2025,9 @@ var AutoLayoutService = /** @class */ (function () {
1993
2025
  fittedSizes = calculateFittedSizes(newParentWidth, newParentHeight);
1994
2026
  (_a = resolveParentSize(fittedSizes), newParentWidth = _a.width, newParentHeight = _a.height);
1995
2027
  var availableWidth = Math.max(0, newParentWidth - padding.x * 2);
1996
- var availableHeight = Math.max(0, newParentHeight - padding.y * 2);
2028
+ var availableHeight = Math.max(0, newParentHeight - padding.y * 2 - labelReservedTopLane);
1997
2029
  var cursorX = padding.x;
1998
- var cursorY = padding.y;
2030
+ var cursorY = padding.y + labelReservedTopLane;
1999
2031
  var desiredPositions = new Map();
2000
2032
  var desiredSizes = new Map();
2001
2033
  sorted.forEach(function (child, index) {
@@ -2003,10 +2035,10 @@ var AutoLayoutService = /** @class */ (function () {
2003
2035
  desiredSizes.set(child.id, fittedSize);
2004
2036
  if (axis === 'horizontal') {
2005
2037
  var y = align === 'start'
2006
- ? padding.y
2038
+ ? padding.y + labelReservedTopLane
2007
2039
  : align === 'end'
2008
2040
  ? newParentHeight - padding.y - fittedSize.height
2009
- : padding.y + Math.max(0, (availableHeight - fittedSize.height) / 2);
2041
+ : padding.y + labelReservedTopLane + Math.max(0, (availableHeight - fittedSize.height) / 2);
2010
2042
  desiredPositions.set(child.id, { x: cursorX, y: y });
2011
2043
  cursorX += fittedSize.width + (index < sorted.length - 1 ? gap : 0);
2012
2044
  }
@@ -2099,6 +2131,45 @@ var AutoLayoutService = /** @class */ (function () {
2099
2131
  y: (_c = padding.y) !== null && _c !== void 0 ? _c : 12,
2100
2132
  };
2101
2133
  };
2134
+ AutoLayoutService.prototype.resolveLabelReservedTopLane = function (parentId, layout) {
2135
+ var _a, _b, _c, _d;
2136
+ var policy = layout === null || layout === void 0 ? void 0 : layout.labelReservedSpace;
2137
+ if (!policy)
2138
+ return 0;
2139
+ var mode = (_a = policy.mode) !== null && _a !== void 0 ? _a : 'none';
2140
+ if (mode === 'none')
2141
+ return 0;
2142
+ if (((_b = policy.placement) !== null && _b !== void 0 ? _b : 'top') !== 'top')
2143
+ return 0;
2144
+ var minSize = Math.max(0, (_c = policy.minSize) !== null && _c !== void 0 ? _c : 0);
2145
+ var maxSize = typeof policy.maxSize === 'number' && Number.isFinite(policy.maxSize)
2146
+ ? Math.max(minSize, policy.maxSize)
2147
+ : Number.POSITIVE_INFINITY;
2148
+ var resolved = 0;
2149
+ if (mode === 'fixed') {
2150
+ resolved = Math.max(0, (_d = policy.size) !== null && _d !== void 0 ? _d : 0);
2151
+ }
2152
+ else {
2153
+ resolved = this.resolveFlexibleLabelLaneFromText(parentId);
2154
+ }
2155
+ return this.clampLayoutSize(resolved, minSize, maxSize);
2156
+ };
2157
+ AutoLayoutService.prototype.resolveFlexibleLabelLaneFromText = function (parentId) {
2158
+ var lane = 0;
2159
+ this.model.texts.forEach(function (text) {
2160
+ var _a, _b, _c;
2161
+ if (text.ownerId !== parentId)
2162
+ return;
2163
+ var offset = (_a = text.displayOffset) !== null && _a !== void 0 ? _a : { x: 0, y: 0 };
2164
+ var size = (_b = text.displayClipSize) !== null && _b !== void 0 ? _b : text.size;
2165
+ var height = (_c = size === null || size === void 0 ? void 0 : size.height) !== null && _c !== void 0 ? _c : 0;
2166
+ var bottom = text.position.y + offset.y + height;
2167
+ if (bottom > lane) {
2168
+ lane = bottom;
2169
+ }
2170
+ });
2171
+ return Math.max(0, lane);
2172
+ };
2102
2173
  AutoLayoutService.prototype.clampLayoutSize = function (value, min, max) {
2103
2174
  var minValue = min !== null && min !== void 0 ? min : 0;
2104
2175
  var maxValue = max !== null && max !== void 0 ? max : Number.POSITIVE_INFINITY;
@@ -2167,7 +2238,106 @@ var AutoLayoutService = /** @class */ (function () {
2167
2238
  return AutoLayoutService;
2168
2239
  }());
2169
2240
 
2241
+ var ZERO_POINT = { x: 0, y: 0 };
2242
+ var clonePoint = function (point) { return ({ x: point.x, y: point.y }); };
2243
+ var borderSideToNormal = function (side) {
2244
+ if (side === 'left')
2245
+ return { x: -1, y: 0 };
2246
+ if (side === 'right')
2247
+ return { x: 1, y: 0 };
2248
+ if (side === 'top')
2249
+ return { x: 0, y: -1 };
2250
+ return { x: 0, y: 1 };
2251
+ };
2252
+ var resolvePortGeometryPoints = function (port, attachMode) {
2253
+ var _a, _b, _c, _d, _e;
2254
+ var placementPoint = clonePoint((_a = port.placementPoint) !== null && _a !== void 0 ? _a : ZERO_POINT);
2255
+ var sharedLinkAttachPoint = clonePoint((_b = port.linkAttachPoint) !== null && _b !== void 0 ? _b : placementPoint);
2256
+ var effectiveLinkAttachPoint = clonePoint(attachMode === 'internal'
2257
+ ? (_c = port.internalLinkAttachPoint) !== null && _c !== void 0 ? _c : sharedLinkAttachPoint
2258
+ : (_d = port.externalLinkAttachPoint) !== null && _d !== void 0 ? _d : sharedLinkAttachPoint);
2259
+ var rotationPivot = clonePoint((_e = port.rotationPivot) !== null && _e !== void 0 ? _e : placementPoint);
2260
+ return {
2261
+ placementPoint: placementPoint,
2262
+ sharedLinkAttachPoint: sharedLinkAttachPoint,
2263
+ effectiveLinkAttachPoint: effectiveLinkAttachPoint,
2264
+ rotationPivot: rotationPivot,
2265
+ };
2266
+ };
2267
+ var resolvePortOrientationContext = function (options) {
2268
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
2269
+ var port = options.port, worldPlacement = options.worldPlacement, host = options.host, shapeRegistry = options.shapeRegistry, attachMode = options.attachMode;
2270
+ var portShape = port.shapeId ? shapeRegistry.get(port.shapeId) : undefined;
2271
+ var localRotation = ((_a = portShape === null || portShape === void 0 ? void 0 : portShape.baseRotation) !== null && _a !== void 0 ? _a : 0) +
2272
+ (typeof ((_b = port.style) === null || _b === void 0 ? void 0 : _b.rotation) === 'number' ? port.style.rotation : 0);
2273
+ var nodeAnchorPoint = port.anchorCenter && (portShape === null || portShape === void 0 ? void 0 : portShape.svgPath)
2274
+ ? {
2275
+ x: ((_f = (_d = (_c = portShape.svgSize) === null || _c === void 0 ? void 0 : _c.width) !== null && _d !== void 0 ? _d : (_e = port.size) === null || _e === void 0 ? void 0 : _e.width) !== null && _f !== void 0 ? _f : 0) / 2,
2276
+ y: ((_k = (_h = (_g = portShape.svgSize) === null || _g === void 0 ? void 0 : _g.height) !== null && _h !== void 0 ? _h : (_j = port.size) === null || _j === void 0 ? void 0 : _j.height) !== null && _k !== void 0 ? _k : 0) / 2,
2277
+ }
2278
+ : __assign({}, ZERO_POINT);
2279
+ if (port.moveMode !== 'border' || port.orientToHostBorder === false || !host) {
2280
+ return { localRotation: localRotation, rotation: 0, offset: __assign({}, ZERO_POINT), nodeAnchorPoint: nodeAnchorPoint };
2281
+ }
2282
+ var hostRect = {
2283
+ x: host.position.x,
2284
+ y: host.position.y,
2285
+ width: host.size.width,
2286
+ height: host.size.height,
2287
+ };
2288
+ var shape = shapeRegistry.get(host.shapeId);
2289
+ var side = (shape === null || shape === void 0 ? void 0 : shape.resolveBorderSide)
2290
+ ? shape.resolveBorderSide(worldPlacement, hostRect)
2291
+ : resolveBoundarySide(worldPlacement, hostRect, 'rect');
2292
+ var normal = (shape === null || shape === void 0 ? void 0 : shape.resolveBorderNormal)
2293
+ ? shape.resolveBorderNormal(worldPlacement, hostRect)
2294
+ : borderSideToNormal(side);
2295
+ var geometry = resolvePortGeometryPoints(port, attachMode);
2296
+ var hookContext = {
2297
+ side: side,
2298
+ normal: normal,
2299
+ hostRect: hostRect,
2300
+ attachMode: attachMode,
2301
+ effectiveLinkAttachPoint: geometry.effectiveLinkAttachPoint,
2302
+ placementPoint: geometry.placementPoint,
2303
+ rotationPivot: geometry.rotationPivot,
2304
+ portSize: port.size,
2305
+ };
2306
+ var hookResult = (_l = shape === null || shape === void 0 ? void 0 : shape.resolvePortBorderTransform) === null || _l === void 0 ? void 0 : _l.call(shape, hookContext);
2307
+ return {
2308
+ localRotation: localRotation,
2309
+ nodeAnchorPoint: nodeAnchorPoint,
2310
+ side: side,
2311
+ normal: normal,
2312
+ rotation: borderSideToInwardRotation(side) + ((_m = hookResult === null || hookResult === void 0 ? void 0 : hookResult.rotation) !== null && _m !== void 0 ? _m : 0),
2313
+ offset: (hookResult === null || hookResult === void 0 ? void 0 : hookResult.offset) ? clonePoint(hookResult.offset) : __assign({}, ZERO_POINT),
2314
+ };
2315
+ };
2316
+ var resolvePortWorldTransform = function (options) {
2317
+ var port = options.port, worldPlacement = options.worldPlacement, attachMode = options.attachMode, orientation = options.orientation;
2318
+ var geometry = resolvePortGeometryPoints(port, attachMode);
2319
+ var totalRotation = orientation.localRotation + orientation.rotation;
2320
+ var rotatedPlacement = rotatePoint({
2321
+ x: geometry.placementPoint.x - orientation.nodeAnchorPoint.x,
2322
+ y: geometry.placementPoint.y - orientation.nodeAnchorPoint.y,
2323
+ }, ZERO_POINT, totalRotation);
2324
+ var rotatedAttach = rotatePoint({
2325
+ x: geometry.effectiveLinkAttachPoint.x - orientation.nodeAnchorPoint.x,
2326
+ y: geometry.effectiveLinkAttachPoint.y - orientation.nodeAnchorPoint.y,
2327
+ }, ZERO_POINT, totalRotation);
2328
+ var nodePosition = {
2329
+ x: worldPlacement.x - rotatedPlacement.x + orientation.offset.x,
2330
+ y: worldPlacement.y - rotatedPlacement.y + orientation.offset.y,
2331
+ };
2332
+ var linkAttachWorld = {
2333
+ x: nodePosition.x + rotatedAttach.x,
2334
+ y: nodePosition.y + rotatedAttach.y,
2335
+ };
2336
+ return { nodePosition: nodePosition, linkAttachWorld: linkAttachWorld };
2337
+ };
2338
+
2170
2339
  var EDGE_TOLERANCE = 0.5;
2340
+ var POSITION_EPSILON$1 = 1e-6;
2171
2341
  var LinkRoutingService = /** @class */ (function () {
2172
2342
  function LinkRoutingService(config) {
2173
2343
  this.model = config.model;
@@ -2191,8 +2361,9 @@ var LinkRoutingService = /** @class */ (function () {
2191
2361
  }
2192
2362
  if (updatedLinks.has(link.id))
2193
2363
  return;
2194
- var source = _this.model.getPortWorldPosition(link.sourcePortId);
2195
- var target = _this.model.getPortWorldPosition(link.targetPortId);
2364
+ var endpoints = _this.resolveLinkEndpoints(link);
2365
+ var source = endpoints.source;
2366
+ var target = endpoints.target;
2196
2367
  if (!source || !target)
2197
2368
  return;
2198
2369
  var points = _this.resolveLinkPointsForUpdate(link, source, target);
@@ -2209,8 +2380,9 @@ var LinkRoutingService = /** @class */ (function () {
2209
2380
  var _a;
2210
2381
  if (link.points.length > 0)
2211
2382
  return;
2212
- var source = _this.model.getPortWorldPosition(link.sourcePortId);
2213
- var target = _this.model.getPortWorldPosition(link.targetPortId);
2383
+ var endpoints = _this.resolveLinkEndpoints(link);
2384
+ var source = endpoints.source;
2385
+ var target = endpoints.target;
2214
2386
  if (!source || !target)
2215
2387
  return;
2216
2388
  var points = ((_a = link.routing) !== null && _a !== void 0 ? _a : 'auto') === 'manual'
@@ -2221,6 +2393,31 @@ var LinkRoutingService = /** @class */ (function () {
2221
2393
  });
2222
2394
  return patches;
2223
2395
  };
2396
+ LinkRoutingService.prototype.getPortLinkWorldPosition = function (portId, options) {
2397
+ var _a;
2398
+ var port = this.model.getPort(portId);
2399
+ if (!port)
2400
+ return null;
2401
+ var worldPlacement = this.model.getPortWorldPosition(portId);
2402
+ if (!worldPlacement)
2403
+ return null;
2404
+ var host = this.resolveHostForPort(portId);
2405
+ var attachMode = (_a = options === null || options === void 0 ? void 0 : options.attachMode) !== null && _a !== void 0 ? _a : this.resolveAttachModeForPorts(portId, options === null || options === void 0 ? void 0 : options.oppositePortId);
2406
+ var orientation = resolvePortOrientationContext({
2407
+ port: port.toData(),
2408
+ worldPlacement: worldPlacement,
2409
+ host: host,
2410
+ shapeRegistry: this.shapeRegistry,
2411
+ attachMode: attachMode,
2412
+ });
2413
+ var transformed = resolvePortWorldTransform({
2414
+ port: port.toData(),
2415
+ worldPlacement: worldPlacement,
2416
+ attachMode: attachMode,
2417
+ orientation: orientation,
2418
+ });
2419
+ return transformed.linkAttachWorld;
2420
+ };
2224
2421
  LinkRoutingService.prototype.computeAutoRoute = function (link, source, target) {
2225
2422
  var routed = this.router.route(source, target, this.buildRouteContext(link));
2226
2423
  if (!routed || routed.length < 2) {
@@ -2239,15 +2436,37 @@ var LinkRoutingService = /** @class */ (function () {
2239
2436
  }
2240
2437
  return this.computeAutoRoute(link, source, target);
2241
2438
  };
2439
+ LinkRoutingService.prototype.resolveLinkEndpoints = function (link) {
2440
+ return {
2441
+ source: this.getPortLinkWorldPosition(link.sourcePortId, { oppositePortId: link.targetPortId }),
2442
+ target: this.getPortLinkWorldPosition(link.targetPortId, { oppositePortId: link.sourcePortId }),
2443
+ };
2444
+ };
2242
2445
  LinkRoutingService.prototype.updateManualRoute = function (points, source, target) {
2243
2446
  if (points.length < 2) {
2244
2447
  return [__assign({}, source), __assign({}, target)];
2245
2448
  }
2449
+ var sourceDelta = {
2450
+ x: source.x - points[0].x,
2451
+ y: source.y - points[0].y,
2452
+ };
2453
+ var targetDelta = {
2454
+ x: target.x - points[points.length - 1].x,
2455
+ y: target.y - points[points.length - 1].y,
2456
+ };
2457
+ var shouldTranslateAllPoints = Math.abs(sourceDelta.x - targetDelta.x) <= POSITION_EPSILON$1 &&
2458
+ Math.abs(sourceDelta.y - targetDelta.y) <= POSITION_EPSILON$1;
2246
2459
  return points.map(function (point, index) {
2247
2460
  if (index === 0)
2248
2461
  return __assign({}, source);
2249
2462
  if (index === points.length - 1)
2250
2463
  return __assign({}, target);
2464
+ if (shouldTranslateAllPoints) {
2465
+ return {
2466
+ x: point.x + sourceDelta.x,
2467
+ y: point.y + sourceDelta.y,
2468
+ };
2469
+ }
2251
2470
  return __assign({}, point);
2252
2471
  });
2253
2472
  };
@@ -2258,8 +2477,9 @@ var LinkRoutingService = /** @class */ (function () {
2258
2477
  var targetPort = this.model.getPort(link.targetPortId);
2259
2478
  var sourceElementId = sourcePort === null || sourcePort === void 0 ? void 0 : sourcePort.elementId;
2260
2479
  var targetElementId = targetPort === null || targetPort === void 0 ? void 0 : targetPort.elementId;
2261
- var sourcePosition = this.model.getPortWorldPosition(link.sourcePortId);
2262
- var targetPosition = this.model.getPortWorldPosition(link.targetPortId);
2480
+ var endpoints = this.resolveLinkEndpoints(link);
2481
+ var sourcePosition = endpoints.source;
2482
+ var targetPosition = endpoints.target;
2263
2483
  var sourceRect = sourceElementId ? this.getElementRect(sourceElementId) : null;
2264
2484
  var targetRect = targetElementId ? this.getElementRect(targetElementId) : null;
2265
2485
  var sourceEndpointGeometry = sourcePosition && sourceRect
@@ -2389,6 +2609,37 @@ var LinkRoutingService = /** @class */ (function () {
2389
2609
  height: element.size.height,
2390
2610
  };
2391
2611
  };
2612
+ LinkRoutingService.prototype.resolveHostForPort = function (portId) {
2613
+ var _a;
2614
+ var port = this.model.getPort(portId);
2615
+ if (!port)
2616
+ return null;
2617
+ var element = this.model.getElement(port.elementId);
2618
+ if (!element)
2619
+ return null;
2620
+ return {
2621
+ id: element.id,
2622
+ position: (_a = this.model.getElementWorldPosition(element.id)) !== null && _a !== void 0 ? _a : element.position,
2623
+ size: element.size,
2624
+ shapeId: element.shapeId,
2625
+ };
2626
+ };
2627
+ LinkRoutingService.prototype.resolveAttachModeForPorts = function (portId, oppositePortId) {
2628
+ var _a, _b;
2629
+ if (!oppositePortId)
2630
+ return 'external';
2631
+ var elementId = (_a = this.model.getPort(portId)) === null || _a === void 0 ? void 0 : _a.elementId;
2632
+ var oppositeElementId = (_b = this.model.getPort(oppositePortId)) === null || _b === void 0 ? void 0 : _b.elementId;
2633
+ if (!elementId || !oppositeElementId)
2634
+ return 'external';
2635
+ return this.isAncestorOf(elementId, oppositeElementId) ? 'internal' : 'external';
2636
+ };
2637
+ LinkRoutingService.prototype.isAncestorOf = function (candidateAncestorId, candidateDescendantId) {
2638
+ if (candidateAncestorId === candidateDescendantId)
2639
+ return false;
2640
+ var descendantChain = this.getAncestorChain(candidateDescendantId);
2641
+ return descendantChain.includes(candidateAncestorId);
2642
+ };
2392
2643
  LinkRoutingService.prototype.getAncestorChain = function (elementId) {
2393
2644
  var _a;
2394
2645
  var chain = [];
@@ -2547,11 +2798,17 @@ var DiagramEngine = /** @class */ (function () {
2547
2798
  DiagramEngine.prototype.load = function (state) {
2548
2799
  var _this = this;
2549
2800
  var patches = this.commandQueue.run(createLoadCommand(state), this.model);
2550
- var allPatches = this.mutationPipeline.run({
2801
+ var mutationPatches = this.mutationPipeline.run({
2551
2802
  basePatches: patches,
2552
2803
  layoutSteps: [function () { return _this.applyAllLayouts(); }],
2553
2804
  includeEmptyLinkRouting: true,
2554
2805
  });
2806
+ var normalizedPorts = this.normalizePortsForHostPolicies();
2807
+ var normalizedLinkPatches = normalizedPorts.movedPortIds.length > 0
2808
+ ? this.updateLinksForPorts(normalizedPorts.movedPortIds)
2809
+ : [];
2810
+ var textPresentationPatches = this.resolveAllTextPresentationPatches(false);
2811
+ var allPatches = __spreadArray(__spreadArray(__spreadArray(__spreadArray([], mutationPatches, true), normalizedPorts.patches, true), normalizedLinkPatches, true), textPresentationPatches, true);
2555
2812
  this.emitChange(allPatches);
2556
2813
  };
2557
2814
  DiagramEngine.prototype.getState = function () {
@@ -2766,8 +3023,12 @@ var DiagramEngine = /** @class */ (function () {
2766
3023
  };
2767
3024
  DiagramEngine.prototype.addLink = function (link) {
2768
3025
  var _a;
2769
- var source = this.model.getPortWorldPosition(link.sourcePortId);
2770
- var target = this.model.getPortWorldPosition(link.targetPortId);
3026
+ var source = this.linkRoutingService.getPortLinkWorldPosition(link.sourcePortId, {
3027
+ oppositePortId: link.targetPortId,
3028
+ });
3029
+ var target = this.linkRoutingService.getPortLinkWorldPosition(link.targetPortId, {
3030
+ oppositePortId: link.sourcePortId,
3031
+ });
2771
3032
  var routing = (_a = link.routing) !== null && _a !== void 0 ? _a : 'auto';
2772
3033
  var points = link.points;
2773
3034
  if (source && target) {
@@ -2791,8 +3052,12 @@ var DiagramEngine = /** @class */ (function () {
2791
3052
  return;
2792
3053
  var update = { routing: mode };
2793
3054
  if (mode === 'auto') {
2794
- var source = this.model.getPortWorldPosition(link.sourcePortId);
2795
- var target = this.model.getPortWorldPosition(link.targetPortId);
3055
+ var source = this.linkRoutingService.getPortLinkWorldPosition(link.sourcePortId, {
3056
+ oppositePortId: link.targetPortId,
3057
+ });
3058
+ var target = this.linkRoutingService.getPortLinkWorldPosition(link.targetPortId, {
3059
+ oppositePortId: link.sourcePortId,
3060
+ });
2796
3061
  if (source && target) {
2797
3062
  update.points = this.computeAutoRoute(link, source, target);
2798
3063
  }
@@ -2826,8 +3091,12 @@ var DiagramEngine = /** @class */ (function () {
2826
3091
  var routing = (_a = link.routing) !== null && _a !== void 0 ? _a : 'auto';
2827
3092
  if (routing === 'manual' && !includeManual)
2828
3093
  return;
2829
- var source = _this.model.getPortWorldPosition(link.sourcePortId);
2830
- var target = _this.model.getPortWorldPosition(link.targetPortId);
3094
+ var source = _this.linkRoutingService.getPortLinkWorldPosition(link.sourcePortId, {
3095
+ oppositePortId: link.targetPortId,
3096
+ });
3097
+ var target = _this.linkRoutingService.getPortLinkWorldPosition(link.targetPortId, {
3098
+ oppositePortId: link.sourcePortId,
3099
+ });
2831
3100
  if (!source || !target)
2832
3101
  return;
2833
3102
  var points = _this.computeAutoRoute(link, source, target);
@@ -2851,8 +3120,10 @@ var DiagramEngine = /** @class */ (function () {
2851
3120
  this.emitChange(patches);
2852
3121
  };
2853
3122
  DiagramEngine.prototype.updateText = function (id, content) {
3123
+ var _this = this;
2854
3124
  var patches = this.commandQueue.run(createUpdateTextCommand(id, content), this.model);
2855
3125
  var text = this.model.getText(id);
3126
+ var layoutOwnerId = (text === null || text === void 0 ? void 0 : text.ownerId) && this.hasFlexibleLabelReservedSpace(text.ownerId) ? text.ownerId : null;
2856
3127
  if (text) {
2857
3128
  var resolved = this.resolveTextPresentation(text.toData());
2858
3129
  text.setSize(resolved.size);
@@ -2873,7 +3144,18 @@ var DiagramEngine = /** @class */ (function () {
2873
3144
  reason: 'content',
2874
3145
  });
2875
3146
  }
2876
- this.emitChange(patches);
3147
+ if (!layoutOwnerId) {
3148
+ this.emitChange(patches);
3149
+ return;
3150
+ }
3151
+ var allPatches = this.mutationPipeline.run({
3152
+ basePatches: patches,
3153
+ layoutSteps: [
3154
+ function () { return _this.applyLayoutForParent(layoutOwnerId); },
3155
+ function () { var _a, _b; return _this.applyLayoutCascade((_b = (_a = _this.model.getElement(layoutOwnerId)) === null || _a === void 0 ? void 0 : _a.parentId) !== null && _b !== void 0 ? _b : null); },
3156
+ ],
3157
+ });
3158
+ this.emitChange(allPatches);
2877
3159
  };
2878
3160
  DiagramEngine.prototype.moveTextTo = function (id, x, y) {
2879
3161
  var text = this.model.getText(id);
@@ -2976,6 +3258,9 @@ var DiagramEngine = /** @class */ (function () {
2976
3258
  DiagramEngine.prototype.getPortWorldPosition = function (id) {
2977
3259
  return this.model.getPortWorldPosition(id);
2978
3260
  };
3261
+ DiagramEngine.prototype.getPortLinkWorldPosition = function (id, options) {
3262
+ return this.linkRoutingService.getPortLinkWorldPosition(id, options);
3263
+ };
2979
3264
  DiagramEngine.prototype.getTextWorldPosition = function (id) {
2980
3265
  return this.model.getTextWorldPosition(id);
2981
3266
  };
@@ -3115,7 +3400,7 @@ var DiagramEngine = /** @class */ (function () {
3115
3400
  if (!host)
3116
3401
  return;
3117
3402
  host.portIds.forEach(function (portId) {
3118
- var _a;
3403
+ var _a, _b, _c;
3119
3404
  var port = _this.model.getPort(portId);
3120
3405
  if (!port)
3121
3406
  return;
@@ -3138,11 +3423,16 @@ var DiagramEngine = /** @class */ (function () {
3138
3423
  return;
3139
3424
  }
3140
3425
  var projected = _this.resolveBorderPortResizeProjection(port.position, host.shapeId, sizeInfo, host.size);
3141
- var unchanged = Math.abs(projected.x - port.position.x) <= POSITION_EPSILON &&
3142
- Math.abs(projected.y - port.position.y) <= POSITION_EPSILON;
3426
+ var constrained = _this.resolveConstrainedPortRelativePosition(port, host, projected);
3427
+ var unchanged = Math.abs(constrained.position.x - port.position.x) <= POSITION_EPSILON &&
3428
+ Math.abs(constrained.position.y - port.position.y) <= POSITION_EPSILON &&
3429
+ ((_b = constrained.currentAnchorId) !== null && _b !== void 0 ? _b : null) === ((_c = port.currentAnchorId) !== null && _c !== void 0 ? _c : null);
3143
3430
  if (unchanged)
3144
3431
  return;
3145
- var patchesForPort = _this.commandQueue.run(createMovePortCommand(port.id, { position: projected, currentAnchorId: null }), _this.model);
3432
+ var patchesForPort = _this.commandQueue.run(createMovePortCommand(port.id, {
3433
+ position: constrained.position,
3434
+ currentAnchorId: constrained.currentAnchorId,
3435
+ }), _this.model);
3146
3436
  reprojectionPatches.push.apply(reprojectionPatches, patchesForPort);
3147
3437
  movedPortIds.add(port.id);
3148
3438
  });
@@ -3199,10 +3489,10 @@ var DiagramEngine = /** @class */ (function () {
3199
3489
  return this.projectPointToHostBorder(projectedTarget, shapeId, nextSize);
3200
3490
  };
3201
3491
  DiagramEngine.prototype.resolveConstrainedPortRelativePosition = function (port, element, requestedPosition) {
3202
- var _a, _b, _c, _d, _e;
3492
+ var _a, _b, _c, _d, _e, _f, _g;
3203
3493
  var position = __assign({}, requestedPosition);
3204
3494
  var effectiveMoveMode = this.resolveEffectivePortMoveMode(port, element);
3205
- if (effectiveMoveMode && effectiveMoveMode !== 'free' && effectiveMoveMode !== 'anchors') {
3495
+ if (effectiveMoveMode === 'inside' || effectiveMoveMode === 'border') {
3206
3496
  var widthLimit = Math.max(0, element.size.width - ((_b = (_a = port.size) === null || _a === void 0 ? void 0 : _a.width) !== null && _b !== void 0 ? _b : 0));
3207
3497
  var heightLimit = Math.max(0, element.size.height - ((_d = (_c = port.size) === null || _c === void 0 ? void 0 : _c.height) !== null && _d !== void 0 ? _d : 0));
3208
3498
  var bounds = {
@@ -3226,9 +3516,12 @@ var DiagramEngine = /** @class */ (function () {
3226
3516
  height: Math.max(0, element.size.height),
3227
3517
  };
3228
3518
  }
3229
- position = effectiveMoveMode === 'inside'
3230
- ? clampToRect(position, bounds)
3231
- : this.constrainPortToHostBorder(position, element);
3519
+ if (effectiveMoveMode === 'inside') {
3520
+ position = clampToRect(position, bounds);
3521
+ }
3522
+ else {
3523
+ position = this.constrainPortToHostBorder(position, element);
3524
+ }
3232
3525
  }
3233
3526
  var style = port.style;
3234
3527
  if ((style === null || style === void 0 ? void 0 : style.moveAxis) === 'horizontal') {
@@ -3242,18 +3535,134 @@ var DiagramEngine = /** @class */ (function () {
3242
3535
  position.x = clamp(position.x, bounds.x, bounds.x + bounds.width);
3243
3536
  position.y = clamp(position.y, bounds.y, bounds.y + bounds.height);
3244
3537
  }
3538
+ if (effectiveMoveMode === 'border') {
3539
+ var resolvedBorder = this.resolveBorderPositionWithLimits(position, element, (_e = element.portMovement) === null || _e === void 0 ? void 0 : _e.positionLimits);
3540
+ position = resolvedBorder !== null && resolvedBorder !== void 0 ? resolvedBorder : this.constrainPortToHostBorder(position, element);
3541
+ }
3542
+ else {
3543
+ position = this.applyPortPositionLimits(position, (_f = element.portMovement) === null || _f === void 0 ? void 0 : _f.positionLimits);
3544
+ }
3245
3545
  if (effectiveMoveMode === 'anchors') {
3246
- var anchor = this.resolveNearestPortAnchor(element, position);
3546
+ var anchor = this.resolveNearestPortAnchor(element, position, port.currentAnchorId);
3247
3547
  if (anchor) {
3248
3548
  return {
3249
3549
  position: __assign({}, anchor.position),
3250
3550
  currentAnchorId: anchor.id,
3251
3551
  };
3252
3552
  }
3253
- return { position: position, currentAnchorId: (_e = port.currentAnchorId) !== null && _e !== void 0 ? _e : null };
3553
+ return { position: __assign({}, port.position), currentAnchorId: (_g = port.currentAnchorId) !== null && _g !== void 0 ? _g : null };
3254
3554
  }
3255
3555
  return { position: position, currentAnchorId: null };
3256
3556
  };
3557
+ DiagramEngine.prototype.applyPortPositionLimits = function (position, limits) {
3558
+ if (!limits)
3559
+ return __assign({}, position);
3560
+ var x = position.x;
3561
+ var y = position.y;
3562
+ if (limits.x) {
3563
+ if (typeof limits.x.min === 'number') {
3564
+ x = Math.max(x, limits.x.min);
3565
+ }
3566
+ if (typeof limits.x.max === 'number') {
3567
+ x = Math.min(x, limits.x.max);
3568
+ }
3569
+ }
3570
+ if (limits.y) {
3571
+ if (typeof limits.y.min === 'number') {
3572
+ y = Math.max(y, limits.y.min);
3573
+ }
3574
+ if (typeof limits.y.max === 'number') {
3575
+ y = Math.min(y, limits.y.max);
3576
+ }
3577
+ }
3578
+ return { x: x, y: y };
3579
+ };
3580
+ DiagramEngine.prototype.resolveBorderPositionWithLimits = function (position, element, limits) {
3581
+ var _this = this;
3582
+ var _a, _b, _c, _d;
3583
+ var borderBase = this.constrainPortToHostBorder(position, element);
3584
+ if (!limits)
3585
+ return borderBase;
3586
+ if (this.isPointWithinPositionLimits(borderBase, limits))
3587
+ return borderBase;
3588
+ var target = this.applyPortPositionLimits(borderBase, limits);
3589
+ var xValues = new Set([borderBase.x, target.x, 0, Math.max(0, element.size.width)]);
3590
+ var yValues = new Set([borderBase.y, target.y, 0, Math.max(0, element.size.height)]);
3591
+ if (typeof ((_a = limits.x) === null || _a === void 0 ? void 0 : _a.min) === 'number')
3592
+ xValues.add(limits.x.min);
3593
+ if (typeof ((_b = limits.x) === null || _b === void 0 ? void 0 : _b.max) === 'number')
3594
+ xValues.add(limits.x.max);
3595
+ if (typeof ((_c = limits.y) === null || _c === void 0 ? void 0 : _c.min) === 'number')
3596
+ yValues.add(limits.y.min);
3597
+ if (typeof ((_d = limits.y) === null || _d === void 0 ? void 0 : _d.max) === 'number')
3598
+ yValues.add(limits.y.max);
3599
+ var seeds = [];
3600
+ xValues.forEach(function (x) { return yValues.forEach(function (y) { return seeds.push({ x: x, y: y }); }); });
3601
+ seeds.push({ x: borderBase.x, y: target.y }, { x: target.x, y: borderBase.y });
3602
+ var candidates = [];
3603
+ var seen = new Set();
3604
+ seeds.forEach(function (seed) {
3605
+ var candidate = _this.constrainPortToHostBorder(seed, element);
3606
+ var key = "".concat(candidate.x.toFixed(6), ":").concat(candidate.y.toFixed(6));
3607
+ if (seen.has(key))
3608
+ return;
3609
+ seen.add(key);
3610
+ candidates.push(candidate);
3611
+ });
3612
+ var valid = candidates.filter(function (candidate) { return _this.isPointWithinPositionLimits(candidate, limits); });
3613
+ if (valid.length === 0)
3614
+ return null;
3615
+ return valid.reduce(function (best, candidate) {
3616
+ var bestDistance = Math.pow((best.x - target.x), 2) + Math.pow((best.y - target.y), 2);
3617
+ var candidateDistance = Math.pow((candidate.x - target.x), 2) + Math.pow((candidate.y - target.y), 2);
3618
+ if (candidateDistance < bestDistance)
3619
+ return candidate;
3620
+ if (candidateDistance > bestDistance)
3621
+ return best;
3622
+ if (candidate.x < best.x)
3623
+ return candidate;
3624
+ if (candidate.x > best.x)
3625
+ return best;
3626
+ return candidate.y < best.y ? candidate : best;
3627
+ }, valid[0]);
3628
+ };
3629
+ DiagramEngine.prototype.isPointWithinPositionLimits = function (position, limits) {
3630
+ if (!limits)
3631
+ return true;
3632
+ if (limits.x) {
3633
+ if (typeof limits.x.min === 'number' && position.x < limits.x.min)
3634
+ return false;
3635
+ if (typeof limits.x.max === 'number' && position.x > limits.x.max)
3636
+ return false;
3637
+ }
3638
+ if (limits.y) {
3639
+ if (typeof limits.y.min === 'number' && position.y < limits.y.min)
3640
+ return false;
3641
+ if (typeof limits.y.max === 'number' && position.y > limits.y.max)
3642
+ return false;
3643
+ }
3644
+ return true;
3645
+ };
3646
+ DiagramEngine.prototype.filterAnchorsByPositionLimits = function (anchors, limits) {
3647
+ if (!limits)
3648
+ return anchors;
3649
+ return anchors.filter(function (anchor) {
3650
+ var position = anchor.position;
3651
+ if (limits.x) {
3652
+ if (typeof limits.x.min === 'number' && position.x < limits.x.min)
3653
+ return false;
3654
+ if (typeof limits.x.max === 'number' && position.x > limits.x.max)
3655
+ return false;
3656
+ }
3657
+ if (limits.y) {
3658
+ if (typeof limits.y.min === 'number' && position.y < limits.y.min)
3659
+ return false;
3660
+ if (typeof limits.y.max === 'number' && position.y > limits.y.max)
3661
+ return false;
3662
+ }
3663
+ return true;
3664
+ });
3665
+ };
3257
3666
  DiagramEngine.prototype.resolveEffectivePortMoveMode = function (port, element) {
3258
3667
  var _a, _b;
3259
3668
  return (_b = (_a = element.portMovement) === null || _a === void 0 ? void 0 : _a.moveMode) !== null && _b !== void 0 ? _b : port.moveMode;
@@ -3288,7 +3697,8 @@ var DiagramEngine = /** @class */ (function () {
3288
3697
  return [];
3289
3698
  };
3290
3699
  DiagramEngine.prototype.resolveNearestPortAnchor = function (element, target, preferredAnchorId) {
3291
- var anchors = this.resolvePortAnchorsForElement(element);
3700
+ var _a;
3701
+ var anchors = this.filterAnchorsByPositionLimits(this.resolvePortAnchorsForElement(element), (_a = element.portMovement) === null || _a === void 0 ? void 0 : _a.positionLimits);
3292
3702
  if (anchors.length === 0)
3293
3703
  return null;
3294
3704
  if (preferredAnchorId) {
@@ -3353,6 +3763,46 @@ var DiagramEngine = /** @class */ (function () {
3353
3763
  DiagramEngine.prototype.resolveTextPresentation = function (text) {
3354
3764
  return this.textLayoutService.resolveTextPresentation(text);
3355
3765
  };
3766
+ DiagramEngine.prototype.resolveAllTextPresentationPatches = function (emitTextUpdated) {
3767
+ var _this = this;
3768
+ var textPatches = [];
3769
+ this.model.texts.forEach(function (text) {
3770
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s;
3771
+ var current = text.toData();
3772
+ var resolved = _this.resolveTextPresentation(current);
3773
+ var currentDisplay = (_a = current.displayContent) !== null && _a !== void 0 ? _a : current.content;
3774
+ var sizeChanged = !current.size ||
3775
+ current.size.width !== resolved.size.width ||
3776
+ current.size.height !== resolved.size.height;
3777
+ var displayChanged = currentDisplay !== resolved.displayContent;
3778
+ var offsetChanged = ((_c = (_b = current.displayOffset) === null || _b === void 0 ? void 0 : _b.x) !== null && _c !== void 0 ? _c : 0) !== ((_e = (_d = resolved.displayOffset) === null || _d === void 0 ? void 0 : _d.x) !== null && _e !== void 0 ? _e : 0) ||
3779
+ ((_g = (_f = current.displayOffset) === null || _f === void 0 ? void 0 : _f.y) !== null && _g !== void 0 ? _g : 0) !== ((_j = (_h = resolved.displayOffset) === null || _h === void 0 ? void 0 : _h.y) !== null && _j !== void 0 ? _j : 0);
3780
+ var clipChanged = ((_l = (_k = current.displayClipSize) === null || _k === void 0 ? void 0 : _k.width) !== null && _l !== void 0 ? _l : 0) !== ((_o = (_m = resolved.displayClipSize) === null || _m === void 0 ? void 0 : _m.width) !== null && _o !== void 0 ? _o : 0) ||
3781
+ ((_q = (_p = current.displayClipSize) === null || _p === void 0 ? void 0 : _p.height) !== null && _q !== void 0 ? _q : 0) !== ((_s = (_r = resolved.displayClipSize) === null || _r === void 0 ? void 0 : _r.height) !== null && _s !== void 0 ? _s : 0);
3782
+ if (!sizeChanged && !displayChanged && !offsetChanged && !clipChanged)
3783
+ return;
3784
+ text.setSize(resolved.size);
3785
+ text.setDisplayContent(resolved.displayContent);
3786
+ text.setDisplayOffset(resolved.displayOffset);
3787
+ text.setDisplayClipSize(resolved.displayClipSize);
3788
+ textPatches.push(patchUpdate('text', text.id, {
3789
+ size: resolved.size,
3790
+ displayContent: resolved.displayContent,
3791
+ displayOffset: resolved.displayOffset,
3792
+ displayClipSize: resolved.displayClipSize,
3793
+ }));
3794
+ if (emitTextUpdated) {
3795
+ _this.events.emit('textUpdated', {
3796
+ textId: text.id,
3797
+ ownerId: text.ownerId,
3798
+ content: text.content,
3799
+ displayContent: resolved.displayContent,
3800
+ reason: 'layout',
3801
+ });
3802
+ }
3803
+ });
3804
+ return textPatches;
3805
+ };
3356
3806
  DiagramEngine.prototype.emitSelection = function () {
3357
3807
  var _this = this;
3358
3808
  var selectedIds = this.selection.get();
@@ -3384,6 +3834,12 @@ var DiagramEngine = /** @class */ (function () {
3384
3834
  DiagramEngine.prototype.applyAllLayouts = function () {
3385
3835
  return this.autoLayoutService.applyAllLayouts();
3386
3836
  };
3837
+ DiagramEngine.prototype.hasFlexibleLabelReservedSpace = function (elementId) {
3838
+ var _a, _b, _c;
3839
+ var element = this.model.getElement(elementId);
3840
+ var mode = (_c = (_b = (_a = element === null || element === void 0 ? void 0 : element.layout) === null || _a === void 0 ? void 0 : _a.labelReservedSpace) === null || _b === void 0 ? void 0 : _b.mode) !== null && _c !== void 0 ? _c : 'none';
3841
+ return mode === 'flexible';
3842
+ };
3387
3843
  DiagramEngine.prototype.updateLinksForPorts = function (portIds) {
3388
3844
  return this.linkRoutingService.updateLinksForPorts(portIds);
3389
3845
  };
@@ -3436,6 +3892,40 @@ var DiagramEngine = /** @class */ (function () {
3436
3892
  DiagramEngine.prototype.routeLinksWithEmptyPoints = function () {
3437
3893
  return this.linkRoutingService.routeLinksWithEmptyPoints();
3438
3894
  };
3895
+ DiagramEngine.prototype.normalizePortsForHostPolicies = function (portIds) {
3896
+ var _this = this;
3897
+ var ids = portIds !== null && portIds !== void 0 ? portIds : Array.from(this.model.ports.keys());
3898
+ var normalizedPatches = [];
3899
+ var movedPortIds = new Set();
3900
+ ids.forEach(function (portId) {
3901
+ var _a, _b;
3902
+ var port = _this.model.getPort(portId);
3903
+ if (!port)
3904
+ return;
3905
+ var element = _this.model.getElement(port.elementId);
3906
+ if (!element)
3907
+ return;
3908
+ var constrained = _this.resolveConstrainedPortRelativePosition(port, element, port.position);
3909
+ var previousAnchorId = (_a = port.currentAnchorId) !== null && _a !== void 0 ? _a : null;
3910
+ var shouldPersistAnchorId = previousAnchorId !== null || constrained.currentAnchorId === null;
3911
+ var nextAnchorId = shouldPersistAnchorId ? ((_b = constrained.currentAnchorId) !== null && _b !== void 0 ? _b : null) : previousAnchorId;
3912
+ var unchanged = Math.abs(constrained.position.x - port.position.x) <= POSITION_EPSILON &&
3913
+ Math.abs(constrained.position.y - port.position.y) <= POSITION_EPSILON &&
3914
+ previousAnchorId === nextAnchorId;
3915
+ if (unchanged)
3916
+ return;
3917
+ var update = {
3918
+ position: constrained.position,
3919
+ };
3920
+ if (shouldPersistAnchorId) {
3921
+ update.currentAnchorId = constrained.currentAnchorId;
3922
+ }
3923
+ var patches = _this.commandQueue.run(createMovePortCommand(port.id, update), _this.model);
3924
+ normalizedPatches.push.apply(normalizedPatches, patches);
3925
+ movedPortIds.add(port.id);
3926
+ });
3927
+ return { patches: normalizedPatches, movedPortIds: Array.from(movedPortIds) };
3928
+ };
3439
3929
  DiagramEngine.prototype.computeRemovalDiff = function (before) {
3440
3930
  var after = this.model.toState();
3441
3931
  var removedPatches = [];
@@ -3681,6 +4171,21 @@ var KonvaNodeFactory = /** @class */ (function () {
3681
4171
  }
3682
4172
  return node;
3683
4173
  };
4174
+ KonvaNodeFactory.prototype.createTextBackgroundNode = function (config) {
4175
+ return new this.konva.Rect({
4176
+ id: config.id,
4177
+ x: config.x,
4178
+ y: config.y,
4179
+ width: config.width,
4180
+ height: config.height,
4181
+ fill: config.fill,
4182
+ stroke: config.stroke,
4183
+ strokeWidth: config.strokeWidth,
4184
+ cornerRadius: config.cornerRadius,
4185
+ name: 'text-background',
4186
+ listening: false,
4187
+ });
4188
+ };
3684
4189
  KonvaNodeFactory.prototype.createHandleNode = function (config) {
3685
4190
  return new this.konva.Rect({
3686
4191
  id: config.id,
@@ -3760,7 +4265,8 @@ var KonvaNodeFactory = /** @class */ (function () {
3760
4265
  KonvaNodeFactory.prototype.createDrawNode = function (model, shape, config) {
3761
4266
  var _a, _b;
3762
4267
  var style = model.style;
3763
- var attrs = __assign(__assign({ id: model.id, x: model.position.x, y: model.position.y, name: config.name }, (style !== null && style !== void 0 ? style : {})), { __shapeDraw: true, __model: model, sceneFunc: function (ctx, node) {
4268
+ var _c = this.resolveShapeRotation(shape, style), resolvedStyle = _c.style, rotation = _c.rotation;
4269
+ var attrs = __assign(__assign({ id: model.id, x: model.position.x, y: model.position.y, name: config.name }, (resolvedStyle !== null && resolvedStyle !== void 0 ? resolvedStyle : {})), { __shapeDraw: true, __model: model, rotation: rotation, sceneFunc: function (ctx, node) {
3764
4270
  var _a, _b, _c;
3765
4271
  var resolvedModel = (_b = (node.getAttr ? node.getAttr('__model') : (_a = node.attrs) === null || _a === void 0 ? void 0 : _a.__model)) !== null && _b !== void 0 ? _b : model;
3766
4272
  (_c = shape.draw) === null || _c === void 0 ? void 0 : _c.call(shape, { ctx: ctx, model: resolvedModel });
@@ -3776,6 +4282,7 @@ var KonvaNodeFactory = /** @class */ (function () {
3776
4282
  KonvaNodeFactory.prototype.createSvgPathNode = function (model, shape, config) {
3777
4283
  var _a, _b, _c, _d, _e, _f, _g;
3778
4284
  var style = model.style;
4285
+ var _h = this.resolveShapeRotation(shape, style), resolvedStyle = _h.style, rotation = _h.rotation;
3779
4286
  var sizeUpdater = function (_a) {
3780
4287
  var _b, _c;
3781
4288
  var nextSize = _a.size, anchorCenter = _a.anchorCenter, updateOffsetX = _a.updateOffsetX, updateOffsetY = _a.updateOffsetY, getNodeAttr = _a.getNodeAttr;
@@ -3797,7 +4304,7 @@ var KonvaNodeFactory = /** @class */ (function () {
3797
4304
  return attrs;
3798
4305
  };
3799
4306
  var size = (_a = config.size) !== null && _a !== void 0 ? _a : { width: 0, height: 0 };
3800
- var node = new this.konva.Path(__assign(__assign({ id: model.id, x: model.position.x, y: model.position.y, data: shape.svgPath, name: config.name }, (style !== null && style !== void 0 ? style : {})), { shapeKind: 'svg-path', __autoOffsetX: true, __autoOffsetY: true }));
4307
+ var node = new this.konva.Path(__assign(__assign({ id: model.id, x: model.position.x, y: model.position.y, rotation: rotation, data: shape.svgPath, name: config.name }, (resolvedStyle !== null && resolvedStyle !== void 0 ? resolvedStyle : {})), { shapeKind: 'svg-path', __autoOffsetX: true, __autoOffsetY: true }));
3801
4308
  var rect = node.getClientRect ? node.getClientRect({ skipTransform: true }) : null;
3802
4309
  var baseWidth = (_d = (_c = (_b = shape.svgSize) === null || _b === void 0 ? void 0 : _b.width) !== null && _c !== void 0 ? _c : rect === null || rect === void 0 ? void 0 : rect.width) !== null && _d !== void 0 ? _d : size.width;
3803
4310
  var baseHeight = (_g = (_f = (_e = shape.svgSize) === null || _e === void 0 ? void 0 : _e.height) !== null && _f !== void 0 ? _f : rect === null || rect === void 0 ? void 0 : rect.height) !== null && _g !== void 0 ? _g : size.height;
@@ -3814,6 +4321,20 @@ var KonvaNodeFactory = /** @class */ (function () {
3814
4321
  }
3815
4322
  return node;
3816
4323
  };
4324
+ KonvaNodeFactory.prototype.resolveShapeRotation = function (shape, style) {
4325
+ var _a, _b;
4326
+ if (!style) {
4327
+ return {
4328
+ style: undefined,
4329
+ rotation: (_a = shape.baseRotation) !== null && _a !== void 0 ? _a : 0,
4330
+ };
4331
+ }
4332
+ var rotation = style.rotation, rest = __rest(style, ["rotation"]);
4333
+ return {
4334
+ style: rest,
4335
+ rotation: ((_b = shape.baseRotation) !== null && _b !== void 0 ? _b : 0) + (typeof rotation === 'number' ? rotation : 0),
4336
+ };
4337
+ };
3817
4338
  KonvaNodeFactory.prototype.applyShapeBehaviorAttrs = function (node, shape) {
3818
4339
  if (!node.setAttrs || !shape.sizeUpdater)
3819
4340
  return;
@@ -3845,6 +4366,7 @@ var KonvaRenderer = /** @class */ (function () {
3845
4366
  this.portNodes = new Map();
3846
4367
  this.linkNodes = new Map();
3847
4368
  this.textNodes = new Map();
4369
+ this.textBackgroundNodes = new Map();
3848
4370
  this.selectedIds = new Set();
3849
4371
  this.tempLinkNode = null;
3850
4372
  this.tempPortNode = null;
@@ -4014,7 +4536,7 @@ var KonvaRenderer = /** @class */ (function () {
4014
4536
  this.drawOverlays();
4015
4537
  };
4016
4538
  KonvaRenderer.prototype.renderPortPlaceholder = function (port, hostElement) {
4017
- var _a, _b, _c, _d;
4539
+ var _a, _b, _c, _d, _e, _f;
4018
4540
  var shapeId = port.shapeId;
4019
4541
  if (!this.tempPortNode || this.tempPortShapeId !== shapeId) {
4020
4542
  (_b = (_a = this.tempPortNode) === null || _a === void 0 ? void 0 : _a.destroy) === null || _b === void 0 ? void 0 : _b.call(_a);
@@ -4033,6 +4555,9 @@ var KonvaRenderer = /** @class */ (function () {
4033
4555
  }
4034
4556
  }
4035
4557
  if (this.tempPortNode) {
4558
+ this.updateSize(this.tempPortNode, (_e = port.size) !== null && _e !== void 0 ? _e : { width: 8, height: 8 }, {
4559
+ anchorCenter: (_f = port.anchorCenter) !== null && _f !== void 0 ? _f : true,
4560
+ });
4036
4561
  this.applyPortOrientation(this.tempPortNode, port, port.position, undefined, hostElement);
4037
4562
  }
4038
4563
  this.drawOverlays();
@@ -4141,6 +4666,8 @@ var KonvaRenderer = /** @class */ (function () {
4141
4666
  this.elementNodes.clear();
4142
4667
  this.portNodes.clear();
4143
4668
  this.linkNodes.clear();
4669
+ this.textBackgroundNodes.forEach(function (node) { var _a; return (_a = node.destroy) === null || _a === void 0 ? void 0 : _a.call(node); });
4670
+ this.textBackgroundNodes.clear();
4144
4671
  this.textNodes.clear();
4145
4672
  this.resizeHandleNodes.clear();
4146
4673
  this.linkHandleNodes.clear();
@@ -4292,7 +4819,7 @@ var KonvaRenderer = /** @class */ (function () {
4292
4819
  var _this = this;
4293
4820
  var ports = Array.from(model.ports.values());
4294
4821
  ports.forEach(function (port) {
4295
- var _a, _b, _c;
4822
+ var _a, _b, _c, _d, _e;
4296
4823
  var data = port.toData();
4297
4824
  var node = _this.portNodes.get(port.id);
4298
4825
  if (!node) {
@@ -4304,6 +4831,7 @@ var KonvaRenderer = /** @class */ (function () {
4304
4831
  node.setAttrs({ __model: data });
4305
4832
  }
4306
4833
  var position = (_c = model.getPortWorldPosition(port.id)) !== null && _c !== void 0 ? _c : port.position;
4834
+ _this.updateSize(node, (_d = data.size) !== null && _d !== void 0 ? _d : { width: 8, height: 8 }, { anchorCenter: (_e = data.anchorCenter) !== null && _e !== void 0 ? _e : true });
4307
4835
  _this.updatePosition(node, position);
4308
4836
  _this.applyPortOrientation(node, data, position, model);
4309
4837
  });
@@ -4346,7 +4874,7 @@ var KonvaRenderer = /** @class */ (function () {
4346
4874
  var _this = this;
4347
4875
  var texts = Array.from(model.texts.values());
4348
4876
  texts.forEach(function (text) {
4349
- var _a, _b, _c, _d, _e, _f, _g, _h;
4877
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s;
4350
4878
  var node = _this.textNodes.get(text.id);
4351
4879
  if (!node) {
4352
4880
  node = _this.nodeFactory.createTextNode(text.toData());
@@ -4355,32 +4883,124 @@ var KonvaRenderer = /** @class */ (function () {
4355
4883
  }
4356
4884
  var position = (_c = model.getTextWorldPosition(text.id)) !== null && _c !== void 0 ? _c : text.position;
4357
4885
  var displayOffset = (_d = text.displayOffset) !== null && _d !== void 0 ? _d : { x: 0, y: 0 };
4358
- _this.updatePosition(node, {
4886
+ var textPosition = {
4359
4887
  x: position.x + displayOffset.x,
4360
4888
  y: position.y + displayOffset.y,
4889
+ };
4890
+ _this.updatePosition(node, {
4891
+ x: textPosition.x,
4892
+ y: textPosition.y,
4361
4893
  });
4362
4894
  if (node.setAttrs) {
4363
- var style = text.style;
4364
- var defaults = resolveTextStyleDefaults(style);
4365
- var baseFill = (_g = (_f = (_e = style === null || style === void 0 ? void 0 : style.fill) !== null && _e !== void 0 ? _e : _this.getNodeAttr(node, '__baseFill')) !== null && _f !== void 0 ? _f : _this.getNodeAttr(node, 'fill')) !== null && _g !== void 0 ? _g : 'black';
4895
+ var style_1 = text.style;
4896
+ var defaults = resolveTextStyleDefaults(style_1);
4897
+ var baseFill = (_g = (_f = (_e = style_1 === null || style_1 === void 0 ? void 0 : style_1.fill) !== null && _e !== void 0 ? _e : _this.getNodeAttr(node, '__baseFill')) !== null && _f !== void 0 ? _f : _this.getNodeAttr(node, 'fill')) !== null && _g !== void 0 ? _g : 'black';
4366
4898
  var fill = _this.selectedIds.has(text.id) ? '#ff7a00' : baseFill;
4367
- var clip = text.displayClipSize;
4368
- node.setAttrs(__assign(__assign({ text: (_h = text.displayContent) !== null && _h !== void 0 ? _h : text.content, fontSize: defaults.fontSize, fontFamily: defaults.fontFamily, lineHeight: defaults.lineHeight }, (style !== null && style !== void 0 ? style : {})), { width: clip === null || clip === void 0 ? void 0 : clip.width, height: clip === null || clip === void 0 ? void 0 : clip.height, wrap: clip ? 'none' : undefined, ellipsis: false, fill: fill, __baseFill: baseFill,
4899
+ var clip_1 = text.displayClipSize;
4900
+ node.setAttrs(__assign(__assign({ text: (_h = text.displayContent) !== null && _h !== void 0 ? _h : text.content, fontSize: defaults.fontSize, fontFamily: defaults.fontFamily, lineHeight: defaults.lineHeight }, (style_1 !== null && style_1 !== void 0 ? style_1 : {})), { width: clip_1 === null || clip_1 === void 0 ? void 0 : clip_1.width, height: clip_1 === null || clip_1 === void 0 ? void 0 : clip_1.height, wrap: clip_1 ? 'none' : undefined, ellipsis: false, fill: fill, __baseFill: baseFill,
4369
4901
  // Keep metadata for tests/debugging; Konva clip attrs do not apply on Text nodes.
4370
- clipX: clip ? 0 : undefined, clipY: clip ? 0 : undefined, clipWidth: clip === null || clip === void 0 ? void 0 : clip.width, clipHeight: clip === null || clip === void 0 ? void 0 : clip.height }));
4902
+ clipX: clip_1 ? 0 : undefined, clipY: clip_1 ? 0 : undefined, clipWidth: clip_1 === null || clip_1 === void 0 ? void 0 : clip_1.width, clipHeight: clip_1 === null || clip_1 === void 0 ? void 0 : clip_1.height }));
4903
+ }
4904
+ var style = text.style;
4905
+ var backgroundFill = style === null || style === void 0 ? void 0 : style.backgroundFill;
4906
+ var clip = text.displayClipSize;
4907
+ var backgroundWidth = (_j = clip === null || clip === void 0 ? void 0 : clip.width) !== null && _j !== void 0 ? _j : (_k = text.size) === null || _k === void 0 ? void 0 : _k.width;
4908
+ var backgroundHeight = (_l = clip === null || clip === void 0 ? void 0 : clip.height) !== null && _l !== void 0 ? _l : (_m = text.size) === null || _m === void 0 ? void 0 : _m.height;
4909
+ var backgroundMeta = _this.resolveTextBackgroundMeta(model, text.toData());
4910
+ var hasBackground = typeof backgroundFill === 'string' &&
4911
+ backgroundFill.length > 0 &&
4912
+ typeof backgroundWidth === 'number' &&
4913
+ typeof backgroundHeight === 'number' &&
4914
+ backgroundWidth > 0 &&
4915
+ backgroundHeight > 0;
4916
+ if (hasBackground) {
4917
+ var baseX = textPosition.x + backgroundMeta.inset;
4918
+ var baseY = textPosition.y + backgroundMeta.inset;
4919
+ var width = Math.max(0, backgroundWidth - backgroundMeta.inset * 2);
4920
+ var height = Math.max(0, backgroundHeight - backgroundMeta.inset);
4921
+ var backgroundStroke = typeof (style === null || style === void 0 ? void 0 : style.backgroundStroke) === 'string' && style.backgroundStroke.length > 0
4922
+ ? style.backgroundStroke
4923
+ : undefined;
4924
+ var backgroundStrokeWidth = typeof (style === null || style === void 0 ? void 0 : style.backgroundStrokeWidth) === 'number'
4925
+ ? Math.max(0, style.backgroundStrokeWidth)
4926
+ : undefined;
4927
+ var backgroundNode = _this.textBackgroundNodes.get(text.id);
4928
+ if (!backgroundNode) {
4929
+ backgroundNode = _this.nodeFactory.createTextBackgroundNode({
4930
+ id: "text-background:".concat(text.id),
4931
+ x: baseX,
4932
+ y: baseY,
4933
+ width: width,
4934
+ height: height,
4935
+ fill: backgroundFill,
4936
+ stroke: backgroundStroke,
4937
+ strokeWidth: backgroundStrokeWidth,
4938
+ cornerRadius: backgroundMeta.cornerRadius,
4939
+ });
4940
+ _this.textBackgroundNodes.set(text.id, backgroundNode);
4941
+ (_p = (_o = _this.layers.getLayer('texts')) === null || _o === void 0 ? void 0 : _o.add) === null || _p === void 0 ? void 0 : _p.call(_o, backgroundNode);
4942
+ }
4943
+ else {
4944
+ _this.updatePosition(backgroundNode, { x: baseX, y: baseY });
4945
+ (_q = backgroundNode.setAttrs) === null || _q === void 0 ? void 0 : _q.call(backgroundNode, {
4946
+ width: width,
4947
+ height: height,
4948
+ fill: backgroundFill,
4949
+ stroke: backgroundStroke,
4950
+ strokeWidth: backgroundStrokeWidth,
4951
+ cornerRadius: backgroundMeta.cornerRadius,
4952
+ listening: false,
4953
+ name: 'text-background',
4954
+ });
4955
+ }
4956
+ (_r = node.moveToTop) === null || _r === void 0 ? void 0 : _r.call(node);
4957
+ }
4958
+ else {
4959
+ var backgroundNode = _this.textBackgroundNodes.get(text.id);
4960
+ (_s = backgroundNode === null || backgroundNode === void 0 ? void 0 : backgroundNode.destroy) === null || _s === void 0 ? void 0 : _s.call(backgroundNode);
4961
+ _this.textBackgroundNodes.delete(text.id);
4371
4962
  }
4372
4963
  });
4373
4964
  Array.from(this.textNodes.keys()).forEach(function (id) {
4374
- var _a;
4965
+ var _a, _b;
4375
4966
  if (!model.texts.has(id)) {
4967
+ var backgroundNode = _this.textBackgroundNodes.get(id);
4968
+ (_a = backgroundNode === null || backgroundNode === void 0 ? void 0 : backgroundNode.destroy) === null || _a === void 0 ? void 0 : _a.call(backgroundNode);
4969
+ _this.textBackgroundNodes.delete(id);
4376
4970
  var node = _this.textNodes.get(id);
4377
- (_a = node === null || node === void 0 ? void 0 : node.destroy) === null || _a === void 0 ? void 0 : _a.call(node);
4971
+ (_b = node === null || node === void 0 ? void 0 : node.destroy) === null || _b === void 0 ? void 0 : _b.call(node);
4378
4972
  _this.textNodes.delete(id);
4379
4973
  _this.layers.markDirty('texts');
4380
4974
  }
4381
4975
  });
4382
4976
  this.layers.markDirty('texts');
4383
4977
  };
4978
+ KonvaRenderer.prototype.resolveTextBackgroundMeta = function (model, text) {
4979
+ var _a;
4980
+ var ownerId = (_a = text.ownerId) !== null && _a !== void 0 ? _a : null;
4981
+ if (!ownerId)
4982
+ return { inset: 0 };
4983
+ var owner = model.getElement(ownerId);
4984
+ if (!owner)
4985
+ return { inset: 0 };
4986
+ var ownerStyle = owner.style;
4987
+ var strokeWidth = typeof (ownerStyle === null || ownerStyle === void 0 ? void 0 : ownerStyle.strokeWidth) === 'number' ? Math.max(0, ownerStyle.strokeWidth) : 0;
4988
+ var inset = strokeWidth > 0 ? strokeWidth / 2 : 0;
4989
+ var rawCornerRadius = ownerStyle === null || ownerStyle === void 0 ? void 0 : ownerStyle.cornerRadius;
4990
+ var isTopLabel = text.position.y <= 1;
4991
+ if (!isTopLabel)
4992
+ return { inset: inset };
4993
+ if (typeof rawCornerRadius === 'number' && rawCornerRadius > 0) {
4994
+ var topRadius = Math.max(0, rawCornerRadius - inset);
4995
+ return { inset: inset, cornerRadius: [topRadius, topRadius, 0, 0] };
4996
+ }
4997
+ if (Array.isArray(rawCornerRadius) && rawCornerRadius.length === 4) {
4998
+ var tl = typeof rawCornerRadius[0] === 'number' ? Math.max(0, rawCornerRadius[0] - inset) : 0;
4999
+ var tr = typeof rawCornerRadius[1] === 'number' ? Math.max(0, rawCornerRadius[1] - inset) : 0;
5000
+ return { inset: inset, cornerRadius: [tl, tr, 0, 0] };
5001
+ }
5002
+ return { inset: inset };
5003
+ };
4384
5004
  KonvaRenderer.prototype.updatePosition = function (node, position) {
4385
5005
  if (node.position) {
4386
5006
  node.position({ x: position.x, y: position.y });
@@ -4398,27 +5018,22 @@ var KonvaRenderer = /** @class */ (function () {
4398
5018
  if (this.getNodeAttr(node, '__baseRotation') === undefined) {
4399
5019
  node.setAttrs({ __baseRotation: baseRotation });
4400
5020
  }
4401
- var orientedRotation = this.resolvePortBorderRotation(port, worldPosition, model, hostElementOverride);
4402
- node.setAttrs({ rotation: baseRotation + (orientedRotation !== null && orientedRotation !== void 0 ? orientedRotation : 0) });
4403
- };
4404
- KonvaRenderer.prototype.resolvePortBorderRotation = function (port, worldPosition, model, hostElementOverride) {
4405
- if (port.moveMode !== 'border' || port.orientToHostBorder === false) {
4406
- return null;
4407
- }
4408
5021
  var host = hostElementOverride !== null && hostElementOverride !== void 0 ? hostElementOverride : this.resolveHostElement(port.elementId, model);
4409
- if (!host)
4410
- return null;
4411
- var hostRect = {
4412
- x: host.position.x,
4413
- y: host.position.y,
4414
- width: host.size.width,
4415
- height: host.size.height,
4416
- };
4417
- var shape = this.shapeRegistry.get(host.shapeId);
4418
- var side = (shape === null || shape === void 0 ? void 0 : shape.resolveBorderSide)
4419
- ? shape.resolveBorderSide(worldPosition, hostRect)
4420
- : resolveBoundarySide(worldPosition, hostRect, 'rect');
4421
- return borderSideToInwardRotation(side);
5022
+ var orientation = resolvePortOrientationContext({
5023
+ port: port,
5024
+ worldPlacement: worldPosition,
5025
+ host: host,
5026
+ shapeRegistry: this.shapeRegistry,
5027
+ attachMode: 'external',
5028
+ });
5029
+ var transform = resolvePortWorldTransform({
5030
+ port: port,
5031
+ worldPlacement: worldPosition,
5032
+ attachMode: 'external',
5033
+ orientation: orientation,
5034
+ });
5035
+ this.updatePosition(node, transform.nodePosition);
5036
+ node.setAttrs({ rotation: baseRotation + orientation.rotation });
4422
5037
  };
4423
5038
  KonvaRenderer.prototype.resolveHostElement = function (elementId, model) {
4424
5039
  var _a;
@@ -4520,6 +5135,7 @@ var KonvaInteraction = /** @class */ (function () {
4520
5135
  if (config === void 0) { config = {}; }
4521
5136
  var _a, _b;
4522
5137
  this.linkDragContext = null;
5138
+ this.programmaticLinkSession = null;
4523
5139
  this.bound = false;
4524
5140
  this.handlers = [];
4525
5141
  this.windowHandlers = [];
@@ -4534,6 +5150,8 @@ var KonvaInteraction = /** @class */ (function () {
4534
5150
  this.textEditor = null;
4535
5151
  this.dragThreshold = 4;
4536
5152
  this.panSpeed = 0.5;
5153
+ this.occupiedVertexTolerance = 2;
5154
+ this.emittingElementLinkEnded = false;
4537
5155
  this.engine = engine;
4538
5156
  this.stage = config.stage;
4539
5157
  this.hitTester = (_a = config.hitTester) !== null && _a !== void 0 ? _a : new KonvaHitTester();
@@ -4554,6 +5172,121 @@ var KonvaInteraction = /** @class */ (function () {
4554
5172
  this.updateShapeHoverControl(this.lastPointerPosition);
4555
5173
  }
4556
5174
  };
5175
+ KonvaInteraction.prototype.startLinkFromPort = function (sourcePortId, pointer) {
5176
+ var _a, _b, _c;
5177
+ var sourceElementId = this.engine.getPortElementId(sourcePortId);
5178
+ if (!sourceElementId)
5179
+ return;
5180
+ var sourcePoint = (_a = this.engine.getPortLinkWorldPosition(sourcePortId)) !== null && _a !== void 0 ? _a : this.engine.getPortWorldPosition(sourcePortId);
5181
+ if (!sourcePoint)
5182
+ return;
5183
+ if (((_b = this.dragState) === null || _b === void 0 ? void 0 : _b.mode) === 'link-drag' || this.programmaticLinkSession) {
5184
+ this.cancelLink();
5185
+ }
5186
+ if (this.dragState &&
5187
+ this.dragState.mode !== 'shape-control-drag' &&
5188
+ this.dragState.mode !== 'link-drag') {
5189
+ return;
5190
+ }
5191
+ var start = __assign({}, sourcePoint);
5192
+ if (((_c = this.dragState) === null || _c === void 0 ? void 0 : _c.mode) === 'shape-control-drag') {
5193
+ this.programmaticLinkSession = {
5194
+ sourcePortId: sourcePortId,
5195
+ sourceElementId: sourceElementId,
5196
+ start: start,
5197
+ current: start,
5198
+ };
5199
+ }
5200
+ else {
5201
+ this.dragState = {
5202
+ mode: 'link-drag',
5203
+ sourcePortId: sourcePortId,
5204
+ sourceElementId: sourceElementId,
5205
+ start: start,
5206
+ current: start,
5207
+ isMulti: false,
5208
+ hasMoved: false,
5209
+ completionBehavior: 'explicit',
5210
+ };
5211
+ }
5212
+ this.linkDragContext = { sourcePortId: sourcePortId, sourceElementId: sourceElementId };
5213
+ this.engine.emitElementLinkStarted({ sourcePortId: sourcePortId, sourceElementId: sourceElementId, startWorld: __assign({}, start) });
5214
+ this.setCursor('crosshair');
5215
+ if (pointer) {
5216
+ this.updateLinkPreview(pointer);
5217
+ }
5218
+ };
5219
+ KonvaInteraction.prototype.updateLinkPreview = function (pointer) {
5220
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
5221
+ if (this.programmaticLinkSession) {
5222
+ this.programmaticLinkSession.current = __assign({}, pointer);
5223
+ }
5224
+ else if (((_a = this.dragState) === null || _a === void 0 ? void 0 : _a.mode) === 'link-drag') {
5225
+ this.dragState.current = __assign({}, pointer);
5226
+ this.dragState.hasMoved = true;
5227
+ }
5228
+ else {
5229
+ return;
5230
+ }
5231
+ var sourcePortId = (_c = (_b = this.programmaticLinkSession) === null || _b === void 0 ? void 0 : _b.sourcePortId) !== null && _c !== void 0 ? _c : (((_d = this.dragState) === null || _d === void 0 ? void 0 : _d.mode) === 'link-drag' ? this.dragState.sourcePortId : null);
5232
+ if (!sourcePortId)
5233
+ return;
5234
+ var source = this.resolveLinkPreviewSource(sourcePortId, pointer);
5235
+ if (source) {
5236
+ (_e = this.renderer) === null || _e === void 0 ? void 0 : _e.renderTempLink([source, pointer]);
5237
+ }
5238
+ var hit = this.resolveHit(pointer);
5239
+ if ((hit === null || hit === void 0 ? void 0 : hit.type) === 'element') {
5240
+ var placeholder = this.createPlaceholderPort(hit.id, pointer, sourcePortId);
5241
+ if (placeholder) {
5242
+ var hostElement = this.getElementById(hit.id);
5243
+ if (hostElement) {
5244
+ var hostWorld = (_f = this.engine.getElementWorldPosition(hit.id)) !== null && _f !== void 0 ? _f : hostElement.position;
5245
+ (_h = (_g = this.renderer) === null || _g === void 0 ? void 0 : _g.renderPortPlaceholder) === null || _h === void 0 ? void 0 : _h.call(_g, placeholder, { id: hostElement.id, position: hostWorld, size: hostElement.size, shapeId: hostElement.shapeId });
5246
+ }
5247
+ else {
5248
+ (_k = (_j = this.renderer) === null || _j === void 0 ? void 0 : _j.renderPortPlaceholder) === null || _k === void 0 ? void 0 : _k.call(_j, placeholder);
5249
+ }
5250
+ }
5251
+ return;
5252
+ }
5253
+ (_m = (_l = this.renderer) === null || _l === void 0 ? void 0 : _l.clearPortPlaceholder) === null || _m === void 0 ? void 0 : _m.call(_l);
5254
+ };
5255
+ KonvaInteraction.prototype.completeLinkToPort = function (targetPortId) {
5256
+ var _a, _b;
5257
+ var session = this.resolveActiveLinkSession();
5258
+ if (!session)
5259
+ return;
5260
+ var completion = this.tryCreateLinkToPort(session.sourcePortId, session.sourceElementId, targetPortId);
5261
+ this.finishLinkDragSession({
5262
+ sourcePortId: session.sourcePortId,
5263
+ sourceElementId: session.sourceElementId,
5264
+ createdLinkId: (_a = completion.createdLinkId) !== null && _a !== void 0 ? _a : undefined,
5265
+ targetPortId: completion.targetPortId,
5266
+ targetElementId: (_b = completion.targetElementId) !== null && _b !== void 0 ? _b : undefined,
5267
+ cancelled: completion.createdLinkId === null,
5268
+ fromProgrammatic: session.fromProgrammatic,
5269
+ });
5270
+ };
5271
+ KonvaInteraction.prototype.completeLinkToElement = function (targetElementId, pointer) {
5272
+ var _a, _b, _c;
5273
+ var session = this.resolveActiveLinkSession();
5274
+ if (!session)
5275
+ return;
5276
+ var completion = this.tryCreateLinkToElement(session.sourcePortId, session.sourceElementId, targetElementId, pointer);
5277
+ this.finishLinkDragSession({
5278
+ sourcePortId: session.sourcePortId,
5279
+ sourceElementId: session.sourceElementId,
5280
+ createdLinkId: (_a = completion.createdLinkId) !== null && _a !== void 0 ? _a : undefined,
5281
+ targetPortId: (_b = completion.targetPortId) !== null && _b !== void 0 ? _b : undefined,
5282
+ targetElementId: (_c = completion.targetElementId) !== null && _c !== void 0 ? _c : undefined,
5283
+ cancelled: completion.createdLinkId === null,
5284
+ fromProgrammatic: session.fromProgrammatic,
5285
+ });
5286
+ };
5287
+ KonvaInteraction.prototype.cancelLink = function () {
5288
+ this.cancelLinkDrag();
5289
+ };
4557
5290
  KonvaInteraction.prototype.buildPointerInfo = function (world, nativeEvent) {
4558
5291
  var evt = nativeEvent !== null && nativeEvent !== void 0 ? nativeEvent : undefined;
4559
5292
  var client = evt ? { x: evt.clientX, y: evt.clientY } : { x: world.x, y: world.y };
@@ -4681,6 +5414,7 @@ var KonvaInteraction = /** @class */ (function () {
4681
5414
  current: point,
4682
5415
  isMulti: isMulti,
4683
5416
  hasMoved: false,
5417
+ completionBehavior: 'hover-or-release',
4684
5418
  };
4685
5419
  _this.linkDragContext = { sourcePortId: hit.id, sourceElementId: elementId };
4686
5420
  _this.engine.emitElementLinkStarted({ sourcePortId: hit.id, sourceElementId: elementId, startWorld: __assign({}, point) });
@@ -4755,22 +5489,29 @@ var KonvaInteraction = /** @class */ (function () {
4755
5489
  }
4756
5490
  _this.clearActiveShapeHoverControl();
4757
5491
  if (_this.dragState.mode === 'shape-control-drag') {
4758
- var delta = { x: point.x - _this.dragState.start.x, y: point.y - _this.dragState.start.y };
5492
+ var dragState = _this.dragState;
5493
+ var delta = { x: point.x - dragState.start.x, y: point.y - dragState.start.y };
4759
5494
  var moved = Math.hypot(delta.x, delta.y) >= _this.dragThreshold;
4760
- if (!_this.dragState.hasMoved && moved) {
4761
- _this.dragState.hasMoved = true;
4762
- _this.emitShapeHoverControlInteraction('drag-start', _this.dragState.control, point, nativeEvent, {
4763
- sessionId: _this.dragState.sessionId,
4764
- startPointer: _this.dragState.startPointer,
5495
+ if (!dragState.hasMoved && moved) {
5496
+ dragState.hasMoved = true;
5497
+ _this.emitShapeHoverControlInteraction('drag-start', dragState.control, point, nativeEvent, {
5498
+ sessionId: dragState.sessionId,
5499
+ startPointer: dragState.startPointer,
4765
5500
  delta: delta,
4766
5501
  });
5502
+ if (_this.dragState !== dragState) {
5503
+ return;
5504
+ }
4767
5505
  }
4768
- if (_this.dragState.hasMoved) {
4769
- _this.emitShapeHoverControlInteraction('drag-move', _this.dragState.control, point, nativeEvent, {
4770
- sessionId: _this.dragState.sessionId,
4771
- startPointer: _this.dragState.startPointer,
5506
+ if (dragState.hasMoved) {
5507
+ _this.emitShapeHoverControlInteraction('drag-move', dragState.control, point, nativeEvent, {
5508
+ sessionId: dragState.sessionId,
5509
+ startPointer: dragState.startPointer,
4772
5510
  delta: delta,
4773
5511
  });
5512
+ if (_this.dragState !== dragState) {
5513
+ return;
5514
+ }
4774
5515
  }
4775
5516
  }
4776
5517
  else if (_this.dragState.mode === 'move') {
@@ -4808,12 +5549,14 @@ var KonvaInteraction = /** @class */ (function () {
4808
5549
  _this.dragState.hasMoved = _this.dragState.hasMoved || moved;
4809
5550
  _this.dragState.current = point;
4810
5551
  if (_this.dragState.hasMoved) {
4811
- var source = _this.engine.getPortWorldPosition(_this.dragState.sourcePortId);
5552
+ var hit = _this.resolveHit(point);
5553
+ var source = _this.resolveLinkPreviewSource(_this.dragState.sourcePortId, point, hit);
4812
5554
  if (source) {
4813
5555
  (_b = _this.renderer) === null || _b === void 0 ? void 0 : _b.renderTempLink([source, point]);
4814
5556
  }
4815
- var hit = _this.resolveHit(point);
4816
- if ((hit === null || hit === void 0 ? void 0 : hit.type) === 'port' && hit.id !== linkDrag.sourcePortId) {
5557
+ if (linkDrag.completionBehavior === 'hover-or-release' &&
5558
+ (hit === null || hit === void 0 ? void 0 : hit.type) === 'port' &&
5559
+ hit.id !== linkDrag.sourcePortId) {
4817
5560
  var completion = _this.tryCreateLinkToPort(linkDrag.sourcePortId, linkDrag.sourceElementId, hit.id);
4818
5561
  if (completion.createdLinkId) {
4819
5562
  var pointerInfo = _this.buildPointerInfo(point, nativeEvent);
@@ -4822,7 +5565,9 @@ var KonvaInteraction = /** @class */ (function () {
4822
5565
  elementId: linkDrag.sourceElementId,
4823
5566
  pointer: pointerInfo,
4824
5567
  });
4825
- _this.engine.emitElementLinkEnded({
5568
+ _this.dragState = null;
5569
+ _this.linkDragContext = null;
5570
+ _this.emitElementLinkEndedSafely({
4826
5571
  sourcePortId: linkDrag.sourcePortId,
4827
5572
  sourceElementId: linkDrag.sourceElementId,
4828
5573
  linkId: completion.createdLinkId,
@@ -4832,8 +5577,6 @@ var KonvaInteraction = /** @class */ (function () {
4832
5577
  });
4833
5578
  (_d = _this.renderer) === null || _d === void 0 ? void 0 : _d.clearTempLink();
4834
5579
  (_f = (_e = _this.renderer) === null || _e === void 0 ? void 0 : _e.clearPortPlaceholder) === null || _f === void 0 ? void 0 : _f.call(_e);
4835
- _this.dragState = null;
4836
- _this.linkDragContext = null;
4837
5580
  _this.setCursor('default');
4838
5581
  return;
4839
5582
  }
@@ -4924,6 +5667,7 @@ var KonvaInteraction = /** @class */ (function () {
4924
5667
  var pointerPoint = _this.getPointerPosition();
4925
5668
  if (((_a = _this.dragState) === null || _a === void 0 ? void 0 : _a.mode) === 'shape-control-drag') {
4926
5669
  var dragState = _this.dragState;
5670
+ _this.dragState = null;
4927
5671
  var point = pointerPoint !== null && pointerPoint !== void 0 ? pointerPoint : dragState.start;
4928
5672
  var delta = { x: point.x - dragState.start.x, y: point.y - dragState.start.y };
4929
5673
  var dragContext = {
@@ -4938,7 +5682,6 @@ var KonvaInteraction = /** @class */ (function () {
4938
5682
  _this.emitShapeHoverControlInteraction('click', dragState.control, point, nativeEvent);
4939
5683
  _this.emitLegacyShapeHoverControlActivation(dragState.control, point, nativeEvent);
4940
5684
  }
4941
- _this.dragState = null;
4942
5685
  if (pointerPoint) {
4943
5686
  _this.lastPointerPosition = __assign({}, pointerPoint);
4944
5687
  _this.updateShapeHoverControl(pointerPoint);
@@ -4951,46 +5694,45 @@ var KonvaInteraction = /** @class */ (function () {
4951
5694
  return;
4952
5695
  }
4953
5696
  if (((_b = _this.dragState) === null || _b === void 0 ? void 0 : _b.mode) === 'link-drag') {
5697
+ var linkState = _this.dragState;
4954
5698
  var point = pointerPoint;
4955
- var pointerInfo = _this.buildPointerInfo(point !== null && point !== void 0 ? point : _this.dragState.start, nativeEvent);
5699
+ var pointerInfo = _this.buildPointerInfo(point !== null && point !== void 0 ? point : linkState.start, nativeEvent);
4956
5700
  var sourcePortPayload = {
4957
- portId: _this.dragState.sourcePortId,
4958
- elementId: _this.dragState.sourceElementId,
5701
+ portId: linkState.sourcePortId,
5702
+ elementId: linkState.sourceElementId,
4959
5703
  pointer: pointerInfo,
4960
5704
  };
4961
5705
  _this.engine.emitPortMouseUp(sourcePortPayload);
4962
5706
  var createdLinkId = null;
4963
5707
  var targetPortId = null;
4964
5708
  var targetElementId = null;
4965
- if (!_this.dragState.hasMoved) {
4966
- _this.handleSelection({ id: _this.dragState.sourcePortId, type: 'port' }, _this.dragState.isMulti);
5709
+ if (!linkState.hasMoved) {
5710
+ _this.handleSelection({ id: linkState.sourcePortId, type: 'port' }, linkState.isMulti);
4967
5711
  }
4968
5712
  else {
4969
5713
  var hit = point ? _this.resolveHit(point) : null;
4970
- if (hit && hit.type === 'port' && hit.id !== _this.dragState.sourcePortId) {
4971
- var completion = _this.tryCreateLinkToPort(_this.dragState.sourcePortId, _this.dragState.sourceElementId, hit.id);
5714
+ if (linkState.completionBehavior === 'hover-or-release' &&
5715
+ hit &&
5716
+ hit.type === 'port' &&
5717
+ hit.id !== linkState.sourcePortId) {
5718
+ var completion = _this.tryCreateLinkToPort(linkState.sourcePortId, linkState.sourceElementId, hit.id);
4972
5719
  createdLinkId = completion.createdLinkId;
4973
5720
  targetPortId = completion.targetPortId;
4974
5721
  targetElementId = completion.targetElementId;
4975
5722
  }
4976
- else if (hit && hit.type === 'element' && point) {
5723
+ else if (linkState.completionBehavior === 'hover-or-release' && hit && hit.type === 'element' && point) {
4977
5724
  targetElementId = hit.id;
4978
- var createdPortId = _this.createPortForLink(hit.id, point, _this.dragState.sourcePortId);
4979
- if (createdPortId) {
4980
- targetPortId = createdPortId;
4981
- createdLinkId = createId();
4982
- _this.engine.addLink({
4983
- id: createdLinkId,
4984
- sourcePortId: _this.dragState.sourcePortId,
4985
- targetPortId: createdPortId,
4986
- points: [],
4987
- });
4988
- }
5725
+ var completion = _this.tryCreateLinkToElement(linkState.sourcePortId, linkState.sourceElementId, hit.id, point);
5726
+ targetPortId = completion.targetPortId;
5727
+ createdLinkId = completion.createdLinkId;
5728
+ targetElementId = completion.targetElementId;
4989
5729
  }
4990
5730
  }
4991
- _this.engine.emitElementLinkEnded({
4992
- sourcePortId: _this.dragState.sourcePortId,
4993
- sourceElementId: _this.dragState.sourceElementId,
5731
+ _this.dragState = null;
5732
+ _this.linkDragContext = null;
5733
+ _this.emitElementLinkEndedSafely({
5734
+ sourcePortId: linkState.sourcePortId,
5735
+ sourceElementId: linkState.sourceElementId,
4994
5736
  linkId: createdLinkId !== null && createdLinkId !== void 0 ? createdLinkId : undefined,
4995
5737
  targetPortId: targetPortId !== null && targetPortId !== void 0 ? targetPortId : undefined,
4996
5738
  targetElementId: targetElementId !== null && targetElementId !== void 0 ? targetElementId : undefined,
@@ -5224,7 +5966,7 @@ var KonvaInteraction = /** @class */ (function () {
5224
5966
  addHit(this.findElementHit(point));
5225
5967
  if (hits.length === 0)
5226
5968
  return null;
5227
- var priority = ['resize-handle', 'link-handle', 'shape-hover-control', 'port', 'link', 'text', 'element'];
5969
+ var priority = ['resize-handle', 'link-handle', 'port', 'shape-hover-control', 'link', 'text', 'element'];
5228
5970
  var _loop_1 = function (i) {
5229
5971
  var candidates = hits.filter(function (hit) { return hit.type === priority[i]; });
5230
5972
  if (candidates.length === 0)
@@ -5670,10 +6412,10 @@ var KonvaInteraction = /** @class */ (function () {
5670
6412
  for (var index = 0; index < controls.length; index += 1) {
5671
6413
  var control = controls[index];
5672
6414
  var targetHoverCandidate = control.visibilityTriggers.includes('target-hover')
5673
- ? this.resolveTargetHoverCandidate(point, transformed, ellipseMidPoints, control)
6415
+ ? this.resolveTargetHoverCandidate(point, transformed, ellipseMidPoints, control, elementId)
5674
6416
  : null;
5675
6417
  var elementHoverCandidate = control.visibilityTriggers.includes('element-hover')
5676
- ? this.resolveElementHoverCandidate(point, transformed, ellipseMidPoints, control)
6418
+ ? this.resolveElementHoverCandidate(point, transformed, ellipseMidPoints, control, elementId)
5677
6419
  : null;
5678
6420
  var candidate = targetHoverCandidate !== null && targetHoverCandidate !== void 0 ? targetHoverCandidate : elementHoverCandidate;
5679
6421
  if (!candidate)
@@ -5689,7 +6431,7 @@ var KonvaInteraction = /** @class */ (function () {
5689
6431
  }
5690
6432
  return null;
5691
6433
  };
5692
- KonvaInteraction.prototype.resolveTargetHoverCandidate = function (point, geometry, ellipseMidPoints, control) {
6434
+ KonvaInteraction.prototype.resolveTargetHoverCandidate = function (point, geometry, ellipseMidPoints, control, elementId) {
5693
6435
  if (control.targetKind === 'ellipse-midpoint') {
5694
6436
  var targets = this.resolveEligibleEllipseMidPoints(control, ellipseMidPoints);
5695
6437
  if (!targets.length || control.tolerance <= 0)
@@ -5710,7 +6452,7 @@ var KonvaInteraction = /** @class */ (function () {
5710
6452
  }
5711
6453
  if (!geometry)
5712
6454
  return null;
5713
- var indices = this.resolveEligibleTargetIndices(control, geometry);
6455
+ var indices = this.resolveEligibleTargetIndices(control, geometry, elementId);
5714
6456
  if (!indices.length || control.tolerance <= 0)
5715
6457
  return null;
5716
6458
  if (control.targetKind === 'vertex') {
@@ -5760,7 +6502,7 @@ var KonvaInteraction = /** @class */ (function () {
5760
6502
  }
5761
6503
  return best ? { targetIndex: best.targetIndex, target: best.target } : null;
5762
6504
  };
5763
- KonvaInteraction.prototype.resolveElementHoverCandidate = function (point, geometry, ellipseMidPoints, control) {
6505
+ KonvaInteraction.prototype.resolveElementHoverCandidate = function (point, geometry, ellipseMidPoints, control, elementId) {
5764
6506
  if (control.targetKind === 'ellipse-midpoint') {
5765
6507
  var targets = this.resolveEligibleEllipseMidPoints(control, ellipseMidPoints);
5766
6508
  if (!targets.length)
@@ -5779,7 +6521,7 @@ var KonvaInteraction = /** @class */ (function () {
5779
6521
  }
5780
6522
  if (!geometry)
5781
6523
  return null;
5782
- var indices = this.resolveEligibleTargetIndices(control, geometry);
6524
+ var indices = this.resolveEligibleTargetIndices(control, geometry, elementId);
5783
6525
  if (!indices.length)
5784
6526
  return null;
5785
6527
  if (control.targetKind === 'vertex') {
@@ -5823,17 +6565,46 @@ var KonvaInteraction = /** @class */ (function () {
5823
6565
  }
5824
6566
  return best ? { targetIndex: best.targetIndex, target: best.target } : null;
5825
6567
  };
5826
- KonvaInteraction.prototype.resolveEligibleTargetIndices = function (control, geometry) {
6568
+ KonvaInteraction.prototype.resolveEligibleTargetIndices = function (control, geometry, elementId) {
5827
6569
  var _a;
5828
6570
  var source = control.targetKind === 'vertex' ? geometry.vertices : geometry.edges;
5829
6571
  if (!source.length)
5830
6572
  return [];
6573
+ var occupiedVertexIndices = this.resolveOccupiedVertexIndices(elementId, geometry);
5831
6574
  if (control.allowAllTargets === true) {
5832
- return Array.from({ length: source.length }, function (_, index) { return index; });
6575
+ return Array.from({ length: source.length }, function (_, index) { return index; }).filter(function (index) {
6576
+ return control.targetKind === 'vertex' ? !occupiedVertexIndices.has(index) : true;
6577
+ });
5833
6578
  }
5834
6579
  if (!((_a = control.targetIndices) === null || _a === void 0 ? void 0 : _a.length))
5835
6580
  return [];
5836
- return control.targetIndices.filter(function (targetIndex) { return targetIndex >= 0 && targetIndex < source.length; });
6581
+ return control.targetIndices.filter(function (targetIndex) {
6582
+ return targetIndex >= 0 &&
6583
+ targetIndex < source.length &&
6584
+ (control.targetKind !== 'vertex' || !occupiedVertexIndices.has(targetIndex));
6585
+ });
6586
+ };
6587
+ KonvaInteraction.prototype.resolveOccupiedVertexIndices = function (elementId, geometry) {
6588
+ var _this = this;
6589
+ if (!geometry.vertices.length)
6590
+ return new Set();
6591
+ var ports = this.engine.getState().ports.filter(function (port) { return port.elementId === elementId; });
6592
+ if (!ports.length)
6593
+ return new Set();
6594
+ var tolerance = this.occupiedVertexTolerance;
6595
+ var occupied = new Set();
6596
+ ports.forEach(function (port) {
6597
+ var world = _this.engine.getPortWorldPosition(port.id);
6598
+ if (!world)
6599
+ return;
6600
+ geometry.vertices.forEach(function (vertex, index) {
6601
+ if (Math.abs(vertex.position.x - world.x) <= tolerance &&
6602
+ Math.abs(vertex.position.y - world.y) <= tolerance) {
6603
+ occupied.add(index);
6604
+ }
6605
+ });
6606
+ });
6607
+ return occupied;
5837
6608
  };
5838
6609
  KonvaInteraction.prototype.resolveEligibleEllipseMidPoints = function (control, targets) {
5839
6610
  var _a;
@@ -6255,14 +7026,19 @@ var KonvaInteraction = /** @class */ (function () {
6255
7026
  this.engine.setSelection(Array.from(selected));
6256
7027
  };
6257
7028
  KonvaInteraction.prototype.applyPortConstraints = function (portId, worldTarget) {
7029
+ var _a;
6258
7030
  var port = this.getPortById(portId);
6259
7031
  if (!port)
6260
7032
  return worldTarget;
7033
+ var element = this.getElementById(port.elementId);
7034
+ if (!element)
7035
+ return worldTarget;
6261
7036
  var elementPos = this.engine.getElementWorldPosition(port.elementId);
6262
7037
  if (!elementPos)
6263
7038
  return worldTarget;
6264
7039
  var relative = { x: worldTarget.x - elementPos.x, y: worldTarget.y - elementPos.y };
6265
7040
  var style = port.style;
7041
+ var limits = (_a = element.portMovement) === null || _a === void 0 ? void 0 : _a.positionLimits;
6266
7042
  var constrained = __assign({}, relative);
6267
7043
  if ((style === null || style === void 0 ? void 0 : style.moveAxis) === 'horizontal') {
6268
7044
  constrained.y = port.position.y;
@@ -6275,8 +7051,78 @@ var KonvaInteraction = /** @class */ (function () {
6275
7051
  constrained.x = Math.min(bounds.x + bounds.width, Math.max(bounds.x, constrained.x));
6276
7052
  constrained.y = Math.min(bounds.y + bounds.height, Math.max(bounds.y, constrained.y));
6277
7053
  }
7054
+ if (limits === null || limits === void 0 ? void 0 : limits.x) {
7055
+ if (typeof limits.x.min === 'number')
7056
+ constrained.x = Math.max(constrained.x, limits.x.min);
7057
+ if (typeof limits.x.max === 'number')
7058
+ constrained.x = Math.min(constrained.x, limits.x.max);
7059
+ }
7060
+ if (limits === null || limits === void 0 ? void 0 : limits.y) {
7061
+ if (typeof limits.y.min === 'number')
7062
+ constrained.y = Math.max(constrained.y, limits.y.min);
7063
+ if (typeof limits.y.max === 'number')
7064
+ constrained.y = Math.min(constrained.y, limits.y.max);
7065
+ }
6278
7066
  return { x: elementPos.x + constrained.x, y: elementPos.y + constrained.y };
6279
7067
  };
7068
+ KonvaInteraction.prototype.resolveLinkPreviewSource = function (sourcePortId, pointer, hit) {
7069
+ var resolvedHit = hit !== null && hit !== void 0 ? hit : this.resolveHit(pointer);
7070
+ if ((resolvedHit === null || resolvedHit === void 0 ? void 0 : resolvedHit.type) === 'port' && resolvedHit.id !== sourcePortId) {
7071
+ return this.engine.getPortLinkWorldPosition(sourcePortId, { oppositePortId: resolvedHit.id });
7072
+ }
7073
+ return this.engine.getPortLinkWorldPosition(sourcePortId);
7074
+ };
7075
+ KonvaInteraction.prototype.resolveActiveLinkSession = function () {
7076
+ var _a;
7077
+ if (this.programmaticLinkSession) {
7078
+ return {
7079
+ sourcePortId: this.programmaticLinkSession.sourcePortId,
7080
+ sourceElementId: this.programmaticLinkSession.sourceElementId,
7081
+ fromProgrammatic: true,
7082
+ };
7083
+ }
7084
+ if (((_a = this.dragState) === null || _a === void 0 ? void 0 : _a.mode) === 'link-drag') {
7085
+ return {
7086
+ sourcePortId: this.dragState.sourcePortId,
7087
+ sourceElementId: this.dragState.sourceElementId,
7088
+ fromProgrammatic: false,
7089
+ };
7090
+ }
7091
+ return null;
7092
+ };
7093
+ KonvaInteraction.prototype.finishLinkDragSession = function (result) {
7094
+ var _a, _b, _c, _d;
7095
+ this.linkDragContext = null;
7096
+ if (result.fromProgrammatic) {
7097
+ this.programmaticLinkSession = null;
7098
+ }
7099
+ else if (((_a = this.dragState) === null || _a === void 0 ? void 0 : _a.mode) === 'link-drag') {
7100
+ this.dragState = null;
7101
+ }
7102
+ (_b = this.renderer) === null || _b === void 0 ? void 0 : _b.clearTempLink();
7103
+ (_d = (_c = this.renderer) === null || _c === void 0 ? void 0 : _c.clearPortPlaceholder) === null || _d === void 0 ? void 0 : _d.call(_c);
7104
+ this.clearActiveShapeHoverControl();
7105
+ this.setCursor('default');
7106
+ this.emitElementLinkEndedSafely({
7107
+ sourcePortId: result.sourcePortId,
7108
+ sourceElementId: result.sourceElementId,
7109
+ linkId: result.createdLinkId,
7110
+ targetPortId: result.targetPortId,
7111
+ targetElementId: result.targetElementId,
7112
+ cancelled: result.cancelled,
7113
+ });
7114
+ };
7115
+ KonvaInteraction.prototype.emitElementLinkEndedSafely = function (event) {
7116
+ if (this.emittingElementLinkEnded)
7117
+ return;
7118
+ this.emittingElementLinkEnded = true;
7119
+ try {
7120
+ this.engine.emitElementLinkEnded(event);
7121
+ }
7122
+ finally {
7123
+ this.emittingElementLinkEnded = false;
7124
+ }
7125
+ };
6280
7126
  KonvaInteraction.prototype.tryCreateLinkToPort = function (sourcePortId, sourceElementId, targetPortId) {
6281
7127
  var targetElementId = this.engine.getPortElementId(targetPortId);
6282
7128
  var cancelledByHost = targetElementId !== null &&
@@ -6300,6 +7146,33 @@ var KonvaInteraction = /** @class */ (function () {
6300
7146
  });
6301
7147
  return { createdLinkId: createdLinkId, targetPortId: targetPortId, targetElementId: targetElementId };
6302
7148
  };
7149
+ KonvaInteraction.prototype.tryCreateLinkToElement = function (sourcePortId, sourceElementId, targetElementId, worldPoint) {
7150
+ var targetPort = this.createPortForLink(targetElementId, worldPoint, sourcePortId);
7151
+ if (!targetPort) {
7152
+ return { createdLinkId: null, targetPortId: null, targetElementId: null };
7153
+ }
7154
+ var cancelledByHost = this.engine.emitElementLinkConnecting({
7155
+ sourcePortId: sourcePortId,
7156
+ sourceElementId: sourceElementId,
7157
+ targetPortId: targetPort.id,
7158
+ targetElementId: targetElementId,
7159
+ cancel: function () { },
7160
+ cancelled: false,
7161
+ });
7162
+ if (cancelledByHost) {
7163
+ return { createdLinkId: null, targetPortId: targetPort.id, targetElementId: targetElementId };
7164
+ }
7165
+ this.engine.addPortToElement(targetElementId, targetPort);
7166
+ this.engine.movePortTo(targetPort.id, worldPoint.x, worldPoint.y);
7167
+ var createdLinkId = createId();
7168
+ this.engine.addLink({
7169
+ id: createdLinkId,
7170
+ sourcePortId: sourcePortId,
7171
+ targetPortId: targetPort.id,
7172
+ points: [],
7173
+ });
7174
+ return { createdLinkId: createdLinkId, targetPortId: targetPort.id, targetElementId: targetElementId };
7175
+ };
6303
7176
  KonvaInteraction.prototype.createPortForLink = function (elementId, worldPoint, sourcePortId) {
6304
7177
  var _a, _b, _c, _d;
6305
7178
  var element = this.getElementById(elementId);
@@ -6314,9 +7187,8 @@ var KonvaInteraction = /** @class */ (function () {
6314
7187
  var destinationMoveMode = ((_b = element.portMovement) === null || _b === void 0 ? void 0 : _b.moveMode) && element.portMovement.moveMode !== 'anchors'
6315
7188
  ? element.portMovement.moveMode
6316
7189
  : undefined;
6317
- var portId = createId();
6318
- this.engine.addPortToElement(elementId, {
6319
- id: portId,
7190
+ return {
7191
+ id: createId(),
6320
7192
  elementId: elementId,
6321
7193
  position: relative,
6322
7194
  shapeId: sourcePort === null || sourcePort === void 0 ? void 0 : sourcePort.shapeId,
@@ -6325,9 +7197,12 @@ var KonvaInteraction = /** @class */ (function () {
6325
7197
  moveMode: destinationMoveMode !== null && destinationMoveMode !== void 0 ? destinationMoveMode : sourcePort === null || sourcePort === void 0 ? void 0 : sourcePort.moveMode,
6326
7198
  anchorCenter: (_c = sourcePort === null || sourcePort === void 0 ? void 0 : sourcePort.anchorCenter) !== null && _c !== void 0 ? _c : true,
6327
7199
  orientToHostBorder: (_d = sourcePort === null || sourcePort === void 0 ? void 0 : sourcePort.orientToHostBorder) !== null && _d !== void 0 ? _d : true,
6328
- });
6329
- this.engine.movePortTo(portId, worldPoint.x, worldPoint.y);
6330
- return portId;
7200
+ placementPoint: (sourcePort === null || sourcePort === void 0 ? void 0 : sourcePort.placementPoint) ? __assign({}, sourcePort.placementPoint) : undefined,
7201
+ linkAttachPoint: (sourcePort === null || sourcePort === void 0 ? void 0 : sourcePort.linkAttachPoint) ? __assign({}, sourcePort.linkAttachPoint) : undefined,
7202
+ externalLinkAttachPoint: (sourcePort === null || sourcePort === void 0 ? void 0 : sourcePort.externalLinkAttachPoint) ? __assign({}, sourcePort.externalLinkAttachPoint) : undefined,
7203
+ internalLinkAttachPoint: (sourcePort === null || sourcePort === void 0 ? void 0 : sourcePort.internalLinkAttachPoint) ? __assign({}, sourcePort.internalLinkAttachPoint) : undefined,
7204
+ rotationPivot: (sourcePort === null || sourcePort === void 0 ? void 0 : sourcePort.rotationPivot) ? __assign({}, sourcePort.rotationPivot) : undefined,
7205
+ };
6331
7206
  };
6332
7207
  KonvaInteraction.prototype.createPlaceholderPort = function (elementId, worldPoint, sourcePortId) {
6333
7208
  var _a, _b, _c;
@@ -6346,6 +7221,11 @@ var KonvaInteraction = /** @class */ (function () {
6346
7221
  moveMode: destinationMoveMode !== null && destinationMoveMode !== void 0 ? destinationMoveMode : sourcePort === null || sourcePort === void 0 ? void 0 : sourcePort.moveMode,
6347
7222
  anchorCenter: (_b = sourcePort === null || sourcePort === void 0 ? void 0 : sourcePort.anchorCenter) !== null && _b !== void 0 ? _b : true,
6348
7223
  orientToHostBorder: (_c = sourcePort === null || sourcePort === void 0 ? void 0 : sourcePort.orientToHostBorder) !== null && _c !== void 0 ? _c : true,
7224
+ placementPoint: (sourcePort === null || sourcePort === void 0 ? void 0 : sourcePort.placementPoint) ? __assign({}, sourcePort.placementPoint) : undefined,
7225
+ linkAttachPoint: (sourcePort === null || sourcePort === void 0 ? void 0 : sourcePort.linkAttachPoint) ? __assign({}, sourcePort.linkAttachPoint) : undefined,
7226
+ externalLinkAttachPoint: (sourcePort === null || sourcePort === void 0 ? void 0 : sourcePort.externalLinkAttachPoint) ? __assign({}, sourcePort.externalLinkAttachPoint) : undefined,
7227
+ internalLinkAttachPoint: (sourcePort === null || sourcePort === void 0 ? void 0 : sourcePort.internalLinkAttachPoint) ? __assign({}, sourcePort.internalLinkAttachPoint) : undefined,
7228
+ rotationPivot: (sourcePort === null || sourcePort === void 0 ? void 0 : sourcePort.rotationPivot) ? __assign({}, sourcePort.rotationPivot) : undefined,
6349
7229
  };
6350
7230
  };
6351
7231
  KonvaInteraction.prototype.getElementById = function (id) {
@@ -6389,47 +7269,77 @@ var KonvaInteraction = /** @class */ (function () {
6389
7269
  (_b = stageAny === null || stageAny === void 0 ? void 0 : stageAny.position) === null || _b === void 0 ? void 0 : _b.call(stageAny, this.pan);
6390
7270
  };
6391
7271
  KonvaInteraction.prototype.cancelLinkDrag = function () {
6392
- var _a, _b, _c, _d, _e, _f;
7272
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
6393
7273
  if (((_a = this.dragState) === null || _a === void 0 ? void 0 : _a.mode) === 'shape-control-drag') {
6394
- var point_1 = (_b = this.lastPointerPosition) !== null && _b !== void 0 ? _b : this.dragState.start;
6395
- if (this.dragState.hasMoved) {
6396
- this.emitShapeHoverControlInteraction('drag-end', this.dragState.control, point_1, undefined, {
6397
- sessionId: this.dragState.sessionId,
6398
- startPointer: this.dragState.startPointer,
7274
+ var dragState = this.dragState;
7275
+ var point_1 = (_b = this.lastPointerPosition) !== null && _b !== void 0 ? _b : dragState.start;
7276
+ this.dragState = null;
7277
+ if (dragState.hasMoved) {
7278
+ this.emitShapeHoverControlInteraction('drag-end', dragState.control, point_1, undefined, {
7279
+ sessionId: dragState.sessionId,
7280
+ startPointer: dragState.startPointer,
6399
7281
  delta: {
6400
- x: point_1.x - this.dragState.start.x,
6401
- y: point_1.y - this.dragState.start.y,
7282
+ x: point_1.x - dragState.start.x,
7283
+ y: point_1.y - dragState.start.y,
6402
7284
  },
6403
7285
  });
6404
7286
  }
6405
- this.dragState = null;
7287
+ if (this.programmaticLinkSession) {
7288
+ var session = this.programmaticLinkSession;
7289
+ this.programmaticLinkSession = null;
7290
+ this.linkDragContext = null;
7291
+ (_c = this.renderer) === null || _c === void 0 ? void 0 : _c.clearTempLink();
7292
+ (_e = (_d = this.renderer) === null || _d === void 0 ? void 0 : _d.clearPortPlaceholder) === null || _e === void 0 ? void 0 : _e.call(_d);
7293
+ this.emitElementLinkEndedSafely({
7294
+ sourcePortId: session.sourcePortId,
7295
+ sourceElementId: session.sourceElementId,
7296
+ cancelled: true,
7297
+ });
7298
+ }
7299
+ this.clearActiveShapeHoverControl();
7300
+ this.setCursor('default');
7301
+ return;
7302
+ }
7303
+ if (this.programmaticLinkSession) {
7304
+ var session = this.programmaticLinkSession;
7305
+ this.programmaticLinkSession = null;
7306
+ this.linkDragContext = null;
7307
+ (_f = this.renderer) === null || _f === void 0 ? void 0 : _f.clearTempLink();
7308
+ (_h = (_g = this.renderer) === null || _g === void 0 ? void 0 : _g.clearPortPlaceholder) === null || _h === void 0 ? void 0 : _h.call(_g);
7309
+ this.emitElementLinkEndedSafely({
7310
+ sourcePortId: session.sourcePortId,
7311
+ sourceElementId: session.sourceElementId,
7312
+ cancelled: true,
7313
+ });
6406
7314
  this.clearActiveShapeHoverControl();
6407
7315
  this.setCursor('default');
6408
7316
  return;
6409
7317
  }
6410
7318
  if (!this.dragState || this.dragState.mode !== 'link-drag') {
6411
7319
  if (this.linkDragContext) {
6412
- this.engine.emitElementLinkEnded(__assign(__assign({}, this.linkDragContext), { cancelled: true }));
7320
+ var context = this.linkDragContext;
6413
7321
  this.linkDragContext = null;
7322
+ this.emitElementLinkEndedSafely(__assign(__assign({}, context), { cancelled: true }));
6414
7323
  }
6415
7324
  return;
6416
7325
  }
6417
- var point = (_c = this.dragState.current) !== null && _c !== void 0 ? _c : this.dragState.start;
7326
+ var linkState = this.dragState;
7327
+ var point = (_j = linkState.current) !== null && _j !== void 0 ? _j : linkState.start;
6418
7328
  var pointerInfo = this.buildPointerInfo(point, null);
6419
7329
  this.engine.emitPortMouseUp({
6420
- portId: this.dragState.sourcePortId,
6421
- elementId: this.dragState.sourceElementId,
7330
+ portId: linkState.sourcePortId,
7331
+ elementId: linkState.sourceElementId,
6422
7332
  pointer: pointerInfo,
6423
7333
  });
6424
- this.engine.emitElementLinkEnded({
6425
- sourcePortId: this.dragState.sourcePortId,
6426
- sourceElementId: this.dragState.sourceElementId,
7334
+ this.dragState = null;
7335
+ this.linkDragContext = null;
7336
+ (_k = this.renderer) === null || _k === void 0 ? void 0 : _k.clearTempLink();
7337
+ (_m = (_l = this.renderer) === null || _l === void 0 ? void 0 : _l.clearPortPlaceholder) === null || _m === void 0 ? void 0 : _m.call(_l);
7338
+ this.emitElementLinkEndedSafely({
7339
+ sourcePortId: linkState.sourcePortId,
7340
+ sourceElementId: linkState.sourceElementId,
6427
7341
  cancelled: true,
6428
7342
  });
6429
- this.linkDragContext = null;
6430
- (_d = this.renderer) === null || _d === void 0 ? void 0 : _d.clearTempLink();
6431
- (_f = (_e = this.renderer) === null || _e === void 0 ? void 0 : _e.clearPortPlaceholder) === null || _f === void 0 ? void 0 : _f.call(_e);
6432
- this.dragState = null;
6433
7343
  this.clearActiveShapeHoverControl();
6434
7344
  this.setCursor('default');
6435
7345
  };
@@ -6653,6 +7563,15 @@ var normalizeVector = function (vector) {
6653
7563
  return { x: 0, y: -1 };
6654
7564
  return { x: vector.x / length, y: vector.y / length };
6655
7565
  };
7566
+ var sideToNormal = function (side) {
7567
+ if (side === 'left')
7568
+ return { x: -1, y: 0 };
7569
+ if (side === 'right')
7570
+ return { x: 1, y: 0 };
7571
+ if (side === 'top')
7572
+ return { x: 0, y: -1 };
7573
+ return { x: 0, y: 1 };
7574
+ };
6656
7575
  var resolveCardinalAnchors = function (rect) {
6657
7576
  var cx = rect.x + rect.width / 2;
6658
7577
  var cy = rect.y + rect.height / 2;
@@ -6732,9 +7651,15 @@ var BuiltInShape = /** @class */ (function () {
6732
7651
  BuiltInShape.prototype.resolveBorderSide = function (point, rect) {
6733
7652
  return resolveBoundarySide(point, rect, 'rect');
6734
7653
  };
7654
+ BuiltInShape.prototype.resolveBorderNormal = function (point, rect) {
7655
+ return sideToNormal(this.resolveBorderSide(point, rect));
7656
+ };
6735
7657
  BuiltInShape.prototype.resolvePortAnchors = function (_rect, _options) {
6736
7658
  return [];
6737
7659
  };
7660
+ BuiltInShape.prototype.resolvePortBorderTransform = function (_context) {
7661
+ return undefined;
7662
+ };
6738
7663
  BuiltInShape.prototype.resolveHoverGeometry = function (_rect) {
6739
7664
  return undefined;
6740
7665
  };
@@ -6964,6 +7889,78 @@ var getKonva = function () {
6964
7889
  var module = require('konva');
6965
7890
  return (_a = module.default) !== null && _a !== void 0 ? _a : module;
6966
7891
  };
7892
+ var createBounds = function () { return ({
7893
+ minX: Number.POSITIVE_INFINITY,
7894
+ minY: Number.POSITIVE_INFINITY,
7895
+ maxX: Number.NEGATIVE_INFINITY,
7896
+ maxY: Number.NEGATIVE_INFINITY,
7897
+ }); };
7898
+ var expandBounds = function (bounds, x, y) {
7899
+ if (x < bounds.minX)
7900
+ bounds.minX = x;
7901
+ if (y < bounds.minY)
7902
+ bounds.minY = y;
7903
+ if (x > bounds.maxX)
7904
+ bounds.maxX = x;
7905
+ if (y > bounds.maxY)
7906
+ bounds.maxY = y;
7907
+ };
7908
+ var includeRect = function (bounds, x, y, width, height) {
7909
+ var safeWidth = Math.max(0, width);
7910
+ var safeHeight = Math.max(0, height);
7911
+ expandBounds(bounds, x, y);
7912
+ expandBounds(bounds, x + safeWidth, y + safeHeight);
7913
+ };
7914
+ var hasBounds = function (bounds) {
7915
+ return Number.isFinite(bounds.minX) &&
7916
+ Number.isFinite(bounds.minY) &&
7917
+ Number.isFinite(bounds.maxX) &&
7918
+ Number.isFinite(bounds.maxY) &&
7919
+ bounds.maxX >= bounds.minX &&
7920
+ bounds.maxY >= bounds.minY;
7921
+ };
7922
+ var resolveStateWorldBounds = function (state) {
7923
+ var bounds = createBounds();
7924
+ state.elements.forEach(function (element) {
7925
+ includeRect(bounds, element.position.x, element.position.y, element.size.width, element.size.height);
7926
+ });
7927
+ state.ports.forEach(function (port) {
7928
+ var _a;
7929
+ var size = port.size;
7930
+ if (!size) {
7931
+ expandBounds(bounds, port.position.x, port.position.y);
7932
+ return;
7933
+ }
7934
+ var anchorCenter = (_a = port.anchorCenter) !== null && _a !== void 0 ? _a : true;
7935
+ var x = anchorCenter ? port.position.x - size.width / 2 : port.position.x;
7936
+ var y = anchorCenter ? port.position.y - size.height / 2 : port.position.y;
7937
+ includeRect(bounds, x, y, size.width, size.height);
7938
+ });
7939
+ state.links.forEach(function (link) {
7940
+ link.points.forEach(function (point) {
7941
+ expandBounds(bounds, point.x, point.y);
7942
+ });
7943
+ });
7944
+ state.texts.forEach(function (text) {
7945
+ var _a;
7946
+ var offset = (_a = text.displayOffset) !== null && _a !== void 0 ? _a : { x: 0, y: 0 };
7947
+ var position = { x: text.position.x + offset.x, y: text.position.y + offset.y };
7948
+ var clipSize = text.displayClipSize;
7949
+ var size = clipSize !== null && clipSize !== void 0 ? clipSize : text.size;
7950
+ if (size) {
7951
+ includeRect(bounds, position.x, position.y, size.width, size.height);
7952
+ return;
7953
+ }
7954
+ expandBounds(bounds, position.x, position.y);
7955
+ });
7956
+ return hasBounds(bounds) ? bounds : null;
7957
+ };
7958
+ var resolveFitToContentPadding = function (fitToContent) {
7959
+ if (typeof fitToContent === 'object' && typeof fitToContent.padding === 'number') {
7960
+ return Math.max(0, fitToContent.padding);
7961
+ }
7962
+ return 0;
7963
+ };
6967
7964
  var getNodeAttr = function (node, key) {
6968
7965
  if (node.getAttr) {
6969
7966
  return node.getAttr(key);
@@ -7002,7 +7999,13 @@ var registerSimpleShapes = function (registry, shapes, isPort) {
7002
7999
  : undefined,
7003
8000
  projectToBorder: function (point, rect) { return behavior.projectToBorder(point, rect); },
7004
8001
  resolveBorderSide: function (point, rect) { return behavior.resolveBorderSide(point, rect); },
8002
+ resolveBorderNormal: behavior.resolveBorderNormal
8003
+ ? function (point, rect) { return behavior.resolveBorderNormal(point, rect); }
8004
+ : undefined,
7005
8005
  resolvePortAnchors: function (rect, options) { return behavior.resolvePortAnchors(rect, options); },
8006
+ resolvePortBorderTransform: behavior.resolvePortBorderTransform
8007
+ ? function (context) { return behavior.resolvePortBorderTransform(context); }
8008
+ : undefined,
7006
8009
  resolveHoverGeometry: function (rect) { return behavior.resolveHoverGeometry(rect); },
7007
8010
  resolveEllipseMidPoints: function (rect) { return behavior.resolveEllipseMidPoints(rect); },
7008
8011
  createNode: function (model) {
@@ -7076,7 +8079,7 @@ var createDiagramEditor = function (config) {
7076
8079
  .filter(function (hit) { return Boolean(hit); });
7077
8080
  if (hits.length === 0)
7078
8081
  return { id: '', type: 'none' };
7079
- var priority = ['resize-handle', 'link-handle', 'shape-hover-control', 'port', 'link', 'text', 'element'];
8082
+ var priority = ['resize-handle', 'link-handle', 'port', 'shape-hover-control', 'link', 'text', 'element'];
7080
8083
  var _loop_1 = function (i) {
7081
8084
  var candidates = hits.filter(function (hit) { return hit.type === priority[i]; });
7082
8085
  if (candidates.length === 0)
@@ -7167,6 +8170,36 @@ var createDiagramEditor = function (config) {
7167
8170
  setSnapping: function (snapper) { return engine.setSnapping(snapper); },
7168
8171
  registerShape: function (shape) { return engine.registerShape(shape); },
7169
8172
  render: function () { return engine.render(); },
8173
+ startLinkFromPort: function (sourcePortId, pointer) { return interaction.startLinkFromPort(sourcePortId, pointer); },
8174
+ updateLinkPreview: function (pointer) { return interaction.updateLinkPreview(pointer); },
8175
+ completeLinkToPort: function (targetPortId) { return interaction.completeLinkToPort(targetPortId); },
8176
+ completeLinkToElement: function (targetElementId, pointer) { return interaction.completeLinkToElement(targetElementId, pointer); },
8177
+ cancelLink: function () { return interaction.cancelLink(); },
8178
+ exportImage: function (options) {
8179
+ engine.render();
8180
+ if (typeof stage.toDataURL !== 'function') {
8181
+ throw new Error('Diagram image export is not available on the current stage.');
8182
+ }
8183
+ if (!options) {
8184
+ return stage.toDataURL();
8185
+ }
8186
+ var fitToContent = options.fitToContent, baseOptions = __rest(options, ["fitToContent"]);
8187
+ if (!fitToContent) {
8188
+ return stage.toDataURL(baseOptions);
8189
+ }
8190
+ var padding = resolveFitToContentPadding(fitToContent);
8191
+ var worldBounds = resolveStateWorldBounds(engine.getState());
8192
+ if (!worldBounds) {
8193
+ return stage.toDataURL(baseOptions);
8194
+ }
8195
+ var viewport = engine.getViewport();
8196
+ var safeZoom = viewport.zoom === 0 ? 1 : viewport.zoom;
8197
+ var cropX = worldBounds.minX * safeZoom + viewport.pan.x - padding;
8198
+ var cropY = worldBounds.minY * safeZoom + viewport.pan.y - padding;
8199
+ var cropWidth = Math.max(1, (worldBounds.maxX - worldBounds.minX) * safeZoom + padding * 2);
8200
+ var cropHeight = Math.max(1, (worldBounds.maxY - worldBounds.minY) * safeZoom + padding * 2);
8201
+ return stage.toDataURL(__assign(__assign({}, baseOptions), { x: cropX, y: cropY, width: cropWidth, height: cropHeight }));
8202
+ },
7170
8203
  resize: function (width, height) {
7171
8204
  stage.width(width);
7172
8205
  stage.height(height);