diff --git a/.changeset/deep-paths-rest.md b/.changeset/deep-paths-rest.md new file mode 100644 index 00000000..fb5f4fb5 --- /dev/null +++ b/.changeset/deep-paths-rest.md @@ -0,0 +1,5 @@ +--- +'@genseki/react': patch +--- + +Add sticky column pinning style diff --git a/packages/react/src/react/components/primitives/tanstack-table.tsx b/packages/react/src/react/components/primitives/tanstack-table.tsx index 2df3760e..a7ca1e7f 100644 --- a/packages/react/src/react/components/primitives/tanstack-table.tsx +++ b/packages/react/src/react/components/primitives/tanstack-table.tsx @@ -1,19 +1,21 @@ 'use client' -import React, { useRef } from 'react' +import React, { type CSSProperties, useRef } from 'react' import { CircleNotchIcon, WarningCircleIcon, WarningIcon } from '@phosphor-icons/react' import { CaretDownIcon, CaretUpDownIcon, CaretUpIcon } from '@phosphor-icons/react/dist/ssr' import { + type Column, flexRender, type Row, type SortDirection, type Table as TanstackTableCore, } from '@tanstack/react-table' -import clsx from 'clsx' import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from './table' +import { cn } from '../../utils/cn' + type RowClickHandler = (row: Row, e: React.MouseEvent) => void export interface TanstackTableProps { @@ -41,6 +43,25 @@ export interface TanstackTableProps { } } +const getCommonPinningClassesAndStyle = (column: Column) => { + const isPinned = column.getIsPinned() + const isLastLeftPinnedColumn = isPinned === 'left' && column.getIsLastColumn('left') + const isFirstRightPinnedColumn = isPinned === 'right' && column.getIsFirstColumn('right') + + const className = cn( + isPinned ? 'sticky z-[1]' : 'relative', + isLastLeftPinnedColumn && 'shadow-[inset_-4px_0_4px_-4px_gray]', + isFirstRightPinnedColumn && 'shadow-[inset_4px_0_4px_-4px_gray]' + ) + + const style: CSSProperties = { + left: isPinned === 'left' ? `${column.getStart('left')}px` : undefined, + right: isPinned === 'right' ? `${column.getAfter('right')}px` : undefined, + } + + return { className, style } +} + export const getSortIcon = (isSorted: false | SortDirection) => { switch (isSorted) { case false: @@ -92,15 +113,19 @@ export function TanstackTable({ const canSort = configuration?.sortBy?.some( ([columnPath]) => columnPath === normalizeColumnId(header.column.id) ) + const { className: pinnedHeaderClassName, style: pinnedHeaderStyle } = + getCommonPinningClassesAndStyle(header.column) return ( 1 && 'border-bluegray-300 border-b', classNames?.tableHead, + pinnedHeaderClassName, header.column.columnDef.meta?.thClassName )} + style={pinnedHeaderStyle} onClick={ canSort && children ? header.column.getToggleSortingHandler() : undefined } @@ -109,7 +134,7 @@ export function TanstackTable({ tabIndex={canSort ? 0 : -1} > 1 && 'justify-center' )} @@ -123,7 +148,7 @@ export function TanstackTable({ ))} - + {isLoading ? ( ) : isError ? ( @@ -135,13 +160,20 @@ export function TanstackTable({ {row.getVisibleCells().map((cell) => { + const { className: pinnedCellClassName, style: pinnedCellStyle } = + getCommonPinningClassesAndStyle(cell.column) return ( onRowClick?.(row, e)} > {flexRender(cell.column.columnDef.cell, cell.getContext())} diff --git a/packages/react/src/types/tanstack.d.ts b/packages/react/src/types/tanstack.d.ts index c0553d76..29a5f63d 100644 --- a/packages/react/src/types/tanstack.d.ts +++ b/packages/react/src/types/tanstack.d.ts @@ -4,5 +4,6 @@ import '@tanstack/react-table' declare module '@tanstack/react-table' { interface ColumnMeta { thClassName?: string + tdClassName?: string } }