@@ -182,6 +182,8 @@ const WorkflowContent = React.memo(() => {
182182 const [ isCanvasReady , setIsCanvasReady ] = useState ( false )
183183 const [ potentialParentId , setPotentialParentId ] = useState < string | null > ( null )
184184 const [ selectedEdgeInfo , setSelectedEdgeInfo ] = useState < SelectedEdgeInfo | null > ( null )
185+ const [ isShiftPressed , setIsShiftPressed ] = useState ( false )
186+ const [ isSelectionDragActive , setIsSelectionDragActive ] = useState ( false )
185187 const [ isErrorConnectionDrag , setIsErrorConnectionDrag ] = useState ( false )
186188 const [ oauthModal , setOauthModal ] = useState < {
187189 provider : OAuthProvider
@@ -1737,6 +1739,21 @@ const WorkflowContent = React.memo(() => {
17371739 // Local state for nodes - allows smooth drag without store updates on every frame
17381740 const [ displayNodes , setDisplayNodes ] = useState < Node [ ] > ( [ ] )
17391741
1742+ useEffect ( ( ) => {
1743+ const handleKeyDown = ( e : KeyboardEvent ) => {
1744+ if ( e . key === 'Shift' ) setIsShiftPressed ( true )
1745+ }
1746+ const handleKeyUp = ( e : KeyboardEvent ) => {
1747+ if ( e . key === 'Shift' ) setIsShiftPressed ( false )
1748+ }
1749+ window . addEventListener ( 'keydown' , handleKeyDown )
1750+ window . addEventListener ( 'keyup' , handleKeyUp )
1751+ return ( ) => {
1752+ window . removeEventListener ( 'keydown' , handleKeyDown )
1753+ window . removeEventListener ( 'keyup' , handleKeyUp )
1754+ }
1755+ } , [ ] )
1756+
17401757 // Sync derived nodes to display nodes when structure changes
17411758 useEffect ( ( ) => {
17421759 setDisplayNodes ( derivedNodes )
@@ -2390,8 +2407,20 @@ const WorkflowContent = React.memo(() => {
23902407 ]
23912408 )
23922409
2410+ // Lock selection mode when selection drag starts (captures Shift state at drag start)
2411+ const onSelectionStart = useCallback ( ( ) => {
2412+ if ( isShiftPressed ) {
2413+ setIsSelectionDragActive ( true )
2414+ }
2415+ } , [ isShiftPressed ] )
2416+
2417+ const onSelectionEnd = useCallback ( ( ) => {
2418+ requestAnimationFrame ( ( ) => setIsSelectionDragActive ( false ) )
2419+ } , [ ] )
2420+
23932421 const onSelectionDragStop = useCallback (
23942422 ( _event : React . MouseEvent , nodes : any [ ] ) => {
2423+ requestAnimationFrame ( ( ) => setIsSelectionDragActive ( false ) )
23952424 if ( nodes . length === 0 ) return
23962425
23972426 const positionUpdates = nodes . map ( ( node ) => {
@@ -2599,8 +2628,10 @@ const WorkflowContent = React.memo(() => {
25992628 onPointerMove = { handleCanvasPointerMove }
26002629 onPointerLeave = { handleCanvasPointerLeave }
26012630 elementsSelectable = { true }
2602- selectionOnDrag = { true }
2603- panOnDrag = { [ 0 , 1 ] }
2631+ selectionOnDrag = { isShiftPressed || isSelectionDragActive }
2632+ panOnDrag = { isShiftPressed || isSelectionDragActive ? false : [ 0 , 1 ] }
2633+ onSelectionStart = { onSelectionStart }
2634+ onSelectionEnd = { onSelectionEnd }
26042635 multiSelectionKeyCode = { [ 'Meta' , 'Control' ] }
26052636 nodesConnectable = { effectivePermissions . canEdit }
26062637 nodesDraggable = { effectivePermissions . canEdit }
0 commit comments