diff --git a/docs/examples/range.tsx b/docs/examples/range.tsx
index 7c00e8d34..286c0956b 100644
--- a/docs/examples/range.tsx
+++ b/docs/examples/range.tsx
@@ -62,6 +62,9 @@ export default () => {
defaultValue={[moment('1990-09-03'), moment('1989-11-28')]}
clearIcon={X}
suffixIcon={O}
+ onBlur={() => {
+ console.log('trigger blur')
+ }}
/>
{...sharedProps}
diff --git a/src/RangePicker.tsx b/src/RangePicker.tsx
index 9962d935b..732b51f89 100644
--- a/src/RangePicker.tsx
+++ b/src/RangePicker.tsx
@@ -648,10 +648,13 @@ function InnerRangePicker(props: RangePickerProps) {
},
});
+ const currentFocusedKey = useRef('');
const [startInputProps, { focused: startFocused, typing: startTyping }] = usePickerInput({
...getSharedInputHookProps(0, resetStartText),
open: startOpen,
value: startText,
+ currentFocusedKey,
+ key: "start",
onKeyDown: (e, preventDefault) => {
onKeyDown?.(e, preventDefault);
},
@@ -661,11 +664,14 @@ function InnerRangePicker(props: RangePickerProps) {
...getSharedInputHookProps(1, resetEndText),
open: endOpen,
value: endText,
+ currentFocusedKey,
+ key: "end",
onKeyDown: (e, preventDefault) => {
onKeyDown?.(e, preventDefault);
},
});
+
// ========================== Click Picker ==========================
const onPickerClick = (e: React.MouseEvent) => {
// When click inside the picker & outside the picker's input elements
diff --git a/src/hooks/usePickerInput.ts b/src/hooks/usePickerInput.ts
index 0d54e3fcf..4cb6f4ed6 100644
--- a/src/hooks/usePickerInput.ts
+++ b/src/hooks/usePickerInput.ts
@@ -15,6 +15,8 @@ export default function usePickerInput({
onCancel,
onFocus,
onBlur,
+ currentFocusedKey,
+ key = 'start'
}: {
open: boolean;
value: string;
@@ -27,9 +29,12 @@ export default function usePickerInput({
onCancel: () => void;
onFocus?: React.FocusEventHandler;
onBlur?: React.FocusEventHandler;
+ currentFocusedKey?: React.MutableRefObject
+ key: string;
}): [React.DOMAttributes, { focused: boolean; typing: boolean }] {
const [typing, setTyping] = useState(false);
const [focused, setFocused] = useState(false);
+ const delayBlurTimer = useRef();
/**
* We will prevent blur to handle open event when user click outside,
@@ -98,7 +103,8 @@ export default function usePickerInput({
onFocus: (e) => {
setTyping(true);
setFocused(true);
-
+ currentFocusedKey.current = key;
+ clearTimeout(delayBlurTimer.current);
if (onFocus) {
onFocus(e);
}
@@ -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);
},
};
@@ -167,5 +178,7 @@ export default function usePickerInput({
}),
);
+ useEffect(() => () => clearTimeout(delayBlurTimer.current), []);
+
return [inputProps, { focused, typing }];
}
diff --git a/tests/range.spec.tsx b/tests/range.spec.tsx
index 6f5a2d806..1ca444e92 100644
--- a/tests/range.spec.tsx
+++ b/tests/range.spec.tsx
@@ -1128,6 +1128,32 @@ describe('Picker.Range', () => {
expect(wrapper.isOpen()).toBeFalsy();
});
+ it('blur in range', (done) => {
+ const ref = React.createRef();
+ const blurFn = jest.fn();
+ const wrapper = mount(
+ ,
+ );
+
+ 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(
,