Widgets were not snapping to grid cells despite the snap logic being implemented.
The drag event handlers were expecting data.clientX and data.clientY directly from the @neodrag/solid library, but the library actually provides:
{
offsetX: number, // Offset relative to draggable element
offsetY: number, // Offset relative to draggable element
event: MouseEvent, // The actual mouse/touch event
rootNode: HTMLElement,
currentNode: HTMLElement
}
The actual mouse coordinates are in data.event.clientX and data.event.clientY, not directly on the data object.
// Before
type DragEventData = {
clientX: number;
clientY: number;
offsetX?: number;
offsetY?: number;
deltaX?: number;
deltaY?: number;
};
// After
type DragEventData = {
offsetX: number;
offsetY: number;
event: MouseEvent | TouchEvent;
rootNode: HTMLElement;
currentNode: HTMLElement;
};
All three drag handlers (handleDragStart, handleDrag, handleDragEnd) now extract clientX/clientY from the event:
const event = data.event;
const clientX = "clientX" in event
? event.clientX
: (event as TouchEvent).touches[0].clientX;
const clientY = "clientY" in event
? event.clientY
: (event as TouchEvent).touches[0].clientY;
This also adds touch event support for mobile devices.
npm run devWhen dragging near a cell:
[Snap Debug] DRAG START { widgetId: "...", clientX: 450, clientY: 320, gridCellsCount: 4 }
[Snap Debug] Drag start positions: { dragStartPointerPos: {...}, dragStartWidgetPos: {...} }
[Snap Debug] Finding target: { widgetRect: {...}, widgetCenter: {...}, cellsCount: 4, threshold: 30 }
[Snap Debug] Checking cell: { cellId: "cell-1", cellCenter: {...}, distance: 15.2, withinThreshold: true }
[Snap Debug] Cell is candidate: { cellId: "cell-1", overlap: 0.45, score: -7.3 }
[Snap Debug] Best cell: "cell-1"
/src/components/WidgetRenderer.tsx - Fixed event handling in all drag handlers