diff --git a/src/PickerPanel.tsx b/src/PickerPanel.tsx index b8ff9d221..bd90c28ba 100644 --- a/src/PickerPanel.tsx +++ b/src/PickerPanel.tsx @@ -18,6 +18,7 @@ import { PanelRefProps, PickerMode, DisabledTime, + OnPanelChange, } from './interface'; import { isEqual } from './utils/dateUtil'; import PanelContext from './PanelContext'; @@ -55,7 +56,7 @@ export interface PickerPanelSharedProps { // Event onSelect?: (value: DateType) => void; onChange?: (value: DateType) => void; - onPanelChange?: (value: DateType, mode: PanelMode) => void; + onPanelChange?: OnPanelChange; onMouseDown?: React.MouseEventHandler; } diff --git a/src/RangePicker.tsx b/src/RangePicker.tsx index ae468ae30..25463fd48 100644 --- a/src/RangePicker.tsx +++ b/src/RangePicker.tsx @@ -11,6 +11,7 @@ import { DisabledTime, PickerMode, PanelMode, + OnPanelChange, } from './interface'; import { toArray } from './utils/miscUtil'; import RangeContext from './RangeContext'; @@ -18,10 +19,11 @@ import { isSameDate } from './utils/dateUtil'; import { getDefaultFormat } from './utils/uiUtil'; import { SharedTimeProps } from './panels/TimePanel'; -type RangeValue = [DateType | null, DateType | null] | null; +type EventValue = DateType | null; +type RangeValue = [EventValue, EventValue] | null; function canTriggerChange( - dates: [DateType | null, DateType | null], + dates: [EventValue, EventValue], allowEmpty?: [boolean, boolean], ): boolean { const passStart = dates[0] || (allowEmpty && allowEmpty[0]); @@ -35,7 +37,7 @@ export interface RangePickerSharedProps { defaultPickerValue?: [DateType, DateType]; placeholder?: [string, string]; disabledTime?: ( - date: DateType | null, + date: EventValue, type: 'start' | 'end', ) => DisabledTimes; ranges?: Record< @@ -48,13 +50,17 @@ export interface RangePickerSharedProps { selectable?: [boolean, boolean]; mode?: [PanelMode, PanelMode]; onChange?: ( - value: RangeValue, + values: RangeValue, formatString: [string, string], ) => void; onCalendarChange?: ( - value: RangeValue, + values: RangeValue, formatString: [string, string], ) => void; + onPanelChange?: ( + values: RangeValue, + modes: [PanelMode, PanelMode], + ) => void; onFocus?: React.FocusEventHandler; onBlur?: React.FocusEventHandler; } @@ -64,13 +70,14 @@ type OmitPickerProps = Omit< | 'value' | 'defaultValue' | 'defaultPickerValue' - | 'onChange' - | 'onSelect' | 'placeholder' | 'disabledTime' | 'showToday' | 'showTime' | 'mode' + | 'onChange' + | 'onSelect' + | 'onPanelChange' >; export interface RangePickerBaseProps @@ -135,6 +142,7 @@ function InternalRangePicker( disabled, onChange, onCalendarChange, + onPanelChange, onFocus, onBlur, } = props as MergedRangePickerProps & { @@ -248,6 +256,69 @@ function InternalRangePicker( } }; + // ============================== Mode ============================== + + /** + * [Legacy] handle internal `onPanelChange` + */ + const [innerModes, setInnerModes] = React.useState((): [ + PanelMode, + PanelMode, + ] => { + if (mode) { + return mode; + } + if (picker) { + return [picker, picker]; + } + return showTime ? ['datetime', 'datetime'] : ['date', 'date']; + }); + const [onStartPanelChange, onEndPanelChange] = React.useMemo< + [OnPanelChange | undefined, OnPanelChange | undefined] + >(() => { + const onInternalPanelChange = ( + newValue: DateType, + newMode: PanelMode, + source: 'start' | 'end', + ) => { + const values: [EventValue, EventValue] = [ + ...(mergedValue || []), + ] as [EventValue, EventValue]; + const modes: [PanelMode, PanelMode] = [...innerModes] as [ + PanelMode, + PanelMode, + ]; + + if (source === 'start') { + values[0] = newValue; + modes[0] = newMode; + } else { + values[1] = newValue; + modes[1] = newMode; + } + setInnerModes(modes); + + if (onPanelChange) { + onPanelChange(values, modes); + } + }; + + return [ + (newVal: DateType, newMode: PanelMode) => { + onInternalPanelChange(newVal, newMode, 'start'); + }, + (newVal: DateType, newMode: PanelMode) => { + onInternalPanelChange(newVal, newMode, 'end'); + }, + ]; + }, [onPanelChange, mode, picker]); + + React.useEffect(() => { + if (mode) { + setInnerModes(mode); + } + }, [mode]); + // ============================= Render ============================= const pickerProps = { ...props, @@ -257,6 +328,7 @@ function InternalRangePicker( style: undefined, placeholder: undefined, disabledTime: undefined, + onPanelChange: undefined, }; // Time @@ -344,6 +416,7 @@ function InternalRangePicker( onSelect={onStartSelect} onFocus={onFocus} onBlur={onBlur} + onPanelChange={onStartPanelChange} /> {separator} @@ -362,6 +435,7 @@ function InternalRangePicker( onSelect={onEndSelect} onFocus={onFocus} onBlur={onBlur} + onPanelChange={onEndPanelChange} /> diff --git a/src/interface.ts b/src/interface.ts index 6f34f1b67..817e55a05 100644 --- a/src/interface.ts +++ b/src/interface.ts @@ -92,3 +92,8 @@ export interface DisabledTimes { } export type DisabledTime = (date: DateType | null) => DisabledTimes; + +export type OnPanelChange = ( + value: DateType, + mode: PanelMode, +) => void; diff --git a/tests/range.spec.tsx b/tests/range.spec.tsx index 7b0c80d93..1bce43993 100644 --- a/tests/range.spec.tsx +++ b/tests/range.spec.tsx @@ -456,4 +456,64 @@ describe('Range', () => { wrapper.openPicker(1); expect(wrapper.find('.rc-picker-month-panel')).toHaveLength(1); }); + + describe('onPanelChange is array args', () => { + it('mode', () => { + const onPanelChange = jest.fn(); + const wrapper = mount( + , + ); + + wrapper.openPicker(); + wrapper.selectCell('Feb'); + expect(isSame(onPanelChange.mock.calls[0][0][0], '1990-02-03')); + expect(onPanelChange.mock.calls[0][1]).toEqual(['date', 'year']); + + wrapper.closePicker(); + onPanelChange.mockReset(); + + wrapper.openPicker(1); + wrapper.selectCell(1993, 1); + expect(isSame(onPanelChange.mock.calls[0][0][1], '1993-09-03')); + expect(onPanelChange.mock.calls[0][1]).toEqual(['month', 'month']); + }); + + it('picker', () => { + const onPanelChange = jest.fn(); + const wrapper = mount( + , + ); + + // First go to year panel + wrapper.openPicker(); + wrapper.find('.rc-picker-month-panel-year-btn').simulate('click'); + expect(isSame(onPanelChange.mock.calls[0][0][0], '1990-09-03')); + expect(onPanelChange.mock.calls[0][1]).toEqual(['year', 'month']); + + // First nack to month panel + onPanelChange.mockReset(); + wrapper.selectCell(1993); + expect(onPanelChange).toHaveBeenCalled(); + expect(isSame(onPanelChange.mock.calls[0][0][0], '1993-09-03')); + expect(onPanelChange.mock.calls[0][1]).toEqual(['month', 'month']); + + // Last go to year panel + wrapper.closePicker(); + wrapper.openPicker(1); + wrapper + .find('Picker') + .last() + .find('.rc-picker-month-panel-year-btn') + .simulate('click'); + onPanelChange.mockReset(); + + // Last nack to month panel + wrapper.selectCell(1998, 1); + expect(isSame(onPanelChange.mock.calls[0][0][1], '1998-09-03')); + expect(onPanelChange.mock.calls[0][1]).toEqual(['month', 'month']); + }); + }); });