mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-28 06:08:50 +01:00
feat(DataTable): Implement new DataTable component with hooks and optimized features
- Added DataTable component with support for virtual scrolling, row selection, and customizable columns. - Introduced hooks for debouncing search input, managing row selection, and calculating column styles. - Enhanced accessibility with keyboard navigation and selection checkboxes. - Implemented skeleton loading state for better user experience during data fetching. - Added DataTableSearch component for filtering data with debounced input. - Created utility logger for improved debugging in development. - Updated translations to support new UI elements and actions.
This commit is contained in:
parent
ecadc2ec88
commit
76b34775f0
14 changed files with 1215 additions and 3294 deletions
105
packages/client/src/components/DataTable/DataTableComponents.tsx
Normal file
105
packages/client/src/components/DataTable/DataTableComponents.tsx
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
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';
|
||||
Loading…
Add table
Add a link
Reference in a new issue