summaryrefslogtreecommitdiff
path: root/hooks/useAutoSizeColumns.ts
blob: 6e9cc7dca43d8d6ea8da6a2d704796e11feab29a (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
105
106
107
108
import { useEffect, useRef } from "react"
import { Table, ColumnDef } from "@tanstack/react-table"

// 커스텀 메타 타입 정의
declare module '@tanstack/react-table' {
  interface ColumnMeta<TData, TValue> {
    paddingFactor?: number;
    excelHeader?: string;
  }
}

export function useAutoSizeColumns<T>(
  table: Table<T>,
  enabled: boolean = true
) {
  const hasResized = useRef(false)
  
  useEffect(() => {
    if (!enabled || hasResized.current) return
    
    // Wait for the table to render
    const timer = setTimeout(() => {
      const calculateColumnWidths = () => {
        const defaultMinWidth = 80
        const defaultPadding = 24
        
        const newColumnSizing: Record<string, number> = {}
        
        // Process each visible column
        table.getAllColumns().forEach(column => {
          if (column.id === 'select' || column.id === 'actions') {
            // Fixed width for utility columns
            newColumnSizing[column.id] = column.id === 'select' ? 40 : 60
            return
          }
          
          const columnId = column.id
          // Get column-specific padding from meta if available
          const paddingFactor = column.columnDef.meta?.paddingFactor || 1
          const extraPadding = paddingFactor * defaultPadding
          
          // Get all cells for this column
          const headerElement = document.querySelector(`th[data-column-id="${columnId}"]`)
          const cells = document.querySelectorAll(`tbody td[data-column-id="${columnId}"]`)
          
          // Create measuring element
          const measureElement = document.createElement('div')
          measureElement.style.position = 'absolute'
          measureElement.style.visibility = 'hidden'
          measureElement.style.whiteSpace = 'nowrap'
          measureElement.style.font = headerElement
            ? window.getComputedStyle(headerElement).font
            : window.getComputedStyle(document.body).font
          document.body.appendChild(measureElement)
          
          // Measure header - 헤더 요소 자체의 너비를 직접 측정
          let headerWidth = 0
          if (headerElement) {
            // 1. 먼저 텍스트 콘텐츠 측정
            const headerText = headerElement.textContent || ""
            measureElement.textContent = headerText
            headerWidth = measureElement.getBoundingClientRect().width
            
            // 2. 헤더에 아이콘이나 다른 요소가 있을 경우를 고려
            // 헤더 요소의 실제 너비 확인 (텍스트외 요소 포함)
            const headerClientWidth = headerElement.querySelector('div')?.clientWidth || 
                                     headerElement.clientWidth || 0
            
            // 텍스트 너비와 실제 요소 너비 중 큰 값 선택
            headerWidth = Math.max(headerWidth, headerClientWidth)
          }
          
          // 초기 최대 너비를 헤더 너비로 설정
          let maxWidth = headerWidth
          
          // Measure cells (limit to first 20 for performance)
          Array.from(cells).slice(0, 20).forEach(cell => {
            const cellText = cell.textContent || ""
            measureElement.textContent = cellText
            const cellWidth = measureElement.getBoundingClientRect().width
            maxWidth = Math.max(maxWidth, cellWidth)
          })
          
          // Clean up measuring element
          document.body.removeChild(measureElement)
          
          // Calculate final width
          let finalWidth = maxWidth + extraPadding
          const minWidth = column.columnDef.minSize || defaultMinWidth
          finalWidth = Math.max(finalWidth, minWidth)
          
          // Add to sizing object
          newColumnSizing[columnId] = finalWidth
        })
        
        // Apply all column sizes at once
        table.setColumnSizing(newColumnSizing)
        hasResized.current = true
      }
      
      calculateColumnWidths()
    }, 100) // Short delay to ensure DOM is ready
    
    return () => clearTimeout(timer)
  }, [table, enabled])
  
  return { resetAutoSize: () => { hasResized.current = false } }
}