summaryrefslogtreecommitdiff
path: root/components/data-table/data-table-resizer.tsx
blob: 8053606ded3b27d14d4875657b638f1cd81a8c21 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
"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>
}

export function DataTableResizer<TData, TValue>({
  header,
  className,
  ...props
}: DataTableResizerProps<TData, TValue>) {
  const contentRef = React.useRef<HTMLDivElement>(null)
  
  // 더블클릭 시 너비 자동 조정 함수
  const handleDoubleClick = React.useCallback(() => {

    // 테이블 인스턴스 가져오기
    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)
  }, [header])

  const handleMouseDown = React.useCallback((e: React.MouseEvent) => {
    // 기본 resize handler 사용
    header.getResizeHandler()(e);
  }, [header]);

  return (
    <>
      {/* 헤더 콘텐츠 참조를 위한 요소 */}
      <div ref={contentRef} className="absolute opacity-0 pointer-events-none" />

      {/* 리사이저 */}
      <div
        {...props}
        onMouseDown={handleMouseDown}
        onTouchStart={header.getResizeHandler()}
        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="더블 클릭하여 내용에 맞게 크기 조정" // 힌트 추가
      />
    </>
  )
}