@@ -94,6 +94,15 @@ const useStore = defineStore("store", {
9494 "Media" ,
9595 "Advanced" ,
9696 ] as BlockTemplate [ "category" ] [ ] ,
97+ isDragging : false ,
98+ isDropping : false ,
99+ dropTarget : {
100+ x : < number | null > null ,
101+ y : < number | null > null ,
102+ placeholder : < HTMLElement | null > null ,
103+ parentBlock : < Block | null > null ,
104+ index : < number | null > null ,
105+ }
97106 } ) ,
98107 actions : {
99108 clearBlocks ( ) {
@@ -546,6 +555,75 @@ const useStore = defineStore("store", {
546555 fragmentId : null ,
547556 } ;
548557 } ,
558+ // drag and drop
559+ handleDragStart ( ev : DragEvent ) {
560+ if ( ev . target && ev . dataTransfer ) {
561+ this . isDragging = true ;
562+ const ghostScale = this . activeCanvas ?. canvasProps . scale ;
563+
564+ // Clone the entire draggable element
565+ const dragElement = ( ev . target as HTMLElement )
566+ if ( ! dragElement ) return ;
567+ const ghostDiv = document . createElement ( "div" ) ;
568+ const ghostElement = dragElement . cloneNode ( true ) as HTMLElement ;
569+ ghostDiv . appendChild ( ghostElement ) ;
570+ ghostDiv . id = "ghost" ;
571+ ghostDiv . style . position = "fixed" ;
572+ ghostDiv . style . transform = `scale(${ ghostScale || 1 } )` ;
573+ ghostDiv . style . pointerEvents = "none" ;
574+ ghostDiv . style . zIndex = "99999" ;
575+ // Append the ghostDiv to the DOM
576+ document . body . appendChild ( ghostDiv ) ;
577+
578+ // Wait for the next frame to ensure the ghostDiv is rendered
579+ requestAnimationFrame ( ( ) => {
580+ ev . dataTransfer ?. setDragImage ( ghostDiv , 0 , 0 ) ;
581+ // Clean up the ghostDiv after a short delay
582+ setTimeout ( ( ) => {
583+ document . body . removeChild ( ghostDiv ) ;
584+ } , 0 ) ;
585+ } ) ;
586+ this . insertDropPlaceholder ( ) ;
587+ }
588+ } ,
589+ handleDragEnd ( ) {
590+ // check flag to avoid race condition with async onDrop
591+ if ( ! this . isDropping ) {
592+ this . resetDropTarget ( ) ;
593+ }
594+ } ,
595+ resetDropTarget ( ) {
596+ this . removeDropPlaceholder ( ) ;
597+ this . dropTarget = {
598+ x : null ,
599+ y : null ,
600+ placeholder : null ,
601+ parentBlock : null ,
602+ index : null ,
603+ }
604+ this . isDragging = false
605+ this . isDropping = false
606+ } ,
607+ insertDropPlaceholder ( ) {
608+ // append placeholder component to the dom directly
609+ // to avoid re-rendering the whole canvas
610+ if ( this . dropTarget . placeholder ) return ;
611+
612+ let element = document . createElement ( "div" ) ;
613+ element . id = "placeholder" ;
614+
615+ const root = document . querySelector ( ".__builder_component__[data-block-id='root']" ) ;
616+ if ( root ) {
617+ this . dropTarget . placeholder = root . appendChild ( element ) ;
618+ }
619+ return this . dropTarget . placeholder ;
620+ } ,
621+ removeDropPlaceholder ( ) {
622+ const placeholder = document . getElementById ( "placeholder" )
623+ if ( placeholder ) {
624+ placeholder . remove ( )
625+ }
626+ }
549627 } ,
550628} ) ;
551629
0 commit comments