import { useCallback , useEffect , useState , DragEvent } from 'react' ; import { generateUID } from '../../helpers' ; import useHandler from '../../hooks/useHandler' ; import { DRAG_ITEM_ID_KEY , DRAG_ITEM_KEY } from './constants' ; import './items.scss' ; type AbstractItem = { ID ? : string ; } ; param items param checkedIDs param onCheck param getDragHtml returns const useItemsDraggable = < Item extends AbstractItem > ( items , checkedIDs , onCheck , getDragHtml ) => { const [ dragElement , setDragElement ] = useState < HTMLDivElement > ( ) ; const [ draggedIDs , setDraggedIDs ] = useState < string [ ] > ( [ ] ) ; const [ savedCheck , setSavedCheck ] = useState < string [ ] > ( ) ; useEffect ( ( ) => { setDraggedIDs ( [ ] ) ; } , [ items ] ) ; const clearDragElement = useCallback ( ( ) => { if ( dragElement ) { document . body . removeChild ( dragElement ) ; setDragElement ( undefined ) ; } } , [ setDragElement ] ) ; const handleDragCanceled = useHandler ( ( ) => { setDraggedIDs ( [ ] ) ; if ( savedCheck ) { onCheck ( savedCheck , true , true ) ; setSavedCheck ( undefined ) ; } } ) ; /**
     * Drag end handler to use on the draggable element
     */ const handleDragEnd = useCallback ( ( event ) => { clearDragElement ( ) ; if ( event . dataTransfer . dropEffect === 'none' || event . dataTransfer . dropEffect === 'copy' ) { return handleDragCanceled ( ) ; } } , [ clearDragElement , handleDragCanceled ] ) ; const handleDragSucceed = useHandler ( ( action ) => { clearDragElement ( ) ; setDraggedIDs ( [ ] ) ; if ( savedCheck ) { if ( action === 'link' ) { onCheck ( savedCheck , true , true ) ; } setSavedCheck ( undefined ) ; } } ) ; /**
     * Drag start handler to use on the draggable element
     */ const handleDragStart = useCallback ( ( event , item ) => { clearDragElement ( ) ; const ID = item . ID || '' ; const dragInSelection = checkedIDs . includes ( ID ) ; const selection = dragInSelection ? checkedIDs : [ ID ] ; setDraggedIDs ( selection ) ; setSavedCheck ( checkedIDs ) ; if ( ! dragInSelection ) { onCheck ( [ ] , true , true ) ; } const dragElement = document . createElement ( 'div' ) ; dragElement . innerHTML = getDragHtml ( selection ) ; dragElement . className = 'drag-element p1 bordered rounded' ; dragElement . id = generateUID ( DRAG_ITEM_ID_KEY ) ; dragElement . addEventListener ( 'dragend' , ( event ) => handleDragSucceed ( event . dataTransfer ?. dropEffect ) ) ; document . body . appendChild ( dragElement ) ; event . dataTransfer . setDragImage ( dragElement , 0 , 0 ) ; event . dataTransfer . setData ( DRAG_ITEM_KEY , JSON . stringify ( selection ) ) ; event . dataTransfer . setData ( DRAG_ITEM_ID_KEY , dragElement . id ) ; setDragElement ( dragElement ) ; } , [ checkedIDs , onCheck ] ) ; return { draggedIDs , handleDragStart , handleDragEnd } ; } ; export default useItemsDraggable ;