feat: TableListComponent 컬럼 너비 드래그 조절 기능 추가

- 실제 화면에서 사용되는 TableListComponent에도 리사이즈 기능 추가
- InteractiveDataTable과 동일한 리사이즈 핸들 구현
- columnWidths 상태로 각 컬럼 너비 관리
- 드래그 중 텍스트 선택 방지 및 이벤트 전파 차단
- 최소 너비 80px 보장
This commit is contained in:
kjs 2025-11-03 10:54:23 +09:00
parent 107f722e7a
commit 787bfd363f
1 changed files with 70 additions and 25 deletions

View File

@ -244,6 +244,7 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
const [selectedRows, setSelectedRows] = useState<Set<string>>(new Set());
const [isDragging, setIsDragging] = useState(false);
const [draggedRowIndex, setDraggedRowIndex] = useState<number | null>(null);
const [columnWidths, setColumnWidths] = useState<Record<string, number>>({});
const [isAllSelected, setIsAllSelected] = useState(false);
// 필터 설정 관련 상태
@ -1018,31 +1019,75 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
className="sticky top-0 z-10 bg-background"
>
<tr className="h-10 border-b border-border sm:h-12">
{visibleColumns.map((column) => (
<th
key={column.columnName}
className={cn(
"h-10 px-2 py-2 text-xs font-semibold text-foreground overflow-hidden text-ellipsis bg-background sm:h-12 sm:px-6 sm:py-3 sm:text-sm sm:whitespace-nowrap",
column.sortable && "cursor-pointer"
)}
style={{
textAlign: column.align || "left",
width: `${100 / visibleColumns.length}%`, // 컬럼 수에 따라 균등 분배
}}
onClick={() => column.sortable && handleSort(column.columnName)}
>
{column.columnName === "__checkbox__" ? (
renderCheckboxHeader()
) : (
<div style={{ display: "flex", alignItems: "center", gap: "8px" }}>
<span>{columnLabels[column.columnName] || column.displayName}</span>
{column.sortable && sortColumn === column.columnName && (
<span>{sortDirection === "asc" ? "↑" : "↓"}</span>
)}
</div>
)}
</th>
))}
{visibleColumns.map((column, columnIndex) => {
const columnWidth = columnWidths[column.columnName];
const defaultWidth = `${100 / visibleColumns.length}%`;
return (
<th
key={column.columnName}
className={cn(
"relative h-10 px-2 py-2 text-xs font-semibold text-foreground overflow-hidden text-ellipsis bg-background select-none sm:h-12 sm:px-6 sm:py-3 sm:text-sm sm:whitespace-nowrap",
column.sortable && "cursor-pointer"
)}
style={{
textAlign: column.align || "left",
width: columnWidth ? `${columnWidth}px` : defaultWidth,
minWidth: '80px',
userSelect: 'none'
}}
onClick={() => column.sortable && handleSort(column.columnName)}
>
{column.columnName === "__checkbox__" ? (
renderCheckboxHeader()
) : (
<div style={{ display: "flex", alignItems: "center", gap: "8px" }}>
<span>{columnLabels[column.columnName] || column.displayName}</span>
{column.sortable && sortColumn === column.columnName && (
<span>{sortDirection === "asc" ? "↑" : "↓"}</span>
)}
</div>
)}
{/* 리사이즈 핸들 */}
{columnIndex < visibleColumns.length - 1 && (
<div
className="absolute right-0 top-0 h-full w-1 cursor-col-resize hover:bg-blue-500"
onClick={(e) => e.stopPropagation()} // 정렬 클릭 방지
onMouseDown={(e) => {
e.preventDefault();
e.stopPropagation();
const startX = e.clientX;
const startWidth = columnWidth || (e.currentTarget.parentElement?.offsetWidth || 100);
// 드래그 중 텍스트 선택 방지
document.body.style.userSelect = 'none';
document.body.style.cursor = 'col-resize';
const handleMouseMove = (moveEvent: MouseEvent) => {
moveEvent.preventDefault();
const diff = moveEvent.clientX - startX;
const newWidth = Math.max(80, startWidth + diff);
setColumnWidths(prev => ({ ...prev, [column.columnName]: newWidth }));
};
const handleMouseUp = () => {
// 텍스트 선택 복원
document.body.style.userSelect = '';
document.body.style.cursor = '';
document.removeEventListener('mousemove', handleMouseMove);
document.removeEventListener('mouseup', handleMouseUp);
};
document.addEventListener('mousemove', handleMouseMove);
document.addEventListener('mouseup', handleMouseUp);
}}
/>
)}
</th>
);
})}
</tr>
</thead>