import React, { memo, forwardRef } from 'react'; import { flexRender } from '@tanstack/react-table'; import type { TableColumn } from './DataTable.types'; import type { Row } from '@tanstack/react-table'; import { TableCell, TableRow, TableRowHeader } from '../Table'; import { Checkbox } from '../Checkbox'; import { Skeleton } from '../Skeleton'; import { cn } from '~/utils'; export const SelectionCheckbox = memo( ({ checked, onChange, ariaLabel, }: { checked: boolean; onChange: (value: boolean) => void; ariaLabel: string; }) => (
{ if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); onChange(!checked); } e.stopPropagation(); }} className="flex h-full w-8 items-center justify-center" onClick={(e) => { e.stopPropagation(); onChange(!checked); }} >
), ); SelectionCheckbox.displayName = 'SelectionCheckbox'; interface TableRowComponentProps> { row: Row; virtualIndex?: number; style?: React.CSSProperties; selected: boolean; } // ...existing code... const TableRowComponent = >( { row, virtualIndex, style, selected }: TableRowComponentProps, ref: React.Ref, ) => { // Check if we're on mobile - use window.innerWidth for component-level check const isSmallScreen = typeof window !== 'undefined' && window.innerWidth < 768; return ( {row.getVisibleCells().map((cell) => { const meta = cell.column.columnDef.meta as | { className?: string; desktopOnly?: boolean; width?: number; isRowHeader?: boolean } | undefined; const isDesktopOnly = meta?.desktopOnly; const isRowHeader = meta?.isRowHeader; const percent = meta?.width; const widthStyle = cell.column.id === 'select' ? { width: '32px', maxWidth: '32px', minWidth: '32px' } : percent ? { width: `${percent}%`, maxWidth: `${percent}%`, minWidth: `${percent}%`, // Don't shrink on mobile } : undefined; const CellComponent = isRowHeader ? TableRowHeader : TableCell; // For desktop-only columns on mobile, keep them in DOM but visually hidden // This ensures screen readers can still access the content const cellProps = isDesktopOnly && isSmallScreen ? { 'aria-hidden': false as const } // Keep accessible to screen readers : {}; return ( {flexRender(cell.column.columnDef.cell, cell.getContext())} ); })} ); }; // ...existing code... type ForwardTableRowComponentType = >( props: TableRowComponentProps & React.RefAttributes, ) => JSX.Element; const ForwardTableRowComponent = forwardRef(TableRowComponent) as ForwardTableRowComponentType; interface GenericRowProps { row: Row>; virtualIndex?: number; style?: React.CSSProperties; selected: boolean; } export const MemoizedTableRow = memo( ForwardTableRowComponent as (props: GenericRowProps) => JSX.Element, (prev: GenericRowProps, next: GenericRowProps) => prev.row.original === next.row.original && prev.selected === next.selected, ); export const SkeletonRows = memo( , TValue>({ count = 10, columns, }: { count?: number; columns: TableColumn[]; }) => ( <> {Array.from({ length: count }, (_, index) => ( {columns.map((column) => { const columnKey = String( column.id ?? ('accessorKey' in column && column.accessorKey) ?? '', ); const meta = column.meta as { className?: string; desktopOnly?: boolean } | undefined; return ( ); })} ))} ), ); SkeletonRows.displayName = 'SkeletonRows';