expo-router 5.2.0-canary-20250729-d8899ae → 5.2.0-canary-20250811-5c940c0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/_ctx.android.js +1 -1
- package/_ctx.ios.js +1 -1
- package/_ctx.web.js +1 -1
- package/assets/modal.module.css +12 -3
- package/build/ExpoRoot.d.ts.map +1 -1
- package/build/ExpoRoot.js +12 -2
- package/build/ExpoRoot.js.map +1 -1
- package/build/Route.d.ts +9 -0
- package/build/Route.d.ts.map +1 -1
- package/build/Route.js.map +1 -1
- package/build/constants.d.ts +2 -0
- package/build/constants.d.ts.map +1 -1
- package/build/constants.js +3 -1
- package/build/constants.js.map +1 -1
- package/build/doctor/index.d.ts +1 -1
- package/build/doctor/index.d.ts.map +1 -1
- package/build/doctor/index.js +4 -1
- package/build/doctor/index.js.map +1 -1
- package/build/exports.d.ts +2 -2
- package/build/exports.d.ts.map +1 -1
- package/build/exports.js +6 -6
- package/build/exports.js.map +1 -1
- package/build/fork/native-stack/createNativeStackNavigator.d.ts +2 -2
- package/build/fork/native-stack/createNativeStackNavigator.d.ts.map +1 -1
- package/build/fork/native-stack/createNativeStackNavigator.js +82 -2
- package/build/fork/native-stack/createNativeStackNavigator.js.map +1 -1
- package/build/fork/useLinking.js +2 -2
- package/build/fork/useLinking.js.map +1 -1
- package/build/getLinkingConfig.d.ts +29 -2
- package/build/getLinkingConfig.d.ts.map +1 -1
- package/build/getLinkingConfig.js +35 -4
- package/build/getLinkingConfig.js.map +1 -1
- package/build/getRoutesCore.d.ts +1 -0
- package/build/getRoutesCore.d.ts.map +1 -1
- package/build/getRoutesCore.js +60 -0
- package/build/getRoutesCore.js.map +1 -1
- package/build/getServerManifest.d.ts +20 -1
- package/build/getServerManifest.d.ts.map +1 -1
- package/build/getServerManifest.js +8 -1
- package/build/getServerManifest.js.map +1 -1
- package/build/global-state/routeInfo.d.ts.map +1 -1
- package/build/global-state/routeInfo.js +12 -1
- package/build/global-state/routeInfo.js.map +1 -1
- package/build/global-state/router-store.d.ts.map +1 -1
- package/build/global-state/router-store.js +4 -0
- package/build/global-state/router-store.js.map +1 -1
- package/build/global-state/routing.d.ts +29 -1
- package/build/global-state/routing.d.ts.map +1 -1
- package/build/global-state/routing.js +78 -42
- package/build/global-state/routing.js.map +1 -1
- package/build/global-state/utils.d.ts +4 -0
- package/build/global-state/utils.d.ts.map +1 -0
- package/build/global-state/utils.js +29 -0
- package/build/global-state/utils.js.map +1 -0
- package/build/hooks.d.ts +1 -1
- package/build/hooks.d.ts.map +1 -1
- package/build/hooks.js +9 -4
- package/build/hooks.js.map +1 -1
- package/build/layouts/DrawerClient.d.ts +2 -2
- package/build/layouts/StackClient.d.ts +2 -2
- package/build/layouts/StackClient.d.ts.map +1 -1
- package/build/layouts/StackClient.js +11 -6
- package/build/layouts/StackClient.js.map +1 -1
- package/build/layouts/TabsClient.d.ts +3 -3
- package/build/layouts/withLayoutContext.d.ts.map +1 -1
- package/build/layouts/withLayoutContext.js +13 -0
- package/build/layouts/withLayoutContext.js.map +1 -1
- package/build/link/ExpoLink.d.ts.map +1 -1
- package/build/link/ExpoLink.js +3 -2
- package/build/link/ExpoLink.js.map +1 -1
- package/build/link/InternalLinkPreviewContext.d.ts +6 -0
- package/build/link/InternalLinkPreviewContext.d.ts.map +1 -0
- package/build/link/InternalLinkPreviewContext.js +6 -0
- package/build/link/InternalLinkPreviewContext.js.map +1 -0
- package/build/link/Link.d.ts +2 -67
- package/build/link/Link.d.ts.map +1 -1
- package/build/link/Link.js +5 -70
- package/build/link/Link.js.map +1 -1
- package/build/link/LinkWithPreview.d.ts +1 -46
- package/build/link/LinkWithPreview.d.ts.map +1 -1
- package/build/link/LinkWithPreview.js +20 -113
- package/build/link/LinkWithPreview.js.map +1 -1
- package/build/link/elements.d.ts +166 -0
- package/build/link/elements.d.ts.map +1 -0
- package/build/link/elements.js +172 -0
- package/build/link/elements.js.map +1 -0
- package/build/link/preview/HrefPreview.d.ts +1 -1
- package/build/link/preview/HrefPreview.d.ts.map +1 -1
- package/build/link/preview/HrefPreview.js +43 -7
- package/build/link/preview/HrefPreview.js.map +1 -1
- package/build/link/preview/LinkPreviewContext.d.ts +3 -2
- package/build/link/preview/LinkPreviewContext.d.ts.map +1 -1
- package/build/link/preview/LinkPreviewContext.js +3 -2
- package/build/link/preview/LinkPreviewContext.js.map +1 -1
- package/build/link/preview/native.d.ts +14 -6
- package/build/link/preview/native.d.ts.map +1 -1
- package/build/link/preview/native.js.map +1 -1
- package/build/link/preview/useNextScreenId.d.ts +8 -1
- package/build/link/preview/useNextScreenId.d.ts.map +1 -1
- package/build/link/preview/useNextScreenId.js +37 -32
- package/build/link/preview/useNextScreenId.js.map +1 -1
- package/build/link/preview/utils.d.ts +12 -0
- package/build/link/preview/utils.d.ts.map +1 -0
- package/build/link/preview/utils.js +66 -0
- package/build/link/preview/utils.js.map +1 -0
- package/build/modal/Modal.js +1 -1
- package/build/modal/Modal.js.map +1 -1
- package/build/modal/ModalsRenderer.js +1 -1
- package/build/modal/ModalsRenderer.js.map +1 -1
- package/build/modal/web/ModalStackRouteDrawer.web.d.ts.map +1 -1
- package/build/modal/web/ModalStackRouteDrawer.web.js +0 -1
- package/build/modal/web/ModalStackRouteDrawer.web.js.map +1 -1
- package/build/native-tabs/NativeBottomTabs/NativeBottomTabsNavigator.d.ts +25 -0
- package/build/native-tabs/NativeBottomTabs/NativeBottomTabsNavigator.d.ts.map +1 -0
- package/build/native-tabs/NativeBottomTabs/NativeBottomTabsNavigator.js +27 -0
- package/build/native-tabs/NativeBottomTabs/NativeBottomTabsNavigator.js.map +1 -0
- package/build/native-tabs/NativeBottomTabs/NativeBottomTabsRouter.d.ts +3 -0
- package/build/native-tabs/NativeBottomTabs/NativeBottomTabsRouter.d.ts.map +1 -0
- package/build/native-tabs/NativeBottomTabs/NativeBottomTabsRouter.js +65 -0
- package/build/native-tabs/NativeBottomTabs/NativeBottomTabsRouter.js.map +1 -0
- package/build/native-tabs/NativeBottomTabs/NativeTabs.d.ts +7 -0
- package/build/native-tabs/NativeBottomTabs/NativeTabs.d.ts.map +1 -0
- package/build/native-tabs/NativeBottomTabs/NativeTabs.js +9 -0
- package/build/native-tabs/NativeBottomTabs/NativeTabs.js.map +1 -0
- package/build/native-tabs/NativeBottomTabs/NativeTabsView.d.ts +103 -0
- package/build/native-tabs/NativeBottomTabs/NativeTabsView.d.ts.map +1 -0
- package/build/native-tabs/NativeBottomTabs/NativeTabsView.js +69 -0
- package/build/native-tabs/NativeBottomTabs/NativeTabsView.js.map +1 -0
- package/build/native-tabs/NativeBottomTabs/TabOptions.d.ts +40 -0
- package/build/native-tabs/NativeBottomTabs/TabOptions.d.ts.map +1 -0
- package/build/native-tabs/NativeBottomTabs/TabOptions.js +103 -0
- package/build/native-tabs/NativeBottomTabs/TabOptions.js.map +1 -0
- package/build/native-tabs/NativeBottomTabs/utils.d.ts +7 -0
- package/build/native-tabs/NativeBottomTabs/utils.d.ts.map +1 -0
- package/build/native-tabs/NativeBottomTabs/utils.js +21 -0
- package/build/native-tabs/NativeBottomTabs/utils.js.map +1 -0
- package/build/native-tabs/common/elements.d.ts +59 -0
- package/build/native-tabs/common/elements.d.ts.map +1 -0
- package/build/native-tabs/common/elements.js +15 -0
- package/build/native-tabs/common/elements.js.map +1 -0
- package/build/native-tabs/index.d.ts +3 -0
- package/build/native-tabs/index.d.ts.map +1 -0
- package/build/native-tabs/index.js +10 -0
- package/build/native-tabs/index.js.map +1 -0
- package/build/routes-manifest.d.ts +42 -0
- package/build/routes-manifest.d.ts.map +1 -1
- package/build/routes-manifest.js.map +1 -1
- package/build/testing-library/mock-config.d.ts +18 -0
- package/build/testing-library/mock-config.d.ts.map +1 -1
- package/build/testing-library/mock-config.js +4 -1
- package/build/testing-library/mock-config.js.map +1 -1
- package/build/ui/common.d.ts.map +1 -1
- package/build/ui/common.js +7 -6
- package/build/ui/common.js.map +1 -1
- package/build/useNavigation.d.ts.map +1 -1
- package/build/useNavigation.js +8 -5
- package/build/useNavigation.js.map +1 -1
- package/build/views/NoSSR.d.ts +5 -0
- package/build/views/NoSSR.d.ts.map +1 -0
- package/build/views/NoSSR.js +22 -0
- package/build/views/NoSSR.js.map +1 -0
- package/build/views/Screen.d.ts.map +1 -1
- package/build/views/Screen.js +4 -1
- package/build/views/Screen.js.map +1 -1
- package/build/views/Sitemap.d.ts.map +1 -1
- package/build/views/Sitemap.js +75 -2
- package/build/views/Sitemap.js.map +1 -1
- package/build/views/Unmatched.d.ts.map +1 -1
- package/build/views/Unmatched.js +14 -4
- package/build/views/Unmatched.js.map +1 -1
- package/ios/ExpoHead.podspec +10 -1
- package/ios/LinkPreview/LinkPreviewNativeActionView.swift +159 -21
- package/ios/LinkPreview/LinkPreviewNativeModule.swift +37 -5
- package/ios/LinkPreview/LinkPreviewNativeNavigation.h +37 -11
- package/ios/LinkPreview/LinkPreviewNativeNavigation.mm +110 -87
- package/ios/LinkPreview/LinkPreviewNativeNavigation.swift +136 -0
- package/ios/LinkPreview/LinkPreviewNativeView.swift +70 -70
- package/package.json +38 -9
- package/plugin/build/index.d.ts +2 -0
- package/plugin/options.json +5 -0
- package/plugin/src/index.ts +2 -0
- package/server.d.ts +2 -1
|
@@ -1,24 +1,50 @@
|
|
|
1
1
|
// Copyright 2015-present 650 Industries. All rights reserved.
|
|
2
2
|
|
|
3
|
-
#import <RNScreens/
|
|
3
|
+
#import <RNScreens/RNSDismissibleModalProtocol.h>
|
|
4
|
+
#import <RNScreens/RNSTabBarController.h>
|
|
4
5
|
|
|
5
|
-
@interface
|
|
6
|
+
@interface LinkPreviewNativeNavigationObjC : NSObject
|
|
6
7
|
|
|
7
8
|
/*
|
|
8
|
-
*
|
|
9
|
-
* This function will
|
|
10
|
-
*/
|
|
11
|
-
|
|
9
|
+
* Pushes the previously preloaded view.
|
|
10
|
+
* This function will set the activity state of the preloaded screen view to 2
|
|
11
|
+
*/
|
|
12
|
+
+ (void)pushPreloadedView:(nonnull UIView *)view
|
|
13
|
+
ontoStackView:(nonnull UIView *)rawStackView;
|
|
12
14
|
|
|
13
15
|
/*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*/
|
|
17
|
-
|
|
16
|
+
* Helper function to check if the view is a RNSScreenStackView. Can be used in
|
|
17
|
+
* Swift
|
|
18
|
+
*/
|
|
19
|
+
+ (BOOL)isRNSScreenStackView:(UIView *)view;
|
|
20
|
+
/*
|
|
21
|
+
* Helper function to get all screen IDs from a RNSScreenStackView.
|
|
22
|
+
*/
|
|
23
|
+
+ (nonnull NSArray<NSString *> *)getStackViewScreenIds:(UIView *)view;
|
|
24
|
+
/*
|
|
25
|
+
* Helper function to get all screen views from a RNSScreenStackView.
|
|
26
|
+
*/
|
|
27
|
+
+ (nonnull NSArray<UIView *> *)getScreenViews:(UIView *)view;
|
|
28
|
+
/*
|
|
29
|
+
* Helper function to get the screen ID of a RNSScreenView.
|
|
30
|
+
*/
|
|
31
|
+
+ (nonnull NSString *)getScreenId:(UIView *)view;
|
|
32
|
+
|
|
33
|
+
+ (nonnull NSString *)getTabKey:(UIView *)view;
|
|
34
|
+
|
|
35
|
+
+ (BOOL)isRNSBottomTabsScreenComponentView:(UIView *)view;
|
|
36
|
+
|
|
37
|
+
+ (BOOL)isRNSTabBarController:(UIView *)view;
|
|
38
|
+
|
|
39
|
+
+ (nullable RNSTabBarController *)getBottomTabControllerFromView:(UIView *)view;
|
|
40
|
+
|
|
41
|
+
+ (BOOL)isRNSBottomTabsHostComponentView:(UIView *)view;
|
|
42
|
+
|
|
43
|
+
+ (nullable UIView *)getTab:(UITabBarController *)controller
|
|
44
|
+
withKey:(NSString *)key;
|
|
18
45
|
|
|
19
46
|
@end
|
|
20
47
|
|
|
21
48
|
@protocol LinkPreviewModalDismissible <RNSDismissibleModalProtocol>
|
|
22
49
|
@required
|
|
23
50
|
@end
|
|
24
|
-
|
|
@@ -6,12 +6,116 @@
|
|
|
6
6
|
#import <RNScreens/RNSScreen.h>
|
|
7
7
|
#import <RNScreens/RNSScreenStack.h>
|
|
8
8
|
|
|
9
|
-
@implementation
|
|
10
|
-
RNSScreenView *preloadedScreenView;
|
|
11
|
-
RNSScreenStackView *stackView;
|
|
9
|
+
@implementation LinkPreviewNativeNavigationObjC {
|
|
12
10
|
}
|
|
13
11
|
|
|
14
|
-
|
|
12
|
+
+ (BOOL)isRNSScreenStackView:(UIView *)view {
|
|
13
|
+
if (view != nil) {
|
|
14
|
+
return [view isKindOfClass:[RNSScreenStackView class]];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return NO;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
+ (BOOL)isRNSBottomTabsScreenComponentView:(UIView *)view {
|
|
21
|
+
if (view != nil) {
|
|
22
|
+
return [view isKindOfClass:[RNSBottomTabsScreenComponentView class]];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return NO;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
+ (BOOL)isRNSBottomTabsHostComponentView:(UIView *)view {
|
|
29
|
+
if (view != nil) {
|
|
30
|
+
return [view isKindOfClass:[RNSBottomTabsHostComponentView class]];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return NO;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
+ (nullable UITabBarController *)getBottomTabControllerFromView:(UIView *)view {
|
|
37
|
+
if ([view isKindOfClass:[RNSBottomTabsScreenComponentView class]]) {
|
|
38
|
+
RNSBottomTabsScreenComponentView *bottomTabsView =
|
|
39
|
+
(RNSBottomTabsScreenComponentView *)view;
|
|
40
|
+
UIViewController *reactVC = [bottomTabsView reactViewController];
|
|
41
|
+
if (reactVC != nil &&
|
|
42
|
+
[reactVC.tabBarController isKindOfClass:[RNSTabBarController class]]) {
|
|
43
|
+
RNSTabBarController *tabBarController =
|
|
44
|
+
(RNSTabBarController *)reactVC.tabBarController;
|
|
45
|
+
return tabBarController;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
if ([view isKindOfClass:[RNSBottomTabsHostComponentView class]]) {
|
|
49
|
+
RNSBottomTabsHostComponentView *bottomTabsView =
|
|
50
|
+
(RNSBottomTabsHostComponentView *)view;
|
|
51
|
+
return [bottomTabsView controller];
|
|
52
|
+
}
|
|
53
|
+
return nil;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
+ (nullable UIView *)getTab:(UITabBarController *)controller
|
|
57
|
+
withKey:(NSString *)key {
|
|
58
|
+
if (controller != nil) {
|
|
59
|
+
for (UIViewController *subcontroller in controller.viewControllers) {
|
|
60
|
+
if ([subcontroller.view
|
|
61
|
+
isKindOfClass:[RNSBottomTabsScreenComponentView class]]) {
|
|
62
|
+
if (((RNSBottomTabsScreenComponentView *)subcontroller.view).tabKey ==
|
|
63
|
+
key) {
|
|
64
|
+
return subcontroller.view;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return nil;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
+ (nonnull NSArray<NSString *> *)getStackViewScreenIds:(UIView *)view {
|
|
74
|
+
if (view != nil && [view isKindOfClass:[RNSScreenStackView class]]) {
|
|
75
|
+
RNSScreenStackView *stackView = (RNSScreenStackView *)view;
|
|
76
|
+
return stackView.screenIds;
|
|
77
|
+
}
|
|
78
|
+
return @[];
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
+ (nonnull NSArray<UIView *> *)getScreenViews:(UIView *)view {
|
|
82
|
+
if (view != nil && [view isKindOfClass:[RNSScreenStackView class]]) {
|
|
83
|
+
RNSScreenStackView *stackView = (RNSScreenStackView *)view;
|
|
84
|
+
return stackView.reactSubviews;
|
|
85
|
+
}
|
|
86
|
+
return @[];
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
+ (nonnull NSString *)getScreenId:(UIView *)view {
|
|
90
|
+
if (view != nil && [view isKindOfClass:[RNSScreenView class]]) {
|
|
91
|
+
RNSScreenView *screenView = (RNSScreenView *)view;
|
|
92
|
+
return screenView.screenId;
|
|
93
|
+
}
|
|
94
|
+
return nil;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
+ (nonnull NSString *)getTabKey:(UIView *)view {
|
|
98
|
+
if (view != nil &&
|
|
99
|
+
[view isKindOfClass:[RNSBottomTabsScreenComponentView class]]) {
|
|
100
|
+
RNSBottomTabsScreenComponentView *tabScreenView =
|
|
101
|
+
(RNSBottomTabsScreenComponentView *)view;
|
|
102
|
+
return tabScreenView.tabKey;
|
|
103
|
+
}
|
|
104
|
+
return @"";
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
+ (void)pushPreloadedView:(nonnull UIView *)view
|
|
108
|
+
ontoStackView:(nonnull UIView *)rawStackView {
|
|
109
|
+
if (![LinkPreviewNativeNavigationObjC isRNSScreenStackView:rawStackView]) {
|
|
110
|
+
NSLog(@"ExpoRouter: The provided stack view is not a RNSScreenStackView.");
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
if (![view isKindOfClass:[RNSScreenView class]]) {
|
|
114
|
+
NSLog(@"ExpoRouter: The provided view is not a RNSScreenView.");
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
RNSScreenStackView *stackView = (RNSScreenStackView *)rawStackView;
|
|
118
|
+
RNSScreenView *preloadedScreenView = (RNSScreenView *)view;
|
|
15
119
|
if (preloadedScreenView != nil && stackView != nil) {
|
|
16
120
|
// Instead of pushing the preloaded screen view, we set its activity state
|
|
17
121
|
// React native screens will then handle the rest.
|
|
@@ -41,7 +145,8 @@
|
|
|
41
145
|
[firstChild isKindOfClass:[RNSScreenView class]]) {
|
|
42
146
|
RNSScreenView *screenContentView = (RNSScreenView *)firstChild;
|
|
43
147
|
// Same as above, we let React Native Screens handle the transition.
|
|
44
|
-
// We need to set the activity of inner screen as well, because its
|
|
148
|
+
// We need to set the activity of inner screen as well, because its
|
|
149
|
+
// react value is the same as the preloaded screen - 0.
|
|
45
150
|
// https://github.com/software-mansion/react-native-screens/blob/8b82e081e8fdfa6e0864821134bda9e87a745b00/src/components/ScreenStackItem.tsx#L151
|
|
46
151
|
[screenContentView setActivityState:2];
|
|
47
152
|
[innerScreenStack markChildUpdated];
|
|
@@ -56,86 +161,4 @@
|
|
|
56
161
|
}
|
|
57
162
|
}
|
|
58
163
|
|
|
59
|
-
- (void)updatePreloadedView:(nullable NSString *)screenId
|
|
60
|
-
withUiResponder:(nonnull UIResponder *)responder {
|
|
61
|
-
if (screenId != nil && [screenId length] > 0) {
|
|
62
|
-
if ([self setPreloadedScreenViewWithScreenId:screenId
|
|
63
|
-
withUiResponder:responder]) {
|
|
64
|
-
NSLog(@"ExpoRouter: Preloaded screen view updated.");
|
|
65
|
-
} else {
|
|
66
|
-
NSLog(@"ExpoRouter: No native screen view found with screenId: %@",
|
|
67
|
-
screenId);
|
|
68
|
-
}
|
|
69
|
-
} else {
|
|
70
|
-
preloadedScreenView = nil;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
- (nonnull NSArray<RNSScreenStackView *> *)
|
|
75
|
-
findAllScreenStackViewsInResponderChain:(nonnull UIResponder *)responder {
|
|
76
|
-
NSMutableArray<RNSScreenStackView *> *stackViews = [NSMutableArray array];
|
|
77
|
-
|
|
78
|
-
while (responder) {
|
|
79
|
-
responder = [responder nextResponder];
|
|
80
|
-
if ([responder isKindOfClass:[RNSScreenStackView class]]) {
|
|
81
|
-
[stackViews addObject:(RNSScreenStackView *)responder];
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
return stackViews;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
- (nonnull NSArray<RNSScreenView *> *)extractScreenViewsFromSubviews:
|
|
89
|
-
(nonnull NSArray<UIView *> *)subviews {
|
|
90
|
-
NSMutableArray<RNSScreenView *> *screenViews = [NSMutableArray array];
|
|
91
|
-
|
|
92
|
-
for (UIView *subview in subviews) {
|
|
93
|
-
if ([subview isKindOfClass:[RNSScreenView class]]) {
|
|
94
|
-
[screenViews addObject:(RNSScreenView *)subview];
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
return screenViews;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
- (BOOL)setPreloadedScreenViewWithScreenId:(nonnull NSString *)screenId
|
|
101
|
-
withUiResponder:(nonnull UIResponder *)responder {
|
|
102
|
-
NSArray<RNSScreenStackView *> *stacks =
|
|
103
|
-
[self findAllScreenStackViewsInResponderChain:responder];
|
|
104
|
-
|
|
105
|
-
for (RNSScreenStackView *stack in stacks) {
|
|
106
|
-
if ([stack.screenIds containsObject:screenId] &&
|
|
107
|
-
[self setPreloadedScreenViewWithScreenId:screenId
|
|
108
|
-
withStackView:stack]) {
|
|
109
|
-
return YES;
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
return NO;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
- (BOOL)setPreloadedScreenViewWithScreenId:(nonnull NSString *)screenId
|
|
116
|
-
withStackView:(nonnull RNSScreenStackView *)stack {
|
|
117
|
-
NSArray<RNSScreenView *> *screenSubviews =
|
|
118
|
-
[self extractScreenViewsFromSubviews:stack.reactSubviews];
|
|
119
|
-
RNSScreenView *screenView = [self findPreloadedScreenView:screenSubviews
|
|
120
|
-
withScreenId:screenId];
|
|
121
|
-
if (screenView != nil) {
|
|
122
|
-
preloadedScreenView = screenView;
|
|
123
|
-
stackView = stack;
|
|
124
|
-
return YES;
|
|
125
|
-
}
|
|
126
|
-
return NO;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
- (nullable RNSScreenView *)
|
|
130
|
-
findPreloadedScreenView:(nonnull NSArray<RNSScreenView *> *)screenViews
|
|
131
|
-
withScreenId:(nonnull NSString *)screenId {
|
|
132
|
-
for (RNSScreenView *screenView in screenViews) {
|
|
133
|
-
if (screenView.activityState == 0 &&
|
|
134
|
-
[screenView.screenId isEqualToString:screenId]) {
|
|
135
|
-
return screenView;
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
return nil;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
164
|
@end
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import UIKit
|
|
2
|
+
|
|
3
|
+
struct TabChangeCommand {
|
|
4
|
+
weak var tabBarController: UITabBarController?
|
|
5
|
+
let tabIndex: Int
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
internal class LinkPreviewNativeNavigation {
|
|
9
|
+
private var preloadedView: UIView?
|
|
10
|
+
private var preloadedStackView: UIView?
|
|
11
|
+
private var tabChangeCommands: [TabChangeCommand] = []
|
|
12
|
+
|
|
13
|
+
init() {}
|
|
14
|
+
|
|
15
|
+
func pushPreloadedView() {
|
|
16
|
+
self.tabChangeCommands.forEach { command in
|
|
17
|
+
command.tabBarController?.selectedIndex = command.tabIndex
|
|
18
|
+
}
|
|
19
|
+
guard let preloadedView,
|
|
20
|
+
let preloadedStackView
|
|
21
|
+
else {
|
|
22
|
+
return
|
|
23
|
+
}
|
|
24
|
+
LinkPreviewNativeNavigationObjC.pushPreloadedView(
|
|
25
|
+
preloadedView, ontoStackView: preloadedStackView)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
func updatePreloadedView(screenId: String?, tabPath: TabPathPayload?, responder: UIView) {
|
|
29
|
+
self.tabChangeCommands = []
|
|
30
|
+
let oldTabKeys = tabPath?.path.map { $0.oldTabKey } ?? []
|
|
31
|
+
let stackOrTabView = findStackViewWithScreenIdOrTabBarController(
|
|
32
|
+
screenId: screenId, tabKeys: oldTabKeys, responder: responder)
|
|
33
|
+
if let stackOrTabView = stackOrTabView {
|
|
34
|
+
if LinkPreviewNativeNavigationObjC.isRNSBottomTabsScreenComponentView(stackOrTabView) {
|
|
35
|
+
let tabView = stackOrTabView
|
|
36
|
+
let newTabKeys = tabPath?.path.map { $0.newTabKey } ?? []
|
|
37
|
+
let stackView = findStackViewWithScreenIdInSubViews(
|
|
38
|
+
screenId: screenId, tabKeys: newTabKeys, rootView: tabView)
|
|
39
|
+
if let stackView = stackView {
|
|
40
|
+
let screenViews = LinkPreviewNativeNavigationObjC.getScreenViews(stackView)
|
|
41
|
+
if let screenView = screenViews.first(where: {
|
|
42
|
+
LinkPreviewNativeNavigationObjC.getScreenId($0) == screenId
|
|
43
|
+
}) {
|
|
44
|
+
preloadedView = screenView
|
|
45
|
+
preloadedStackView = stackView
|
|
46
|
+
print("LinkPreviewNativeNavigation: Preloaded view for screenId \(screenId).")
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
} else if LinkPreviewNativeNavigationObjC.isRNSScreenStackView(stackOrTabView) {
|
|
50
|
+
let stackView = stackOrTabView
|
|
51
|
+
let screenViews = LinkPreviewNativeNavigationObjC.getScreenViews(stackView)
|
|
52
|
+
if let screenView = screenViews.first(where: {
|
|
53
|
+
LinkPreviewNativeNavigationObjC.getScreenId($0) == screenId
|
|
54
|
+
}) {
|
|
55
|
+
preloadedView = screenView
|
|
56
|
+
preloadedStackView = stackView
|
|
57
|
+
print("LinkPreviewNativeNavigation: Preloaded view for screenId \(screenId).")
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
} else {
|
|
61
|
+
print("LinkPreviewNativeNavigation: No stack view found for screenId \(screenId).")
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
private func findStackViewWithScreenIdInSubViews(
|
|
66
|
+
screenId: String?, tabKeys: [String], rootView: UIView
|
|
67
|
+
) -> UIView? {
|
|
68
|
+
if LinkPreviewNativeNavigationObjC.isRNSScreenStackView(rootView),
|
|
69
|
+
let _screenId = screenId {
|
|
70
|
+
let screenIds = LinkPreviewNativeNavigationObjC.getStackViewScreenIds(rootView)
|
|
71
|
+
if screenIds.contains(_screenId) {
|
|
72
|
+
return rootView
|
|
73
|
+
}
|
|
74
|
+
} else if LinkPreviewNativeNavigationObjC.isRNSBottomTabsScreenComponentView(rootView)
|
|
75
|
+
|| LinkPreviewNativeNavigationObjC.isRNSBottomTabsHostComponentView(rootView) {
|
|
76
|
+
let tabBarController = LinkPreviewNativeNavigationObjC.getBottomTabController(from: rootView)
|
|
77
|
+
if let tabBarController = tabBarController {
|
|
78
|
+
let views = tabBarController.viewControllers?.compactMap { $0.view } ?? []
|
|
79
|
+
let enumeratedViews = views.enumerated()
|
|
80
|
+
if let (tabIndex, tabView) =
|
|
81
|
+
enumeratedViews
|
|
82
|
+
.first(where: { _, view in
|
|
83
|
+
LinkPreviewNativeNavigationObjC.isRNSBottomTabsScreenComponentView(view)
|
|
84
|
+
&& tabKeys.contains(LinkPreviewNativeNavigationObjC.getTabKey(view))
|
|
85
|
+
}) {
|
|
86
|
+
self.tabChangeCommands.append(
|
|
87
|
+
TabChangeCommand(tabBarController: tabBarController, tabIndex: tabIndex))
|
|
88
|
+
let test = tabBarController.viewControllers
|
|
89
|
+
|
|
90
|
+
for subview in tabView.subviews {
|
|
91
|
+
let result = findStackViewWithScreenIdInSubViews(
|
|
92
|
+
screenId: screenId, tabKeys: tabKeys, rootView: subview)
|
|
93
|
+
if result != nil {
|
|
94
|
+
return result
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
} else {
|
|
100
|
+
for subview in rootView.subviews {
|
|
101
|
+
let result = findStackViewWithScreenIdInSubViews(
|
|
102
|
+
screenId: screenId, tabKeys: tabKeys, rootView: subview)
|
|
103
|
+
if result != nil {
|
|
104
|
+
return result
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return nil
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
private func findStackViewWithScreenIdOrTabBarController(
|
|
113
|
+
screenId: String?, tabKeys: [String], responder: UIView
|
|
114
|
+
) -> UIView? {
|
|
115
|
+
var currentResponder: UIResponder? = responder
|
|
116
|
+
|
|
117
|
+
while let nextResponder = currentResponder?.next {
|
|
118
|
+
if let view = nextResponder as? UIView,
|
|
119
|
+
LinkPreviewNativeNavigationObjC.isRNSScreenStackView(view),
|
|
120
|
+
let _screenId = screenId {
|
|
121
|
+
let screenIds = LinkPreviewNativeNavigationObjC.getStackViewScreenIds(view)
|
|
122
|
+
if screenIds.contains(_screenId) {
|
|
123
|
+
return view
|
|
124
|
+
}
|
|
125
|
+
} else if let tabView = nextResponder as? UIView,
|
|
126
|
+
LinkPreviewNativeNavigationObjC.isRNSBottomTabsScreenComponentView(tabView) {
|
|
127
|
+
let tabKey = LinkPreviewNativeNavigationObjC.getTabKey(tabView)
|
|
128
|
+
if tabKeys.contains(tabKey) {
|
|
129
|
+
return tabView
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
currentResponder = nextResponder
|
|
133
|
+
}
|
|
134
|
+
return nil
|
|
135
|
+
}
|
|
136
|
+
}
|
|
@@ -1,10 +1,20 @@
|
|
|
1
1
|
import ExpoModulesCore
|
|
2
2
|
|
|
3
|
-
class NativeLinkPreviewView: ExpoView, UIContextMenuInteractionDelegate,
|
|
3
|
+
class NativeLinkPreviewView: ExpoView, UIContextMenuInteractionDelegate,
|
|
4
|
+
LinkPreviewModalDismissible, LinkPreviewMenuUpdatable {
|
|
4
5
|
private var trigger: NativeLinkPreviewTrigger?
|
|
5
6
|
private var preview: NativeLinkPreviewContentView?
|
|
6
7
|
private var interaction: UIContextMenuInteraction?
|
|
7
|
-
|
|
8
|
+
var nextScreenId: String? {
|
|
9
|
+
didSet {
|
|
10
|
+
performUpdateOfPreloadedView()
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
var tabPath: TabPathPayload? {
|
|
14
|
+
didSet {
|
|
15
|
+
performUpdateOfPreloadedView()
|
|
16
|
+
}
|
|
17
|
+
}
|
|
8
18
|
private var actions: [LinkPreviewNativeActionView] = []
|
|
9
19
|
|
|
10
20
|
private let linkPreviewNativeNavigation = LinkPreviewNativeNavigation()
|
|
@@ -15,7 +25,6 @@ class NativeLinkPreviewView: ExpoView, UIContextMenuInteractionDelegate, LinkPre
|
|
|
15
25
|
let onDidPreviewOpen = EventDispatcher()
|
|
16
26
|
let onPreviewWillClose = EventDispatcher()
|
|
17
27
|
let onPreviewDidClose = EventDispatcher()
|
|
18
|
-
let onActionSelected = EventDispatcher()
|
|
19
28
|
|
|
20
29
|
required init(appContext: AppContext? = nil) {
|
|
21
30
|
super.init(appContext: appContext)
|
|
@@ -30,56 +39,62 @@ class NativeLinkPreviewView: ExpoView, UIContextMenuInteractionDelegate, LinkPre
|
|
|
30
39
|
|
|
31
40
|
// MARK: - Props
|
|
32
41
|
|
|
33
|
-
func
|
|
34
|
-
|
|
35
|
-
|
|
42
|
+
func performUpdateOfPreloadedView() {
|
|
43
|
+
if nextScreenId == nil || tabPath?.path.isEmpty != false {
|
|
44
|
+
return
|
|
45
|
+
}
|
|
46
|
+
print("Perform update \(nextScreenId) \(tabPath) \(self)")
|
|
47
|
+
linkPreviewNativeNavigation.updatePreloadedView(
|
|
48
|
+
screenId: nextScreenId, tabPath: tabPath, responder: self)
|
|
36
49
|
}
|
|
37
50
|
|
|
38
51
|
// MARK: - Children
|
|
39
|
-
#if RCT_NEW_ARCH_ENABLED
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
52
|
+
#if RCT_NEW_ARCH_ENABLED
|
|
53
|
+
override func mountChildComponentView(_ childComponentView: UIView, index: Int) {
|
|
54
|
+
if let triggerView = childComponentView as? NativeLinkPreviewTrigger {
|
|
55
|
+
trigger = triggerView
|
|
56
|
+
if let interaction = self.interaction {
|
|
57
|
+
triggerView.addInteraction(interaction)
|
|
58
|
+
}
|
|
59
|
+
super.mountChildComponentView(childComponentView, index: index)
|
|
60
|
+
} else if let previewView = childComponentView as? NativeLinkPreviewContentView {
|
|
61
|
+
preview = previewView
|
|
62
|
+
if let interaction = self.interaction, let trigger = self.trigger {
|
|
63
|
+
trigger.addInteraction(interaction)
|
|
64
|
+
}
|
|
65
|
+
} else if let actionView = childComponentView as? LinkPreviewNativeActionView {
|
|
66
|
+
actionView.parentMenuUpdatable = self
|
|
67
|
+
actions.append(actionView)
|
|
68
|
+
} else {
|
|
69
|
+
print(
|
|
70
|
+
"ExpoRouter: Unknown child component view (\(childComponentView)) mounted to NativeLinkPreviewView"
|
|
71
|
+
)
|
|
45
72
|
}
|
|
46
|
-
super.mountChildComponentView(childComponentView, index: index)
|
|
47
|
-
} else if let previewView = childComponentView as? NativeLinkPreviewContentView {
|
|
48
|
-
preview = previewView
|
|
49
|
-
if let interaction = self.interaction, let trigger = self.trigger {
|
|
50
|
-
trigger.addInteraction(interaction)
|
|
51
|
-
}
|
|
52
|
-
} else if let actionView = childComponentView as? LinkPreviewNativeActionView {
|
|
53
|
-
actions.append(actionView)
|
|
54
|
-
} else {
|
|
55
|
-
print(
|
|
56
|
-
"ExpoRouter: Unknown child component view (\(childComponentView)) mounted to NativeLinkPreviewView"
|
|
57
|
-
)
|
|
58
73
|
}
|
|
59
|
-
}
|
|
60
74
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
75
|
+
override func unmountChildComponentView(_ child: UIView, index: Int) {
|
|
76
|
+
if child is NativeLinkPreviewTrigger {
|
|
77
|
+
if let interaction = self.interaction {
|
|
78
|
+
trigger?.removeInteraction(interaction)
|
|
79
|
+
}
|
|
80
|
+
trigger = nil
|
|
81
|
+
super.unmountChildComponentView(child, index: index)
|
|
82
|
+
} else if child is NativeLinkPreviewContentView {
|
|
83
|
+
preview = nil
|
|
84
|
+
if let interaction = self.interaction {
|
|
85
|
+
trigger?.removeInteraction(interaction)
|
|
86
|
+
}
|
|
87
|
+
} else if let actionView = child as? LinkPreviewNativeActionView {
|
|
88
|
+
actions.removeAll(where: {
|
|
89
|
+
$0 == actionView
|
|
90
|
+
})
|
|
91
|
+
} else {
|
|
92
|
+
print(
|
|
93
|
+
"ExpoRouter: Unknown child component view (\(child)) unmounted from NativeLinkPreviewView"
|
|
94
|
+
)
|
|
65
95
|
}
|
|
66
|
-
trigger = nil
|
|
67
|
-
super.unmountChildComponentView(child, index: index)
|
|
68
|
-
} else if child is NativeLinkPreviewContentView {
|
|
69
|
-
preview = nil
|
|
70
|
-
if let interaction = self.interaction {
|
|
71
|
-
trigger?.removeInteraction(interaction)
|
|
72
|
-
}
|
|
73
|
-
} else if let actionView = child as? LinkPreviewNativeActionView {
|
|
74
|
-
actions.removeAll(where: {
|
|
75
|
-
$0 == actionView
|
|
76
|
-
})
|
|
77
|
-
} else {
|
|
78
|
-
print(
|
|
79
|
-
"ExpoRouter: Unknown child component view (\(child)) unmounted from NativeLinkPreviewView")
|
|
80
96
|
}
|
|
81
|
-
|
|
82
|
-
#endif
|
|
97
|
+
#endif
|
|
83
98
|
|
|
84
99
|
// MARK: - UIContextMenuInteractionDelegate
|
|
85
100
|
|
|
@@ -154,9 +169,9 @@ class NativeLinkPreviewView: ExpoView, UIContextMenuInteractionDelegate, LinkPre
|
|
|
154
169
|
|
|
155
170
|
// MARK: - Context Menu Helpers
|
|
156
171
|
|
|
157
|
-
private func createPreviewViewController() -> UIViewController {
|
|
172
|
+
private func createPreviewViewController() -> UIViewController? {
|
|
158
173
|
guard let preview = preview else {
|
|
159
|
-
return
|
|
174
|
+
return nil
|
|
160
175
|
}
|
|
161
176
|
|
|
162
177
|
let vc = PreviewViewController(linkPreviewNativePreview: preview)
|
|
@@ -167,38 +182,23 @@ class NativeLinkPreviewView: ExpoView, UIContextMenuInteractionDelegate, LinkPre
|
|
|
167
182
|
return vc
|
|
168
183
|
}
|
|
169
184
|
|
|
185
|
+
func updateMenu() {
|
|
186
|
+
self.interaction?.updateVisibleMenu { _ in
|
|
187
|
+
self.createContextMenu()
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
170
191
|
private func createContextMenu() -> UIMenu {
|
|
171
|
-
if actions.count == 1, let menu =
|
|
192
|
+
if actions.count == 1, let menu = actions[0].uiAction as? UIMenu {
|
|
172
193
|
return menu
|
|
173
194
|
}
|
|
174
195
|
return UIMenu(
|
|
175
196
|
title: "",
|
|
176
197
|
children: actions.map { action in
|
|
177
|
-
|
|
198
|
+
action.uiAction
|
|
178
199
|
}
|
|
179
200
|
)
|
|
180
201
|
}
|
|
181
|
-
|
|
182
|
-
private func convertActionViewToUiAction(_ action: LinkPreviewNativeActionView) -> UIMenuElement {
|
|
183
|
-
if !action.subActions.isEmpty {
|
|
184
|
-
let subActions = action.subActions.map { subAction in
|
|
185
|
-
self.convertActionViewToUiAction(subAction)
|
|
186
|
-
}
|
|
187
|
-
return UIMenu(
|
|
188
|
-
title: action.title,
|
|
189
|
-
image: action.icon.flatMap { UIImage(systemName: $0) },
|
|
190
|
-
children: subActions
|
|
191
|
-
)
|
|
192
|
-
}
|
|
193
|
-
return UIAction(
|
|
194
|
-
title: action.title,
|
|
195
|
-
image: action.icon.flatMap { UIImage(systemName: $0) }
|
|
196
|
-
) { _ in
|
|
197
|
-
self.onActionSelected([
|
|
198
|
-
"id": action.id
|
|
199
|
-
])
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
202
|
}
|
|
203
203
|
|
|
204
204
|
class PreviewViewController: UIViewController {
|