Skip to content

Commit 5f7dcf0

Browse files
fix(library): keep a native-handle connection in its previewed lane and shape
Two preview-versus-commit gaps for a new connection: - The valid onConnect path minted a fresh edge id instead of reusing the preview's pendingConnectionId, so parallel native-handle connections could re-lane the instant the ghost was released (sibling lanes are settled by edge id). - The pending preview edge dropped its source/target handles, but straight-hook edge types (use-case, syntax-tree, Petri-net) resolve their endpoints through getEdgePosition, which reads those handles — so the ghost could attach at a different point than the committed edge. Carry the same handles the commit uses. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 228403f commit 5f7dcf0

2 files changed

Lines changed: 20 additions & 1 deletion

File tree

library/lib/components/ReconnectConnectionLine.tsx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import {
2323
adjustTargetCoordinates,
2424
getDefaultEdgeType,
2525
getEdgeMarkerStyles,
26+
getSideHandleIdForPosition,
2627
preserveOrthogonalEdgePoints,
2728
routeOrthogonalPath,
2829
} from "@/utils/edgeUtils"
@@ -98,6 +99,7 @@ export const ReconnectConnectionLine = ({
9899
connectionLineStyle,
99100
connectionLineType,
100101
fromNode,
102+
fromHandle,
101103
fromX,
102104
fromY,
103105
toX,
@@ -216,12 +218,23 @@ export const ReconnectConnectionLine = ({
216218
const pinnedTargetAnchor = newConnection.targetId
217219
? newConnection.targetAnchor
218220
: null
221+
// The handles the commit will assign (source: the one the drag started on; target:
222+
// the side the drop resolved to). Straight-hook edge types — use-case, syntax-tree,
223+
// Petri-net — resolve their endpoints through `getEdgePosition`, which reads these
224+
// handles, so the preview must carry them or its line attaches at a different point
225+
// than the committed edge.
226+
const previewSourceHandle = fromHandle?.id ?? undefined
227+
const previewTargetHandle = newConnection.targetId
228+
? getSideHandleIdForPosition(newConnection.toPosition)
229+
: undefined
219230
const pendingEdge = useMemo<Edge | null>(() => {
220231
if (!isNewConnection || !fromNodeId || !newConnection.targetId) return null
221232
return {
222233
id: pendingEdgeId,
223234
source: fromNodeId,
224235
target: newConnection.targetId,
236+
sourceHandle: previewSourceHandle,
237+
targetHandle: previewTargetHandle,
225238
type: previewEdgeType,
226239
data: pinnedTargetAnchor
227240
? { points: [], targetAnchor: pinnedTargetAnchor }
@@ -231,6 +244,8 @@ export const ReconnectConnectionLine = ({
231244
isNewConnection,
232245
fromNodeId,
233246
newConnection.targetId,
247+
previewSourceHandle,
248+
previewTargetHandle,
234249
pinnedTargetAnchor,
235250
previewEdgeType,
236251
pendingEdgeId,

library/lib/hooks/useConnect.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,11 @@ export const useConnect = () => {
202202

203203
const newEdge: Edge = {
204204
...connection,
205-
id: generateUUID(),
205+
// Reuse the id minted for the live preview (see onConnectStart) so a native
206+
// handle-drop commits into the SAME fan lane it previewed in — sibling lanes
207+
// are settled by edge id, so a fresh id here would re-lane parallel
208+
// connections on release. Falls back to a new id if the gesture had none.
209+
id: pendingConnectionId.current ?? generateUUID(),
206210
type: defaultEdgeType,
207211
selected: false,
208212
}

0 commit comments

Comments
 (0)