Skip to content

Commit 549b6a7

Browse files
committed
Merge branch 'main' into @mbert/docs-badges
2 parents 0cd3c28 + 560d1b5 commit 549b6a7

14 files changed

Lines changed: 224 additions & 161 deletions

packages/react-native-gesture-handler/apple/RNGestureHandler.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@
8585
@property (nonatomic) BOOL dispatchesReanimatedEvents;
8686
@property (nonatomic, weak, nullable) RNGHUIView *hostDetectorView;
8787
@property (nonatomic, nullable, assign) NSNumber *virtualViewTag;
88+
@property (nonatomic, copy, nullable) NSNumber *viewTag;
8889

8990
- (BOOL)isViewParagraphComponent:(nullable RNGHUIView *)view;
9091
- (nonnull RNGHUIView *)chooseViewForInteraction:(nonnull UIGestureRecognizer *)recognizer;

packages/react-native-gesture-handler/apple/RNGestureHandler.mm

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,8 @@ - (void)bindToView:(RNGHUIView *)view
262262

263263
[recognizerView addGestureRecognizer:self.recognizer];
264264
[self bindManualActivationToView:recognizerView];
265+
266+
self.viewTag = view.reactTag;
265267
}
266268

267269
- (void)unbindFromView
@@ -271,6 +273,7 @@ - (void)unbindFromView
271273

272274
self.hostDetectorView = nil;
273275
self.virtualViewTag = nil;
276+
self.viewTag = nil;
274277

275278
[self unbindManualActivation];
276279
}

packages/react-native-gesture-handler/apple/RNGestureHandlerManager.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,6 @@
4242
- (nullable RNGestureHandler *)handlerWithTag:(nonnull NSNumber *)handlerTag;
4343

4444
- (nullable RNGHUIView *)viewForReactTag:(nonnull NSNumber *)reactTag;
45+
46+
- (void)reattachHandlersIfNeeded;
4547
@end

packages/react-native-gesture-handler/apple/RNGestureHandlerManager.mm

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,21 @@ - (void)attachGestureHandler:(nonnull NSNumber *)handlerTag
171171
}
172172

173173
[_attachRetryCounter removeObjectForKey:viewTag];
174+
[self maybeBindHandler:handlerTag toViewWithTag:viewTag withActionType:actionType withHostDetector:hostDetector];
175+
}
176+
177+
// Resolves a view tag to its native UIView (including contentView unwrapping),
178+
// sets reactTag, and binds the gesture handler to it. No-op if the handler is
179+
// already attached to the correct view.
180+
- (void)maybeBindHandler:(nonnull NSNumber *)handlerTag
181+
toViewWithTag:(nonnull NSNumber *)viewTag
182+
withActionType:(RNGestureHandlerActionType)actionType
183+
withHostDetector:(nullable RNGHUIView *)hostDetector
184+
{
185+
RNGHUIView *view = [_viewRegistry viewForReactTag:viewTag];
186+
if (view == nil || view.superview == nil) {
187+
return;
188+
}
174189

175190
// I think it should be moved to RNNativeViewHandler, but that would require
176191
// additional logic for setting contentView.reactTag, this works for now
@@ -181,12 +196,17 @@ - (void)attachGestureHandler:(nonnull NSNumber *)handlerTag
181196
}
182197
}
183198

199+
RNGestureHandler *handler = [_registry handlerWithTag:handlerTag];
200+
201+
// Already attached to the correct native view, nothing to do.
202+
if (handler != nil && handler.recognizer.view == view && handler.actionType == actionType) {
203+
return;
204+
}
205+
184206
view.reactTag = viewTag; // necessary for RNReanimated eventHash (e.g. "42onGestureHandlerEvent"), also will be
185207
// returned as event.target
186208

187209
[_registry attachHandlerWithTag:handlerTag toView:view withActionType:actionType withHostDetector:hostDetector];
188-
189-
// register view if not already there
190210
[self registerViewWithGestureRecognizerAttachedIfNeeded:view];
191211
}
192212

@@ -224,6 +244,24 @@ - (id)handlerWithTag:(NSNumber *)handlerTag
224244
return [_registry handlerWithTag:handlerTag];
225245
}
226246

247+
- (void)reattachHandlersIfNeeded
248+
{
249+
// Re-bind handlers to their current native views. On Fabric, when a parent view has
250+
// display:none and siblings change, the native UIView backing a component may be recycled
251+
// and replaced. maybeBindHandler is a no-op if the view is nil or unchanged. This is only
252+
// needed for handlers using the old api.
253+
for (RNGestureHandler *handler in _registry.handlers.objectEnumerator) {
254+
if (handler.viewTag == nil || [handler usesNativeOrVirtualDetector]) {
255+
continue;
256+
}
257+
258+
[self maybeBindHandler:handler.tag
259+
toViewWithTag:handler.viewTag
260+
withActionType:handler.actionType
261+
withHostDetector:nil];
262+
}
263+
}
264+
227265
#pragma mark Root Views Management
228266

229267
- (void)registerViewWithGestureRecognizerAttachedIfNeeded:(RNGHUIView *)childView

packages/react-native-gesture-handler/apple/RNGestureHandlerModule.mm

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -171,18 +171,21 @@ - (void)flushOperations
171171
{
172172
// On the new arch we rely on `flushOperations` for scheduling the operations on the UI thread.
173173
// On the old arch we rely on `uiManagerWillPerformMounting`
174-
if (_operations.count == 0) {
175-
return;
176-
}
177-
178174
RNGestureHandlerManager *manager = [RNGestureHandlerModule handlerManagerForModuleId:_moduleId];
179-
NSArray<GestureHandlerOperation> *operations = _operations;
180-
_operations = [NSMutableArray new];
175+
176+
if (_operations.count > 0) {
177+
NSArray<GestureHandlerOperation> *operations = _operations;
178+
_operations = [NSMutableArray new];
179+
180+
[self.viewRegistry_DEPRECATED addUIBlock:^(RCTViewRegistry *viewRegistry) {
181+
for (GestureHandlerOperation operation in operations) {
182+
operation(manager);
183+
}
184+
}];
185+
}
181186

182187
[self.viewRegistry_DEPRECATED addUIBlock:^(RCTViewRegistry *viewRegistry) {
183-
for (GestureHandlerOperation operation in operations) {
184-
operation(manager);
185-
}
188+
[manager reattachHandlersIfNeeded];
186189
}];
187190
}
188191

packages/react-native-gesture-handler/apple/RNGestureHandlerRegistry.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,6 @@
2121
- (void)dropHandlerWithTag:(nonnull NSNumber *)handlerTag;
2222
- (void)dropAllHandlers;
2323

24+
@property (nonatomic, readonly, nonnull) NSDictionary<NSNumber *, RNGestureHandler *> *handlers;
25+
2426
@end

packages/react-native-gesture-handler/apple/RNGestureHandlerRegistry.m

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@ - (instancetype)init
2222
return self;
2323
}
2424

25+
- (NSDictionary<NSNumber *, RNGestureHandler *> *)handlers
26+
{
27+
return _handlers;
28+
}
29+
2530
- (RNGestureHandler *)handlerWithTag:(NSNumber *)handlerTag
2631
{
2732
return _handlers[handlerTag];

packages/react-native-gesture-handler/src/components/GestureHandlerButton.tsx

Lines changed: 101 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,110 @@
1-
import { HostComponent, StyleSheet, View } from 'react-native';
2-
import type { RawButtonProps } from '../v3/components/GestureButtonsProps';
1+
import {
2+
AccessibilityProps,
3+
ColorValue,
4+
HostComponent,
5+
LayoutChangeEvent,
6+
StyleProp,
7+
StyleSheet,
8+
View,
9+
ViewProps,
10+
ViewStyle,
11+
} from 'react-native';
312
import RNGestureHandlerButtonNativeComponent from '../specs/RNGestureHandlerButtonNativeComponent';
413
import RNGestureHandlerButtonWrapperNativeComponent from '../specs/RNGestureHandlerButtonWrapperNativeComponent';
514
import { useMemo } from 'react';
615

16+
export interface ButtonProps extends ViewProps, AccessibilityProps {
17+
children?: React.ReactNode;
18+
19+
/**
20+
* Defines if buttons should respond to touches. By default set to true.
21+
*/
22+
enabled?: boolean;
23+
24+
/**
25+
* Defines if more than one button could be pressed simultaneously. By default
26+
* set true.
27+
*/
28+
exclusive?: boolean;
29+
30+
/**
31+
* Android only.
32+
*
33+
* Defines color of native ripple animation used since API level 21.
34+
*/
35+
rippleColor?: number | ColorValue | null;
36+
37+
/**
38+
* Android only.
39+
*
40+
* Defines radius of native ripple animation used since API level 21.
41+
*/
42+
rippleRadius?: number | null;
43+
44+
/**
45+
* Android only.
46+
*
47+
* Set this to true if you want the ripple animation to render outside the view bounds.
48+
*/
49+
borderless?: boolean;
50+
51+
/**
52+
* Android only.
53+
*
54+
* Defines whether the ripple animation should be drawn on the foreground of the view.
55+
*/
56+
foreground?: boolean;
57+
58+
/**
59+
* Android only.
60+
*
61+
* Set this to true if you don't want the system to play sound when the button is pressed.
62+
*/
63+
touchSoundDisabled?: boolean;
64+
65+
/**
66+
* Style object, use it to set additional styles.
67+
*/
68+
style?: StyleProp<ViewStyle>;
69+
70+
/**
71+
* Invoked on mount and layout changes.
72+
*/
73+
onLayout?: (event: LayoutChangeEvent) => void;
74+
75+
/**
76+
* Used for testing-library compatibility, not passed to the native component.
77+
* @deprecated test-only props are deprecated and will be removed in the future.
78+
*/
79+
// eslint-disable-next-line @typescript-eslint/ban-types
80+
testOnly_onPress?: Function | null;
81+
82+
/**
83+
* Used for testing-library compatibility, not passed to the native component.
84+
* @deprecated test-only props are deprecated and will be removed in the future.
85+
*/
86+
// eslint-disable-next-line @typescript-eslint/ban-types
87+
testOnly_onPressIn?: Function | null;
88+
89+
/**
90+
* Used for testing-library compatibility, not passed to the native component.
91+
* @deprecated test-only props are deprecated and will be removed in the future.
92+
*/
93+
// eslint-disable-next-line @typescript-eslint/ban-types
94+
testOnly_onPressOut?: Function | null;
95+
96+
/**
97+
* Used for testing-library compatibility, not passed to the native component.
98+
* @deprecated test-only props are deprecated and will be removed in the future.
99+
*/
100+
// eslint-disable-next-line @typescript-eslint/ban-types
101+
testOnly_onLongPress?: Function | null;
102+
}
103+
7104
const ButtonComponent =
8-
RNGestureHandlerButtonNativeComponent as HostComponent<RawButtonProps>;
105+
RNGestureHandlerButtonNativeComponent as HostComponent<ButtonProps>;
9106

10-
export default function GestureHandlerButton({
11-
style,
12-
...rest
13-
}: RawButtonProps) {
107+
export default function GestureHandlerButton({ style, ...rest }: ButtonProps) {
14108
const flattenedStyle = useMemo(() => StyleSheet.flatten(style), [style]);
15109

16110
const {

0 commit comments

Comments
 (0)