Skip to content

Commit 68d295d

Browse files
authored
refactor:transfer (#6247)
* refactor:transfer * merge v4 branch & fix theme interface conflict * docs:update & refactor: transfer type
1 parent bbfb3ce commit 68d295d

15 files changed

+558
-445
lines changed

components/style.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ import './table/style';
4141
// import './progress/style';
4242
import './timeline/style';
4343
import './input-number/style';
44-
import './transfer/style';
44+
// import './transfer/style';
4545
import './tree/style';
4646
import './upload/style';
4747
// import './layout/style';

components/theme/interface/components.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ import type { ComponentToken as SpinComponentToken } from '../../spin/style';
4242
import type { ComponentToken as TagComponentToken } from '../../tag/style';
4343
// import type { ComponentToken as TimelineComponentToken } from '../../timeline/style';
4444
import type { ComponentToken as TooltipComponentToken } from '../../tooltip/style';
45-
// import type { ComponentToken as TransferComponentToken } from '../../transfer/style';
45+
import type { ComponentToken as TransferComponentToken } from '../../transfer/style';
4646
import type { ComponentToken as TypographyComponentToken } from '../../typography/style';
4747
// import type { ComponentToken as UploadComponentToken } from '../../upload/style';
4848
// import type { ComponentToken as TourComponentToken } from '../../tour/style';
@@ -100,7 +100,7 @@ export interface ComponentTokenMap {
100100
TreeSelect?: {};
101101
Typography?: TypographyComponentToken;
102102
// Timeline?: TimelineComponentToken;
103-
// Transfer?: TransferComponentToken;
103+
Transfer?: TransferComponentToken;
104104
// Tabs?: TabsComponentToken;
105105
// Calendar?: CalendarComponentToken;
106106
// Steps?: StepsComponentToken;

components/transfer/ListBody.tsx

+3-2
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,14 @@ import ListItem from './ListItem';
55
import Pagination from '../pagination';
66
import PropTypes from '../_util/vue-types';
77
import type { TransferItem } from '.';
8+
import { booleanType } from '../_util/type';
89

910
export const transferListBodyProps = {
1011
prefixCls: String,
1112
filteredRenderItems: PropTypes.array.def([]),
1213
selectedKeys: PropTypes.array,
13-
disabled: { type: Boolean, default: undefined },
14-
showRemove: { type: Boolean, default: undefined },
14+
disabled: booleanType(),
15+
showRemove: booleanType(),
1516
pagination: PropTypes.any,
1617
onItemSelect: Function,
1718
onScroll: Function,

components/transfer/ListItem.tsx

+4-3
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,18 @@ import TransButton from '../_util/transButton';
88
import LocaleReceiver from '../locale-provider/LocaleReceiver';
99
import type { ExtractPropTypes } from 'vue';
1010
import { defineComponent } from 'vue';
11+
import { booleanType } from '../_util/type';
1112

1213
function noop() {}
1314

1415
export const transferListItemProps = {
1516
renderedText: PropTypes.any,
1617
renderedEl: PropTypes.any,
1718
item: PropTypes.any,
18-
checked: { type: Boolean, default: undefined },
19+
checked: booleanType(),
1920
prefixCls: String,
20-
disabled: { type: Boolean, default: undefined },
21-
showRemove: { type: Boolean, default: undefined },
21+
disabled: booleanType(),
22+
showRemove: booleanType(),
2223
onClick: Function,
2324
onRemove: Function,
2425
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
<docs>
2+
---
3+
order: 4
4+
title:
5+
zh-CN: 自定义全选文字
6+
en-US: Custom Select All Labels
7+
---
8+
9+
10+
## zh-CN
11+
12+
自定义穿梭框全选按钮的文字。
13+
14+
## en-US
15+
16+
Custom the labels for select all checkboxs.
17+
18+
</docs>
19+
20+
<template>
21+
<div>
22+
<a-transfer
23+
v-model:target-keys="targetKeys"
24+
v-model:selected-keys="selectedKeys"
25+
:data-source="mockData"
26+
:titles="['Source', 'Target']"
27+
:render="item => item.title"
28+
:select-all-labels="selectAllLabels"
29+
:disabled="disabled"
30+
@change="handleChange"
31+
@selectChange="handleSelectChange"
32+
@scroll="handleScroll"
33+
/>
34+
<a-switch
35+
v-model:checked="disabled"
36+
un-checked-children="enabled"
37+
checked-children="disabled"
38+
style="margin-top: 16px"
39+
/>
40+
</div>
41+
</template>
42+
<script lang="ts">
43+
import { defineComponent, ref } from 'vue';
44+
import type { SelectAllLabel } from 'ant-design-vue/es/transfer';
45+
46+
interface MockData {
47+
key: string;
48+
title: string;
49+
description: string;
50+
disabled: boolean;
51+
}
52+
const mockData: MockData[] = [];
53+
for (let i = 0; i < 20; i++) {
54+
mockData.push({
55+
key: i.toString(),
56+
title: `content${i + 1}`,
57+
description: `description of content${i + 1}`,
58+
disabled: i % 3 < 1,
59+
});
60+
}
61+
62+
const oriTargetKeys = mockData.filter(item => +item.key % 3 > 1).map(item => item.key);
63+
export default defineComponent({
64+
data() {
65+
const disabled = ref<boolean>(false);
66+
67+
const targetKeys = ref<string[]>(oriTargetKeys);
68+
69+
const selectedKeys = ref<string[]>(['1', '4']);
70+
71+
const handleChange = (nextTargetKeys: string[], direction: string, moveKeys: string[]) => {
72+
console.log('targetKeys: ', nextTargetKeys);
73+
console.log('direction: ', direction);
74+
console.log('moveKeys: ', moveKeys);
75+
};
76+
const handleSelectChange = (sourceSelectedKeys: string[], targetSelectedKeys: string[]) => {
77+
console.log('sourceSelectedKeys: ', sourceSelectedKeys);
78+
console.log('targetSelectedKeys: ', targetSelectedKeys);
79+
};
80+
const handleScroll = (direction: string, e: Event) => {
81+
console.log('direction:', direction);
82+
console.log('target:', e.target);
83+
};
84+
85+
const selectAllLabels: SelectAllLabel[] = [
86+
'Select All',
87+
({ selectedCount, totalCount }) => `${selectedCount}/${totalCount}`,
88+
];
89+
90+
return {
91+
mockData,
92+
targetKeys,
93+
selectedKeys,
94+
disabled,
95+
selectAllLabels,
96+
handleChange,
97+
handleSelectChange,
98+
handleScroll,
99+
};
100+
},
101+
});
102+
</script>

components/transfer/demo/index.vue

+3
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
<table-transfer />
1010
<tree-transfer />
1111
<statusVue />
12+
<custom-select-all-labels></custom-select-all-labels>
1213
</demo-sort>
1314
</template>
1415
<script lang="ts">
@@ -17,6 +18,7 @@ import Oneway from './oneway.vue';
1718
import Search from './search.vue';
1819
import Advanced from './advanced.vue';
1920
import CustomItem from './custom-item.vue';
21+
import CustomSelectAllLabels from './custom-select-all-labels.vue';
2022
import TableTransfer from './table-transfer.vue';
2123
import TreeTransfer from './tree-transfer.vue';
2224
import Pagination from './pagination.vue';
@@ -35,6 +37,7 @@ export default defineComponent({
3537
Search,
3638
Advanced,
3739
CustomItem,
40+
CustomSelectAllLabels,
3841
Pagination,
3942
TableTransfer,
4043
TreeTransfer,

components/transfer/index.en-US.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
category: Components
33
type: Data Entry
44
title: Transfer
5-
cover: https://gw.alipayobjects.com/zos/alicdn/QAXskNI4G/Transfer.svg
5+
cover: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*EAApQ5ephigAAAAAAAAAAAAADrJ8AQ/original
66
---
77

88
Alert component for feedback.
@@ -31,6 +31,7 @@ One or more elements can be selected from either column, one click on the proper
3131
| operationStyle | A custom CSS style used for rendering the operations column | CSSProperties | - | 3.0.0 |
3232
| pagination | Use pagination. Not work in render props | boolean \| { pageSize: number, simple: boolean, showSizeChanger?: boolean, showLessItems?: boolean } | false | 3.0.0 |
3333
| render | The function to generate the item shown on a column. Based on an record (element of the dataSource array), this function should return a element which is generated from that record. Also, it can return a plain object with `value` and `label`, `label` is a element and `value` is for title | Function(record) \| slot | | |
34+
| selectAllLabels | A set of customized labels for select all checkboxes on the header | VueNode \| ((info: { selectedCount: number; totalCount: number }) => VueNode); | - | 3.0.0 |
3435
| selectedKeys(v-model) | A set of keys of selected items. | string\[] | \[] | |
3536
| showSearch | If included, a search box is shown on each column. | boolean | false | |
3637
| showSelectAll | Show select all checkbox on the header | boolean | true | |

components/transfer/index.tsx

+58-40
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { CSSProperties, ExtractPropTypes, PropType } from 'vue';
1+
import type { CSSProperties, ExtractPropTypes } from 'vue';
22
import { computed, watchEffect, defineComponent, ref, watch, toRaw } from 'vue';
33
import PropTypes from '../_util/vue-types';
44
import { getPropsSlot } from '../_util/props-util';
@@ -8,7 +8,15 @@ import Operation from './operation';
88
import LocaleReceiver from '../locale-provider/LocaleReceiver';
99
import defaultLocale from '../locale/en_US';
1010
import type { VueNode } from '../_util/type';
11-
import { withInstall } from '../_util/type';
11+
import {
12+
withInstall,
13+
stringType,
14+
arrayType,
15+
someType,
16+
booleanType,
17+
objectType,
18+
functionType,
19+
} from '../_util/type';
1220
import useConfigInject from '../config-provider/hooks/useConfigInject';
1321
import type { TransferListBodyProps } from './ListBody';
1422
import type { PaginationType } from './interface';
@@ -17,6 +25,9 @@ import type { RenderEmptyHandler } from '../config-provider/renderEmpty';
1725
import type { InputStatus } from '../_util/statusUtils';
1826
import { getStatusClassNames, getMergedStatus } from '../_util/statusUtils';
1927

28+
// CSSINJS
29+
import useStyle from './style';
30+
2031
export type { TransferListProps } from './list';
2132
export type { TransferOperationProps } from './operation';
2233
export type { TransferSearchProps } from './search';
@@ -69,40 +80,41 @@ export interface TransferLocale {
6980
export const transferProps = () => ({
7081
id: String,
7182
prefixCls: String,
72-
dataSource: { type: Array as PropType<TransferItem[]>, default: [] },
73-
disabled: { type: Boolean, default: undefined },
74-
targetKeys: { type: Array as PropType<string[]>, default: undefined },
75-
selectedKeys: { type: Array as PropType<string[]>, default: undefined },
76-
render: { type: Function as PropType<TransferRender<TransferItem>> },
77-
listStyle: {
78-
type: [Function, Object] as PropType<((style: ListStyle) => CSSProperties) | CSSProperties>,
79-
default: () => ({}),
80-
},
81-
operationStyle: { type: Object as PropType<CSSProperties>, default: undefined as CSSProperties },
82-
titles: { type: Array as PropType<string[]> },
83-
operations: { type: Array as PropType<string[]> },
84-
showSearch: { type: Boolean, default: false },
85-
filterOption: { type: Function as PropType<(inputValue: string, item: TransferItem) => boolean> },
83+
dataSource: arrayType<TransferItem[]>([]),
84+
disabled: booleanType(),
85+
targetKeys: arrayType<string[]>(),
86+
selectedKeys: arrayType<string[]>(),
87+
render: functionType<TransferRender<TransferItem>>(),
88+
listStyle: someType<((style: ListStyle) => CSSProperties) | CSSProperties>(
89+
[Function, Object],
90+
() => ({}),
91+
),
92+
operationStyle: objectType<CSSProperties>(undefined as CSSProperties),
93+
titles: arrayType<string[]>(),
94+
operations: arrayType<string[]>(),
95+
showSearch: booleanType(false),
96+
filterOption: functionType<(inputValue: string, item: TransferItem) => boolean>(),
8697
searchPlaceholder: String,
8798
notFoundContent: PropTypes.any,
88-
locale: { type: Object as PropType<Partial<TransferLocale>>, default: () => ({}) },
89-
rowKey: { type: Function as PropType<(record: TransferItem) => string> },
90-
showSelectAll: { type: Boolean, default: undefined },
91-
selectAllLabels: { type: Array as PropType<SelectAllLabel[]> },
92-
children: { type: Function as PropType<(props: TransferListBodyProps) => VueNode> },
93-
oneWay: { type: Boolean, default: undefined },
94-
pagination: { type: [Object, Boolean] as PropType<PaginationType>, default: undefined },
95-
status: String as PropType<InputStatus>,
96-
onChange: Function as PropType<
97-
(targetKeys: string[], direction: TransferDirection, moveKeys: string[]) => void
98-
>,
99-
onSelectChange: Function as PropType<
99+
locale: objectType(),
100+
rowKey: functionType<(record: TransferItem) => string>(),
101+
showSelectAll: booleanType(),
102+
selectAllLabels: arrayType<SelectAllLabel[]>(),
103+
children: functionType<(props: TransferListBodyProps) => VueNode>(),
104+
oneWay: booleanType(),
105+
pagination: someType<PaginationType>([Object, Boolean]),
106+
status: stringType<InputStatus>(),
107+
onChange:
108+
functionType<
109+
(targetKeys: string[], direction: TransferDirection, moveKeys: string[]) => void
110+
>(),
111+
onSelectChange: functionType<
100112
(sourceSelectedKeys: string[], targetSelectedKeys: string[]) => void
101113
>,
102-
onSearch: Function as PropType<(direction: TransferDirection, value: string) => void>,
103-
onScroll: Function as PropType<(direction: TransferDirection, e: UIEvent) => void>,
104-
'onUpdate:targetKeys': Function as PropType<(keys: string[]) => void>,
105-
'onUpdate:selectedKeys': Function as PropType<(keys: string[]) => void>,
114+
onSearch: functionType<(direction: TransferDirection, value: string) => void>(),
115+
onScroll: functionType<(direction: TransferDirection, e: UIEvent) => void>(),
116+
'onUpdate:targetKeys': functionType<(keys: string[]) => void>(),
117+
'onUpdate:selectedKeys': functionType<(keys: string[]) => void>(),
106118
});
107119

108120
export type TransferProps = Partial<ExtractPropTypes<ReturnType<typeof transferProps>>>;
@@ -125,6 +137,10 @@ const Transfer = defineComponent({
125137
// emits: ['update:targetKeys', 'update:selectedKeys', 'change', 'search', 'scroll', 'selectChange'],
126138
setup(props, { emit, attrs, slots, expose }) {
127139
const { configProvider, prefixCls, direction } = useConfigInject('transfer', props);
140+
141+
// style
142+
const [wrapSSR, hashId] = useStyle(prefixCls);
143+
128144
const sourceSelectedKeys = ref([]);
129145
const targetSelectedKeys = ref([]);
130146

@@ -349,14 +365,15 @@ const Transfer = defineComponent({
349365
[`${prefixCls.value}-rtl`]: direction.value === 'rtl',
350366
},
351367
getStatusClassNames(prefixCls.value, mergedStatus.value, formItemInputContext.hasFeedback),
368+
hashId.value,
352369
);
353370
const titles = props.titles;
354371
const leftTitle =
355372
(titles && titles[0]) ?? slots.leftTitle?.() ?? (locale.titles || ['', ''])[0];
356373
const rightTitle =
357374
(titles && titles[1]) ?? slots.rightTitle?.() ?? (locale.titles || ['', ''])[1];
358375
return (
359-
<div class={cls} style={style as CSSProperties} id={id}>
376+
<div {...attrs} class={cls} style={style as CSSProperties} id={id}>
360377
<List
361378
key="leftList"
362379
prefixCls={`${prefixCls.value}-list`}
@@ -422,13 +439,14 @@ const Transfer = defineComponent({
422439
</div>
423440
);
424441
};
425-
return () => (
426-
<LocaleReceiver
427-
componentName="Transfer"
428-
defaultLocale={defaultLocale.Transfer}
429-
children={renderTransfer}
430-
/>
431-
);
442+
return () =>
443+
wrapSSR(
444+
<LocaleReceiver
445+
componentName="Transfer"
446+
defaultLocale={defaultLocale.Transfer}
447+
children={renderTransfer}
448+
/>,
449+
);
432450
},
433451
});
434452

components/transfer/index.zh-CN.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ category: Components
33
type: 数据录入
44
title: Transfer
55
subtitle: 穿梭框
6-
cover: https://gw.alipayobjects.com/zos/alicdn/QAXskNI4G/Transfer.svg
6+
cover: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*EAApQ5ephigAAAAAAAAAAAAADrJ8AQ/original
77
---
88

99
双栏穿梭选择框。
@@ -32,6 +32,7 @@ cover: https://gw.alipayobjects.com/zos/alicdn/QAXskNI4G/Transfer.svg
3232
| operationStyle | 操作栏的自定义样式 | CSSProperties | - | 3.0.0 |
3333
| pagination | 使用分页样式,自定义渲染列表下无效 | boolean \| { pageSize: number, simple: boolean, showSizeChanger?: boolean, showLessItems?: boolean } | flase | 3.0.0 |
3434
| render | 每行数据渲染函数,该函数的入参为 `dataSource` 中的项,返回值为 element。或者返回一个普通对象,其中 `label` 字段为 element,`value` 字段为 title | Function(record)\| slot | | |
35+
| selectAllLabels | 自定义顶部多选框标题的集合 | VueNode \| ((info: { selectedCount: number; totalCount: number }) => VueNode); | - | 3.0.0 |
3536
| selectedKeys(v-model) | 设置哪些项应该被选中 | string\[] | \[] | |
3637
| showSearch | 是否显示搜索框 | boolean | false | |
3738
| showSelectAll | 是否展示全选勾选框 | boolean | true | |

0 commit comments

Comments
 (0)