summaryrefslogtreecommitdiff
path: root/components/client-data-table/data-table-resizer.tsx
diff options
context:
space:
mode:
authorjoonhoekim <26rote@gmail.com>2025-03-25 15:55:45 +0900
committerjoonhoekim <26rote@gmail.com>2025-03-25 15:55:45 +0900
commit1a2241c40e10193c5ff7008a7b7b36cc1d855d96 (patch)
tree8a5587f10ca55b162d7e3254cb088b323a34c41b /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.tsx119
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