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 } }
}
|