"use client" // Basic Draggable List - Free Version "use client" import * as React from "react" import { cn } from "../../lib/utils" export interface DraggableListProps { items: T[] onReorder: (items: T[]) => void renderItem: (item: T, index: number) => React.ReactNode keyExtractor: (item: T) => string className?: string disabled?: boolean } export function DraggableList({ items, onReorder, renderItem, keyExtractor, className, disabled = false }: DraggableListProps) { const [draggedIndex, setDraggedIndex] = React.useState(null) const handleDragStart = (e: React.DragEvent, index: number) => { if (disabled) return setDraggedIndex(index) e.dataTransfer.effectAllowed = "move" } const handleDragOver = (e: React.DragEvent) => { e.preventDefault() e.dataTransfer.dropEffect = "move" } const handleDrop = (e: React.DragEvent, dropIndex: number) => { e.preventDefault() if (disabled || draggedIndex === null || draggedIndex === dropIndex) { setDraggedIndex(null) return } const newItems = [...items] const draggedItem = newItems[draggedIndex] newItems.splice(draggedIndex, 1) newItems.splice(dropIndex, 0, draggedItem) onReorder(newItems) setDraggedIndex(null) } const handleDragEnd = () => { setDraggedIndex(null) } return (
{items.map((item, index) => (
handleDragStart(e, index)} onDragOver={handleDragOver} onDrop={(e) => handleDrop(e, index)} onDragEnd={handleDragEnd} className={cn( "transition-opacity duration-200", !disabled && "cursor-move hover:opacity-80", draggedIndex === index && "opacity-50", disabled && "cursor-not-allowed" )} > {renderItem(item, index)}
))}
) }