feat(pagination): add server-side pagination support and controls

- Implement pagination control UI with page navigation and size selector
- Enable server-side callbacks for page changes and size adjustments
- Integrate pagination into Griddy component with data count handling
This commit is contained in:
2026-02-14 14:43:36 +02:00
parent b49d008745
commit 635da0ea18
27 changed files with 1320 additions and 39 deletions

View File

@@ -18,6 +18,7 @@ import React, { forwardRef, type Ref, useEffect, useImperativeHandle, useMemo, u
import type { GriddyProps, GriddyRef } from './types'
import { useKeyboardNavigation } from '../features/keyboard/useKeyboardNavigation'
import { PaginationControl } from '../features/pagination'
import { SearchOverlay } from '../features/search/SearchOverlay'
import { useGridVirtualizer } from '../rendering/hooks/useGridVirtualizer'
import { TableHeader } from '../rendering/TableHeader'
@@ -60,6 +61,9 @@ function GriddyInner<T>({ tableRef }: { tableRef: Ref<GriddyRef<T>> }) {
const height = useGriddyStore((s) => s.height)
const keyboardNavigation = useGriddyStore((s) => s.keyboardNavigation)
const className = useGriddyStore((s) => s.className)
const manualSorting = useGriddyStore((s) => s.manualSorting)
const manualFiltering = useGriddyStore((s) => s.manualFiltering)
const dataCount = useGriddyStore((s) => s.dataCount)
const setTable = useGriddyStore((s) => s.setTable)
const setVirtualizer = useGriddyStore((s) => s.setVirtualizer)
const setScrollRef = useGriddyStore((s) => s.setScrollRef)
@@ -91,6 +95,23 @@ function GriddyInner<T>({ tableRef }: { tableRef: Ref<GriddyRef<T>> }) {
pageSize: paginationConfig?.pageSize ?? DEFAULTS.pageSize,
})
// Wrap pagination setters to call callbacks
const handlePaginationChange = (updater: any) => {
setInternalPagination(prev => {
const next = typeof updater === 'function' ? updater(prev) : updater
// Call callbacks if pagination config exists
if (paginationConfig) {
if (next.pageIndex !== prev.pageIndex && paginationConfig.onPageChange) {
paginationConfig.onPageChange(next.pageIndex)
}
if (next.pageSize !== prev.pageSize && paginationConfig.onPageSizeChange) {
paginationConfig.onPageSizeChange(next.pageSize)
}
}
return next
})
}
// Resolve controlled vs uncontrolled
const sorting = controlledSorting ?? internalSorting
const setSorting = onSortingChange ?? setInternalSorting
@@ -114,16 +135,19 @@ function GriddyInner<T>({ tableRef }: { tableRef: Ref<GriddyRef<T>> }) {
enableRowSelection,
enableSorting: true,
getCoreRowModel: getCoreRowModel(),
getFilteredRowModel: getFilteredRowModel(),
getFilteredRowModel: manualFiltering ? undefined : getFilteredRowModel(),
getRowId: getRowId as any ?? ((_, index) => String(index)),
getSortedRowModel: getSortedRowModel(),
getSortedRowModel: manualSorting ? undefined : getSortedRowModel(),
manualFiltering: manualFiltering ?? false,
manualSorting: manualSorting ?? false,
onColumnFiltersChange: setColumnFilters as any,
onColumnOrderChange: setColumnOrder,
onColumnVisibilityChange: setColumnVisibility,
onGlobalFilterChange: setGlobalFilter,
onPaginationChange: paginationConfig?.enabled ? setInternalPagination : undefined,
onPaginationChange: paginationConfig?.enabled ? handlePaginationChange : undefined,
onRowSelectionChange: setRowSelection as any,
onSortingChange: setSorting as any,
rowCount: dataCount,
state: {
columnFilters,
columnOrder,
@@ -238,6 +262,12 @@ function GriddyInner<T>({ tableRef }: { tableRef: Ref<GriddyRef<T>> }) {
<TableHeader />
<VirtualBody />
</div>
{paginationConfig?.enabled && (
<PaginationControl
pageSizeOptions={paginationConfig.pageSizeOptions}
table={table}
/>
)}
</div>
)
}