expo-router 5.2.0-canary-20250729-d8899ae → 6.0.0-beta.0

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.
Files changed (215) hide show
  1. package/_ctx.android.js +1 -1
  2. package/_ctx.ios.js +1 -1
  3. package/_ctx.web.js +1 -1
  4. package/assets/modal.module.css +12 -3
  5. package/build/ExpoRoot.d.ts.map +1 -1
  6. package/build/ExpoRoot.js +12 -2
  7. package/build/ExpoRoot.js.map +1 -1
  8. package/build/Route.d.ts +9 -0
  9. package/build/Route.d.ts.map +1 -1
  10. package/build/Route.js.map +1 -1
  11. package/build/constants.d.ts +2 -0
  12. package/build/constants.d.ts.map +1 -1
  13. package/build/constants.js +3 -1
  14. package/build/constants.js.map +1 -1
  15. package/build/doctor/index.d.ts +1 -1
  16. package/build/doctor/index.d.ts.map +1 -1
  17. package/build/doctor/index.js +4 -1
  18. package/build/doctor/index.js.map +1 -1
  19. package/build/exports.d.ts +2 -2
  20. package/build/exports.d.ts.map +1 -1
  21. package/build/exports.js +6 -6
  22. package/build/exports.js.map +1 -1
  23. package/build/fork/native-stack/createNativeStackNavigator.d.ts +2 -2
  24. package/build/fork/native-stack/createNativeStackNavigator.d.ts.map +1 -1
  25. package/build/fork/native-stack/createNativeStackNavigator.js +82 -2
  26. package/build/fork/native-stack/createNativeStackNavigator.js.map +1 -1
  27. package/build/fork/useLinking.js +2 -2
  28. package/build/fork/useLinking.js.map +1 -1
  29. package/build/getLinkingConfig.d.ts +29 -2
  30. package/build/getLinkingConfig.d.ts.map +1 -1
  31. package/build/getLinkingConfig.js +35 -4
  32. package/build/getLinkingConfig.js.map +1 -1
  33. package/build/getRoutesCore.d.ts +1 -0
  34. package/build/getRoutesCore.d.ts.map +1 -1
  35. package/build/getRoutesCore.js +60 -0
  36. package/build/getRoutesCore.js.map +1 -1
  37. package/build/getServerManifest.d.ts +20 -1
  38. package/build/getServerManifest.d.ts.map +1 -1
  39. package/build/getServerManifest.js +8 -1
  40. package/build/getServerManifest.js.map +1 -1
  41. package/build/global-state/routeInfo.d.ts.map +1 -1
  42. package/build/global-state/routeInfo.js +12 -1
  43. package/build/global-state/routeInfo.js.map +1 -1
  44. package/build/global-state/router-store.d.ts.map +1 -1
  45. package/build/global-state/router-store.js +4 -0
  46. package/build/global-state/router-store.js.map +1 -1
  47. package/build/global-state/routing.d.ts +29 -1
  48. package/build/global-state/routing.d.ts.map +1 -1
  49. package/build/global-state/routing.js +78 -42
  50. package/build/global-state/routing.js.map +1 -1
  51. package/build/global-state/utils.d.ts +4 -0
  52. package/build/global-state/utils.d.ts.map +1 -0
  53. package/build/global-state/utils.js +29 -0
  54. package/build/global-state/utils.js.map +1 -0
  55. package/build/hooks.d.ts +1 -1
  56. package/build/hooks.d.ts.map +1 -1
  57. package/build/hooks.js +9 -4
  58. package/build/hooks.js.map +1 -1
  59. package/build/layouts/DrawerClient.d.ts +2 -2
  60. package/build/layouts/Stack.web.d.ts +1 -1
  61. package/build/layouts/Stack.web.d.ts.map +1 -1
  62. package/build/layouts/Stack.web.js +3 -3
  63. package/build/layouts/Stack.web.js.map +1 -1
  64. package/build/layouts/StackClient.d.ts +2 -2
  65. package/build/layouts/StackClient.d.ts.map +1 -1
  66. package/build/layouts/StackClient.js +18 -14
  67. package/build/layouts/StackClient.js.map +1 -1
  68. package/build/layouts/TabsClient.d.ts +3 -3
  69. package/build/layouts/withLayoutContext.d.ts.map +1 -1
  70. package/build/layouts/withLayoutContext.js +13 -0
  71. package/build/layouts/withLayoutContext.js.map +1 -1
  72. package/build/link/ExpoLink.d.ts.map +1 -1
  73. package/build/link/ExpoLink.js +3 -2
  74. package/build/link/ExpoLink.js.map +1 -1
  75. package/build/link/InternalLinkPreviewContext.d.ts +6 -0
  76. package/build/link/InternalLinkPreviewContext.d.ts.map +1 -0
  77. package/build/link/InternalLinkPreviewContext.js +6 -0
  78. package/build/link/InternalLinkPreviewContext.js.map +1 -0
  79. package/build/link/Link.d.ts +2 -67
  80. package/build/link/Link.d.ts.map +1 -1
  81. package/build/link/Link.js +5 -70
  82. package/build/link/Link.js.map +1 -1
  83. package/build/link/LinkWithPreview.d.ts +1 -46
  84. package/build/link/LinkWithPreview.d.ts.map +1 -1
  85. package/build/link/LinkWithPreview.js +30 -114
  86. package/build/link/LinkWithPreview.js.map +1 -1
  87. package/build/link/elements.d.ts +174 -0
  88. package/build/link/elements.d.ts.map +1 -0
  89. package/build/link/elements.js +172 -0
  90. package/build/link/elements.js.map +1 -0
  91. package/build/link/preview/HrefPreview.d.ts +1 -1
  92. package/build/link/preview/HrefPreview.d.ts.map +1 -1
  93. package/build/link/preview/HrefPreview.js +61 -7
  94. package/build/link/preview/HrefPreview.js.map +1 -1
  95. package/build/link/preview/LinkPreviewContext.d.ts +3 -2
  96. package/build/link/preview/LinkPreviewContext.d.ts.map +1 -1
  97. package/build/link/preview/LinkPreviewContext.js +3 -2
  98. package/build/link/preview/LinkPreviewContext.js.map +1 -1
  99. package/build/link/preview/native.d.ts +14 -6
  100. package/build/link/preview/native.d.ts.map +1 -1
  101. package/build/link/preview/native.js.map +1 -1
  102. package/build/link/preview/useNextScreenId.d.ts +8 -1
  103. package/build/link/preview/useNextScreenId.d.ts.map +1 -1
  104. package/build/link/preview/useNextScreenId.js +36 -32
  105. package/build/link/preview/useNextScreenId.js.map +1 -1
  106. package/build/link/preview/utils.d.ts +12 -0
  107. package/build/link/preview/utils.d.ts.map +1 -0
  108. package/build/link/preview/utils.js +66 -0
  109. package/build/link/preview/utils.js.map +1 -0
  110. package/build/modal/Modal.js +1 -1
  111. package/build/modal/Modal.js.map +1 -1
  112. package/build/modal/ModalsRenderer.js +1 -1
  113. package/build/modal/ModalsRenderer.js.map +1 -1
  114. package/build/modal/ModalsRenderer.web.js +4 -4
  115. package/build/modal/ModalsRenderer.web.js.map +1 -1
  116. package/build/modal/web/{ModalStack.web.d.ts → ModalStack.d.ts} +1 -1
  117. package/build/modal/web/ModalStack.d.ts.map +1 -0
  118. package/build/modal/web/{ModalStack.web.js → ModalStack.js} +5 -5
  119. package/build/modal/web/ModalStack.js.map +1 -0
  120. package/build/modal/web/{ModalStackRouteDrawer.web.d.ts → ModalStackRouteDrawer.d.ts} +1 -1
  121. package/build/modal/web/ModalStackRouteDrawer.d.ts.map +1 -0
  122. package/build/modal/web/{ModalStackRouteDrawer.web.js → ModalStackRouteDrawer.js} +1 -2
  123. package/build/modal/web/ModalStackRouteDrawer.js.map +1 -0
  124. package/build/modal/web/{TransparentModalStackRouteDrawer.web.d.ts → TransparentModalStackRouteDrawer.d.ts} +1 -1
  125. package/build/modal/web/TransparentModalStackRouteDrawer.d.ts.map +1 -0
  126. package/build/modal/web/{TransparentModalStackRouteDrawer.web.js → TransparentModalStackRouteDrawer.js} +1 -1
  127. package/build/modal/web/TransparentModalStackRouteDrawer.js.map +1 -0
  128. package/build/native-tabs/NativeBottomTabs/NativeBottomTabsNavigator.d.ts +17 -0
  129. package/build/native-tabs/NativeBottomTabs/NativeBottomTabsNavigator.d.ts.map +1 -0
  130. package/build/native-tabs/NativeBottomTabs/NativeBottomTabsNavigator.js +27 -0
  131. package/build/native-tabs/NativeBottomTabs/NativeBottomTabsNavigator.js.map +1 -0
  132. package/build/native-tabs/NativeBottomTabs/NativeBottomTabsRouter.d.ts +3 -0
  133. package/build/native-tabs/NativeBottomTabs/NativeBottomTabsRouter.d.ts.map +1 -0
  134. package/build/native-tabs/NativeBottomTabs/NativeBottomTabsRouter.js +65 -0
  135. package/build/native-tabs/NativeBottomTabs/NativeBottomTabsRouter.js.map +1 -0
  136. package/build/native-tabs/NativeBottomTabs/NativeTabTrigger.d.ts +47 -0
  137. package/build/native-tabs/NativeBottomTabs/NativeTabTrigger.d.ts.map +1 -0
  138. package/build/native-tabs/NativeBottomTabs/NativeTabTrigger.js +153 -0
  139. package/build/native-tabs/NativeBottomTabs/NativeTabTrigger.js.map +1 -0
  140. package/build/native-tabs/NativeBottomTabs/NativeTabs.d.ts +24 -0
  141. package/build/native-tabs/NativeBottomTabs/NativeTabs.d.ts.map +1 -0
  142. package/build/native-tabs/NativeBottomTabs/NativeTabs.js +27 -0
  143. package/build/native-tabs/NativeBottomTabs/NativeTabs.js.map +1 -0
  144. package/build/native-tabs/NativeBottomTabs/NativeTabsView.d.ts +4 -0
  145. package/build/native-tabs/NativeBottomTabs/NativeTabsView.d.ts.map +1 -0
  146. package/build/native-tabs/NativeBottomTabs/NativeTabsView.js +116 -0
  147. package/build/native-tabs/NativeBottomTabs/NativeTabsView.js.map +1 -0
  148. package/build/native-tabs/NativeBottomTabs/types.d.ts +166 -0
  149. package/build/native-tabs/NativeBottomTabs/types.d.ts.map +1 -0
  150. package/build/native-tabs/NativeBottomTabs/types.js +3 -0
  151. package/build/native-tabs/NativeBottomTabs/types.js.map +1 -0
  152. package/build/native-tabs/NativeBottomTabs/utils.d.ts +7 -0
  153. package/build/native-tabs/NativeBottomTabs/utils.d.ts.map +1 -0
  154. package/build/native-tabs/NativeBottomTabs/utils.js +21 -0
  155. package/build/native-tabs/NativeBottomTabs/utils.js.map +1 -0
  156. package/build/native-tabs/common/elements.d.ts +74 -0
  157. package/build/native-tabs/common/elements.d.ts.map +1 -0
  158. package/build/native-tabs/common/elements.js +21 -0
  159. package/build/native-tabs/common/elements.js.map +1 -0
  160. package/build/native-tabs/index.d.ts +5 -0
  161. package/build/native-tabs/index.d.ts.map +1 -0
  162. package/build/native-tabs/index.js +23 -0
  163. package/build/native-tabs/index.js.map +1 -0
  164. package/build/routes-manifest.d.ts +42 -0
  165. package/build/routes-manifest.d.ts.map +1 -1
  166. package/build/routes-manifest.js.map +1 -1
  167. package/build/rsc/middleware.d.ts +1 -1
  168. package/build/rsc/middleware.d.ts.map +1 -1
  169. package/build/rsc/middleware.js.map +1 -1
  170. package/build/testing-library/mock-config.d.ts +18 -0
  171. package/build/testing-library/mock-config.d.ts.map +1 -1
  172. package/build/testing-library/mock-config.js +4 -1
  173. package/build/testing-library/mock-config.js.map +1 -1
  174. package/build/ui/common.d.ts.map +1 -1
  175. package/build/ui/common.js +7 -6
  176. package/build/ui/common.js.map +1 -1
  177. package/build/useNavigation.d.ts.map +1 -1
  178. package/build/useNavigation.js +8 -5
  179. package/build/useNavigation.js.map +1 -1
  180. package/build/views/NoSSR.d.ts +5 -0
  181. package/build/views/NoSSR.d.ts.map +1 -0
  182. package/build/views/NoSSR.js +22 -0
  183. package/build/views/NoSSR.js.map +1 -0
  184. package/build/views/Screen.d.ts.map +1 -1
  185. package/build/views/Screen.js +4 -1
  186. package/build/views/Screen.js.map +1 -1
  187. package/build/views/Sitemap.d.ts.map +1 -1
  188. package/build/views/Sitemap.js +113 -10
  189. package/build/views/Sitemap.js.map +1 -1
  190. package/build/views/Unmatched.d.ts.map +1 -1
  191. package/build/views/Unmatched.js +14 -4
  192. package/build/views/Unmatched.js.map +1 -1
  193. package/ios/ExpoHead.podspec +10 -1
  194. package/ios/LinkPreview/LinkPreviewNativeActionView.swift +159 -21
  195. package/ios/LinkPreview/LinkPreviewNativeModule.swift +44 -6
  196. package/ios/LinkPreview/LinkPreviewNativeNavigation.h +37 -11
  197. package/ios/LinkPreview/LinkPreviewNativeNavigation.mm +110 -87
  198. package/ios/LinkPreview/LinkPreviewNativeNavigation.swift +136 -0
  199. package/ios/LinkPreview/LinkPreviewNativePreviewView.swift +0 -1
  200. package/ios/LinkPreview/LinkPreviewNativeTriggerView.swift +1 -1
  201. package/ios/LinkPreview/LinkPreviewNativeView.swift +72 -71
  202. package/package.json +42 -10
  203. package/plugin/build/index.d.ts +2 -0
  204. package/plugin/options.json +5 -0
  205. package/plugin/src/index.ts +2 -0
  206. package/plugin/tsconfig.tsbuildinfo +1 -0
  207. package/server.d.ts +2 -1
  208. package/unstable-native-tabs.d.ts +1 -0
  209. package/unstable-native-tabs.js +1 -0
  210. package/build/modal/web/ModalStack.web.d.ts.map +0 -1
  211. package/build/modal/web/ModalStack.web.js.map +0 -1
  212. package/build/modal/web/ModalStackRouteDrawer.web.d.ts.map +0 -1
  213. package/build/modal/web/ModalStackRouteDrawer.web.js.map +0 -1
  214. package/build/modal/web/TransparentModalStackRouteDrawer.web.d.ts.map +0 -1
  215. package/build/modal/web/TransparentModalStackRouteDrawer.web.js.map +0 -1
@@ -6,7 +6,11 @@ public class LinkPreviewNativeModule: Module {
6
6
 
7
7
  View(NativeLinkPreviewView.self) {
8
8
  Prop("nextScreenId") { (view: NativeLinkPreviewView, nextScreenId: String) in
9
- view.setNextScreenId(nextScreenId)
9
+ view.nextScreenId = nextScreenId
10
+ }
11
+
12
+ Prop("tabPath") { (view: NativeLinkPreviewView, tabPath: TabPathPayload) in
13
+ view.tabPath = tabPath
10
14
  }
11
15
 
12
16
  Events(
@@ -16,7 +20,6 @@ public class LinkPreviewNativeModule: Module {
16
20
  "onDidPreviewOpen",
17
21
  "onPreviewWillClose",
18
22
  "onPreviewDidClose",
19
- "onActionSelected"
20
23
  )
21
24
  }
22
25
 
@@ -38,17 +41,52 @@ public class LinkPreviewNativeModule: Module {
38
41
  }
39
42
 
40
43
  View(LinkPreviewNativeActionView.self) {
41
- Prop("id") { (view: LinkPreviewNativeActionView, id: String) in
42
- view.id = id
43
- }
44
44
  Prop("title") { (view: LinkPreviewNativeActionView, title: String) in
45
45
  view.title = title
46
46
  }
47
47
  Prop("icon") { (view: LinkPreviewNativeActionView, icon: String) in
48
48
  view.icon = icon
49
49
  }
50
+ Prop("disabled") { (view: LinkPreviewNativeActionView, disabled: Bool) in
51
+ view.disabled = disabled
52
+ }
53
+ Prop("destructive") { (view: LinkPreviewNativeActionView, destructive: Bool) in
54
+ view.destructive = destructive
55
+ }
56
+ Prop("singleSelection") { (view: LinkPreviewNativeActionView, singleSelection: Bool) in
57
+ view.singleSelection = singleSelection
58
+ }
59
+ Prop("displayAsPalette") { (view: LinkPreviewNativeActionView, displayAsPalette: Bool) in
60
+ view.displayAsPalette = displayAsPalette
61
+ }
62
+ Prop("isOn") { (view: LinkPreviewNativeActionView, isOn: Bool) in
63
+ view.isOn = isOn
64
+ }
65
+ Prop("keepPresented") { (view: LinkPreviewNativeActionView, keepPresented: Bool) in
66
+ view.keepPresented = keepPresented
67
+ }
68
+ Prop("displayInline") { (view: LinkPreviewNativeActionView, displayInline: Bool) in
69
+ view.displayInline = displayInline
70
+ }
71
+
72
+ Events("onSelected")
50
73
  }
51
74
 
52
- View(NativeLinkPreviewTrigger.self) {}
75
+ View(NativeLinkPreviewTrigger.self) {
76
+ Prop("borderRadius") { (view, borderRadius: Double?) in
77
+ if let borderRadius = borderRadius {
78
+ view.triggerBorderRadius = borderRadius
79
+ }
80
+ }
81
+ }
53
82
  }
54
83
  }
84
+
85
+ struct TabPathPayload: Record {
86
+ @Field var path: [TabStatePath]
87
+ }
88
+
89
+ struct TabStatePath: Record {
90
+ @Field var oldTabKey: String
91
+ @Field var newTabKey: String
92
+ }
@@ -1,24 +1,50 @@
1
1
  // Copyright 2015-present 650 Industries. All rights reserved.
2
2
 
3
- #import <RNScreens/RNSScreenStack.h>
3
+ #import <RNScreens/RNSDismissibleModalProtocol.h>
4
+ #import <RNScreens/RNSTabBarController.h>
4
5
 
5
- @interface LinkPreviewNativeNavigation: NSObject
6
+ @interface LinkPreviewNativeNavigationObjC : NSObject
6
7
 
7
8
  /*
8
- * Updates the preloaded view with the given screenId and UIResponder.
9
- * This function will go through the responder's view hierarchy to find the screen view with the given screenId and activity state 0.
10
- */
11
- - (void)updatePreloadedView:(NSString *)screenId withUiResponder:(UIResponder *)responder;
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
- * Pushes the previously preloaded view.
15
- * This function will set the activity state of the preloaded screen view to 2
16
- */
17
- - (void)pushPreloadedView;
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 LinkPreviewNativeNavigation {
10
- RNSScreenView *preloadedScreenView;
11
- RNSScreenStackView *stackView;
9
+ @implementation LinkPreviewNativeNavigationObjC {
12
10
  }
13
11
 
14
- - (void)pushPreloadedView {
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 react value is the same as the preloaded screen - 0.
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
+ }
@@ -6,7 +6,6 @@ class NativeLinkPreviewContentView: ExpoView {
6
6
 
7
7
  required init(appContext: AppContext? = nil) {
8
8
  super.init(appContext: appContext)
9
- clipsToBounds = true
10
9
  }
11
10
 
12
11
  func setInitialSize(bounds: CGRect) {
@@ -2,8 +2,8 @@ import ExpoModulesCore
2
2
  import WebKit
3
3
 
4
4
  class NativeLinkPreviewTrigger: ExpoView {
5
+ var triggerBorderRadius: Double = 0
5
6
  required init(appContext: AppContext? = nil) {
6
7
  super.init(appContext: appContext)
7
- clipsToBounds = true
8
8
  }
9
9
  }