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