diff options
Diffstat (limited to 'components/data-table/infinite-data-table.tsx')
| -rw-r--r-- | components/data-table/infinite-data-table.tsx | 69 |
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( |
