diff --git a/examples/transfer/demos/base.vue b/examples/transfer/demos/base.vue index 28c955de39..c5ba936126 100644 --- a/examples/transfer/demos/base.vue +++ b/examples/transfer/demos/base.vue @@ -5,7 +5,7 @@ :data="list" :checked="checked" @change="onChange" - @checkedChange="handleCheckedChange" + @checked-change="handleCheckedChange" /> diff --git a/examples/transfer/demos/search.vue b/examples/transfer/demos/search.vue index a38611c43f..03babd14c6 100644 --- a/examples/transfer/demos/search.vue +++ b/examples/transfer/demos/search.vue @@ -1,6 +1,6 @@ diff --git a/src/_common b/src/_common index 3e7828ad11..0487f2ce98 160000 --- a/src/_common +++ b/src/_common @@ -1 +1 @@ -Subproject commit 3e7828ad11a37a70083f40359956a0591a97533d +Subproject commit 0487f2ce98b15de46590c26693e094874d988292 diff --git a/src/drawer/drawer.tsx b/src/drawer/drawer.tsx index af9ce1dac6..a55c4bdad7 100644 --- a/src/drawer/drawer.tsx +++ b/src/drawer/drawer.tsx @@ -1,4 +1,4 @@ -import { computed, defineComponent, nextTick, onUpdated, ref, watch } from 'vue'; +import { computed, defineComponent, nextTick, onUpdated, toRefs, ref, watch } from 'vue'; import { CloseIcon } from 'tdesign-icons-vue-next'; import { useConfig, usePrefixClass } from '../hooks/useConfig'; import { isServer, addClass, removeClass } from '../utils/dom'; @@ -14,17 +14,10 @@ type FooterButtonType = 'confirm' | 'cancel'; export default defineComponent({ name: 'TDrawer', - - components: { - CloseIcon, - TButton, - }, - directives: { TransferDom, }, props, - // TODO update:visible 是否是受控的 emits: ['update:visible'], setup(props, context) { const { global } = useConfig('drawer'); @@ -119,14 +112,14 @@ export default defineComponent({ const theme = isCancel ? 'default' : 'primary'; const isApiObject = typeof btnApi === 'object'; return ( - {btnApi && typeof btnApi === 'object' ? btnApi.content : btnApi} - + ); }; const isUseDefault = (btnApi: FooterButton) => { @@ -224,18 +217,19 @@ export default defineComponent({ render() { const { COMPONENT_NAME } = this; if (this.destroyOnClose && !this.visible) return; - const defaultCloseBtn = ; + const defaultCloseBtn = ; const body = renderContent(this, 'body', 'default'); const headerContent = renderTNodeJSX(this, 'header'); const defaultFooter = this.getDefaultFooter(); return (
{this.showOverlay &&
}
diff --git a/src/hooks/useDefaultValue.ts b/src/hooks/useDefaultValue.ts index cd4e185a11..2cd65cccdf 100644 --- a/src/hooks/useDefaultValue.ts +++ b/src/hooks/useDefaultValue.ts @@ -2,12 +2,12 @@ import { ref, Ref, getCurrentInstance, watch } from 'vue'; import { ChangeHandler } from './useVModel'; // 用于实现 v-model:propsName -export default function useDefaultValue( +export default function useDefaultValue void>( value: Ref, defaultValue: T, - onChange: ChangeHandler, + onChange: P, propsName: string, -): [Ref, ChangeHandler] { +): [Ref, ChangeHandler] { const { emit, attrs } = getCurrentInstance(); const internalValue = ref(); internalValue.value = defaultValue; diff --git a/src/hooks/useVModel.ts b/src/hooks/useVModel.ts index ec9b575bd4..79083c04d7 100644 --- a/src/hooks/useVModel.ts +++ b/src/hooks/useVModel.ts @@ -1,15 +1,15 @@ import { ref, Ref, getCurrentInstance, watch } from 'vue'; -export type ChangeHandler = (value: T, ...args: P) => void; +export type ChangeHandler = (value: T, ...args: any) => void; -export default function useVModel( +export default function useVModel void>( value: Ref, modelValue: Ref, defaultValue: T, - onChange: ChangeHandler, + onChange: P, propName = 'value', // emit 和 eventName 用于支持 v-model 和 xxx.sync 语法糖 -): [Ref, ChangeHandler] { +): [Ref, ChangeHandler] { const { emit, attrs } = getCurrentInstance(); const internalValue: Ref = ref(); diff --git a/src/menu/submenu.tsx b/src/menu/submenu.tsx index 54c27d5901..60600d2036 100644 --- a/src/menu/submenu.tsx +++ b/src/menu/submenu.tsx @@ -185,7 +185,7 @@ export default defineComponent({ class={[ // ...this.popupClass, `${this.classPrefix}-menu__spacer`, - `${this.classPrefix}-menu__spacer--${!this.isNested && this.head ? 'top' : 'left'}`, + `${this.classPrefix}-menu__spacer--${!this.isNested && this.isHead ? 'top' : 'left'}`, ]} onMouseenter={this.handleEnterPopup} onMouseleave={this.handleMouseLeavePopup} diff --git a/src/progress/progress.tsx b/src/progress/progress.tsx index fe6a5d37d4..76ef905f3a 100644 --- a/src/progress/progress.tsx +++ b/src/progress/progress.tsx @@ -1,4 +1,4 @@ -import { defineComponent, VNode, computed } from 'vue'; +import { defineComponent, VNode, computed, CSSProperties } from 'vue'; import { CloseCircleFilledIcon, CheckCircleFilledIcon, @@ -23,16 +23,20 @@ export default defineComponent({ if (props.percentage >= 100) { return 'success'; } - return props.status; + return props.status || 'default'; }); const trackBgStyle = computed(() => { - const height = typeof props.strokeWidth === 'string' ? props.strokeWidth : `${props.strokeWidth}px`; - return { - height, - backgroundColor: props.trackColor, - borderRadius: height, - }; + const style: CSSProperties = {}; + if (props.strokeWidth) { + const height = typeof props.strokeWidth === 'string' ? props.strokeWidth : `${props.strokeWidth}px`; + style.height = height; + style.borderRadius = height; + } + if (props.trackColor) { + style.backgroundColor = props.trackColor; + } + return style; }); const barStyle = computed(() => { diff --git a/src/select/props.ts b/src/select/props.ts index 5fd62588fd..ffc17ed0a6 100644 --- a/src/select/props.ts +++ b/src/select/props.ts @@ -113,7 +113,12 @@ export default { selectInputProps: { type: Object as PropType, }, - /** 是否显示右侧箭头,默认显示 */ + /** 【讨论中】是否显示全选 */ + showCheckAlll: Boolean, + /** + * 是否显示右侧箭头,默认显示 + * @default true + */ showArrow: { type: Boolean, default: true, diff --git a/src/select/select.tsx b/src/select/select.tsx index 89d0a75b05..7f32e163af 100644 --- a/src/select/select.tsx +++ b/src/select/select.tsx @@ -192,11 +192,12 @@ export default defineComponent({ // to fix Computed property "showArrow" is already defined in Props. innerShowArrow(): boolean { return ( - !this.clearable || - !this.isHover || - this.disabled || - (!this.multiple && !this.value && this.value !== 0) || - (this.multiple && (!Array.isArray(this.value) || (Array.isArray(this.value) && !this.value.length))) + this.showArrow && + (!this.clearable || + !this.isHover || + this.disabled || + (!this.multiple && !this.value && this.value !== 0) || + (this.multiple && (!Array.isArray(this.value) || (Array.isArray(this.value) && !this.value.length)))) ); }, canFilter(): boolean { @@ -478,6 +479,10 @@ export default defineComponent({ emitEvent>(this, 'change', value, { trigger }); }, createOption(value: string) { + this.$nextTick(() => { + this.searchInput = ''; + this.showCreateOption = false; + }); emitEvent>(this, 'create', value); }, debounceOnRemote: debounce(function (this: any) { @@ -534,9 +539,6 @@ export default defineComponent({ case 'Enter': if (this.showCreateOption) { this.createOption(this.searchInput); - this.$nextTick(() => { - this.searchInput = ''; - }); } this.hoverOptions[this.hoverIndex] && this.onOptionClick(this.hoverOptions[this.hoverIndex][this.realValue], e); diff --git a/src/transfer/components/transfer-list.tsx b/src/transfer/components/transfer-list.tsx index ef6ba8fff7..c463a98f43 100644 --- a/src/transfer/components/transfer-list.tsx +++ b/src/transfer/components/transfer-list.tsx @@ -10,7 +10,7 @@ import { } from '../interface'; import { PageInfo, TdPaginationProps, Pagination } from '../../pagination'; import { Checkbox as TCheckbox, CheckboxGroup as TCheckboxGroup, CheckboxProps } from '../../checkbox'; -import { getLeefCount, getDataValues } from '../utils'; +import { getLefCount, getDataValues } from '../utils'; import Search from './transfer-search'; import { useTNodeDefault } from '../../hooks/tnode'; @@ -121,9 +121,7 @@ export default defineComponent({ } : {}; }); - const hasFooter = computed(() => { - return !!slots.default; - }); + const isAllChecked = computed(() => { return ( props.checkedValue.length > 0 && @@ -135,7 +133,7 @@ export default defineComponent({ }); const totalCount = computed(() => { - return getLeefCount(props.dataSource); + return getLefCount(props.dataSource); }); const handlePaginationChange = (pageInfo: PageInfo) => { diff --git a/src/transfer/props.ts b/src/transfer/props.ts index 60be33e437..a26076cdb7 100644 --- a/src/transfer/props.ts +++ b/src/transfer/props.ts @@ -16,7 +16,7 @@ export default { /** 数据列表选中项 */ checked: { type: Array as PropType, - default: (): TdTransferProps['checked'] => [], + default: undefined, }, /** 数据列表选中项,非受控属性 */ defaultChecked: { diff --git a/src/transfer/transfer.tsx b/src/transfer/transfer.tsx index b9171047b9..0b6c4dfcc0 100644 --- a/src/transfer/transfer.tsx +++ b/src/transfer/transfer.tsx @@ -2,21 +2,14 @@ import { defineComponent, computed, toRefs, ref } from 'vue'; import pick from 'lodash/pick'; import TransferList from './components/transfer-list'; import TransferOperations from './components/transfer-operations'; -import { - TransferListType, - TransferItemOption, - CheckedOptions, - TransferValue, - EmptyType, - TargetParams, - SearchEvent, -} from './interface'; +import { TransferListType, CheckedOptions, TransferValue, EmptyType, TargetParams, SearchEvent } from './interface'; import { getTransferListOption, getDataValues, getTransferData, filterTransferData, TRANSFER_NAME } from './utils'; import { PageInfo, TdPaginationProps } from '../pagination/type'; import props from './props'; import { TNode } from '../common'; import useVModel from '../hooks/useVModel'; +import useDefaultValue from '../hooks/useDefaultValue'; // hooks import { useFormDisabled } from '../form/hooks'; @@ -33,18 +26,9 @@ export default defineComponent({ const disabled = useFormDisabled(); const classPrefix = usePrefixClass(); const { t, global } = useConfig('transfer'); - const { value, modelValue } = toRefs(props); + const { value, modelValue, checked } = toRefs(props); const [innerValue, setInnerValue] = useVModel(value, modelValue, props.defaultValue, props.onChange); - const initChecked = computed(() => { - if (props.checked && props.checked.length) { - return props.checked; - } - if (props.defaultChecked && props.defaultChecked.length) { - return props.defaultChecked; - } - return []; - }); - const checkedValueList = computed(() => initChecked.value); + const [innerChecked] = useDefaultValue(checked, props.defaultChecked, props.onCheckedChange, 'checked'); const valueList = ref(innerValue.value || []); const isTreeMode = computed(() => { @@ -67,8 +51,8 @@ export default defineComponent({ // 被选中的value const checkedValue = computed(() => { return { - [SOURCE]: getDataValues(sourceList.value, checkedValueList.value, { isTreeMode: isTreeMode.value }), - [TARGET]: getDataValues(targetList.value, checkedValueList.value, { isTreeMode: isTreeMode.value }), + [SOURCE]: getDataValues(sourceList.value, innerChecked.value, { isTreeMode: isTreeMode.value }), + [TARGET]: getDataValues(targetList.value, innerChecked.value, { isTreeMode: isTreeMode.value }), }; }); const hasFooter = computed(() => { @@ -115,9 +99,8 @@ export default defineComponent({ targetChecked, type: listType, }; - // 支持v-model:checked - // TODO: 换成 useVModel - props['onUpdate:checked']?.(checked); + // TODO onCheckedChange 参数有点不合理 + innerChecked.value = checked; props.onCheckedChange?.(event); }; @@ -158,16 +141,7 @@ export default defineComponent({ const transferToLeft = () => { transferTo(SOURCE); }; - const filterMethod = ( - transferList: Array, - targetValueList: Array, - needMatch: boolean, - ): Array => { - return transferList.filter((item) => { - const isMatch = targetValueList.includes(item.value); - return needMatch ? isMatch : !isMatch; - }); - }; + const handleScroll = (e: Event, listType: TransferListType) => { const target = e.target as HTMLElement; const bottomDistance = target.scrollHeight - target.scrollTop - target.clientHeight; diff --git a/src/transfer/utils.ts b/src/transfer/utils.ts index d56b0e4135..de8d868aff 100644 --- a/src/transfer/utils.ts +++ b/src/transfer/utils.ts @@ -181,11 +181,11 @@ function filterTransferData( } // 获取树节点的叶子数量 -function getLeefCount(nodes: Array): number { +function getLefCount(nodes: Array): number { let total = 0; nodes.forEach((child) => { if (child.children && child.children.length > 0) { - total += getLeefCount(child.children); + total += getLefCount(child.children); } else { total += 1; } @@ -200,5 +200,5 @@ export { getTransferData, cloneTreeWithFilter, filterTransferData, - getLeefCount, + getLefCount, }; diff --git a/test/snap/__snapshots__/csr.test.js.snap b/test/snap/__snapshots__/csr.test.js.snap index 1a1f8805a7..d78d685e3e 100644 --- a/test/snap/__snapshots__/csr.test.js.snap +++ b/test/snap/__snapshots__/csr.test.js.snap @@ -44243,6 +44243,7 @@ exports[`csr snapshot test > csr test ./examples/config-provider/demos/popconfir
csr test ./examples/drawer/demos/attach-parent.vue
csr test ./examples/drawer/demos/base.vue 1`] = `
csr test ./examples/drawer/demos/custom.vue 1`] = `
csr test ./examples/drawer/demos/custom.vue 1`] = `
csr test ./examples/drawer/demos/custom.vue 1`] = `
csr test ./examples/drawer/demos/no-mask.vue 1`] =
csr test ./examples/drawer/demos/operation.vue 1`]
csr test ./examples/drawer/demos/placement.vue 1`]
csr test ./examples/drawer/demos/size.vue 1`] = `
csr test ./examples/progress/demos/circle.vue 1`] =
csr test ./examples/progress/demos/circle.vue 1`] =
csr test ./examples/progress/demos/circle.vue 1`] =
csr test ./examples/progress/demos/circle.vue 1`] =
csr test ./examples/progress/demos/custom.vue 1`] =
csr test ./examples/progress/demos/custom.vue 1`] = data-v-9f8aa44c="" >
csr test ./examples/progress/demos/custom.vue 1`] = data-v-9f8aa44c="" >
csr test ./examples/progress/demos/custom.vue 1`] =
csr test ./examples/progress/demos/custom.vue 1`] = >
csr test ./examples/progress/demos/custom.vue 1`] =
csr test ./examples/progress/demos/custom.vue 1`] = data-v-9f8aa44c="" >
csr test ./examples/progress/demos/custom.vue 1`] =
csr test ./examples/progress/demos/line.vue 1`] = ` data-v-c2968dc6="" >
csr test ./examples/progress/demos/line.vue 1`] = ` >
csr test ./examples/progress/demos/line.vue 1`] = ` >
csr test ./examples/progress/demos/line.vue 1`] = ` >
csr test ./examples/progress/demos/line.vue 1`] = ` >
csr test ./examples/progress/demos/line.vue 1`] = ` >
csr test ./examples/progress/demos/line.vue 1`] = ` >
csr test ./examples/progress/demos/line.vue 1`] = ` >
csr test ./examples/progress/demos/plump.vue 1`] = >
csr test ./examples/progress/demos/plump.vue 1`] = >
csr test ./examples/progress/demos/plump.vue 1`] =
csr test ./examples/progress/demos/plump.vue 1`] =
csr test ./examples/progress/demos/plump.vue 1`] =
csr test ./examples/progress/demos/plump.vue 1`] =
csr test ./examples/progress/demos/plump.vue 1`] =
csr test ./examples/progress/demos/size.vue 1`] = `
csr test ./examples/progress/demos/size.vue 1`] = `
csr test ./examples/progress/demos/size.vue 1`] = `
csr test ./examples/progress/demos/status.vue 1`] = >
csr test ./examples/progress/demos/status.vue 1`] =
csr test ./examples/progress/demos/status.vue 1`] = >
csr test ./examples/progress/demos/status.vue 1`] =
csr test ./examples/progress/demos/status.vue 1`] = >
csr test ./examples/progress/demos/status.vue 1`] =
csr test ./examples/progress/demos/status.vue 1`] = >
csr test ./examples/transfer/demos/pagination.vue 1 exports[`csr snapshot test > csr test ./examples/transfer/demos/search.vue 1`] = `