Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
77 changes: 0 additions & 77 deletions .yarn/patches/react-native-screens-npm-4.18.0-fa7de65975.patch
Original file line number Diff line number Diff line change
@@ -1,60 +1,3 @@
diff --git a/ios/RNSScreen.mm b/ios/RNSScreen.mm
index 65c18f1ddccc64b3169e050e577eab77fd8c183b..8ffd9d4b48f85e53c6fcf0a76963cfcf946dad97 100644
--- a/ios/RNSScreen.mm
+++ b/ios/RNSScreen.mm
@@ -38,6 +38,7 @@
#import "RNSTabBarController.h"

#import "RNSDefines.h"
+#import "integrations/RNSLifecycleListenerProtocol.h"
#import "UIView+RNSUtility.h"

#ifdef RCT_NEW_ARCH_ENABLED
@@ -74,6 +75,7 @@ struct ContentWrapperBox {
ContentWrapperBox _contentWrapperBox;
bool _sheetHasInitialDetentSet;
BOOL _shouldUpdateScrollEdgeEffects;
+ RNSScreen *_controllerBeforeInvalidate;
#ifdef RCT_NEW_ARCH_ENABLED
RCTSurfaceTouchHandler *_touchHandler;
react::RNSScreenShadowNode::ConcreteState::Shared _state;
@@ -608,6 +610,26 @@ RNS_IGNORE_SUPER_CALL_END
if (_hideKeyboardOnSwipe) {
[self endEditing:YES];
}
+
+ // Notify any presented view controllers that conform to RNSLifecycleListenerProtocol
+ RNSScreen *controller = _controller ?: _controllerBeforeInvalidate;
+ if (controller) {
+ UIViewController *presented = controller.presentedViewController;
+ while (presented) {
+ UIViewController *next = presented.presentedViewController;
+ if ([presented conformsToProtocol:@protocol(RNSLifecycleListenerProtocol)]) {
+ BOOL isPresenterUnmounting = NO;
+ RNSScreen *presenter = (RNSScreen *)presented.presentingViewController;
+ if ([presenter isKindOfClass:[RNSScreen class]]) {
+ isPresenterUnmounting = presenter.screenView.isMarkedForUnmountInCurrentTransaction;
+ }
+ [(id<RNSLifecycleListenerProtocol>)presented screenWillDisappear:controller
+ isPresenterUnmounting:isPresenterUnmounting];
+ }
+ presented = next;
+ }
+ }
+
#ifdef RCT_NEW_ARCH_ENABLED
// If screen is already unmounted then there will be no event emitter
if (_eventEmitter != nullptr) {
@@ -927,6 +949,9 @@ RNS_IGNORE_SUPER_CALL_END

- (void)invalidate
{
+ if (_controller && !_controllerBeforeInvalidate) {
+ _controllerBeforeInvalidate = _controller;
+ }
_controller = nil;
[_sheetsScrollView removeObserver:self forKeyPath:@"bounds" context:nil];
}
diff --git a/ios/RNSScreenStack.mm b/ios/RNSScreenStack.mm
index 51f021831aed26a4eed3c85014020423b7b3108b..268fa69dfee2b20d8b5a66c77c1b4cbd8c831573 100644
--- a/ios/RNSScreenStack.mm
Expand Down Expand Up @@ -130,23 +73,3 @@ index 006f809d104c1d4fbdf6eccca89d6c6e190cca71..89e297f1b7a9582fee3e19237dfba8d4
@end

NS_ASSUME_NONNULL_END
diff --git a/ios/integrations/RNSLifecycleListenerProtocol.h b/ios/integrations/RNSLifecycleListenerProtocol.h
new file mode 100644
index 0000000000000000000000000000000000000000..025b4231c0b45f9f10034280037617b9b6d6fec4
--- /dev/null
+++ b/ios/integrations/RNSLifecycleListenerProtocol.h
@@ -0,0 +1,14 @@
+#import <UIKit/UIKit.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@protocol RNSLifecycleListenerProtocol <NSObject>
+
+// Called when a screen in the presenting hierarchy is about to disappear.
+// @param screen The screen controller that is disappearing
+// @param isPresenterUnmounting YES if the presenter (modal) itself is being unmounted
+- (void)screenWillDisappear:(UIViewController *)screen isPresenterUnmounting:(BOOL)isPresenterUnmounting;
+
+@end
+
+NS_ASSUME_NONNULL_END
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## Unreleased

### 💡 Others

- **iOS**: Refactored screen unmount detection to use C++ EventDispatcher instead of RNSLifecycleListenerProtocol. ([#410](https://github.com/lodev09/react-native-true-sheet/pull/410) by [@lodev09](https://github.com/lodev09))

## 3.7.3

### 🐛 Bug fixes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ class TrueSheetViewComponentDescriptor final
concreteShadowNode.adjustLayoutWithState();

ConcreteComponentDescriptor::adopt(shadowNode);

#if !defined(ANDROID)
concreteShadowNode.setEventDispatcher(eventDispatcher_);
#endif
}
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,17 @@ void TrueSheetViewShadowNode::adjustLayoutWithState() {
}
}

#if !defined(ANDROID)
void TrueSheetViewShadowNode::setEventDispatcher(
std::weak_ptr<const EventDispatcher> dispatcher) {
getStateDataMutable().setEventDispatcher(dispatcher);
}

TrueSheetViewShadowNode::StateData &
TrueSheetViewShadowNode::getStateDataMutable() {
ensureUnsealed();
return const_cast<TrueSheetViewShadowNode::StateData &>(getStateData());
}
#endif

} // namespace facebook::react
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

namespace facebook::react {

class EventDispatcher;

JSI_EXPORT extern const char TrueSheetViewComponentName[];

/*
Expand All @@ -22,13 +24,22 @@ class JSI_EXPORT TrueSheetViewShadowNode final
using ConcreteViewShadowNode::ConcreteViewShadowNode;

public:
using StateData = ConcreteViewShadowNode::ConcreteStateData;

static ShadowNodeTraits BaseTraits() {
auto traits = ConcreteViewShadowNode::BaseTraits();
traits.set(ShadowNodeTraits::Trait::RootNodeKind);
return traits;
}

void adjustLayoutWithState();

#if !defined(ANDROID)
void setEventDispatcher(std::weak_ptr<const EventDispatcher> dispatcher);

private:
StateData &getStateDataMutable();
#endif
};

} // namespace facebook::react
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,16 @@ folly::dynamic TrueSheetViewState::getDynamic() const {
}
#endif

#if !defined(ANDROID)
void TrueSheetViewState::setEventDispatcher(
std::weak_ptr<const EventDispatcher> dispatcher) {
eventDispatcher_ = dispatcher;
}

std::weak_ptr<const EventDispatcher> TrueSheetViewState::getEventDispatcher()
const noexcept {
return eventDispatcher_;
}
#endif

} // namespace facebook::react
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

namespace facebook::react {

class EventDispatcher;

/*
* State for <TrueSheetView> component.
* Contains the container dimensions from native.
Expand Down Expand Up @@ -37,6 +39,14 @@ class TrueSheetViewState final {
return MapBufferBuilder::EMPTY();
}
#endif

#if !defined(ANDROID)
void setEventDispatcher(std::weak_ptr<const EventDispatcher> dispatcher);
std::weak_ptr<const EventDispatcher> getEventDispatcher() const noexcept;

private:
std::weak_ptr<const EventDispatcher> eventDispatcher_;
#endif
};

} // namespace facebook::react
2 changes: 1 addition & 1 deletion docs/docs/guides/navigation.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -236,5 +236,5 @@ navigation.navigate('SomeScreen')
```

:::note
Requires a [patch to react-native-screens](https://github.com/lodev09/react-native-true-sheet/blob/main/.yarn/patches/react-native-screens-npm-4.18.0-fa7de65975.patch). See [PR #3415](https://github.com/software-mansion/react-native-screens/pull/3415), [PR #3527](https://github.com/software-mansion/react-native-screens/pull/3527).
Requires a [patch to react-native-screens](https://github.com/lodev09/react-native-true-sheet/blob/main/.yarn/patches/react-native-screens-npm-4.18.0-fa7de65975.patch). See [PR #3415](https://github.com/software-mansion/react-native-screens/pull/3415).
:::
4 changes: 2 additions & 2 deletions example/bare/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2646,7 +2646,7 @@ PODS:
- ReactCommon/turbomodule/core
- SocketRocket
- Yoga
- RNTrueSheet (3.7.2):
- RNTrueSheet (3.7.3):
- boost
- DoubleConversion
- fast_float
Expand Down Expand Up @@ -3095,7 +3095,7 @@ SPEC CHECKSUMS:
RNGestureHandler: e1cf8ef3f11045536eed6bd4f132b003ef5f9a5f
RNReanimated: f1868b36f4b2b52a0ed00062cfda69506f75eaee
RNScreens: d821082c6dd1cb397cc0c98b026eeafaa68be479
RNTrueSheet: fdf1146eb62282d33c4982c2903593466913afdd
RNTrueSheet: ccd12867de774263d4c4f9dd4ea621900d69780c
RNWorklets: d9c050940f140af5d8b611d937eab1cbfce5e9a5
SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748
Yoga: 689c8e04277f3ad631e60fe2a08e41d411daf8eb
Expand Down
12 changes: 10 additions & 2 deletions example/bare/src/navigators/RootNavigator.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { createNativeStackNavigator } from '@react-navigation/native-stack';

import { MapScreen, StandardScreen } from '@example/shared/screens';
import { MapScreen, StandardScreen, TestScreen } from '@example/shared/screens';
import { DARK_BLUE } from '@example/shared/utils';
import { Map } from '@example/shared/components';
import { ModalStackNavigator } from './ModalStackNavigator';
import { SheetNavigator } from './SheetNavigator';
Expand All @@ -18,6 +19,7 @@ const MapScreenWrapper = () => {
MapComponent={Map}
onNavigateToModal={() => navigation.navigate('ModalStack')}
onNavigateToSheetStack={() => navigation.navigate('SheetStack')}
onNavigateToTest={() => navigation.navigate('Test')}
/>
);
};
Expand All @@ -33,10 +35,15 @@ const StandardScreenWrapper = () => {
);
};

const TestScreenWrapper = () => {
const navigation = useAppNavigation();
return <TestScreen onGoBack={() => navigation.goBack()} />;
};

export const RootNavigator = () => {
return (
<Stack.Navigator
screenOptions={{ headerTransparent: true, headerTintColor: 'white' }}
screenOptions={{ headerTintColor: 'white', headerStyle: { backgroundColor: DARK_BLUE } }}
initialRouteName={INITIAL_ROUTE_NAME}
>
<Stack.Screen
Expand All @@ -55,6 +62,7 @@ export const RootNavigator = () => {
component={ModalStackNavigator}
options={{ presentation: 'fullScreenModal', headerShown: false }}
/>
<Stack.Screen name="Test" component={TestScreenWrapper} options={{ title: 'Test' }} />
</Stack.Navigator>
);
};
6 changes: 5 additions & 1 deletion example/expo/app/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import * as SplashScreen from 'expo-splash-screen';
import { useEffect } from 'react';
import { useColorScheme } from 'react-native';
import { TrueSheetProvider } from '@lodev09/react-native-true-sheet';
import { DARK_BLUE } from '@example/shared/utils';
import 'react-native-reanimated';

export {
Expand Down Expand Up @@ -50,9 +51,12 @@ function RootLayoutNav() {
return (
<ThemeProvider value={colorScheme === 'dark' ? DarkTheme : DefaultTheme}>
<TrueSheetProvider>
<Stack screenOptions={{ headerTransparent: true, headerTintColor: 'white' }}>
<Stack
screenOptions={{ headerTintColor: 'white', headerStyle: { backgroundColor: DARK_BLUE } }}
>
<Stack.Screen name="index" options={{ headerShown: false }} />
<Stack.Screen name="standard" options={{ headerShown: false, title: 'Standard' }} />
<Stack.Screen name="test" options={{ title: 'Test' }} />
<Stack.Screen
name="modal"
options={{
Expand Down
1 change: 1 addition & 0 deletions example/expo/app/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export default function Index() {
MapComponent={Map}
onNavigateToModal={() => router.push('/modal')}
onNavigateToSheetStack={() => router.push('/sheet')}
onNavigateToTest={() => router.push('/test')}
/>
);
}
7 changes: 7 additions & 0 deletions example/expo/app/test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { TestScreen } from '@example/shared/screens';
import { useRouter } from 'expo-router';

export default function Test() {
const router = useRouter();
return <TestScreen onGoBack={() => router.back()} />;
}
38 changes: 26 additions & 12 deletions example/shared/src/screens/MapScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,14 @@ export interface MapScreenProps {
MapComponent: ComponentType<{ style?: StyleProp<ViewStyle> }>;
onNavigateToModal?: () => void;
onNavigateToSheetStack?: () => void;
onNavigateToTest?: () => void;
}

const MapScreenInner = ({
MapComponent,
onNavigateToModal,
onNavigateToSheetStack,
onNavigateToTest,
}: MapScreenProps) => {
const { height } = useWindowDimensions();
const { animatedPosition } = useReanimatedTrueSheet();
Expand Down Expand Up @@ -149,23 +151,35 @@ const MapScreenInner = ({
<Text style={styles.subtitle}>The true native bottom sheet experience.</Text>
</View>
<Button text="TrueSheet View" onPress={() => presentBasicSheet(0)} />
<Button text="TrueSheet Prompt" onPress={() => promptSheet.current?.present()} />
<Button
text="TrueSheet ScrollView"
loading={scrollViewLoading}
disabled={scrollViewLoading}
onPress={presentScrollViewSheet}
/>
<Button text="TrueSheet FlatList" onPress={() => flatListSheet.current?.present()} />
<Button text="TrueSheet Gestures" onPress={() => gestureSheet.current?.present()} />
<View style={styles.buttonRow}>
<Button style={styles.rowButton} text="Open Modal" onPress={onNavigateToModal} />
<Button
style={styles.rowButton}
text="Sheet Navigator"
onPress={onNavigateToSheetStack}
text="Prompt"
onPress={() => promptSheet.current?.present()}
/>
<Button
style={styles.rowButton}
text="Gestures"
onPress={() => gestureSheet.current?.present()}
/>
</View>
<View style={styles.buttonRow}>
<Button
style={styles.rowButton}
text="ScrollView"
loading={scrollViewLoading}
disabled={scrollViewLoading}
onPress={presentScrollViewSheet}
/>
<Button
style={styles.rowButton}
text="FlatList"
onPress={() => flatListSheet.current?.present()}
/>
</View>
<Button text="Open Modal" onPress={onNavigateToModal} />
<Button text="Sheet Navigator" onPress={onNavigateToSheetStack} />
<Button text="Test Screen" onPress={onNavigateToTest} />
<Spacer />
{showExtraContent && <DemoContent text="Extra content that changes height" />}
<View style={styles.buttonRow}>
Expand Down
Loading