11'use client'
22
3- import React , { useRef } from 'react'
3+ import React , { type CSSProperties , useRef } from 'react'
44
55import { CircleNotchIcon , WarningCircleIcon , WarningIcon } from '@phosphor-icons/react'
66import { CaretDownIcon , CaretUpDownIcon , CaretUpIcon } from '@phosphor-icons/react/dist/ssr'
77import {
8+ type Column ,
89 flexRender ,
910 type Row ,
1011 type SortDirection ,
1112 type Table as TanstackTableCore ,
1213} from '@tanstack/react-table'
13- import clsx from 'clsx'
1414
1515import { Table , TableBody , TableCell , TableHead , TableHeader , TableRow } from './table'
1616
17+ import { cn } from '../../utils/cn'
18+
1719type RowClickHandler < T > = ( row : Row < T > , e : React . MouseEvent < HTMLTableCellElement > ) => void
1820
1921export interface TanstackTableProps < T > {
@@ -41,6 +43,25 @@ export interface TanstackTableProps<T> {
4143 }
4244}
4345
46+ const getCommonPinningClassesAndStyle = ( column : Column < any > ) => {
47+ const isPinned = column . getIsPinned ( )
48+ const isLastLeftPinnedColumn = isPinned === 'left' && column . getIsLastColumn ( 'left' )
49+ const isFirstRightPinnedColumn = isPinned === 'right' && column . getIsFirstColumn ( 'right' )
50+
51+ const className = cn (
52+ isPinned ? 'sticky z-[1]' : 'relative' ,
53+ isLastLeftPinnedColumn && 'shadow-[inset_-4px_0_4px_-4px_gray]' ,
54+ isFirstRightPinnedColumn && 'shadow-[inset_4px_0_4px_-4px_gray]'
55+ )
56+
57+ const style : CSSProperties = {
58+ left : isPinned === 'left' ? `${ column . getStart ( 'left' ) } px` : undefined ,
59+ right : isPinned === 'right' ? `${ column . getAfter ( 'right' ) } px` : undefined ,
60+ }
61+
62+ return { className, style }
63+ }
64+
4465export const getSortIcon = ( isSorted : false | SortDirection ) => {
4566 switch ( isSorted ) {
4667 case false :
@@ -92,15 +113,19 @@ export function TanstackTable<T>({
92113 const canSort = configuration ?. sortBy ?. some (
93114 ( [ columnPath ] ) => columnPath === normalizeColumnId ( header . column . id )
94115 )
116+ const { className : pinnedHeaderClassName , style : pinnedHeaderStyle } =
117+ getCommonPinningClassesAndStyle ( header . column )
95118 return (
96119 < TableHead
97120 key = { normalizeColumnId ( header . id ) }
98- className = { clsx (
121+ className = { cn (
99122 'focus-visible:ring-focus ring-inset' ,
100123 header . colSpan > 1 && 'border-bluegray-300 border-b' ,
101124 classNames ?. tableHead ,
125+ pinnedHeaderClassName ,
102126 header . column . columnDef . meta ?. thClassName
103127 ) }
128+ style = { pinnedHeaderStyle }
104129 onClick = {
105130 canSort && children ? header . column . getToggleSortingHandler ( ) : undefined
106131 }
@@ -109,7 +134,7 @@ export function TanstackTable<T>({
109134 tabIndex = { canSort ? 0 : - 1 }
110135 >
111136 < span
112- className = { clsx (
137+ className = { cn (
113138 'inline-flex items-center gap-2 w-full' ,
114139 header . colSpan > 1 && 'justify-center'
115140 ) }
@@ -123,7 +148,7 @@ export function TanstackTable<T>({
123148 </ TableRow >
124149 ) ) }
125150 </ TableHeader >
126- < TableBody className = { clsx ( classNames ?. tableBody ) } >
151+ < TableBody className = { cn ( classNames ?. tableBody ) } >
127152 { isLoading ? (
128153 < TableLoading table = { table } />
129154 ) : isError ? (
@@ -135,13 +160,20 @@ export function TanstackTable<T>({
135160 < TableRow
136161 key = { row . id }
137162 data-state = { row . getIsSelected ( ) && 'selected' }
138- className = { clsx ( 'border-b border-border last:border-b-0' , classNames ?. tableBodyRow ) }
163+ className = { cn ( 'border-b border-border last:border-b-0' , classNames ?. tableBodyRow ) }
139164 >
140165 { row . getVisibleCells ( ) . map ( ( cell ) => {
166+ const { className : pinnedCellClassName , style : pinnedCellStyle } =
167+ getCommonPinningClassesAndStyle ( cell . column )
141168 return (
142169 < TableCell
143170 key = { cell . id }
144- className = { clsx ( classNames ?. tableCell ) }
171+ className = { cn (
172+ classNames ?. tableCell ,
173+ pinnedCellClassName ,
174+ cell . column . columnDef . meta ?. tdClassName
175+ ) }
176+ style = { pinnedCellStyle }
145177 onClick = { ( e ) => onRowClick ?.( row , e ) }
146178 >
147179 { flexRender ( cell . column . columnDef . cell , cell . getContext ( ) ) }
0 commit comments