Skip to content
Open
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
3 changes: 3 additions & 0 deletions docs/examples/range.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ export default () => {
defaultValue={[moment('1990-09-03'), moment('1989-11-28')]}
clearIcon={<span>X</span>}
suffixIcon={<span>O</span>}
onBlur={() => {
console.log('trigger blur')
}}
/>
<RangePicker<Moment>
{...sharedProps}
Expand Down
6 changes: 6 additions & 0 deletions src/RangePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -648,10 +648,13 @@ function InnerRangePicker<DateType>(props: RangePickerProps<DateType>) {
},
});

const currentFocusedKey = useRef<string>('');
const [startInputProps, { focused: startFocused, typing: startTyping }] = usePickerInput({
...getSharedInputHookProps(0, resetStartText),
open: startOpen,
value: startText,
currentFocusedKey,
key: "start",
onKeyDown: (e, preventDefault) => {
onKeyDown?.(e, preventDefault);
},
Expand All @@ -661,11 +664,14 @@ function InnerRangePicker<DateType>(props: RangePickerProps<DateType>) {
...getSharedInputHookProps(1, resetEndText),
open: endOpen,
value: endText,
currentFocusedKey,
key: "end",
onKeyDown: (e, preventDefault) => {
onKeyDown?.(e, preventDefault);
},
});


// ========================== Click Picker ==========================
const onPickerClick = (e: React.MouseEvent<HTMLDivElement>) => {
// When click inside the picker & outside the picker's input elements
Expand Down
23 changes: 18 additions & 5 deletions src/hooks/usePickerInput.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ export default function usePickerInput({
onCancel,
onFocus,
onBlur,
currentFocusedKey,
key = 'start'
}: {
open: boolean;
value: string;
Expand All @@ -27,9 +29,12 @@ export default function usePickerInput({
onCancel: () => void;
onFocus?: React.FocusEventHandler<HTMLInputElement>;
onBlur?: React.FocusEventHandler<HTMLInputElement>;
currentFocusedKey?: React.MutableRefObject<string>
key: string;
}): [React.DOMAttributes<HTMLInputElement>, { focused: boolean; typing: boolean }] {
const [typing, setTyping] = useState(false);
const [focused, setFocused] = useState(false);
const delayBlurTimer = useRef<NodeJS.Timeout>();

/**
* We will prevent blur to handle open event when user click outside,
Expand Down Expand Up @@ -98,7 +103,8 @@ export default function usePickerInput({
onFocus: (e) => {
setTyping(true);
setFocused(true);

currentFocusedKey.current = key;
clearTimeout(delayBlurTimer.current);
if (onFocus) {
onFocus(e);
}
Expand Down Expand Up @@ -129,10 +135,15 @@ export default function usePickerInput({
}
}
setFocused(false);

if (onBlur) {
onBlur(e);
}
currentFocusedKey.current = '';
// Delay to prevent 'range' focus transitions from firing resulting in incorrect out-of-focus events
delayBlurTimer.current = setTimeout(() => {
// Prevent the 'blur' event from firing when there is currently a focused input
if(currentFocusedKey.current) return;
if (onBlur) {
onBlur(e);
}
}, 100);
},
};

Expand Down Expand Up @@ -167,5 +178,7 @@ export default function usePickerInput({
}),
);

useEffect(() => () => clearTimeout(delayBlurTimer.current), []);

return [inputProps, { focused, typing }];
}
26 changes: 26 additions & 0 deletions tests/range.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1128,6 +1128,32 @@ describe('Picker.Range', () => {
expect(wrapper.isOpen()).toBeFalsy();
});

it('blur in range', (done) => {
const ref = React.createRef<MomentRangePicker>();
const blurFn = jest.fn();
const wrapper = mount(
<MomentRangePicker ref={ref} defaultValue={[getMoment('1989-01-01'), getMoment('1990-01-01')]} onBlur={blurFn} />,
);

wrapper.openPicker(0);
wrapper.inputValue('1990-11-28');
wrapper.closePicker(0);
expect(wrapper.isOpen()).toBeTruthy();
expect(blurFn).toBeCalledTimes(0);

wrapper.inputValue('1990-12-23');
wrapper.closePicker(1);
expect(wrapper.isOpen()).toBeFalsy();
expect(blurFn).toBeCalledTimes(0);

ref.current!.rangePickerRef.current!.blur();
setTimeout(() => {
expect(blurFn).toBeCalledTimes(1);
done();
}, 120);

});

it('new start is after end', () => {
const wrapper = mount(
<MomentRangePicker defaultValue={[getMoment('1989-01-10'), getMoment('1989-01-15')]} />,
Expand Down