[react-interactions] Ensure blur to window disengages press (#18125)

This commit is contained in:
Dominic Gannaway
2020-02-25 14:14:19 +00:00
committed by GitHub
parent bf13d3e3c6
commit a29a273c17
2 changed files with 40 additions and 0 deletions
@@ -126,6 +126,7 @@ const rootEventTypes = hasPointerEvents
'click',
'keyup',
'scroll',
'blur',
]
: [
'click',
@@ -138,6 +139,7 @@ const rootEventTypes = hasPointerEvents
'dragstart',
'mouseup_active',
'touchend',
'blur',
];
function isFunction(obj): boolean {
@@ -881,6 +883,21 @@ const pressResponderImpl = {
case 'touchcancel':
case 'dragstart': {
dispatchCancel(event, context, props, state);
break;
}
case 'blur': {
// If we encounter a blur event that moves focus to
// the window, then the relatedTarget will be null.
// In this case, we should cancel the active press.
// Alternatively, if the blur target matches the
// current pressed target, we should also cancel
// the active press.
if (
isPressed &&
(nativeEvent.relatedTarget === null || target === state.pressTarget)
) {
dispatchCancel(event, context, props, state);
}
}
}
},
@@ -1167,4 +1167,27 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => {
expect(onPressStart).toBeCalled();
expect(onPressEnd).toBeCalled();
});
it('focus moving to the window should stop the press', () => {
const onPress = jest.fn(e => e.preventDefault());
const onPressStart = jest.fn(e => e.preventDefault());
const onPressEnd = jest.fn(e => e.preventDefault());
const buttonRef = React.createRef();
const Component = () => {
const listener = usePress({onPress, onPressStart, onPressEnd});
return <button ref={buttonRef} DEPRECATED_flareListeners={listener} />;
};
ReactDOM.render(<Component />, container);
const target = createEventTarget(buttonRef.current);
target.pointerdown();
const secondTarget = createEventTarget(document);
// relatedTarget is null when moving focus to window
expect(onPressStart).toBeCalled();
secondTarget.blur({relatedTarget: null});
expect(onPressEnd).toBeCalled();
target.pointerup();
expect(onPress).not.toBeCalled();
});
});