Skip to content

Commit

Permalink
Merge branch 'main' into @latekvo/clean-project-packages
Browse files Browse the repository at this point in the history
  • Loading branch information
latekvo committed Feb 10, 2025
2 parents 7eb6639 + 03be039 commit 7303e65
Show file tree
Hide file tree
Showing 24 changed files with 143 additions and 59 deletions.
4 changes: 2 additions & 2 deletions FabricExample/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1499,7 +1499,7 @@ PODS:
- React-logger (= 0.77.0)
- React-perflogger (= 0.77.0)
- React-utils (= 0.77.0)
- RNGestureHandler (2.22.1):
- RNGestureHandler (2.23.1):
- DoubleConversion
- glog
- hermes-engine
Expand Down Expand Up @@ -1801,7 +1801,7 @@ SPEC CHECKSUMS:
ReactAppDependencyProvider: 6e8d68583f39dc31ee65235110287277eb8556ef
ReactCodegen: c08a5113d9c9c895fe10f3c296f74c6b705a60a9
ReactCommon: 1bd2dc684d7992acbf0dfee887b89a57a1ead86d
RNGestureHandler: ab7b3143904577382d4e93f6d35d52f321660db6
RNGestureHandler: 93014de1ee4e1d539a74c6ce7aea72edd1fff6e0
SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748
Yoga: 78d74e245ed67bb94275a1316cdc170b9b7fe884

Expand Down
4 changes: 2 additions & 2 deletions MacOSExample/macos/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1166,7 +1166,7 @@ PODS:
- React-utils (= 0.74.6)
- RNCAsyncStorage (1.24.0):
- React-Core
- RNGestureHandler (2.22.1):
- RNGestureHandler (2.23.1):
- DoubleConversion
- glog
- hermes-engine
Expand Down Expand Up @@ -1496,7 +1496,7 @@ SPEC CHECKSUMS:
React-utils: d1f30e28b14bea6aa6b009be03ab502bbf2cf5c6
ReactCommon: 68cae4af53cf2d34e6a26c0099f434f170495dd1
RNCAsyncStorage: ec53e44dc3e75b44aa2a9f37618a49c3bc080a7a
RNGestureHandler: ae092c8f9da8d2c0f47257caadc8eadebd03fa90
RNGestureHandler: 006e7ebf1a3d37843d951031389fb12712c7dd8e
RNReanimated: 45553a3ae29a75a76269595f8554d07d4090e392
RNSVG: 4590aa95758149fa27c5c83e54a6a466349a1688
SocketRocket: f6c6249082c011e6de2de60ed641ef8bbe0cfac9
Expand Down
8 changes: 8 additions & 0 deletions RNGestureHandler.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,12 @@ Pod::Spec.new do |s|
else
s.dependency "React-Core"
end

if ENV['USE_FRAMEWORKS'] != nil && ENV['RCT_NEW_ARCH_ENABLED'] == '1'
add_dependency(s, "React-FabricComponents", :additional_framework_paths => [
"react/renderer/textlayoutmanager/platform/ios",
"react/renderer/components/textinput/platform/ios",
])
end

end
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,15 @@ class RNGestureHandlerButtonViewManager : ViewGroupManager<ButtonViewGroup>(), R
val eventTime = event.eventTime
val action = event.action

if (touchResponder != null && touchResponder !== this && touchResponder!!.exclusive) {
if (isPressed) {
setPressed(false)
}
lastEventTime = eventTime
lastAction = action
return false
}

if (event.action == MotionEvent.ACTION_CANCEL) {
tryFreeingResponder()
}
Expand Down
31 changes: 19 additions & 12 deletions android/src/main/jni/cpp-adapter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ using namespace facebook;
using namespace react;

void decorateRuntime(jsi::Runtime &runtime) {
auto isFormsStackingContext = jsi::Function::createFromHostFunction(
auto isViewFlatteningDisabled = jsi::Function::createFromHostFunction(
runtime,
jsi::PropNameID::forAscii(runtime, "isFormsStackingContext"),
jsi::PropNameID::forAscii(runtime, "isViewFlatteningDisabled"),
1,
[](jsi::Runtime &runtime,
const jsi::Value &thisValue,
Expand All @@ -20,21 +20,28 @@ void decorateRuntime(jsi::Runtime &runtime) {
}

auto shadowNode = shadowNodeFromValue(runtime, arguments[0]);
bool isFormsStackingContext = shadowNode->getTraits().check(ShadowNodeTraits::FormsStackingContext);
bool isViewFlatteningDisabled = shadowNode->getTraits().check(
ShadowNodeTraits::FormsStackingContext);

return jsi::Value(isFormsStackingContext);
// This is done using component names instead of type checking because
// of duplicate symbols for RN types, which prevent RTTI from working.
const char *componentName = shadowNode->getComponentName();
bool isTextComponent = strcmp(componentName, "Paragraph") == 0 ||
strcmp(componentName, "Text") == 0;

return jsi::Value(isViewFlatteningDisabled || isTextComponent);
});
runtime.global().setProperty(
runtime, "isFormsStackingContext", std::move(isFormsStackingContext));
runtime, "isViewFlatteningDisabled", std::move(isViewFlatteningDisabled));
}

extern "C" JNIEXPORT void JNICALL
Java_com_swmansion_gesturehandler_react_RNGestureHandlerModule_decorateRuntime(
JNIEnv *env,
jobject clazz,
jlong jsiPtr) {
jsi::Runtime *runtime = reinterpret_cast<jsi::Runtime *>(jsiPtr);
if (runtime) {
decorateRuntime(*runtime);
}
JNIEnv *env,
jobject clazz,
jlong jsiPtr) {
jsi::Runtime *runtime = reinterpret_cast<jsi::Runtime *>(jsiPtr);
if (runtime) {
decorateRuntime(*runtime);
}
}
14 changes: 12 additions & 2 deletions apple/RNGestureHandlerButton.mm
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,20 @@ - (BOOL)shouldHandleTouch:(RNGHUIView *)view
return button.userEnabled;
}

// Certain subviews such as RCTViewComponentView have been observed to have disabled
// accessibility gesture recognizers such as _UIAccessibilityHUDGateGestureRecognizer,
// ostensibly set by iOS. Such gesture recognizers cause this function to return YES
// even when the passed view is static text and does not respond to touches. This in
// turn prevents the button from receiving touches, breaking functionality. To handle
// such case, we can count only the enabled gesture recognizers when determining
// whether a view should receive touches.
NSPredicate *isEnabledPredicate = [NSPredicate predicateWithFormat:@"isEnabled == YES"];
NSArray *enabledGestureRecognizers = [view.gestureRecognizers filteredArrayUsingPredicate:isEnabledPredicate];

#if !TARGET_OS_OSX
return [view isKindOfClass:[UIControl class]] || [view.gestureRecognizers count] > 0;
return [view isKindOfClass:[UIControl class]] || [enabledGestureRecognizers count] > 0;
#else
return [view isKindOfClass:[NSControl class]] || [view.gestureRecognizers count] > 0;
return [view isKindOfClass:[NSControl class]] || [enabledGestureRecognizers count] > 0;
#endif
}

Expand Down
22 changes: 17 additions & 5 deletions apple/RNGestureHandlerModule.mm
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
#import <ReactCommon/CallInvoker.h>
#import <ReactCommon/RCTTurboModule.h>

#import <react/renderer/components/text/ParagraphShadowNode.h>
#import <react/renderer/components/text/TextShadowNode.h>
#import <react/renderer/uimanager/primitives.h>
#endif // RCT_NEW_ARCH_ENABLED

Expand Down Expand Up @@ -91,19 +93,29 @@ - (dispatch_queue_t)methodQueue
#ifdef RCT_NEW_ARCH_ENABLED
void decorateRuntime(jsi::Runtime &runtime)
{
auto isFormsStackingContext = jsi::Function::createFromHostFunction(
auto isViewFlatteningDisabled = jsi::Function::createFromHostFunction(
runtime,
jsi::PropNameID::forAscii(runtime, "isFormsStackingContext"),
jsi::PropNameID::forAscii(runtime, "isViewFlatteningDisabled"),
1,
[](jsi::Runtime &runtime, const jsi::Value &thisValue, const jsi::Value *arguments, size_t count) -> jsi::Value {
if (!arguments[0].isObject()) {
return jsi::Value::null();
}
auto shadowNode = shadowNodeFromValue(runtime, arguments[0]);
bool isFormsStackingContext = shadowNode->getTraits().check(ShadowNodeTraits::FormsStackingContext);
return jsi::Value(isFormsStackingContext);

if (dynamic_pointer_cast<const ParagraphShadowNode>(shadowNode)) {
return jsi::Value(true);
}

if (dynamic_pointer_cast<const TextShadowNode>(shadowNode)) {
return jsi::Value(true);
}

bool isViewFlatteningDisabled = shadowNode->getTraits().check(ShadowNodeTraits::FormsStackingContext);

return jsi::Value(isViewFlatteningDisabled);
});
runtime.global().setProperty(runtime, "isFormsStackingContext", std::move(isFormsStackingContext));
runtime.global().setProperty(runtime, "isViewFlatteningDisabled", std::move(isViewFlatteningDisabled));
}
#endif // RCT_NEW_ARCH_ENABLED

Expand Down
2 changes: 1 addition & 1 deletion docs/docs/components/touchables.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ sidebar_label: Touchables
---

:::warning
Touchables will be removed in the future version of Gesture Handler.
Touchables will be removed in the future version of Gesture Handler. Use Pressable instead.
:::

Gesture Handler library provides an implementation of RN's touchable components that are based on [native buttons](buttons.mdx) and does not rely on JS responder system utilized by RN. Our touchable implementation follows the same API and aims to be a drop-in replacement for touchables available in React Native.
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-native-gesture-handler",
"version": "2.22.1",
"version": "2.23.1",
"description": "Declarative API exposing native platform touch and gesture system to React Native",
"scripts": {
"prepare": "bob build && husky install",
Expand Down
15 changes: 13 additions & 2 deletions src/components/GestureButtons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,15 @@ import type {
BorderlessButtonWithRefProps,
BorderlessButtonProps,
} from './GestureButtonsProps';
import { isFabric } from '../utils';

export const RawButton = createNativeWrapper(GestureHandlerButton, {
shouldCancelWhenOutside: false,
shouldActivateOnStart: false,
});

let IS_FABRIC: null | boolean = null;

class InnerBaseButton extends React.Component<BaseButtonWithRefProps> {
static defaultProps = {
delayLongPress: 600,
Expand Down Expand Up @@ -120,12 +123,20 @@ class InnerBaseButton extends React.Component<BaseButtonWithRefProps> {
};

render() {
const { rippleColor, style, ...rest } = this.props;
const { rippleColor: unprocessedRippleColor, style, ...rest } = this.props;

if (IS_FABRIC === null) {
IS_FABRIC = isFabric();
}

const rippleColor = IS_FABRIC
? unprocessedRippleColor
: processColor(unprocessedRippleColor ?? undefined);

return (
<RawButton
ref={this.props.innerRef}
rippleColor={processColor(rippleColor)}
rippleColor={rippleColor}
style={[style, Platform.OS === 'ios' && { cursor: undefined }]}
{...rest}
onGestureEvent={this.onGestureEvent}
Expand Down
9 changes: 7 additions & 2 deletions src/components/GestureButtonsProps.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import * as React from 'react';
import { AccessibilityProps, StyleProp, ViewStyle } from 'react-native';
import {
AccessibilityProps,
ColorValue,
StyleProp,
ViewStyle,
} from 'react-native';
import type { NativeViewGestureHandlerProps } from '../handlers/NativeViewGestureHandler';

export interface RawButtonProps
Expand All @@ -16,7 +21,7 @@ export interface RawButtonProps
*
* Defines color of native ripple animation used since API level 21.
*/
rippleColor?: any; // it was present in BaseButtonProps before but is used here in code
rippleColor?: number | ColorValue | null;

/**
* Android only.
Expand Down
20 changes: 16 additions & 4 deletions src/components/Pressable/Pressable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,13 @@ import {
} from './utils';
import { PressabilityDebugView } from '../../handlers/PressabilityDebugView';
import { GestureTouchEvent } from '../../handlers/gestureHandlerCommon';
import { INT32_MAX, isTestEnv } from '../../utils';
import { INT32_MAX, isFabric, isTestEnv } from '../../utils';

const DEFAULT_LONG_PRESS_DURATION = 500;
const IS_TEST_ENV = isTestEnv();

let IS_FABRIC: null | boolean = null;

export default function Pressable(props: PressableProps) {
const {
testOnly_pressed,
Expand Down Expand Up @@ -367,8 +369,6 @@ export default function Pressable(props: PressableProps) {

const gesture = Gesture.Simultaneous(...gestures);

const defaultRippleColor = android_ripple ? undefined : 'transparent';

// `cursor: 'pointer'` on `RNButton` crashes iOS
const pointerStyle: StyleProp<ViewStyle> =
Platform.OS === 'web' ? { cursor: 'pointer' } : {};
Expand All @@ -381,6 +381,18 @@ export default function Pressable(props: PressableProps) {
? children({ pressed: pressedState })
: children;

const rippleColor = useMemo(() => {
if (IS_FABRIC === null) {
IS_FABRIC = isFabric();
}

const defaultRippleColor = android_ripple ? undefined : 'transparent';
const unprocessedRippleColor = android_ripple?.color ?? defaultRippleColor;
return IS_FABRIC
? unprocessedRippleColor
: processColor(unprocessedRippleColor);
}, [android_ripple]);

return (
<GestureDetector gesture={gesture}>
<NativeButton
Expand All @@ -389,7 +401,7 @@ export default function Pressable(props: PressableProps) {
hitSlop={appliedHitSlop}
enabled={isPressableEnabled}
touchSoundDisabled={android_disableSound ?? undefined}
rippleColor={processColor(android_ripple?.color ?? defaultRippleColor)}
rippleColor={rippleColor}
rippleRadius={android_ripple?.radius ?? undefined}
style={[pointerStyle, styleProp]}
testOnly_onPress={IS_TEST_ENV ? onPress : undefined}
Expand Down
15 changes: 4 additions & 11 deletions src/components/Pressable/PressableProps.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,15 @@
import {
ColorValue,
AccessibilityProps,
ViewProps,
Insets,
StyleProp,
ViewStyle,
PressableStateCallbackType as RNPressableStateCallbackType,
PressableAndroidRippleConfig as RNPressableAndroidRippleConfig,
} from 'react-native';

export interface PressableStateCallbackType {
readonly pressed: boolean;
}

export interface PressableAndroidRippleConfig {
color?: null | ColorValue | undefined;
borderless?: null | boolean | undefined;
radius?: null | number | undefined;
foreground?: null | boolean | undefined;
}
export type PressableStateCallbackType = RNPressableStateCallbackType;
export type PressableAndroidRippleConfig = RNPressableAndroidRippleConfig;

export type InnerPressableEvent = {
changedTouches: InnerPressableEvent[];
Expand Down
5 changes: 4 additions & 1 deletion src/components/Pressable/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
export type { PressableProps } from './PressableProps';
export type {
PressableProps,
PressableStateCallbackType,
} from './PressableProps';
export { default } from './Pressable';
4 changes: 2 additions & 2 deletions src/components/touchables/TouchableHighlight.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@ interface State {
}

/**
* @deprecated TouchableHighlight will be removed in the future version of Gesture Handler.
* @deprecated TouchableHighlight will be removed in the future version of Gesture Handler. Use Pressable instead.
*/
export type TouchableHighlightProps = RNTouchableHighlightProps &
GenericTouchableProps;

/**
* @deprecated TouchableHighlight will be removed in the future version of Gesture Handler.
* @deprecated TouchableHighlight will be removed in the future version of Gesture Handler. Use Pressable instead.
*
* TouchableHighlight follows RN's implementation
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
} from './TouchableNativeFeedbackProps';

/**
* @deprecated TouchableNativeFeedback will be removed in the future version of Gesture Handler.
* @deprecated TouchableNativeFeedback will be removed in the future version of Gesture Handler. Use Pressable instead.
*
* TouchableNativeFeedback behaves slightly different than RN's TouchableNativeFeedback.
* There's small difference with handling long press ripple since RN's implementation calls
Expand Down
2 changes: 1 addition & 1 deletion src/components/touchables/TouchableNativeFeedback.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { TouchableNativeFeedback as RNTouchableNativeFeedback } from 'react-native';

/**
* @deprecated TouchableNativeFeedback will be removed in the future version of Gesture Handler.
* @deprecated TouchableNativeFeedback will be removed in the future version of Gesture Handler. Use Pressable instead.
*/
const TouchableNativeFeedback = RNTouchableNativeFeedback;

Expand Down
2 changes: 1 addition & 1 deletion src/components/touchables/TouchableNativeFeedbackProps.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export type TouchableNativeFeedbackExtraProps = {
};

/**
* @deprecated TouchableNativeFeedback will be removed in the future version of Gesture Handler.
* @deprecated TouchableNativeFeedback will be removed in the future version of Gesture Handler. Use Pressable instead.
*/
export type TouchableNativeFeedbackProps = RNTouchableNativeFeedbackProps &
GenericTouchableProps;
Loading

0 comments on commit 7303e65

Please sign in to comment.