diff --git a/packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/core/GestureHandler.kt b/packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/core/GestureHandler.kt index b9e4b2c6e2..3d1f6cb971 100644 --- a/packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/core/GestureHandler.kt +++ b/packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/core/GestureHandler.kt @@ -577,11 +577,22 @@ open class GestureHandler { onStateChange(newState, oldState) } - fun wantsEvent(event: MotionEvent): Boolean = isEnabled && - state != STATE_FAILED && - state != STATE_CANCELLED && - state != STATE_END && - isTrackingPointer(event.getPointerId(event.actionIndex)) + fun wantsEvent(event: MotionEvent): Boolean { + if (!isEnabled || state == STATE_FAILED || state == STATE_CANCELLED || state == STATE_END) { + return false + } + + if (event.actionMasked == MotionEvent.ACTION_MOVE) { + for (i in 0 until event.pointerCount) { + if (isTrackingPointer(event.getPointerId(i))) { + return true + } + } + return false + } else { + return isTrackingPointer(event.getPointerId(event.actionIndex)) + } + } open fun shouldRequireToWaitForFailure(handler: GestureHandler): Boolean { if (handler === this) { diff --git a/packages/react-native-gesture-handler/apple/Handlers/RNFlingHandler.m b/packages/react-native-gesture-handler/apple/Handlers/RNFlingHandler.m index 777270c749..eeb48043b3 100644 --- a/packages/react-native-gesture-handler/apple/Handlers/RNFlingHandler.m +++ b/packages/react-native-gesture-handler/apple/Handlers/RNFlingHandler.m @@ -16,7 +16,7 @@ @implementation RNBetterSwipeGestureRecognizer { - (id)initWithGestureHandler:(RNGestureHandler *)gestureHandler { - if ((self = [super initWithTarget:gestureHandler action:@selector(handleGesture:fromReset:)])) { + if ((self = [super initWithTarget:gestureHandler action:@selector(handleGesture:)])) { _gestureHandler = gestureHandler; _lastPoint = CGPointZero; _hasBegan = NO; @@ -26,7 +26,7 @@ - (id)initWithGestureHandler:(RNGestureHandler *)gestureHandler - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { - [_gestureHandler setCurrentPointerType:event]; + [_gestureHandler setCurrentPointerTypeForEvent:event]; _lastPoint = [[[touches allObjects] objectAtIndex:0] locationInView:_gestureHandler.recognizer.view]; [_gestureHandler reset]; [super touchesBegan:touches withEvent:event]; @@ -119,7 +119,7 @@ @implementation RNBetterSwipeGestureRecognizer { - (id)initWithGestureHandler:(RNGestureHandler *)gestureHandler { - if ((self = [super initWithTarget:self action:@selector(handleGesture:fromReset:)])) { + if ((self = [super initWithTarget:self action:@selector(handleGesture:)])) { _gestureHandler = gestureHandler; maxDuration = 1.0; @@ -132,9 +132,9 @@ - (id)initWithGestureHandler:(RNGestureHandler *)gestureHandler return self; } -- (void)handleGesture:(NSPanGestureRecognizer *)gestureRecognizer fromReset:(BOOL)fromReset +- (void)handleGesture:(NSPanGestureRecognizer *)gestureRecognizer { - [_gestureHandler handleGesture:self fromReset:fromReset]; + [_gestureHandler handleGesture:self]; } - (void)mouseDown:(NSEvent *)event diff --git a/packages/react-native-gesture-handler/apple/Handlers/RNForceTouchHandler.m b/packages/react-native-gesture-handler/apple/Handlers/RNForceTouchHandler.m index e7054a081f..3f2e97a713 100644 --- a/packages/react-native-gesture-handler/apple/Handlers/RNForceTouchHandler.m +++ b/packages/react-native-gesture-handler/apple/Handlers/RNForceTouchHandler.m @@ -28,7 +28,7 @@ @implementation RNForceTouchGestureRecognizer { - (id)initWithGestureHandler:(RNGestureHandler *)gestureHandler { - if ((self = [super initWithTarget:gestureHandler action:@selector(handleGesture:fromReset:)])) { + if ((self = [super initWithTarget:gestureHandler action:@selector(handleGesture:)])) { _gestureHandler = gestureHandler; _force = defaultForce; _minForce = defaultMinForce; @@ -40,7 +40,7 @@ - (id)initWithGestureHandler:(RNGestureHandler *)gestureHandler - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { - [_gestureHandler setCurrentPointerType:event]; + [_gestureHandler setCurrentPointerTypeForEvent:event]; if (_firstTouch) { // ignore rest of fingers return; diff --git a/packages/react-native-gesture-handler/apple/Handlers/RNHoverHandler.m b/packages/react-native-gesture-handler/apple/Handlers/RNHoverHandler.m index f800c84612..289bf43a73 100644 --- a/packages/react-native-gesture-handler/apple/Handlers/RNHoverHandler.m +++ b/packages/react-native-gesture-handler/apple/Handlers/RNHoverHandler.m @@ -40,13 +40,22 @@ @implementation RNBetterHoverGestureRecognizer { - (id)initWithGestureHandler:(RNGestureHandler *)gestureHandler { - if ((self = [super initWithTarget:gestureHandler action:@selector(handleGesture:fromReset:)])) { + if ((self = [super initWithTarget:self action:@selector(handleGesture:)])) { _gestureHandler = gestureHandler; _hoverEffect = RNGestureHandlerHoverEffectNone; } return self; } +- (void)handleGesture:(UIHoverGestureRecognizer *)recognizer +{ + if (recognizer.state == UIGestureRecognizerStateBegan) { + [_gestureHandler setCurrentPointerType:RNGestureHandlerMouse]; + } + + [_gestureHandler handleGesture:self]; +} + - (void)triggerAction { [_gestureHandler handleGesture:self fromReset:NO]; @@ -153,11 +162,22 @@ - (void)configure:(NSDictionary *)config #endif } +- (void)setCurrentPointerType:(RNGestureHandlerPointerType)pointerType +{ + _pointerType = pointerType; + + if (@available(iOS 16.1, *)) { + if (((UIHoverGestureRecognizer *)self.recognizer).zOffset > 0.0) { + _pointerType = RNGestureHandlerStylus; + } + } +} + - (RNGestureHandlerEventExtraData *)eventExtraData:(UIGestureRecognizer *)recognizer { return [RNGestureHandlerEventExtraData forPosition:[recognizer locationInView:recognizer.view] withAbsolutePosition:[recognizer locationInView:recognizer.view.window] - withPointerType:UITouchTypePencil]; + withPointerType:_pointerType]; } @end @@ -173,6 +193,7 @@ - (instancetype)initWithTag:(NSNumber *)tag { if ((self = [super initWithTag:tag])) { _recognizer = [NSGestureRecognizer alloc]; + _pointerType = RNGestureHandlerMouse; } return self; @@ -199,21 +220,29 @@ - (void)mouseEntered:(NSEvent *)event { [self sendEventsInState:RNGestureHandlerStateBegan forViewWithTag:_view.reactTag - withExtraData:[RNGestureHandlerEventExtraData forPointerInside:YES withPointerType:_pointerType]]; + withExtraData:[RNGestureHandlerEventExtraData forPointerInside:YES + withNumberOfTouches:1 + withPointerType:_pointerType]]; [self sendEventsInState:RNGestureHandlerStateActive forViewWithTag:_view.reactTag - withExtraData:[RNGestureHandlerEventExtraData forPointerInside:YES withPointerType:_pointerType]]; + withExtraData:[RNGestureHandlerEventExtraData forPointerInside:YES + withNumberOfTouches:1 + withPointerType:_pointerType]]; } - (void)mouseExited:(NSEvent *)theEvent { [self sendEventsInState:RNGestureHandlerStateEnd forViewWithTag:_view.reactTag - withExtraData:[RNGestureHandlerEventExtraData forPointerInside:YES withPointerType:_pointerType]]; + withExtraData:[RNGestureHandlerEventExtraData forPointerInside:NO + withNumberOfTouches:1 + withPointerType:_pointerType]]; [self sendEventsInState:RNGestureHandlerStateUndetermined forViewWithTag:_view.reactTag - withExtraData:[RNGestureHandlerEventExtraData forPointerInside:YES withPointerType:_pointerType]]; + withExtraData:[RNGestureHandlerEventExtraData forPointerInside:NO + withNumberOfTouches:1 + withPointerType:_pointerType]]; } @end diff --git a/packages/react-native-gesture-handler/apple/Handlers/RNLongPressHandler.m b/packages/react-native-gesture-handler/apple/Handlers/RNLongPressHandler.m index e9fcd47a02..4579ff73e3 100644 --- a/packages/react-native-gesture-handler/apple/Handlers/RNLongPressHandler.m +++ b/packages/react-native-gesture-handler/apple/Handlers/RNLongPressHandler.m @@ -33,8 +33,10 @@ - (id)initWithGestureHandler:(RNGestureHandler *)gestureHandler; - (NSUInteger)getDuration; #if !TARGET_OS_OSX +- (void)handleGesture:(UIGestureRecognizer *)recognizer; - (void)handleGesture:(UIGestureRecognizer *)recognizer fromReset:(BOOL)fromReset; #else +- (void)handleGesture:(NSGestureRecognizer *)recognizer; - (void)handleGesture:(NSGestureRecognizer *)recognizer fromReset:(BOOL)fromReset; #endif @@ -47,12 +49,18 @@ @implementation RNBetterLongPressGestureRecognizer { - (id)initWithGestureHandler:(RNGestureHandler *)gestureHandler { - if ((self = [super initWithTarget:self action:@selector(handleGesture:fromReset:)])) { + if ((self = [super initWithTarget:self action:@selector(handleGesture:)])) { _gestureHandler = gestureHandler; } return self; } +- (void)handleGesture:(UIGestureRecognizer *)recognizer +{ + previousTime = CACurrentMediaTime(); + [_gestureHandler handleGesture:recognizer fromReset:NO]; +} + - (void)handleGesture:(UIGestureRecognizer *)recognizer fromReset:(BOOL)fromReset { previousTime = CACurrentMediaTime(); @@ -79,7 +87,7 @@ - (CGPoint)translationInView - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { - [_gestureHandler setCurrentPointerType:event]; + [_gestureHandler setCurrentPointerTypeForEvent:event]; [super touchesBegan:touches withEvent:event]; [_gestureHandler.pointerTracker touchesBegan:touches withEvent:event]; diff --git a/packages/react-native-gesture-handler/apple/Handlers/RNManualHandler.m b/packages/react-native-gesture-handler/apple/Handlers/RNManualHandler.m index d8d620e38d..f0b3b1f38b 100644 --- a/packages/react-native-gesture-handler/apple/Handlers/RNManualHandler.m +++ b/packages/react-native-gesture-handler/apple/Handlers/RNManualHandler.m @@ -16,7 +16,7 @@ @implementation RNManualRecognizer { - (id)initWithGestureHandler:(RNGestureHandler *)gestureHandler { - if ((self = [super initWithTarget:gestureHandler action:@selector(handleGesture:fromReset:)])) { + if ((self = [super initWithTarget:gestureHandler action:@selector(handleGesture:)])) { _gestureHandler = gestureHandler; _shouldSendBeginEvent = YES; } @@ -59,7 +59,7 @@ - (void)interactionsEnded:(NSSet *)touches withEvent:(UIEvent *)event #if !TARGET_OS_OSX - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { - [_gestureHandler setCurrentPointerType:event]; + [_gestureHandler setCurrentPointerTypeForEvent:event]; [super touchesBegan:touches withEvent:event]; [self interactionsBegan:touches withEvent:event]; diff --git a/packages/react-native-gesture-handler/apple/Handlers/RNNativeViewHandler.mm b/packages/react-native-gesture-handler/apple/Handlers/RNNativeViewHandler.mm index 966f8e3658..cd273b171b 100644 --- a/packages/react-native-gesture-handler/apple/Handlers/RNNativeViewHandler.mm +++ b/packages/react-native-gesture-handler/apple/Handlers/RNNativeViewHandler.mm @@ -29,7 +29,7 @@ @implementation RNDummyGestureRecognizer { - (id)initWithGestureHandler:(RNGestureHandler *)gestureHandler { - if ((self = [super initWithTarget:gestureHandler action:@selector(handleGesture:fromReset:)])) { + if ((self = [super initWithTarget:gestureHandler action:@selector(handleGesture:)])) { _gestureHandler = gestureHandler; } return self; @@ -38,7 +38,7 @@ - (id)initWithGestureHandler:(RNGestureHandler *)gestureHandler #if !TARGET_OS_OSX - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { - [_gestureHandler setCurrentPointerType:event]; + [_gestureHandler setCurrentPointerTypeForEvent:event]; [_gestureHandler.pointerTracker touchesBegan:touches withEvent:event]; } @@ -166,7 +166,7 @@ - (void)bindToView:(UIView *)view - (void)handleTouchDown:(UIView *)sender forEvent:(UIEvent *)event { - [self setCurrentPointerType:event]; + [self setCurrentPointerTypeForEvent:event]; [self reset]; if (_disallowInterruption) { @@ -182,21 +182,27 @@ - (void)handleTouchDown:(UIView *)sender forEvent:(UIEvent *)event [self sendEventsInState:RNGestureHandlerStateActive forViewWithTag:sender.reactTag - withExtraData:[RNGestureHandlerEventExtraData forPointerInside:YES withPointerType:_pointerType]]; + withExtraData:[RNGestureHandlerEventExtraData forPointerInside:YES + withNumberOfTouches:event.allTouches.count + withPointerType:_pointerType]]; } - (void)handleTouchUpOutside:(UIView *)sender forEvent:(UIEvent *)event { [self sendEventsInState:RNGestureHandlerStateEnd forViewWithTag:sender.reactTag - withExtraData:[RNGestureHandlerEventExtraData forPointerInside:NO withPointerType:_pointerType]]; + withExtraData:[RNGestureHandlerEventExtraData forPointerInside:NO + withNumberOfTouches:event.allTouches.count + withPointerType:_pointerType]]; } - (void)handleTouchUpInside:(UIView *)sender forEvent:(UIEvent *)event { [self sendEventsInState:RNGestureHandlerStateEnd forViewWithTag:sender.reactTag - withExtraData:[RNGestureHandlerEventExtraData forPointerInside:YES withPointerType:_pointerType]]; + withExtraData:[RNGestureHandlerEventExtraData forPointerInside:YES + withNumberOfTouches:event.allTouches.count + withPointerType:_pointerType]]; } - (void)handleDragExit:(UIView *)sender forEvent:(UIEvent *)event @@ -207,11 +213,15 @@ - (void)handleDragExit:(UIView *)sender forEvent:(UIEvent *)event [control cancelTrackingWithEvent:event]; [self sendEventsInState:RNGestureHandlerStateEnd forViewWithTag:sender.reactTag - withExtraData:[RNGestureHandlerEventExtraData forPointerInside:NO withPointerType:_pointerType]]; + withExtraData:[RNGestureHandlerEventExtraData forPointerInside:NO + withNumberOfTouches:event.allTouches.count + withPointerType:_pointerType]]; } else { [self sendEventsInState:RNGestureHandlerStateActive forViewWithTag:sender.reactTag - withExtraData:[RNGestureHandlerEventExtraData forPointerInside:NO withPointerType:_pointerType]]; + withExtraData:[RNGestureHandlerEventExtraData forPointerInside:NO + withNumberOfTouches:event.allTouches.count + withPointerType:_pointerType]]; } } @@ -219,14 +229,18 @@ - (void)handleDragEnter:(UIView *)sender forEvent:(UIEvent *)event { [self sendEventsInState:RNGestureHandlerStateActive forViewWithTag:sender.reactTag - withExtraData:[RNGestureHandlerEventExtraData forPointerInside:YES withPointerType:_pointerType]]; + withExtraData:[RNGestureHandlerEventExtraData forPointerInside:YES + withNumberOfTouches:event.allTouches.count + withPointerType:_pointerType]]; } - (void)handleTouchCancel:(UIView *)sender forEvent:(UIEvent *)event { [self sendEventsInState:RNGestureHandlerStateCancelled forViewWithTag:sender.reactTag - withExtraData:[RNGestureHandlerEventExtraData forPointerInside:NO withPointerType:_pointerType]]; + withExtraData:[RNGestureHandlerEventExtraData forPointerInside:NO + withNumberOfTouches:event.allTouches.count + withPointerType:_pointerType]]; } #else @@ -234,6 +248,7 @@ - (void)handleTouchCancel:(UIView *)sender forEvent:(UIEvent *)event - (RNGestureHandlerEventExtraData *)eventExtraData:(RNDummyGestureRecognizer *)recognizer { return [RNGestureHandlerEventExtraData forPointerInside:[self containsPointInView] + withNumberOfTouches:1 withPointerType:RNGestureHandlerMouse]; } diff --git a/packages/react-native-gesture-handler/apple/Handlers/RNPanHandler.m b/packages/react-native-gesture-handler/apple/Handlers/RNPanHandler.m index 32fb34497c..361bf4b592 100644 --- a/packages/react-native-gesture-handler/apple/Handlers/RNPanHandler.m +++ b/packages/react-native-gesture-handler/apple/Handlers/RNPanHandler.m @@ -50,7 +50,7 @@ @implementation RNBetterPanGestureRecognizer { - (id)initWithGestureHandler:(RNGestureHandler *)gestureHandler { - if ((self = [super initWithTarget:gestureHandler action:@selector(handleGesture:fromReset:)])) { + if ((self = [super initWithTarget:gestureHandler action:@selector(handleGesture:)])) { _gestureHandler = gestureHandler; _minDistSq = NAN; _minVelocityX = NAN; @@ -233,7 +233,7 @@ - (void)mouseUp:(NSEvent *)event - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { - [_gestureHandler setCurrentPointerType:event]; + [_gestureHandler setCurrentPointerTypeForEvent:event]; // super call was moved to interactionsBegan method to keep the // original order of calls [self interactionsBegan:touches withEvent:event]; diff --git a/packages/react-native-gesture-handler/apple/Handlers/RNPinchHandler.m b/packages/react-native-gesture-handler/apple/Handlers/RNPinchHandler.m index be535d5b27..489d3f4b9b 100644 --- a/packages/react-native-gesture-handler/apple/Handlers/RNPinchHandler.m +++ b/packages/react-native-gesture-handler/apple/Handlers/RNPinchHandler.m @@ -33,7 +33,7 @@ @implementation RNBetterPinchRecognizer { - (id)initWithGestureHandler:(RNGestureHandler *)gestureHandler { - if ((self = [super initWithTarget:self action:@selector(handleGesture:fromReset:)])) { + if ((self = [super initWithTarget:self action:@selector(handleGesture:)])) { _gestureHandler = gestureHandler; } #if TARGET_OS_OSX @@ -43,7 +43,7 @@ - (id)initWithGestureHandler:(RNGestureHandler *)gestureHandler return self; } -- (void)handleGesture:(UIGestureRecognizer *)recognizer fromReset:(BOOL)fromReset +- (void)handleGesture:(UIGestureRecognizer *)recognizer { if (self.state == UIGestureRecognizerStateBegan) { #if TARGET_OS_OSX @@ -52,7 +52,8 @@ - (void)handleGesture:(UIGestureRecognizer *)recognizer fromReset:(BOOL)fromRese self.scale = 1; #endif } - [_gestureHandler handleGesture:recognizer fromReset:fromReset]; + + [_gestureHandler handleGesture:recognizer fromReset:NO]; } - (void)interactionsBegan:(NSSet *)touches withEvent:(UIEvent *)event @@ -103,7 +104,7 @@ - (void)magnifyWithEvent:(NSEvent *)event #else - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { - [_gestureHandler setCurrentPointerType:event]; + [_gestureHandler setCurrentPointerTypeForEvent:event]; [super touchesBegan:touches withEvent:event]; [self interactionsBegan:touches withEvent:event]; } diff --git a/packages/react-native-gesture-handler/apple/Handlers/RNRotationHandler.m b/packages/react-native-gesture-handler/apple/Handlers/RNRotationHandler.m index 6291d841e0..d03c72fa78 100644 --- a/packages/react-native-gesture-handler/apple/Handlers/RNRotationHandler.m +++ b/packages/react-native-gesture-handler/apple/Handlers/RNRotationHandler.m @@ -31,7 +31,7 @@ @implementation RNBetterRotationRecognizer { - (id)initWithGestureHandler:(RNGestureHandler *)gestureHandler { - if ((self = [super initWithTarget:self action:@selector(handleGesture:fromReset:)])) { + if ((self = [super initWithTarget:self action:@selector(handleGesture:)])) { _gestureHandler = gestureHandler; } #if TARGET_OS_OSX @@ -41,12 +41,12 @@ - (id)initWithGestureHandler:(RNGestureHandler *)gestureHandler return self; } -- (void)handleGesture:(UIGestureRecognizer *)recognizer fromReset:(BOOL)fromReset +- (void)handleGesture:(UIGestureRecognizer *)recognizer { if (self.state == UIGestureRecognizerStateBegan) { self.rotation = 0; } - [_gestureHandler handleGesture:recognizer fromReset:fromReset]; + [_gestureHandler handleGesture:recognizer fromReset:NO]; } - (void)interactionsBegan:(NSSet *)touches withEvent:(UIEvent *)event @@ -97,7 +97,7 @@ - (void)rotateWithEvent:(NSEvent *)event #else - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { - [_gestureHandler setCurrentPointerType:event]; + [_gestureHandler setCurrentPointerTypeForEvent:event]; [super touchesBegan:touches withEvent:event]; [self interactionsBegan:touches withEvent:event]; } diff --git a/packages/react-native-gesture-handler/apple/Handlers/RNTapHandler.m b/packages/react-native-gesture-handler/apple/Handlers/RNTapHandler.m index 5f0d3492a0..eafe7192b3 100644 --- a/packages/react-native-gesture-handler/apple/Handlers/RNTapHandler.m +++ b/packages/react-native-gesture-handler/apple/Handlers/RNTapHandler.m @@ -47,7 +47,7 @@ @implementation RNBetterTapGestureRecognizer { - (id)initWithGestureHandler:(RNGestureHandler *)gestureHandler { - if ((self = [super initWithTarget:gestureHandler action:@selector(handleGesture:fromReset:)])) { + if ((self = [super initWithTarget:gestureHandler action:@selector(handleGesture:)])) { _gestureHandler = gestureHandler; _tapsSoFar = 0; _numberOfTaps = defaultNumberOfTaps; @@ -143,6 +143,8 @@ - (void)interactionsCancelled:(NSSet *)touches withEvent:(UIEvent *)event { [_gestureHandler.pointerTracker touchesCancelled:touches withEvent:event]; self.state = UIGestureRecognizerStateCancelled; + + [self triggerAction]; } #if TARGET_OS_OSX @@ -186,7 +188,7 @@ - (void)rightMouseUp:(NSEvent *)event - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { - [_gestureHandler setCurrentPointerType:event]; + [_gestureHandler setCurrentPointerTypeForEvent:event]; [super touchesBegan:touches withEvent:event]; [self interactionsBegan:touches withEvent:event]; } diff --git a/packages/react-native-gesture-handler/apple/RNGestureHandler.h b/packages/react-native-gesture-handler/apple/RNGestureHandler.h index 750caba184..dd1c470d35 100644 --- a/packages/react-native-gesture-handler/apple/RNGestureHandler.h +++ b/packages/react-native-gesture-handler/apple/RNGestureHandler.h @@ -72,6 +72,7 @@ @property (nonatomic) BOOL shouldCancelWhenOutside; @property (nonatomic) BOOL needsPointerData; @property (nonatomic) BOOL manualActivation; +@property (nonatomic, copy, nullable) NSNumber *viewTag; #if RCT_NEW_ARCH_ENABLED - (BOOL)isViewParagraphComponent:(nullable RNGHUIView *)view; @@ -81,6 +82,7 @@ - (void)unbindFromView; - (void)resetConfig NS_REQUIRES_SUPER; - (void)configure:(nullable NSDictionary *)config NS_REQUIRES_SUPER; +- (void)handleGesture:(nonnull id)recognizer; - (void)handleGesture:(nonnull id)recognizer fromReset:(BOOL)fromReset; - (void)handleGesture:(nonnull id)recognizer inState:(RNGestureHandlerState)state; - (BOOL)containsPointInView; @@ -92,6 +94,7 @@ - (void)sendEventsInState:(RNGestureHandlerState)state forViewWithTag:(nonnull NSNumber *)reactTag withExtraData:(nonnull RNGestureHandlerEventExtraData *)extraData; + - (void)sendEvent:(nonnull RNGestureHandlerStateChange *)event; - (void)sendTouchEventInState:(RNGestureHandlerState)state forViewWithTag:(nonnull NSNumber *)reactTag; - (nullable RNGHUIScrollView *)retrieveScrollView:(nonnull RNGHUIView *)view; @@ -103,7 +106,8 @@ #endif #if !TARGET_OS_OSX -- (void)setCurrentPointerType:(nonnull UIEvent *)event; +- (void)setCurrentPointerType:(RNGestureHandlerPointerType)pointerType; +- (void)setCurrentPointerTypeForEvent:(nonnull UIEvent *)event; #else - (void)setCurrentPointerTypeToMouse; #endif diff --git a/packages/react-native-gesture-handler/apple/RNGestureHandler.mm b/packages/react-native-gesture-handler/apple/RNGestureHandler.mm index c4f760c41a..59e36c2991 100644 --- a/packages/react-native-gesture-handler/apple/RNGestureHandler.mm +++ b/packages/react-native-gesture-handler/apple/RNGestureHandler.mm @@ -184,8 +184,13 @@ - (void)setEnabled:(BOOL)enabled self.recognizer.enabled = enabled; } +- (void)setCurrentPointerType:(RNGestureHandlerPointerType)pointerType +{ + _pointerType = pointerType; +} + #if !TARGET_OS_OSX -- (void)setCurrentPointerType:(UIEvent *)event +- (void)setCurrentPointerTypeForEvent:(UIEvent *)event { UITouch *touch = [[event allTouches] anyObject]; @@ -242,6 +247,8 @@ - (void)bindToView:(RNGHUIView *)view [recognizerView addGestureRecognizer:self.recognizer]; [self bindManualActivationToView:recognizerView]; + + self.viewTag = view.reactTag; } - (void)unbindFromView @@ -249,6 +256,8 @@ - (void)unbindFromView [self.recognizer.view removeGestureRecognizer:self.recognizer]; self.recognizer.delegate = nil; + self.viewTag = nil; + [self unbindManualActivation]; } @@ -280,6 +289,11 @@ - (RNGHUIView *)chooseViewForInteraction:(UIGestureRecognizer *)recognizer #endif } +- (void)handleGesture:(UIGestureRecognizer *)recognizer +{ + [self handleGesture:recognizer fromReset:NO]; +} + - (void)handleGesture:(UIGestureRecognizer *)recognizer fromReset:(BOOL)fromReset { RNGHUIView *view = [self chooseViewForInteraction:recognizer]; diff --git a/packages/react-native-gesture-handler/apple/RNGestureHandlerButtonComponentView.mm b/packages/react-native-gesture-handler/apple/RNGestureHandlerButtonComponentView.mm index 4979bad4da..d6aeed496e 100644 --- a/packages/react-native-gesture-handler/apple/RNGestureHandlerButtonComponentView.mm +++ b/packages/react-native-gesture-handler/apple/RNGestureHandlerButtonComponentView.mm @@ -47,10 +47,12 @@ + (BOOL)shouldBeRecycled #endif // Needed because of this: https://github.com/facebook/react-native/pull/37274 +#ifdef RCT_DYNAMIC_FRAMEWORKS + (void)load { [super load]; } +#endif - (instancetype)initWithFrame:(CGRect)frame { diff --git a/packages/react-native-gesture-handler/apple/RNGestureHandlerEvents.h b/packages/react-native-gesture-handler/apple/RNGestureHandlerEvents.h index 6b7bfa2089..3685d7c09d 100644 --- a/packages/react-native-gesture-handler/apple/RNGestureHandlerEvents.h +++ b/packages/react-native-gesture-handler/apple/RNGestureHandlerEvents.h @@ -52,7 +52,9 @@ withAllPointers:(NSArray *)allPointers withNumberOfTouches:(NSUInteger)numberOfTouches withPointerType:(NSInteger)pointerType; -+ (RNGestureHandlerEventExtraData *)forPointerInside:(BOOL)pointerInside withPointerType:(NSInteger)pointerType; ++ (RNGestureHandlerEventExtraData *)forPointerInside:(BOOL)pointerInside + withNumberOfTouches:(NSUInteger)numberOfTouches + withPointerType:(NSInteger)pointerType; @end @interface RNGestureHandlerEvent : NSObject diff --git a/packages/react-native-gesture-handler/apple/RNGestureHandlerEvents.m b/packages/react-native-gesture-handler/apple/RNGestureHandlerEvents.m index 4d01cf1010..a0c2b5314c 100644 --- a/packages/react-native-gesture-handler/apple/RNGestureHandlerEvents.m +++ b/packages/react-native-gesture-handler/apple/RNGestureHandlerEvents.m @@ -156,10 +156,15 @@ + (RNGestureHandlerEventExtraData *)forEventType:(RNGHTouchEventType)eventType }]; } -+ (RNGestureHandlerEventExtraData *)forPointerInside:(BOOL)pointerInside withPointerType:(NSInteger)pointerType ++ (RNGestureHandlerEventExtraData *)forPointerInside:(BOOL)pointerInside + withNumberOfTouches:(NSUInteger)numberOfTouches + withPointerType:(NSInteger)pointerType { - return [[RNGestureHandlerEventExtraData alloc] - initWithData:@{@"pointerInside" : @(pointerInside), @"pointerType" : @(pointerType)}]; + return [[RNGestureHandlerEventExtraData alloc] initWithData:@{ + @"pointerInside" : @(pointerInside), + @"numberOfPointers" : @(numberOfTouches), + @"pointerType" : @(pointerType) + }]; } @end diff --git a/packages/react-native-gesture-handler/apple/RNGestureHandlerManager.h b/packages/react-native-gesture-handler/apple/RNGestureHandlerManager.h index a191817419..021c893777 100644 --- a/packages/react-native-gesture-handler/apple/RNGestureHandlerManager.h +++ b/packages/react-native-gesture-handler/apple/RNGestureHandlerManager.h @@ -37,4 +37,8 @@ - (nullable RNGestureHandler *)handlerWithTag:(nonnull NSNumber *)handlerTag; +- (nullable RNGHUIView *)viewForReactTag:(nonnull NSNumber *)reactTag; + +- (void)reattachHandlersIfNeeded; + @end diff --git a/packages/react-native-gesture-handler/apple/RNGestureHandlerManager.mm b/packages/react-native-gesture-handler/apple/RNGestureHandlerManager.mm index d0b59b9ee5..335c78f833 100644 --- a/packages/react-native-gesture-handler/apple/RNGestureHandlerManager.mm +++ b/packages/react-native-gesture-handler/apple/RNGestureHandlerManager.mm @@ -180,6 +180,20 @@ - (void)attachGestureHandler:(nonnull NSNumber *)handlerTag } [_attachRetryCounter removeObjectForKey:viewTag]; + [self maybeBindHandler:handlerTag toViewWithTag:viewTag withActionType:actionType]; +} + +// Resolves a view tag to its native UIView (including contentView unwrapping), +// sets reactTag, and binds the gesture handler to it. No-op if the handler is +// already attached to the correct view. +- (void)maybeBindHandler:(nonnull NSNumber *)handlerTag + toViewWithTag:(nonnull NSNumber *)viewTag + withActionType:(RNGestureHandlerActionType)actionType +{ + RNGHUIView *view = [_viewRegistry viewForReactTag:viewTag]; + if (view == nil || view.superview == nil) { + return; + } // I think it should be moved to RNNativeViewHandler, but that would require // additional logic for setting contentView.reactTag, this works for now @@ -190,13 +204,19 @@ - (void)attachGestureHandler:(nonnull NSNumber *)handlerTag } } + RNGestureHandler *handler = [_registry handlerWithTag:handlerTag]; + + // Already attached to the correct native view, nothing to do. + if (handler != nil && handler.recognizer.view == view && handler.actionType == actionType) { + return; + } + view.reactTag = viewTag; // necessary for RNReanimated eventHash (e.g. "42onGestureHandlerEvent"), also will be // returned as event.target #endif // RCT_NEW_ARCH_ENABLED [_registry attachHandlerWithTag:handlerTag toView:view withActionType:actionType]; - // register view if not already there [self registerViewWithGestureRecognizerAttachedIfNeeded:view]; } @@ -236,6 +256,23 @@ - (id)handlerWithTag:(NSNumber *)handlerTag return [_registry handlerWithTag:handlerTag]; } +- (void)reattachHandlersIfNeeded +{ + // Re-bind handlers to their current native views. On Fabric, when a parent view has + // display:none and siblings change, the native UIView backing a component may be recycled + // and replaced. maybeBindHandler is a no-op if the view is nil or unchanged. This is only + // needed for handlers using the old api. + for (RNGestureHandler *handler in _registry.handlers.objectEnumerator) { + if (handler.viewTag == nil) { + continue; + } + + [self maybeBindHandler:handler.tag + toViewWithTag:handler.viewTag + withActionType:handler.actionType]; + } +} + #pragma mark Root Views Management - (void)registerViewWithGestureRecognizerAttachedIfNeeded:(RNGHUIView *)childView @@ -434,4 +471,13 @@ - (void)sendEventForDeviceEvent:(RNGestureHandlerStateChange *)event [_eventDispatcher sendDeviceEventWithName:@"onGestureHandlerStateChange" body:body]; } +- (RNGHUIView *)viewForReactTag:(NSNumber *)reactTag +{ +#ifdef RCT_NEW_ARCH_ENABLED + return [_viewRegistry viewForReactTag:reactTag]; +#else + return [_uiManager viewForReactTag:reactTag]; +#endif // RCT_NEW_ARCH_ENABLED +} + @end diff --git a/packages/react-native-gesture-handler/apple/RNGestureHandlerModule.mm b/packages/react-native-gesture-handler/apple/RNGestureHandlerModule.mm index b5f89946a2..a38f2f133d 100644 --- a/packages/react-native-gesture-handler/apple/RNGestureHandlerModule.mm +++ b/packages/react-native-gesture-handler/apple/RNGestureHandlerModule.mm @@ -214,17 +214,20 @@ - (void)setBridge:(RCTBridge *)bridge // On the new arch we rely on `flushOperations` for scheduling the operations on the UI thread. // On the old arch we rely on `uiManagerWillPerformMounting` #ifdef RCT_NEW_ARCH_ENABLED - if (_operations.count == 0) { - return; + if (_operations.count > 0) { + NSArray *operations = _operations; + _operations = [NSMutableArray new]; + + [self.viewRegistry_DEPRECATED addUIBlock:^(RCTViewRegistry *viewRegistry) { + for (GestureHandlerOperation operation in operations) { + operation(self->_manager); + } + }]; } - NSArray *operations = _operations; - _operations = [NSMutableArray new]; - [self.viewRegistry_DEPRECATED addUIBlock:^(RCTViewRegistry *viewRegistry) { - for (GestureHandlerOperation operation in operations) { - operation(self->_manager); - } + [self->_manager reattachHandlersIfNeeded]; + }]; }]; #endif // RCT_NEW_ARCH_ENABLED } diff --git a/packages/react-native-gesture-handler/apple/RNGestureHandlerRegistry.h b/packages/react-native-gesture-handler/apple/RNGestureHandlerRegistry.h index 5e86c07973..48140af3fc 100644 --- a/packages/react-native-gesture-handler/apple/RNGestureHandlerRegistry.h +++ b/packages/react-native-gesture-handler/apple/RNGestureHandlerRegistry.h @@ -18,4 +18,6 @@ - (void)dropHandlerWithTag:(nonnull NSNumber *)handlerTag; - (void)dropAllHandlers; +@property (nonatomic, readonly, nonnull) NSDictionary *handlers; + @end diff --git a/packages/react-native-gesture-handler/apple/RNGestureHandlerRegistry.m b/packages/react-native-gesture-handler/apple/RNGestureHandlerRegistry.m index 197e0409d6..0438431271 100644 --- a/packages/react-native-gesture-handler/apple/RNGestureHandlerRegistry.m +++ b/packages/react-native-gesture-handler/apple/RNGestureHandlerRegistry.m @@ -22,6 +22,11 @@ - (instancetype)init return self; } +- (NSDictionary *)handlers +{ + return _handlers; +} + - (RNGestureHandler *)handlerWithTag:(NSNumber *)handlerTag { return _handlers[handlerTag]; diff --git a/packages/react-native-gesture-handler/apple/RNManualActivationRecognizer.m b/packages/react-native-gesture-handler/apple/RNManualActivationRecognizer.m index 0b96541f2e..2ecaef6e2e 100644 --- a/packages/react-native-gesture-handler/apple/RNManualActivationRecognizer.m +++ b/packages/react-native-gesture-handler/apple/RNManualActivationRecognizer.m @@ -2,7 +2,7 @@ #import "RNGestureHandler.h" @implementation RNManualActivationRecognizer { - RNGestureHandler *_handler; + __weak RNGestureHandler *_handler; int _activePointers; } diff --git a/packages/react-native-gesture-handler/package.json b/packages/react-native-gesture-handler/package.json index a171342c8d..dcd2e538b8 100644 --- a/packages/react-native-gesture-handler/package.json +++ b/packages/react-native-gesture-handler/package.json @@ -72,6 +72,7 @@ "homepage": "https://docs.swmansion.com/react-native-gesture-handler/", "dependencies": { "@egjs/hammerjs": "^2.0.17", + "@types/react-test-renderer": "^19.1.0", "hoist-non-react-statics": "^3.3.0", "invariant": "^2.2.4" }, @@ -85,7 +86,6 @@ "@types/invariant": "^2.2.37", "@types/jest": "^27.0.3", "@types/react": "^19.2.0", - "@types/react-test-renderer": "^19.1.0", "@typescript-eslint/eslint-plugin": "^6.9.0", "@typescript-eslint/parser": "^6.9.0", "babel-plugin-module-resolver": "^5.0.2", diff --git a/packages/react-native-gesture-handler/src/components/GestureButtonsProps.ts b/packages/react-native-gesture-handler/src/components/GestureButtonsProps.ts index e9504bff32..a04dc8d04f 100644 --- a/packages/react-native-gesture-handler/src/components/GestureButtonsProps.ts +++ b/packages/react-native-gesture-handler/src/components/GestureButtonsProps.ts @@ -15,42 +15,42 @@ export interface RawButtonProps * Defines if more than one button could be pressed simultaneously. By default * set true. */ - exclusive?: boolean; + exclusive?: boolean | undefined; // TODO: we should transform props in `createNativeWrapper` /** * Android only. * * Defines color of native ripple animation used since API level 21. */ - rippleColor?: number | ColorValue | null; + rippleColor?: number | ColorValue | null | undefined; /** * Android only. * * Defines radius of native ripple animation used since API level 21. */ - rippleRadius?: number | null; + rippleRadius?: number | null | undefined; /** * Android only. * * Set this to true if you want the ripple animation to render outside the view bounds. */ - borderless?: boolean; + borderless?: boolean | undefined; /** * Android only. * * Defines whether the ripple animation should be drawn on the foreground of the view. */ - foreground?: boolean; + foreground?: boolean | undefined; /** * Android only. * * Set this to true if you don't want the system to play sound when the button is pressed. */ - touchSoundDisabled?: boolean; + touchSoundDisabled?: boolean | undefined; /** * Style object, use it to set additional styles. @@ -67,31 +67,31 @@ export interface RawButtonProps * @deprecated test-only props are deprecated and will be removed in the future. */ // eslint-disable-next-line @typescript-eslint/ban-types - testOnly_onPress?: Function | null; + testOnly_onPress?: Function | null | undefined; /** * Used for testing-library compatibility, not passed to the native component. * @deprecated test-only props are deprecated and will be removed in the future. */ // eslint-disable-next-line @typescript-eslint/ban-types - testOnly_onPressIn?: Function | null; + testOnly_onPressIn?: Function | null | undefined; /** * Used for testing-library compatibility, not passed to the native component. * @deprecated test-only props are deprecated and will be removed in the future. */ // eslint-disable-next-line @typescript-eslint/ban-types - testOnly_onPressOut?: Function | null; + testOnly_onPressOut?: Function | null | undefined; /** * Used for testing-library compatibility, not passed to the native component. * @deprecated test-only props are deprecated and will be removed in the future. */ // eslint-disable-next-line @typescript-eslint/ban-types - testOnly_onLongPress?: Function | null; + testOnly_onLongPress?: Function | null | undefined; } interface ButtonWithRefProps { - innerRef?: React.ForwardedRef>; + innerRef?: React.ForwardedRef> | undefined; } export interface BaseButtonProps extends RawButtonProps { @@ -99,28 +99,28 @@ export interface BaseButtonProps extends RawButtonProps { * Called when the button gets pressed (analogous to `onPress` in * `TouchableHighlight` from RN core). */ - onPress?: (pointerInside: boolean) => void; + onPress?: ((pointerInside: boolean) => void) | undefined; /** * Called when the button gets pressed and is held for `delayLongPress` * milliseconds. */ - onLongPress?: () => void; + onLongPress?: (() => void) | undefined; /** * Called when button changes from inactive to active and vice versa. It * passes active state as a boolean variable as a first parameter for that * method. */ - onActiveStateChange?: (active: boolean) => void; + onActiveStateChange?: ((active: boolean) => void) | undefined; style?: StyleProp; - testID?: string; + testID?: string | undefined; /** * Delay, in milliseconds, after which the `onLongPress` callback gets called. * Defaults to 600. */ - delayLongPress?: number; + delayLongPress?: number | undefined; } export interface BaseButtonWithRefProps extends BaseButtonProps, @@ -130,14 +130,14 @@ export interface RectButtonProps extends BaseButtonProps { /** * Background color that will be dimmed when button is in active state. */ - underlayColor?: string; + underlayColor?: string | undefined; /** * iOS only. * * Opacity applied to the underlay when button is in active state. */ - activeOpacity?: number; + activeOpacity?: number | undefined; } export interface RectButtonWithRefProps extends RectButtonProps, @@ -149,7 +149,7 @@ export interface BorderlessButtonProps extends BaseButtonProps { * * Opacity applied to the button when it is in an active state. */ - activeOpacity?: number; + activeOpacity?: number | undefined; } export interface BorderlessButtonWithRefProps extends BorderlessButtonProps, diff --git a/packages/react-native-gesture-handler/src/components/Pressable/PressableProps.tsx b/packages/react-native-gesture-handler/src/components/Pressable/PressableProps.tsx index 0a18f75d4c..3f016961db 100644 --- a/packages/react-native-gesture-handler/src/components/Pressable/PressableProps.tsx +++ b/packages/react-native-gesture-handler/src/components/Pressable/PressableProps.tsx @@ -25,7 +25,7 @@ export type InnerPressableEvent = { target: number; timestamp: number; touches: InnerPressableEvent[]; - force?: number; + force?: number | undefined; }; export type PressableEvent = { nativeEvent: InnerPressableEvent }; diff --git a/packages/react-native-gesture-handler/src/components/Text.tsx b/packages/react-native-gesture-handler/src/components/Text.tsx index 8d8bcf2986..02210ce0f3 100644 --- a/packages/react-native-gesture-handler/src/components/Text.tsx +++ b/packages/react-native-gesture-handler/src/components/Text.tsx @@ -1,10 +1,4 @@ -import React, { - ForwardedRef, - forwardRef, - RefObject, - useEffect, - useRef, -} from 'react'; +import React, { ComponentRef, Ref, useEffect, useMemo, useRef } from 'react'; import { Platform, Text as RNText, @@ -14,20 +8,22 @@ import { import { GestureObjects as Gesture } from '../handlers/gestures/gestureObjects'; import { GestureDetector } from '../handlers/gestures/GestureDetector'; -export const Text = forwardRef( - ( - props: RNTextProps, - ref: ForwardedRef> - ) => { - const { onPress, onLongPress, ...rest } = props; +type TextProps = RNTextProps & { + ref?: Ref | null>; +}; +type RNGHTextRef = Ref & { rngh?: boolean }; - const textRef = useRef(null); - const native = Gesture.Native().runOnJS(true); +export const Text = (props: TextProps) => { + const { onPress, onLongPress, ref, ...rest } = props; - const refHandler = (node: any) => { + const textRef = useRef(null); + const native = useMemo(() => Gesture.Native().runOnJS(true), []); + + const refHandler = useMemo(() => { + const handler: RNGHTextRef = (node: RNText | null) => { textRef.current = node; - if (ref === null) { + if (!ref) { return; } @@ -41,37 +37,36 @@ export const Text = forwardRef( // This is a special case for `Text` component. After https://github.com/software-mansion/react-native-gesture-handler/pull/3379 we check for // `displayName` field. However, `Text` from RN has this field set to `Text`, but is also present in `RNSVGElements` set. // We don't want to treat our `Text` as the one from `SVG`, therefore we add special field to ref. - refHandler.rngh = true; - - useEffect(() => { - if (Platform.OS !== 'web') { - return; - } + handler.rngh = true; - const textElement = ref - ? (ref as RefObject>).current - : textRef.current; + return handler; + }, [ref]); - // At this point we are sure that textElement is div in HTML tree - (textElement as unknown as HTMLDivElement)?.setAttribute( - 'rnghtext', - 'true' - ); - }, []); + useEffect(() => { + if (Platform.OS !== 'web') { + return; + } - return onPress || onLongPress ? ( - - - - ) : ( - + // At this point we are sure that textElement is div in HTML tree + (textRef.current as unknown as HTMLDivElement)?.setAttribute( + 'rnghtext', + 'true' ); - } -); + }, []); + + return onPress || onLongPress ? ( + + + + ) : ( + + ); +}; + // eslint-disable-next-line @typescript-eslint/no-redeclare export type Text = typeof Text & RNText; diff --git a/packages/react-native-gesture-handler/src/components/touchables/ExtraButtonProps.ts b/packages/react-native-gesture-handler/src/components/touchables/ExtraButtonProps.ts index 0658560482..73f3ff7048 100644 --- a/packages/react-native-gesture-handler/src/components/touchables/ExtraButtonProps.ts +++ b/packages/react-native-gesture-handler/src/components/touchables/ExtraButtonProps.ts @@ -1,7 +1,7 @@ export type ExtraButtonProps = { - borderless?: boolean; - rippleColor?: number | string | null; - rippleRadius?: number | null; - foreground?: boolean; - exclusive?: boolean; + borderless?: boolean | undefined; + rippleColor?: number | string | null | undefined; + rippleRadius?: number | null | undefined; + foreground?: boolean | undefined; + exclusive?: boolean | undefined; }; diff --git a/packages/react-native-gesture-handler/src/components/touchables/TouchableHighlight.tsx b/packages/react-native-gesture-handler/src/components/touchables/TouchableHighlight.tsx index 384bcc6847..da3d519e52 100644 --- a/packages/react-native-gesture-handler/src/components/touchables/TouchableHighlight.tsx +++ b/packages/react-native-gesture-handler/src/components/touchables/TouchableHighlight.tsx @@ -12,10 +12,10 @@ import { interface State { extraChildStyle: null | { - opacity?: number; + opacity?: number | undefined; }; extraUnderlayStyle: null | { - backgroundColor?: ColorValue; + backgroundColor?: ColorValue | undefined; }; } diff --git a/packages/react-native-gesture-handler/src/handlers/GestureHandlerEventPayload.ts b/packages/react-native-gesture-handler/src/handlers/GestureHandlerEventPayload.ts index a5a3e13c1e..7590b22753 100644 --- a/packages/react-native-gesture-handler/src/handlers/GestureHandlerEventPayload.ts +++ b/packages/react-native-gesture-handler/src/handlers/GestureHandlerEventPayload.ts @@ -129,7 +129,7 @@ export type PanGestureHandlerEventPayload = { /** * Object containing additional stylus data. */ - stylusData?: StylusData; + stylusData?: StylusData | undefined; }; export type PinchGestureHandlerEventPayload = { @@ -225,5 +225,5 @@ export type HoverGestureHandlerEventPayload = { /** * Object containing additional stylus data. */ - stylusData?: StylusData; + stylusData?: StylusData | undefined; }; diff --git a/packages/react-native-gesture-handler/src/handlers/NativeViewGestureHandler.ts b/packages/react-native-gesture-handler/src/handlers/NativeViewGestureHandler.ts index 1271e266d0..e7461f9b9b 100644 --- a/packages/react-native-gesture-handler/src/handlers/NativeViewGestureHandler.ts +++ b/packages/react-native-gesture-handler/src/handlers/NativeViewGestureHandler.ts @@ -17,13 +17,13 @@ export interface NativeViewGestureConfig { * Determines whether the handler should check for an existing touch event on * instantiation. */ - shouldActivateOnStart?: boolean; + shouldActivateOnStart?: boolean | undefined; /** * When `true`, cancels all other gesture handlers when this * `NativeViewGestureHandler` receives an `ACTIVE` state event. */ - disallowInterruption?: boolean; + disallowInterruption?: boolean | undefined; } /** diff --git a/packages/react-native-gesture-handler/src/handlers/gestureHandlerCommon.ts b/packages/react-native-gesture-handler/src/handlers/gestureHandlerCommon.ts index 7ec04b358d..88b0e5ac1f 100644 --- a/packages/react-native-gesture-handler/src/handlers/gestureHandlerCommon.ts +++ b/packages/react-native-gesture-handler/src/handlers/gestureHandlerCommon.ts @@ -63,7 +63,7 @@ export type HitSlop = | Partial< Record< 'left' | 'right' | 'top' | 'bottom' | 'vertical' | 'horizontal', - number + number | undefined > > | Record<'width' | 'left', number> @@ -173,14 +173,14 @@ export type GestureStateChangeEvent< > = HandlerStateChangeEventPayload & GestureStateChangeEventPayloadT; export type CommonGestureConfig = { - enabled?: boolean; - shouldCancelWhenOutside?: boolean; - hitSlop?: HitSlop; - userSelect?: UserSelect; - activeCursor?: ActiveCursor; - mouseButton?: MouseButton; - enableContextMenu?: boolean; - touchAction?: TouchAction; + enabled?: boolean | undefined; + shouldCancelWhenOutside?: boolean | undefined; + hitSlop?: HitSlop | undefined; + userSelect?: UserSelect | undefined; + activeCursor?: ActiveCursor | undefined; + mouseButton?: MouseButton | undefined; + enableContextMenu?: boolean | undefined; + touchAction?: TouchAction | undefined; }; // Events payloads are types instead of interfaces due to TS limitation. @@ -188,24 +188,26 @@ export type CommonGestureConfig = { export type BaseGestureHandlerProps< ExtraEventPayloadT extends Record = Record, > = CommonGestureConfig & { - id?: string; - waitFor?: React.Ref | React.Ref[]; - simultaneousHandlers?: React.Ref | React.Ref[]; - blocksHandlers?: React.Ref | React.Ref[]; - testID?: string; - cancelsTouchesInView?: boolean; + id?: string | undefined; + waitFor?: React.Ref | React.Ref[] | undefined; + simultaneousHandlers?: React.Ref | React.Ref[] | undefined; + blocksHandlers?: React.Ref | React.Ref[] | undefined; + testID?: string | undefined; + cancelsTouchesInView?: boolean | undefined; // TODO(TS) - fix event types - onBegan?: (event: HandlerStateChangeEvent) => void; - onFailed?: (event: HandlerStateChangeEvent) => void; - onCancelled?: (event: HandlerStateChangeEvent) => void; - onActivated?: (event: HandlerStateChangeEvent) => void; - onEnded?: (event: HandlerStateChangeEvent) => void; + onBegan?: ((event: HandlerStateChangeEvent) => void) | undefined; + onFailed?: ((event: HandlerStateChangeEvent) => void) | undefined; + onCancelled?: ((event: HandlerStateChangeEvent) => void) | undefined; + onActivated?: ((event: HandlerStateChangeEvent) => void) | undefined; + onEnded?: ((event: HandlerStateChangeEvent) => void) | undefined; // TODO(TS) consider using NativeSyntheticEvent - onGestureEvent?: (event: GestureEvent) => void; - onHandlerStateChange?: ( - event: HandlerStateChangeEvent - ) => void; + onGestureEvent?: + | ((event: GestureEvent) => void) + | undefined; + onHandlerStateChange?: + | ((event: HandlerStateChangeEvent) => void) + | undefined; // Implicit `children` prop has been removed in @types/react^18.0.0 children?: React.ReactNode; }; diff --git a/packages/react-native-gesture-handler/src/web/interfaces.ts b/packages/react-native-gesture-handler/src/web/interfaces.ts index d2b6391bca..0163dac35e 100644 --- a/packages/react-native-gesture-handler/src/web/interfaces.ts +++ b/packages/react-native-gesture-handler/src/web/interfaces.ts @@ -9,14 +9,14 @@ import { State } from '../State'; import { PointerType } from '../PointerType'; export interface HitSlop { - left?: number; - right?: number; - top?: number; - bottom?: number; - horizontal?: number; - vertical?: number; - width?: number; - height?: number; + left?: number | undefined; + right?: number | undefined; + top?: number | undefined; + bottom?: number | undefined; + horizontal?: number | undefined; + vertical?: number | undefined; + width?: number | undefined; + height?: number | undefined; } export interface Handler { @@ -37,17 +37,17 @@ type ConfigArgs = export interface Config extends Record { enabled: boolean; - simultaneousHandlers?: Handler[] | null; - waitFor?: Handler[] | null; - blocksHandlers?: Handler[] | null; - hitSlop?: HitSlop; - shouldCancelWhenOutside?: boolean; - userSelect?: UserSelect; - activeCursor?: ActiveCursor; - mouseButton?: MouseButton; - enableContextMenu?: boolean; - touchAction?: TouchAction; - manualActivation?: boolean; + simultaneousHandlers?: Handler[] | null | undefined; + waitFor?: Handler[] | null | undefined; + blocksHandlers?: Handler[] | null | undefined; + hitSlop?: HitSlop | undefined; + shouldCancelWhenOutside?: boolean | undefined; + userSelect?: UserSelect | undefined; + activeCursor?: ActiveCursor | undefined; + mouseButton?: MouseButton | undefined; + enableContextMenu?: boolean | undefined; + touchAction?: TouchAction | undefined; + manualActivation?: boolean | undefined; activateAfterLongPress?: number; failOffsetXStart?: number; @@ -88,7 +88,7 @@ interface NativeEvent extends Record { pointerInside: boolean | undefined; handlerTag: number; target: number; - oldState?: State; + oldState?: State | undefined; pointerType: PointerType; } @@ -150,9 +150,9 @@ export interface AdaptedEvent { eventType: EventTypes; pointerType: PointerType; time: number; - button?: MouseButton; - stylusData?: StylusData; - wheelDeltaY?: number; + button?: MouseButton | undefined; + stylusData?: StylusData | undefined; + wheelDeltaY?: number | undefined; } export enum EventTypes { diff --git a/packages/react-native-gesture-handler/tsconfig.json b/packages/react-native-gesture-handler/tsconfig.json index 5eb83bab6f..5d8024ade8 100644 --- a/packages/react-native-gesture-handler/tsconfig.json +++ b/packages/react-native-gesture-handler/tsconfig.json @@ -2,6 +2,7 @@ "extends": "../../tsconfig.json", "compilerOptions": { "outDir": "lib/typescript", + "exactOptionalPropertyTypes": true, "paths": { "react-native-gesture-handler": ["./src"] }