feat(data-table): Introduce comprehensive DataTable component with full feature set

This commit is contained in:
ghost2023
2026-05-19 16:50:01 +03:00
parent 4085e856e3
commit 634747640a
7 changed files with 399 additions and 0 deletions

View File

@@ -0,0 +1,119 @@
import { Button } from "../button";
import { DataTableFooterProps } from "./types";
export interface DataTableFooterOptions {
pageSizeOptions?: number[];
showPageSizeSelector?: boolean;
showRowCount?: boolean;
showPagination?: boolean;
labels?: {
rowsPerPage?: string;
page?: string;
of?: string;
showing?: string;
ofLabel?: string;
items?: string;
previous?: string;
next?: string;
};
}
interface DataTableFooterComponentProps<
TData,
> extends DataTableFooterProps<TData> {
options?: DataTableFooterOptions;
}
const defaultOptions: DataTableFooterOptions = {
pageSizeOptions: [5, 10, 25, 50],
showPageSizeSelector: true,
showRowCount: true,
showPagination: true,
labels: {
rowsPerPage: "Rows per page",
page: "Page",
of: "of",
showing: "Showing",
ofLabel: "of",
items: "items",
previous: "Previous",
next: "Next",
},
};
export function DataTableFooter<TData>({
table,
pagination,
options = {},
}: DataTableFooterComponentProps<TData>) {
const opts = { ...defaultOptions, ...options };
const labels = { ...defaultOptions.labels, ...options.labels };
const pageIndex = pagination.pageIndex ?? 0;
const pageSize = pagination.pageSize ?? 10;
const totalCount = pagination.totalCount ?? 0;
const start = totalCount === 0 ? 0 : pageIndex * pageSize + 1;
const end = Math.min((pageIndex + 1) * pageSize, totalCount);
const handlePageSizeChange = (newPageSize: number) => {
table?.setPageSize(newPageSize);
};
return (
<div className="flex flex-wrap items-center justify-between gap-4 p-4 max-sm:flex-col max-sm:items-start">
{(opts.showPageSizeSelector || opts.showRowCount) && (
<div className="flex flex-wrap items-center gap-3 text-sm text-slate-500">
{opts.showPageSizeSelector && (
<>
<label htmlFor="page-size" className="font-medium text-slate-700">
{labels.rowsPerPage}
</label>
<select
id="page-size"
value={pageSize}
onChange={(e) => handlePageSizeChange(Number(e.target.value))}
className="h-9 rounded-xl border border-slate-200 bg-white px-3 text-sm text-slate-700 outline-none transition focus:border-[#33578D]/50 focus:ring-2 focus:ring-[#33578D]/20"
>
{opts.pageSizeOptions?.map((size) => (
<option key={size} value={size}>
{size}
</option>
))}
</select>
</>
)}
{opts.showRowCount && (
<span>
{labels.showing} {start}{end} {labels.ofLabel} {totalCount}{" "}
{labels.items}
</span>
)}
</div>
)}
{opts.showPagination && (
<div className="flex items-center justify-end space-x-2">
<div className="space-x-2">
<Button
variant="outline"
size="sm"
onClick={() => table?.previousPage()}
disabled={!table?.getCanPreviousPage()}
>
{labels.previous}
</Button>
<Button
variant="outline"
size="sm"
onClick={() => table?.nextPage()}
disabled={!table?.getCanNextPage()}
>
{labels.next}
</Button>
</div>
</div>
)}
</div>
);
}