orcasvn-react-diagrams 0.2.3 → 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +15 -11
  3. package/dist/cjs/examples.js +857 -139
  4. package/dist/cjs/index.js +408 -41
  5. package/dist/cjs/types/api/types.d.ts +9 -0
  6. package/dist/cjs/types/displaybox/demos/labelStyleDemo.d.ts +2 -0
  7. package/dist/cjs/types/displaybox/demos/portPositionLimitsDemo.d.ts +2 -0
  8. package/dist/cjs/types/engine/DiagramEngine.d.ts +6 -0
  9. package/dist/cjs/types/engine/LinkRoutingService.d.ts +1 -1
  10. package/dist/cjs/types/renderer/konva/KonvaNodeFactory.d.ts +11 -0
  11. package/dist/cjs/types/renderer/konva/KonvaRenderer.d.ts +2 -0
  12. package/dist/cjs/types/strategies/ObstacleRouter.d.ts +2 -0
  13. package/dist/esm/examples.js +857 -139
  14. package/dist/esm/examples.js.map +1 -1
  15. package/dist/esm/index.js +408 -41
  16. package/dist/esm/index.js.map +1 -1
  17. package/dist/esm/types/api/types.d.ts +9 -0
  18. package/dist/esm/types/displaybox/demos/labelStyleDemo.d.ts +2 -0
  19. package/dist/esm/types/displaybox/demos/portPositionLimitsDemo.d.ts +2 -0
  20. package/dist/esm/types/engine/DiagramEngine.d.ts +6 -0
  21. package/dist/esm/types/engine/LinkRoutingService.d.ts +1 -1
  22. package/dist/esm/types/renderer/konva/KonvaNodeFactory.d.ts +11 -0
  23. package/dist/esm/types/renderer/konva/KonvaRenderer.d.ts +2 -0
  24. package/dist/esm/types/strategies/ObstacleRouter.d.ts +2 -0
  25. package/dist/examples.d.ts +9 -0
  26. package/dist/index.d.ts +10 -1
  27. package/package.json +11 -11
  28. package/src/displaybox/demos/ObstacleRoutingDemoTab.tsx +11 -10
  29. package/src/displaybox/demos/index.tsx +27 -13
  30. package/src/displaybox/demos/labelStyleDemo.ts +101 -0
  31. package/src/displaybox/demos/obstacleRoutingDemo.ts +212 -176
  32. package/src/displaybox/demos/portPositionLimitsDemo.ts +211 -0
package/dist/cjs/index.js CHANGED
@@ -1283,21 +1283,42 @@ var ObstacleRouter = /** @class */ (function () {
1283
1283
  ObstacleRouter.prototype.computeStubEndpoint = function (point, endpoint, bounds, obstacles) {
1284
1284
  if (!(endpoint === null || endpoint === void 0 ? void 0 : endpoint.onEdgeSide) || !endpoint.rect)
1285
1285
  return null;
1286
- var normal = this.getNormal(endpoint.onEdgeSide);
1286
+ var outwardNormal = this.getNormal(endpoint.onEdgeSide);
1287
+ var selectedNormal = outwardNormal;
1288
+ var maxLength = this.computeAvailableStubLength(point, outwardNormal, bounds, obstacles, endpoint.elementId);
1289
+ // If the outward normal is fully blocked by route bounds on the endpoint host, fall back inward
1290
+ // to preserve a visible perpendicular stub for bounded parent-child routes.
1291
+ if (maxLength <= this.tolerance && bounds && this.rectsEqual(bounds, endpoint.rect)) {
1292
+ var inwardNormal = { x: -outwardNormal.x, y: -outwardNormal.y };
1293
+ var inwardLength = this.computeAvailableStubLength(point, inwardNormal, bounds, obstacles, endpoint.elementId);
1294
+ if (inwardLength > maxLength) {
1295
+ selectedNormal = inwardNormal;
1296
+ maxLength = inwardLength;
1297
+ }
1298
+ }
1299
+ if (maxLength <= 0)
1300
+ return null;
1301
+ return {
1302
+ x: point.x + selectedNormal.x * maxLength,
1303
+ y: point.y + selectedNormal.y * maxLength,
1304
+ };
1305
+ };
1306
+ ObstacleRouter.prototype.computeAvailableStubLength = function (point, normal, bounds, obstacles, ignoreId) {
1287
1307
  var maxLength = this.stubLength;
1288
1308
  if (bounds) {
1289
1309
  maxLength = Math.min(maxLength, this.distanceToBounds(point, normal, bounds));
1290
1310
  }
1291
- var obstacleLimit = this.distanceToObstacles(point, normal, obstacles, endpoint.elementId);
1311
+ var obstacleLimit = this.distanceToObstacles(point, normal, obstacles, ignoreId);
1292
1312
  if (obstacleLimit !== null) {
1293
1313
  maxLength = Math.min(maxLength, obstacleLimit);
1294
1314
  }
1295
- if (maxLength <= 0)
1296
- return null;
1297
- return {
1298
- x: point.x + normal.x * maxLength,
1299
- y: point.y + normal.y * maxLength,
1300
- };
1315
+ return maxLength;
1316
+ };
1317
+ ObstacleRouter.prototype.rectsEqual = function (a, b) {
1318
+ return (Math.abs(a.x - b.x) <= this.tolerance &&
1319
+ Math.abs(a.y - b.y) <= this.tolerance &&
1320
+ Math.abs(a.width - b.width) <= this.tolerance &&
1321
+ Math.abs(a.height - b.height) <= this.tolerance);
1301
1322
  };
1302
1323
  ObstacleRouter.prototype.getNormal = function (side) {
1303
1324
  switch (side) {
@@ -1594,7 +1615,7 @@ var borderSideToInwardRotation = function (side) {
1594
1615
  return 0;
1595
1616
  };
1596
1617
 
1597
- var POSITION_EPSILON$1 = 1e-6;
1618
+ var POSITION_EPSILON$2 = 1e-6;
1598
1619
  var MIN_TRUNCATION_WIDTH_SAFETY_EPSILON = 0.5;
1599
1620
  var FONT_SIZE_TRUNCATION_SAFETY_RATIO = 1.4;
1600
1621
  var FONT_SIZE_TRUNCATION_SAFETY_BASE = 2;
@@ -1620,7 +1641,7 @@ var TextLayoutService = /** @class */ (function () {
1620
1641
  var textRenderPadding = this.resolveTextRenderPadding(text.style);
1621
1642
  var horizontalRenderInset = textRenderPadding * 2;
1622
1643
  var verticalRenderInset = textRenderPadding * 2;
1623
- var zeroPaddingInset = padding <= POSITION_EPSILON$1 && this.shouldTrackOwnerBoundLayout(text) ? 0.5 : 0;
1644
+ var zeroPaddingInset = padding <= POSITION_EPSILON$2 && this.shouldTrackOwnerBoundLayout(text) ? 0.5 : 0;
1624
1645
  var drawableWidth = maxWidth !== undefined ? Math.max(0, maxWidth - zeroPaddingInset * 2 - horizontalRenderInset) : undefined;
1625
1646
  var drawableHeight = maxHeight !== undefined ? Math.max(0, maxHeight - zeroPaddingInset * 2 - verticalRenderInset) : undefined;
1626
1647
  var lineHeight = this.textMeasurer.measure(__assign(__assign({}, text), { content: 'M' })).height;
@@ -2318,6 +2339,7 @@ var resolvePortWorldTransform = function (options) {
2318
2339
  };
2319
2340
 
2320
2341
  var EDGE_TOLERANCE = 0.5;
2342
+ var POSITION_EPSILON$1 = 1e-6;
2321
2343
  var LinkRoutingService = /** @class */ (function () {
2322
2344
  function LinkRoutingService(config) {
2323
2345
  this.model = config.model;
@@ -2426,11 +2448,27 @@ var LinkRoutingService = /** @class */ (function () {
2426
2448
  if (points.length < 2) {
2427
2449
  return [__assign({}, source), __assign({}, target)];
2428
2450
  }
2451
+ var sourceDelta = {
2452
+ x: source.x - points[0].x,
2453
+ y: source.y - points[0].y,
2454
+ };
2455
+ var targetDelta = {
2456
+ x: target.x - points[points.length - 1].x,
2457
+ y: target.y - points[points.length - 1].y,
2458
+ };
2459
+ var shouldTranslateAllPoints = Math.abs(sourceDelta.x - targetDelta.x) <= POSITION_EPSILON$1 &&
2460
+ Math.abs(sourceDelta.y - targetDelta.y) <= POSITION_EPSILON$1;
2429
2461
  return points.map(function (point, index) {
2430
2462
  if (index === 0)
2431
2463
  return __assign({}, source);
2432
2464
  if (index === points.length - 1)
2433
2465
  return __assign({}, target);
2466
+ if (shouldTranslateAllPoints) {
2467
+ return {
2468
+ x: point.x + sourceDelta.x,
2469
+ y: point.y + sourceDelta.y,
2470
+ };
2471
+ }
2434
2472
  return __assign({}, point);
2435
2473
  });
2436
2474
  };
@@ -2596,16 +2634,13 @@ var LinkRoutingService = /** @class */ (function () {
2596
2634
  var oppositeElementId = (_b = this.model.getPort(oppositePortId)) === null || _b === void 0 ? void 0 : _b.elementId;
2597
2635
  if (!elementId || !oppositeElementId)
2598
2636
  return 'external';
2599
- return this.hasAncestorRelation(elementId, oppositeElementId) ? 'internal' : 'external';
2637
+ return this.isAncestorOf(elementId, oppositeElementId) ? 'internal' : 'external';
2600
2638
  };
2601
- LinkRoutingService.prototype.hasAncestorRelation = function (sourceElementId, targetElementId) {
2602
- if (sourceElementId === targetElementId)
2639
+ LinkRoutingService.prototype.isAncestorOf = function (candidateAncestorId, candidateDescendantId) {
2640
+ if (candidateAncestorId === candidateDescendantId)
2603
2641
  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);
2642
+ var descendantChain = this.getAncestorChain(candidateDescendantId);
2643
+ return descendantChain.includes(candidateAncestorId);
2609
2644
  };
2610
2645
  LinkRoutingService.prototype.getAncestorChain = function (elementId) {
2611
2646
  var _a;
@@ -2765,11 +2800,17 @@ var DiagramEngine = /** @class */ (function () {
2765
2800
  DiagramEngine.prototype.load = function (state) {
2766
2801
  var _this = this;
2767
2802
  var patches = this.commandQueue.run(createLoadCommand(state), this.model);
2768
- var allPatches = this.mutationPipeline.run({
2803
+ var mutationPatches = this.mutationPipeline.run({
2769
2804
  basePatches: patches,
2770
2805
  layoutSteps: [function () { return _this.applyAllLayouts(); }],
2771
2806
  includeEmptyLinkRouting: true,
2772
2807
  });
2808
+ var normalizedPorts = this.normalizePortsForHostPolicies();
2809
+ var normalizedLinkPatches = normalizedPorts.movedPortIds.length > 0
2810
+ ? this.updateLinksForPorts(normalizedPorts.movedPortIds)
2811
+ : [];
2812
+ var textPresentationPatches = this.resolveAllTextPresentationPatches(false);
2813
+ var allPatches = __spreadArray(__spreadArray(__spreadArray(__spreadArray([], mutationPatches, true), normalizedPorts.patches, true), normalizedLinkPatches, true), textPresentationPatches, true);
2773
2814
  this.emitChange(allPatches);
2774
2815
  };
2775
2816
  DiagramEngine.prototype.getState = function () {
@@ -3361,7 +3402,7 @@ var DiagramEngine = /** @class */ (function () {
3361
3402
  if (!host)
3362
3403
  return;
3363
3404
  host.portIds.forEach(function (portId) {
3364
- var _a;
3405
+ var _a, _b, _c;
3365
3406
  var port = _this.model.getPort(portId);
3366
3407
  if (!port)
3367
3408
  return;
@@ -3384,11 +3425,16 @@ var DiagramEngine = /** @class */ (function () {
3384
3425
  return;
3385
3426
  }
3386
3427
  var projected = _this.resolveBorderPortResizeProjection(port.position, host.shapeId, sizeInfo, host.size);
3387
- var unchanged = Math.abs(projected.x - port.position.x) <= POSITION_EPSILON &&
3388
- Math.abs(projected.y - port.position.y) <= POSITION_EPSILON;
3428
+ var constrained = _this.resolveConstrainedPortRelativePosition(port, host, projected);
3429
+ var unchanged = Math.abs(constrained.position.x - port.position.x) <= POSITION_EPSILON &&
3430
+ Math.abs(constrained.position.y - port.position.y) <= POSITION_EPSILON &&
3431
+ ((_b = constrained.currentAnchorId) !== null && _b !== void 0 ? _b : null) === ((_c = port.currentAnchorId) !== null && _c !== void 0 ? _c : null);
3389
3432
  if (unchanged)
3390
3433
  return;
3391
- var patchesForPort = _this.commandQueue.run(createMovePortCommand(port.id, { position: projected, currentAnchorId: null }), _this.model);
3434
+ var patchesForPort = _this.commandQueue.run(createMovePortCommand(port.id, {
3435
+ position: constrained.position,
3436
+ currentAnchorId: constrained.currentAnchorId,
3437
+ }), _this.model);
3392
3438
  reprojectionPatches.push.apply(reprojectionPatches, patchesForPort);
3393
3439
  movedPortIds.add(port.id);
3394
3440
  });
@@ -3445,10 +3491,10 @@ var DiagramEngine = /** @class */ (function () {
3445
3491
  return this.projectPointToHostBorder(projectedTarget, shapeId, nextSize);
3446
3492
  };
3447
3493
  DiagramEngine.prototype.resolveConstrainedPortRelativePosition = function (port, element, requestedPosition) {
3448
- var _a, _b, _c, _d, _e;
3494
+ var _a, _b, _c, _d, _e, _f, _g;
3449
3495
  var position = __assign({}, requestedPosition);
3450
3496
  var effectiveMoveMode = this.resolveEffectivePortMoveMode(port, element);
3451
- if (effectiveMoveMode && effectiveMoveMode !== 'free' && effectiveMoveMode !== 'anchors') {
3497
+ if (effectiveMoveMode === 'inside' || effectiveMoveMode === 'border') {
3452
3498
  var widthLimit = Math.max(0, element.size.width - ((_b = (_a = port.size) === null || _a === void 0 ? void 0 : _a.width) !== null && _b !== void 0 ? _b : 0));
3453
3499
  var heightLimit = Math.max(0, element.size.height - ((_d = (_c = port.size) === null || _c === void 0 ? void 0 : _c.height) !== null && _d !== void 0 ? _d : 0));
3454
3500
  var bounds = {
@@ -3472,9 +3518,12 @@ var DiagramEngine = /** @class */ (function () {
3472
3518
  height: Math.max(0, element.size.height),
3473
3519
  };
3474
3520
  }
3475
- position = effectiveMoveMode === 'inside'
3476
- ? clampToRect(position, bounds)
3477
- : this.constrainPortToHostBorder(position, element);
3521
+ if (effectiveMoveMode === 'inside') {
3522
+ position = clampToRect(position, bounds);
3523
+ }
3524
+ else {
3525
+ position = this.constrainPortToHostBorder(position, element);
3526
+ }
3478
3527
  }
3479
3528
  var style = port.style;
3480
3529
  if ((style === null || style === void 0 ? void 0 : style.moveAxis) === 'horizontal') {
@@ -3488,18 +3537,134 @@ var DiagramEngine = /** @class */ (function () {
3488
3537
  position.x = clamp(position.x, bounds.x, bounds.x + bounds.width);
3489
3538
  position.y = clamp(position.y, bounds.y, bounds.y + bounds.height);
3490
3539
  }
3540
+ if (effectiveMoveMode === 'border') {
3541
+ var resolvedBorder = this.resolveBorderPositionWithLimits(position, element, (_e = element.portMovement) === null || _e === void 0 ? void 0 : _e.positionLimits);
3542
+ position = resolvedBorder !== null && resolvedBorder !== void 0 ? resolvedBorder : this.constrainPortToHostBorder(position, element);
3543
+ }
3544
+ else {
3545
+ position = this.applyPortPositionLimits(position, (_f = element.portMovement) === null || _f === void 0 ? void 0 : _f.positionLimits);
3546
+ }
3491
3547
  if (effectiveMoveMode === 'anchors') {
3492
- var anchor = this.resolveNearestPortAnchor(element, position);
3548
+ var anchor = this.resolveNearestPortAnchor(element, position, port.currentAnchorId);
3493
3549
  if (anchor) {
3494
3550
  return {
3495
3551
  position: __assign({}, anchor.position),
3496
3552
  currentAnchorId: anchor.id,
3497
3553
  };
3498
3554
  }
3499
- return { position: position, currentAnchorId: (_e = port.currentAnchorId) !== null && _e !== void 0 ? _e : null };
3555
+ return { position: __assign({}, port.position), currentAnchorId: (_g = port.currentAnchorId) !== null && _g !== void 0 ? _g : null };
3500
3556
  }
3501
3557
  return { position: position, currentAnchorId: null };
3502
3558
  };
3559
+ DiagramEngine.prototype.applyPortPositionLimits = function (position, limits) {
3560
+ if (!limits)
3561
+ return __assign({}, position);
3562
+ var x = position.x;
3563
+ var y = position.y;
3564
+ if (limits.x) {
3565
+ if (typeof limits.x.min === 'number') {
3566
+ x = Math.max(x, limits.x.min);
3567
+ }
3568
+ if (typeof limits.x.max === 'number') {
3569
+ x = Math.min(x, limits.x.max);
3570
+ }
3571
+ }
3572
+ if (limits.y) {
3573
+ if (typeof limits.y.min === 'number') {
3574
+ y = Math.max(y, limits.y.min);
3575
+ }
3576
+ if (typeof limits.y.max === 'number') {
3577
+ y = Math.min(y, limits.y.max);
3578
+ }
3579
+ }
3580
+ return { x: x, y: y };
3581
+ };
3582
+ DiagramEngine.prototype.resolveBorderPositionWithLimits = function (position, element, limits) {
3583
+ var _this = this;
3584
+ var _a, _b, _c, _d;
3585
+ var borderBase = this.constrainPortToHostBorder(position, element);
3586
+ if (!limits)
3587
+ return borderBase;
3588
+ if (this.isPointWithinPositionLimits(borderBase, limits))
3589
+ return borderBase;
3590
+ var target = this.applyPortPositionLimits(borderBase, limits);
3591
+ var xValues = new Set([borderBase.x, target.x, 0, Math.max(0, element.size.width)]);
3592
+ var yValues = new Set([borderBase.y, target.y, 0, Math.max(0, element.size.height)]);
3593
+ if (typeof ((_a = limits.x) === null || _a === void 0 ? void 0 : _a.min) === 'number')
3594
+ xValues.add(limits.x.min);
3595
+ if (typeof ((_b = limits.x) === null || _b === void 0 ? void 0 : _b.max) === 'number')
3596
+ xValues.add(limits.x.max);
3597
+ if (typeof ((_c = limits.y) === null || _c === void 0 ? void 0 : _c.min) === 'number')
3598
+ yValues.add(limits.y.min);
3599
+ if (typeof ((_d = limits.y) === null || _d === void 0 ? void 0 : _d.max) === 'number')
3600
+ yValues.add(limits.y.max);
3601
+ var seeds = [];
3602
+ xValues.forEach(function (x) { return yValues.forEach(function (y) { return seeds.push({ x: x, y: y }); }); });
3603
+ seeds.push({ x: borderBase.x, y: target.y }, { x: target.x, y: borderBase.y });
3604
+ var candidates = [];
3605
+ var seen = new Set();
3606
+ seeds.forEach(function (seed) {
3607
+ var candidate = _this.constrainPortToHostBorder(seed, element);
3608
+ var key = "".concat(candidate.x.toFixed(6), ":").concat(candidate.y.toFixed(6));
3609
+ if (seen.has(key))
3610
+ return;
3611
+ seen.add(key);
3612
+ candidates.push(candidate);
3613
+ });
3614
+ var valid = candidates.filter(function (candidate) { return _this.isPointWithinPositionLimits(candidate, limits); });
3615
+ if (valid.length === 0)
3616
+ return null;
3617
+ return valid.reduce(function (best, candidate) {
3618
+ var bestDistance = Math.pow((best.x - target.x), 2) + Math.pow((best.y - target.y), 2);
3619
+ var candidateDistance = Math.pow((candidate.x - target.x), 2) + Math.pow((candidate.y - target.y), 2);
3620
+ if (candidateDistance < bestDistance)
3621
+ return candidate;
3622
+ if (candidateDistance > bestDistance)
3623
+ return best;
3624
+ if (candidate.x < best.x)
3625
+ return candidate;
3626
+ if (candidate.x > best.x)
3627
+ return best;
3628
+ return candidate.y < best.y ? candidate : best;
3629
+ }, valid[0]);
3630
+ };
3631
+ DiagramEngine.prototype.isPointWithinPositionLimits = function (position, limits) {
3632
+ if (!limits)
3633
+ return true;
3634
+ if (limits.x) {
3635
+ if (typeof limits.x.min === 'number' && position.x < limits.x.min)
3636
+ return false;
3637
+ if (typeof limits.x.max === 'number' && position.x > limits.x.max)
3638
+ return false;
3639
+ }
3640
+ if (limits.y) {
3641
+ if (typeof limits.y.min === 'number' && position.y < limits.y.min)
3642
+ return false;
3643
+ if (typeof limits.y.max === 'number' && position.y > limits.y.max)
3644
+ return false;
3645
+ }
3646
+ return true;
3647
+ };
3648
+ DiagramEngine.prototype.filterAnchorsByPositionLimits = function (anchors, limits) {
3649
+ if (!limits)
3650
+ return anchors;
3651
+ return anchors.filter(function (anchor) {
3652
+ var position = anchor.position;
3653
+ if (limits.x) {
3654
+ if (typeof limits.x.min === 'number' && position.x < limits.x.min)
3655
+ return false;
3656
+ if (typeof limits.x.max === 'number' && position.x > limits.x.max)
3657
+ return false;
3658
+ }
3659
+ if (limits.y) {
3660
+ if (typeof limits.y.min === 'number' && position.y < limits.y.min)
3661
+ return false;
3662
+ if (typeof limits.y.max === 'number' && position.y > limits.y.max)
3663
+ return false;
3664
+ }
3665
+ return true;
3666
+ });
3667
+ };
3503
3668
  DiagramEngine.prototype.resolveEffectivePortMoveMode = function (port, element) {
3504
3669
  var _a, _b;
3505
3670
  return (_b = (_a = element.portMovement) === null || _a === void 0 ? void 0 : _a.moveMode) !== null && _b !== void 0 ? _b : port.moveMode;
@@ -3534,7 +3699,8 @@ var DiagramEngine = /** @class */ (function () {
3534
3699
  return [];
3535
3700
  };
3536
3701
  DiagramEngine.prototype.resolveNearestPortAnchor = function (element, target, preferredAnchorId) {
3537
- var anchors = this.resolvePortAnchorsForElement(element);
3702
+ var _a;
3703
+ var anchors = this.filterAnchorsByPositionLimits(this.resolvePortAnchorsForElement(element), (_a = element.portMovement) === null || _a === void 0 ? void 0 : _a.positionLimits);
3538
3704
  if (anchors.length === 0)
3539
3705
  return null;
3540
3706
  if (preferredAnchorId) {
@@ -3599,6 +3765,46 @@ var DiagramEngine = /** @class */ (function () {
3599
3765
  DiagramEngine.prototype.resolveTextPresentation = function (text) {
3600
3766
  return this.textLayoutService.resolveTextPresentation(text);
3601
3767
  };
3768
+ DiagramEngine.prototype.resolveAllTextPresentationPatches = function (emitTextUpdated) {
3769
+ var _this = this;
3770
+ var textPatches = [];
3771
+ this.model.texts.forEach(function (text) {
3772
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s;
3773
+ var current = text.toData();
3774
+ var resolved = _this.resolveTextPresentation(current);
3775
+ var currentDisplay = (_a = current.displayContent) !== null && _a !== void 0 ? _a : current.content;
3776
+ var sizeChanged = !current.size ||
3777
+ current.size.width !== resolved.size.width ||
3778
+ current.size.height !== resolved.size.height;
3779
+ var displayChanged = currentDisplay !== resolved.displayContent;
3780
+ var offsetChanged = ((_c = (_b = current.displayOffset) === null || _b === void 0 ? void 0 : _b.x) !== null && _c !== void 0 ? _c : 0) !== ((_e = (_d = resolved.displayOffset) === null || _d === void 0 ? void 0 : _d.x) !== null && _e !== void 0 ? _e : 0) ||
3781
+ ((_g = (_f = current.displayOffset) === null || _f === void 0 ? void 0 : _f.y) !== null && _g !== void 0 ? _g : 0) !== ((_j = (_h = resolved.displayOffset) === null || _h === void 0 ? void 0 : _h.y) !== null && _j !== void 0 ? _j : 0);
3782
+ var clipChanged = ((_l = (_k = current.displayClipSize) === null || _k === void 0 ? void 0 : _k.width) !== null && _l !== void 0 ? _l : 0) !== ((_o = (_m = resolved.displayClipSize) === null || _m === void 0 ? void 0 : _m.width) !== null && _o !== void 0 ? _o : 0) ||
3783
+ ((_q = (_p = current.displayClipSize) === null || _p === void 0 ? void 0 : _p.height) !== null && _q !== void 0 ? _q : 0) !== ((_s = (_r = resolved.displayClipSize) === null || _r === void 0 ? void 0 : _r.height) !== null && _s !== void 0 ? _s : 0);
3784
+ if (!sizeChanged && !displayChanged && !offsetChanged && !clipChanged)
3785
+ return;
3786
+ text.setSize(resolved.size);
3787
+ text.setDisplayContent(resolved.displayContent);
3788
+ text.setDisplayOffset(resolved.displayOffset);
3789
+ text.setDisplayClipSize(resolved.displayClipSize);
3790
+ textPatches.push(patchUpdate('text', text.id, {
3791
+ size: resolved.size,
3792
+ displayContent: resolved.displayContent,
3793
+ displayOffset: resolved.displayOffset,
3794
+ displayClipSize: resolved.displayClipSize,
3795
+ }));
3796
+ if (emitTextUpdated) {
3797
+ _this.events.emit('textUpdated', {
3798
+ textId: text.id,
3799
+ ownerId: text.ownerId,
3800
+ content: text.content,
3801
+ displayContent: resolved.displayContent,
3802
+ reason: 'layout',
3803
+ });
3804
+ }
3805
+ });
3806
+ return textPatches;
3807
+ };
3602
3808
  DiagramEngine.prototype.emitSelection = function () {
3603
3809
  var _this = this;
3604
3810
  var selectedIds = this.selection.get();
@@ -3688,6 +3894,40 @@ var DiagramEngine = /** @class */ (function () {
3688
3894
  DiagramEngine.prototype.routeLinksWithEmptyPoints = function () {
3689
3895
  return this.linkRoutingService.routeLinksWithEmptyPoints();
3690
3896
  };
3897
+ DiagramEngine.prototype.normalizePortsForHostPolicies = function (portIds) {
3898
+ var _this = this;
3899
+ var ids = portIds !== null && portIds !== void 0 ? portIds : Array.from(this.model.ports.keys());
3900
+ var normalizedPatches = [];
3901
+ var movedPortIds = new Set();
3902
+ ids.forEach(function (portId) {
3903
+ var _a, _b;
3904
+ var port = _this.model.getPort(portId);
3905
+ if (!port)
3906
+ return;
3907
+ var element = _this.model.getElement(port.elementId);
3908
+ if (!element)
3909
+ return;
3910
+ var constrained = _this.resolveConstrainedPortRelativePosition(port, element, port.position);
3911
+ var previousAnchorId = (_a = port.currentAnchorId) !== null && _a !== void 0 ? _a : null;
3912
+ var shouldPersistAnchorId = previousAnchorId !== null || constrained.currentAnchorId === null;
3913
+ var nextAnchorId = shouldPersistAnchorId ? ((_b = constrained.currentAnchorId) !== null && _b !== void 0 ? _b : null) : previousAnchorId;
3914
+ var unchanged = Math.abs(constrained.position.x - port.position.x) <= POSITION_EPSILON &&
3915
+ Math.abs(constrained.position.y - port.position.y) <= POSITION_EPSILON &&
3916
+ previousAnchorId === nextAnchorId;
3917
+ if (unchanged)
3918
+ return;
3919
+ var update = {
3920
+ position: constrained.position,
3921
+ };
3922
+ if (shouldPersistAnchorId) {
3923
+ update.currentAnchorId = constrained.currentAnchorId;
3924
+ }
3925
+ var patches = _this.commandQueue.run(createMovePortCommand(port.id, update), _this.model);
3926
+ normalizedPatches.push.apply(normalizedPatches, patches);
3927
+ movedPortIds.add(port.id);
3928
+ });
3929
+ return { patches: normalizedPatches, movedPortIds: Array.from(movedPortIds) };
3930
+ };
3691
3931
  DiagramEngine.prototype.computeRemovalDiff = function (before) {
3692
3932
  var after = this.model.toState();
3693
3933
  var removedPatches = [];
@@ -3933,6 +4173,21 @@ var KonvaNodeFactory = /** @class */ (function () {
3933
4173
  }
3934
4174
  return node;
3935
4175
  };
4176
+ KonvaNodeFactory.prototype.createTextBackgroundNode = function (config) {
4177
+ return new this.konva.Rect({
4178
+ id: config.id,
4179
+ x: config.x,
4180
+ y: config.y,
4181
+ width: config.width,
4182
+ height: config.height,
4183
+ fill: config.fill,
4184
+ stroke: config.stroke,
4185
+ strokeWidth: config.strokeWidth,
4186
+ cornerRadius: config.cornerRadius,
4187
+ name: 'text-background',
4188
+ listening: false,
4189
+ });
4190
+ };
3936
4191
  KonvaNodeFactory.prototype.createHandleNode = function (config) {
3937
4192
  return new this.konva.Rect({
3938
4193
  id: config.id,
@@ -4113,6 +4368,7 @@ var KonvaRenderer = /** @class */ (function () {
4113
4368
  this.portNodes = new Map();
4114
4369
  this.linkNodes = new Map();
4115
4370
  this.textNodes = new Map();
4371
+ this.textBackgroundNodes = new Map();
4116
4372
  this.selectedIds = new Set();
4117
4373
  this.tempLinkNode = null;
4118
4374
  this.tempPortNode = null;
@@ -4412,6 +4668,8 @@ var KonvaRenderer = /** @class */ (function () {
4412
4668
  this.elementNodes.clear();
4413
4669
  this.portNodes.clear();
4414
4670
  this.linkNodes.clear();
4671
+ this.textBackgroundNodes.forEach(function (node) { var _a; return (_a = node.destroy) === null || _a === void 0 ? void 0 : _a.call(node); });
4672
+ this.textBackgroundNodes.clear();
4415
4673
  this.textNodes.clear();
4416
4674
  this.resizeHandleNodes.clear();
4417
4675
  this.linkHandleNodes.clear();
@@ -4618,7 +4876,7 @@ var KonvaRenderer = /** @class */ (function () {
4618
4876
  var _this = this;
4619
4877
  var texts = Array.from(model.texts.values());
4620
4878
  texts.forEach(function (text) {
4621
- var _a, _b, _c, _d, _e, _f, _g, _h;
4879
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s;
4622
4880
  var node = _this.textNodes.get(text.id);
4623
4881
  if (!node) {
4624
4882
  node = _this.nodeFactory.createTextNode(text.toData());
@@ -4627,32 +4885,124 @@ var KonvaRenderer = /** @class */ (function () {
4627
4885
  }
4628
4886
  var position = (_c = model.getTextWorldPosition(text.id)) !== null && _c !== void 0 ? _c : text.position;
4629
4887
  var displayOffset = (_d = text.displayOffset) !== null && _d !== void 0 ? _d : { x: 0, y: 0 };
4630
- _this.updatePosition(node, {
4888
+ var textPosition = {
4631
4889
  x: position.x + displayOffset.x,
4632
4890
  y: position.y + displayOffset.y,
4891
+ };
4892
+ _this.updatePosition(node, {
4893
+ x: textPosition.x,
4894
+ y: textPosition.y,
4633
4895
  });
4634
4896
  if (node.setAttrs) {
4635
- var style = text.style;
4636
- var defaults = resolveTextStyleDefaults(style);
4637
- var baseFill = (_g = (_f = (_e = style === null || style === void 0 ? void 0 : style.fill) !== null && _e !== void 0 ? _e : _this.getNodeAttr(node, '__baseFill')) !== null && _f !== void 0 ? _f : _this.getNodeAttr(node, 'fill')) !== null && _g !== void 0 ? _g : 'black';
4897
+ var style_1 = text.style;
4898
+ var defaults = resolveTextStyleDefaults(style_1);
4899
+ var baseFill = (_g = (_f = (_e = style_1 === null || style_1 === void 0 ? void 0 : style_1.fill) !== null && _e !== void 0 ? _e : _this.getNodeAttr(node, '__baseFill')) !== null && _f !== void 0 ? _f : _this.getNodeAttr(node, 'fill')) !== null && _g !== void 0 ? _g : 'black';
4638
4900
  var fill = _this.selectedIds.has(text.id) ? '#ff7a00' : baseFill;
4639
- var clip = text.displayClipSize;
4640
- node.setAttrs(__assign(__assign({ text: (_h = text.displayContent) !== null && _h !== void 0 ? _h : text.content, fontSize: defaults.fontSize, fontFamily: defaults.fontFamily, lineHeight: defaults.lineHeight }, (style !== null && style !== void 0 ? style : {})), { width: clip === null || clip === void 0 ? void 0 : clip.width, height: clip === null || clip === void 0 ? void 0 : clip.height, wrap: clip ? 'none' : undefined, ellipsis: false, fill: fill, __baseFill: baseFill,
4901
+ var clip_1 = text.displayClipSize;
4902
+ node.setAttrs(__assign(__assign({ text: (_h = text.displayContent) !== null && _h !== void 0 ? _h : text.content, fontSize: defaults.fontSize, fontFamily: defaults.fontFamily, lineHeight: defaults.lineHeight }, (style_1 !== null && style_1 !== void 0 ? style_1 : {})), { width: clip_1 === null || clip_1 === void 0 ? void 0 : clip_1.width, height: clip_1 === null || clip_1 === void 0 ? void 0 : clip_1.height, wrap: clip_1 ? 'none' : undefined, ellipsis: false, fill: fill, __baseFill: baseFill,
4641
4903
  // Keep metadata for tests/debugging; Konva clip attrs do not apply on Text nodes.
4642
- clipX: clip ? 0 : undefined, clipY: clip ? 0 : undefined, clipWidth: clip === null || clip === void 0 ? void 0 : clip.width, clipHeight: clip === null || clip === void 0 ? void 0 : clip.height }));
4904
+ clipX: clip_1 ? 0 : undefined, clipY: clip_1 ? 0 : undefined, clipWidth: clip_1 === null || clip_1 === void 0 ? void 0 : clip_1.width, clipHeight: clip_1 === null || clip_1 === void 0 ? void 0 : clip_1.height }));
4905
+ }
4906
+ var style = text.style;
4907
+ var backgroundFill = style === null || style === void 0 ? void 0 : style.backgroundFill;
4908
+ var clip = text.displayClipSize;
4909
+ var backgroundWidth = (_j = clip === null || clip === void 0 ? void 0 : clip.width) !== null && _j !== void 0 ? _j : (_k = text.size) === null || _k === void 0 ? void 0 : _k.width;
4910
+ var backgroundHeight = (_l = clip === null || clip === void 0 ? void 0 : clip.height) !== null && _l !== void 0 ? _l : (_m = text.size) === null || _m === void 0 ? void 0 : _m.height;
4911
+ var backgroundMeta = _this.resolveTextBackgroundMeta(model, text.toData());
4912
+ var hasBackground = typeof backgroundFill === 'string' &&
4913
+ backgroundFill.length > 0 &&
4914
+ typeof backgroundWidth === 'number' &&
4915
+ typeof backgroundHeight === 'number' &&
4916
+ backgroundWidth > 0 &&
4917
+ backgroundHeight > 0;
4918
+ if (hasBackground) {
4919
+ var baseX = textPosition.x + backgroundMeta.inset;
4920
+ var baseY = textPosition.y + backgroundMeta.inset;
4921
+ var width = Math.max(0, backgroundWidth - backgroundMeta.inset * 2);
4922
+ var height = Math.max(0, backgroundHeight - backgroundMeta.inset);
4923
+ var backgroundStroke = typeof (style === null || style === void 0 ? void 0 : style.backgroundStroke) === 'string' && style.backgroundStroke.length > 0
4924
+ ? style.backgroundStroke
4925
+ : undefined;
4926
+ var backgroundStrokeWidth = typeof (style === null || style === void 0 ? void 0 : style.backgroundStrokeWidth) === 'number'
4927
+ ? Math.max(0, style.backgroundStrokeWidth)
4928
+ : undefined;
4929
+ var backgroundNode = _this.textBackgroundNodes.get(text.id);
4930
+ if (!backgroundNode) {
4931
+ backgroundNode = _this.nodeFactory.createTextBackgroundNode({
4932
+ id: "text-background:".concat(text.id),
4933
+ x: baseX,
4934
+ y: baseY,
4935
+ width: width,
4936
+ height: height,
4937
+ fill: backgroundFill,
4938
+ stroke: backgroundStroke,
4939
+ strokeWidth: backgroundStrokeWidth,
4940
+ cornerRadius: backgroundMeta.cornerRadius,
4941
+ });
4942
+ _this.textBackgroundNodes.set(text.id, backgroundNode);
4943
+ (_p = (_o = _this.layers.getLayer('texts')) === null || _o === void 0 ? void 0 : _o.add) === null || _p === void 0 ? void 0 : _p.call(_o, backgroundNode);
4944
+ }
4945
+ else {
4946
+ _this.updatePosition(backgroundNode, { x: baseX, y: baseY });
4947
+ (_q = backgroundNode.setAttrs) === null || _q === void 0 ? void 0 : _q.call(backgroundNode, {
4948
+ width: width,
4949
+ height: height,
4950
+ fill: backgroundFill,
4951
+ stroke: backgroundStroke,
4952
+ strokeWidth: backgroundStrokeWidth,
4953
+ cornerRadius: backgroundMeta.cornerRadius,
4954
+ listening: false,
4955
+ name: 'text-background',
4956
+ });
4957
+ }
4958
+ (_r = node.moveToTop) === null || _r === void 0 ? void 0 : _r.call(node);
4959
+ }
4960
+ else {
4961
+ var backgroundNode = _this.textBackgroundNodes.get(text.id);
4962
+ (_s = backgroundNode === null || backgroundNode === void 0 ? void 0 : backgroundNode.destroy) === null || _s === void 0 ? void 0 : _s.call(backgroundNode);
4963
+ _this.textBackgroundNodes.delete(text.id);
4643
4964
  }
4644
4965
  });
4645
4966
  Array.from(this.textNodes.keys()).forEach(function (id) {
4646
- var _a;
4967
+ var _a, _b;
4647
4968
  if (!model.texts.has(id)) {
4969
+ var backgroundNode = _this.textBackgroundNodes.get(id);
4970
+ (_a = backgroundNode === null || backgroundNode === void 0 ? void 0 : backgroundNode.destroy) === null || _a === void 0 ? void 0 : _a.call(backgroundNode);
4971
+ _this.textBackgroundNodes.delete(id);
4648
4972
  var node = _this.textNodes.get(id);
4649
- (_a = node === null || node === void 0 ? void 0 : node.destroy) === null || _a === void 0 ? void 0 : _a.call(node);
4973
+ (_b = node === null || node === void 0 ? void 0 : node.destroy) === null || _b === void 0 ? void 0 : _b.call(node);
4650
4974
  _this.textNodes.delete(id);
4651
4975
  _this.layers.markDirty('texts');
4652
4976
  }
4653
4977
  });
4654
4978
  this.layers.markDirty('texts');
4655
4979
  };
4980
+ KonvaRenderer.prototype.resolveTextBackgroundMeta = function (model, text) {
4981
+ var _a;
4982
+ var ownerId = (_a = text.ownerId) !== null && _a !== void 0 ? _a : null;
4983
+ if (!ownerId)
4984
+ return { inset: 0 };
4985
+ var owner = model.getElement(ownerId);
4986
+ if (!owner)
4987
+ return { inset: 0 };
4988
+ var ownerStyle = owner.style;
4989
+ var strokeWidth = typeof (ownerStyle === null || ownerStyle === void 0 ? void 0 : ownerStyle.strokeWidth) === 'number' ? Math.max(0, ownerStyle.strokeWidth) : 0;
4990
+ var inset = strokeWidth > 0 ? strokeWidth / 2 : 0;
4991
+ var rawCornerRadius = ownerStyle === null || ownerStyle === void 0 ? void 0 : ownerStyle.cornerRadius;
4992
+ var isTopLabel = text.position.y <= 1;
4993
+ if (!isTopLabel)
4994
+ return { inset: inset };
4995
+ if (typeof rawCornerRadius === 'number' && rawCornerRadius > 0) {
4996
+ var topRadius = Math.max(0, rawCornerRadius - inset);
4997
+ return { inset: inset, cornerRadius: [topRadius, topRadius, 0, 0] };
4998
+ }
4999
+ if (Array.isArray(rawCornerRadius) && rawCornerRadius.length === 4) {
5000
+ var tl = typeof rawCornerRadius[0] === 'number' ? Math.max(0, rawCornerRadius[0] - inset) : 0;
5001
+ var tr = typeof rawCornerRadius[1] === 'number' ? Math.max(0, rawCornerRadius[1] - inset) : 0;
5002
+ return { inset: inset, cornerRadius: [tl, tr, 0, 0] };
5003
+ }
5004
+ return { inset: inset };
5005
+ };
4656
5006
  KonvaRenderer.prototype.updatePosition = function (node, position) {
4657
5007
  if (node.position) {
4658
5008
  node.position({ x: position.x, y: position.y });
@@ -6678,14 +7028,19 @@ var KonvaInteraction = /** @class */ (function () {
6678
7028
  this.engine.setSelection(Array.from(selected));
6679
7029
  };
6680
7030
  KonvaInteraction.prototype.applyPortConstraints = function (portId, worldTarget) {
7031
+ var _a;
6681
7032
  var port = this.getPortById(portId);
6682
7033
  if (!port)
6683
7034
  return worldTarget;
7035
+ var element = this.getElementById(port.elementId);
7036
+ if (!element)
7037
+ return worldTarget;
6684
7038
  var elementPos = this.engine.getElementWorldPosition(port.elementId);
6685
7039
  if (!elementPos)
6686
7040
  return worldTarget;
6687
7041
  var relative = { x: worldTarget.x - elementPos.x, y: worldTarget.y - elementPos.y };
6688
7042
  var style = port.style;
7043
+ var limits = (_a = element.portMovement) === null || _a === void 0 ? void 0 : _a.positionLimits;
6689
7044
  var constrained = __assign({}, relative);
6690
7045
  if ((style === null || style === void 0 ? void 0 : style.moveAxis) === 'horizontal') {
6691
7046
  constrained.y = port.position.y;
@@ -6698,6 +7053,18 @@ var KonvaInteraction = /** @class */ (function () {
6698
7053
  constrained.x = Math.min(bounds.x + bounds.width, Math.max(bounds.x, constrained.x));
6699
7054
  constrained.y = Math.min(bounds.y + bounds.height, Math.max(bounds.y, constrained.y));
6700
7055
  }
7056
+ if (limits === null || limits === void 0 ? void 0 : limits.x) {
7057
+ if (typeof limits.x.min === 'number')
7058
+ constrained.x = Math.max(constrained.x, limits.x.min);
7059
+ if (typeof limits.x.max === 'number')
7060
+ constrained.x = Math.min(constrained.x, limits.x.max);
7061
+ }
7062
+ if (limits === null || limits === void 0 ? void 0 : limits.y) {
7063
+ if (typeof limits.y.min === 'number')
7064
+ constrained.y = Math.max(constrained.y, limits.y.min);
7065
+ if (typeof limits.y.max === 'number')
7066
+ constrained.y = Math.min(constrained.y, limits.y.max);
7067
+ }
6701
7068
  return { x: elementPos.x + constrained.x, y: elementPos.y + constrained.y };
6702
7069
  };
6703
7070
  KonvaInteraction.prototype.resolveLinkPreviewSource = function (sourcePortId, pointer, hit) {