From 63e87106b7110faa2d609f8c1e69dae3a3e2ebb5 Mon Sep 17 00:00:00 2001 From: anlyyao Date: Mon, 14 Oct 2024 20:39:51 +0800 Subject: [PATCH] fix(Cacader): fixed multiple issues --- .../__test__/__snapshots__/demo.test.jsx.snap | 702 ++++++++---------- .../__snapshots__/index.test.jsx.snap | 57 +- src/cascader/__test__/index.test.jsx | 21 +- src/cascader/cascader.en-US.md | 18 +- src/cascader/cascader.md | 39 +- src/cascader/cascader.tsx | 352 +++++++++ src/cascader/cascader.vue | 359 --------- src/cascader/index.ts | 2 +- src/cascader/props.ts | 16 +- src/cascader/type.ts | 20 +- .../__test__/__snapshots__/demo.test.jsx.snap | 171 ++--- 11 files changed, 817 insertions(+), 940 deletions(-) create mode 100644 src/cascader/cascader.tsx delete mode 100644 src/cascader/cascader.vue diff --git a/src/cascader/__test__/__snapshots__/demo.test.jsx.snap b/src/cascader/__test__/__snapshots__/demo.test.jsx.snap index 93e585d75..061fb5e85 100644 --- a/src/cascader/__test__/__snapshots__/demo.test.jsx.snap +++ b/src/cascader/__test__/__snapshots__/demo.test.jsx.snap @@ -73,9 +73,7 @@ exports[`Cascader > Cascader baseVue demo works fine 1`] = `
- 选择地址 -
Cascader baseVue demo works fine 1`] = `
-
+
+
-
+
-
-
- - 选择选项 - -
- - - + 选择选项
- + + +
- +
- +
Cascader baseVue demo works fine 1`] = ` class="t-cascader__options" >
Cascader checkStrictlyVue demo works fine 1`] = `
- 选择地址 -
Cascader checkStrictlyVue demo works fine 1`] = `
-
+
+
-
+
-
-
- - 选择选项 - -
- - - + 选择选项
- + + +
- +
- +
Cascader checkStrictlyVue demo works fine 1`] = ` class="t-cascader__options" >
Cascader keysVue demo works fine 1`] = `
- 选择地址 -
Cascader keysVue demo works fine 1`] = `
-
+
+
-
+
-
-
- - 选择选项 - -
- - - + 选择选项
- + + +
- +
- +
Cascader keysVue demo works fine 1`] = ` class="t-cascader__options" >
Cascader lazyVue demo works fine 1`] = `
- 选择地址 -
Cascader lazyVue demo works fine 1`] = `
-
+
+
-
+
-
-
- - 选择选项 - -
- - - + 选择选项
- + + +
- +
- +
Cascader lazyVue demo works fine 1`] = ` class="t-cascader__options" >
Cascader mobileVue demo works fine 1`] = `
- 选择地址 -
Cascader mobileVue demo works fine 1`] = `
-
+
+
-
+
-
-
- - 选择选项 - -
- - - + 选择选项
- + + +
- +
- +
Cascader mobileVue demo works fine 1`] = ` class="t-cascader__options" >
Cascader mobileVue demo works fine 1`] = `
- 选择地址 -
Cascader mobileVue demo works fine 1`] = `
-
- - -
- + +
Cascader mobileVue demo works fine 1`] = ` class="t-cascader__options" >
Cascader mobileVue demo works fine 1`] = `
- 选择地址 -
Cascader mobileVue demo works fine 1`] = `
-
+
+
-
+
-
-
- - 选择选项 - -
- - - + 选择选项
- + + +
- +
- +
Cascader mobileVue demo works fine 1`] = ` class="t-cascader__options" >
Cascader mobileVue demo works fine 1`] = `
- 选择地址 -
Cascader mobileVue demo works fine 1`] = `
-
+
+
-
+
-
-
- - 选择选项 - -
- - - + 选择选项
- + + +
- +
- +
Cascader mobileVue demo works fine 1`] = ` class="t-cascader__options" >
Cascader mobileVue demo works fine 1`] = `
- 选择地址 -
Cascader mobileVue demo works fine 1`] = `
-
+
+
-
+
-
-
- - 选择选项 - -
- - - + 选择选项
- + + +
- +
Cascader mobileVue demo works fine 1`] = ` class="t-cascader__options" >
Cascader mobileVue demo works fine 1`] = `
- 选择地址 -
Cascader mobileVue demo works fine 1`] = `
-
+
+
-
+
-
-
- - 选择选项 - -
- - - + 选择选项
- + + +
- +
- +
Cascader mobileVue demo works fine 1`] = ` class="t-cascader__options" >
Cascader mobileVue demo works fine 1`] = `
- 选择地址 -
Cascader mobileVue demo works fine 1`] = `
-
+
+
-
+
-
-
- - 选择选项 - -
- - - + 选择选项
- + + +
- +
- +
Cascader mobileVue demo works fine 1`] = ` class="t-cascader__options" >
Cascader themeTabVue demo works fine 1`] = `
- 选择地址 -
Cascader themeTabVue demo works fine 1`] = `
-
- - -
- + +
Cascader themeTabVue demo works fine 1`] = ` class="t-cascader__options" >
Cascader withTitleVue demo works fine 1`] = `
- 选择地址 -
Cascader withTitleVue demo works fine 1`] = `
-
+
+
-
+
-
-
- - 选择选项 - -
- - - + 选择选项
- + + +
- +
Cascader withTitleVue demo works fine 1`] = ` class="t-cascader__options" >
Cascader withValueVue demo works fine 1`] = `
- 选择地址 -
Cascader withValueVue demo works fine 1`] = `
-
+
+
-
+
-
-
- - 选择选项 - -
- - - + 选择选项
- + + +
- +
- +
Cascader withValueVue demo works fine 1`] = ` class="t-cascader__options" >
events > : pick 1`] = `
- + 标题
events > : pick 1`] = `
-
+
+
-
+
-
-
- - 选择选项 - -
- - - + 选择选项
- + + +
- +
- +
events > : pick 1`] = ` class="t-cascader__options" >
{ describe('props', () => { @@ -202,18 +202,15 @@ describe('cascader', () => { }); it(': title', async () => { - const wrapper = mount(); + const title = TEXT; + const wrapper = mount(); const $title = wrapper.find(`.${name}__title`); - const title = TEXT; const newTitle = 'Cascader 级联选择器'; - await wrapper.setProps({ - title, - }); expect($title.text()).toBe(TEXT); - await wrapper.setProps({ - title: newTitle, - }); + // await wrapper.setProps({ + // title: newTitle, + // }); }); it(': placeholder', async () => { @@ -293,13 +290,13 @@ describe('cascader', () => { const $closeBtn = wrapper.find(`.${name}__close-btn`); await $closeBtn.trigger('click'); expect(onClose).toHaveBeenCalledTimes(1); - expect(onClose).toHaveBeenLastCalledWith({ trigger: 'close-btn' }); + expect(onClose).toHaveBeenLastCalledWith('close-btn'); // overlay const $overlay = wrapper.find(`.${prefix}-overlay`); $overlay.trigger('click'); expect(onClose).toBeCalledTimes(2); - expect(onClose).toHaveBeenLastCalledWith({ trigger: 'overlay' }); + expect(onClose).toHaveBeenLastCalledWith('overlay'); }); it(': pick', async () => { diff --git a/src/cascader/cascader.en-US.md b/src/cascader/cascader.en-US.md index c06e16997..0efa3dc00 100644 --- a/src/cascader/cascader.en-US.md +++ b/src/cascader/cascader.en-US.md @@ -6,31 +6,31 @@ name | type | default | description | required -- | -- | -- | -- | -- +checkStrictly | Boolean | false | \- | N closeBtn | Boolean / Slot / Function | true | Typescript:`boolean \| TNode`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N -keys | Object | - | Typescript:`KeysType`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N +keys | Object | - | Typescript:`CascaderKeysType` `type CascaderKeysType = KeysType`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts)。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/cascader/type.ts) | N options | Array | [] | Typescript:`Array` | N +placeholder | String / Slot / Function | '选择选项' | Typescript:`string \| TNode`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N subTitles | Array | [] | Typescript:`Array` | N -theme | String | step | options:step/tab | N +theme | String | step | options: step/tab | N title | String / Slot / Function | - | Typescript:`string \| TNode`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N value | String / Number | - | `v-model` and `v-model:value` is supported | N defaultValue | String / Number | - | uncontrolled property | N visible | Boolean | false | \- | N -checkStrictly | Boolean | false | 父子节点选中状态不再关联,可各自选中或取消 | N -placeholder | String / Slot / Function | - | Typescript:`string \| TNode`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N -onChange | Function | | Typescript:`(value: string \| number, selectedOptions: string[]) => void`
| N +onChange | Function | | Typescript:`(value: string \| number, selectedOptions: CascaderOption[]) => void`
| N onClose | Function | | Typescript:`(trigger: CascaderTriggerSource) => void`
[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/cascader/type.ts)。
`type CascaderTriggerSource = 'overlay' \| 'close-btn' \| 'finish'`
| N -onPick | Function | | Typescript:`(context: { level: number; value: string | number; index: number }) => void`
| N +onPick | Function | | Typescript:`(context: { level: number, value: string \| number, index: number }) => void`
| N ### Cascader Events name | params | description -- | -- | -- -change | `(value: string \| number, selectedOptions: string[])` | \- +change | `(value: string \| number, selectedOptions: CascaderOption[])` | \- close | `(trigger: CascaderTriggerSource)` | [see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/cascader/type.ts)。
`type CascaderTriggerSource = 'overlay' \| 'close-btn' \| 'finish'`
pick | `(context: { level: number, value: string \| number, index: number })` | \- - ### CSS Variables + The component provides the following CSS variables, which can be used to customize styles. Name | Default Value | Description -- | -- | -- @@ -43,4 +43,4 @@ Name | Default Value | Description --td-cascader-step-dot-size | 8px | - --td-cascader-step-height | 44px | - --td-cascader-title-color | @font-gray-1 | - ---td-cascder-title-font-size | 18px | - +--td-cascder-title-font-size | 18px | - \ No newline at end of file diff --git a/src/cascader/cascader.md b/src/cascader/cascader.md index 5c1e71602..9b42aba21 100644 --- a/src/cascader/cascader.md +++ b/src/cascader/cascader.md @@ -1,22 +1,23 @@ :: BASE_DOC :: ## API + ### Cascader Props -名称 | 类型 | 默认值 | 说明 | 必传 +名称 | 类型 | 默认值 | 描述 | 必传 -- | -- | -- | -- | -- +checkStrictly | Boolean | false | 父子节点选中状态不再关联,可各自选中或取消 | N closeBtn | Boolean / Slot / Function | true | 关闭按钮。TS 类型:`boolean \| TNode`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N -keys | Object | - | 用来定义 value / label 在 `options` 中对应的字段别名。TS 类型:`KeysType`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N +keys | Object | - | 用来定义 value / label 在 `options` 中对应的字段别名。TS 类型:`CascaderKeysType` `type CascaderKeysType = KeysType`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts)。[详细类型定义](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/cascader/type.ts) | N options | Array | [] | 可选项数据源。TS 类型:`Array` | N +placeholder | String / Slot / Function | '选择选项' | 未选中时的提示文案。TS 类型:`string \| TNode`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N subTitles | Array | [] | 每级展示的次标题。TS 类型:`Array` | N theme | String | step | 展示风格。可选项:step/tab | N title | String / Slot / Function | - | 标题。TS 类型:`string \| TNode`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N value | String / Number | - | 选项值。支持语法糖 `v-model` 或 `v-model:value` | N defaultValue | String / Number | - | 选项值。非受控属性 | N visible | Boolean | false | 是否展示 | N -checkStrictly | Boolean | false | 父子节点选中状态不再关联,可各自选中或取消 | N -placeholder | String / Slot / Function | 选择选项 | 未选中时的提示文案。TS 类型:`string \| TNode`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N -onChange | Function | | TS 类型:`(value: string \| number, selectedOptions: string[]) => void`
值发生变更时触发 | N +onChange | Function | | TS 类型:`(value: string \| number, selectedOptions: CascaderOption[]) => void`
值发生变更时触发 | N onClose | Function | | TS 类型:`(trigger: CascaderTriggerSource) => void`
关闭时触发。[详细类型定义](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/cascader/type.ts)。
`type CascaderTriggerSource = 'overlay' \| 'close-btn' \| 'finish'`
| N onPick | Function | | TS 类型:`(context: { level: number, value: string \| number, index: number }) => void`
选择后触发 | N @@ -24,22 +25,22 @@ onPick | Function | | TS 类型:`(context: { level: number, value: string \| 名称 | 参数 | 描述 -- | -- | -- -change | `(value: string \| number, selectedOptions: string[])` | 值发生变更时触发 +change | `(value: string \| number, selectedOptions: CascaderOption[])` | 值发生变更时触发 close | `(trigger: CascaderTriggerSource)` | 关闭时触发。[详细类型定义](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/cascader/type.ts)。
`type CascaderTriggerSource = 'overlay' \| 'close-btn' \| 'finish'`
pick | `(context: { level: number, value: string \| number, index: number })` | 选择后触发 - ### CSS Variables + 组件提供了下列 CSS 变量,可用于自定义样式。 -名称 | 默认值 | 描述 --- | -- | -- ---td-cascader-active-color | @brand-color | - ---td-cascader-border-color | @border-color | - ---td-cascader-disabled-color | @font-gray-4 | - ---td-cascader-options-height | 320px | - ---td-cascader-options-title-color | @font-gray-3 | - ---td-cascader-step-arrow-color | @font-gray-3 | - ---td-cascader-step-dot-size | 8px | - ---td-cascader-step-height | 44px | - ---td-cascader-title-color | @font-gray-1 | - ---td-cascder-title-font-size | 18px | - +| 名称 | 默认值 | 描述 | +| --------------------------------- | ------------- | ---- | +| --td-cascader-active-color | @brand-color | - | +| --td-cascader-border-color | @border-color | - | +| --td-cascader-disabled-color | @font-gray-4 | - | +| --td-cascader-options-height | 320px | - | +| --td-cascader-options-title-color | @font-gray-3 | - | +| --td-cascader-step-arrow-color | @font-gray-3 | - | +| --td-cascader-step-dot-size | 8px | - | +| --td-cascader-step-height | 44px | - | +| --td-cascader-title-color | @font-gray-1 | - | +| --td-cascder-title-font-size | 18px | - | \ No newline at end of file diff --git a/src/cascader/cascader.tsx b/src/cascader/cascader.tsx new file mode 100644 index 000000000..8a7f1a6e3 --- /dev/null +++ b/src/cascader/cascader.tsx @@ -0,0 +1,352 @@ +import { CloseIcon, ChevronRightIcon } from 'tdesign-icons-vue-next'; +import { defineComponent, toRefs, computed, ref, toRaw, reactive, watch, onMounted, Transition } from 'vue'; +import TPopup from '../popup'; +import { Tabs } from '../tabs'; +import { RadioValue, RadioGroup as TRadioGroup } from '../radio'; +import config from '../config'; +import props from './props'; +import { useVModel } from '../shared'; +import { TreeOptionData } from '../common'; +import { useConfig } from '../config-provider/useConfig'; +import { useTNodeJSX } from '../hooks/tnode'; +import { usePrefixClass } from '../hooks/useClass'; +import { CascaderTriggerSource } from './type'; + +const { prefix } = config; +const name = `${prefix}-cascader`; + +interface ChildrenInfoType { + value: string | number | boolean; + level: number; +} + +const childrenInfo: ChildrenInfoType = { + value: '', + level: 0, +}; + +interface KeysType { + value?: string; + label?: string; + children?: string; +} + +export default defineComponent({ + name, + props, + emits: ['update:visible', 'update:value', 'update:modelValue'], + setup(props, context) { + const renderTNodeJSX = useTNodeJSX(); + const cascaderClass = usePrefixClass('cascader'); + const { globalConfig } = useConfig('cascader'); + + const { visible, value, modelValue } = toRefs(props); + const [cascaderValue, setCascaderValue] = useVModel(value, modelValue, props.defaultValue, props.onChange); + + const open = ref(visible.value || false); + const placeholder = computed(() => props.placeholder || globalConfig.value.placeholder); + + const stepIndex = ref(0); + const selectedIndexes = reactive([]); + const selectedValue = reactive([]); + const items: Array> = reactive([props.options ?? []]); + const steps = reactive([placeholder.value]); + + const initWithValue = () => { + if (cascaderValue.value != null) { + steps.length = 0; + selectedValue.length = 0; + selectedIndexes.splice(0, selectedIndexes.length); + + const path = getIndexesByValue(props.options, cascaderValue.value); + path?.forEach((e: number) => { + // @ts-ignore + selectedIndexes.push(e); + }); + watchSelectedIndexes(); + } + }; + + const watchSelectedIndexes = () => { + if (props.options && props.options.length > 0) { + items.splice(0, items.length, ...[props.options]); + + const keys = props.keys as KeysType; + for (let i = 0, size = selectedIndexes.length; i < size; i += 1) { + const index = selectedIndexes[i]; + const next = items[i]?.[index]; + selectedValue.push(next[keys?.value ?? 'value']); + steps.push(next[keys?.label ?? 'label']); + if (next[keys?.children ?? 'children']) { + items.push(next[keys?.children ?? 'children']); + } + } + } + + if (steps.length < items.length) { + steps.push(placeholder.value); + } + stepIndex.value = items.length - 1; + }; + + const getIndexesByValue = (options: any, value: any) => { + const keys = props.keys as KeysType; + for (let i = 0; i < options.length; i++) { + if (options[i][keys?.value ?? 'value'] === value) { + return [i]; + } + if (options[i][keys?.children ?? 'children']) { + const res: any = getIndexesByValue(options[i][keys?.children ?? 'children'], value); + if (res) { + return [i, ...res]; + } + } + } + }; + + const chooseSelect = (value: RadioValue, level: number, index: number, item: any) => { + const keys = props.keys as KeysType; + selectedIndexes[level] = index; + selectedIndexes.length = level + 1; + selectedValue[level] = String(value); + selectedValue.length = level + 1; + steps[level] = item[keys?.label ?? 'label'] as string; + if (item[keys?.children ?? 'children']?.length) { + items[level + 1] = item[keys?.children ?? 'children']; + items.length = level + 2; + stepIndex.value += 1; + steps[level + 1] = placeholder.value; + steps.length = level + 2; + } else if (item[keys?.children ?? 'children']?.length === 0) { + childrenInfo.value = value; + childrenInfo.level = level; + } else { + setCascaderValue( + item[keys?.value ?? 'value'], + items.map((item, index) => toRaw(item?.[selectedIndexes[index]])), + ); + close('finish'); + } + }; + + const cancelSelect = (value: RadioValue, level: number, index: number, item: any) => { + const keys = props.keys as KeysType; + selectedIndexes[level] = index; + selectedIndexes.length = level; + selectedValue.length = level; + steps[level] = String(placeholder.value); + steps[level + 1] = placeholder.value; + steps.length = level + 1; + + if (item[keys?.children ?? 'children']?.length) { + items[level + 1] = item[keys?.children ?? 'children']; + } else if (item[keys?.children ?? 'children']?.length === 0) { + childrenInfo.value = value; + childrenInfo.level = level; + } + }; + + const handleSelect = (value: RadioValue, level: number) => { + const keys = props.keys as KeysType; + const index = items[level].findIndex((item: any) => item[keys?.value ?? 'value'] === value); + const item = items[level][index]; + if (item.disabled) { + return; + } + props.onPick?.({ level, value: item[keys?.value ?? 'value'], index }); + + if (props.checkStrictly && selectedValue.includes(String(value))) { + cancelSelect(value, level, index, item); + } else { + chooseSelect(value, level, index, item); + } + }; + + const close = (trigger: CascaderTriggerSource) => { + props.onClose?.(trigger); + }; + + const handleVisibleChange = (visible: boolean, e: any) => { + if (e?.trigger !== 'overlay') return; + close('overlay'); + }; + + const updateCascaderValue = () => { + setCascaderValue( + selectedValue[selectedValue.length - 1], + items + .filter((item, index) => !!item && selectedIndexes.length > index) + .map((item, index) => toRaw(item?.[selectedIndexes[index]])), + ); + }; + + const onClose = () => { + open.value = false; + close('close-btn'); + }; + + const onCloseBtn = () => { + if (props.checkStrictly) { + updateCascaderValue(); + onClose(); + } else { + onClose(); + } + }; + + const onStepClick = (index: number) => { + stepIndex.value = index; + }; + + const onTabChange = (value: number | string) => { + stepIndex.value = Number(value); + }; + + watch(open, () => { + context.emit('update:visible', open.value); + }); + + watch(visible, () => { + open.value = visible.value; + if (visible.value) { + initWithValue(); + } + }); + + watch( + () => props.options, + () => { + items.splice(0, items.length, ...[props.options ?? []]); + + if (open.value) { + handleSelect(childrenInfo.value, childrenInfo.level); + } + }, + { + deep: true, + }, + ); + + watch(placeholder, (newValue, oldValue) => { + const index = steps.indexOf(oldValue); + if (index !== -1) { + steps[index] = newValue; + } + }); + + onMounted(() => { + initWithValue(); + }); + + return () => { + const title = renderTNodeJSX('title') || globalConfig.value.title; + const closeBtn = renderTNodeJSX('closeBtn', { defaultNode: }); + const PlaceholderNode = renderTNodeJSX('placeholder'); + + const readerStep = () => { + return ( +
+ {steps.map((step, index) => { + return ( +
{ + onStepClick(index); + }} + > +
+
+ {PlaceholderNode && !(typeof PlaceholderNode === 'string') && step === placeholder.value + ? PlaceholderNode + : step} +
+ +
+ ); + })} +
+ ); + }; + + const renderTabStep = () => { + const _steps = steps.map((item, index) => ({ value: index, label: item })); + return ; + }; + + const readerSteps = () => { + if (steps.length === 0) { + return null; + } + if (props.theme === 'step') { + return readerStep(); + } + + if (open.value && props.theme === 'tab') { + return renderTabStep(); + } + }; + return ( + +
+
{title}
+
+ {closeBtn} +
+
+ {readerSteps()} + {props.subTitles && props.subTitles[stepIndex.value] && ( +
{props.subTitles[stepIndex.value]}
+ )} +
+ {items.map((options, index) => { + return ( +
+ +
+ { + handleSelect(value, index); + }} + /> +
+
+
+ ); + })} +
+
+
+
+ ); + }; + }, +}); diff --git a/src/cascader/cascader.vue b/src/cascader/cascader.vue deleted file mode 100644 index c74b51233..000000000 --- a/src/cascader/cascader.vue +++ /dev/null @@ -1,359 +0,0 @@ - - - diff --git a/src/cascader/index.ts b/src/cascader/index.ts index 7b73f85e0..f435e7399 100644 --- a/src/cascader/index.ts +++ b/src/cascader/index.ts @@ -1,4 +1,4 @@ -import _Cascader from './cascader.vue'; +import _Cascader from './cascader'; import { withInstall, WithInstallType } from '../shared'; import './style'; diff --git a/src/cascader/props.ts b/src/cascader/props.ts index dedacc5be..139549f27 100644 --- a/src/cascader/props.ts +++ b/src/cascader/props.ts @@ -8,6 +8,8 @@ import { TdCascaderProps } from './type'; import { PropType } from 'vue'; export default { + /** 父子节点选中状态不再关联,可各自选中或取消 */ + checkStrictly: Boolean, /** 关闭按钮 */ closeBtn: { type: [Boolean, Function] as PropType, @@ -22,6 +24,11 @@ export default { type: Array as PropType, default: (): TdCascaderProps['options'] => [], }, + /** 未选中时的提示文案 */ + placeholder: { + type: [String, Function] as PropType, + default: '选择选项', + }, /** 每级展示的次标题 */ subTitles: { type: Array as PropType, @@ -53,17 +60,8 @@ export default { defaultValue: { type: [String, Number] as PropType, }, - /** 未选中时的提示文案 */ - placeholder: { - type: [String, Function] as PropType, - }, /** 是否展示 */ visible: Boolean, - /** 父子节点选中状态不再关联,可各自选中或取消 */ - checkStrictly: { - type: Boolean, - default: false, - }, /** 值发生变更时触发 */ onChange: Function as PropType, /** 关闭时触发 */ diff --git a/src/cascader/type.ts b/src/cascader/type.ts index cabfa983a..035797c0d 100644 --- a/src/cascader/type.ts +++ b/src/cascader/type.ts @@ -7,6 +7,11 @@ import { TNode, TreeOptionData, KeysType } from '../common'; export interface TdCascaderProps { + /** + * 父子节点选中状态不再关联,可各自选中或取消 + * @default false + */ + checkStrictly?: boolean; /** * 关闭按钮 * @default true @@ -15,12 +20,17 @@ export interface TdCascaderProps; + /** + * 未选中时的提示文案 + * @default '选择选项' + */ + placeholder?: string | TNode; /** * 每级展示的次标题 * @default [] @@ -52,14 +62,10 @@ export interface TdCascaderProps void; + onChange?: (value: string | number, selectedOptions: CascaderOption[]) => void; /** * 关闭时触发 */ @@ -70,4 +76,6 @@ export interface TdCascaderProps void; } +export type CascaderKeysType = KeysType; + export type CascaderTriggerSource = 'overlay' | 'close-btn' | 'finish'; diff --git a/src/form/__test__/__snapshots__/demo.test.jsx.snap b/src/form/__test__/__snapshots__/demo.test.jsx.snap index d7dabbbe1..6fea87464 100644 --- a/src/form/__test__/__snapshots__/demo.test.jsx.snap +++ b/src/form/__test__/__snapshots__/demo.test.jsx.snap @@ -811,9 +811,7 @@ exports[`Form > Form horizontalVue demo works fine 1`] = `
- 选择地址 -
Form horizontalVue demo works fine 1`] = `
-
+
+
-
+
-
-
- - 选择选项 - -
- - - + 选择选项
- + + +
- +
- +
Form horizontalVue demo works fine 1`] = ` class="t-cascader__options" >
Form mobileVue demo works fine 1`] = `
- 选择地址 -
Form mobileVue demo works fine 1`] = `
-
+
+
-
+
-
-
- - 选择选项 - -
- - - + 选择选项
- + + +
- +
- +
Form mobileVue demo works fine 1`] = ` class="t-cascader__options" >
Form verticalVue demo works fine 1`] = `
- 选择地址 -
Form verticalVue demo works fine 1`] = `
-
+
+
-
+
-
-
- - 选择选项 - -
- - - + 选择选项
- + + +
- +
- +
Form verticalVue demo works fine 1`] = ` class="t-cascader__options" >