New useTable() hook
Signed-off-by: Charles de Dreuille <charles.dedreuille@gmail.com>
This commit is contained in:
@@ -1581,19 +1581,19 @@ export function TablePagination(props: TablePaginationProps): JSX_2.Element;
|
||||
export interface TablePaginationProps
|
||||
extends React.HTMLAttributes<HTMLDivElement> {
|
||||
// (undocumented)
|
||||
offset?: number;
|
||||
// (undocumented)
|
||||
onNextPage?: () => void;
|
||||
// (undocumented)
|
||||
onPageSizeChange?: (pageSize: number) => void;
|
||||
// (undocumented)
|
||||
onPreviousPage?: () => void;
|
||||
// (undocumented)
|
||||
pageIndex?: number;
|
||||
// (undocumented)
|
||||
pageSize?: number;
|
||||
// (undocumented)
|
||||
rowCount?: number;
|
||||
// (undocumented)
|
||||
setPageIndex?: (pageIndex: number) => void;
|
||||
setOffset?: (offset: number) => void;
|
||||
// (undocumented)
|
||||
setPageSize?: (pageSize: number) => void;
|
||||
// (undocumented)
|
||||
@@ -1727,6 +1727,50 @@ export const useBreakpoint: () => {
|
||||
// @public (undocumented)
|
||||
export const useIcons: () => IconContextProps;
|
||||
|
||||
// @public
|
||||
export function useTable<T = any>(
|
||||
config?: UseTableConfig<T>,
|
||||
): UseTableResult<T>;
|
||||
|
||||
// @public (undocumented)
|
||||
export interface UseTableConfig<T = any> {
|
||||
data?: T[];
|
||||
pagination?: UseTablePaginationConfig;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export interface UseTablePagination<T = any> {
|
||||
data?: T[];
|
||||
nextPage: () => void;
|
||||
offset: number;
|
||||
pageSize: number;
|
||||
paginationProps: TablePaginationProps;
|
||||
previousPage: () => void;
|
||||
setOffset: (offset: number) => void;
|
||||
setPageSize: (pageSize: number) => void;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export interface UseTablePaginationConfig {
|
||||
defaultOffset?: number;
|
||||
defaultPageSize?: number;
|
||||
offset?: number;
|
||||
onNextPage?: () => void;
|
||||
onOffsetChange?: (offset: number) => void;
|
||||
onPageSizeChange?: (pageSize: number) => void;
|
||||
onPreviousPage?: () => void;
|
||||
pageSize?: number;
|
||||
rowCount?: number;
|
||||
showPageSizeOptions?: boolean;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export interface UseTableResult<T = any> {
|
||||
data?: T[];
|
||||
pagination: UseTablePagination<T>;
|
||||
paginationProps: TablePaginationProps;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export interface UtilityProps extends SpaceProps {
|
||||
// (undocumented)
|
||||
|
||||
@@ -24,6 +24,7 @@ import {
|
||||
Row,
|
||||
Cell,
|
||||
CellProfile as CellProfileBUI,
|
||||
useTable,
|
||||
} from '.';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { data as data1 } from './mocked-data1';
|
||||
@@ -80,15 +81,9 @@ export const TableOnly: Story = {
|
||||
},
|
||||
};
|
||||
|
||||
export const WithPagination: Story = {
|
||||
export const WithPaginationUncontrolled: Story = {
|
||||
render: () => {
|
||||
const [pageIndex, setPageIndex] = useState(0);
|
||||
const [pageSize, setPageSize] = useState(10);
|
||||
|
||||
const newData = data1.slice(
|
||||
pageIndex * pageSize,
|
||||
(pageIndex + 1) * pageSize,
|
||||
);
|
||||
const { data, paginationProps } = useTable({ data: data1 });
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -100,7 +95,7 @@ export const WithPagination: Story = {
|
||||
<Column>Lifecycle</Column>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{newData.map(item => (
|
||||
{data?.map(item => (
|
||||
<Row key={item.name}>
|
||||
<Cell
|
||||
title={item.name}
|
||||
@@ -114,27 +109,28 @@ export const WithPagination: Story = {
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
<TablePagination
|
||||
pageIndex={pageIndex}
|
||||
pageSize={pageSize}
|
||||
rowCount={data1.length}
|
||||
setPageIndex={setPageIndex}
|
||||
setPageSize={setPageSize}
|
||||
/>
|
||||
<TablePagination {...paginationProps} />
|
||||
</>
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
export const TableRockBand: Story = {
|
||||
export const WithPaginationControlled: Story = {
|
||||
render: () => {
|
||||
const [pageIndex, setPageIndex] = useState(0);
|
||||
const [offset, setOffset] = useState(0);
|
||||
const [pageSize, setPageSize] = useState(5);
|
||||
|
||||
const newData = data4.slice(
|
||||
pageIndex * pageSize,
|
||||
(pageIndex + 1) * pageSize,
|
||||
);
|
||||
const { data, paginationProps } = useTable({
|
||||
data: data4,
|
||||
pagination: {
|
||||
offset,
|
||||
pageSize,
|
||||
onOffsetChange: setOffset,
|
||||
onPageSizeChange: setPageSize,
|
||||
onNextPage: () => console.log('Next page analytics'),
|
||||
onPreviousPage: () => console.log('Previous page analytics'),
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -146,7 +142,7 @@ export const TableRockBand: Story = {
|
||||
<Column>Albums</Column>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{newData.map(item => (
|
||||
{data?.map(item => (
|
||||
<Row key={item.name}>
|
||||
<CellProfileBUI
|
||||
name={item.name}
|
||||
@@ -160,27 +156,23 @@ export const TableRockBand: Story = {
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
<TablePagination
|
||||
pageIndex={pageIndex}
|
||||
pageSize={pageSize}
|
||||
rowCount={data4.length}
|
||||
setPageIndex={setPageIndex}
|
||||
setPageSize={setPageSize}
|
||||
/>
|
||||
<TablePagination {...paginationProps} />
|
||||
<div style={{ marginTop: '16px', fontSize: '12px', color: '#666' }}>
|
||||
Current state: offset={offset}, pageSize={pageSize}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
export const RowClick: Story = {
|
||||
export const TableRockBand: Story = {
|
||||
render: () => {
|
||||
const [pageIndex, setPageIndex] = useState(0);
|
||||
const [pageSize, setPageSize] = useState(5);
|
||||
|
||||
const newData = data4.slice(
|
||||
pageIndex * pageSize,
|
||||
(pageIndex + 1) * pageSize,
|
||||
);
|
||||
const { data, paginationProps } = useTable({
|
||||
data: data4,
|
||||
pagination: {
|
||||
defaultPageSize: 5,
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -192,7 +184,46 @@ export const RowClick: Story = {
|
||||
<Column>Albums</Column>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{newData.map(item => (
|
||||
{data?.map(item => (
|
||||
<Row key={item.name}>
|
||||
<CellProfileBUI
|
||||
name={item.name}
|
||||
src={item.image}
|
||||
href={item.website}
|
||||
/>
|
||||
<Cell title={item.genre} />
|
||||
<Cell title={item.yearFormed.toString()} />
|
||||
<Cell title={item.albums.toString()} />
|
||||
</Row>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
<TablePagination {...paginationProps} />
|
||||
</>
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
export const RowClick: Story = {
|
||||
render: () => {
|
||||
const { data, paginationProps } = useTable({
|
||||
data: data4,
|
||||
pagination: {
|
||||
defaultPageSize: 5,
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<Column isRowHeader>Band name</Column>
|
||||
<Column>Genre</Column>
|
||||
<Column>Year formed</Column>
|
||||
<Column>Albums</Column>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{data?.map(item => (
|
||||
<Row key={item.name} onAction={() => alert('Row clicked')}>
|
||||
<CellProfileBUI
|
||||
name={item.name}
|
||||
@@ -206,13 +237,7 @@ export const RowClick: Story = {
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
<TablePagination
|
||||
pageIndex={pageIndex}
|
||||
pageSize={pageSize}
|
||||
rowCount={data4.length}
|
||||
setPageIndex={setPageIndex}
|
||||
setPageSize={setPageSize}
|
||||
/>
|
||||
<TablePagination {...paginationProps} />
|
||||
</>
|
||||
);
|
||||
},
|
||||
@@ -220,13 +245,12 @@ export const RowClick: Story = {
|
||||
|
||||
export const RowLink: Story = {
|
||||
render: () => {
|
||||
const [pageIndex, setPageIndex] = useState(0);
|
||||
const [pageSize, setPageSize] = useState(5);
|
||||
|
||||
const newData = data4.slice(
|
||||
pageIndex * pageSize,
|
||||
(pageIndex + 1) * pageSize,
|
||||
);
|
||||
const { data, paginationProps } = useTable({
|
||||
data: data4,
|
||||
pagination: {
|
||||
defaultPageSize: 5,
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -238,7 +262,7 @@ export const RowLink: Story = {
|
||||
<Column>Albums</Column>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{newData.map(item => (
|
||||
{data?.map(item => (
|
||||
<Row key={item.name} href="/band">
|
||||
<CellProfileBUI
|
||||
name={item.name}
|
||||
@@ -252,13 +276,7 @@ export const RowLink: Story = {
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
<TablePagination
|
||||
pageIndex={pageIndex}
|
||||
pageSize={pageSize}
|
||||
rowCount={data4.length}
|
||||
setPageIndex={setPageIndex}
|
||||
setPageSize={setPageSize}
|
||||
/>
|
||||
<TablePagination {...paginationProps} />
|
||||
</>
|
||||
);
|
||||
},
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright 2025 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { TablePaginationProps } from '../../TablePagination/types';
|
||||
|
||||
/** @public */
|
||||
export interface UseTablePaginationConfig {
|
||||
/** Total number of rows in the dataset - only needed when data is not provided at the top level */
|
||||
rowCount?: number;
|
||||
|
||||
// Controlled pagination with offset/pageSize (Backstage style)
|
||||
/** Current offset. When provided, pagination is controlled */
|
||||
offset?: number;
|
||||
/** Current page size. When provided, pagination is controlled */
|
||||
pageSize?: number;
|
||||
/** Callback when offset changes */
|
||||
onOffsetChange?: (offset: number) => void;
|
||||
/** Callback when page size changes */
|
||||
onPageSizeChange?: (pageSize: number) => void;
|
||||
|
||||
// Uncontrolled pagination defaults
|
||||
/** Default page size for uncontrolled mode */
|
||||
defaultPageSize?: number;
|
||||
/** Default offset for uncontrolled mode */
|
||||
defaultOffset?: number;
|
||||
|
||||
// Analytics callbacks
|
||||
/** Callback when next page is clicked */
|
||||
onNextPage?: () => void;
|
||||
/** Callback when previous page is clicked */
|
||||
onPreviousPage?: () => void;
|
||||
|
||||
// UI options
|
||||
/** Whether to show page size options */
|
||||
showPageSizeOptions?: boolean;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export interface UseTablePagination<T = any> {
|
||||
/** Props to pass to TablePagination component */
|
||||
paginationProps: TablePaginationProps;
|
||||
/** Current offset */
|
||||
offset: number;
|
||||
/** Current page size */
|
||||
pageSize: number;
|
||||
/** Sliced data for current page - only available when data is provided to useTable */
|
||||
data?: T[];
|
||||
/** Go to next page */
|
||||
nextPage: () => void;
|
||||
/** Go to previous page */
|
||||
previousPage: () => void;
|
||||
/** Set specific offset */
|
||||
setOffset: (offset: number) => void;
|
||||
/** Set page size */
|
||||
setPageSize: (pageSize: number) => void;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export interface UseTableConfig<T = any> {
|
||||
/** Full dataset - when provided, rowCount is calculated automatically and sliced data is returned */
|
||||
data?: T[];
|
||||
/** Pagination configuration */
|
||||
pagination?: UseTablePaginationConfig;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export interface UseTableResult<T = any> {
|
||||
/** Sliced data for current page */
|
||||
data?: T[];
|
||||
/** Props to pass to TablePagination component */
|
||||
paginationProps: TablePaginationProps;
|
||||
/** Pagination utilities */
|
||||
pagination: UseTablePagination<T>;
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
* Copyright 2025 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { useState, useMemo, useCallback } from 'react';
|
||||
import type { TablePaginationProps } from '../../TablePagination/types';
|
||||
import type {
|
||||
UseTableConfig,
|
||||
UseTableResult,
|
||||
UseTablePagination,
|
||||
} from './types';
|
||||
|
||||
/**
|
||||
* Hook for managing table state including pagination and future features like sorting.
|
||||
* Supports both controlled and uncontrolled modes using offset/pageSize pattern (Backstage style).
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export function useTable<T = any>(
|
||||
config: UseTableConfig<T> = {},
|
||||
): UseTableResult<T> {
|
||||
const { data, pagination: paginationConfig = {} } = config;
|
||||
|
||||
const {
|
||||
rowCount: providedRowCount,
|
||||
offset: controlledOffset,
|
||||
pageSize: controlledPageSize,
|
||||
onOffsetChange,
|
||||
onPageSizeChange,
|
||||
defaultPageSize = 10,
|
||||
defaultOffset = 0,
|
||||
onNextPage,
|
||||
onPreviousPage,
|
||||
showPageSizeOptions = true,
|
||||
} = paginationConfig;
|
||||
|
||||
// Determine if we're in controlled mode
|
||||
const isControlled =
|
||||
controlledOffset !== undefined || controlledPageSize !== undefined;
|
||||
|
||||
// Calculate row count from data or use provided value
|
||||
const rowCount = data?.length ?? providedRowCount ?? 0;
|
||||
|
||||
// Internal state for uncontrolled mode
|
||||
const [internalOffset, setInternalOffset] = useState(defaultOffset);
|
||||
const [internalPageSize, setInternalPageSize] = useState(defaultPageSize);
|
||||
|
||||
// Calculate current values
|
||||
const currentOffset = controlledOffset ?? internalOffset;
|
||||
const currentPageSize = controlledPageSize ?? internalPageSize;
|
||||
|
||||
// Calculate sliced data if data array is provided
|
||||
const currentData = useMemo(() => {
|
||||
if (!data) return undefined;
|
||||
return data.slice(currentOffset, currentOffset + currentPageSize);
|
||||
}, [data, currentOffset, currentPageSize]);
|
||||
|
||||
// Update functions
|
||||
const setOffset = useCallback(
|
||||
(newOffset: number) => {
|
||||
if (isControlled) {
|
||||
onOffsetChange?.(newOffset);
|
||||
} else {
|
||||
setInternalOffset(newOffset);
|
||||
}
|
||||
},
|
||||
[isControlled, onOffsetChange],
|
||||
);
|
||||
|
||||
const setPageSize = useCallback(
|
||||
(newPageSize: number) => {
|
||||
// When changing page size, reset to first page to avoid showing empty results
|
||||
const newOffset = 0;
|
||||
|
||||
if (isControlled) {
|
||||
onPageSizeChange?.(newPageSize);
|
||||
onOffsetChange?.(newOffset);
|
||||
} else {
|
||||
setInternalPageSize(newPageSize);
|
||||
setInternalOffset(newOffset);
|
||||
}
|
||||
},
|
||||
[isControlled, onPageSizeChange, onOffsetChange],
|
||||
);
|
||||
|
||||
const nextPage = useCallback(() => {
|
||||
const nextOffset = currentOffset + currentPageSize;
|
||||
if (nextOffset < rowCount) {
|
||||
onNextPage?.();
|
||||
setOffset(nextOffset);
|
||||
}
|
||||
}, [currentOffset, currentPageSize, rowCount, onNextPage, setOffset]);
|
||||
|
||||
const previousPage = useCallback(() => {
|
||||
if (currentOffset > 0) {
|
||||
onPreviousPage?.();
|
||||
const prevOffset = Math.max(0, currentOffset - currentPageSize);
|
||||
setOffset(prevOffset);
|
||||
}
|
||||
}, [currentOffset, currentPageSize, onPreviousPage, setOffset]);
|
||||
|
||||
// Pagination props for TablePagination component
|
||||
const paginationProps: TablePaginationProps = useMemo(
|
||||
() => ({
|
||||
offset: currentOffset,
|
||||
pageSize: currentPageSize,
|
||||
rowCount,
|
||||
setOffset,
|
||||
setPageSize,
|
||||
onNextPage,
|
||||
onPreviousPage,
|
||||
showPageSizeOptions,
|
||||
}),
|
||||
[
|
||||
currentOffset,
|
||||
currentPageSize,
|
||||
rowCount,
|
||||
setOffset,
|
||||
setPageSize,
|
||||
onNextPage,
|
||||
onPreviousPage,
|
||||
showPageSizeOptions,
|
||||
],
|
||||
);
|
||||
|
||||
const pagination: UseTablePagination<T> = useMemo(
|
||||
() => ({
|
||||
paginationProps,
|
||||
offset: currentOffset,
|
||||
pageSize: currentPageSize,
|
||||
data: currentData,
|
||||
nextPage,
|
||||
previousPage,
|
||||
setOffset,
|
||||
setPageSize,
|
||||
}),
|
||||
[
|
||||
paginationProps,
|
||||
currentOffset,
|
||||
currentPageSize,
|
||||
currentData,
|
||||
nextPage,
|
||||
previousPage,
|
||||
setOffset,
|
||||
setPageSize,
|
||||
],
|
||||
);
|
||||
|
||||
return {
|
||||
data: currentData,
|
||||
paginationProps,
|
||||
pagination,
|
||||
};
|
||||
}
|
||||
@@ -21,5 +21,12 @@ export { Column } from './components/Column';
|
||||
export { Row } from './components/Row';
|
||||
export { Cell } from './components/Cell';
|
||||
export { CellProfile } from './components/CellProfile';
|
||||
export { useTable } from './hooks/useTable';
|
||||
|
||||
export type { CellProps, CellProfileProps } from './types';
|
||||
export type {
|
||||
UseTableConfig,
|
||||
UseTableResult,
|
||||
UseTablePagination,
|
||||
UseTablePaginationConfig,
|
||||
} from './hooks/types';
|
||||
|
||||
@@ -22,11 +22,11 @@ const meta = {
|
||||
title: 'Components/TablePagination',
|
||||
component: TablePagination,
|
||||
argTypes: {
|
||||
pageIndex: { control: 'number' },
|
||||
offset: { control: 'number' },
|
||||
pageSize: { control: 'radio', options: [5, 10, 20, 30, 40, 50] },
|
||||
rowCount: { control: 'number' },
|
||||
showPageSizeOptions: { control: 'boolean', defaultValue: true },
|
||||
setPageIndex: { action: 'setPageIndex' },
|
||||
setOffset: { action: 'setOffset' },
|
||||
setPageSize: { action: 'setPageSize' },
|
||||
},
|
||||
} satisfies Meta<typeof TablePagination>;
|
||||
@@ -36,7 +36,7 @@ type Story = StoryObj<typeof meta>;
|
||||
|
||||
export const Default: Story = {
|
||||
args: {
|
||||
pageIndex: 0,
|
||||
offset: 0,
|
||||
pageSize: 10,
|
||||
rowCount: 100,
|
||||
},
|
||||
@@ -46,8 +46,8 @@ export const Default: Story = {
|
||||
return (
|
||||
<TablePagination
|
||||
{...args}
|
||||
setPageIndex={value => {
|
||||
updateArgs({ pageIndex: value });
|
||||
setOffset={value => {
|
||||
updateArgs({ offset: value });
|
||||
}}
|
||||
setPageSize={value => {
|
||||
updateArgs({ pageSize: value });
|
||||
|
||||
@@ -26,45 +26,41 @@ import type { TablePaginationProps } from './types';
|
||||
export function TablePagination(props: TablePaginationProps) {
|
||||
const {
|
||||
className,
|
||||
pageIndex,
|
||||
offset,
|
||||
pageSize,
|
||||
rowCount,
|
||||
onNextPage,
|
||||
onPreviousPage,
|
||||
onPageSizeChange,
|
||||
setPageIndex,
|
||||
setOffset,
|
||||
setPageSize,
|
||||
showPageSizeOptions = true,
|
||||
...rest
|
||||
} = props;
|
||||
|
||||
const fromCount = (pageIndex ?? 0) * (pageSize ?? 10) + 1;
|
||||
const toCount = Math.min(
|
||||
((pageIndex ?? 0) + 1) * (pageSize ?? 10),
|
||||
rowCount ?? 0,
|
||||
);
|
||||
const currentOffset = offset ?? 0;
|
||||
const currentPageSize = pageSize ?? 10;
|
||||
|
||||
const fromCount = currentOffset + 1;
|
||||
const toCount = Math.min(currentOffset + currentPageSize, rowCount ?? 0);
|
||||
|
||||
const nextPage = () => {
|
||||
const currentPageIndex = pageIndex ?? 0;
|
||||
const currentPageSize = pageSize ?? 10;
|
||||
const totalRows = rowCount ?? 0;
|
||||
const nextOffset = currentOffset + currentPageSize;
|
||||
|
||||
// Check if there are more pages to navigate to
|
||||
const maxPageIndex = Math.ceil(totalRows / currentPageSize) - 1;
|
||||
|
||||
if (currentPageIndex < maxPageIndex) {
|
||||
// Check if there are more items to navigate to
|
||||
if (nextOffset < totalRows) {
|
||||
onNextPage?.(); // Analytics tracking
|
||||
setPageIndex?.(currentPageIndex + 1); // Navigate to next page
|
||||
setOffset?.(nextOffset); // Navigate to next page
|
||||
}
|
||||
};
|
||||
|
||||
const previousPage = () => {
|
||||
const currentPageIndex = pageIndex ?? 0;
|
||||
|
||||
// Check if we can go to previous page
|
||||
if (currentPageIndex > 0) {
|
||||
if (currentOffset > 0) {
|
||||
onPreviousPage?.(); // Analytics tracking
|
||||
setPageIndex?.(currentPageIndex - 1); // Navigate to previous page
|
||||
const prevOffset = Math.max(0, currentOffset - currentPageSize);
|
||||
setOffset?.(prevOffset); // Navigate to previous page
|
||||
}
|
||||
};
|
||||
|
||||
@@ -103,7 +99,7 @@ export function TablePagination(props: TablePaginationProps) {
|
||||
variant="secondary"
|
||||
size="small"
|
||||
onClick={previousPage}
|
||||
isDisabled={pageIndex === 0}
|
||||
isDisabled={currentOffset === 0}
|
||||
icon={<Icon name="chevron-left" />}
|
||||
aria-label="Previous"
|
||||
/>
|
||||
@@ -112,10 +108,8 @@ export function TablePagination(props: TablePaginationProps) {
|
||||
size="small"
|
||||
onClick={nextPage}
|
||||
isDisabled={
|
||||
pageIndex !== undefined &&
|
||||
pageSize !== undefined &&
|
||||
rowCount !== undefined &&
|
||||
pageIndex >= Math.ceil(rowCount / pageSize) - 1
|
||||
currentOffset + currentPageSize >= rowCount
|
||||
}
|
||||
icon={<Icon name="chevron-right" />}
|
||||
aria-label="Next"
|
||||
|
||||
@@ -17,10 +17,10 @@
|
||||
/** @public */
|
||||
export interface TablePaginationProps
|
||||
extends React.HTMLAttributes<HTMLDivElement> {
|
||||
pageIndex?: number;
|
||||
offset?: number;
|
||||
pageSize?: number;
|
||||
setPageSize?: (pageSize: number) => void;
|
||||
setPageIndex?: (pageIndex: number) => void;
|
||||
setOffset?: (offset: number) => void;
|
||||
rowCount?: number;
|
||||
onNextPage?: () => void;
|
||||
onPreviousPage?: () => void;
|
||||
|
||||
Reference in New Issue
Block a user