From 2329afb69ac44900c6b7a4e29246ecdcd2226fda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?w=C5=AB=20y=C4=81ng?= Date: Fri, 18 Oct 2024 18:03:42 +0800 Subject: [PATCH] chore: release 1.10.4-naruto (#3367) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore(deps-dev): bump @rollup/plugin-node-resolve from 11.2.1 to 15.3.0 (#3352) Bumps [@rollup/plugin-node-resolve](https://github.com/rollup/plugins/tree/HEAD/packages/node-resolve) from 11.2.1 to 15.3.0. - [Changelog](https://github.com/rollup/plugins/blob/master/packages/node-resolve/CHANGELOG.md) - [Commits](https://github.com/rollup/plugins/commits/node-resolve-v15.3.0/packages/node-resolve) --- updated-dependencies: - dependency-name: "@rollup/plugin-node-resolve" dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * fix(tree): custom icons cannot be clicked without child nodes (#3354) * chore: fix select input demo (#3358) * chore: fix select input demo * chore: update snapshot * fix: fix shaking when dialog and drawer show (#3362) * fix: fix shaking when dialog and drawer show * chore: update common * feat(TimePicker): support autoswap API (#3363) * feat(timepicker): support autoswap API * feat(timepicker): support autoswap API * chore: live demo * chore: release 1.10.4 (#3366) * chore: release 1.10.4 * chore: changelog's changes --------- Co-authored-by: github-actions[bot] * fix(cascader): custom option * chore: update CHANGELOG --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: 阿菜 Cai Co-authored-by: github-actions[bot] --- CHANGELOG.md | 11 ++++ package.json | 4 +- src/cascader/components/Item.tsx | 14 ++++- src/cascader/components/Panel.tsx | 56 +++++++++++-------- src/date-picker/date-picker.en-US.md | 4 +- src/date-picker/date-picker.md | 4 +- src/drawer/drawer.tsx | 3 +- .../_example-composition/multiple.vue | 2 +- src/select-input/_example/multiple.vue | 2 +- .../_usage/time-range-picker-props.json | 6 ++ src/time-picker/time-picker.en-US.md | 1 + src/time-picker/time-picker.md | 1 + src/time-picker/time-range-picker-props.ts | 5 ++ src/time-picker/time-range-picker.tsx | 54 ++++++------------ src/time-picker/type.ts | 5 ++ src/tree/__tests__/expand.test.jsx | 32 +++++++++++ src/tree/hooks/useTreeAction.ts | 3 + test/snap/__snapshots__/csr.test.js.snap | 1 - test/snap/__snapshots__/ssr.test.js.snap | 2 +- 19 files changed, 135 insertions(+), 75 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 74e63aee7..413276b8f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,17 @@ toc: false docClass: timeline --- +## 🌈 1.10.4 `2024-10-18` +### 🚀 Features +- `TimePicker`: 新增 `autoSwap` API,支持`1.10.2` 版本之后仍支持保持选定的左右侧时间大小顺序 @uyarn ([#3363](https://github.com/Tencent/tdesign-vue/pull/3363)) +### 🐞 Bug Fixes +- `Tree`: 修复叶子节点自定义的图标可被点击的问题 @RSS1102 ([#3354](https://github.com/Tencent/tdesign-vue/pull/3354)) +- `Drawer`: 修复打开 `drawer` 时页面抖动的问题 @RSS1102 @uyarn ([#3362](https://github.com/Tencent/tdesign-vue/pull/3362)) +- `Dialog`: 修复打开 `dialog` 时页面抖动的问题 @RSS1102 ([#3362](https://github.com/Tencent/tdesign-vue/pull/3362)) +- `Cascader`: 修复不能通过插槽自定义选项内容的问题 +### 🚧 Others +- `DatePicker`: 移除文档中错误的`value` 类型描述 + ## 🌈 1.10.3 `2024-09-27` ### 🐞 Bug Fixes - `Cascader`: 修复初始化滚动节点时未兼容单选父节点滚动的缺陷 @uyarn ([#3342](https://github.com/Tencent/tdesign-vue/pull/3342)) diff --git a/package.json b/package.json index d45589698..aabf0d735 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "tdesign-vue", "purename": "tdesign", - "version": "1.10.3-naruto", + "version": "1.10.4-naruto", "description": "tdesign-vue", "title": "tdesign-vue", "keywords": [ @@ -119,7 +119,7 @@ "@rollup/plugin-babel": "^5.1.0", "@rollup/plugin-commonjs": "^18.0.0", "@rollup/plugin-json": "^4.1.0", - "@rollup/plugin-node-resolve": "^11.2.1", + "@rollup/plugin-node-resolve": "^15.3.0", "@rollup/plugin-replace": "^2.4.2", "@rollup/plugin-url": "^5.0.1", "@testing-library/dom": "^8.20.0", diff --git a/src/cascader/components/Item.tsx b/src/cascader/components/Item.tsx index e292023cd..5045d38a5 100644 --- a/src/cascader/components/Item.tsx +++ b/src/cascader/components/Item.tsx @@ -9,7 +9,9 @@ import TLoading from '../../loading'; // type import { getKeepAnimationMixins } from '../../config-provider/config-receiver'; -import { CascaderContextType, TreeNodeValue, TreeNode } from '../interface'; +import { + CascaderContextType, TreeNodeValue, TreeNode, TdCascaderProps, +} from '../interface'; import { usePrefixClass, useCommonClassName } from '../../hooks/useConfig'; import { useGlobalIcon } from '../../hooks/useGlobalIcon'; import Ripple from '../../utils/ripple'; @@ -23,6 +25,9 @@ const props = { return {}; }, }, + optionChild: { + type: [Object, Array] as PropType, + }, cascaderContext: { type: Object as PropType, }, @@ -54,7 +59,7 @@ export default defineComponent({ }, render() { const { - iconClass, cascaderContext, itemClass, node, COMPONENT_NAME, onChange, ChevronRightIcon, + iconClass, cascaderContext, itemClass, node, COMPONENT_NAME, onChange, ChevronRightIcon, optionChild, } = this; function RenderLabelInner(node: TreeNode, cascaderContext: CascaderContextType) { @@ -129,7 +134,10 @@ export default defineComponent({ this.onMouseenter(); }} > - {cascaderContext.multiple ? RenderCheckBox(node, cascaderContext) : RenderLabelContent(node, cascaderContext)} + {optionChild + || (cascaderContext.multiple + ? RenderCheckBox(node, cascaderContext) + : RenderLabelContent(node, cascaderContext))} {node.children && (node.loading ? : )} diff --git a/src/cascader/components/Panel.tsx b/src/cascader/components/Panel.tsx index e525689d3..4a6732302 100644 --- a/src/cascader/components/Panel.tsx +++ b/src/cascader/components/Panel.tsx @@ -4,6 +4,7 @@ import { TreeNode, CascaderContextType, CascaderValue } from '../interface'; import CascaderProps from '../props'; import { usePrefixClass, useConfig } from '../../hooks/useConfig'; import { useTNodeDefault } from '../../hooks/tnode'; +import { getDefaultNode } from '../../hooks/render-tnode'; import { getPanels } from '../core/helper'; import { expendClickEffect, valueChangeEffect } from '../core/effect'; @@ -56,29 +57,38 @@ export default defineComponent({ global, COMPONENT_NAME, handleExpand, renderTNodeJSXDefault, cascaderContext, panels, emit, } = this; - const renderItem = (node: TreeNode) => ( - { - emit('click', node.value, node); - handleExpand(node, 'click'); - }, - onMouseenter: () => { - handleExpand(node, 'hover'); - }, - onChange: () => { - valueChangeEffect(node, cascaderContext); + const renderItem = (node: TreeNode, index: number) => { + const optionChild = node.data.content + ? getDefaultNode(node.data.content(this.$createElement)) + : renderTNodeJSXDefault('option', { + params: { item: node.data, index }, + }); + + return ( + { + emit('click', node.value, node); + handleExpand(node, 'click'); + }, + onMouseenter: () => { + handleExpand(node, 'hover'); + }, + onChange: () => { + valueChangeEffect(node, cascaderContext); + }, }, - }, - }} - /> - ); + }} + /> + ); + }; const renderList = (treeNodes: TreeNode[], isFilter = false, segment = true, key = '1') => (
    - {treeNodes.map((node: TreeNode) => renderItem(node))} + {treeNodes.map((node: TreeNode, index: number) => renderItem(node, index))}
); diff --git a/src/date-picker/date-picker.en-US.md b/src/date-picker/date-picker.en-US.md index 21a45eb56..ada1d5a17 100644 --- a/src/date-picker/date-picker.en-US.md +++ b/src/date-picker/date-picker.en-US.md @@ -29,8 +29,8 @@ status | String | default | options: default/success/warning/error | N suffixIcon | Slot / Function | - | Typescript:`TNode`。[see more ts definition](https://github.com/Tencent/tdesign-vue/blob/develop/src/common.ts) | N timePickerProps | Object | - | Typescript:`TimePickerProps`,[TimePicker API Documents](./time-picker?tab=api)。[see more ts definition](https://github.com/Tencent/tdesign-vue/tree/develop/src/date-picker/type.ts) | N tips | String / Slot / Function | - | Typescript:`string \| TNode`。[see more ts definition](https://github.com/Tencent/tdesign-vue/blob/develop/src/common.ts) | N -value | String / Number / Array / Date | '' | `v-model` is supported。Typescript:`DateValue` `type DateValue = string \| number \| Date`。[see more ts definition](https://github.com/Tencent/tdesign-vue/tree/develop/src/date-picker/type.ts) | N -defaultValue | String / Number / Array / Date | '' | uncontrolled property。Typescript:`DateValue` `type DateValue = string \| number \| Date`。[see more ts definition](https://github.com/Tencent/tdesign-vue/tree/develop/src/date-picker/type.ts) | N +value | String / Number / Date | '' | `v-model` is supported。Typescript:`DateValue` `type DateValue = string \| number \| Date`。[see more ts definition](https://github.com/Tencent/tdesign-vue/tree/develop/src/date-picker/type.ts) | N +defaultValue | String / Number / Date | '' | uncontrolled property。Typescript:`DateValue` `type DateValue = string \| number \| Date`。[see more ts definition](https://github.com/Tencent/tdesign-vue/tree/develop/src/date-picker/type.ts) | N valueType | String | - | Typescript:`DatePickerValueType` `type DatePickerValueType = 'time-stamp' \| 'Date' \| 'YYYY' \| 'YYYY-MM' \| 'YYYY-MM-DD' \| 'YYYY-MM-DD HH' \| 'YYYY-MM-DD HH:mm' \| 'YYYY-MM-DD HH:mm:ss' \| 'YYYY-MM-DD HH:mm:ss:SSS'` `type ValueTypeEnum = DatePickerValueType`。[see more ts definition](https://github.com/Tencent/tdesign-vue/tree/develop/src/date-picker/type.ts) | N onBlur | Function | | Typescript:`(context: { value: DateValue; e: FocusEvent }) => void`
| N onChange | Function | | Typescript:`(value: DateValue, context: { dayjsValue?: Dayjs, trigger?: DatePickerTriggerSource }) => void`
[see more ts definition](https://github.com/Tencent/tdesign-vue/tree/develop/src/date-picker/type.ts)。
`import { Dayjs } from 'dayjs'`

`type DatePickerTriggerSource = 'confirm' \| 'pick' \| 'enter' \| 'preset' \| 'clear'`
| N diff --git a/src/date-picker/date-picker.md b/src/date-picker/date-picker.md index 54c693dd3..120545672 100644 --- a/src/date-picker/date-picker.md +++ b/src/date-picker/date-picker.md @@ -29,8 +29,8 @@ status | String | default | 输入框状态。可选项:default/success/warnin suffixIcon | Slot / Function | - | 用于自定义组件后置图标。TS 类型:`TNode`。[通用类型定义](https://github.com/Tencent/tdesign-vue/blob/develop/src/common.ts) | N timePickerProps | Object | - | 透传 TimePicker 组件属性。TS 类型:`TimePickerProps`,[TimePicker API Documents](./time-picker?tab=api)。[详细类型定义](https://github.com/Tencent/tdesign-vue/tree/develop/src/date-picker/type.ts) | N tips | String / Slot / Function | - | 输入框下方提示文本,会根据不同的 `status` 呈现不同的样式。TS 类型:`string \| TNode`。[通用类型定义](https://github.com/Tencent/tdesign-vue/blob/develop/src/common.ts) | N -value | String / Number / Array / Date | '' | 选中值。支持语法糖 `v-model`。TS 类型:`DateValue` `type DateValue = string \| number \| Date`。[详细类型定义](https://github.com/Tencent/tdesign-vue/tree/develop/src/date-picker/type.ts) | N -defaultValue | String / Number / Array / Date | '' | 选中值。非受控属性。TS 类型:`DateValue` `type DateValue = string \| number \| Date`。[详细类型定义](https://github.com/Tencent/tdesign-vue/tree/develop/src/date-picker/type.ts) | N +value | String / Number / Date | '' | 选中值。支持语法糖 `v-model`。TS 类型:`DateValue` `type DateValue = string \| number \| Date`。[详细类型定义](https://github.com/Tencent/tdesign-vue/tree/develop/src/date-picker/type.ts) | N +defaultValue | String / Number / Date | '' | 选中值。非受控属性。TS 类型:`DateValue` `type DateValue = string \| number \| Date`。[详细类型定义](https://github.com/Tencent/tdesign-vue/tree/develop/src/date-picker/type.ts) | N valueType | String | - | 用于格式化日期的值,仅支持部分格式,时间戳、日期等。⚠️ `YYYYMMDD` 这种格式不支持,请勿使用,如果希望支持可以给 `dayjs` 提个 PR。注意和 `format` 的区别,`format` 仅用于处理日期在页面中呈现的格式。`ValueTypeEnum` 即将废弃,请更为使用 `DatePickerValueType`。TS 类型:`DatePickerValueType` `type DatePickerValueType = 'time-stamp' \| 'Date' \| 'YYYY' \| 'YYYY-MM' \| 'YYYY-MM-DD' \| 'YYYY-MM-DD HH' \| 'YYYY-MM-DD HH:mm' \| 'YYYY-MM-DD HH:mm:ss' \| 'YYYY-MM-DD HH:mm:ss:SSS'` `type ValueTypeEnum = DatePickerValueType`。[详细类型定义](https://github.com/Tencent/tdesign-vue/tree/develop/src/date-picker/type.ts) | N onBlur | Function | | TS 类型:`(context: { value: DateValue; e: FocusEvent }) => void`
当输入框失去焦点时触发 | N onChange | Function | | TS 类型:`(value: DateValue, context: { dayjsValue?: Dayjs, trigger?: DatePickerTriggerSource }) => void`
选中值发生变化时触发。[详细类型定义](https://github.com/Tencent/tdesign-vue/tree/develop/src/date-picker/type.ts)。
`import { Dayjs } from 'dayjs'`

`type DatePickerTriggerSource = 'confirm' \| 'pick' \| 'enter' \| 'preset' \| 'clear'`
| N diff --git a/src/drawer/drawer.tsx b/src/drawer/drawer.tsx index daf7a55be..35706edc6 100644 --- a/src/drawer/drawer.tsx +++ b/src/drawer/drawer.tsx @@ -137,7 +137,8 @@ export default mixins(ActionMixin, getConfigReceiverMixins('d }, mounted() { - const hasScrollBar = document.body.scrollHeight > document.body.clientHeight; + const hasScrollBar = window.innerWidth > document.documentElement.clientWidth; + const scrollWidth = hasScrollBar ? getScrollbarWidth() : 0; this.styleEl = document.createElement('style'); diff --git a/src/select-input/_example-composition/multiple.vue b/src/select-input/_example-composition/multiple.vue index f54bc0e6d..1041d6885 100644 --- a/src/select-input/_example-composition/multiple.vue +++ b/src/select-input/_example-composition/multiple.vue @@ -16,7 +16,7 @@ Partial<{ hour: Array, minute: Array, second: Array }>` `type TimeRangePickerPartial = 'start' \| 'end'`。[see more ts definition](https://github.com/Tencent/tdesign-vue/tree/develop/src/time-picker/type.ts) | N diff --git a/src/time-picker/time-picker.md b/src/time-picker/time-picker.md index 600daccc1..7b35923c5 100644 --- a/src/time-picker/time-picker.md +++ b/src/time-picker/time-picker.md @@ -50,6 +50,7 @@ pick | `(value: TimePickerValue, context: { e: MouseEvent })` | 面板选中值 名称 | 类型 | 默认值 | 描述 | 必传 -- | -- | -- | -- | -- allowInput | Boolean | false | 是否允许直接输入时间 | N +autoSwap | Boolean | true | 是否自动调换左右区间的顺序,默认为 true;若需要支持跨天的场景,可以设置为 false | N borderless | Boolean | false | 无边框模式 | N clearable | Boolean | false | 是否允许清除选中值 | N disableTime | Function | - | 禁用时间项。TS 类型:`(h: number, m: number, s: number, context: { partial: TimeRangePickerPartial }) =>Partial<{ hour: Array, minute: Array, second: Array }>` `type TimeRangePickerPartial = 'start' \| 'end'`。[详细类型定义](https://github.com/Tencent/tdesign-vue/tree/develop/src/time-picker/type.ts) | N diff --git a/src/time-picker/time-range-picker-props.ts b/src/time-picker/time-range-picker-props.ts index 939beaaf6..34184031b 100644 --- a/src/time-picker/time-range-picker-props.ts +++ b/src/time-picker/time-range-picker-props.ts @@ -10,6 +10,11 @@ import { PropType } from 'vue'; export default { /** 是否允许直接输入时间 */ allowInput: Boolean, + /** 是否自动调换左右区间的顺序,默认为 true;若需要支持跨天的场景,可以设置为 false */ + autoSwap: { + type: Boolean, + default: true, + }, /** 无边框模式 */ borderless: Boolean, /** 是否允许清除选中值 */ diff --git a/src/time-picker/time-range-picker.tsx b/src/time-picker/time-range-picker.tsx index 9f1619153..19d5bd81c 100644 --- a/src/time-picker/time-range-picker.tsx +++ b/src/time-picker/time-range-picker.tsx @@ -42,7 +42,6 @@ export default defineComponent({ const currentPanelIdx = ref(undefined); const currentValue = ref>(TIME_PICKER_EMPTY); const isShowPanel = ref(false); - let openedPanels: number[] = []; const inputClasses = computed(() => [ `${componentName.value}__group`, @@ -73,7 +72,6 @@ export default defineComponent({ const handleClick = ({ position }: { position: 'first' | 'second' }) => { currentPanelIdx.value = position === 'first' ? 0 : 1; - openedPanels.push(currentPanelIdx.value); }; const handleTimeChange = (newValue: string) => { @@ -84,18 +82,6 @@ export default defineComponent({ } }; - const setCurrentValue2InnerValue = () => { - const [startTime, endTime] = currentValue.value; - const startDayjs = dayjs(startTime, props.format); - const endDayjs = dayjs(endTime, props.format); - - if (startDayjs.isAfter(endDayjs, 'second')) { - setInnerValue([currentValue.value[1], currentValue.value[0]]); - } else { - setInnerValue([currentValue.value[0], currentValue.value[1]]); - } - }; - const handleInputBlur = (value: TimeRangeValue, { e }: { e: FocusEvent }) => { if (props.allowInput) { const isValidTime = validateInputValue(currentValue.value[currentPanelIdx.value], format.value); @@ -104,7 +90,6 @@ export default defineComponent({ currentPanelIdx.value === 0 ? (currentValue.value = [formattedVal, currentValue.value[1] ?? formattedVal]) : (currentValue.value = [currentValue.value[0] ?? formattedVal, formattedVal]); - setCurrentValue2InnerValue(); } } props.onBlur?.({ value, e }); @@ -120,33 +105,29 @@ export default defineComponent({ }; const handleClickConfirm = () => { - if (openedPanels.length < 2) { - currentPanelIdx.value = currentPanelIdx.value === 1 ? 0 : 1; - openedPanels.push(currentPanelIdx.value); - return; - } - - const noValidIndex = currentValue.value.findIndex((v) => !validateInputValue(v, format.value)); - if (noValidIndex !== -1) { - currentPanelIdx.value = noValidIndex; - openedPanels.push(currentPanelIdx.value); - return; - } - - setCurrentValue2InnerValue(); + const isValidTime = !currentValue.value.find((v) => !validateInputValue(v, format.value)); + if (isValidTime) setInnerValue(currentValue.value); + if (props.autoSwap) autoSwapTime(); isShowPanel.value = false; }; const handleFocus = (value: TimeRangeValue, { e, position }: { e: FocusEvent; position: RangeInputPosition }) => { - const panelIndex = position === 'first' ? 0 : 1; - if (isShowPanel.value && currentPanelIdx.value !== panelIndex) { - currentPanelIdx.value = panelIndex; - openedPanels.push(currentPanelIdx.value); - } props.onFocus?.({ value, e, position: position === 'first' ? 'start' : 'end' }); ctx.emit('focus', { value, e, position: position === 'first' ? 'start' : 'end' }); }; + const autoSwapTime = () => { + const [startTime, endTime] = currentValue.value; + const startDayjs = dayjs(startTime, props.format); + const endDayjs = dayjs(endTime, props.format); + + if (startDayjs.isAfter(endDayjs, 'second')) { + setInnerValue([currentValue.value[1], currentValue.value[0]]); + } else { + setInnerValue([currentValue.value[0], currentValue.value[1]]); + } + }; + const handleOnPick = (pickValue: string, e: MouseEvent) => { let pickedRangeValue = []; let context: { e: MouseEvent; position?: TimeRangePickerPartial } = { e }; @@ -165,10 +146,7 @@ export default defineComponent({ () => isShowPanel.value, () => { currentValue.value = isShowPanel.value ? innerValue.value ?? TIME_PICKER_EMPTY : TIME_PICKER_EMPTY; - if (!isShowPanel.value) { - currentPanelIdx.value = undefined; - openedPanels = []; - } + if (!isShowPanel.value) currentPanelIdx.value = undefined; }, ); return { diff --git a/src/time-picker/type.ts b/src/time-picker/type.ts index 3417b0773..51cc18f73 100644 --- a/src/time-picker/type.ts +++ b/src/time-picker/type.ts @@ -134,6 +134,11 @@ export interface TdTimeRangePickerProps { * @default false */ allowInput?: boolean; + /** + * 是否自动调换左右区间的顺序,默认为 true;若需要支持跨天的场景,可以设置为 false + * @default true + */ + autoSwap?: boolean; /** * 无边框模式 * @default false diff --git a/src/tree/__tests__/expand.test.jsx b/src/tree/__tests__/expand.test.jsx index 21ee9d6fe..f09a116ab 100644 --- a/src/tree/__tests__/expand.test.jsx +++ b/src/tree/__tests__/expand.test.jsx @@ -1,5 +1,6 @@ import { mount } from '@vue/test-utils'; import Tree from '@/src/tree/index.ts'; +import Icon from '@/src/icon/index.ts'; import { delay } from './kit'; import { ref } from './adapt'; @@ -376,6 +377,37 @@ describe('Tree:expand', () => { expect(wrapper.find('[data-value="t1.1"]').exists()).toBe(true); }); + it('自定义图标-点击父节点图标可触发展开子节点', async () => { + const data = [ + { + value: 't1', + children: [ + { + value: 't1.1', + }, + ], + }, + ]; + const wrapper = mount({ + render() { + return }>; + }, + }); + // 测试: 点击一级 一级展开 二级存在 + wrapper.find('[data-value="t1"] .t-tree__icon').trigger('click'); + await delay(10); + const t1d1 = wrapper.find('[data-value="t1.1"]'); + expect(t1d1.attributes('class')).toContain('t-tree__item--visible'); + const t1 = wrapper.find('[data-value="t1"]'); + expect(t1.attributes('class')).toContain('t-tree__item--open'); + + // 测试:点击二级 二级状态不展开 + wrapper.find('[data-value="t1.1"] .t-tree__icon').trigger('click'); + await delay(10); + const t1d1_two = wrapper.find('[data-value="t1.1"]'); + expect(t1d1_two.attributes('class')).not.toContain('t-tree__item--open'); + }); + it('点击已展开的父节点图标,可触发收起子节点', async () => { const data = [ { diff --git a/src/tree/hooks/useTreeAction.ts b/src/tree/hooks/useTreeAction.ts index dd570eb18..286cce1eb 100644 --- a/src/tree/hooks/useTreeAction.ts +++ b/src/tree/hooks/useTreeAction.ts @@ -47,6 +47,9 @@ export default function useTreeAction(state: TypeTreeState) { const toggleExpanded = (item: TypeTargetNode): TreeNodeValue[] => { const node = getNode(store, item); + + if (!node.children) return; + return setExpanded(node, !node.isExpanded()); }; diff --git a/test/snap/__snapshots__/csr.test.js.snap b/test/snap/__snapshots__/csr.test.js.snap index bb3022862..b037fb82b 100644 --- a/test/snap/__snapshots__/csr.test.js.snap +++ b/test/snap/__snapshots__/csr.test.js.snap @@ -93253,7 +93253,6 @@ exports[`csr snapshot test > csr test ./src/select-input/_example/multiple.vue 1 >
renders ./src/select-input/_example/excess-tags-dis exports[`ssr snapshot test > renders ./src/select-input/_example/label-suffix.vue correctly 1`] = `"
前置内容:


单位:元
"`; -exports[`ssr snapshot test > renders ./src/select-input/_example/multiple.vue correctly 1`] = `"
Vue
React
Miniprogram
"`; +exports[`ssr snapshot test > renders ./src/select-input/_example/multiple.vue correctly 1`] = `"
Vue
React
Miniprogram
"`; exports[`ssr snapshot test > renders ./src/select-input/_example/single.vue correctly 1`] = `"
"`;