Skip to content

Commit 721a5aa

Browse files
authored
feat: Add onDoubleClick event handler (#2731)
## Summary: Cherry pick another change from #2117 around Fabric We actually already had this prop in Paper, but I had removed it in one RNM upgrade. It turns out that onPress / pointer events don't expose a "count" property, so there isnt' an easy way to listen to double click. Adding this back + changes to add to Fabric. ## Test Plan: Event fires in Pressable Feedback example
1 parent 9c6efe8 commit 721a5aa

File tree

15 files changed

+138
-81
lines changed

15 files changed

+138
-81
lines changed

packages/react-native/Libraries/Components/View/ReactNativeViewAttributes.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ const UIView = {
4646
focusable: true,
4747
onMouseEnter: true,
4848
onMouseLeave: true,
49+
onDoubleClick: true,
4950
onDragEnter: true,
5051
onDragLeave: true,
5152
onDrop: true,

packages/react-native/Libraries/Components/View/ViewPropTypes.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ export interface ViewPropsMacOS {
119119
enableFocusRing?: boolean | undefined;
120120
onMouseEnter?: ((event: MouseEvent) => void) | undefined;
121121
onMouseLeave?: ((event: MouseEvent) => void) | undefined;
122+
onDoubleClick?: ((event: MouseEvent) => void) | undefined;
122123
onDragEnter?: ((event: DragEvent) => void) | undefined;
123124
onDragLeave?: ((event: DragEvent) => void) | undefined;
124125
onDrop?: ((event: DragEvent) => void) | undefined;

packages/react-native/Libraries/Components/View/ViewPropTypes.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ export type KeyboardEventProps = $ReadOnly<{|
127127
type MouseEventProps = $ReadOnly<{
128128
onMouseEnter?: ?(event: MouseEvent) => void,
129129
onMouseLeave?: ?(event: MouseEvent) => void,
130+
onDoubleClick?: ?(event: MouseEvent) => void, // [macOS]
130131
}>;
131132

132133
// Experimental/Work in Progress Pointer Event Callbacks (not yet ready for use)

packages/react-native/Libraries/NativeComponent/BaseViewConfig.macos.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ const bubblingEventTypes = {
3434

3535
const directEventTypes = {
3636
...PlatformBaseViewConfigIos.directEventTypes,
37+
topDoubleClick: {
38+
registrationName: 'onDoubleClick',
39+
},
3740
topDragEnter: {
3841
registrationName: 'onDragEnter',
3942
},
@@ -68,6 +71,7 @@ const validAttributesForNonEventProps = {
6871
// Props for bubbling and direct events
6972
const validAttributesForEventProps = ConditionallyIgnoredEventHandlers({
7073
onBlur: true,
74+
onDoubleClick: true,
7175
onDragEnter: true,
7276
onDragLeave: true,
7377
onDrop: true,

packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3866,6 +3866,7 @@ exports[`public API should not change unintentionally Libraries/Components/View/
38663866
focusable: true,
38673867
onMouseEnter: true,
38683868
onMouseLeave: true,
3869+
onDoubleClick: true,
38693870
onDragEnter: true,
38703871
onDragLeave: true,
38713872
onDrop: true,
@@ -4106,6 +4107,7 @@ export type KeyboardEventProps = $ReadOnly<{|
41064107
type MouseEventProps = $ReadOnly<{
41074108
onMouseEnter?: ?(event: MouseEvent) => void,
41084109
onMouseLeave?: ?(event: MouseEvent) => void,
4110+
onDoubleClick?: ?(event: MouseEvent) => void,
41094111
}>;
41104112
type PointerEventProps = $ReadOnly<{
41114113
onClick?: ?(event: PointerEvent) => void,

packages/react-native/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1905,7 +1905,14 @@ - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
19051905

19061906
#pragma mark - Mouse Events
19071907

1908-
- (void)emitMouseEvent {
1908+
enum MouseEventType {
1909+
MouseEnter,
1910+
MouseLeave,
1911+
DoubleClick,
1912+
};
1913+
1914+
- (void)emitMouseEvent:(MouseEventType)eventType
1915+
{
19091916
if (!_eventEmitter) {
19101917
return;
19111918
}
@@ -1926,10 +1933,18 @@ - (void)emitMouseEvent {
19261933
.metaKey = static_cast<bool>(modifierFlags & NSEventModifierFlagCommand),
19271934
};
19281935

1929-
if (_hasMouseOver) {
1930-
_eventEmitter->onMouseEnter(mouseEvent);
1931-
} else {
1932-
_eventEmitter->onMouseLeave(mouseEvent);
1936+
switch (eventType) {
1937+
case MouseEnter:
1938+
_eventEmitter->onMouseEnter(mouseEvent);
1939+
break;
1940+
1941+
case MouseLeave:
1942+
_eventEmitter->onMouseLeave(mouseEvent);
1943+
break;
1944+
1945+
case DoubleClick:
1946+
_eventEmitter->onDoubleClick(mouseEvent);
1947+
break;
19331948
}
19341949
}
19351950

@@ -1958,7 +1973,7 @@ - (void)updateMouseOverIfNeeded
19581973

19591974
if (hasMouseOver != _hasMouseOver) {
19601975
_hasMouseOver = hasMouseOver;
1961-
[self emitMouseEvent];
1976+
[self emitMouseEvent:hasMouseOver ? MouseEnter : MouseLeave];
19621977
}
19631978
}
19641979

@@ -2031,7 +2046,7 @@ - (void)mouseEntered:(NSEvent *)event
20312046
}
20322047

20332048
_hasMouseOver = YES;
2034-
[self emitMouseEvent];
2049+
[self emitMouseEvent:MouseEnter];
20352050
}
20362051

20372052
- (void)mouseExited:(NSEvent *)event
@@ -2041,7 +2056,17 @@ - (void)mouseExited:(NSEvent *)event
20412056
}
20422057

20432058
_hasMouseOver = NO;
2044-
[self emitMouseEvent];
2059+
[self emitMouseEvent:MouseLeave];
2060+
}
2061+
2062+
- (void)mouseUp:(NSEvent *)event
2063+
{
2064+
BOOL hasDoubleClickEventHandler = _props->hostPlatformEvents[HostPlatformViewEvents::Offset::DoubleClick];
2065+
if (hasDoubleClickEventHandler && event.clickCount == 2) {
2066+
[self emitMouseEvent :DoubleClick];
2067+
} else {
2068+
[super mouseUp:event];
2069+
}
20452070
}
20462071
#endif // macOS]
20472072

packages/react-native/React/Views/RCTView.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ extern const UIAccessibilityTraits SwitchAccessibilityTrait;
174174
@property (nonatomic, copy) RCTDirectEventBlock onDragEnter;
175175
@property (nonatomic, copy) RCTDirectEventBlock onDragLeave;
176176
@property (nonatomic, copy) RCTDirectEventBlock onDrop;
177+
@property (nonatomic, copy) RCTDirectEventBlock onDoubleClick;
177178

178179
// Keyboarding events
179180
// NOTE does not properly work with single line text inputs (most key downs). This is because those are

packages/react-native/React/Views/RCTView.m

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1552,6 +1552,15 @@ - (void)mouseExited:(NSEvent *)event
15521552
additionalData:nil];
15531553
}
15541554

1555+
- (void)mouseUp:(NSEvent *)event
1556+
{
1557+
if (_onDoubleClick && event.clickCount == 2){
1558+
_onDoubleClick(nil);
1559+
} else {
1560+
[super mouseUp:event];
1561+
}
1562+
}
1563+
15551564
- (BOOL)mouseDownCanMoveWindow
15561565
{
15571566
return _mouseDownCanMoveWindow;

packages/react-native/React/Views/RCTViewManager.m

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -641,6 +641,7 @@ - (void) updateAccessibilityRole:(RCTView *)view withDefaultView:(RCTView *)defa
641641
RCT_EXPORT_VIEW_PROPERTY(onFocus, RCTBubblingEventBlock)
642642
RCT_EXPORT_VIEW_PROPERTY(onBlur, RCTBubblingEventBlock)
643643

644+
RCT_EXPORT_VIEW_PROPERTY(onDoubleClick, RCTDirectEventBlock)
644645
RCT_EXPORT_VIEW_PROPERTY(onMouseEnter, RCTDirectEventBlock)
645646
RCT_EXPORT_VIEW_PROPERTY(onMouseLeave, RCTDirectEventBlock)
646647
RCT_EXPORT_VIEW_PROPERTY(onDragEnter, RCTDirectEventBlock)

packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/HostPlatformViewEventEmitter.cpp

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -67,17 +67,23 @@ static jsi::Object mouseEventPayload(jsi::Runtime& runtime, const MouseEvent& ev
6767
};
6868

6969
void HostPlatformViewEventEmitter::onMouseEnter(const MouseEvent& mouseEvent) const {
70-
dispatchEvent("mouseEnter", [mouseEvent](jsi::Runtime &runtime) {
70+
dispatchEvent("mouseEnter", [mouseEvent](jsi::Runtime& runtime) {
7171
return mouseEventPayload(runtime, mouseEvent);
7272
});
7373
}
7474

7575
void HostPlatformViewEventEmitter::onMouseLeave(const MouseEvent& mouseEvent) const {
76-
dispatchEvent("mouseLeave", [mouseEvent](jsi::Runtime &runtime) {
76+
dispatchEvent("mouseLeave", [mouseEvent](jsi::Runtime& runtime) {
7777
return mouseEventPayload(runtime, mouseEvent);
7878
});
7979
}
8080

81+
void HostPlatformViewEventEmitter::onDoubleClick(const MouseEvent& mouseEvent) const {
82+
dispatchEvent("doubleClick", [mouseEvent](jsi::Runtime& runtime) {
83+
return mouseEventPayload(runtime, mouseEvent);
84+
});
85+
}
86+
8187
#pragma mark - Drag and Drop Events
8288

8389
jsi::Value HostPlatformViewEventEmitter::dataTransferPayload(
@@ -170,20 +176,20 @@ static jsi::Value dragEventPayload(
170176
return payload;
171177
}
172178

173-
void HostPlatformViewEventEmitter::onDragEnter(DragEvent const& dragEvent) const {
174-
dispatchEvent("dragEnter", [dragEvent](jsi::Runtime &runtime) {
179+
void HostPlatformViewEventEmitter::onDragEnter(const DragEvent& dragEvent) const {
180+
dispatchEvent("dragEnter", [dragEvent](jsi::Runtime& runtime) {
175181
return dragEventPayload(runtime, dragEvent);
176182
});
177183
}
178184

179-
void HostPlatformViewEventEmitter::onDragLeave(DragEvent const& dragEvent) const {
180-
dispatchEvent("dragLeave", [dragEvent](jsi::Runtime &runtime) {
185+
void HostPlatformViewEventEmitter::onDragLeave(const DragEvent& dragEvent) const {
186+
dispatchEvent("dragLeave", [dragEvent](jsi::Runtime& runtime) {
181187
return dragEventPayload(runtime, dragEvent);
182188
});
183189
}
184190

185-
void HostPlatformViewEventEmitter::onDrop(DragEvent const& dragEvent) const {
186-
dispatchEvent("drop", [dragEvent](jsi::Runtime &runtime) {
191+
void HostPlatformViewEventEmitter::onDrop(const DragEvent& dragEvent) const {
192+
dispatchEvent("drop", [dragEvent](jsi::Runtime& runtime) {
187193
return dragEventPayload(runtime, dragEvent);
188194
});
189195
}

0 commit comments

Comments
 (0)