diff --git a/docs/examples/debug.tsx b/docs/examples/debug.tsx index 345c9c748..e44893ad7 100644 --- a/docs/examples/debug.tsx +++ b/docs/examples/debug.tsx @@ -128,7 +128,7 @@ export default () => { const singleRef = React.useRef(null); const [value, setValue] = React.useState(null); - const [rangeValue, setRangeValue] = React.useState<[Dayjs?, Dayjs?]>( + const [rangeValue, setRangeValue] = React.useState<[Dayjs, Dayjs]>( // [dayjs('2000-12-15'), dayjs('2020-12-22')], // null, undefined, @@ -149,24 +149,27 @@ export default () => { date.date() >= 5} - getPopupContainer={(node) => { - console.log('Popup!', node); - return node.parentElement!; - }} + // getPopupContainer={(node) => { + // console.log('Popup!', node); + // return node.parentElement!; + // }} + picker="time" + defaultPickerValue={dayjs('2000-01-01 03:05:08')} presets={[ { label: 'Good', @@ -193,7 +196,7 @@ export default () => { }} />
- { start: 'inputStart', end: 'inputEnd', }} - /> + /> */}
diff --git a/src/PickerInput/Popup/index.tsx b/src/PickerInput/Popup/index.tsx index 3eacfee3c..37c56a7cd 100644 --- a/src/PickerInput/Popup/index.tsx +++ b/src/PickerInput/Popup/index.tsx @@ -28,6 +28,7 @@ export interface PopupProps boolean; + onOk: VoidFunction; } export default function Popup(props: PopupProps) { @@ -56,7 +57,11 @@ export default function Popup(props: PopupProps(props: PopupProps { - const valueList = toArray(value).filter((val) => val); + function filterEmpty(list: T[]) { + return list.filter((item) => item); + } + + const valueList = React.useMemo(() => filterEmpty(toArray(value)), [value]); + + const isTimePicker = picker === 'time'; + const isEmptyValue = !valueList.length; + + const footerSubmitValue = React.useMemo(() => { + if (isTimePicker && isEmptyValue) { + return filterEmpty([pickerValue]); + } + return valueList; + }, [isTimePicker, valueList, isEmptyValue, pickerValue]); + const disableSubmit = React.useMemo(() => { // Empty is invalid - if (!valueList.length) { + if (!footerSubmitValue.length) { return true; } - return valueList.some((val) => isInvalid(val)); - }, [value, isInvalid]); + return footerSubmitValue.some((val) => isInvalid(val)); + }, [footerSubmitValue, isInvalid]); + + const onFooterSubmit = () => { + // For TimePicker, we will additional trigger the value update + if (isTimePicker && isEmptyValue) { + onSelect(pickerValue); + } + + onOk(); + onSubmit(); + }; let mergedNodes: React.ReactNode = (
@@ -112,7 +141,12 @@ export default function Popup(props: PopupProps
-
+
); diff --git a/src/PickerInput/RangePicker.tsx b/src/PickerInput/RangePicker.tsx index def1d0542..9c1c5d676 100644 --- a/src/PickerInput/RangePicker.tsx +++ b/src/PickerInput/RangePicker.tsx @@ -79,12 +79,12 @@ export interface BaseRangePickerProps * * Note: `defaultPickerValue` priority is higher than `value` for the first open. */ - defaultPickerValue?: [DateType, DateType] | null; + defaultPickerValue?: [DateType, DateType] | DateType | null; /** * Config each start & end field popup panel date. * When config `pickerValue`, you must also provide `onPickerValueChange` to handle changes. */ - pickerValue?: [DateType, DateType] | null; + pickerValue?: [DateType, DateType] | DateType | null; /** * Each popup panel `pickerValue` includes `mode` change will trigger the callback. * @param date The changed picker value diff --git a/src/PickerInput/hooks/useFilledProps.ts b/src/PickerInput/hooks/useFilledProps.ts index d5aa930eb..b0596848b 100644 --- a/src/PickerInput/hooks/useFilledProps.ts +++ b/src/PickerInput/hooks/useFilledProps.ts @@ -1,9 +1,9 @@ import { warning } from 'rc-util'; import * as React from 'react'; -import { toArray } from '../../utils/miscUtil'; import { fillLocale } from '../../hooks/useLocale'; import { getTimeConfig } from '../../hooks/useTimeConfig'; import type { FormatType, InternalMode } from '../../interface'; +import { toArray } from '../../utils/miscUtil'; import type { RangePickerProps } from '../RangePicker'; import { fillClearIcon } from '../Selector/hooks/useClearIcon'; import useDisabledBoundary from './useDisabledBoundary'; @@ -32,6 +32,7 @@ type PickedProps = Pick< | 'disabledDate' | 'minDate' | 'maxDate' + | 'defaultOpenValue' > & { multiple?: boolean; // RangePicker showTime definition is different with Picker @@ -48,8 +49,16 @@ type GetGeneric = T extends PickedProps ? U : never; type ToArrayType = T extends any[] ? T : DateType[]; -function useList(value: T | T[]) { - const values = React.useMemo(() => (value ? toArray(value) : value), [value]); +function useList(value: T | T[], fillMode = false) { + const values = React.useMemo(() => { + const list = value ? toArray(value) : value; + + if (fillMode && list) { + list[1] = list[1] || list[0]; + } + + return list; + }, [value, fillMode]); return values; } @@ -105,25 +114,32 @@ export default function useFilledProps< defaultValue, pickerValue, defaultPickerValue, + defaultOpenValue, } = props; const values = useList(value); const defaultValues = useList(defaultValue); + const defaultOpenValues = useList(defaultOpenValue, true); const pickerValues = useList(pickerValue); - const defaultPickerValues = useList(defaultPickerValue); + const defaultPickerValues = useList(defaultPickerValue) || defaultOpenValues; const mergedLocale = fillLocale(locale); const mergedShowTime = getTimeConfig(props); // ======================= Warning ======================== - if ( - process.env.NODE_ENV !== 'production' && - picker === 'time' && - ['disabledHours', 'disabledMinutes', 'disabledSeconds'].some((key) => (props as any)[key]) - ) { + if (process.env.NODE_ENV !== 'production' && picker === 'time') { + if ( + ['disabledHours', 'disabledMinutes', 'disabledSeconds'].some((key) => (props as any)[key]) + ) { + warning( + false, + `'disabledHours', 'disabledMinutes', 'disabledSeconds' will be removed in the next major version, please use 'disabledTime' instead.`, + ); + } + warning( - false, - `'disabledHours', 'disabledMinutes', 'disabledSeconds' will be removed in the next major version, please use 'disabledTime' instead.`, + !defaultOpenValue, + `'defaultOpenValue' is deprecated which merged into 'defaultPickerValue' instead.`, ); } diff --git a/src/PickerInput/hooks/useRangePickerValue.ts b/src/PickerInput/hooks/useRangePickerValue.ts index bce91c2bd..618d2597a 100644 --- a/src/PickerInput/hooks/useRangePickerValue.ts +++ b/src/PickerInput/hooks/useRangePickerValue.ts @@ -76,22 +76,21 @@ export default function useRangePickerValue - // Merge the `showTime.defaultValue` into `pickerValue` - fillTime( - generateConfig, - [mergedStartPickerValue, mergedEndPickerValue][mergedActiveIndex], - timeDefaultValue[mergedActiveIndex], - ), - [ - mergedStartPickerValue, - mergedEndPickerValue, - mergedActiveIndex, - generateConfig, - timeDefaultValue, - ], - ); + const currentPickerValue = React.useMemo(() => { + const current = [mergedStartPickerValue, mergedEndPickerValue][mergedActiveIndex]; + + // Merge the `showTime.defaultValue` into `pickerValue` + return pickerMode === 'time' + ? current + : fillTime(generateConfig, current, timeDefaultValue[mergedActiveIndex]); + }, [ + pickerMode, + mergedStartPickerValue, + mergedEndPickerValue, + mergedActiveIndex, + generateConfig, + timeDefaultValue, + ]); const setCurrentPickerValue = ( nextPickerValue: DateType, diff --git a/src/interface.tsx b/src/interface.tsx index 01048bf99..f0500036d 100644 --- a/src/interface.tsx +++ b/src/interface.tsx @@ -368,6 +368,8 @@ export interface SharedPickerProps maxDate?: DateType; // Open + /** @deprecated Please use `defaultPickerValue` instead */ + defaultOpenValue?: DateType; defaultOpen?: boolean; open?: boolean; onOpenChange?: (open: boolean) => void; diff --git a/tests/picker.spec.tsx b/tests/picker.spec.tsx index 3612d482d..76f3116ae 100644 --- a/tests/picker.spec.tsx +++ b/tests/picker.spec.tsx @@ -777,11 +777,9 @@ describe('Picker.Basic', () => { it('not open when disabled', () => { const { rerender } = render(); - // document.querySelector('.rc-picker').simulate('click'); fireEvent.click(document.querySelector('.rc-picker')); expect(isOpen()).toBeFalsy(); - // wrapper.setProps({ disabled: false }); rerender(); expect(isOpen()).toBeFalsy(); }); @@ -791,38 +789,35 @@ describe('Picker.Basic', () => { const inputElement = document.querySelector('input'); inputElement.focus = jest.fn(); - // document.querySelector('.rc-picker').simulate('mouseup'); fireEvent.mouseUp(document.querySelector('.rc-picker')); expect(inputElement.focus).toHaveBeenCalledTimes(0); expect(isOpen()).toBeFalsy(); }); - // Removed `defaultOpenValue` - // it('defaultOpenValue in timePicker', () => { - // resetWarned(); - // const onChange = jest.fn(); - // const errSpy = jest.spyOn(console, 'error').mockImplementation(() => {}); + it('defaultOpenValue in timePicker', () => { + resetWarned(); + const onChange = jest.fn(); + const errSpy = jest.spyOn(console, 'error').mockImplementation(() => {}); - // const { container } = render( - // , - // ); + const { container } = render( + , + ); - // expect(errSpy).toHaveBeenCalledWith( - // 'Warning: `defaultOpenValue` may confuse user for the current value status. Please use `defaultValue` instead.', - // ); + expect(errSpy).toHaveBeenCalledWith( + "Warning: 'defaultOpenValue' is deprecated which merged into 'defaultPickerValue' instead.", + ); - // openPicker(container); - // // document.querySelector('.rc-picker-ok button').simulate('click'); - // fireEvent.click(document.querySelector('.rc-picker-ok button')); + openPicker(container); + fireEvent.click(document.querySelector('.rc-picker-ok button')); - // expect(isSame(onChange.mock.calls[0][0], '2000-01-01 00:10:23')).toBeTruthy(); + expect(isSame(onChange.mock.calls[0][0], '2000-01-01 00:10:23')).toBeTruthy(); - // errSpy.mockRestore(); - // }); + errSpy.mockRestore(); + }); it('close to reset', () => { const { container } = render();