diff --git a/src/config.json b/src/config.json index 70976e92f3..ac1ac996d7 100644 --- a/src/config.json +++ b/src/config.json @@ -688,8 +688,8 @@ "sort": 10, "show": true, "taro": true, - "author": "dsj", - "dd": false + "dd": false, + "author": "songsong" }, { "version": "3.0.0", @@ -1456,4 +1456,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/src/packages/datepicker/__test__/datepicker.spec.tsx b/src/packages/datepicker/__test__/datepicker.spec.tsx index 2bfbba3dcc..26a75e4ae9 100644 --- a/src/packages/datepicker/__test__/datepicker.spec.tsx +++ b/src/packages/datepicker/__test__/datepicker.spec.tsx @@ -21,7 +21,7 @@ test('Show Chinese', async () => { fireEvent.click(confirmBtn) await waitFor(() => { expect( - confirm.mock.calls[0][0].map((option: any) => option.text).join('') + confirm.mock.calls[0][0].map((option: any) => option.label).join('') ).toEqual(`${currentYear - 10}年01月01日`) }) }) @@ -40,13 +40,9 @@ test('Min date & Max date', async () => { /> ) - const columns = container.querySelectorAll('.nut-picker-list')[0] - const lists = columns.querySelectorAll('.nut-picker-roller-item-title') - const years = ['2020', '2021', '2022'] + const columns = container.querySelectorAll('.nut-pickerview-list') + const lists = columns[0].querySelectorAll('.nut-pickerview-roller-item-tiled') expect(lists.length).toBe(3) - lists.forEach((list, i) => { - expect(list.textContent).toEqual(years[i]) - }) rerender( { const formatter = (type: string, option: any) => { switch (type) { case 'year': - option.text += '' + option.label += '' break case 'month': - option.text += 'M' + option.label += 'M' break case 'day': - option.text += 'D' + option.label += 'D' break case 'hour': - option.text += 'H' + option.label += 'H' break case 'minute': - option.text += 'M' + option.label += 'M' break default: - option.text += '' + option.label += '' } return option } @@ -148,7 +144,7 @@ test('should pick defaultValue', async () => { fireEvent.click(confirmBtn) await waitFor(() => expect( - confirm.mock.calls[0][0].map((option: any) => option.text).join('') + confirm.mock.calls[0][0].map((option: any) => option.label).join('') ).toEqual('20210301') ) }) @@ -166,8 +162,8 @@ test('Increment step setting', async () => { /> ) - const columns = container.querySelectorAll('.nut-picker-list')[1] - const lists = columns.querySelectorAll('.nut-picker-roller-item') + const columns = container.querySelectorAll('.nut-pickerview-list') + const lists = columns[1].querySelectorAll('.nut-pickerview-roller-item') expect(lists.length).toBe(12) }) @@ -189,7 +185,7 @@ test('Filter Time', async () => { /> ) - const columns = container.querySelectorAll('.nut-picker-list')[3] - const lists = columns.querySelectorAll('.nut-picker-roller-item') + const columns = container.querySelectorAll('.nut-pickerview-list') + const lists = columns[3].querySelectorAll('.nut-pickerview-roller-item') expect(lists.length).toBe(4) }) diff --git a/src/packages/datepicker/datepicker.taro.tsx b/src/packages/datepicker/datepicker.taro.tsx index 702f1e4e07..3a6719d316 100644 --- a/src/packages/datepicker/datepicker.taro.tsx +++ b/src/packages/datepicker/datepicker.taro.tsx @@ -1,11 +1,16 @@ import React, { FunctionComponent, useState, useEffect } from 'react' import { View } from '@tarojs/components' -import Picker, { PickerOption, PickerProps } from '@/packages/picker/index.taro' +import Picker, { PickerProps } from '@/packages/picker/index.taro' import { useConfig } from '@/packages/configprovider/index.taro' import { usePropsValue } from '@/hooks/use-props-value' import { BasicComponent, ComponentDefaults } from '@/utils/typings' import { isDate } from '@/utils/is-date' import { padZero } from '@/utils/pad-zero' +import { + PickerOption, + PickerOptions, + PickerValue, +} from '@/packages/pickerview/types' export interface DatePickerProps extends BasicComponent { value?: Date @@ -39,16 +44,16 @@ export interface DatePickerProps extends BasicComponent { > > formatter: (type: string, option: PickerOption) => PickerOption - filter: (type: string, option: PickerOption[]) => PickerOption[] + filter: (type: string, options: PickerOptions) => PickerOptions onClose: () => void onCancel: () => void onConfirm: ( - selectedOptions: PickerOption[], - selectedValue: (string | number)[] + selectedOptions: PickerOptions, + selectedValue: PickerValue[] ) => void onChange?: ( - selectedOptions: PickerOption[], - selectedValue: (string | number)[], + selectedOptions: PickerOptions, + selectedValue: PickerValue[], columnIndex: number ) => void } @@ -104,8 +109,8 @@ export const DatePicker: FunctionComponent< minute: lang.min, seconds: lang.seconds, } - const [pickerValue, setPickerValue] = useState<(string | number)[]>([]) - const [pickerOptions, setPickerOptions] = useState([]) + const [pickerValue, setPickerValue] = useState([]) + const [pickerOptions, setPickerOptions] = useState([]) const formatValue = (value: Date | null) => { if (!value || (value && !isDate(value))) { value = startDate @@ -218,7 +223,7 @@ export const DatePicker: FunctionComponent< const compareDateChange = ( currentDate: number, newDate: Date | null, - selectedOptions: PickerOption[], + selectedOptions: PickerOptions, index: number ) => { const isEqual = new Date(currentDate)?.getTime() === newDate?.getTime() @@ -238,8 +243,8 @@ export const DatePicker: FunctionComponent< } } const handlePickerChange = ( - selectedOptions: PickerOption[], - selectedValue: (number | string)[], + selectedOptions: PickerOptions, + selectedValue: PickerValue[], index: number ) => { const rangeType = type.toLocaleLowerCase() @@ -248,7 +253,7 @@ export const DatePicker: FunctionComponent< rangeType ) ) { - const formatDate: (number | string)[] = [] + const formatDate: PickerValue[] = [] selectedValue.forEach((item) => { formatDate.push(item) }) @@ -313,13 +318,13 @@ export const DatePicker: FunctionComponent< const formatOption = (type: string, value: string | number) => { if (formatter) { return formatter(type, { - text: padZero(value, 2), + label: padZero(value, 2), value: padZero(value, 2), }) } const padMin = padZero(value, 2) const fatter = showChinese ? zhCNType[type] : '' - return { text: padMin + fatter, value: padMin } + return { label: padMin + fatter, value: padMin } } const generateColumn = ( @@ -412,14 +417,13 @@ export const DatePicker: FunctionComponent< onClose={onClose} onCancel={onCancel} value={pickerValue} - onConfirm={(options: PickerOption[], value: (string | number)[]) => - onConfirm && onConfirm(options, value) - } - onChange={( - options: PickerOption[], - value: (number | string)[], - index: number - ) => handlePickerChange(options, value, index)} + onConfirm={( + selectedOptions: PickerOptions, + selectedValue: PickerValue[] + ) => onConfirm && onConfirm(selectedOptions, selectedValue)} + onChange={({ value, index, selectedOptions }) => { + handlePickerChange(selectedOptions, value, index) + }} threeDimensional={threeDimensional} /> )} diff --git a/src/packages/datepicker/datepicker.tsx b/src/packages/datepicker/datepicker.tsx index 47011cdc27..91f53c4780 100644 --- a/src/packages/datepicker/datepicker.tsx +++ b/src/packages/datepicker/datepicker.tsx @@ -1,11 +1,15 @@ import React, { FunctionComponent, useState, useEffect } from 'react' -import Picker from '@/packages/picker' -import { PickerOption, PickerProps } from '@/packages/picker/index' +import Picker, { PickerProps } from '@/packages/picker/index' import { useConfig } from '@/packages/configprovider' import { usePropsValue } from '@/hooks/use-props-value' import { BasicComponent, ComponentDefaults } from '@/utils/typings' import { isDate } from '@/utils/is-date' import { padZero } from '@/utils/pad-zero' +import { + PickerOption, + PickerOptions, + PickerValue, +} from '@/packages/pickerview/types' export interface DatePickerProps extends BasicComponent { value?: Date @@ -39,16 +43,16 @@ export interface DatePickerProps extends BasicComponent { > > formatter: (type: string, option: PickerOption) => PickerOption - filter: (type: string, option: PickerOption[]) => PickerOption[] + filter: (type: string, options: PickerOptions) => PickerOptions onClose: () => void onCancel: () => void onConfirm: ( - selectedOptions: PickerOption[], - selectedValue: (string | number)[] + selectedOptions: PickerOptions, + selectedValue: PickerValue[] ) => void onChange?: ( - selectedOptions: PickerOption[], - selectedValue: (string | number)[], + selectedOptions: PickerOptions, + selectedValue: PickerValue[], columnIndex: number ) => void } @@ -104,8 +108,8 @@ export const DatePicker: FunctionComponent< minute: lang.min, seconds: lang.seconds, } - const [pickerValue, setPickerValue] = useState<(string | number)[]>([]) - const [pickerOptions, setPickerOptions] = useState([]) + const [pickerValue, setPickerValue] = useState([]) + const [pickerOptions, setPickerOptions] = useState([]) const formatValue = (value: Date | null) => { if (!value || (value && !isDate(value))) { value = startDate @@ -218,7 +222,7 @@ export const DatePicker: FunctionComponent< const compareDateChange = ( currentDate: number, newDate: Date | null, - selectedOptions: PickerOption[], + selectedOptions: PickerOptions, index: number ) => { const isEqual = new Date(currentDate)?.getTime() === newDate?.getTime() @@ -238,8 +242,8 @@ export const DatePicker: FunctionComponent< } } const handlePickerChange = ( - selectedOptions: PickerOption[], - selectedValue: (number | string)[], + selectedOptions: PickerOptions, + selectedValue: PickerValue[], index: number ) => { const rangeType = type.toLocaleLowerCase() @@ -248,7 +252,7 @@ export const DatePicker: FunctionComponent< rangeType ) ) { - const formatDate: (number | string)[] = [] + const formatDate: PickerValue[] = [] selectedValue.forEach((item) => { formatDate.push(item) }) @@ -313,13 +317,13 @@ export const DatePicker: FunctionComponent< const formatOption = (type: string, value: string | number) => { if (formatter) { return formatter(type, { - text: padZero(value, 2), + label: padZero(value, 2), value: padZero(value, 2), }) } const padMin = padZero(value, 2) const fatter = showChinese ? zhCNType[type] : '' - return { text: padMin + fatter, value: padMin } + return { label: padMin + fatter, value: padMin } } const generateColumn = ( @@ -407,14 +411,13 @@ export const DatePicker: FunctionComponent< onClose={onClose} onCancel={onCancel} value={pickerValue} - onConfirm={(options: PickerOption[], value: (string | number)[]) => - onConfirm && onConfirm(options, value) - } - onChange={( - options: PickerOption[], - value: (number | string)[], - index: number - ) => handlePickerChange(options, value, index)} + onConfirm={( + selectedOptions: PickerOptions, + selectedValue: PickerValue[] + ) => onConfirm && onConfirm(selectedOptions, selectedValue)} + onChange={({ value, index, selectedOptions }) => { + handlePickerChange(selectedOptions, value, index) + }} threeDimensional={threeDimensional} /> )} diff --git a/src/packages/datepicker/demos/h5/demo1.tsx b/src/packages/datepicker/demos/h5/demo1.tsx index f227a06824..769885abf8 100644 --- a/src/packages/datepicker/demos/h5/demo1.tsx +++ b/src/packages/datepicker/demos/h5/demo1.tsx @@ -1,5 +1,10 @@ import React, { useState } from 'react' -import { DatePicker, Cell, type PickerOption } from '@nutui/nutui-react' +import { + DatePicker, + Cell, + PickerValue, + PickerOptions, +} from '@nutui/nutui-react' const Demo1 = () => { const defaultValue = new Date() @@ -12,13 +17,14 @@ const Demo1 = () => { const [value, setValue] = useState('2023/01/01') const [show2, setShow2] = useState(false) const [desc2, setDesc2] = useState('') - const confirm1 = (values: (string | number)[], options: PickerOption[]) => { - setDesc1(options.map((option) => option.text).join(' ')) + const confirm1 = (values: PickerValue[], options: PickerOptions) => { + setDesc1(options.map((option) => option.label).join(' ')) } - const change = (options: PickerOption[], values: (string | number)[]) => { + const change = (options: PickerOptions, values: PickerValue[]) => { const v = values.join('/') + setValue(v) - setDesc2(options.map((option) => option.text).join(' ')) + setDesc2(options.map((option) => option.label).join(' ')) } return ( <> @@ -39,7 +45,7 @@ const Demo1 = () => { onConfirm={(options, values) => { setShow1(false) confirm1(values, options) - console.log('onconfirm') + console.log('onconfirm', values, options) }} /> { const defaultValue = new Date() @@ -8,8 +13,9 @@ const Demo2 = () => { `${defaultValue.getMonth() + 1}-${defaultValue.getDate()}` ) - const confirm = (values: (string | number)[], options: PickerOption[]) => { - setDesc(options.map((option) => option.text).join('-')) + const confirm = (values: PickerValue[], options: PickerOptions) => { + console.log('values', values, options) + setDesc(options.map((option) => option.label).join('-')) } return ( <> diff --git a/src/packages/datepicker/demos/h5/demo3.tsx b/src/packages/datepicker/demos/h5/demo3.tsx index 1143b67773..bf0cce9a2e 100644 --- a/src/packages/datepicker/demos/h5/demo3.tsx +++ b/src/packages/datepicker/demos/h5/demo3.tsx @@ -1,5 +1,10 @@ import React, { useState } from 'react' -import { DatePicker, Cell, type PickerOption } from '@nutui/nutui-react' +import { + DatePicker, + Cell, + PickerOptions, + PickerValue, +} from '@nutui/nutui-react' const Demo3 = () => { const defaultValue = new Date() @@ -11,7 +16,7 @@ const Demo3 = () => { const endDate = new Date(2025, 10, 1) const [show, setShow] = useState(false) const [desc, setDesc] = useState(`${defaultDescription} 11:08`) - const confirm = (values: (string | number)[], options: PickerOption[]) => { + const confirm = (values: PickerValue[], options: PickerOptions) => { const date = values.slice(0, 3).join('-') const time = values.slice(3).join(':') setDesc(`${date} ${time}`) diff --git a/src/packages/datepicker/demos/h5/demo4.tsx b/src/packages/datepicker/demos/h5/demo4.tsx index fefb4b317d..7e01fa6996 100644 --- a/src/packages/datepicker/demos/h5/demo4.tsx +++ b/src/packages/datepicker/demos/h5/demo4.tsx @@ -1,5 +1,10 @@ import React, { useState } from 'react' -import { DatePicker, Cell, type PickerOption } from '@nutui/nutui-react' +import { + DatePicker, + Cell, + PickerValue, + PickerOptions, +} from '@nutui/nutui-react' const Demo4 = () => { const defaultValue = new Date() @@ -10,8 +15,8 @@ const Demo4 = () => { const endDate = new Date(2025, 10, 1) const [show, setShow] = useState(false) const [desc, setDesc] = useState('10:10:00') - const confirm = (values: (string | number)[], options: PickerOption[]) => { - setDesc(options.map((option) => option.text).join(':')) + const confirm = (values: PickerValue[], options: PickerOptions) => { + setDesc(options.map((option) => option.label).join(':')) } return ( diff --git a/src/packages/datepicker/demos/h5/demo5.tsx b/src/packages/datepicker/demos/h5/demo5.tsx index 0ab54a263e..e396a55a9f 100644 --- a/src/packages/datepicker/demos/h5/demo5.tsx +++ b/src/packages/datepicker/demos/h5/demo5.tsx @@ -1,5 +1,10 @@ import React, { useState } from 'react' -import { DatePicker, Cell, type PickerOption } from '@nutui/nutui-react' +import { + DatePicker, + Cell, + PickerOptions, + PickerValue, +} from '@nutui/nutui-react' const Demo5 = () => { const defaultValue = new Date() @@ -10,8 +15,8 @@ const Demo5 = () => { const endDate = new Date(2025, 10, 1) const [show, setShow] = useState(false) const [desc, setDesc] = useState('10:10') - const confirm8 = (options: PickerOption[], values: (string | number)[]) => { - setDesc(options.map((option) => option.text).join(':')) + const confirm8 = (options: PickerOptions, values: PickerValue[]) => { + setDesc(options.map((option) => option.label).join(':')) } return ( diff --git a/src/packages/datepicker/demos/h5/demo6.tsx b/src/packages/datepicker/demos/h5/demo6.tsx index 09e831821c..21350012de 100644 --- a/src/packages/datepicker/demos/h5/demo6.tsx +++ b/src/packages/datepicker/demos/h5/demo6.tsx @@ -1,5 +1,11 @@ import React, { useState } from 'react' -import { DatePicker, Cell, type PickerOption } from '@nutui/nutui-react' +import { + DatePicker, + Cell, + PickerValue, + PickerOption, + PickerOptions, +} from '@nutui/nutui-react' const Demo6 = () => { const defaultValue = new Date() @@ -9,36 +15,36 @@ const Demo6 = () => { const [show, setShow] = useState(false) const [desc, setDesc] = useState(`${defaultDescription} 10:10`) - const confirm = (values: (string | number)[], options: PickerOption[]) => { + const confirm = (values: PickerValue[], options: PickerOptions) => { const date = options .slice(1, 3) - .map((op) => op.text) + .map((op) => op.label) .join('') const time = options .slice(3) .map((op) => op.value) .join(':') - setDesc(`${options[0].text}年${date} ${time}`) + setDesc(`${options[0].label}年${date} ${time}`) } const formatter = (type: string, option: PickerOption) => { switch (type) { case 'year': - option.text += '' + option.label += '' break case 'month': - option.text += '月' + option.label += '月' break case 'day': - option.text += '日' + option.label += '日' break case 'hour': - option.text += '时' + option.label += '时' break case 'minute': - option.text += '分' + option.label += '分' break default: - option.text += '' + option.label += '' } return option } diff --git a/src/packages/datepicker/demos/h5/demo7.tsx b/src/packages/datepicker/demos/h5/demo7.tsx index a447fa27f5..ba3b8f9366 100644 --- a/src/packages/datepicker/demos/h5/demo7.tsx +++ b/src/packages/datepicker/demos/h5/demo7.tsx @@ -1,5 +1,10 @@ import React, { useState } from 'react' -import { DatePicker, Cell, type PickerOption } from '@nutui/nutui-react' +import { + DatePicker, + Cell, + PickerValue, + PickerOptions, +} from '@nutui/nutui-react' const Demo7 = () => { const defaultValue = new Date() @@ -11,8 +16,8 @@ const Demo7 = () => { const [show, setShow] = useState(false) const [desc, setDesc] = useState('10:10:00') - const confirm6 = (values: (string | number)[], options: PickerOption[]) => { - setDesc(options.map((option) => option.text).join(':')) + const confirm6 = (values: PickerValue[], options: PickerOptions) => { + setDesc(options.map((option) => option.label).join(':')) } return ( <> diff --git a/src/packages/datepicker/demos/h5/demo8.tsx b/src/packages/datepicker/demos/h5/demo8.tsx index a5cce7f3eb..79886c8d19 100644 --- a/src/packages/datepicker/demos/h5/demo8.tsx +++ b/src/packages/datepicker/demos/h5/demo8.tsx @@ -1,5 +1,11 @@ import React, { useState } from 'react' -import { DatePicker, Cell, type PickerOption } from '@nutui/nutui-react' +import { + DatePicker, + Cell, + PickerValue, + PickerOption, + PickerOptions, +} from '@nutui/nutui-react' const Demo8 = () => { const startDate = new Date(2020, 0, 1) @@ -11,10 +17,10 @@ const Demo8 = () => { const [show, setShow] = useState(false) const [desc, setDesc] = useState(`${defaultDescription} 00`) - const confirm = (values: (string | number)[], options: PickerOption[]) => { - setDesc(options.map((option) => option.text).join(' ')) + const confirm = (values: PickerValue[], options: PickerOptions) => { + setDesc(options.map((option) => option.label).join(' ')) } - const filter = (type: string, options: PickerOption[]) => { + const filter = (type: string, options: PickerOptions) => { if (type === 'hour') { return options.filter((option) => Number(option.value) % 6 === 0) } @@ -23,19 +29,19 @@ const Demo8 = () => { const formatter1 = (type: string, option: PickerOption) => { switch (type) { case 'year': - option.text += `年` + option.label += `年` break case 'month': - option.text += `月` + option.label += `月` break case 'day': - option.text += `日` + option.label += `日` break case 'hour': - option.text += `时` + option.label += `时` break default: - option.text += '' + option.label += '' } return option } diff --git a/src/packages/datepicker/demos/taro/demo1.tsx b/src/packages/datepicker/demos/taro/demo1.tsx index dadd406cb0..1a9c273446 100644 --- a/src/packages/datepicker/demos/taro/demo1.tsx +++ b/src/packages/datepicker/demos/taro/demo1.tsx @@ -1,5 +1,10 @@ import React, { useState } from 'react' -import { DatePicker, Cell, type PickerOption } from '@nutui/nutui-react-taro' +import { + DatePicker, + Cell, + PickerValue, + PickerOptions, +} from '@nutui/nutui-react-taro' const Demo1 = () => { const defaultValue = new Date() @@ -12,13 +17,14 @@ const Demo1 = () => { const [value, setValue] = useState('2023/01/01') const [show2, setShow2] = useState(false) const [desc2, setDesc2] = useState('') - const confirm = (values: (string | number)[], options: PickerOption[]) => { - setDesc1(options.map((option) => option.text).join(' ')) + const confirm = (values: PickerValue[], options: PickerOptions) => { + setDesc1(options.map((option) => option.label).join(' ')) } - const change = (options: PickerOption[], values: (string | number)[]) => { + const change = (options: PickerOptions, values: PickerValue[]) => { const v = values.join('/') + setValue(v) - setDesc2(options.map((option) => option.text).join(' ')) + setDesc2(options.map((option) => option.label).join(' ')) } return ( <> diff --git a/src/packages/datepicker/demos/taro/demo2.tsx b/src/packages/datepicker/demos/taro/demo2.tsx index 7d3b42edaf..9e57427a40 100644 --- a/src/packages/datepicker/demos/taro/demo2.tsx +++ b/src/packages/datepicker/demos/taro/demo2.tsx @@ -1,5 +1,10 @@ import React, { useState } from 'react' -import { DatePicker, Cell, type PickerOption } from '@nutui/nutui-react-taro' +import { + DatePicker, + Cell, + PickerOptions, + PickerValue, +} from '@nutui/nutui-react-taro' const Demo2 = () => { const defaultValue = new Date() @@ -7,8 +12,8 @@ const Demo2 = () => { const [desc, setDesc] = useState( `${defaultValue.getMonth() + 1}-${defaultValue.getDate()}` ) - const confirm = (values: (string | number)[], options: PickerOption[]) => { - setDesc(options.map((option) => option.text).join('-')) + const confirm = (values: PickerValue[], options: PickerOptions) => { + setDesc(options.map((option) => option.label).join('-')) } return ( <> diff --git a/src/packages/datepicker/demos/taro/demo3.tsx b/src/packages/datepicker/demos/taro/demo3.tsx index 0334291b40..b4dedc010f 100644 --- a/src/packages/datepicker/demos/taro/demo3.tsx +++ b/src/packages/datepicker/demos/taro/demo3.tsx @@ -1,5 +1,10 @@ import React, { useState } from 'react' -import { DatePicker, Cell, type PickerOption } from '@nutui/nutui-react-taro' +import { + DatePicker, + Cell, + PickerValue, + PickerOptions, +} from '@nutui/nutui-react-taro' const Demo3 = () => { const defaultValue = new Date() @@ -11,7 +16,7 @@ const Demo3 = () => { const endDate = new Date(2025, 10, 1) const [show, setShow] = useState(false) const [desc, setDesc] = useState(`${defaultDescription} 11:08`) - const confirm = (values: (string | number)[], options: PickerOption[]) => { + const confirm = (values: PickerValue[], options: PickerOptions) => { const date = values.slice(0, 3).join('-') const time = values.slice(3).join(':') setDesc(`${date} ${time}`) diff --git a/src/packages/datepicker/demos/taro/demo4.tsx b/src/packages/datepicker/demos/taro/demo4.tsx index 99f4ca3a55..00e85593b7 100644 --- a/src/packages/datepicker/demos/taro/demo4.tsx +++ b/src/packages/datepicker/demos/taro/demo4.tsx @@ -1,5 +1,10 @@ import React, { useState } from 'react' -import { DatePicker, Cell, type PickerOption } from '@nutui/nutui-react-taro' +import { + DatePicker, + Cell, + PickerValue, + PickerOptions, +} from '@nutui/nutui-react-taro' const Demo4 = () => { const defaultValue = new Date() @@ -10,8 +15,8 @@ const Demo4 = () => { const endDate = new Date(2025, 10, 1) const [show, setShow] = useState(false) const [desc, setDesc] = useState('10:10:00') - const confirm = (values: (string | number)[], options: PickerOption[]) => { - setDesc(options.map((option) => option.text).join(':')) + const confirm = (values: PickerValue[], options: PickerOptions) => { + setDesc(options.map((option) => option.label).join(':')) } return ( diff --git a/src/packages/datepicker/demos/taro/demo5.tsx b/src/packages/datepicker/demos/taro/demo5.tsx index db834280b3..0386bc9c61 100644 --- a/src/packages/datepicker/demos/taro/demo5.tsx +++ b/src/packages/datepicker/demos/taro/demo5.tsx @@ -1,5 +1,10 @@ import React, { useState } from 'react' -import { DatePicker, Cell, type PickerOption } from '@nutui/nutui-react-taro' +import { + DatePicker, + Cell, + PickerValue, + PickerOptions, +} from '@nutui/nutui-react-taro' const Demo5 = () => { const defaultValue = new Date() @@ -10,8 +15,8 @@ const Demo5 = () => { const endDate = new Date(2025, 10, 1) const [show, setShow] = useState(false) const [desc, setDesc] = useState('10:10') - const confirm = (options: PickerOption[], values: (string | number)[]) => { - setDesc(options.map((option) => option.text).join(':')) + const confirm = (options: PickerOptions, values: PickerValue[]) => { + setDesc(options.map((option) => option.label).join(':')) } return ( diff --git a/src/packages/datepicker/demos/taro/demo6.tsx b/src/packages/datepicker/demos/taro/demo6.tsx index 037c396eec..9aa1371946 100644 --- a/src/packages/datepicker/demos/taro/demo6.tsx +++ b/src/packages/datepicker/demos/taro/demo6.tsx @@ -1,5 +1,11 @@ import React, { useState } from 'react' -import { DatePicker, Cell, type PickerOption } from '@nutui/nutui-react-taro' +import { + DatePicker, + Cell, + PickerValue, + PickerOption, + PickerOptions, +} from '@nutui/nutui-react-taro' const Demo6 = () => { const defaultValue = new Date() @@ -9,36 +15,36 @@ const Demo6 = () => { const [show, setShow] = useState(false) const [desc, setDesc] = useState(`${defaultDescription} 10:10`) - const confirm = (values: (string | number)[], options: PickerOption[]) => { + const confirm = (values: PickerValue[], options: PickerOptions) => { const date = options .slice(1, 3) - .map((op) => op.text) + .map((op) => op.label) .join('') const time = options .slice(3) .map((op) => op.value) .join(':') - setDesc(`${options[0].text}年${date} ${time}`) + setDesc(`${options[0].label}年${date} ${time}`) } const formatter = (type: string, option: PickerOption) => { switch (type) { case 'year': - option.text += '' + option.label += '' break case 'month': - option.text += '月' + option.label += '月' break case 'day': - option.text += '日' + option.label += '日' break case 'hour': - option.text += '时' + option.label += '时' break case 'minute': - option.text += '分' + option.label += '分' break default: - option.text += '' + option.label += '' } return option } diff --git a/src/packages/datepicker/demos/taro/demo7.tsx b/src/packages/datepicker/demos/taro/demo7.tsx index 24702e28bf..6f7210ac00 100644 --- a/src/packages/datepicker/demos/taro/demo7.tsx +++ b/src/packages/datepicker/demos/taro/demo7.tsx @@ -1,5 +1,10 @@ import React, { useState } from 'react' -import { DatePicker, Cell, type PickerOption } from '@nutui/nutui-react-taro' +import { + DatePicker, + Cell, + PickerValue, + PickerOptions, +} from '@nutui/nutui-react-taro' const Demo7 = () => { const defaultValue = new Date() @@ -11,8 +16,8 @@ const Demo7 = () => { const [show, setShow] = useState(false) const [desc, setDesc] = useState('10:10:00') - const confirm = (values: (string | number)[], options: PickerOption[]) => { - setDesc(options.map((option) => option.text).join(':')) + const confirm = (values: PickerValue[], options: PickerOptions) => { + setDesc(options.map((option) => option.label).join(':')) } return ( <> diff --git a/src/packages/datepicker/demos/taro/demo8.tsx b/src/packages/datepicker/demos/taro/demo8.tsx index 31911a0f5a..42441084f5 100644 --- a/src/packages/datepicker/demos/taro/demo8.tsx +++ b/src/packages/datepicker/demos/taro/demo8.tsx @@ -1,5 +1,11 @@ import React, { useState } from 'react' -import { DatePicker, Cell, type PickerOption } from '@nutui/nutui-react-taro' +import { + DatePicker, + Cell, + PickerValue, + PickerOption, + PickerOptions, +} from '@nutui/nutui-react-taro' const Demo8 = () => { const startDate = new Date(2020, 0, 1) @@ -11,10 +17,10 @@ const Demo8 = () => { const [show, setShow] = useState(false) const [desc, setDesc] = useState(`${defaultDescription} 00`) - const confirm = (values: (string | number)[], options: PickerOption[]) => { - setDesc(options.map((option) => option.text).join(' ')) + const confirm = (values: PickerValue[], options: PickerOptions) => { + setDesc(options.map((option) => option.label).join(' ')) } - const filter = (type: string, options: PickerOption[]) => { + const filter = (type: string, options: PickerOptions) => { if (type === 'hour') { return options.filter((option) => Number(option.value) % 6 === 0) } @@ -23,19 +29,19 @@ const Demo8 = () => { const formatter = (type: string, option: PickerOption) => { switch (type) { case 'year': - option.text += `年` + option.label += `年` break case 'month': - option.text += `月` + option.label += `月` break case 'day': - option.text += `日` + option.label += `日` break case 'hour': - option.text += `时` + option.label += `时` break default: - option.text += '' + option.label += '' } return option } diff --git a/src/packages/form/demos/h5/demo7.tsx b/src/packages/form/demos/h5/demo7.tsx index f0387f47a7..8ba20b1cd3 100644 --- a/src/packages/form/demos/h5/demo7.tsx +++ b/src/packages/form/demos/h5/demo7.tsx @@ -17,14 +17,15 @@ import { ArrowRight } from '@nutui/icons-react' const Demo7 = () => { const pickerOptions = [ - { value: 4, text: 'BeiJing' }, - { value: 1, text: 'NanJing' }, - { value: 2, text: 'WuXi' }, - { value: 8, text: 'DaQing' }, - { value: 9, text: 'SuiHua' }, - { value: 10, text: 'WeiFang' }, - { value: 12, text: 'ShiJiaZhuang' }, + { value: 1, label: 'BeiJing' }, + { value: 2, label: 'NanJing' }, + { value: 3, label: 'WuXi' }, + { value: 4, label: 'DaQing' }, + { value: 5, label: 'SuiHua' }, + { value: 6, label: 'WeiFang' }, + { value: 7, label: 'ShiJiaZhuang' }, ] + const submitFailed = (error: any) => { Toast.show({ content: JSON.stringify(error), icon: 'fail' }) } @@ -106,7 +107,7 @@ const Demo7 = () => { title={ value.length ? pickerOptions.filter((po) => po.value === value[0])[0] - ?.text + ?.label : 'Please select' } extra={} diff --git a/src/packages/form/demos/taro/demo7.tsx b/src/packages/form/demos/taro/demo7.tsx index bee2dae660..97713f58e1 100644 --- a/src/packages/form/demos/taro/demo7.tsx +++ b/src/packages/form/demos/taro/demo7.tsx @@ -18,13 +18,13 @@ import { View } from '@tarojs/components' const Demo7 = () => { const pickerOptions = [ - { value: 4, text: 'BeiJing' }, - { value: 1, text: 'NanJing' }, - { value: 2, text: 'WuXi' }, - { value: 8, text: 'DaQing' }, - { value: 9, text: 'SuiHua' }, - { value: 10, text: 'WeiFang' }, - { value: 12, text: 'ShiJiaZhuang' }, + { value: 1, label: 'BeiJing' }, + { value: 2, label: 'NanJing' }, + { value: 3, label: 'WuXi' }, + { value: 4, label: 'DaQing' }, + { value: 5, label: 'SuiHua' }, + { value: 6, label: 'WeiFang' }, + { value: 7, label: 'ShiJiaZhuang' }, ] const submitFailed = (error: any) => { Taro.showToast({ title: JSON.stringify(error), icon: 'error' }) @@ -107,7 +107,7 @@ const Demo7 = () => { title={ value.length ? pickerOptions.filter((po) => po.value === value[0])[0] - ?.text + ?.label : 'Please select' } extra={} diff --git a/src/packages/picker/__tests__/picker.spec.tsx b/src/packages/picker/__tests__/picker.spec.tsx index 0c08207240..60fe500538 100644 --- a/src/packages/picker/__tests__/picker.spec.tsx +++ b/src/packages/picker/__tests__/picker.spec.tsx @@ -10,7 +10,7 @@ function sleep(delay = 0): Promise { } interface PickerOption { - text: string | number + label: string | number value: string | number disabled?: boolean children?: PickerOption[] @@ -18,72 +18,76 @@ interface PickerOption { } const simpleColumns = [ - { text: '南京市', value: 'NanJing' }, - { text: '无锡市', value: 'WuXi' }, - { text: '海北藏族自治区', value: 'ZangZu' }, - { text: '北京市', value: 'BeiJing' }, - { text: '连云港市', value: 'LianYunGang' }, + [ + { label: '南京市', value: 'NanJing' }, + { label: '无锡市', value: 'WuXi' }, + { label: '海北藏族自治区', value: 'ZangZu' }, + { label: '北京市', value: 'BeiJing' }, + { label: '连云港市', value: 'LianYunGang' }, + ], ] const multipleColumns = [ [ - { text: '周一', value: 'Monday' }, - { text: '周二', value: 'Tuesday' }, - { text: '周三', value: 'Wednesday' }, - { text: '周四', value: 'Thursday' }, - { text: '周五', value: 'Friday' }, + { label: '周一', value: 'Monday' }, + { label: '周二', value: 'Tuesday' }, + { label: '周三', value: 'Wednesday' }, + { label: '周四', value: 'Thursday' }, + { label: '周五', value: 'Friday' }, ], // 第二列 [ - { text: '上午', value: 'Morning' }, - { text: '下午', value: 'Afternoon' }, - { text: '晚上', value: 'Evening' }, + { label: '上午', value: 'Morning' }, + { label: '下午', value: 'Afternoon' }, + { label: '晚上', value: 'Evening' }, ], ] const multistageColumns = [ - { - text: '浙江', - value: 'ZheJiang', - children: [ - { - text: '杭州', - value: 'HangZhou', - children: [ - { text: '西湖区', value: 'XiHu' }, - { text: '余杭区', value: 'YuHang' }, - ], - }, - { - text: '温州', - value: 'WenZhou', - children: [ - { text: '鹿城区', value: 'LuCheng' }, - { text: '瓯海区', value: 'OuHai' }, - ], - }, - ], - }, - { - text: '福建', - value: 'FuJian', - children: [ - { - text: '福州', - value: 'FuZhou', - children: [ - { text: '鼓楼区', value: 'GuLou' }, - { text: '台江区', value: 'TaiJiang' }, - ], - }, - { - text: '厦门', - value: 'XiaMen', - children: [ - { text: '思明区', value: 'SiMing' }, - { text: '海沧区', value: 'HaiCang' }, - ], - }, - ], - }, + [ + { + label: '浙江', + value: 'ZheJiang', + children: [ + { + label: '杭州', + value: 'HangZhou', + children: [ + { label: '西湖区', value: 'XiHu' }, + { label: '余杭区', value: 'YuHang' }, + ], + }, + { + label: '温州', + value: 'WenZhou', + children: [ + { label: '鹿城区', value: 'LuCheng' }, + { label: '瓯海区', value: 'OuHai' }, + ], + }, + ], + }, + { + label: '福建', + value: 'FuJian', + children: [ + { + label: '福州', + value: 'FuZhou', + children: [ + { label: '鼓楼区', value: 'GuLou' }, + { label: '台江区', value: 'TaiJiang' }, + ], + }, + { + label: '厦门', + value: 'XiaMen', + children: [ + { label: '思明区', value: 'SiMing' }, + { label: '海沧区', value: 'HaiCang' }, + ], + }, + ], + }, + ], ] test('renderLabel works', async () => { @@ -98,8 +102,9 @@ test('simple list-data confirm event', async () => { const { container } = render( confirm(value)} + onConfirm={(selectedOptions, value) => confirm(value)} /> ) const confirmBtn = container.querySelectorAll('.nut-picker-confirm-btn')[0] @@ -137,6 +142,7 @@ test('multiple list-data render', async () => { const { container } = render( confirm(value)} /> @@ -154,6 +160,7 @@ test('multistageColumns list-data render', async () => { confirm(value)} /> ) @@ -167,7 +174,7 @@ test('multistageColumns list-data render', async () => { test('async list-data render', async () => { const confirm = vi.fn() const PenderContent = () => { - const [asyncColumns, setasyncColumns] = useState([]) + const [asyncColumns, setasyncColumns] = useState([]) setTimeout(() => { setasyncColumns(simpleColumns) @@ -176,6 +183,7 @@ test('async list-data render', async () => { return ( confirm(value)} /> diff --git a/src/packages/picker/demos/h5/demo1.tsx b/src/packages/picker/demos/h5/demo1.tsx index b0c5f799ba..480bf28554 100644 --- a/src/packages/picker/demos/h5/demo1.tsx +++ b/src/packages/picker/demos/h5/demo1.tsx @@ -1,40 +1,44 @@ import React, { useState } from 'react' -import { Picker, Cell } from '@nutui/nutui-react' - -interface PickerOption { - text: string | number - value: string | number - disabled?: boolean - children?: PickerOption[] - className?: string | number -} +import { + Picker, + Cell, + PickerOptions, + PickerValue, + PickerOnChangeCallbackParameter, + PickerOption, +} from '@nutui/nutui-react' const Demo1 = () => { const [visible, setVisible] = useState(false) const [baseDesc, setBaseDesc] = useState('') - const listData1 = [ + const options = [ [ - { value: 1, text: '南京市' }, - { value: 2, text: '无锡市' }, - { value: 3, text: '海北藏族自治区' }, - { value: 4, text: '北京市' }, - { value: 5, text: '连云港市' }, - { value: 8, text: '大庆市' }, - { value: 9, text: '绥化市' }, - { value: 10, text: '潍坊市' }, - { value: 12, text: '乌鲁木齐市' }, + { value: 1, label: '南京市' }, + { value: 2, label: '无锡市' }, + { value: 3, label: '海北藏族自治区' }, + { value: 4, label: '北京市' }, + { value: 5, label: '连云港市' }, + { value: 8, label: '大庆市' }, + { value: 9, label: '绥化市' }, + { value: 10, label: '潍坊市' }, + { value: 12, label: '乌鲁木齐市' }, ], ] - const changePicker = (list: any[], option: any, columnIndex: number) => { - console.log(columnIndex, option) + const changePicker = ({ + value, + index, + selectedOptions, + }: PickerOnChangeCallbackParameter) => { + console.log('changePicker', value, index, selectedOptions) } const confirmPicker = ( - options: PickerOption[], - values: (string | number)[] + selectedOptions: PickerOptions, + selectedValue: PickerValue[] ) => { + console.log('confirmPicker', selectedOptions, selectedValue) let description = '' - options.forEach((option: any) => { - description += ` ${option.text}` + selectedOptions.forEach((option: PickerOption) => { + description += ` ${option.label}` }) setBaseDesc(description) } @@ -48,8 +52,8 @@ const Demo1 = () => { confirmPicker(list, values)} + options={options} + onConfirm={confirmPicker} onClose={() => setVisible(false)} onChange={changePicker} /> diff --git a/src/packages/picker/demos/h5/demo2.tsx b/src/packages/picker/demos/h5/demo2.tsx index 22b87f1203..643137b163 100644 --- a/src/packages/picker/demos/h5/demo2.tsx +++ b/src/packages/picker/demos/h5/demo2.tsx @@ -1,54 +1,46 @@ import React, { useState } from 'react' -import { Picker, Cell } from '@nutui/nutui-react' +import { Picker, Cell, PickerOptions, PickerValue } from '@nutui/nutui-react' -interface PickerOption { - text: string | number - value: string | number - disabled?: boolean - children?: PickerOption[] - className?: string | number -} const Demo2 = () => { const [visible, setVisible] = useState(false) - const [baseDefault, setbaseDefault] = useState('') + const [baseDesc, setBaseDesc] = useState('无锡市') const [defaultValue] = useState([2]) - - const listData1 = [ + const options = [ [ - { value: 1, text: '南京市' }, - { value: 2, text: '无锡市' }, - { value: 3, text: '海北藏族自治区' }, - { value: 4, text: '北京市' }, - { value: 5, text: '连云港市' }, - { value: 8, text: '大庆市' }, - { value: 9, text: '绥化市' }, - { value: 10, text: '潍坊市' }, - { value: 12, text: '乌鲁木齐市' }, + { value: 1, label: '南京市' }, + { value: 2, label: '无锡市' }, + { value: 3, label: '海北藏族自治区' }, + { value: 4, label: '北京市' }, + { value: 5, label: '连云港市' }, + { value: 8, label: '大庆市' }, + { value: 9, label: '绥化市' }, + { value: 10, label: '潍坊市' }, + { value: 12, label: '乌鲁木齐市' }, ], ] const confirmPicker = ( - options: PickerOption[], - values: (string | number)[] + selectedOptions: PickerOptions, + selectedValue: PickerValue[] ) => { let description = '' - options.forEach((option: any) => { - description += ` ${option.text}` + selectedOptions.forEach((option: any) => { + description += ` ${option.label}` }) - setbaseDefault(description) + setBaseDesc(description) } return ( <> setVisible(!visible)} /> confirmPicker(list, values)} + options={options} + onConfirm={confirmPicker} onClose={() => setVisible(false)} /> diff --git a/src/packages/picker/demos/h5/demo3.tsx b/src/packages/picker/demos/h5/demo3.tsx index a4652af91d..81f59dcdfb 100644 --- a/src/packages/picker/demos/h5/demo3.tsx +++ b/src/packages/picker/demos/h5/demo3.tsx @@ -1,59 +1,64 @@ import React, { useState } from 'react' -import { Picker, Cell } from '@nutui/nutui-react' +import { Picker, Cell, PickerOptions, PickerValue } from '@nutui/nutui-react' +import isEqual from 'react-fast-compare' +import { PickerOnChangeCallbackParameter } from '@/packages/pickerview/types' -interface PickerOption { - text: string | number - value: string | number - disabled?: boolean - children?: PickerOption[] - className?: string | number -} const Demo3 = () => { - const [isVisible, setIsVisible] = useState(false) + const [visible, setVisible] = useState(false) const [baseDesc, setBaseDesc] = useState('') - const [val, setVal] = useState>([]) + const [value, setValue] = useState([] as PickerValue[]) const options = [ [ - { value: 1, text: '南京市' }, - { value: 2, text: '无锡市' }, - { value: 3, text: '海北藏族自治区' }, - { value: 4, text: '北京市' }, - { value: 5, text: '连云港市' }, - { value: 8, text: '大庆市' }, - { value: 9, text: '绥化市' }, - { value: 10, text: '潍坊市' }, - { value: 12, text: '乌鲁木齐市' }, + { value: 1, label: '南京市' }, + { value: 2, label: '无锡市' }, + { value: 3, label: '海北藏族自治区' }, + { value: 4, label: '北京市' }, + { value: 5, label: '连云港市' }, + { value: 8, label: '大庆市' }, + { value: 9, label: '绥化市' }, + { value: 10, label: '潍坊市' }, + { value: 12, label: '乌鲁木齐市' }, ], ] + + const changePicker = ({ + value, + index, + selectedOptions, + }: PickerOnChangeCallbackParameter) => { + console.log('changePicker', value, index, selectedOptions) + } const confirmPicker = ( - options: PickerOption[], - values: (string | number)[] + selectedOptions: PickerOptions, + selectedValue: PickerValue[] ) => { - let description = '' - options.forEach((option: any) => { - description += ` ${option.text}` - }) - setBaseDesc(description) + if (isEqual(selectedValue, [3])) { + setValue([1]) + setBaseDesc('南京市') + } else { + setValue(selectedValue) + let description = '' + selectedOptions.forEach((option: any) => { + description += ` ${option.label}` + }) + setBaseDesc(description) + } } return ( <> setIsVisible(!isVisible)} + onClick={() => setVisible(!visible)} /> { - confirmPicker(list, values) - setVal(values) - }} - onClose={() => { - setIsVisible(false) - }} + onChange={changePicker} + onConfirm={confirmPicker} + onClose={() => setVisible(false)} /> ) diff --git a/src/packages/picker/demos/h5/demo4.tsx b/src/packages/picker/demos/h5/demo4.tsx index b9594ffb6b..16192241fd 100644 --- a/src/packages/picker/demos/h5/demo4.tsx +++ b/src/packages/picker/demos/h5/demo4.tsx @@ -1,39 +1,34 @@ import React, { useState } from 'react' -import { Picker, Cell } from '@nutui/nutui-react' +import { Picker, Cell, PickerOptions, PickerValue } from '@nutui/nutui-react' -interface PickerOption { - text: string | number - value: string | number - disabled?: boolean - children?: PickerOption[] - className?: string | number -} const Demo4 = () => { - const [isVisible2, setIsVisible2] = useState(false) - const [mutilDesc, setMutilDesc] = useState('') - const listData2 = [ + const [visible, setVisible] = useState(false) + const [mutilDesc, setMutilDesc] = useState('周三') + const [defaultValue] = useState(['Wednesday']) + const options = [ // 第一列 [ - { text: '周一', value: 'Monday' }, - { text: '周二', value: 'Tuesday' }, - { text: '周三', value: 'Wednesday' }, - { text: '周四', value: 'Thursday' }, - { text: '周五', value: 'Friday' }, + { label: '周一', value: 'Monday' }, + { label: '周二', value: 'Tuesday' }, + { label: '周三', value: 'Wednesday' }, + { label: '周四', value: 'Thursday' }, + { label: '周五', value: 'Friday' }, ], // 第二列 [ - { text: '上午', value: 'Morning' }, - { text: '下午', value: 'Afternoon' }, - { text: '晚上', value: 'Evening' }, + { label: '上午', value: 'Morning' }, + { label: '下午', value: 'Afternoon' }, + { label: '晚上', value: 'Evening' }, ], ] const confirmPicker = ( - options: PickerOption[], - values: (string | number)[] + selectedOptions: PickerOptions, + selectedValue: PickerValue[] ) => { + console.log('confirmPicker', selectedOptions) let description = '' - options.forEach((option: any) => { - description += ` ${option.text}` + selectedOptions.forEach((option: any) => { + option?.label && (description += ` ${option.label}`) }) setMutilDesc(description) } @@ -42,14 +37,14 @@ const Demo4 = () => { setIsVisible2(!isVisible2)} + onClick={() => setVisible(!visible)} /> setIsVisible2(false)} - defaultValue={['Wednesday']} - onConfirm={(list, values) => confirmPicker(list, values)} + visible={visible} + options={options} + onClose={() => setVisible(false)} + defaultValue={defaultValue} + onConfirm={confirmPicker} /> ) diff --git a/src/packages/picker/demos/h5/demo5.tsx b/src/packages/picker/demos/h5/demo5.tsx index aeb6a2f1e0..73a72fd091 100644 --- a/src/packages/picker/demos/h5/demo5.tsx +++ b/src/packages/picker/demos/h5/demo5.tsx @@ -1,38 +1,27 @@ import React, { useState } from 'react' -import { Picker, Cell } from '@nutui/nutui-react' +import { Picker, Cell, PickerOptions, PickerValue } from '@nutui/nutui-react' -interface PickerOption { - text: string | number - value: string | number - disabled?: boolean - children?: PickerOption[] - className?: string | number -} const Demo5 = () => { - const [tileDesc, settileDesc] = useState('') const [isVisible, setIsVisible] = useState(false) - - const listData1 = [ + const [tileDesc, settileDesc] = useState('无锡市') + const options = [ [ - { value: 1, text: '南京市' }, - { value: 2, text: '无锡市' }, - { value: 3, text: '海北藏族自治区' }, - { value: 4, text: '北京市' }, - { value: 5, text: '连云港市' }, - { value: 8, text: '大庆市' }, - { value: 9, text: '绥化市' }, - { value: 10, text: '潍坊市' }, - { value: 12, text: '乌鲁木齐市' }, + { value: 1, label: '南京市' }, + { value: 2, label: '无锡市' }, + { value: 3, label: '海北藏族自治区' }, + { value: 4, label: '北京市' }, + { value: 5, label: '连云港市' }, + { value: 8, label: '大庆市' }, + { value: 9, label: '绥化市' }, + { value: 10, label: '潍坊市' }, + { value: 12, label: '乌鲁木齐市' }, ], ] - const confirmPicker = ( - options: PickerOption[], - values: (string | number)[] - ) => { + const confirmPicker = (options: PickerOptions, values: PickerValue[]) => { let description = '' options.forEach((option: any) => { - description += ` ${option.text}` + description += ` ${option.label}` }) settileDesc(description) setIsVisible(false) @@ -46,8 +35,8 @@ const Demo5 = () => { /> confirmPicker(list, values)} + options={options} + onConfirm={confirmPicker} defaultValue={[2]} threeDimensional={false} duration={1000} diff --git a/src/packages/picker/demos/h5/demo6.tsx b/src/packages/picker/demos/h5/demo6.tsx index 007a1f8352..f39d06544a 100644 --- a/src/packages/picker/demos/h5/demo6.tsx +++ b/src/packages/picker/demos/h5/demo6.tsx @@ -1,105 +1,93 @@ import React, { useState } from 'react' -import { Picker, Cell } from '@nutui/nutui-react' +import { + Picker, + Cell, + PickerOptions, + PickerValue, + PickerOption, +} from '@nutui/nutui-react' -interface PickerOption { - text: string | number - value: string | number - disabled?: boolean - children?: PickerOption[] - className?: string | number -} const Demo6 = () => { const [isVisible, setIsVisible] = useState(false) + const [value, setValue] = useState([2]) + const [cityCustom, setCityCustom] = useState('上海') const customCityData = [ - { - value: 1, - text: '北京', - children: [ - { - value: 1, - text: '朝阳区', - }, - { - value: 2, - text: '海淀区', - }, - { - value: 3, - text: '大兴区', - }, - { - value: 4, - text: '东城区', - }, - { - value: 5, - text: '西城区', - }, - { - value: 6, - text: '丰台区', - }, - ], - }, - { - value: 2, - text: '上海', - children: [ - { - value: 1, - text: '黄埔区', - }, - { - value: 2, - text: '长宁区', - }, - { - value: 3, - text: '普陀区', - }, - { - value: 4, - text: '杨浦区', - }, - { - value: 5, - text: '浦东新区', - }, - ], - }, + [ + { + value: 1, + label: '北京', + children: [ + { + value: 1, + label: '朝阳区', + }, + { + value: 2, + label: '海淀区', + }, + { + value: 3, + label: '大兴区', + }, + { + value: 4, + label: '东城区', + }, + { + value: 5, + label: '西城区', + }, + { + value: 6, + label: '丰台区', + }, + ], + }, + { + value: 2, + label: '上海', + children: [ + { + value: 1, + label: '黄埔区', + }, + { + value: 2, + label: '长宁区', + }, + { + value: 3, + label: '普陀区', + }, + { + value: 4, + label: '杨浦区', + }, + { + value: 5, + label: '浦东新区', + }, + ], + }, + ], ] - const [asyncData] = useState([ - { - value: 1, - text: '北京市', - children: [ - { value: 1, text: '朝阳区' }, - { value: 2, text: '海淀区' }, - { value: 3, text: '大兴区' }, - { value: 4, text: '东城区' }, - { value: 5, text: '西城区' }, - { value: 6, text: '丰台区' }, - ], - }, - { - value: 2, - text: '上海市', - children: [], - }, - ]) - const [cityCustom, setCityCustom] = useState('') const setChooseValueCustom = ( - options: PickerOption[], - values: (string | number)[] + selectedOptions: PickerOptions, + selectedValue: PickerValue[] ) => { - const str = options.map((item) => item.text).join('-') - setCityCustom(str) + console.log('onconfirm', selectedOptions, selectedValue) + const city = selectedOptions + .map((item: PickerOption) => item.label) + .join('-') + setCityCustom(city) + setValue(selectedValue) } + return ( <> setIsVisible(!isVisible)} /> @@ -107,13 +95,12 @@ const Demo6 = () => { setIsVisible(false)} - onConfirm={(list, values) => setChooseValueCustom(list, values)} - onChange={( - options: PickerOption[], - value: (string | number)[], - columnIndex: number - ) => console.log(asyncData, '多级联动', columnIndex, value, options)} + onConfirm={setChooseValueCustom} + onChange={({ value, index, selectedOptions }) => + console.log('多级联动', value, index, selectedOptions) + } /> ) diff --git a/src/packages/picker/demos/h5/demo7.tsx b/src/packages/picker/demos/h5/demo7.tsx index 1707e8c4aa..553359db48 100644 --- a/src/packages/picker/demos/h5/demo7.tsx +++ b/src/packages/picker/demos/h5/demo7.tsx @@ -1,77 +1,100 @@ import React, { useState } from 'react' -import { Picker, Cell } from '@nutui/nutui-react' +import { + Picker, + Cell, + PickerOptions, + PickerValue, + PickerOnChangeCallbackParameter, + PickerOption, +} from '@nutui/nutui-react' -interface PickerOption { - text: string | number - value: string | number - disabled?: boolean - children?: PickerOption[] - className?: string | number -} const Demo7 = () => { const [isVisible, setIsVisible] = useState(false) - const [asyncDesc, setasyncDesc] = useState('') + const [value, setValue] = useState([1]) + const [asyncDesc, setasyncDesc] = useState('北京') const [asyncData, setAsyncData] = useState([ - { - value: 1, - text: '北京市', - children: [ - { value: 1, text: '朝阳区' }, - { value: 2, text: '海淀区' }, - { value: 3, text: '大兴区' }, - { value: 4, text: '东城区' }, - { value: 5, text: '西城区' }, - { value: 6, text: '丰台区' }, - ], - }, - { - value: 2, - text: '上海市', - children: [], - }, + [ + { + value: 1, + label: '北京', + children: [ + { + value: 1, + label: '朝阳区', + }, + { + value: 2, + label: '海淀区', + }, + { + value: 3, + label: '大兴区', + }, + { + value: 4, + label: '东城区', + }, + { + value: 5, + label: '西城区', + }, + { + value: 6, + label: '丰台区', + }, + ], + }, + { + value: 2, + label: '上海', + children: [], + }, + ], ]) - const updateChooseValueCustmer = ( - options: PickerOption[], - values: (string | number)[], - columnIndex: number - ) => { - console.log('updateChooseValueCustmer', columnIndex, values, options) - if (columnIndex === 0 && values[0] === 2) { + const updateChooseValueCustmer = ({ + value, + index, + selectedOptions, + }: PickerOnChangeCallbackParameter) => { + if (value[0] === 2 && asyncData[0]?.[1].children.length === 0) { + console.log('updateChooseValueCustmer', index, value, selectedOptions) setTimeout(() => { - if (asyncData[1].children.length === 0) { - asyncData[1].children = [ - { - value: 1, - text: '黄埔区', - }, - { - value: 2, - text: '长宁区', - }, - { - value: 3, - text: '普陀区', - }, - { - value: 4, - text: '杨浦区', - }, - { - value: 5, - text: '浦东新区', - }, - ] - setAsyncData([...asyncData]) - } - }, 100) + asyncData[0][1].children = [ + { + value: 1, + label: '黄埔区', + }, + { + value: 2, + label: '长宁区', + }, + { + value: 3, + label: '普陀区', + }, + { + value: 4, + label: '杨浦区', + }, + { + value: 5, + label: '浦东新区', + }, + ] + setAsyncData([...[...asyncData]]) + }, 0) } } const setAsyncConfirm = ( - options: PickerOption[], - values: (string | number)[] + selectedOptions: PickerOptions, + selectedValue: PickerValue[] ) => { - const str = options.map((item) => item.text).join('-') - setasyncDesc(str) + console.log('onconfirm', selectedOptions, selectedValue) + const city = selectedOptions + .map((item: PickerOption) => item.label) + .join('-') + setasyncDesc(city) + setValue(selectedValue) } return ( @@ -81,18 +104,14 @@ const Demo7 = () => { description={asyncDesc} onClick={() => setIsVisible(!isVisible)} /> + setIsVisible(false)} - onConfirm={(list, values) => setAsyncConfirm(list, values)} - onChange={( - selectedOptions: PickerOption[], - selectedValue: (string | number)[], - columnIndex: number - ) => - updateChooseValueCustmer(selectedOptions, selectedValue, columnIndex) - } + onConfirm={setAsyncConfirm} + onChange={updateChooseValueCustmer} /> ) diff --git a/src/packages/picker/demos/h5/demo8.tsx b/src/packages/picker/demos/h5/demo8.tsx index 493b5dce06..4f16c7e357 100644 --- a/src/packages/picker/demos/h5/demo8.tsx +++ b/src/packages/picker/demos/h5/demo8.tsx @@ -1,50 +1,47 @@ import React, { useState } from 'react' -import { Picker, Cell, ConfigProvider } from '@nutui/nutui-react' +import { + Picker, + Cell, + ConfigProvider, + PickerOption, + PickerOptions, + PickerValue, +} from '@nutui/nutui-react' -interface PickerOption { - text: string | number - value: string | number - disabled?: boolean - children?: PickerOption[] - className?: string | number -} const Demo8 = () => { - const [isVisible, setIsVisible] = useState(false) + const [visible, setVisible] = useState(false) + const [baseDesc, setBaseDesc] = useState('') const options = [ [ - { value: 1, text: '南京市' }, - { value: 2, text: '无锡市' }, - { value: 3, text: '海北藏族自治区' }, - { value: 4, text: '北京市' }, - { value: 5, text: '连云港市' }, - { value: 8, text: '大庆市' }, - { value: 9, text: '绥化市' }, - { value: 10, text: '潍坊市' }, - { value: 12, text: '乌鲁木齐市' }, + { value: 1, label: '南京市' }, + { value: 2, label: '无锡市' }, + { value: 3, label: '海北藏族自治区' }, + { value: 4, label: '北京市' }, + { value: 5, label: '连云港市' }, + { value: 8, label: '大庆市' }, + { value: 9, label: '绥化市' }, + { value: 10, label: '潍坊市' }, + { value: 12, label: '乌鲁木齐市' }, ], ] - const [baseDesc, setBaseDesc] = useState('') - const confirmPicker = ( - options: PickerOption[], - values: (string | number)[] + selectedOptions: PickerOptions, + selectedValue: PickerValue[] ) => { - console.log('demo 确定', options, values) + console.log('confirmPicker', selectedOptions, selectedValue) let description = '' - options.forEach((option: any) => { - description += ` ${option.text}` + selectedOptions.forEach((option: PickerOption) => { + description += ` ${option.label}` }) setBaseDesc(description) - setIsVisible(false) } - return ( <> setIsVisible(!isVisible)} + onClick={() => setVisible(!visible)} /> { }} > confirmPicker(list, values)} - onClose={() => { - setIsVisible(false) - console.log('onclose') - }} + onConfirm={confirmPicker} + onClose={() => setVisible(false)} /> diff --git a/src/packages/picker/demos/taro/demo1.tsx b/src/packages/picker/demos/taro/demo1.tsx index f34f7003f3..94bbae0cdf 100644 --- a/src/packages/picker/demos/taro/demo1.tsx +++ b/src/packages/picker/demos/taro/demo1.tsx @@ -1,40 +1,44 @@ import React, { useState } from 'react' -import { Picker, Cell } from '@nutui/nutui-react-taro' - -interface PickerOption { - text: string | number - value: string | number - disabled?: boolean - children?: PickerOption[] - className?: string | number -} +import { + Picker, + Cell, + PickerOptions, + PickerValue, + PickerOnChangeCallbackParameter, + PickerOption, +} from '@nutui/nutui-react-taro' const Demo1 = () => { const [visible, setVisible] = useState(false) const [baseDesc, setBaseDesc] = useState('') - const listData1 = [ + const options = [ [ - { value: 1, text: '南京市' }, - { value: 2, text: '无锡市' }, - { value: 3, text: '海北藏族自治区' }, - { value: 4, text: '北京市' }, - { value: 5, text: '连云港市' }, - { value: 8, text: '大庆市' }, - { value: 9, text: '绥化市' }, - { value: 10, text: '潍坊市' }, - { value: 12, text: '乌鲁木齐市' }, + { value: 1, label: '南京市' }, + { value: 2, label: '无锡市' }, + { value: 3, label: '海北藏族自治区' }, + { value: 4, label: '北京市' }, + { value: 5, label: '连云港市' }, + { value: 8, label: '大庆市' }, + { value: 9, label: '绥化市' }, + { value: 10, label: '潍坊市' }, + { value: 12, label: '乌鲁木齐市' }, ], ] - const changePicker = (list: any[], option: any, columnIndex: number) => { - console.log(columnIndex, option) + const changePicker = ({ + value, + index, + selectedOptions, + }: PickerOnChangeCallbackParameter) => { + console.log('changePicker', value, index, selectedOptions) } const confirmPicker = ( - options: PickerOption[], - values: (string | number)[] + selectedOptions: PickerOptions, + selectedValue: PickerValue[] ) => { + console.log('confirmPicker', selectedOptions, selectedValue) let description = '' - options.forEach((option: any) => { - description += ` ${option.text}` + selectedOptions.forEach((option: PickerOption) => { + description += ` ${option.label}` }) setBaseDesc(description) } @@ -48,8 +52,8 @@ const Demo1 = () => { confirmPicker(list, values)} + options={options} + onConfirm={confirmPicker} onClose={() => setVisible(false)} onChange={changePicker} /> diff --git a/src/packages/picker/demos/taro/demo2.tsx b/src/packages/picker/demos/taro/demo2.tsx index ca6a3d4c09..f4fe925b36 100644 --- a/src/packages/picker/demos/taro/demo2.tsx +++ b/src/packages/picker/demos/taro/demo2.tsx @@ -1,54 +1,51 @@ import React, { useState } from 'react' -import { Picker, Cell } from '@nutui/nutui-react-taro' +import { + Picker, + Cell, + PickerOptions, + PickerValue, +} from '@nutui/nutui-react-taro' -interface PickerOption { - text: string | number - value: string | number - disabled?: boolean - children?: PickerOption[] - className?: string | number -} const Demo2 = () => { const [visible, setVisible] = useState(false) - const [baseDefault, setbaseDefault] = useState('') + const [baseDesc, setBaseDesc] = useState('无锡市') const [defaultValue] = useState([2]) - - const listData1 = [ + const options = [ [ - { value: 1, text: '南京市' }, - { value: 2, text: '无锡市' }, - { value: 3, text: '海北藏族自治区' }, - { value: 4, text: '北京市' }, - { value: 5, text: '连云港市' }, - { value: 8, text: '大庆市' }, - { value: 9, text: '绥化市' }, - { value: 10, text: '潍坊市' }, - { value: 12, text: '乌鲁木齐市' }, + { value: 1, label: '南京市' }, + { value: 2, label: '无锡市' }, + { value: 3, label: '海北藏族自治区' }, + { value: 4, label: '北京市' }, + { value: 5, label: '连云港市' }, + { value: 8, label: '大庆市' }, + { value: 9, label: '绥化市' }, + { value: 10, label: '潍坊市' }, + { value: 12, label: '乌鲁木齐市' }, ], ] const confirmPicker = ( - options: PickerOption[], - values: (string | number)[] + selectedOptions: PickerOptions, + selectedValue: PickerValue[] ) => { let description = '' - options.forEach((option: any) => { - description += ` ${option.text}` + selectedOptions.forEach((option: any) => { + description += ` ${option.label}` }) - setbaseDefault(description) + setBaseDesc(description) } return ( <> setVisible(!visible)} /> confirmPicker(list, values)} + options={options} + onConfirm={confirmPicker} onClose={() => setVisible(false)} /> diff --git a/src/packages/picker/demos/taro/demo3.tsx b/src/packages/picker/demos/taro/demo3.tsx index f183117990..c0cee40ba1 100644 --- a/src/packages/picker/demos/taro/demo3.tsx +++ b/src/packages/picker/demos/taro/demo3.tsx @@ -1,59 +1,69 @@ import React, { useState } from 'react' -import { Picker, Cell } from '@nutui/nutui-react-taro' +import { + Picker, + Cell, + PickerOptions, + PickerValue, +} from '@nutui/nutui-react-taro' +import isEqual from 'react-fast-compare' +import { PickerOnChangeCallbackParameter } from '@/packages/pickerview/types' -interface PickerOption { - text: string | number - value: string | number - disabled?: boolean - children?: PickerOption[] - className?: string | number -} const Demo3 = () => { - const [isVisible, setIsVisible] = useState(false) + const [visible, setVisible] = useState(false) const [baseDesc, setBaseDesc] = useState('') - const [val, setVal] = useState>([]) + const [value, setValue] = useState([] as PickerValue[]) const options = [ [ - { value: 1, text: '南京市' }, - { value: 2, text: '无锡市' }, - { value: 3, text: '海北藏族自治区' }, - { value: 4, text: '北京市' }, - { value: 5, text: '连云港市' }, - { value: 8, text: '大庆市' }, - { value: 9, text: '绥化市' }, - { value: 10, text: '潍坊市' }, - { value: 12, text: '乌鲁木齐市' }, + { value: 1, label: '南京市' }, + { value: 2, label: '无锡市' }, + { value: 3, label: '海北藏族自治区' }, + { value: 4, label: '北京市' }, + { value: 5, label: '连云港市' }, + { value: 8, label: '大庆市' }, + { value: 9, label: '绥化市' }, + { value: 10, label: '潍坊市' }, + { value: 12, label: '乌鲁木齐市' }, ], ] + + const changePicker = ({ + value, + index, + selectedOptions, + }: PickerOnChangeCallbackParameter) => { + console.log('changePicker', value, index, selectedOptions) + } const confirmPicker = ( - options: PickerOption[], - values: (string | number)[] + selectedOptions: PickerOptions, + selectedValue: PickerValue[] ) => { - let description = '' - options.forEach((option: any) => { - description += ` ${option.text}` - }) - setBaseDesc(description) + if (isEqual(selectedValue, [3])) { + setValue([1]) + setBaseDesc('南京市') + } else { + setValue(selectedValue) + let description = '' + selectedOptions.forEach((option: any) => { + description += ` ${option.label}` + }) + setBaseDesc(description) + } } return ( <> setIsVisible(!isVisible)} + onClick={() => setVisible(!visible)} /> { - confirmPicker(list, values) - setVal(values) - }} - onClose={() => { - setIsVisible(false) - }} + onChange={changePicker} + onConfirm={confirmPicker} + onClose={() => setVisible(false)} /> ) diff --git a/src/packages/picker/demos/taro/demo4.tsx b/src/packages/picker/demos/taro/demo4.tsx index 79992790c3..ea0cfdfab9 100644 --- a/src/packages/picker/demos/taro/demo4.tsx +++ b/src/packages/picker/demos/taro/demo4.tsx @@ -1,59 +1,55 @@ import React, { useState } from 'react' -import { Picker, Cell } from '@nutui/nutui-react-taro' +import { + Picker, + Cell, + PickerOptions, + PickerValue, +} from '@nutui/nutui-react-taro' -interface PickerOption { - text: string | number - value: string | number - disabled?: boolean - children?: PickerOption[] - className?: string | number -} const Demo4 = () => { - const [isVisible2, setIsVisible2] = useState(false) - const [mutilDesc, setMutilDesc] = useState('') - const listData2 = [ + const [visible, setVisible] = useState(false) + const [mutilDesc, setMutilDesc] = useState('周三') + const [defaultValue] = useState(['Wednesday']) + const options = [ // 第一列 [ - { text: '周一', value: 'Monday' }, - { text: '周二', value: 'Tuesday' }, - { text: '周三', value: 'Wednesday' }, - { text: '周四', value: 'Thursday' }, - { text: '周五', value: 'Friday' }, + { label: '周一', value: 'Monday' }, + { label: '周二', value: 'Tuesday' }, + { label: '周三', value: 'Wednesday' }, + { label: '周四', value: 'Thursday' }, + { label: '周五', value: 'Friday' }, ], // 第二列 [ - { text: '上午', value: 'Morning' }, - { text: '下午', value: 'Afternoon' }, - { text: '晚上', value: 'Evening' }, + { label: '上午', value: 'Morning' }, + { label: '下午', value: 'Afternoon' }, + { label: '晚上', value: 'Evening' }, ], ] const confirmPicker = ( - options: PickerOption[], - values: (string | number)[] + selectedOptions: PickerOptions, + selectedValue: PickerValue[] ) => { + console.log('confirmPicker', selectedOptions) let description = '' - options.forEach((option: any) => { - description += ` ${option.text}` + selectedOptions.forEach((option: any) => { + option?.label && (description += ` ${option.label}`) }) setMutilDesc(description) } - const changePicker = (options: any[], values: any, columnIndex: number) => { - console.log('picker onChange', columnIndex, values, options) - } return ( <> setIsVisible2(!isVisible2)} + onClick={() => setVisible(!visible)} /> setIsVisible2(false)} - defaultValue={['Wednesday']} - onChange={changePicker} - onConfirm={(list, values) => confirmPicker(list, values)} + visible={visible} + options={options} + onClose={() => setVisible(false)} + defaultValue={defaultValue} + onConfirm={confirmPicker} /> ) diff --git a/src/packages/picker/demos/taro/demo5.tsx b/src/packages/picker/demos/taro/demo5.tsx index df1c6c3d36..cd4fcd0af9 100644 --- a/src/packages/picker/demos/taro/demo5.tsx +++ b/src/packages/picker/demos/taro/demo5.tsx @@ -1,45 +1,36 @@ import React, { useState } from 'react' -import { Picker, Cell } from '@nutui/nutui-react-taro' +import { + Picker, + Cell, + PickerOptions, + PickerValue, +} from '@nutui/nutui-react-taro' -interface PickerOption { - text: string | number - value: string | number - disabled?: boolean - children?: PickerOption[] - className?: string | number -} const Demo5 = () => { - const [tileDesc, settileDesc] = useState('') const [isVisible, setIsVisible] = useState(false) - - const listData1 = [ + const [tileDesc, settileDesc] = useState('无锡市') + const options = [ [ - { value: 1, text: '南京市' }, - { value: 2, text: '无锡市' }, - { value: 3, text: '海北藏族自治区' }, - { value: 4, text: '北京市' }, - { value: 5, text: '连云港市' }, - { value: 8, text: '大庆市' }, - { value: 9, text: '绥化市' }, - { value: 10, text: '潍坊市' }, - { value: 12, text: '乌鲁木齐市' }, + { value: 1, label: '南京市' }, + { value: 2, label: '无锡市' }, + { value: 3, label: '海北藏族自治区' }, + { value: 4, label: '北京市' }, + { value: 5, label: '连云港市' }, + { value: 8, label: '大庆市' }, + { value: 9, label: '绥化市' }, + { value: 10, label: '潍坊市' }, + { value: 12, label: '乌鲁木齐市' }, ], ] - const confirmPicker = ( - options: PickerOption[], - values: (string | number)[] - ) => { + const confirmPicker = (options: PickerOptions, values: PickerValue[]) => { let description = '' options.forEach((option: any) => { - description += ` ${option.text}` + description += ` ${option.label}` }) settileDesc(description) setIsVisible(false) } - const changePicker = (options: any[], values: any, columnIndex: number) => { - console.log('picker onChange', columnIndex, values, options) - } return ( <> { /> confirmPicker(list, values)} + options={options} + onConfirm={confirmPicker} defaultValue={[2]} threeDimensional={false} duration={1000} onClose={() => setIsVisible(false)} - onChange={changePicker} /> ) diff --git a/src/packages/picker/demos/taro/demo6.tsx b/src/packages/picker/demos/taro/demo6.tsx index 3c3e880622..64f6bf4ba9 100644 --- a/src/packages/picker/demos/taro/demo6.tsx +++ b/src/packages/picker/demos/taro/demo6.tsx @@ -1,105 +1,93 @@ import React, { useState } from 'react' -import { Picker, Cell } from '@nutui/nutui-react-taro' +import { + Picker, + Cell, + PickerOptions, + PickerValue, + PickerOption, +} from '@nutui/nutui-react-taro' -interface PickerOption { - text: string | number - value: string | number - disabled?: boolean - children?: PickerOption[] - className?: string | number -} const Demo6 = () => { const [isVisible, setIsVisible] = useState(false) + const [value, setValue] = useState([2]) + const [cityCustom, setCityCustom] = useState('上海') const customCityData = [ - { - value: 1, - text: '北京', - children: [ - { - value: 1, - text: '朝阳区', - }, - { - value: 2, - text: '海淀区', - }, - { - value: 3, - text: '大兴区', - }, - { - value: 4, - text: '东城区', - }, - { - value: 5, - text: '西城区', - }, - { - value: 6, - text: '丰台区', - }, - ], - }, - { - value: 2, - text: '上海', - children: [ - { - value: 1, - text: '黄埔区', - }, - { - value: 2, - text: '长宁区', - }, - { - value: 3, - text: '普陀区', - }, - { - value: 4, - text: '杨浦区', - }, - { - value: 5, - text: '浦东新区', - }, - ], - }, + [ + { + value: 1, + label: '北京', + children: [ + { + value: 1, + label: '朝阳区', + }, + { + value: 2, + label: '海淀区', + }, + { + value: 3, + label: '大兴区', + }, + { + value: 4, + label: '东城区', + }, + { + value: 5, + label: '西城区', + }, + { + value: 6, + label: '丰台区', + }, + ], + }, + { + value: 2, + label: '上海', + children: [ + { + value: 1, + label: '黄埔区', + }, + { + value: 2, + label: '长宁区', + }, + { + value: 3, + label: '普陀区', + }, + { + value: 4, + label: '杨浦区', + }, + { + value: 5, + label: '浦东新区', + }, + ], + }, + ], ] - const [asyncData] = useState([ - { - value: 1, - text: '北京市', - children: [ - { value: 1, text: '朝阳区' }, - { value: 2, text: '海淀区' }, - { value: 3, text: '大兴区' }, - { value: 4, text: '东城区' }, - { value: 5, text: '西城区' }, - { value: 6, text: '丰台区' }, - ], - }, - { - value: 2, - text: '上海市', - children: [], - }, - ]) - const [cityCustom, setCityCustom] = useState('') const setChooseValueCustom = ( - options: PickerOption[], - values: (string | number)[] + selectedOptions: PickerOptions, + selectedValue: PickerValue[] ) => { - const str = options.map((item) => item.text).join('-') - setCityCustom(str) + console.log('onconfirm', selectedOptions, selectedValue) + const city = selectedOptions + .map((item: PickerOption) => item.label) + .join('-') + setCityCustom(city) + setValue(selectedValue) } + return ( <> setIsVisible(!isVisible)} /> @@ -107,13 +95,12 @@ const Demo6 = () => { setIsVisible(false)} - onConfirm={(list, values) => setChooseValueCustom(list, values)} - onChange={( - options: PickerOption[], - value: (string | number)[], - columnIndex: number - ) => console.log(asyncData, '多级联动', columnIndex, value, options)} + onConfirm={setChooseValueCustom} + onChange={({ value, index, selectedOptions }) => + console.log('多级联动', value, index, selectedOptions) + } /> ) diff --git a/src/packages/picker/demos/taro/demo7.tsx b/src/packages/picker/demos/taro/demo7.tsx index 2bd3af5785..2071f0010f 100644 --- a/src/packages/picker/demos/taro/demo7.tsx +++ b/src/packages/picker/demos/taro/demo7.tsx @@ -1,77 +1,100 @@ import React, { useState } from 'react' -import { Picker, Cell } from '@nutui/nutui-react-taro' +import { + Picker, + Cell, + PickerOptions, + PickerValue, + PickerOnChangeCallbackParameter, + PickerOption, +} from '@nutui/nutui-react-taro' -interface PickerOption { - text: string | number - value: string | number - disabled?: boolean - children?: PickerOption[] - className?: string | number -} const Demo7 = () => { const [isVisible, setIsVisible] = useState(false) - const [asyncDesc, setasyncDesc] = useState('') + const [value, setValue] = useState([1]) + const [asyncDesc, setasyncDesc] = useState('北京') const [asyncData, setAsyncData] = useState([ - { - value: 1, - text: '北京市', - children: [ - { value: 1, text: '朝阳区' }, - { value: 2, text: '海淀区' }, - { value: 3, text: '大兴区' }, - { value: 4, text: '东城区' }, - { value: 5, text: '西城区' }, - { value: 6, text: '丰台区' }, - ], - }, - { - value: 2, - text: '上海市', - children: [], - }, + [ + { + value: 1, + label: '北京', + children: [ + { + value: 1, + label: '朝阳区', + }, + { + value: 2, + label: '海淀区', + }, + { + value: 3, + label: '大兴区', + }, + { + value: 4, + label: '东城区', + }, + { + value: 5, + label: '西城区', + }, + { + value: 6, + label: '丰台区', + }, + ], + }, + { + value: 2, + label: '上海', + children: [], + }, + ], ]) - const updateChooseValueCustmer = ( - options: PickerOption[], - values: (string | number)[], - columnIndex: number - ) => { - console.log('updateChooseValueCustmer', columnIndex, values, options) - if (columnIndex === 0 && values[0] === 2) { + const updateChooseValueCustmer = ({ + value, + index, + selectedOptions, + }: PickerOnChangeCallbackParameter) => { + if (value[0] === 2 && asyncData[0]?.[1].children.length === 0) { + console.log('updateChooseValueCustmer', index, value, selectedOptions) setTimeout(() => { - if (asyncData[1].children.length === 0) { - asyncData[1].children = [ - { - value: 1, - text: '黄埔区', - }, - { - value: 2, - text: '长宁区', - }, - { - value: 3, - text: '普陀区', - }, - { - value: 4, - text: '杨浦区', - }, - { - value: 5, - text: '浦东新区', - }, - ] - setAsyncData([...asyncData]) - } - }, 100) + asyncData[0][1].children = [ + { + value: 1, + label: '黄埔区', + }, + { + value: 2, + label: '长宁区', + }, + { + value: 3, + label: '普陀区', + }, + { + value: 4, + label: '杨浦区', + }, + { + value: 5, + label: '浦东新区', + }, + ] + setAsyncData([...[...asyncData]]) + }, 0) } } const setAsyncConfirm = ( - options: PickerOption[], - values: (string | number)[] + selectedOptions: PickerOptions, + selectedValue: PickerValue[] ) => { - const str = options.map((item) => item.text).join('-') - setasyncDesc(str) + console.log('onconfirm', selectedOptions, selectedValue) + const city = selectedOptions + .map((item: PickerOption) => item.label) + .join('-') + setasyncDesc(city) + setValue(selectedValue) } return ( @@ -81,18 +104,14 @@ const Demo7 = () => { description={asyncDesc} onClick={() => setIsVisible(!isVisible)} /> + setIsVisible(false)} - onConfirm={(list, values) => setAsyncConfirm(list, values)} - onChange={( - selectedOptions: PickerOption[], - selectedValue: (string | number)[], - columnIndex: number - ) => - updateChooseValueCustmer(selectedOptions, selectedValue, columnIndex) - } + onConfirm={setAsyncConfirm} + onChange={updateChooseValueCustmer} /> ) diff --git a/src/packages/picker/demos/taro/demo8.tsx b/src/packages/picker/demos/taro/demo8.tsx index 029c6a2d79..5cb9b00514 100644 --- a/src/packages/picker/demos/taro/demo8.tsx +++ b/src/packages/picker/demos/taro/demo8.tsx @@ -1,50 +1,47 @@ import React, { useState } from 'react' -import { Picker, Cell, ConfigProvider } from '@nutui/nutui-react-taro' +import { + Picker, + Cell, + ConfigProvider, + PickerOption, + PickerOptions, + PickerValue, +} from '@nutui/nutui-react-taro' -interface PickerOption { - text: string | number - value: string | number - disabled?: boolean - children?: PickerOption[] - className?: string | number -} const Demo8 = () => { - const [isVisible, setIsVisible] = useState(false) + const [visible, setVisible] = useState(false) + const [baseDesc, setBaseDesc] = useState('') const options = [ [ - { value: 1, text: '南京市' }, - { value: 2, text: '无锡市' }, - { value: 3, text: '海北藏族自治区' }, - { value: 4, text: '北京市' }, - { value: 5, text: '连云港市' }, - { value: 8, text: '大庆市' }, - { value: 9, text: '绥化市' }, - { value: 10, text: '潍坊市' }, - { value: 12, text: '乌鲁木齐市' }, + { value: 1, label: '南京市' }, + { value: 2, label: '无锡市' }, + { value: 3, label: '海北藏族自治区' }, + { value: 4, label: '北京市' }, + { value: 5, label: '连云港市' }, + { value: 8, label: '大庆市' }, + { value: 9, label: '绥化市' }, + { value: 10, label: '潍坊市' }, + { value: 12, label: '乌鲁木齐市' }, ], ] - const [baseDesc, setBaseDesc] = useState('') - const confirmPicker = ( - options: PickerOption[], - values: (string | number)[] + selectedOptions: PickerOptions, + selectedValue: PickerValue[] ) => { - console.log('demo 确定', options, values) + console.log('confirmPicker', selectedOptions, selectedValue) let description = '' - options.forEach((option: any) => { - description += ` ${option.text}` + selectedOptions.forEach((option: PickerOption) => { + description += ` ${option.label}` }) setBaseDesc(description) - setIsVisible(false) } - return ( <> setIsVisible(!isVisible)} + onClick={() => setVisible(!visible)} /> { }} > confirmPicker(list, values)} - onClose={() => { - setIsVisible(false) - console.log('onclose') - }} + onConfirm={confirmPicker} + onClose={() => setVisible(false)} /> diff --git a/src/packages/picker/index.taro.ts b/src/packages/picker/index.taro.ts index edc33812b3..ff0b062781 100644 --- a/src/packages/picker/index.taro.ts +++ b/src/packages/picker/index.taro.ts @@ -1,5 +1,4 @@ import Picker from './picker.taro' -export type { PickerOption } from './types' export type { PickerProps } from './picker.taro' export default Picker diff --git a/src/packages/picker/index.ts b/src/packages/picker/index.ts index 2f320e8d33..212b25cb51 100644 --- a/src/packages/picker/index.ts +++ b/src/packages/picker/index.ts @@ -1,5 +1,4 @@ import Picker from './picker' -export type { PickerOption } from './types' export type { PickerProps } from './picker' export default Picker diff --git a/src/packages/picker/picker.scss b/src/packages/picker/picker.scss index 6516efc1bf..a95a838b80 100644 --- a/src/packages/picker/picker.scss +++ b/src/packages/picker/picker.scss @@ -6,11 +6,12 @@ &-control { display: flex; - height: $popup-title-height; - font-size: $popup-title-font-size; align-items: center; justify-content: space-between; + height: $popup-title-height; padding: $popup-title-padding; + box-sizing: border-box; + font-size: $popup-title-font-size; } &-cancel-btn { @@ -36,135 +37,5 @@ &-panel { display: flex; - position: relative; - } - - &-indicator { - position: absolute; - top: 108px; - height: $picker-item-height; - width: 100%; - border: $picker-item-active-line-border; - border-left: 0; - border-right: 0; - color: $picker-item-text-color; - font-size: $picker-item-text-font-size; - z-index: 3; - - &-taro { - height: $picker-item-height; - border: 0; - - &::before, - &::after { - border: $picker-item-active-line-border; - border-left: 0; - border-right: 0; - } - } - } - - &-list { - flex: 1; - position: relative; - height: $picker-list-height; - overflow: hidden; - text-align: center; - } - - &-list-panel { - transform-style: preserve-3d; - } - - &-mask { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - background-image: $picker-mask-background; - background-position: top, bottom; - background-size: 100% 108px; - background-repeat: no-repeat; - transform: translateZ(0); - z-index: 3; - } - - &-view-panel { - height: $picker-list-height; - flex-grow: 1; - } - - &-content, - &-roller { - position: absolute; - top: 108px; - width: 100%; - height: $picker-item-height; - } - - &-content { - background: #fff; - z-index: 2; - overflow: hidden; - } - - &-item, - &-roller-item { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - height: $picker-item-height; - line-height: $picker-item-height; - color: $picker-item-text-color; - font-size: $picker-item-text-font-size; - text-align: center; - } - - &-item { - font-size: 16px; - background: #fff; } - - &-roller { - z-index: 1; - transform-style: preserve-3d; - } - - &-roller-item { - backface-visibility: hidden; - -moz-backface-visibility: hidden; - -webkit-backface-visibility: hidden; - position: absolute; - top: 0; - width: 100%; - } - - &-roller-item-title { - display: block; - width: 100%; - height: $picker-item-height; - line-height: $picker-item-height; - text-align: center; - color: $color-title; - font-size: $font-size-base; - } - - &-roller-item-hidden { - visibility: hidden; - opacity: 0; - } - - &-placeholder { - height: 1px; - } -} - -[dir='rtl'] .nut-picker-mask, -.nut-rtl .nut-picker-mask { - background-image: var( - --picker-mask-background, - linear-gradient(-180deg, var(--nutui-white-12), var(--nutui-white-7)), - linear-gradient(0deg, var(--nutui-white-12), var(--nutui-white-7)) - ); } diff --git a/src/packages/picker/picker.taro.tsx b/src/packages/picker/picker.taro.tsx index 19c1fff276..cba096362d 100644 --- a/src/packages/picker/picker.taro.tsx +++ b/src/packages/picker/picker.taro.tsx @@ -2,73 +2,64 @@ import React, { useState, useEffect, useRef, - RefObject, ForwardRefRenderFunction, useImperativeHandle, } from 'react' +import { View } from '@tarojs/components' import classNames from 'classnames' -import Taro from '@tarojs/taro' -import { View, PickerView, PickerViewColumn } from '@tarojs/components' +import isEqual from 'react-fast-compare' +import { + PickerOptions, + PickerValue, + PickerOption, + PickerOnChangeCallbackParameter, +} from '@/packages/pickerview/types' +import PickerView from '@/packages/pickerview/index.taro' import Popup, { PopupProps } from '@/packages/popup/index.taro' -import PickerPanel from './pickerpanel.taro' +import SafeArea from '@/packages/safearea/index.taro' import useRefs from '@/hooks/use-refs' import { useConfig } from '@/packages/configprovider/index.taro' -import { PickerOption } from './types' import { usePropsValue } from '@/hooks/use-props-value' import { BasicComponent, ComponentDefaults } from '@/utils/typings' - -export type PickerActions = { - open: () => void - close: () => void -} +import { PickerActions, PickerRef } from './types' export interface PickerProps extends Omit { visible?: boolean | undefined title?: string - options: (PickerOption | PickerOption[])[] - value?: (number | string)[] - defaultValue?: (number | string)[] + options: PickerOptions[] + value?: PickerValue[] + defaultValue?: PickerValue[] threeDimensional?: boolean duration: number | string closeOnOverlayClick: boolean + renderLabel?: (item: PickerOption) => React.ReactNode + popupProps: Partial< Omit > onConfirm?: ( - selectedOptions: PickerOption[], - selectedValue: (string | number)[] + selectedOptions: PickerOptions, + selectedValue: PickerValue[] ) => void onCancel?: () => void onClose?: ( - selectedOptions: PickerOption[], - selectedValue: (string | number)[] - ) => void - afterClose?: ( - selectedOptions: PickerOption[], - selectedValue: (string | number)[], - pickerRef: RefObject - ) => void - onChange?: ( - selectedOptions: PickerOption[], - selectedValue: (string | number)[], - columnIndex: number + selectedOptions: PickerOptions, + selectedValue: PickerValue[] ) => void + onChange?: (args0: PickerOnChangeCallbackParameter) => void children?: any } const defaultProps = { ...ComponentDefaults, - visible: false, title: '', options: [], - value: [], + value: undefined, defaultValue: [], - threeDimensional: true, closeOnOverlayClick: true, - duration: 1000, } as unknown as PickerProps const InternalPicker: ForwardRefRenderFunction< - unknown, + PickerRef, Partial > = (props, ref) => { const { locale } = useConfig() @@ -87,37 +78,29 @@ const InternalPicker: ForwardRefRenderFunction< onConfirm, onCancel, onClose, - afterClose, onChange, ...rest } = { ...defaultProps, ...props } const classPrefix = 'nut-picker' const classes = classNames(classPrefix, className) - const [selectedValue, setSelectedValue] = usePropsValue< - Array - >({ + const [selectedValue, setSelectedValue] = usePropsValue({ value: props.value, defaultValue: [...defaultValue], finalValue: [...defaultValue], - onChange: (val) => { - props.onConfirm?.(setSelectedOptions(), val) + onChange: (value: PickerValue[]) => { + props.onConfirm?.(selectedOptionsRef.current, value) }, }) const [innerVisible, setInnerVisible] = usePropsValue({ value: props.visible, defaultValue: false, finalValue: false, - onChange: (val: boolean) => { - props.onClose?.(setSelectedOptions(), innerValue) + onChange: (v: boolean) => { + if (!v) { + props.onClose?.(selectedOptionsRef.current, innerValue) + } }, }) - const [innerValue, setInnerValue] = useState(selectedValue) - const [currentValue, setCurrentValue] = useState([]) - const [columnIndex, setColumnIndex] = useState(0) // 选中列 - const pickerRef = useRef(null) - const [refs, setRefs] = useRefs() - const [columnsList, setColumnsList] = useState([]) // 格式化后每一列的数据 - const isConfirmEvent = useRef(false) const actions: PickerActions = { open: () => { @@ -127,190 +110,56 @@ const InternalPicker: ForwardRefRenderFunction< setInnerVisible(false) }, } - useImperativeHandle(ref, () => actions) - // 级联数据格式化 - const formatCascade = ( - columns: PickerOption[], - values: (number | string)[] - ) => { - const formatted: PickerOption[][] = [] - let columnOptions: PickerOption = { - text: '', - value: '', - children: columns, - } - - let columnIndex = 0 - while (columnOptions && columnOptions.children) { - const options: PickerOption[] = columnOptions.children - const value = values[columnIndex] - let index = options.findIndex((columnItem) => columnItem.value === value) - if (index === -1) index = 0 - columnOptions = columnOptions.children[index] - columnIndex++ - formatted.push(options) - } - return formatted - } - - // 数据类型:多列、嵌套、单列 - const columnsType = () => { - const firstColumn: PickerOption | PickerOption[] = options[0] - if (firstColumn) { - if (Array.isArray(firstColumn)) { - return 'multiple' - } - if ('children' in firstColumn) { - return 'cascade' - } - } - return 'single' - } - - // 传入的数据格式化 - const normalListData = (innerValue: any) => { - const type = columnsType() - switch (type) { - case 'multiple': - return options - case 'cascade': - // 级联数据处理 - return formatCascade(options as PickerOption[], innerValue) - default: - return [options] - } - } - const init = () => { - const normalData: PickerOption[][] = normalListData( - innerValue - ) as PickerOption[][] - setColumnsList(normalData) - // 初始化默认选中数据 - const data: (string | number)[] = [] - normalData.length > 0 && - normalData.map((item) => { - item[0] && data.push(item[0].value) - return item - }) - if (!innerValue.length && innerValue.length === 0) { - setInnerValue([...data]) - } - } - - useEffect(() => { - setInnerValue(innerValue !== selectedValue ? selectedValue : innerValue) - }, [innerVisible, selectedValue]) + const [innerValue, setInnerValue] = useState([...selectedValue]) + const innerValueRef = useRef(innerValue) + const [innerOptions, setInnerOptions] = useState([]) + const selectedOptionsRef = useRef([] as PickerOptions) + const [refs, setRefs] = useRefs() useEffect(() => { if (innerVisible) { - init() + setInnerValue(selectedValue) + setInnerOptions(options as PickerOptions[]) } - }, [options, innerVisible]) - - // 选中值进行修改 - useEffect(() => { - if (!innerVisible) { - return + }, [selectedValue, innerOptions, innerVisible]) + + const onChangeItem = ({ + value, + index, + selectedOptions, + }: PickerOnChangeCallbackParameter) => { + if (selectedOptions?.length) { + selectedOptionsRef.current = selectedOptions } - Taro.getEnv() !== 'WEB' && setCurrentValue(defaultValuesConvert()) - onChange && onChange(setSelectedOptions(), innerValue, columnIndex) - }, [innerValue, columnsList, innerVisible]) - - const setSelectedOptions = () => { - const options: PickerOption[] = [] - let currOptions = [] - columnsList.forEach((columnOptions: PickerOption[], index: number) => { - currOptions = columnOptions.filter( - (item) => item.value === innerValue[index] - ) - if (currOptions[0]) { - options.push(currOptions[0]) - } else { - columnOptions[0] && options.push(columnOptions[0]) - } - }) - return options - } - - const defaultValuesConvert = () => { - const defaultIndexs: number[] = [] - if (innerValue.length > 0) { - innerValue.forEach((value, index) => { - for (let i = 0; i < columnsList?.[index]?.length; i++) { - if (columnsList[index][i].value === value) { - defaultIndexs.push(i) - break - } - } - }) - } else if (columnsList && columnsList.length > 0) { - columnsList.forEach((item) => { - defaultIndexs.push(0) - item.length > 0 && selectedValue.push(item[0].value) + if (isEqual(value, innerValueRef.current)) return + innerValueRef.current = value + setInnerValue(value) + innerVisible && + onChange?.({ + selectedOptions, + value, + index, }) - } - - return defaultIndexs } - // 更新已选择数据 - const chooseItem = (columnOptions: PickerOption, columnIndex: number) => { - const values: any = [] - const start = columnIndex - if (columnOptions && Object.keys(columnOptions).length) { - // 切换数据后,数据有变动才触发。 - if (values[columnIndex] !== columnOptions.value) { - if (columnsType() === 'cascade') { - values[columnIndex] = columnOptions.value || '' - while (columnOptions?.children?.[0]) { - values[columnIndex + 1] = columnOptions.children[0].value - columnIndex++ - columnOptions = columnOptions.children[0] - } - // 当前改变列的下一列 children 值为空 - if (columnOptions?.children?.length) { - values[columnIndex + 1] = '' - } - const combineResult = [ - ...innerValue.slice(0, start), - ...values.splice(start), - ] - setInnerValue(combineResult) - setColumnsList(normalListData(combineResult) as PickerOption[][]) - } else { - setInnerValue((data: (number | string)[]) => { - const cdata: (number | string)[] = [...data] - cdata[columnIndex] = Object.prototype.hasOwnProperty.call( - columnOptions, - 'value' - ) - ? columnOptions.value - : '' - return cdata - }) - } - setColumnIndex(columnIndex) - } - } - } - // 点击确定 - const confirm = () => { + const onConfirmEvent = () => { let moving = false refs.forEach((ref: any) => { if (ref.moving) moving = true ref.stopMomentum() }) - if (moving) { - isConfirmEvent.current = true - } else { + if (!moving) { setSelectedValue(innerValue, true) setInnerVisible(false) } - setTimeout(() => { - isConfirmEvent.current = false - }, 0) + } + + const onCancelEvent = () => { + setInnerValue(selectedValue) + onCancel?.() + setInnerVisible(false) } const renderTitleBar = () => { @@ -320,8 +169,7 @@ const InternalPicker: ForwardRefRenderFunction< className={`${classPrefix}-cancel-btn`} onClick={(e) => { e.stopPropagation() - onCancel?.() - setInnerVisible(false) + onCancelEvent() }} > {locale?.cancel} @@ -331,7 +179,7 @@ const InternalPicker: ForwardRefRenderFunction< className={`${classPrefix}-confirm-btn`} onClick={(e) => { e.stopPropagation() - confirm() + onConfirmEvent() }} > {locale.confirm} @@ -340,32 +188,28 @@ const InternalPicker: ForwardRefRenderFunction< ) } - const [, setPickingStatus] = useState(false) - - const pickerStart = () => { - setPickingStatus(true) - } - - const pickerEnd = () => { - setPickingStatus(false) - } - - const pickerChange = (data: any) => { - const prevDefaultValue = currentValue - let changeIndex = 0 - // 判断变化的是第几个 - const list = data.detail.value - for (let i = 0, len = list.length; i < len; i++) { - if (prevDefaultValue[i] !== list[i]) { - changeIndex = i - break - } - } - - // 选择的是哪个 option - chooseItem( - columnsList[changeIndex][data.detail.value[changeIndex]], - changeIndex + const renderPickerElement = () => { + return ( + + {renderTitleBar()} + {typeof children !== 'function' && children} + + { + onChangeItem({ value, index, selectedOptions }) + }} + /> + + ) } @@ -377,72 +221,16 @@ const InternalPicker: ForwardRefRenderFunction< visible={innerVisible} position="bottom" onOverlayClick={() => { - if (closeOnOverlayClick) { - props.onCancel?.() - setInnerVisible(false) - } - }} - afterClose={() => { - afterClose?.(setSelectedOptions(), innerValue, pickerRef) + if (!closeOnOverlayClick) return + onCancelEvent() }} > - - {renderTitleBar()} - {typeof children !== 'function' && children} - - {Taro.getEnv() === 'WEB' ? ( - columnsList?.map((item, index) => { - return ( - - chooseItem(value, index) - } - duration={duration} - key={index} - keyIndex={index} - itemShow={visible} - /> - ) - }) - ) : ( - - {columnsList?.map((columnOptions, index) => { - return ( - - {columnOptions.map((item, index) => { - return ( - - <>{item.text} - - ) - })} - - ) - })} - - )} - - + {innerVisible ? <>{renderPickerElement()} : null} + ) } -const Picker = React.forwardRef>(InternalPicker) +const Picker = React.forwardRef>(InternalPicker) export default Picker diff --git a/src/packages/picker/picker.tsx b/src/packages/picker/picker.tsx index 3ffbb5c2e0..a2a965bfc6 100644 --- a/src/packages/picker/picker.tsx +++ b/src/packages/picker/picker.tsx @@ -2,56 +2,50 @@ import React, { useState, useEffect, useRef, - RefObject, ForwardRefRenderFunction, useImperativeHandle, } from 'react' import classNames from 'classnames' +import isEqual from 'react-fast-compare' +import { + PickerOptions, + PickerValue, + PickerOption, + PickerOnChangeCallbackParameter, +} from '@/packages/pickerview/types' +import PickerView from '@/packages/pickerview/index' import Popup, { PopupProps } from '@/packages/popup/index' -import { SafeArea } from '@/packages/safearea/safearea' -import PickerPanel from './pickerpanel' +import SafeArea from '@/packages/safearea/index' import useRefs from '@/hooks/use-refs' import { useConfig } from '@/packages/configprovider' -import { PickerOption } from './types' import { usePropsValue } from '@/hooks/use-props-value' import { BasicComponent, ComponentDefaults } from '@/utils/typings' - -export type PickerActions = { - open: () => void - close: () => void -} +import { PickerActions, PickerRef } from './types' export interface PickerProps extends Omit { visible?: boolean | undefined title?: string - options: (PickerOption | PickerOption[])[] - value?: (number | string)[] - defaultValue?: (number | string)[] + options: PickerOptions[] + value?: PickerValue[] + defaultValue?: PickerValue[] threeDimensional?: boolean duration: number | string closeOnOverlayClick: boolean + renderLabel?: (item: PickerOption) => React.ReactNode + popupProps: Partial< Omit > onConfirm?: ( - selectedOptions: PickerOption[], - selectedValue: (string | number)[] + selectedOptions: PickerOptions, + selectedValue: PickerValue[] ) => void onCancel?: () => void onClose?: ( - selectedOptions: PickerOption[], - selectedValue: (string | number)[] - ) => void - afterClose?: ( - selectedOptions: PickerOption[], - selectedValue: (string | number)[], - pickerRef: RefObject - ) => void - onChange?: ( - selectedOptions: PickerOption[], - selectedValue: (string | number)[], - columnIndex: number + selectedOptions: PickerOptions, + selectedValue: PickerValue[] ) => void + onChange?: (args0: PickerOnChangeCallbackParameter) => void children?: any } @@ -59,14 +53,12 @@ const defaultProps = { ...ComponentDefaults, title: '', options: [], - value: [], + value: undefined, defaultValue: [], - threeDimensional: true, closeOnOverlayClick: true, - duration: 1000, } as unknown as PickerProps const InternalPicker: ForwardRefRenderFunction< - unknown, + PickerRef, Partial > = (props, ref) => { const { locale } = useConfig() @@ -85,36 +77,29 @@ const InternalPicker: ForwardRefRenderFunction< onConfirm, onCancel, onClose, - afterClose, onChange, ...rest } = { ...defaultProps, ...props } const classPrefix = 'nut-picker' const classes = classNames(classPrefix, className) - const [selectedValue, setSelectedValue] = usePropsValue< - Array - >({ + const [selectedValue, setSelectedValue] = usePropsValue({ value: props.value, defaultValue: [...defaultValue], finalValue: [...defaultValue], - onChange: (val: (string | number)[]) => { - props.onConfirm?.(setSelectedOptions(), val) + onChange: (value: PickerValue[]) => { + props.onConfirm?.(selectedOptionsRef.current, value) }, }) const [innerVisible, setInnerVisible] = usePropsValue({ value: props.visible, defaultValue: false, finalValue: false, - onChange: (val: boolean) => { - props.onClose?.(setSelectedOptions(), innerValue) + onChange: (v: boolean) => { + if (!v) { + props.onClose?.(selectedOptionsRef.current, innerValue) + } }, }) - const [innerValue, setInnerValue] = useState(selectedValue) - const [columnIndex, setColumnIndex] = useState(0) // 选中列 - const pickerRef = useRef(null) - const [refs, setRefs] = useRefs() - const [columnsList, setColumnsList] = useState([]) // 格式化后每一列的数据 - const isConfirmEvent = useRef(false) const actions: PickerActions = { open: () => { @@ -124,164 +109,56 @@ const InternalPicker: ForwardRefRenderFunction< setInnerVisible(false) }, } - useImperativeHandle(ref, () => actions) - // 级联数据格式化 - const formatCascade = ( - columns: PickerOption[], - values: (number | string)[] - ) => { - const formatted: PickerOption[][] = [] - let columnOptions: PickerOption = { - text: '', - value: '', - children: columns, - } - - let columnIndex = 0 - while (columnOptions && columnOptions.children) { - const options: PickerOption[] = columnOptions.children - const value = values[columnIndex] - let index = options.findIndex((columnItem) => columnItem.value === value) - if (index === -1) index = 0 - columnOptions = columnOptions.children[index] - columnIndex++ - formatted.push(options) - } - return formatted - } - - // 数据类型:多列、嵌套、单列 - const columnsType = () => { - const firstColumn: PickerOption | PickerOption[] = options[0] - if (firstColumn) { - if (Array.isArray(firstColumn)) { - return 'multiple' - } - if ('children' in firstColumn) { - return 'cascade' - } - } - return 'single' - } - - // 传入的数据格式化 - const normalListData = (innerValue: any) => { - const type = columnsType() - switch (type) { - case 'multiple': - return options - case 'cascade': - // 级联数据处理 - return formatCascade(options as PickerOption[], innerValue) - default: - return [options] - } - } - const init = () => { - const normalData: PickerOption[][] = normalListData( - innerValue - ) as PickerOption[][] - setColumnsList(normalData) - // 初始化默认选中数据 - const data: (string | number)[] = [] - normalData.length > 0 && - normalData.map((item) => { - item[0] && data.push(item[0].value) - return item - }) - if (!innerValue.length && innerValue.length === 0) { - setInnerValue([...data]) - } - } - - useEffect(() => { - setInnerValue(innerValue !== selectedValue ? selectedValue : innerValue) - }, [innerVisible, selectedValue]) + const [innerValue, setInnerValue] = useState([...selectedValue]) + const innerValueRef = useRef(innerValue) + const [innerOptions, setInnerOptions] = useState([]) + const selectedOptionsRef = useRef([] as PickerOptions) + const [refs, setRefs] = useRefs() useEffect(() => { if (innerVisible) { - init() + setInnerValue(selectedValue) + setInnerOptions(options as PickerOptions[]) } - }, [options, innerVisible]) - - // 选中值进行修改 - useEffect(() => { - onChange && onChange(setSelectedOptions(), innerValue, columnIndex) - }, [innerValue, columnsList]) - - const setSelectedOptions = () => { - const options: PickerOption[] = [] - let currOptions = [] - columnsList.forEach((columnOptions: PickerOption[], index: number) => { - currOptions = columnOptions.filter( - (item) => item.value === innerValue[index] - ) - if (currOptions[0]) { - options.push(currOptions[0]) - } else { - columnOptions[0] && options.push(columnOptions[0]) - } - }) - return options - } - - // 更新已选择数据 - const chooseItem = (columnOptions: PickerOption, columnIndex: number) => { - const values: any = [] - const start = columnIndex - if (columnOptions && Object.keys(columnOptions).length) { - // 切换数据后,数据有变动才触发。 - if (values[columnIndex] !== columnOptions.value) { - if (columnsType() === 'cascade') { - values[columnIndex] = columnOptions.value || '' - while (columnOptions?.children?.[0]) { - values[columnIndex + 1] = columnOptions.children[0].value - columnIndex++ - columnOptions = columnOptions.children[0] - } - // 当前改变列的下一列 children 值为空 - if (columnOptions?.children?.length) { - values[columnIndex + 1] = '' - } - const combineResult = [ - ...innerValue.slice(0, start), - ...values.splice(start), - ] - setInnerValue(combineResult) - setColumnsList(normalListData(combineResult) as PickerOption[][]) - } else { - setInnerValue((data: (number | string)[]) => { - const cdata: (number | string)[] = [...data] - cdata[columnIndex] = Object.prototype.hasOwnProperty.call( - columnOptions, - 'value' - ) - ? columnOptions.value - : '' - return cdata - }) - } - setColumnIndex(columnIndex) - } + }, [selectedValue, innerOptions, innerVisible]) + + const onChangeItem = ({ + value, + index, + selectedOptions, + }: PickerOnChangeCallbackParameter) => { + if (selectedOptions?.length) { + selectedOptionsRef.current = selectedOptions } + if (isEqual(value, innerValueRef.current)) return + innerValueRef.current = value + setInnerValue(value) + innerVisible && + onChange?.({ + selectedOptions, + value, + index, + }) } - const confirm = () => { + + const onConfirmEvent = () => { let moving = false refs.forEach((ref: any) => { if (ref.moving) moving = true ref.stopMomentum() }) - if (moving) { - isConfirmEvent.current = true - } else { + if (!moving) { setSelectedValue(innerValue, true) setInnerVisible(false) } - setTimeout(() => { - isConfirmEvent.current = false - }, 0) + } + + const onCancelEvent = () => { + setInnerValue(selectedValue) + onCancel?.() + setInnerVisible(false) } const renderTitleBar = () => { @@ -291,8 +168,7 @@ const InternalPicker: ForwardRefRenderFunction< className={`${classPrefix}-cancel-btn`} onClick={(e) => { e.stopPropagation() - onCancel?.() - setInnerVisible(false) + onCancelEvent() }} > {locale?.cancel} @@ -302,7 +178,7 @@ const InternalPicker: ForwardRefRenderFunction< className={`${classPrefix}-confirm-btn`} onClick={(e) => { e.stopPropagation() - confirm() + onConfirmEvent() }} > {locale.confirm} @@ -311,50 +187,49 @@ const InternalPicker: ForwardRefRenderFunction< ) } + const renderPickerElement = () => { + return ( +
+ {renderTitleBar()} + {typeof children !== 'function' && children} +
+ { + onChangeItem({ value, index, selectedOptions }) + }} + /> +
+
+ ) + } return ( <> {typeof children === 'function' && children(selectedValue)} + { - if (closeOnOverlayClick) { - props.onCancel?.() - setInnerVisible(false) - } - }} - afterClose={() => { - afterClose?.(setSelectedOptions(), innerValue, pickerRef) + if (!closeOnOverlayClick) return + onCancelEvent() }} > -
- {renderTitleBar()} - {typeof children !== 'function' && children} -
- {columnsList?.map((item, index) => { - return ( - - chooseItem(value, index) - } - duration={duration} - key={index} - keyIndex={index} - /> - ) - })} -
-
+ {innerVisible ? <>{renderPickerElement()} : null}
) } -const Picker = React.forwardRef>(InternalPicker) +const Picker = React.forwardRef>(InternalPicker) export default Picker diff --git a/src/packages/picker/pickerpanel.taro.tsx b/src/packages/picker/pickerpanel.taro.tsx deleted file mode 100644 index 0ecb888d61..0000000000 --- a/src/packages/picker/pickerpanel.taro.tsx +++ /dev/null @@ -1,322 +0,0 @@ -import React, { - useState, - useEffect, - useRef, - ForwardRefRenderFunction, - useImperativeHandle, -} from 'react' -import { View } from '@tarojs/components' -import { PickerOption } from './types' -import { useTouch } from '@/hooks/use-touch' -import { getRectByTaro } from '@/utils/get-rect-by-taro' -import { passiveSupported } from '@/utils/supports-passive' - -interface PickerPanelProps { - keyIndex?: number - defaultValue?: string | number - options?: PickerOption[] - threeDimensional: boolean - duration: number | string - itemShow: boolean - chooseItem?: (val: PickerOption, idx: number) => void -} - -const InternalPickerPanel: ForwardRefRenderFunction< - { stopMomentum: () => void; moving: boolean }, - Partial -> = (props, ref) => { - const { - keyIndex = 0, - defaultValue, - options = [], - threeDimensional = true, - duration = 1000, - itemShow = false, - chooseItem, - } = props - - const touch = useTouch() - const DEFAULT_DURATION = 200 - // 触发惯性滑动条件: - // 在手指离开屏幕时,如果和上一次 move 时的间隔小于 `MOMENTUM_TIME` 且 move - // 距离大于 `MOMENTUM_DISTANCE` 时,执行惯性滑动 - const INERTIA_TIME = 300 - const INERTIA_DISTANCE = 15 - const [currIndex, setCurrIndex] = useState(1) - const lineSpacing = useRef(36) - const [touchTime, setTouchTime] = useState(0) - const [touchDeg, setTouchDeg] = useState('0deg') - const rotation = 20 - const moving = useRef(false) - let timer: number | undefined - - const listRef = useRef(null) - const rollerRef = useRef(null) - const pickerPanelRef = useRef(null) - - const [startTime, setStartTime] = useState(0) - const [startY, setStartY] = useState(0) - - const transformY = useRef(0) - const [scrollDistance, setScrollDistance] = useState(0) - - const isHidden = (index: number) => { - if (index >= currIndex + 8 || index <= currIndex - 8) { - return true - } - return false - } - - const setTransform = ( - type: string, - deg: string, - time = DEFAULT_DURATION, - translateY = 0 - ) => { - let nTime = time - if (type !== 'end') { - nTime = 0 - } - setTouchTime(nTime) - setTouchDeg(deg) - setScrollDistance(translateY) - } - - const setMove = (move: number, type?: string, time?: number) => { - let updateMove = move + transformY.current - if (type === 'end') { - // 限定滚动距离 - if (updateMove > 0) { - updateMove = 0 - } - if (updateMove < -(options.length - 1) * lineSpacing.current) { - updateMove = -(options.length - 1) * lineSpacing.current - } - - // 设置滚动距离为lineSpacing的倍数值 - const endMove = - Math.round(updateMove / lineSpacing.current) * lineSpacing.current - const deg = `${ - (Math.abs(Math.round(endMove / lineSpacing.current)) + 1) * rotation - }deg` - - setTransform(type, deg, time, endMove) - setCurrIndex(Math.abs(Math.round(endMove / lineSpacing.current)) + 1) - } else { - let deg = 0 - const currentDeg = (-updateMove / lineSpacing.current + 1) * rotation - - // picker 滚动的最大角度 - const maxDeg = (options.length + 1) * rotation - const minDeg = 0 - deg = Math.min(Math.max(currentDeg, minDeg), maxDeg) - - if (minDeg < deg && deg < maxDeg) { - setTransform('', `${deg}deg`, undefined, updateMove) - setCurrIndex(Math.abs(Math.round(updateMove / lineSpacing.current)) + 1) - } - } - } - - const setChooseValue = (move: number) => { - chooseItem?.(options?.[Math.round(-move / lineSpacing.current)], keyIndex) - } - - // 开始滚动 - const touchStart = (event: React.TouchEvent) => { - touch.start(event) - setStartY(touch.deltaY.current) - setStartTime(Date.now()) - transformY.current = scrollDistance - } - - const touchMove = (event: React.TouchEvent) => { - touch.move(event) - if ((touch as any).isVertical) { - moving.current = true - preventDefault(event, true) - } - const move = touch.deltaY.current - startY - setMove(move) - } - - const touchEnd = () => { - if (!moving.current) return - const move = touch.deltaY.current - startY - const moveTime = Date.now() - startTime - // 区分是否为惯性滚动 - if (moveTime <= INERTIA_TIME && Math.abs(move) > INERTIA_DISTANCE) { - // 惯性滚动 - const distance = momentum(move, moveTime) - setMove(distance, 'end', +duration) - } else { - setMove(move, 'end') - } - setTimeout(() => { - touch.reset() - }, 0) - } - - // 惯性滚动 距离 - const momentum = (distance: number, duration: number) => { - let nDistance = distance - // 惯性滚动的速度 - const speed = Math.abs(nDistance / duration) - // 惯性滚动的距离 - nDistance = (speed / 0.003) * (nDistance < 0 ? -1 : 1) - return nDistance - } - - const modifyStatus = (type?: boolean, val?: string | number) => { - const value = val || defaultValue - let index = -1 - if (value) { - options.some((item, idx) => { - if (item.value === value) { - index = idx - return true - } - return false - }) - } else { - options.forEach((item, i) => { - if (item.value === defaultValue) { - index = i - } - }) - } - - setCurrIndex(index === -1 ? 1 : index + 1) - const move = index === -1 ? 0 : index * lineSpacing.current - type && setChooseValue(-move) - setMove(-move) - } - - // 惯性滚动结束 - const stopMomentum = () => { - moving.current = false - setTouchTime(0) - setChooseValue(scrollDistance) - } - // 阻止默认事件 - const preventDefault = ( - event: React.TouchEvent, - isStopPropagation?: boolean - ) => { - event.preventDefault() - if (isStopPropagation) { - event.stopPropagation() - } - } - - const getReference = async () => { - const refe = await getRectByTaro(listRef?.current) - lineSpacing.current = refe.height ? refe.height : 36 - } - - const touchRollerStyle = () => { - return { - transition: `transform ${touchTime}ms cubic-bezier(0.17, 0.89, 0.45, 1)`, - transform: `rotate3d(1, 0, 0, ${touchDeg})`, - } - } - const touchTileStyle = () => { - return { - transition: `transform ${touchTime}ms cubic-bezier(0.17, 0.89, 0.45, 1)`, - transform: `translate3d(0, ${scrollDistance}px, 0)`, - } - } - - useEffect(() => { - setScrollDistance(0) - transformY.current = 0 - modifyStatus(false) - return () => { - clearTimeout(timer) - } - }, [options]) - - useEffect(() => { - if (itemShow) { - setTimeout(() => { - getReference() - }, 200) - } - }, [itemShow]) - - useImperativeHandle(ref, () => ({ - stopMomentum, - moving: moving.current, - })) - - useEffect(() => { - const eventOptions = passiveSupported - ? { passive: false, once: true } - : false - const element = pickerPanelRef.current - element.addEventListener('touchstart', touchStart, eventOptions) - element.addEventListener('touchmove', touchMove, eventOptions) - element.addEventListener('touchend', touchEnd, eventOptions) - return () => { - element.removeEventListener('touchstart', touchStart, eventOptions) - element.removeEventListener('touchmove', touchMove, eventOptions) - element.removeEventListener('touchend', touchEnd, eventOptions) - } - }) - - return ( - - - {/* 3D 效果 */} - {threeDimensional && - options.map((item, index) => { - return ( - - <>{item.text} - - ) - })} - {/* 平铺 */} - {!threeDimensional && - options.map((item, index) => { - return ( - - <>{item.text} - - ) - })} - - - - - ) -} -const PickerPanel = React.forwardRef< - { stopMomentum: () => void; moving: boolean }, - Partial ->(InternalPickerPanel) -export default PickerPanel diff --git a/src/packages/picker/pickerpanel.tsx b/src/packages/picker/pickerpanel.tsx deleted file mode 100644 index efe7e986fe..0000000000 --- a/src/packages/picker/pickerpanel.tsx +++ /dev/null @@ -1,305 +0,0 @@ -import React, { - useState, - useEffect, - useRef, - ForwardRefRenderFunction, - useImperativeHandle, -} from 'react' -import { PickerOption } from './types' -import { useTouch } from '@/hooks/use-touch' -import { passiveSupported } from '@/utils/supports-passive' - -interface PickerPanelProps { - keyIndex?: number - defaultValue?: string | number - options?: PickerOption[] - threeDimensional: boolean - duration: number | string - chooseItem?: (val: PickerOption, idx: number) => void -} - -const InternalPickerPanel: ForwardRefRenderFunction< - { stopMomentum: () => void; moving: boolean }, - Partial -> = (props, ref) => { - const { - keyIndex = 0, - defaultValue, - options = [], - threeDimensional = true, - duration = 1000, - chooseItem, - } = props - - const touch = useTouch() - const DEFAULT_DURATION = 200 - // 触发惯性滑动条件: - // 在手指离开屏幕时,如果和上一次 move 时的间隔小于 `MOMENTUM_TIME` 且 move - // 距离大于 `MOMENTUM_DISTANCE` 时,执行惯性滑动 - const INERTIA_TIME = 300 - const INERTIA_DISTANCE = 15 - const [currIndex, setCurrIndex] = useState(1) - const lineSpacing = 36 - const [touchTime, setTouchTime] = useState(0) - const [touchDeg, setTouchDeg] = useState('0deg') - const rotation = 20 - const moving = useRef(false) - let timer: number | undefined - - const rollerRef = useRef(null) - const PickerPanelRef = useRef(null) - - const [startTime, setStartTime] = useState(0) - const [startY, setStartY] = useState(0) - - const transformY = useRef(0) - const [scrollDistance, setScrollDistance] = useState(0) - - const isHidden = (index: number) => { - if (index >= currIndex + 8 || index <= currIndex - 8) { - return true - } - return false - } - - const setTransform = ( - type: string, - deg: string, - time = DEFAULT_DURATION, - translateY = 0 - ) => { - let nTime = time - if (type !== 'end') { - nTime = 0 - } - setTouchTime(nTime) - setTouchDeg(deg) - setScrollDistance(translateY) - } - - const setMove = (move: number, type?: string, time?: number) => { - let updateMove = move + transformY.current - if (type === 'end') { - // 限定滚动距离 - if (updateMove > 0) { - updateMove = 0 - } - if (updateMove < -(options.length - 1) * lineSpacing) { - updateMove = -(options.length - 1) * lineSpacing - } - - // 设置滚动距离为lineSpacing的倍数值 - const endMove = Math.round(updateMove / lineSpacing) * lineSpacing - const deg = `${ - (Math.abs(Math.round(endMove / lineSpacing)) + 1) * rotation - }deg` - - setTransform(type, deg, time, endMove) - setCurrIndex(Math.abs(Math.round(endMove / lineSpacing)) + 1) - } else { - let deg = 0 - const currentDeg = (-updateMove / lineSpacing + 1) * rotation - - // picker 滚动的最大角度 - const maxDeg = (options.length + 1) * rotation - const minDeg = 0 - - deg = Math.min(Math.max(currentDeg, minDeg), maxDeg) - - if (minDeg < deg && deg < maxDeg) { - setTransform('', `${deg}deg`, undefined, updateMove) - setCurrIndex(Math.abs(Math.round(updateMove / lineSpacing)) + 1) - } - } - } - - const setChooseValue = (move: number) => { - chooseItem?.(options?.[Math.round(-move / lineSpacing)], keyIndex) - } - - // 开始滚动 - const touchStart = (event: React.TouchEvent) => { - touch.start(event) - setStartY(touch.deltaY.current) - setStartTime(Date.now()) - transformY.current = scrollDistance - } - - const touchMove = (event: React.TouchEvent) => { - touch.move(event) - if ((touch as any).isVertical) { - moving.current = true - preventDefault(event, true) - } - const move = touch.deltaY.current - startY - setMove(move) - } - - const touchEnd = () => { - if (!moving.current) return - const move = touch.deltaY.current - startY - const moveTime = Date.now() - startTime - // 区分是否为惯性滚动 - if (moveTime <= INERTIA_TIME && Math.abs(move) > INERTIA_DISTANCE) { - // 惯性滚动 - const distance = momentum(move, moveTime) - setMove(distance, 'end', +duration) - } else { - setMove(move, 'end') - } - setTimeout(() => { - touch.reset() - }, 0) - } - - // 惯性滚动 距离 - const momentum = (distance: number, duration: number) => { - let nDistance = distance - // 惯性滚动的速度 - const speed = Math.abs(nDistance / duration) - // 惯性滚动的距离 - nDistance = (speed / 0.003) * (nDistance < 0 ? -1 : 1) - return nDistance - } - - const modifyStatus = (type?: boolean, val?: string | number) => { - const value = val || defaultValue - let index = -1 - if (value) { - options.some((item, idx) => { - if (item.value === value) { - index = idx - return true - } - return false - }) - } else { - options.forEach((item, i) => { - if (item.value === defaultValue) { - index = i - } - }) - } - - setCurrIndex(index === -1 ? 1 : index + 1) - const move = index === -1 ? 0 : index * lineSpacing - type && setChooseValue(-move) - setMove(-move) - } - - // 惯性滚动结束 - const stopMomentum = () => { - moving.current = false - setTouchTime(0) - setChooseValue(scrollDistance) - } - // 阻止默认事件 - const preventDefault = ( - event: React.TouchEvent, - isStopPropagation?: boolean - ) => { - /* istanbul ignore else */ - if (typeof event.cancelable !== 'boolean' || event.cancelable) { - event.preventDefault() - } - - if (isStopPropagation) { - event.stopPropagation() - } - } - - const touchRollerStyle = () => { - return { - transition: `transform ${touchTime}ms cubic-bezier(0.17, 0.89, 0.45, 1)`, - transform: `rotate3d(1, 0, 0, ${touchDeg})`, - } - } - const touchTileStyle = () => { - return { - transition: `transform ${touchTime}ms cubic-bezier(0.17, 0.89, 0.45, 1)`, - transform: `translate3d(0, ${scrollDistance}px, 0)`, - } - } - - useEffect(() => { - setScrollDistance(0) - transformY.current = 0 - modifyStatus(false) - return () => { - clearTimeout(timer) - } - }, [options]) - - useImperativeHandle(ref, () => ({ - stopMomentum, - moving: moving.current, - })) - - useEffect(() => { - const options = passiveSupported ? { passive: false } : false - PickerPanelRef.current?.addEventListener('touchstart', touchStart, options) - PickerPanelRef.current?.addEventListener('touchmove', touchMove, options) - PickerPanelRef.current?.addEventListener('touchend', touchEnd, options) - return () => { - PickerPanelRef.current?.removeEventListener('touchstart', touchStart) - PickerPanelRef.current?.removeEventListener('touchmove', touchMove) - PickerPanelRef.current?.removeEventListener('touchend', touchEnd) - } - }) - - return ( -
-
- {/* 3D 效果 */} - {threeDimensional && - options.map((item, index) => { - return ( -
- <>{item.text} -
- ) - })} - {/* 平铺 */} - {!threeDimensional && - options.map((item, index) => { - return ( -
- <>{item.text} -
- ) - })} -
-
-
-
- ) -} -const PickerPanel = React.forwardRef< - { stopMomentum: () => void; moving: boolean }, - Partial ->(InternalPickerPanel) -export default PickerPanel diff --git a/src/packages/picker/types.ts b/src/packages/picker/types.ts index 5c7e00b846..ae6fabdd59 100644 --- a/src/packages/picker/types.ts +++ b/src/packages/picker/types.ts @@ -1,7 +1,6 @@ -export interface PickerOption { - text: string | number - value: string | number - disabled?: boolean - children?: PickerOption[] - className?: string | number +export type PickerRef = PickerActions +export type PickerActions = { + open: () => void + close: () => void } +export type ColumnsType = 'single' | 'multiple' | 'cascade' diff --git a/src/packages/pickerview/__test__/pickerview.spec.tsx b/src/packages/pickerview/__test__/pickerview.spec.tsx index 5dfd175869..6f67fe5c6c 100644 --- a/src/packages/pickerview/__test__/pickerview.spec.tsx +++ b/src/packages/pickerview/__test__/pickerview.spec.tsx @@ -133,7 +133,7 @@ test('should render with Multi Column', () => { test('should match onchange', async () => { const PenderContent = () => { - const [value, setValue] = useState([]) + const [value, setValue] = useState([] as number[]) const [options, setInnerOptions] = useState([]) useEffect(() => { diff --git a/src/packages/pickerview/doc.en-US.md b/src/packages/pickerview/doc.en-US.md index 42006732bd..0193489639 100644 --- a/src/packages/pickerview/doc.en-US.md +++ b/src/packages/pickerview/doc.en-US.md @@ -71,13 +71,13 @@ import { PickerView } from '@nutui/nutui-react' | duration | The duration of inertial rolling during rapid sliding, in ms | `string` \| `number` | `1000` | | onChange | Called when the value of each column changes | `({value, index, selectedOptions}) => void` | `-` | -### PickerOptionItem +### PickerOption | Property | Description | Type | Default | | --- | --- | --- | --- | | label | Text of column | `string` \| `number` | `-` | | value | Value of column | `string` \| `number` | `-` | -| children | Cascader Option | `PickerOptionItem[]` | `-` | +| children | Cascader Option | `PickerOptions` | `-` | ## Theming diff --git a/src/packages/pickerview/doc.md b/src/packages/pickerview/doc.md index ef3cb7dc18..378d917da3 100644 --- a/src/packages/pickerview/doc.md +++ b/src/packages/pickerview/doc.md @@ -71,13 +71,13 @@ import { PickerView } from '@nutui/nutui-react' | duration | 快速滑动时惯性滚动的时长,单位 ms | `string` \| `number` | `1000` | | onChange | 每一列值变更时调用 | `({value, index, selectedOptions}) => void` | `-` | -### PickerOptionItem +### PickerOption | 属性 | 说明 | 类型 | 默认值 | | --- | --- | --- | --- | | label | 选项的文字内容 | `string` \| `number` | `-` | | value | 选项对应的值,且唯一 | `string` \| `number` | `-` | -| children | 用于级联选项 | `PickerOptionItem[]` | `-` | +| children | 用于级联选项 | `PickerOptions` | `-` | ## 主题定制 diff --git a/src/packages/pickerview/doc.taro.md b/src/packages/pickerview/doc.taro.md index 344fc9dee3..cc0bcb4e1d 100644 --- a/src/packages/pickerview/doc.taro.md +++ b/src/packages/pickerview/doc.taro.md @@ -71,13 +71,13 @@ import { PickerView } from '@nutui/nutui-react-taro' | duration | 快速滑动时惯性滚动的时长,单位 ms | `string` \| `number` | `1000` | | onChange | 每一列值变更时调用 | `({value, index, selectedOptions}) => void` | `-` | -### PickerOptionItem +### PickerOption | 属性 | 说明 | 类型 | 默认值 | | --- | --- | --- | --- | | label | 选项的文字内容 | `string` \| `number` | `-` | | value | 选项对应的值,且唯一 | `string` \| `number` | `-` | -| children | 用于级联选项 | `PickerOptionItem[]` | `-` | +| children | 用于级联选项 | `PickerOptions` | `-` | ## 主题定制 diff --git a/src/packages/pickerview/doc.zh-TW.md b/src/packages/pickerview/doc.zh-TW.md index 073f5b8e4f..cfe5e7360e 100644 --- a/src/packages/pickerview/doc.zh-TW.md +++ b/src/packages/pickerview/doc.zh-TW.md @@ -71,13 +71,13 @@ import { PickerView } from '@nutui/nutui-react-taro' | duration | 快速滑動時慣性滾動的時長,單位 ms | `string` \| `number` | `1000` | | onChange | 每一列值變更時調用 | `({value, index, selectedOptions}) => void` | `-` | -### PickerOptionItem +### PickerOption | 屬性 | 說明 | 類型 | 默認值 | | --- | --- | --- | --- | | label | 選項的文字內容 | `string` \| `number` | `-` | | value | 選項對應的值,且唯一 | `string` \| `number` | `-` | -| children | 用於級聯選項 | `PickerOptionItem[]` | `-` | +| children | 用於級聯選項 | `PickerOptions` | `-` | ## 主題定制 diff --git a/src/packages/pickerview/index.taro.ts b/src/packages/pickerview/index.taro.ts index 1bd5f2a397..8d492244e8 100644 --- a/src/packages/pickerview/index.taro.ts +++ b/src/packages/pickerview/index.taro.ts @@ -2,7 +2,7 @@ import PickerView from './pickerview.taro' export type { PickerViewProps, - PickerOptionItem, + PickerOption, PickerRollerProps, PickerValue, PickerOptions, diff --git a/src/packages/pickerview/index.ts b/src/packages/pickerview/index.ts index 15c781a272..bff2bf6714 100644 --- a/src/packages/pickerview/index.ts +++ b/src/packages/pickerview/index.ts @@ -2,7 +2,7 @@ import PickerView from './pickerview' export type { PickerViewProps, - PickerOptionItem, + PickerOption, PickerRollerProps, PickerValue, PickerOptions, diff --git a/src/packages/pickerview/pickerroller.taro.tsx b/src/packages/pickerview/pickerroller.taro.tsx index 10c38d145f..2acf57c520 100644 --- a/src/packages/pickerview/pickerroller.taro.tsx +++ b/src/packages/pickerview/pickerroller.taro.tsx @@ -8,7 +8,7 @@ import React, { import { View } from '@tarojs/components' import { useTouch } from '@/hooks/use-touch' import { passiveSupported } from '@/utils/supports-passive' -import { PickerRollerProps, PickerOptionItem } from './types' +import { PickerRollerProps, PickerOption } from './types' import { web } from '@/utils/platform-taro' import { preventDefault } from '@/utils' import { momentum, useStyles } from './utils' @@ -23,7 +23,7 @@ const InternalPickerRoller: ForwardRefRenderFunction< threeDimensional = true, duration = 1000, onSelect, - renderLabel = (item: PickerOptionItem) => item.label, + renderLabel = (item: PickerOption) => item.label, } = props const DEFAULT_DURATION = 200 @@ -132,7 +132,9 @@ const InternalPickerRoller: ForwardRefRenderFunction< const updateStatus = (shouldSelect?: boolean, value?: string | number) => { const selectedValue = value || props.value - const index = options.findIndex((item) => item.value === selectedValue) + const index = options.findIndex( + (item: PickerOption) => item.value === selectedValue + ) setCurrentIndex(index === -1 ? 1 : index + 1) const move = index * lineSpacing.current shouldSelect && selectValue(-move) @@ -223,7 +225,7 @@ const InternalPickerRoller: ForwardRefRenderFunction< > {/* 3D 效果 */} {threeDimensional && - options.map((item, index) => ( + options.map((item: PickerOption, index: number) => ( { + options.map((item: PickerOption, index: number) => { return ( item.label, + renderLabel = (item: PickerOption) => item.label, } = props const DEFAULT_DURATION = 200 @@ -130,7 +130,9 @@ const InternalPickerRoller: ForwardRefRenderFunction< const updateStatus = (shouldSelect?: boolean, value?: string | number) => { const selectedValue = value || props.value - const index = options.findIndex((item) => item.value === selectedValue) + const index = options.findIndex( + (item: PickerOption) => item.value === selectedValue + ) setCurrentIndex(index === -1 ? 1 : index + 1) const move = index * lineSpacing.current shouldSelect && selectValue(-move) @@ -210,7 +212,7 @@ const InternalPickerRoller: ForwardRefRenderFunction< > {/* 3D */} {threeDimensional && - options.map((item, index) => ( + options.map((item: PickerOption, index: number) => (
( + options.map((item: PickerOption, index: number) => (
item.label, + renderLabel: (item: PickerOption) => item.label, } as PickerViewProps const InternalPickerView: ForwardRefRenderFunction< @@ -77,7 +77,7 @@ const InternalPickerView: ForwardRefRenderFunction< if (!options.length) return [] // 如果 options 为空,直接返回空数组 const formatted: PickerOptions[] = [] - let columnOptions: PickerOptionItem = { + let columnOptions: PickerOption = { label: '', value: '', children: options, @@ -95,7 +95,7 @@ const InternalPickerView: ForwardRefRenderFunction< } else if (currentValue) { // 如果 currentValue 存在,查找匹配的项 const index = currentOptions.findIndex( - (columnItem) => columnItem.value === currentValue + (columnItem: PickerOption) => columnItem.value === currentValue ) columnOptions = currentOptions[index === -1 ? 0 : index] // 如果未找到,默认取第一个 } else { @@ -131,7 +131,7 @@ const InternalPickerView: ForwardRefRenderFunction< }, [selectedValue]) const handleSelect = useCallback( - (option: PickerOptionItem, index: number) => { + (option: PickerOption, index: number) => { const newValue = option?.value if (!newValue || innerValue[index] === newValue) return changeIndex.current = index @@ -159,7 +159,7 @@ const InternalPickerView: ForwardRefRenderFunction< ...values.splice(startIndex), ] setInnerValue([...combineResult]) - const optionFirst = props?.options?.[0] as PickerOptionItem[] + const optionFirst = props?.options?.[0] as PickerOptions if ( !isEqual( formatCascadeOptions(optionFirst, combineResult), @@ -177,12 +177,12 @@ const InternalPickerView: ForwardRefRenderFunction< return innerOptions .map((columnOptions, index) => { const selectedOption = columnOptions.find( - (item) => item.value === innerValue[index] + (item: PickerOption) => item.value === innerValue[index] ) return selectedOption // return selectedOption || columnOptions[0] }) - .filter(Boolean) as PickerOptionItem[] + .filter(Boolean) as PickerOptions }, [innerOptions, innerValue]) useEffect(() => { diff --git a/src/packages/pickerview/pickerview.tsx b/src/packages/pickerview/pickerview.tsx index 0fef411bea..fbf2189c52 100644 --- a/src/packages/pickerview/pickerview.tsx +++ b/src/packages/pickerview/pickerview.tsx @@ -12,7 +12,7 @@ import { ComponentDefaults } from '@/utils/typings' import { usePropsValue } from '@/hooks/use-props-value' import { PickerViewProps, - PickerOptionItem, + PickerOption, PickerValue, PickerOptions, } from './types' @@ -23,7 +23,7 @@ const defaultProps = { options: [], defaultValue: [], value: undefined, - renderLabel: (item: PickerOptionItem) => item.label, + renderLabel: (item: PickerOption) => item.label, } as PickerViewProps const InternalPickerView: ForwardRefRenderFunction< @@ -76,7 +76,7 @@ const InternalPickerView: ForwardRefRenderFunction< if (!options.length) return [] // 如果 options 为空,直接返回空数组 const formatted: PickerOptions[] = [] - let columnOptions: PickerOptionItem = { + let columnOptions: PickerOption = { label: '', value: '', children: options, @@ -94,7 +94,7 @@ const InternalPickerView: ForwardRefRenderFunction< } else if (currentValue) { // 如果 currentValue 存在,查找匹配的项 const index = currentOptions.findIndex( - (columnItem) => columnItem.value === currentValue + (columnItem: PickerOption) => columnItem.value === currentValue ) columnOptions = currentOptions[index === -1 ? 0 : index] // 如果未找到,默认取第一个 } else { @@ -130,7 +130,7 @@ const InternalPickerView: ForwardRefRenderFunction< }, [selectedValue]) const handleSelect = useCallback( - (option: PickerOptionItem, index: number) => { + (option: PickerOption, index: number) => { const newValue = option?.value if (!newValue || innerValue[index] === newValue) return changeIndex.current = index @@ -158,7 +158,7 @@ const InternalPickerView: ForwardRefRenderFunction< ...values.splice(startIndex), ] setInnerValue([...combineResult]) - const optionFirst = props?.options?.[0] as PickerOptionItem[] + const optionFirst = props?.options?.[0] as PickerOptions if ( !isEqual( formatCascadeOptions(optionFirst, combineResult), @@ -176,12 +176,12 @@ const InternalPickerView: ForwardRefRenderFunction< return innerOptions .map((columnOptions, index) => { const selectedOption = columnOptions.find( - (item) => item.value === innerValue[index] + (item: PickerOption) => item.value === innerValue[index] ) return selectedOption // return selectedOption || columnOptions[0] }) - .filter(Boolean) as PickerOptionItem[] + .filter(Boolean) as PickerOptions }, [innerOptions, innerValue]) useEffect(() => { diff --git a/src/packages/pickerview/types.ts b/src/packages/pickerview/types.ts index e25d83faf5..57efbd2b7e 100644 --- a/src/packages/pickerview/types.ts +++ b/src/packages/pickerview/types.ts @@ -2,28 +2,28 @@ import { BasicComponent } from '@/utils/typings' export type PickerValue = string | number | null -export interface PickerOptionItem { +export interface PickerOption { label: string | number value: string | number - children?: PickerOptionItem[] + children?: PickerOptions } -export type PickerOptions = PickerOptionItem[] +export type PickerOptions = PickerOption[] export interface PickerRollerProps { - options: PickerOptionItem[] + options: PickerOptions keyIndex: number value: PickerValue threeDimensional?: boolean duration?: number | string - onSelect: (option: PickerOptionItem, index: number) => void - renderLabel: (item: PickerOptionItem) => React.ReactNode + onSelect: (option: PickerOption, index: number) => void + renderLabel: (item: PickerOption) => React.ReactNode } export interface PickerOnChangeCallbackParameter { value: PickerValue[] index: number - selectedOptions: PickerOptionItem[] + selectedOptions: PickerOptions } export interface PickerViewProps extends BasicComponent { @@ -33,6 +33,6 @@ export interface PickerViewProps extends BasicComponent { defaultValue?: PickerValue[] threeDimensional?: boolean duration?: number | string - renderLabel: (item: PickerOptionItem) => React.ReactNode + renderLabel: (item: PickerOption) => React.ReactNode onChange?: (arg0: PickerOnChangeCallbackParameter) => void }