Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions FabricTestExample/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ import Test2008 from './src/Test2008';
import Test2028 from './src/Test2028';
import Test2048 from './src/Test2048';
import Test2069 from './src/Test2069';
import Test2118 from './src/Test2118';

enableFreeze(true);

Expand Down
88 changes: 88 additions & 0 deletions FabricTestExample/src/Test2118.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import React from 'react';
import { View, Text, Button, Pressable, StyleSheet, Alert } from 'react-native';
import { NavigationContainer, useNavigation } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';

const Stack = createNativeStackNavigator(); // <-- change to createStackNavigator to see a difference

const ModalStack = createNativeStackNavigator();

export default function App() {
return (
<NavigationContainer>
<Stack.Navigator screenOptions={{ animation: 'slide_from_left' }}>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="DetailsStack" component={DetailsScreen} />
<Stack.Screen
name="StackInModal"
component={StackInModal}
options={{ presentation: 'modal' }}
/>
</Stack.Navigator>
</NavigationContainer>
);
}

function HomeScreen() {
const navigation = useNavigation();
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
<Button
title="Go to Details"
onPress={() => navigation.navigate('DetailsStack')}
/>
<Button
title="Go to StackInModal"
onPress={() => navigation.navigate('StackInModal')}
/>
</View>
);
}

function DetailsScreen() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
{new Array(10).fill(0).map((_, i) => (
<Pressable
key={i.toString()}
onPress={() => {
Alert.alert('Pressed!');
}}
style={({ pressed }) => [
{
backgroundColor: pressed ? 'rgb(210, 230, 255)' : 'white',
},
styles.wrapperCustom,
]}>
{({ pressed }) => (
<Text style={styles.text}>{pressed ? 'Pressed!' : 'Press Me'}</Text>
)}
</Pressable>
))}
</View>
);
}

function StackInModal() {
return (
<ModalStack.Navigator>
<ModalStack.Screen name="ModalHome" component={HomeScreen} />
<ModalStack.Screen name="ModalDetails" component={DetailsScreen} />
</ModalStack.Navigator>
);
}

const styles = StyleSheet.create({
wrapperCustom: {
width: '100%',
height: 100,
marginHorizontal: 30,
borderRadius: 10,
margin: 10,
},
text: {
fontSize: 20,
color: 'black',
},
});
2 changes: 0 additions & 2 deletions FabricTestExample/src/Test654.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import { createNativeStackNavigator } from '@react-navigation/native-stack';

const Stack = createNativeStackNavigator();

I18nManager.forceRTL(true);

export default function App() {
return (
<NavigationContainer>
Expand Down
2 changes: 0 additions & 2 deletions FabricTestExample/src/Test831.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ type Props = {

const Stack = createNativeStackNavigator();

I18nManager.forceRTL(true);

export default function App(): JSX.Element {
return (
<NavigationContainer>
Expand Down
1 change: 1 addition & 0 deletions TestsExample/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ import Test1981 from './src/Test1981';
import Test2008 from './src/Test2008';
import Test2048 from './src/Test2048';
import Test2069 from './src/Test2069';
import Test2118 from './src/Test2118';

enableFreeze(true);

Expand Down
88 changes: 88 additions & 0 deletions TestsExample/src/Test2118.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import React from 'react';
import { View, Text, Button, Pressable, StyleSheet, Alert } from 'react-native';
import { NavigationContainer, useNavigation } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';

const Stack = createNativeStackNavigator(); // <-- change to createStackNavigator to see a difference

const ModalStack = createNativeStackNavigator();

export default function App() {
return (
<NavigationContainer>
<Stack.Navigator screenOptions={{ animation: 'slide_from_left' }}>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="DetailsStack" component={DetailsScreen} />
<Stack.Screen
name="StackInModal"
component={StackInModal}
options={{ presentation: 'modal' }}
/>
</Stack.Navigator>
</NavigationContainer>
);
}

function HomeScreen() {
const navigation = useNavigation();
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
<Button
title="Go to Details"
onPress={() => navigation.navigate('DetailsStack')}
/>
<Button
title="Go to StackInModal"
onPress={() => navigation.navigate('StackInModal')}
/>
</View>
);
}

function DetailsScreen() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
{new Array(10).fill(0).map((_, i) => (
<Pressable
key={i.toString()}
onPress={() => {
Alert.alert('Pressed!');
}}
style={({ pressed }) => [
{
backgroundColor: pressed ? 'rgb(210, 230, 255)' : 'white',
},
styles.wrapperCustom,
]}>
{({ pressed }) => (
<Text style={styles.text}>{pressed ? 'Pressed!' : 'Press Me'}</Text>
)}
</Pressable>
))}
</View>
);
}

function StackInModal() {
return (
<ModalStack.Navigator>
<ModalStack.Screen name="ModalHome" component={HomeScreen} />
<ModalStack.Screen name="ModalDetails" component={DetailsScreen} />
</ModalStack.Navigator>
);
}

const styles = StyleSheet.create({
wrapperCustom: {
width: '100%',
height: 100,
marginHorizontal: 30,
borderRadius: 10,
margin: 10,
},
text: {
fontSize: 20,
color: 'black',
},
});
44 changes: 36 additions & 8 deletions ios/RNSScreenStack.mm
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
#ifdef RCT_NEW_ARCH_ENABLED
#import <React/RCTFabricComponentsPlugins.h>
#import <React/RCTFabricSurface.h>
#import <React/RCTMountingTransactionObserving.h>
#import <React/RCTSurfaceTouchHandler.h>
#import <React/RCTSurfaceView.h>
#import <React/UIView+React.h>
#import <react/renderer/components/rnscreens/ComponentDescriptors.h>
#import <react/renderer/components/rnscreens/EventEmitters.h>
#import <react/renderer/components/rnscreens/Props.h>
#import <react/renderer/components/rnscreens/RCTComponentViewHelpers.h>
#import "RCTSurfaceTouchHandler+RNSUtility.h"
#else
#import <React/RCTBridge.h>
#import <React/RCTRootContentView.h>
#import <React/RCTShadowView.h>
#import <React/RCTTouchHandler.h>
#import <React/RCTUIManager.h>
#import <React/RCTUIManagerUtils.h>
#import "RCTTouchHandler+RNSUtility.h"
#endif // RCT_NEW_ARCH_ENABLED

#import "RNSScreen.h"
Expand Down Expand Up @@ -731,19 +735,43 @@ - (void)cancelTouchesInParent
// item is close to an edge and we start pulling from edge we want the Touchable to be cancelled.
// Without the below code the Touchable will remain active (highlighted) for the duration of back
// gesture and onPress may fire when we release the finger.
#ifdef RCT_NEW_ARCH_ENABLED
// On Fabric there is no view that exposes touchHandler above us in the view hierarchy, however it is still
// utilised. `RCTSurfaceView` should be present above us, which hosts `RCTFabricSurface` instance, which in turn
// hosts `RCTSurfaceTouchHandler` as a private field. When initialised, `RCTSurfaceTouchHandler` is attached to the
// surface view as a gestureRecognizer <- and this is where we can lay our hands on it.
UIView *parent = _controller.view;
while (parent != nil && ![parent respondsToSelector:@selector(touchHandler)])
while (parent != nil && ![parent isKindOfClass:RCTSurfaceView.class]) {
parent = parent.superview;
if (parent != nil) {
#ifdef RCT_NEW_ARCH_ENABLED
RCTSurfaceTouchHandler *touchHandler = [parent performSelector:@selector(touchHandler)];
}

// This could be possible in modal context
if (parent == nil) {
return;
}

RCTSurfaceTouchHandler *touchHandler = nil;
// Experimentation shows that RCTSurfaceTouchHandler is the only gestureRecogniser registered here,
// so we should not be afraid of any performance hit here.
for (UIGestureRecognizer *recognizer in parent.gestureRecognizers) {
if ([recognizer isKindOfClass:RCTSurfaceTouchHandler.class]) {
touchHandler = static_cast<RCTSurfaceTouchHandler *>(recognizer);
}
}

[touchHandler rns_cancelTouches];
#else
// On Paper we can access touchHandler hosted by `RCTRootContentView` which should be above ScreenStack
// in view hierarchy.
UIView *parent = _controller.view;
while (parent != nil && ![parent respondsToSelector:@selector(touchHandler)]) {
parent = parent.superview;
}
if (parent != nil) {
RCTTouchHandler *touchHandler = [parent performSelector:@selector(touchHandler)];
#endif
[touchHandler setEnabled:NO];
[touchHandler setEnabled:YES];
[touchHandler reset];
[touchHandler rns_cancelTouches];
}
#endif // RCT_NEW_ARCH_ENABLED
}

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
Expand Down
15 changes: 15 additions & 0 deletions ios/utils/RCTSurfaceTouchHandler+RNSUtility.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#ifdef RCT_NEW_ARCH_ENABLED

#import <React/RCTSurfaceTouchHandler.h>

NS_ASSUME_NONNULL_BEGIN

@interface RCTSurfaceTouchHandler (RNSUtility)

- (void)rns_cancelTouches;

@end

NS_ASSUME_NONNULL_END

#endif // RCT_NEW_ARCH_ENABLED
14 changes: 14 additions & 0 deletions ios/utils/RCTSurfaceTouchHandler+RNSUtility.mm
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#ifdef RCT_NEW_ARCH_ENABLED
#import "RCTSurfaceTouchHandler+RNSUtility.h"

@implementation RCTSurfaceTouchHandler (RNSUtility)

- (void)rns_cancelTouches
{
[self setEnabled:NO];
[self setEnabled:YES];
[self reset];
}

@end
#endif // RCT_NEW_ARCH_ENABLED
15 changes: 15 additions & 0 deletions ios/utils/RCTTouchHandler+RNSUtility.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#ifndef RCT_NEW_ARCH_ENABLED

#import <React/RCTTouchHandler.h>

NS_ASSUME_NONNULL_BEGIN

@interface RCTTouchHandler (RNSUtility)

- (void)rns_cancelTouches;

@end

NS_ASSUME_NONNULL_END

#endif // !RCT_NEW_ARCH_ENABLED
15 changes: 15 additions & 0 deletions ios/utils/RCTTouchHandler+RNSUtility.mm
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#ifndef RCT_NEW_ARCH_ENABLED
#import "RCTTouchHandler+RNSUtility.h"

@implementation RCTTouchHandler (RNSUtility)

- (void)rns_cancelTouches
{
[self setEnabled:NO];
[self setEnabled:YES];
[self reset];
}

@end

#endif // !RCT_NEW_ARCH_ENABLED