reactflow-edge-routing 0.1.1 → 0.1.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.
- package/package.json +1 -1
- package/src/routing-core.ts +85 -77
- package/src/use-edge-routing.ts +9 -8
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "reactflow-edge-routing",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "Orthogonal edge routing for React Flow using obstacle-router. Edges route around nodes while pins stay fixed at their anchor points.",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"types": "./src/index.ts",
|
package/src/routing-core.ts
CHANGED
|
@@ -114,10 +114,10 @@ export type AvoidRouterOptions = {
|
|
|
114
114
|
edgeRounding?: number;
|
|
115
115
|
/** Snap waypoints to grid. Default: 0 (no grid) */
|
|
116
116
|
diagramGridSize?: number;
|
|
117
|
-
/**
|
|
118
|
-
shouldSplitEdgesNearHandle?: boolean;
|
|
119
|
-
/** Length (px) of the stub segment when shouldSplitEdgesNearHandle is off. Default: 20 */
|
|
117
|
+
/** Length (px) of the stub exit segment from the node border. Default: 20 */
|
|
120
118
|
stubSize?: number;
|
|
119
|
+
/** When true, each edge gets its own stub spread laterally by handleSpacing (fan-out at handle). When false, all edges share one stub exit point and libavoid routes them apart after. Default: true */
|
|
120
|
+
shouldSplitEdgesNearHandle?: boolean;
|
|
121
121
|
/** Auto-select best connection side based on relative node positions. Default: true */
|
|
122
122
|
autoBestSideConnection?: boolean;
|
|
123
123
|
/** Debounce delay for routing updates (ms). Default: 0 */
|
|
@@ -613,10 +613,8 @@ function configureRouter(router: AvoidRouter, options: AvoidRouterOptions): void
|
|
|
613
613
|
}
|
|
614
614
|
|
|
615
615
|
// --- Routing options ---
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
router.setRoutingOption(nudgeOrthogonalSegmentsConnectedToShapesOpt, splitNearHandle ? (options.nudgeOrthogonalSegmentsConnectedToShapes ?? true) : false);
|
|
619
|
-
router.setRoutingOption(nudgeSharedPathsWithCommonEndPointOpt, splitNearHandle ? (options.nudgeSharedPathsWithCommonEndPoint ?? true) : false);
|
|
616
|
+
router.setRoutingOption(nudgeOrthogonalSegmentsConnectedToShapesOpt, options.nudgeOrthogonalSegmentsConnectedToShapes ?? true);
|
|
617
|
+
router.setRoutingOption(nudgeSharedPathsWithCommonEndPointOpt, options.nudgeSharedPathsWithCommonEndPoint ?? true);
|
|
620
618
|
router.setRoutingOption(performUnifyingNudgingPreprocessingStepOpt, options.performUnifyingNudgingPreprocessingStep ?? true);
|
|
621
619
|
router.setRoutingOption(nudgeOrthogonalTouchingColinearSegmentsOpt, options.nudgeOrthogonalTouchingColinearSegments ?? false);
|
|
622
620
|
router.setRoutingOption(improveHyperedgeRoutesMovingJunctionsOpt, options.improveHyperedgeRoutesMovingJunctions ?? true);
|
|
@@ -686,17 +684,6 @@ function createObstacles(
|
|
|
686
684
|
}
|
|
687
685
|
|
|
688
686
|
|
|
689
|
-
/**
|
|
690
|
-
* Find the first enriched pin matching a handle type (source/target).
|
|
691
|
-
* Used when edge.sourceHandle/targetHandle is null (default handles).
|
|
692
|
-
*/
|
|
693
|
-
function findDefaultHandle(node: FlowNode, kind: "source" | "target"): string | null {
|
|
694
|
-
const pins = (node._handlePins as HandlePin[] | undefined) ?? [];
|
|
695
|
-
// Enriched pins from default handles are named __source_N or __target_N
|
|
696
|
-
const prefix = `__${kind}_`;
|
|
697
|
-
const pin = pins.find((p) => p.handleId.startsWith(prefix));
|
|
698
|
-
return pin?.handleId ?? null;
|
|
699
|
-
}
|
|
700
687
|
|
|
701
688
|
|
|
702
689
|
/** Offset a point away from the node border by stubLength in the direction of the side */
|
|
@@ -709,84 +696,109 @@ function offsetFromSide(pt: { x: number; y: number }, side: HandlePosition, stub
|
|
|
709
696
|
}
|
|
710
697
|
}
|
|
711
698
|
|
|
712
|
-
/**
|
|
699
|
+
/** Shift a point laterally along a node border (perpendicular to the exit direction) */
|
|
700
|
+
function applyLateralOffset(pt: { x: number; y: number }, side: HandlePosition, offset: number): { x: number; y: number } {
|
|
701
|
+
switch (side) {
|
|
702
|
+
case "left":
|
|
703
|
+
case "right": return { x: pt.x, y: pt.y + offset };
|
|
704
|
+
case "top":
|
|
705
|
+
case "bottom": return { x: pt.x + offset, y: pt.y };
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
|
|
710
|
+
/** Info needed to add stubs after routing */
|
|
713
711
|
type StubInfo = {
|
|
714
712
|
edgeId: string;
|
|
715
713
|
srcHandlePt: { x: number; y: number };
|
|
716
714
|
tgtHandlePt: { x: number; y: number };
|
|
715
|
+
srcStubPt: { x: number; y: number };
|
|
716
|
+
tgtStubPt: { x: number; y: number };
|
|
717
|
+
merged: boolean; // true = shared stub mode (splitNearHandle=false)
|
|
717
718
|
};
|
|
718
719
|
|
|
719
720
|
function createConnections(
|
|
720
721
|
router: AvoidRouter,
|
|
721
722
|
edges: FlowEdge[],
|
|
722
723
|
nodeById: Map<string, FlowNode>,
|
|
723
|
-
shapeRefMap: Map<string, AvoidShapeRef>,
|
|
724
|
-
pinRegistry: PinRegistry,
|
|
725
724
|
options: AvoidRouterOptions
|
|
726
725
|
): { connRefs: { edgeId: string; connRef: AvoidConnRef }[]; stubs: StubInfo[] } {
|
|
727
726
|
const connRefs: { edgeId: string; connRef: AvoidConnRef }[] = [];
|
|
728
727
|
const stubs: StubInfo[] = [];
|
|
729
728
|
const autoBestSide = options.autoBestSideConnection ?? true;
|
|
730
|
-
const splitNearHandle = options.shouldSplitEdgesNearHandle ?? true;
|
|
731
729
|
const stubLength = options.stubSize ?? 20;
|
|
730
|
+
const handleSpacing = options.handleNudgingDistance ?? 0;
|
|
732
731
|
const connType = getConnType(options.connectorType);
|
|
733
732
|
const hateCrossings = options.hateCrossings ?? false;
|
|
734
733
|
|
|
734
|
+
// Pre-pass: group edges by node+side and compute lateral fan-out offsets so each edge
|
|
735
|
+
// gets its own stub spread by handleSpacing pixels along the node border.
|
|
736
|
+
const stubLateralOffsets = new Map<string, { srcOffset: number; tgtOffset: number }>();
|
|
737
|
+
const splitNearHandle = options.shouldSplitEdgesNearHandle ?? true;
|
|
738
|
+
if (splitNearHandle && handleSpacing > 0) {
|
|
739
|
+
const srcGroups = new Map<string, string[]>();
|
|
740
|
+
const tgtGroups = new Map<string, string[]>();
|
|
741
|
+
for (const edge of edges) {
|
|
742
|
+
const src = nodeById.get(edge.source);
|
|
743
|
+
const tgt = nodeById.get(edge.target);
|
|
744
|
+
if (!src || !tgt) continue;
|
|
745
|
+
const sb = Geometry.getNodeBoundsAbsolute(src, nodeById);
|
|
746
|
+
const tb = Geometry.getNodeBoundsAbsolute(tgt, nodeById);
|
|
747
|
+
const srcSide = autoBestSide ? Geometry.getBestSides(sb, tb).sourcePos : Geometry.getHandlePosition(src, "source");
|
|
748
|
+
const tgtSide = autoBestSide ? Geometry.getBestSides(sb, tb).targetPos : Geometry.getHandlePosition(tgt, "target");
|
|
749
|
+
const sk = `${edge.source}:${srcSide}`;
|
|
750
|
+
const tk = `${edge.target}:${tgtSide}`;
|
|
751
|
+
if (!srcGroups.has(sk)) srcGroups.set(sk, []);
|
|
752
|
+
srcGroups.get(sk)!.push(edge.id);
|
|
753
|
+
if (!tgtGroups.has(tk)) tgtGroups.set(tk, []);
|
|
754
|
+
tgtGroups.get(tk)!.push(edge.id);
|
|
755
|
+
}
|
|
756
|
+
for (const [, ids] of srcGroups) {
|
|
757
|
+
const n = ids.length;
|
|
758
|
+
ids.forEach((id, i) => {
|
|
759
|
+
const prev = stubLateralOffsets.get(id) ?? { srcOffset: 0, tgtOffset: 0 };
|
|
760
|
+
prev.srcOffset = (i - (n - 1) / 2) * handleSpacing;
|
|
761
|
+
stubLateralOffsets.set(id, prev);
|
|
762
|
+
});
|
|
763
|
+
}
|
|
764
|
+
for (const [, ids] of tgtGroups) {
|
|
765
|
+
const n = ids.length;
|
|
766
|
+
ids.forEach((id, i) => {
|
|
767
|
+
const prev = stubLateralOffsets.get(id) ?? { srcOffset: 0, tgtOffset: 0 };
|
|
768
|
+
prev.tgtOffset = (i - (n - 1) / 2) * handleSpacing;
|
|
769
|
+
stubLateralOffsets.set(id, prev);
|
|
770
|
+
});
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
|
|
735
774
|
for (const edge of edges) {
|
|
736
775
|
const src = nodeById.get(edge.source);
|
|
737
776
|
const tgt = nodeById.get(edge.target);
|
|
738
777
|
if (!src || !tgt) continue;
|
|
739
778
|
|
|
740
|
-
const srcShapeRef = shapeRefMap.get(edge.source);
|
|
741
|
-
const tgtShapeRef = shapeRefMap.get(edge.target);
|
|
742
|
-
|
|
743
779
|
const srcBounds = Geometry.getNodeBoundsAbsolute(src, nodeById);
|
|
744
780
|
const tgtBounds = Geometry.getNodeBoundsAbsolute(tgt, nodeById);
|
|
745
781
|
|
|
746
782
|
let srcEnd: AvoidConnEnd;
|
|
747
783
|
let tgtEnd: AvoidConnEnd;
|
|
748
784
|
|
|
749
|
-
|
|
750
|
-
//
|
|
751
|
-
|
|
752
|
-
if (srcShapeRef && srcHandle) {
|
|
753
|
-
const pinId = pinRegistry.getOrCreate(edge.source, srcHandle);
|
|
754
|
-
srcEnd = AvoidConnEnd.fromShapePin(srcShapeRef as any, pinId);
|
|
755
|
-
} else if (srcShapeRef) {
|
|
756
|
-
srcEnd = AvoidConnEnd.fromShapePin(srcShapeRef as any, pinRegistry.getOrCreate(edge.source, `__auto_best`));
|
|
757
|
-
} else {
|
|
758
|
-
const side = autoBestSide ? Geometry.getBestSides(srcBounds, tgtBounds).sourcePos : Geometry.getHandlePosition(src, "source");
|
|
759
|
-
srcEnd = (() => { const pt = Geometry.getHandlePoint(srcBounds, side); return AvoidConnEnd.fromPoint(new AvoidPoint(pt.x, pt.y)); })();
|
|
760
|
-
}
|
|
761
|
-
|
|
762
|
-
const tgtHandle = edge.targetHandle ?? (autoBestSide ? null : findDefaultHandle(tgt, "target"));
|
|
763
|
-
if (tgtShapeRef && tgtHandle) {
|
|
764
|
-
const pinId = pinRegistry.getOrCreate(edge.target, tgtHandle);
|
|
765
|
-
tgtEnd = AvoidConnEnd.fromShapePin(tgtShapeRef as any, pinId);
|
|
766
|
-
} else if (tgtShapeRef) {
|
|
767
|
-
tgtEnd = AvoidConnEnd.fromShapePin(tgtShapeRef as any, pinRegistry.getOrCreate(edge.target, `__auto_best`));
|
|
768
|
-
} else {
|
|
769
|
-
const side = autoBestSide ? Geometry.getBestSides(srcBounds, tgtBounds).targetPos : Geometry.getHandlePosition(tgt, "target");
|
|
770
|
-
tgtEnd = (() => { const pt = Geometry.getHandlePoint(tgtBounds, side); return AvoidConnEnd.fromPoint(new AvoidPoint(pt.x, pt.y)); })();
|
|
771
|
-
}
|
|
772
|
-
} else {
|
|
773
|
-
// Point-based with stubs: all edges from the same side converge to center of side,
|
|
774
|
-
// then route from a stub point offset outward
|
|
785
|
+
{
|
|
786
|
+
// Each edge fans out laterally from its side center by handleSpacing,
|
|
787
|
+
// then exits outward via a stub of stubLength before libavoid routes the middle.
|
|
775
788
|
const srcSide = autoBestSide ? Geometry.getBestSides(srcBounds, tgtBounds).sourcePos : Geometry.getHandlePosition(src, "source");
|
|
776
789
|
const tgtSide = autoBestSide ? Geometry.getBestSides(srcBounds, tgtBounds).targetPos : Geometry.getHandlePosition(tgt, "target");
|
|
777
790
|
|
|
778
|
-
|
|
779
|
-
const srcHandlePt = Geometry.getHandlePoint(srcBounds, srcSide);
|
|
780
|
-
const tgtHandlePt = Geometry.getHandlePoint(tgtBounds, tgtSide);
|
|
791
|
+
const lateral = stubLateralOffsets.get(edge.id) ?? { srcOffset: 0, tgtOffset: 0 };
|
|
792
|
+
const srcHandlePt = applyLateralOffset(Geometry.getHandlePoint(srcBounds, srcSide), srcSide, lateral.srcOffset);
|
|
793
|
+
const tgtHandlePt = applyLateralOffset(Geometry.getHandlePoint(tgtBounds, tgtSide), tgtSide, lateral.tgtOffset);
|
|
781
794
|
|
|
782
|
-
// Route from stub endpoints (offset from center of side)
|
|
783
795
|
const srcStubPt = offsetFromSide(srcHandlePt, srcSide, stubLength);
|
|
784
796
|
const tgtStubPt = offsetFromSide(tgtHandlePt, tgtSide, stubLength);
|
|
785
797
|
|
|
786
798
|
srcEnd = AvoidConnEnd.fromPoint(new AvoidPoint(srcStubPt.x, srcStubPt.y));
|
|
787
799
|
tgtEnd = AvoidConnEnd.fromPoint(new AvoidPoint(tgtStubPt.x, tgtStubPt.y));
|
|
788
800
|
|
|
789
|
-
stubs.push({ edgeId: edge.id, srcHandlePt, tgtHandlePt });
|
|
801
|
+
stubs.push({ edgeId: edge.id, srcHandlePt, tgtHandlePt, srcStubPt, tgtStubPt, merged: !splitNearHandle });
|
|
790
802
|
}
|
|
791
803
|
|
|
792
804
|
const connRef = new AvoidConnRef(router as any, srcEnd, tgtEnd);
|
|
@@ -829,8 +841,8 @@ export class RoutingEngine {
|
|
|
829
841
|
const router = createRouter(routerFlags);
|
|
830
842
|
configureRouter(router, opts);
|
|
831
843
|
|
|
832
|
-
const {
|
|
833
|
-
const { connRefs, stubs } = createConnections(router, edges, nodeById,
|
|
844
|
+
const { shapeRefList } = createObstacles(router, nodes, nodeById, pinRegistry, opts);
|
|
845
|
+
const { connRefs, stubs } = createConnections(router, edges, nodeById, opts);
|
|
834
846
|
|
|
835
847
|
const result: Record<string, AvoidRoute> = {};
|
|
836
848
|
try { router.processTransaction(); } catch (e) { console.error("[edge-routing] processTransaction failed:", e); RoutingEngine.cleanup(router, connRefs, shapeRefList); return result; }
|
|
@@ -845,16 +857,13 @@ export class RoutingEngine {
|
|
|
845
857
|
if (stub) {
|
|
846
858
|
points.unshift(stub.srcHandlePt);
|
|
847
859
|
points.push(stub.tgtHandlePt);
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
const handleNudging = opts.handleNudgingDistance ?? idealNudging;
|
|
856
|
-
if (handleNudging !== idealNudging && edgePoints.size > 0) {
|
|
857
|
-
HandleSpacing.adjust(edges, edgePoints, handleNudging, idealNudging);
|
|
860
|
+
// In merged mode (splitNearHandle=false), force the adjacent stub waypoints
|
|
861
|
+
// back to the exact stub endpoints so libavoid's nudging doesn't spread the
|
|
862
|
+
// entry/exit segments — all edges share one visible trunk line to the stub point.
|
|
863
|
+
if (stub.merged && points.length >= 3) {
|
|
864
|
+
points[1] = { ...stub.srcStubPt };
|
|
865
|
+
points[points.length - 2] = { ...stub.tgtStubPt };
|
|
866
|
+
}
|
|
858
867
|
}
|
|
859
868
|
}
|
|
860
869
|
|
|
@@ -992,7 +1001,7 @@ export class PersistentRouter {
|
|
|
992
1001
|
const result = createObstacles(this.router, this.prevNodes, this.nodeById, this.pinRegistry, opts);
|
|
993
1002
|
this.shapeRefMap = result.shapeRefMap;
|
|
994
1003
|
this.shapeRefList = result.shapeRefList;
|
|
995
|
-
const conn = createConnections(this.router, this.prevEdges, this.nodeById,
|
|
1004
|
+
const conn = createConnections(this.router, this.prevEdges, this.nodeById, opts);
|
|
996
1005
|
this.connRefList = conn.connRefs;
|
|
997
1006
|
this.stubList = conn.stubs;
|
|
998
1007
|
|
|
@@ -1004,8 +1013,6 @@ export class PersistentRouter {
|
|
|
1004
1013
|
|
|
1005
1014
|
private readRoutes(): Record<string, AvoidRoute> {
|
|
1006
1015
|
const opts = this.prevOptions;
|
|
1007
|
-
const idealNudging = opts.idealNudgingDistance ?? 10;
|
|
1008
|
-
const handleNudging = opts.handleNudgingDistance ?? idealNudging;
|
|
1009
1016
|
const gridSize = opts.diagramGridSize ?? 0;
|
|
1010
1017
|
const result: Record<string, AvoidRoute> = {};
|
|
1011
1018
|
|
|
@@ -1019,15 +1026,16 @@ export class PersistentRouter {
|
|
|
1019
1026
|
if (stub) {
|
|
1020
1027
|
points.unshift(stub.srcHandlePt);
|
|
1021
1028
|
points.push(stub.tgtHandlePt);
|
|
1029
|
+
// In merged mode (splitNearHandle=false), force the adjacent stub waypoints
|
|
1030
|
+
// back to the exact stub endpoints so libavoid's nudging doesn't spread the
|
|
1031
|
+
// entry/exit segments — all edges share one visible trunk line to the stub point.
|
|
1032
|
+
if (stub.merged && points.length >= 3) {
|
|
1033
|
+
points[1] = { ...stub.srcStubPt };
|
|
1034
|
+
points[points.length - 2] = { ...stub.tgtStubPt };
|
|
1035
|
+
}
|
|
1022
1036
|
}
|
|
1023
1037
|
}
|
|
1024
1038
|
|
|
1025
|
-
// Adjust spacing at shared handles (fan-out effect) — skip when splitNearHandle is off
|
|
1026
|
-
const splitNearHandle = opts.shouldSplitEdgesNearHandle ?? true;
|
|
1027
|
-
if (splitNearHandle && handleNudging !== idealNudging && edgePoints.size > 0) {
|
|
1028
|
-
HandleSpacing.adjust(this.prevEdges, edgePoints, handleNudging, idealNudging);
|
|
1029
|
-
}
|
|
1030
|
-
|
|
1031
1039
|
const connType = opts.connectorType ?? "orthogonal";
|
|
1032
1040
|
for (const [edgeId, points] of edgePoints) {
|
|
1033
1041
|
const edgeRounding = opts.edgeRounding ?? 0;
|
package/src/use-edge-routing.ts
CHANGED
|
@@ -64,10 +64,10 @@ export interface UseEdgeRoutingOptions {
|
|
|
64
64
|
// --- Rendering / layout ---
|
|
65
65
|
edgeRounding?: number;
|
|
66
66
|
diagramGridSize?: number;
|
|
67
|
-
/**
|
|
68
|
-
shouldSplitEdgesNearHandle?: boolean;
|
|
69
|
-
/** Length (px) of the stub segment when shouldSplitEdgesNearHandle is off. Default: 20 */
|
|
67
|
+
/** Length (px) of the stub exit segment from the node border. Default: 20 */
|
|
70
68
|
stubSize?: number;
|
|
69
|
+
/** When true, each edge gets its own stub spread by handleSpacing (fan-out). When false, all edges share one stub and libavoid routes them apart after. Default: true */
|
|
70
|
+
shouldSplitEdgesNearHandle?: boolean;
|
|
71
71
|
autoBestSideConnection?: boolean;
|
|
72
72
|
debounceMs?: number;
|
|
73
73
|
|
|
@@ -90,7 +90,6 @@ const DEFAULT_OPTIONS: UseEdgeRoutingOptions = {
|
|
|
90
90
|
edgeToNodeSpacing: 8,
|
|
91
91
|
handleSpacing: 2,
|
|
92
92
|
diagramGridSize: 0,
|
|
93
|
-
shouldSplitEdgesNearHandle: true,
|
|
94
93
|
autoBestSideConnection: false,
|
|
95
94
|
debounceMs: 0,
|
|
96
95
|
};
|
|
@@ -100,7 +99,7 @@ function toRouterOptions(opts?: UseEdgeRoutingOptions): AvoidRouterOptions {
|
|
|
100
99
|
// Core spacing
|
|
101
100
|
idealNudgingDistance: opts?.edgeToEdgeSpacing ?? DEFAULT_OPTIONS.edgeToEdgeSpacing,
|
|
102
101
|
shapeBufferDistance: opts?.edgeToNodeSpacing ?? DEFAULT_OPTIONS.edgeToNodeSpacing,
|
|
103
|
-
handleNudgingDistance: opts?.handleSpacing ?? DEFAULT_OPTIONS.
|
|
102
|
+
handleNudgingDistance: opts?.handleSpacing ?? opts?.edgeToEdgeSpacing ?? DEFAULT_OPTIONS.edgeToEdgeSpacing,
|
|
104
103
|
|
|
105
104
|
// Routing parameters
|
|
106
105
|
segmentPenalty: opts?.segmentPenalty,
|
|
@@ -128,9 +127,11 @@ function toRouterOptions(opts?: UseEdgeRoutingOptions): AvoidRouterOptions {
|
|
|
128
127
|
// Rendering
|
|
129
128
|
edgeRounding: opts?.edgeRounding ?? DEFAULT_OPTIONS.edgeRounding,
|
|
130
129
|
diagramGridSize: opts?.diagramGridSize ?? DEFAULT_OPTIONS.diagramGridSize,
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
autoBestSideConnection:
|
|
130
|
+
stubSize: opts?.stubSize ?? opts?.edgeToEdgeSpacing ?? DEFAULT_OPTIONS.edgeToEdgeSpacing,
|
|
131
|
+
shouldSplitEdgesNearHandle: opts?.shouldSplitEdgesNearHandle ?? true,
|
|
132
|
+
// bezier defaults to autoBestSideConnection: true — explicit handles
|
|
133
|
+
// make no visual sense on curved paths, so auto-side is the right default.
|
|
134
|
+
autoBestSideConnection: opts?.autoBestSideConnection ?? (opts?.connectorType === "bezier" ? true : DEFAULT_OPTIONS.autoBestSideConnection),
|
|
134
135
|
debounceMs: opts?.debounceMs ?? DEFAULT_OPTIONS.debounceMs,
|
|
135
136
|
};
|
|
136
137
|
}
|