"use client"; import { ArrowIcon, GripIcon } from "../ui/icons.tsx"; import { useReducedMotion } from "../motion/Preferences.tsx"; import { Reorder, useDragControls } from "motion/react"; export type ReorderEntry = { id: string; label: string; description?: string }; function Entry({ item, index, total, move, }: { item: ReorderEntry; index: number; total: number; move: (from: number, to: number) => void; }) { const controls = useDragControls(), reduced = useReducedMotion(); return ( controls.start(e)} onKeyDown={(e) => { if (e.key === "ArrowUp" || e.key === "ArrowDown") { e.preventDefault(); move(index, index + (e.key === "ArrowUp" ? -1 : 1)); } }} > {item.label} {item.description && {item.description}} move(index, index - 1)} > move(index, index + 1)} > ); } export function ReorderList({ items, onReorder, label = "Reorder items", className = "", }: { items: readonly T[]; onReorder: (items: T[]) => void; label?: string; className?: string; }) { const move = (from: number, to: number) => { if (to < 0 || to >= items.length || from === to) return; const next = [...items]; next.splice(to, 0, next.splice(from, 1)[0]!); onReorder(next); }; return ( {label} i.id)} aria-label={label} onReorder={(ids) => onReorder(ids.map((id) => items.find((i) => i.id === id)!)) } > {items.map((item, index) => ( ))} {!items.length && No items to reorder.} Drag a handle, use its arrow keys, or use the move buttons. ); }
{label}
No items to reorder.
Drag a handle, use its arrow keys, or use the move buttons.