@@ -75,6 +75,7 @@ type PressState = {
7575 ignoreEmulatedMouseEvents : boolean ,
7676 activePointerId : null | number ,
7777 shouldPreventClick : boolean ,
78+ touchEvent : null | Touch ,
7879} ;
7980
8081type PressEventType =
@@ -160,6 +161,7 @@ function createPressEvent(
160161 target : Element | Document ,
161162 pointerType : PointerType ,
162163 event : ?ReactDOMResponderEvent ,
164+ touchEvent : null | Touch ,
163165 defaultPrevented : boolean ,
164166) : PressEvent {
165167 const timeStamp = context . getTimeStamp ( ) ;
@@ -180,11 +182,7 @@ function createPressEvent(
180182 // Only check for one property, checking for all of them is costly. We can assume
181183 // if clientX exists, so do the rest.
182184 let eventObject ;
183- if ( nativeEvent . clientX !== undefined ) {
184- eventObject = ( nativeEvent : any ) ;
185- } else if ( isNativeTouchEvent ( nativeEvent ) ) {
186- eventObject = getTouchFromPressEvent ( nativeEvent ) ;
187- }
185+ eventObject = ( touchEvent : any ) || ( nativeEvent : any ) ;
188186 if ( eventObject ) {
189187 ( { clientX, clientY, pageX, pageY, screenX, screenY} = eventObject ) ;
190188 }
@@ -223,12 +221,14 @@ function dispatchEvent(
223221 const defaultPrevented =
224222 ( event != null && event . nativeEvent . defaultPrevented === true ) ||
225223 ( name === 'press' && state . shouldPreventClick ) ;
224+ const touchEvent = state . touchEvent ;
226225 const syntheticEvent = createPressEvent (
227226 context ,
228227 name ,
229228 target ,
230229 pointerType ,
231230 event ,
231+ touchEvent ,
232232 defaultPrevented ,
233233 ) ;
234234 context . dispatchEvent ( syntheticEvent , listener , eventPriority ) ;
@@ -269,10 +269,10 @@ function dispatchLongPressChangeEvent(
269269
270270function activate ( event : ReactDOMResponderEvent , context , props , state ) {
271271 const nativeEvent : any = event . nativeEvent ;
272- const { x, y} = getEventViewportCoords ( nativeEvent ) ;
272+ const { clientX : x , clientY : y } = state . touchEvent || nativeEvent ;
273273 const wasActivePressed = state . isActivePressed ;
274274 state . isActivePressed = true ;
275- if ( x !== null && y !== null ) {
275+ if ( x !== undefined && y !== undefined ) {
276276 state . activationPosition = { x, y} ;
277277 }
278278
@@ -433,6 +433,7 @@ function dispatchCancel(
433433 props : PressProps ,
434434 state : PressState ,
435435) : void {
436+ state . touchEvent = null ;
436437 if ( state . isPressed ) {
437438 state . ignoreEmulatedMouseEvents = false ;
438439 dispatchPressEndEvents ( event , context , props , state ) ;
@@ -495,33 +496,12 @@ function calculateResponderRegion(
495496 } ;
496497}
497498
498- function isNativeTouchEvent ( nativeEvent : Event ) : boolean {
499- const changedTouches = ( ( nativeEvent : any ) : TouchEvent ) . changedTouches ;
500- return changedTouches && typeof changedTouches . length === 'number' ;
501- }
502-
503- function getTouchFromPressEvent ( nativeEvent : TouchEvent ) : Touch {
504- const { changedTouches, touches} = nativeEvent ;
505- return changedTouches . length > 0
506- ? changedTouches [ 0 ]
507- : touches . length > 0
508- ? touches [ 0 ]
509- : ( nativeEvent : any ) ;
510- }
511-
512- function getEventViewportCoords (
513- nativeEvent : Event ,
514- ) : { x: null | number , y : null | number } {
515- let eventObject = ( nativeEvent : any ) ;
516- if ( isNativeTouchEvent ( eventObject ) ) {
517- eventObject = getTouchFromPressEvent ( eventObject ) ;
499+ function getTouchFromPressEvent ( nativeEvent : TouchEvent ) : null | Touch {
500+ const targetTouches = nativeEvent . targetTouches ;
501+ if ( targetTouches . length > 0 ) {
502+ return targetTouches [ 0 ] ;
518503 }
519- const x = eventObject . clientX ;
520- const y = eventObject . clientY ;
521- return {
522- x : x != null ? x : null ,
523- y : y != null ? y : null ,
524- } ;
504+ return null ;
525505}
526506
527507function unmountResponder (
@@ -575,54 +555,46 @@ function getTouchTarget(context: ReactDOMResponderContext, touchEvent: Touch) {
575555}
576556
577557function updateIsPressWithinResponderRegion (
578- target : Element | Document ,
579558 nativeEventOrTouchEvent : Event | Touch ,
580559 context : ReactDOMResponderContext ,
581560 props : PressProps ,
582561 state : PressState ,
583562) : void {
584- let isPressWithinResponderRegion = true ;
585- if (
586- state . pressTarget != null &&
587- ! context . isTargetWithinElement ( target , state . pressTarget )
588- ) {
589- // Calculate the responder region we use for deactivation if not
590- // already done during move event.
591- if ( state . responderRegionOnDeactivation == null ) {
592- state . responderRegionOnDeactivation = calculateResponderRegion (
593- context ,
594- state . pressTarget ,
595- props ,
596- ) ;
597- }
598- const { responderRegionOnActivation, responderRegionOnDeactivation} = state ;
599- let left , top , right , bottom ;
600-
601- if ( responderRegionOnActivation != null ) {
602- left = responderRegionOnActivation . left ;
603- top = responderRegionOnActivation . top ;
604- right = responderRegionOnActivation . right ;
605- bottom = responderRegionOnActivation . bottom ;
606-
607- if ( responderRegionOnDeactivation != null ) {
608- left = Math . min ( left , responderRegionOnDeactivation . left ) ;
609- top = Math . min ( top , responderRegionOnDeactivation . top ) ;
610- right = Math . max ( right , responderRegionOnDeactivation . right ) ;
611- bottom = Math . max ( bottom , responderRegionOnDeactivation . bottom ) ;
612- }
563+ // Calculate the responder region we use for deactivation if not
564+ // already done during move event.
565+ if ( state . responderRegionOnDeactivation == null ) {
566+ state . responderRegionOnDeactivation = calculateResponderRegion (
567+ context ,
568+ ( ( state . pressTarget : any ) : Element ) ,
569+ props ,
570+ ) ;
571+ }
572+ const { responderRegionOnActivation, responderRegionOnDeactivation} = state ;
573+ let left , top , right , bottom ;
574+
575+ if ( responderRegionOnActivation != null ) {
576+ left = responderRegionOnActivation . left ;
577+ top = responderRegionOnActivation . top ;
578+ right = responderRegionOnActivation . right ;
579+ bottom = responderRegionOnActivation . bottom ;
580+
581+ if ( responderRegionOnDeactivation != null ) {
582+ left = Math . min ( left , responderRegionOnDeactivation . left ) ;
583+ top = Math . min ( top , responderRegionOnDeactivation . top ) ;
584+ right = Math . max ( right , responderRegionOnDeactivation . right ) ;
585+ bottom = Math . max ( bottom , responderRegionOnDeactivation . bottom ) ;
613586 }
614- const { clientX : x , clientY : y } = ( nativeEventOrTouchEvent : any ) ;
615-
616- isPressWithinResponderRegion =
617- left != null &&
618- right != null &&
619- top != null &&
620- bottom != null &&
621- x !== null &&
622- y !== null &&
623- ( x >= left && x <= right && y >= top && y <= bottom ) ;
624587 }
625- state . isPressWithinResponderRegion = isPressWithinResponderRegion ;
588+ const { clientX : x , clientY : y } = ( nativeEventOrTouchEvent : any ) ;
589+
590+ state . isPressWithinResponderRegion =
591+ left != null &&
592+ right != null &&
593+ top != null &&
594+ bottom != null &&
595+ x !== null &&
596+ y !== null &&
597+ ( x >= left && x <= right && y >= top && y <= bottom ) ;
626598}
627599
628600function handleStopPropagation (
@@ -650,7 +622,6 @@ const PressResponder: ReactDOMEventResponder = {
650622 return {
651623 activationPosition : null ,
652624 addedRootEvents : false ,
653- didDispatchEvent : false ,
654625 isActivePressed : false ,
655626 isActivePressStart : false ,
656627 isLongPressed : false ,
@@ -666,6 +637,7 @@ const PressResponder: ReactDOMEventResponder = {
666637 ignoreEmulatedMouseEvents : false ,
667638 activePointerId : null ,
668639 shouldPreventClick : false ,
640+ touchEvent : null ,
669641 } ;
670642 } ,
671643 allowMultipleHostChildren : false ,
@@ -731,6 +703,10 @@ const PressResponder: ReactDOMEventResponder = {
731703 state . activePointerId = pointerId ;
732704 } else if ( isTouchEvent ) {
733705 const touchEvent = getTouchFromPressEvent ( nativeEvent ) ;
706+ if ( touchEvent === null ) {
707+ return ;
708+ }
709+ state . touchEvent = touchEvent ;
734710 state . activePointerId = touchEvent . identifier ;
735711 }
736712
@@ -852,18 +828,23 @@ const PressResponder: ReactDOMEventResponder = {
852828 if ( touchEvent === null ) {
853829 return ;
854830 }
855- target = getTouchTarget ( context , touchEvent ) ;
831+ state . touchEvent = touchEvent ;
856832 }
857833
858- // Calculate the responder region we use for deactivation, as the
859- // element dimensions may have changed since activation.
860- updateIsPressWithinResponderRegion (
861- target ,
862- touchEvent || nativeEvent ,
863- context ,
864- props ,
865- state ,
866- ) ;
834+ if (
835+ state . pressTarget !== null &&
836+ ( pointerType !== 'mouse' ||
837+ ! context . isTargetWithinElement ( target , state . pressTarget ) )
838+ ) {
839+ // Calculate the responder region we use for deactivation, as the
840+ // element dimensions may have changed since activation.
841+ updateIsPressWithinResponderRegion (
842+ touchEvent || nativeEvent ,
843+ context ,
844+ props ,
845+ state ,
846+ ) ;
847+ }
867848
868849 if ( state . isPressWithinResponderRegion ) {
869850 if ( isPressed ) {
@@ -914,6 +895,7 @@ const PressResponder: ReactDOMEventResponder = {
914895 if ( touchEvent === null ) {
915896 return ;
916897 }
898+ state . touchEvent = touchEvent ;
917899 target = getTouchTarget ( context , touchEvent ) ;
918900 } else if ( type === 'keyup' ) {
919901 // Ignore unrelated keyboard events
@@ -961,12 +943,16 @@ const PressResponder: ReactDOMEventResponder = {
961943 dispatchPressEndEvents ( event , context , props , state ) ;
962944
963945 if ( state . pressTarget !== null && props . onPress ) {
964- if ( ! isKeyboardEvent ) {
946+ if (
947+ ! isKeyboardEvent &&
948+ state . pressTarget !== null &&
949+ ( pointerType !== 'mouse' ||
950+ ! context . isTargetWithinElement ( target , state . pressTarget ) )
951+ ) {
965952 // If the event target isn't within the press target, check if we're still
966953 // within the responder region. The region may have changed if the
967954 // element's layout was modified after activation.
968955 updateIsPressWithinResponderRegion (
969- target ,
970956 touchEvent || nativeEvent ,
971957 context ,
972958 props ,
@@ -992,6 +978,7 @@ const PressResponder: ReactDOMEventResponder = {
992978 }
993979 }
994980 }
981+ state . touchEvent = null ;
995982 } else if ( type === 'mouseup' ) {
996983 state . ignoreEmulatedMouseEvents = false ;
997984 }
0 commit comments