Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions examples/range.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ export default () => {
allowClear
ref={rangePickerRef}
defaultValue={[moment('1990-09-03'), moment('1989-11-28')]}
clearIcon={<span>X</span>}
suffixIcon={<span>O</span>}
/>
<RangePicker<Moment>
{...sharedProps}
Expand Down
51 changes: 43 additions & 8 deletions src/RangePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,17 @@ function InnerRangePicker<DateType>(props: RangePickerProps<DateType>) {
}
}

function triggerOpenAndFocus(index: 0 | 1) {
triggerOpen(true, index);
// Use setTimeout to make sure panel DOM exists
setTimeout(() => {
const inputRef = [startInputRef, endInputRef][index];
if (inputRef.current) {
inputRef.current.focus();
}
}, 0);
}

function triggerChange(newValue: RangeValue<DateType>, sourceIndex: 0 | 1) {
let values = newValue;
const startValue = getValue(values, 0);
Expand Down Expand Up @@ -454,15 +465,8 @@ function InnerRangePicker<DateType>(props: RangePickerProps<DateType>) {
!openRecordsRef.current[nextOpenIndex] &&
getValue(values, sourceIndex)
) {
triggerOpen(true, nextOpenIndex);

// Delay to focus to avoid input blur trigger expired selectedValues
setTimeout(() => {
const inputRef = [startInputRef, endInputRef][nextOpenIndex];
if (inputRef.current) {
inputRef.current.focus();
}
}, 0);
triggerOpenAndFocus(nextOpenIndex);
} else {
triggerOpen(false, sourceIndex);
}
Expand Down Expand Up @@ -565,6 +569,35 @@ function InnerRangePicker<DateType>(props: RangePickerProps<DateType>) {
value: endText,
});

// ========================== Click Picker ==========================
const onPickerClick = (e: MouseEvent) => {
// When click inside the picker & outside the picker's input elements
// the panel should still be opened
if (
!mergedOpen &&
!startInputRef.current.contains(e.target as Node) &&
!endInputRef.current.contains(e.target as Node)
) {
if (!mergedDisabled[0]) {
triggerOpenAndFocus(0);
} else if (!mergedDisabled[1]) {
triggerOpenAndFocus(1);
}
}
};

const onPickerMouseDown = (e: MouseEvent) => {
// shouldn't affect input elements if picker is active
if (
mergedOpen &&
(startFocused || endFocused) &&
!startInputRef.current.contains(e.target as Node) &&
!endInputRef.current.contains(e.target as Node)
) {
e.preventDefault();
}
};

// ============================= Sync ==============================
// Close should sync back with text value
const startStr =
Expand Down Expand Up @@ -960,6 +993,8 @@ function InnerRangePicker<DateType>(props: RangePickerProps<DateType>) {
[`${prefixCls}-rtl`]: direction === 'rtl',
})}
style={style}
onClick={onPickerClick}
onMouseDown={onPickerMouseDown}
{...getDataOrAriaProps(props)}
>
<div
Expand Down
46 changes: 46 additions & 0 deletions tests/range.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1299,4 +1299,50 @@ describe('Picker.Range', () => {
expect(wrapper.isOpen()).toBeFalsy();
});
});

describe('click at non-input elements', () => {
it('should focus on the first element by default', () => {
jest.useFakeTimers();
const wrapper = mount(<MomentRangePicker />);
wrapper.find('.rc-picker').simulate('click');
expect(wrapper.isOpen()).toBeTruthy();
jest.runAllTimers();
expect(document.activeElement).toStrictEqual(
wrapper
.find('input')
.first()
.getDOMNode(),
);
jest.useRealTimers();
});
it('should focus on the second element if first is disabled', () => {
jest.useFakeTimers();
const wrapper = mount(<MomentRangePicker disabled={[true, false]} />);
wrapper.find('.rc-picker').simulate('click');
expect(wrapper.isOpen()).toBeTruthy();
jest.runAllTimers();
expect(document.activeElement).toStrictEqual(
wrapper
.find('input')
.last()
.getDOMNode(),
);
jest.useRealTimers();
});
it("shouldn't let mousedown blur the input", () => {
jest.useFakeTimers();
const preventDefault = jest.fn();
const wrapper = mount(<MomentRangePicker />, {
attachTo: document.body,
});
wrapper.find('.rc-picker').simulate('click');
jest.runAllTimers();
wrapper.find('.rc-picker').simulate('mousedown', {
preventDefault,
});
expect(wrapper.isOpen()).toBeTruthy();
expect(preventDefault).toHaveBeenCalled();
jest.useRealTimers();
});
});
});