Fix column resizing in Pricing table

Improve resize logic with proper mouse delta calculation
This commit is contained in:
Christian Vidal Wolf
2026-04-21 08:49:02 +02:00
parent b4cb7cbe57
commit 964bb62838
+30 -23
View File
@@ -51,8 +51,15 @@ export function PricingView({ data, headers, onSaveRow, onCaptureState, onEdit,
const [filterMode, setFilterMode] = useState<FilterMode>('all_errors'); const [filterMode, setFilterMode] = useState<FilterMode>('all_errors');
const [search, setSearch] = useState(''); const [search, setSearch] = useState('');
const [searchMode, setSearchMode] = useState<'all' | 'selected'>('all'); const [searchMode, setSearchMode] = useState<'all' | 'selected'>('all');
const [columnWidths, setColumnWidths] = useState<Record<string, number>>({}); const [columnWidths, setColumnWidths] = useState<Record<string, number>>({
articleNo: 100,
articleName: 220,
line: 100,
classification: 130,
});
const [resizingColumn, setResizingColumn] = useState<string | null>(null); const [resizingColumn, setResizingColumn] = useState<string | null>(null);
const [resizeStartX, setResizeStartX] = useState<number | null>(null);
const [resizeStartWidth, setResizeStartWidth] = useState<number | null>(null);
const tableRef = useRef<HTMLTableElement>(null); const tableRef = useRef<HTMLTableElement>(null);
const [editingCell, setEditingCell] = useState<EditingCell | null>(null); const [editingCell, setEditingCell] = useState<EditingCell | null>(null);
const [savingCell, setSavingCell] = useState<{ rowIndex: number; colIndex: number } | null>(null); const [savingCell, setSavingCell] = useState<{ rowIndex: number; colIndex: number } | null>(null);
@@ -114,36 +121,36 @@ export function PricingView({ data, headers, onSaveRow, onCaptureState, onEdit,
setSearchMode('all'); setSearchMode('all');
}; };
const handleResizeStart = (e: React.MouseEvent, colKey: string) => { const handleResizeStart = (e: React.MouseEvent, colKey: string, currentWidth: number) => {
e.preventDefault(); e.preventDefault();
e.stopPropagation();
setResizingColumn(colKey); setResizingColumn(colKey);
setResizeStartX(e.clientX);
setResizeStartWidth(currentWidth);
}; };
React.useEffect(() => { React.useEffect(() => {
if (!resizingColumn || resizeStartX === null || resizeStartWidth === null) return;
const handleMouseMove = (e: MouseEvent) => { const handleMouseMove = (e: MouseEvent) => {
if (!resizingColumn || !tableRef.current) return; const delta = e.clientX - resizeStartX;
const th = tableRef.current.querySelector(`th[data-col-key="${resizingColumn}"]`) as HTMLElement; const newWidth = Math.max(50, Math.min(400, resizeStartWidth + delta));
if (!th) return; setColumnWidths(prev => ({ ...prev, [resizingColumn]: newWidth }));
const rect = th.getBoundingClientRect();
const newWidth = e.clientX - rect.left;
if (newWidth >= 50 && newWidth <= 400) {
setColumnWidths(prev => ({ ...prev, [resizingColumn]: newWidth }));
}
}; };
const handleMouseUp = () => { const handleMouseUp = () => {
setResizingColumn(null); setResizingColumn(null);
setResizeStartX(null);
setResizeStartWidth(null);
}; };
if (resizingColumn) { document.addEventListener('mousemove', handleMouseMove);
document.addEventListener('mousemove', handleMouseMove as any); document.addEventListener('mouseup', handleMouseUp);
document.addEventListener('mouseup', handleMouseUp); return () => {
return () => { document.removeEventListener('mousemove', handleMouseMove);
document.removeEventListener('mousemove', handleMouseMove as any); document.removeEventListener('mouseup', handleMouseUp);
document.removeEventListener('mouseup', handleMouseUp); };
}; }, [resizingColumn, resizeStartX, resizeStartWidth]);
}
}, [resizingColumn]);
// ── Dynamic column detection ────────────────────────────────────────────── // ── Dynamic column detection ──────────────────────────────────────────────
const { uvpIdx, srpCols, containerCols } = useMemo(() => { const { uvpIdx, srpCols, containerCols } = useMemo(() => {
@@ -656,7 +663,7 @@ export function PricingView({ data, headers, onSaveRow, onCaptureState, onEdit,
<tr> <tr>
<th data-col-key="articleNo" style={{ width: columnWidths.articleNo || 100 }} className="text-left px-3 py-3 text-xs font-semibold text-slate-400 uppercase tracking-wider border-b border-slate-700 whitespace-nowrap relative"> <th data-col-key="articleNo" style={{ width: columnWidths.articleNo || 100 }} className="text-left px-3 py-3 text-xs font-semibold text-slate-400 uppercase tracking-wider border-b border-slate-700 whitespace-nowrap relative">
Art. No. Art. No.
<div onMouseDown={(e) => handleResizeStart(e, 'articleNo')} className="absolute right-0 top-0 bottom-0 w-2 cursor-col-resize hover:bg-blue-500/30" /> <div onMouseDown={(e) => handleResizeStart(e, 'articleNo', columnWidths.articleNo || 100)} className="absolute right-0 top-0 bottom-0 w-2 cursor-col-resize hover:bg-blue-500/30" />
</th> </th>
<th data-col-key="articleName" style={{ width: columnWidths.articleName || 220 }} className="text-left px-3 py-3 text-xs font-semibold text-slate-400 uppercase tracking-wider border-b border-slate-700 group relative"> <th data-col-key="articleName" style={{ width: columnWidths.articleName || 220 }} className="text-left px-3 py-3 text-xs font-semibold text-slate-400 uppercase tracking-wider border-b border-slate-700 group relative">
<div className="flex items-center gap-1"><span>Article Name</span> <div className="flex items-center gap-1"><span>Article Name</span>
@@ -923,9 +930,9 @@ export function PricingView({ data, headers, onSaveRow, onCaptureState, onEdit,
<tr <tr
key={dataIndex} key={dataIndex}
className={cn( className={cn(
'border-b border-slate-700/50 transition-colors hover:bg-slate-700/20', 'border-b border-slate-700/50 transition-colors',
isValidated isValidated
? 'bg-emerald-500/10' ? 'bg-green-400/30 border-l-4 border-l-green-400' // Vibrant high-visibility green
: saveStatus === 'error' : saveStatus === 'error'
? 'bg-red-400/20 border-l-4 border-l-red-500' ? 'bg-red-400/20 border-l-4 border-l-red-500'
: saveStatus === 'pending' : saveStatus === 'pending'
@@ -1068,7 +1075,7 @@ export function PricingView({ data, headers, onSaveRow, onCaptureState, onEdit,
<td className={cn( <td className={cn(
"px-2 py-2.5 sticky right-0 shadow-[-4px_0_8px_rgba(0,0,0,0.1)] transition-colors", "px-2 py-2.5 sticky right-0 shadow-[-4px_0_8px_rgba(0,0,0,0.1)] transition-colors",
isValidated ? "bg-[#1e2a25]" : "bg-slate-800", isValidated ? "bg-[#1b4d24]" : "bg-slate-800",
"group-hover:bg-slate-700/40" "group-hover:bg-slate-700/40"
)}> )}>
<button <button