diff --git a/packages/react-native/Libraries/Components/View/ViewPropTypes.js b/packages/react-native/Libraries/Components/View/ViewPropTypes.js index 1a37bd3206b..06672257cc7 100644 --- a/packages/react-native/Libraries/Components/View/ViewPropTypes.js +++ b/packages/react-native/Libraries/Components/View/ViewPropTypes.js @@ -105,6 +105,8 @@ type PointerEventProps = $ReadOnly<{| onPointerOverCapture?: ?(e: PointerEvent) => void, onPointerOut?: ?(e: PointerEvent) => void, onPointerOutCapture?: ?(e: PointerEvent) => void, + onGotPointerCapture?: ?(e: PointerEvent) => void, + onLostPointerCapture?: ?(e: PointerEvent) => void, |}>; type FocusEventProps = $ReadOnly<{| diff --git a/packages/react-native/Libraries/NativeComponent/BaseViewConfig.ios.js b/packages/react-native/Libraries/NativeComponent/BaseViewConfig.ios.js index bb13443bf44..92b2959aad1 100644 --- a/packages/react-native/Libraries/NativeComponent/BaseViewConfig.ios.js +++ b/packages/react-native/Libraries/NativeComponent/BaseViewConfig.ios.js @@ -144,6 +144,18 @@ const bubblingEventTypes = { bubbled: 'onPointerOut', }, }, + topGotPointerCapture: { + phasedRegistrationNames: { + captured: 'onGotPointerCaptureCapture', + bubbled: 'onGotPointerCapture', + }, + }, + topLostPointerCapture: { + phasedRegistrationNames: { + captured: 'onLostPointerCaptureCapture', + bubbled: 'onLostPointerCapture', + }, + }, }; const directEventTypes = { @@ -366,6 +378,8 @@ const validAttributesForEventProps = ConditionallyIgnoredEventHandlers({ onPointerLeave: true, onPointerOver: true, onPointerOut: true, + onGotPointerCapture: true, + onLostPointerCapture: true, }); /** diff --git a/packages/react-native/React/Views/RCTView.h b/packages/react-native/React/Views/RCTView.h index fc5e2217cf5..200d8b451bf 100644 --- a/packages/react-native/React/Views/RCTView.h +++ b/packages/react-native/React/Views/RCTView.h @@ -132,5 +132,7 @@ extern const UIAccessibilityTraits SwitchAccessibilityTrait; @property (nonatomic, assign) RCTCapturingEventBlock onPointerLeave; @property (nonatomic, assign) RCTBubblingEventBlock onPointerOver; @property (nonatomic, assign) RCTBubblingEventBlock onPointerOut; +@property (nonatomic, assign) RCTBubblingEventBlock onGotPointerCapture; +@property (nonatomic, assign) RCTBubblingEventBlock onLostPointerCapture; @end diff --git a/packages/react-native/React/Views/RCTViewManager.m b/packages/react-native/React/Views/RCTViewManager.m index 9a0af4e74ce..eb3ff9c00d8 100644 --- a/packages/react-native/React/Views/RCTViewManager.m +++ b/packages/react-native/React/Views/RCTViewManager.m @@ -549,5 +549,7 @@ RCT_EXPORT_VIEW_PROPERTY(onPointerEnter, RCTCapturingEventBlock) RCT_EXPORT_VIEW_PROPERTY(onPointerLeave, RCTCapturingEventBlock) RCT_EXPORT_VIEW_PROPERTY(onPointerOver, RCTBubblingEventBlock) RCT_EXPORT_VIEW_PROPERTY(onPointerOut, RCTBubblingEventBlock) +RCT_EXPORT_VIEW_PROPERTY(onGotPointerCapture, RCTBubblingEventBlock) +RCT_EXPORT_VIEW_PROPERTY(onLostPointerCapture, RCTBubblingEventBlock) @end diff --git a/packages/react-native/ReactCommon/react/renderer/components/view/TouchEventEmitter.cpp b/packages/react-native/ReactCommon/react/renderer/components/view/TouchEventEmitter.cpp index 747dedcf7dd..d0c4fc399c2 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/view/TouchEventEmitter.cpp +++ b/packages/react-native/ReactCommon/react/renderer/components/view/TouchEventEmitter.cpp @@ -223,4 +223,20 @@ void TouchEventEmitter::onPointerOut(const PointerEvent &event) const { RawEvent::Category::ContinuousStart); } +void TouchEventEmitter::onGotPointerCapture(const PointerEvent &event) const { + dispatchPointerEvent( + "gotPointerCapture", + event, + EventPriority::AsynchronousBatched, + RawEvent::Category::ContinuousStart); +} + +void TouchEventEmitter::onLostPointerCapture(const PointerEvent &event) const { + dispatchPointerEvent( + "lostPointerCapture", + event, + EventPriority::AsynchronousBatched, + RawEvent::Category::ContinuousEnd); +} + } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/components/view/TouchEventEmitter.h b/packages/react-native/ReactCommon/react/renderer/components/view/TouchEventEmitter.h index ad42dfa7674..ef2e11b9548 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/view/TouchEventEmitter.h +++ b/packages/react-native/ReactCommon/react/renderer/components/view/TouchEventEmitter.h @@ -38,6 +38,8 @@ class TouchEventEmitter : public EventEmitter { void onPointerLeave(PointerEvent const &event) const; void onPointerOver(PointerEvent const &event) const; void onPointerOut(PointerEvent const &event) const; + void onGotPointerCapture(PointerEvent const &event) const; + void onLostPointerCapture(PointerEvent const &event) const; private: void dispatchTouchEvent( diff --git a/packages/react-native/ReactCommon/react/renderer/components/view/primitives.h b/packages/react-native/ReactCommon/react/renderer/components/view/primitives.h index 04daf6e3367..70ebe7f2d92 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/view/primitives.h +++ b/packages/react-native/ReactCommon/react/renderer/components/view/primitives.h @@ -60,6 +60,10 @@ struct ViewEvents { PointerOutCapture = 29, Click = 30, ClickCapture = 31, + GotPointerCapture = 32, + GotPointerCaptureCapture = 33, + LostPointerCapture = 34, + LostPointerCaptureCapture = 35, }; constexpr bool operator[](const Offset offset) const { diff --git a/packages/react-native/ReactCommon/react/renderer/components/view/propsConversions.h b/packages/react-native/ReactCommon/react/renderer/components/view/propsConversions.h index 704a00f404c..0139cd25202 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/view/propsConversions.h +++ b/packages/react-native/ReactCommon/react/renderer/components/view/propsConversions.h @@ -616,6 +616,30 @@ static inline ViewEvents convertRawProp( "onClickCapture", sourceValue[Offset::ClickCapture], defaultValue[Offset::ClickCapture]); + result[Offset::GotPointerCapture] = convertRawProp( + context, + rawProps, + "onGotPointerCapture", + sourceValue[Offset::GotPointerCapture], + defaultValue[Offset::GotPointerCapture]); + result[Offset::GotPointerCaptureCapture] = convertRawProp( + context, + rawProps, + "onGotPointerCaptureCapture", + sourceValue[Offset::GotPointerCaptureCapture], + defaultValue[Offset::GotPointerCaptureCapture]); + result[Offset::LostPointerCapture] = convertRawProp( + context, + rawProps, + "onLostPointerCapture", + sourceValue[Offset::LostPointerCapture], + defaultValue[Offset::LostPointerCapture]); + result[Offset::LostPointerCaptureCapture] = convertRawProp( + context, + rawProps, + "onLostPointerCaptureCapture", + sourceValue[Offset::LostPointerCaptureCapture], + defaultValue[Offset::LostPointerCaptureCapture]); // PanResponder callbacks result[Offset::MoveShouldSetResponder] = convertRawProp(