@@ -33,7 +33,7 @@ import type React from 'react'
3333import { useCallback , useState } from 'react'
3434
3535import { useCurrentFile } from '../atoms/current-file'
36- import { useFileTreeStore } from '../atoms/file-tree'
36+ import { useDraggableNode , useFileTreeStore } from '../atoms/file-tree'
3737import type { FileNode } from '../services/types'
3838import { getWebContainerInstance , readAllFiles } from '../services/webcontainer'
3939
@@ -56,12 +56,6 @@ interface FileTreeProps {
5656 ) => Promise < void >
5757}
5858
59- interface DragState {
60- path : string
61- isDirectory : boolean
62- name : string
63- }
64-
6559export function FileTree ( {
6660 nodes,
6761 onFileSelect,
@@ -79,6 +73,8 @@ export function FileTree({
7973 setLastClickedItem,
8074 setHighlightedFolderPath,
8175 } = useFileTreeStore ( )
76+ const draggable = useDraggableNode ( )
77+
8278 const [ expandedFolders , setExpandedFolders ] = useState < Set < string > > (
8379 new Set ( nodes . filter ( ( n ) => n . type === 'directory' ) . map ( ( n ) => n . path ) )
8480 )
@@ -109,16 +105,15 @@ export function FileTree({
109105 e . preventDefault ( )
110106 e . stopPropagation ( )
111107
112- if ( dragState && dragState . path . includes ( '/' ) ) {
113- const hasCollision = nodes . some ( ( n ) => n . name === dragState . name )
108+ if ( draggable . active && draggable . path . includes ( '/' ) ) {
109+ const hasCollision = nodes . some ( ( n ) => n . name === draggable . name )
114110 if ( hasCollision ) {
115111 e . dataTransfer . dropEffect = 'none'
116112 return
117113 }
118114 }
119115
120116 e . dataTransfer . dropEffect = 'move'
121- setIsRootDragOver ( true )
122117 setHighlightedFolderPath ( '' )
123118 }
124119
@@ -133,28 +128,26 @@ export function FileTree({
133128 y <= rect . top ||
134129 y >= rect . bottom
135130 ) {
136- setIsRootDragOver ( false )
137131 setHighlightedFolderPath ( null )
138132 }
139133 }
140134
141135 const handleRootDrop = async ( e : React . DragEvent ) => {
142136 e . preventDefault ( )
143137 e . stopPropagation ( )
144- setIsRootDragOver ( false )
145138 setHighlightedFolderPath ( null )
146139
147- if ( ! onMove || ! dragState ) return
140+ if ( ! onMove || ! draggable . active ) return
148141
149- const hasCollision = nodes . some ( ( n ) => n . name === dragState . name )
142+ const hasCollision = nodes . some ( ( n ) => n . name === draggable . name )
150143 if ( hasCollision ) {
151144 print . warn ( 'Cannot move to root: item with same name already exists' )
152145 return
153146 }
154147
155148 try {
156- const sourcePath = dragState . path
157- const isDirectory = dragState . isDirectory
149+ const sourcePath = draggable . path
150+ const isDirectory = draggable . isDirectory
158151
159152 if ( sourcePath . includes ( '/' ) ) {
160153 const fileName = sourcePath . split ( '/' ) . pop ( )
@@ -207,9 +200,8 @@ export function FileTree({
207200 }
208201
209202 const handleRootDragEnd = ( ) => {
210- setIsRootDragOver ( false )
211203 setHighlightedFolderPath ( null )
212- setDragState ( null )
204+ draggable . reset ( )
213205 }
214206
215207 const handleStartCreateItem = ( type : 'file' | 'folder' ) => {
@@ -316,7 +308,7 @@ export function FileTree({
316308 </ div >
317309
318310 < div
319- className = { ` transition-colors min-h-[200px] ${ isRootDragOver ? 'bg-primary/10' : '' } ` }
311+ className = " transition-colors min-h-[200px]"
320312 onDragOver = { handleRootDragOver }
321313 onDragLeave = { handleRootDragLeave }
322314 onDrop = { handleRootDrop }
@@ -366,8 +358,6 @@ export function FileTree({
366358 level = { 0 }
367359 expandedFolders = { expandedFolders }
368360 setExpandedFolders = { setExpandedFolders }
369- dragState = { dragState }
370- setDragState = { setDragState }
371361 allNodes = { nodes }
372362 onCreateItem = { handleCreateItem }
373363 onCancelCreateItem = { handleCancelCreateItem }
@@ -415,8 +405,6 @@ export function FileTree({
415405 level = { 0 }
416406 expandedFolders = { expandedFolders }
417407 setExpandedFolders = { setExpandedFolders }
418- dragState = { dragState }
419- setDragState = { setDragState }
420408 allNodes = { nodes }
421409 onCreateItem = { handleCreateItem }
422410 onCancelCreateItem = { handleCancelCreateItem }
@@ -428,12 +416,6 @@ export function FileTree({
428416 </ >
429417 )
430418 } ) ( ) }
431-
432- { isRootDragOver && (
433- < div className = "p-4 text-center text-sm text-muted-foreground border-2 border-dashed border-primary rounded m-2" >
434- Drop here to move to root folder
435- </ div >
436- ) }
437419 </ div >
438420 </ div >
439421 )
@@ -457,8 +439,6 @@ interface FileTreeNodeProps {
457439 level : number
458440 expandedFolders : Set < string >
459441 setExpandedFolders : React . Dispatch < React . SetStateAction < Set < string > > >
460- dragState : DragState | null
461- setDragState : React . Dispatch < React . SetStateAction < DragState | null > >
462442 allNodes ?: FileNode [ ]
463443 onCreateItem ?: ( ) => Promise < void >
464444 onCancelCreateItem ?: ( ) => void
@@ -477,8 +457,6 @@ function FileTreeNode({
477457 level,
478458 expandedFolders,
479459 setExpandedFolders,
480- dragState,
481- setDragState,
482460 allNodes,
483461 onCreateItem,
484462 onCancelCreateItem,
@@ -496,10 +474,10 @@ function FileTreeNode({
496474 const [ showDeleteDialog , setShowDeleteDialog ] = useState ( false )
497475 const [ isRenaming , setIsRenaming ] = useState ( false )
498476 const [ renameValue , setRenameValue ] = useState ( node . name )
499- const [ isDragOver , setIsDragOver ] = useState ( false )
500477 const isSelected = selectedFile === node . path
501478 const isExpanded = expandedFolders . has ( node . path )
502479 const isLastClickedItem = lastClickedItemPath === node . path
480+ const draggable = useDraggableNode ( )
503481
504482 const isHighlighted =
505483 highlightedFolderPath !== null &&
@@ -621,18 +599,18 @@ function FileTreeNode({
621599 isDirectory : node . type === 'directory' ,
622600 } )
623601 )
624- setDragState ( {
625- path : node . path ,
626- isDirectory : node . type === 'directory' ,
602+ draggable . set ( {
627603 name : node . name ,
604+ isDirectory : node . type === 'directory' ,
605+ path : node . path ,
628606 } )
629607 }
630608
631609 const handleDragOver = ( e : React . DragEvent ) => {
632610 e . preventDefault ( )
633611 e . stopPropagation ( )
634612
635- if ( ! dragState ) return
613+ if ( ! draggable . active ) return
636614
637615 let targetFolder : string
638616 if ( node . type === 'directory' ) {
@@ -643,30 +621,28 @@ function FileTreeNode({
643621 pathParts . length > 1 ? pathParts . slice ( 0 , - 1 ) . join ( '/' ) : ''
644622 }
645623
646- const sourceParent = dragState . path . includes ( '/' )
647- ? dragState . path . substring ( 0 , dragState . path . lastIndexOf ( '/' ) )
624+ const sourceParent = draggable . path . includes ( '/' )
625+ ? draggable . path . substring ( 0 , draggable . path . lastIndexOf ( '/' ) )
648626 : ''
649627
650628 const isSameParent = sourceParent === targetFolder
651629 const isMovingIntoSelf =
652- dragState . path === targetFolder ||
653- node . path . startsWith ( dragState . path + '/' )
630+ draggable . path === targetFolder ||
631+ node . path . startsWith ( draggable . path + '/' )
654632
655633 const targetChildren =
656634 node . type === 'directory'
657635 ? node . children || [ ]
658636 : getNodesInFolder ( targetFolder )
659637 const hasCollision = targetChildren . some (
660- ( child ) => child . name === dragState . name
638+ ( child ) => child . name === draggable . name
661639 )
662640
663641 if ( isSameParent || isMovingIntoSelf || hasCollision ) {
664642 e . dataTransfer . dropEffect = 'none'
665- setIsDragOver ( false )
666643 setHighlightedFolderPath ( null )
667644 } else {
668645 e . dataTransfer . dropEffect = 'move'
669- setIsDragOver ( true )
670646 setHighlightedFolderPath ( targetFolder )
671647 }
672648 }
@@ -682,29 +658,26 @@ function FileTreeNode({
682658 y <= rect . top ||
683659 y >= rect . bottom
684660 ) {
685- setIsDragOver ( false )
686661 setHighlightedFolderPath ( null )
687662 }
688663 }
689664
690665 const handleDragEnd = ( ) => {
691- setIsDragOver ( false )
692666 setHighlightedFolderPath ( null )
693- setDragState ( null )
667+ draggable . reset ( )
694668 }
695669
696670 const handleDrop = async ( e : React . DragEvent ) => {
697671 e . preventDefault ( )
698672 e . stopPropagation ( )
699- setIsDragOver ( false )
700673 setHighlightedFolderPath ( null )
701674
702- if ( ! onMove || ! dragState ) return
675+ if ( ! onMove || ! draggable . active ) return
703676
704677 try {
705- const sourcePath = dragState . path
706- const isDirectory = dragState . isDirectory
707- const sourceName = dragState . name
678+ const sourcePath = draggable . path
679+ const isDirectory = draggable . isDirectory
680+ const sourceName = draggable . name
708681
709682 let targetFolder : string
710683
@@ -773,11 +746,10 @@ function FileTreeNode({
773746 < div >
774747 < div
775748 className = { cn (
776- 'flex items-center gap-1 px-2 py-1 cursor-pointer hover:bg-accent transition-colors group' ,
749+ 'flex items-center gap-1 px-2 py-1 cursor-pointer hover:bg-accent transition-colors group border-l-2 border-transparent ' ,
777750 isSelected && 'bg-accent text-accent-foreground' ,
778751 isLastClickedItem && 'bg-accent text-accent-foreground' ,
779- isDragOver && 'border-l-2 border-primary' ,
780- isHighlighted && 'bg-primary/10'
752+ isHighlighted && 'border-primary bg-primary/10'
781753 ) }
782754 style = { { paddingLeft : `${ level * 12 + 8 } px` } }
783755 onClick = { handleClick }
@@ -900,8 +872,6 @@ function FileTreeNode({
900872 level = { level + 1 }
901873 expandedFolders = { expandedFolders }
902874 setExpandedFolders = { setExpandedFolders }
903- dragState = { dragState }
904- setDragState = { setDragState }
905875 allNodes = { allNodes }
906876 onCreateItem = { onCreateItem }
907877 onCancelCreateItem = { onCancelCreateItem }
@@ -949,8 +919,6 @@ function FileTreeNode({
949919 level = { level + 1 }
950920 expandedFolders = { expandedFolders }
951921 setExpandedFolders = { setExpandedFolders }
952- dragState = { dragState }
953- setDragState = { setDragState }
954922 allNodes = { allNodes }
955923 onCreateItem = { onCreateItem }
956924 onCancelCreateItem = { onCancelCreateItem }
0 commit comments