Fix drag selection with refs

This commit is contained in:
Christian Vidal Wolf
2026-04-16 11:55:30 +02:00
parent dc46f91e7b
commit 19ca75c1b9
+37 -22
View File
@@ -37,42 +37,57 @@ export function ColumnFilterPopover({
const isAllSelected = selectedValues.length === uniqueValues.length && uniqueValues.length > 0;
const isDraggingRef = React.useRef(false);
const dragStartRef = React.useRef<number | null>(null);
const hoveredIndexRef = React.useRef<number | null>(null);
const selectedValuesRef = React.useRef<string[]>(selectedValues);
const onSelectAllRef = React.useRef(onSelectAll);
const filteredValuesRef = React.useRef(filteredValues);
selectedValuesRef.current = selectedValues;
onSelectAllRef.current = onSelectAll;
filteredValuesRef.current = filteredValues;
const handleMouseDown = (index: number) => {
isDraggingRef.current = true;
dragStartRef.current = index;
hoveredIndexRef.current = index;
setIsDragging(true);
setDragStart(index);
setHoveredIndex(index);
};
const handleMouseEnter = (index: number) => {
if (isDragging && dragStart !== null) {
if (isDraggingRef.current && dragStartRef.current !== null) {
hoveredIndexRef.current = index;
setHoveredIndex(index);
}
};
const handleMouseUp = () => {
if (isDragging && dragStart !== null && hoveredIndex !== null) {
const start = Math.min(dragStart, hoveredIndex);
const end = Math.max(dragStart, hoveredIndex);
const itemsToSelect = filteredValues.slice(start, end + 1).map(v => v);
const newSelected = new Set([...selectedValues]);
itemsToSelect.forEach(v => newSelected.add(v));
onSelectAll(Array.from(newSelected));
}
setIsDragging(false);
setDragStart(null);
setHoveredIndex(null);
};
React.useEffect(() => {
const handleGlobalMouseUp = () => {
if (isDragging) {
handleMouseUp();
if (isDraggingRef.current) {
const start = dragStartRef.current;
const end = hoveredIndexRef.current;
if (start !== null && end !== null) {
const s = Math.min(start, end);
const e = Math.max(start, end);
const itemsToSelect = filteredValuesRef.current.slice(s, e + 1).map(v => v);
const newSelected = new Set([...selectedValuesRef.current]);
itemsToSelect.forEach(v => newSelected.add(v));
onSelectAllRef.current(Array.from(newSelected));
}
isDraggingRef.current = false;
dragStartRef.current = null;
hoveredIndexRef.current = null;
setIsDragging(false);
setDragStart(null);
setHoveredIndex(null);
}
};
if (isDragging) {
document.addEventListener('mouseup', handleGlobalMouseUp);
return () => document.removeEventListener('mouseup', handleGlobalMouseUp);
}
}, [isDragging, dragStart, hoveredIndex]);
document.addEventListener('mouseup', handleGlobalMouseUp);
return () => document.removeEventListener('mouseup', handleGlobalMouseUp);
}, []);
return (
<div