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
+32 -17
View File
@@ -37,42 +37,57 @@ export function ColumnFilterPopover({
const isAllSelected = selectedValues.length === uniqueValues.length && uniqueValues.length > 0; 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) => { const handleMouseDown = (index: number) => {
isDraggingRef.current = true;
dragStartRef.current = index;
hoveredIndexRef.current = index;
setIsDragging(true); setIsDragging(true);
setDragStart(index); setDragStart(index);
setHoveredIndex(index);
}; };
const handleMouseEnter = (index: number) => { const handleMouseEnter = (index: number) => {
if (isDragging && dragStart !== null) { if (isDraggingRef.current && dragStartRef.current !== null) {
hoveredIndexRef.current = index;
setHoveredIndex(index); setHoveredIndex(index);
} }
}; };
const handleMouseUp = () => { React.useEffect(() => {
if (isDragging && dragStart !== null && hoveredIndex !== null) { const handleGlobalMouseUp = () => {
const start = Math.min(dragStart, hoveredIndex); if (isDraggingRef.current) {
const end = Math.max(dragStart, hoveredIndex); const start = dragStartRef.current;
const itemsToSelect = filteredValues.slice(start, end + 1).map(v => v); const end = hoveredIndexRef.current;
const newSelected = new Set([...selectedValues]); 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)); itemsToSelect.forEach(v => newSelected.add(v));
onSelectAll(Array.from(newSelected)); onSelectAllRef.current(Array.from(newSelected));
} }
isDraggingRef.current = false;
dragStartRef.current = null;
hoveredIndexRef.current = null;
setIsDragging(false); setIsDragging(false);
setDragStart(null); setDragStart(null);
setHoveredIndex(null); setHoveredIndex(null);
};
React.useEffect(() => {
const handleGlobalMouseUp = () => {
if (isDragging) {
handleMouseUp();
} }
}; };
if (isDragging) {
document.addEventListener('mouseup', handleGlobalMouseUp); document.addEventListener('mouseup', handleGlobalMouseUp);
return () => document.removeEventListener('mouseup', handleGlobalMouseUp); return () => document.removeEventListener('mouseup', handleGlobalMouseUp);
} }, []);
}, [isDragging, dragStart, hoveredIndex]);
return ( return (
<div <div