From bbf732266b688228474eca7128d3c22ef4f213bb Mon Sep 17 00:00:00 2001 From: shrimbly Date: Thu, 19 Feb 2026 13:49:26 +1300 Subject: [PATCH] fix: prevent copied nodes from executing original on first run after paste Two fixes in pasteNodes: 1. Deep copy node data with JSON.parse/stringify (was shallow spread) 2. requestAnimationFrame selection correction to override React Flow's stale selection reconciliation that could re-select original nodes Co-Authored-By: Claude Opus 4.6 --- src/store/workflowStore.ts | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/store/workflowStore.ts b/src/store/workflowStore.ts index a0e86678..79343ac7 100644 --- a/src/store/workflowStore.ts +++ b/src/store/workflowStore.ts @@ -569,7 +569,7 @@ export const useWorkflowStore = create((set, get) => ({ y: node.position.y + offset.y, }, selected: true, // Select newly pasted nodes - data: { ...node.data }, // Deep copy data + data: JSON.parse(JSON.stringify(node.data)), })); // Create new edges with updated source/target IDs @@ -591,6 +591,20 @@ export const useWorkflowStore = create((set, get) => ({ edges: [...edges, ...newEdges], hasUnsavedChanges: true, }); + + // Fix React Flow selection race condition: After paste, React Flow's internal + // reconciliation may fire onNodesChange with stale selection state that re-selects + // original nodes. Schedule an explicit selection correction after reconciliation. + const newNodeIdSet = new Set(newNodes.map(n => n.id)); + requestAnimationFrame(() => { + const currentNodes = get().nodes; + const selectionChanges: NodeChange[] = currentNodes.map(n => ({ + type: 'select' as const, + id: n.id, + selected: newNodeIdSet.has(n.id), + })); + get().onNodesChange(selectionChanges); + }); }, clearClipboard: () => {