@samitouri / QOS-React-2 / commits / 312b462d54

[react-interactions] Improve consistency of Tap responder (#16837)

Makes sure that touch events with modifier keys behave the same way as other pointer types (i.e., does not call `onTapStart` if the gesture begins with a modifier key held down)

Nicolas Gallagher committed Sep 23, 2019 at 10:48 UTC 312b462d5444c231d5acf656efea6780ad9ba89d
2 files changed +33 -31
packages/react-interactions/events/src/dom/Tap.js
+16 -16
@@ -350,23 +350,26 @@ function isActivePointer(
350 }
351 }
352
353 -function isAuxiliary(buttons: number, nativeEvent: any): boolean {
353 +function isAuxiliary(buttons: number, event: ReactDOMResponderEvent): boolean {
354 + const nativeEvent: any = event.nativeEvent;
355 + const isPrimaryPointer =
356 + buttons === buttonsEnum.primary || event.pointerType === 'touch';
357 return (
358 // middle-click
359 buttons === buttonsEnum.auxiliary ||
360 // open-in-new-tab
358 - (buttons === buttonsEnum.primary && nativeEvent.metaKey) ||
361 + (isPrimaryPointer && nativeEvent.metaKey) ||
362 // open-in-new-window
360 - (buttons === buttonsEnum.primary && nativeEvent.shiftKey)
363 + (isPrimaryPointer && nativeEvent.shiftKey)
364 );
365 }
366
367 function shouldActivate(event: ReactDOMResponderEvent): boolean {
368 const nativeEvent: any = event.nativeEvent;
366 - const pointerType = event.pointerType;
367 - const buttons = nativeEvent.buttons;
368 - const isValidButton = buttons === buttonsEnum.primary;
369 - return pointerType === 'touch' || (isValidButton && !hasModifierKey(event));
369 + const isPrimaryPointer =
370 + nativeEvent.buttons === buttonsEnum.primary ||
371 + event.pointerType === 'touch';
372 + return isPrimaryPointer && !hasModifierKey(event);
373 }
374
375 /**
@@ -514,10 +517,7 @@ const responderImpl = {
517
518 if (!state.isActive) {
519 const activate = shouldActivate(event);
517 - const activateAuxiliary = isAuxiliary(
518 - nativeEvent.buttons,
519 - nativeEvent,
520 - );
520 + const activateAuxiliary = isAuxiliary(nativeEvent.buttons, event);
521
522 if (activate || activateAuxiliary) {
523 state.buttons = nativeEvent.buttons;
@@ -531,7 +531,9 @@ const responderImpl = {
531 }
532 }
533
534 - if (activate) {
534 + if (activateAuxiliary) {
535 + state.isAuxiliaryActive = true;
536 + } else if (activate) {
537 const gestureState = createGestureState(
538 context,
539 props,
@@ -544,8 +546,6 @@ const responderImpl = {
546 state.initialPosition.x = gestureState.x;
547 state.initialPosition.y = gestureState.y;
548 dispatchStart(context, props, state);
547 - } else if (activateAuxiliary) {
548 - state.isAuxiliaryActive = true;
549 }
550 }
551 break;
@@ -611,7 +611,7 @@ const responderImpl = {
611 if (state.isActive && isActivePointer(event, state)) {
612 state.gestureState = createGestureState(context, props, state, event);
613 state.isActive = false;
614 - if (isAuxiliary(state.buttons, nativeEvent)) {
614 + if (isAuxiliary(state.buttons, event)) {
615 dispatchCancel(context, props, state);
616 dispatchAuxiliaryTap(context, props, state);
617 // Remove the root events here as no 'click' event is dispatched
@@ -626,7 +626,7 @@ const responderImpl = {
626 }
627 } else if (
628 state.isAuxiliaryActive &&
629 - isAuxiliary(state.buttons, nativeEvent)
629 + isAuxiliary(state.buttons, event)
630 ) {
631 state.isAuxiliaryActive = false;
632 state.gestureState = createGestureState(context, props, state, event);
packages/react-interactions/events/src/dom/__tests__/Tap-test.internal.js
+17 -15
@@ -302,29 +302,31 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
302 expect(onTapStart).toHaveBeenCalledTimes(1);
303 });
304
305 - test('ignored buttons and modifiers', () => {
305 + testWithPointerType('ignored buttons and modifiers', pointerType => {
306 const target = createEventTarget(ref.current);
307 - const primary = buttonsType.primary;
308 - // right-click
309 - target.pointerdown({buttons: buttonsType.secondary});
310 - target.pointerup();
311 - // middle-click
312 - target.pointerdown({buttons: buttonsType.auxiliary});
313 - target.pointerup();
314 - // pen eraser
315 - target.pointerdown({buttons: buttonsType.eraser});
316 - target.pointerup();
307 + const {auxiliary, eraser, primary, secondary} = buttonsType;
308 + if (pointerType !== 'touch') {
309 + // right-click
310 + target.pointerdown({buttons: secondary, pointerType});
311 + target.pointerup();
312 + // middle-click
313 + target.pointerdown({buttons: auxiliary, pointerType});
314 + target.pointerup();
315 + // pen eraser
316 + target.pointerdown({buttons: eraser, pointerType});
317 + target.pointerup();
318 + }
319 // alt-click
318 - target.pointerdown({buttons: primary, altKey: true});
320 + target.pointerdown({buttons: primary, altKey: true, pointerType});
321 target.pointerup();
322 // ctrl-click
321 - target.pointerdown({buttons: primary, ctrlKey: true});
323 + target.pointerdown({buttons: primary, ctrlKey: true, pointerType});
324 target.pointerup();
325 // meta-click
324 - target.pointerdown({buttons: primary, metaKey: true});
326 + target.pointerdown({buttons: primary, metaKey: true, pointerType});
327 target.pointerup();
328 // shift-click
327 - target.pointerdown({buttons: primary, shiftKey: true});
329 + target.pointerdown({buttons: primary, shiftKey: true, pointerType});
330 target.pointerup();
331
332 expect(onTapStart).toHaveBeenCalledTimes(0);