diff --git a/components/_util/transKeys.ts b/components/_util/transKeys.ts new file mode 100644 index 000000000..d196b1137 --- /dev/null +++ b/components/_util/transKeys.ts @@ -0,0 +1,17 @@ +export const groupKeysMap = (keys: string[]) => { + const map = new Map(); + keys.forEach((key, index) => { + map.set(key, index); + }); + return map; +}; + +export const groupDisabledKeysMap = (dataSource: RecordType) => { + const map = new Map(); + dataSource.forEach(({ disabled, key }, index) => { + if (disabled) { + map.set(key, index); + } + }); + return map; +}; diff --git a/components/transfer/ListBody.tsx b/components/transfer/ListBody.tsx index e90fde6e5..d798dae10 100644 --- a/components/transfer/ListBody.tsx +++ b/components/transfer/ListBody.tsx @@ -76,10 +76,7 @@ const ListBody = defineComponent({ const maxPageCount = Math.ceil( props.filteredRenderItems.length / mergedPagination.value.pageSize, ); - - if (current.value > maxPageCount) { - current.value = maxPageCount; - } + current.value = Math.min(current.value, maxPageCount); } }, { immediate: true }, diff --git a/components/transfer/index.tsx b/components/transfer/index.tsx index b0075161b..8d2e0e773 100644 --- a/components/transfer/index.tsx +++ b/components/transfer/index.tsx @@ -24,7 +24,7 @@ import { FormItemInputContext, useInjectFormItemContext } from '../form/FormItem import type { RenderEmptyHandler } from '../config-provider/renderEmpty'; import type { InputStatus } from '../_util/statusUtils'; import { getStatusClassNames, getMergedStatus } from '../_util/statusUtils'; - +import { groupKeysMap, groupDisabledKeysMap } from '../_util/transKeys'; // CSSINJS import useStyle from './style'; @@ -64,17 +64,17 @@ export type SelectAllLabel = | ((info: { selectedCount: number; totalCount: number }) => VueNode); export interface TransferLocale { - titles: VueNode[]; + titles?: VueNode[]; notFoundContent?: VueNode; searchPlaceholder: string; itemUnit: string; itemsUnit: string; - remove: string; - selectAll: string; - selectCurrent: string; - selectInvert: string; - removeAll: string; - removeCurrent: string; + remove?: string; + selectAll?: string; + selectCurrent?: string; + selectInvert?: string; + removeAll?: string; + removeCurrent?: string; } export const transferProps = () => ({ @@ -108,9 +108,8 @@ export const transferProps = () => ({ functionType< (targetKeys: string[], direction: TransferDirection, moveKeys: string[]) => void >(), - onSelectChange: functionType< - (sourceSelectedKeys: string[], targetSelectedKeys: string[]) => void - >, + onSelectChange: + functionType<(sourceSelectedKeys: string[], targetSelectedKeys: string[]) => void>(), onSearch: functionType<(direction: TransferDirection, value: string) => void>(), onScroll: functionType<(direction: TransferDirection, e: UIEvent) => void>(), 'onUpdate:targetKeys': functionType<(keys: string[]) => void>(), @@ -177,15 +176,16 @@ const Transfer = defineComponent({ const moveTo = (direction: TransferDirection) => { const { targetKeys = [], dataSource = [] } = props; const moveKeys = direction === 'right' ? sourceSelectedKeys.value : targetSelectedKeys.value; + const dataSourceDisabledKeysMap = groupDisabledKeysMap(dataSource); // filter the disabled options - const newMoveKeys = moveKeys.filter( - key => !dataSource.some(data => !!(key === data.key && data.disabled)), - ); + const newMoveKeys = moveKeys.filter(key => !dataSourceDisabledKeysMap.has(key)); + const newMoveKeysMap = groupKeysMap(newMoveKeys); + // move items to target box const newTargetKeys = direction === 'right' ? newMoveKeys.concat(targetKeys) - : targetKeys.filter(targetKey => newMoveKeys.indexOf(targetKey) === -1); + : targetKeys.filter(targetKey => !newMoveKeysMap.has(targetKey)); // empty checked keys const oppositeDirection = direction === 'right' ? 'left' : 'right'; @@ -309,16 +309,16 @@ const Transfer = defineComponent({ const ld = []; const rd = new Array(targetKeys.length); + const targetKeysMap = groupKeysMap(targetKeys); dataSource.forEach(record => { if (rowKey) { record.key = rowKey(record); } - // rightDataSource should be ordered by targetKeys - // leftDataSource should be ordered by dataSource - const indexOfKey = targetKeys.indexOf(record.key); - if (indexOfKey !== -1) { - rd[indexOfKey] = record; + // rightData should be ordered by targetKeys + // leftData should be ordered by dataSource + if (targetKeysMap.has(record.key)) { + rd[targetKeysMap.get(record.key)!] = record; } else { ld.push(record); } diff --git a/components/transfer/list.tsx b/components/transfer/list.tsx index c8e0cb76f..2673b7db8 100644 --- a/components/transfer/list.tsx +++ b/components/transfer/list.tsx @@ -12,6 +12,7 @@ import { watchEffect, computed, defineComponent, ref } from 'vue'; import type { RadioChangeEvent } from '../radio/interface'; import type { TransferDirection, TransferItem } from './index'; import { stringType, arrayType, booleanType } from '../_util/type'; +import { groupKeysMap } from '../_util/transKeys'; const defaultRender = () => null; @@ -125,9 +126,8 @@ export default defineComponent({ if (checkedKeys.length === 0) { return 'none'; } - if ( - filteredItems.value.every(item => checkedKeys.indexOf(item.key) >= 0 || !!item.disabled) - ) { + const checkedKeysMap = groupKeysMap(checkedKeys); + if (filteredItems.value.every(item => checkedKeysMap.has(item.key) || !!item.disabled)) { return 'all'; } return 'part'; @@ -147,7 +147,7 @@ export default defineComponent({ const checkedAll = checkStatus.value === 'all'; const checkAllCheckbox = ( = 0; + return text.includes(filterValue.value); }; const getSelectAllLabel = (selectedCount: number, totalCount: number) => { @@ -199,6 +199,11 @@ export default defineComponent({ ); }; + const notFoundContentEle = computed(() => + Array.isArray(props.notFoundContent) + ? props.notFoundContent[props.direction === 'left' ? 0 : 1] + : props.notFoundContent, + ); const getListBody = ( prefixCls: string, searchPlaceholder: string, @@ -237,7 +242,7 @@ export default defineComponent({ bodyNode = filteredItems.value.length ? ( bodyContent ) : ( -
{props.notFoundContent}
+
{notFoundContentEle.value}
); }