"use client"; import React, { useState } from "react"; import { motion, AnimatePresence, Reorder, useDragControls, } from "framer-motion"; import { GripVertical, X, Plus } from "lucide-react"; import { cn } from "../lib/utils"; export interface ReorderItem { id: string; label: string; description?: string; icon?: React.ReactNode; } interface DraggableReorderListProps { /** Initial items */ items: ReorderItem[]; /** Callback with new order when reordered */ onReorder?: (items: ReorderItem[]) => void; /** Allow removing items */ removable?: boolean; /** Additional classes */ className?: string; } function Item({ item, onRemove, removable, }: { item: ReorderItem; onRemove: (id: string) => void; removable: boolean; }) { const dragControls = useDragControls(); return ( e.preventDefault()} className={cn( "flex items-center gap-3 rounded-xl border bg-background px-4 py-3", "shadow-sm hover:shadow-md transition-shadow cursor-default select-none" )} > {/* Drag Handle */} dragControls.start(e)} className="flex-shrink-0 cursor-grab active:cursor-grabbing touch-none text-muted-foreground/40 hover:text-muted-foreground transition-colors" whileHover={{ scale: 1.1 }} > {/* Icon */} {item.icon && (
{item.icon}
)} {/* Content */}

{item.label}

{item.description && (

{item.description}

)}
{/* Remove Button */} {removable && ( onRemove(item.id)} aria-label={`Remove ${item.label}`} className="flex-shrink-0 flex h-6 w-6 items-center justify-center rounded-full text-muted-foreground/40 hover:text-destructive hover:bg-destructive/10 transition-colors focus:outline-none" whileHover={{ scale: 1.15 }} whileTap={{ scale: 0.9 }} > )}
); } export function DraggableReorderList({ items: initialItems, onReorder, removable = true, className, }: DraggableReorderListProps) { const [items, setItems] = useState(initialItems); const handleReorder = (newOrder: ReorderItem[]) => { setItems(newOrder); onReorder?.(newOrder); }; const handleRemove = (id: string) => { const next = items.filter((item) => item.id !== id); setItems(next); onReorder?.(next); }; return (
{items.map((item) => ( ))} {items.length === 0 && (

All items removed

)}
); }