import React, { useRef } from 'react'; import { useDrag, useDrop } from '../../hooks'; import styles from './silke-sortable-list.scss'; type SilkeSortableItemWrapperProps = { items: T[]; index: number; listId: string; triggerState: 'over' | 'drop'; className?: string; children: React.ReactElement; onSort: (sortedItems: T[]) => void; disabled?: boolean; }; type SortData = { listId: string; index: number; items: T[]; onSort: (sortedItems: T[]) => void; }; export function SilkeSortableItemWrapper({ index, items, listId, children, triggerState, className, disabled, onSort, }: SilkeSortableItemWrapperProps) { const ref = useRef(null); const data: SortData = { listId, index, items, onSort }; const dragState = useDrag({ data, ref, disabled, isolated: true }); const handleSort = (from: SortData) => { const toList = items.slice(); const fromList = items !== from.items ? from.items.slice() : toList; const [item] = fromList.splice(from.index, 1); if (fromList !== toList) { from.onSort(fromList); // If the item is removed from the fromList, it will give us an outdated version of the fromList // WHich causes the item to be inserted multiple times in the toList // So we need to remove all the items from the toList before inserting let index: number; while ((index = toList.indexOf(item)) !== -1) { toList.splice(index, 1); } } toList.splice(index, 0, item); onSort(toList); }; const dropState = useDrop>({ ref, canDrop: (item) => item.listId === listId, onOver: (from) => triggerState === 'over' && handleSort(from), onDrop: (from) => triggerState === 'drop' && handleSort(from), disabled, }); let cl = styles.item; if (className) cl += ' ' + className; if (dragState === 'dragging') cl += ' ' + styles.dragging; else if (dropState === 'over') cl += ' ' + styles.over; return (
{children}
); }