fix: Pagination select props order (#51962)
Some checks are pending
Publish Any Commit / build (push) Waiting to run
🔀 Sync mirror to Gitee / mirror (push) Waiting to run
✅ test / lint (push) Waiting to run
✅ test / test-react-legacy (16, 1/2) (push) Waiting to run
✅ test / test-react-legacy (16, 2/2) (push) Waiting to run
✅ test / test-react-legacy (17, 1/2) (push) Waiting to run
✅ test / test-react-legacy (17, 2/2) (push) Waiting to run
✅ test / test-node (push) Waiting to run
✅ test / test-react-latest (dom, 1/2) (push) Waiting to run
✅ test / test-react-latest (dom, 2/2) (push) Waiting to run
✅ test / test-react-latest-dist (dist, 1/2) (push) Blocked by required conditions
✅ test / test-react-latest-dist (dist, 2/2) (push) Blocked by required conditions
✅ test / test-react-latest-dist (dist-min, 1/2) (push) Blocked by required conditions
✅ test / test-react-latest-dist (dist-min, 2/2) (push) Blocked by required conditions
✅ test / test-coverage (push) Blocked by required conditions
✅ test / build (push) Waiting to run
✅ test / test lib/es module (es, 1/2) (push) Waiting to run
✅ test / test lib/es module (es, 2/2) (push) Waiting to run
✅ test / test lib/es module (lib, 1/2) (push) Waiting to run
✅ test / test lib/es module (lib, 2/2) (push) Waiting to run
👁️ Visual Regression Persist Start / test image (push) Waiting to run

* fix: Pagination select props order

* chore: replace with select

* chore: back of support

* chore: bump rc-pagination

* chore: merge selection

* chore: fix lint
This commit is contained in:
二货爱吃白萝卜 2024-12-11 11:42:51 +08:00 committed by GitHub
parent 9b4400b268
commit 846dc9b022
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 136 additions and 33 deletions

View File

@ -8,17 +8,20 @@ import type { PaginationLocale, PaginationProps as RcPaginationProps } from 'rc-
import RcPagination from 'rc-pagination'; import RcPagination from 'rc-pagination';
import enUS from 'rc-pagination/lib/locale/en_US'; import enUS from 'rc-pagination/lib/locale/en_US';
import { devUseWarning } from '../_util/warning';
import { ConfigContext } from '../config-provider'; import { ConfigContext } from '../config-provider';
import useSize from '../config-provider/hooks/useSize'; import useSize from '../config-provider/hooks/useSize';
import useBreakpoint from '../grid/hooks/useBreakpoint'; import useBreakpoint from '../grid/hooks/useBreakpoint';
import type { SelectProps } from '../select';
import { useLocale } from '../locale'; import { useLocale } from '../locale';
import type { SelectProps } from '../select';
import Select from '../select';
import { useToken } from '../theme/internal'; import { useToken } from '../theme/internal';
import { MiddleSelect, MiniSelect } from './Select';
import useStyle from './style'; import useStyle from './style';
import BorderedStyle from './style/bordered'; import BorderedStyle from './style/bordered';
import useShowSizeChanger from './useShowSizeChanger';
export interface PaginationProps extends RcPaginationProps { export interface PaginationProps
extends Omit<RcPaginationProps, 'showSizeChanger' | 'pageSizeOptions'> {
showQuickJumper?: boolean | { goButton?: React.ReactNode }; showQuickJumper?: boolean | { goButton?: React.ReactNode };
size?: 'default' | 'small'; size?: 'default' | 'small';
responsive?: boolean; responsive?: boolean;
@ -26,6 +29,10 @@ export interface PaginationProps extends RcPaginationProps {
totalBoundaryShowSizeChanger?: number; totalBoundaryShowSizeChanger?: number;
rootClassName?: string; rootClassName?: string;
showSizeChanger?: boolean | SelectProps; showSizeChanger?: boolean | SelectProps;
/** @deprecated Not official support. Will be removed in next major version. */
selectComponentClass?: any;
/** `string` type will be removed in next major version. */
pageSizeOptions?: (string | number)[];
} }
export type PaginationPosition = 'top' | 'bottom' | 'both'; export type PaginationPosition = 'top' | 'bottom' | 'both';
@ -46,9 +53,10 @@ const Pagination: React.FC<PaginationProps> = (props) => {
style, style,
size: customizeSize, size: customizeSize,
locale: customLocale, locale: customLocale,
selectComponentClass,
responsive, responsive,
showSizeChanger, showSizeChanger,
selectComponentClass,
pageSizeOptions,
...restProps ...restProps
} = props; } = props;
const { xs } = useBreakpoint(responsive); const { xs } = useBreakpoint(responsive);
@ -60,8 +68,86 @@ const Pagination: React.FC<PaginationProps> = (props) => {
// Style // Style
const [wrapCSSVar, hashId, cssVarCls] = useStyle(prefixCls); const [wrapCSSVar, hashId, cssVarCls] = useStyle(prefixCls);
const mergedShowSizeChanger = showSizeChanger ?? pagination.showSizeChanger; // ============================== Size ==============================
const mergedSize = useSize(customizeSize);
const isSmall = mergedSize === 'small' || !!(xs && !mergedSize && responsive);
// ============================= Locale =============================
const [contextLocale] = useLocale('Pagination', enUS);
const locale = { ...contextLocale, ...customLocale };
// ========================== Size Changer ==========================
// Merge the props showSizeChanger
const [propShowSizeChanger, propSizeChangerSelectProps] = useShowSizeChanger(showSizeChanger);
const [contextShowSizeChanger, contextSizeChangerSelectProps] = useShowSizeChanger(
pagination.showSizeChanger,
);
const mergedShowSizeChanger = propShowSizeChanger ?? contextShowSizeChanger;
const mergedShowSizeChangerSelectProps =
propSizeChangerSelectProps ?? contextSizeChangerSelectProps;
const SizeChanger: typeof Select = selectComponentClass || Select;
// Generate options
const mergedPageSizeOptions = React.useMemo(() => {
return pageSizeOptions ? pageSizeOptions.map((option) => Number(option)) : undefined;
}, [pageSizeOptions]);
// Render size changer
const sizeChangerRender: RcPaginationProps['sizeChangerRender'] = (info) => {
const {
disabled,
size: pageSize,
onSizeChange,
'aria-label': ariaLabel,
className: sizeChangerClassName,
options,
} = info;
const { className: propSizeChangerClassName, onChange: propSizeChangerOnChange } =
mergedShowSizeChangerSelectProps || {};
// Origin Select is using Select.Option,
// So it make the option value must be string
// Just for compatible
const selectedValue = options.find(
(option) => String(option.value) === String(pageSize),
)?.value;
return (
<SizeChanger
disabled={disabled}
showSearch
popupMatchSelectWidth={false}
getPopupContainer={(triggerNode) => triggerNode.parentNode}
aria-label={ariaLabel}
options={options}
{...mergedShowSizeChangerSelectProps}
value={selectedValue}
onChange={(nextSize, option) => {
onSizeChange?.(nextSize);
propSizeChangerOnChange?.(nextSize, option);
}}
size={isSmall ? 'small' : 'middle'}
className={classNames(sizeChangerClassName, propSizeChangerClassName)}
/>
);
};
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning('Pagination');
warning(
!selectComponentClass,
'usage',
'`selectComponentClass` is not official api which will be removed.',
);
}
// ============================= Render =============================
const iconsProps = React.useMemo<Record<PropertyKey, React.ReactNode>>(() => { const iconsProps = React.useMemo<Record<PropertyKey, React.ReactNode>>(() => {
const ellipsis = <span className={`${prefixCls}-item-ellipsis`}></span>; const ellipsis = <span className={`${prefixCls}-item-ellipsis`}></span>;
const prevIcon = ( const prevIcon = (
@ -103,14 +189,6 @@ const Pagination: React.FC<PaginationProps> = (props) => {
return { prevIcon, nextIcon, jumpPrevIcon, jumpNextIcon }; return { prevIcon, nextIcon, jumpPrevIcon, jumpNextIcon };
}, [direction, prefixCls]); }, [direction, prefixCls]);
const [contextLocale] = useLocale('Pagination', enUS);
const locale = { ...contextLocale, ...customLocale };
const mergedSize = useSize(customizeSize);
const isSmall = mergedSize === 'small' || !!(xs && !mergedSize && responsive);
const selectPrefixCls = getPrefixCls('select', customizeSelectPrefixCls); const selectPrefixCls = getPrefixCls('select', customizeSelectPrefixCls);
const extendedClassName = classNames( const extendedClassName = classNames(
@ -139,9 +217,10 @@ const Pagination: React.FC<PaginationProps> = (props) => {
prefixCls={prefixCls} prefixCls={prefixCls}
selectPrefixCls={selectPrefixCls} selectPrefixCls={selectPrefixCls}
className={extendedClassName} className={extendedClassName}
selectComponentClass={selectComponentClass || (isSmall ? MiniSelect : MiddleSelect)}
locale={locale} locale={locale}
pageSizeOptions={mergedPageSizeOptions}
showSizeChanger={mergedShowSizeChanger} showSizeChanger={mergedShowSizeChanger}
sizeChangerRender={sizeChangerRender}
/> />
</>, </>,
); );

View File

@ -1,16 +0,0 @@
import * as React from 'react';
import type { SelectProps } from '../select';
import Select from '../select';
type CompoundedComponent = React.FC<SelectProps> & {
Option: typeof Select.Option;
};
const MiniSelect: CompoundedComponent = (props) => <Select {...props} showSearch size="small" />;
const MiddleSelect: CompoundedComponent = (props) => <Select {...props} showSearch size="middle" />;
MiniSelect.Option = Select.Option;
MiddleSelect.Option = Select.Option;
export { MiniSelect, MiddleSelect };

View File

@ -56,6 +56,8 @@ describe('Pagination', () => {
}); });
it('should support custom selectComponentClass', () => { it('should support custom selectComponentClass', () => {
const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
const CustomSelect: React.FC<{ className?: string }> & { Option: OptionFC } = ({ const CustomSelect: React.FC<{ className?: string }> & { Option: OptionFC } = ({
className, className,
...props ...props
@ -67,6 +69,11 @@ describe('Pagination', () => {
<Pagination defaultCurrent={1} total={500} selectComponentClass={CustomSelect} />, <Pagination defaultCurrent={1} total={500} selectComponentClass={CustomSelect} />,
); );
expect(container.querySelectorAll('.custom-select').length).toBeTruthy(); expect(container.querySelectorAll('.custom-select').length).toBeTruthy();
expect(errorSpy).toHaveBeenCalledWith(
'Warning: [antd: Pagination] `selectComponentClass` is not official api which will be removed.',
);
errorSpy.mockRestore();
}); });
describe('ConfigProvider', () => { describe('ConfigProvider', () => {
@ -104,4 +111,19 @@ describe('Pagination', () => {
expect(container.querySelector('.ant-pagination-end')).toBeTruthy(); expect(container.querySelector('.ant-pagination-end')).toBeTruthy();
}); });
}); });
it('showSizeChanger support showSearch=false', () => {
const { container } = render(
<Pagination
defaultCurrent={1}
total={500}
showSizeChanger={{
showSearch: false,
}}
/>,
);
// Expect `input` is `readonly`
expect(container.querySelector('.ant-select input')).toHaveAttribute('readonly');
});
}); });

View File

@ -47,7 +47,7 @@ Common props ref[Common props](/docs/react/common-props)
| hideOnSinglePage | Whether to hide pager on single page | boolean | false | | | hideOnSinglePage | Whether to hide pager on single page | boolean | false | |
| itemRender | To customize item's innerHTML | (page, type: 'page' \| 'prev' \| 'next', originalElement) => React.ReactNode | - | | | itemRender | To customize item's innerHTML | (page, type: 'page' \| 'prev' \| 'next', originalElement) => React.ReactNode | - | |
| pageSize | Number of data items per page | number | - | | | pageSize | Number of data items per page | number | - | |
| pageSizeOptions | Specify the sizeChanger options | string\[] \| number\[] | \[`10`, `20`, `50`, `100`] | | | pageSizeOptions | Specify the sizeChanger options | number\[] | \[`10`, `20`, `50`, `100`] | |
| responsive | If `size` is not specified, `Pagination` would resize according to the width of the window | boolean | - | | | responsive | If `size` is not specified, `Pagination` would resize according to the width of the window | boolean | - | |
| showLessItems | Show less page items | boolean | false | | | showLessItems | Show less page items | boolean | false | |
| showQuickJumper | Determine whether you can jump to pages directly | boolean \| { goButton: ReactNode } | false | | | showQuickJumper | Determine whether you can jump to pages directly | boolean \| { goButton: ReactNode } | false | |

View File

@ -48,7 +48,7 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*WM86SrBC8TsAAA
| hideOnSinglePage | 只有一页时是否隐藏分页器 | boolean | false | | | hideOnSinglePage | 只有一页时是否隐藏分页器 | boolean | false | |
| itemRender | 用于自定义页码的结构,可用于优化 SEO | (page, type: 'page' \| 'prev' \| 'next', originalElement) => React.ReactNode | - | | | itemRender | 用于自定义页码的结构,可用于优化 SEO | (page, type: 'page' \| 'prev' \| 'next', originalElement) => React.ReactNode | - | |
| pageSize | 每页条数 | number | - | | | pageSize | 每页条数 | number | - | |
| pageSizeOptions | 指定每页可以显示多少条 | string\[] \| number\[] | \[`10`, `20`, `50`, `100`] | | | pageSizeOptions | 指定每页可以显示多少条 | number\[] | \[`10`, `20`, `50`, `100`] | |
| responsive | 当 size 未指定时,根据屏幕宽度自动调整尺寸 | boolean | - | | | responsive | 当 size 未指定时,根据屏幕宽度自动调整尺寸 | boolean | - | |
| showLessItems | 是否显示较少页面内容 | boolean | false | | | showLessItems | 是否显示较少页面内容 | boolean | false | |
| showQuickJumper | 是否可以快速跳转至某页 | boolean \| { goButton: ReactNode } | false | | | showQuickJumper | 是否可以快速跳转至某页 | boolean \| { goButton: ReactNode } | false | |

View File

@ -0,0 +1,18 @@
import { useMemo } from 'react';
import type { PaginationProps } from '.';
import type { SelectProps } from '../select';
export default function useShowSizeChanger(showSizeChanger?: PaginationProps['showSizeChanger']) {
return useMemo<[show: boolean | undefined, selectProps: SelectProps | undefined]>(() => {
if (typeof showSizeChanger === 'boolean') {
return [showSizeChanger, {}];
}
if (showSizeChanger && typeof showSizeChanger === 'object') {
return [true, showSizeChanger];
}
return [undefined, undefined];
}, [showSizeChanger]);
}

View File

@ -134,7 +134,7 @@
"rc-menu": "~9.16.0", "rc-menu": "~9.16.0",
"rc-motion": "^2.9.3", "rc-motion": "^2.9.3",
"rc-notification": "~5.6.2", "rc-notification": "~5.6.2",
"rc-pagination": "~4.3.0", "rc-pagination": "~5.0.0",
"rc-picker": "~4.8.3", "rc-picker": "~4.8.3",
"rc-progress": "~4.0.0", "rc-progress": "~4.0.0",
"rc-rate": "~2.13.0", "rc-rate": "~2.13.0",