diff --git a/src/packages/datepicker/__test__/datepicker.spec.tsx b/src/packages/datepicker/__test__/datepicker.spec.tsx index 2bfbba3dcc..9952adc4b2 100644 --- a/src/packages/datepicker/__test__/datepicker.spec.tsx +++ b/src/packages/datepicker/__test__/datepicker.spec.tsx @@ -1,7 +1,7 @@ import React from 'react' import { render, waitFor, fireEvent } from '@testing-library/react' import '@testing-library/jest-dom' -import { DatePicker } from '../datepicker' +import DatePicker from '../datepicker' const currentYear = new Date().getFullYear() test('Show Chinese', async () => { diff --git a/src/packages/datepicker/datepicker.taro.tsx b/src/packages/datepicker/datepicker.taro.tsx index 702f1e4e07..afdcf64d92 100644 --- a/src/packages/datepicker/datepicker.taro.tsx +++ b/src/packages/datepicker/datepicker.taro.tsx @@ -1,59 +1,27 @@ -import React, { FunctionComponent, useState, useEffect } from 'react' +import React, { + useState, + useEffect, + ForwardRefRenderFunction, + useImperativeHandle, +} from 'react' import { View } from '@tarojs/components' -import Picker, { PickerOption, PickerProps } from '@/packages/picker/index.taro' +import Picker, { PickerOption } 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 { ComponentDefaults } from '@/utils/typings' import { isDate } from '@/utils/is-date' -import { padZero } from '@/utils/pad-zero' - -export interface DatePickerProps extends BasicComponent { - value?: Date - defaultValue?: Date - visible: boolean - title: string - type: - | 'date' - | 'time' - | 'year-month' - | 'month-day' - | 'datehour' - | 'datetime' - | 'hour-minutes' - showChinese: boolean - minuteStep: number - startDate: Date - endDate: Date - threeDimensional: boolean - pickerProps: Partial< - Omit< - PickerProps, - | 'defaultValue' - | 'threeDimensional' - | 'title' - | 'value' - | 'onConfirm' - | 'onClose' - | 'onCancel' - | 'onChange' - > - > - formatter: (type: string, option: PickerOption) => PickerOption - filter: (type: string, option: PickerOption[]) => PickerOption[] - onClose: () => void - onCancel: () => void - onConfirm: ( - selectedOptions: PickerOption[], - selectedValue: (string | number)[] - ) => void - onChange?: ( - selectedOptions: PickerOption[], - selectedValue: (string | number)[], - columnIndex: number - ) => void -} +import { + formatValue, + generateDatePickerRanges, + generatePickerColumnWithCallback, + getDatePartValue, + handlePickerValueChange, +} from './utils' +import { DatePickerActions, DatePickerRef } from './types' +import { DatePickerProps } from './types.taro' const currentYear = new Date().getFullYear() + const defaultProps = { ...ComponentDefaults, visible: false, @@ -66,10 +34,10 @@ const defaultProps = { endDate: new Date(currentYear + 10, 11, 31), } as DatePickerProps -export const DatePicker: FunctionComponent< - Partial & - Omit, 'onChange' | 'defaultValue'> -> = (props) => { +const InternalPicker: ForwardRefRenderFunction< + DatePickerRef, + Partial +> = (props, ref) => { const { startDate, endDate, @@ -89,13 +57,16 @@ export const DatePicker: FunctionComponent< threeDimensional, className, style, + children, ...rest } = { ...defaultProps, ...props, } + const { locale } = useConfig() const lang = locale.datepicker + const zhCNType: { [key: string]: string } = { day: lang.day, year: lang.year, @@ -104,127 +75,45 @@ export const DatePicker: FunctionComponent< minute: lang.min, seconds: lang.seconds, } + const [pickerValue, setPickerValue] = useState<(string | number)[]>([]) const [pickerOptions, setPickerOptions] = useState([]) - const formatValue = (value: Date | null) => { - if (!value || (value && !isDate(value))) { - value = startDate - } - return Math.min( - Math.max(value.getTime(), startDate.getTime()), - endDate.getTime() - ) - } + const [selectedDate, setSelectedDate] = usePropsValue({ - value: props.value && formatValue(props.value), - defaultValue: props.defaultValue && formatValue(props.defaultValue), + value: props.value && formatValue(props.value, startDate, endDate), + defaultValue: + props.defaultValue && formatValue(props.defaultValue, startDate, endDate), finalValue: 0, }) - function getMonthEndDay(year: number, month: number): number { - return new Date(year, month, 0).getDate() - } + const [innerDate, setInnerDate] = useState(selectedDate) - const getBoundary = (type: string, value: Date) => { - const boundary = type === 'min' ? startDate : endDate - const year = boundary.getFullYear() - let month = 1 - let date = 1 - let hour = 0 - let minute = 0 + const [innerVisible, setInnerVisible] = usePropsValue({ + value: props.visible, + defaultValue: false, + finalValue: false, + }) - if (type === 'max') { - month = 12 - date = getMonthEndDay(value.getFullYear(), value.getMonth() + 1) - hour = 23 - minute = 59 - } - const seconds = minute - if (value.getFullYear() === year) { - month = boundary.getMonth() + 1 - if (value.getMonth() + 1 === month) { - date = boundary.getDate() - if (value.getDate() === date) { - hour = boundary.getHours() - if (value.getHours() === hour) { - minute = boundary.getMinutes() - } - } - } - } - return { - [`${type}Year`]: year, - [`${type}Month`]: month, - [`${type}Date`]: date, - [`${type}Hour`]: hour, - [`${type}Minute`]: minute, - [`${type}Seconds`]: seconds, - } + const actions: DatePickerActions = { + open: () => { + setInnerVisible(true) + }, + close: () => { + setInnerVisible(false) + }, } - const ranges = () => { - const selected = new Date(selectedDate) - if (!selected) return [] - const { maxYear, maxDate, maxMonth, maxHour, maxMinute, maxSeconds } = - getBoundary('max', selected) - const { minYear, minDate, minMonth, minHour, minMinute, minSeconds } = - getBoundary('min', selected) - const result = [ - { - type: 'year', - range: [minYear, maxYear], - }, - { - type: 'month', - range: [minMonth, maxMonth], - }, - { - type: 'day', - range: [minDate, maxDate], - }, - { - type: 'hour', - range: [minHour, maxHour], - }, - { - type: 'minute', - range: [minMinute, maxMinute], - }, - { - type: 'seconds', - range: [minSeconds, maxSeconds], - }, - ] - switch (type.toLocaleLowerCase()) { - case 'date': - return result.slice(0, 3) - case 'datetime': - return result.slice(0, 5) - case 'time': - return result.slice(3, 6) - case 'year-month': - return result.slice(0, 2) - case 'hour-minutes': - return result.slice(3, 5) - case 'month-day': - return result.slice(1, 3) - case 'datehour': - return result.slice(0, 4) - default: - return result - } - } + useImperativeHandle(ref, () => actions) - const compareDateChange = ( - currentDate: number, + const handleDateComparison = ( newDate: Date | null, selectedOptions: PickerOption[], index: number ) => { - const isEqual = new Date(currentDate)?.getTime() === newDate?.getTime() + const isEqual = new Date(innerDate)?.getTime() === newDate?.getTime() if (newDate && isDate(newDate)) { if (!isEqual) { - setSelectedDate(formatValue(newDate as Date)) + setInnerDate(formatValue(newDate, startDate, endDate)) } onChange?.( selectedOptions, @@ -237,194 +126,130 @@ export const DatePicker: FunctionComponent< ) } } - const handlePickerChange = ( - selectedOptions: PickerOption[], - selectedValue: (number | string)[], - index: number - ) => { - const rangeType = type.toLocaleLowerCase() - if ( - ['date', 'datetime', 'datehour', 'month-day', 'year-month'].includes( - rangeType - ) - ) { - const formatDate: (number | string)[] = [] - selectedValue.forEach((item) => { - formatDate.push(item) - }) - if (rangeType === 'month-day' && formatDate.length < 3) { - formatDate.unshift( - new Date(defaultValue || startDate || endDate).getFullYear() - ) - } - - if (rangeType === 'year-month' && formatDate.length < 3) { - formatDate.push( - new Date(defaultValue || startDate || endDate).getDate() - ) - } - const year = Number(formatDate[0]) - const month = Number(formatDate[1]) - 1 - const day = Math.min( - Number(formatDate[2]), - getMonthEndDay(Number(formatDate[0]), Number(formatDate[1])) - ) - let date: Date | null = null - if ( - rangeType === 'date' || - rangeType === 'month-day' || - rangeType === 'year-month' - ) { - date = new Date(year, month, day) - } else if (rangeType === 'datetime') { - date = new Date( - year, - month, - day, - Number(formatDate[3]), - Number(formatDate[4]) - ) - } else if (rangeType === 'datehour') { - date = new Date(year, month, day, Number(formatDate[3])) + const handleConfirmDateComparison = (newDate: Date | null) => { + if (newDate && isDate(newDate)) { + const isEqual = new Date(selectedDate)?.getTime() === newDate?.getTime() + if (!isEqual) { + setSelectedDate(formatValue(newDate, startDate, endDate)) } + } + } - compareDateChange(selectedDate, date, selectedOptions, index) - } else { - // 'hour-minutes' 'time' - const [hour, minute, seconds] = selectedValue - const currentDate = new Date(selectedDate) - const year = currentDate.getFullYear() - const month = currentDate.getMonth() - const day = currentDate.getDate() + const handleCancel = () => { + setInnerDate(selectedDate) + onCancel?.() + } - const date = new Date( - year, - month, - day, - Number(hour), - Number(minute), - rangeType === 'time' ? Number(seconds) : 0 - ) - compareDateChange(selectedDate, date, selectedOptions, index) - } + const handleClose = () => { + setInnerVisible(false) + onClose?.() } - const formatOption = (type: string, value: string | number) => { - if (formatter) { - return formatter(type, { - text: padZero(value, 2), - value: padZero(value, 2), - }) - } - const padMin = padZero(value, 2) - const fatter = showChinese ? zhCNType[type] : '' - return { text: padMin + fatter, value: padMin } + const handleConfirm = ( + options: PickerOption[], + value: (string | number)[] + ) => { + handlePickerValueChange( + options, + value, + 0, + type, + defaultValue || startDate || endDate, + handleConfirmDateComparison + ) + onConfirm?.(options, value) } - const generateColumn = ( - min: number, - max: number, - val: number | string, - type: string, - columnIndex: number + const handleChange = ( + selectedOptions: PickerOption[], + selectedValue: (string | number)[], + index: number ) => { - let cmin = min - const arr: Array = [] - let index = 0 - while (cmin <= max) { - arr.push(formatOption(type, cmin)) + innerVisible && + handlePickerValueChange( + selectedOptions, + selectedValue, + index, + type, + defaultValue || startDate || endDate, + handleDateComparison + ) + } - if (type === 'minute') { - cmin += minuteStep - } else { - cmin++ - } + const generatePickerColumns = (): PickerOption[][] => { + const dateRanges = generateDatePickerRanges( + type, + innerDate, + startDate, + endDate + ) - if (cmin <= Number(val)) { - index++ - } - } + const columns = dateRanges.map((rangeConfig, columnIndex) => { + const { type: columnType, range } = rangeConfig + const selectedValue = getDatePartValue(columnType, innerDate) + + const pickerColumn = generatePickerColumnWithCallback( + range[0], + range[1], + selectedValue, + columnType, + minuteStep, + (selectedIndex, options) => { + pickerValue[columnIndex] = options[selectedIndex]?.value + setPickerValue([...pickerValue]) + }, + showChinese, + zhCNType, + formatter + ) - pickerValue[columnIndex] = arr[index]?.value - setPickerValue([...pickerValue]) + if (filter?.(columnType, pickerColumn)) { + return filter(columnType, pickerColumn) + } - if (filter?.(type, arr)) { - return filter?.(type, arr) - } - return arr - } + return pickerColumn + }) - const getDateIndex = (type: string) => { - const date = new Date(selectedDate) - if (!selectedDate) return 0 - if (type === 'year') { - return date.getFullYear() - } - if (type === 'month') { - return date.getMonth() + 1 - } - if (type === 'day') { - return date.getDate() - } - if (type === 'hour') { - return date.getHours() - } - if (type === 'minute') { - return date.getMinutes() - } - if (type === 'seconds') { - return date.getSeconds() - } - return 0 + return columns || [] } - const columns = () => { - const val = ranges().map((res, columnIndex) => { - return generateColumn( - res.range[0], - res.range[1], - getDateIndex(res.type), - res.type, - columnIndex - ) - }) - return val || [] - } + useEffect(() => { + setInnerDate(selectedDate) + }, [selectedDate]) useEffect(() => { - setPickerOptions(columns()) - }, [selectedDate, startDate, endDate]) + setPickerOptions(generatePickerColumns()) + }, [innerDate, startDate, endDate]) return ( - - {pickerOptions.length > 0 && ( - - onConfirm && onConfirm(options, value) - } - onChange={( - options: PickerOption[], - value: (number | string)[], - index: number - ) => handlePickerChange(options, value, index)} - threeDimensional={threeDimensional} - /> - )} - + <> + {typeof children === 'function' && children(selectedDate)} + + {pickerOptions.length && ( + handleChange(options, value, index)} + threeDimensional={threeDimensional} + /> + )} + + ) } -DatePicker.displayName = 'NutDatePicker' +const DatePicker = React.forwardRef>( + InternalPicker +) +export default DatePicker diff --git a/src/packages/datepicker/datepicker.tsx b/src/packages/datepicker/datepicker.tsx index 47011cdc27..42eb940025 100644 --- a/src/packages/datepicker/datepicker.tsx +++ b/src/packages/datepicker/datepicker.tsx @@ -1,59 +1,25 @@ -import React, { FunctionComponent, useState, useEffect } from 'react' -import Picker from '@/packages/picker' -import { PickerOption, PickerProps } from '@/packages/picker/index' +import React, { + useState, + useEffect, + ForwardRefRenderFunction, + useImperativeHandle, +} from 'react' +import Picker, { PickerOption } from '@/packages/picker' import { useConfig } from '@/packages/configprovider' import { usePropsValue } from '@/hooks/use-props-value' -import { BasicComponent, ComponentDefaults } from '@/utils/typings' +import { ComponentDefaults } from '@/utils/typings' import { isDate } from '@/utils/is-date' -import { padZero } from '@/utils/pad-zero' - -export interface DatePickerProps extends BasicComponent { - value?: Date - defaultValue?: Date - visible: boolean - title: string - type: - | 'date' - | 'time' - | 'year-month' - | 'month-day' - | 'datehour' - | 'datetime' - | 'hour-minutes' - showChinese: boolean - minuteStep: number - startDate: Date - endDate: Date - threeDimensional: boolean - pickerProps: Partial< - Omit< - PickerProps, - | 'defaultValue' - | 'threeDimensional' - | 'title' - | 'value' - | 'onConfirm' - | 'onClose' - | 'onCancel' - | 'onChange' - > - > - formatter: (type: string, option: PickerOption) => PickerOption - filter: (type: string, option: PickerOption[]) => PickerOption[] - onClose: () => void - onCancel: () => void - onConfirm: ( - selectedOptions: PickerOption[], - selectedValue: (string | number)[] - ) => void - onChange?: ( - selectedOptions: PickerOption[], - selectedValue: (string | number)[], - columnIndex: number - ) => void -} +import { + formatValue, + generateDatePickerRanges, + generatePickerColumnWithCallback, + getDatePartValue, + handlePickerValueChange, +} from './utils' +import { DatePickerActions, DatePickerProps, DatePickerRef } from './types' const currentYear = new Date().getFullYear() + const defaultProps = { ...ComponentDefaults, visible: false, @@ -66,10 +32,10 @@ const defaultProps = { endDate: new Date(currentYear + 10, 11, 31), } as DatePickerProps -export const DatePicker: FunctionComponent< - Partial & - Omit, 'onChange' | 'defaultValue'> -> = (props) => { +const InternalPicker: ForwardRefRenderFunction< + DatePickerRef, + Partial +> = (props, ref) => { const { startDate, endDate, @@ -89,13 +55,16 @@ export const DatePicker: FunctionComponent< threeDimensional, className, style, + children, ...rest } = { ...defaultProps, ...props, } + const { locale } = useConfig() const lang = locale.datepicker + const zhCNType: { [key: string]: string } = { day: lang.day, year: lang.year, @@ -104,127 +73,45 @@ export const DatePicker: FunctionComponent< minute: lang.min, seconds: lang.seconds, } + const [pickerValue, setPickerValue] = useState<(string | number)[]>([]) const [pickerOptions, setPickerOptions] = useState([]) - const formatValue = (value: Date | null) => { - if (!value || (value && !isDate(value))) { - value = startDate - } - return Math.min( - Math.max(value.getTime(), startDate.getTime()), - endDate.getTime() - ) - } + const [selectedDate, setSelectedDate] = usePropsValue({ - value: props.value && formatValue(props.value), - defaultValue: props.defaultValue && formatValue(props.defaultValue), + value: props.value && formatValue(props.value, startDate, endDate), + defaultValue: + props.defaultValue && formatValue(props.defaultValue, startDate, endDate), finalValue: 0, }) - function getMonthEndDay(year: number, month: number): number { - return new Date(year, month, 0).getDate() - } + const [innerDate, setInnerDate] = useState(selectedDate) - const getBoundary = (type: string, value: Date) => { - const boundary = type === 'min' ? startDate : endDate - const year = boundary.getFullYear() - let month = 1 - let date = 1 - let hour = 0 - let minute = 0 + const [innerVisible, setInnerVisible] = usePropsValue({ + value: props.visible, + defaultValue: false, + finalValue: false, + }) - if (type === 'max') { - month = 12 - date = getMonthEndDay(value.getFullYear(), value.getMonth() + 1) - hour = 23 - minute = 59 - } - const seconds = minute - if (value.getFullYear() === year) { - month = boundary.getMonth() + 1 - if (value.getMonth() + 1 === month) { - date = boundary.getDate() - if (value.getDate() === date) { - hour = boundary.getHours() - if (value.getHours() === hour) { - minute = boundary.getMinutes() - } - } - } - } - return { - [`${type}Year`]: year, - [`${type}Month`]: month, - [`${type}Date`]: date, - [`${type}Hour`]: hour, - [`${type}Minute`]: minute, - [`${type}Seconds`]: seconds, - } + const actions: DatePickerActions = { + open: () => { + setInnerVisible(true) + }, + close: () => { + setInnerVisible(false) + }, } - const ranges = () => { - const selected = new Date(selectedDate) - if (!selected) return [] - const { maxYear, maxDate, maxMonth, maxHour, maxMinute, maxSeconds } = - getBoundary('max', selected) - const { minYear, minDate, minMonth, minHour, minMinute, minSeconds } = - getBoundary('min', selected) - const result = [ - { - type: 'year', - range: [minYear, maxYear], - }, - { - type: 'month', - range: [minMonth, maxMonth], - }, - { - type: 'day', - range: [minDate, maxDate], - }, - { - type: 'hour', - range: [minHour, maxHour], - }, - { - type: 'minute', - range: [minMinute, maxMinute], - }, - { - type: 'seconds', - range: [minSeconds, maxSeconds], - }, - ] - switch (type.toLocaleLowerCase()) { - case 'date': - return result.slice(0, 3) - case 'datetime': - return result.slice(0, 5) - case 'time': - return result.slice(3, 6) - case 'year-month': - return result.slice(0, 2) - case 'hour-minutes': - return result.slice(3, 5) - case 'month-day': - return result.slice(1, 3) - case 'datehour': - return result.slice(0, 4) - default: - return result - } - } + useImperativeHandle(ref, () => actions) - const compareDateChange = ( - currentDate: number, + const handleDateComparison = ( newDate: Date | null, selectedOptions: PickerOption[], index: number ) => { - const isEqual = new Date(currentDate)?.getTime() === newDate?.getTime() + const isEqual = new Date(innerDate)?.getTime() === newDate?.getTime() if (newDate && isDate(newDate)) { if (!isEqual) { - setSelectedDate(formatValue(newDate as Date)) + setInnerDate(formatValue(newDate, startDate, endDate)) } onChange?.( selectedOptions, @@ -237,189 +124,130 @@ export const DatePicker: FunctionComponent< ) } } - const handlePickerChange = ( - selectedOptions: PickerOption[], - selectedValue: (number | string)[], - index: number - ) => { - const rangeType = type.toLocaleLowerCase() - if ( - ['date', 'datetime', 'datehour', 'month-day', 'year-month'].includes( - rangeType - ) - ) { - const formatDate: (number | string)[] = [] - selectedValue.forEach((item) => { - formatDate.push(item) - }) - if (rangeType === 'month-day' && formatDate.length < 3) { - formatDate.unshift( - new Date(defaultValue || startDate || endDate).getFullYear() - ) - } - - if (rangeType === 'year-month' && formatDate.length < 3) { - formatDate.push( - new Date(defaultValue || startDate || endDate).getDate() - ) - } - const year = Number(formatDate[0]) - const month = Number(formatDate[1]) - 1 - const day = Math.min( - Number(formatDate[2]), - getMonthEndDay(Number(formatDate[0]), Number(formatDate[1])) - ) - let date: Date | null = null - if ( - rangeType === 'date' || - rangeType === 'month-day' || - rangeType === 'year-month' - ) { - date = new Date(year, month, day) - } else if (rangeType === 'datetime') { - date = new Date( - year, - month, - day, - Number(formatDate[3]), - Number(formatDate[4]) - ) - } else if (rangeType === 'datehour') { - date = new Date(year, month, day, Number(formatDate[3])) + const handleConfirmDateComparison = (newDate: Date | null) => { + if (newDate && isDate(newDate)) { + const isEqual = new Date(selectedDate)?.getTime() === newDate?.getTime() + if (!isEqual) { + setSelectedDate(formatValue(newDate, startDate, endDate)) } + } + } - compareDateChange(selectedDate, date, selectedOptions, index) - } else { - // 'hour-minutes' 'time' - const [hour, minute, seconds] = selectedValue - const currentDate = new Date(selectedDate) - const year = currentDate.getFullYear() - const month = currentDate.getMonth() - const day = currentDate.getDate() + const handleCancel = () => { + setInnerDate(selectedDate) + onCancel?.() + } - const date = new Date( - year, - month, - day, - Number(hour), - Number(minute), - rangeType === 'time' ? Number(seconds) : 0 - ) - compareDateChange(selectedDate, date, selectedOptions, index) - } + const handleClose = () => { + setInnerVisible(false) + onClose?.() } - const formatOption = (type: string, value: string | number) => { - if (formatter) { - return formatter(type, { - text: padZero(value, 2), - value: padZero(value, 2), - }) - } - const padMin = padZero(value, 2) - const fatter = showChinese ? zhCNType[type] : '' - return { text: padMin + fatter, value: padMin } + const handleConfirm = ( + options: PickerOption[], + value: (string | number)[] + ) => { + handlePickerValueChange( + options, + value, + 0, + type, + defaultValue || startDate || endDate, + handleConfirmDateComparison + ) + onConfirm?.(options, value) } - const generateColumn = ( - min: number, - max: number, - val: number | string, - type: string, - columnIndex: number + const handleChange = ( + selectedOptions: PickerOption[], + selectedValue: (string | number)[], + index: number ) => { - let cmin = min - const arr: Array = [] - let index = 0 - while (cmin <= max) { - arr.push(formatOption(type, cmin)) + innerVisible && + handlePickerValueChange( + selectedOptions, + selectedValue, + index, + type, + defaultValue || startDate || endDate, + handleDateComparison + ) + } - if (type === 'minute') { - cmin += minuteStep - } else { - cmin++ - } + const generatePickerColumns = (): PickerOption[][] => { + const dateRanges = generateDatePickerRanges( + type, + innerDate, + startDate, + endDate + ) - if (cmin <= Number(val)) { - index++ - } - } + const columns = dateRanges.map((rangeConfig, columnIndex) => { + const { type: columnType, range } = rangeConfig + const selectedValue = getDatePartValue(columnType, innerDate) + + const pickerColumn = generatePickerColumnWithCallback( + range[0], + range[1], + selectedValue, + columnType, + minuteStep, + (selectedIndex, options) => { + pickerValue[columnIndex] = options[selectedIndex]?.value + setPickerValue([...pickerValue]) + }, + showChinese, + zhCNType, + formatter + ) - pickerValue[columnIndex] = arr[index]?.value - setPickerValue([...pickerValue]) + if (filter?.(columnType, pickerColumn)) { + return filter(columnType, pickerColumn) + } - if (filter?.(type, arr)) { - return filter?.(type, arr) - } - return arr - } + return pickerColumn + }) - const getDateIndex = (type: string) => { - const date = new Date(selectedDate) - if (!selectedDate) return 0 - if (type === 'year') { - return date.getFullYear() - } - if (type === 'month') { - return date.getMonth() + 1 - } - if (type === 'day') { - return date.getDate() - } - if (type === 'hour') { - return date.getHours() - } - if (type === 'minute') { - return date.getMinutes() - } - if (type === 'seconds') { - return date.getSeconds() - } - return 0 + return columns || [] } - const columns = () => { - const val = ranges().map((res, columnIndex) => { - return generateColumn( - res.range[0], - res.range[1], - getDateIndex(res.type), - res.type, - columnIndex - ) - }) - return val || [] - } + useEffect(() => { + setInnerDate(selectedDate) + }, [selectedDate]) useEffect(() => { - setPickerOptions(columns()) - }, [selectedDate, startDate, endDate]) + setPickerOptions(generatePickerColumns()) + }, [innerDate, startDate, endDate]) return ( -
- {pickerOptions.length > 0 && ( - - onConfirm && onConfirm(options, value) - } - onChange={( - options: PickerOption[], - value: (number | string)[], - index: number - ) => handlePickerChange(options, value, index)} - threeDimensional={threeDimensional} - /> - )} -
+ <> + {typeof children === 'function' && children(selectedDate)} +
+ {pickerOptions.length && ( + handleChange(options, value, index)} + threeDimensional={threeDimensional} + /> + )} +
+ ) } -DatePicker.displayName = 'NutDatePicker' +const DatePicker = React.forwardRef>( + InternalPicker +) +export default DatePicker diff --git a/src/packages/datepicker/demos/h5/demo1.tsx b/src/packages/datepicker/demos/h5/demo1.tsx index f227a06824..ff87453056 100644 --- a/src/packages/datepicker/demos/h5/demo1.tsx +++ b/src/packages/datepicker/demos/h5/demo1.tsx @@ -1,25 +1,50 @@ import React, { useState } from 'react' import { DatePicker, Cell, type PickerOption } from '@nutui/nutui-react' +import isEqual from 'react-fast-compare' + +const useDatePicker = (initialDate: Date) => { + const defaultDateObj = { + year: initialDate.getFullYear(), + month: initialDate.getMonth() + 1, + day: initialDate.getDate(), + } + + const defaultDesc = `${defaultDateObj.year}年${defaultDateObj.month}月${defaultDateObj.day}日` + const defaultValue = Object.values(defaultDateObj).join('-') + + return { defaultDesc, defaultValue } +} const Demo1 = () => { - const defaultValue = new Date() - const defaultDescription = `${defaultValue.getFullYear()}-${ - defaultValue.getMonth() + 1 - }-${defaultValue.getDate()}` - const [show, setShow1] = useState(false) - const [desc1, setDesc1] = useState(defaultDescription) - - const [value, setValue] = useState('2023/01/01') + const defaultDate = new Date() + const { defaultDesc: defaultDesc1, defaultValue: defaultValue1 } = + useDatePicker(defaultDate) + const { defaultDesc: defaultDesc2, defaultValue: defaultValue2 } = + useDatePicker(defaultDate) + + const [show1, setShow1] = useState(false) + const [desc1, setDesc1] = useState(defaultDesc1) + + const [value, setValue] = useState(defaultValue2) const [show2, setShow2] = useState(false) - const [desc2, setDesc2] = useState('') - const confirm1 = (values: (string | number)[], options: PickerOption[]) => { - setDesc1(options.map((option) => option.text).join(' ')) - } - const change = (options: PickerOption[], values: (string | number)[]) => { - const v = values.join('/') - setValue(v) - setDesc2(options.map((option) => option.text).join(' ')) - } + const [desc2, setDesc2] = useState(defaultDesc2) + + const handleConfirm = + (setDesc: (desc: string) => void, setValue?: (value: string) => void) => + (options: PickerOption[], values: (string | number)[]) => { + if (setValue) { + if (isEqual(values, ['2026', '02', '21'])) { + setValue('2026/03/22') + setDesc('2026年03月22日') + } else { + setValue(values.join('/')) + setDesc(options.map((option) => option.text).join('')) + } + } else { + setDesc(options.map((option) => option.text).join('')) + } + } + return ( <> { /> setShow1(false)} - onConfirm={(options, values) => { - setShow1(false) - confirm1(values, options) - console.log('onconfirm') - }} + onClose={() => setShow1(false)} + onConfirm={handleConfirm(setDesc1)} /> { showChinese onClose={() => setShow2(false)} threeDimensional={false} - onChange={(options, values) => change(options, values)} + onConfirm={handleConfirm(setDesc2, setValue)} /> ) } + export default Demo1 diff --git a/src/packages/datepicker/demos/h5/demo2.tsx b/src/packages/datepicker/demos/h5/demo2.tsx index bd4350dcde..60a695dc40 100644 --- a/src/packages/datepicker/demos/h5/demo2.tsx +++ b/src/packages/datepicker/demos/h5/demo2.tsx @@ -20,9 +20,9 @@ const Demo2 = () => { /> setShow(false)} diff --git a/src/packages/datepicker/demos/h5/demo8.tsx b/src/packages/datepicker/demos/h5/demo8.tsx index a5cce7f3eb..84f2b853e3 100644 --- a/src/packages/datepicker/demos/h5/demo8.tsx +++ b/src/packages/datepicker/demos/h5/demo8.tsx @@ -7,9 +7,13 @@ const Demo8 = () => { const defaultValue = new Date() const defaultDescription = `${defaultValue.getFullYear()}-${ defaultValue.getMonth() + 1 - }-${defaultValue.getDate()}` + }-${defaultValue.getDate()} 06:00` const [show, setShow] = useState(false) - const [desc, setDesc] = useState(`${defaultDescription} 00`) + const [desc, setDesc] = useState( + `${defaultValue.getFullYear()}年${ + defaultValue.getMonth() + 1 + }月${defaultValue.getDate()}日 06时` + ) const confirm = (values: (string | number)[], options: PickerOption[]) => { setDesc(options.map((option) => option.text).join(' ')) @@ -42,7 +46,7 @@ const Demo8 = () => { return ( <> setShow(true)} /> diff --git a/src/packages/datepicker/demos/taro/demo1.tsx b/src/packages/datepicker/demos/taro/demo1.tsx index dadd406cb0..a81c77dfc5 100644 --- a/src/packages/datepicker/demos/taro/demo1.tsx +++ b/src/packages/datepicker/demos/taro/demo1.tsx @@ -1,25 +1,50 @@ import React, { useState } from 'react' import { DatePicker, Cell, type PickerOption } from '@nutui/nutui-react-taro' +import isEqual from 'react-fast-compare' + +const useDatePicker = (initialDate: Date) => { + const defaultDateObj = { + year: initialDate.getFullYear(), + month: initialDate.getMonth() + 1, + day: initialDate.getDate(), + } + + const defaultDesc = `${defaultDateObj.year}年${defaultDateObj.month}月${defaultDateObj.day}日` + const defaultValue = Object.values(defaultDateObj).join('-') + + return { defaultDesc, defaultValue } +} const Demo1 = () => { - const defaultValue = new Date() - const defaultDescription = `${defaultValue.getFullYear()}-${ - defaultValue.getMonth() + 1 - }-${defaultValue.getDate()}` + const defaultDate = new Date() + const { defaultDesc: defaultDesc1, defaultValue: defaultValue1 } = + useDatePicker(defaultDate) + const { defaultDesc: defaultDesc2, defaultValue: defaultValue2 } = + useDatePicker(defaultDate) + const [show1, setShow1] = useState(false) - const [desc1, setDesc1] = useState(defaultDescription) + const [desc1, setDesc1] = useState(defaultDesc1) - const [value, setValue] = useState('2023/01/01') + const [value, setValue] = useState(defaultValue2) const [show2, setShow2] = useState(false) - const [desc2, setDesc2] = useState('') - const confirm = (values: (string | number)[], options: PickerOption[]) => { - setDesc1(options.map((option) => option.text).join(' ')) - } - const change = (options: PickerOption[], values: (string | number)[]) => { - const v = values.join('/') - setValue(v) - setDesc2(options.map((option) => option.text).join(' ')) - } + const [desc2, setDesc2] = useState(defaultDesc2) + + const handleConfirm = + (setDesc: (desc: string) => void, setValue?: (value: string) => void) => + (options: PickerOption[], values: (string | number)[]) => { + if (setValue) { + if (isEqual(values, ['2026', '02', '21'])) { + setValue('2026/03/22') + setDesc('2026年03月22日') + } else { + setValue(values.join('/')) + setDesc(options.map((option) => option.text).join('')) + } + } else { + setDesc(options.map((option) => option.text).join('')) + } + } + return ( <> { pickerProps={{ popupProps: { zIndex: 1220 }, }} - defaultValue={new Date(`${defaultDescription}`)} + defaultValue={new Date(defaultValue1)} showChinese - onCancel={() => setShow1(false)} - onConfirm={(options, values) => { - setShow1(false) - confirm(values, options) - console.log('onconfirm') - }} + onClose={() => setShow1(false)} + onConfirm={handleConfirm(setDesc1)} /> { showChinese onClose={() => setShow2(false)} threeDimensional={false} - onChange={(options, values) => change(options, values)} + onConfirm={handleConfirm(setDesc2, setValue)} /> ) } + export default Demo1 diff --git a/src/packages/datepicker/demos/taro/demo2.tsx b/src/packages/datepicker/demos/taro/demo2.tsx index 7d3b42edaf..947d497e95 100644 --- a/src/packages/datepicker/demos/taro/demo2.tsx +++ b/src/packages/datepicker/demos/taro/demo2.tsx @@ -7,6 +7,7 @@ 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('-')) } @@ -19,9 +20,9 @@ const Demo2 = () => { /> setShow(false)} diff --git a/src/packages/datepicker/index.taro.ts b/src/packages/datepicker/index.taro.ts index d990ce8459..e5aef5354a 100644 --- a/src/packages/datepicker/index.taro.ts +++ b/src/packages/datepicker/index.taro.ts @@ -1,4 +1,4 @@ -import { DatePicker } from './datepicker.taro' +import DatePicker from './datepicker' -export type { DatePickerProps } from './datepicker.taro' +export type { DatePickerProps } from './types.taro' export default DatePicker diff --git a/src/packages/datepicker/index.ts b/src/packages/datepicker/index.ts index 0c83b853f5..976678232c 100644 --- a/src/packages/datepicker/index.ts +++ b/src/packages/datepicker/index.ts @@ -1,4 +1,4 @@ -import { DatePicker } from './datepicker' +import DatePicker from './datepicker' -export type { DatePickerProps } from './datepicker' +export type { DatePickerProps } from './types' export default DatePicker diff --git a/src/packages/datepicker/types.taro.ts b/src/packages/datepicker/types.taro.ts new file mode 100644 index 0000000000..d4bfaa00d5 --- /dev/null +++ b/src/packages/datepicker/types.taro.ts @@ -0,0 +1,18 @@ +import { PickerProps } from '@/packages/picker/types.taro' +import { DatePickerProps as DatePickerWebProps } from './types' + +export type DatePickerProps = Omit & { + pickerProps: Partial< + Omit< + PickerProps, + | 'defaultValue' + | 'threeDimensional' + | 'title' + | 'value' + | 'onConfirm' + | 'onClose' + | 'onCancel' + | 'onChange' + > + > +} diff --git a/src/packages/datepicker/types.ts b/src/packages/datepicker/types.ts new file mode 100644 index 0000000000..0af55e6625 --- /dev/null +++ b/src/packages/datepicker/types.ts @@ -0,0 +1,55 @@ +import { BasicComponent } from '@/utils/typings' +import { PickerOption, PickerProps } from '../picker/types' + +export type DatePickerRef = DatePickerActions +export type DatePickerActions = { + open: () => void + close: () => void +} + +export interface DatePickerProps extends BasicComponent { + value?: Date + defaultValue?: Date + visible: boolean + title: string + type: + | 'date' + | 'time' + | 'year-month' + | 'month-day' + | 'datehour' + | 'datetime' + | 'hour-minutes' + showChinese: boolean + minuteStep: number + startDate: Date + endDate: Date + threeDimensional: boolean + pickerProps: Partial< + Omit< + PickerProps, + | 'defaultValue' + | 'threeDimensional' + | 'title' + | 'value' + | 'onConfirm' + | 'onClose' + | 'onCancel' + | 'onChange' + > + > + formatter: (type: string, option: PickerOption) => PickerOption + filter: (type: string, option: PickerOption[]) => PickerOption[] + onClose: () => void + onCancel: () => void + onConfirm: ( + selectedOptions: PickerOption[], + selectedValue: (string | number)[] + ) => void + onChange?: ( + selectedOptions: PickerOption[], + selectedValue: (string | number)[], + columnIndex: number + ) => void + children?: any +} diff --git a/src/packages/datepicker/utils.ts b/src/packages/datepicker/utils.ts new file mode 100644 index 0000000000..cc82353bc2 --- /dev/null +++ b/src/packages/datepicker/utils.ts @@ -0,0 +1,332 @@ +import { padZero } from '@/utils/pad-zero' +import { isDate } from '@/utils/is-date' +import { PickerOption } from '../picker/types' + +/** + * 获取指定年份和月份的最后一天 + * @param year - 年份 + * @param month - 月份(1 到 12) + * @returns 返回该月份的最后一天 + */ +export function getLastDayOfMonth(year: number, month: number): number { + return new Date(year, month, 0).getDate() +} + +/** + * 根据类型和日期值,计算并返回日期边界值(年、月、日、时、分、秒) + * @param type 边界类型:'min' 表示最小值,'max' 表示最大值 + * @param value 传入的日期值 + * @param startDate 传入的开始时间 + * @param endDate 传入的结束时间 + * @returns 返回包含边界值的对象 + */ +export const calculateDateBoundary = ( + type: 'min' | 'max', + value: Date, + startDate: Date, + endDate: Date +) => { + const boundary = type === 'min' ? startDate : endDate + const year = boundary.getFullYear() + const isMax = type === 'max' + let month = isMax ? 12 : 1 + let date = isMax + ? getLastDayOfMonth(value.getFullYear(), value.getMonth() + 1) + : 1 + let hour = isMax ? 23 : 0 + let minute = isMax ? 59 : 0 + + if (value.getFullYear() === year) { + month = boundary.getMonth() + 1 + + if (value.getMonth() + 1 === month) { + date = boundary.getDate() + + if (value.getDate() === date) { + hour = boundary.getHours() + + if (value.getHours() === hour) { + minute = boundary.getMinutes() + } + } + } + } + + // 返回边界值的对象 + return { + [`${type}Year`]: year, + [`${type}Month`]: month, + [`${type}Date`]: date, + [`${type}Hour`]: hour, + [`${type}Minute`]: minute, + [`${type}Seconds`]: minute, // 返回秒数(与分钟相同) + } +} + +/** + * 根据选中的日期和类型,生成日期选择器的范围配置 + * @returns {Array} 返回日期选择器的范围配置数组 + */ +export const generateDatePickerRanges = ( + type: string, + selectedDate: number, + startDate: Date, + endDate: Date +) => { + const selected = new Date(selectedDate) + if (!selected) return [] + + // 获取最大和最小边界值 + const { maxYear, maxDate, maxMonth, maxHour, maxMinute, maxSeconds } = + calculateDateBoundary('max', selected, startDate, endDate) + const { minYear, minDate, minMonth, minHour, minMinute, minSeconds } = + calculateDateBoundary('min', selected, startDate, endDate) + + const fullRanges = [ + { type: 'year', range: [minYear, maxYear] }, + { type: 'month', range: [minMonth, maxMonth] }, + { type: 'day', range: [minDate, maxDate] }, + { type: 'hour', range: [minHour, maxHour] }, + { type: 'minute', range: [minMinute, maxMinute] }, + { type: 'seconds', range: [minSeconds, maxSeconds] }, + ] + + // 根据类型返回对应的范围配置 + switch (type.toLocaleLowerCase()) { + case 'date': + return fullRanges.slice(0, 3) + case 'datetime': + return fullRanges.slice(0, 5) + case 'time': + return fullRanges.slice(3, 6) + case 'year-month': + return fullRanges.slice(0, 2) + case 'hour-minutes': + return fullRanges.slice(3, 5) + case 'month-day': + return fullRanges.slice(1, 3) + case 'datehour': + return fullRanges.slice(0, 4) + default: + return fullRanges + } +} + +/** + * 根据类型获取日期对象中对应的值 + * @param type 需要获取的日期部分(如 'year', 'month', 'day' 等) + * @param selectedDate 选中的日期时间戳 + * @returns 返回日期对象中对应部分的值,如果类型无效或日期无效,返回 0 + */ +export const getDatePartValue = ( + type: string, + selectedDate: number +): number => { + const date = new Date(selectedDate) + + if (!selectedDate) return 0 + + switch (type) { + case 'year': + return date.getFullYear() + case 'month': + return date.getMonth() + 1 + case 'day': + return date.getDate() + case 'hour': + return date.getHours() + case 'minute': + return date.getMinutes() + case 'seconds': + return date.getSeconds() + default: + return 0 + } +} + +/** + * 生成 Picker 的列数据,并触发回调函数返回选中索引 + * @param min 最小值 + * @param max 最大值 + * @param currentValue 当前选中的值 + * @param type 列的类型(如 'year', 'month', 'minute' 等) + * @param minuteStep 分钟步长(仅当类型为 'minute' 时生效) + * @param callback 回调函数,用于返回选中索引 + * @returns 返回生成的 Picker 列数据 + */ +export const generatePickerColumnWithCallback = ( + min: number, + max: number, + currentValue: number | string, + type: string, + minuteStep: number, + callback: (selectedIndex: number, options: PickerOption[]) => void, + showChinese: boolean, + zhCNType: { [key: string]: string }, + formatter?: (type: string, option: PickerOption) => PickerOption +): PickerOption[] => { + let currentMin = min + const options: PickerOption[] = [] + let selectedIndex = 0 + + // 遍历从最小值到最大值的范围 + while (currentMin <= max) { + // 将当前值格式化为 PickerOption 并添加到数组中 + options.push( + formatPickerOption(type, currentMin, showChinese, zhCNType, formatter) + ) + + // 根据类型决定步长:如果是分钟,使用 minuteStep,否则步长为 1 + if (type === 'minute') { + currentMin += minuteStep + } else { + currentMin++ + } + + // 如果当前值小于等于选中的值,更新选中索引 + if (currentMin <= Number(currentValue)) { + selectedIndex++ + } + } + + callback(selectedIndex, options) + + return options +} + +/** + * 格式化 Picker 选项 + * @param type 选项类型(如 'year', 'month', 'minute' 等) + * @param value 选项的值 + * @param showChinese 是否显示中文文本 + * @param zhCNType 中文文本映射对象 + * @param formatter 自定义格式化函数 + * @returns 返回格式化后的 Picker 选项 + */ +export const formatPickerOption = ( + type: string, + value: string | number, + showChinese: boolean, + zhCNType: { [key: string]: string }, + formatter?: (type: string, option: PickerOption) => PickerOption +): PickerOption => { + if (formatter) { + return formatter(type, { + text: padZero(value, 2), + value: padZero(value, 2), + }) + } + + const paddedValue = padZero(value, 2) + + const chineseText = showChinese ? zhCNType[type] : '' + + return { + text: paddedValue + chineseText, + value: paddedValue, + } +} + +/** + * 格式化日期值,确保其在 startDate 和 endDate 之间 + */ +export const formatValue = ( + value: Date | null, + startDate: Date, + endDate: Date +) => { + if (!value || (value && !isDate(value))) { + value = startDate + } + return Math.min( + Math.max(value.getTime(), startDate.getTime()), + endDate.getTime() + ) +} + +/** + * 处理 Picker 值变化的逻辑 + * @param selectedOptions 选中的选项数组 + * @param selectedValue 选中的值数组 + * @param index 当前列的索引 + */ +export const handlePickerValueChange = ( + selectedOptions: PickerOption[], + selectedValue: (string | number)[], + index: number, + type: string, + defaultDate: Date, + handleDateComparison: ( + newDate: Date | null, + selectedOptions: PickerOption[], + index: number + ) => void +) => { + const rangeType = type.toLocaleLowerCase() + + if ( + ['date', 'datetime', 'datehour', 'month-day', 'year-month'].includes( + rangeType + ) + ) { + const formattedDate: (string | number)[] = [] + + selectedValue.forEach((item) => { + formattedDate.push(item) + }) + + if (rangeType === 'month-day' && formattedDate.length < 3) { + formattedDate.unshift(new Date(defaultDate).getFullYear()) + } + + if (rangeType === 'year-month' && formattedDate.length < 3) { + formattedDate.push(new Date(defaultDate).getDate()) + } + + const year = Number(formattedDate[0]) + const month = Number(formattedDate[1]) - 1 + const day = Math.min( + Number(formattedDate[2]), + getLastDayOfMonth(year, month + 1) + ) + + let date: Date | null = null + + if ( + rangeType === 'date' || + rangeType === 'month-day' || + rangeType === 'year-month' + ) { + date = new Date(year, month, day) + } else if (rangeType === 'datetime') { + date = new Date( + year, + month, + day, + Number(formattedDate[3]), + Number(formattedDate[4]) + ) + } else if (rangeType === 'datehour') { + date = new Date(year, month, day, Number(formattedDate[3])) + } + + handleDateComparison(date, selectedOptions, index) + } else { + const [hour, minute, seconds] = selectedValue + const currentDate = new Date(defaultDate) + const year = currentDate.getFullYear() + const month = currentDate.getMonth() + const day = currentDate.getDate() + + const date = new Date( + year, + month, + day, + Number(hour), + Number(minute), + rangeType === 'time' ? Number(seconds) : 0 + ) + + handleDateComparison(date, selectedOptions, index) + } +} diff --git a/src/packages/form/demos/h5/demo7.tsx b/src/packages/form/demos/h5/demo7.tsx index f0387f47a7..ddd6ac960d 100644 --- a/src/packages/form/demos/h5/demo7.tsx +++ b/src/packages/form/demos/h5/demo7.tsx @@ -12,6 +12,7 @@ import { Rate, Range, Toast, + DatePicker, } from '@nutui/nutui-react' import { ArrowRight } from '@nutui/icons-react' @@ -116,6 +117,40 @@ const Demo7 = () => { }} + { + console.log('sssss', args[0]) + return new Date(args[1].join('/')) + }} + onClick={(event, ref: any) => { + ref.open() + }} + initialValue={new Date()} + > + + {(value: any) => { + return ( + } + align="center" + /> + ) + }} + + { }} + { + console.log('sssss', args[0]) + return new Date(args[1].join('/')) + }} + onClick={(event, ref: any) => { + ref.open() + }} + initialValue={new Date()} + > + + {(value: any) => { + return ( + } + align="center" + /> + ) + }} + + void close: () => void } -export interface PickerProps extends Omit { - visible?: boolean | undefined - title?: string - options: (PickerOption | PickerOption[])[] - value?: (number | string)[] - defaultValue?: (number | string)[] - threeDimensional?: boolean - duration: number | string - closeOnOverlayClick: boolean - popupProps: Partial< - Omit - > - onConfirm?: ( - selectedOptions: PickerOption[], - selectedValue: (string | number)[] - ) => 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 - ) => void - children?: any -} - const defaultProps = { ...ComponentDefaults, visible: false, diff --git a/src/packages/picker/picker.tsx b/src/packages/picker/picker.tsx index 3ffbb5c2e0..e8faab6f04 100644 --- a/src/packages/picker/picker.tsx +++ b/src/packages/picker/picker.tsx @@ -2,59 +2,24 @@ import React, { useState, useEffect, useRef, - RefObject, ForwardRefRenderFunction, useImperativeHandle, } from 'react' import classNames from 'classnames' -import Popup, { PopupProps } from '@/packages/popup/index' +import Popup from '@/packages/popup/index' import { SafeArea } from '@/packages/safearea/safearea' import PickerPanel from './pickerpanel' import useRefs from '@/hooks/use-refs' import { useConfig } from '@/packages/configprovider' -import { PickerOption } from './types' +import { PickerOption, PickerProps } from './types' import { usePropsValue } from '@/hooks/use-props-value' -import { BasicComponent, ComponentDefaults } from '@/utils/typings' +import { ComponentDefaults } from '@/utils/typings' export type PickerActions = { open: () => void close: () => void } -export interface PickerProps extends Omit { - visible?: boolean | undefined - title?: string - options: (PickerOption | PickerOption[])[] - value?: (number | string)[] - defaultValue?: (number | string)[] - threeDimensional?: boolean - duration: number | string - closeOnOverlayClick: boolean - popupProps: Partial< - Omit - > - onConfirm?: ( - selectedOptions: PickerOption[], - selectedValue: (string | number)[] - ) => 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 - ) => void - children?: any -} - const defaultProps = { ...ComponentDefaults, title: '', diff --git a/src/packages/picker/types.taro.ts b/src/packages/picker/types.taro.ts new file mode 100644 index 0000000000..e2b2ea9777 --- /dev/null +++ b/src/packages/picker/types.taro.ts @@ -0,0 +1,8 @@ +import { PopupProps } from '@/packages/popup/types.taro' +import { PickerProps as PickerWebProps } from './types' + +export type PickerProps = Omit & { + popupProps: Partial< + Omit + > +} diff --git a/src/packages/picker/types.ts b/src/packages/picker/types.ts index 5c7e00b846..f59149fe30 100644 --- a/src/packages/picker/types.ts +++ b/src/packages/picker/types.ts @@ -1,3 +1,7 @@ +import { RefObject } from 'react' +import { PopupProps } from '../popup/types' +import { BasicComponent } from '@/utils/typings' + export interface PickerOption { text: string | number value: string | number @@ -5,3 +9,37 @@ export interface PickerOption { children?: PickerOption[] className?: string | number } + +export interface PickerProps extends Omit { + visible?: boolean | undefined + title?: string + options: (PickerOption | PickerOption[])[] + value?: (number | string)[] + defaultValue?: (number | string)[] + threeDimensional?: boolean + duration: number | string + closeOnOverlayClick: boolean + popupProps: Partial< + Omit + > + onConfirm?: ( + selectedOptions: PickerOption[], + selectedValue: (string | number)[] + ) => 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 + ) => void + children?: any +}