orcasvn-react-diagrams 0.2.2 → 0.2.3

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 (73) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/README.md +11 -3
  3. package/dist/cjs/examples.js +1768 -161
  4. package/dist/cjs/index.js +786 -120
  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 +32 -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/layoutLabelReservedSpaceDemo.d.ts +11 -0
  14. package/dist/cjs/types/displaybox/demos/vertexControlLinkSessionDemo.d.ts +12 -0
  15. package/dist/cjs/types/displaybox/useDemoControls.d.ts +4 -0
  16. package/dist/cjs/types/engine/AutoLayoutService.d.ts +2 -0
  17. package/dist/cjs/types/engine/DiagramEngine.d.ts +5 -0
  18. package/dist/cjs/types/engine/LinkRoutingService.d.ts +9 -1
  19. package/dist/cjs/types/models/PortModel.d.ts +5 -0
  20. package/dist/cjs/types/renderer/RenderTypes.d.ts +3 -1
  21. package/dist/cjs/types/renderer/konva/KonvaInteraction.d.ts +14 -0
  22. package/dist/cjs/types/renderer/konva/KonvaNodeFactory.d.ts +1 -0
  23. package/dist/cjs/types/renderer/konva/KonvaRenderer.d.ts +0 -1
  24. package/dist/cjs/types/shapes/BuiltInShapes.d.ts +3 -1
  25. package/dist/cjs/types/utils/__tests__/portGeometry.test.d.ts +1 -0
  26. package/dist/cjs/types/utils/portGeometry.d.ts +44 -0
  27. package/dist/esm/examples.js +1769 -162
  28. package/dist/esm/examples.js.map +1 -1
  29. package/dist/esm/index.js +786 -120
  30. package/dist/esm/index.js.map +1 -1
  31. package/dist/esm/types/api/createDiagramEditor.d.ts +19 -1
  32. package/dist/esm/types/api/index.d.ts +1 -1
  33. package/dist/esm/types/api/types.d.ts +32 -0
  34. package/dist/esm/types/displaybox/DisplayBoxControls.d.ts +5 -1
  35. package/dist/esm/types/displaybox/demos/AsymmetricPortMultiAnchorDemoTab.d.ts +3 -0
  36. package/dist/esm/types/displaybox/demos/LayoutLabelReservedSpaceDemoTab.d.ts +3 -0
  37. package/dist/esm/types/displaybox/demos/VertexControlLinkSessionDemoTab.d.ts +3 -0
  38. package/dist/esm/types/displaybox/demos/asymmetricPortMultiAnchorDemo.d.ts +31 -0
  39. package/dist/esm/types/displaybox/demos/layoutLabelReservedSpaceDemo.d.ts +11 -0
  40. package/dist/esm/types/displaybox/demos/vertexControlLinkSessionDemo.d.ts +12 -0
  41. package/dist/esm/types/displaybox/useDemoControls.d.ts +4 -0
  42. package/dist/esm/types/engine/AutoLayoutService.d.ts +2 -0
  43. package/dist/esm/types/engine/DiagramEngine.d.ts +5 -0
  44. package/dist/esm/types/engine/LinkRoutingService.d.ts +9 -1
  45. package/dist/esm/types/models/PortModel.d.ts +5 -0
  46. package/dist/esm/types/renderer/RenderTypes.d.ts +3 -1
  47. package/dist/esm/types/renderer/konva/KonvaInteraction.d.ts +14 -0
  48. package/dist/esm/types/renderer/konva/KonvaNodeFactory.d.ts +1 -0
  49. package/dist/esm/types/renderer/konva/KonvaRenderer.d.ts +0 -1
  50. package/dist/esm/types/shapes/BuiltInShapes.d.ts +3 -1
  51. package/dist/esm/types/utils/__tests__/portGeometry.test.d.ts +1 -0
  52. package/dist/esm/types/utils/portGeometry.d.ts +44 -0
  53. package/dist/examples.d.ts +50 -0
  54. package/dist/index.d.ts +58 -1
  55. package/package.json +11 -10
  56. package/src/displaybox/demos/AsymmetricPortMultiAnchorDemoTab.tsx +269 -0
  57. package/src/displaybox/demos/AutoLayoutDemoTab.tsx +113 -11
  58. package/src/displaybox/demos/DeletionEventsDemoTab.tsx +6 -1
  59. package/src/displaybox/demos/EngineEventsDemoTab.tsx +5 -0
  60. package/src/displaybox/demos/EventHandlersDemoTab.tsx +5 -0
  61. package/src/displaybox/demos/ExternalDragDropDemoTab.tsx +5 -0
  62. package/src/displaybox/demos/LayoutLabelReservedSpaceDemoTab.tsx +291 -0
  63. package/src/displaybox/demos/LinkCancelDemoTab.tsx +5 -0
  64. package/src/displaybox/demos/ShapeHoverControlsDemoTab.tsx +6 -1
  65. package/src/displaybox/demos/SimpleDemo.tsx +5 -0
  66. package/src/displaybox/demos/SvgPathDemoTab.tsx +5 -0
  67. package/src/displaybox/demos/TextLayoutDemoTab.tsx +6 -1
  68. package/src/displaybox/demos/VertexControlLinkSessionDemoTab.tsx +302 -0
  69. package/src/displaybox/demos/asymmetricPortMultiAnchorDemo.ts +357 -0
  70. package/src/displaybox/demos/autoLayoutDemo.ts +23 -5
  71. package/src/displaybox/demos/index.tsx +91 -75
  72. package/src/displaybox/demos/layoutLabelReservedSpaceDemo.ts +121 -0
  73. package/src/displaybox/demos/vertexControlLinkSessionDemo.ts +145 -0
package/dist/esm/index.js CHANGED
@@ -215,6 +215,11 @@ var PortModel = /** @class */ (function () {
215
215
  this.moveMode = data.moveMode;
216
216
  this.anchorCenter = (_a = data.anchorCenter) !== null && _a !== void 0 ? _a : true;
217
217
  this.orientToHostBorder = (_b = data.orientToHostBorder) !== null && _b !== void 0 ? _b : true;
218
+ this.placementPoint = data.placementPoint ? __assign({}, data.placementPoint) : undefined;
219
+ this.linkAttachPoint = data.linkAttachPoint ? __assign({}, data.linkAttachPoint) : undefined;
220
+ this.externalLinkAttachPoint = data.externalLinkAttachPoint ? __assign({}, data.externalLinkAttachPoint) : undefined;
221
+ this.internalLinkAttachPoint = data.internalLinkAttachPoint ? __assign({}, data.internalLinkAttachPoint) : undefined;
222
+ this.rotationPivot = data.rotationPivot ? __assign({}, data.rotationPivot) : undefined;
218
223
  this.currentAnchorId = data.currentAnchorId;
219
224
  }
220
225
  PortModel.prototype.setPosition = function (position) {
@@ -243,6 +248,11 @@ var PortModel = /** @class */ (function () {
243
248
  moveMode: this.moveMode,
244
249
  anchorCenter: this.anchorCenter,
245
250
  orientToHostBorder: this.orientToHostBorder,
251
+ placementPoint: this.placementPoint ? __assign({}, this.placementPoint) : undefined,
252
+ linkAttachPoint: this.linkAttachPoint ? __assign({}, this.linkAttachPoint) : undefined,
253
+ externalLinkAttachPoint: this.externalLinkAttachPoint ? __assign({}, this.externalLinkAttachPoint) : undefined,
254
+ internalLinkAttachPoint: this.internalLinkAttachPoint ? __assign({}, this.internalLinkAttachPoint) : undefined,
255
+ rotationPivot: this.rotationPivot ? __assign({}, this.rotationPivot) : undefined,
246
256
  currentAnchorId: this.currentAnchorId,
247
257
  };
248
258
  };
@@ -1925,6 +1935,7 @@ var AutoLayoutService = /** @class */ (function () {
1925
1935
  var childFitCrossAxis = (_e = layout.childFitCrossAxis) !== null && _e !== void 0 ? _e : 'none';
1926
1936
  var childFitMinSize = layout.childFitMinSize;
1927
1937
  var childFitMaxSize = layout.childFitMaxSize;
1938
+ var labelReservedTopLane = this.resolveLabelReservedTopLane(parentId, layout);
1928
1939
  var sorted = __spreadArray([], children, true).sort(function (a, b) {
1929
1940
  var aPos = axis === 'horizontal' ? a.position.x : a.position.y;
1930
1941
  var bPos = axis === 'horizontal' ? b.position.x : b.position.y;
@@ -1935,7 +1946,7 @@ var AutoLayoutService = /** @class */ (function () {
1935
1946
  var gapCount = Math.max(0, sorted.length - 1);
1936
1947
  var calculateFittedSizes = function (parentWidth, parentHeight) {
1937
1948
  var availableWidth = Math.max(0, parentWidth - padding.x * 2);
1938
- var availableHeight = Math.max(0, parentHeight - padding.y * 2);
1949
+ var availableHeight = Math.max(0, parentHeight - padding.y * 2 - labelReservedTopLane);
1939
1950
  var availableMain = axis === 'horizontal'
1940
1951
  ? Math.max(0, availableWidth - gap * gapCount)
1941
1952
  : Math.max(0, availableHeight - gap * gapCount);
@@ -1980,12 +1991,12 @@ var AutoLayoutService = /** @class */ (function () {
1980
1991
  if (axis === 'horizontal') {
1981
1992
  return {
1982
1993
  width: Math.max(parent.size.width, padding.x * 2 + totalWidth + gap * gapCount),
1983
- height: Math.max(parent.size.height, padding.y * 2 + maxHeight),
1994
+ height: Math.max(parent.size.height, padding.y * 2 + labelReservedTopLane + maxHeight),
1984
1995
  };
1985
1996
  }
1986
1997
  return {
1987
1998
  width: Math.max(parent.size.width, padding.x * 2 + maxWidth),
1988
- height: Math.max(parent.size.height, padding.y * 2 + totalHeight + gap * gapCount),
1999
+ height: Math.max(parent.size.height, padding.y * 2 + labelReservedTopLane + totalHeight + gap * gapCount),
1989
2000
  };
1990
2001
  };
1991
2002
  var fittedSizes = calculateFittedSizes(parent.size.width, parent.size.height);
@@ -1993,9 +2004,9 @@ var AutoLayoutService = /** @class */ (function () {
1993
2004
  fittedSizes = calculateFittedSizes(newParentWidth, newParentHeight);
1994
2005
  (_a = resolveParentSize(fittedSizes), newParentWidth = _a.width, newParentHeight = _a.height);
1995
2006
  var availableWidth = Math.max(0, newParentWidth - padding.x * 2);
1996
- var availableHeight = Math.max(0, newParentHeight - padding.y * 2);
2007
+ var availableHeight = Math.max(0, newParentHeight - padding.y * 2 - labelReservedTopLane);
1997
2008
  var cursorX = padding.x;
1998
- var cursorY = padding.y;
2009
+ var cursorY = padding.y + labelReservedTopLane;
1999
2010
  var desiredPositions = new Map();
2000
2011
  var desiredSizes = new Map();
2001
2012
  sorted.forEach(function (child, index) {
@@ -2003,10 +2014,10 @@ var AutoLayoutService = /** @class */ (function () {
2003
2014
  desiredSizes.set(child.id, fittedSize);
2004
2015
  if (axis === 'horizontal') {
2005
2016
  var y = align === 'start'
2006
- ? padding.y
2017
+ ? padding.y + labelReservedTopLane
2007
2018
  : align === 'end'
2008
2019
  ? newParentHeight - padding.y - fittedSize.height
2009
- : padding.y + Math.max(0, (availableHeight - fittedSize.height) / 2);
2020
+ : padding.y + labelReservedTopLane + Math.max(0, (availableHeight - fittedSize.height) / 2);
2010
2021
  desiredPositions.set(child.id, { x: cursorX, y: y });
2011
2022
  cursorX += fittedSize.width + (index < sorted.length - 1 ? gap : 0);
2012
2023
  }
@@ -2099,6 +2110,45 @@ var AutoLayoutService = /** @class */ (function () {
2099
2110
  y: (_c = padding.y) !== null && _c !== void 0 ? _c : 12,
2100
2111
  };
2101
2112
  };
2113
+ AutoLayoutService.prototype.resolveLabelReservedTopLane = function (parentId, layout) {
2114
+ var _a, _b, _c, _d;
2115
+ var policy = layout === null || layout === void 0 ? void 0 : layout.labelReservedSpace;
2116
+ if (!policy)
2117
+ return 0;
2118
+ var mode = (_a = policy.mode) !== null && _a !== void 0 ? _a : 'none';
2119
+ if (mode === 'none')
2120
+ return 0;
2121
+ if (((_b = policy.placement) !== null && _b !== void 0 ? _b : 'top') !== 'top')
2122
+ return 0;
2123
+ var minSize = Math.max(0, (_c = policy.minSize) !== null && _c !== void 0 ? _c : 0);
2124
+ var maxSize = typeof policy.maxSize === 'number' && Number.isFinite(policy.maxSize)
2125
+ ? Math.max(minSize, policy.maxSize)
2126
+ : Number.POSITIVE_INFINITY;
2127
+ var resolved = 0;
2128
+ if (mode === 'fixed') {
2129
+ resolved = Math.max(0, (_d = policy.size) !== null && _d !== void 0 ? _d : 0);
2130
+ }
2131
+ else {
2132
+ resolved = this.resolveFlexibleLabelLaneFromText(parentId);
2133
+ }
2134
+ return this.clampLayoutSize(resolved, minSize, maxSize);
2135
+ };
2136
+ AutoLayoutService.prototype.resolveFlexibleLabelLaneFromText = function (parentId) {
2137
+ var lane = 0;
2138
+ this.model.texts.forEach(function (text) {
2139
+ var _a, _b, _c;
2140
+ if (text.ownerId !== parentId)
2141
+ return;
2142
+ var offset = (_a = text.displayOffset) !== null && _a !== void 0 ? _a : { x: 0, y: 0 };
2143
+ var size = (_b = text.displayClipSize) !== null && _b !== void 0 ? _b : text.size;
2144
+ var height = (_c = size === null || size === void 0 ? void 0 : size.height) !== null && _c !== void 0 ? _c : 0;
2145
+ var bottom = text.position.y + offset.y + height;
2146
+ if (bottom > lane) {
2147
+ lane = bottom;
2148
+ }
2149
+ });
2150
+ return Math.max(0, lane);
2151
+ };
2102
2152
  AutoLayoutService.prototype.clampLayoutSize = function (value, min, max) {
2103
2153
  var minValue = min !== null && min !== void 0 ? min : 0;
2104
2154
  var maxValue = max !== null && max !== void 0 ? max : Number.POSITIVE_INFINITY;
@@ -2167,6 +2217,104 @@ var AutoLayoutService = /** @class */ (function () {
2167
2217
  return AutoLayoutService;
2168
2218
  }());
2169
2219
 
2220
+ var ZERO_POINT = { x: 0, y: 0 };
2221
+ var clonePoint = function (point) { return ({ x: point.x, y: point.y }); };
2222
+ var borderSideToNormal = function (side) {
2223
+ if (side === 'left')
2224
+ return { x: -1, y: 0 };
2225
+ if (side === 'right')
2226
+ return { x: 1, y: 0 };
2227
+ if (side === 'top')
2228
+ return { x: 0, y: -1 };
2229
+ return { x: 0, y: 1 };
2230
+ };
2231
+ var resolvePortGeometryPoints = function (port, attachMode) {
2232
+ var _a, _b, _c, _d, _e;
2233
+ var placementPoint = clonePoint((_a = port.placementPoint) !== null && _a !== void 0 ? _a : ZERO_POINT);
2234
+ var sharedLinkAttachPoint = clonePoint((_b = port.linkAttachPoint) !== null && _b !== void 0 ? _b : placementPoint);
2235
+ var effectiveLinkAttachPoint = clonePoint(attachMode === 'internal'
2236
+ ? (_c = port.internalLinkAttachPoint) !== null && _c !== void 0 ? _c : sharedLinkAttachPoint
2237
+ : (_d = port.externalLinkAttachPoint) !== null && _d !== void 0 ? _d : sharedLinkAttachPoint);
2238
+ var rotationPivot = clonePoint((_e = port.rotationPivot) !== null && _e !== void 0 ? _e : placementPoint);
2239
+ return {
2240
+ placementPoint: placementPoint,
2241
+ sharedLinkAttachPoint: sharedLinkAttachPoint,
2242
+ effectiveLinkAttachPoint: effectiveLinkAttachPoint,
2243
+ rotationPivot: rotationPivot,
2244
+ };
2245
+ };
2246
+ var resolvePortOrientationContext = function (options) {
2247
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
2248
+ var port = options.port, worldPlacement = options.worldPlacement, host = options.host, shapeRegistry = options.shapeRegistry, attachMode = options.attachMode;
2249
+ var portShape = port.shapeId ? shapeRegistry.get(port.shapeId) : undefined;
2250
+ var localRotation = ((_a = portShape === null || portShape === void 0 ? void 0 : portShape.baseRotation) !== null && _a !== void 0 ? _a : 0) +
2251
+ (typeof ((_b = port.style) === null || _b === void 0 ? void 0 : _b.rotation) === 'number' ? port.style.rotation : 0);
2252
+ var nodeAnchorPoint = port.anchorCenter && (portShape === null || portShape === void 0 ? void 0 : portShape.svgPath)
2253
+ ? {
2254
+ 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,
2255
+ 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,
2256
+ }
2257
+ : __assign({}, ZERO_POINT);
2258
+ if (port.moveMode !== 'border' || port.orientToHostBorder === false || !host) {
2259
+ return { localRotation: localRotation, rotation: 0, offset: __assign({}, ZERO_POINT), nodeAnchorPoint: nodeAnchorPoint };
2260
+ }
2261
+ var hostRect = {
2262
+ x: host.position.x,
2263
+ y: host.position.y,
2264
+ width: host.size.width,
2265
+ height: host.size.height,
2266
+ };
2267
+ var shape = shapeRegistry.get(host.shapeId);
2268
+ var side = (shape === null || shape === void 0 ? void 0 : shape.resolveBorderSide)
2269
+ ? shape.resolveBorderSide(worldPlacement, hostRect)
2270
+ : resolveBoundarySide(worldPlacement, hostRect, 'rect');
2271
+ var normal = (shape === null || shape === void 0 ? void 0 : shape.resolveBorderNormal)
2272
+ ? shape.resolveBorderNormal(worldPlacement, hostRect)
2273
+ : borderSideToNormal(side);
2274
+ var geometry = resolvePortGeometryPoints(port, attachMode);
2275
+ var hookContext = {
2276
+ side: side,
2277
+ normal: normal,
2278
+ hostRect: hostRect,
2279
+ attachMode: attachMode,
2280
+ effectiveLinkAttachPoint: geometry.effectiveLinkAttachPoint,
2281
+ placementPoint: geometry.placementPoint,
2282
+ rotationPivot: geometry.rotationPivot,
2283
+ portSize: port.size,
2284
+ };
2285
+ var hookResult = (_l = shape === null || shape === void 0 ? void 0 : shape.resolvePortBorderTransform) === null || _l === void 0 ? void 0 : _l.call(shape, hookContext);
2286
+ return {
2287
+ localRotation: localRotation,
2288
+ nodeAnchorPoint: nodeAnchorPoint,
2289
+ side: side,
2290
+ normal: normal,
2291
+ rotation: borderSideToInwardRotation(side) + ((_m = hookResult === null || hookResult === void 0 ? void 0 : hookResult.rotation) !== null && _m !== void 0 ? _m : 0),
2292
+ offset: (hookResult === null || hookResult === void 0 ? void 0 : hookResult.offset) ? clonePoint(hookResult.offset) : __assign({}, ZERO_POINT),
2293
+ };
2294
+ };
2295
+ var resolvePortWorldTransform = function (options) {
2296
+ var port = options.port, worldPlacement = options.worldPlacement, attachMode = options.attachMode, orientation = options.orientation;
2297
+ var geometry = resolvePortGeometryPoints(port, attachMode);
2298
+ var totalRotation = orientation.localRotation + orientation.rotation;
2299
+ var rotatedPlacement = rotatePoint({
2300
+ x: geometry.placementPoint.x - orientation.nodeAnchorPoint.x,
2301
+ y: geometry.placementPoint.y - orientation.nodeAnchorPoint.y,
2302
+ }, ZERO_POINT, totalRotation);
2303
+ var rotatedAttach = rotatePoint({
2304
+ x: geometry.effectiveLinkAttachPoint.x - orientation.nodeAnchorPoint.x,
2305
+ y: geometry.effectiveLinkAttachPoint.y - orientation.nodeAnchorPoint.y,
2306
+ }, ZERO_POINT, totalRotation);
2307
+ var nodePosition = {
2308
+ x: worldPlacement.x - rotatedPlacement.x + orientation.offset.x,
2309
+ y: worldPlacement.y - rotatedPlacement.y + orientation.offset.y,
2310
+ };
2311
+ var linkAttachWorld = {
2312
+ x: nodePosition.x + rotatedAttach.x,
2313
+ y: nodePosition.y + rotatedAttach.y,
2314
+ };
2315
+ return { nodePosition: nodePosition, linkAttachWorld: linkAttachWorld };
2316
+ };
2317
+
2170
2318
  var EDGE_TOLERANCE = 0.5;
2171
2319
  var LinkRoutingService = /** @class */ (function () {
2172
2320
  function LinkRoutingService(config) {
@@ -2191,8 +2339,9 @@ var LinkRoutingService = /** @class */ (function () {
2191
2339
  }
2192
2340
  if (updatedLinks.has(link.id))
2193
2341
  return;
2194
- var source = _this.model.getPortWorldPosition(link.sourcePortId);
2195
- var target = _this.model.getPortWorldPosition(link.targetPortId);
2342
+ var endpoints = _this.resolveLinkEndpoints(link);
2343
+ var source = endpoints.source;
2344
+ var target = endpoints.target;
2196
2345
  if (!source || !target)
2197
2346
  return;
2198
2347
  var points = _this.resolveLinkPointsForUpdate(link, source, target);
@@ -2209,8 +2358,9 @@ var LinkRoutingService = /** @class */ (function () {
2209
2358
  var _a;
2210
2359
  if (link.points.length > 0)
2211
2360
  return;
2212
- var source = _this.model.getPortWorldPosition(link.sourcePortId);
2213
- var target = _this.model.getPortWorldPosition(link.targetPortId);
2361
+ var endpoints = _this.resolveLinkEndpoints(link);
2362
+ var source = endpoints.source;
2363
+ var target = endpoints.target;
2214
2364
  if (!source || !target)
2215
2365
  return;
2216
2366
  var points = ((_a = link.routing) !== null && _a !== void 0 ? _a : 'auto') === 'manual'
@@ -2221,6 +2371,31 @@ var LinkRoutingService = /** @class */ (function () {
2221
2371
  });
2222
2372
  return patches;
2223
2373
  };
2374
+ LinkRoutingService.prototype.getPortLinkWorldPosition = function (portId, options) {
2375
+ var _a;
2376
+ var port = this.model.getPort(portId);
2377
+ if (!port)
2378
+ return null;
2379
+ var worldPlacement = this.model.getPortWorldPosition(portId);
2380
+ if (!worldPlacement)
2381
+ return null;
2382
+ var host = this.resolveHostForPort(portId);
2383
+ 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);
2384
+ var orientation = resolvePortOrientationContext({
2385
+ port: port.toData(),
2386
+ worldPlacement: worldPlacement,
2387
+ host: host,
2388
+ shapeRegistry: this.shapeRegistry,
2389
+ attachMode: attachMode,
2390
+ });
2391
+ var transformed = resolvePortWorldTransform({
2392
+ port: port.toData(),
2393
+ worldPlacement: worldPlacement,
2394
+ attachMode: attachMode,
2395
+ orientation: orientation,
2396
+ });
2397
+ return transformed.linkAttachWorld;
2398
+ };
2224
2399
  LinkRoutingService.prototype.computeAutoRoute = function (link, source, target) {
2225
2400
  var routed = this.router.route(source, target, this.buildRouteContext(link));
2226
2401
  if (!routed || routed.length < 2) {
@@ -2239,6 +2414,12 @@ var LinkRoutingService = /** @class */ (function () {
2239
2414
  }
2240
2415
  return this.computeAutoRoute(link, source, target);
2241
2416
  };
2417
+ LinkRoutingService.prototype.resolveLinkEndpoints = function (link) {
2418
+ return {
2419
+ source: this.getPortLinkWorldPosition(link.sourcePortId, { oppositePortId: link.targetPortId }),
2420
+ target: this.getPortLinkWorldPosition(link.targetPortId, { oppositePortId: link.sourcePortId }),
2421
+ };
2422
+ };
2242
2423
  LinkRoutingService.prototype.updateManualRoute = function (points, source, target) {
2243
2424
  if (points.length < 2) {
2244
2425
  return [__assign({}, source), __assign({}, target)];
@@ -2258,8 +2439,9 @@ var LinkRoutingService = /** @class */ (function () {
2258
2439
  var targetPort = this.model.getPort(link.targetPortId);
2259
2440
  var sourceElementId = sourcePort === null || sourcePort === void 0 ? void 0 : sourcePort.elementId;
2260
2441
  var targetElementId = targetPort === null || targetPort === void 0 ? void 0 : targetPort.elementId;
2261
- var sourcePosition = this.model.getPortWorldPosition(link.sourcePortId);
2262
- var targetPosition = this.model.getPortWorldPosition(link.targetPortId);
2442
+ var endpoints = this.resolveLinkEndpoints(link);
2443
+ var sourcePosition = endpoints.source;
2444
+ var targetPosition = endpoints.target;
2263
2445
  var sourceRect = sourceElementId ? this.getElementRect(sourceElementId) : null;
2264
2446
  var targetRect = targetElementId ? this.getElementRect(targetElementId) : null;
2265
2447
  var sourceEndpointGeometry = sourcePosition && sourceRect
@@ -2389,6 +2571,40 @@ var LinkRoutingService = /** @class */ (function () {
2389
2571
  height: element.size.height,
2390
2572
  };
2391
2573
  };
2574
+ LinkRoutingService.prototype.resolveHostForPort = function (portId) {
2575
+ var _a;
2576
+ var port = this.model.getPort(portId);
2577
+ if (!port)
2578
+ return null;
2579
+ var element = this.model.getElement(port.elementId);
2580
+ if (!element)
2581
+ return null;
2582
+ return {
2583
+ id: element.id,
2584
+ position: (_a = this.model.getElementWorldPosition(element.id)) !== null && _a !== void 0 ? _a : element.position,
2585
+ size: element.size,
2586
+ shapeId: element.shapeId,
2587
+ };
2588
+ };
2589
+ LinkRoutingService.prototype.resolveAttachModeForPorts = function (portId, oppositePortId) {
2590
+ var _a, _b;
2591
+ if (!oppositePortId)
2592
+ return 'external';
2593
+ var elementId = (_a = this.model.getPort(portId)) === null || _a === void 0 ? void 0 : _a.elementId;
2594
+ var oppositeElementId = (_b = this.model.getPort(oppositePortId)) === null || _b === void 0 ? void 0 : _b.elementId;
2595
+ if (!elementId || !oppositeElementId)
2596
+ return 'external';
2597
+ return this.hasAncestorRelation(elementId, oppositeElementId) ? 'internal' : 'external';
2598
+ };
2599
+ LinkRoutingService.prototype.hasAncestorRelation = function (sourceElementId, targetElementId) {
2600
+ if (sourceElementId === targetElementId)
2601
+ return false;
2602
+ var sourceChain = this.getAncestorChain(sourceElementId);
2603
+ if (sourceChain.includes(targetElementId))
2604
+ return true;
2605
+ var targetChain = this.getAncestorChain(targetElementId);
2606
+ return targetChain.includes(sourceElementId);
2607
+ };
2392
2608
  LinkRoutingService.prototype.getAncestorChain = function (elementId) {
2393
2609
  var _a;
2394
2610
  var chain = [];
@@ -2766,8 +2982,12 @@ var DiagramEngine = /** @class */ (function () {
2766
2982
  };
2767
2983
  DiagramEngine.prototype.addLink = function (link) {
2768
2984
  var _a;
2769
- var source = this.model.getPortWorldPosition(link.sourcePortId);
2770
- var target = this.model.getPortWorldPosition(link.targetPortId);
2985
+ var source = this.linkRoutingService.getPortLinkWorldPosition(link.sourcePortId, {
2986
+ oppositePortId: link.targetPortId,
2987
+ });
2988
+ var target = this.linkRoutingService.getPortLinkWorldPosition(link.targetPortId, {
2989
+ oppositePortId: link.sourcePortId,
2990
+ });
2771
2991
  var routing = (_a = link.routing) !== null && _a !== void 0 ? _a : 'auto';
2772
2992
  var points = link.points;
2773
2993
  if (source && target) {
@@ -2791,8 +3011,12 @@ var DiagramEngine = /** @class */ (function () {
2791
3011
  return;
2792
3012
  var update = { routing: mode };
2793
3013
  if (mode === 'auto') {
2794
- var source = this.model.getPortWorldPosition(link.sourcePortId);
2795
- var target = this.model.getPortWorldPosition(link.targetPortId);
3014
+ var source = this.linkRoutingService.getPortLinkWorldPosition(link.sourcePortId, {
3015
+ oppositePortId: link.targetPortId,
3016
+ });
3017
+ var target = this.linkRoutingService.getPortLinkWorldPosition(link.targetPortId, {
3018
+ oppositePortId: link.sourcePortId,
3019
+ });
2796
3020
  if (source && target) {
2797
3021
  update.points = this.computeAutoRoute(link, source, target);
2798
3022
  }
@@ -2826,8 +3050,12 @@ var DiagramEngine = /** @class */ (function () {
2826
3050
  var routing = (_a = link.routing) !== null && _a !== void 0 ? _a : 'auto';
2827
3051
  if (routing === 'manual' && !includeManual)
2828
3052
  return;
2829
- var source = _this.model.getPortWorldPosition(link.sourcePortId);
2830
- var target = _this.model.getPortWorldPosition(link.targetPortId);
3053
+ var source = _this.linkRoutingService.getPortLinkWorldPosition(link.sourcePortId, {
3054
+ oppositePortId: link.targetPortId,
3055
+ });
3056
+ var target = _this.linkRoutingService.getPortLinkWorldPosition(link.targetPortId, {
3057
+ oppositePortId: link.sourcePortId,
3058
+ });
2831
3059
  if (!source || !target)
2832
3060
  return;
2833
3061
  var points = _this.computeAutoRoute(link, source, target);
@@ -2851,8 +3079,10 @@ var DiagramEngine = /** @class */ (function () {
2851
3079
  this.emitChange(patches);
2852
3080
  };
2853
3081
  DiagramEngine.prototype.updateText = function (id, content) {
3082
+ var _this = this;
2854
3083
  var patches = this.commandQueue.run(createUpdateTextCommand(id, content), this.model);
2855
3084
  var text = this.model.getText(id);
3085
+ var layoutOwnerId = (text === null || text === void 0 ? void 0 : text.ownerId) && this.hasFlexibleLabelReservedSpace(text.ownerId) ? text.ownerId : null;
2856
3086
  if (text) {
2857
3087
  var resolved = this.resolveTextPresentation(text.toData());
2858
3088
  text.setSize(resolved.size);
@@ -2873,7 +3103,18 @@ var DiagramEngine = /** @class */ (function () {
2873
3103
  reason: 'content',
2874
3104
  });
2875
3105
  }
2876
- this.emitChange(patches);
3106
+ if (!layoutOwnerId) {
3107
+ this.emitChange(patches);
3108
+ return;
3109
+ }
3110
+ var allPatches = this.mutationPipeline.run({
3111
+ basePatches: patches,
3112
+ layoutSteps: [
3113
+ function () { return _this.applyLayoutForParent(layoutOwnerId); },
3114
+ 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); },
3115
+ ],
3116
+ });
3117
+ this.emitChange(allPatches);
2877
3118
  };
2878
3119
  DiagramEngine.prototype.moveTextTo = function (id, x, y) {
2879
3120
  var text = this.model.getText(id);
@@ -2976,6 +3217,9 @@ var DiagramEngine = /** @class */ (function () {
2976
3217
  DiagramEngine.prototype.getPortWorldPosition = function (id) {
2977
3218
  return this.model.getPortWorldPosition(id);
2978
3219
  };
3220
+ DiagramEngine.prototype.getPortLinkWorldPosition = function (id, options) {
3221
+ return this.linkRoutingService.getPortLinkWorldPosition(id, options);
3222
+ };
2979
3223
  DiagramEngine.prototype.getTextWorldPosition = function (id) {
2980
3224
  return this.model.getTextWorldPosition(id);
2981
3225
  };
@@ -3384,6 +3628,12 @@ var DiagramEngine = /** @class */ (function () {
3384
3628
  DiagramEngine.prototype.applyAllLayouts = function () {
3385
3629
  return this.autoLayoutService.applyAllLayouts();
3386
3630
  };
3631
+ DiagramEngine.prototype.hasFlexibleLabelReservedSpace = function (elementId) {
3632
+ var _a, _b, _c;
3633
+ var element = this.model.getElement(elementId);
3634
+ 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';
3635
+ return mode === 'flexible';
3636
+ };
3387
3637
  DiagramEngine.prototype.updateLinksForPorts = function (portIds) {
3388
3638
  return this.linkRoutingService.updateLinksForPorts(portIds);
3389
3639
  };
@@ -3760,7 +4010,8 @@ var KonvaNodeFactory = /** @class */ (function () {
3760
4010
  KonvaNodeFactory.prototype.createDrawNode = function (model, shape, config) {
3761
4011
  var _a, _b;
3762
4012
  var style = model.style;
3763
- var attrs = __assign(__assign({ id: model.id, x: model.position.x, y: model.position.y, name: config.name }, (style !== null && style !== void 0 ? style : {})), { __shapeDraw: true, __model: model, sceneFunc: function (ctx, node) {
4013
+ var _c = this.resolveShapeRotation(shape, style), resolvedStyle = _c.style, rotation = _c.rotation;
4014
+ var attrs = __assign(__assign({ id: model.id, x: model.position.x, y: model.position.y, name: config.name }, (resolvedStyle !== null && resolvedStyle !== void 0 ? resolvedStyle : {})), { __shapeDraw: true, __model: model, rotation: rotation, sceneFunc: function (ctx, node) {
3764
4015
  var _a, _b, _c;
3765
4016
  var resolvedModel = (_b = (node.getAttr ? node.getAttr('__model') : (_a = node.attrs) === null || _a === void 0 ? void 0 : _a.__model)) !== null && _b !== void 0 ? _b : model;
3766
4017
  (_c = shape.draw) === null || _c === void 0 ? void 0 : _c.call(shape, { ctx: ctx, model: resolvedModel });
@@ -3776,6 +4027,7 @@ var KonvaNodeFactory = /** @class */ (function () {
3776
4027
  KonvaNodeFactory.prototype.createSvgPathNode = function (model, shape, config) {
3777
4028
  var _a, _b, _c, _d, _e, _f, _g;
3778
4029
  var style = model.style;
4030
+ var _h = this.resolveShapeRotation(shape, style), resolvedStyle = _h.style, rotation = _h.rotation;
3779
4031
  var sizeUpdater = function (_a) {
3780
4032
  var _b, _c;
3781
4033
  var nextSize = _a.size, anchorCenter = _a.anchorCenter, updateOffsetX = _a.updateOffsetX, updateOffsetY = _a.updateOffsetY, getNodeAttr = _a.getNodeAttr;
@@ -3797,7 +4049,7 @@ var KonvaNodeFactory = /** @class */ (function () {
3797
4049
  return attrs;
3798
4050
  };
3799
4051
  var size = (_a = config.size) !== null && _a !== void 0 ? _a : { width: 0, height: 0 };
3800
- var node = new this.konva.Path(__assign(__assign({ id: model.id, x: model.position.x, y: model.position.y, data: shape.svgPath, name: config.name }, (style !== null && style !== void 0 ? style : {})), { shapeKind: 'svg-path', __autoOffsetX: true, __autoOffsetY: true }));
4052
+ var node = new this.konva.Path(__assign(__assign({ id: model.id, x: model.position.x, y: model.position.y, rotation: rotation, data: shape.svgPath, name: config.name }, (resolvedStyle !== null && resolvedStyle !== void 0 ? resolvedStyle : {})), { shapeKind: 'svg-path', __autoOffsetX: true, __autoOffsetY: true }));
3801
4053
  var rect = node.getClientRect ? node.getClientRect({ skipTransform: true }) : null;
3802
4054
  var baseWidth = (_d = (_c = (_b = shape.svgSize) === null || _b === void 0 ? void 0 : _b.width) !== null && _c !== void 0 ? _c : rect === null || rect === void 0 ? void 0 : rect.width) !== null && _d !== void 0 ? _d : size.width;
3803
4055
  var baseHeight = (_g = (_f = (_e = shape.svgSize) === null || _e === void 0 ? void 0 : _e.height) !== null && _f !== void 0 ? _f : rect === null || rect === void 0 ? void 0 : rect.height) !== null && _g !== void 0 ? _g : size.height;
@@ -3814,6 +4066,20 @@ var KonvaNodeFactory = /** @class */ (function () {
3814
4066
  }
3815
4067
  return node;
3816
4068
  };
4069
+ KonvaNodeFactory.prototype.resolveShapeRotation = function (shape, style) {
4070
+ var _a, _b;
4071
+ if (!style) {
4072
+ return {
4073
+ style: undefined,
4074
+ rotation: (_a = shape.baseRotation) !== null && _a !== void 0 ? _a : 0,
4075
+ };
4076
+ }
4077
+ var rotation = style.rotation, rest = __rest(style, ["rotation"]);
4078
+ return {
4079
+ style: rest,
4080
+ rotation: ((_b = shape.baseRotation) !== null && _b !== void 0 ? _b : 0) + (typeof rotation === 'number' ? rotation : 0),
4081
+ };
4082
+ };
3817
4083
  KonvaNodeFactory.prototype.applyShapeBehaviorAttrs = function (node, shape) {
3818
4084
  if (!node.setAttrs || !shape.sizeUpdater)
3819
4085
  return;
@@ -4014,7 +4280,7 @@ var KonvaRenderer = /** @class */ (function () {
4014
4280
  this.drawOverlays();
4015
4281
  };
4016
4282
  KonvaRenderer.prototype.renderPortPlaceholder = function (port, hostElement) {
4017
- var _a, _b, _c, _d;
4283
+ var _a, _b, _c, _d, _e, _f;
4018
4284
  var shapeId = port.shapeId;
4019
4285
  if (!this.tempPortNode || this.tempPortShapeId !== shapeId) {
4020
4286
  (_b = (_a = this.tempPortNode) === null || _a === void 0 ? void 0 : _a.destroy) === null || _b === void 0 ? void 0 : _b.call(_a);
@@ -4033,6 +4299,9 @@ var KonvaRenderer = /** @class */ (function () {
4033
4299
  }
4034
4300
  }
4035
4301
  if (this.tempPortNode) {
4302
+ this.updateSize(this.tempPortNode, (_e = port.size) !== null && _e !== void 0 ? _e : { width: 8, height: 8 }, {
4303
+ anchorCenter: (_f = port.anchorCenter) !== null && _f !== void 0 ? _f : true,
4304
+ });
4036
4305
  this.applyPortOrientation(this.tempPortNode, port, port.position, undefined, hostElement);
4037
4306
  }
4038
4307
  this.drawOverlays();
@@ -4292,7 +4561,7 @@ var KonvaRenderer = /** @class */ (function () {
4292
4561
  var _this = this;
4293
4562
  var ports = Array.from(model.ports.values());
4294
4563
  ports.forEach(function (port) {
4295
- var _a, _b, _c;
4564
+ var _a, _b, _c, _d, _e;
4296
4565
  var data = port.toData();
4297
4566
  var node = _this.portNodes.get(port.id);
4298
4567
  if (!node) {
@@ -4304,6 +4573,7 @@ var KonvaRenderer = /** @class */ (function () {
4304
4573
  node.setAttrs({ __model: data });
4305
4574
  }
4306
4575
  var position = (_c = model.getPortWorldPosition(port.id)) !== null && _c !== void 0 ? _c : port.position;
4576
+ _this.updateSize(node, (_d = data.size) !== null && _d !== void 0 ? _d : { width: 8, height: 8 }, { anchorCenter: (_e = data.anchorCenter) !== null && _e !== void 0 ? _e : true });
4307
4577
  _this.updatePosition(node, position);
4308
4578
  _this.applyPortOrientation(node, data, position, model);
4309
4579
  });
@@ -4398,27 +4668,22 @@ var KonvaRenderer = /** @class */ (function () {
4398
4668
  if (this.getNodeAttr(node, '__baseRotation') === undefined) {
4399
4669
  node.setAttrs({ __baseRotation: baseRotation });
4400
4670
  }
4401
- var orientedRotation = this.resolvePortBorderRotation(port, worldPosition, model, hostElementOverride);
4402
- node.setAttrs({ rotation: baseRotation + (orientedRotation !== null && orientedRotation !== void 0 ? orientedRotation : 0) });
4403
- };
4404
- KonvaRenderer.prototype.resolvePortBorderRotation = function (port, worldPosition, model, hostElementOverride) {
4405
- if (port.moveMode !== 'border' || port.orientToHostBorder === false) {
4406
- return null;
4407
- }
4408
4671
  var host = hostElementOverride !== null && hostElementOverride !== void 0 ? hostElementOverride : this.resolveHostElement(port.elementId, model);
4409
- if (!host)
4410
- return null;
4411
- var hostRect = {
4412
- x: host.position.x,
4413
- y: host.position.y,
4414
- width: host.size.width,
4415
- height: host.size.height,
4416
- };
4417
- var shape = this.shapeRegistry.get(host.shapeId);
4418
- var side = (shape === null || shape === void 0 ? void 0 : shape.resolveBorderSide)
4419
- ? shape.resolveBorderSide(worldPosition, hostRect)
4420
- : resolveBoundarySide(worldPosition, hostRect, 'rect');
4421
- return borderSideToInwardRotation(side);
4672
+ var orientation = resolvePortOrientationContext({
4673
+ port: port,
4674
+ worldPlacement: worldPosition,
4675
+ host: host,
4676
+ shapeRegistry: this.shapeRegistry,
4677
+ attachMode: 'external',
4678
+ });
4679
+ var transform = resolvePortWorldTransform({
4680
+ port: port,
4681
+ worldPlacement: worldPosition,
4682
+ attachMode: 'external',
4683
+ orientation: orientation,
4684
+ });
4685
+ this.updatePosition(node, transform.nodePosition);
4686
+ node.setAttrs({ rotation: baseRotation + orientation.rotation });
4422
4687
  };
4423
4688
  KonvaRenderer.prototype.resolveHostElement = function (elementId, model) {
4424
4689
  var _a;
@@ -4520,6 +4785,7 @@ var KonvaInteraction = /** @class */ (function () {
4520
4785
  if (config === void 0) { config = {}; }
4521
4786
  var _a, _b;
4522
4787
  this.linkDragContext = null;
4788
+ this.programmaticLinkSession = null;
4523
4789
  this.bound = false;
4524
4790
  this.handlers = [];
4525
4791
  this.windowHandlers = [];
@@ -4534,6 +4800,8 @@ var KonvaInteraction = /** @class */ (function () {
4534
4800
  this.textEditor = null;
4535
4801
  this.dragThreshold = 4;
4536
4802
  this.panSpeed = 0.5;
4803
+ this.occupiedVertexTolerance = 2;
4804
+ this.emittingElementLinkEnded = false;
4537
4805
  this.engine = engine;
4538
4806
  this.stage = config.stage;
4539
4807
  this.hitTester = (_a = config.hitTester) !== null && _a !== void 0 ? _a : new KonvaHitTester();
@@ -4554,6 +4822,121 @@ var KonvaInteraction = /** @class */ (function () {
4554
4822
  this.updateShapeHoverControl(this.lastPointerPosition);
4555
4823
  }
4556
4824
  };
4825
+ KonvaInteraction.prototype.startLinkFromPort = function (sourcePortId, pointer) {
4826
+ var _a, _b, _c;
4827
+ var sourceElementId = this.engine.getPortElementId(sourcePortId);
4828
+ if (!sourceElementId)
4829
+ return;
4830
+ var sourcePoint = (_a = this.engine.getPortLinkWorldPosition(sourcePortId)) !== null && _a !== void 0 ? _a : this.engine.getPortWorldPosition(sourcePortId);
4831
+ if (!sourcePoint)
4832
+ return;
4833
+ if (((_b = this.dragState) === null || _b === void 0 ? void 0 : _b.mode) === 'link-drag' || this.programmaticLinkSession) {
4834
+ this.cancelLink();
4835
+ }
4836
+ if (this.dragState &&
4837
+ this.dragState.mode !== 'shape-control-drag' &&
4838
+ this.dragState.mode !== 'link-drag') {
4839
+ return;
4840
+ }
4841
+ var start = __assign({}, sourcePoint);
4842
+ if (((_c = this.dragState) === null || _c === void 0 ? void 0 : _c.mode) === 'shape-control-drag') {
4843
+ this.programmaticLinkSession = {
4844
+ sourcePortId: sourcePortId,
4845
+ sourceElementId: sourceElementId,
4846
+ start: start,
4847
+ current: start,
4848
+ };
4849
+ }
4850
+ else {
4851
+ this.dragState = {
4852
+ mode: 'link-drag',
4853
+ sourcePortId: sourcePortId,
4854
+ sourceElementId: sourceElementId,
4855
+ start: start,
4856
+ current: start,
4857
+ isMulti: false,
4858
+ hasMoved: false,
4859
+ completionBehavior: 'explicit',
4860
+ };
4861
+ }
4862
+ this.linkDragContext = { sourcePortId: sourcePortId, sourceElementId: sourceElementId };
4863
+ this.engine.emitElementLinkStarted({ sourcePortId: sourcePortId, sourceElementId: sourceElementId, startWorld: __assign({}, start) });
4864
+ this.setCursor('crosshair');
4865
+ if (pointer) {
4866
+ this.updateLinkPreview(pointer);
4867
+ }
4868
+ };
4869
+ KonvaInteraction.prototype.updateLinkPreview = function (pointer) {
4870
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
4871
+ if (this.programmaticLinkSession) {
4872
+ this.programmaticLinkSession.current = __assign({}, pointer);
4873
+ }
4874
+ else if (((_a = this.dragState) === null || _a === void 0 ? void 0 : _a.mode) === 'link-drag') {
4875
+ this.dragState.current = __assign({}, pointer);
4876
+ this.dragState.hasMoved = true;
4877
+ }
4878
+ else {
4879
+ return;
4880
+ }
4881
+ 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);
4882
+ if (!sourcePortId)
4883
+ return;
4884
+ var source = this.resolveLinkPreviewSource(sourcePortId, pointer);
4885
+ if (source) {
4886
+ (_e = this.renderer) === null || _e === void 0 ? void 0 : _e.renderTempLink([source, pointer]);
4887
+ }
4888
+ var hit = this.resolveHit(pointer);
4889
+ if ((hit === null || hit === void 0 ? void 0 : hit.type) === 'element') {
4890
+ var placeholder = this.createPlaceholderPort(hit.id, pointer, sourcePortId);
4891
+ if (placeholder) {
4892
+ var hostElement = this.getElementById(hit.id);
4893
+ if (hostElement) {
4894
+ var hostWorld = (_f = this.engine.getElementWorldPosition(hit.id)) !== null && _f !== void 0 ? _f : hostElement.position;
4895
+ (_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 });
4896
+ }
4897
+ else {
4898
+ (_k = (_j = this.renderer) === null || _j === void 0 ? void 0 : _j.renderPortPlaceholder) === null || _k === void 0 ? void 0 : _k.call(_j, placeholder);
4899
+ }
4900
+ }
4901
+ return;
4902
+ }
4903
+ (_m = (_l = this.renderer) === null || _l === void 0 ? void 0 : _l.clearPortPlaceholder) === null || _m === void 0 ? void 0 : _m.call(_l);
4904
+ };
4905
+ KonvaInteraction.prototype.completeLinkToPort = function (targetPortId) {
4906
+ var _a, _b;
4907
+ var session = this.resolveActiveLinkSession();
4908
+ if (!session)
4909
+ return;
4910
+ var completion = this.tryCreateLinkToPort(session.sourcePortId, session.sourceElementId, targetPortId);
4911
+ this.finishLinkDragSession({
4912
+ sourcePortId: session.sourcePortId,
4913
+ sourceElementId: session.sourceElementId,
4914
+ createdLinkId: (_a = completion.createdLinkId) !== null && _a !== void 0 ? _a : undefined,
4915
+ targetPortId: completion.targetPortId,
4916
+ targetElementId: (_b = completion.targetElementId) !== null && _b !== void 0 ? _b : undefined,
4917
+ cancelled: completion.createdLinkId === null,
4918
+ fromProgrammatic: session.fromProgrammatic,
4919
+ });
4920
+ };
4921
+ KonvaInteraction.prototype.completeLinkToElement = function (targetElementId, pointer) {
4922
+ var _a, _b, _c;
4923
+ var session = this.resolveActiveLinkSession();
4924
+ if (!session)
4925
+ return;
4926
+ var completion = this.tryCreateLinkToElement(session.sourcePortId, session.sourceElementId, targetElementId, pointer);
4927
+ this.finishLinkDragSession({
4928
+ sourcePortId: session.sourcePortId,
4929
+ sourceElementId: session.sourceElementId,
4930
+ createdLinkId: (_a = completion.createdLinkId) !== null && _a !== void 0 ? _a : undefined,
4931
+ targetPortId: (_b = completion.targetPortId) !== null && _b !== void 0 ? _b : undefined,
4932
+ targetElementId: (_c = completion.targetElementId) !== null && _c !== void 0 ? _c : undefined,
4933
+ cancelled: completion.createdLinkId === null,
4934
+ fromProgrammatic: session.fromProgrammatic,
4935
+ });
4936
+ };
4937
+ KonvaInteraction.prototype.cancelLink = function () {
4938
+ this.cancelLinkDrag();
4939
+ };
4557
4940
  KonvaInteraction.prototype.buildPointerInfo = function (world, nativeEvent) {
4558
4941
  var evt = nativeEvent !== null && nativeEvent !== void 0 ? nativeEvent : undefined;
4559
4942
  var client = evt ? { x: evt.clientX, y: evt.clientY } : { x: world.x, y: world.y };
@@ -4681,6 +5064,7 @@ var KonvaInteraction = /** @class */ (function () {
4681
5064
  current: point,
4682
5065
  isMulti: isMulti,
4683
5066
  hasMoved: false,
5067
+ completionBehavior: 'hover-or-release',
4684
5068
  };
4685
5069
  _this.linkDragContext = { sourcePortId: hit.id, sourceElementId: elementId };
4686
5070
  _this.engine.emitElementLinkStarted({ sourcePortId: hit.id, sourceElementId: elementId, startWorld: __assign({}, point) });
@@ -4755,22 +5139,29 @@ var KonvaInteraction = /** @class */ (function () {
4755
5139
  }
4756
5140
  _this.clearActiveShapeHoverControl();
4757
5141
  if (_this.dragState.mode === 'shape-control-drag') {
4758
- var delta = { x: point.x - _this.dragState.start.x, y: point.y - _this.dragState.start.y };
5142
+ var dragState = _this.dragState;
5143
+ var delta = { x: point.x - dragState.start.x, y: point.y - dragState.start.y };
4759
5144
  var moved = Math.hypot(delta.x, delta.y) >= _this.dragThreshold;
4760
- if (!_this.dragState.hasMoved && moved) {
4761
- _this.dragState.hasMoved = true;
4762
- _this.emitShapeHoverControlInteraction('drag-start', _this.dragState.control, point, nativeEvent, {
4763
- sessionId: _this.dragState.sessionId,
4764
- startPointer: _this.dragState.startPointer,
5145
+ if (!dragState.hasMoved && moved) {
5146
+ dragState.hasMoved = true;
5147
+ _this.emitShapeHoverControlInteraction('drag-start', dragState.control, point, nativeEvent, {
5148
+ sessionId: dragState.sessionId,
5149
+ startPointer: dragState.startPointer,
4765
5150
  delta: delta,
4766
5151
  });
5152
+ if (_this.dragState !== dragState) {
5153
+ return;
5154
+ }
4767
5155
  }
4768
- if (_this.dragState.hasMoved) {
4769
- _this.emitShapeHoverControlInteraction('drag-move', _this.dragState.control, point, nativeEvent, {
4770
- sessionId: _this.dragState.sessionId,
4771
- startPointer: _this.dragState.startPointer,
5156
+ if (dragState.hasMoved) {
5157
+ _this.emitShapeHoverControlInteraction('drag-move', dragState.control, point, nativeEvent, {
5158
+ sessionId: dragState.sessionId,
5159
+ startPointer: dragState.startPointer,
4772
5160
  delta: delta,
4773
5161
  });
5162
+ if (_this.dragState !== dragState) {
5163
+ return;
5164
+ }
4774
5165
  }
4775
5166
  }
4776
5167
  else if (_this.dragState.mode === 'move') {
@@ -4808,12 +5199,14 @@ var KonvaInteraction = /** @class */ (function () {
4808
5199
  _this.dragState.hasMoved = _this.dragState.hasMoved || moved;
4809
5200
  _this.dragState.current = point;
4810
5201
  if (_this.dragState.hasMoved) {
4811
- var source = _this.engine.getPortWorldPosition(_this.dragState.sourcePortId);
5202
+ var hit = _this.resolveHit(point);
5203
+ var source = _this.resolveLinkPreviewSource(_this.dragState.sourcePortId, point, hit);
4812
5204
  if (source) {
4813
5205
  (_b = _this.renderer) === null || _b === void 0 ? void 0 : _b.renderTempLink([source, point]);
4814
5206
  }
4815
- var hit = _this.resolveHit(point);
4816
- if ((hit === null || hit === void 0 ? void 0 : hit.type) === 'port' && hit.id !== linkDrag.sourcePortId) {
5207
+ if (linkDrag.completionBehavior === 'hover-or-release' &&
5208
+ (hit === null || hit === void 0 ? void 0 : hit.type) === 'port' &&
5209
+ hit.id !== linkDrag.sourcePortId) {
4817
5210
  var completion = _this.tryCreateLinkToPort(linkDrag.sourcePortId, linkDrag.sourceElementId, hit.id);
4818
5211
  if (completion.createdLinkId) {
4819
5212
  var pointerInfo = _this.buildPointerInfo(point, nativeEvent);
@@ -4822,7 +5215,9 @@ var KonvaInteraction = /** @class */ (function () {
4822
5215
  elementId: linkDrag.sourceElementId,
4823
5216
  pointer: pointerInfo,
4824
5217
  });
4825
- _this.engine.emitElementLinkEnded({
5218
+ _this.dragState = null;
5219
+ _this.linkDragContext = null;
5220
+ _this.emitElementLinkEndedSafely({
4826
5221
  sourcePortId: linkDrag.sourcePortId,
4827
5222
  sourceElementId: linkDrag.sourceElementId,
4828
5223
  linkId: completion.createdLinkId,
@@ -4832,8 +5227,6 @@ var KonvaInteraction = /** @class */ (function () {
4832
5227
  });
4833
5228
  (_d = _this.renderer) === null || _d === void 0 ? void 0 : _d.clearTempLink();
4834
5229
  (_f = (_e = _this.renderer) === null || _e === void 0 ? void 0 : _e.clearPortPlaceholder) === null || _f === void 0 ? void 0 : _f.call(_e);
4835
- _this.dragState = null;
4836
- _this.linkDragContext = null;
4837
5230
  _this.setCursor('default');
4838
5231
  return;
4839
5232
  }
@@ -4924,6 +5317,7 @@ var KonvaInteraction = /** @class */ (function () {
4924
5317
  var pointerPoint = _this.getPointerPosition();
4925
5318
  if (((_a = _this.dragState) === null || _a === void 0 ? void 0 : _a.mode) === 'shape-control-drag') {
4926
5319
  var dragState = _this.dragState;
5320
+ _this.dragState = null;
4927
5321
  var point = pointerPoint !== null && pointerPoint !== void 0 ? pointerPoint : dragState.start;
4928
5322
  var delta = { x: point.x - dragState.start.x, y: point.y - dragState.start.y };
4929
5323
  var dragContext = {
@@ -4938,7 +5332,6 @@ var KonvaInteraction = /** @class */ (function () {
4938
5332
  _this.emitShapeHoverControlInteraction('click', dragState.control, point, nativeEvent);
4939
5333
  _this.emitLegacyShapeHoverControlActivation(dragState.control, point, nativeEvent);
4940
5334
  }
4941
- _this.dragState = null;
4942
5335
  if (pointerPoint) {
4943
5336
  _this.lastPointerPosition = __assign({}, pointerPoint);
4944
5337
  _this.updateShapeHoverControl(pointerPoint);
@@ -4951,46 +5344,45 @@ var KonvaInteraction = /** @class */ (function () {
4951
5344
  return;
4952
5345
  }
4953
5346
  if (((_b = _this.dragState) === null || _b === void 0 ? void 0 : _b.mode) === 'link-drag') {
5347
+ var linkState = _this.dragState;
4954
5348
  var point = pointerPoint;
4955
- var pointerInfo = _this.buildPointerInfo(point !== null && point !== void 0 ? point : _this.dragState.start, nativeEvent);
5349
+ var pointerInfo = _this.buildPointerInfo(point !== null && point !== void 0 ? point : linkState.start, nativeEvent);
4956
5350
  var sourcePortPayload = {
4957
- portId: _this.dragState.sourcePortId,
4958
- elementId: _this.dragState.sourceElementId,
5351
+ portId: linkState.sourcePortId,
5352
+ elementId: linkState.sourceElementId,
4959
5353
  pointer: pointerInfo,
4960
5354
  };
4961
5355
  _this.engine.emitPortMouseUp(sourcePortPayload);
4962
5356
  var createdLinkId = null;
4963
5357
  var targetPortId = null;
4964
5358
  var targetElementId = null;
4965
- if (!_this.dragState.hasMoved) {
4966
- _this.handleSelection({ id: _this.dragState.sourcePortId, type: 'port' }, _this.dragState.isMulti);
5359
+ if (!linkState.hasMoved) {
5360
+ _this.handleSelection({ id: linkState.sourcePortId, type: 'port' }, linkState.isMulti);
4967
5361
  }
4968
5362
  else {
4969
5363
  var hit = point ? _this.resolveHit(point) : null;
4970
- if (hit && hit.type === 'port' && hit.id !== _this.dragState.sourcePortId) {
4971
- var completion = _this.tryCreateLinkToPort(_this.dragState.sourcePortId, _this.dragState.sourceElementId, hit.id);
5364
+ if (linkState.completionBehavior === 'hover-or-release' &&
5365
+ hit &&
5366
+ hit.type === 'port' &&
5367
+ hit.id !== linkState.sourcePortId) {
5368
+ var completion = _this.tryCreateLinkToPort(linkState.sourcePortId, linkState.sourceElementId, hit.id);
4972
5369
  createdLinkId = completion.createdLinkId;
4973
5370
  targetPortId = completion.targetPortId;
4974
5371
  targetElementId = completion.targetElementId;
4975
5372
  }
4976
- else if (hit && hit.type === 'element' && point) {
5373
+ else if (linkState.completionBehavior === 'hover-or-release' && hit && hit.type === 'element' && point) {
4977
5374
  targetElementId = hit.id;
4978
- var createdPortId = _this.createPortForLink(hit.id, point, _this.dragState.sourcePortId);
4979
- if (createdPortId) {
4980
- targetPortId = createdPortId;
4981
- createdLinkId = createId();
4982
- _this.engine.addLink({
4983
- id: createdLinkId,
4984
- sourcePortId: _this.dragState.sourcePortId,
4985
- targetPortId: createdPortId,
4986
- points: [],
4987
- });
4988
- }
5375
+ var completion = _this.tryCreateLinkToElement(linkState.sourcePortId, linkState.sourceElementId, hit.id, point);
5376
+ targetPortId = completion.targetPortId;
5377
+ createdLinkId = completion.createdLinkId;
5378
+ targetElementId = completion.targetElementId;
4989
5379
  }
4990
5380
  }
4991
- _this.engine.emitElementLinkEnded({
4992
- sourcePortId: _this.dragState.sourcePortId,
4993
- sourceElementId: _this.dragState.sourceElementId,
5381
+ _this.dragState = null;
5382
+ _this.linkDragContext = null;
5383
+ _this.emitElementLinkEndedSafely({
5384
+ sourcePortId: linkState.sourcePortId,
5385
+ sourceElementId: linkState.sourceElementId,
4994
5386
  linkId: createdLinkId !== null && createdLinkId !== void 0 ? createdLinkId : undefined,
4995
5387
  targetPortId: targetPortId !== null && targetPortId !== void 0 ? targetPortId : undefined,
4996
5388
  targetElementId: targetElementId !== null && targetElementId !== void 0 ? targetElementId : undefined,
@@ -5224,7 +5616,7 @@ var KonvaInteraction = /** @class */ (function () {
5224
5616
  addHit(this.findElementHit(point));
5225
5617
  if (hits.length === 0)
5226
5618
  return null;
5227
- var priority = ['resize-handle', 'link-handle', 'shape-hover-control', 'port', 'link', 'text', 'element'];
5619
+ var priority = ['resize-handle', 'link-handle', 'port', 'shape-hover-control', 'link', 'text', 'element'];
5228
5620
  var _loop_1 = function (i) {
5229
5621
  var candidates = hits.filter(function (hit) { return hit.type === priority[i]; });
5230
5622
  if (candidates.length === 0)
@@ -5670,10 +6062,10 @@ var KonvaInteraction = /** @class */ (function () {
5670
6062
  for (var index = 0; index < controls.length; index += 1) {
5671
6063
  var control = controls[index];
5672
6064
  var targetHoverCandidate = control.visibilityTriggers.includes('target-hover')
5673
- ? this.resolveTargetHoverCandidate(point, transformed, ellipseMidPoints, control)
6065
+ ? this.resolveTargetHoverCandidate(point, transformed, ellipseMidPoints, control, elementId)
5674
6066
  : null;
5675
6067
  var elementHoverCandidate = control.visibilityTriggers.includes('element-hover')
5676
- ? this.resolveElementHoverCandidate(point, transformed, ellipseMidPoints, control)
6068
+ ? this.resolveElementHoverCandidate(point, transformed, ellipseMidPoints, control, elementId)
5677
6069
  : null;
5678
6070
  var candidate = targetHoverCandidate !== null && targetHoverCandidate !== void 0 ? targetHoverCandidate : elementHoverCandidate;
5679
6071
  if (!candidate)
@@ -5689,7 +6081,7 @@ var KonvaInteraction = /** @class */ (function () {
5689
6081
  }
5690
6082
  return null;
5691
6083
  };
5692
- KonvaInteraction.prototype.resolveTargetHoverCandidate = function (point, geometry, ellipseMidPoints, control) {
6084
+ KonvaInteraction.prototype.resolveTargetHoverCandidate = function (point, geometry, ellipseMidPoints, control, elementId) {
5693
6085
  if (control.targetKind === 'ellipse-midpoint') {
5694
6086
  var targets = this.resolveEligibleEllipseMidPoints(control, ellipseMidPoints);
5695
6087
  if (!targets.length || control.tolerance <= 0)
@@ -5710,7 +6102,7 @@ var KonvaInteraction = /** @class */ (function () {
5710
6102
  }
5711
6103
  if (!geometry)
5712
6104
  return null;
5713
- var indices = this.resolveEligibleTargetIndices(control, geometry);
6105
+ var indices = this.resolveEligibleTargetIndices(control, geometry, elementId);
5714
6106
  if (!indices.length || control.tolerance <= 0)
5715
6107
  return null;
5716
6108
  if (control.targetKind === 'vertex') {
@@ -5760,7 +6152,7 @@ var KonvaInteraction = /** @class */ (function () {
5760
6152
  }
5761
6153
  return best ? { targetIndex: best.targetIndex, target: best.target } : null;
5762
6154
  };
5763
- KonvaInteraction.prototype.resolveElementHoverCandidate = function (point, geometry, ellipseMidPoints, control) {
6155
+ KonvaInteraction.prototype.resolveElementHoverCandidate = function (point, geometry, ellipseMidPoints, control, elementId) {
5764
6156
  if (control.targetKind === 'ellipse-midpoint') {
5765
6157
  var targets = this.resolveEligibleEllipseMidPoints(control, ellipseMidPoints);
5766
6158
  if (!targets.length)
@@ -5779,7 +6171,7 @@ var KonvaInteraction = /** @class */ (function () {
5779
6171
  }
5780
6172
  if (!geometry)
5781
6173
  return null;
5782
- var indices = this.resolveEligibleTargetIndices(control, geometry);
6174
+ var indices = this.resolveEligibleTargetIndices(control, geometry, elementId);
5783
6175
  if (!indices.length)
5784
6176
  return null;
5785
6177
  if (control.targetKind === 'vertex') {
@@ -5823,17 +6215,46 @@ var KonvaInteraction = /** @class */ (function () {
5823
6215
  }
5824
6216
  return best ? { targetIndex: best.targetIndex, target: best.target } : null;
5825
6217
  };
5826
- KonvaInteraction.prototype.resolveEligibleTargetIndices = function (control, geometry) {
6218
+ KonvaInteraction.prototype.resolveEligibleTargetIndices = function (control, geometry, elementId) {
5827
6219
  var _a;
5828
6220
  var source = control.targetKind === 'vertex' ? geometry.vertices : geometry.edges;
5829
6221
  if (!source.length)
5830
6222
  return [];
6223
+ var occupiedVertexIndices = this.resolveOccupiedVertexIndices(elementId, geometry);
5831
6224
  if (control.allowAllTargets === true) {
5832
- return Array.from({ length: source.length }, function (_, index) { return index; });
6225
+ return Array.from({ length: source.length }, function (_, index) { return index; }).filter(function (index) {
6226
+ return control.targetKind === 'vertex' ? !occupiedVertexIndices.has(index) : true;
6227
+ });
5833
6228
  }
5834
6229
  if (!((_a = control.targetIndices) === null || _a === void 0 ? void 0 : _a.length))
5835
6230
  return [];
5836
- return control.targetIndices.filter(function (targetIndex) { return targetIndex >= 0 && targetIndex < source.length; });
6231
+ return control.targetIndices.filter(function (targetIndex) {
6232
+ return targetIndex >= 0 &&
6233
+ targetIndex < source.length &&
6234
+ (control.targetKind !== 'vertex' || !occupiedVertexIndices.has(targetIndex));
6235
+ });
6236
+ };
6237
+ KonvaInteraction.prototype.resolveOccupiedVertexIndices = function (elementId, geometry) {
6238
+ var _this = this;
6239
+ if (!geometry.vertices.length)
6240
+ return new Set();
6241
+ var ports = this.engine.getState().ports.filter(function (port) { return port.elementId === elementId; });
6242
+ if (!ports.length)
6243
+ return new Set();
6244
+ var tolerance = this.occupiedVertexTolerance;
6245
+ var occupied = new Set();
6246
+ ports.forEach(function (port) {
6247
+ var world = _this.engine.getPortWorldPosition(port.id);
6248
+ if (!world)
6249
+ return;
6250
+ geometry.vertices.forEach(function (vertex, index) {
6251
+ if (Math.abs(vertex.position.x - world.x) <= tolerance &&
6252
+ Math.abs(vertex.position.y - world.y) <= tolerance) {
6253
+ occupied.add(index);
6254
+ }
6255
+ });
6256
+ });
6257
+ return occupied;
5837
6258
  };
5838
6259
  KonvaInteraction.prototype.resolveEligibleEllipseMidPoints = function (control, targets) {
5839
6260
  var _a;
@@ -6277,6 +6698,64 @@ var KonvaInteraction = /** @class */ (function () {
6277
6698
  }
6278
6699
  return { x: elementPos.x + constrained.x, y: elementPos.y + constrained.y };
6279
6700
  };
6701
+ KonvaInteraction.prototype.resolveLinkPreviewSource = function (sourcePortId, pointer, hit) {
6702
+ var resolvedHit = hit !== null && hit !== void 0 ? hit : this.resolveHit(pointer);
6703
+ if ((resolvedHit === null || resolvedHit === void 0 ? void 0 : resolvedHit.type) === 'port' && resolvedHit.id !== sourcePortId) {
6704
+ return this.engine.getPortLinkWorldPosition(sourcePortId, { oppositePortId: resolvedHit.id });
6705
+ }
6706
+ return this.engine.getPortLinkWorldPosition(sourcePortId);
6707
+ };
6708
+ KonvaInteraction.prototype.resolveActiveLinkSession = function () {
6709
+ var _a;
6710
+ if (this.programmaticLinkSession) {
6711
+ return {
6712
+ sourcePortId: this.programmaticLinkSession.sourcePortId,
6713
+ sourceElementId: this.programmaticLinkSession.sourceElementId,
6714
+ fromProgrammatic: true,
6715
+ };
6716
+ }
6717
+ if (((_a = this.dragState) === null || _a === void 0 ? void 0 : _a.mode) === 'link-drag') {
6718
+ return {
6719
+ sourcePortId: this.dragState.sourcePortId,
6720
+ sourceElementId: this.dragState.sourceElementId,
6721
+ fromProgrammatic: false,
6722
+ };
6723
+ }
6724
+ return null;
6725
+ };
6726
+ KonvaInteraction.prototype.finishLinkDragSession = function (result) {
6727
+ var _a, _b, _c, _d;
6728
+ this.linkDragContext = null;
6729
+ if (result.fromProgrammatic) {
6730
+ this.programmaticLinkSession = null;
6731
+ }
6732
+ else if (((_a = this.dragState) === null || _a === void 0 ? void 0 : _a.mode) === 'link-drag') {
6733
+ this.dragState = null;
6734
+ }
6735
+ (_b = this.renderer) === null || _b === void 0 ? void 0 : _b.clearTempLink();
6736
+ (_d = (_c = this.renderer) === null || _c === void 0 ? void 0 : _c.clearPortPlaceholder) === null || _d === void 0 ? void 0 : _d.call(_c);
6737
+ this.clearActiveShapeHoverControl();
6738
+ this.setCursor('default');
6739
+ this.emitElementLinkEndedSafely({
6740
+ sourcePortId: result.sourcePortId,
6741
+ sourceElementId: result.sourceElementId,
6742
+ linkId: result.createdLinkId,
6743
+ targetPortId: result.targetPortId,
6744
+ targetElementId: result.targetElementId,
6745
+ cancelled: result.cancelled,
6746
+ });
6747
+ };
6748
+ KonvaInteraction.prototype.emitElementLinkEndedSafely = function (event) {
6749
+ if (this.emittingElementLinkEnded)
6750
+ return;
6751
+ this.emittingElementLinkEnded = true;
6752
+ try {
6753
+ this.engine.emitElementLinkEnded(event);
6754
+ }
6755
+ finally {
6756
+ this.emittingElementLinkEnded = false;
6757
+ }
6758
+ };
6280
6759
  KonvaInteraction.prototype.tryCreateLinkToPort = function (sourcePortId, sourceElementId, targetPortId) {
6281
6760
  var targetElementId = this.engine.getPortElementId(targetPortId);
6282
6761
  var cancelledByHost = targetElementId !== null &&
@@ -6300,6 +6779,33 @@ var KonvaInteraction = /** @class */ (function () {
6300
6779
  });
6301
6780
  return { createdLinkId: createdLinkId, targetPortId: targetPortId, targetElementId: targetElementId };
6302
6781
  };
6782
+ KonvaInteraction.prototype.tryCreateLinkToElement = function (sourcePortId, sourceElementId, targetElementId, worldPoint) {
6783
+ var targetPort = this.createPortForLink(targetElementId, worldPoint, sourcePortId);
6784
+ if (!targetPort) {
6785
+ return { createdLinkId: null, targetPortId: null, targetElementId: null };
6786
+ }
6787
+ var cancelledByHost = this.engine.emitElementLinkConnecting({
6788
+ sourcePortId: sourcePortId,
6789
+ sourceElementId: sourceElementId,
6790
+ targetPortId: targetPort.id,
6791
+ targetElementId: targetElementId,
6792
+ cancel: function () { },
6793
+ cancelled: false,
6794
+ });
6795
+ if (cancelledByHost) {
6796
+ return { createdLinkId: null, targetPortId: targetPort.id, targetElementId: targetElementId };
6797
+ }
6798
+ this.engine.addPortToElement(targetElementId, targetPort);
6799
+ this.engine.movePortTo(targetPort.id, worldPoint.x, worldPoint.y);
6800
+ var createdLinkId = createId();
6801
+ this.engine.addLink({
6802
+ id: createdLinkId,
6803
+ sourcePortId: sourcePortId,
6804
+ targetPortId: targetPort.id,
6805
+ points: [],
6806
+ });
6807
+ return { createdLinkId: createdLinkId, targetPortId: targetPort.id, targetElementId: targetElementId };
6808
+ };
6303
6809
  KonvaInteraction.prototype.createPortForLink = function (elementId, worldPoint, sourcePortId) {
6304
6810
  var _a, _b, _c, _d;
6305
6811
  var element = this.getElementById(elementId);
@@ -6314,9 +6820,8 @@ var KonvaInteraction = /** @class */ (function () {
6314
6820
  var destinationMoveMode = ((_b = element.portMovement) === null || _b === void 0 ? void 0 : _b.moveMode) && element.portMovement.moveMode !== 'anchors'
6315
6821
  ? element.portMovement.moveMode
6316
6822
  : undefined;
6317
- var portId = createId();
6318
- this.engine.addPortToElement(elementId, {
6319
- id: portId,
6823
+ return {
6824
+ id: createId(),
6320
6825
  elementId: elementId,
6321
6826
  position: relative,
6322
6827
  shapeId: sourcePort === null || sourcePort === void 0 ? void 0 : sourcePort.shapeId,
@@ -6325,9 +6830,12 @@ var KonvaInteraction = /** @class */ (function () {
6325
6830
  moveMode: destinationMoveMode !== null && destinationMoveMode !== void 0 ? destinationMoveMode : sourcePort === null || sourcePort === void 0 ? void 0 : sourcePort.moveMode,
6326
6831
  anchorCenter: (_c = sourcePort === null || sourcePort === void 0 ? void 0 : sourcePort.anchorCenter) !== null && _c !== void 0 ? _c : true,
6327
6832
  orientToHostBorder: (_d = sourcePort === null || sourcePort === void 0 ? void 0 : sourcePort.orientToHostBorder) !== null && _d !== void 0 ? _d : true,
6328
- });
6329
- this.engine.movePortTo(portId, worldPoint.x, worldPoint.y);
6330
- return portId;
6833
+ placementPoint: (sourcePort === null || sourcePort === void 0 ? void 0 : sourcePort.placementPoint) ? __assign({}, sourcePort.placementPoint) : undefined,
6834
+ linkAttachPoint: (sourcePort === null || sourcePort === void 0 ? void 0 : sourcePort.linkAttachPoint) ? __assign({}, sourcePort.linkAttachPoint) : undefined,
6835
+ externalLinkAttachPoint: (sourcePort === null || sourcePort === void 0 ? void 0 : sourcePort.externalLinkAttachPoint) ? __assign({}, sourcePort.externalLinkAttachPoint) : undefined,
6836
+ internalLinkAttachPoint: (sourcePort === null || sourcePort === void 0 ? void 0 : sourcePort.internalLinkAttachPoint) ? __assign({}, sourcePort.internalLinkAttachPoint) : undefined,
6837
+ rotationPivot: (sourcePort === null || sourcePort === void 0 ? void 0 : sourcePort.rotationPivot) ? __assign({}, sourcePort.rotationPivot) : undefined,
6838
+ };
6331
6839
  };
6332
6840
  KonvaInteraction.prototype.createPlaceholderPort = function (elementId, worldPoint, sourcePortId) {
6333
6841
  var _a, _b, _c;
@@ -6346,6 +6854,11 @@ var KonvaInteraction = /** @class */ (function () {
6346
6854
  moveMode: destinationMoveMode !== null && destinationMoveMode !== void 0 ? destinationMoveMode : sourcePort === null || sourcePort === void 0 ? void 0 : sourcePort.moveMode,
6347
6855
  anchorCenter: (_b = sourcePort === null || sourcePort === void 0 ? void 0 : sourcePort.anchorCenter) !== null && _b !== void 0 ? _b : true,
6348
6856
  orientToHostBorder: (_c = sourcePort === null || sourcePort === void 0 ? void 0 : sourcePort.orientToHostBorder) !== null && _c !== void 0 ? _c : true,
6857
+ placementPoint: (sourcePort === null || sourcePort === void 0 ? void 0 : sourcePort.placementPoint) ? __assign({}, sourcePort.placementPoint) : undefined,
6858
+ linkAttachPoint: (sourcePort === null || sourcePort === void 0 ? void 0 : sourcePort.linkAttachPoint) ? __assign({}, sourcePort.linkAttachPoint) : undefined,
6859
+ externalLinkAttachPoint: (sourcePort === null || sourcePort === void 0 ? void 0 : sourcePort.externalLinkAttachPoint) ? __assign({}, sourcePort.externalLinkAttachPoint) : undefined,
6860
+ internalLinkAttachPoint: (sourcePort === null || sourcePort === void 0 ? void 0 : sourcePort.internalLinkAttachPoint) ? __assign({}, sourcePort.internalLinkAttachPoint) : undefined,
6861
+ rotationPivot: (sourcePort === null || sourcePort === void 0 ? void 0 : sourcePort.rotationPivot) ? __assign({}, sourcePort.rotationPivot) : undefined,
6349
6862
  };
6350
6863
  };
6351
6864
  KonvaInteraction.prototype.getElementById = function (id) {
@@ -6389,47 +6902,77 @@ var KonvaInteraction = /** @class */ (function () {
6389
6902
  (_b = stageAny === null || stageAny === void 0 ? void 0 : stageAny.position) === null || _b === void 0 ? void 0 : _b.call(stageAny, this.pan);
6390
6903
  };
6391
6904
  KonvaInteraction.prototype.cancelLinkDrag = function () {
6392
- var _a, _b, _c, _d, _e, _f;
6905
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
6393
6906
  if (((_a = this.dragState) === null || _a === void 0 ? void 0 : _a.mode) === 'shape-control-drag') {
6394
- var point_1 = (_b = this.lastPointerPosition) !== null && _b !== void 0 ? _b : this.dragState.start;
6395
- if (this.dragState.hasMoved) {
6396
- this.emitShapeHoverControlInteraction('drag-end', this.dragState.control, point_1, undefined, {
6397
- sessionId: this.dragState.sessionId,
6398
- startPointer: this.dragState.startPointer,
6907
+ var dragState = this.dragState;
6908
+ var point_1 = (_b = this.lastPointerPosition) !== null && _b !== void 0 ? _b : dragState.start;
6909
+ this.dragState = null;
6910
+ if (dragState.hasMoved) {
6911
+ this.emitShapeHoverControlInteraction('drag-end', dragState.control, point_1, undefined, {
6912
+ sessionId: dragState.sessionId,
6913
+ startPointer: dragState.startPointer,
6399
6914
  delta: {
6400
- x: point_1.x - this.dragState.start.x,
6401
- y: point_1.y - this.dragState.start.y,
6915
+ x: point_1.x - dragState.start.x,
6916
+ y: point_1.y - dragState.start.y,
6402
6917
  },
6403
6918
  });
6404
6919
  }
6405
- this.dragState = null;
6920
+ if (this.programmaticLinkSession) {
6921
+ var session = this.programmaticLinkSession;
6922
+ this.programmaticLinkSession = null;
6923
+ this.linkDragContext = null;
6924
+ (_c = this.renderer) === null || _c === void 0 ? void 0 : _c.clearTempLink();
6925
+ (_e = (_d = this.renderer) === null || _d === void 0 ? void 0 : _d.clearPortPlaceholder) === null || _e === void 0 ? void 0 : _e.call(_d);
6926
+ this.emitElementLinkEndedSafely({
6927
+ sourcePortId: session.sourcePortId,
6928
+ sourceElementId: session.sourceElementId,
6929
+ cancelled: true,
6930
+ });
6931
+ }
6932
+ this.clearActiveShapeHoverControl();
6933
+ this.setCursor('default');
6934
+ return;
6935
+ }
6936
+ if (this.programmaticLinkSession) {
6937
+ var session = this.programmaticLinkSession;
6938
+ this.programmaticLinkSession = null;
6939
+ this.linkDragContext = null;
6940
+ (_f = this.renderer) === null || _f === void 0 ? void 0 : _f.clearTempLink();
6941
+ (_h = (_g = this.renderer) === null || _g === void 0 ? void 0 : _g.clearPortPlaceholder) === null || _h === void 0 ? void 0 : _h.call(_g);
6942
+ this.emitElementLinkEndedSafely({
6943
+ sourcePortId: session.sourcePortId,
6944
+ sourceElementId: session.sourceElementId,
6945
+ cancelled: true,
6946
+ });
6406
6947
  this.clearActiveShapeHoverControl();
6407
6948
  this.setCursor('default');
6408
6949
  return;
6409
6950
  }
6410
6951
  if (!this.dragState || this.dragState.mode !== 'link-drag') {
6411
6952
  if (this.linkDragContext) {
6412
- this.engine.emitElementLinkEnded(__assign(__assign({}, this.linkDragContext), { cancelled: true }));
6953
+ var context = this.linkDragContext;
6413
6954
  this.linkDragContext = null;
6955
+ this.emitElementLinkEndedSafely(__assign(__assign({}, context), { cancelled: true }));
6414
6956
  }
6415
6957
  return;
6416
6958
  }
6417
- var point = (_c = this.dragState.current) !== null && _c !== void 0 ? _c : this.dragState.start;
6959
+ var linkState = this.dragState;
6960
+ var point = (_j = linkState.current) !== null && _j !== void 0 ? _j : linkState.start;
6418
6961
  var pointerInfo = this.buildPointerInfo(point, null);
6419
6962
  this.engine.emitPortMouseUp({
6420
- portId: this.dragState.sourcePortId,
6421
- elementId: this.dragState.sourceElementId,
6963
+ portId: linkState.sourcePortId,
6964
+ elementId: linkState.sourceElementId,
6422
6965
  pointer: pointerInfo,
6423
6966
  });
6424
- this.engine.emitElementLinkEnded({
6425
- sourcePortId: this.dragState.sourcePortId,
6426
- sourceElementId: this.dragState.sourceElementId,
6967
+ this.dragState = null;
6968
+ this.linkDragContext = null;
6969
+ (_k = this.renderer) === null || _k === void 0 ? void 0 : _k.clearTempLink();
6970
+ (_m = (_l = this.renderer) === null || _l === void 0 ? void 0 : _l.clearPortPlaceholder) === null || _m === void 0 ? void 0 : _m.call(_l);
6971
+ this.emitElementLinkEndedSafely({
6972
+ sourcePortId: linkState.sourcePortId,
6973
+ sourceElementId: linkState.sourceElementId,
6427
6974
  cancelled: true,
6428
6975
  });
6429
- this.linkDragContext = null;
6430
- (_d = this.renderer) === null || _d === void 0 ? void 0 : _d.clearTempLink();
6431
- (_f = (_e = this.renderer) === null || _e === void 0 ? void 0 : _e.clearPortPlaceholder) === null || _f === void 0 ? void 0 : _f.call(_e);
6432
- this.dragState = null;
6433
6976
  this.clearActiveShapeHoverControl();
6434
6977
  this.setCursor('default');
6435
6978
  };
@@ -6653,6 +7196,15 @@ var normalizeVector = function (vector) {
6653
7196
  return { x: 0, y: -1 };
6654
7197
  return { x: vector.x / length, y: vector.y / length };
6655
7198
  };
7199
+ var sideToNormal = function (side) {
7200
+ if (side === 'left')
7201
+ return { x: -1, y: 0 };
7202
+ if (side === 'right')
7203
+ return { x: 1, y: 0 };
7204
+ if (side === 'top')
7205
+ return { x: 0, y: -1 };
7206
+ return { x: 0, y: 1 };
7207
+ };
6656
7208
  var resolveCardinalAnchors = function (rect) {
6657
7209
  var cx = rect.x + rect.width / 2;
6658
7210
  var cy = rect.y + rect.height / 2;
@@ -6732,9 +7284,15 @@ var BuiltInShape = /** @class */ (function () {
6732
7284
  BuiltInShape.prototype.resolveBorderSide = function (point, rect) {
6733
7285
  return resolveBoundarySide(point, rect, 'rect');
6734
7286
  };
7287
+ BuiltInShape.prototype.resolveBorderNormal = function (point, rect) {
7288
+ return sideToNormal(this.resolveBorderSide(point, rect));
7289
+ };
6735
7290
  BuiltInShape.prototype.resolvePortAnchors = function (_rect, _options) {
6736
7291
  return [];
6737
7292
  };
7293
+ BuiltInShape.prototype.resolvePortBorderTransform = function (_context) {
7294
+ return undefined;
7295
+ };
6738
7296
  BuiltInShape.prototype.resolveHoverGeometry = function (_rect) {
6739
7297
  return undefined;
6740
7298
  };
@@ -6964,6 +7522,78 @@ var getKonva = function () {
6964
7522
  var module = require('konva');
6965
7523
  return (_a = module.default) !== null && _a !== void 0 ? _a : module;
6966
7524
  };
7525
+ var createBounds = function () { return ({
7526
+ minX: Number.POSITIVE_INFINITY,
7527
+ minY: Number.POSITIVE_INFINITY,
7528
+ maxX: Number.NEGATIVE_INFINITY,
7529
+ maxY: Number.NEGATIVE_INFINITY,
7530
+ }); };
7531
+ var expandBounds = function (bounds, x, y) {
7532
+ if (x < bounds.minX)
7533
+ bounds.minX = x;
7534
+ if (y < bounds.minY)
7535
+ bounds.minY = y;
7536
+ if (x > bounds.maxX)
7537
+ bounds.maxX = x;
7538
+ if (y > bounds.maxY)
7539
+ bounds.maxY = y;
7540
+ };
7541
+ var includeRect = function (bounds, x, y, width, height) {
7542
+ var safeWidth = Math.max(0, width);
7543
+ var safeHeight = Math.max(0, height);
7544
+ expandBounds(bounds, x, y);
7545
+ expandBounds(bounds, x + safeWidth, y + safeHeight);
7546
+ };
7547
+ var hasBounds = function (bounds) {
7548
+ return Number.isFinite(bounds.minX) &&
7549
+ Number.isFinite(bounds.minY) &&
7550
+ Number.isFinite(bounds.maxX) &&
7551
+ Number.isFinite(bounds.maxY) &&
7552
+ bounds.maxX >= bounds.minX &&
7553
+ bounds.maxY >= bounds.minY;
7554
+ };
7555
+ var resolveStateWorldBounds = function (state) {
7556
+ var bounds = createBounds();
7557
+ state.elements.forEach(function (element) {
7558
+ includeRect(bounds, element.position.x, element.position.y, element.size.width, element.size.height);
7559
+ });
7560
+ state.ports.forEach(function (port) {
7561
+ var _a;
7562
+ var size = port.size;
7563
+ if (!size) {
7564
+ expandBounds(bounds, port.position.x, port.position.y);
7565
+ return;
7566
+ }
7567
+ var anchorCenter = (_a = port.anchorCenter) !== null && _a !== void 0 ? _a : true;
7568
+ var x = anchorCenter ? port.position.x - size.width / 2 : port.position.x;
7569
+ var y = anchorCenter ? port.position.y - size.height / 2 : port.position.y;
7570
+ includeRect(bounds, x, y, size.width, size.height);
7571
+ });
7572
+ state.links.forEach(function (link) {
7573
+ link.points.forEach(function (point) {
7574
+ expandBounds(bounds, point.x, point.y);
7575
+ });
7576
+ });
7577
+ state.texts.forEach(function (text) {
7578
+ var _a;
7579
+ var offset = (_a = text.displayOffset) !== null && _a !== void 0 ? _a : { x: 0, y: 0 };
7580
+ var position = { x: text.position.x + offset.x, y: text.position.y + offset.y };
7581
+ var clipSize = text.displayClipSize;
7582
+ var size = clipSize !== null && clipSize !== void 0 ? clipSize : text.size;
7583
+ if (size) {
7584
+ includeRect(bounds, position.x, position.y, size.width, size.height);
7585
+ return;
7586
+ }
7587
+ expandBounds(bounds, position.x, position.y);
7588
+ });
7589
+ return hasBounds(bounds) ? bounds : null;
7590
+ };
7591
+ var resolveFitToContentPadding = function (fitToContent) {
7592
+ if (typeof fitToContent === 'object' && typeof fitToContent.padding === 'number') {
7593
+ return Math.max(0, fitToContent.padding);
7594
+ }
7595
+ return 0;
7596
+ };
6967
7597
  var getNodeAttr = function (node, key) {
6968
7598
  if (node.getAttr) {
6969
7599
  return node.getAttr(key);
@@ -7002,7 +7632,13 @@ var registerSimpleShapes = function (registry, shapes, isPort) {
7002
7632
  : undefined,
7003
7633
  projectToBorder: function (point, rect) { return behavior.projectToBorder(point, rect); },
7004
7634
  resolveBorderSide: function (point, rect) { return behavior.resolveBorderSide(point, rect); },
7635
+ resolveBorderNormal: behavior.resolveBorderNormal
7636
+ ? function (point, rect) { return behavior.resolveBorderNormal(point, rect); }
7637
+ : undefined,
7005
7638
  resolvePortAnchors: function (rect, options) { return behavior.resolvePortAnchors(rect, options); },
7639
+ resolvePortBorderTransform: behavior.resolvePortBorderTransform
7640
+ ? function (context) { return behavior.resolvePortBorderTransform(context); }
7641
+ : undefined,
7006
7642
  resolveHoverGeometry: function (rect) { return behavior.resolveHoverGeometry(rect); },
7007
7643
  resolveEllipseMidPoints: function (rect) { return behavior.resolveEllipseMidPoints(rect); },
7008
7644
  createNode: function (model) {
@@ -7076,7 +7712,7 @@ var createDiagramEditor = function (config) {
7076
7712
  .filter(function (hit) { return Boolean(hit); });
7077
7713
  if (hits.length === 0)
7078
7714
  return { id: '', type: 'none' };
7079
- var priority = ['resize-handle', 'link-handle', 'shape-hover-control', 'port', 'link', 'text', 'element'];
7715
+ var priority = ['resize-handle', 'link-handle', 'port', 'shape-hover-control', 'link', 'text', 'element'];
7080
7716
  var _loop_1 = function (i) {
7081
7717
  var candidates = hits.filter(function (hit) { return hit.type === priority[i]; });
7082
7718
  if (candidates.length === 0)
@@ -7167,6 +7803,36 @@ var createDiagramEditor = function (config) {
7167
7803
  setSnapping: function (snapper) { return engine.setSnapping(snapper); },
7168
7804
  registerShape: function (shape) { return engine.registerShape(shape); },
7169
7805
  render: function () { return engine.render(); },
7806
+ startLinkFromPort: function (sourcePortId, pointer) { return interaction.startLinkFromPort(sourcePortId, pointer); },
7807
+ updateLinkPreview: function (pointer) { return interaction.updateLinkPreview(pointer); },
7808
+ completeLinkToPort: function (targetPortId) { return interaction.completeLinkToPort(targetPortId); },
7809
+ completeLinkToElement: function (targetElementId, pointer) { return interaction.completeLinkToElement(targetElementId, pointer); },
7810
+ cancelLink: function () { return interaction.cancelLink(); },
7811
+ exportImage: function (options) {
7812
+ engine.render();
7813
+ if (typeof stage.toDataURL !== 'function') {
7814
+ throw new Error('Diagram image export is not available on the current stage.');
7815
+ }
7816
+ if (!options) {
7817
+ return stage.toDataURL();
7818
+ }
7819
+ var fitToContent = options.fitToContent, baseOptions = __rest(options, ["fitToContent"]);
7820
+ if (!fitToContent) {
7821
+ return stage.toDataURL(baseOptions);
7822
+ }
7823
+ var padding = resolveFitToContentPadding(fitToContent);
7824
+ var worldBounds = resolveStateWorldBounds(engine.getState());
7825
+ if (!worldBounds) {
7826
+ return stage.toDataURL(baseOptions);
7827
+ }
7828
+ var viewport = engine.getViewport();
7829
+ var safeZoom = viewport.zoom === 0 ? 1 : viewport.zoom;
7830
+ var cropX = worldBounds.minX * safeZoom + viewport.pan.x - padding;
7831
+ var cropY = worldBounds.minY * safeZoom + viewport.pan.y - padding;
7832
+ var cropWidth = Math.max(1, (worldBounds.maxX - worldBounds.minX) * safeZoom + padding * 2);
7833
+ var cropHeight = Math.max(1, (worldBounds.maxY - worldBounds.minY) * safeZoom + padding * 2);
7834
+ return stage.toDataURL(__assign(__assign({}, baseOptions), { x: cropX, y: cropY, width: cropWidth, height: cropHeight }));
7835
+ },
7170
7836
  resize: function (width, height) {
7171
7837
  stage.width(width);
7172
7838
  stage.height(height);