diff --git a/README.md b/README.md index 71d2b5c8..cca5fac1 100644 --- a/README.md +++ b/README.md @@ -68,41 +68,41 @@ Then open `http://localhost:8000`. ### Pagination -| Property | Type | Default | Description | -| ---------------------------- | ------------------------------------------ | -------------------------------------- | ----------------------------------------------- | -| align | `'start' \| 'center' \| 'end'` | - | Align pagination items. | -| className | `string` | - | Class name for the root element. | -| classNames | `Partial>` | - | Semantic class names. | -| current | `number` | - | Controlled current page. | -| defaultCurrent | `number` | `1` | Initial current page. | -| defaultPageSize | `number` | `10` | Initial page size. | -| disabled | `boolean` | `false` | Disable pagination interactions. | -| hideOnSinglePage | `boolean` | `false` | Hide when there is only one page. | -| itemRender | `(page, type, element) => ReactNode` | - | Customize page, previous, next, and jump items. | -| jumpNextIcon | `ReactNode \| ComponentType` | - | Custom next-jump icon. | -| jumpPrevIcon | `ReactNode \| ComponentType` | - | Custom previous-jump icon. | -| locale | `PaginationLocale` | `zh_CN` | Locale text. | -| nextIcon | `ReactNode \| ComponentType` | - | Custom next icon. | -| pageSize | `number` | - | Controlled page size. | -| pageSizeOptions | `number[]` | - | Page-size options. | -| prefixCls | `string` | `rc-pagination` | Class name prefix. | -| prevIcon | `ReactNode \| ComponentType` | - | Custom previous icon. | -| role | `React.AriaRole` | - | WAI-ARIA role. | -| selectPrefixCls | `string` | `rc-select` | Prefix for the size changer select. | -| showLessItems | `boolean` | `false` | Show fewer page items. | -| showPrevNextJumpers | `boolean` | `true` | Show previous and next jumpers. | -| showQuickJumper | `boolean \| object` | `false` | Show quick page jumper. | -| showSizeChanger | `boolean` | `total > totalBoundaryShowSizeChanger` | Show page-size changer. | -| showTitle | `boolean` | `true` | Show title on page items. | -| showTotal | `(total, range) => ReactNode` | - | Render total text. | -| simple | `boolean \| { readOnly?: boolean }` | `false` | Use simple pager. | -| sizeChangerRender | `SizeChangerRender` | - | Customize the size changer. | -| style | `React.CSSProperties` | - | Root inline style. | -| styles | `Partial>` | - | Semantic styles. | -| total | `number` | `0` | Total item count. | -| totalBoundaryShowSizeChanger | `number` | `50` | Boundary for default `showSizeChanger`. | -| onChange | `(page: number, pageSize: number) => void` | - | Triggered when page or page size changes. | -| onShowSizeChange | `(current: number, size: number) => void` | - | Triggered when page size changes. | +| Property | Type | Default | Description | +| ---------------------------- | ----------------------------------------------------------------------------- | -------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| align | `'start' \| 'center' \| 'end'` | - | Align pagination items. | +| className | `string` | - | Class name for the root element. | +| classNames | `Partial>` | - | Semantic class names. | +| current | `number` | - | Controlled current page. | +| defaultCurrent | `number` | `1` | Initial current page. | +| defaultPageSize | `number` | `10` | Initial page size. | +| disabled | `boolean` | `false` | Disable pagination interactions. | +| hideOnSinglePage | `boolean` | `false` | Hide when there is only one page. | +| itemRender | `(page, type, element) => ReactNode` | - | Customize page, previous, next, and jump items. | +| jumpNextIcon | `ReactNode \| ComponentType` | - | Custom next-jump icon. | +| jumpPrevIcon | `ReactNode \| ComponentType` | - | Custom previous-jump icon. | +| locale | `PaginationLocale` | `zh_CN` | Locale text. | +| nextIcon | `ReactNode \| ComponentType` | - | Custom next icon. | +| pageSize | `number` | - | Controlled page size. | +| pageSizeOptions | `number[]` | - | Page-size options. | +| prefixCls | `string` | `rc-pagination` | Class name prefix. | +| prevIcon | `ReactNode \| ComponentType` | - | Custom previous icon. | +| role | `React.AriaRole` | - | WAI-ARIA role. | +| selectPrefixCls | `string` | `rc-select` | Prefix for the size changer select. | +| showLessItems | `boolean` | `false` | Show fewer page items. | +| showPrevNextJumpers | `boolean` | `true` | Show previous and next jumpers. | +| showQuickJumper | `boolean \| object` | `false` | Show quick page jumper. | +| showSizeChanger | `boolean` | `total > totalBoundaryShowSizeChanger` | Show page-size changer. | +| showTitle | `boolean` | `true` | Show title on page items. | +| showTotal | `(total, range) => ReactNode` | - | Render total text. | +| simple | `boolean \| { readOnly?: boolean }` | `false` | Use simple pager. | +| sizeChangerRender | `SizeChangerRender` | - | Customize the size changer. | +| style | `React.CSSProperties` | - | Root inline style. | +| styles | `Partial>` | - | Semantic styles. | +| total | `number` | `0` | Total item count. | +| totalBoundaryShowSizeChanger | `number` | `50` | Boundary for default `showSizeChanger`. | +| onChange | `(page: number, pageSize: number, info?: { recommendPage?: number }) => void` | - | Triggered when page or page size changes. The `info.recommendPage` is only provided when pageSize changes, indicating the recommended page number based on the new page size. | +| onShowSizeChange | `(current: number, size: number) => void` | - | Triggered when page size changes. | ## Development diff --git a/README.zh-CN.md b/README.zh-CN.md index 21bbfd08..b9e425fe 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -68,41 +68,41 @@ npm start ### Pagination -| 参数 | 类型 | 默认值 | 说明 | -| ---------------------------- | ------------------------------------------ | -------------------------------------- | -------------------------------------- | -| align | `'start' \| 'center' \| 'end'` | - | 对齐分页项目。 | -| className | `string` | - | 根元素的 className。 | -| classNames | `Partial>` | - | 语义 className。 | -| current | `number` | - | 控制当前页面。 | -| defaultCurrent | `number` | `1` | 初始当前页面。 | -| defaultPageSize | `number` | `10` | 初始页面大小。 | -| disabled | `boolean` | `false` | 禁用分页交互。 | -| hideOnSinglePage | `boolean` | `false` | 当只有一页时隐藏。 | -| itemRender | `(page, type, element) => ReactNode` | - | 自定义页面、上一个、下一个和跳转项目。 | -| jumpNextIcon | `ReactNode \| ComponentType` | - | 自定义下一跳图标。 | -| jumpPrevIcon | `ReactNode \| ComponentType` | - | 自定义上一跳转图标。 | -| locale | `PaginationLocale` | `zh_CN` | 区域设置文本。 | -| nextIcon | `ReactNode \| ComponentType` | - | 自定义下一个图标。 | -| pageSize | `number` | - | 受控的页面大小。 | -| pageSizeOptions | `number[]` | - | 页面大小选项。 | -| prefixCls | `string` | `rc-pagination` | className 前缀。 | -| prevIcon | `ReactNode \| ComponentType` | - | 自定义上一个图标。 | -| role | `React.AriaRole` | - | WAI-ARIA 角色。 | -| selectPrefixCls | `string` | `rc-select` | 尺寸变换器选择的前缀。 | -| showLessItems | `boolean` | `false` | 显示较少的页面项目。 | -| showPrevNextJumpers | `boolean` | `true` | 显示上一个和下一个跳线。 | -| showQuickJumper | `boolean \| object` | `false` | 显示快速跳页。 | -| showSizeChanger | `boolean` | `total > totalBoundaryShowSizeChanger` | 显示页面大小更改器。 | -| showTitle | `boolean` | `true` | 在页面项目上显示标题。 | -| showTotal | `(total, range) => ReactNode` | - | 渲染总文本。 | -| simple | `boolean \| { readOnly?: boolean }` | `false` | 使用简洁分页器。 | -| sizeChangerRender | `SizeChangerRender` | - | 定制尺寸变换器。 | -| style | `React.CSSProperties` | - | 根内联样式。 | -| styles | `Partial>` | - | 语义化样式。 | -| total | `number` | `0` | 项目总数。 | -| totalBoundaryShowSizeChanger | `number` | `50` | 默认的边界 `showSizeChanger`。 | -| onChange | `(page: number, pageSize: number) => void` | - | 当页面或页面大小更改时触发。 | -| onShowSizeChange | `(current: number, size: number) => void` | - | 当页面大小改变时触发。 | +| 参数 | 类型 | 默认值 | 说明 | +| ---------------------------- | ----------------------------------------------------------------------------- | -------------------------------------- | ------------------------------------------------------------------------------------------------------------- | +| align | `'start' \| 'center' \| 'end'` | - | 对齐分页项目。 | +| className | `string` | - | 根元素的 className。 | +| classNames | `Partial>` | - | 语义 className。 | +| current | `number` | - | 控制当前页面。 | +| defaultCurrent | `number` | `1` | 初始当前页面。 | +| defaultPageSize | `number` | `10` | 初始页面大小。 | +| disabled | `boolean` | `false` | 禁用分页交互。 | +| hideOnSinglePage | `boolean` | `false` | 当只有一页时隐藏。 | +| itemRender | `(page, type, element) => ReactNode` | - | 自定义页面、上一个、下一个和跳转项目。 | +| jumpNextIcon | `ReactNode \| ComponentType` | - | 自定义下一跳图标。 | +| jumpPrevIcon | `ReactNode \| ComponentType` | - | 自定义上一跳转图标。 | +| locale | `PaginationLocale` | `zh_CN` | 区域设置文本。 | +| nextIcon | `ReactNode \| ComponentType` | - | 自定义下一个图标。 | +| pageSize | `number` | - | 受控的页面大小。 | +| pageSizeOptions | `number[]` | - | 页面大小选项。 | +| prefixCls | `string` | `rc-pagination` | className 前缀。 | +| prevIcon | `ReactNode \| ComponentType` | - | 自定义上一个图标。 | +| role | `React.AriaRole` | - | WAI-ARIA 角色。 | +| selectPrefixCls | `string` | `rc-select` | 尺寸变换器选择的前缀。 | +| showLessItems | `boolean` | `false` | 显示较少的页面项目。 | +| showPrevNextJumpers | `boolean` | `true` | 显示上一个和下一个跳线。 | +| showQuickJumper | `boolean \| object` | `false` | 显示快速跳页。 | +| showSizeChanger | `boolean` | `total > totalBoundaryShowSizeChanger` | 显示页面大小更改器。 | +| showTitle | `boolean` | `true` | 在页面项目上显示标题。 | +| showTotal | `(total, range) => ReactNode` | - | 渲染总文本。 | +| simple | `boolean \| { readOnly?: boolean }` | `false` | 使用简洁分页器。 | +| sizeChangerRender | `SizeChangerRender` | - | 定制尺寸变换器。 | +| style | `React.CSSProperties` | - | 根内联样式。 | +| styles | `Partial>` | - | 语义化样式。 | +| total | `number` | `0` | 项目总数。 | +| totalBoundaryShowSizeChanger | `number` | `50` | 默认的边界 `showSizeChanger`。 | +| onChange | `(page: number, pageSize: number, info?: { recommendPage?: number }) => void` | - | 当页面或页面大小更改时触发。`info.recommendPage` 仅在切换 pageSize 时传入,表示基于新页面大小推荐的分页号码。 | +| onShowSizeChange | `(current: number, size: number) => void` | - | 当页面大小改变时触发。 | ## 本地开发 diff --git a/docs/examples/jumper.tsx b/docs/examples/jumper.tsx index 9dbeef2f..d3b39ebb 100644 --- a/docs/examples/jumper.tsx +++ b/docs/examples/jumper.tsx @@ -9,9 +9,10 @@ function onShowSizeChange(current, pageSize) { console.log(pageSize); } -function onChange(current, pageSize) { +function onChange(current, pageSize, info) { console.log('onChange:current=', current); console.log('onChange:pageSize=', pageSize); + console.log('onChange:recommendPage=', info?.recommendPage); } const App = () => ( diff --git a/src/Pagination.tsx b/src/Pagination.tsx index 53f0076c..ac1c4b26 100644 --- a/src/Pagination.tsx +++ b/src/Pagination.tsx @@ -197,7 +197,11 @@ const Pagination: React.FC = (props) => { } function changePageSize(size: number) { + const preservedPage = Math.floor(((current - 1) * pageSize) / size) + 1; const newCurrent = calculatePage(size, pageSize, total); + const recommendPage = + newCurrent === 0 ? 1 : Math.min(preservedPage, newCurrent); + const nextCurrent = current > newCurrent && newCurrent !== 0 ? newCurrent : current; @@ -205,7 +209,7 @@ const Pagination: React.FC = (props) => { setInternalInputVal(nextCurrent); onShowSizeChange?.(current, size); setCurrent(nextCurrent); - onChange?.(nextCurrent, size); + onChange?.(nextCurrent, size, { recommendPage }); } function handleChange(page: number) { diff --git a/src/index.ts b/src/index.ts index ac30e303..39c480d3 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,2 +1,6 @@ export { default } from './Pagination'; -export type { PaginationLocale, PaginationProps } from './interface'; +export type { + PaginationLocale, + PaginationProps, + PaginationOnChangeInfo, +} from './interface'; diff --git a/src/interface.ts b/src/interface.ts index b37a0788..2b82cab4 100644 --- a/src/interface.ts +++ b/src/interface.ts @@ -56,10 +56,17 @@ export interface PaginationData { jumpNextIcon: React.ComponentType | React.ReactNode; } +export interface PaginationOnChangeInfo { + recommendPage?: number; +} + export interface PaginationProps - extends Partial, - React.AriaAttributes { - onChange?: (page: number, pageSize: number) => void; + extends Partial, React.AriaAttributes { + onChange?: ( + page: number, + pageSize: number, + info?: PaginationOnChangeInfo, + ) => void; onShowSizeChange?: (current: number, size: number) => void; itemRender?: ( page: number, diff --git a/tests/index.test.tsx b/tests/index.test.tsx index 45fa5487..7cba57e2 100644 --- a/tests/index.test.tsx +++ b/tests/index.test.tsx @@ -483,7 +483,7 @@ describe('current value on onShowSizeChange when total is 0', () => { fireEvent.keyDown(input, { key: 'Down', keyCode: 40, which: 40 }); fireEvent.keyDown(input, { key: 'Enter', keyCode: 13, which: 13 }); expect(onShowSizeChange).toHaveBeenLastCalledWith(1, 20); - expect(onChange).toHaveBeenLastCalledWith(1, 20); + expect(onChange).toHaveBeenLastCalledWith(1, 20, { recommendPage: 1 }); }); it('when total is 0, pager should show `1` and being disabled', () => { diff --git a/tests/simple.test.tsx b/tests/simple.test.tsx index 568858a4..fb3e644b 100644 --- a/tests/simple.test.tsx +++ b/tests/simple.test.tsx @@ -131,7 +131,7 @@ describe('simple Pagination', () => { const pageSize1 = container.querySelectorAll('.rc-select-item')[0]; fireEvent.click(pageSize1); expect(onChange).toHaveBeenCalled(); - expect(onChange).toHaveBeenLastCalledWith(1, 10); + expect(onChange).toHaveBeenLastCalledWith(1, 10, { recommendPage: 1 }); }); it('should support keyboard event', () => { diff --git a/tests/sizer.test.tsx b/tests/sizer.test.tsx index ba4d1d3b..78ce3b8b 100644 --- a/tests/sizer.test.tsx +++ b/tests/sizer.test.tsx @@ -50,24 +50,21 @@ describe('Pagination with sizer', () => { ); }); - it('should onChange called when pageSize change', () => { + it('should provide correct recommendPage when shrinking pageSize', () => { const onChange = jest.fn(); const { container, getByRole } = render( , ); fireEvent.mouseDown(getByRole('combobox')); - expect(container.querySelectorAll('.rc-select-item')[2]).toHaveTextContent( - '50 条/页', - ); - const pageSize1 = container.querySelectorAll('.rc-select-item')[0]; - fireEvent.click(pageSize1); - expect(onChange).toHaveBeenCalled(); - expect(onChange).toHaveBeenLastCalledWith(1, 10); + const pageSize10 = container.querySelectorAll('.rc-select-item')[0]; + fireEvent.click(pageSize10); + expect(onChange).toHaveBeenLastCalledWith(3, 10, { recommendPage: 11 }); }); // https://github.com/ant-design/ant-design/issues/26580