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/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
  };
@@ -1927,6 +1937,7 @@ var AutoLayoutService = /** @class */ (function () {
1927
1937
  var childFitCrossAxis = (_e = layout.childFitCrossAxis) !== null && _e !== void 0 ? _e : 'none';
1928
1938
  var childFitMinSize = layout.childFitMinSize;
1929
1939
  var childFitMaxSize = layout.childFitMaxSize;
1940
+ var labelReservedTopLane = this.resolveLabelReservedTopLane(parentId, layout);
1930
1941
  var sorted = __spreadArray([], children, true).sort(function (a, b) {
1931
1942
  var aPos = axis === 'horizontal' ? a.position.x : a.position.y;
1932
1943
  var bPos = axis === 'horizontal' ? b.position.x : b.position.y;
@@ -1937,7 +1948,7 @@ var AutoLayoutService = /** @class */ (function () {
1937
1948
  var gapCount = Math.max(0, sorted.length - 1);
1938
1949
  var calculateFittedSizes = function (parentWidth, parentHeight) {
1939
1950
  var availableWidth = Math.max(0, parentWidth - padding.x * 2);
1940
- var availableHeight = Math.max(0, parentHeight - padding.y * 2);
1951
+ var availableHeight = Math.max(0, parentHeight - padding.y * 2 - labelReservedTopLane);
1941
1952
  var availableMain = axis === 'horizontal'
1942
1953
  ? Math.max(0, availableWidth - gap * gapCount)
1943
1954
  : Math.max(0, availableHeight - gap * gapCount);
@@ -1982,12 +1993,12 @@ var AutoLayoutService = /** @class */ (function () {
1982
1993
  if (axis === 'horizontal') {
1983
1994
  return {
1984
1995
  width: Math.max(parent.size.width, padding.x * 2 + totalWidth + gap * gapCount),
1985
- height: Math.max(parent.size.height, padding.y * 2 + maxHeight),
1996
+ height: Math.max(parent.size.height, padding.y * 2 + labelReservedTopLane + maxHeight),
1986
1997
  };
1987
1998
  }
1988
1999
  return {
1989
2000
  width: Math.max(parent.size.width, padding.x * 2 + maxWidth),
1990
- height: Math.max(parent.size.height, padding.y * 2 + totalHeight + gap * gapCount),
2001
+ height: Math.max(parent.size.height, padding.y * 2 + labelReservedTopLane + totalHeight + gap * gapCount),
1991
2002
  };
1992
2003
  };
1993
2004
  var fittedSizes = calculateFittedSizes(parent.size.width, parent.size.height);
@@ -1995,9 +2006,9 @@ var AutoLayoutService = /** @class */ (function () {
1995
2006
  fittedSizes = calculateFittedSizes(newParentWidth, newParentHeight);
1996
2007
  (_a = resolveParentSize(fittedSizes), newParentWidth = _a.width, newParentHeight = _a.height);
1997
2008
  var availableWidth = Math.max(0, newParentWidth - padding.x * 2);
1998
- var availableHeight = Math.max(0, newParentHeight - padding.y * 2);
2009
+ var availableHeight = Math.max(0, newParentHeight - padding.y * 2 - labelReservedTopLane);
1999
2010
  var cursorX = padding.x;
2000
- var cursorY = padding.y;
2011
+ var cursorY = padding.y + labelReservedTopLane;
2001
2012
  var desiredPositions = new Map();
2002
2013
  var desiredSizes = new Map();
2003
2014
  sorted.forEach(function (child, index) {
@@ -2005,10 +2016,10 @@ var AutoLayoutService = /** @class */ (function () {
2005
2016
  desiredSizes.set(child.id, fittedSize);
2006
2017
  if (axis === 'horizontal') {
2007
2018
  var y = align === 'start'
2008
- ? padding.y
2019
+ ? padding.y + labelReservedTopLane
2009
2020
  : align === 'end'
2010
2021
  ? newParentHeight - padding.y - fittedSize.height
2011
- : padding.y + Math.max(0, (availableHeight - fittedSize.height) / 2);
2022
+ : padding.y + labelReservedTopLane + Math.max(0, (availableHeight - fittedSize.height) / 2);
2012
2023
  desiredPositions.set(child.id, { x: cursorX, y: y });
2013
2024
  cursorX += fittedSize.width + (index < sorted.length - 1 ? gap : 0);
2014
2025
  }
@@ -2101,6 +2112,45 @@ var AutoLayoutService = /** @class */ (function () {
2101
2112
  y: (_c = padding.y) !== null && _c !== void 0 ? _c : 12,
2102
2113
  };
2103
2114
  };
2115
+ AutoLayoutService.prototype.resolveLabelReservedTopLane = function (parentId, layout) {
2116
+ var _a, _b, _c, _d;
2117
+ var policy = layout === null || layout === void 0 ? void 0 : layout.labelReservedSpace;
2118
+ if (!policy)
2119
+ return 0;
2120
+ var mode = (_a = policy.mode) !== null && _a !== void 0 ? _a : 'none';
2121
+ if (mode === 'none')
2122
+ return 0;
2123
+ if (((_b = policy.placement) !== null && _b !== void 0 ? _b : 'top') !== 'top')
2124
+ return 0;
2125
+ var minSize = Math.max(0, (_c = policy.minSize) !== null && _c !== void 0 ? _c : 0);
2126
+ var maxSize = typeof policy.maxSize === 'number' && Number.isFinite(policy.maxSize)
2127
+ ? Math.max(minSize, policy.maxSize)
2128
+ : Number.POSITIVE_INFINITY;
2129
+ var resolved = 0;
2130
+ if (mode === 'fixed') {
2131
+ resolved = Math.max(0, (_d = policy.size) !== null && _d !== void 0 ? _d : 0);
2132
+ }
2133
+ else {
2134
+ resolved = this.resolveFlexibleLabelLaneFromText(parentId);
2135
+ }
2136
+ return this.clampLayoutSize(resolved, minSize, maxSize);
2137
+ };
2138
+ AutoLayoutService.prototype.resolveFlexibleLabelLaneFromText = function (parentId) {
2139
+ var lane = 0;
2140
+ this.model.texts.forEach(function (text) {
2141
+ var _a, _b, _c;
2142
+ if (text.ownerId !== parentId)
2143
+ return;
2144
+ var offset = (_a = text.displayOffset) !== null && _a !== void 0 ? _a : { x: 0, y: 0 };
2145
+ var size = (_b = text.displayClipSize) !== null && _b !== void 0 ? _b : text.size;
2146
+ var height = (_c = size === null || size === void 0 ? void 0 : size.height) !== null && _c !== void 0 ? _c : 0;
2147
+ var bottom = text.position.y + offset.y + height;
2148
+ if (bottom > lane) {
2149
+ lane = bottom;
2150
+ }
2151
+ });
2152
+ return Math.max(0, lane);
2153
+ };
2104
2154
  AutoLayoutService.prototype.clampLayoutSize = function (value, min, max) {
2105
2155
  var minValue = min !== null && min !== void 0 ? min : 0;
2106
2156
  var maxValue = max !== null && max !== void 0 ? max : Number.POSITIVE_INFINITY;
@@ -2169,6 +2219,104 @@ var AutoLayoutService = /** @class */ (function () {
2169
2219
  return AutoLayoutService;
2170
2220
  }());
2171
2221
 
2222
+ var ZERO_POINT = { x: 0, y: 0 };
2223
+ var clonePoint = function (point) { return ({ x: point.x, y: point.y }); };
2224
+ var borderSideToNormal = function (side) {
2225
+ if (side === 'left')
2226
+ return { x: -1, y: 0 };
2227
+ if (side === 'right')
2228
+ return { x: 1, y: 0 };
2229
+ if (side === 'top')
2230
+ return { x: 0, y: -1 };
2231
+ return { x: 0, y: 1 };
2232
+ };
2233
+ var resolvePortGeometryPoints = function (port, attachMode) {
2234
+ var _a, _b, _c, _d, _e;
2235
+ var placementPoint = clonePoint((_a = port.placementPoint) !== null && _a !== void 0 ? _a : ZERO_POINT);
2236
+ var sharedLinkAttachPoint = clonePoint((_b = port.linkAttachPoint) !== null && _b !== void 0 ? _b : placementPoint);
2237
+ var effectiveLinkAttachPoint = clonePoint(attachMode === 'internal'
2238
+ ? (_c = port.internalLinkAttachPoint) !== null && _c !== void 0 ? _c : sharedLinkAttachPoint
2239
+ : (_d = port.externalLinkAttachPoint) !== null && _d !== void 0 ? _d : sharedLinkAttachPoint);
2240
+ var rotationPivot = clonePoint((_e = port.rotationPivot) !== null && _e !== void 0 ? _e : placementPoint);
2241
+ return {
2242
+ placementPoint: placementPoint,
2243
+ sharedLinkAttachPoint: sharedLinkAttachPoint,
2244
+ effectiveLinkAttachPoint: effectiveLinkAttachPoint,
2245
+ rotationPivot: rotationPivot,
2246
+ };
2247
+ };
2248
+ var resolvePortOrientationContext = function (options) {
2249
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
2250
+ var port = options.port, worldPlacement = options.worldPlacement, host = options.host, shapeRegistry = options.shapeRegistry, attachMode = options.attachMode;
2251
+ var portShape = port.shapeId ? shapeRegistry.get(port.shapeId) : undefined;
2252
+ var localRotation = ((_a = portShape === null || portShape === void 0 ? void 0 : portShape.baseRotation) !== null && _a !== void 0 ? _a : 0) +
2253
+ (typeof ((_b = port.style) === null || _b === void 0 ? void 0 : _b.rotation) === 'number' ? port.style.rotation : 0);
2254
+ var nodeAnchorPoint = port.anchorCenter && (portShape === null || portShape === void 0 ? void 0 : portShape.svgPath)
2255
+ ? {
2256
+ 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,
2257
+ 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,
2258
+ }
2259
+ : __assign({}, ZERO_POINT);
2260
+ if (port.moveMode !== 'border' || port.orientToHostBorder === false || !host) {
2261
+ return { localRotation: localRotation, rotation: 0, offset: __assign({}, ZERO_POINT), nodeAnchorPoint: nodeAnchorPoint };
2262
+ }
2263
+ var hostRect = {
2264
+ x: host.position.x,
2265
+ y: host.position.y,
2266
+ width: host.size.width,
2267
+ height: host.size.height,
2268
+ };
2269
+ var shape = shapeRegistry.get(host.shapeId);
2270
+ var side = (shape === null || shape === void 0 ? void 0 : shape.resolveBorderSide)
2271
+ ? shape.resolveBorderSide(worldPlacement, hostRect)
2272
+ : resolveBoundarySide(worldPlacement, hostRect, 'rect');
2273
+ var normal = (shape === null || shape === void 0 ? void 0 : shape.resolveBorderNormal)
2274
+ ? shape.resolveBorderNormal(worldPlacement, hostRect)
2275
+ : borderSideToNormal(side);
2276
+ var geometry = resolvePortGeometryPoints(port, attachMode);
2277
+ var hookContext = {
2278
+ side: side,
2279
+ normal: normal,
2280
+ hostRect: hostRect,
2281
+ attachMode: attachMode,
2282
+ effectiveLinkAttachPoint: geometry.effectiveLinkAttachPoint,
2283
+ placementPoint: geometry.placementPoint,
2284
+ rotationPivot: geometry.rotationPivot,
2285
+ portSize: port.size,
2286
+ };
2287
+ var hookResult = (_l = shape === null || shape === void 0 ? void 0 : shape.resolvePortBorderTransform) === null || _l === void 0 ? void 0 : _l.call(shape, hookContext);
2288
+ return {
2289
+ localRotation: localRotation,
2290
+ nodeAnchorPoint: nodeAnchorPoint,
2291
+ side: side,
2292
+ normal: normal,
2293
+ rotation: borderSideToInwardRotation(side) + ((_m = hookResult === null || hookResult === void 0 ? void 0 : hookResult.rotation) !== null && _m !== void 0 ? _m : 0),
2294
+ offset: (hookResult === null || hookResult === void 0 ? void 0 : hookResult.offset) ? clonePoint(hookResult.offset) : __assign({}, ZERO_POINT),
2295
+ };
2296
+ };
2297
+ var resolvePortWorldTransform = function (options) {
2298
+ var port = options.port, worldPlacement = options.worldPlacement, attachMode = options.attachMode, orientation = options.orientation;
2299
+ var geometry = resolvePortGeometryPoints(port, attachMode);
2300
+ var totalRotation = orientation.localRotation + orientation.rotation;
2301
+ var rotatedPlacement = rotatePoint({
2302
+ x: geometry.placementPoint.x - orientation.nodeAnchorPoint.x,
2303
+ y: geometry.placementPoint.y - orientation.nodeAnchorPoint.y,
2304
+ }, ZERO_POINT, totalRotation);
2305
+ var rotatedAttach = rotatePoint({
2306
+ x: geometry.effectiveLinkAttachPoint.x - orientation.nodeAnchorPoint.x,
2307
+ y: geometry.effectiveLinkAttachPoint.y - orientation.nodeAnchorPoint.y,
2308
+ }, ZERO_POINT, totalRotation);
2309
+ var nodePosition = {
2310
+ x: worldPlacement.x - rotatedPlacement.x + orientation.offset.x,
2311
+ y: worldPlacement.y - rotatedPlacement.y + orientation.offset.y,
2312
+ };
2313
+ var linkAttachWorld = {
2314
+ x: nodePosition.x + rotatedAttach.x,
2315
+ y: nodePosition.y + rotatedAttach.y,
2316
+ };
2317
+ return { nodePosition: nodePosition, linkAttachWorld: linkAttachWorld };
2318
+ };
2319
+
2172
2320
  var EDGE_TOLERANCE = 0.5;
2173
2321
  var LinkRoutingService = /** @class */ (function () {
2174
2322
  function LinkRoutingService(config) {
@@ -2193,8 +2341,9 @@ var LinkRoutingService = /** @class */ (function () {
2193
2341
  }
2194
2342
  if (updatedLinks.has(link.id))
2195
2343
  return;
2196
- var source = _this.model.getPortWorldPosition(link.sourcePortId);
2197
- var target = _this.model.getPortWorldPosition(link.targetPortId);
2344
+ var endpoints = _this.resolveLinkEndpoints(link);
2345
+ var source = endpoints.source;
2346
+ var target = endpoints.target;
2198
2347
  if (!source || !target)
2199
2348
  return;
2200
2349
  var points = _this.resolveLinkPointsForUpdate(link, source, target);
@@ -2211,8 +2360,9 @@ var LinkRoutingService = /** @class */ (function () {
2211
2360
  var _a;
2212
2361
  if (link.points.length > 0)
2213
2362
  return;
2214
- var source = _this.model.getPortWorldPosition(link.sourcePortId);
2215
- var target = _this.model.getPortWorldPosition(link.targetPortId);
2363
+ var endpoints = _this.resolveLinkEndpoints(link);
2364
+ var source = endpoints.source;
2365
+ var target = endpoints.target;
2216
2366
  if (!source || !target)
2217
2367
  return;
2218
2368
  var points = ((_a = link.routing) !== null && _a !== void 0 ? _a : 'auto') === 'manual'
@@ -2223,6 +2373,31 @@ var LinkRoutingService = /** @class */ (function () {
2223
2373
  });
2224
2374
  return patches;
2225
2375
  };
2376
+ LinkRoutingService.prototype.getPortLinkWorldPosition = function (portId, options) {
2377
+ var _a;
2378
+ var port = this.model.getPort(portId);
2379
+ if (!port)
2380
+ return null;
2381
+ var worldPlacement = this.model.getPortWorldPosition(portId);
2382
+ if (!worldPlacement)
2383
+ return null;
2384
+ var host = this.resolveHostForPort(portId);
2385
+ 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);
2386
+ var orientation = resolvePortOrientationContext({
2387
+ port: port.toData(),
2388
+ worldPlacement: worldPlacement,
2389
+ host: host,
2390
+ shapeRegistry: this.shapeRegistry,
2391
+ attachMode: attachMode,
2392
+ });
2393
+ var transformed = resolvePortWorldTransform({
2394
+ port: port.toData(),
2395
+ worldPlacement: worldPlacement,
2396
+ attachMode: attachMode,
2397
+ orientation: orientation,
2398
+ });
2399
+ return transformed.linkAttachWorld;
2400
+ };
2226
2401
  LinkRoutingService.prototype.computeAutoRoute = function (link, source, target) {
2227
2402
  var routed = this.router.route(source, target, this.buildRouteContext(link));
2228
2403
  if (!routed || routed.length < 2) {
@@ -2241,6 +2416,12 @@ var LinkRoutingService = /** @class */ (function () {
2241
2416
  }
2242
2417
  return this.computeAutoRoute(link, source, target);
2243
2418
  };
2419
+ LinkRoutingService.prototype.resolveLinkEndpoints = function (link) {
2420
+ return {
2421
+ source: this.getPortLinkWorldPosition(link.sourcePortId, { oppositePortId: link.targetPortId }),
2422
+ target: this.getPortLinkWorldPosition(link.targetPortId, { oppositePortId: link.sourcePortId }),
2423
+ };
2424
+ };
2244
2425
  LinkRoutingService.prototype.updateManualRoute = function (points, source, target) {
2245
2426
  if (points.length < 2) {
2246
2427
  return [__assign({}, source), __assign({}, target)];
@@ -2260,8 +2441,9 @@ var LinkRoutingService = /** @class */ (function () {
2260
2441
  var targetPort = this.model.getPort(link.targetPortId);
2261
2442
  var sourceElementId = sourcePort === null || sourcePort === void 0 ? void 0 : sourcePort.elementId;
2262
2443
  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);
2444
+ var endpoints = this.resolveLinkEndpoints(link);
2445
+ var sourcePosition = endpoints.source;
2446
+ var targetPosition = endpoints.target;
2265
2447
  var sourceRect = sourceElementId ? this.getElementRect(sourceElementId) : null;
2266
2448
  var targetRect = targetElementId ? this.getElementRect(targetElementId) : null;
2267
2449
  var sourceEndpointGeometry = sourcePosition && sourceRect
@@ -2391,6 +2573,40 @@ var LinkRoutingService = /** @class */ (function () {
2391
2573
  height: element.size.height,
2392
2574
  };
2393
2575
  };
2576
+ LinkRoutingService.prototype.resolveHostForPort = function (portId) {
2577
+ var _a;
2578
+ var port = this.model.getPort(portId);
2579
+ if (!port)
2580
+ return null;
2581
+ var element = this.model.getElement(port.elementId);
2582
+ if (!element)
2583
+ return null;
2584
+ return {
2585
+ id: element.id,
2586
+ position: (_a = this.model.getElementWorldPosition(element.id)) !== null && _a !== void 0 ? _a : element.position,
2587
+ size: element.size,
2588
+ shapeId: element.shapeId,
2589
+ };
2590
+ };
2591
+ LinkRoutingService.prototype.resolveAttachModeForPorts = function (portId, oppositePortId) {
2592
+ var _a, _b;
2593
+ if (!oppositePortId)
2594
+ return 'external';
2595
+ var elementId = (_a = this.model.getPort(portId)) === null || _a === void 0 ? void 0 : _a.elementId;
2596
+ var oppositeElementId = (_b = this.model.getPort(oppositePortId)) === null || _b === void 0 ? void 0 : _b.elementId;
2597
+ if (!elementId || !oppositeElementId)
2598
+ return 'external';
2599
+ return this.hasAncestorRelation(elementId, oppositeElementId) ? 'internal' : 'external';
2600
+ };
2601
+ LinkRoutingService.prototype.hasAncestorRelation = function (sourceElementId, targetElementId) {
2602
+ if (sourceElementId === targetElementId)
2603
+ return false;
2604
+ var sourceChain = this.getAncestorChain(sourceElementId);
2605
+ if (sourceChain.includes(targetElementId))
2606
+ return true;
2607
+ var targetChain = this.getAncestorChain(targetElementId);
2608
+ return targetChain.includes(sourceElementId);
2609
+ };
2394
2610
  LinkRoutingService.prototype.getAncestorChain = function (elementId) {
2395
2611
  var _a;
2396
2612
  var chain = [];
@@ -2768,8 +2984,12 @@ var DiagramEngine = /** @class */ (function () {
2768
2984
  };
2769
2985
  DiagramEngine.prototype.addLink = function (link) {
2770
2986
  var _a;
2771
- var source = this.model.getPortWorldPosition(link.sourcePortId);
2772
- var target = this.model.getPortWorldPosition(link.targetPortId);
2987
+ var source = this.linkRoutingService.getPortLinkWorldPosition(link.sourcePortId, {
2988
+ oppositePortId: link.targetPortId,
2989
+ });
2990
+ var target = this.linkRoutingService.getPortLinkWorldPosition(link.targetPortId, {
2991
+ oppositePortId: link.sourcePortId,
2992
+ });
2773
2993
  var routing = (_a = link.routing) !== null && _a !== void 0 ? _a : 'auto';
2774
2994
  var points = link.points;
2775
2995
  if (source && target) {
@@ -2793,8 +3013,12 @@ var DiagramEngine = /** @class */ (function () {
2793
3013
  return;
2794
3014
  var update = { routing: mode };
2795
3015
  if (mode === 'auto') {
2796
- var source = this.model.getPortWorldPosition(link.sourcePortId);
2797
- var target = this.model.getPortWorldPosition(link.targetPortId);
3016
+ var source = this.linkRoutingService.getPortLinkWorldPosition(link.sourcePortId, {
3017
+ oppositePortId: link.targetPortId,
3018
+ });
3019
+ var target = this.linkRoutingService.getPortLinkWorldPosition(link.targetPortId, {
3020
+ oppositePortId: link.sourcePortId,
3021
+ });
2798
3022
  if (source && target) {
2799
3023
  update.points = this.computeAutoRoute(link, source, target);
2800
3024
  }
@@ -2828,8 +3052,12 @@ var DiagramEngine = /** @class */ (function () {
2828
3052
  var routing = (_a = link.routing) !== null && _a !== void 0 ? _a : 'auto';
2829
3053
  if (routing === 'manual' && !includeManual)
2830
3054
  return;
2831
- var source = _this.model.getPortWorldPosition(link.sourcePortId);
2832
- var target = _this.model.getPortWorldPosition(link.targetPortId);
3055
+ var source = _this.linkRoutingService.getPortLinkWorldPosition(link.sourcePortId, {
3056
+ oppositePortId: link.targetPortId,
3057
+ });
3058
+ var target = _this.linkRoutingService.getPortLinkWorldPosition(link.targetPortId, {
3059
+ oppositePortId: link.sourcePortId,
3060
+ });
2833
3061
  if (!source || !target)
2834
3062
  return;
2835
3063
  var points = _this.computeAutoRoute(link, source, target);
@@ -2853,8 +3081,10 @@ var DiagramEngine = /** @class */ (function () {
2853
3081
  this.emitChange(patches);
2854
3082
  };
2855
3083
  DiagramEngine.prototype.updateText = function (id, content) {
3084
+ var _this = this;
2856
3085
  var patches = this.commandQueue.run(createUpdateTextCommand(id, content), this.model);
2857
3086
  var text = this.model.getText(id);
3087
+ var layoutOwnerId = (text === null || text === void 0 ? void 0 : text.ownerId) && this.hasFlexibleLabelReservedSpace(text.ownerId) ? text.ownerId : null;
2858
3088
  if (text) {
2859
3089
  var resolved = this.resolveTextPresentation(text.toData());
2860
3090
  text.setSize(resolved.size);
@@ -2875,7 +3105,18 @@ var DiagramEngine = /** @class */ (function () {
2875
3105
  reason: 'content',
2876
3106
  });
2877
3107
  }
2878
- this.emitChange(patches);
3108
+ if (!layoutOwnerId) {
3109
+ this.emitChange(patches);
3110
+ return;
3111
+ }
3112
+ var allPatches = this.mutationPipeline.run({
3113
+ basePatches: patches,
3114
+ layoutSteps: [
3115
+ function () { return _this.applyLayoutForParent(layoutOwnerId); },
3116
+ 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); },
3117
+ ],
3118
+ });
3119
+ this.emitChange(allPatches);
2879
3120
  };
2880
3121
  DiagramEngine.prototype.moveTextTo = function (id, x, y) {
2881
3122
  var text = this.model.getText(id);
@@ -2978,6 +3219,9 @@ var DiagramEngine = /** @class */ (function () {
2978
3219
  DiagramEngine.prototype.getPortWorldPosition = function (id) {
2979
3220
  return this.model.getPortWorldPosition(id);
2980
3221
  };
3222
+ DiagramEngine.prototype.getPortLinkWorldPosition = function (id, options) {
3223
+ return this.linkRoutingService.getPortLinkWorldPosition(id, options);
3224
+ };
2981
3225
  DiagramEngine.prototype.getTextWorldPosition = function (id) {
2982
3226
  return this.model.getTextWorldPosition(id);
2983
3227
  };
@@ -3386,6 +3630,12 @@ var DiagramEngine = /** @class */ (function () {
3386
3630
  DiagramEngine.prototype.applyAllLayouts = function () {
3387
3631
  return this.autoLayoutService.applyAllLayouts();
3388
3632
  };
3633
+ DiagramEngine.prototype.hasFlexibleLabelReservedSpace = function (elementId) {
3634
+ var _a, _b, _c;
3635
+ var element = this.model.getElement(elementId);
3636
+ 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';
3637
+ return mode === 'flexible';
3638
+ };
3389
3639
  DiagramEngine.prototype.updateLinksForPorts = function (portIds) {
3390
3640
  return this.linkRoutingService.updateLinksForPorts(portIds);
3391
3641
  };
@@ -3762,7 +4012,8 @@ var KonvaNodeFactory = /** @class */ (function () {
3762
4012
  KonvaNodeFactory.prototype.createDrawNode = function (model, shape, config) {
3763
4013
  var _a, _b;
3764
4014
  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) {
4015
+ var _c = this.resolveShapeRotation(shape, style), resolvedStyle = _c.style, rotation = _c.rotation;
4016
+ 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
4017
  var _a, _b, _c;
3767
4018
  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
4019
  (_c = shape.draw) === null || _c === void 0 ? void 0 : _c.call(shape, { ctx: ctx, model: resolvedModel });
@@ -3778,6 +4029,7 @@ var KonvaNodeFactory = /** @class */ (function () {
3778
4029
  KonvaNodeFactory.prototype.createSvgPathNode = function (model, shape, config) {
3779
4030
  var _a, _b, _c, _d, _e, _f, _g;
3780
4031
  var style = model.style;
4032
+ var _h = this.resolveShapeRotation(shape, style), resolvedStyle = _h.style, rotation = _h.rotation;
3781
4033
  var sizeUpdater = function (_a) {
3782
4034
  var _b, _c;
3783
4035
  var nextSize = _a.size, anchorCenter = _a.anchorCenter, updateOffsetX = _a.updateOffsetX, updateOffsetY = _a.updateOffsetY, getNodeAttr = _a.getNodeAttr;
@@ -3799,7 +4051,7 @@ var KonvaNodeFactory = /** @class */ (function () {
3799
4051
  return attrs;
3800
4052
  };
3801
4053
  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 }));
4054
+ 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
4055
  var rect = node.getClientRect ? node.getClientRect({ skipTransform: true }) : null;
3804
4056
  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
4057
  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 +4068,20 @@ var KonvaNodeFactory = /** @class */ (function () {
3816
4068
  }
3817
4069
  return node;
3818
4070
  };
4071
+ KonvaNodeFactory.prototype.resolveShapeRotation = function (shape, style) {
4072
+ var _a, _b;
4073
+ if (!style) {
4074
+ return {
4075
+ style: undefined,
4076
+ rotation: (_a = shape.baseRotation) !== null && _a !== void 0 ? _a : 0,
4077
+ };
4078
+ }
4079
+ var rotation = style.rotation, rest = __rest(style, ["rotation"]);
4080
+ return {
4081
+ style: rest,
4082
+ rotation: ((_b = shape.baseRotation) !== null && _b !== void 0 ? _b : 0) + (typeof rotation === 'number' ? rotation : 0),
4083
+ };
4084
+ };
3819
4085
  KonvaNodeFactory.prototype.applyShapeBehaviorAttrs = function (node, shape) {
3820
4086
  if (!node.setAttrs || !shape.sizeUpdater)
3821
4087
  return;
@@ -4016,7 +4282,7 @@ var KonvaRenderer = /** @class */ (function () {
4016
4282
  this.drawOverlays();
4017
4283
  };
4018
4284
  KonvaRenderer.prototype.renderPortPlaceholder = function (port, hostElement) {
4019
- var _a, _b, _c, _d;
4285
+ var _a, _b, _c, _d, _e, _f;
4020
4286
  var shapeId = port.shapeId;
4021
4287
  if (!this.tempPortNode || this.tempPortShapeId !== shapeId) {
4022
4288
  (_b = (_a = this.tempPortNode) === null || _a === void 0 ? void 0 : _a.destroy) === null || _b === void 0 ? void 0 : _b.call(_a);
@@ -4035,6 +4301,9 @@ var KonvaRenderer = /** @class */ (function () {
4035
4301
  }
4036
4302
  }
4037
4303
  if (this.tempPortNode) {
4304
+ this.updateSize(this.tempPortNode, (_e = port.size) !== null && _e !== void 0 ? _e : { width: 8, height: 8 }, {
4305
+ anchorCenter: (_f = port.anchorCenter) !== null && _f !== void 0 ? _f : true,
4306
+ });
4038
4307
  this.applyPortOrientation(this.tempPortNode, port, port.position, undefined, hostElement);
4039
4308
  }
4040
4309
  this.drawOverlays();
@@ -4294,7 +4563,7 @@ var KonvaRenderer = /** @class */ (function () {
4294
4563
  var _this = this;
4295
4564
  var ports = Array.from(model.ports.values());
4296
4565
  ports.forEach(function (port) {
4297
- var _a, _b, _c;
4566
+ var _a, _b, _c, _d, _e;
4298
4567
  var data = port.toData();
4299
4568
  var node = _this.portNodes.get(port.id);
4300
4569
  if (!node) {
@@ -4306,6 +4575,7 @@ var KonvaRenderer = /** @class */ (function () {
4306
4575
  node.setAttrs({ __model: data });
4307
4576
  }
4308
4577
  var position = (_c = model.getPortWorldPosition(port.id)) !== null && _c !== void 0 ? _c : port.position;
4578
+ _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
4579
  _this.updatePosition(node, position);
4310
4580
  _this.applyPortOrientation(node, data, position, model);
4311
4581
  });
@@ -4400,27 +4670,22 @@ var KonvaRenderer = /** @class */ (function () {
4400
4670
  if (this.getNodeAttr(node, '__baseRotation') === undefined) {
4401
4671
  node.setAttrs({ __baseRotation: baseRotation });
4402
4672
  }
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
4673
  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);
4674
+ var orientation = resolvePortOrientationContext({
4675
+ port: port,
4676
+ worldPlacement: worldPosition,
4677
+ host: host,
4678
+ shapeRegistry: this.shapeRegistry,
4679
+ attachMode: 'external',
4680
+ });
4681
+ var transform = resolvePortWorldTransform({
4682
+ port: port,
4683
+ worldPlacement: worldPosition,
4684
+ attachMode: 'external',
4685
+ orientation: orientation,
4686
+ });
4687
+ this.updatePosition(node, transform.nodePosition);
4688
+ node.setAttrs({ rotation: baseRotation + orientation.rotation });
4424
4689
  };
4425
4690
  KonvaRenderer.prototype.resolveHostElement = function (elementId, model) {
4426
4691
  var _a;
@@ -4522,6 +4787,7 @@ var KonvaInteraction = /** @class */ (function () {
4522
4787
  if (config === void 0) { config = {}; }
4523
4788
  var _a, _b;
4524
4789
  this.linkDragContext = null;
4790
+ this.programmaticLinkSession = null;
4525
4791
  this.bound = false;
4526
4792
  this.handlers = [];
4527
4793
  this.windowHandlers = [];
@@ -4536,6 +4802,8 @@ var KonvaInteraction = /** @class */ (function () {
4536
4802
  this.textEditor = null;
4537
4803
  this.dragThreshold = 4;
4538
4804
  this.panSpeed = 0.5;
4805
+ this.occupiedVertexTolerance = 2;
4806
+ this.emittingElementLinkEnded = false;
4539
4807
  this.engine = engine;
4540
4808
  this.stage = config.stage;
4541
4809
  this.hitTester = (_a = config.hitTester) !== null && _a !== void 0 ? _a : new KonvaHitTester();
@@ -4556,6 +4824,121 @@ var KonvaInteraction = /** @class */ (function () {
4556
4824
  this.updateShapeHoverControl(this.lastPointerPosition);
4557
4825
  }
4558
4826
  };
4827
+ KonvaInteraction.prototype.startLinkFromPort = function (sourcePortId, pointer) {
4828
+ var _a, _b, _c;
4829
+ var sourceElementId = this.engine.getPortElementId(sourcePortId);
4830
+ if (!sourceElementId)
4831
+ return;
4832
+ var sourcePoint = (_a = this.engine.getPortLinkWorldPosition(sourcePortId)) !== null && _a !== void 0 ? _a : this.engine.getPortWorldPosition(sourcePortId);
4833
+ if (!sourcePoint)
4834
+ return;
4835
+ if (((_b = this.dragState) === null || _b === void 0 ? void 0 : _b.mode) === 'link-drag' || this.programmaticLinkSession) {
4836
+ this.cancelLink();
4837
+ }
4838
+ if (this.dragState &&
4839
+ this.dragState.mode !== 'shape-control-drag' &&
4840
+ this.dragState.mode !== 'link-drag') {
4841
+ return;
4842
+ }
4843
+ var start = __assign({}, sourcePoint);
4844
+ if (((_c = this.dragState) === null || _c === void 0 ? void 0 : _c.mode) === 'shape-control-drag') {
4845
+ this.programmaticLinkSession = {
4846
+ sourcePortId: sourcePortId,
4847
+ sourceElementId: sourceElementId,
4848
+ start: start,
4849
+ current: start,
4850
+ };
4851
+ }
4852
+ else {
4853
+ this.dragState = {
4854
+ mode: 'link-drag',
4855
+ sourcePortId: sourcePortId,
4856
+ sourceElementId: sourceElementId,
4857
+ start: start,
4858
+ current: start,
4859
+ isMulti: false,
4860
+ hasMoved: false,
4861
+ completionBehavior: 'explicit',
4862
+ };
4863
+ }
4864
+ this.linkDragContext = { sourcePortId: sourcePortId, sourceElementId: sourceElementId };
4865
+ this.engine.emitElementLinkStarted({ sourcePortId: sourcePortId, sourceElementId: sourceElementId, startWorld: __assign({}, start) });
4866
+ this.setCursor('crosshair');
4867
+ if (pointer) {
4868
+ this.updateLinkPreview(pointer);
4869
+ }
4870
+ };
4871
+ KonvaInteraction.prototype.updateLinkPreview = function (pointer) {
4872
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
4873
+ if (this.programmaticLinkSession) {
4874
+ this.programmaticLinkSession.current = __assign({}, pointer);
4875
+ }
4876
+ else if (((_a = this.dragState) === null || _a === void 0 ? void 0 : _a.mode) === 'link-drag') {
4877
+ this.dragState.current = __assign({}, pointer);
4878
+ this.dragState.hasMoved = true;
4879
+ }
4880
+ else {
4881
+ return;
4882
+ }
4883
+ 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);
4884
+ if (!sourcePortId)
4885
+ return;
4886
+ var source = this.resolveLinkPreviewSource(sourcePortId, pointer);
4887
+ if (source) {
4888
+ (_e = this.renderer) === null || _e === void 0 ? void 0 : _e.renderTempLink([source, pointer]);
4889
+ }
4890
+ var hit = this.resolveHit(pointer);
4891
+ if ((hit === null || hit === void 0 ? void 0 : hit.type) === 'element') {
4892
+ var placeholder = this.createPlaceholderPort(hit.id, pointer, sourcePortId);
4893
+ if (placeholder) {
4894
+ var hostElement = this.getElementById(hit.id);
4895
+ if (hostElement) {
4896
+ var hostWorld = (_f = this.engine.getElementWorldPosition(hit.id)) !== null && _f !== void 0 ? _f : hostElement.position;
4897
+ (_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 });
4898
+ }
4899
+ else {
4900
+ (_k = (_j = this.renderer) === null || _j === void 0 ? void 0 : _j.renderPortPlaceholder) === null || _k === void 0 ? void 0 : _k.call(_j, placeholder);
4901
+ }
4902
+ }
4903
+ return;
4904
+ }
4905
+ (_m = (_l = this.renderer) === null || _l === void 0 ? void 0 : _l.clearPortPlaceholder) === null || _m === void 0 ? void 0 : _m.call(_l);
4906
+ };
4907
+ KonvaInteraction.prototype.completeLinkToPort = function (targetPortId) {
4908
+ var _a, _b;
4909
+ var session = this.resolveActiveLinkSession();
4910
+ if (!session)
4911
+ return;
4912
+ var completion = this.tryCreateLinkToPort(session.sourcePortId, session.sourceElementId, targetPortId);
4913
+ this.finishLinkDragSession({
4914
+ sourcePortId: session.sourcePortId,
4915
+ sourceElementId: session.sourceElementId,
4916
+ createdLinkId: (_a = completion.createdLinkId) !== null && _a !== void 0 ? _a : undefined,
4917
+ targetPortId: completion.targetPortId,
4918
+ targetElementId: (_b = completion.targetElementId) !== null && _b !== void 0 ? _b : undefined,
4919
+ cancelled: completion.createdLinkId === null,
4920
+ fromProgrammatic: session.fromProgrammatic,
4921
+ });
4922
+ };
4923
+ KonvaInteraction.prototype.completeLinkToElement = function (targetElementId, pointer) {
4924
+ var _a, _b, _c;
4925
+ var session = this.resolveActiveLinkSession();
4926
+ if (!session)
4927
+ return;
4928
+ var completion = this.tryCreateLinkToElement(session.sourcePortId, session.sourceElementId, targetElementId, pointer);
4929
+ this.finishLinkDragSession({
4930
+ sourcePortId: session.sourcePortId,
4931
+ sourceElementId: session.sourceElementId,
4932
+ createdLinkId: (_a = completion.createdLinkId) !== null && _a !== void 0 ? _a : undefined,
4933
+ targetPortId: (_b = completion.targetPortId) !== null && _b !== void 0 ? _b : undefined,
4934
+ targetElementId: (_c = completion.targetElementId) !== null && _c !== void 0 ? _c : undefined,
4935
+ cancelled: completion.createdLinkId === null,
4936
+ fromProgrammatic: session.fromProgrammatic,
4937
+ });
4938
+ };
4939
+ KonvaInteraction.prototype.cancelLink = function () {
4940
+ this.cancelLinkDrag();
4941
+ };
4559
4942
  KonvaInteraction.prototype.buildPointerInfo = function (world, nativeEvent) {
4560
4943
  var evt = nativeEvent !== null && nativeEvent !== void 0 ? nativeEvent : undefined;
4561
4944
  var client = evt ? { x: evt.clientX, y: evt.clientY } : { x: world.x, y: world.y };
@@ -4683,6 +5066,7 @@ var KonvaInteraction = /** @class */ (function () {
4683
5066
  current: point,
4684
5067
  isMulti: isMulti,
4685
5068
  hasMoved: false,
5069
+ completionBehavior: 'hover-or-release',
4686
5070
  };
4687
5071
  _this.linkDragContext = { sourcePortId: hit.id, sourceElementId: elementId };
4688
5072
  _this.engine.emitElementLinkStarted({ sourcePortId: hit.id, sourceElementId: elementId, startWorld: __assign({}, point) });
@@ -4757,22 +5141,29 @@ var KonvaInteraction = /** @class */ (function () {
4757
5141
  }
4758
5142
  _this.clearActiveShapeHoverControl();
4759
5143
  if (_this.dragState.mode === 'shape-control-drag') {
4760
- var delta = { x: point.x - _this.dragState.start.x, y: point.y - _this.dragState.start.y };
5144
+ var dragState = _this.dragState;
5145
+ var delta = { x: point.x - dragState.start.x, y: point.y - dragState.start.y };
4761
5146
  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,
5147
+ if (!dragState.hasMoved && moved) {
5148
+ dragState.hasMoved = true;
5149
+ _this.emitShapeHoverControlInteraction('drag-start', dragState.control, point, nativeEvent, {
5150
+ sessionId: dragState.sessionId,
5151
+ startPointer: dragState.startPointer,
4767
5152
  delta: delta,
4768
5153
  });
5154
+ if (_this.dragState !== dragState) {
5155
+ return;
5156
+ }
4769
5157
  }
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,
5158
+ if (dragState.hasMoved) {
5159
+ _this.emitShapeHoverControlInteraction('drag-move', dragState.control, point, nativeEvent, {
5160
+ sessionId: dragState.sessionId,
5161
+ startPointer: dragState.startPointer,
4774
5162
  delta: delta,
4775
5163
  });
5164
+ if (_this.dragState !== dragState) {
5165
+ return;
5166
+ }
4776
5167
  }
4777
5168
  }
4778
5169
  else if (_this.dragState.mode === 'move') {
@@ -4810,12 +5201,14 @@ var KonvaInteraction = /** @class */ (function () {
4810
5201
  _this.dragState.hasMoved = _this.dragState.hasMoved || moved;
4811
5202
  _this.dragState.current = point;
4812
5203
  if (_this.dragState.hasMoved) {
4813
- var source = _this.engine.getPortWorldPosition(_this.dragState.sourcePortId);
5204
+ var hit = _this.resolveHit(point);
5205
+ var source = _this.resolveLinkPreviewSource(_this.dragState.sourcePortId, point, hit);
4814
5206
  if (source) {
4815
5207
  (_b = _this.renderer) === null || _b === void 0 ? void 0 : _b.renderTempLink([source, point]);
4816
5208
  }
4817
- var hit = _this.resolveHit(point);
4818
- if ((hit === null || hit === void 0 ? void 0 : hit.type) === 'port' && hit.id !== linkDrag.sourcePortId) {
5209
+ if (linkDrag.completionBehavior === 'hover-or-release' &&
5210
+ (hit === null || hit === void 0 ? void 0 : hit.type) === 'port' &&
5211
+ hit.id !== linkDrag.sourcePortId) {
4819
5212
  var completion = _this.tryCreateLinkToPort(linkDrag.sourcePortId, linkDrag.sourceElementId, hit.id);
4820
5213
  if (completion.createdLinkId) {
4821
5214
  var pointerInfo = _this.buildPointerInfo(point, nativeEvent);
@@ -4824,7 +5217,9 @@ var KonvaInteraction = /** @class */ (function () {
4824
5217
  elementId: linkDrag.sourceElementId,
4825
5218
  pointer: pointerInfo,
4826
5219
  });
4827
- _this.engine.emitElementLinkEnded({
5220
+ _this.dragState = null;
5221
+ _this.linkDragContext = null;
5222
+ _this.emitElementLinkEndedSafely({
4828
5223
  sourcePortId: linkDrag.sourcePortId,
4829
5224
  sourceElementId: linkDrag.sourceElementId,
4830
5225
  linkId: completion.createdLinkId,
@@ -4834,8 +5229,6 @@ var KonvaInteraction = /** @class */ (function () {
4834
5229
  });
4835
5230
  (_d = _this.renderer) === null || _d === void 0 ? void 0 : _d.clearTempLink();
4836
5231
  (_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
5232
  _this.setCursor('default');
4840
5233
  return;
4841
5234
  }
@@ -4926,6 +5319,7 @@ var KonvaInteraction = /** @class */ (function () {
4926
5319
  var pointerPoint = _this.getPointerPosition();
4927
5320
  if (((_a = _this.dragState) === null || _a === void 0 ? void 0 : _a.mode) === 'shape-control-drag') {
4928
5321
  var dragState = _this.dragState;
5322
+ _this.dragState = null;
4929
5323
  var point = pointerPoint !== null && pointerPoint !== void 0 ? pointerPoint : dragState.start;
4930
5324
  var delta = { x: point.x - dragState.start.x, y: point.y - dragState.start.y };
4931
5325
  var dragContext = {
@@ -4940,7 +5334,6 @@ var KonvaInteraction = /** @class */ (function () {
4940
5334
  _this.emitShapeHoverControlInteraction('click', dragState.control, point, nativeEvent);
4941
5335
  _this.emitLegacyShapeHoverControlActivation(dragState.control, point, nativeEvent);
4942
5336
  }
4943
- _this.dragState = null;
4944
5337
  if (pointerPoint) {
4945
5338
  _this.lastPointerPosition = __assign({}, pointerPoint);
4946
5339
  _this.updateShapeHoverControl(pointerPoint);
@@ -4953,46 +5346,45 @@ var KonvaInteraction = /** @class */ (function () {
4953
5346
  return;
4954
5347
  }
4955
5348
  if (((_b = _this.dragState) === null || _b === void 0 ? void 0 : _b.mode) === 'link-drag') {
5349
+ var linkState = _this.dragState;
4956
5350
  var point = pointerPoint;
4957
- var pointerInfo = _this.buildPointerInfo(point !== null && point !== void 0 ? point : _this.dragState.start, nativeEvent);
5351
+ var pointerInfo = _this.buildPointerInfo(point !== null && point !== void 0 ? point : linkState.start, nativeEvent);
4958
5352
  var sourcePortPayload = {
4959
- portId: _this.dragState.sourcePortId,
4960
- elementId: _this.dragState.sourceElementId,
5353
+ portId: linkState.sourcePortId,
5354
+ elementId: linkState.sourceElementId,
4961
5355
  pointer: pointerInfo,
4962
5356
  };
4963
5357
  _this.engine.emitPortMouseUp(sourcePortPayload);
4964
5358
  var createdLinkId = null;
4965
5359
  var targetPortId = null;
4966
5360
  var targetElementId = null;
4967
- if (!_this.dragState.hasMoved) {
4968
- _this.handleSelection({ id: _this.dragState.sourcePortId, type: 'port' }, _this.dragState.isMulti);
5361
+ if (!linkState.hasMoved) {
5362
+ _this.handleSelection({ id: linkState.sourcePortId, type: 'port' }, linkState.isMulti);
4969
5363
  }
4970
5364
  else {
4971
5365
  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);
5366
+ if (linkState.completionBehavior === 'hover-or-release' &&
5367
+ hit &&
5368
+ hit.type === 'port' &&
5369
+ hit.id !== linkState.sourcePortId) {
5370
+ var completion = _this.tryCreateLinkToPort(linkState.sourcePortId, linkState.sourceElementId, hit.id);
4974
5371
  createdLinkId = completion.createdLinkId;
4975
5372
  targetPortId = completion.targetPortId;
4976
5373
  targetElementId = completion.targetElementId;
4977
5374
  }
4978
- else if (hit && hit.type === 'element' && point) {
5375
+ else if (linkState.completionBehavior === 'hover-or-release' && hit && hit.type === 'element' && point) {
4979
5376
  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
- }
5377
+ var completion = _this.tryCreateLinkToElement(linkState.sourcePortId, linkState.sourceElementId, hit.id, point);
5378
+ targetPortId = completion.targetPortId;
5379
+ createdLinkId = completion.createdLinkId;
5380
+ targetElementId = completion.targetElementId;
4991
5381
  }
4992
5382
  }
4993
- _this.engine.emitElementLinkEnded({
4994
- sourcePortId: _this.dragState.sourcePortId,
4995
- sourceElementId: _this.dragState.sourceElementId,
5383
+ _this.dragState = null;
5384
+ _this.linkDragContext = null;
5385
+ _this.emitElementLinkEndedSafely({
5386
+ sourcePortId: linkState.sourcePortId,
5387
+ sourceElementId: linkState.sourceElementId,
4996
5388
  linkId: createdLinkId !== null && createdLinkId !== void 0 ? createdLinkId : undefined,
4997
5389
  targetPortId: targetPortId !== null && targetPortId !== void 0 ? targetPortId : undefined,
4998
5390
  targetElementId: targetElementId !== null && targetElementId !== void 0 ? targetElementId : undefined,
@@ -5226,7 +5618,7 @@ var KonvaInteraction = /** @class */ (function () {
5226
5618
  addHit(this.findElementHit(point));
5227
5619
  if (hits.length === 0)
5228
5620
  return null;
5229
- var priority = ['resize-handle', 'link-handle', 'shape-hover-control', 'port', 'link', 'text', 'element'];
5621
+ var priority = ['resize-handle', 'link-handle', 'port', 'shape-hover-control', 'link', 'text', 'element'];
5230
5622
  var _loop_1 = function (i) {
5231
5623
  var candidates = hits.filter(function (hit) { return hit.type === priority[i]; });
5232
5624
  if (candidates.length === 0)
@@ -5672,10 +6064,10 @@ var KonvaInteraction = /** @class */ (function () {
5672
6064
  for (var index = 0; index < controls.length; index += 1) {
5673
6065
  var control = controls[index];
5674
6066
  var targetHoverCandidate = control.visibilityTriggers.includes('target-hover')
5675
- ? this.resolveTargetHoverCandidate(point, transformed, ellipseMidPoints, control)
6067
+ ? this.resolveTargetHoverCandidate(point, transformed, ellipseMidPoints, control, elementId)
5676
6068
  : null;
5677
6069
  var elementHoverCandidate = control.visibilityTriggers.includes('element-hover')
5678
- ? this.resolveElementHoverCandidate(point, transformed, ellipseMidPoints, control)
6070
+ ? this.resolveElementHoverCandidate(point, transformed, ellipseMidPoints, control, elementId)
5679
6071
  : null;
5680
6072
  var candidate = targetHoverCandidate !== null && targetHoverCandidate !== void 0 ? targetHoverCandidate : elementHoverCandidate;
5681
6073
  if (!candidate)
@@ -5691,7 +6083,7 @@ var KonvaInteraction = /** @class */ (function () {
5691
6083
  }
5692
6084
  return null;
5693
6085
  };
5694
- KonvaInteraction.prototype.resolveTargetHoverCandidate = function (point, geometry, ellipseMidPoints, control) {
6086
+ KonvaInteraction.prototype.resolveTargetHoverCandidate = function (point, geometry, ellipseMidPoints, control, elementId) {
5695
6087
  if (control.targetKind === 'ellipse-midpoint') {
5696
6088
  var targets = this.resolveEligibleEllipseMidPoints(control, ellipseMidPoints);
5697
6089
  if (!targets.length || control.tolerance <= 0)
@@ -5712,7 +6104,7 @@ var KonvaInteraction = /** @class */ (function () {
5712
6104
  }
5713
6105
  if (!geometry)
5714
6106
  return null;
5715
- var indices = this.resolveEligibleTargetIndices(control, geometry);
6107
+ var indices = this.resolveEligibleTargetIndices(control, geometry, elementId);
5716
6108
  if (!indices.length || control.tolerance <= 0)
5717
6109
  return null;
5718
6110
  if (control.targetKind === 'vertex') {
@@ -5762,7 +6154,7 @@ var KonvaInteraction = /** @class */ (function () {
5762
6154
  }
5763
6155
  return best ? { targetIndex: best.targetIndex, target: best.target } : null;
5764
6156
  };
5765
- KonvaInteraction.prototype.resolveElementHoverCandidate = function (point, geometry, ellipseMidPoints, control) {
6157
+ KonvaInteraction.prototype.resolveElementHoverCandidate = function (point, geometry, ellipseMidPoints, control, elementId) {
5766
6158
  if (control.targetKind === 'ellipse-midpoint') {
5767
6159
  var targets = this.resolveEligibleEllipseMidPoints(control, ellipseMidPoints);
5768
6160
  if (!targets.length)
@@ -5781,7 +6173,7 @@ var KonvaInteraction = /** @class */ (function () {
5781
6173
  }
5782
6174
  if (!geometry)
5783
6175
  return null;
5784
- var indices = this.resolveEligibleTargetIndices(control, geometry);
6176
+ var indices = this.resolveEligibleTargetIndices(control, geometry, elementId);
5785
6177
  if (!indices.length)
5786
6178
  return null;
5787
6179
  if (control.targetKind === 'vertex') {
@@ -5825,17 +6217,46 @@ var KonvaInteraction = /** @class */ (function () {
5825
6217
  }
5826
6218
  return best ? { targetIndex: best.targetIndex, target: best.target } : null;
5827
6219
  };
5828
- KonvaInteraction.prototype.resolveEligibleTargetIndices = function (control, geometry) {
6220
+ KonvaInteraction.prototype.resolveEligibleTargetIndices = function (control, geometry, elementId) {
5829
6221
  var _a;
5830
6222
  var source = control.targetKind === 'vertex' ? geometry.vertices : geometry.edges;
5831
6223
  if (!source.length)
5832
6224
  return [];
6225
+ var occupiedVertexIndices = this.resolveOccupiedVertexIndices(elementId, geometry);
5833
6226
  if (control.allowAllTargets === true) {
5834
- return Array.from({ length: source.length }, function (_, index) { return index; });
6227
+ return Array.from({ length: source.length }, function (_, index) { return index; }).filter(function (index) {
6228
+ return control.targetKind === 'vertex' ? !occupiedVertexIndices.has(index) : true;
6229
+ });
5835
6230
  }
5836
6231
  if (!((_a = control.targetIndices) === null || _a === void 0 ? void 0 : _a.length))
5837
6232
  return [];
5838
- return control.targetIndices.filter(function (targetIndex) { return targetIndex >= 0 && targetIndex < source.length; });
6233
+ return control.targetIndices.filter(function (targetIndex) {
6234
+ return targetIndex >= 0 &&
6235
+ targetIndex < source.length &&
6236
+ (control.targetKind !== 'vertex' || !occupiedVertexIndices.has(targetIndex));
6237
+ });
6238
+ };
6239
+ KonvaInteraction.prototype.resolveOccupiedVertexIndices = function (elementId, geometry) {
6240
+ var _this = this;
6241
+ if (!geometry.vertices.length)
6242
+ return new Set();
6243
+ var ports = this.engine.getState().ports.filter(function (port) { return port.elementId === elementId; });
6244
+ if (!ports.length)
6245
+ return new Set();
6246
+ var tolerance = this.occupiedVertexTolerance;
6247
+ var occupied = new Set();
6248
+ ports.forEach(function (port) {
6249
+ var world = _this.engine.getPortWorldPosition(port.id);
6250
+ if (!world)
6251
+ return;
6252
+ geometry.vertices.forEach(function (vertex, index) {
6253
+ if (Math.abs(vertex.position.x - world.x) <= tolerance &&
6254
+ Math.abs(vertex.position.y - world.y) <= tolerance) {
6255
+ occupied.add(index);
6256
+ }
6257
+ });
6258
+ });
6259
+ return occupied;
5839
6260
  };
5840
6261
  KonvaInteraction.prototype.resolveEligibleEllipseMidPoints = function (control, targets) {
5841
6262
  var _a;
@@ -6279,6 +6700,64 @@ var KonvaInteraction = /** @class */ (function () {
6279
6700
  }
6280
6701
  return { x: elementPos.x + constrained.x, y: elementPos.y + constrained.y };
6281
6702
  };
6703
+ KonvaInteraction.prototype.resolveLinkPreviewSource = function (sourcePortId, pointer, hit) {
6704
+ var resolvedHit = hit !== null && hit !== void 0 ? hit : this.resolveHit(pointer);
6705
+ if ((resolvedHit === null || resolvedHit === void 0 ? void 0 : resolvedHit.type) === 'port' && resolvedHit.id !== sourcePortId) {
6706
+ return this.engine.getPortLinkWorldPosition(sourcePortId, { oppositePortId: resolvedHit.id });
6707
+ }
6708
+ return this.engine.getPortLinkWorldPosition(sourcePortId);
6709
+ };
6710
+ KonvaInteraction.prototype.resolveActiveLinkSession = function () {
6711
+ var _a;
6712
+ if (this.programmaticLinkSession) {
6713
+ return {
6714
+ sourcePortId: this.programmaticLinkSession.sourcePortId,
6715
+ sourceElementId: this.programmaticLinkSession.sourceElementId,
6716
+ fromProgrammatic: true,
6717
+ };
6718
+ }
6719
+ if (((_a = this.dragState) === null || _a === void 0 ? void 0 : _a.mode) === 'link-drag') {
6720
+ return {
6721
+ sourcePortId: this.dragState.sourcePortId,
6722
+ sourceElementId: this.dragState.sourceElementId,
6723
+ fromProgrammatic: false,
6724
+ };
6725
+ }
6726
+ return null;
6727
+ };
6728
+ KonvaInteraction.prototype.finishLinkDragSession = function (result) {
6729
+ var _a, _b, _c, _d;
6730
+ this.linkDragContext = null;
6731
+ if (result.fromProgrammatic) {
6732
+ this.programmaticLinkSession = null;
6733
+ }
6734
+ else if (((_a = this.dragState) === null || _a === void 0 ? void 0 : _a.mode) === 'link-drag') {
6735
+ this.dragState = null;
6736
+ }
6737
+ (_b = this.renderer) === null || _b === void 0 ? void 0 : _b.clearTempLink();
6738
+ (_d = (_c = this.renderer) === null || _c === void 0 ? void 0 : _c.clearPortPlaceholder) === null || _d === void 0 ? void 0 : _d.call(_c);
6739
+ this.clearActiveShapeHoverControl();
6740
+ this.setCursor('default');
6741
+ this.emitElementLinkEndedSafely({
6742
+ sourcePortId: result.sourcePortId,
6743
+ sourceElementId: result.sourceElementId,
6744
+ linkId: result.createdLinkId,
6745
+ targetPortId: result.targetPortId,
6746
+ targetElementId: result.targetElementId,
6747
+ cancelled: result.cancelled,
6748
+ });
6749
+ };
6750
+ KonvaInteraction.prototype.emitElementLinkEndedSafely = function (event) {
6751
+ if (this.emittingElementLinkEnded)
6752
+ return;
6753
+ this.emittingElementLinkEnded = true;
6754
+ try {
6755
+ this.engine.emitElementLinkEnded(event);
6756
+ }
6757
+ finally {
6758
+ this.emittingElementLinkEnded = false;
6759
+ }
6760
+ };
6282
6761
  KonvaInteraction.prototype.tryCreateLinkToPort = function (sourcePortId, sourceElementId, targetPortId) {
6283
6762
  var targetElementId = this.engine.getPortElementId(targetPortId);
6284
6763
  var cancelledByHost = targetElementId !== null &&
@@ -6302,6 +6781,33 @@ var KonvaInteraction = /** @class */ (function () {
6302
6781
  });
6303
6782
  return { createdLinkId: createdLinkId, targetPortId: targetPortId, targetElementId: targetElementId };
6304
6783
  };
6784
+ KonvaInteraction.prototype.tryCreateLinkToElement = function (sourcePortId, sourceElementId, targetElementId, worldPoint) {
6785
+ var targetPort = this.createPortForLink(targetElementId, worldPoint, sourcePortId);
6786
+ if (!targetPort) {
6787
+ return { createdLinkId: null, targetPortId: null, targetElementId: null };
6788
+ }
6789
+ var cancelledByHost = this.engine.emitElementLinkConnecting({
6790
+ sourcePortId: sourcePortId,
6791
+ sourceElementId: sourceElementId,
6792
+ targetPortId: targetPort.id,
6793
+ targetElementId: targetElementId,
6794
+ cancel: function () { },
6795
+ cancelled: false,
6796
+ });
6797
+ if (cancelledByHost) {
6798
+ return { createdLinkId: null, targetPortId: targetPort.id, targetElementId: targetElementId };
6799
+ }
6800
+ this.engine.addPortToElement(targetElementId, targetPort);
6801
+ this.engine.movePortTo(targetPort.id, worldPoint.x, worldPoint.y);
6802
+ var createdLinkId = createId();
6803
+ this.engine.addLink({
6804
+ id: createdLinkId,
6805
+ sourcePortId: sourcePortId,
6806
+ targetPortId: targetPort.id,
6807
+ points: [],
6808
+ });
6809
+ return { createdLinkId: createdLinkId, targetPortId: targetPort.id, targetElementId: targetElementId };
6810
+ };
6305
6811
  KonvaInteraction.prototype.createPortForLink = function (elementId, worldPoint, sourcePortId) {
6306
6812
  var _a, _b, _c, _d;
6307
6813
  var element = this.getElementById(elementId);
@@ -6316,9 +6822,8 @@ var KonvaInteraction = /** @class */ (function () {
6316
6822
  var destinationMoveMode = ((_b = element.portMovement) === null || _b === void 0 ? void 0 : _b.moveMode) && element.portMovement.moveMode !== 'anchors'
6317
6823
  ? element.portMovement.moveMode
6318
6824
  : undefined;
6319
- var portId = createId();
6320
- this.engine.addPortToElement(elementId, {
6321
- id: portId,
6825
+ return {
6826
+ id: createId(),
6322
6827
  elementId: elementId,
6323
6828
  position: relative,
6324
6829
  shapeId: sourcePort === null || sourcePort === void 0 ? void 0 : sourcePort.shapeId,
@@ -6327,9 +6832,12 @@ var KonvaInteraction = /** @class */ (function () {
6327
6832
  moveMode: destinationMoveMode !== null && destinationMoveMode !== void 0 ? destinationMoveMode : sourcePort === null || sourcePort === void 0 ? void 0 : sourcePort.moveMode,
6328
6833
  anchorCenter: (_c = sourcePort === null || sourcePort === void 0 ? void 0 : sourcePort.anchorCenter) !== null && _c !== void 0 ? _c : true,
6329
6834
  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;
6835
+ placementPoint: (sourcePort === null || sourcePort === void 0 ? void 0 : sourcePort.placementPoint) ? __assign({}, sourcePort.placementPoint) : undefined,
6836
+ linkAttachPoint: (sourcePort === null || sourcePort === void 0 ? void 0 : sourcePort.linkAttachPoint) ? __assign({}, sourcePort.linkAttachPoint) : undefined,
6837
+ externalLinkAttachPoint: (sourcePort === null || sourcePort === void 0 ? void 0 : sourcePort.externalLinkAttachPoint) ? __assign({}, sourcePort.externalLinkAttachPoint) : undefined,
6838
+ internalLinkAttachPoint: (sourcePort === null || sourcePort === void 0 ? void 0 : sourcePort.internalLinkAttachPoint) ? __assign({}, sourcePort.internalLinkAttachPoint) : undefined,
6839
+ rotationPivot: (sourcePort === null || sourcePort === void 0 ? void 0 : sourcePort.rotationPivot) ? __assign({}, sourcePort.rotationPivot) : undefined,
6840
+ };
6333
6841
  };
6334
6842
  KonvaInteraction.prototype.createPlaceholderPort = function (elementId, worldPoint, sourcePortId) {
6335
6843
  var _a, _b, _c;
@@ -6348,6 +6856,11 @@ var KonvaInteraction = /** @class */ (function () {
6348
6856
  moveMode: destinationMoveMode !== null && destinationMoveMode !== void 0 ? destinationMoveMode : sourcePort === null || sourcePort === void 0 ? void 0 : sourcePort.moveMode,
6349
6857
  anchorCenter: (_b = sourcePort === null || sourcePort === void 0 ? void 0 : sourcePort.anchorCenter) !== null && _b !== void 0 ? _b : true,
6350
6858
  orientToHostBorder: (_c = sourcePort === null || sourcePort === void 0 ? void 0 : sourcePort.orientToHostBorder) !== null && _c !== void 0 ? _c : true,
6859
+ placementPoint: (sourcePort === null || sourcePort === void 0 ? void 0 : sourcePort.placementPoint) ? __assign({}, sourcePort.placementPoint) : undefined,
6860
+ linkAttachPoint: (sourcePort === null || sourcePort === void 0 ? void 0 : sourcePort.linkAttachPoint) ? __assign({}, sourcePort.linkAttachPoint) : undefined,
6861
+ externalLinkAttachPoint: (sourcePort === null || sourcePort === void 0 ? void 0 : sourcePort.externalLinkAttachPoint) ? __assign({}, sourcePort.externalLinkAttachPoint) : undefined,
6862
+ internalLinkAttachPoint: (sourcePort === null || sourcePort === void 0 ? void 0 : sourcePort.internalLinkAttachPoint) ? __assign({}, sourcePort.internalLinkAttachPoint) : undefined,
6863
+ rotationPivot: (sourcePort === null || sourcePort === void 0 ? void 0 : sourcePort.rotationPivot) ? __assign({}, sourcePort.rotationPivot) : undefined,
6351
6864
  };
6352
6865
  };
6353
6866
  KonvaInteraction.prototype.getElementById = function (id) {
@@ -6391,47 +6904,77 @@ var KonvaInteraction = /** @class */ (function () {
6391
6904
  (_b = stageAny === null || stageAny === void 0 ? void 0 : stageAny.position) === null || _b === void 0 ? void 0 : _b.call(stageAny, this.pan);
6392
6905
  };
6393
6906
  KonvaInteraction.prototype.cancelLinkDrag = function () {
6394
- var _a, _b, _c, _d, _e, _f;
6907
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
6395
6908
  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,
6909
+ var dragState = this.dragState;
6910
+ var point_1 = (_b = this.lastPointerPosition) !== null && _b !== void 0 ? _b : dragState.start;
6911
+ this.dragState = null;
6912
+ if (dragState.hasMoved) {
6913
+ this.emitShapeHoverControlInteraction('drag-end', dragState.control, point_1, undefined, {
6914
+ sessionId: dragState.sessionId,
6915
+ startPointer: dragState.startPointer,
6401
6916
  delta: {
6402
- x: point_1.x - this.dragState.start.x,
6403
- y: point_1.y - this.dragState.start.y,
6917
+ x: point_1.x - dragState.start.x,
6918
+ y: point_1.y - dragState.start.y,
6404
6919
  },
6405
6920
  });
6406
6921
  }
6407
- this.dragState = null;
6922
+ if (this.programmaticLinkSession) {
6923
+ var session = this.programmaticLinkSession;
6924
+ this.programmaticLinkSession = null;
6925
+ this.linkDragContext = null;
6926
+ (_c = this.renderer) === null || _c === void 0 ? void 0 : _c.clearTempLink();
6927
+ (_e = (_d = this.renderer) === null || _d === void 0 ? void 0 : _d.clearPortPlaceholder) === null || _e === void 0 ? void 0 : _e.call(_d);
6928
+ this.emitElementLinkEndedSafely({
6929
+ sourcePortId: session.sourcePortId,
6930
+ sourceElementId: session.sourceElementId,
6931
+ cancelled: true,
6932
+ });
6933
+ }
6934
+ this.clearActiveShapeHoverControl();
6935
+ this.setCursor('default');
6936
+ return;
6937
+ }
6938
+ if (this.programmaticLinkSession) {
6939
+ var session = this.programmaticLinkSession;
6940
+ this.programmaticLinkSession = null;
6941
+ this.linkDragContext = null;
6942
+ (_f = this.renderer) === null || _f === void 0 ? void 0 : _f.clearTempLink();
6943
+ (_h = (_g = this.renderer) === null || _g === void 0 ? void 0 : _g.clearPortPlaceholder) === null || _h === void 0 ? void 0 : _h.call(_g);
6944
+ this.emitElementLinkEndedSafely({
6945
+ sourcePortId: session.sourcePortId,
6946
+ sourceElementId: session.sourceElementId,
6947
+ cancelled: true,
6948
+ });
6408
6949
  this.clearActiveShapeHoverControl();
6409
6950
  this.setCursor('default');
6410
6951
  return;
6411
6952
  }
6412
6953
  if (!this.dragState || this.dragState.mode !== 'link-drag') {
6413
6954
  if (this.linkDragContext) {
6414
- this.engine.emitElementLinkEnded(__assign(__assign({}, this.linkDragContext), { cancelled: true }));
6955
+ var context = this.linkDragContext;
6415
6956
  this.linkDragContext = null;
6957
+ this.emitElementLinkEndedSafely(__assign(__assign({}, context), { cancelled: true }));
6416
6958
  }
6417
6959
  return;
6418
6960
  }
6419
- var point = (_c = this.dragState.current) !== null && _c !== void 0 ? _c : this.dragState.start;
6961
+ var linkState = this.dragState;
6962
+ var point = (_j = linkState.current) !== null && _j !== void 0 ? _j : linkState.start;
6420
6963
  var pointerInfo = this.buildPointerInfo(point, null);
6421
6964
  this.engine.emitPortMouseUp({
6422
- portId: this.dragState.sourcePortId,
6423
- elementId: this.dragState.sourceElementId,
6965
+ portId: linkState.sourcePortId,
6966
+ elementId: linkState.sourceElementId,
6424
6967
  pointer: pointerInfo,
6425
6968
  });
6426
- this.engine.emitElementLinkEnded({
6427
- sourcePortId: this.dragState.sourcePortId,
6428
- sourceElementId: this.dragState.sourceElementId,
6969
+ this.dragState = null;
6970
+ this.linkDragContext = null;
6971
+ (_k = this.renderer) === null || _k === void 0 ? void 0 : _k.clearTempLink();
6972
+ (_m = (_l = this.renderer) === null || _l === void 0 ? void 0 : _l.clearPortPlaceholder) === null || _m === void 0 ? void 0 : _m.call(_l);
6973
+ this.emitElementLinkEndedSafely({
6974
+ sourcePortId: linkState.sourcePortId,
6975
+ sourceElementId: linkState.sourceElementId,
6429
6976
  cancelled: true,
6430
6977
  });
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
6978
  this.clearActiveShapeHoverControl();
6436
6979
  this.setCursor('default');
6437
6980
  };
@@ -6655,6 +7198,15 @@ var normalizeVector = function (vector) {
6655
7198
  return { x: 0, y: -1 };
6656
7199
  return { x: vector.x / length, y: vector.y / length };
6657
7200
  };
7201
+ var sideToNormal = function (side) {
7202
+ if (side === 'left')
7203
+ return { x: -1, y: 0 };
7204
+ if (side === 'right')
7205
+ return { x: 1, y: 0 };
7206
+ if (side === 'top')
7207
+ return { x: 0, y: -1 };
7208
+ return { x: 0, y: 1 };
7209
+ };
6658
7210
  var resolveCardinalAnchors = function (rect) {
6659
7211
  var cx = rect.x + rect.width / 2;
6660
7212
  var cy = rect.y + rect.height / 2;
@@ -6734,9 +7286,15 @@ var BuiltInShape = /** @class */ (function () {
6734
7286
  BuiltInShape.prototype.resolveBorderSide = function (point, rect) {
6735
7287
  return resolveBoundarySide(point, rect, 'rect');
6736
7288
  };
7289
+ BuiltInShape.prototype.resolveBorderNormal = function (point, rect) {
7290
+ return sideToNormal(this.resolveBorderSide(point, rect));
7291
+ };
6737
7292
  BuiltInShape.prototype.resolvePortAnchors = function (_rect, _options) {
6738
7293
  return [];
6739
7294
  };
7295
+ BuiltInShape.prototype.resolvePortBorderTransform = function (_context) {
7296
+ return undefined;
7297
+ };
6740
7298
  BuiltInShape.prototype.resolveHoverGeometry = function (_rect) {
6741
7299
  return undefined;
6742
7300
  };
@@ -6966,6 +7524,78 @@ var getKonva = function () {
6966
7524
  var module = require('konva');
6967
7525
  return (_a = module.default) !== null && _a !== void 0 ? _a : module;
6968
7526
  };
7527
+ var createBounds = function () { return ({
7528
+ minX: Number.POSITIVE_INFINITY,
7529
+ minY: Number.POSITIVE_INFINITY,
7530
+ maxX: Number.NEGATIVE_INFINITY,
7531
+ maxY: Number.NEGATIVE_INFINITY,
7532
+ }); };
7533
+ var expandBounds = function (bounds, x, y) {
7534
+ if (x < bounds.minX)
7535
+ bounds.minX = x;
7536
+ if (y < bounds.minY)
7537
+ bounds.minY = y;
7538
+ if (x > bounds.maxX)
7539
+ bounds.maxX = x;
7540
+ if (y > bounds.maxY)
7541
+ bounds.maxY = y;
7542
+ };
7543
+ var includeRect = function (bounds, x, y, width, height) {
7544
+ var safeWidth = Math.max(0, width);
7545
+ var safeHeight = Math.max(0, height);
7546
+ expandBounds(bounds, x, y);
7547
+ expandBounds(bounds, x + safeWidth, y + safeHeight);
7548
+ };
7549
+ var hasBounds = function (bounds) {
7550
+ return Number.isFinite(bounds.minX) &&
7551
+ Number.isFinite(bounds.minY) &&
7552
+ Number.isFinite(bounds.maxX) &&
7553
+ Number.isFinite(bounds.maxY) &&
7554
+ bounds.maxX >= bounds.minX &&
7555
+ bounds.maxY >= bounds.minY;
7556
+ };
7557
+ var resolveStateWorldBounds = function (state) {
7558
+ var bounds = createBounds();
7559
+ state.elements.forEach(function (element) {
7560
+ includeRect(bounds, element.position.x, element.position.y, element.size.width, element.size.height);
7561
+ });
7562
+ state.ports.forEach(function (port) {
7563
+ var _a;
7564
+ var size = port.size;
7565
+ if (!size) {
7566
+ expandBounds(bounds, port.position.x, port.position.y);
7567
+ return;
7568
+ }
7569
+ var anchorCenter = (_a = port.anchorCenter) !== null && _a !== void 0 ? _a : true;
7570
+ var x = anchorCenter ? port.position.x - size.width / 2 : port.position.x;
7571
+ var y = anchorCenter ? port.position.y - size.height / 2 : port.position.y;
7572
+ includeRect(bounds, x, y, size.width, size.height);
7573
+ });
7574
+ state.links.forEach(function (link) {
7575
+ link.points.forEach(function (point) {
7576
+ expandBounds(bounds, point.x, point.y);
7577
+ });
7578
+ });
7579
+ state.texts.forEach(function (text) {
7580
+ var _a;
7581
+ var offset = (_a = text.displayOffset) !== null && _a !== void 0 ? _a : { x: 0, y: 0 };
7582
+ var position = { x: text.position.x + offset.x, y: text.position.y + offset.y };
7583
+ var clipSize = text.displayClipSize;
7584
+ var size = clipSize !== null && clipSize !== void 0 ? clipSize : text.size;
7585
+ if (size) {
7586
+ includeRect(bounds, position.x, position.y, size.width, size.height);
7587
+ return;
7588
+ }
7589
+ expandBounds(bounds, position.x, position.y);
7590
+ });
7591
+ return hasBounds(bounds) ? bounds : null;
7592
+ };
7593
+ var resolveFitToContentPadding = function (fitToContent) {
7594
+ if (typeof fitToContent === 'object' && typeof fitToContent.padding === 'number') {
7595
+ return Math.max(0, fitToContent.padding);
7596
+ }
7597
+ return 0;
7598
+ };
6969
7599
  var getNodeAttr = function (node, key) {
6970
7600
  if (node.getAttr) {
6971
7601
  return node.getAttr(key);
@@ -7004,7 +7634,13 @@ var registerSimpleShapes = function (registry, shapes, isPort) {
7004
7634
  : undefined,
7005
7635
  projectToBorder: function (point, rect) { return behavior.projectToBorder(point, rect); },
7006
7636
  resolveBorderSide: function (point, rect) { return behavior.resolveBorderSide(point, rect); },
7637
+ resolveBorderNormal: behavior.resolveBorderNormal
7638
+ ? function (point, rect) { return behavior.resolveBorderNormal(point, rect); }
7639
+ : undefined,
7007
7640
  resolvePortAnchors: function (rect, options) { return behavior.resolvePortAnchors(rect, options); },
7641
+ resolvePortBorderTransform: behavior.resolvePortBorderTransform
7642
+ ? function (context) { return behavior.resolvePortBorderTransform(context); }
7643
+ : undefined,
7008
7644
  resolveHoverGeometry: function (rect) { return behavior.resolveHoverGeometry(rect); },
7009
7645
  resolveEllipseMidPoints: function (rect) { return behavior.resolveEllipseMidPoints(rect); },
7010
7646
  createNode: function (model) {
@@ -7078,7 +7714,7 @@ var createDiagramEditor = function (config) {
7078
7714
  .filter(function (hit) { return Boolean(hit); });
7079
7715
  if (hits.length === 0)
7080
7716
  return { id: '', type: 'none' };
7081
- var priority = ['resize-handle', 'link-handle', 'shape-hover-control', 'port', 'link', 'text', 'element'];
7717
+ var priority = ['resize-handle', 'link-handle', 'port', 'shape-hover-control', 'link', 'text', 'element'];
7082
7718
  var _loop_1 = function (i) {
7083
7719
  var candidates = hits.filter(function (hit) { return hit.type === priority[i]; });
7084
7720
  if (candidates.length === 0)
@@ -7169,6 +7805,36 @@ var createDiagramEditor = function (config) {
7169
7805
  setSnapping: function (snapper) { return engine.setSnapping(snapper); },
7170
7806
  registerShape: function (shape) { return engine.registerShape(shape); },
7171
7807
  render: function () { return engine.render(); },
7808
+ startLinkFromPort: function (sourcePortId, pointer) { return interaction.startLinkFromPort(sourcePortId, pointer); },
7809
+ updateLinkPreview: function (pointer) { return interaction.updateLinkPreview(pointer); },
7810
+ completeLinkToPort: function (targetPortId) { return interaction.completeLinkToPort(targetPortId); },
7811
+ completeLinkToElement: function (targetElementId, pointer) { return interaction.completeLinkToElement(targetElementId, pointer); },
7812
+ cancelLink: function () { return interaction.cancelLink(); },
7813
+ exportImage: function (options) {
7814
+ engine.render();
7815
+ if (typeof stage.toDataURL !== 'function') {
7816
+ throw new Error('Diagram image export is not available on the current stage.');
7817
+ }
7818
+ if (!options) {
7819
+ return stage.toDataURL();
7820
+ }
7821
+ var fitToContent = options.fitToContent, baseOptions = __rest(options, ["fitToContent"]);
7822
+ if (!fitToContent) {
7823
+ return stage.toDataURL(baseOptions);
7824
+ }
7825
+ var padding = resolveFitToContentPadding(fitToContent);
7826
+ var worldBounds = resolveStateWorldBounds(engine.getState());
7827
+ if (!worldBounds) {
7828
+ return stage.toDataURL(baseOptions);
7829
+ }
7830
+ var viewport = engine.getViewport();
7831
+ var safeZoom = viewport.zoom === 0 ? 1 : viewport.zoom;
7832
+ var cropX = worldBounds.minX * safeZoom + viewport.pan.x - padding;
7833
+ var cropY = worldBounds.minY * safeZoom + viewport.pan.y - padding;
7834
+ var cropWidth = Math.max(1, (worldBounds.maxX - worldBounds.minX) * safeZoom + padding * 2);
7835
+ var cropHeight = Math.max(1, (worldBounds.maxY - worldBounds.minY) * safeZoom + padding * 2);
7836
+ return stage.toDataURL(__assign(__assign({}, baseOptions), { x: cropX, y: cropY, width: cropWidth, height: cropHeight }));
7837
+ },
7172
7838
  resize: function (width, height) {
7173
7839
  stage.width(width);
7174
7840
  stage.height(height);