mirror of
https://github.com/ant-design/ant-design.git
synced 2024-12-30 04:18:28 +08:00
c8635a7bc0
* feat: add Transfer's key type * docs: update prop * fix: key type * fix: cycle dependency
153 lines
4.5 KiB
TypeScript
153 lines
4.5 KiB
TypeScript
import * as React from 'react';
|
|
import classNames from 'classnames';
|
|
import useMergedState from 'rc-util/lib/hooks/useMergedState';
|
|
|
|
import type { KeyWiseTransferItem } from '.';
|
|
import Pagination from '../pagination';
|
|
import type { PaginationType, TransferKey } from './interface';
|
|
import type { RenderedItem, TransferListProps } from './list';
|
|
import ListItem from './ListItem';
|
|
|
|
export const OmitProps = ['handleFilter', 'handleClear', 'checkedKeys'] as const;
|
|
export type OmitProp = (typeof OmitProps)[number];
|
|
type PartialTransferListProps<RecordType> = Omit<TransferListProps<RecordType>, OmitProp>;
|
|
type ExistPagination = Exclude<PaginationType, boolean>;
|
|
|
|
export interface TransferListBodyProps<RecordType> extends PartialTransferListProps<RecordType> {
|
|
filteredItems: RecordType[];
|
|
filteredRenderItems: RenderedItem<RecordType>[];
|
|
selectedKeys: TransferKey[];
|
|
}
|
|
|
|
const parsePagination = (pagination?: ExistPagination) => {
|
|
const defaultPagination: PaginationType = {
|
|
simple: true,
|
|
showSizeChanger: false,
|
|
showLessItems: false,
|
|
};
|
|
|
|
return { ...defaultPagination, ...pagination };
|
|
};
|
|
export interface ListBodyRef<RecordType extends KeyWiseTransferItem> {
|
|
items?: RenderedItem<RecordType>[];
|
|
}
|
|
|
|
const TransferListBody: React.ForwardRefRenderFunction<
|
|
ListBodyRef<KeyWiseTransferItem>,
|
|
TransferListBodyProps<KeyWiseTransferItem>
|
|
> = <RecordType extends KeyWiseTransferItem>(
|
|
props: TransferListBodyProps<RecordType>,
|
|
ref: React.ForwardedRef<ListBodyRef<RecordType>>,
|
|
) => {
|
|
const {
|
|
prefixCls,
|
|
filteredRenderItems,
|
|
selectedKeys,
|
|
disabled: globalDisabled,
|
|
showRemove,
|
|
pagination,
|
|
onScroll,
|
|
onItemSelect,
|
|
onItemRemove,
|
|
} = props;
|
|
const [current, setCurrent] = React.useState<number>(1);
|
|
|
|
const mergedPagination = React.useMemo(() => {
|
|
if (!pagination) {
|
|
return null;
|
|
}
|
|
|
|
const convertPagination = typeof pagination === 'object' ? pagination : {};
|
|
|
|
return parsePagination(convertPagination);
|
|
}, [pagination]);
|
|
|
|
const [pageSize, setPageSize] = useMergedState<number>(10, {
|
|
value: mergedPagination?.pageSize,
|
|
});
|
|
|
|
React.useEffect(() => {
|
|
if (mergedPagination) {
|
|
const maxPageCount = Math.ceil(filteredRenderItems.length / pageSize!);
|
|
setCurrent(Math.min(current, maxPageCount));
|
|
}
|
|
}, [filteredRenderItems, mergedPagination, pageSize]);
|
|
|
|
const onInternalClick = (item: RecordType, e: React.MouseEvent<Element, MouseEvent>) => {
|
|
onItemSelect(item.key, !selectedKeys.includes(item.key), e);
|
|
};
|
|
|
|
const onRemove = (item: RecordType) => {
|
|
onItemRemove?.([item.key]);
|
|
};
|
|
|
|
const onPageChange = (cur: number) => {
|
|
setCurrent(cur);
|
|
};
|
|
|
|
const onSizeChange = (cur: number, size: number) => {
|
|
setCurrent(cur);
|
|
setPageSize(size);
|
|
};
|
|
|
|
const memoizedItems = React.useMemo<RenderedItem<RecordType>[]>(() => {
|
|
const displayItems = mergedPagination
|
|
? filteredRenderItems.slice((current - 1) * pageSize!, current * pageSize!)
|
|
: filteredRenderItems;
|
|
return displayItems;
|
|
}, [current, filteredRenderItems, mergedPagination, pageSize]);
|
|
|
|
React.useImperativeHandle(ref, () => ({ items: memoizedItems }));
|
|
|
|
const paginationNode: React.ReactNode = mergedPagination ? (
|
|
<Pagination
|
|
size="small"
|
|
disabled={globalDisabled}
|
|
simple={mergedPagination.simple}
|
|
pageSize={pageSize}
|
|
showLessItems={mergedPagination.showLessItems}
|
|
showSizeChanger={mergedPagination.showSizeChanger}
|
|
className={`${prefixCls}-pagination`}
|
|
total={filteredRenderItems.length}
|
|
current={current}
|
|
onChange={onPageChange}
|
|
onShowSizeChange={onSizeChange}
|
|
/>
|
|
) : null;
|
|
|
|
const cls = classNames(`${prefixCls}-content`, {
|
|
[`${prefixCls}-content-show-remove`]: showRemove,
|
|
});
|
|
|
|
return (
|
|
<>
|
|
<ul className={cls} onScroll={onScroll}>
|
|
{(memoizedItems || []).map(({ renderedEl, renderedText, item }) => (
|
|
<ListItem
|
|
key={item.key}
|
|
item={item}
|
|
renderedText={renderedText}
|
|
renderedEl={renderedEl}
|
|
prefixCls={prefixCls}
|
|
showRemove={showRemove}
|
|
onClick={onInternalClick}
|
|
onRemove={onRemove}
|
|
checked={selectedKeys.includes(item.key)}
|
|
disabled={globalDisabled || item.disabled}
|
|
/>
|
|
))}
|
|
</ul>
|
|
{paginationNode}
|
|
</>
|
|
);
|
|
};
|
|
|
|
if (process.env.NODE_ENV !== 'production') {
|
|
TransferListBody.displayName = 'TransferListBody';
|
|
}
|
|
|
|
export default React.forwardRef<
|
|
ListBodyRef<KeyWiseTransferItem>,
|
|
TransferListBodyProps<KeyWiseTransferItem>
|
|
>(TransferListBody);
|