@@ -232,6 +232,16 @@ static BOOL IsViewListeningToEvent(UIView *view, ViewEvents::Offset eventType)
232232 return NO ;
233233}
234234
235+ static BOOL IsAnyViewInPathListeningToEvent (NSOrderedSet <UIView *> *viewPath, ViewEvents::Offset eventType)
236+ {
237+ for (UIView *view in viewPath) {
238+ if (IsViewListeningToEvent (view, eventType)) {
239+ return YES ;
240+ }
241+ }
242+ return NO ;
243+ }
244+
235245/* *
236246 * Surprisingly, `__unsafe_unretained id` pointers are not regular pointers
237247 * and `std::hash<>` cannot hash them.
@@ -563,11 +573,22 @@ - (void)hovering:(UIHoverGestureRecognizer *)recognizer API_AVAILABLE(ios(13.0))
563573
564574 UIView *targetView = [listenerView hitTest: clientLocation withEvent: nil ];
565575 targetView = FindClosestFabricManagedTouchableView (targetView);
576+ UIView *prevTargetView = [_currentlyHoveredViews firstObject ];
566577
567578 NSOrderedSet *eventPathViews = GetTouchableViewsInPathToRoot (targetView);
568579
569580 NSTimeInterval timestamp = CACurrentMediaTime ();
570581
582+ // Over
583+ if (prevTargetView != targetView) {
584+ BOOL shouldEmitOverEvent = IsAnyViewInPathListeningToEvent (eventPathViews, ViewEvents::Offset::PointerOver);
585+ SharedTouchEventEmitter eventEmitter = GetTouchEmitterFromView (targetView, [recognizer locationInView: targetView]);
586+ if (shouldEmitOverEvent && eventEmitter != nil ) {
587+ PointerEvent event = CreatePointerEventFromIncompleteHoverData (targetView, clientLocation, timestamp);
588+ eventEmitter->onPointerOver (event);
589+ }
590+ }
591+
571592 // Entering
572593
573594 // We only want to emit events to JS if there is a view that is currently listening to said event
@@ -595,6 +616,17 @@ - (void)hovering:(UIHoverGestureRecognizer *)recognizer API_AVAILABLE(ios(13.0))
595616 }
596617 }
597618
619+ // Out
620+ if (prevTargetView != targetView) {
621+ BOOL shouldEmitOutEvent = IsAnyViewInPathListeningToEvent (_currentlyHoveredViews, ViewEvents::Offset::PointerOut);
622+ SharedTouchEventEmitter eventEmitter =
623+ GetTouchEmitterFromView (prevTargetView, [recognizer locationInView: prevTargetView]);
624+ if (shouldEmitOutEvent && eventEmitter != nil ) {
625+ PointerEvent event = CreatePointerEventFromIncompleteHoverData (prevTargetView, clientLocation, timestamp);
626+ eventEmitter->onPointerOut (event);
627+ }
628+ }
629+
598630 // Leaving
599631
600632 // pointerleave events need to be emited from the deepest target to the root but
0 commit comments