Skip to content

refactor:transfer #6247

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Feb 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion components/style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ import './table/style';
// import './progress/style';
import './timeline/style';
import './input-number/style';
import './transfer/style';
// import './transfer/style';
import './tree/style';
import './upload/style';
// import './layout/style';
Expand Down
4 changes: 2 additions & 2 deletions components/theme/interface/components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ import type { ComponentToken as SpinComponentToken } from '../../spin/style';
import type { ComponentToken as TagComponentToken } from '../../tag/style';
// import type { ComponentToken as TimelineComponentToken } from '../../timeline/style';
import type { ComponentToken as TooltipComponentToken } from '../../tooltip/style';
// import type { ComponentToken as TransferComponentToken } from '../../transfer/style';
import type { ComponentToken as TransferComponentToken } from '../../transfer/style';
import type { ComponentToken as TypographyComponentToken } from '../../typography/style';
// import type { ComponentToken as UploadComponentToken } from '../../upload/style';
// import type { ComponentToken as TourComponentToken } from '../../tour/style';
Expand Down Expand Up @@ -100,7 +100,7 @@ export interface ComponentTokenMap {
TreeSelect?: {};
Typography?: TypographyComponentToken;
// Timeline?: TimelineComponentToken;
// Transfer?: TransferComponentToken;
Transfer?: TransferComponentToken;
// Tabs?: TabsComponentToken;
// Calendar?: CalendarComponentToken;
// Steps?: StepsComponentToken;
Expand Down
5 changes: 3 additions & 2 deletions components/transfer/ListBody.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@ import ListItem from './ListItem';
import Pagination from '../pagination';
import PropTypes from '../_util/vue-types';
import type { TransferItem } from '.';
import { booleanType } from '../_util/type';

export const transferListBodyProps = {
prefixCls: String,
filteredRenderItems: PropTypes.array.def([]),
selectedKeys: PropTypes.array,
disabled: { type: Boolean, default: undefined },
showRemove: { type: Boolean, default: undefined },
disabled: booleanType(),
showRemove: booleanType(),
pagination: PropTypes.any,
onItemSelect: Function,
onScroll: Function,
Expand Down
7 changes: 4 additions & 3 deletions components/transfer/ListItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,18 @@ import TransButton from '../_util/transButton';
import LocaleReceiver from '../locale-provider/LocaleReceiver';
import type { ExtractPropTypes } from 'vue';
import { defineComponent } from 'vue';
import { booleanType } from '../_util/type';

function noop() {}

export const transferListItemProps = {
renderedText: PropTypes.any,
renderedEl: PropTypes.any,
item: PropTypes.any,
checked: { type: Boolean, default: undefined },
checked: booleanType(),
prefixCls: String,
disabled: { type: Boolean, default: undefined },
showRemove: { type: Boolean, default: undefined },
disabled: booleanType(),
showRemove: booleanType(),
onClick: Function,
onRemove: Function,
};
Expand Down
102 changes: 102 additions & 0 deletions components/transfer/demo/custom-select-all-labels.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
<docs>
---
order: 4
title:
zh-CN: 自定义全选文字
en-US: Custom Select All Labels
---


## zh-CN

自定义穿梭框全选按钮的文字。

## en-US

Custom the labels for select all checkboxs.

</docs>

<template>
<div>
<a-transfer
v-model:target-keys="targetKeys"
v-model:selected-keys="selectedKeys"
:data-source="mockData"
:titles="['Source', 'Target']"
:render="item => item.title"
:select-all-labels="selectAllLabels"
:disabled="disabled"
@change="handleChange"
@selectChange="handleSelectChange"
@scroll="handleScroll"
/>
<a-switch
v-model:checked="disabled"
un-checked-children="enabled"
checked-children="disabled"
style="margin-top: 16px"
/>
</div>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
import type { SelectAllLabel } from 'ant-design-vue/es/transfer';

interface MockData {
key: string;
title: string;
description: string;
disabled: boolean;
}
const mockData: MockData[] = [];
for (let i = 0; i < 20; i++) {
mockData.push({
key: i.toString(),
title: `content${i + 1}`,
description: `description of content${i + 1}`,
disabled: i % 3 < 1,
});
}

const oriTargetKeys = mockData.filter(item => +item.key % 3 > 1).map(item => item.key);
export default defineComponent({
data() {
const disabled = ref<boolean>(false);

const targetKeys = ref<string[]>(oriTargetKeys);

const selectedKeys = ref<string[]>(['1', '4']);

const handleChange = (nextTargetKeys: string[], direction: string, moveKeys: string[]) => {
console.log('targetKeys: ', nextTargetKeys);
console.log('direction: ', direction);
console.log('moveKeys: ', moveKeys);
};
const handleSelectChange = (sourceSelectedKeys: string[], targetSelectedKeys: string[]) => {
console.log('sourceSelectedKeys: ', sourceSelectedKeys);
console.log('targetSelectedKeys: ', targetSelectedKeys);
};
const handleScroll = (direction: string, e: Event) => {
console.log('direction:', direction);
console.log('target:', e.target);
};

const selectAllLabels: SelectAllLabel[] = [
'Select All',
({ selectedCount, totalCount }) => `${selectedCount}/${totalCount}`,
];

return {
mockData,
targetKeys,
selectedKeys,
disabled,
selectAllLabels,
handleChange,
handleSelectChange,
handleScroll,
};
},
});
</script>
3 changes: 3 additions & 0 deletions components/transfer/demo/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
<table-transfer />
<tree-transfer />
<statusVue />
<custom-select-all-labels></custom-select-all-labels>
</demo-sort>
</template>
<script lang="ts">
Expand All @@ -17,6 +18,7 @@ import Oneway from './oneway.vue';
import Search from './search.vue';
import Advanced from './advanced.vue';
import CustomItem from './custom-item.vue';
import CustomSelectAllLabels from './custom-select-all-labels.vue';
import TableTransfer from './table-transfer.vue';
import TreeTransfer from './tree-transfer.vue';
import Pagination from './pagination.vue';
Expand All @@ -35,6 +37,7 @@ export default defineComponent({
Search,
Advanced,
CustomItem,
CustomSelectAllLabels,
Pagination,
TableTransfer,
TreeTransfer,
Expand Down
3 changes: 2 additions & 1 deletion components/transfer/index.en-US.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
category: Components
type: Data Entry
title: Transfer
cover: https://gw.alipayobjects.com/zos/alicdn/QAXskNI4G/Transfer.svg
cover: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*EAApQ5ephigAAAAAAAAAAAAADrJ8AQ/original
---

Alert component for feedback.
Expand Down Expand Up @@ -31,6 +31,7 @@ One or more elements can be selected from either column, one click on the proper
| operationStyle | A custom CSS style used for rendering the operations column | CSSProperties | - | 3.0.0 |
| pagination | Use pagination. Not work in render props | boolean \| { pageSize: number, simple: boolean, showSizeChanger?: boolean, showLessItems?: boolean } | false | 3.0.0 |
| 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 | | |
| selectAllLabels | A set of customized labels for select all checkboxes on the header | VueNode \| ((info: { selectedCount: number; totalCount: number }) => VueNode); | - | 3.0.0 |
| selectedKeys(v-model) | A set of keys of selected items. | string\[] | \[] | |
| showSearch | If included, a search box is shown on each column. | boolean | false | |
| showSelectAll | Show select all checkbox on the header | boolean | true | |
Expand Down
98 changes: 58 additions & 40 deletions components/transfer/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { CSSProperties, ExtractPropTypes, PropType } from 'vue';
import type { CSSProperties, ExtractPropTypes } from 'vue';
import { computed, watchEffect, defineComponent, ref, watch, toRaw } from 'vue';
import PropTypes from '../_util/vue-types';
import { getPropsSlot } from '../_util/props-util';
Expand All @@ -8,7 +8,15 @@ import Operation from './operation';
import LocaleReceiver from '../locale-provider/LocaleReceiver';
import defaultLocale from '../locale/en_US';
import type { VueNode } from '../_util/type';
import { withInstall } from '../_util/type';
import {
withInstall,
stringType,
arrayType,
someType,
booleanType,
objectType,
functionType,
} from '../_util/type';
import useConfigInject from '../config-provider/hooks/useConfigInject';
import type { TransferListBodyProps } from './ListBody';
import type { PaginationType } from './interface';
Expand All @@ -17,6 +25,9 @@ import type { RenderEmptyHandler } from '../config-provider/renderEmpty';
import type { InputStatus } from '../_util/statusUtils';
import { getStatusClassNames, getMergedStatus } from '../_util/statusUtils';

// CSSINJS
import useStyle from './style';

export type { TransferListProps } from './list';
export type { TransferOperationProps } from './operation';
export type { TransferSearchProps } from './search';
Expand Down Expand Up @@ -69,40 +80,41 @@ export interface TransferLocale {
export const transferProps = () => ({
id: String,
prefixCls: String,
dataSource: { type: Array as PropType<TransferItem[]>, default: [] },
disabled: { type: Boolean, default: undefined },
targetKeys: { type: Array as PropType<string[]>, default: undefined },
selectedKeys: { type: Array as PropType<string[]>, default: undefined },
render: { type: Function as PropType<TransferRender<TransferItem>> },
listStyle: {
type: [Function, Object] as PropType<((style: ListStyle) => CSSProperties) | CSSProperties>,
default: () => ({}),
},
operationStyle: { type: Object as PropType<CSSProperties>, default: undefined as CSSProperties },
titles: { type: Array as PropType<string[]> },
operations: { type: Array as PropType<string[]> },
showSearch: { type: Boolean, default: false },
filterOption: { type: Function as PropType<(inputValue: string, item: TransferItem) => boolean> },
dataSource: arrayType<TransferItem[]>([]),
disabled: booleanType(),
targetKeys: arrayType<string[]>(),
selectedKeys: arrayType<string[]>(),
render: functionType<TransferRender<TransferItem>>(),
listStyle: someType<((style: ListStyle) => CSSProperties) | CSSProperties>(
[Function, Object],
() => ({}),
),
operationStyle: objectType<CSSProperties>(undefined as CSSProperties),
titles: arrayType<string[]>(),
operations: arrayType<string[]>(),
showSearch: booleanType(false),
filterOption: functionType<(inputValue: string, item: TransferItem) => boolean>(),
searchPlaceholder: String,
notFoundContent: PropTypes.any,
locale: { type: Object as PropType<Partial<TransferLocale>>, default: () => ({}) },
rowKey: { type: Function as PropType<(record: TransferItem) => string> },
showSelectAll: { type: Boolean, default: undefined },
selectAllLabels: { type: Array as PropType<SelectAllLabel[]> },
children: { type: Function as PropType<(props: TransferListBodyProps) => VueNode> },
oneWay: { type: Boolean, default: undefined },
pagination: { type: [Object, Boolean] as PropType<PaginationType>, default: undefined },
status: String as PropType<InputStatus>,
onChange: Function as PropType<
(targetKeys: string[], direction: TransferDirection, moveKeys: string[]) => void
>,
onSelectChange: Function as PropType<
locale: objectType(),
rowKey: functionType<(record: TransferItem) => string>(),
showSelectAll: booleanType(),
selectAllLabels: arrayType<SelectAllLabel[]>(),
children: functionType<(props: TransferListBodyProps) => VueNode>(),
oneWay: booleanType(),
pagination: someType<PaginationType>([Object, Boolean]),
status: stringType<InputStatus>(),
onChange:
functionType<
(targetKeys: string[], direction: TransferDirection, moveKeys: string[]) => void
>(),
onSelectChange: functionType<
(sourceSelectedKeys: string[], targetSelectedKeys: string[]) => void
>,
onSearch: Function as PropType<(direction: TransferDirection, value: string) => void>,
onScroll: Function as PropType<(direction: TransferDirection, e: UIEvent) => void>,
'onUpdate:targetKeys': Function as PropType<(keys: string[]) => void>,
'onUpdate:selectedKeys': Function as PropType<(keys: string[]) => void>,
onSearch: functionType<(direction: TransferDirection, value: string) => void>(),
onScroll: functionType<(direction: TransferDirection, e: UIEvent) => void>(),
'onUpdate:targetKeys': functionType<(keys: string[]) => void>(),
'onUpdate:selectedKeys': functionType<(keys: string[]) => void>(),
});

export type TransferProps = Partial<ExtractPropTypes<ReturnType<typeof transferProps>>>;
Expand All @@ -125,6 +137,10 @@ const Transfer = defineComponent({
// emits: ['update:targetKeys', 'update:selectedKeys', 'change', 'search', 'scroll', 'selectChange'],
setup(props, { emit, attrs, slots, expose }) {
const { configProvider, prefixCls, direction } = useConfigInject('transfer', props);

// style
const [wrapSSR, hashId] = useStyle(prefixCls);

const sourceSelectedKeys = ref([]);
const targetSelectedKeys = ref([]);

Expand Down Expand Up @@ -349,14 +365,15 @@ const Transfer = defineComponent({
[`${prefixCls.value}-rtl`]: direction.value === 'rtl',
},
getStatusClassNames(prefixCls.value, mergedStatus.value, formItemInputContext.hasFeedback),
hashId.value,
);
const titles = props.titles;
const leftTitle =
(titles && titles[0]) ?? slots.leftTitle?.() ?? (locale.titles || ['', ''])[0];
const rightTitle =
(titles && titles[1]) ?? slots.rightTitle?.() ?? (locale.titles || ['', ''])[1];
return (
<div class={cls} style={style as CSSProperties} id={id}>
<div {...attrs} class={cls} style={style as CSSProperties} id={id}>
<List
key="leftList"
prefixCls={`${prefixCls.value}-list`}
Expand Down Expand Up @@ -422,13 +439,14 @@ const Transfer = defineComponent({
</div>
);
};
return () => (
<LocaleReceiver
componentName="Transfer"
defaultLocale={defaultLocale.Transfer}
children={renderTransfer}
/>
);
return () =>
wrapSSR(
<LocaleReceiver
componentName="Transfer"
defaultLocale={defaultLocale.Transfer}
children={renderTransfer}
/>,
);
},
});

Expand Down
3 changes: 2 additions & 1 deletion components/transfer/index.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ category: Components
type: 数据录入
title: Transfer
subtitle: 穿梭框
cover: https://gw.alipayobjects.com/zos/alicdn/QAXskNI4G/Transfer.svg
cover: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*EAApQ5ephigAAAAAAAAAAAAADrJ8AQ/original
---

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