import { closestLayoutCenter , createSortable , DragDropContext , DragDropSensors , SortableContext } from '@thisbeyond/solid-dnd' ; import { Component , createSignal , For , JSX , JSXElement , Show } from 'solid-js' ; import { useOnScreen } from '../lib/hooks' ; interface ListProps { items : any [ ] ; children : ( data : any ) => JSXElement ; getItemId : ( props : any ) => number | string ; onReorderItems : ( updatedItems : any [ ] ) => void ; } interface ListItemProps { id : number | string ; children : unknown ; } const getSiblings = ( e ) => { let siblings = [ ] ; if ( e . parentNode ) { let sibling = e . parentNode . firstChild ; while ( sibling ) { if ( sibling . nodeType === 1 && sibling !== e ) siblings . push ( sibling ) ; sibling = sibling . nextSibling ; } } return siblings as HTMLElement [ ] ; } ; const reorder = ( list , fromIndex , toIndex ) => { const result = [ ... list ] ; result . splice ( toIndex , 0 , ... result . splice ( fromIndex , 1 ) ) ; return result ; } ; const SortableItem = ( props ) => { const sortable = createSortable ( { id : props . id } ) ; const [ ref , isVisible ] = useOnScreen ( ) ; const onMouseUp = ( e ) => { sortable . isActiveDraggable && e . preventDefault ( ) ; } ; return ( < div use : sortable ref = { ref } className = "sortable" classList = { { 'is--dragged' : sortable . isActiveDraggable } } onMouseUp = { onMouseUp } > < Show when = { isVisible ( ) } > { props . children } < /Show> < /div>); } ; const DraggableList = ( props ) => { const getItemIds = ( items ) => items . map ( props . getItemId ) ; const [ items , setItems ] = createSignal ( getItemIds ( props . items ) ) ; const ids = ( ) => items ( ) ; const onDragStart = ( { draggable : { node } } ) => { getSiblings ( node ) . forEach ( ( n ) => ( n . style . transition = 'transform 0.3s ease-out' ) ) ; } ; const onDragEnd = ( { draggable , droppable } ) => { if ( ! draggable || ! droppable ) { return ; } getSiblings ( draggable . node ) . forEach ( ( n ) => ( n . style . transition = '' ) ) ; const currentItems = ids ( ) ; const fromIndex = currentItems . indexOf ( draggable . id ) ; const toIndex = currentItems . indexOf ( droppable . id ) ; if ( fromIndex !== toIndex ) { const updatedItems = reorder ( props . items , fromIndex , toIndex ) ; setItems ( getItemIds ( updatedItems ) ) ; props . onReorderItems ( updatedItems ) ; } } ; return ( < DragDropContext onDragStart = { onDragStart } onDragEnd = { onDragEnd } collisionDetectionAlgorith = { closestLayoutCenter } > < DragDropSensors /> < SortableContext ids = { ids ( ) } > < For each = { props . items } > { ( item ) => ( < SortableItem id = { props . getItemId ( item ) } > { props . children ( item ) } < /SortableItem>)} < /For> < /SortableContext> < /DragDropContext>); } ; export default DraggableList ;