From ab1543cf3a11e00610f37967f79ee5d2cce2dec1 Mon Sep 17 00:00:00 2001 From: neverland Date: Fri, 15 Oct 2021 17:53:04 +0800 Subject: [PATCH] types(Cascader): add CascaderProps type (#9684) --- packages/vant/src/cascader/Cascader.tsx | 119 +++++++++------------ packages/vant/src/cascader/README.md | 2 +- packages/vant/src/cascader/README.zh-CN.md | 2 +- packages/vant/src/cascader/index.ts | 5 +- packages/vant/src/cascader/types.ts | 21 ++++ 5 files changed, 79 insertions(+), 70 deletions(-) create mode 100644 packages/vant/src/cascader/types.ts diff --git a/packages/vant/src/cascader/Cascader.tsx b/packages/vant/src/cascader/Cascader.tsx index 0493a79b0..25833afcd 100644 --- a/packages/vant/src/cascader/Cascader.tsx +++ b/packages/vant/src/cascader/Cascader.tsx @@ -1,4 +1,11 @@ -import { nextTick, PropType, reactive, watch, defineComponent } from 'vue'; +import { + ref, + watch, + nextTick, + PropType, + defineComponent, + ExtractPropTypes, +} from 'vue'; import { extend, truthProp, @@ -15,53 +22,34 @@ import { Icon } from '../icon'; // Types import type { TabsClickTabEventParams } from '../tabs/types'; +import type { CascaderTab, CascaderOption, CascaderFieldNames } from './types'; const [name, bem, t] = createNamespace('cascader'); -export type CascaderOption = { - text?: string; - value?: string | number; - color?: string; - disabled?: boolean; - children?: CascaderOption[]; - className?: unknown; - // for custom filed names - [key: PropertyKey]: any; +const props = { + title: String, + options: makeArrayProp(), + closeable: truthProp, + swipeable: truthProp, + closeIcon: makeStringProp('cross'), + modelValue: numericProp, + fieldNames: Object as PropType, + placeholder: String, + activeColor: String, }; -type CascaderTab = { - options: CascaderOption[]; - selected: CascaderOption | null; -}; - -export type CascaderFieldNames = { - text?: string; - value?: string; - children?: string; -}; +export type CascaderProps = ExtractPropTypes; export default defineComponent({ name, - props: { - title: String, - options: makeArrayProp(), - closeable: truthProp, - swipeable: truthProp, - closeIcon: makeStringProp('cross'), - modelValue: numericProp, - fieldNames: Object as PropType, - placeholder: String, - activeColor: String, - }, + props, - emits: ['close', 'change', 'finish', 'update:modelValue', 'click-tab'], + emits: ['close', 'change', 'finish', 'click-tab', 'update:modelValue'], setup(props, { slots, emit }) { - const state = reactive({ - tabs: [] as CascaderTab[], - activeTab: 0, - }); + const tabs = ref([]); + const activeTab = ref(0); const { text: textKey, @@ -98,16 +86,15 @@ export default defineComponent({ }; const updateTabs = () => { - if (props.modelValue || props.modelValue === 0) { - const selectedOptions = getSelectedOptionsByValue( - props.options, - props.modelValue - ); + const { options, modelValue } = props; + + if (modelValue !== undefined) { + const selectedOptions = getSelectedOptionsByValue(options, modelValue); if (selectedOptions) { - let optionsCursor = props.options; + let optionsCursor = options; - state.tabs = selectedOptions.map((option) => { + tabs.value = selectedOptions.map((option) => { const tab = { options: optionsCursor, selected: option, @@ -124,23 +111,23 @@ export default defineComponent({ }); if (optionsCursor) { - state.tabs.push({ + tabs.value.push({ options: optionsCursor, selected: null, }); } nextTick(() => { - state.activeTab = state.tabs.length - 1; + activeTab.value = tabs.value.length - 1; }); return; } } - state.tabs = [ + tabs.value = [ { - options: props.options, + options, selected: null, }, ]; @@ -151,10 +138,10 @@ export default defineComponent({ return; } - state.tabs[tabIndex].selected = option; + tabs.value[tabIndex].selected = option; - if (state.tabs.length > tabIndex + 1) { - state.tabs = state.tabs.slice(0, tabIndex + 1); + if (tabs.value.length > tabIndex + 1) { + tabs.value = tabs.value.slice(0, tabIndex + 1); } if (option[childrenKey]) { @@ -163,31 +150,32 @@ export default defineComponent({ selected: null, }; - if (state.tabs[tabIndex + 1]) { - state.tabs[tabIndex + 1] = nextTab; + if (tabs.value[tabIndex + 1]) { + tabs.value[tabIndex + 1] = nextTab; } else { - state.tabs.push(nextTab); + tabs.value.push(nextTab); } nextTick(() => { - state.activeTab++; + activeTab.value++; }); } - const selectedOptions = state.tabs + const selectedOptions = tabs.value .map((tab) => tab.selected) .filter(Boolean); - const eventParams = { + emit('update:modelValue', option[valueKey]); + + const params = { value: option[valueKey], tabIndex, selectedOptions, }; - emit('update:modelValue', option[valueKey]); - emit('change', eventParams); + emit('change', params); if (!option[childrenKey]) { - emit('finish', eventParams); + emit('finish', params); } }; @@ -260,9 +248,8 @@ export default defineComponent({ const renderTab = (tab: CascaderTab, tabIndex: number) => { const { options, selected } = tab; - const title = selected - ? selected[textKey] - : props.placeholder || t('select'); + const placeholder = props.placeholder || t('select'); + const title = selected ? selected[textKey] : placeholder; return ( ( - {state.tabs.map(renderTab)} + {tabs.value.map(renderTab)} ); @@ -296,8 +283,8 @@ export default defineComponent({ watch( () => props.modelValue, (value) => { - if (value || value === 0) { - const values = state.tabs.map((tab) => tab.selected?.[valueKey]); + if (value !== undefined) { + const values = tabs.value.map((tab) => tab.selected?.[valueKey]); if (values.includes(value)) { return; } diff --git a/packages/vant/src/cascader/README.md b/packages/vant/src/cascader/README.md index dd45e01e3..0759d050d 100644 --- a/packages/vant/src/cascader/README.md +++ b/packages/vant/src/cascader/README.md @@ -245,7 +245,7 @@ export default { The component exports the following type definitions: ```ts -import type { CascaderOption, CascaderFieldNames } from 'vant'; +import type { CascaderProps, CascaderOption, CascaderFieldNames } from 'vant'; ``` ## Theming diff --git a/packages/vant/src/cascader/README.zh-CN.md b/packages/vant/src/cascader/README.zh-CN.md index b42f26645..1960fe577 100644 --- a/packages/vant/src/cascader/README.zh-CN.md +++ b/packages/vant/src/cascader/README.zh-CN.md @@ -257,7 +257,7 @@ export default { 组件导出以下类型定义: ```ts -import type { CascaderOption, CascaderFieldNames } from 'vant'; +import type { CascaderProps, CascaderOption, CascaderFieldNames } from 'vant'; ``` ## 主题定制 diff --git a/packages/vant/src/cascader/index.ts b/packages/vant/src/cascader/index.ts index f3dd32d3b..2e45e910c 100644 --- a/packages/vant/src/cascader/index.ts +++ b/packages/vant/src/cascader/index.ts @@ -1,6 +1,7 @@ import { withInstall } from '../utils'; -import _Cascader from './Cascader'; +import _Cascader, { CascaderProps } from './Cascader'; export const Cascader = withInstall(_Cascader); export default Cascader; -export type { CascaderOption, CascaderFieldNames } from './Cascader'; +export type { CascaderProps }; +export type { CascaderOption, CascaderFieldNames } from './types'; diff --git a/packages/vant/src/cascader/types.ts b/packages/vant/src/cascader/types.ts new file mode 100644 index 000000000..2fc1ae502 --- /dev/null +++ b/packages/vant/src/cascader/types.ts @@ -0,0 +1,21 @@ +export type CascaderOption = { + text?: string; + value?: string | number; + color?: string; + disabled?: boolean; + children?: CascaderOption[]; + className?: unknown; + // for custom filed names + [key: PropertyKey]: any; +}; + +export type CascaderTab = { + options: CascaderOption[]; + selected: CascaderOption | null; +}; + +export type CascaderFieldNames = { + text?: string; + value?: string; + children?: string; +};