'use client' import { DndContext, type DragEndEvent, type DraggableAttributes, type DraggableSyntheticListeners, KeyboardSensor, PointerSensor, closestCenter, useSensor, useSensors, } from '@dnd-kit/core' import { SortableContext, sortableKeyboardCoordinates, useSortable, verticalListSortingStrategy, } from '@dnd-kit/sortable' import { CSS } from '@dnd-kit/utilities' import * as React from 'react' import { cn } from '../../../utils/cn' export interface SortableRowRenderArgs { dragHandleProps: DraggableSyntheticListeners dragHandleAttributes: DraggableAttributes isDragging: boolean } export interface TicketStatusConfigListProps { items: T[] onReorder: (oldIndex: number, newIndex: number) => void renderRow: (item: T, args: SortableRowRenderArgs) => React.ReactNode className?: string } export function TicketStatusConfigList({ items, onReorder, renderRow, className, }: TicketStatusConfigListProps) { const sensors = useSensors( useSensor(PointerSensor, { activationConstraint: { distance: 4 } }), useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates }), ) const handleDragEnd = (event: DragEndEvent) => { const { active, over } = event if (!over || active.id === over.id) return const oldIndex = items.findIndex(i => i.id === active.id) const newIndex = items.findIndex(i => i.id === over.id) if (oldIndex === -1 || newIndex === -1) return onReorder(oldIndex, newIndex) } const sortableIds = React.useMemo(() => items.map(i => i.id), [items]) return (
{items.map(item => ( {args => renderRow(item, args)} ))}
) } function SortableRow({ id, children, }: { id: string children: (args: SortableRowRenderArgs) => React.ReactNode }) { const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({ id }) const style: React.CSSProperties = { transform: CSS.Transform.toString(transform), transition, // Raise the actively dragged row above its siblings — without this the // stacking follows DOM order, so a row dragged DOWN slides UNDER the rows // below it while a row dragged up correctly renders on top. zIndex: isDragging ? 1 : undefined, } return (
{children({ dragHandleProps: listeners, dragHandleAttributes: attributes, isDragging, })}
) }