From 8eab666986ab3664b4a9078d5561b56abab4fd3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E5=AE=87=E9=98=B3?= Date: Mon, 26 Aug 2024 13:31:46 +0800 Subject: [PATCH 1/5] fix(TimePicker): fixed only support hh:mm format --- src/time-picker/__tests__/index.test.jsx | 8 ++++ src/time-picker/panel/single-panel.tsx | 51 +++++++++++++++--------- 2 files changed, 41 insertions(+), 18 deletions(-) diff --git a/src/time-picker/__tests__/index.test.jsx b/src/time-picker/__tests__/index.test.jsx index 256afd20f..6f40a87b8 100644 --- a/src/time-picker/__tests__/index.test.jsx +++ b/src/time-picker/__tests__/index.test.jsx @@ -76,6 +76,14 @@ describe('TimePicker', () => { const panelNode = document.querySelector('.t-time-picker__panel'); // format为HH:mm 只展示两列 即时分 expect(panelNode.querySelectorAll('.t-time-picker__panel-body-scroll').length).toBe(2); + + await wrapper.setProps({ + popupProps: { + visible: true, + }, + format: 'HH时mm分', + }); + expect(panelNode.querySelectorAll('.t-time-picker__panel-body-scroll').length).toBe(2); panelNode.parentNode.removeChild(panelNode); }); diff --git a/src/time-picker/panel/single-panel.tsx b/src/time-picker/panel/single-panel.tsx index 5dacb513d..f600248cb 100644 --- a/src/time-picker/panel/single-panel.tsx +++ b/src/time-picker/panel/single-panel.tsx @@ -9,12 +9,7 @@ import customParseFormat from 'dayjs/plugin/customParseFormat'; import { panelColProps } from './props'; import { - EPickerCols, - TWELVE_HOUR_FORMAT, - TIME_FORMAT, - AM, - PM, - MERIDIEM_LIST, + EPickerCols, TWELVE_HOUR_FORMAT, AM, PM, MERIDIEM_LIST, } from '../../_common/js/time-picker/const'; import { closestLookup } from '../../_common/js/time-picker/utils'; import { useConfig } from '../../hooks/useConfig'; @@ -28,6 +23,8 @@ const panelOffset = { bottom: 21, }; +export const REGEX_FORMAT = /\[([^\]]+)]|Y{1,4}|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|Z{1,2}|SSS/g; + export default defineComponent({ name: 'TTimePickerPanelCol', props: { @@ -82,22 +79,40 @@ export default defineComponent({ ); onMounted(() => { - const match = format.value.match(TIME_FORMAT); - - const [, startCol, hourCol, minuteCol, secondCol, milliSecondCol, endCol] = match; + const match = format.value.match(REGEX_FORMAT); const { meridiem, hour, minute, second, milliSecond, } = EPickerCols; - const renderCol = [ - startCol && meridiem, - hourCol && hour, - minuteCol && minute, - secondCol && second, - milliSecondCol && milliSecond, - endCol && meridiem, - ].filter((v) => !!v); - + const renderCol: EPickerCols[] = []; + + match.forEach((m) => { + switch (m) { + case 'H': + case 'HH': + case 'h': + case 'hh': + renderCol.push(hour); + break; + case 'a': + case 'A': + renderCol.push(meridiem); + break; + case 'm': + case 'mm': + renderCol.push(minute); + break; + case 's': + case 'ss': + renderCol.push(second); + break; + case 'SSS': + renderCol.push(milliSecond); + break; + default: + break; + } + }); cols.value = renderCol; }); From c44f9db7febb40593c113d29a6370c08f70ba3cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E5=AE=87=E9=98=B3?= Date: Tue, 27 Aug 2024 12:40:28 +0800 Subject: [PATCH 2/5] fix(TimePicker): disabled position only is start --- src/time-picker/panel/props.ts | 1 + src/time-picker/panel/time-picker-panel.tsx | 1 + 2 files changed, 2 insertions(+) diff --git a/src/time-picker/panel/props.ts b/src/time-picker/panel/props.ts index 7daa564d0..96c3b8e38 100644 --- a/src/time-picker/panel/props.ts +++ b/src/time-picker/panel/props.ts @@ -20,6 +20,7 @@ export const panelProps = () => ({ type: String, default: 'HH:mm:ss', }, + position: String, steps: { type: Array as PropType>, default: () => [1, 1, 1], diff --git a/src/time-picker/panel/time-picker-panel.tsx b/src/time-picker/panel/time-picker-panel.tsx index cee0d92d3..d9dce7406 100644 --- a/src/time-picker/panel/time-picker-panel.tsx +++ b/src/time-picker/panel/time-picker-panel.tsx @@ -109,6 +109,7 @@ export default defineComponent({ steps: this.steps || DEFAULT_STEPS, triggerScroll: this.triggerScroll, disableTime: this.disableTime, + position: this.position, resetTriggerScroll: this.resetTriggerScroll, isShowPanel: this.isShowPanel, hideDisabledTime: this.hideDisabledTime, From d5baa7d4450c18f2c91a2b4a415bff64fb78c944 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E5=AE=87=E9=98=B3?= Date: Thu, 5 Sep 2024 19:38:39 +0800 Subject: [PATCH 3/5] fix(Upload): fixed vue error on uploadPastedFiles is false --- src/upload/upload.tsx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/upload/upload.tsx b/src/upload/upload.tsx index 90d1a338b..b1d75b402 100644 --- a/src/upload/upload.tsx +++ b/src/upload/upload.tsx @@ -94,9 +94,15 @@ export default defineComponent({ }, ]); + const handlePasteFileChange = (e: ClipboardEvent) => { + if (props.uploadPastedFiles) { + onPasteFileChange(e); + } + }; + return { ...uploadData, - onPasteFileChange, + handlePasteFileChange, commonDisplayFileProps, dragProps, uploadClasses, @@ -246,7 +252,7 @@ export default defineComponent({ render() { return ( -
+
Date: Wed, 11 Sep 2024 12:26:28 +0800 Subject: [PATCH 4/5] docs: add readonly in api --- src/date-picker/date-picker.en-US.md | 1 + src/date-picker/date-picker.md | 1 + src/time-picker/time-picker.en-US.md | 1 + src/time-picker/time-picker.md | 1 + 4 files changed, 4 insertions(+) diff --git a/src/date-picker/date-picker.en-US.md b/src/date-picker/date-picker.en-US.md index a04cb7b39..21a45eb56 100644 --- a/src/date-picker/date-picker.en-US.md +++ b/src/date-picker/date-picker.en-US.md @@ -23,6 +23,7 @@ popupProps | Object | - | Typescript:`PopupProps`,[Popup API Documents](./po prefixIcon | Slot / Function | - | Typescript:`TNode`。[see more ts definition](https://github.com/Tencent/tdesign-vue/blob/develop/src/common.ts) | N presets | Object | - | Typescript:`PresetDate` `interface PresetDate { [name: string]: DateValue \| (() => DateValue) }`。[see more ts definition](https://github.com/Tencent/tdesign-vue/tree/develop/src/date-picker/type.ts) | N presetsPlacement | String | bottom | options: left/top/right/bottom | N +readonly | Boolean | false | \- | N size | String | medium | options: small/medium/large。Typescript:`SizeEnum`。[see more ts definition](https://github.com/Tencent/tdesign-vue/blob/develop/src/common.ts) | N 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 diff --git a/src/date-picker/date-picker.md b/src/date-picker/date-picker.md index c2a07f3be..54c693dd3 100644 --- a/src/date-picker/date-picker.md +++ b/src/date-picker/date-picker.md @@ -23,6 +23,7 @@ popupProps | Object | - | 透传给 popup 组件的参数。TS 类型:`PopupPr prefixIcon | Slot / Function | - | 用于自定义组件前置图标。TS 类型:`TNode`。[通用类型定义](https://github.com/Tencent/tdesign-vue/blob/develop/src/common.ts) | N presets | Object | - | 预设快捷日期选择,示例:`{ '元旦': '2021-01-01', '昨天': dayjs().subtract(1, 'day').format('YYYY-MM-DD'), '特定日期': () => ['2021-02-01'] }`。TS 类型:`PresetDate` `interface PresetDate { [name: string]: DateValue \| (() => DateValue) }`。[详细类型定义](https://github.com/Tencent/tdesign-vue/tree/develop/src/date-picker/type.ts) | N presetsPlacement | String | bottom | 预设面板展示区域(包含确定按钮)。可选项:left/top/right/bottom | N +readonly | Boolean | false | 只读状态,值为真会隐藏输入框,且无法打开下拉框 | N size | String | medium | 输入框尺寸。可选项:small/medium/large。TS 类型:`SizeEnum`。[通用类型定义](https://github.com/Tencent/tdesign-vue/blob/develop/src/common.ts) | N status | String | default | 输入框状态。可选项:default/success/warning/error | N suffixIcon | Slot / Function | - | 用于自定义组件后置图标。TS 类型:`TNode`。[通用类型定义](https://github.com/Tencent/tdesign-vue/blob/develop/src/common.ts) | N diff --git a/src/time-picker/time-picker.en-US.md b/src/time-picker/time-picker.en-US.md index 3c9145352..0591185e9 100644 --- a/src/time-picker/time-picker.en-US.md +++ b/src/time-picker/time-picker.en-US.md @@ -17,6 +17,7 @@ inputProps | Object | - | Typescript:`InputProps`,[Input API Documents](./in placeholder | String | undefined | \- | N popupProps | Object | - | Typescript:`PopupProps`,[Popup API Documents](./popup?tab=api)。[see more ts definition](https://github.com/Tencent/tdesign-vue/tree/develop/src/time-picker/type.ts) | N presets | Object | - | Typescript:`PresetTime` `interface PresetTime { [presetName: string]: TimePickerValue \| (() => TimePickerValue) }`。[see more ts definition](https://github.com/Tencent/tdesign-vue/tree/develop/src/time-picker/type.ts) | N +readonly | Boolean | false | \- | N size | String | medium | options: small/medium/large | N status | String | default | options: default/success/warning/error | N steps | Array | [1, 1, 1] | Typescript:`Array` | N diff --git a/src/time-picker/time-picker.md b/src/time-picker/time-picker.md index 592d08ed2..600daccc1 100644 --- a/src/time-picker/time-picker.md +++ b/src/time-picker/time-picker.md @@ -17,6 +17,7 @@ inputProps | Object | - | 透传给输入框(Input)组件的参数。TS 类 placeholder | String | undefined | 占位符 | N popupProps | Object | - | 透传给 popup 组件的参数。TS 类型:`PopupProps`,[Popup API Documents](./popup?tab=api)。[详细类型定义](https://github.com/Tencent/tdesign-vue/tree/develop/src/time-picker/type.ts) | N presets | Object | - | 预设快捷时间选择,示例:`{ '前一小时': '11:00:00' }`。TS 类型:`PresetTime` `interface PresetTime { [presetName: string]: TimePickerValue \| (() => TimePickerValue) }`。[详细类型定义](https://github.com/Tencent/tdesign-vue/tree/develop/src/time-picker/type.ts) | N +readonly | Boolean | false | 只读状态,值为真会隐藏输入框,且无法打开下拉框 | N size | String | medium | 尺寸。可选项:small/medium/large | N status | String | default | 输入框状态。可选项:default/success/warning/error | N steps | Array | [1, 1, 1] | 时间间隔步数,数组排列 [小时, 分钟, 秒],示例:[2, 1, 1] 或者 ['2', '1', '1']。TS 类型:`Array` | N From bb2e7e6f23c895944f0725bf6bfc812fb9a6fbac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E5=AE=87=E9=98=B3?= Date: Sun, 15 Sep 2024 16:05:02 +0800 Subject: [PATCH 5/5] fix: check component change tag to name --- src/checkbox/__tests__/index.test.jsx | 14 +++++++++----- src/checkbox/group.tsx | 4 +++- src/list/hooks/useListItem.ts | 5 ++++- src/select/hooks/useSelectOptions.ts | 8 ++++++-- src/tabs/tabs.tsx | 7 ++++--- src/utils/helper.ts | 9 +++++++++ 6 files changed, 35 insertions(+), 12 deletions(-) diff --git a/src/checkbox/__tests__/index.test.jsx b/src/checkbox/__tests__/index.test.jsx index 0d22fdbcd..a7d94b062 100644 --- a/src/checkbox/__tests__/index.test.jsx +++ b/src/checkbox/__tests__/index.test.jsx @@ -157,14 +157,18 @@ describe('Checkbox CheckboxGroup', () => { describe('@event', () => { it('Event passthrough', async () => { const wrapper = mount({ + components: { + ACheckboxGroup: CheckboxGroup, + ACheckbox: Checkbox, + }, render() { return ( - - 广州 - + + 广州 + 深圳 - - + + ); }, }); diff --git a/src/checkbox/group.tsx b/src/checkbox/group.tsx index c93f01527..d67781b79 100644 --- a/src/checkbox/group.tsx +++ b/src/checkbox/group.tsx @@ -13,6 +13,7 @@ import intersection from 'lodash/intersection'; import isObject from 'lodash/isObject'; import isUndefined from 'lodash/isUndefined'; import { VNode } from 'vue'; +import { getVNodeComponentName, getVueComponentName } from '../utils/helper'; import Checkbox from './checkbox'; import props from './checkbox-group-props'; import { CheckboxOptionObj, TdCheckboxProps, CheckboxGroupValue } from './type'; @@ -196,7 +197,8 @@ export default defineComponent({ if (!nodes) return; for (let i = 0, len = nodes.length; i < len; i++) { const vNode = nodes[i]; - if (vNode.componentOptions && /TCheckbox/.test(vNode.tag)) { + const componentName = getVNodeComponentName(vNode); + if (vNode.componentOptions && componentName && componentName === getVueComponentName(Checkbox)) { (vNode.componentOptions.propsData as any).storeKey = storeKey; } if (vNode.children?.length) { diff --git a/src/list/hooks/useListItem.ts b/src/list/hooks/useListItem.ts index 4d4b1fb4c..424023a49 100644 --- a/src/list/hooks/useListItem.ts +++ b/src/list/hooks/useListItem.ts @@ -1,5 +1,7 @@ import { VNode } from 'vue'; import { computed, getCurrentInstance } from '@vue/composition-api'; +import { getVNodeComponentName, getVueComponentName } from '../../utils/helper'; +import ListItem from '../list-item'; const useListItems = () => { const instance = getCurrentInstance(); @@ -8,7 +10,8 @@ const useListItems = () => { const listItems = computed(() => { const computedListItems: VNode[] = []; currentSlots.forEach((child) => { - if (child.componentOptions?.tag === 't-list-item') { + const componentName = getVNodeComponentName(child); + if (componentName && componentName === getVueComponentName(ListItem)) { computedListItems.push({ class: child.data.staticClass, style: child.data.staticStyle, diff --git a/src/select/hooks/useSelectOptions.ts b/src/select/hooks/useSelectOptions.ts index e451d8695..4a65db414 100644 --- a/src/select/hooks/useSelectOptions.ts +++ b/src/select/hooks/useSelectOptions.ts @@ -8,6 +8,9 @@ import { } from '@vue/composition-api'; import { VNode } from 'vue'; import get from 'lodash/get'; +import { getVNodeComponentName, getVueComponentName } from '../../utils/helper'; +import Option from '../option'; +import OptionGroup from '../optionGroup'; import { TdSelectProps, TdOptionProps, SelectOptionGroup, SelectValue, } from '../type'; @@ -62,7 +65,8 @@ export default function useSelectOptions( // 处理 slots 中 t-option 与 t-option-group const currentSlots = instance.proxy.$slots.default || []; currentSlots.forEach((child) => { - if (child.componentOptions?.tag === 't-option') { + const componentName = getVNodeComponentName(child); + if (componentName && componentName === getVueComponentName(Option)) { // 独立选项 innerOptions.push({ // 单独处理 style 和 class 参数的透传 @@ -74,7 +78,7 @@ export default function useSelectOptions( index: dynamicIndex, } as TdOptionProps); dynamicIndex += 1; - } else if (child.componentOptions?.tag === 't-option-group') { + } else if (componentName && componentName === getVueComponentName(OptionGroup)) { // 分组选项 const groupOption = { group: (child.componentOptions.propsData as TdOptionProps)?.label, diff --git a/src/tabs/tabs.tsx b/src/tabs/tabs.tsx index af81ad1b1..54092198a 100644 --- a/src/tabs/tabs.tsx +++ b/src/tabs/tabs.tsx @@ -1,5 +1,5 @@ import Vue, { VNode, VueConstructor } from 'vue'; -import kebabCase from 'lodash/kebabCase'; +import { getVNodeComponentName, getVueComponentName } from '../utils/helper'; import props from './props'; import TTabPanel from './tab-panel'; import TTabNav from './tab-nav'; @@ -68,9 +68,10 @@ export default mixins(Vue as VueConstructor, classPrefixMixi return; } const newPanels = this.listPanels + .filter((child) => getVNodeComponentName(child) === getVueComponentName(TTabPanel)) .map((panel: VNode) => panel.componentInstance as InstanceType) - .filter(Boolean) - .filter((child) => kebabCase(child?.$vnode?.tag).endsWith('t-tab-panel')); // 不可用classPrefix替换 此处是判断组件tag + .filter(Boolean); + const isUnchanged = () => newPanels.length === this.panels.length && this.panels.every((panel, index) => panel === newPanels[index]); if (isUnchanged() && !force) return; this.panels = newPanels; diff --git a/src/utils/helper.ts b/src/utils/helper.ts index 624700193..63966f05d 100644 --- a/src/utils/helper.ts +++ b/src/utils/helper.ts @@ -1,4 +1,5 @@ import camelCase from 'lodash/camelCase'; +import type { VNode } from 'vue'; export function omit(obj: object, fields: string[]): object { const shallowCopy = { @@ -153,3 +154,11 @@ export function setTransform(value: string): object { '-webkit-transform': value, }; } + +export function getVueComponentName(component: any) { + return component?.options?.name || component?.name; +} + +export function getVNodeComponentName(vnode: VNode) { + return (vnode?.componentOptions?.Ctor as any)?.options?.name; +}