diff options
| author | joonhoekim <26rote@gmail.com> | 2025-03-25 15:55:45 +0900 |
|---|---|---|
| committer | joonhoekim <26rote@gmail.com> | 2025-03-25 15:55:45 +0900 |
| commit | 1a2241c40e10193c5ff7008a7b7b36cc1d855d96 (patch) | |
| tree | 8a5587f10ca55b162d7e3254cb088b323a34c41b /components/client-data-table/data-table-resizer.tsx | |
initial commit
Diffstat (limited to 'components/client-data-table/data-table-resizer.tsx')
| -rw-r--r-- | components/client-data-table/data-table-resizer.tsx | 119 |
1 files changed, 119 insertions, 0 deletions
diff --git a/components/client-data-table/data-table-resizer.tsx b/components/client-data-table/data-table-resizer.tsx new file mode 100644 index 00000000..7dc8f523 --- /dev/null +++ b/components/client-data-table/data-table-resizer.tsx @@ -0,0 +1,119 @@ +"use client" + +import * as React from "react" +import { cn } from "@/lib/utils" +import { Header } from "@tanstack/react-table" + +interface DataTableResizerProps<TData, TValue> + extends React.HTMLAttributes<HTMLDivElement> { + header: Header<TData, TValue> + onResizeStart?: () => void + onResizeEnd?: () => void +} + +export function DataTableResizer<TData, TValue>({ + header, + onResizeStart, + onResizeEnd, + className, + ...props +}: DataTableResizerProps<TData, TValue>) { + const contentRef = React.useRef<HTMLDivElement>(null) + + // 더블클릭 시 너비 자동 조정 함수 + const handleDoubleClick = React.useCallback((e: React.MouseEvent) => { + e.stopPropagation(); // 이벤트 버블링 중지 + + // 테이블 인스턴스 가져오기 + const table = header.getContext().table + + // 0. 몇 가지 기본 설정 + const defaultMinWidth = 80 // 기본 최소 너비 + const extraPadding = 24 // 여유 공간 + + // 헤더 타이틀 얻기 시도 + const headerElement = contentRef.current?.closest('th') + const headerText = headerElement?.textContent || "" + + // 1. 컬럼 ID 가져오기 + const columnId = header.column.id + + // 2. 테이블 바디에서 해당 ID를 가진 모든 셀 선택 + const allCells = document.querySelectorAll(`tbody td[data-column-id="${columnId}"]`) + + // 3. 최대 컨텐츠 너비 측정을 위한 임시 요소 생성 + const measureElement = document.createElement('div') + measureElement.style.position = 'absolute' + measureElement.style.visibility = 'hidden' + measureElement.style.whiteSpace = 'nowrap' // 내용이 줄바꿈되지 않도록 + measureElement.style.font = window.getComputedStyle(headerElement || document.body).font // 동일한 폰트 사용 + document.body.appendChild(measureElement) + + // 4. 헤더 너비 측정 + measureElement.textContent = headerText + let maxWidth = measureElement.getBoundingClientRect().width + + // 5. 모든 셀의 내용 너비 측정하고 최대값 찾기 + Array.from(allCells).forEach(cell => { + const cellText = cell.textContent || "" + measureElement.textContent = cellText + const cellWidth = measureElement.getBoundingClientRect().width + maxWidth = Math.max(maxWidth, cellWidth) + }) + + // 6. 측정용 요소 제거 + document.body.removeChild(measureElement) + + // 7. 계산된 너비에 여유 공간 추가 + let finalWidth = maxWidth + extraPadding + + // 8. 최소 너비 적용 + const minWidth = header.column.columnDef.minSize || defaultMinWidth + finalWidth = Math.max(finalWidth, minWidth) + + // 9. 컬럼 사이즈 업데이트 + const columnSizingInfo = table.getState().columnSizing + const updatedSizing = { + ...columnSizingInfo, + [columnId]: finalWidth + } + + // 사이즈 업데이트 + table.setColumnSizing(updatedSizing) + + // 콘솔 로그 추가 (디버깅용) + console.log(`컬럼 [${columnId}] 너비 자동 조정: ${finalWidth}px`); + }, [header]) + + // 마우스 다운 핸들러 (리사이징 시작) + const handleMouseDown = React.useCallback((e: React.MouseEvent | React.TouchEvent) => { + // 리사이즈 시작을 알림 + if (onResizeStart) onResizeStart() + + // 기존 리사이즈 핸들러 호출 + if (header.getResizeHandler()) { + header.getResizeHandler()(e as any) + } + }, [header, onResizeStart]) + + return ( + <> + {/* 헤더 콘텐츠 참조를 위한 요소 */} + <div ref={contentRef} className="absolute opacity-0 pointer-events-none" /> + + {/* 리사이저 */} + <div + {...props} + onMouseDown={handleMouseDown} + onTouchStart={handleMouseDown} + onDoubleClick={handleDoubleClick} + className={cn( + "absolute right-0 top-0 h-full w-1 cursor-col-resize bg-transparent hover:bg-gray-300 active:bg-gray-400", + header.column.getIsResizing() ? "bg-gray-400" : "", + className + )} + title="더블 클릭하여 내용에 맞게 크기 조정" // 힌트 추가 + /> + </> + ) +}
\ No newline at end of file |
