spytial-core 1.4.21 → 1.4.22

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.
@@ -91338,9 +91338,6 @@ VVbdfjptxz|~\x80\x82\x84\xA6\xA8W\b
91338
91338
  const bbox2 = hasgetBBox(element2) ? element2.getBBox() : { x: 0, y: 0, width: 0, height: 0 };
91339
91339
  return !(bbox2.x > bbox1.x + bbox1.width || bbox2.x + bbox2.width < bbox1.x || bbox2.y > bbox1.y + bbox1.height || bbox2.y + bbox2.height < bbox1.y);
91340
91340
  }
91341
- function hasInnerBounds(target) {
91342
- return target && typeof target === "object" && "innerBounds" in target;
91343
- }
91344
91341
  var d32, cola, DEFAULT_SCALE_FACTOR, _WebColaCnDGraph, WebColaCnDGraph;
91345
91342
  var init_webcola_cnd_graph = __esm({
91346
91343
  "src/translators/webcola/webcola-cnd-graph.ts"() {
@@ -91350,7 +91347,7 @@ VVbdfjptxz|~\x80\x82\x84\xA6\xA8W\b
91350
91347
  cola = window.cola;
91351
91348
  DEFAULT_SCALE_FACTOR = 5;
91352
91349
  _WebColaCnDGraph = class _WebColaCnDGraph extends HTMLElement {
91353
- constructor() {
91350
+ constructor(isInputAllowed = false) {
91354
91351
  super();
91355
91352
  // Reduced from 5 for performance, but kept at 1 for alignment
91356
91353
  /**
@@ -91383,6 +91380,23 @@ VVbdfjptxz|~\x80\x82\x84\xA6\xA8W\b
91383
91380
  * Input mode state management for edge creation and modification
91384
91381
  */
91385
91382
  this.isInputModeActive = false;
91383
+ this.inputModeEnabled = true;
91384
+ this.inputModeListenersAttached = false;
91385
+ this.handleInputModeKeydown = (event) => {
91386
+ if ((event.metaKey || event.ctrlKey) && !this.isInputModeActive) {
91387
+ this.activateInputMode();
91388
+ }
91389
+ };
91390
+ this.handleInputModeKeyup = (event) => {
91391
+ if (!event.metaKey && !event.ctrlKey && this.isInputModeActive) {
91392
+ this.deactivateInputMode();
91393
+ }
91394
+ };
91395
+ this.handleInputModeBlur = () => {
91396
+ if (this.isInputModeActive) {
91397
+ this.deactivateInputMode();
91398
+ }
91399
+ };
91386
91400
  this.edgeCreationState = {
91387
91401
  isCreating: false,
91388
91402
  sourceNode: null,
@@ -91405,6 +91419,7 @@ VVbdfjptxz|~\x80\x82\x84\xA6\xA8W\b
91405
91419
  this.initializeDOM();
91406
91420
  this.initializeD3();
91407
91421
  this.lineFunction = d32.line().x((d) => d.x).y((d) => d.y).curve(d32.curveBasis);
91422
+ this.inputModeEnabled = isInputAllowed;
91408
91423
  this.initializeInputModeHandlers();
91409
91424
  }
91410
91425
  /**
@@ -91780,21 +91795,27 @@ VVbdfjptxz|~\x80\x82\x84\xA6\xA8W\b
91780
91795
  * Initialize keyboard event handlers for input mode activation
91781
91796
  */
91782
91797
  initializeInputModeHandlers() {
91783
- document.addEventListener("keydown", (event) => {
91784
- if ((event.metaKey || event.ctrlKey) && !this.isInputModeActive) {
91785
- this.activateInputMode();
91786
- }
91787
- });
91788
- document.addEventListener("keyup", (event) => {
91789
- if (!event.metaKey && !event.ctrlKey && this.isInputModeActive) {
91790
- this.deactivateInputMode();
91791
- }
91792
- });
91793
- window.addEventListener("blur", () => {
91794
- if (this.isInputModeActive) {
91795
- this.deactivateInputMode();
91796
- }
91797
- });
91798
+ if (this.inputModeEnabled) {
91799
+ this.attachInputModeListeners();
91800
+ }
91801
+ }
91802
+ attachInputModeListeners() {
91803
+ if (this.inputModeListenersAttached) {
91804
+ return;
91805
+ }
91806
+ document.addEventListener("keydown", this.handleInputModeKeydown);
91807
+ document.addEventListener("keyup", this.handleInputModeKeyup);
91808
+ window.addEventListener("blur", this.handleInputModeBlur);
91809
+ this.inputModeListenersAttached = true;
91810
+ }
91811
+ detachInputModeListeners() {
91812
+ if (!this.inputModeListenersAttached) {
91813
+ return;
91814
+ }
91815
+ document.removeEventListener("keydown", this.handleInputModeKeydown);
91816
+ document.removeEventListener("keyup", this.handleInputModeKeyup);
91817
+ window.removeEventListener("blur", this.handleInputModeBlur);
91818
+ this.inputModeListenersAttached = false;
91798
91819
  }
91799
91820
  /**
91800
91821
  * Activate input mode for edge creation and modification
@@ -92996,35 +93017,17 @@ VVbdfjptxz|~\x80\x82\x84\xA6\xA8W\b
92996
93017
  const targetGroup = potentialGroups.find((group) => group.keyNode === this.getNodeIndex(source));
92997
93018
  if (targetGroup) {
92998
93019
  target = targetGroup;
92999
- if (hasInnerBounds(target)) {
93000
- target.innerBounds = targetGroup.bounds?.inflate(-1 * (targetGroup.padding || 10));
93001
- }
93002
- } else {
93003
- console.log("Target group not found", potentialGroups, this.getNodeIndex(target));
93004
93020
  }
93005
93021
  } else if (addSourceToGroup) {
93006
93022
  const potentialGroups = this.getContainingGroups(this.currentLayout?.groups || [], source);
93007
93023
  const sourceGroup = potentialGroups.find((group) => group.keyNode === this.getNodeIndex(target));
93008
93024
  if (sourceGroup) {
93009
93025
  source = sourceGroup;
93010
- if (hasInnerBounds(source)) {
93011
- source.innerBounds = sourceGroup.bounds?.inflate(-1 * (sourceGroup.padding || 10));
93012
- }
93013
- } else {
93014
- console.log("Source group not found", potentialGroups, this.getNodeIndex(source));
93015
93026
  }
93016
- } else {
93017
- console.log("This is a group edge (on tick), but neither source nor target is a group.", d);
93018
93027
  }
93019
93028
  }
93020
- if (typeof cola.makeEdgeBetween === "function" && hasInnerBounds(source) && hasInnerBounds(target) && source.innerBounds && target.innerBounds) {
93021
- const route = cola.makeEdgeBetween(source.innerBounds, target.innerBounds, 5);
93022
- return this.lineFunction([route.sourceIntersection, route.arrowStart]);
93023
- }
93024
- return this.lineFunction([
93025
- { x: source.x || 0, y: source.y || 0 },
93026
- { x: target.x || 0, y: target.y || 0 }
93027
- ]);
93029
+ const route = this.getStableEdgePath(source, target);
93030
+ return this.lineFunction(route);
93028
93031
  }).attr("marker-end", (d) => {
93029
93032
  if (this.isAlignmentEdge(d)) return "none";
93030
93033
  return "url(#end-arrow)";
@@ -93660,6 +93663,83 @@ VVbdfjptxz|~\x80\x82\x84\xA6\xA8W\b
93660
93663
  const closestY = Math.max(y, Math.min(point.y, Y));
93661
93664
  return { x: closestX, y: closestY };
93662
93665
  }
93666
+ /**
93667
+ * Calculates a stable anchor point on a rectangle's perimeter for edge drawing.
93668
+ * This method produces consistent, jitter-free anchor points by using the
93669
+ * center of the rectangle edge that faces the target point.
93670
+ *
93671
+ * Unlike intersection-based approaches that can jump erratically as rectangles
93672
+ * move, this method selects one of four edge centers (top, bottom, left, right)
93673
+ * based on the dominant direction to the target, producing smooth transitions.
93674
+ *
93675
+ * @param bounds - Rectangle bounds with x, y, X, Y properties (or cx(), cy(), width(), height() methods)
93676
+ * @param targetPoint - The point the edge is connecting to
93677
+ * @returns Stable anchor point on the rectangle's perimeter
93678
+ */
93679
+ getStableEdgeAnchor(bounds, targetPoint) {
93680
+ if (!bounds) return targetPoint;
93681
+ let cx, cy, halfWidth, halfHeight;
93682
+ if (typeof bounds.cx === "function") {
93683
+ cx = bounds.cx();
93684
+ cy = bounds.cy();
93685
+ halfWidth = bounds.width() / 2;
93686
+ halfHeight = bounds.height() / 2;
93687
+ } else if (bounds.x !== void 0 && bounds.X !== void 0) {
93688
+ cx = (bounds.x + bounds.X) / 2;
93689
+ cy = (bounds.y + bounds.Y) / 2;
93690
+ halfWidth = (bounds.X - bounds.x) / 2;
93691
+ halfHeight = (bounds.Y - bounds.y) / 2;
93692
+ } else {
93693
+ return targetPoint;
93694
+ }
93695
+ const dx = targetPoint.x - cx;
93696
+ const dy = targetPoint.y - cy;
93697
+ const normalizedDx = Math.abs(dx) / halfWidth;
93698
+ const normalizedDy = Math.abs(dy) / halfHeight;
93699
+ if (normalizedDx > normalizedDy) {
93700
+ if (dx > 0) {
93701
+ return { x: cx + halfWidth, y: cy };
93702
+ } else {
93703
+ return { x: cx - halfWidth, y: cy };
93704
+ }
93705
+ } else {
93706
+ if (dy > 0) {
93707
+ return { x: cx, y: cy + halfHeight };
93708
+ } else {
93709
+ return { x: cx, y: cy - halfHeight };
93710
+ }
93711
+ }
93712
+ }
93713
+ /**
93714
+ * Calculates stable edge path points for drawing during tick/drag operations.
93715
+ * This method avoids jitter by using stable anchor points instead of
93716
+ * dynamic intersection calculations.
93717
+ *
93718
+ * @param source - Source node or group with bounds
93719
+ * @param target - Target node or group with bounds
93720
+ * @returns Array of two points for a simple line path
93721
+ */
93722
+ getStableEdgePath(source, target) {
93723
+ let targetCenter;
93724
+ if (target.bounds && typeof target.bounds.cx === "function") {
93725
+ targetCenter = { x: target.bounds.cx(), y: target.bounds.cy() };
93726
+ } else if (target.bounds) {
93727
+ targetCenter = { x: (target.bounds.x + target.bounds.X) / 2, y: (target.bounds.y + target.bounds.Y) / 2 };
93728
+ } else {
93729
+ targetCenter = { x: target.x || 0, y: target.y || 0 };
93730
+ }
93731
+ let sourceCenter;
93732
+ if (source.bounds && typeof source.bounds.cx === "function") {
93733
+ sourceCenter = { x: source.bounds.cx(), y: source.bounds.cy() };
93734
+ } else if (source.bounds) {
93735
+ sourceCenter = { x: (source.bounds.x + source.bounds.X) / 2, y: (source.bounds.y + source.bounds.Y) / 2 };
93736
+ } else {
93737
+ sourceCenter = { x: source.x || 0, y: source.y || 0 };
93738
+ }
93739
+ const sourceAnchor = source.bounds || source.innerBounds ? this.getStableEdgeAnchor(source.bounds || source.innerBounds, targetCenter) : sourceCenter;
93740
+ const targetAnchor = target.bounds || target.innerBounds ? this.getStableEdgeAnchor(target.bounds || target.innerBounds, sourceCenter) : targetCenter;
93741
+ return [sourceAnchor, targetAnchor];
93742
+ }
93663
93743
  /**
93664
93744
  * Adjusts a point to lie on the perimeter of a rectangle.
93665
93745
  *
@@ -94720,6 +94800,7 @@ VVbdfjptxz|~\x80\x82\x84\xA6\xA8W\b
94720
94800
  * - Temporary UI elements (modals, overlays)
94721
94801
  */
94722
94802
  dispose() {
94803
+ this.detachInputModeListeners();
94723
94804
  this.deactivateInputMode();
94724
94805
  if (this.svg) {
94725
94806
  this.svg.on(".zoom", null);
@@ -95534,7 +95615,7 @@ VVbdfjptxz|~\x80\x82\x84\xA6\xA8W\b
95534
95615
  init_layoutspec();
95535
95616
  exports.StructuredInputGraph = class extends WebColaCnDGraph {
95536
95617
  constructor(dataInstance) {
95537
- super();
95618
+ super(true);
95538
95619
  this.evaluator = null;
95539
95620
  this.layoutInstance = null;
95540
95621
  this.cndSpecString = "";