👁️
at main 68 lines 1.6 kB view raw
1import { 2 DndContext, 3 type DragCancelEvent, 4 type DragEndEvent, 5 KeyboardSensor, 6 PointerSensor, 7 TouchSensor, 8 useSensor, 9 useSensors, 10} from "@dnd-kit/core"; 11import { type ReactNode, useId, useState } from "react"; 12 13interface DragDropProviderProps { 14 children: ReactNode; 15 onDragEnd: (event: DragEndEvent) => void; 16 onDragCancel?: (event: DragCancelEvent) => void; 17} 18 19export function DragDropProvider({ 20 children, 21 onDragEnd, 22 onDragCancel, 23}: DragDropProviderProps) { 24 const dndContextId = useId(); 25 26 // WARN: Screen size is checked once on mount and never updated. 27 // dnd-kit's useSensors doesn't support dynamic sensor changes. 28 // This will break on foldable phones that change size mid-session. 29 // Fix requires either dnd-kit fix or remounting DndContext on resize. 30 const [isLargeScreen] = useState(() => { 31 if (typeof window === "undefined") return true; 32 return window.matchMedia("(min-width: 768px)").matches; 33 }); 34 35 const pointerSensor = useSensor(PointerSensor, { 36 activationConstraint: { 37 distance: 8, 38 }, 39 }); 40 41 const touchSensor = useSensor(TouchSensor, { 42 activationConstraint: { 43 delay: 250, 44 tolerance: 5, 45 }, 46 }); 47 48 const keyboardSensor = useSensor(KeyboardSensor); 49 50 // Only include touch sensor on larger screens (tablets, laptops) 51 // On small screens (<768px), touch scrolls instead of dragging 52 const sensors = useSensors( 53 pointerSensor, 54 ...(isLargeScreen ? [touchSensor] : []), 55 keyboardSensor, 56 ); 57 58 return ( 59 <DndContext 60 id={dndContextId} 61 sensors={sensors} 62 onDragEnd={onDragEnd} 63 onDragCancel={onDragCancel} 64 > 65 {children} 66 </DndContext> 67 ); 68}