summaryrefslogtreecommitdiff
path: root/components/data-table/infinite-data-table.tsx
diff options
context:
space:
mode:
authordujinkim <dujin.kim@dtsolution.co.kr>2025-06-01 13:52:21 +0000
committerdujinkim <dujin.kim@dtsolution.co.kr>2025-06-01 13:52:21 +0000
commitbac0228d21b7195065e9cddcc327ae33659c7bcc (patch)
tree8f3016ae4533c8706d0c00a605d9b1d41968c2bc /components/data-table/infinite-data-table.tsx
parent2fdce8d7a57c792bba0ac36fa554dca9c9cc31e3 (diff)
(대표님) 20250601까지 작업사항
Diffstat (limited to 'components/data-table/infinite-data-table.tsx')
-rw-r--r--components/data-table/infinite-data-table.tsx69
1 files changed, 60 insertions, 9 deletions
diff --git a/components/data-table/infinite-data-table.tsx b/components/data-table/infinite-data-table.tsx
index fcac56ee..b8764d62 100644
--- a/components/data-table/infinite-data-table.tsx
+++ b/components/data-table/infinite-data-table.tsx
@@ -6,7 +6,7 @@ import { ChevronRight, ChevronUp, Loader2 } from "lucide-react"
import { useIntersection } from "@mantine/hooks"
import { cn } from "@/lib/utils"
-import { getCommonPinningStyles } from "@/lib/data-table"
+import { getCommonPinningStylesWithBorder } from "@/lib/data-table"
import {
Table,
TableBody,
@@ -53,6 +53,9 @@ export function InfiniteDataTable<TData>({
useAutoSizeColumns(table, autoSizeColumns)
+ // 🎯 스크롤 상태 감지 추가
+ const [isScrolled, setIsScrolled] = React.useState(false)
+
// Intersection Observer for infinite scroll
const { ref: loadMoreRef, entry } = useIntersection({
threshold: 0.1,
@@ -65,21 +68,62 @@ export function InfiniteDataTable<TData>({
}
}, [entry?.isIntersecting, hasNextPage, isLoadingMore, onLoadMore])
+ // 🎯 스크롤 핸들러 추가
+ const handleScroll = (e: React.UIEvent<HTMLDivElement>) => {
+ const scrollLeft = e.currentTarget.scrollLeft
+ setIsScrolled(scrollLeft > 0)
+ }
+
+ // 🎯 동적 핀 스타일 함수 (width 중복 제거)
+ const getPinnedStyle = (column: any, isHeader: boolean = false) => {
+ const baseStyle = getCommonPinningStylesWithBorder({ column })
+ const pinnedSide = column.getIsPinned()
+
+ // width를 제외한 나머지 스타일만 반환
+ const { width, ...restBaseStyle } = baseStyle
+
+ return {
+ ...restBaseStyle,
+ // 헤더는 핀 여부와 관계없이 항상 배경 유지 (sticky로 고정되어 있기 때문)
+ ...(isHeader && {
+ background: "hsl(var(--background))",
+ transition: "none",
+ }),
+ // 바디 셀은 핀된 경우에만 스크롤 상태에 따라 동적 변경
+ ...(!isHeader && pinnedSide && {
+ background: isScrolled
+ ? "hsl(var(--background))"
+ : "transparent",
+ transition: "background-color 0.15s ease-out",
+ }),
+ }
+ }
+
+ // 🎯 테이블 총 너비 계산
+ const getTableWidth = React.useCallback(() => {
+ const totalSize = table.getCenterTotalSize() + table.getLeftTotalSize() + table.getRightTotalSize()
+ return Math.max(totalSize, 800) // 최소 800px 보장
+ }, [table])
+
// 컴팩트 모드를 위한 클래스 정의
const compactStyles = compact ? {
row: "h-7",
cell: "py-1 px-2 text-sm",
+ header: "py-1 px-2 text-sm", // 헤더 스타일 추가
+ headerRow: "h-8", // 헤더 행 높이 추가
groupRow: "py-1 bg-muted/20 text-sm",
emptyRow: "h-16",
} : {
row: "",
cell: "",
+ header: "", // 헤더 스타일 추가
+ headerRow: "", // 헤더 행 높이 추가
groupRow: "bg-muted/20",
emptyRow: "h-24",
}
return (
- <div className={cn("w-full space-y-2.5 overflow-auto", className)} {...props}>
+ <div className={cn("w-full space-y-2.5", className)} {...props}>
{children}
{/* 총 개수 표시 */}
@@ -97,12 +141,19 @@ export function InfiniteDataTable<TData>({
<div
className="max-w-[100vw] overflow-auto"
style={{ maxHeight: maxHeight || '35rem' }}
+ onScroll={handleScroll} // 🎯 스크롤 이벤트 핸들러 추가
>
- <Table className="[&>thead]:sticky [&>thead]:top-0 [&>thead]:z-10 table-fixed">
+ <Table
+ className="[&>thead]:sticky [&>thead]:top-0 [&>thead]:z-10"
+ style={{
+ width: getTableWidth(), // 🎯 동적 너비 계산
+ minWidth: '100%'
+ }}
+ >
{/* 테이블 헤더 */}
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
- <TableRow key={headerGroup.id} className={compact ? "h-8" : ""}>
+ <TableRow key={headerGroup.id} className={compactStyles.headerRow}>
{headerGroup.headers.map((header) => {
if (header.column.getIsGrouped()) {
return null
@@ -113,10 +164,10 @@ export function InfiniteDataTable<TData>({
key={header.id}
colSpan={header.colSpan}
data-column-id={header.column.id}
- className={compact ? "py-1 px-2 text-sm" : ""}
+ className={compactStyles.header}
style={{
- ...getCommonPinningStyles({ column: header.column }),
- width: header.getSize(),
+ ...getPinnedStyle(header.column, true), // 🎯 헤더임을 명시
+ width: header.getSize(), // 🎯 width 별도 설정
}}
>
<div style={{ position: "relative" }}>
@@ -211,8 +262,8 @@ export function InfiniteDataTable<TData>({
data-column-id={cell.column.id}
className={compactStyles.cell}
style={{
- ...getCommonPinningStyles({ column: cell.column }),
- width: cell.column.getSize(),
+ ...getPinnedStyle(cell.column, false), // 🎯 바디 셀임을 명시
+ width: cell.column.getSize(), // 🎯 width 별도 설정
}}
>
{flexRender(