LibreChat/packages/client/src/components/DataTable/DataTableComponents.tsx

106 lines
2.9 KiB
TypeScript
Raw Normal View History

import { memo } from 'react';
import { flexRender } from '@tanstack/react-table';
import type { Row, ColumnDef } from '@tanstack/react-table';
import type { TableColumn } from './DataTable.types';
import { Checkbox, TableCell, TableRow, Skeleton } from '~/components';
import { cn } from '~/utils';
export const SelectionCheckbox = memo(
({
checked,
onChange,
ariaLabel,
}: {
checked: boolean;
onChange: (value: boolean) => void;
ariaLabel: string;
}) => (
<div
role="button"
tabIndex={0}
onKeyDown={(e) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
onChange(!checked);
}
e.stopPropagation();
}}
className="flex h-full w-[30px] items-center justify-center"
onClick={(e) => {
e.stopPropagation();
onChange(!checked);
}}
>
<Checkbox checked={checked} onCheckedChange={onChange} aria-label={ariaLabel} />
</div>
),
);
SelectionCheckbox.displayName = 'SelectionCheckbox';
const TableRowComponent = <TData extends Record<string, unknown>>({
row,
virtualIndex,
}: {
row: Row<TData>;
columns: ColumnDef<TData, unknown>[];
index: number;
virtualIndex?: number;
}) => (
<TableRow
data-state={row.getIsSelected() ? 'selected' : undefined}
data-index={virtualIndex}
className="border-none hover:bg-surface-secondary"
>
{row.getVisibleCells().map((cell) => {
const meta = cell.column.columnDef.meta as { className?: string } | undefined;
return (
<TableCell
key={cell.id}
className={cn('truncate p-3', cell.column.id === 'select' && 'p-1', meta?.className)}
>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</TableCell>
);
})}
</TableRow>
);
export const MemoizedTableRow = memo(
TableRowComponent,
(prev, next) =>
prev.row.original === next.row.original &&
prev.row.getIsSelected() === next.row.getIsSelected() &&
prev.columns === next.columns,
);
export const SkeletonRows = memo(
<TData extends Record<string, unknown>, TValue>({
count = 10,
columns,
}: {
count?: number;
columns: TableColumn<TData, TValue>[];
}) => (
<>
{Array.from({ length: count }, (_, index) => (
<TableRow key={`skeleton-${index}`} className="h-[56px] border-b border-border-light">
{columns.map((column) => {
const columnKey = String(
column.id ?? ('accessorKey' in column && column.accessorKey) ?? '',
);
const meta = column.meta as { className?: string } | undefined;
return (
<TableCell key={columnKey} className={cn('px-2 py-2 md:px-3', meta?.className)}>
<Skeleton className="h-6 w-full" />
</TableCell>
);
})}
</TableRow>
))}
</>
),
);
SkeletonRows.displayName = 'SkeletonRows';