React events: ignore device buttons that aren't for primary interactions (#15402)
The Pointer Events spec mentions that the value of `button` in a nativeEvent can be anything between 0 and 5 for "down" events. We only care about those with a value of 0.
Nicolas Gallagher committed
Apr 12, 2019 at 13:36 UTC
8cf963c6c3e4dc41d0c006513aff19d725348d82
2 files changed
+33
-26
packages/react-events/src/Press.js
+26
-26
@@ -426,7 +426,8 @@ const PressResponder = {
426
props: PressProps,
427
state: PressState,
428
): void {
429
- const {target, type, nativeEvent} = event;
429
+ const {target, type} = event;
430
+ const nativeEvent: any = event.nativeEvent;
431
432
switch (type) {
433
/**
@@ -442,21 +443,23 @@ const PressResponder = {
443
const pointerType = getPointerType(nativeEvent);
444
state.pointerType = pointerType;
445
445
- if (pointerType === 'mouse' || type === 'mousedown') {
446
- if (
447
- // Ignore right- and middle-clicks
448
- nativeEvent.button === 1 ||
449
- nativeEvent.button === 2 ||
450
- // Ignore pressing on hit slop area with mouse
451
- context.isPositionWithinTouchHitTarget(
452
- target.ownerDocument,
453
- (nativeEvent: any).x,
454
- (nativeEvent: any).y,
455
- )
456
- ) {
457
- return;
458
- }
446
+ // Ignore any device buttons except left-mouse and touch/pen contact
447
+ if (nativeEvent.button > 0) {
448
+ return;
449
+ }
450
+
451
+ // Ignore pressing on hit slop area with mouse
452
+ if (
453
+ (pointerType === 'mouse' || type === 'mousedown') &&
454
+ context.isPositionWithinTouchHitTarget(
455
+ target.ownerDocument,
456
+ nativeEvent.x,
457
+ nativeEvent.y,
458
+ )
459
+ ) {
460
+ return;
461
}
462
+
463
state.pressTarget = target;
464
state.isPressWithinResponderRegion = true;
465
dispatchPressStartEvents(context, props, state);
@@ -574,7 +577,7 @@ const PressResponder = {
577
578
if (type !== 'touchcancel' && props.onPress) {
579
// Find if the X/Y of the end touch is still that of the original target
577
- const changedTouch = (nativeEvent: any).changedTouches[0];
580
+ const changedTouch = nativeEvent.changedTouches[0];
581
const doc = (target: any).ownerDocument;
582
const fromTarget = doc.elementFromPoint(
583
changedTouch.screenX,
@@ -607,14 +610,11 @@ const PressResponder = {
610
*/
611
case 'keydown':
612
case 'keypress': {
610
- if (
611
- !context.hasOwnership() &&
612
- isValidKeyPress((nativeEvent: any).key)
613
- ) {
613
+ if (!context.hasOwnership() && isValidKeyPress(nativeEvent.key)) {
614
if (state.isPressed) {
615
// Prevent spacebar press from scrolling the window
616
- if ((nativeEvent: any).key === ' ') {
617
- (nativeEvent: any).preventDefault();
616
+ if (nativeEvent.key === ' ') {
617
+ nativeEvent.preventDefault();
618
}
619
} else {
620
const pointerType = getPointerType(nativeEvent);
@@ -627,7 +627,7 @@ const PressResponder = {
627
break;
628
}
629
case 'keyup': {
630
- if (state.isPressed && isValidKeyPress((nativeEvent: any).key)) {
630
+ if (state.isPressed && isValidKeyPress(nativeEvent.key)) {
631
const wasLongPressed = state.isLongPressed;
632
dispatchPressEndEvents(context, props, state);
633
if (state.pressTarget !== null && props.onPress) {
@@ -659,11 +659,11 @@ const PressResponder = {
659
660
case 'click': {
661
if (isAnchorTagElement(target)) {
662
- const {ctrlKey, metaKey, shiftKey} = ((nativeEvent: any): MouseEvent);
662
+ const {ctrlKey, metaKey, shiftKey} = (nativeEvent: MouseEvent);
663
// Check "open in new window/tab" and "open context menu" key modifiers
664
const preventDefault = props.preventDefault;
665
if (preventDefault !== false && !shiftKey && !metaKey && !ctrlKey) {
666
- (nativeEvent: any).preventDefault();
666
+ nativeEvent.preventDefault();
667
}
668
}
669
break;
@@ -672,7 +672,7 @@ const PressResponder = {
672
case 'contextmenu': {
673
if (state.isPressed) {
674
if (props.preventDefault !== false) {
675
- (nativeEvent: any).preventDefault();
675
+ nativeEvent.preventDefault();
676
} else {
677
state.shouldSkipMouseAfterTouch = false;
678
dispatchPressEndEvents(context, props, state);
packages/react-events/src/__tests__/Press-test.internal.js
+7
@@ -85,6 +85,13 @@ describe('Event responder: Press', () => {
85
expect(onPressStart).toHaveBeenCalledTimes(1);
86
});
87
88
+ it('ignores any events not caused by left-click or touch/pen contact', () => {
89
+ ref.current.dispatchEvent(createPointerEvent('pointerdown', {button: 1}));
90
+ ref.current.dispatchEvent(createPointerEvent('pointerdown', {button: 5}));
91
+ ref.current.dispatchEvent(createPointerEvent('mousedown', {button: 2}));
92
+ expect(onPressStart).toHaveBeenCalledTimes(0);
93
+ });
94
+
95
it('is called once after "keydown" events for Enter', () => {
96
ref.current.dispatchEvent(createKeyboardEvent('keydown', {key: 'Enter'}));
97
ref.current.dispatchEvent(createKeyboardEvent('keydown', {key: 'Enter'}));