dnd-kit
dnd-kit copied to clipboard
isOver for a brief moment even if disabled
Often times, isOver returns true even if disabled for a brief moment.
https://github.com/user-attachments/assets/d90084af-4491-43fe-b3b1-feae1ed271d4
https://codesandbox.io/p/sandbox/dnd-isover-bug-x8pllw
import "./styles.css";
import {
SortableContext,
useSortable,
verticalListSortingStrategy,
} from "@dnd-kit/sortable";
import {
DndContext,
PointerSensor,
pointerWithin,
useSensor,
useSensors,
UniqueIdentifier,
useDndContext,
} from "@dnd-kit/core";
interface ItemProps extends Item {}
function Item({ id }: ItemProps) {
const { active } = useDndContext();
const isDroppableDisabled = active?.id === id;
const { attributes, listeners, setNodeRef, isOver } = useSortable({
id,
disabled: {
droppable: isDroppableDisabled,
},
});
// often times when dragging, isDroppableDisabled and isOver are both true at the same time
return (
<div
ref={setNodeRef}
{...attributes}
{...listeners}
style={{
backgroundColor: isOver ? "red" : "transparent",
}}
>
{id}
</div>
);
}
interface Item {
id: UniqueIdentifier;
}
export default function App() {
const items: Item[] = [
{
id: "1",
},
{
id: "2",
},
{
id: "3",
},
];
const sortedIds = items.map((_) => _.id);
const sensors = useSensors(
useSensor(PointerSensor, {
activationConstraint: {
distance: 0.01,
},
})
);
return (
<div className="App">
<h1>@dnd-kit isOver bug</h1>
<DndContext
autoScroll={false}
collisionDetection={pointerWithin}
sensors={sensors}
>
<SortableContext
items={sortedIds}
strategy={verticalListSortingStrategy}
>
{items.map((item) => (
<Item key={item.id} {...item} />
))}
</SortableContext>
</DndContext>
</div>
);
}
So a disabled useSortable can still return isOver === true for a few frames.