one 1.17.10 → 1.17.11

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 (494) hide show
  1. package/dist/cjs/Root.native.js.map +1 -1
  2. package/dist/cjs/__mocks__/@react-navigation/native-stack.cjs +3 -1
  3. package/dist/cjs/__mocks__/@react-navigation/native-stack.native.js +4 -0
  4. package/dist/cjs/__mocks__/@react-navigation/native-stack.native.js.map +1 -1
  5. package/dist/cjs/__mocks__/expo-linking.native.js.map +1 -1
  6. package/dist/cjs/__mocks__/expo-modules-core.native.js.map +1 -1
  7. package/dist/cjs/__mocks__/react-native-screens.native.js.map +1 -1
  8. package/dist/cjs/babel-plugins/environment-guard.native.js.map +1 -1
  9. package/dist/cjs/babel-plugins/inline-one-server-url.native.js.map +1 -1
  10. package/dist/cjs/babel-plugins/one-router-metro.native.js.map +1 -1
  11. package/dist/cjs/babel-plugins/one-router-metro.test.native.js.map +1 -1
  12. package/dist/cjs/babel-plugins/remove-server-code.native.js.map +1 -1
  13. package/dist/cjs/babel-preset/index.native.js.map +1 -1
  14. package/dist/cjs/babel-preset/index.test.native.js.map +1 -1
  15. package/dist/cjs/babel-preset/integration.test.native.js.map +1 -1
  16. package/dist/cjs/cli/build.native.js.map +1 -1
  17. package/dist/cjs/cli/buildPage.native.js.map +1 -1
  18. package/dist/cjs/cli/buildPageWorker.native.js.map +1 -1
  19. package/dist/cjs/cli/checkNodeVersion.native.js.map +1 -1
  20. package/dist/cjs/cli/daemon.native.js.map +1 -1
  21. package/dist/cjs/cli/dev.native.js.map +1 -1
  22. package/dist/cjs/cli/generateBundlerConfig.native.js.map +1 -1
  23. package/dist/cjs/cli/generateBundlerConfig.test.native.js.map +1 -1
  24. package/dist/cjs/cli/generateRoutes.native.js.map +1 -1
  25. package/dist/cjs/cli/generateSitemap.native.js.map +1 -1
  26. package/dist/cjs/cli/generateSitemap.test.native.js.map +1 -1
  27. package/dist/cjs/cli/install-error-handlers.native.js.map +1 -1
  28. package/dist/cjs/cli/label-process.native.js.map +1 -1
  29. package/dist/cjs/cli/main.native.js.map +1 -1
  30. package/dist/cjs/cli/patch.native.js.map +1 -1
  31. package/dist/cjs/cli/patch.test.native.js.map +1 -1
  32. package/dist/cjs/cli/prebuild.native.js.map +1 -1
  33. package/dist/cjs/cli/runAndroid.native.js.map +1 -1
  34. package/dist/cjs/cli/runIos.native.js.map +1 -1
  35. package/dist/cjs/cli/securityScan.native.js.map +1 -1
  36. package/dist/cjs/cli/workerPool.native.js.map +1 -1
  37. package/dist/cjs/cli.native.js.map +1 -1
  38. package/dist/cjs/clientLoaderResolver.native.js.map +1 -1
  39. package/dist/cjs/config.native.js.map +1 -1
  40. package/dist/cjs/constants.native.js.map +1 -1
  41. package/dist/cjs/constants.test.native.js.map +1 -1
  42. package/dist/cjs/createAPIRoute.native.js.map +1 -1
  43. package/dist/cjs/createHandleRequest.cjs +21 -12
  44. package/dist/cjs/createHandleRequest.native.js +22 -12
  45. package/dist/cjs/createHandleRequest.native.js.map +1 -1
  46. package/dist/cjs/createHandleRequest.test.cjs +51 -6
  47. package/dist/cjs/createHandleRequest.test.native.js +53 -6
  48. package/dist/cjs/createHandleRequest.test.native.js.map +1 -1
  49. package/dist/cjs/createMiddleware.native.js.map +1 -1
  50. package/dist/cjs/daemon/index.native.js.map +1 -1
  51. package/dist/cjs/daemon/ipc.native.js.map +1 -1
  52. package/dist/cjs/daemon/picker.native.js.map +1 -1
  53. package/dist/cjs/daemon/proxy.native.js.map +1 -1
  54. package/dist/cjs/daemon/registry.native.js.map +1 -1
  55. package/dist/cjs/daemon/server.native.js.map +1 -1
  56. package/dist/cjs/daemon/tui.native.js.map +1 -1
  57. package/dist/cjs/daemon/types.native.js.map +1 -1
  58. package/dist/cjs/daemon/utils.native.js.map +1 -1
  59. package/dist/cjs/devtools/registry.native.js.map +1 -1
  60. package/dist/cjs/drawer.native.js.map +1 -1
  61. package/dist/cjs/fallbackViews/Sitemap.native.js.map +1 -1
  62. package/dist/cjs/fallbackViews/Unmatched.native.js.map +1 -1
  63. package/dist/cjs/fork/NavigationContainer.native.js.map +1 -1
  64. package/dist/cjs/fork/SSRNavigationContainer.native.js.map +1 -1
  65. package/dist/cjs/fork/__tests__/getPathFromState.test.native.js.map +1 -1
  66. package/dist/cjs/fork/__tests__/getStateFromPath.test.native.js.map +1 -1
  67. package/dist/cjs/fork/_shared.native.js.map +1 -1
  68. package/dist/cjs/fork/createMemoryHistory.native.js.map +1 -1
  69. package/dist/cjs/fork/createMemoryHistory.test.native.js.map +1 -1
  70. package/dist/cjs/fork/extractPathFromURL.native.js.map +1 -1
  71. package/dist/cjs/fork/extractPathFromURL.test.native.js.map +1 -1
  72. package/dist/cjs/fork/findFocusedRoute.native.js.map +1 -1
  73. package/dist/cjs/fork/getPathFromState-mods.native.js.map +1 -1
  74. package/dist/cjs/fork/getPathFromState.native.js.map +1 -1
  75. package/dist/cjs/fork/getPathFromState.test.native.js.map +1 -1
  76. package/dist/cjs/fork/getStateFromPath-mods.native.js.map +1 -1
  77. package/dist/cjs/fork/getStateFromPath.native.js.map +1 -1
  78. package/dist/cjs/fork/getStateFromPath.test.native.js.map +1 -1
  79. package/dist/cjs/fork/useThenable.native.js.map +1 -1
  80. package/dist/cjs/fork/validatePathConfig.native.js.map +1 -1
  81. package/dist/cjs/getReactNavigationConfig.native.js.map +1 -1
  82. package/dist/cjs/head/Head.native.js.map +1 -1
  83. package/dist/cjs/head/HeadModule.native.js.map +1 -1
  84. package/dist/cjs/head/index.native.js.map +1 -1
  85. package/dist/cjs/head/types.native.js.map +1 -1
  86. package/dist/cjs/head/url.native.js.map +1 -1
  87. package/dist/cjs/headless-server.native.js.map +1 -1
  88. package/dist/cjs/headless.cjs +1 -0
  89. package/dist/cjs/headless.native.js +1 -0
  90. package/dist/cjs/headless.native.js.map +1 -1
  91. package/dist/cjs/hooks.native.js.map +1 -1
  92. package/dist/cjs/hooks.test.native.js.map +1 -1
  93. package/dist/cjs/href.native.js.map +1 -1
  94. package/dist/cjs/image/getImageData.native.js.map +1 -1
  95. package/dist/cjs/image.native.js.map +1 -1
  96. package/dist/cjs/index.cjs +3 -0
  97. package/dist/cjs/index.native.js +4 -1
  98. package/dist/cjs/index.native.js.map +1 -1
  99. package/dist/cjs/interfaces/router.native.js.map +1 -1
  100. package/dist/cjs/layouts/Drawer.cjs +46 -1
  101. package/dist/cjs/layouts/Drawer.native.js +47 -1
  102. package/dist/cjs/layouts/Drawer.native.js.map +1 -1
  103. package/dist/cjs/layouts/NativeTabs.native.js.map +1 -1
  104. package/dist/cjs/layouts/Stack.cjs +12 -3
  105. package/dist/cjs/layouts/Stack.native.js +13 -4
  106. package/dist/cjs/layouts/Stack.native.js.map +1 -1
  107. package/dist/cjs/layouts/Tabs.cjs +42 -8
  108. package/dist/cjs/layouts/Tabs.native.js +43 -8
  109. package/dist/cjs/layouts/Tabs.native.js.map +1 -1
  110. package/dist/cjs/layouts/stack-navigator.cjs +29 -0
  111. package/dist/cjs/layouts/stack-navigator.native.js +32 -0
  112. package/dist/cjs/layouts/stack-navigator.native.js.map +1 -0
  113. package/dist/cjs/layouts/stack-utils/StackHeaderBackButton.native.js.map +1 -1
  114. package/dist/cjs/layouts/stack-utils/StackHeaderComponent.native.js.map +1 -1
  115. package/dist/cjs/layouts/stack-utils/StackHeaderLeft.native.js.map +1 -1
  116. package/dist/cjs/layouts/stack-utils/StackHeaderRight.native.js.map +1 -1
  117. package/dist/cjs/layouts/stack-utils/StackHeaderSearchBar.native.js.map +1 -1
  118. package/dist/cjs/layouts/stack-utils/StackHeaderTitle.native.js.map +1 -1
  119. package/dist/cjs/layouts/stack-utils/StackScreen.native.js.map +1 -1
  120. package/dist/cjs/layouts/stack-utils/__tests__/composition.test.native.js.map +1 -1
  121. package/dist/cjs/layouts/stack-utils/index.native.js.map +1 -1
  122. package/dist/cjs/layouts/withLayoutContext.native.js.map +1 -1
  123. package/dist/cjs/lazyWithRetry.native.js.map +1 -1
  124. package/dist/cjs/link/Link.native.js.map +1 -1
  125. package/dist/cjs/link/Redirect.native.js.map +1 -1
  126. package/dist/cjs/link/getLinking.native.js.map +1 -1
  127. package/dist/cjs/link/href.native.js.map +1 -1
  128. package/dist/cjs/link/path.native.js.map +1 -1
  129. package/dist/cjs/link/prefetchIntent.native.js.map +1 -1
  130. package/dist/cjs/link/prefetchIntent.test.native.js.map +1 -1
  131. package/dist/cjs/link/prefetchViewport.native.js.map +1 -1
  132. package/dist/cjs/link/prefetchViewport.test.native.js.map +1 -1
  133. package/dist/cjs/link/useLinkTo.native.js.map +1 -1
  134. package/dist/cjs/link/useLoadedNavigation.native.js.map +1 -1
  135. package/dist/cjs/metro-config/buildOneMetroResolverOverrides.native.js.map +1 -1
  136. package/dist/cjs/metro-config/getViteMetroPluginOptions.integration.test.native.js.map +1 -1
  137. package/dist/cjs/metro-config/getViteMetroPluginOptions.native.js +1 -1
  138. package/dist/cjs/metro-config/getViteMetroPluginOptions.native.js.map +1 -1
  139. package/dist/cjs/metro-config/withOne.native.js.map +1 -1
  140. package/dist/cjs/metro-config/withOne.test.native.js.map +1 -1
  141. package/dist/cjs/native-tabs.native.js.map +1 -1
  142. package/dist/cjs/notFoundState.native.js.map +1 -1
  143. package/dist/cjs/polyfills-mobile.native.js.map +1 -1
  144. package/dist/cjs/polyfills-server.native.js.map +1 -1
  145. package/dist/cjs/router/FlagsContext.native.js.map +1 -1
  146. package/dist/cjs/router/Route.native.js.map +1 -1
  147. package/dist/cjs/router/RouteInfoContext.native.js.map +1 -1
  148. package/dist/cjs/router/RouterStore.native.js.map +1 -1
  149. package/dist/cjs/router/SpaShellContext.native.js.map +1 -1
  150. package/dist/cjs/router/createRoute.native.js.map +1 -1
  151. package/dist/cjs/router/filterRootHTML.native.js.map +1 -1
  152. package/dist/cjs/router/findRouteNode.native.js.map +1 -1
  153. package/dist/cjs/router/getLinkingConfig.native.js.map +1 -1
  154. package/dist/cjs/router/getLinkingConfig.test.native.js.map +1 -1
  155. package/dist/cjs/router/getNormalizedStatePath.native.js.map +1 -1
  156. package/dist/cjs/router/getRouteInfo.native.js.map +1 -1
  157. package/dist/cjs/router/getRoutes.native.js.map +1 -1
  158. package/dist/cjs/router/getRoutes.test.native.js.map +1 -1
  159. package/dist/cjs/router/glob-patterns.native.js.map +1 -1
  160. package/dist/cjs/router/imperative-api.native.js.map +1 -1
  161. package/dist/cjs/router/interceptRoutes.native.js.map +1 -1
  162. package/dist/cjs/router/isIndexPath.native.js.map +1 -1
  163. package/dist/cjs/router/lastAction.native.js.map +1 -1
  164. package/dist/cjs/router/linkingConfig.native.js.map +1 -1
  165. package/dist/cjs/router/matchers.native.js.map +1 -1
  166. package/dist/cjs/router/matchers.test.native.js.map +1 -1
  167. package/dist/cjs/router/params.native.js.map +1 -1
  168. package/dist/cjs/router/renderingRegistry.cjs +53 -0
  169. package/dist/cjs/router/renderingRegistry.native.js +56 -0
  170. package/dist/cjs/router/renderingRegistry.native.js.map +1 -0
  171. package/dist/cjs/router/router.cjs +2 -0
  172. package/dist/cjs/router/router.native.js.map +1 -1
  173. package/dist/cjs/router/serverLocationContext.native.js.map +1 -1
  174. package/dist/cjs/router/sitemap.native.js.map +1 -1
  175. package/dist/cjs/router/sitemap.test.native.js.map +1 -1
  176. package/dist/cjs/router/sortRoutes.native.js.map +1 -1
  177. package/dist/cjs/router/useInitializeOneRouter.native.js.map +1 -1
  178. package/dist/cjs/router/useNavigation.native.js.map +1 -1
  179. package/dist/cjs/router/useScreens.native.js.map +1 -1
  180. package/dist/cjs/router/useViteRoutes.native.js.map +1 -1
  181. package/dist/cjs/router/utils/getNavigateAction.native.js.map +1 -1
  182. package/dist/cjs/router/utils/getNavigateAction.test.native.js.map +1 -1
  183. package/dist/cjs/router/web/ScreenRenderContext.cjs +36 -0
  184. package/dist/cjs/router/web/ScreenRenderContext.native.js +38 -0
  185. package/dist/cjs/router/web/ScreenRenderContext.native.js.map +1 -0
  186. package/dist/cjs/router/web/WebStackNavigator.cjs +74 -0
  187. package/dist/cjs/router/web/WebStackNavigator.native.js +78 -0
  188. package/dist/cjs/router/web/WebStackNavigator.native.js.map +1 -0
  189. package/dist/cjs/router/web/WebStackView.cjs +182 -0
  190. package/dist/cjs/router/web/WebStackView.native.js +235 -0
  191. package/dist/cjs/router/web/WebStackView.native.js.map +1 -0
  192. package/dist/cjs/router/web/__tests__/WebStackView.runtime.test.cjs +295 -0
  193. package/dist/cjs/router/web/__tests__/WebStackView.runtime.test.native.js +335 -0
  194. package/dist/cjs/router/web/__tests__/WebStackView.runtime.test.native.js.map +1 -0
  195. package/dist/cjs/router/web/__tests__/WebStackView.test.cjs +464 -0
  196. package/dist/cjs/router/web/__tests__/WebStackView.test.native.js +515 -0
  197. package/dist/cjs/router/web/__tests__/WebStackView.test.native.js.map +1 -0
  198. package/dist/cjs/router/web/__tests__/stackStateUtils.test.cjs +134 -0
  199. package/dist/cjs/router/web/__tests__/stackStateUtils.test.native.js +163 -0
  200. package/dist/cjs/router/web/__tests__/stackStateUtils.test.native.js.map +1 -0
  201. package/dist/cjs/router/web/stackStateUtils.cjs +60 -0
  202. package/dist/cjs/router/web/stackStateUtils.native.js +66 -0
  203. package/dist/cjs/router/web/stackStateUtils.native.js.map +1 -0
  204. package/dist/cjs/screensFeatureFlags.native.js.map +1 -1
  205. package/dist/cjs/serve-worker.native.js.map +1 -1
  206. package/dist/cjs/serve.native.js.map +1 -1
  207. package/dist/cjs/server/ServerContextScript.cjs +2 -1
  208. package/dist/cjs/server/ServerContextScript.native.js +2 -1
  209. package/dist/cjs/server/ServerContextScript.native.js.map +1 -1
  210. package/dist/cjs/server/createRoutesManifest.native.js.map +1 -1
  211. package/dist/cjs/server/getServerManifest.native.js.map +1 -1
  212. package/dist/cjs/server/getServerManifest.test.native.js.map +1 -1
  213. package/dist/cjs/server/oneServe.native.js.map +1 -1
  214. package/dist/cjs/server/setServerGlobals.native.js.map +1 -1
  215. package/dist/cjs/server/setupBuildOptions.native.js.map +1 -1
  216. package/dist/cjs/server/setupServerGlobals.native.js.map +1 -1
  217. package/dist/cjs/server/ssrLoaderData.native.js.map +1 -1
  218. package/dist/cjs/server/staticHtmlFetcher.native.js.map +1 -1
  219. package/dist/cjs/server/workerHandler.native.js.map +1 -1
  220. package/dist/cjs/server-render.native.js.map +1 -1
  221. package/dist/cjs/skewProtection.native.js.map +1 -1
  222. package/dist/cjs/testing-utils.native.js.map +1 -1
  223. package/dist/cjs/typed-routes/generateRouteTypes.native.js.map +1 -1
  224. package/dist/cjs/typed-routes/generateRouteTypes.test.native.js.map +1 -1
  225. package/dist/cjs/typed-routes/getTypedRoutesDeclarationFile.native.js.map +1 -1
  226. package/dist/cjs/typed-routes/getTypedRoutesDeclarationFile.test.native.js.map +1 -1
  227. package/dist/cjs/typed-routes/injectRouteHelpers.native.js.map +1 -1
  228. package/dist/cjs/types.native.js.map +1 -1
  229. package/dist/cjs/ui/Slot.native.js.map +1 -1
  230. package/dist/cjs/ui/TabContext.native.js.map +1 -1
  231. package/dist/cjs/ui/TabList.native.js.map +1 -1
  232. package/dist/cjs/ui/TabRouter.native.js.map +1 -1
  233. package/dist/cjs/ui/TabSlot.native.js.map +1 -1
  234. package/dist/cjs/ui/TabTrigger.native.js.map +1 -1
  235. package/dist/cjs/ui/Tabs.native.js.map +1 -1
  236. package/dist/cjs/ui/common.native.js.map +1 -1
  237. package/dist/cjs/ui/index.native.js.map +1 -1
  238. package/dist/cjs/ui/useComponent.native.js.map +1 -1
  239. package/dist/cjs/useFocusEffect.native.js.map +1 -1
  240. package/dist/cjs/useLoader.native.js.map +1 -1
  241. package/dist/cjs/useMatches.native.js.map +1 -1
  242. package/dist/cjs/useMatches.test.native.js.map +1 -1
  243. package/dist/cjs/useServerHeadInsertion.native.js.map +1 -1
  244. package/dist/cjs/utils/assertIsReady.native.js.map +1 -1
  245. package/dist/cjs/utils/buildOutputPointer.native.js.map +1 -1
  246. package/dist/cjs/utils/buildOutputPointer.test.native.js.map +1 -1
  247. package/dist/cjs/utils/children.native.js.map +1 -1
  248. package/dist/cjs/utils/cleanUrl.native.js.map +1 -1
  249. package/dist/cjs/utils/cleanUrl.test.native.js.map +1 -1
  250. package/dist/cjs/utils/dynamicImport.native.js.map +1 -1
  251. package/dist/cjs/utils/dynamicImport.test.native.js.map +1 -1
  252. package/dist/cjs/utils/ensureExists.native.js.map +1 -1
  253. package/dist/cjs/utils/evictOldest.native.js.map +1 -1
  254. package/dist/cjs/utils/existsAsync.native.js.map +1 -1
  255. package/dist/cjs/utils/findRootLayout.native.js.map +1 -1
  256. package/dist/cjs/utils/getPageExport.native.js.map +1 -1
  257. package/dist/cjs/utils/getPathnameFromFilePath.native.js.map +1 -1
  258. package/dist/cjs/utils/getPathnameFromFilePath.test.native.js.map +1 -1
  259. package/dist/cjs/utils/getRouterRootFromOneOptions.native.js.map +1 -1
  260. package/dist/cjs/utils/globDir.native.js.map +1 -1
  261. package/dist/cjs/utils/hashString.native.js.map +1 -1
  262. package/dist/cjs/utils/htmlEscape.native.js.map +1 -1
  263. package/dist/cjs/utils/isResponse.native.js.map +1 -1
  264. package/dist/cjs/utils/isRolldown.native.js.map +1 -1
  265. package/dist/cjs/utils/isStatus.native.js.map +1 -1
  266. package/dist/cjs/utils/pLimit.native.js.map +1 -1
  267. package/dist/cjs/utils/posixPathContract.test.native.js.map +1 -1
  268. package/dist/cjs/utils/promiseWithResolvers.native.js.map +1 -1
  269. package/dist/cjs/utils/rand.native.js.map +1 -1
  270. package/dist/cjs/utils/redirect.native.js.map +1 -1
  271. package/dist/cjs/utils/removeParams.native.js.map +1 -1
  272. package/dist/cjs/utils/removeSearch.native.js.map +1 -1
  273. package/dist/cjs/utils/removeUndefined.native.js.map +1 -1
  274. package/dist/cjs/utils/routeFileWatch.native.js.map +1 -1
  275. package/dist/cjs/utils/routeFileWatch.test.native.js.map +1 -1
  276. package/dist/cjs/utils/style.native.js.map +1 -1
  277. package/dist/cjs/utils/toAbsolute.native.js.map +1 -1
  278. package/dist/cjs/utils/toServerOutputPath.native.js.map +1 -1
  279. package/dist/cjs/utils/toServerOutputPath.test.native.js.map +1 -1
  280. package/dist/cjs/utils/trackLoaderDependencies.native.js.map +1 -1
  281. package/dist/cjs/utils/url.native.js.map +1 -1
  282. package/dist/cjs/utils/useConstant.native.js.map +1 -1
  283. package/dist/cjs/utils/watchFile.native.js.map +1 -1
  284. package/dist/cjs/utils/weakKey.native.js.map +1 -1
  285. package/dist/cjs/utils/weakMemo.native.js.map +1 -1
  286. package/dist/cjs/utils/withStaticProperties.native.js.map +1 -1
  287. package/dist/cjs/utils/workerImport.native.js.map +1 -1
  288. package/dist/cjs/validateParams.native.js.map +1 -1
  289. package/dist/cjs/validateSearch.native.js.map +1 -1
  290. package/dist/cjs/vercel/build/buildVercelOutputDirectory.native.js.map +1 -1
  291. package/dist/cjs/vercel/build/config/vc-build-output-config-base.native.js.map +1 -1
  292. package/dist/cjs/vercel/build/config/vc-config-base.native.js.map +1 -1
  293. package/dist/cjs/vercel/build/config/vc-package-base.native.js.map +1 -1
  294. package/dist/cjs/vercel/build/generate/createApiServerlessFunction.native.js.map +1 -1
  295. package/dist/cjs/vercel/build/generate/createSsrServerlessFunction.native.js.map +1 -1
  296. package/dist/cjs/vercel/build/getPathFromRoute.native.js.map +1 -1
  297. package/dist/cjs/views/EmptyRoute.native.js.map +1 -1
  298. package/dist/cjs/views/ErrorBoundary.native.js.map +1 -1
  299. package/dist/cjs/views/LoadProgressBar.native.js.map +1 -1
  300. package/dist/cjs/views/Navigator.native.js.map +1 -1
  301. package/dist/cjs/views/OneStackRouter.native.js.map +1 -1
  302. package/dist/cjs/views/Protected.native.js.map +1 -1
  303. package/dist/cjs/views/RootErrorBoundary.native.js.map +1 -1
  304. package/dist/cjs/views/Screen.native.js.map +1 -1
  305. package/dist/cjs/views/ScrollBehavior.native.js.map +1 -1
  306. package/dist/cjs/views/SourceInspector.native.js.map +1 -1
  307. package/dist/cjs/views/Try.native.js.map +1 -1
  308. package/dist/cjs/vite/DevHead.native.js.map +1 -1
  309. package/dist/cjs/vite/constants.native.js.map +1 -1
  310. package/dist/cjs/vite/customNodeExternals.native.js.map +1 -1
  311. package/dist/cjs/vite/ensureTsConfig.native.js.map +1 -1
  312. package/dist/cjs/vite/findDepsToOptimize.native.js.map +1 -1
  313. package/dist/cjs/vite/getManifest.native.js.map +1 -1
  314. package/dist/cjs/vite/getManifest.test.native.js.map +1 -1
  315. package/dist/cjs/vite/loadConfig.native.js.map +1 -1
  316. package/dist/cjs/vite/makePluginWebOnly.native.js.map +1 -1
  317. package/dist/cjs/vite/one-server-only.test.native.js.map +1 -1
  318. package/dist/cjs/vite/one.native.js.map +1 -1
  319. package/dist/cjs/vite/plugins/SSRCSSPlugin.native.js.map +1 -1
  320. package/dist/cjs/vite/plugins/clientTreeShakePlugin.native.js.map +1 -1
  321. package/dist/cjs/vite/plugins/clientTreeShakePlugin.test.native.js.map +1 -1
  322. package/dist/cjs/vite/plugins/criticalCSSPlugin.native.js.map +1 -1
  323. package/dist/cjs/vite/plugins/criticalCSSPlugin.test.native.js.map +1 -1
  324. package/dist/cjs/vite/plugins/devtoolsPlugin.native.js.map +1 -1
  325. package/dist/cjs/vite/plugins/environmentGuardPlugin.native.js.map +1 -1
  326. package/dist/cjs/vite/plugins/environmentGuardPlugin.test.native.js.map +1 -1
  327. package/dist/cjs/vite/plugins/fileSystemRouterPlugin.native.js.map +1 -1
  328. package/dist/cjs/vite/plugins/fileSystemRouterPlugin.test.native.js.map +1 -1
  329. package/dist/cjs/vite/plugins/fixDependenciesPlugin.native.js.map +1 -1
  330. package/dist/cjs/vite/plugins/generateFileSystemRouteTypesPlugin.native.js.map +1 -1
  331. package/dist/cjs/vite/plugins/imageDataPlugin.native.js.map +1 -1
  332. package/dist/cjs/vite/plugins/imageDataPlugin.test.native.js.map +1 -1
  333. package/dist/cjs/vite/plugins/removeReactNativeWebAnimatedPlugin.native.js.map +1 -1
  334. package/dist/cjs/vite/plugins/sourceInspectorPlugin.native.js.map +1 -1
  335. package/dist/cjs/vite/plugins/sourceInspectorPlugin.test.native.js.map +1 -1
  336. package/dist/cjs/vite/plugins/useDomPlugin.native.js.map +1 -1
  337. package/dist/cjs/vite/plugins/virtualEntryConstants.native.js.map +1 -1
  338. package/dist/cjs/vite/plugins/virtualEntryPlugin.native.js.map +1 -1
  339. package/dist/cjs/vite/plugins/virtualEntryPlugin.test.native.js.map +1 -1
  340. package/dist/cjs/vite/plugins/warmRoutesPlugin.native.js.map +1 -1
  341. package/dist/cjs/vite/replaceLoader.native.js.map +1 -1
  342. package/dist/cjs/vite/resolveResponse.native.js.map +1 -1
  343. package/dist/cjs/vite/types.native.js.map +1 -1
  344. package/dist/cjs/vite-auto-warm.native.js.map +1 -1
  345. package/dist/cjs/vite.native.js.map +1 -1
  346. package/dist/cjs/zero/getQueryKey.native.js.map +1 -1
  347. package/dist/cjs/zero/isZeroQuery.native.js.map +1 -1
  348. package/dist/cjs/zero/resolveQuery.native.js.map +1 -1
  349. package/dist/cjs/zero/subscribeToQuery.native.js.map +1 -1
  350. package/dist/cjs/zero/types.native.js.map +1 -1
  351. package/dist/cjs/zero/useQuery.native.js.map +1 -1
  352. package/dist/cjs/zero/useQueryZero.native.js.map +1 -1
  353. package/dist/cjs/zero.native.js.map +1 -1
  354. package/dist/esm/__mocks__/@react-navigation/native-stack.mjs +2 -1
  355. package/dist/esm/__mocks__/@react-navigation/native-stack.mjs.map +1 -1
  356. package/dist/esm/__mocks__/@react-navigation/native-stack.native.js +4 -1
  357. package/dist/esm/__mocks__/@react-navigation/native-stack.native.js.map +1 -1
  358. package/dist/esm/constants.test.mjs.map +1 -1
  359. package/dist/esm/constants.test.native.js.map +1 -1
  360. package/dist/esm/createHandleRequest.mjs +21 -12
  361. package/dist/esm/createHandleRequest.mjs.map +1 -1
  362. package/dist/esm/createHandleRequest.native.js +22 -12
  363. package/dist/esm/createHandleRequest.native.js.map +1 -1
  364. package/dist/esm/createHandleRequest.test.mjs +51 -6
  365. package/dist/esm/createHandleRequest.test.mjs.map +1 -1
  366. package/dist/esm/createHandleRequest.test.native.js +53 -6
  367. package/dist/esm/createHandleRequest.test.native.js.map +1 -1
  368. package/dist/esm/headless.mjs +1 -0
  369. package/dist/esm/headless.mjs.map +1 -1
  370. package/dist/esm/headless.native.js +1 -0
  371. package/dist/esm/headless.native.js.map +1 -1
  372. package/dist/esm/index.js +2 -1
  373. package/dist/esm/index.js.map +1 -1
  374. package/dist/esm/index.mjs +2 -1
  375. package/dist/esm/index.mjs.map +1 -1
  376. package/dist/esm/index.native.js +2 -1
  377. package/dist/esm/index.native.js.map +1 -1
  378. package/dist/esm/layouts/Drawer.mjs +35 -1
  379. package/dist/esm/layouts/Drawer.mjs.map +1 -1
  380. package/dist/esm/layouts/Drawer.native.js +36 -1
  381. package/dist/esm/layouts/Drawer.native.js.map +1 -1
  382. package/dist/esm/layouts/Stack.mjs +12 -3
  383. package/dist/esm/layouts/Stack.mjs.map +1 -1
  384. package/dist/esm/layouts/Stack.native.js +12 -3
  385. package/dist/esm/layouts/Stack.native.js.map +1 -1
  386. package/dist/esm/layouts/Tabs.mjs +31 -8
  387. package/dist/esm/layouts/Tabs.mjs.map +1 -1
  388. package/dist/esm/layouts/Tabs.native.js +32 -8
  389. package/dist/esm/layouts/Tabs.native.js.map +1 -1
  390. package/dist/esm/layouts/stack-navigator.mjs +4 -0
  391. package/dist/esm/layouts/stack-navigator.mjs.map +1 -0
  392. package/dist/esm/layouts/stack-navigator.native.js +4 -0
  393. package/dist/esm/layouts/stack-navigator.native.js.map +1 -0
  394. package/dist/esm/layouts/stack-utils/StackScreen.mjs.map +1 -1
  395. package/dist/esm/layouts/stack-utils/StackScreen.native.js.map +1 -1
  396. package/dist/esm/layouts/stack-utils/index.mjs.map +1 -1
  397. package/dist/esm/router/renderingRegistry.mjs +26 -0
  398. package/dist/esm/router/renderingRegistry.mjs.map +1 -0
  399. package/dist/esm/router/renderingRegistry.native.js +26 -0
  400. package/dist/esm/router/renderingRegistry.native.js.map +1 -0
  401. package/dist/esm/router/router.mjs +2 -0
  402. package/dist/esm/router/router.mjs.map +1 -1
  403. package/dist/esm/router/router.native.js.map +1 -1
  404. package/dist/esm/router/web/ScreenRenderContext.mjs +10 -0
  405. package/dist/esm/router/web/ScreenRenderContext.mjs.map +1 -0
  406. package/dist/esm/router/web/ScreenRenderContext.native.js +10 -0
  407. package/dist/esm/router/web/ScreenRenderContext.native.js.map +1 -0
  408. package/dist/esm/router/web/WebStackNavigator.mjs +49 -0
  409. package/dist/esm/router/web/WebStackNavigator.mjs.map +1 -0
  410. package/dist/esm/router/web/WebStackNavigator.native.js +51 -0
  411. package/dist/esm/router/web/WebStackNavigator.native.js.map +1 -0
  412. package/dist/esm/router/web/WebStackView.mjs +155 -0
  413. package/dist/esm/router/web/WebStackView.mjs.map +1 -0
  414. package/dist/esm/router/web/WebStackView.native.js +206 -0
  415. package/dist/esm/router/web/WebStackView.native.js.map +1 -0
  416. package/dist/esm/router/web/__tests__/WebStackView.runtime.test.mjs +272 -0
  417. package/dist/esm/router/web/__tests__/WebStackView.runtime.test.mjs.map +1 -0
  418. package/dist/esm/router/web/__tests__/WebStackView.runtime.test.native.js +309 -0
  419. package/dist/esm/router/web/__tests__/WebStackView.runtime.test.native.js.map +1 -0
  420. package/dist/esm/router/web/__tests__/WebStackView.test.mjs +465 -0
  421. package/dist/esm/router/web/__tests__/WebStackView.test.mjs.map +1 -0
  422. package/dist/esm/router/web/__tests__/WebStackView.test.native.js +513 -0
  423. package/dist/esm/router/web/__tests__/WebStackView.test.native.js.map +1 -0
  424. package/dist/esm/router/web/__tests__/stackStateUtils.test.mjs +135 -0
  425. package/dist/esm/router/web/__tests__/stackStateUtils.test.mjs.map +1 -0
  426. package/dist/esm/router/web/__tests__/stackStateUtils.test.native.js +161 -0
  427. package/dist/esm/router/web/__tests__/stackStateUtils.test.native.js.map +1 -0
  428. package/dist/esm/router/web/stackStateUtils.mjs +32 -0
  429. package/dist/esm/router/web/stackStateUtils.mjs.map +1 -0
  430. package/dist/esm/router/web/stackStateUtils.native.js +35 -0
  431. package/dist/esm/router/web/stackStateUtils.native.js.map +1 -0
  432. package/dist/esm/server/ServerContextScript.mjs +2 -1
  433. package/dist/esm/server/ServerContextScript.mjs.map +1 -1
  434. package/dist/esm/server/ServerContextScript.native.js +2 -1
  435. package/dist/esm/server/ServerContextScript.native.js.map +1 -1
  436. package/dist/esm/utils/dynamicImport.test.mjs.map +1 -1
  437. package/dist/esm/utils/dynamicImport.test.native.js.map +1 -1
  438. package/package.json +10 -9
  439. package/src/__mocks__/@react-navigation/native-stack.ts +22 -0
  440. package/src/constants.test.ts +12 -8
  441. package/src/createHandleRequest.test.ts +50 -6
  442. package/src/createHandleRequest.ts +26 -24
  443. package/src/headless.tsx +6 -0
  444. package/src/index.ts +20 -5
  445. package/src/layouts/Drawer.tsx +43 -1
  446. package/src/layouts/Stack.tsx +51 -33
  447. package/src/layouts/Tabs.tsx +89 -57
  448. package/src/layouts/stack-navigator.ts +9 -0
  449. package/src/layouts/stack-navigator.web.ts +3 -0
  450. package/src/layouts/stack-utils/StackScreen.tsx +30 -9
  451. package/src/layouts/stack-utils/index.tsx +1 -0
  452. package/src/router/renderingRegistry.ts +109 -0
  453. package/src/router/router.ts +33 -9
  454. package/src/router/web/ScreenRenderContext.tsx +61 -0
  455. package/src/router/web/WebStackNavigator.tsx +87 -0
  456. package/src/router/web/WebStackView.tsx +264 -0
  457. package/src/router/web/__tests__/WebStackView.runtime.test.tsx +309 -0
  458. package/src/router/web/__tests__/WebStackView.test.tsx +444 -0
  459. package/src/router/web/__tests__/stackStateUtils.test.ts +153 -0
  460. package/src/router/web/stackStateUtils.ts +89 -0
  461. package/src/server/ServerContextScript.tsx +8 -7
  462. package/src/utils/dynamicImport.test.ts +9 -7
  463. package/types/__mocks__/@react-navigation/native-stack.d.ts +9 -0
  464. package/types/__mocks__/@react-navigation/native-stack.d.ts.map +1 -1
  465. package/types/createHandleRequest.d.ts.map +1 -1
  466. package/types/headless.d.ts.map +1 -1
  467. package/types/index.d.ts +4 -2
  468. package/types/index.d.ts.map +1 -1
  469. package/types/layouts/Drawer.d.ts +13 -2
  470. package/types/layouts/Drawer.d.ts.map +1 -1
  471. package/types/layouts/Stack.d.ts +11 -1
  472. package/types/layouts/Stack.d.ts.map +1 -1
  473. package/types/layouts/Tabs.d.ts +14 -4
  474. package/types/layouts/Tabs.d.ts.map +1 -1
  475. package/types/layouts/stack-navigator.d.ts +9 -0
  476. package/types/layouts/stack-navigator.d.ts.map +1 -0
  477. package/types/layouts/stack-navigator.web.d.ts +2 -0
  478. package/types/layouts/stack-navigator.web.d.ts.map +1 -0
  479. package/types/layouts/stack-utils/StackScreen.d.ts +24 -2
  480. package/types/layouts/stack-utils/StackScreen.d.ts.map +1 -1
  481. package/types/layouts/stack-utils/index.d.ts +1 -1
  482. package/types/layouts/stack-utils/index.d.ts.map +1 -1
  483. package/types/router/renderingRegistry.d.ts +90 -0
  484. package/types/router/renderingRegistry.d.ts.map +1 -0
  485. package/types/router/router.d.ts.map +1 -1
  486. package/types/router/web/ScreenRenderContext.d.ts +46 -0
  487. package/types/router/web/ScreenRenderContext.d.ts.map +1 -0
  488. package/types/router/web/WebStackNavigator.d.ts +2 -0
  489. package/types/router/web/WebStackNavigator.d.ts.map +1 -0
  490. package/types/router/web/WebStackView.d.ts +42 -0
  491. package/types/router/web/WebStackView.d.ts.map +1 -0
  492. package/types/router/web/stackStateUtils.d.ts +35 -0
  493. package/types/router/web/stackStateUtils.d.ts.map +1 -0
  494. package/types/server/ServerContextScript.d.ts.map +1 -1
@@ -0,0 +1,444 @@
1
+ import { describe, expect, it, vi } from 'vitest'
2
+ import { createElement, type ReactNode } from 'react'
3
+ import { renderToStaticMarkup } from 'react-dom/server'
4
+
5
+ import { OverlayHost, resolveOverlayRender, WebStackView } from '../WebStackView'
6
+ import { StackRenderProvider, type StackRender } from '../ScreenRenderContext'
7
+
8
+ type Descriptor = {
9
+ options: any
10
+ render: () => ReactNode
11
+ navigation: any
12
+ }
13
+
14
+ function makeRoute(name: string) {
15
+ return { key: `${name}-key`, name, params: undefined }
16
+ }
17
+
18
+ function makeState(names: string[], index: number) {
19
+ return {
20
+ key: 'stack-1',
21
+ index,
22
+ routeNames: names,
23
+ routes: names.map(makeRoute),
24
+ type: 'stack',
25
+ stale: false,
26
+ preloadedRoutes: [],
27
+ } as any
28
+ }
29
+
30
+ function makeDescriptors(
31
+ perRoute: Record<string, { options: any; content?: ReactNode }>
32
+ ): Record<string, Descriptor> {
33
+ const out: Record<string, Descriptor> = {}
34
+ for (const name of Object.keys(perRoute)) {
35
+ out[`${name}-key`] = {
36
+ options: perRoute[name]!.options,
37
+ render: () => perRoute[name]!.content ?? null,
38
+ navigation: {},
39
+ }
40
+ }
41
+ return out
42
+ }
43
+
44
+ describe('resolveOverlayRender', () => {
45
+ const A = () => null
46
+ const B = () => null
47
+
48
+ it('prefers per-route render over context', () => {
49
+ const result = resolveOverlayRender(
50
+ { presentation: 'formSheet', render: { web: A } },
51
+ { web: B }
52
+ )
53
+ expect(result).toBe(A)
54
+ })
55
+
56
+ it('falls back to context render when route has none', () => {
57
+ const result = resolveOverlayRender({ presentation: 'formSheet' }, { web: B })
58
+ expect(result).toBe(B)
59
+ })
60
+
61
+ it('returns undefined when nothing is configured', () => {
62
+ expect(resolveOverlayRender({ presentation: 'formSheet' }, undefined)).toBeUndefined()
63
+ expect(
64
+ resolveOverlayRender({ presentation: 'formSheet' }, { ios: A })
65
+ ).toBeUndefined()
66
+ })
67
+
68
+ it('does not pick from ios/android slots on web', () => {
69
+ expect(
70
+ resolveOverlayRender({ presentation: 'formSheet', render: { ios: A } }, { web: B })
71
+ ).toBe(B)
72
+ })
73
+ })
74
+
75
+ describe('OverlayHost', () => {
76
+ it('invokes the render component with route props for overlay presentations', () => {
77
+ const captured: any[] = []
78
+ const Render = vi.fn((props: any) => {
79
+ captured.push(props)
80
+ return createElement('div', { 'data-modal': props.routeKey }, props.children)
81
+ })
82
+
83
+ const descriptors = makeDescriptors({
84
+ filter: {
85
+ options: {
86
+ presentation: 'formSheet',
87
+ sheetAllowedDetents: [0.5, 1],
88
+ sheetGrabberVisible: true,
89
+ },
90
+ content: createElement('span', null, 'filter-body'),
91
+ },
92
+ })
93
+
94
+ const markup = renderToStaticMarkup(
95
+ createElement(OverlayHost, {
96
+ route: makeRoute('filter'),
97
+ descriptor: descriptors['filter-key']!,
98
+ contextRender: { web: Render },
99
+ onDismiss: () => {},
100
+ })
101
+ )
102
+
103
+ expect(Render).toHaveBeenCalledTimes(1)
104
+ expect(captured[0]).toMatchObject({
105
+ routeKey: 'filter-key',
106
+ presentation: 'formSheet',
107
+ sheetAllowedDetents: [0.5, 1],
108
+ sheetGrabberVisible: true,
109
+ dismissible: true,
110
+ })
111
+ expect(typeof captured[0].dismiss).toBe('function')
112
+ expect(markup).toContain('data-modal="filter-key"')
113
+ expect(markup).toContain('filter-body')
114
+ })
115
+
116
+ it('falls back to inline rendering when no render is configured', () => {
117
+ const descriptors = makeDescriptors({
118
+ filter: {
119
+ options: { presentation: 'formSheet' },
120
+ content: createElement('span', null, 'inline-content'),
121
+ },
122
+ })
123
+
124
+ const markup = renderToStaticMarkup(
125
+ createElement(OverlayHost, {
126
+ route: makeRoute('filter'),
127
+ descriptor: descriptors['filter-key']!,
128
+ contextRender: undefined,
129
+ onDismiss: () => {},
130
+ })
131
+ )
132
+
133
+ expect(markup).toContain('inline-content')
134
+ })
135
+
136
+ it('skips render when presentation is not an overlay', () => {
137
+ const Render = vi.fn(() => null)
138
+ const descriptors = makeDescriptors({
139
+ home: {
140
+ options: { presentation: 'card' },
141
+ content: createElement('span', null, 'card-content'),
142
+ },
143
+ })
144
+
145
+ const markup = renderToStaticMarkup(
146
+ createElement(OverlayHost, {
147
+ route: makeRoute('home'),
148
+ descriptor: descriptors['home-key']!,
149
+ contextRender: { web: Render },
150
+ onDismiss: () => {},
151
+ })
152
+ )
153
+
154
+ expect(Render).not.toHaveBeenCalled()
155
+ expect(markup).toContain('card-content')
156
+ })
157
+
158
+ it('per-route render overrides context render', () => {
159
+ const ContextRender = vi.fn(() => null)
160
+ const PerRoute = vi.fn(() => createElement('em', null, 'per-route'))
161
+ const descriptors = makeDescriptors({
162
+ sheet: {
163
+ options: {
164
+ presentation: 'formSheet',
165
+ render: { web: PerRoute },
166
+ },
167
+ content: createElement('span', null, 'body'),
168
+ },
169
+ })
170
+
171
+ const markup = renderToStaticMarkup(
172
+ createElement(OverlayHost, {
173
+ route: makeRoute('sheet'),
174
+ descriptor: descriptors['sheet-key']!,
175
+ contextRender: { web: ContextRender },
176
+ onDismiss: () => {},
177
+ })
178
+ )
179
+
180
+ expect(PerRoute).toHaveBeenCalledTimes(1)
181
+ expect(ContextRender).not.toHaveBeenCalled()
182
+ expect(markup).toContain('per-route')
183
+ })
184
+
185
+ it('dismiss callback wraps the supplied onDismiss', () => {
186
+ const onDismiss = vi.fn()
187
+ let capturedDismiss: (() => void) | undefined
188
+ const Render = (props: any) => {
189
+ capturedDismiss = props.dismiss
190
+ return null
191
+ }
192
+ const descriptors = makeDescriptors({
193
+ sheet: { options: { presentation: 'formSheet' } },
194
+ })
195
+
196
+ renderToStaticMarkup(
197
+ createElement(OverlayHost, {
198
+ route: makeRoute('sheet'),
199
+ descriptor: descriptors['sheet-key']!,
200
+ contextRender: { web: Render },
201
+ onDismiss,
202
+ })
203
+ )
204
+
205
+ expect(typeof capturedDismiss).toBe('function')
206
+ capturedDismiss!()
207
+ expect(onDismiss).toHaveBeenCalledTimes(1)
208
+ })
209
+
210
+ it('respects gestureEnabled: false as dismissible: false', () => {
211
+ let captured: any
212
+ const Render = (props: any) => {
213
+ captured = props
214
+ return null
215
+ }
216
+ const descriptors = makeDescriptors({
217
+ sheet: { options: { presentation: 'formSheet', gestureEnabled: false } },
218
+ })
219
+
220
+ renderToStaticMarkup(
221
+ createElement(OverlayHost, {
222
+ route: makeRoute('sheet'),
223
+ descriptor: descriptors['sheet-key']!,
224
+ contextRender: { web: Render },
225
+ onDismiss: () => {},
226
+ })
227
+ )
228
+
229
+ expect(captured.dismissible).toBe(false)
230
+ })
231
+ })
232
+
233
+ describe('WebStackView overlay dispatch', () => {
234
+ it('renders each overlay route via the configured render', () => {
235
+ const calls: string[] = []
236
+ const Render = (props: any) => {
237
+ calls.push(props.routeKey)
238
+ return createElement('div', { 'data-route': props.routeKey })
239
+ }
240
+
241
+ const state = makeState(['home', 'filter', 'help'], 2)
242
+ const descriptors = makeDescriptors({
243
+ home: { options: { presentation: 'card' } },
244
+ filter: { options: { presentation: 'formSheet' } },
245
+ help: { options: { presentation: 'modal' } },
246
+ })
247
+
248
+ const navigation = { dispatch: vi.fn() } as any
249
+
250
+ const markup = renderToStaticMarkup(
251
+ createElement(
252
+ StackRenderProvider,
253
+ { value: { web: Render } as StackRender },
254
+ createElement(WebStackView, {
255
+ state,
256
+ navigation,
257
+ descriptors: descriptors as any,
258
+ })
259
+ )
260
+ )
261
+
262
+ expect(calls).toEqual(['filter-key', 'help-key'])
263
+ expect(markup).toContain('data-route="filter-key"')
264
+ expect(markup).toContain('data-route="help-key"')
265
+ })
266
+
267
+ it('leaves overlay routes in the underlying NativeStackView when no render is configured', () => {
268
+ // No render in context → no overlay split → NativeStackView (mocked to
269
+ // return null) renders the route normally. No extra DOM from overlays.
270
+ const state = makeState(['home', 'filter'], 1)
271
+ const descriptors = makeDescriptors({
272
+ home: { options: { presentation: 'card' } },
273
+ filter: {
274
+ options: { presentation: 'formSheet' },
275
+ content: createElement('span', null, 'should-not-render-as-overlay'),
276
+ },
277
+ })
278
+ const navigation = { dispatch: vi.fn() } as any
279
+
280
+ const markup = renderToStaticMarkup(
281
+ createElement(WebStackView, {
282
+ state,
283
+ navigation,
284
+ descriptors: descriptors as any,
285
+ })
286
+ )
287
+
288
+ // Mock NativeStackView returns null, and we shouldn't have rendered the
289
+ // overlay route ourselves either.
290
+ expect(markup).not.toContain('should-not-render-as-overlay')
291
+ })
292
+
293
+ it('passes open: true to the regular overlay render', () => {
294
+ let captured: any
295
+ const Render = (props: any) => {
296
+ captured = props
297
+ return null
298
+ }
299
+ const state = makeState(['home', 'sheet'], 1)
300
+ const descriptors = makeDescriptors({
301
+ home: { options: { presentation: 'card' } },
302
+ sheet: { options: { presentation: 'formSheet' } },
303
+ })
304
+ const navigation = { dispatch: vi.fn() } as any
305
+
306
+ renderToStaticMarkup(
307
+ createElement(
308
+ StackRenderProvider,
309
+ { value: { web: Render } as StackRender },
310
+ createElement(WebStackView, {
311
+ state,
312
+ navigation,
313
+ descriptors: descriptors as any,
314
+ })
315
+ )
316
+ )
317
+
318
+ expect(captured.open).toBe(true)
319
+ expect(captured.routeName).toBe('sheet')
320
+ })
321
+
322
+ it('keepMounted: keeps rendering the route via the persistent slot after the route is popped', () => {
323
+ const calls: { name: string; open: boolean; bodyMarker?: any }[] = []
324
+ let mountTrackerCalls = 0
325
+ const Render = (props: any) => {
326
+ calls.push({ name: props.routeName, open: props.open })
327
+ return createElement(
328
+ 'div',
329
+ { 'data-route': props.routeName, 'data-open': String(props.open) },
330
+ props.children
331
+ )
332
+ }
333
+
334
+ // Probe: a component that tracks how many times it mounts vs. re-renders.
335
+ // If the persistent slot works, this mounts once and re-renders many
336
+ // times. If it remounts, mountTrackerCalls increases.
337
+ const MountTracker = () => {
338
+ mountTrackerCalls++
339
+ return createElement('span', null, `mounted-${mountTrackerCalls}`)
340
+ }
341
+
342
+ const initialState = makeState(['home', 'settings'], 1)
343
+ const settingsDescriptor: Descriptor = {
344
+ options: { presentation: 'formSheet', keepMounted: true },
345
+ render: () => createElement(MountTracker),
346
+ navigation: {},
347
+ }
348
+ const descriptors: Record<string, Descriptor> = {
349
+ 'home-key': {
350
+ options: { presentation: 'card' },
351
+ render: () => null,
352
+ navigation: {},
353
+ },
354
+ 'settings-key': settingsDescriptor,
355
+ }
356
+
357
+ // Render once with settings open.
358
+ const navigation = { dispatch: vi.fn() } as any
359
+ const tree = createElement(
360
+ StackRenderProvider,
361
+ { value: { web: Render } as StackRender },
362
+ createElement(WebStackView, {
363
+ state: initialState,
364
+ navigation,
365
+ descriptors: descriptors as any,
366
+ })
367
+ )
368
+ const out1 = renderToStaticMarkup(tree)
369
+
370
+ expect(calls.some((c) => c.name === 'settings' && c.open === true)).toBe(true)
371
+ expect(out1).toContain('data-route="settings"')
372
+ expect(out1).toContain('data-open="true"')
373
+
374
+ // Now re-render with settings popped (only home in state). Persistent
375
+ // slot should still render the settings route with open=false.
376
+ // Note: SSR renderToStaticMarkup does NOT share refs across calls, so
377
+ // for this assertion we instead verify the rendered shape: even though
378
+ // the persistent slot ref is fresh in SSR, the API contract says the
379
+ // FIRST render captures and SUBSEQUENT renders keep emitting. We test
380
+ // that path in the jsdom test below - here we just verify single-pass
381
+ // capture happens with open=true on the initial render.
382
+ expect(calls).toHaveLength(1)
383
+ })
384
+
385
+ it('peels off only overlay routes with a render configured, leaving render-less overlays in the underlying view', () => {
386
+ // help (modal, no render) is below filter (formSheet, with render).
387
+ // help should stay in NativeStackView; filter should be dispatched to
388
+ // the render component as the trailing overlay.
389
+ const PerRoute = vi.fn(() => createElement('div', { 'data-route': 'filter' }))
390
+ const state = makeState(['home', 'help', 'filter'], 2)
391
+ const descriptors = makeDescriptors({
392
+ home: { options: { presentation: 'card' } },
393
+ help: { options: { presentation: 'modal' } }, // overlay-presented, no render
394
+ filter: {
395
+ options: { presentation: 'formSheet', render: { web: PerRoute } },
396
+ },
397
+ })
398
+ const navigation = { dispatch: vi.fn() } as any
399
+
400
+ renderToStaticMarkup(
401
+ createElement(WebStackView, {
402
+ state,
403
+ navigation,
404
+ descriptors: descriptors as any,
405
+ })
406
+ )
407
+
408
+ expect(PerRoute).toHaveBeenCalledTimes(1)
409
+ })
410
+
411
+ it('dispatches a pop action when an overlay calls dismiss', () => {
412
+ let captured: any
413
+ const Render = (props: any) => {
414
+ captured = props
415
+ return null
416
+ }
417
+ const state = makeState(['home', 'filter'], 1)
418
+ const descriptors = makeDescriptors({
419
+ home: { options: { presentation: 'card' } },
420
+ filter: { options: { presentation: 'formSheet' } },
421
+ })
422
+ const dispatch = vi.fn()
423
+ const navigation = { dispatch, isFocused: () => true } as any
424
+
425
+ renderToStaticMarkup(
426
+ createElement(
427
+ StackRenderProvider,
428
+ { value: { web: Render } as StackRender },
429
+ createElement(WebStackView, {
430
+ state,
431
+ navigation,
432
+ descriptors: descriptors as any,
433
+ })
434
+ )
435
+ )
436
+
437
+ captured.dismiss()
438
+ expect(dispatch).toHaveBeenCalledTimes(1)
439
+ const action = dispatch.mock.calls[0]![0]
440
+ expect(action.type).toBe('POP')
441
+ expect(action.source).toBe('filter-key')
442
+ expect(action.target).toBe('stack-1')
443
+ })
444
+ })
@@ -0,0 +1,153 @@
1
+ import { describe, expect, it } from 'vitest'
2
+ import type { ParamListBase, StackNavigationState } from '@react-navigation/native'
3
+ import type { NativeStackNavigationOptions } from '@react-navigation/native-stack'
4
+
5
+ import {
6
+ convertStackStateToNonOverlayState,
7
+ findLastNonOverlayIndex,
8
+ isOverlayPresentation,
9
+ isTransparentOverlay,
10
+ } from '../stackStateUtils'
11
+
12
+ type Descriptors = Record<string, { options: NativeStackNavigationOptions }>
13
+
14
+ function makeState(
15
+ routeNames: string[],
16
+ index: number
17
+ ): StackNavigationState<ParamListBase> {
18
+ const routes = routeNames.map((name) => ({
19
+ key: `${name}-key`,
20
+ name,
21
+ params: undefined,
22
+ })) as StackNavigationState<ParamListBase>['routes']
23
+ return {
24
+ key: 'stack',
25
+ index,
26
+ routeNames,
27
+ routes,
28
+ type: 'stack',
29
+ stale: false,
30
+ preloadedRoutes: [],
31
+ } as unknown as StackNavigationState<ParamListBase>
32
+ }
33
+
34
+ function makeDescriptors(
35
+ routeNames: string[],
36
+ presentations: Record<string, NativeStackNavigationOptions['presentation']>
37
+ ): Descriptors {
38
+ const out: Descriptors = {}
39
+ for (const name of routeNames) {
40
+ out[`${name}-key`] = { options: { presentation: presentations[name] } }
41
+ }
42
+ return out
43
+ }
44
+
45
+ describe('isOverlayPresentation', () => {
46
+ it('returns true for known overlay presentations', () => {
47
+ for (const p of [
48
+ 'modal',
49
+ 'transparentModal',
50
+ 'fullScreenModal',
51
+ 'formSheet',
52
+ 'pageSheet',
53
+ 'containedModal',
54
+ 'containedTransparentModal',
55
+ ] as const) {
56
+ expect(isOverlayPresentation({ presentation: p })).toBe(true)
57
+ }
58
+ })
59
+
60
+ it('returns false for card and undefined', () => {
61
+ expect(isOverlayPresentation({ presentation: 'card' })).toBe(false)
62
+ expect(isOverlayPresentation({})).toBe(false)
63
+ expect(isOverlayPresentation(undefined)).toBe(false)
64
+ expect(isOverlayPresentation(null)).toBe(false)
65
+ })
66
+ })
67
+
68
+ describe('isTransparentOverlay', () => {
69
+ it('flags transparent variants only', () => {
70
+ expect(isTransparentOverlay({ presentation: 'transparentModal' })).toBe(true)
71
+ expect(isTransparentOverlay({ presentation: 'containedTransparentModal' })).toBe(true)
72
+ expect(isTransparentOverlay({ presentation: 'modal' })).toBe(false)
73
+ expect(isTransparentOverlay({ presentation: 'formSheet' })).toBe(false)
74
+ })
75
+ })
76
+
77
+ describe('convertStackStateToNonOverlayState', () => {
78
+ it('removes overlay routes and keeps card routes', () => {
79
+ const state = makeState(['home', 'detail', 'filter'], 2)
80
+ const descriptors = makeDescriptors(['home', 'detail', 'filter'], {
81
+ home: 'card',
82
+ detail: 'card',
83
+ filter: 'formSheet',
84
+ })
85
+ const out = convertStackStateToNonOverlayState(state, descriptors)
86
+ expect(out.routes.map((r) => r.name)).toEqual(['home', 'detail'])
87
+ })
88
+
89
+ it('falls back to last remaining route when active route was an overlay', () => {
90
+ const state = makeState(['home', 'detail', 'filter'], 2)
91
+ const descriptors = makeDescriptors(['home', 'detail', 'filter'], {
92
+ home: 'card',
93
+ detail: 'card',
94
+ filter: 'formSheet',
95
+ })
96
+ const out = convertStackStateToNonOverlayState(state, descriptors)
97
+ expect(out.index).toBe(1)
98
+ expect(out.routes[out.index]!.name).toBe('detail')
99
+ })
100
+
101
+ it('preserves active index when active route is not an overlay', () => {
102
+ const state = makeState(['home', 'detail', 'filter'], 1)
103
+ const descriptors = makeDescriptors(['home', 'detail', 'filter'], {
104
+ home: 'card',
105
+ detail: 'card',
106
+ filter: 'formSheet',
107
+ })
108
+ const out = convertStackStateToNonOverlayState(state, descriptors)
109
+ expect(out.routes[out.index]!.name).toBe('detail')
110
+ })
111
+
112
+ it('does not strip mid-stack overlays (regression: only the trailing overlay suffix is removed)', () => {
113
+ // User opened a sheet then navigated forward to a card. The sheet is
114
+ // sandwiched in the middle. It MUST stay in the underlying state so
115
+ // detail's previous-route / header-back context references the sheet.
116
+ const state = makeState(['home', 'sheet', 'detail'], 2)
117
+ const descriptors = makeDescriptors(['home', 'sheet', 'detail'], {
118
+ home: 'card',
119
+ sheet: 'formSheet',
120
+ detail: 'card',
121
+ })
122
+ const out = convertStackStateToNonOverlayState(state, descriptors)
123
+ expect(out.routes.map((r) => r.name)).toEqual(['home', 'sheet', 'detail'])
124
+ expect(out.index).toBe(2)
125
+ })
126
+
127
+ it('handles all-overlay state without crashing', () => {
128
+ const state = makeState(['only-sheet'], 0)
129
+ const descriptors = makeDescriptors(['only-sheet'], { 'only-sheet': 'formSheet' })
130
+ const out = convertStackStateToNonOverlayState(state, descriptors)
131
+ expect(out.routes).toHaveLength(0)
132
+ expect(out.index).toBe(0)
133
+ })
134
+ })
135
+
136
+ describe('findLastNonOverlayIndex', () => {
137
+ it('returns the highest index that is not an overlay', () => {
138
+ const state = makeState(['home', 'detail', 'filter', 'pop'], 3)
139
+ const descriptors = makeDescriptors(['home', 'detail', 'filter', 'pop'], {
140
+ home: 'card',
141
+ detail: 'card',
142
+ filter: 'formSheet',
143
+ pop: 'transparentModal',
144
+ })
145
+ expect(findLastNonOverlayIndex(state, descriptors)).toBe(1)
146
+ })
147
+
148
+ it('returns -1 when every route is an overlay', () => {
149
+ const state = makeState(['sheet'], 0)
150
+ const descriptors = makeDescriptors(['sheet'], { sheet: 'formSheet' })
151
+ expect(findLastNonOverlayIndex(state, descriptors)).toBe(-1)
152
+ })
153
+ })
@@ -0,0 +1,89 @@
1
+ import type { ParamListBase, StackNavigationState } from '@react-navigation/native'
2
+ import type { NativeStackNavigationOptions } from '@react-navigation/native-stack'
3
+
4
+ const OVERLAY_PRESENTATIONS = [
5
+ 'modal',
6
+ 'transparentModal',
7
+ 'fullScreenModal',
8
+ 'formSheet',
9
+ 'pageSheet',
10
+ 'containedModal',
11
+ 'containedTransparentModal',
12
+ ] as const
13
+
14
+ type OverlayPresentation = (typeof OVERLAY_PRESENTATIONS)[number]
15
+
16
+ type DescriptorMap = Record<string, { options: NativeStackNavigationOptions }>
17
+
18
+ export function isOverlayPresentation(
19
+ options: NativeStackNavigationOptions | undefined | null
20
+ ): boolean {
21
+ const presentation = options?.presentation
22
+ if (!presentation) return false
23
+ return (OVERLAY_PRESENTATIONS as readonly string[]).includes(presentation)
24
+ }
25
+
26
+ export function isTransparentOverlay(
27
+ options: NativeStackNavigationOptions | undefined | null
28
+ ): boolean {
29
+ const presentation = options?.presentation
30
+ return (
31
+ presentation === 'transparentModal' || presentation === 'containedTransparentModal'
32
+ )
33
+ }
34
+
35
+ /**
36
+ * Returns the underlying navigation state for NativeStackView with the
37
+ * trailing overlay suffix removed.
38
+ *
39
+ * Important: we only strip the suffix of overlay routes at the top of the
40
+ * stack. Overlay routes that are SANDWICHED between cards (e.g. user
41
+ * navigated forward from a sheet to a card) stay in the underlying state
42
+ * so NativeStackView still has a complete history and downstream routes
43
+ * keep their correct previous-route / header-back context.
44
+ *
45
+ * The `isOverlay` predicate defaults to `isOverlayPresentation`; callers
46
+ * can narrow it (e.g. only routes that actually have a render component
47
+ * configured).
48
+ */
49
+ export function convertStackStateToNonOverlayState(
50
+ state: StackNavigationState<ParamListBase>,
51
+ descriptors: DescriptorMap,
52
+ isOverlay: (
53
+ options: NativeStackNavigationOptions | undefined | null
54
+ ) => boolean = isOverlayPresentation
55
+ ): { routes: typeof state.routes; index: number } {
56
+ const lastNonOverlay = findLastNonOverlayIndex(state, descriptors, isOverlay)
57
+ const routes = state.routes.slice(0, lastNonOverlay + 1)
58
+
59
+ // If the active route was in the trailing overlay suffix, clamp the index
60
+ // to the last route still in the underlying view.
61
+ let index = state.index
62
+ if (index >= routes.length) {
63
+ index = routes.length > 0 ? routes.length - 1 : 0
64
+ }
65
+
66
+ return { routes, index }
67
+ }
68
+
69
+ /**
70
+ * Index of the last route that is NOT an overlay. Returns -1 if every route
71
+ * is an overlay. Accepts the same predicate as
72
+ * `convertStackStateToNonOverlayState`.
73
+ */
74
+ export function findLastNonOverlayIndex(
75
+ state: StackNavigationState<ParamListBase>,
76
+ descriptors: DescriptorMap,
77
+ isOverlay: (
78
+ options: NativeStackNavigationOptions | undefined | null
79
+ ) => boolean = isOverlayPresentation
80
+ ): number {
81
+ for (let i = state.routes.length - 1; i >= 0; i--) {
82
+ if (!isOverlay(descriptors[state.routes[i]!.key]?.options)) {
83
+ return i
84
+ }
85
+ }
86
+ return -1
87
+ }
88
+
89
+ export type { OverlayPresentation }