one 1.2.57 → 1.2.58

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 (481) hide show
  1. package/dist/cjs/cli/buildPage.cjs +1 -1
  2. package/dist/cjs/cli/buildPage.js +1 -1
  3. package/dist/cjs/cli/buildPage.native.js +1 -1
  4. package/dist/cjs/cli/buildPage.native.js.map +1 -1
  5. package/dist/cjs/cli/dev.cjs +4 -4
  6. package/dist/cjs/cli/dev.js +4 -4
  7. package/dist/cjs/cli/dev.js.map +1 -1
  8. package/dist/cjs/cli/dev.native.js +4 -4
  9. package/dist/cjs/cli/dev.native.js.map +1 -1
  10. package/dist/cjs/createApp.cjs +2 -1
  11. package/dist/cjs/createApp.js +2 -2
  12. package/dist/cjs/createApp.js.map +1 -1
  13. package/dist/cjs/createHandleRequest.test.js +3 -1
  14. package/dist/cjs/createHandleRequest.test.js.map +1 -1
  15. package/dist/cjs/createHandleRequest.test.native.js.map +1 -1
  16. package/dist/cjs/devtools/registry.cjs +30 -0
  17. package/dist/cjs/devtools/registry.js +25 -0
  18. package/dist/cjs/devtools/registry.js.map +6 -0
  19. package/dist/cjs/devtools/registry.native.js +33 -0
  20. package/dist/cjs/devtools/registry.native.js.map +1 -0
  21. package/dist/cjs/fork/createMemoryHistory.cjs +20 -9
  22. package/dist/cjs/fork/createMemoryHistory.js +22 -4
  23. package/dist/cjs/fork/createMemoryHistory.js.map +1 -1
  24. package/dist/cjs/fork/createMemoryHistory.native.js +20 -9
  25. package/dist/cjs/fork/createMemoryHistory.native.js.map +1 -1
  26. package/dist/cjs/fork/useLinking.cjs +11 -5
  27. package/dist/cjs/fork/useLinking.js +6 -6
  28. package/dist/cjs/fork/useLinking.js.map +1 -1
  29. package/dist/cjs/index.cjs +17 -1
  30. package/dist/cjs/index.js +12 -2
  31. package/dist/cjs/index.js.map +1 -1
  32. package/dist/cjs/index.native.js +17 -1
  33. package/dist/cjs/index.native.js.map +1 -1
  34. package/dist/cjs/layouts/withLayoutContext.cjs +34 -15
  35. package/dist/cjs/layouts/withLayoutContext.js +29 -13
  36. package/dist/cjs/layouts/withLayoutContext.js.map +1 -1
  37. package/dist/cjs/layouts/withLayoutContext.native.js +42 -19
  38. package/dist/cjs/layouts/withLayoutContext.native.js.map +1 -1
  39. package/dist/cjs/link/Link.cjs +5 -2
  40. package/dist/cjs/link/Link.js +3 -2
  41. package/dist/cjs/link/Link.js.map +1 -1
  42. package/dist/cjs/link/Link.native.js +6 -1
  43. package/dist/cjs/link/Link.native.js.map +1 -1
  44. package/dist/cjs/link/useLinkTo.cjs +11 -3
  45. package/dist/cjs/link/useLinkTo.js +6 -3
  46. package/dist/cjs/link/useLinkTo.js.map +1 -1
  47. package/dist/cjs/link/useLinkTo.native.js +11 -3
  48. package/dist/cjs/link/useLinkTo.native.js.map +1 -1
  49. package/dist/cjs/router/Route.js.map +1 -1
  50. package/dist/cjs/router/Route.native.js.map +1 -1
  51. package/dist/cjs/router/findRouteNode.cjs +70 -0
  52. package/dist/cjs/router/findRouteNode.js +72 -0
  53. package/dist/cjs/router/findRouteNode.js.map +6 -0
  54. package/dist/cjs/router/findRouteNode.native.js +104 -0
  55. package/dist/cjs/router/findRouteNode.native.js.map +1 -0
  56. package/dist/cjs/router/router.cjs +160 -11
  57. package/dist/cjs/router/router.js +142 -7
  58. package/dist/cjs/router/router.js.map +2 -2
  59. package/dist/cjs/router/router.native.js +241 -57
  60. package/dist/cjs/router/router.native.js.map +1 -1
  61. package/dist/cjs/router/useScreens.cjs +1 -1
  62. package/dist/cjs/router/useScreens.js +1 -1
  63. package/dist/cjs/router/useScreens.js.map +1 -1
  64. package/dist/cjs/router/useScreens.native.js +5 -2
  65. package/dist/cjs/router/useScreens.native.js.map +1 -1
  66. package/dist/cjs/server/oneServe.js.map +1 -1
  67. package/dist/cjs/server/oneServe.native.js.map +1 -1
  68. package/dist/cjs/useBlocker.cjs +158 -0
  69. package/dist/cjs/useBlocker.js +145 -0
  70. package/dist/cjs/useBlocker.js.map +6 -0
  71. package/dist/cjs/useBlocker.native.js +89 -0
  72. package/dist/cjs/useBlocker.native.js.map +1 -0
  73. package/dist/cjs/useLoader.cjs +69 -3
  74. package/dist/cjs/useLoader.js +57 -4
  75. package/dist/cjs/useLoader.js.map +2 -2
  76. package/dist/cjs/useLoader.native.js +90 -6
  77. package/dist/cjs/useLoader.native.js.map +1 -1
  78. package/dist/cjs/useScrollGroup.cjs +37 -0
  79. package/dist/cjs/useScrollGroup.js +30 -0
  80. package/dist/cjs/useScrollGroup.js.map +6 -0
  81. package/dist/cjs/useScrollGroup.native.js +29 -0
  82. package/dist/cjs/useScrollGroup.native.js.map +1 -0
  83. package/dist/cjs/validateParams.cjs +80 -0
  84. package/dist/cjs/validateParams.js +84 -0
  85. package/dist/cjs/validateParams.js.map +6 -0
  86. package/dist/cjs/validateParams.native.js +180 -0
  87. package/dist/cjs/validateParams.native.js.map +1 -0
  88. package/dist/cjs/validateSearch.cjs +104 -0
  89. package/dist/cjs/validateSearch.js +99 -0
  90. package/dist/cjs/validateSearch.js.map +6 -0
  91. package/dist/cjs/validateSearch.native.js +202 -0
  92. package/dist/cjs/validateSearch.native.js.map +1 -0
  93. package/dist/cjs/views/ErrorBoundary.cjs +293 -10
  94. package/dist/cjs/views/ErrorBoundary.js +328 -8
  95. package/dist/cjs/views/ErrorBoundary.js.map +2 -2
  96. package/dist/cjs/views/ErrorBoundary.native.js +159 -4
  97. package/dist/cjs/views/ErrorBoundary.native.js.map +1 -1
  98. package/dist/cjs/views/Navigator.cjs +10 -3
  99. package/dist/cjs/views/Navigator.js +7 -3
  100. package/dist/cjs/views/Navigator.js.map +1 -1
  101. package/dist/cjs/views/Navigator.native.js +12 -3
  102. package/dist/cjs/views/Navigator.native.js.map +1 -1
  103. package/dist/cjs/views/Protected.cjs +36 -0
  104. package/dist/cjs/views/Protected.js +27 -0
  105. package/dist/cjs/views/Protected.js.map +6 -0
  106. package/dist/cjs/views/Protected.native.js +44 -0
  107. package/dist/cjs/views/Protected.native.js.map +1 -0
  108. package/dist/cjs/views/RootErrorBoundary.cjs +193 -8
  109. package/dist/cjs/views/RootErrorBoundary.js +213 -8
  110. package/dist/cjs/views/RootErrorBoundary.js.map +1 -1
  111. package/dist/cjs/views/RootErrorBoundary.native.js +192 -8
  112. package/dist/cjs/views/RootErrorBoundary.native.js.map +1 -1
  113. package/dist/cjs/views/ScrollBehavior.cjs +49 -11
  114. package/dist/cjs/views/ScrollBehavior.js +47 -11
  115. package/dist/cjs/views/ScrollBehavior.js.map +1 -1
  116. package/dist/cjs/views/ScrollBehavior.native.js +68 -10
  117. package/dist/cjs/views/ScrollBehavior.native.js.map +1 -1
  118. package/dist/cjs/views/SourceInspector.cjs +28 -0
  119. package/dist/cjs/views/SourceInspector.js +23 -0
  120. package/dist/cjs/views/SourceInspector.js.map +6 -0
  121. package/dist/cjs/views/SourceInspector.native.js +32 -0
  122. package/dist/cjs/views/SourceInspector.native.js.map +1 -0
  123. package/dist/cjs/views/Try.cjs +40 -7
  124. package/dist/cjs/views/Try.js +38 -4
  125. package/dist/cjs/views/Try.js.map +1 -1
  126. package/dist/cjs/views/Try.native.js +42 -7
  127. package/dist/cjs/views/Try.native.js.map +1 -1
  128. package/dist/cjs/vite/DevHead.cjs +797 -43
  129. package/dist/cjs/vite/DevHead.js +802 -51
  130. package/dist/cjs/vite/DevHead.js.map +1 -1
  131. package/dist/cjs/vite/DevHead.native.js +783 -1
  132. package/dist/cjs/vite/DevHead.native.js.map +1 -1
  133. package/dist/cjs/vite/one.cjs +7 -1
  134. package/dist/cjs/vite/one.js +7 -2
  135. package/dist/cjs/vite/one.js.map +1 -1
  136. package/dist/cjs/vite/one.native.js +11 -1
  137. package/dist/cjs/vite/one.native.js.map +1 -1
  138. package/dist/cjs/vite/plugins/SSRCSSPlugin.cjs +44 -4
  139. package/dist/cjs/vite/plugins/SSRCSSPlugin.js +48 -4
  140. package/dist/cjs/vite/plugins/SSRCSSPlugin.js.map +1 -1
  141. package/dist/cjs/vite/plugins/SSRCSSPlugin.native.js +62 -5
  142. package/dist/cjs/vite/plugins/SSRCSSPlugin.native.js.map +1 -1
  143. package/dist/cjs/vite/plugins/fileSystemRouterPlugin.js +6 -3
  144. package/dist/cjs/vite/plugins/fileSystemRouterPlugin.js.map +1 -1
  145. package/dist/cjs/vite/plugins/fileSystemRouterPlugin.native.js.map +1 -1
  146. package/dist/cjs/vite/plugins/generateFileSystemRouteTypesPlugin.cjs +5 -1
  147. package/dist/cjs/vite/plugins/generateFileSystemRouteTypesPlugin.js +11 -6
  148. package/dist/cjs/vite/plugins/generateFileSystemRouteTypesPlugin.js.map +1 -1
  149. package/dist/cjs/vite/plugins/generateFileSystemRouteTypesPlugin.native.js +1 -0
  150. package/dist/cjs/vite/plugins/generateFileSystemRouteTypesPlugin.native.js.map +1 -1
  151. package/dist/cjs/vite/plugins/sourceInspectorPlugin.cjs +155 -0
  152. package/dist/cjs/vite/plugins/sourceInspectorPlugin.js +148 -0
  153. package/dist/cjs/vite/plugins/sourceInspectorPlugin.js.map +6 -0
  154. package/dist/cjs/vite/plugins/sourceInspectorPlugin.native.js +231 -0
  155. package/dist/cjs/vite/plugins/sourceInspectorPlugin.native.js.map +1 -0
  156. package/dist/cjs/vite/plugins/virtualEntryPlugin.cjs +25 -6
  157. package/dist/cjs/vite/plugins/virtualEntryPlugin.js +16 -6
  158. package/dist/cjs/vite/plugins/virtualEntryPlugin.js.map +1 -1
  159. package/dist/cjs/vite/plugins/virtualEntryPlugin.native.js +26 -7
  160. package/dist/cjs/vite/plugins/virtualEntryPlugin.native.js.map +1 -1
  161. package/dist/esm/cli/buildPage.js +1 -1
  162. package/dist/esm/cli/buildPage.mjs +1 -1
  163. package/dist/esm/cli/buildPage.mjs.map +1 -1
  164. package/dist/esm/cli/buildPage.native.js +1 -1
  165. package/dist/esm/cli/buildPage.native.js.map +1 -1
  166. package/dist/esm/cli/dev.js +4 -4
  167. package/dist/esm/cli/dev.js.map +1 -1
  168. package/dist/esm/cli/dev.mjs +4 -4
  169. package/dist/esm/cli/dev.mjs.map +1 -1
  170. package/dist/esm/cli/dev.native.js +4 -4
  171. package/dist/esm/cli/dev.native.js.map +1 -1
  172. package/dist/esm/createApp.js +2 -2
  173. package/dist/esm/createApp.js.map +1 -1
  174. package/dist/esm/createApp.mjs +2 -1
  175. package/dist/esm/createApp.mjs.map +1 -1
  176. package/dist/esm/createHandleRequest.test.js +3 -1
  177. package/dist/esm/createHandleRequest.test.js.map +1 -1
  178. package/dist/esm/createHandleRequest.test.mjs.map +1 -1
  179. package/dist/esm/createHandleRequest.test.native.js.map +1 -1
  180. package/dist/esm/devtools/registry.js +9 -0
  181. package/dist/esm/devtools/registry.js.map +6 -0
  182. package/dist/esm/devtools/registry.mjs +6 -0
  183. package/dist/esm/devtools/registry.mjs.map +1 -0
  184. package/dist/esm/devtools/registry.native.js +6 -0
  185. package/dist/esm/devtools/registry.native.js.map +1 -0
  186. package/dist/esm/fork/createMemoryHistory.js +22 -4
  187. package/dist/esm/fork/createMemoryHistory.js.map +1 -1
  188. package/dist/esm/fork/createMemoryHistory.mjs +20 -9
  189. package/dist/esm/fork/createMemoryHistory.mjs.map +1 -1
  190. package/dist/esm/fork/createMemoryHistory.native.js +20 -9
  191. package/dist/esm/fork/createMemoryHistory.native.js.map +1 -1
  192. package/dist/esm/fork/useLinking.js +6 -5
  193. package/dist/esm/fork/useLinking.js.map +1 -1
  194. package/dist/esm/fork/useLinking.mjs +11 -5
  195. package/dist/esm/fork/useLinking.mjs.map +1 -1
  196. package/dist/esm/index.js +30 -2
  197. package/dist/esm/index.js.map +1 -1
  198. package/dist/esm/index.mjs +8 -2
  199. package/dist/esm/index.mjs.map +1 -1
  200. package/dist/esm/index.native.js +8 -2
  201. package/dist/esm/index.native.js.map +1 -1
  202. package/dist/esm/layouts/withLayoutContext.js +30 -12
  203. package/dist/esm/layouts/withLayoutContext.js.map +1 -1
  204. package/dist/esm/layouts/withLayoutContext.mjs +34 -15
  205. package/dist/esm/layouts/withLayoutContext.mjs.map +1 -1
  206. package/dist/esm/layouts/withLayoutContext.native.js +42 -19
  207. package/dist/esm/layouts/withLayoutContext.native.js.map +1 -1
  208. package/dist/esm/link/Link.js +3 -2
  209. package/dist/esm/link/Link.js.map +1 -1
  210. package/dist/esm/link/Link.mjs +5 -2
  211. package/dist/esm/link/Link.mjs.map +1 -1
  212. package/dist/esm/link/Link.native.js +6 -1
  213. package/dist/esm/link/Link.native.js.map +1 -1
  214. package/dist/esm/link/useLinkTo.js +6 -3
  215. package/dist/esm/link/useLinkTo.js.map +1 -1
  216. package/dist/esm/link/useLinkTo.mjs +11 -3
  217. package/dist/esm/link/useLinkTo.mjs.map +1 -1
  218. package/dist/esm/link/useLinkTo.native.js +11 -3
  219. package/dist/esm/link/useLinkTo.native.js.map +1 -1
  220. package/dist/esm/router/Route.js.map +1 -1
  221. package/dist/esm/router/Route.mjs.map +1 -1
  222. package/dist/esm/router/Route.native.js.map +1 -1
  223. package/dist/esm/router/findRouteNode.js +56 -0
  224. package/dist/esm/router/findRouteNode.js.map +6 -0
  225. package/dist/esm/router/findRouteNode.mjs +44 -0
  226. package/dist/esm/router/findRouteNode.mjs.map +1 -0
  227. package/dist/esm/router/findRouteNode.native.js +75 -0
  228. package/dist/esm/router/findRouteNode.native.js.map +1 -0
  229. package/dist/esm/router/router.js +154 -6
  230. package/dist/esm/router/router.js.map +1 -1
  231. package/dist/esm/router/router.mjs +151 -10
  232. package/dist/esm/router/router.mjs.map +1 -1
  233. package/dist/esm/router/router.native.js +232 -56
  234. package/dist/esm/router/router.native.js.map +1 -1
  235. package/dist/esm/router/useScreens.js +1 -1
  236. package/dist/esm/router/useScreens.js.map +1 -1
  237. package/dist/esm/router/useScreens.mjs +1 -1
  238. package/dist/esm/router/useScreens.mjs.map +1 -1
  239. package/dist/esm/router/useScreens.native.js +5 -2
  240. package/dist/esm/router/useScreens.native.js.map +1 -1
  241. package/dist/esm/server/oneServe.js.map +1 -1
  242. package/dist/esm/server/oneServe.mjs.map +1 -1
  243. package/dist/esm/server/oneServe.native.js.map +1 -1
  244. package/dist/esm/useBlocker.js +122 -0
  245. package/dist/esm/useBlocker.js.map +6 -0
  246. package/dist/esm/useBlocker.mjs +123 -0
  247. package/dist/esm/useBlocker.mjs.map +1 -0
  248. package/dist/esm/useBlocker.native.js +51 -0
  249. package/dist/esm/useBlocker.native.js.map +1 -0
  250. package/dist/esm/useLoader.js +57 -3
  251. package/dist/esm/useLoader.js.map +2 -2
  252. package/dist/esm/useLoader.mjs +69 -4
  253. package/dist/esm/useLoader.mjs.map +1 -1
  254. package/dist/esm/useLoader.native.js +90 -7
  255. package/dist/esm/useLoader.native.js.map +1 -1
  256. package/dist/esm/useScrollGroup.js +16 -0
  257. package/dist/esm/useScrollGroup.js.map +6 -0
  258. package/dist/esm/useScrollGroup.mjs +14 -0
  259. package/dist/esm/useScrollGroup.mjs.map +1 -0
  260. package/dist/esm/useScrollGroup.native.js +3 -0
  261. package/dist/esm/useScrollGroup.native.js.map +1 -0
  262. package/dist/esm/validateParams.js +68 -0
  263. package/dist/esm/validateParams.js.map +6 -0
  264. package/dist/esm/validateParams.mjs +54 -0
  265. package/dist/esm/validateParams.mjs.map +1 -0
  266. package/dist/esm/validateParams.native.js +151 -0
  267. package/dist/esm/validateParams.native.js.map +1 -0
  268. package/dist/esm/validateSearch.js +83 -0
  269. package/dist/esm/validateSearch.js.map +6 -0
  270. package/dist/esm/validateSearch.mjs +77 -0
  271. package/dist/esm/validateSearch.mjs.map +1 -0
  272. package/dist/esm/validateSearch.native.js +172 -0
  273. package/dist/esm/validateSearch.native.js.map +1 -0
  274. package/dist/esm/views/ErrorBoundary.js +325 -7
  275. package/dist/esm/views/ErrorBoundary.js.map +2 -2
  276. package/dist/esm/views/ErrorBoundary.mjs +289 -6
  277. package/dist/esm/views/ErrorBoundary.mjs.map +1 -1
  278. package/dist/esm/views/ErrorBoundary.native.js +159 -4
  279. package/dist/esm/views/ErrorBoundary.native.js.map +1 -1
  280. package/dist/esm/views/Navigator.js +7 -2
  281. package/dist/esm/views/Navigator.js.map +1 -1
  282. package/dist/esm/views/Navigator.mjs +10 -3
  283. package/dist/esm/views/Navigator.mjs.map +1 -1
  284. package/dist/esm/views/Navigator.native.js +12 -3
  285. package/dist/esm/views/Navigator.native.js.map +1 -1
  286. package/dist/esm/views/Protected.js +14 -0
  287. package/dist/esm/views/Protected.js.map +6 -0
  288. package/dist/esm/views/Protected.mjs +11 -0
  289. package/dist/esm/views/Protected.mjs.map +1 -0
  290. package/dist/esm/views/Protected.native.js +16 -0
  291. package/dist/esm/views/Protected.native.js.map +1 -0
  292. package/dist/esm/views/RootErrorBoundary.js +214 -7
  293. package/dist/esm/views/RootErrorBoundary.js.map +1 -1
  294. package/dist/esm/views/RootErrorBoundary.mjs +192 -7
  295. package/dist/esm/views/RootErrorBoundary.mjs.map +1 -1
  296. package/dist/esm/views/RootErrorBoundary.native.js +191 -7
  297. package/dist/esm/views/RootErrorBoundary.native.js.map +1 -1
  298. package/dist/esm/views/ScrollBehavior.js +47 -11
  299. package/dist/esm/views/ScrollBehavior.js.map +1 -1
  300. package/dist/esm/views/ScrollBehavior.mjs +48 -11
  301. package/dist/esm/views/ScrollBehavior.mjs.map +1 -1
  302. package/dist/esm/views/ScrollBehavior.native.js +67 -10
  303. package/dist/esm/views/ScrollBehavior.native.js.map +1 -1
  304. package/dist/esm/views/SourceInspector.js +7 -0
  305. package/dist/esm/views/SourceInspector.js.map +6 -0
  306. package/dist/esm/views/SourceInspector.mjs +5 -0
  307. package/dist/esm/views/SourceInspector.mjs.map +1 -0
  308. package/dist/esm/views/SourceInspector.native.js +6 -0
  309. package/dist/esm/views/SourceInspector.native.js.map +1 -0
  310. package/dist/esm/views/Try.js +38 -4
  311. package/dist/esm/views/Try.js.map +1 -1
  312. package/dist/esm/views/Try.mjs +40 -7
  313. package/dist/esm/views/Try.mjs.map +1 -1
  314. package/dist/esm/views/Try.native.js +42 -7
  315. package/dist/esm/views/Try.native.js.map +1 -1
  316. package/dist/esm/vite/DevHead.js +802 -51
  317. package/dist/esm/vite/DevHead.js.map +1 -1
  318. package/dist/esm/vite/DevHead.mjs +797 -43
  319. package/dist/esm/vite/DevHead.mjs.map +1 -1
  320. package/dist/esm/vite/DevHead.native.js +782 -0
  321. package/dist/esm/vite/DevHead.native.js.map +1 -1
  322. package/dist/esm/vite/one.js +7 -1
  323. package/dist/esm/vite/one.js.map +1 -1
  324. package/dist/esm/vite/one.mjs +7 -1
  325. package/dist/esm/vite/one.mjs.map +1 -1
  326. package/dist/esm/vite/one.native.js +11 -1
  327. package/dist/esm/vite/one.native.js.map +1 -1
  328. package/dist/esm/vite/plugins/SSRCSSPlugin.js +48 -4
  329. package/dist/esm/vite/plugins/SSRCSSPlugin.js.map +1 -1
  330. package/dist/esm/vite/plugins/SSRCSSPlugin.mjs +44 -4
  331. package/dist/esm/vite/plugins/SSRCSSPlugin.mjs.map +1 -1
  332. package/dist/esm/vite/plugins/SSRCSSPlugin.native.js +61 -4
  333. package/dist/esm/vite/plugins/SSRCSSPlugin.native.js.map +1 -1
  334. package/dist/esm/vite/plugins/fileSystemRouterPlugin.js +6 -3
  335. package/dist/esm/vite/plugins/fileSystemRouterPlugin.js.map +1 -1
  336. package/dist/esm/vite/plugins/fileSystemRouterPlugin.mjs.map +1 -1
  337. package/dist/esm/vite/plugins/fileSystemRouterPlugin.native.js.map +1 -1
  338. package/dist/esm/vite/plugins/generateFileSystemRouteTypesPlugin.js +11 -6
  339. package/dist/esm/vite/plugins/generateFileSystemRouteTypesPlugin.js.map +1 -1
  340. package/dist/esm/vite/plugins/generateFileSystemRouteTypesPlugin.mjs +5 -1
  341. package/dist/esm/vite/plugins/generateFileSystemRouteTypesPlugin.mjs.map +1 -1
  342. package/dist/esm/vite/plugins/generateFileSystemRouteTypesPlugin.native.js +1 -0
  343. package/dist/esm/vite/plugins/generateFileSystemRouteTypesPlugin.native.js.map +1 -1
  344. package/dist/esm/vite/plugins/sourceInspectorPlugin.js +126 -0
  345. package/dist/esm/vite/plugins/sourceInspectorPlugin.js.map +6 -0
  346. package/dist/esm/vite/plugins/sourceInspectorPlugin.mjs +121 -0
  347. package/dist/esm/vite/plugins/sourceInspectorPlugin.mjs.map +1 -0
  348. package/dist/esm/vite/plugins/sourceInspectorPlugin.native.js +194 -0
  349. package/dist/esm/vite/plugins/sourceInspectorPlugin.native.js.map +1 -0
  350. package/dist/esm/vite/plugins/virtualEntryPlugin.js +16 -6
  351. package/dist/esm/vite/plugins/virtualEntryPlugin.js.map +1 -1
  352. package/dist/esm/vite/plugins/virtualEntryPlugin.mjs +25 -6
  353. package/dist/esm/vite/plugins/virtualEntryPlugin.mjs.map +1 -1
  354. package/dist/esm/vite/plugins/virtualEntryPlugin.native.js +26 -7
  355. package/dist/esm/vite/plugins/virtualEntryPlugin.native.js.map +1 -1
  356. package/package.json +11 -9
  357. package/src/cli/buildPage.ts +1 -1
  358. package/src/cli/dev.ts +4 -4
  359. package/src/createApp.tsx +11 -1
  360. package/src/createHandleRequest.test.ts +3 -1
  361. package/src/devtools/registry.ts +21 -0
  362. package/src/fork/createMemoryHistory.tsx +43 -11
  363. package/src/fork/useLinking.ts +14 -4
  364. package/src/index.ts +34 -1
  365. package/src/interfaces/router.ts +48 -0
  366. package/src/layouts/withLayoutContext.tsx +48 -8
  367. package/src/link/Link.tsx +7 -2
  368. package/src/link/useLinkTo.tsx +7 -3
  369. package/src/router/Route.tsx +32 -3
  370. package/src/router/findRouteNode.ts +127 -0
  371. package/src/router/router.ts +286 -2
  372. package/src/router/useScreens.tsx +9 -3
  373. package/src/useBlocker.native.ts +153 -0
  374. package/src/useBlocker.ts +340 -0
  375. package/src/useLoader.ts +139 -1
  376. package/src/useScrollGroup.native.ts +7 -0
  377. package/src/useScrollGroup.ts +44 -0
  378. package/src/validateParams.ts +196 -0
  379. package/src/validateSearch.ts +241 -0
  380. package/src/views/ErrorBoundary.tsx +154 -156
  381. package/src/views/ErrorBoundary.web.tsx +321 -0
  382. package/src/views/Navigator.tsx +14 -2
  383. package/src/views/Protected.tsx +62 -0
  384. package/src/views/RootErrorBoundary.tsx +214 -17
  385. package/src/views/ScrollBehavior.tsx +82 -3
  386. package/src/views/SourceInspector.tsx +39 -0
  387. package/src/views/Try.tsx +81 -12
  388. package/src/vite/DevHead.tsx +819 -54
  389. package/src/vite/one.ts +13 -0
  390. package/src/vite/plugins/SSRCSSPlugin.ts +104 -0
  391. package/src/vite/plugins/fileSystemRouterPlugin.tsx +11 -8
  392. package/src/vite/plugins/generateFileSystemRouteTypesPlugin.tsx +4 -0
  393. package/src/vite/plugins/sourceInspectorPlugin.ts +246 -0
  394. package/src/vite/plugins/virtualEntryPlugin.ts +35 -10
  395. package/src/vite/types.ts +28 -0
  396. package/types/Route.d.ts.map +1 -0
  397. package/types/cleanUrl.d.ts.map +1 -0
  398. package/types/cli/run.d.ts.map +1 -0
  399. package/types/createApp.d.ts +5 -0
  400. package/types/createApp.d.ts.map +1 -1
  401. package/types/createRoute.d.ts.map +1 -0
  402. package/types/devtools/registry.d.ts +15 -0
  403. package/types/devtools/registry.d.ts.map +1 -0
  404. package/types/fork/NavigationContainer.native.d.ts.map +1 -0
  405. package/types/fork/createMemoryHistory.d.ts +8 -3
  406. package/types/fork/createMemoryHistory.d.ts.map +1 -1
  407. package/types/fork/useLinking.d.ts.map +1 -1
  408. package/types/getLinkingConfig.d.ts.map +1 -0
  409. package/types/getRoutes.d.ts.map +1 -0
  410. package/types/imperative-api.d.ts.map +1 -0
  411. package/types/index.d.ts +8 -1
  412. package/types/index.d.ts.map +1 -1
  413. package/types/interfaces/router.d.ts +47 -0
  414. package/types/interfaces/router.d.ts.map +1 -1
  415. package/types/layouts/withLayoutContext.d.ts +2 -1
  416. package/types/layouts/withLayoutContext.d.ts.map +1 -1
  417. package/types/link/Link.d.ts.map +1 -1
  418. package/types/link/useLinkTo.d.ts +1 -0
  419. package/types/link/useLinkTo.d.ts.map +1 -1
  420. package/types/matchers.d.ts.map +1 -0
  421. package/types/platform.d.ts.map +1 -0
  422. package/types/router/Route.d.ts +32 -3
  423. package/types/router/Route.d.ts.map +1 -1
  424. package/types/router/findRouteNode.d.ts +31 -0
  425. package/types/router/findRouteNode.d.ts.map +1 -0
  426. package/types/router/router.d.ts +35 -0
  427. package/types/router/router.d.ts.map +1 -1
  428. package/types/router/useScreens.d.ts +2 -0
  429. package/types/router/useScreens.d.ts.map +1 -1
  430. package/types/server/oneServe.d.ts.map +1 -1
  431. package/types/sortRoutes.d.ts.map +1 -0
  432. package/types/useBlocker.d.ts +72 -0
  433. package/types/useBlocker.d.ts.map +1 -0
  434. package/types/useBlocker.native.d.ts +60 -0
  435. package/types/useBlocker.native.d.ts.map +1 -0
  436. package/types/useLoader.d.ts +10 -0
  437. package/types/useLoader.d.ts.map +1 -1
  438. package/types/useNavigation.d.ts.map +1 -0
  439. package/types/useScreens.d.ts.map +1 -0
  440. package/types/useScrollGroup.d.ts +27 -0
  441. package/types/useScrollGroup.d.ts.map +1 -0
  442. package/types/useScrollGroup.native.d.ts +6 -0
  443. package/types/useScrollGroup.native.d.ts.map +1 -0
  444. package/types/useSearch.d.ts.map +1 -0
  445. package/types/useViteRoutes.d.ts.map +1 -0
  446. package/types/validateParams.d.ts +85 -0
  447. package/types/validateParams.d.ts.map +1 -0
  448. package/types/validateSearch.d.ts +107 -0
  449. package/types/validateSearch.d.ts.map +1 -0
  450. package/types/views/ErrorBoundary.d.ts +11 -1
  451. package/types/views/ErrorBoundary.d.ts.map +1 -1
  452. package/types/views/ErrorBoundary.web.d.ts +13 -0
  453. package/types/views/ErrorBoundary.web.d.ts.map +1 -0
  454. package/types/views/Navigator.d.ts.map +1 -1
  455. package/types/views/Protected.d.ts +39 -0
  456. package/types/views/Protected.d.ts.map +1 -0
  457. package/types/views/RootErrorBoundary.d.ts +14 -8
  458. package/types/views/RootErrorBoundary.d.ts.map +1 -1
  459. package/types/views/ScrollBehavior.d.ts +8 -0
  460. package/types/views/ScrollBehavior.d.ts.map +1 -1
  461. package/types/views/ScrollRestoration.d.ts.map +1 -0
  462. package/types/views/SourceInspector.d.ts +35 -0
  463. package/types/views/SourceInspector.d.ts.map +1 -0
  464. package/types/views/Try.d.ts +29 -6
  465. package/types/views/Try.d.ts.map +1 -1
  466. package/types/vite/DevHead.d.ts.map +1 -1
  467. package/types/vite/build.d.ts.map +1 -0
  468. package/types/vite/headers.d.ts.map +1 -0
  469. package/types/vite/headers.native.d.ts.map +1 -0
  470. package/types/vite/one.d.ts.map +1 -1
  471. package/types/vite/plugins/SSRCSSPlugin.d.ts.map +1 -1
  472. package/types/vite/plugins/fileSystemRouterPlugin.d.ts.map +1 -1
  473. package/types/vite/plugins/generateFileSystemRouteTypesPlugin.d.ts.map +1 -1
  474. package/types/vite/plugins/seoPreviewPlugin.d.ts.map +1 -0
  475. package/types/vite/plugins/sourceInspectorPlugin.d.ts +3 -0
  476. package/types/vite/plugins/sourceInspectorPlugin.d.ts.map +1 -0
  477. package/types/vite/plugins/virtualEntryPlugin.d.ts.map +1 -1
  478. package/types/vite/resolveAPIRequest.d.ts.map +1 -0
  479. package/types/vite/server.d.ts.map +1 -0
  480. package/types/vite/types.d.ts +24 -0
  481. package/types/vite/types.d.ts.map +1 -1
@@ -35,11 +35,75 @@ import { sortRoutes } from './sortRoutes'
35
35
  import { getQualifiedRouteComponent } from './useScreens'
36
36
  import { preloadRouteModules } from './useViteRoutes'
37
37
  import { getNavigateAction } from './utils/getNavigateAction'
38
+ import {
39
+ findRouteNodeFromState,
40
+ extractParamsFromState,
41
+ extractSearchFromHref,
42
+ extractPathnameFromHref,
43
+ } from './findRouteNode'
44
+ import {
45
+ validateParams as runValidateParams,
46
+ RouteValidationError,
47
+ ParamValidationError,
48
+ } from '../validateParams'
49
+ import { checkBlocker } from '../useBlocker'
50
+ import { devtoolsRegistry } from '../devtools/registry'
38
51
 
39
52
  // Module-scoped variables
40
53
  export let routeNode: RouteNode | null = null
41
54
  export let rootComponent: ComponentType
42
55
 
56
+ // Global registry for protected routes
57
+ // Key: contextKey (e.g., '/protected-test'), Value: Set of protected route names
58
+ const protectedRouteRegistry = new Map<string, Set<string>>()
59
+
60
+ /**
61
+ * Register protected routes for a navigator context.
62
+ * Called by navigators when their protectedScreens changes.
63
+ */
64
+ export function registerProtectedRoutes(contextKey: string, protectedScreens: Set<string>) {
65
+ if (protectedScreens.size === 0) {
66
+ protectedRouteRegistry.delete(contextKey)
67
+ } else {
68
+ protectedRouteRegistry.set(contextKey, protectedScreens)
69
+ }
70
+ }
71
+
72
+ /**
73
+ * Unregister protected routes for a navigator context.
74
+ * Called when a navigator unmounts.
75
+ */
76
+ export function unregisterProtectedRoutes(contextKey: string) {
77
+ protectedRouteRegistry.delete(contextKey)
78
+ }
79
+
80
+ /**
81
+ * Check if a route path is protected and should be blocked.
82
+ * Returns true if the route is protected.
83
+ */
84
+ export function isRouteProtected(href: string): boolean {
85
+ // Normalize the href (remove leading/trailing slashes)
86
+ const normalizedHref = href.replace(/^\/+|\/+$/g, '')
87
+
88
+ // Check each navigator context to see if this route is protected
89
+ for (const [contextKey, protectedScreens] of protectedRouteRegistry) {
90
+ const normalizedContextKey = contextKey.replace(/^\/+|\/+$/g, '')
91
+
92
+ // Check if this href is under this context
93
+ if (normalizedHref.startsWith(normalizedContextKey)) {
94
+ // Get the route name relative to this context
95
+ const relativePath = normalizedHref.slice(normalizedContextKey.length).replace(/^\//, '')
96
+ const routeName = relativePath.split('/')[0] || 'index'
97
+
98
+ if (protectedScreens.has(routeName)) {
99
+ return true
100
+ }
101
+ }
102
+ }
103
+
104
+ return false
105
+ }
106
+
43
107
  export let hasAttemptedToHideSplash = false
44
108
  export let initialState: OneRouter.ResultState | undefined
45
109
  export let rootState: OneRouter.ResultState | undefined
@@ -56,6 +120,60 @@ const rootStateSubscribers = new Set<OneRouter.RootStateListener>()
56
120
  const loadingStateSubscribers = new Set<OneRouter.LoadingStateListener>()
57
121
  const storeSubscribers = new Set<() => void>()
58
122
 
123
+ // Validation state tracking
124
+ export type ValidationState = {
125
+ status: 'idle' | 'validating' | 'error' | 'valid'
126
+ error?: Error
127
+ lastValidatedHref?: string
128
+ }
129
+
130
+ let validationState: ValidationState = { status: 'idle' }
131
+ const validationStateSubscribers = new Set<(state: ValidationState) => void>()
132
+
133
+ export function subscribeToValidationState(subscriber: (state: ValidationState) => void) {
134
+ validationStateSubscribers.add(subscriber)
135
+ return () => validationStateSubscribers.delete(subscriber)
136
+ }
137
+
138
+ export function setValidationState(state: ValidationState) {
139
+ validationState = state
140
+ for (const subscriber of validationStateSubscribers) {
141
+ subscriber(state)
142
+ }
143
+ // Dispatch event for devtools
144
+ if (
145
+ process.env.TAMAGUI_TARGET !== 'native' &&
146
+ state.status === 'error' &&
147
+ state.error
148
+ ) {
149
+ window.dispatchEvent(
150
+ new CustomEvent('one-validation-error', {
151
+ detail: {
152
+ error: {
153
+ message: state.error.message,
154
+ name: state.error.name,
155
+ stack: state.error.stack,
156
+ },
157
+ href: state.lastValidatedHref,
158
+ timestamp: Date.now(),
159
+ },
160
+ })
161
+ )
162
+ }
163
+ }
164
+
165
+ export function getValidationState(): ValidationState {
166
+ return validationState
167
+ }
168
+
169
+ export function useValidationState() {
170
+ return useSyncExternalStore(
171
+ subscribeToValidationState,
172
+ getValidationState,
173
+ getValidationState
174
+ )
175
+ }
176
+
59
177
  // Initialize function
60
178
  export function initialize(
61
179
  context: One.RouteContext,
@@ -272,6 +390,23 @@ export function updateState(state: OneRouter.ResultState, nextStateParam = state
272
390
  }
273
391
  routeInfo = nextRouteInfo
274
392
  }
393
+
394
+ // Expose devtools API in development
395
+ if (process.env.NODE_ENV === 'development' && typeof window !== 'undefined') {
396
+ // Use registry to avoid circular deps - useLoader registers its function there
397
+ ;(window as any).__oneDevtools = {
398
+ routeInfo: nextRouteInfo,
399
+ rootState: state,
400
+ routeNode,
401
+ getRoutes: () => routeNode?.children || [],
402
+ getLoaderTimingHistory: () => devtoolsRegistry.getLoaderTimingHistory?.() ?? [],
403
+ getPreloadHistory,
404
+ }
405
+ // Dispatch event for devtools panels to listen
406
+ if (process.env.TAMAGUI_TARGET !== 'native') {
407
+ window.dispatchEvent(new CustomEvent('one-route-change', { detail: nextRouteInfo }))
408
+ }
409
+ }
275
410
  }
276
411
 
277
412
  // Subscription functions
@@ -397,6 +532,9 @@ async function doPreload(href: string) {
397
532
  const preloadPath = getPreloadPath(href)
398
533
  const loaderPath = getLoaderPath(href)
399
534
  const cssPreloadPath = getPreloadCSSPath(href)
535
+
536
+ recordPreloadStart(href)
537
+
400
538
  try {
401
539
  const [_preload, cssPreloadModule, loader] = await Promise.all([
402
540
  dynamicImport(preloadPath),
@@ -406,18 +544,24 @@ async function doPreload(href: string) {
406
544
  ])
407
545
 
408
546
  // Store the CSS inject function for later use on navigation
409
- if (cssPreloadModule?.injectCSS) {
547
+ const hasCss = !!cssPreloadModule?.injectCSS
548
+ if (hasCss) {
410
549
  cssInjectFunctions[href] = cssPreloadModule.injectCSS
411
550
  }
412
551
 
413
- if (!loader?.loader) {
552
+ const hasLoader = !!loader?.loader
553
+ if (!hasLoader) {
554
+ recordPreloadComplete(href, false, hasCss)
414
555
  return null
415
556
  }
416
557
 
417
558
  const result = await loader.loader()
559
+ recordPreloadComplete(href, true, hasCss)
418
560
  return result ?? null
419
561
  } catch (err) {
562
+ const errorMessage = err instanceof Error ? err.message : String(err)
420
563
  console.error(`[one] preload error for ${href}:`, err)
564
+ recordPreloadError(href, errorMessage)
421
565
  return null
422
566
  }
423
567
  }
@@ -428,6 +572,79 @@ export const preloadedLoaderData: Record<string, any> = {}
428
572
  // Store CSS inject functions for calling on navigation
429
573
  const cssInjectFunctions: Record<string, (() => Promise<void[]>) | undefined> = {}
430
574
 
575
+ // Preload status tracking for devtools
576
+ export type PreloadStatus = 'pending' | 'loading' | 'loaded' | 'error'
577
+ export type PreloadEntry = {
578
+ href: string
579
+ status: PreloadStatus
580
+ startTime: number
581
+ endTime?: number
582
+ error?: string
583
+ hasLoader: boolean
584
+ hasCss: boolean
585
+ }
586
+
587
+ const preloadHistory: PreloadEntry[] = []
588
+ const MAX_PRELOAD_HISTORY = 30
589
+
590
+ // Preload tracking functions - only do work in development for devtools
591
+ function recordPreloadStart(href: string) {
592
+ if (process.env.NODE_ENV !== 'development') return
593
+
594
+ const existing = preloadHistory.find((p) => p.href === href)
595
+ if (existing) {
596
+ existing.status = 'loading'
597
+ existing.startTime = performance.now()
598
+ return
599
+ }
600
+ preloadHistory.unshift({
601
+ href,
602
+ status: 'loading',
603
+ startTime: performance.now(),
604
+ hasLoader: false,
605
+ hasCss: false,
606
+ })
607
+ if (preloadHistory.length > MAX_PRELOAD_HISTORY) {
608
+ preloadHistory.pop()
609
+ }
610
+ dispatchPreloadEvent()
611
+ }
612
+
613
+ function recordPreloadComplete(href: string, hasLoader: boolean, hasCss: boolean) {
614
+ if (process.env.NODE_ENV !== 'development') return
615
+
616
+ const entry = preloadHistory.find((p) => p.href === href)
617
+ if (entry) {
618
+ entry.status = 'loaded'
619
+ entry.endTime = performance.now()
620
+ entry.hasLoader = hasLoader
621
+ entry.hasCss = hasCss
622
+ }
623
+ dispatchPreloadEvent()
624
+ }
625
+
626
+ function recordPreloadError(href: string, error: string) {
627
+ if (process.env.NODE_ENV !== 'development') return
628
+
629
+ const entry = preloadHistory.find((p) => p.href === href)
630
+ if (entry) {
631
+ entry.status = 'error'
632
+ entry.endTime = performance.now()
633
+ entry.error = error
634
+ }
635
+ dispatchPreloadEvent()
636
+ }
637
+
638
+ function dispatchPreloadEvent() {
639
+ if (process.env.TAMAGUI_TARGET !== 'native') {
640
+ window.dispatchEvent(new CustomEvent('one-preload-update'))
641
+ }
642
+ }
643
+
644
+ export function getPreloadHistory(): PreloadEntry[] {
645
+ return preloadHistory
646
+ }
647
+
431
648
  export function preloadRoute(href: string, injectCSS = false): Promise<any> | undefined {
432
649
  if (process.env.TAMAGUI_TARGET === 'native') {
433
650
  return
@@ -477,6 +694,16 @@ export async function linkTo(
477
694
  return
478
695
  }
479
696
 
697
+ // Check if any blocker wants to block this navigation (web only)
698
+ if (checkBlocker(href, event === 'REPLACE' ? 'replace' : 'push')) {
699
+ return
700
+ }
701
+
702
+ // Check if the route is protected and should be blocked
703
+ if (isRouteProtected(href)) {
704
+ return
705
+ }
706
+
480
707
  assertIsReady(navigationRef)
481
708
  const current = navigationRef.current
482
709
 
@@ -540,8 +767,65 @@ export async function linkTo(
540
767
 
541
768
  setLoadingState('loading')
542
769
 
770
+ // Preload route modules first so loadRoute() won't throw Suspense promises
543
771
  await preloadRoute(href, true)
544
772
 
773
+ // Run async route validation before navigation
774
+ const matchingRouteNode = findRouteNodeFromState(state, routeNode)
775
+ if (matchingRouteNode?.loadRoute) {
776
+ setValidationState({ status: 'validating', lastValidatedHref: href })
777
+
778
+ try {
779
+ const loadedRoute = matchingRouteNode.loadRoute()
780
+ const params = extractParamsFromState(state)
781
+ const search = extractSearchFromHref(href)
782
+ const pathname = extractPathnameFromHref(href)
783
+
784
+ // Run validateParams if exported
785
+ if (loadedRoute.validateParams) {
786
+ runValidateParams(loadedRoute.validateParams, params)
787
+ }
788
+
789
+ // Run validateRoute if exported
790
+ if (loadedRoute.validateRoute) {
791
+ const validationResult = await loadedRoute.validateRoute({
792
+ params,
793
+ search,
794
+ pathname,
795
+ href,
796
+ })
797
+
798
+ // Check for explicit invalid result
799
+ if (validationResult && !validationResult.valid) {
800
+ const error = new RouteValidationError(
801
+ validationResult.error || 'Route validation failed',
802
+ validationResult.details
803
+ )
804
+ setValidationState({ status: 'error', error, lastValidatedHref: href })
805
+ throw error
806
+ }
807
+ }
808
+
809
+ setValidationState({ status: 'valid', lastValidatedHref: href })
810
+ } catch (error) {
811
+ // Handle Suspense promises thrown by loadRoute in dev mode
812
+ if (error && typeof (error as any).then === 'function') {
813
+ // Wait for the route to load and skip validation for this navigation
814
+ await (error as Promise<any>).catch(() => {})
815
+ setValidationState({ status: 'valid', lastValidatedHref: href })
816
+ } else if (
817
+ error instanceof ParamValidationError ||
818
+ error instanceof RouteValidationError
819
+ ) {
820
+ setValidationState({ status: 'error', error, lastValidatedHref: href })
821
+ throw error
822
+ } else {
823
+ // Re-throw other errors
824
+ throw error
825
+ }
826
+ }
827
+ }
828
+
545
829
  const rootState = navigationRef.getRootState()
546
830
 
547
831
  const hash = href.indexOf('#')
@@ -224,7 +224,11 @@ function getSortedChildren(
224
224
  */
225
225
  export function useSortedScreens(
226
226
  order: ScreenProps[],
227
- options?: { onlyMatching?: boolean }
227
+ options?: {
228
+ onlyMatching?: boolean
229
+ /** Set of route names to filter out (protected routes with guard=false) */
230
+ protectedScreens?: Set<string>
231
+ }
228
232
  ): React.ReactNode[] {
229
233
  const node = useRouteNode()
230
234
 
@@ -233,8 +237,10 @@ export function useSortedScreens(
233
237
  ? getSortedChildren(node.children, order, node.initialRouteName, options)
234
238
  : []
235
239
 
236
- return sorted.map((value) => routeToScreen(value.route, value.props))
237
- }, [node?.children, node?.initialRouteName, order])
240
+ return sorted
241
+ .filter((value) => !options?.protectedScreens?.has(value.route.route))
242
+ .map((value) => routeToScreen(value.route, value.props))
243
+ }, [node?.children, node?.initialRouteName, order, options?.protectedScreens])
238
244
 
239
245
  return sortedScreens
240
246
  }
@@ -0,0 +1,153 @@
1
+ import { useNavigation } from '@react-navigation/native'
2
+ import * as React from 'react'
3
+
4
+ export type BlockerState = 'unblocked' | 'blocked' | 'proceeding'
5
+
6
+ export type BlockerFunction = (args: {
7
+ currentLocation: string
8
+ nextLocation: string
9
+ historyAction: 'push' | 'pop' | 'replace'
10
+ }) => boolean
11
+
12
+ export type Blocker =
13
+ | {
14
+ state: 'unblocked'
15
+ reset?: undefined
16
+ proceed?: undefined
17
+ location?: undefined
18
+ }
19
+ | {
20
+ state: 'blocked'
21
+ reset: () => void
22
+ proceed: () => void
23
+ location: string
24
+ }
25
+ | {
26
+ state: 'proceeding'
27
+ reset?: undefined
28
+ proceed?: undefined
29
+ location: string
30
+ }
31
+
32
+ /**
33
+ * Block navigation when a condition is met.
34
+ *
35
+ * On native, this uses React Navigation's `beforeRemove` event to prevent navigation.
36
+ * Note that this only works for navigation within the app - it cannot prevent
37
+ * the app from being closed or backgrounded.
38
+ *
39
+ * @param shouldBlock - Either a boolean or a function that returns whether to block.
40
+ *
41
+ * @example
42
+ * ```tsx
43
+ * function EditForm() {
44
+ * const [isDirty, setIsDirty] = useState(false)
45
+ * const blocker = useBlocker(isDirty)
46
+ *
47
+ * return (
48
+ * <>
49
+ * <TextInput onChange={() => setIsDirty(true)} />
50
+ *
51
+ * {blocker.state === 'blocked' && (
52
+ * <Modal>
53
+ * <Text>You have unsaved changes. Leave anyway?</Text>
54
+ * <Button title="Stay" onPress={blocker.reset} />
55
+ * <Button title="Leave" onPress={blocker.proceed} />
56
+ * </Modal>
57
+ * )}
58
+ * </>
59
+ * )
60
+ * }
61
+ * ```
62
+ */
63
+ export function useBlocker(shouldBlock: BlockerFunction | boolean): Blocker {
64
+ const navigation = useNavigation()
65
+ const [state, setState] = React.useState<BlockerState>('unblocked')
66
+ const [pendingEvent, setPendingEvent] = React.useState<any>(null)
67
+ const [blockedLocation, setBlockedLocation] = React.useState<string | null>(null)
68
+
69
+ const shouldBlockRef = React.useRef(shouldBlock)
70
+ shouldBlockRef.current = shouldBlock
71
+
72
+ React.useEffect(() => {
73
+ const unsubscribe = navigation.addListener('beforeRemove', (e) => {
74
+ const currentShouldBlock = shouldBlockRef.current
75
+
76
+ // Get the next location from the action payload
77
+ const payload = e.data?.action?.payload as { name?: string } | undefined
78
+ const nextLocation = payload?.name || 'previous screen'
79
+
80
+ // Determine if we should block
81
+ const block =
82
+ typeof currentShouldBlock === 'function'
83
+ ? currentShouldBlock({
84
+ currentLocation: '', // Not easily available on native
85
+ nextLocation,
86
+ historyAction: 'pop',
87
+ })
88
+ : currentShouldBlock
89
+
90
+ if (!block) {
91
+ return
92
+ }
93
+
94
+ // Prevent default behavior (leaving the screen)
95
+ e.preventDefault()
96
+
97
+ // Store the event to dispatch later if user confirms
98
+ setPendingEvent(e)
99
+ setBlockedLocation(nextLocation)
100
+ setState('blocked')
101
+ })
102
+
103
+ return unsubscribe
104
+ }, [navigation])
105
+
106
+ const reset = React.useCallback(() => {
107
+ setPendingEvent(null)
108
+ setBlockedLocation(null)
109
+ setState('unblocked')
110
+ }, [])
111
+
112
+ const proceed = React.useCallback(() => {
113
+ if (!pendingEvent) return
114
+
115
+ setState('proceeding')
116
+
117
+ // Dispatch the original action to complete navigation
118
+ navigation.dispatch(pendingEvent.data.action)
119
+
120
+ // Reset after navigation
121
+ setTimeout(() => {
122
+ setPendingEvent(null)
123
+ setBlockedLocation(null)
124
+ setState('unblocked')
125
+ }, 100)
126
+ }, [navigation, pendingEvent])
127
+
128
+ if (state === 'unblocked') {
129
+ return { state: 'unblocked' }
130
+ }
131
+
132
+ if (state === 'proceeding') {
133
+ return { state: 'proceeding', location: blockedLocation! }
134
+ }
135
+
136
+ return {
137
+ state: 'blocked',
138
+ reset,
139
+ proceed,
140
+ location: blockedLocation!,
141
+ }
142
+ }
143
+
144
+ /**
145
+ * No-op on native - native uses React Navigation's beforeRemove event instead.
146
+ * This is only used by the router on web.
147
+ */
148
+ export function checkBlocker(
149
+ _nextLocation: string,
150
+ _historyAction: 'push' | 'pop' | 'replace' = 'push'
151
+ ): boolean {
152
+ return false
153
+ }