Skip to content

Commit 5c09303

Browse files
kiner-tangtangwenhui
andauthored
fix: should not trigger blur event while picker's input focused (#510)
Co-authored-by: tangwenhui <[email protected]>
1 parent 94963a0 commit 5c09303

File tree

4 files changed

+55
-3
lines changed

4 files changed

+55
-3
lines changed

docs/examples/range.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@ export default () => {
6262
defaultValue={[moment('1990-09-03'), moment('1989-11-28')]}
6363
clearIcon={<span>X</span>}
6464
suffixIcon={<span>O</span>}
65+
onBlur={() => {
66+
console.log('trigger blur')
67+
}}
6568
/>
6669
<RangePicker<Moment>
6770
{...sharedProps}

src/RangePicker.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -635,10 +635,13 @@ function InnerRangePicker<DateType>(props: RangePickerProps<DateType>) {
635635
},
636636
});
637637

638+
const currentFocusedKey = useRef<string>('');
638639
const [startInputProps, { focused: startFocused, typing: startTyping }] = usePickerInput({
639640
...getSharedInputHookProps(0, resetStartText),
640641
open: startOpen,
641642
value: startText,
643+
currentFocusedKey,
644+
key: 'start',
642645
onKeyDown: (e, preventDefault) => {
643646
onKeyDown?.(e, preventDefault);
644647
},
@@ -648,6 +651,8 @@ function InnerRangePicker<DateType>(props: RangePickerProps<DateType>) {
648651
...getSharedInputHookProps(1, resetEndText),
649652
open: endOpen,
650653
value: endText,
654+
currentFocusedKey,
655+
key: 'end',
651656
onKeyDown: (e, preventDefault) => {
652657
onKeyDown?.(e, preventDefault);
653658
},

src/hooks/usePickerInput.ts

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ export default function usePickerInput({
1515
onCancel,
1616
onFocus,
1717
onBlur,
18+
currentFocusedKey,
19+
key = 'start',
1820
}: {
1921
open: boolean;
2022
value: string;
@@ -27,9 +29,12 @@ export default function usePickerInput({
2729
onCancel: () => void;
2830
onFocus?: React.FocusEventHandler<HTMLInputElement>;
2931
onBlur?: React.FocusEventHandler<HTMLInputElement>;
32+
currentFocusedKey?: React.MutableRefObject<string>;
33+
key: string;
3034
}): [React.DOMAttributes<HTMLInputElement>, { focused: boolean; typing: boolean }] {
3135
const [typing, setTyping] = useState(false);
3236
const [focused, setFocused] = useState(false);
37+
const delayBlurTimer = useRef<NodeJS.Timeout>();
3338

3439
/**
3540
* We will prevent blur to handle open event when user click outside,
@@ -99,6 +104,8 @@ export default function usePickerInput({
99104
setTyping(true);
100105
setFocused(true);
101106

107+
currentFocusedKey.current = key;
108+
clearTimeout(delayBlurTimer.current);
102109
if (onFocus) {
103110
onFocus(e);
104111
}
@@ -130,9 +137,15 @@ export default function usePickerInput({
130137
}
131138
setFocused(false);
132139

133-
if (onBlur) {
134-
onBlur(e);
135-
}
140+
currentFocusedKey.current = '';
141+
// Delay to prevent 'range' focus transitions from firing resulting in incorrect out-of-focus events
142+
delayBlurTimer.current = setTimeout(() => {
143+
// Prevent the 'blur' event from firing when there is currently a focused input
144+
if (currentFocusedKey.current) return;
145+
if (onBlur) {
146+
onBlur(e);
147+
}
148+
}, 100);
136149
},
137150
};
138151

@@ -167,5 +180,7 @@ export default function usePickerInput({
167180
}),
168181
);
169182

183+
useEffect(() => () => clearTimeout(delayBlurTimer.current), []);
184+
170185
return [inputProps, { focused, typing }];
171186
}

tests/range.spec.tsx

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1127,6 +1127,35 @@ describe('Picker.Range', () => {
11271127
expect(wrapper.isOpen()).toBeFalsy();
11281128
});
11291129

1130+
it('blur in range', (done) => {
1131+
const ref = React.createRef<MomentRangePicker>();
1132+
const blurFn = jest.fn();
1133+
const wrapper = mount(
1134+
<MomentRangePicker
1135+
ref={ref}
1136+
defaultValue={[getMoment('1989-01-01'), getMoment('1990-01-01')]}
1137+
onBlur={blurFn}
1138+
/>,
1139+
);
1140+
1141+
wrapper.openPicker(0);
1142+
wrapper.inputValue('1990-11-28');
1143+
wrapper.closePicker(0);
1144+
expect(wrapper.isOpen()).toBeTruthy();
1145+
expect(blurFn).not.toHaveBeenCalled();
1146+
1147+
wrapper.inputValue('1990-12-23');
1148+
wrapper.closePicker(1);
1149+
expect(wrapper.isOpen()).toBeFalsy();
1150+
expect(blurFn).not.toHaveBeenCalled();
1151+
1152+
ref.current!.rangePickerRef.current!.blur();
1153+
setTimeout(() => {
1154+
expect(blurFn).toHaveBeenCalled();
1155+
done();
1156+
}, 120);
1157+
});
1158+
11301159
it('new start is after end', () => {
11311160
const wrapper = mount(
11321161
<MomentRangePicker defaultValue={[getMoment('1989-01-10'), getMoment('1989-01-15')]} />,

0 commit comments

Comments
 (0)