From da6bc06c851909ea0cd81dd16bfc5f6b35de74cd Mon Sep 17 00:00:00 2001 From: anlyyao Date: Fri, 30 Aug 2024 14:19:28 +0800 Subject: [PATCH 1/3] feat(Picker): added PickerColumn type to columns attr --- src/picker/demos/base.vue | 9 +++++---- src/picker/picker.en-US.md | 8 ++++---- src/picker/picker.md | 9 +++++---- src/picker/picker.tsx | 21 +++++++++++++++++---- src/picker/props.ts | 2 -- src/picker/type.ts | 7 +------ 6 files changed, 32 insertions(+), 24 deletions(-) diff --git a/src/picker/demos/base.vue b/src/picker/demos/base.vue index 3a4e7bc07..5dded9500 100644 --- a/src/picker/demos/base.vue +++ b/src/picker/demos/base.vue @@ -27,8 +27,8 @@ import { reactive } from 'vue'; import { PickerValue } from 'tdesign-mobile-vue'; -const cityOptions = [ - [ +const cityOptions = () => { + return [ { label: '北京市', value: '北京市', @@ -57,8 +57,9 @@ const cityOptions = [ label: '长沙市', value: '长沙市', }, - ], -]; + ]; +}; + const currentYear = Number(new Date().getFullYear()); const yearOptions = Array.from(new Array(10), (_, index) => { return { diff --git a/src/picker/picker.en-US.md b/src/picker/picker.en-US.md index 38dc450f7..dacdc3f1f 100644 --- a/src/picker/picker.en-US.md +++ b/src/picker/picker.en-US.md @@ -1,19 +1,19 @@ :: BASE_DOC :: ## API + ### Picker Props name | type | default | description | required -- | -- | -- | -- | -- cancelBtn | String / Boolean | true | Typescript:`boolean \| string` | N -columns | Array / Function | [] | required。Typescript:`Array \| ((item: Array) => Array)` `type PickerColumn = PickerColumnItem[]` `interface PickerColumnItem { label: string,value: string}`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/picker/type.ts) | Y +columns | Array / Function | [] | required。Typescript:`PickerColumn \| Array \| ((item: Array) => Array)` `type PickerColumn = PickerColumnItem[]` `interface PickerColumnItem { label: string,value: string}`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/picker/type.ts) | Y confirmBtn | String / Boolean | true | Typescript:`boolean \| string` | N header | Slot / Function | - | Typescript:`TNode`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N renderLabel | Function | - | Typescript:`(item: PickerColumnItem) => string` | N title | String | '' | \- | N value | Array | - | `v-model` and `v-model:value` is supported。Typescript:`Array` `type PickerValue = string \| number`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/picker/type.ts) | N defaultValue | Array | - | uncontrolled property。Typescript:`Array` `type PickerValue = string \| number`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/picker/type.ts) | N -visible | Boolean | false | \- | N onCancel | Function | | Typescript:`(context: { e: MouseEvent }) => void`
| N onChange | Function | | Typescript:`(value: Array, context: { columns: Array, e: MouseEvent }) => void`
[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/picker/type.ts)。
`interface PickerContext{ column: number,index: number }`
| N onConfirm | Function | | Typescript:`(value: Array, context: { index: number[], e: MouseEvent, label: string[] }) => void`
| N @@ -28,8 +28,8 @@ change | `(value: Array, context: { columns: Array, confirm | `(value: Array, context: { index: number[], e: MouseEvent, label: string[] })` | \- pick | `(value: Array,context: PickerContext)` | \- - ### CSS Variables + The component provides the following CSS variables, which can be used to customize styles. Name | Default Value | Description -- | -- | -- @@ -51,4 +51,4 @@ Name | Default Value | Description --td-picker-title-font-size | 18px | - --td-picker-title-font-weight | 600 | - --td-picker-title-line-height | 26px | - ---td-picker-toolbar-height | 58px | - +--td-picker-toolbar-height | 58px | - \ No newline at end of file diff --git a/src/picker/picker.md b/src/picker/picker.md index 7893c26a7..8c2cfa128 100644 --- a/src/picker/picker.md +++ b/src/picker/picker.md @@ -2,12 +2,13 @@ ## API + ### Picker Props -名称 | 类型 | 默认值 | 说明 | 必传 +名称 | 类型 | 默认值 | 描述 | 必传 -- | -- | -- | -- | -- cancelBtn | String / Boolean | true | 取消按钮文字。TS 类型:`boolean \| string` | N -columns | Array / Function | [] | 必需。配置每一列的选项。TS 类型:`Array \| ((item: Array) => Array)` `type PickerColumn = PickerColumnItem[]` `interface PickerColumnItem { label: string,value: string}`。[详细类型定义](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/picker/type.ts) | Y +columns | Array / Function | [] | 必需。配置每一列的选项。TS 类型:`PickerColumn \| Array \| ((item: Array) => Array)` `type PickerColumn = PickerColumnItem[]` `interface PickerColumnItem { label: string,value: string}`。[详细类型定义](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/picker/type.ts) | Y confirmBtn | String / Boolean | true | 确定按钮文字。TS 类型:`boolean \| string` | N header | Slot / Function | - | 自定义头部内容。TS 类型:`TNode`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N renderLabel | Function | - | 自定义label。TS 类型:`(item: PickerColumnItem) => string` | N @@ -28,8 +29,8 @@ change | `(value: Array, context: { columns: Array, confirm | `(value: Array, context: { index: number[], e: MouseEvent, label: string[] })` | 点击确认按钮时触发 pick | `(value: Array,context: PickerContext)` | 任何一列选中都会触发,不同的列参数不同。`context.column` 表示第几列变化,`context.index` 表示变化那一列的选中项下标 - ### CSS Variables + 组件提供了下列 CSS 变量,可用于自定义样式。 名称 | 默认值 | 描述 -- | -- | -- @@ -51,4 +52,4 @@ pick | `(value: Array,context: PickerContext)` | 任何一列选中 --td-picker-title-font-size | 18px | - --td-picker-title-font-weight | 600 | - --td-picker-title-line-height | 26px | - ---td-picker-toolbar-height | 58px | - +--td-picker-toolbar-height | 58px | - \ No newline at end of file diff --git a/src/picker/picker.tsx b/src/picker/picker.tsx index 83ce38fea..1746e8be8 100644 --- a/src/picker/picker.tsx +++ b/src/picker/picker.tsx @@ -1,7 +1,8 @@ import { computed, defineComponent, toRefs, ref, watch } from 'vue'; import isString from 'lodash/isString'; import isBoolean from 'lodash/isBoolean'; - +import isArray from 'lodash/isArray'; +import isFunction from 'lodash/isFunction'; import config from '../config'; import PickerProps from './props'; import { PickerValue, PickerColumn, PickerColumnItem } from './type'; @@ -12,6 +13,13 @@ import { useConfig } from '../config-provider/useConfig'; const { prefix } = config; const name = `${prefix}-picker`; + +const isMutipleArray = (arr: PickerColumn | PickerColumn[]) => { + return arr.some((item) => { + return isArray(item); + }); +}; + const getIndexFromColumns = (column: PickerColumn, value: PickerValue) => { if (!value) return 0; return column?.findIndex((item: PickerColumnItem) => item.value === value); @@ -28,20 +36,25 @@ export default defineComponent({ const { value, modelValue } = toRefs(props); const [pickerValue = ref([]), setPickerValue] = useVModel(value, modelValue, props.defaultValue, props.onChange); + const getDefaultText = (prop: string | boolean, defaultText: string): string => { if (isString(prop)) return prop; if (isBoolean(prop) && prop) return defaultText; return ''; }; + const confirmButtonText = computed(() => getDefaultText(props.confirmBtn, globalConfig.value.confirm)); const cancelButtonText = computed(() => getDefaultText(props.cancelBtn, globalConfig.value.cancel)); const curValueArray = ref(pickerValue.value?.map((item: PickerValue) => item) || []); + const realColumns = computed(() => { - if (typeof props.columns === 'function') { - return props.columns(curValueArray.value); + if (isFunction(props.columns)) { + const _columns = props.columns(curValueArray.value); + return isMutipleArray(_columns) ? _columns : [_columns]; } - return props.columns; + return isMutipleArray(props.columns) ? props.columns : [props.columns]; }); + const curIndexArray = realColumns.value.map((item: PickerColumn, index: number) => { return getIndexFromColumns(item, pickerValue.value?.[index]); }); diff --git a/src/picker/props.ts b/src/picker/props.ts index 2fb820c02..a6442d4cc 100644 --- a/src/picker/props.ts +++ b/src/picker/props.ts @@ -50,8 +50,6 @@ export default { defaultValue: { type: Array as PropType, }, - /** 是否显示 */ - visible: Boolean, /** 点击取消按钮时触发 */ onCancel: Function as PropType, /** 选中变化时候触发 */ diff --git a/src/picker/type.ts b/src/picker/type.ts index 4083d7b2e..ecb44b5b0 100644 --- a/src/picker/type.ts +++ b/src/picker/type.ts @@ -16,7 +16,7 @@ export interface TdPickerProps { * 配置每一列的选项 * @default [] */ - columns: Array | ((item: Array) => Array); + columns: PickerColumn | Array | ((item: Array) => Array); /** * 确定按钮文字 * @default true @@ -47,11 +47,6 @@ export interface TdPickerProps { * 选中值 */ modelValue?: Array; - /** - * 是否显示 - * @default false - */ - visible?: boolean; /** * 点击取消按钮时触发 * @default '' From 3a8f6b3884d4d98f222f4b483ff0d2b1320bdb41 Mon Sep 17 00:00:00 2001 From: anlyyao Date: Fri, 30 Aug 2024 14:22:18 +0800 Subject: [PATCH 2/3] fix: fix spelling errors --- src/picker/picker.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/picker/picker.tsx b/src/picker/picker.tsx index 1746e8be8..94961b86d 100644 --- a/src/picker/picker.tsx +++ b/src/picker/picker.tsx @@ -14,7 +14,7 @@ import { useConfig } from '../config-provider/useConfig'; const { prefix } = config; const name = `${prefix}-picker`; -const isMutipleArray = (arr: PickerColumn | PickerColumn[]) => { +const isMultipleArray = (arr: PickerColumn | PickerColumn[]) => { return arr.some((item) => { return isArray(item); }); @@ -50,9 +50,9 @@ export default defineComponent({ const realColumns = computed(() => { if (isFunction(props.columns)) { const _columns = props.columns(curValueArray.value); - return isMutipleArray(_columns) ? _columns : [_columns]; + return isMultipleArray(_columns) ? _columns : [_columns]; } - return isMutipleArray(props.columns) ? props.columns : [props.columns]; + return isMultipleArray(props.columns) ? props.columns : [props.columns]; }); const curIndexArray = realColumns.value.map((item: PickerColumn, index: number) => { From b473cb4b1f5402106a9bc52c2d2a163d9476e1b2 Mon Sep 17 00:00:00 2001 From: anlyyao Date: Fri, 30 Aug 2024 14:37:40 +0800 Subject: [PATCH 3/3] fix: fix type error --- src/_common | 2 +- src/picker/__test__/index.test.jsx | 23 ++++++++++++++++++++--- src/picker/picker-item.tsx | 6 +++--- src/picker/picker.tsx | 14 ++++---------- src/picker/utils.ts | 10 ++++++++++ 5 files changed, 38 insertions(+), 17 deletions(-) create mode 100644 src/picker/utils.ts diff --git a/src/_common b/src/_common index 889f7026c..5d8910f02 160000 --- a/src/_common +++ b/src/_common @@ -1 +1 @@ -Subproject commit 889f7026c7e4b0dda2534c3a4c51ea8cf7f2ac6a +Subproject commit 5d8910f0273e8da29c9f2e20760be48f1b128448 diff --git a/src/picker/__test__/index.test.jsx b/src/picker/__test__/index.test.jsx index 589359c73..529cca8ed 100644 --- a/src/picker/__test__/index.test.jsx +++ b/src/picker/__test__/index.test.jsx @@ -1,11 +1,21 @@ import { nextTick, ref } from 'vue'; +import isFunction from 'lodash/isFunction'; import { mount } from '@vue/test-utils'; import { describe, it, expect, vi } from 'vitest'; import Picker from '../picker'; import PickerItem from '../picker-item'; +import { getPickerColumns } from '../utils'; import { DEFAULT_ITEM_HEIGHT, ANIMATION_TIME_LIMIT } from '../picker.class'; +const getRealColumns = (columns) => { + if (isFunction(columns)) { + const _columns = columns(); + return getPickerColumns(_columns); + } + return getPickerColumns(columns); +}; + const seasonOptions = [ { label: '春', value: 'spring' }, { label: '夏', value: 'summer' }, @@ -111,11 +121,18 @@ describe('picker', () => { return expect(itemContainers).toHaveLength(0); } - expect(itemContainers).toHaveLength(seasonOptions.length); - itemContainers.forEach((container, index) => expect(container.text()).toBe(seasonOptions[index].label)); + const _columns = getRealColumns(columns); + + expect(itemContainers).toHaveLength(_columns[0].length); + + itemContainers.forEach((container, index) => { + if (_columns[index]?.label) { + expect(container.text()).toBe(_columns[index]?.label); + } + }); }; - testColumns([undefined], false); + testColumns([undefined], true); testColumns(undefined, false); testColumns([seasonOptions]); testColumns(() => [seasonOptions]); diff --git a/src/picker/picker-item.tsx b/src/picker/picker-item.tsx index 4950acbbf..95c9bbe80 100644 --- a/src/picker/picker-item.tsx +++ b/src/picker/picker-item.tsx @@ -1,4 +1,4 @@ -import { ref, computed, onMounted, toRefs, defineComponent, PropType, watch } from 'vue'; +import { ref, computed, onMounted, defineComponent, PropType, watch } from 'vue'; import config from '../config'; import Picker from './picker.class'; import { PickerColumnItem, PickerValue } from './type'; @@ -31,7 +31,7 @@ export default defineComponent({ const getIndexByValue = (val: number | string | undefined) => { let defaultIndex = 0; if (val !== undefined) { - defaultIndex = props.options?.findIndex((item: any) => item.value === val); + defaultIndex = props.options?.findIndex((item: any) => item?.value === val); } return defaultIndex < 0 ? 0 : defaultIndex; }; @@ -94,7 +94,7 @@ export default defineComponent({
    {(props.options || []).map((option, index) => (
  • - {props.renderLabel ? props.renderLabel(option) : option.label} + {props.renderLabel ? props.renderLabel(option) : option?.label}
  • ))}
diff --git a/src/picker/picker.tsx b/src/picker/picker.tsx index 94961b86d..702408daa 100644 --- a/src/picker/picker.tsx +++ b/src/picker/picker.tsx @@ -1,7 +1,6 @@ import { computed, defineComponent, toRefs, ref, watch } from 'vue'; import isString from 'lodash/isString'; import isBoolean from 'lodash/isBoolean'; -import isArray from 'lodash/isArray'; import isFunction from 'lodash/isFunction'; import config from '../config'; import PickerProps from './props'; @@ -10,19 +9,14 @@ import { useVModel } from '../shared'; import { useTNodeJSX } from '../hooks/tnode'; import PickerItem from './picker-item'; import { useConfig } from '../config-provider/useConfig'; +import { getPickerColumns } from './utils'; const { prefix } = config; const name = `${prefix}-picker`; -const isMultipleArray = (arr: PickerColumn | PickerColumn[]) => { - return arr.some((item) => { - return isArray(item); - }); -}; - const getIndexFromColumns = (column: PickerColumn, value: PickerValue) => { if (!value) return 0; - return column?.findIndex((item: PickerColumnItem) => item.value === value); + return column?.findIndex((item: PickerColumnItem) => item?.value === value); }; export default defineComponent({ @@ -50,9 +44,9 @@ export default defineComponent({ const realColumns = computed(() => { if (isFunction(props.columns)) { const _columns = props.columns(curValueArray.value); - return isMultipleArray(_columns) ? _columns : [_columns]; + return getPickerColumns(_columns); } - return isMultipleArray(props.columns) ? props.columns : [props.columns]; + return getPickerColumns(props.columns); }); const curIndexArray = realColumns.value.map((item: PickerColumn, index: number) => { diff --git a/src/picker/utils.ts b/src/picker/utils.ts new file mode 100644 index 000000000..ef63f5b18 --- /dev/null +++ b/src/picker/utils.ts @@ -0,0 +1,10 @@ +import isArray from 'lodash/isArray'; +import { PickerColumn } from './type'; + +export const isMultipleArray = (arr: PickerColumn | PickerColumn[]) => { + return isArray(arr[0]); +}; + +export const getPickerColumns = (columns: any): PickerColumn[] => { + return isMultipleArray(columns) ? columns : [columns]; +};