diff --git a/src/components/Paging/Paging.stories.tsx b/src/components/Paging/Paging.stories.tsx new file mode 100644 index 0000000..20045ee --- /dev/null +++ b/src/components/Paging/Paging.stories.tsx @@ -0,0 +1,80 @@ +import type { Meta, StoryObj } from '@storybook/react-vite' +import { fn } from 'storybook/test' +import { useState } from 'react' +import { Paging } from './Paging' + +const meta = { + title: 'Components/Paging', + component: Paging, + tags: ['autodocs'], + parameters: { layout: 'padded' }, + argTypes: { + pagingControls: { + control: 'select', + options: ['STANDARD', 'ROW_COUNT'], + }, + }, +} satisfies Meta + +export default meta +type Story = StoryObj + +export const Standard: Story = { + args: { + totalCount: 50, + pageSize: 10, + currentPage: 1, + pagingControls: 'STANDARD', + onPageChange: fn(), + }, + render: (args) => { + const [currentPage, setCurrentPage] = useState(args.currentPage) + return ( + + ) + }, +} + +export const RowCount: Story = { + args: { + totalCount: 50, + pageSize: 10, + currentPage: 1, + pagingControls: 'ROW_COUNT', + onPageChange: fn(), + }, + render: (args) => { + const [currentPage, setCurrentPage] = useState(args.currentPage) + return ( + + ) + }, +} + +export const TwoPages: Story = { + args: { + totalCount: 15, + pageSize: 10, + currentPage: 1, + pagingControls: 'ROW_COUNT', + onPageChange: fn(), + }, + render: (args) => { + const [currentPage, setCurrentPage] = useState(args.currentPage) + return ( + + ) + }, +} diff --git a/src/components/Paging/Paging.tsx b/src/components/Paging/Paging.tsx new file mode 100644 index 0000000..e5c27d0 --- /dev/null +++ b/src/components/Paging/Paging.tsx @@ -0,0 +1,92 @@ +import * as React from 'react' +import { ChevronLeft, ChevronRight, ChevronsLeft, ChevronsRight } from 'lucide-react' + +export interface PagingProps { + /** Total number of items */ + totalCount: number + /** Number of items per page */ + pageSize: number + /** Current page number (1-based) */ + currentPage: number + /** Callback when page changes */ + onPageChange: (page: number) => void + /** Determines if the paging includes the total row count. "STANDARD" hides total count; "ROW_COUNT" shows total count and first/last controls. */ + pagingControls?: 'STANDARD' | 'ROW_COUNT' + /** Whether the component is displayed */ + showWhen?: boolean +} + +export const Paging: React.FC = ({ + totalCount, + pageSize, + currentPage, + onPageChange, + pagingControls = 'STANDARD', + showWhen = true, +}) => { + if (!showWhen) return null + + const totalPages = Math.ceil(totalCount / pageSize) + if (totalPages <= 1) return null + + const startIndex = (currentPage - 1) * pageSize + 1 + const endIndex = Math.min(currentPage * pageSize, totalCount) + const hasPreviousPage = currentPage > 1 + const hasNextPage = currentPage < totalPages + + return ( +
+ {pagingControls === 'ROW_COUNT' && totalPages >= 3 && ( + + )} + + {pagingControls === 'ROW_COUNT' ? ( + + {startIndex} – {endIndex} + {' '}of {totalCount} + + ) : ( + + {startIndex} – {endIndex} + {' '}of many + + )} + + {pagingControls === 'ROW_COUNT' && totalPages >= 3 && ( + + )} +
+ ) +} diff --git a/src/components/Paging/index.ts b/src/components/Paging/index.ts new file mode 100644 index 0000000..a3c9c93 --- /dev/null +++ b/src/components/Paging/index.ts @@ -0,0 +1,2 @@ +export { Paging } from './Paging' +export type { PagingProps } from './Paging' diff --git a/src/components/ReadOnlyGrid/ReadOnlyGrid.tsx b/src/components/ReadOnlyGrid/ReadOnlyGrid.tsx index 1008bce..91b168d 100644 --- a/src/components/ReadOnlyGrid/ReadOnlyGrid.tsx +++ b/src/components/ReadOnlyGrid/ReadOnlyGrid.tsx @@ -1,5 +1,6 @@ import React from "react"; -import { ChevronLeft, ChevronRight, ChevronsLeft, ChevronsRight, MoveUp, MoveDown } from "lucide-react"; +import { MoveUp, MoveDown } from "lucide-react"; +import { Paging } from "../Paging"; import { isPaletteColor, resolveColorClass } from '../../utils/colorResolver' import { FieldWrapper } from "../shared/FieldWrapper"; import { GridColumn, type GridColumnProps } from "./GridColumn"; @@ -283,8 +284,6 @@ export const ReadOnlyGrid: React.FC = ({ const totalPages = Math.ceil(sortedRows.length / pageSize); const startIndex = (currentPage - 1) * pageSize; const endIndex = Math.min(startIndex + pageSize, sortedRows.length); - const hasPreviousPage = currentPage > 1; - const hasNextPage = currentPage < totalPages; // Slice sorted data for current page const pageRows = sortedRows.slice(startIndex, endIndex); @@ -503,61 +502,13 @@ export const ReadOnlyGrid: React.FC = ({ ) : ( renderTable() )} - {totalPages > 1 && ( -
- {pagingControls === "ROW_COUNT" && totalPages >= 3 && ( - - )} - - {pagingControls === "ROW_COUNT" ? ( - - {startIndex + 1} – {endIndex} - {" "}of {sortedRows.length} - - ) : ( - - {startIndex + 1} – {endIndex} - {" "}of many - - )} - - {pagingControls === "ROW_COUNT" && totalPages >= 3 && ( - - )} -
- )} + )} diff --git a/src/components/index.ts b/src/components/index.ts index d515025..77968fd 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -70,6 +70,9 @@ export * from './SideNavAdmin' // ReadOnlyGrid components export * from './ReadOnlyGrid' +// Paging components +export * from './Paging' + // SiteNav component export * from './SiteNav'