pstream is dead; long live pstream taciturnaxolotl.github.io/pstream-ng/
at main 109 lines 2.8 kB view raw
1import { 2 DndContext, 3 DragEndEvent, 4 KeyboardSensor, 5 MouseSensor, 6 TouchSensor, 7 closestCenter, 8 useSensor, 9 useSensors, 10} from "@dnd-kit/core"; 11import { 12 restrictToParentElement, 13 restrictToVerticalAxis, 14} from "@dnd-kit/modifiers"; 15import { 16 SortableContext, 17 arrayMove, 18 sortableKeyboardCoordinates, 19 useSortable, 20 verticalListSortingStrategy, 21} from "@dnd-kit/sortable"; 22import { CSS } from "@dnd-kit/utilities"; 23import classNames from "classnames"; 24 25import { Icon, Icons } from "../Icon"; 26 27export interface Item { 28 id: string; 29 name: string; 30 disabled?: boolean; 31} 32 33function SortableItem(props: { item: Item }) { 34 const { attributes, listeners, setNodeRef, transform, transition } = 35 useSortable({ id: props.item.id }); 36 37 const style = { 38 transform: CSS.Transform.toString(transform), 39 transition, 40 }; 41 42 return ( 43 <div 44 ref={setNodeRef} 45 style={style} 46 {...attributes} 47 {...listeners} 48 className={classNames( 49 "bg-dropdown-background hover:bg-dropdown-hoverBackground select-none space-x-3 flex items-center max-w-[25rem] py-3 px-4 rounded-lg touch-manipulation", 50 props.item.disabled && "opacity-50", 51 transform ? "cursor-grabbing" : "cursor-grab", 52 )} 53 > 54 <span className="flex-1 text-white font-bold">{props.item.name}</span> 55 {props.item.disabled && <Icon icon={Icons.UNPLUG} />} 56 <Icon icon={Icons.MENU} /> 57 </div> 58 ); 59} 60 61export function SortableList(props: { 62 items: Item[]; 63 setItems: (items: Item[]) => void; 64}) { 65 const sensors = useSensors( 66 useSensor(TouchSensor, { 67 activationConstraint: { 68 delay: 75, 69 tolerance: 1, 70 }, 71 }), 72 useSensor(MouseSensor), 73 useSensor(KeyboardSensor, { 74 coordinateGetter: sortableKeyboardCoordinates, 75 }), 76 ); 77 78 const handleDragEnd = (event: DragEndEvent) => { 79 const { active, over } = event; 80 if (!over) return; 81 if (active.id !== over.id) { 82 const currentItems = props.items; 83 const oldIndex = currentItems.findIndex((item) => item.id === active.id); 84 const newIndex = currentItems.findIndex((item) => item.id === over.id); 85 const newItems = arrayMove(currentItems, oldIndex, newIndex); 86 props.setItems(newItems); 87 } 88 }; 89 90 return ( 91 <DndContext 92 sensors={sensors} 93 collisionDetection={closestCenter} 94 onDragEnd={handleDragEnd} 95 modifiers={[restrictToVerticalAxis, restrictToParentElement]} 96 > 97 <SortableContext 98 items={props.items} 99 strategy={verticalListSortingStrategy} 100 > 101 <div className="flex flex-col gap-2"> 102 {props.items.map((item) => ( 103 <SortableItem key={item.id} item={item} /> 104 ))} 105 </div> 106 </SortableContext> 107 </DndContext> 108 ); 109}