import type { Fn } from "@thi.ng/api" ; import { div } from "@thi.ng/hiccup-html/blocks" ; import type { ComponentLike , NumOrElement } from "@thi.ng/rdom" ; import { Component } from "@thi.ng/rdom/component" ; interface DraggableOpts { scope ? : string ; dropzone : string ; start : any ; hover : any ; end : any ; onstart ? : Fn < DragEvent , void > ; onend ? : Fn < DragEvent , void > ; ondrop ? : Fn < DragEvent , void > ; } export class Draggable extends Component { protected opts : DraggableOpts ; protected active = false ; constructor ( protected inner , opts ? ) { super ( ) ; this . opts = { dropzone : "dropzone" , start : { opacity : 0.5 } , end : { opacity : null } , hover : { background : "yellow" } , ... opts , } ; } async mount ( parent , index ) { const opts = this . opts ; this . el = await this . $tree ( div ( { draggable : true , ondragstart : ( e ) => { e . dataTransfer ! . setData ( "text/plain" , "" ) ; this . active = true ; this . $style ( opts . start ) ; opts . onstart && opts . onstart ( e ) ; } , ondragend : ( e ) => { this . active = false ; this . $style ( opts . end ) ; opts . onend && opts . onend ( e ) ; } , } , this . inner ) , parent , index ) ; const isDropZone = ( e ) => this . active && ( < HTMLElement > e . target ) . dataset . dropzone === opts . dropzone ; const undoHover = objWithNull ( opts . hover ) ; this . $attribs ( { ondragover : ( e ) => e . preventDefault ( ) , ondragenter : ( e ) => isDropZone ( e ) && this . $style ( opts . hover , < Element > e . target ) , ondragleave : ( e ) => isDropZone ( e ) && this . $style ( undoHover , < Element > e . target ) , ondrop : ( e ) => { e . preventDefault ( ) ; if ( isDropZone ( e ) ) { this . $style ( opts . end ) ; this . $style ( undoHover , < Element > e . target ) ; this . $moveTo ( < Element > e . target ) ; opts . ondrop && opts . ondrop ( e ) ; } this . active = false ; opts . onend && opts . onend ( e ) ; } , } , this . opts . scope ? document . getElementById ( this . opts . scope ) ! : < any > document ) ; return this . el ! ; } } const objWithNull = ( obj ) => Object . keys ( obj ) . reduce ( ( acc , id ) => ( ( acc [ id ] = null ) , acc ) , { } ) ;