Skip to content

Commit

Permalink
fix: dateTime mode switch should trigger onCalendarChange (#669)
Browse files Browse the repository at this point in the history
* fix: disabledDate not work when using both showTime and changeOnBlur

* chore: add test case

* feat: dateTime mode switch trigger onCalendarChange

* chore: separate the onCalendarChange

* chore: change test case

* fix: resolve test case error

* chore: trigger setSelectedValue inside the change function

* chore: restore methods and add param

* chore: split the process content

---------

Co-authored-by: dujiaqi <[email protected]>
  • Loading branch information
Yuiai01 and dujiaqi authored Sep 13, 2023
1 parent c23b2b6 commit e1e0d09
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 71 deletions.
88 changes: 52 additions & 36 deletions src/RangePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,11 @@ function InnerRangePicker<DateType>(props: RangePickerProps<DateType>) {
// ============================= Misc ==============================
const formatList = toArray(getDefaultFormat<DateType>(format, picker, showTime, use12Hours));

const formatDateValue = (values: RangeValue<DateType>, index: 0 | 1) =>
values && values[index]
? formatValue(values[index], { generateConfig, locale, format: formatList[0] })
: '';

// Operation ref
const operationRef: React.MutableRefObject<ContextOperationRefProps | null> =
useRef<ContextOperationRefProps>(null);
Expand Down Expand Up @@ -398,7 +403,11 @@ function InnerRangePicker<DateType>(props: RangePickerProps<DateType>) {
}, 0);
}

function triggerChange(newValue: RangeValue<DateType>, sourceIndex: 0 | 1) {
function triggerChange(
newValue: RangeValue<DateType>,
sourceIndex: 0 | 1,
triggerCalendarChangeOnly?: boolean,
) {
let values = newValue;
let startValue = getValue(values, 0);
let endValue = getValue(values, 1);
Expand Down Expand Up @@ -432,37 +441,30 @@ function InnerRangePicker<DateType>(props: RangePickerProps<DateType>) {

setSelectedValue(values);

const startStr =
values && values[0]
? formatValue(values[0], { generateConfig, locale, format: formatList[0] })
: '';
const endStr =
values && values[1]
? formatValue(values[1], { generateConfig, locale, format: formatList[0] })
: '';
const startStr = formatDateValue(values, 0);
const endStr = formatDateValue(values, 1);

if (onCalendarChange) {
const info: RangeInfo = { range: sourceIndex === 0 ? 'start' : 'end' };

onCalendarChange(values, [startStr, endStr], info);
}

// >>>>> Trigger `onChange` event
const canStartValueTrigger = canValueTrigger(startValue, 0, mergedDisabled, allowEmpty);
const canEndValueTrigger = canValueTrigger(endValue, 1, mergedDisabled, allowEmpty);

const canTrigger = values === null || (canStartValueTrigger && canEndValueTrigger);

if (canTrigger) {
// Trigger onChange only when value is validate
setInnerValue(values);

if (
onChange &&
(!isEqual(generateConfig, getValue(mergedValue, 0), startValue) ||
!isEqual(generateConfig, getValue(mergedValue, 1), endValue))
) {
onChange(values, [startStr, endStr]);
if (!triggerCalendarChangeOnly) {
// >>>>> Trigger `onChange` event
const canStartValueTrigger = canValueTrigger(startValue, 0, mergedDisabled, allowEmpty);
const canEndValueTrigger = canValueTrigger(endValue, 1, mergedDisabled, allowEmpty);
const canTrigger = values === null || (canStartValueTrigger && canEndValueTrigger);
if (canTrigger) {
// Trigger onChange only when value is validate
setInnerValue(values);
if (
onChange &&
(!isEqual(generateConfig, getValue(mergedValue, 0), startValue) ||
!isEqual(generateConfig, getValue(mergedValue, 1), endValue))
) {
onChange(values, [startStr, endStr]);
}
}
}
}
Expand Down Expand Up @@ -570,29 +572,44 @@ function InnerRangePicker<DateType>(props: RangePickerProps<DateType>) {
}, [mergedOpen]);

const onInternalBlur: React.FocusEventHandler<HTMLInputElement> = (e) => {
if (changeOnBlur && delayOpen) {
const selectedIndexValue = getValue(selectedValue, mergedActivePickerIndex);
if (selectedIndexValue) {
triggerChange(selectedValue, mergedActivePickerIndex);
if (delayOpen) {
if (changeOnBlur) {
const selectedIndexValue = getValue(selectedValue, mergedActivePickerIndex);

if (selectedIndexValue) {
triggerChange(selectedValue, mergedActivePickerIndex);
}
} else if (needConfirmButton) {
// when in dateTime mode, switching between two date input fields will trigger onCalendarChange.
// when onBlur is triggered, the input field has already switched,
// so it's necessary to obtain the value of the previous input field here.
const needTriggerIndex = mergedActivePickerIndex ? 0 : 1;
const selectedIndexValue = getValue(selectedValue, needTriggerIndex);

if (selectedIndexValue) {
triggerChange(selectedValue, needTriggerIndex, true);
}
}
}

return onBlur?.(e);
};

const getSharedInputHookProps = (index: 0 | 1, resetText: () => void) => ({
blurToCancel: !changeOnBlur && needConfirmButton,
forwardKeyDown,
onBlur: onInternalBlur,
isClickOutside: (target: EventTarget | null) =>
!elementsContains(
isClickOutside: (target: EventTarget | null) => {
const elementsRefs = [startInputDivRef.current, endInputDivRef.current, containerRef.current];
return !elementsContains(
[
// Filter the ref of the currently selected input to trigger the onBlur event of another input.
...(needConfirmButton ? [elementsRefs[mergedActivePickerIndex]] : elementsRefs),
panelDivRef.current,
startInputDivRef.current,
endInputDivRef.current,
containerRef.current,
],
target as HTMLElement,
),
);
},
onFocus: (e: React.FocusEvent<HTMLInputElement>) => {
if (onFocus) {
onFocus(e);
Expand Down Expand Up @@ -637,7 +654,6 @@ function InnerRangePicker<DateType>(props: RangePickerProps<DateType>) {
onKeyDown: (e, preventDefault) => {
onKeyDown?.(e, preventDefault);
},
changeOnBlur,
};

const [startInputProps, { focused: startFocused, typing: startTyping }] = usePickerInput({
Expand Down
4 changes: 1 addition & 3 deletions src/hooks/usePickerInput.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ export default function usePickerInput({
onCancel,
onFocus,
onBlur,
changeOnBlur,
}: {
open: boolean;
value: string;
Expand All @@ -29,7 +28,6 @@ export default function usePickerInput({
onCancel: () => void;
onFocus?: React.FocusEventHandler<HTMLInputElement>;
onBlur?: React.FocusEventHandler<HTMLInputElement>;
changeOnBlur?: boolean;
}): [React.DOMAttributes<HTMLInputElement>, { focused: boolean; typing: boolean }] {
const [typing, setTyping] = useState(false);
const [focused, setFocused] = useState(false);
Expand Down Expand Up @@ -160,7 +158,7 @@ export default function usePickerInput({
raf(() => {
preventBlurRef.current = false;
});
} else if (!changeOnBlur && (!focused || clickedOutside)) {
} else if (!blurToCancel && (!focused || clickedOutside)) {
triggerOpen(false);
}
}
Expand Down
81 changes: 49 additions & 32 deletions tests/range.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ import type { Moment } from 'moment';
import moment from 'moment';
import KeyCode from 'rc-util/lib/KeyCode';
import { spyElementPrototypes } from 'rc-util/lib/test/domHook';
import { resetWarned } from 'rc-util/lib/warning';
import React from 'react';
import type { PickerMode } from '../src/interface';
import zhCN from '../src/locale/zh_CN';
import type { RangePickerProps } from '../src/RangePicker';
import {
clearValue,
clickButton,
Expand All @@ -19,8 +21,6 @@ import {
openPicker,
selectCell,
} from './util/commonUtil';
import type { RangePickerProps } from '../src/RangePicker';
import { resetWarned } from 'rc-util/lib/warning';

describe('Picker.Range', () => {
let errorSpy;
Expand Down Expand Up @@ -286,7 +286,9 @@ describe('Picker.Range', () => {
expect(baseElement.querySelectorAll('.rc-picker-input')).toHaveLength(2);
fireEvent.click(baseElement.querySelectorAll('.rc-picker-input')[1]);
expect(baseElement.querySelector('.rc-picker-dropdown-hidden')).toBeFalsy();
fireEvent.click(baseElement.querySelector('.rc-picker-cell-range-start .rc-picker-cell-inner'));
fireEvent.click(
baseElement.querySelector('.rc-picker-cell-range-start .rc-picker-cell-inner'),
);
fireEvent.click(baseElement.querySelector('.rc-picker-ok button'));
expect(baseElement.querySelector('.rc-picker-dropdown-hidden')).toBeTruthy();
});
Expand Down Expand Up @@ -361,7 +363,6 @@ describe('Picker.Range', () => {
});

function testRangePickerPresetRange(propsType: 'ranges' | 'presets') {

const genProps = (ranges: Record<string, any>) => {
const props: Partial<RangePickerProps<Moment>> = {};
if (propsType === 'ranges') {
Expand All @@ -371,21 +372,19 @@ describe('Picker.Range', () => {
props.presets = [];
Object.entries(ranges).forEach(([label, value]) => {
props.presets.push({ label, value });
})
});
}
return props as RangePickerProps<Moment>;
}
};

it(`${propsType} work`, () => {
const onChange = jest.fn();
const { container } = render(
<MomentRangePicker
{...genProps(
{
test: [getMoment('1989-11-28'), getMoment('1990-09-03')],
func: () => [getMoment('2000-01-01'), getMoment('2010-11-11')],
}
)}
{...genProps({
test: [getMoment('1989-11-28'), getMoment('1990-09-03')],
func: () => [getMoment('2000-01-01'), getMoment('2010-11-11')],
})}
onChange={onChange}
/>,
);
Expand Down Expand Up @@ -420,11 +419,9 @@ describe('Picker.Range', () => {
it(`${propsType} hover className`, () => {
const { container } = render(
<MomentRangePicker
{...genProps(
{
now: [getMoment('1990-09-11'), getMoment('1990-09-13')],
}
)}
{...genProps({
now: [getMoment('1990-09-11'), getMoment('1990-09-13')],
})}
/>,
);

Expand All @@ -439,7 +436,6 @@ describe('Picker.Range', () => {
expect(findCell(12)).not.toHaveClass('rc-picker-cell-in-range');
expect(findCell(13)).not.toHaveClass('rc-picker-cell-range-end');
});

}

describe('ranges or presets', () => {
Expand Down Expand Up @@ -755,7 +751,7 @@ describe('Picker.Range', () => {

expect(container).toMatchSnapshot();
expect(errorSpy).toHaveBeenCalledWith(
'Warning: `clearIcon` will be removed in future. Please use `allowClear` instead.'
'Warning: `clearIcon` will be removed in future. Please use `allowClear` instead.',
);
});

Expand Down Expand Up @@ -1111,19 +1107,19 @@ describe('Picker.Range', () => {
targetCell: string;
match: string[];
}[] = [
{
picker: 'week',
defaultValue: ['2020-06-13'],
targetCell: '9',
match: ['2020-24th'],
},
{
picker: 'quarter',
defaultValue: ['2020-03-30', '2020-05-20'],
targetCell: 'Q1',
match: ['2020-Q1'],
},
];
{
picker: 'week',
defaultValue: ['2020-06-13'],
targetCell: '9',
match: ['2020-24th'],
},
{
picker: 'quarter',
defaultValue: ['2020-03-30', '2020-05-20'],
targetCell: 'Q1',
match: ['2020-Q1'],
},
];

list.forEach(({ picker, defaultValue, match, targetCell }) => {
it(picker, () => {
Expand Down Expand Up @@ -1927,4 +1923,25 @@ describe('Picker.Range', () => {
fireEvent.click(document.querySelector('.rc-picker-cell'));
expect(document.querySelectorAll('.rc-picker-input')[1]).toHaveClass('rc-picker-input-active');
});

it('dateTime mode switch should trigger onCalendarChange', () => {
const onCalendarChange = jest.fn();
const { container } = render(
<MomentRangePicker
showTime
onCalendarChange={onCalendarChange}
/>,
);

openPicker(container, 0);

selectCell(8, 0);

openPicker(container, 1);

// onBlur is triggered when the switch is complete
closePicker(container, 0);

expect(onCalendarChange).toHaveBeenCalled();
});
});

1 comment on commit e1e0d09

@vercel
Copy link

@vercel vercel bot commented on e1e0d09 Sep 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.