@@ -48,7 +48,6 @@ import {
4848 getClampedPositionForNode ,
4949 isInEditableElement ,
5050 resolveParentChildSelectionConflicts ,
51- selectNodesDeferred ,
5251 useAutoLayout ,
5352 useCurrentWorkflow ,
5453 useNodeUtilities ,
@@ -358,6 +357,9 @@ const WorkflowContent = React.memo(() => {
358357 new Map ( )
359358 )
360359
360+ /** Stores node IDs to select on next derivedNodes sync (for paste/duplicate operations). */
361+ const pendingSelectionRef = useRef < Set < string > | null > ( null )
362+
361363 /** Re-applies diff markers when blocks change after socket rehydration. */
362364 const blocksRef = useRef ( blocks )
363365 useEffect ( ( ) => {
@@ -689,19 +691,16 @@ const WorkflowContent = React.memo(() => {
689691 return
690692 }
691693
694+ // Set pending selection before adding blocks - sync effect will apply it
695+ pendingSelectionRef . current = new Set ( pastedBlocksArray . map ( ( b ) => b . id ) )
696+
692697 collaborativeBatchAddBlocks (
693698 pastedBlocksArray ,
694699 pastedEdges ,
695700 pastedLoops ,
696701 pastedParallels ,
697702 pastedSubBlockValues
698703 )
699-
700- selectNodesDeferred (
701- pastedBlocksArray . map ( ( b ) => b . id ) ,
702- setDisplayNodes ,
703- blocks
704- )
705704 } , [
706705 hasClipboard ,
707706 clipboard ,
@@ -738,19 +737,16 @@ const WorkflowContent = React.memo(() => {
738737 return
739738 }
740739
740+ // Set pending selection before adding blocks - sync effect will apply it
741+ pendingSelectionRef . current = new Set ( pastedBlocksArray . map ( ( b ) => b . id ) )
742+
741743 collaborativeBatchAddBlocks (
742744 pastedBlocksArray ,
743745 pastedEdges ,
744746 pastedLoops ,
745747 pastedParallels ,
746748 pastedSubBlockValues
747749 )
748-
749- selectNodesDeferred (
750- pastedBlocksArray . map ( ( b ) => b . id ) ,
751- setDisplayNodes ,
752- blocks
753- )
754750 } , [
755751 contextMenuBlocks ,
756752 copyBlocks ,
@@ -884,19 +880,16 @@ const WorkflowContent = React.memo(() => {
884880 return
885881 }
886882
883+ // Set pending selection before adding blocks - sync effect will apply it
884+ pendingSelectionRef . current = new Set ( pastedBlocks . map ( ( b ) => b . id ) )
885+
887886 collaborativeBatchAddBlocks (
888887 pastedBlocks ,
889888 pasteData . edges ,
890889 pasteData . loops ,
891890 pasteData . parallels ,
892891 pasteData . subBlockValues
893892 )
894-
895- selectNodesDeferred (
896- pastedBlocks . map ( ( b ) => b . id ) ,
897- setDisplayNodes ,
898- blocks
899- )
900893 }
901894 }
902895 }
@@ -1959,15 +1952,27 @@ const WorkflowContent = React.memo(() => {
19591952 } , [ isShiftPressed ] )
19601953
19611954 useEffect ( ( ) => {
1962- // Preserve selection state when syncing from derivedNodes
1955+ // Check for pending selection (from paste/duplicate), otherwise preserve existing selection
1956+ const pendingSelection = pendingSelectionRef . current
1957+ pendingSelectionRef . current = null
1958+
19631959 setDisplayNodes ( ( currentNodes ) => {
1960+ if ( pendingSelection ) {
1961+ // Apply pending selection and resolve parent-child conflicts
1962+ const withSelection = derivedNodes . map ( ( node ) => ( {
1963+ ...node ,
1964+ selected : pendingSelection . has ( node . id ) ,
1965+ } ) )
1966+ return resolveParentChildSelectionConflicts ( withSelection , blocks )
1967+ }
1968+ // Preserve existing selection state
19641969 const selectedIds = new Set ( currentNodes . filter ( ( n ) => n . selected ) . map ( ( n ) => n . id ) )
19651970 return derivedNodes . map ( ( node ) => ( {
19661971 ...node ,
19671972 selected : selectedIds . has ( node . id ) ,
19681973 } ) )
19691974 } )
1970- } , [ derivedNodes ] )
1975+ } , [ derivedNodes , blocks ] )
19711976
19721977 /** Handles ActionBar remove-from-subflow events. */
19731978 useEffect ( ( ) => {
0 commit comments