diff --git a/CHANGELOG.md b/CHANGELOG.md index 199b2d4b3a5..f12109c1f57 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,31 @@ toc: false docClass: timeline --- +## 🌈 1.6.8 `2023-11-07` +### 🚀 Features +- `ImageViewer`: 新增支持 `closeOnEscKeydown`,用于控制是否允许 ESC 退出预览,[#2928](https://github.com/Tencent/tdesign-vue-next/issues/2928) @chaishi ([#3566](https://github.com/Tencent/tdesign-vue-next/pull/3566)) +- `Upload`: @chaishi + - 图片预览功能,新增支持透传图片预览全部属性 `imageViewerProps`,[#2928](https://github.com/Tencent/tdesign-vue-next/issues/2928) ([#3566](https://github.com/Tencent/tdesign-vue-next/pull/3566)) + - ⚠️新增图片上传大小超出限制提醒,有额外单独实现此功能的业务需注意是否存在重复显示大小限制提醒问题,[#2736](https://github.com/Tencent/tdesign-vue-next/issues/2736) ([#3566](https://github.com/Tencent/tdesign-vue-next/pull/3566)) + - 多文件/图片上传场景下,`autoUpload=false` 时,支持使用 Props 属性/函数/插槽等方法自定义上传按钮和取消上传按钮,[#2469](https://github.com/Tencent/tdesign-vue-next/issues/2469) ([#3566](https://github.com/Tencent/tdesign-vue-next/pull/3566)) + - 多文件/图片上传场景下,`autoUpload=false` 时,区分已上传状态和待上传状态,[#2518](https://github.com/Tencent/tdesign-vue-next/issues/2518) ([#3566](https://github.com/Tencent/tdesign-vue-next/pull/3566)) + - 批量文件上传支持在列表中显示上传失败的原因,[#2518](https://github.com/Tencent/tdesign-vue-next/issues/2518) ([#3566](https://github.com/Tencent/tdesign-vue-next/pull/3566)) + - 新增支持 `fileListDisplay=null` 控制单文件或文件列表不显示 ([#3573](https://github.com/Tencent/tdesign-vue-next/pull/3573)) +### 🐞 Bug Fixes +- `Table`: + - 修复 `v1.6.7` 引起的单元格编辑失效问题 @chaishi ([#3577](https://github.com/Tencent/tdesign-vue-next/pull/3577)) + - 多级表头 + 列宽调整场景,修正动态列表头宽度计算错误的问题 @Cat1007 ([#3552](https://github.com/Tencent/tdesign-vue-next/pull/3552)) + - 在提供列配置选项时,默认只提供叶子列作为配置选项,作为最细粒度配置的方式 @Cat1007 ([#3555](https://github.com/Tencent/tdesign-vue-next/pull/3555)) + - 修正列变动时,列宽重置的判断问题 @Cat1007 ([#3568](https://github.com/Tencent/tdesign-vue-next/pull/3568)) + - 修正动态列变化时,表头过小或表头高度更新错误导致意外的滚动条出现的问题 @Cat1007 ([#3557](https://github.com/Tencent/tdesign-vue-next/pull/3557)) +- `TreeSelect`: 处理导入的样式文件异常问题 @betavs ([#3556](https://github.com/Tencent/tdesign-vue-next/pull/3556)) +- `Upload`: @chaishi + - 修复 `max=1 multiple=false` 情况下,无法替换上传文件问题,[#2909](https://github.com/Tencent/tdesign-vue-next/issues/2909) ([#3566](https://github.com/Tencent/tdesign-vue-next/pull/3566)) + - 图片上传场景,修复禁用态卡片无法显示问题 ([#3573](https://github.com/Tencent/tdesign-vue-next/pull/3573)) +- `Tree`: 提供获取树结构数据的 api: getTreeData @TabSpace ([#3571](https://github.com/Tencent/tdesign-vue-next/pull/3571)) +- `Dialog`: 修复以Plugin的方式调用时,更新className会报错并且会覆盖组件的原className。 @Zz-ZzzZ ([#3570](https://github.com/Tencent/tdesign-vue-next/pull/3570)) + + ## 🌈 1.6.7 `2023-11-01` ### 🚀 Features - `Table`: diff --git a/package.json b/package.json index 352b83eb4f1..3dbe9a204a8 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "tdesign-vue-next", "purename": "tdesign", - "version": "1.6.7", + "version": "1.6.8", "title": "tdesign-vue-next", "description": "TDesign Component for vue-next", "keywords": [ diff --git a/src/_common b/src/_common index 56f3acdc7c4..e82c00ea8b2 160000 --- a/src/_common +++ b/src/_common @@ -1 +1 @@ -Subproject commit 56f3acdc7c44c2a1dde6c74deb68f6b952de1a7d +Subproject commit e82c00ea8b279d5d7d8b122068c129ddc63e64ff diff --git a/src/dialog/plugin.tsx b/src/dialog/plugin.tsx index 1d18078b34c..edd496a4f28 100644 --- a/src/dialog/plugin.tsx +++ b/src/dialog/plugin.tsx @@ -2,6 +2,7 @@ import { App, createApp, ref, Plugin, defineComponent, h, onMounted } from 'vue' import DialogComponent from './dialog'; import { getAttach } from '../utils/dom'; import { DialogOptions, DialogMethod, DialogConfirmMethod, DialogAlertMethod, DialogInstance } from './type'; +import omit from 'lodash/omit'; const createDialog: DialogMethod = (props: DialogOptions) => { const options = { ...props }; @@ -50,7 +51,7 @@ const createDialog: DialogMethod = (props: DialogOptions) => { const updateClassNameStyle = (className: string, style: DialogOptions['style']) => { if (className) { - if (preClassName !== className) { + if (preClassName && preClassName !== className) { wrapper.firstElementChild.classList.remove(...preClassName.split(' ').map((name) => name.trim())); } className.split(' ').forEach((name) => { @@ -82,7 +83,8 @@ const createDialog: DialogMethod = (props: DialogOptions) => { visible.value = false; }, update: (newOptions: DialogOptions) => { - dialog.update(newOptions); + // className & style由updateClassNameStyle来处理 + dialog.update(omit(newOptions, ['className', 'style'])); updateClassNameStyle(newOptions.className, newOptions.style); }, destroy: () => { diff --git a/src/hooks/slot.ts b/src/hooks/slot.ts index b0bc26e2230..4dd05d92046 100644 --- a/src/hooks/slot.ts +++ b/src/hooks/slot.ts @@ -1,4 +1,15 @@ -import { Slots, VNode, Component, getCurrentInstance, Fragment, Comment } from 'vue'; +import { + Slots, + VNode, + Component, + getCurrentInstance, + Fragment, + Comment, + RendererNode, + VNodeArrayChildren, + RendererElement, + VNodeChild, +} from 'vue'; import isArray from 'lodash/isArray'; /** @@ -46,7 +57,17 @@ export function useChildComponentSlots() { * @example const getChildSlots = useChildSlots() * @example getChildSlots() */ -export function useChildSlots() { +export function useChildSlots(): () => ( + | VNode< + RendererNode, + RendererElement, + { + [key: string]: any; + } + > + | VNodeArrayChildren + | VNodeChild +)[] { const instance = getCurrentInstance(); return () => { const { slots } = instance; diff --git a/src/table/_example/editable-cell.vue b/src/table/_example/editable-cell.vue index 616b09b0b14..5aae7206068 100644 --- a/src/table/_example/editable-cell.vue +++ b/src/table/_example/editable-cell.vue @@ -99,7 +99,9 @@ const columns = computed(() => [ // 编辑完成,退出编辑态后触发 onEdited: (context) => { console.log(context); - data.value.splice(context.rowIndex, 1, context.newRowData); + const newData = [...data.value]; + newData.splice(context.rowIndex, 1, context.newRowData); + data.value = newData; console.log('Edit firstName:', context); MessagePlugin.success('Success'); }, diff --git a/src/table/hooks/useEditableRow.ts b/src/table/hooks/useEditableRow.ts index 05acfb596b4..60b727aa442 100644 --- a/src/table/hooks/useEditableRow.ts +++ b/src/table/hooks/useEditableRow.ts @@ -180,7 +180,7 @@ export default function useRowEdit(props: PrimaryTableProps) { const getEditRowData = ({ row, col }: PrimaryTableCellParams) => { const rowValue = get(row, props.rowKey || 'id'); const editedRowData = editedFormData.value[rowValue]; - if (editedRowData && props.editableRowKeys.includes(rowValue)) { + if (editedRowData && props.editableRowKeys?.includes(rowValue)) { const tmpRow = { ...editedRowData }; set(tmpRow, col.colKey, get(editedRowData, col.colKey)); return tmpRow; diff --git a/src/tree/__tests__/api.test.jsx b/src/tree/__tests__/api.test.jsx index 773419cf105..8b4aa4d362e 100644 --- a/src/tree/__tests__/api.test.jsx +++ b/src/tree/__tests__/api.test.jsx @@ -945,4 +945,68 @@ describe('Tree:api', () => { expect(pnodes[2].value).toBe('t1.1.1'); }); }); + + // tree.getTreeData + // 获取树结构数据 + describe('getTreeData', () => { + it('获取树结构数据', async () => { + const data = [ + { + value: 't1', + children: [ + { + value: 't1.1', + children: [ + { + value: 't1.1.1', + }, + ], + }, + ], + }, + { + value: 't2', + children: [ + { + value: 't2.1', + children: [ + { + value: 't2.1.1', + }, + ], + }, + ], + }, + ]; + const wrapper = mount({ + render() { + return ; + }, + }); + + const { tree } = wrapper.vm.$refs; + + const pnodes = tree.getTreeData(); + expect(Array.isArray(pnodes)).toBe(true); + expect(pnodes.length).toBe(2); + expect(Array.isArray(pnodes[0].children)).toBe(true); + expect(pnodes[0].children.length).toBe(1); + expect(Array.isArray(pnodes[0].children[0].children)).toBe(true); + expect(pnodes[0].children[0].children[0].value).toBe('t1.1.1'); + expect(pnodes[0].value).toBe('t1'); + expect(pnodes[1].value).toBe('t2'); + + const tnodes = tree.getTreeData('t2.1'); + expect(Array.isArray(tnodes)).toBe(true); + expect(tnodes.length).toBe(1); + expect(Array.isArray(tnodes[0].children)).toBe(true); + expect(tnodes[0].children.length).toBe(1); + expect(tnodes[0].value).toBe('t2.1'); + expect(tnodes[0].children[0].value).toBe('t2.1.1'); + + const nnodes = tree.getTreeData('t2.2'); + expect(Array.isArray(nnodes)).toBe(true); + expect(nnodes.length).toBe(0); + }); + }); }); diff --git a/src/tree/__tests__/event.test.jsx b/src/tree/__tests__/event.test.jsx index 2f67deb5e57..6b27efbbfd3 100644 --- a/src/tree/__tests__/event.test.jsx +++ b/src/tree/__tests__/event.test.jsx @@ -367,10 +367,12 @@ describe('Tree:props:events', () => { }, ]; + const step1 = step(); const loadedValues = []; const onLoad = (context) => { // 这个事件会被触发多次 loadedValues.push(context.node.value); + step1.ready(); }; const loadData = (node) => @@ -406,7 +408,8 @@ describe('Tree:props:events', () => { }, }); - await delay(10); + await delay(1); + await step1; expect(loadedValues[0]).toBe('t1'); }, 300); }); diff --git a/src/tree/_example/checkable.vue b/src/tree/_example/checkable.vue index 9fa383e7c97..4a7e41e0644 100644 --- a/src/tree/_example/checkable.vue +++ b/src/tree/_example/checkable.vue @@ -34,6 +34,97 @@