mirror of
https://github.com/ant-design/ant-design.git
synced 2024-11-27 20:49:53 +08:00
feat: add api for transfer (#29288)
* feat: add api for transfer * feat: Transfer new feature * Update components/transfer/__tests__/index.test.js Co-authored-by: afc163 <afc163@gmail.com> * Update components/transfer/demo/advanced.md Co-authored-by: afc163 <afc163@gmail.com> * Update components/transfer/index.en-US.md Co-authored-by: afc163 <afc163@gmail.com> * Update components/transfer/index.tsx Co-authored-by: afc163 <afc163@gmail.com> * fix: change another way * fix: add test * fix: defaultFooterRender test failed * fix: comment in English * fix: delete unnecessary blank line * fix: fix describe error * fix: add version and Type Guard * fix: transfer docs * fix: docs * fix: docs grammar err Co-authored-by: SimpleZhang <simplezhang@yeahka.com> Co-authored-by: afc163 <afc163@gmail.com>
This commit is contained in:
parent
744ddc4fdf
commit
15580483ce
@ -216,7 +216,7 @@ exports[`renders ./components/transfer/demo/advanced.md correctly 1`] = `
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="ant-transfer-list ant-transfer-list-with-footer"
|
||||
class="ant-transfer-list"
|
||||
style="width:250px;height:300px"
|
||||
>
|
||||
<div
|
||||
@ -352,19 +352,6 @@ exports[`renders ./components/transfer/demo/advanced.md correctly 1`] = `
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-transfer-list-footer"
|
||||
>
|
||||
<button
|
||||
class="ant-btn ant-btn-sm"
|
||||
style="float:right;margin:5px"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
reload
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
@ -558,3 +558,31 @@ describe('immutable data', () => {
|
||||
expect(wrapper).toMatchRenderedSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe('footer render source and target', () => {
|
||||
// https://github.com/ant-design/ant-design/issues/28082
|
||||
it('currently render footer', () => {
|
||||
const differentFooter = () => ({
|
||||
source: (
|
||||
<Button size="small" className="sourceFooter">
|
||||
reload
|
||||
</Button>
|
||||
),
|
||||
target: (
|
||||
<Button size="small" className="targetFooter">
|
||||
reload
|
||||
</Button>
|
||||
),
|
||||
});
|
||||
const defaultFooter = () => (
|
||||
<Button size="small" className="defaultFooter">
|
||||
reload
|
||||
</Button>
|
||||
);
|
||||
const wrapper = mount(<Transfer footer={differentFooter} />);
|
||||
const wrapper2 = mount(<Transfer footer={defaultFooter} />);
|
||||
expect(wrapper.exists('.sourceFooter')).toEqual(true);
|
||||
expect(wrapper.exists('.targetFooter')).toEqual(true);
|
||||
expect(wrapper2.exists('.defaultFooter')).toEqual(true);
|
||||
});
|
||||
});
|
||||
|
@ -50,11 +50,13 @@ class App extends React.Component {
|
||||
this.setState({ targetKeys });
|
||||
};
|
||||
|
||||
renderFooter = () => (
|
||||
<Button size="small" style={{ float: 'right', margin: 5 }} onClick={this.getMock}>
|
||||
reload
|
||||
</Button>
|
||||
);
|
||||
renderFooter = () => ({
|
||||
source: (
|
||||
<Button size="small" style={{ float: 'right', margin: 5 }} onClick={this.getMock}>
|
||||
reload
|
||||
</Button>
|
||||
),
|
||||
});
|
||||
|
||||
render() {
|
||||
return (
|
||||
|
@ -24,7 +24,7 @@ One or more elements can be selected from either column, one click on the proper
|
||||
| dataSource | Used for setting the source data. The elements that are part of this array will be present the left column. Except the elements whose keys are included in `targetKeys` prop | [RecordType extends TransferItem = TransferItem](https://git.io/vMM64)\[] | \[] | |
|
||||
| disabled | Whether disabled transfer | boolean | false | |
|
||||
| filterOption | A function to determine whether an item should show in search result list | (inputValue, option): boolean | - | |
|
||||
| footer | A function used for rendering the footer | (props) => ReactNode | - | |
|
||||
| footer | A function used for rendering the footer | (props) => ReactNode \| { source: ReactNode, target: ReactNode } | - | { source: ReactNode, target: ReactNode }: 4.12.3 |
|
||||
| listStyle | A custom CSS style used for rendering the transfer columns | object \| ({direction: `left` \| `right`}) => object | - | |
|
||||
| locale | The i18n text including filter, empty text, item unit, etc | { itemUnit: string; itemsUnit: string; searchPlaceholder: string; notFoundContent: ReactNode; } | { itemUnit: `item`, itemsUnit: `items`, notFoundContent: `The list is empty`, searchPlaceholder: `Search here` } | |
|
||||
| oneWay | Display as single direction style | boolean | false | 4.3.0 |
|
||||
|
@ -58,7 +58,6 @@ export interface TransferLocale {
|
||||
removeAll: string;
|
||||
removeCurrent: string;
|
||||
}
|
||||
|
||||
export interface TransferProps<RecordType> {
|
||||
prefixCls?: string;
|
||||
className?: string;
|
||||
@ -77,7 +76,14 @@ export interface TransferProps<RecordType> {
|
||||
showSearch?: boolean;
|
||||
filterOption?: (inputValue: string, item: RecordType) => boolean;
|
||||
locale?: Partial<TransferLocale>;
|
||||
footer?: (props: TransferListProps<RecordType>) => React.ReactNode;
|
||||
footer?: (
|
||||
props: TransferListProps<RecordType>,
|
||||
) =>
|
||||
| React.ReactNode
|
||||
| {
|
||||
source?: React.ReactNode;
|
||||
target?: React.ReactNode;
|
||||
};
|
||||
rowKey?: (record: RecordType) => string;
|
||||
onSearch?: (direction: TransferDirection, value: string) => void;
|
||||
onScroll?: (direction: TransferDirection, e: React.SyntheticEvent<HTMLUListElement>) => void;
|
||||
|
@ -27,7 +27,7 @@ cover: https://gw.alipayobjects.com/zos/alicdn/QAXskNI4G/Transfer.svg
|
||||
| dataSource | 数据源,其中的数据将会被渲染到左边一栏中,`targetKeys` 中指定的除外 | [RecordType extends TransferItem = TransferItem](https://git.io/vMM64)\[] | \[] | |
|
||||
| disabled | 是否禁用 | boolean | false | |
|
||||
| filterOption | 接收 `inputValue` `option` 两个参数,当 `option` 符合筛选条件时,应返回 true,反之则返回 false | (inputValue, option): boolean | - | |
|
||||
| footer | 底部渲染函数 | (props) => ReactNode | - | |
|
||||
| footer | 底部渲染函数 | (props) => ReactNode \| { source: ReactNode, target: ReactNode } | - | { source: ReactNode, target: ReactNode }: 4.12.3 |
|
||||
| listStyle | 两个穿梭框的自定义样式 | object\|({direction: `left` \| `right`}) => object | - | |
|
||||
| locale | 各种语言 | { itemUnit: string; itemsUnit: string; searchPlaceholder: string; notFoundContent: ReactNode; } | { itemUnit: `项`, itemsUnit: `项`, searchPlaceholder: `请输入搜索内容` } | |
|
||||
| oneWay | 展示为单向样式 | boolean | false | 4.3.0 |
|
||||
|
@ -39,7 +39,10 @@ export interface RenderedItem<RecordType> {
|
||||
}
|
||||
|
||||
type RenderListFunction<T> = (props: TransferListBodyProps<T>) => React.ReactNode;
|
||||
|
||||
type FooterRender = {
|
||||
source?: React.ReactNode;
|
||||
target?: React.ReactNode;
|
||||
};
|
||||
export interface TransferListProps<RecordType> extends TransferLocale {
|
||||
prefixCls: string;
|
||||
titleText: React.ReactNode;
|
||||
@ -59,7 +62,7 @@ export interface TransferListProps<RecordType> extends TransferLocale {
|
||||
itemUnit: string;
|
||||
itemsUnit: string;
|
||||
renderList?: RenderListFunction<RecordType>;
|
||||
footer?: (props: TransferListProps<RecordType>) => React.ReactNode;
|
||||
footer?: (props: TransferListProps<RecordType>) => React.ReactNode | FooterRender;
|
||||
onScroll: (e: React.UIEvent<HTMLUListElement>) => void;
|
||||
disabled?: boolean;
|
||||
direction: TransferDirection;
|
||||
@ -312,10 +315,27 @@ export default class TransferList<
|
||||
showSelectAll,
|
||||
showRemove,
|
||||
pagination,
|
||||
direction,
|
||||
} = this.props;
|
||||
|
||||
// Custom Layout
|
||||
const footerDom = footer && footer(this.props);
|
||||
// Distinguish different footer
|
||||
const tempDom = footer && footer(this.props);
|
||||
let footerDom;
|
||||
function isFooterRender(obj: any): obj is FooterRender {
|
||||
return obj.source || obj.target;
|
||||
}
|
||||
if (tempDom) {
|
||||
if (isFooterRender(tempDom)) {
|
||||
if (direction === 'left') {
|
||||
footerDom = tempDom.source;
|
||||
} else {
|
||||
footerDom = tempDom.target;
|
||||
}
|
||||
} else {
|
||||
footerDom = tempDom;
|
||||
}
|
||||
}
|
||||
|
||||
const listCls = classNames(prefixCls, {
|
||||
[`${prefixCls}-with-pagination`]: pagination,
|
||||
|
Loading…
Reference in New Issue
Block a user