expo-router 7.0.0-canary-20251120-e46b3cc → 7.0.0-canary-20251205-756eb7a

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 (227) hide show
  1. package/android/build.gradle +2 -2
  2. package/build/fork/getStateFromPath-forks.d.ts +5 -10
  3. package/build/fork/getStateFromPath-forks.d.ts.map +1 -1
  4. package/build/fork/getStateFromPath-forks.js +14 -13
  5. package/build/fork/getStateFromPath-forks.js.map +1 -1
  6. package/build/fork/getStateFromPath.js +3 -3
  7. package/build/fork/getStateFromPath.js.map +1 -1
  8. package/build/fork/native-stack/createNativeStackNavigator.d.ts.map +1 -1
  9. package/build/fork/native-stack/createNativeStackNavigator.js +25 -7
  10. package/build/fork/native-stack/createNativeStackNavigator.js.map +1 -1
  11. package/build/fork/native-stack/descriptors-context.d.ts +8 -0
  12. package/build/fork/native-stack/descriptors-context.d.ts.map +1 -0
  13. package/build/fork/native-stack/descriptors-context.js +6 -0
  14. package/build/fork/native-stack/descriptors-context.js.map +1 -0
  15. package/build/internal/utils.d.ts +1 -0
  16. package/build/internal/utils.d.ts.map +1 -1
  17. package/build/internal/utils.js +3 -1
  18. package/build/internal/utils.js.map +1 -1
  19. package/build/layouts/StackClient.d.ts.map +1 -1
  20. package/build/layouts/StackClient.js +39 -5
  21. package/build/layouts/StackClient.js.map +1 -1
  22. package/build/layouts/stack-utils/StackHeaderComponent.js +6 -6
  23. package/build/layouts/stack-utils/StackHeaderComponent.js.map +1 -1
  24. package/build/layouts/stack-utils/StackHeaderTitle.d.ts.map +1 -1
  25. package/build/layouts/stack-utils/StackHeaderTitle.js +3 -8
  26. package/build/layouts/stack-utils/StackHeaderTitle.js.map +1 -1
  27. package/build/layouts/stack-utils/index.d.ts +0 -1
  28. package/build/layouts/stack-utils/index.d.ts.map +1 -1
  29. package/build/layouts/stack-utils/index.js +1 -3
  30. package/build/layouts/stack-utils/index.js.map +1 -1
  31. package/build/link/ExpoLink.d.ts.map +1 -1
  32. package/build/link/ExpoLink.js +12 -4
  33. package/build/link/ExpoLink.js.map +1 -1
  34. package/build/link/Link.d.ts +2 -0
  35. package/build/link/Link.d.ts.map +1 -1
  36. package/build/link/Link.js +2 -0
  37. package/build/link/Link.js.map +1 -1
  38. package/build/link/LinkWithPreview.d.ts +6 -1
  39. package/build/link/LinkWithPreview.d.ts.map +1 -1
  40. package/build/link/LinkWithPreview.js +10 -11
  41. package/build/link/LinkWithPreview.js.map +1 -1
  42. package/build/link/elements.d.ts +8 -0
  43. package/build/link/elements.d.ts.map +1 -1
  44. package/build/link/elements.js +7 -2
  45. package/build/link/elements.js.map +1 -1
  46. package/build/link/preview/native.d.ts +17 -0
  47. package/build/link/preview/native.d.ts.map +1 -1
  48. package/build/link/preview/native.js +22 -0
  49. package/build/link/preview/native.js.map +1 -1
  50. package/build/link/zoom/ZoomTransitionEnabler.d.ts +5 -0
  51. package/build/link/zoom/ZoomTransitionEnabler.d.ts.map +1 -0
  52. package/build/link/zoom/ZoomTransitionEnabler.ios.d.ts +5 -0
  53. package/build/link/zoom/ZoomTransitionEnabler.ios.d.ts.map +1 -0
  54. package/build/link/zoom/ZoomTransitionEnabler.ios.js +44 -0
  55. package/build/link/zoom/ZoomTransitionEnabler.ios.js.map +1 -0
  56. package/build/link/zoom/ZoomTransitionEnabler.js +13 -0
  57. package/build/link/zoom/ZoomTransitionEnabler.js.map +1 -0
  58. package/build/link/zoom/ZoomTransitionEnabler.types.d.ts +4 -0
  59. package/build/link/zoom/ZoomTransitionEnabler.types.d.ts.map +1 -0
  60. package/build/link/zoom/ZoomTransitionEnabler.types.js +3 -0
  61. package/build/link/zoom/ZoomTransitionEnabler.types.js.map +1 -0
  62. package/build/link/zoom/link-apple-zoom.d.ts +23 -0
  63. package/build/link/zoom/link-apple-zoom.d.ts.map +1 -0
  64. package/build/link/zoom/link-apple-zoom.js +40 -0
  65. package/build/link/zoom/link-apple-zoom.js.map +1 -0
  66. package/build/link/zoom/useZoomTransitionPrimitives.d.ts +6 -0
  67. package/build/link/zoom/useZoomTransitionPrimitives.d.ts.map +1 -0
  68. package/build/link/zoom/useZoomTransitionPrimitives.ios.d.ts +11 -0
  69. package/build/link/zoom/useZoomTransitionPrimitives.ios.d.ts.map +1 -0
  70. package/build/link/zoom/useZoomTransitionPrimitives.ios.js +66 -0
  71. package/build/link/zoom/useZoomTransitionPrimitives.ios.js.map +1 -0
  72. package/build/link/zoom/useZoomTransitionPrimitives.js +9 -0
  73. package/build/link/zoom/useZoomTransitionPrimitives.js.map +1 -0
  74. package/build/link/zoom/zoom-transition-context.d.ts +7 -0
  75. package/build/link/zoom/zoom-transition-context.d.ts.map +1 -0
  76. package/build/link/zoom/zoom-transition-context.js +6 -0
  77. package/build/link/zoom/zoom-transition-context.js.map +1 -0
  78. package/build/native-tabs/NativeBottomTabsNavigator.d.ts +3 -15
  79. package/build/native-tabs/NativeBottomTabsNavigator.d.ts.map +1 -1
  80. package/build/native-tabs/NativeBottomTabsNavigator.js +17 -2
  81. package/build/native-tabs/NativeBottomTabsNavigator.js.map +1 -1
  82. package/build/native-tabs/NativeBottomTabsRouter.d.ts.map +1 -1
  83. package/build/native-tabs/NativeBottomTabsRouter.js +12 -1
  84. package/build/native-tabs/NativeBottomTabsRouter.js.map +1 -1
  85. package/build/native-tabs/NativeTabTrigger.d.ts +2 -2
  86. package/build/native-tabs/NativeTabTrigger.d.ts.map +1 -1
  87. package/build/native-tabs/NativeTabTrigger.js +24 -14
  88. package/build/native-tabs/NativeTabTrigger.js.map +1 -1
  89. package/build/native-tabs/NativeTabs.d.ts +6 -3
  90. package/build/native-tabs/NativeTabs.d.ts.map +1 -1
  91. package/build/native-tabs/NativeTabs.js +7 -2
  92. package/build/native-tabs/NativeTabs.js.map +1 -1
  93. package/build/native-tabs/NativeTabsView.d.ts.map +1 -1
  94. package/build/native-tabs/NativeTabsView.js +26 -3
  95. package/build/native-tabs/NativeTabsView.js.map +1 -1
  96. package/build/native-tabs/appearance.d.ts.map +1 -1
  97. package/build/native-tabs/appearance.js +2 -4
  98. package/build/native-tabs/appearance.js.map +1 -1
  99. package/build/native-tabs/common/elements.d.ts +36 -3
  100. package/build/native-tabs/common/elements.d.ts.map +1 -1
  101. package/build/native-tabs/common/elements.js +30 -1
  102. package/build/native-tabs/common/elements.js.map +1 -1
  103. package/build/native-tabs/hooks.d.ts +45 -0
  104. package/build/native-tabs/hooks.d.ts.map +1 -0
  105. package/build/native-tabs/hooks.js +57 -0
  106. package/build/native-tabs/hooks.js.map +1 -0
  107. package/build/native-tabs/index.d.ts +1 -1
  108. package/build/native-tabs/index.d.ts.map +1 -1
  109. package/build/native-tabs/index.js.map +1 -1
  110. package/build/native-tabs/types.d.ts +42 -55
  111. package/build/native-tabs/types.d.ts.map +1 -1
  112. package/build/native-tabs/types.js.map +1 -1
  113. package/build/native-tabs/utils/bottomAccessory.d.ts +9 -0
  114. package/build/native-tabs/utils/bottomAccessory.d.ts.map +1 -0
  115. package/build/native-tabs/utils/bottomAccessory.js +17 -0
  116. package/build/native-tabs/utils/bottomAccessory.js.map +1 -0
  117. package/build/native-tabs/utils/icon.d.ts +3 -0
  118. package/build/native-tabs/utils/icon.d.ts.map +1 -1
  119. package/build/native-tabs/utils/icon.js +16 -0
  120. package/build/native-tabs/utils/icon.js.map +1 -1
  121. package/build/native-tabs/utils/index.d.ts +0 -1
  122. package/build/native-tabs/utils/index.d.ts.map +1 -1
  123. package/build/native-tabs/utils/index.js +1 -4
  124. package/build/native-tabs/utils/index.js.map +1 -1
  125. package/build/native-tabs/utils/label.d.ts.map +1 -1
  126. package/build/native-tabs/utils/label.js +6 -2
  127. package/build/native-tabs/utils/label.js.map +1 -1
  128. package/build/native-tabs/utils/materialIconConverter.android.d.ts +4 -0
  129. package/build/native-tabs/utils/materialIconConverter.android.d.ts.map +1 -0
  130. package/build/native-tabs/utils/materialIconConverter.android.js +10 -0
  131. package/build/native-tabs/utils/materialIconConverter.android.js.map +1 -0
  132. package/build/native-tabs/utils/materialIconConverter.d.ts +4 -0
  133. package/build/native-tabs/utils/materialIconConverter.d.ts.map +1 -0
  134. package/build/native-tabs/utils/materialIconConverter.js +8 -0
  135. package/build/native-tabs/utils/materialIconConverter.js.map +1 -0
  136. package/build/navigationParams.d.ts +5 -1
  137. package/build/navigationParams.d.ts.map +1 -1
  138. package/build/navigationParams.js +32 -8
  139. package/build/navigationParams.js.map +1 -1
  140. package/build/toolbar/elements.d.ts +24 -0
  141. package/build/toolbar/elements.d.ts.map +1 -0
  142. package/build/toolbar/elements.js +36 -0
  143. package/build/toolbar/elements.js.map +1 -0
  144. package/build/toolbar/index.d.ts +9 -0
  145. package/build/toolbar/index.d.ts.map +1 -0
  146. package/build/toolbar/index.js +12 -0
  147. package/build/toolbar/index.js.map +1 -0
  148. package/build/toolbar/native.d.ts +4 -0
  149. package/build/toolbar/native.d.ts.map +1 -0
  150. package/build/toolbar/native.ios.d.ts +4 -0
  151. package/build/toolbar/native.ios.d.ts.map +1 -0
  152. package/build/toolbar/native.ios.js +21 -0
  153. package/build/toolbar/native.ios.js.map +1 -0
  154. package/build/toolbar/native.js +11 -0
  155. package/build/toolbar/native.js.map +1 -0
  156. package/build/toolbar/native.types.d.ts +30 -0
  157. package/build/toolbar/native.types.d.ts.map +1 -0
  158. package/build/toolbar/native.types.js +3 -0
  159. package/build/toolbar/native.types.js.map +1 -0
  160. package/build/useScreens.d.ts.map +1 -1
  161. package/build/useScreens.js +14 -0
  162. package/build/useScreens.js.map +1 -1
  163. package/build/utils/children.d.ts +7 -0
  164. package/build/utils/children.d.ts.map +1 -0
  165. package/build/utils/children.js +24 -0
  166. package/build/utils/children.js.map +1 -0
  167. package/build/utils/style.d.ts +3 -0
  168. package/build/utils/style.d.ts.map +1 -0
  169. package/build/utils/style.js +10 -0
  170. package/build/utils/style.js.map +1 -0
  171. package/build/views/Sitemap.js +3 -2
  172. package/build/views/Sitemap.js.map +1 -1
  173. package/expo-module.config.json +2 -2
  174. package/ios/LinkPreview/LinkPreviewNativeActionView.swift +1 -0
  175. package/ios/LinkPreview/LinkPreviewNativeModule.swift +49 -1
  176. package/ios/LinkPreview/LinkPreviewNativeNavigation.swift +132 -70
  177. package/ios/LinkPreview/LinkPreviewNativeView.swift +34 -17
  178. package/ios/LinkPreview/LinkZoomTransition.swift +227 -0
  179. package/ios/Toolbar/RouterToolbarHostView.swift +140 -0
  180. package/ios/Toolbar/RouterToolbarItemView.swift +171 -0
  181. package/ios/Toolbar/RouterToolbarModule.swift +102 -0
  182. package/local-maven-repo/expo/modules/router/expo.modules.router/{7.0.0-canary-20251120-e46b3cc/expo.modules.router-7.0.0-canary-20251120-e46b3cc.module → 7.0.0-canary-20251205-756eb7a/expo.modules.router-7.0.0-canary-20251205-756eb7a.module} +7 -7
  183. package/local-maven-repo/expo/modules/router/expo.modules.router/7.0.0-canary-20251205-756eb7a/expo.modules.router-7.0.0-canary-20251205-756eb7a.module.md5 +1 -0
  184. package/local-maven-repo/expo/modules/router/expo.modules.router/7.0.0-canary-20251205-756eb7a/expo.modules.router-7.0.0-canary-20251205-756eb7a.module.sha1 +1 -0
  185. package/local-maven-repo/expo/modules/router/expo.modules.router/7.0.0-canary-20251205-756eb7a/expo.modules.router-7.0.0-canary-20251205-756eb7a.module.sha256 +1 -0
  186. package/local-maven-repo/expo/modules/router/expo.modules.router/7.0.0-canary-20251205-756eb7a/expo.modules.router-7.0.0-canary-20251205-756eb7a.module.sha512 +1 -0
  187. package/local-maven-repo/expo/modules/router/expo.modules.router/{7.0.0-canary-20251120-e46b3cc/expo.modules.router-7.0.0-canary-20251120-e46b3cc.pom → 7.0.0-canary-20251205-756eb7a/expo.modules.router-7.0.0-canary-20251205-756eb7a.pom} +1 -1
  188. package/local-maven-repo/expo/modules/router/expo.modules.router/7.0.0-canary-20251205-756eb7a/expo.modules.router-7.0.0-canary-20251205-756eb7a.pom.md5 +1 -0
  189. package/local-maven-repo/expo/modules/router/expo.modules.router/7.0.0-canary-20251205-756eb7a/expo.modules.router-7.0.0-canary-20251205-756eb7a.pom.sha1 +1 -0
  190. package/local-maven-repo/expo/modules/router/expo.modules.router/7.0.0-canary-20251205-756eb7a/expo.modules.router-7.0.0-canary-20251205-756eb7a.pom.sha256 +1 -0
  191. package/local-maven-repo/expo/modules/router/expo.modules.router/7.0.0-canary-20251205-756eb7a/expo.modules.router-7.0.0-canary-20251205-756eb7a.pom.sha512 +1 -0
  192. package/local-maven-repo/expo/modules/router/expo.modules.router/maven-metadata.xml +4 -4
  193. package/local-maven-repo/expo/modules/router/expo.modules.router/maven-metadata.xml.md5 +1 -1
  194. package/local-maven-repo/expo/modules/router/expo.modules.router/maven-metadata.xml.sha1 +1 -1
  195. package/local-maven-repo/expo/modules/router/expo.modules.router/maven-metadata.xml.sha256 +1 -1
  196. package/local-maven-repo/expo/modules/router/expo.modules.router/maven-metadata.xml.sha512 +1 -1
  197. package/package.json +17 -14
  198. package/unstable-toolbar.d.ts +1 -0
  199. package/unstable-toolbar.js +1 -0
  200. package/build/layouts/stack-utils/utils.d.ts +0 -3
  201. package/build/layouts/stack-utils/utils.d.ts.map +0 -1
  202. package/build/layouts/stack-utils/utils.js +0 -8
  203. package/build/layouts/stack-utils/utils.js.map +0 -1
  204. package/build/native-tabs/utils/children.d.ts +0 -5
  205. package/build/native-tabs/utils/children.d.ts.map +0 -1
  206. package/build/native-tabs/utils/children.js +0 -15
  207. package/build/native-tabs/utils/children.js.map +0 -1
  208. package/ios/LinkPreview/LinkPreviewNativeNavigation.h +0 -50
  209. package/ios/LinkPreview/LinkPreviewNativeNavigation.mm +0 -164
  210. package/local-maven-repo/expo/modules/router/expo.modules.router/7.0.0-canary-20251120-e46b3cc/expo.modules.router-7.0.0-canary-20251120-e46b3cc.module.md5 +0 -1
  211. package/local-maven-repo/expo/modules/router/expo.modules.router/7.0.0-canary-20251120-e46b3cc/expo.modules.router-7.0.0-canary-20251120-e46b3cc.module.sha1 +0 -1
  212. package/local-maven-repo/expo/modules/router/expo.modules.router/7.0.0-canary-20251120-e46b3cc/expo.modules.router-7.0.0-canary-20251120-e46b3cc.module.sha256 +0 -1
  213. package/local-maven-repo/expo/modules/router/expo.modules.router/7.0.0-canary-20251120-e46b3cc/expo.modules.router-7.0.0-canary-20251120-e46b3cc.module.sha512 +0 -1
  214. package/local-maven-repo/expo/modules/router/expo.modules.router/7.0.0-canary-20251120-e46b3cc/expo.modules.router-7.0.0-canary-20251120-e46b3cc.pom.md5 +0 -1
  215. package/local-maven-repo/expo/modules/router/expo.modules.router/7.0.0-canary-20251120-e46b3cc/expo.modules.router-7.0.0-canary-20251120-e46b3cc.pom.sha1 +0 -1
  216. package/local-maven-repo/expo/modules/router/expo.modules.router/7.0.0-canary-20251120-e46b3cc/expo.modules.router-7.0.0-canary-20251120-e46b3cc.pom.sha256 +0 -1
  217. package/local-maven-repo/expo/modules/router/expo.modules.router/7.0.0-canary-20251120-e46b3cc/expo.modules.router-7.0.0-canary-20251120-e46b3cc.pom.sha512 +0 -1
  218. /package/local-maven-repo/expo/modules/router/expo.modules.router/{7.0.0-canary-20251120-e46b3cc/expo.modules.router-7.0.0-canary-20251120-e46b3cc-sources.jar → 7.0.0-canary-20251205-756eb7a/expo.modules.router-7.0.0-canary-20251205-756eb7a-sources.jar} +0 -0
  219. /package/local-maven-repo/expo/modules/router/expo.modules.router/{7.0.0-canary-20251120-e46b3cc/expo.modules.router-7.0.0-canary-20251120-e46b3cc-sources.jar.md5 → 7.0.0-canary-20251205-756eb7a/expo.modules.router-7.0.0-canary-20251205-756eb7a-sources.jar.md5} +0 -0
  220. /package/local-maven-repo/expo/modules/router/expo.modules.router/{7.0.0-canary-20251120-e46b3cc/expo.modules.router-7.0.0-canary-20251120-e46b3cc-sources.jar.sha1 → 7.0.0-canary-20251205-756eb7a/expo.modules.router-7.0.0-canary-20251205-756eb7a-sources.jar.sha1} +0 -0
  221. /package/local-maven-repo/expo/modules/router/expo.modules.router/{7.0.0-canary-20251120-e46b3cc/expo.modules.router-7.0.0-canary-20251120-e46b3cc-sources.jar.sha256 → 7.0.0-canary-20251205-756eb7a/expo.modules.router-7.0.0-canary-20251205-756eb7a-sources.jar.sha256} +0 -0
  222. /package/local-maven-repo/expo/modules/router/expo.modules.router/{7.0.0-canary-20251120-e46b3cc/expo.modules.router-7.0.0-canary-20251120-e46b3cc-sources.jar.sha512 → 7.0.0-canary-20251205-756eb7a/expo.modules.router-7.0.0-canary-20251205-756eb7a-sources.jar.sha512} +0 -0
  223. /package/local-maven-repo/expo/modules/router/expo.modules.router/{7.0.0-canary-20251120-e46b3cc/expo.modules.router-7.0.0-canary-20251120-e46b3cc.aar → 7.0.0-canary-20251205-756eb7a/expo.modules.router-7.0.0-canary-20251205-756eb7a.aar} +0 -0
  224. /package/local-maven-repo/expo/modules/router/expo.modules.router/{7.0.0-canary-20251120-e46b3cc/expo.modules.router-7.0.0-canary-20251120-e46b3cc.aar.md5 → 7.0.0-canary-20251205-756eb7a/expo.modules.router-7.0.0-canary-20251205-756eb7a.aar.md5} +0 -0
  225. /package/local-maven-repo/expo/modules/router/expo.modules.router/{7.0.0-canary-20251120-e46b3cc/expo.modules.router-7.0.0-canary-20251120-e46b3cc.aar.sha1 → 7.0.0-canary-20251205-756eb7a/expo.modules.router-7.0.0-canary-20251205-756eb7a.aar.sha1} +0 -0
  226. /package/local-maven-repo/expo/modules/router/expo.modules.router/{7.0.0-canary-20251120-e46b3cc/expo.modules.router-7.0.0-canary-20251120-e46b3cc.aar.sha256 → 7.0.0-canary-20251205-756eb7a/expo.modules.router-7.0.0-canary-20251205-756eb7a.aar.sha256} +0 -0
  227. /package/local-maven-repo/expo/modules/router/expo.modules.router/{7.0.0-canary-20251120-e46b3cc/expo.modules.router-7.0.0-canary-20251120-e46b3cc.aar.sha512 → 7.0.0-canary-20251205-756eb7a/expo.modules.router-7.0.0-canary-20251205-756eb7a.aar.sha512} +0 -0
@@ -0,0 +1,227 @@
1
+ import ExpoModulesCore
2
+ import RNScreens
3
+ import UIKit
4
+
5
+ class LinkSourceInfo {
6
+ let alignment: CGRect?
7
+ weak var view: UIView?
8
+
9
+ init(alignment: CGRect?, view: UIView) {
10
+ self.alignment = alignment
11
+ self.view = view
12
+ }
13
+ }
14
+
15
+ class LinkZoomTransitionsSourceRepository {
16
+ private var sources: [String: LinkSourceInfo] = [:]
17
+ private let lock = NSLock()
18
+
19
+ init() {}
20
+
21
+ func registerSource(
22
+ identifier: String,
23
+ source: LinkSourceInfo
24
+ ) {
25
+ lock.lock()
26
+ defer { lock.unlock() }
27
+ if sources[identifier] != nil {
28
+ print(
29
+ "[expo-router] LinkPreviewZoomTransitionSource with identifier \(identifier) is already registered. Overwriting the existing source."
30
+ )
31
+ }
32
+ if !identifier.isEmpty {
33
+ sources[identifier] = source
34
+ }
35
+ }
36
+
37
+ func unregisterSource(identifier: String) {
38
+ lock.lock()
39
+ defer { lock.unlock() }
40
+ sources.removeValue(forKey: identifier)
41
+ }
42
+
43
+ func getSource(identifier: String) -> LinkSourceInfo? {
44
+ lock.lock()
45
+ defer { lock.unlock() }
46
+ return sources[identifier]
47
+ }
48
+
49
+ func updateIdentifier(
50
+ oldIdentifier: String,
51
+ newIdentifier: String
52
+ ) {
53
+ lock.lock()
54
+ defer { lock.unlock() }
55
+ if let source = sources[oldIdentifier] {
56
+ if !newIdentifier.isEmpty {
57
+ sources[newIdentifier] = source
58
+ }
59
+ sources.removeValue(forKey: oldIdentifier)
60
+ }
61
+ }
62
+
63
+ func updateAlignment(
64
+ identifier: String,
65
+ alignment: CGRect?
66
+ ) {
67
+ lock.lock()
68
+ defer { lock.unlock() }
69
+ if let source = sources[identifier], let view = source.view, !identifier.isEmpty {
70
+ sources[identifier] = LinkSourceInfo(
71
+ alignment: alignment,
72
+ view: view
73
+ )
74
+ }
75
+ }
76
+ }
77
+
78
+ class LinkZoomTransitionSource: LinkZoomExpoView, LinkPreviewIndirectTriggerProtocol {
79
+ var child: UIView?
80
+
81
+ var indirectTrigger: UIView? {
82
+ return child
83
+ }
84
+
85
+ var alignment: CGRect? {
86
+ didSet {
87
+ // Update alignment info in the repository
88
+ if child != nil {
89
+ repository?.updateAlignment(
90
+ identifier: identifier,
91
+ alignment: alignment
92
+ )
93
+ }
94
+ }
95
+ }
96
+
97
+ var identifier: String = "" {
98
+ didSet {
99
+ guard identifier != oldValue else { return }
100
+ if let child {
101
+ if oldValue.isEmpty {
102
+ repository?.registerSource(
103
+ identifier: identifier,
104
+ source: LinkSourceInfo(alignment: alignment, view: child)
105
+ )
106
+ } else {
107
+ repository?.updateIdentifier(
108
+ oldIdentifier: oldValue,
109
+ newIdentifier: identifier
110
+ )
111
+ }
112
+ } else {
113
+ repository?.unregisterSource(
114
+ identifier: oldValue
115
+ )
116
+ }
117
+ }
118
+ }
119
+
120
+ override func mountChildComponentView(
121
+ _ childComponentView: UIView,
122
+ index: Int
123
+ ) {
124
+ if child != nil {
125
+ print(
126
+ "[expo-router] LinkZoomTransitionSource can only have one child view."
127
+ )
128
+ return
129
+ }
130
+ child = childComponentView
131
+ repository?.registerSource(
132
+ identifier: identifier,
133
+ source: LinkSourceInfo(alignment: alignment, view: childComponentView)
134
+ )
135
+ super.mountChildComponentView(childComponentView, index: index)
136
+ }
137
+
138
+ override func unmountChildComponentView(_ child: UIView, index: Int) {
139
+ if child == self.child {
140
+ self.child = nil
141
+ repository?.unregisterSource(
142
+ identifier: identifier
143
+ )
144
+ }
145
+ super.unmountChildComponentView(child, index: index)
146
+ }
147
+ }
148
+
149
+ class LinkZoomTransitionEnabler: LinkZoomExpoView {
150
+ var zoomTransitionSourceIdentifier: String = ""
151
+ var isPreventingInteractiveDismissal: Bool = false
152
+
153
+ override func didMoveToSuperview() {
154
+ super.didMoveToSuperview()
155
+ if superview != nil {
156
+ // Need to run this async. Otherwise the view has no view controller yet
157
+ DispatchQueue.main.async {
158
+ self.setupZoomTransition()
159
+ }
160
+ }
161
+ }
162
+
163
+ private func setupZoomTransition() {
164
+ if self.zoomTransitionSourceIdentifier.isEmpty {
165
+ print("[expo-router] No zoomTransitionSourceIdentifier passed to LinkZoomTransitionEnabler")
166
+ return
167
+ }
168
+ if let controller = self.findViewController() {
169
+ if #available(iOS 18.0, *) {
170
+ let options = UIViewController.Transition.ZoomOptions()
171
+
172
+ options.alignmentRectProvider = { _ in
173
+ let sourceInfo = self.repository?.getSource(
174
+ identifier: self.zoomTransitionSourceIdentifier)
175
+ return sourceInfo?.alignment
176
+ }
177
+ options.interactiveDismissShouldBegin = { _ in
178
+ !self.isPreventingInteractiveDismissal
179
+ }
180
+ controller.preferredTransition = .zoom(options: options) { _ in
181
+ let sourceInfo = self.repository?.getSource(
182
+ identifier: self.zoomTransitionSourceIdentifier)
183
+ var view: UIView? = sourceInfo?.view
184
+ if let linkPreviewView = view as? NativeLinkPreviewView {
185
+ view = linkPreviewView.directChild
186
+ }
187
+ guard let view else {
188
+ print(
189
+ "[expo-router] No source view found for identifier \(self.zoomTransitionSourceIdentifier) to enable zoom transition"
190
+ )
191
+ return nil
192
+ }
193
+ return view
194
+ }
195
+ return
196
+ }
197
+ } else {
198
+ print("[expo-router] No navigation controller found to enable zoom transition")
199
+ }
200
+ }
201
+
202
+ private func findViewController() -> RNSScreen? {
203
+ var responder: UIResponder? = self
204
+ while let r = responder {
205
+ if let r = r as? RNSScreen {
206
+ return r
207
+ }
208
+ responder = r.next
209
+ }
210
+ return nil
211
+ }
212
+ }
213
+
214
+ class LinkZoomExpoView: ExpoView {
215
+ var module: LinkPreviewNativeModule? {
216
+ return appContext?.moduleRegistry.get(moduleWithName: LinkPreviewNativeModule.moduleName)
217
+ as? LinkPreviewNativeModule
218
+ }
219
+
220
+ var repository: LinkZoomTransitionsSourceRepository? {
221
+ guard let module else {
222
+ print("[expo-router] LinkPreviewNativeModule not loaded")
223
+ return nil
224
+ }
225
+ return module.zoomSourceRepository
226
+ }
227
+ }
@@ -0,0 +1,140 @@
1
+ import ExpoModulesCore
2
+ import RNScreens
3
+ import UIKit
4
+
5
+ class RouterToolbarHostView: ExpoView, LinkPreviewMenuUpdatable {
6
+ // Mutable map of toolbar items
7
+ var toolbarItemsArray: [String] = []
8
+ var toolbarItemsMap: [String: RouterToolbarItemView] = [:]
9
+ var menuItemsMap: [String: LinkPreviewNativeActionView] = [:]
10
+
11
+ required init(appContext: AppContext? = nil) {
12
+ super.init(appContext: appContext)
13
+ }
14
+
15
+ private func addRouterToolbarItemAtIndex(
16
+ _ item: RouterToolbarItemView,
17
+ index: Int
18
+ ) {
19
+ let identifier = item.identifier
20
+ toolbarItemsArray.insert(identifier, at: index)
21
+ toolbarItemsMap[identifier] = item
22
+ item.host = self
23
+ }
24
+
25
+ private func addMenuToolbarItemAtIndex(
26
+ _ item: LinkPreviewNativeActionView,
27
+ index: Int
28
+ ) {
29
+ let identifier = item.identifier
30
+ toolbarItemsArray.insert(identifier, at: index)
31
+ menuItemsMap[identifier] = item
32
+ }
33
+
34
+ private func removeToolbarItemWithId(_ id: String) {
35
+ if let index = toolbarItemsArray.firstIndex(of: id) {
36
+ toolbarItemsArray.remove(at: index)
37
+ toolbarItemsMap.removeValue(forKey: id)
38
+ menuItemsMap.removeValue(forKey: id)
39
+ }
40
+ }
41
+
42
+ func updateToolbarItem(withId id: String) {
43
+ if let controller = self.findViewController() {
44
+ let index = toolbarItemsArray.firstIndex(of: id)
45
+ if let index = index, let item = toolbarItemsMap[id] {
46
+ controller.toolbarItems?[index] = item.barButtonItem
47
+ }
48
+ }
49
+ }
50
+
51
+ func updateToolbarItems() {
52
+ if let controller = self.findViewController() {
53
+ if #available(iOS 18.0, *) {
54
+ controller.setToolbarItems(
55
+ toolbarItemsArray.compactMap {
56
+ if let item = toolbarItemsMap[$0] {
57
+ return item.barButtonItem
58
+ }
59
+ if let menu = menuItemsMap[$0] {
60
+ return UIBarButtonItem(
61
+ title: menu.title,
62
+ image: menu.icon.flatMap { UIImage(systemName: $0) },
63
+ primaryAction: nil,
64
+ menu: menu.uiAction as? UIMenu
65
+ )
66
+ }
67
+ print(
68
+ "[expo-router] Warning: Could not find toolbar item or menu for identifier \($0)"
69
+ )
70
+ return nil
71
+ }, animated: true)
72
+ controller.navigationController?.setToolbarHidden(
73
+ false, animated: true)
74
+ return
75
+ }
76
+ } else {
77
+ print(
78
+ "[expo-router] Warning: Could not find owning UIViewController for RouterToolbarHostView")
79
+ }
80
+ }
81
+
82
+ override func mountChildComponentView(_ childComponentView: UIView, index: Int) {
83
+ if let toolbarItem = childComponentView as? RouterToolbarItemView {
84
+ if toolbarItem.identifier.isEmpty {
85
+ print("[expo-router] RouterToolbarItemView identifier is empty")
86
+ return
87
+ }
88
+ addRouterToolbarItemAtIndex(toolbarItem, index: index)
89
+ } else if let menu = childComponentView as? LinkPreviewNativeActionView {
90
+ addMenuToolbarItemAtIndex(menu, index: index)
91
+ } else {
92
+ print(
93
+ "ExpoRouter: Unknown child component view (\(childComponentView)) mounted to RouterToolbarHost"
94
+ )
95
+ }
96
+ updateToolbarItems()
97
+ }
98
+
99
+ override func unmountChildComponentView(_ childComponentView: UIView, index: Int) {
100
+ if let toolbarItem = childComponentView as? RouterToolbarItemView {
101
+ if toolbarItem.identifier.isEmpty {
102
+ print("[expo-router] RouterToolbarItemView identifier is empty")
103
+ return
104
+ }
105
+ removeToolbarItemWithId(toolbarItem.identifier)
106
+ } else if let menu = childComponentView as? LinkPreviewNativeActionView {
107
+ if menu.identifier.isEmpty {
108
+ print("[expo-router] Menu identifier is empty")
109
+ return
110
+ }
111
+ removeToolbarItemWithId(menu.identifier)
112
+ } else {
113
+ print(
114
+ "ExpoRouter: Unknown child component view (\(childComponentView)) unmounted from RouterToolbarHost"
115
+ )
116
+ }
117
+ updateToolbarItems()
118
+ }
119
+
120
+ override func didMoveToWindow() {
121
+ super.didMoveToWindow()
122
+ // Update toolbar items when the view is added to the window
123
+ updateToolbarItems()
124
+ }
125
+
126
+ func updateMenu() {
127
+ updateToolbarItems()
128
+ }
129
+
130
+ private func findViewController() -> RNSScreen? {
131
+ var responder: UIResponder? = self
132
+ while let r = responder {
133
+ if let r = r as? RNSScreen {
134
+ return r
135
+ }
136
+ responder = r.next
137
+ }
138
+ return nil
139
+ }
140
+ }
@@ -0,0 +1,171 @@
1
+ import ExpoModulesCore
2
+ import React
3
+ import UIKit
4
+
5
+ class RouterToolbarItemView: ExpoView {
6
+ var identifier: String = ""
7
+ @ReactiveProp var type: ItemType?
8
+ @ReactiveProp var title: String?
9
+ @ReactiveProp var systemImageName: String?
10
+ @ReactiveProp var customView: UIView?
11
+ @ReactiveProp var customTintColor: UIColor?
12
+ @ReactiveProp var hidesSharedBackground: Bool = false
13
+ @ReactiveProp var sharesBackground: Bool = true
14
+ @ReactiveProp var barButtonItemStyle: UIBarButtonItem.Style?
15
+ @ReactiveProp var width: Double?
16
+ // Using "routerHidden" to avoid conflict with UIView's "isHidden"
17
+ @ReactiveProp var routerHidden: Bool = false
18
+ @ReactiveProp var selected: Bool = false
19
+ @ReactiveProp var possibleTitles: Set<String>?
20
+ @ReactiveProp var badgeConfiguration: BadgeConfiguration?
21
+
22
+ var host: RouterToolbarHostView?
23
+
24
+ let onSelected = EventDispatcher()
25
+
26
+ func performUpdate() {
27
+ self.host?.updateToolbarItem(withId: self.identifier)
28
+ }
29
+
30
+ @objc func handleAction() {
31
+ onSelected()
32
+ }
33
+
34
+ var barButtonItem: UIBarButtonItem {
35
+ var item = UIBarButtonItem()
36
+ if let customView {
37
+ item = UIBarButtonItem(customView: customView)
38
+ } else if type == .fluidSpacer {
39
+ item = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
40
+ } else if type == .fixedSpacer {
41
+ item = UIBarButtonItem(barButtonSystemItem: .fixedSpace, target: nil, action: nil)
42
+ } else {
43
+ if let title {
44
+ item.title = title
45
+ }
46
+ item.possibleTitles = possibleTitles
47
+ if let systemImageName {
48
+ item.image = UIImage(systemName: systemImageName)
49
+ }
50
+ if let tintColor = customTintColor {
51
+ item.tintColor = tintColor
52
+ }
53
+ }
54
+ if #available(iOS 26.0, *) {
55
+ item.hidesSharedBackground = hidesSharedBackground
56
+ item.sharesBackground = sharesBackground
57
+ }
58
+ if let barButtonItemStyle {
59
+ item.style = barButtonItemStyle
60
+ }
61
+ item.target = self
62
+ item.action = #selector(handleAction)
63
+ if let width = width {
64
+ item.width = CGFloat(width)
65
+ }
66
+ if #available(iOS 16.0, *) {
67
+ item.isHidden = routerHidden
68
+ }
69
+ item.isSelected = selected
70
+ if #available(iOS 26.0, *) {
71
+ if let badgeConfig = badgeConfiguration {
72
+ var badge = UIBarButtonItem.Badge.indicator()
73
+ if let value = badgeConfig.value {
74
+ badge = .string(value)
75
+ }
76
+ if let backgroundColor = badgeConfig.backgroundColor {
77
+ badge.backgroundColor = backgroundColor
78
+ }
79
+ if let foregroundColor = badgeConfig.color {
80
+ badge.foregroundColor = foregroundColor
81
+ }
82
+ if badgeConfig.fontFamily != nil || badgeConfig.fontSize != nil
83
+ || badgeConfig.fontWeight != nil {
84
+ let font = RCTFont.update(
85
+ nil,
86
+ withFamily: badgeConfig.fontFamily,
87
+ size: badgeConfig.fontSize != nil ? NSNumber(value: badgeConfig.fontSize!) : nil,
88
+ weight: badgeConfig.fontWeight,
89
+ style: nil,
90
+ variant: nil,
91
+ scaleMultiplier: 1.0)
92
+ badge.font = font
93
+ }
94
+ // TODO: Find out why this does not work
95
+ item.badge = badge
96
+ }
97
+ }
98
+
99
+ return item
100
+ }
101
+
102
+ required init(appContext: AppContext? = nil) {
103
+ super.init(appContext: appContext)
104
+ }
105
+
106
+ override func mountChildComponentView(_ childComponentView: UIView, index: Int) {
107
+ if customView != nil {
108
+ print(
109
+ "[expo-router] Warning: RouterToolbarItemView can only have one child view"
110
+ )
111
+ return
112
+ }
113
+ customView = childComponentView
114
+ performUpdate()
115
+ }
116
+
117
+ override func unmountChildComponentView(_ childComponentView: UIView, index: Int) {
118
+ if customView == childComponentView {
119
+ childComponentView.removeFromSuperview()
120
+ customView = nil
121
+ performUpdate()
122
+ }
123
+ }
124
+ }
125
+
126
+ enum ItemType: String, Enumerable {
127
+ case normal
128
+ case fixedSpacer
129
+ case fluidSpacer
130
+ }
131
+
132
+ struct BadgeConfiguration: Equatable {
133
+ var value: String?
134
+ var backgroundColor: UIColor?
135
+ var color: UIColor?
136
+ var fontFamily: String?
137
+ var fontSize: Double?
138
+ var fontWeight: String?
139
+ }
140
+
141
+ @propertyWrapper
142
+ struct ReactiveProp<Value: Equatable> {
143
+ private var value: Value
144
+
145
+ init(wrappedValue: Value) {
146
+ self.value = wrappedValue
147
+ }
148
+
149
+ static subscript<EnclosingSelf: RouterToolbarItemView>(
150
+ _enclosingInstance instance: EnclosingSelf,
151
+ wrapped wrappedKeyPath: ReferenceWritableKeyPath<EnclosingSelf, Value>,
152
+ storage storageKeyPath: ReferenceWritableKeyPath<EnclosingSelf, ReactiveProp<Value>>
153
+ ) -> Value {
154
+ get {
155
+ instance[keyPath: storageKeyPath].value
156
+ }
157
+ set {
158
+ let oldValue = instance[keyPath: storageKeyPath].value
159
+ if oldValue != newValue {
160
+ instance[keyPath: storageKeyPath].value = newValue
161
+ instance.performUpdate()
162
+ }
163
+ }
164
+ }
165
+
166
+ @available(*, unavailable, message: "Use the enclosing instance subscript.")
167
+ var wrappedValue: Value {
168
+ get { fatalError() }
169
+ set { fatalError() }
170
+ }
171
+ }
@@ -0,0 +1,102 @@
1
+ import ExpoModulesCore
2
+
3
+ public class RouterToolbarModule: Module {
4
+ public func definition() -> ModuleDefinition {
5
+ Name("ExpoRouterToolbarModule")
6
+
7
+ View(RouterToolbarHostView.self) {
8
+ Prop("disableForceFlatten") { (_: RouterToolbarHostView, _: Bool) in
9
+ // This prop is used in ExpoShadowNode in order to disable force flattening, when display: contents is used
10
+ }
11
+ }
12
+ View(RouterToolbarItemView.self) {
13
+ Prop("identifier") { (view: RouterToolbarItemView, identifier: String) in
14
+ view.identifier = identifier
15
+ }
16
+ Prop("type") { (view: RouterToolbarItemView, type: ItemType) in
17
+ view.type = type
18
+ }
19
+ Prop("title") { (view: RouterToolbarItemView, title: String?) in
20
+ view.title = title
21
+ }
22
+ Prop("systemImageName") { (view: RouterToolbarItemView, systemImageName: String?) in
23
+ view.systemImageName = systemImageName
24
+ }
25
+ Prop("tintColor") { (view: RouterToolbarItemView, tintColor: UIColor?) in
26
+ view.customTintColor = tintColor
27
+ }
28
+ Prop("hidesSharedBackground") { (view: RouterToolbarItemView, hidesSharedBackground: Bool) in
29
+ view.hidesSharedBackground = hidesSharedBackground
30
+ }
31
+ Prop("sharesBackground") { (view: RouterToolbarItemView, sharesBackground: Bool) in
32
+ view.sharesBackground = sharesBackground
33
+ }
34
+ Prop("disableForceFlatten") { (_: RouterToolbarItemView, _: Bool) in
35
+ // This prop is used in ExpoShadowNode in order to disable force flattening, when display: contents is used
36
+ }
37
+ Prop("barButtonItemStyle") { (view: RouterToolbarItemView, style: BarItemStyle?) in
38
+ view.barButtonItemStyle = style?.toUIBarButtonItemStyle()
39
+ }
40
+ Prop("width") { (view: RouterToolbarItemView, width: Double?) in
41
+ view.width = width
42
+ }
43
+ Prop("hidden") { (view: RouterToolbarItemView, hidden: Bool) in
44
+ view.routerHidden = hidden
45
+ }
46
+ Prop("selected") { (view: RouterToolbarItemView, selected: Bool) in
47
+ view.selected = selected
48
+ }
49
+ Prop("possibleTitles") { (view: RouterToolbarItemView, possibleTitles: [String]?) in
50
+ if let possibleTitles = possibleTitles {
51
+ view.possibleTitles = Set(possibleTitles)
52
+ } else {
53
+ view.possibleTitles = nil
54
+ }
55
+ }
56
+ Prop("badgeConfiguration") {
57
+ (view: RouterToolbarItemView, config: BadgeConfigurationRecord?) in
58
+ view.badgeConfiguration = config?.toBadgeConfiguration()
59
+ }
60
+
61
+ Events("onSelected")
62
+ }
63
+ }
64
+ }
65
+
66
+ enum BarItemStyle: String, Enumerable {
67
+ case plain
68
+ case prominent
69
+
70
+ func toUIBarButtonItemStyle() -> UIBarButtonItem.Style {
71
+ switch self {
72
+ case .plain:
73
+ return .plain
74
+ case .prominent:
75
+ if #available(iOS 26.0, *) {
76
+ return .prominent
77
+ } else {
78
+ return .done
79
+ }
80
+ }
81
+ }
82
+ }
83
+
84
+ struct BadgeConfigurationRecord: Record {
85
+ @Field var value: String?
86
+ @Field var backgroundColor: UIColor?
87
+ @Field var color: UIColor?
88
+ @Field var fontFamily: String?
89
+ @Field var fontSize: Double?
90
+ @Field var fontWeight: String?
91
+
92
+ func toBadgeConfiguration() -> BadgeConfiguration {
93
+ return BadgeConfiguration(
94
+ value: value,
95
+ backgroundColor: backgroundColor,
96
+ color: color,
97
+ fontFamily: fontFamily,
98
+ fontSize: fontSize,
99
+ fontWeight: fontWeight
100
+ )
101
+ }
102
+ }
@@ -3,7 +3,7 @@
3
3
  "component": {
4
4
  "group": "expo.modules.router",
5
5
  "module": "expo.modules.router",
6
- "version": "7.0.0-canary-20251120-e46b3cc",
6
+ "version": "7.0.0-canary-20251205-756eb7a",
7
7
  "attributes": {
8
8
  "org.gradle.status": "release"
9
9
  }
@@ -24,8 +24,8 @@
24
24
  },
25
25
  "files": [
26
26
  {
27
- "name": "expo.modules.router-7.0.0-canary-20251120-e46b3cc.aar",
28
- "url": "expo.modules.router-7.0.0-canary-20251120-e46b3cc.aar",
27
+ "name": "expo.modules.router-7.0.0-canary-20251205-756eb7a.aar",
28
+ "url": "expo.modules.router-7.0.0-canary-20251205-756eb7a.aar",
29
29
  "size": 13671,
30
30
  "sha512": "f51bd2a6d3fcc9075dbf99d66f77162d530586d0793d68e109a55f6edfbe4ff98bc9c9c5d587d0feec99807b6ae94a729232000e89f840278b21f4d423caa520",
31
31
  "sha256": "089d182f36875a201ad1b30b44d39812cd5155af987f3d33cd5eef8542103c82",
@@ -60,8 +60,8 @@
60
60
  ],
61
61
  "files": [
62
62
  {
63
- "name": "expo.modules.router-7.0.0-canary-20251120-e46b3cc.aar",
64
- "url": "expo.modules.router-7.0.0-canary-20251120-e46b3cc.aar",
63
+ "name": "expo.modules.router-7.0.0-canary-20251205-756eb7a.aar",
64
+ "url": "expo.modules.router-7.0.0-canary-20251205-756eb7a.aar",
65
65
  "size": 13671,
66
66
  "sha512": "f51bd2a6d3fcc9075dbf99d66f77162d530586d0793d68e109a55f6edfbe4ff98bc9c9c5d587d0feec99807b6ae94a729232000e89f840278b21f4d423caa520",
67
67
  "sha256": "089d182f36875a201ad1b30b44d39812cd5155af987f3d33cd5eef8542103c82",
@@ -80,8 +80,8 @@
80
80
  },
81
81
  "files": [
82
82
  {
83
- "name": "expo.modules.router-7.0.0-canary-20251120-e46b3cc-sources.jar",
84
- "url": "expo.modules.router-7.0.0-canary-20251120-e46b3cc-sources.jar",
83
+ "name": "expo.modules.router-7.0.0-canary-20251205-756eb7a-sources.jar",
84
+ "url": "expo.modules.router-7.0.0-canary-20251205-756eb7a-sources.jar",
85
85
  "size": 2318,
86
86
  "sha512": "9864add8e93e3c0a9a9c930aaed67016b15054c3fafd59a0bd3a5402d7cdc5827be84c22c2c137f3e5acb4e39270d9bfb9ca3fe11234458d4f2e0d4c78747f48",
87
87
  "sha256": "d5dff6259e86de721fc0f07fe740a5e18088e19b76738719b0a6f94caef06224",
@@ -0,0 +1 @@
1
+ cc300b40ae77e49c250c5ce6656d93374e379471c0f0205bd04342c4322722719476feb33995455bc31899fbb20cf65fb20f2e2bd8776a78536b2fcd61b3aa64
@@ -9,7 +9,7 @@
9
9
  <modelVersion>4.0.0</modelVersion>
10
10
  <groupId>expo.modules.router</groupId>
11
11
  <artifactId>expo.modules.router</artifactId>
12
- <version>7.0.0-canary-20251120-e46b3cc</version>
12
+ <version>7.0.0-canary-20251205-756eb7a</version>
13
13
  <packaging>aar</packaging>
14
14
  <name>expo.modules.router</name>
15
15
  <url>https://github.com/expo/expo</url>