Skip to content

Commit dd29e95

Browse files
authored
Merge pull request #279 from PondC/pondc/sticky-table
feat: add style to pin column
2 parents 6e32d75 + 873044a commit dd29e95

3 files changed

Lines changed: 45 additions & 7 deletions

File tree

.changeset/deep-paths-rest.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@genseki/react': patch
3+
---
4+
5+
Add sticky column pinning style

packages/react/src/react/components/primitives/tanstack-table.tsx

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,21 @@
11
'use client'
22

3-
import React, { useRef } from 'react'
3+
import React, { type CSSProperties, useRef } from 'react'
44

55
import { CircleNotchIcon, WarningCircleIcon, WarningIcon } from '@phosphor-icons/react'
66
import { CaretDownIcon, CaretUpDownIcon, CaretUpIcon } from '@phosphor-icons/react/dist/ssr'
77
import {
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

1515
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from './table'
1616

17+
import { cn } from '../../utils/cn'
18+
1719
type RowClickHandler<T> = (row: Row<T>, e: React.MouseEvent<HTMLTableCellElement>) => void
1820

1921
export 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+
4465
export 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())}

packages/react/src/types/tanstack.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@ import '@tanstack/react-table'
44
declare module '@tanstack/react-table' {
55
interface ColumnMeta<TData, TValue> {
66
thClassName?: string
7+
tdClassName?: string
78
}
89
}

0 commit comments

Comments
 (0)