feat(client): add Pagination component and integrate with Table and pages
- add Pagination component with prev/next, ellipsis page range, and optional page-size selector - add Pagination and Table pagination stories (WithPagination, WithPaginationAndSizeSelector) - extend Table with optional pageSize and pageSizeOptions props for built-in client-side pagination - add Timestamp column to Table story fixtures - enable pagination on all four pages with pageSize=10 and size selector - add pagination i18n keys to en.json
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import type { ReactNode } from 'react';
|
||||
import { useState, type ReactNode } from 'react';
|
||||
import { Pagination } from '../Pagination/Pagination';
|
||||
import styles from './Table.module.css';
|
||||
|
||||
export interface TableColumn<T> {
|
||||
@@ -16,6 +17,10 @@ export interface TableProps<T> {
|
||||
loading?: boolean;
|
||||
emptyMessage?: string;
|
||||
className?: string;
|
||||
/** Enable built-in client-side pagination with this default page size */
|
||||
pageSize?: number;
|
||||
/** Offer a page-size selector when pagination is enabled */
|
||||
pageSizeOptions?: number[];
|
||||
}
|
||||
|
||||
export function Table<T>({
|
||||
@@ -25,7 +30,19 @@ export function Table<T>({
|
||||
loading = false,
|
||||
emptyMessage = 'No data.',
|
||||
className,
|
||||
pageSize: defaultPageSize,
|
||||
pageSizeOptions,
|
||||
}: TableProps<T>) {
|
||||
const [page, setPage] = useState(1);
|
||||
const [pageSize, setPageSize] = useState(defaultPageSize ?? 0);
|
||||
|
||||
const paginated = defaultPageSize !== undefined && !loading;
|
||||
const visibleData = paginated ? data.slice((page - 1) * pageSize, page * pageSize) : data;
|
||||
|
||||
// Reset to page 1 when data changes and current page would be empty
|
||||
const lastPage = pageSize > 0 ? Math.ceil(data.length / pageSize) : 1;
|
||||
const safePage = Math.min(page, Math.max(1, lastPage));
|
||||
|
||||
return (
|
||||
<div className={`${styles.wrapper} ${className ?? ''}`}>
|
||||
<table className={styles.table}>
|
||||
@@ -52,14 +69,14 @@ export function Table<T>({
|
||||
Loading…
|
||||
</td>
|
||||
</tr>
|
||||
) : data.length === 0 ? (
|
||||
) : visibleData.length === 0 ? (
|
||||
<tr>
|
||||
<td colSpan={columns.length} className={styles.empty}>
|
||||
{emptyMessage}
|
||||
</td>
|
||||
</tr>
|
||||
) : (
|
||||
data.map((row) => (
|
||||
visibleData.map((row) => (
|
||||
<tr key={rowKey(row)} className={styles.tr}>
|
||||
{columns.map((col) => (
|
||||
<td
|
||||
@@ -75,6 +92,23 @@ export function Table<T>({
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
{paginated && data.length > 0 && (
|
||||
<Pagination
|
||||
page={safePage}
|
||||
pageSize={pageSize}
|
||||
total={data.length}
|
||||
onPageChange={setPage}
|
||||
onPageSizeChange={
|
||||
pageSizeOptions
|
||||
? (size) => {
|
||||
setPageSize(size);
|
||||
setPage(1);
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
pageSizeOptions={pageSizeOptions}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user