diff --git a/package.json b/package.json index bb8d446..da0ed1d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@schemavaults/ui", - "version": "0.13.14", + "version": "0.13.15", "private": false, "license": "UNLICENSED", "description": "React.js UI components for SchemaVaults frontend applications", diff --git a/src/components/ui/datatable/Datatable.stories.tsx b/src/components/ui/datatable/Datatable.stories.tsx index 3f28149..5743c7d 100644 --- a/src/components/ui/datatable/Datatable.stories.tsx +++ b/src/components/ui/datatable/Datatable.stories.tsx @@ -24,6 +24,15 @@ const users: User[] = [ { id: "8", name: "Hannah Montana", email: "hannah@example.com", role: "Editor", status: "Inactive" }, ]; +/** Larger dataset for pagination demos. */ +const manyUsers: User[] = Array.from({ length: 55 }, (_, i) => ({ + id: String(i + 1), + name: `User ${i + 1}`, + email: `user${i + 1}@example.com`, + role: ["Admin", "Editor", "Viewer"][i % 3] as string, + status: ["Active", "Inactive", "Pending"][i % 3] as string, +})); + const columns: ColumnDef[] = [ { accessorKey: "name", @@ -152,3 +161,40 @@ export const NoSearch: Story = { export const WithHiddenColumns: Story = { render: (): ReactElement => , }; + +function CustomPageSizeDemo(): ReactElement { + return ( + + ); +} + +function LargePageSizeDemo(): ReactElement { + return ( + + ); +} + +export const CustomPageSize: Story = { + render: (): ReactElement => , +}; + +export const LargeDefaultPageSize: Story = { + render: (): ReactElement => , +}; diff --git a/src/components/ui/datatable/datatable.tsx b/src/components/ui/datatable/datatable.tsx index 8faf3e8..a6cfbf8 100644 --- a/src/components/ui/datatable/datatable.tsx +++ b/src/components/ui/datatable/datatable.tsx @@ -14,7 +14,13 @@ import { useReactTable, type RowSelectionState, } from "@tanstack/react-table"; -import { ChevronDown } from "lucide-react"; +import { + ChevronDown, + ChevronLeft, + ChevronRight, + ChevronsLeft, + ChevronsRight, +} from "lucide-react"; import { Button } from "@/components/ui/button"; import { @@ -24,6 +30,13 @@ import { DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { Input } from "@/components/ui/input"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; import { Table, TableBody, @@ -36,6 +49,9 @@ import { type ReactElement, useState, type FC } from "react"; export type { ColumnDef }; +/** Default page size options shown in the rows-per-page selector. */ +const DEFAULT_PAGE_SIZE_OPTIONS: readonly number[] = [10, 20, 50, 100]; + export interface DatatableProps { data: TData[]; columns: ColumnDef[]; @@ -52,6 +68,10 @@ export interface DatatableProps { searchColumn?: string | string[]; /** Enable global filtering across all columns. Overrides searchColumn if true. */ enableGlobalFilter?: boolean; + /** Number of rows to show per page. Defaults to 10. */ + defaultPageSize?: number; + /** Options shown in the rows-per-page selector. Defaults to [10, 20, 50, 100]. */ + pageSizeOptions?: number[]; } export function Datatable({ @@ -62,6 +82,8 @@ export function Datatable({ searchColumn, enableGlobalFilter = false, HeaderButtons, + defaultPageSize = 10, + pageSizeOptions = DEFAULT_PAGE_SIZE_OPTIONS as unknown as number[], }: DatatableProps): ReactElement { const [sorting, setSorting] = useState([]); const [columnFilters, setColumnFilters] = useState([]); @@ -99,6 +121,11 @@ export function Datatable({ const table = useReactTable({ data, columns: columns satisfies ColumnDef[], + initialState: { + pagination: { + pageSize: defaultPageSize, + }, + }, onSortingChange: setSorting, onColumnFiltersChange: setColumnFilters, getCoreRowModel: getCoreRowModel(), @@ -236,28 +263,84 @@ export function Datatable({ -
-
+ {/* Pagination */} +
+
{table.getFilteredSelectedRowModel().rows.length} of{" "} {table.getFilteredRowModel().rows.length} row(s) selected.
-
- - +
+ {/* Rows per page selector */} +
+ + Rows per page + + +
+ {/* Page indicator */} + + Page {table.getState().pagination.pageIndex + 1} of{" "} + {table.getPageCount()} + + {/* Navigation buttons */} +
+ + + + +