@@ -24,6 +24,26 @@ typedef NS_ENUM(NSInteger, RCTPointerEventType) {
2424 RCTPointerEventTypeCancel,
2525};
2626
27+ static BOOL AllTouchesAreCancelledOrEnded (NSSet <UITouch *> *touches)
28+ {
29+ for (UITouch *touch in touches) {
30+ if (touch.phase == UITouchPhaseBegan || touch.phase == UITouchPhaseMoved || touch.phase == UITouchPhaseStationary) {
31+ return NO ;
32+ }
33+ }
34+ return YES ;
35+ }
36+
37+ static BOOL AnyTouchesChanged (NSSet <UITouch *> *touches)
38+ {
39+ for (UITouch *touch in touches) {
40+ if (touch.phase == UITouchPhaseBegan || touch.phase == UITouchPhaseMoved) {
41+ return YES ;
42+ }
43+ }
44+ return NO ;
45+ }
46+
2747struct ActivePointer {
2848 /*
2949 * Pointer ID
@@ -349,7 +369,9 @@ static void UpdateActivePointerWithUITouch(
349369 UIEvent *uiEvent,
350370 UIView *rootComponentView)
351371{
352- activePointer.componentView = FindClosestFabricManagedTouchableView (uiTouch.view );
372+ CGPoint location = [uiTouch locationInView: rootComponentView];
373+ UIView *hitTestedView = [rootComponentView hitTest: location withEvent: nil ];
374+ activePointer.componentView = FindClosestFabricManagedTouchableView (hitTestedView);
353375
354376 activePointer.clientPoint = [uiTouch locationInView: rootComponentView];
355377 activePointer.screenPoint = [rootComponentView convertPoint: activePointer.clientPoint
@@ -396,6 +418,22 @@ static BOOL IsAnyViewInPathListeningToEvent(NSOrderedSet<RCTReactTaggedView *> *
396418 return NO ;
397419}
398420
421+ /* *
422+ * Given an ActivePointer determine if it is still within the same event target tree as
423+ * the one which initiated the pointer gesture.
424+ */
425+ static BOOL IsPointerWithinInitialTree (ActivePointer activePointer)
426+ {
427+ NSOrderedSet <RCTReactTaggedView *> *initialViewSet =
428+ GetTouchableViewsInPathToRoot (activePointer.initialComponentView );
429+ for (RCTReactTaggedView *canidateTaggedView in initialViewSet) {
430+ if (canidateTaggedView.tag == activePointer.componentView .tag ) {
431+ return YES ;
432+ }
433+ }
434+ return NO ;
435+ }
436+
399437/* *
400438 * Surprisingly, `__unsafe_unretained id` pointers are not regular pointers
401439 * and `std::hash<>` cannot hash them.
@@ -526,6 +564,8 @@ - (void)_registerTouches:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
526564 activePointer.shouldLeaveWhenReleased = YES ;
527565 }
528566
567+ activePointer.initialComponentView = FindClosestFabricManagedTouchableView (touch.view );
568+
529569 UpdateActivePointerWithUITouch (activePointer, touch, event, _rootComponentView);
530570
531571 _activePointers.emplace (touch, activePointer);
@@ -618,6 +658,11 @@ - (void)_dispatchActivePointers:(std::vector<ActivePointer>)activePointers event
618658 }
619659 case RCTPointerEventTypeEnd: {
620660 eventEmitter->onPointerUp (pointerEvent);
661+
662+ if (pointerEvent.isPrimary && pointerEvent.button == 0 && IsPointerWithinInitialTree (activePointer)) {
663+ eventEmitter->onClick (pointerEvent);
664+ }
665+
621666 if (activePointer.shouldLeaveWhenReleased ) {
622667 [self handleIncomingPointerEvent: pointerEvent onView: nil ];
623668 }
@@ -641,6 +686,12 @@ - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
641686
642687 [self _registerTouches: touches withEvent: event];
643688 [self _dispatchActivePointers: [self _activePointersFromTouches: touches] eventType: RCTPointerEventTypeStart];
689+
690+ if (self.state == UIGestureRecognizerStatePossible) {
691+ self.state = UIGestureRecognizerStateBegan;
692+ } else if (self.state == UIGestureRecognizerStateBegan) {
693+ self.state = UIGestureRecognizerStateChanged;
694+ }
644695}
645696
646697- (void )touchesMoved : (NSSet <UITouch *> *)touches withEvent : (UIEvent *)event
@@ -649,6 +700,8 @@ - (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
649700
650701 [self _updateTouches: touches withEvent: event];
651702 [self _dispatchActivePointers: [self _activePointersFromTouches: touches] eventType: RCTPointerEventTypeMove];
703+
704+ self.state = UIGestureRecognizerStateChanged;
652705}
653706
654707- (void )touchesEnded : (NSSet <UITouch *> *)touches withEvent : (UIEvent *)event
@@ -658,6 +711,12 @@ - (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
658711 [self _updateTouches: touches withEvent: event];
659712 [self _dispatchActivePointers: [self _activePointersFromTouches: touches] eventType: RCTPointerEventTypeEnd];
660713 [self _unregisterTouches: touches];
714+
715+ if (AllTouchesAreCancelledOrEnded (event.allTouches )) {
716+ self.state = UIGestureRecognizerStateEnded;
717+ } else if (AnyTouchesChanged (event.allTouches )) {
718+ self.state = UIGestureRecognizerStateChanged;
719+ }
661720}
662721
663722- (void )touchesCancelled : (NSSet <UITouch *> *)touches withEvent : (UIEvent *)event
@@ -667,6 +726,12 @@ - (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
667726 [self _updateTouches: touches withEvent: event];
668727 [self _dispatchActivePointers: [self _activePointersFromTouches: touches] eventType: RCTPointerEventTypeCancel];
669728 [self _unregisterTouches: touches];
729+
730+ if (AllTouchesAreCancelledOrEnded (event.allTouches )) {
731+ self.state = UIGestureRecognizerStateCancelled;
732+ } else if (AnyTouchesChanged (event.allTouches )) {
733+ self.state = UIGestureRecognizerStateChanged;
734+ }
670735}
671736
672737- (void )reset
0 commit comments