From d1f58464b50e2379818c2c13abf07a59fc36e5c8 Mon Sep 17 00:00:00 2001 From: Nicolas Gallagher Date: Mon, 1 Apr 2019 09:49:36 -0700 Subject: [PATCH 1/6] Add PressProps type to event module --- packages/react-events/src/Press.js | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/packages/react-events/src/Press.js b/packages/react-events/src/Press.js index 03203ded48c9a..ec5ed91f2483e 100644 --- a/packages/react-events/src/Press.js +++ b/packages/react-events/src/Press.js @@ -26,6 +26,23 @@ if (typeof window !== 'undefined' && window.PointerEvent === undefined) { rootEventTypes.push({name: 'mouseup', passive: false}); } +type PressProps = { + disabled: boolean, + delayLongPress: number, + delayPress: number, + delayPressEnd: number, + delayPressStart: number, + hitSlop: Object, + onLongPress: (e: Object) => void, + onLongPressChange: (boolean) => void, + onLongPressShouldCancelPress: () => boolean, + onPress: (e: Object) => void, + onPressChange: (boolean) => void, + onPressEnd: (e: Object) => void, + onPressStart: (e: Object) => void, + pressRententionOffset: Object, +}; + type PressState = { defaultPrevented: boolean, isAnchorTouched: boolean, @@ -47,7 +64,7 @@ function dispatchPressEvent( function dispatchPressStartEvents( context: EventResponderContext, - props: Object, + props: PressProps, state: PressState, ): void { function dispatchPressChangeEvent(bool) { @@ -105,7 +122,7 @@ function dispatchPressStartEvents( function dispatchPressEndEvents( context: EventResponderContext, - props: Object, + props: PressProps, state: PressState, ): void { if (state.longPressTimeout !== null) { @@ -158,7 +175,7 @@ const PressResponder = { }, handleEvent( context: EventResponderContext, - props: Object, + props: PressProps, state: PressState, ): void { const {eventTarget, eventType, event} = context; From c2f16d7579d7538246787689422f6fda0b2804b6 Mon Sep 17 00:00:00 2001 From: Nicolas Gallagher Date: Mon, 1 Apr 2019 09:50:12 -0700 Subject: [PATCH 2/6] Move default Press event delays to constants --- packages/react-events/src/Press.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/react-events/src/Press.js b/packages/react-events/src/Press.js index ec5ed91f2483e..6a1479081538f 100644 --- a/packages/react-events/src/Press.js +++ b/packages/react-events/src/Press.js @@ -10,6 +10,11 @@ import type {EventResponderContext} from 'events/EventTypes'; import {REACT_EVENT_COMPONENT_TYPE} from 'shared/ReactSymbols'; +const DEFAULT_PRESS_DELAY_MS = 0; +const DEFAULT_PRESS_END_DELAY_MS = 0; +const DEFAULT_PRESS_START_DELAY_MS = 0; +const DEFAULT_LONG_PRESS_DELAY_MS = 1000; + const targetEventTypes = [ {name: 'click', passive: false}, {name: 'keydown', passive: false}, @@ -81,7 +86,7 @@ function dispatchPressStartEvents( dispatchPressChangeEvent(true); } if ((props.onLongPress || props.onLongPressChange) && !state.isLongPressed) { - const delayLongPress = calculateDelayMS(props.delayLongPress, 0, 1000); + const delayLongPress = calculateDelayMS(props.delayLongPress, 0, DEFAULT_LONG_PRESS_DELAY_MS); state.longPressTimeout = setTimeout(() => { state.isLongPressed = true; From 20df2bf16d308961e48acac72e46258590c03e1c Mon Sep 17 00:00:00 2001 From: Nicolas Gallagher Date: Mon, 1 Apr 2019 09:50:34 -0700 Subject: [PATCH 3/6] Fix right-click press check for Safari --- packages/react-events/src/Press.js | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/packages/react-events/src/Press.js b/packages/react-events/src/Press.js index 6a1479081538f..0c834c9b12b13 100644 --- a/packages/react-events/src/Press.js +++ b/packages/react-events/src/Press.js @@ -218,8 +218,12 @@ const PressResponder = { dispatchPressEvent(context, state, 'press', keyPressEventListener); break; } + + /** + * Touch event implementations are only needed for Safari, which lacks + * support for pointer events. + */ case 'touchstart': - // Touch events are for Safari, which lack pointer event support. if (!state.isPressed && !context.isTargetOwned(eventTarget)) { // We bail out of polyfilling anchor tags, given the same heuristics // explained above in regards to needing to use click events. @@ -235,7 +239,6 @@ const PressResponder = { break; case 'touchend': { - // Touch events are for Safari, which lack pointer event support if (state.isAnchorTouched) { return; } @@ -275,6 +278,10 @@ const PressResponder = { } break; } + + /** + * Respond to pointer events and fall back to mouse. + */ case 'pointerdown': case 'mousedown': { if ( @@ -282,7 +289,7 @@ const PressResponder = { !context.isTargetOwned(eventTarget) && !state.shouldSkipMouseAfterTouch ) { - if ((event: any).pointerType === 'mouse') { + if ((event: any).pointerType === 'mouse' || eventType === 'mousedown') { // Ignore if we are pressing on hit slop area with mouse if ( context.isPositionWithinTouchHitTarget( @@ -304,8 +311,8 @@ const PressResponder = { } break; } - case 'mouseup': - case 'pointerup': { + case 'pointerup': + case 'mouseup': { if (state.isPressed) { if (state.shouldSkipMouseAfterTouch) { state.shouldSkipMouseAfterTouch = false; @@ -342,6 +349,7 @@ const PressResponder = { state.isAnchorTouched = false; break; } + case 'scroll': case 'touchcancel': case 'contextmenu': From 4c867239fe3154a32cb9874d90a10ef1c4dc3110 Mon Sep 17 00:00:00 2001 From: Nicolas Gallagher Date: Mon, 1 Apr 2019 09:58:25 -0700 Subject: [PATCH 4/6] Prettier and Linter --- packages/react-events/src/Press.js | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/packages/react-events/src/Press.js b/packages/react-events/src/Press.js index 0c834c9b12b13..80e55c65581cd 100644 --- a/packages/react-events/src/Press.js +++ b/packages/react-events/src/Press.js @@ -10,9 +10,9 @@ import type {EventResponderContext} from 'events/EventTypes'; import {REACT_EVENT_COMPONENT_TYPE} from 'shared/ReactSymbols'; -const DEFAULT_PRESS_DELAY_MS = 0; -const DEFAULT_PRESS_END_DELAY_MS = 0; -const DEFAULT_PRESS_START_DELAY_MS = 0; +// const DEFAULT_PRESS_DELAY_MS = 0; +// const DEFAULT_PRESS_END_DELAY_MS = 0; +// const DEFAULT_PRESS_START_DELAY_MS = 0; const DEFAULT_LONG_PRESS_DELAY_MS = 1000; const targetEventTypes = [ @@ -39,10 +39,10 @@ type PressProps = { delayPressStart: number, hitSlop: Object, onLongPress: (e: Object) => void, - onLongPressChange: (boolean) => void, + onLongPressChange: boolean => void, onLongPressShouldCancelPress: () => boolean, onPress: (e: Object) => void, - onPressChange: (boolean) => void, + onPressChange: boolean => void, onPressEnd: (e: Object) => void, onPressStart: (e: Object) => void, pressRententionOffset: Object, @@ -86,7 +86,11 @@ function dispatchPressStartEvents( dispatchPressChangeEvent(true); } if ((props.onLongPress || props.onLongPressChange) && !state.isLongPressed) { - const delayLongPress = calculateDelayMS(props.delayLongPress, 0, DEFAULT_LONG_PRESS_DELAY_MS); + const delayLongPress = calculateDelayMS( + props.delayLongPress, + 0, + DEFAULT_LONG_PRESS_DELAY_MS, + ); state.longPressTimeout = setTimeout(() => { state.isLongPressed = true; @@ -289,7 +293,10 @@ const PressResponder = { !context.isTargetOwned(eventTarget) && !state.shouldSkipMouseAfterTouch ) { - if ((event: any).pointerType === 'mouse' || eventType === 'mousedown') { + if ( + (event: any).pointerType === 'mouse' || + eventType === 'mousedown' + ) { // Ignore if we are pressing on hit slop area with mouse if ( context.isPositionWithinTouchHitTarget( From 8dc9352172eefd12dc366ee5f3b6c412e54f6214 Mon Sep 17 00:00:00 2001 From: Nicolas Gallagher Date: Mon, 1 Apr 2019 10:30:49 -0700 Subject: [PATCH 5/6] Use event.key in press responder event.keyCode is a deprecated API --- packages/react-events/src/Press.js | 19 ++++++++++--------- .../src/__tests__/Press-test.internal.js | 3 +-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/react-events/src/Press.js b/packages/react-events/src/Press.js index 80e55c65581cd..cfc723443329d 100644 --- a/packages/react-events/src/Press.js +++ b/packages/react-events/src/Press.js @@ -164,6 +164,11 @@ function isAnchorTagElement(eventTarget: EventTarget): boolean { return (eventTarget: any).nodeName === 'A'; } +function isValidKeyPress(key: string): boolean { + // Accessibility for keyboards. Space and Enter only. + return key === ' ' || key === 'Enter'; +} + function calculateDelayMS(delay: ?number, min = 0, fallback = 0) { const maybeNumber = delay == null ? null : delay; return Math.max(min, maybeNumber != null ? maybeNumber : fallback); @@ -191,15 +196,11 @@ const PressResponder = { switch (eventType) { case 'keydown': { - if (!props.onPress || context.isTargetOwned(eventTarget)) { - return; - } - const isValidKeyPress = - (event: any).which === 13 || - (event: any).which === 32 || - (event: any).keyCode === 13; - - if (!isValidKeyPress) { + if ( + !props.onPress || + context.isTargetOwned(eventTarget) || + !isValidKeyPress((event: any).key) + ) { return; } let keyPressEventListener = props.onPress; diff --git a/packages/react-events/src/__tests__/Press-test.internal.js b/packages/react-events/src/__tests__/Press-test.internal.js index b86cb24948599..7ecdc3acb8671 100644 --- a/packages/react-events/src/__tests__/Press-test.internal.js +++ b/packages/react-events/src/__tests__/Press-test.internal.js @@ -83,8 +83,7 @@ describe('Press event responder', () => { events = []; const keyDownEvent = new KeyboardEvent('keydown', { - which: 13, - keyCode: 13, + key: 'Enter', bubbles: true, cancelable: true, }); From 77f22842cc23596445354401634a6bee783282a8 Mon Sep 17 00:00:00 2001 From: Nicolas Gallagher Date: Mon, 1 Apr 2019 15:38:12 -0700 Subject: [PATCH 6/6] Remove unused props from Press event module --- packages/react-events/src/Press.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/react-events/src/Press.js b/packages/react-events/src/Press.js index cfc723443329d..fe0310e4e0d26 100644 --- a/packages/react-events/src/Press.js +++ b/packages/react-events/src/Press.js @@ -34,10 +34,8 @@ if (typeof window !== 'undefined' && window.PointerEvent === undefined) { type PressProps = { disabled: boolean, delayLongPress: number, - delayPress: number, delayPressEnd: number, delayPressStart: number, - hitSlop: Object, onLongPress: (e: Object) => void, onLongPressChange: boolean => void, onLongPressShouldCancelPress: () => boolean,