@tanstack/react-router 1.20.0 → 1.20.3-alpha.1

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 (320) hide show
  1. package/README.md +31 -0
  2. package/dist/cjs/Asset.cjs +41 -0
  3. package/dist/cjs/Asset.cjs.map +1 -0
  4. package/dist/cjs/Asset.d.cts +2 -0
  5. package/dist/cjs/CatchBoundary.cjs +16 -12
  6. package/dist/cjs/CatchBoundary.cjs.map +1 -1
  7. package/dist/cjs/CatchBoundary.d.cts +8 -32
  8. package/dist/cjs/ClientOnly.cjs +20 -0
  9. package/dist/cjs/ClientOnly.cjs.map +1 -0
  10. package/dist/cjs/ClientOnly.d.cts +29 -0
  11. package/dist/cjs/HeadContent.cjs +155 -0
  12. package/dist/cjs/HeadContent.cjs.map +1 -0
  13. package/dist/cjs/HeadContent.d.cts +7 -0
  14. package/dist/cjs/Match.cjs +252 -0
  15. package/dist/cjs/Match.cjs.map +1 -0
  16. package/dist/cjs/Match.d.cts +8 -0
  17. package/dist/cjs/Matches.cjs +39 -287
  18. package/dist/cjs/Matches.cjs.map +1 -1
  19. package/dist/cjs/Matches.d.cts +23 -83
  20. package/dist/cjs/RouterProvider.cjs +17 -140
  21. package/dist/cjs/RouterProvider.cjs.map +1 -1
  22. package/dist/cjs/RouterProvider.d.cts +8 -27
  23. package/dist/cjs/SafeFragment.cjs +8 -0
  24. package/dist/cjs/SafeFragment.cjs.map +1 -0
  25. package/dist/cjs/SafeFragment.d.cts +1 -0
  26. package/dist/cjs/ScriptOnce.cjs +28 -0
  27. package/dist/cjs/ScriptOnce.cjs.map +1 -0
  28. package/dist/cjs/ScriptOnce.d.cts +5 -0
  29. package/dist/cjs/Scripts.cjs +51 -0
  30. package/dist/cjs/Scripts.cjs.map +1 -0
  31. package/dist/cjs/Scripts.d.cts +1 -0
  32. package/dist/cjs/ScrollRestoration.cjs +39 -0
  33. package/dist/cjs/ScrollRestoration.cjs.map +1 -0
  34. package/dist/cjs/ScrollRestoration.d.cts +14 -0
  35. package/dist/cjs/Transitioner.cjs +115 -0
  36. package/dist/cjs/Transitioner.cjs.map +1 -0
  37. package/dist/cjs/Transitioner.d.cts +1 -0
  38. package/dist/cjs/awaited.cjs +12 -65
  39. package/dist/cjs/awaited.cjs.map +1 -1
  40. package/dist/cjs/awaited.d.cts +4 -4
  41. package/dist/cjs/fileRoute.cjs +41 -15
  42. package/dist/cjs/fileRoute.cjs.map +1 -1
  43. package/dist/cjs/fileRoute.d.cts +33 -108
  44. package/dist/cjs/history.d.cts +1 -0
  45. package/dist/cjs/index.cjs +216 -73
  46. package/dist/cjs/index.cjs.map +1 -1
  47. package/dist/cjs/index.d.cts +52 -29
  48. package/dist/cjs/lazyRouteComponent.cjs +40 -29
  49. package/dist/cjs/lazyRouteComponent.cjs.map +1 -1
  50. package/dist/cjs/lazyRouteComponent.d.cts +1 -1
  51. package/dist/cjs/link.cjs +212 -106
  52. package/dist/cjs/link.cjs.map +1 -1
  53. package/dist/cjs/link.d.cts +41 -86
  54. package/dist/cjs/matchContext.cjs +27 -0
  55. package/dist/cjs/matchContext.cjs.map +1 -0
  56. package/dist/cjs/matchContext.d.cts +3 -0
  57. package/dist/cjs/not-found.cjs +9 -15
  58. package/dist/cjs/not-found.cjs.map +1 -1
  59. package/dist/cjs/not-found.d.cts +5 -22
  60. package/dist/cjs/renderRouteNotFound.cjs +22 -0
  61. package/dist/cjs/renderRouteNotFound.cjs.map +1 -0
  62. package/dist/cjs/renderRouteNotFound.d.cts +2 -0
  63. package/dist/cjs/route.cjs +110 -79
  64. package/dist/cjs/route.cjs.map +1 -1
  65. package/dist/cjs/route.d.cts +64 -361
  66. package/dist/cjs/router.cjs +12 -1237
  67. package/dist/cjs/router.cjs.map +1 -1
  68. package/dist/cjs/router.d.cts +69 -237
  69. package/dist/cjs/routerContext.cjs +1 -1
  70. package/dist/cjs/routerContext.cjs.map +1 -1
  71. package/dist/cjs/routerContext.d.cts +7 -2
  72. package/dist/cjs/scroll-restoration.cjs +16 -177
  73. package/dist/cjs/scroll-restoration.cjs.map +1 -1
  74. package/dist/cjs/scroll-restoration.d.cts +1 -18
  75. package/dist/cjs/serializer.d.cts +6 -0
  76. package/dist/cjs/structuralSharing.d.cts +8 -0
  77. package/dist/cjs/typePrimitives.d.cts +16 -0
  78. package/dist/cjs/useBlocker.cjs +138 -9
  79. package/dist/cjs/useBlocker.cjs.map +1 -1
  80. package/dist/cjs/useBlocker.d.cts +64 -7
  81. package/dist/cjs/useCanGoBack.cjs +8 -0
  82. package/dist/cjs/useCanGoBack.cjs.map +1 -0
  83. package/dist/cjs/useCanGoBack.d.cts +1 -0
  84. package/dist/cjs/useLoaderData.cjs +15 -0
  85. package/dist/cjs/useLoaderData.cjs.map +1 -0
  86. package/dist/cjs/useLoaderData.d.cts +8 -0
  87. package/dist/cjs/useLoaderDeps.cjs +14 -0
  88. package/dist/cjs/useLoaderDeps.cjs.map +1 -0
  89. package/dist/cjs/useLoaderDeps.d.cts +8 -0
  90. package/dist/cjs/useLocation.cjs +10 -0
  91. package/dist/cjs/useLocation.cjs.map +1 -0
  92. package/dist/cjs/useLocation.d.cts +7 -0
  93. package/dist/cjs/useMatch.cjs +47 -0
  94. package/dist/cjs/useMatch.cjs.map +1 -0
  95. package/dist/cjs/useMatch.d.cts +10 -0
  96. package/dist/cjs/useNavigate.cjs +18 -19
  97. package/dist/cjs/useNavigate.cjs.map +1 -1
  98. package/dist/cjs/useNavigate.d.cts +4 -8
  99. package/dist/cjs/useParams.cjs +8 -8
  100. package/dist/cjs/useParams.cjs.map +1 -1
  101. package/dist/cjs/useParams.d.cts +9 -8
  102. package/dist/cjs/useRouteContext.cjs +3 -3
  103. package/dist/cjs/useRouteContext.cjs.map +1 -1
  104. package/dist/cjs/useRouteContext.d.cts +3 -7
  105. package/dist/cjs/useRouter.cjs.map +1 -1
  106. package/dist/cjs/useRouter.d.cts +3 -4
  107. package/dist/cjs/useRouterState.cjs +18 -1
  108. package/dist/cjs/useRouterState.cjs.map +1 -1
  109. package/dist/cjs/useRouterState.d.cts +8 -6
  110. package/dist/cjs/useSearch.cjs +7 -4
  111. package/dist/cjs/useSearch.cjs.map +1 -1
  112. package/dist/cjs/useSearch.d.cts +9 -7
  113. package/dist/cjs/utils.cjs +40 -122
  114. package/dist/cjs/utils.cjs.map +1 -1
  115. package/dist/cjs/utils.d.cts +46 -50
  116. package/dist/esm/Asset.d.ts +2 -0
  117. package/dist/esm/Asset.js +41 -0
  118. package/dist/esm/Asset.js.map +1 -0
  119. package/dist/esm/CatchBoundary.d.ts +8 -32
  120. package/dist/esm/CatchBoundary.js +16 -12
  121. package/dist/esm/CatchBoundary.js.map +1 -1
  122. package/dist/esm/ClientOnly.d.ts +29 -0
  123. package/dist/esm/ClientOnly.js +20 -0
  124. package/dist/esm/ClientOnly.js.map +1 -0
  125. package/dist/esm/HeadContent.d.ts +7 -0
  126. package/dist/esm/HeadContent.js +139 -0
  127. package/dist/esm/HeadContent.js.map +1 -0
  128. package/dist/esm/Match.d.ts +8 -0
  129. package/dist/esm/Match.js +235 -0
  130. package/dist/esm/Match.js.map +1 -0
  131. package/dist/esm/Matches.d.ts +23 -83
  132. package/dist/esm/Matches.js +36 -284
  133. package/dist/esm/Matches.js.map +1 -1
  134. package/dist/esm/RouterProvider.d.ts +8 -27
  135. package/dist/esm/RouterProvider.js +20 -126
  136. package/dist/esm/RouterProvider.js.map +1 -1
  137. package/dist/esm/SafeFragment.d.ts +1 -0
  138. package/dist/esm/SafeFragment.js +8 -0
  139. package/dist/esm/SafeFragment.js.map +1 -0
  140. package/dist/esm/ScriptOnce.d.ts +5 -0
  141. package/dist/esm/ScriptOnce.js +28 -0
  142. package/dist/esm/ScriptOnce.js.map +1 -0
  143. package/dist/esm/Scripts.d.ts +1 -0
  144. package/dist/esm/Scripts.js +51 -0
  145. package/dist/esm/Scripts.js.map +1 -0
  146. package/dist/esm/ScrollRestoration.d.ts +14 -0
  147. package/dist/esm/ScrollRestoration.js +39 -0
  148. package/dist/esm/ScrollRestoration.js.map +1 -0
  149. package/dist/esm/Transitioner.d.ts +1 -0
  150. package/dist/esm/Transitioner.js +98 -0
  151. package/dist/esm/Transitioner.js.map +1 -0
  152. package/dist/esm/awaited.d.ts +4 -4
  153. package/dist/esm/awaited.js +12 -65
  154. package/dist/esm/awaited.js.map +1 -1
  155. package/dist/esm/fileRoute.d.ts +33 -108
  156. package/dist/esm/fileRoute.js +38 -12
  157. package/dist/esm/fileRoute.js.map +1 -1
  158. package/dist/esm/history.d.ts +1 -0
  159. package/dist/esm/index.d.ts +52 -29
  160. package/dist/esm/index.js +41 -29
  161. package/dist/esm/index.js.map +1 -1
  162. package/dist/esm/lazyRouteComponent.d.ts +1 -1
  163. package/dist/esm/lazyRouteComponent.js +40 -29
  164. package/dist/esm/lazyRouteComponent.js.map +1 -1
  165. package/dist/esm/link.d.ts +41 -86
  166. package/dist/esm/link.js +212 -106
  167. package/dist/esm/link.js.map +1 -1
  168. package/dist/esm/matchContext.d.ts +3 -0
  169. package/dist/esm/matchContext.js +10 -0
  170. package/dist/esm/matchContext.js.map +1 -0
  171. package/dist/esm/not-found.d.ts +5 -22
  172. package/dist/esm/not-found.js +9 -15
  173. package/dist/esm/not-found.js.map +1 -1
  174. package/dist/esm/renderRouteNotFound.d.ts +2 -0
  175. package/dist/esm/renderRouteNotFound.js +22 -0
  176. package/dist/esm/renderRouteNotFound.js.map +1 -0
  177. package/dist/esm/route.d.ts +64 -361
  178. package/dist/esm/route.js +103 -72
  179. package/dist/esm/route.js.map +1 -1
  180. package/dist/esm/router.d.ts +69 -237
  181. package/dist/esm/router.js +13 -1238
  182. package/dist/esm/router.js.map +1 -1
  183. package/dist/esm/routerContext.d.ts +7 -2
  184. package/dist/esm/routerContext.js +1 -1
  185. package/dist/esm/routerContext.js.map +1 -1
  186. package/dist/esm/scroll-restoration.d.ts +1 -18
  187. package/dist/esm/scroll-restoration.js +17 -161
  188. package/dist/esm/scroll-restoration.js.map +1 -1
  189. package/dist/esm/serializer.d.ts +6 -0
  190. package/dist/esm/structuralSharing.d.ts +8 -0
  191. package/dist/esm/typePrimitives.d.ts +16 -0
  192. package/dist/esm/useBlocker.d.ts +64 -7
  193. package/dist/esm/useBlocker.js +138 -9
  194. package/dist/esm/useBlocker.js.map +1 -1
  195. package/dist/esm/useCanGoBack.d.ts +1 -0
  196. package/dist/esm/useCanGoBack.js +8 -0
  197. package/dist/esm/useCanGoBack.js.map +1 -0
  198. package/dist/esm/useLoaderData.d.ts +8 -0
  199. package/dist/esm/useLoaderData.js +15 -0
  200. package/dist/esm/useLoaderData.js.map +1 -0
  201. package/dist/esm/useLoaderDeps.d.ts +8 -0
  202. package/dist/esm/useLoaderDeps.js +14 -0
  203. package/dist/esm/useLoaderDeps.js.map +1 -0
  204. package/dist/esm/useLocation.d.ts +7 -0
  205. package/dist/esm/useLocation.js +10 -0
  206. package/dist/esm/useLocation.js.map +1 -0
  207. package/dist/esm/useMatch.d.ts +10 -0
  208. package/dist/esm/useMatch.js +30 -0
  209. package/dist/esm/useMatch.js.map +1 -0
  210. package/dist/esm/useNavigate.d.ts +4 -8
  211. package/dist/esm/useNavigate.js +18 -19
  212. package/dist/esm/useNavigate.js.map +1 -1
  213. package/dist/esm/useParams.d.ts +9 -8
  214. package/dist/esm/useParams.js +8 -8
  215. package/dist/esm/useParams.js.map +1 -1
  216. package/dist/esm/useRouteContext.d.ts +3 -7
  217. package/dist/esm/useRouteContext.js +2 -2
  218. package/dist/esm/useRouteContext.js.map +1 -1
  219. package/dist/esm/useRouter.d.ts +3 -4
  220. package/dist/esm/useRouter.js.map +1 -1
  221. package/dist/esm/useRouterState.d.ts +8 -6
  222. package/dist/esm/useRouterState.js +18 -1
  223. package/dist/esm/useRouterState.js.map +1 -1
  224. package/dist/esm/useSearch.d.ts +9 -7
  225. package/dist/esm/useSearch.js +6 -3
  226. package/dist/esm/useSearch.js.map +1 -1
  227. package/dist/esm/utils.d.ts +46 -50
  228. package/dist/esm/utils.js +41 -123
  229. package/dist/esm/utils.js.map +1 -1
  230. package/package.json +30 -31
  231. package/src/Asset.tsx +40 -0
  232. package/src/CatchBoundary.tsx +35 -19
  233. package/src/ClientOnly.tsx +68 -0
  234. package/src/HeadContent.tsx +174 -0
  235. package/src/Match.tsx +330 -0
  236. package/src/Matches.tsx +149 -558
  237. package/src/RouterProvider.tsx +58 -212
  238. package/src/SafeFragment.tsx +5 -0
  239. package/src/ScriptOnce.tsx +32 -0
  240. package/src/Scripts.tsx +65 -0
  241. package/src/ScrollRestoration.tsx +69 -0
  242. package/src/Transitioner.tsx +130 -0
  243. package/src/awaited.tsx +16 -87
  244. package/src/fileRoute.ts +145 -248
  245. package/src/history.ts +2 -1
  246. package/src/index.tsx +368 -30
  247. package/src/lazyRouteComponent.tsx +68 -54
  248. package/src/link.tsx +397 -522
  249. package/src/matchContext.tsx +8 -0
  250. package/src/not-found.tsx +13 -34
  251. package/src/renderRouteNotFound.tsx +27 -0
  252. package/src/route.tsx +572 -0
  253. package/src/router.ts +99 -2067
  254. package/src/routerContext.tsx +8 -2
  255. package/src/scroll-restoration.tsx +23 -224
  256. package/src/serializer.ts +7 -0
  257. package/src/structuralSharing.ts +47 -0
  258. package/src/typePrimitives.ts +84 -0
  259. package/src/useBlocker.tsx +297 -15
  260. package/src/useCanGoBack.ts +5 -0
  261. package/src/useLoaderData.tsx +80 -0
  262. package/src/useLoaderDeps.tsx +58 -0
  263. package/src/useLocation.tsx +41 -0
  264. package/src/useMatch.tsx +119 -0
  265. package/src/useNavigate.tsx +41 -61
  266. package/src/useParams.tsx +88 -23
  267. package/src/useRouteContext.ts +24 -18
  268. package/src/useRouter.tsx +4 -5
  269. package/src/useRouterState.tsx +52 -10
  270. package/src/useSearch.tsx +87 -24
  271. package/src/utils.ts +97 -312
  272. package/dist/cjs/createServerFn.cjs +0 -40
  273. package/dist/cjs/createServerFn.cjs.map +0 -1
  274. package/dist/cjs/createServerFn.d.cts +0 -44
  275. package/dist/cjs/defer.cjs +0 -30
  276. package/dist/cjs/defer.cjs.map +0 -1
  277. package/dist/cjs/defer.d.cts +0 -25
  278. package/dist/cjs/location.d.cts +0 -12
  279. package/dist/cjs/path.cjs +0 -213
  280. package/dist/cjs/path.cjs.map +0 -1
  281. package/dist/cjs/path.d.cts +0 -24
  282. package/dist/cjs/qss.cjs +0 -45
  283. package/dist/cjs/qss.cjs.map +0 -1
  284. package/dist/cjs/qss.d.cts +0 -2
  285. package/dist/cjs/redirects.cjs +0 -16
  286. package/dist/cjs/redirects.cjs.map +0 -1
  287. package/dist/cjs/redirects.d.cts +0 -18
  288. package/dist/cjs/routeInfo.d.cts +0 -33
  289. package/dist/cjs/searchParams.cjs +0 -63
  290. package/dist/cjs/searchParams.cjs.map +0 -1
  291. package/dist/cjs/searchParams.d.cts +0 -7
  292. package/dist/esm/createServerFn.d.ts +0 -44
  293. package/dist/esm/createServerFn.js +0 -40
  294. package/dist/esm/createServerFn.js.map +0 -1
  295. package/dist/esm/defer.d.ts +0 -25
  296. package/dist/esm/defer.js +0 -30
  297. package/dist/esm/defer.js.map +0 -1
  298. package/dist/esm/location.d.ts +0 -12
  299. package/dist/esm/path.d.ts +0 -24
  300. package/dist/esm/path.js +0 -213
  301. package/dist/esm/path.js.map +0 -1
  302. package/dist/esm/qss.d.ts +0 -2
  303. package/dist/esm/qss.js +0 -45
  304. package/dist/esm/qss.js.map +0 -1
  305. package/dist/esm/redirects.d.ts +0 -18
  306. package/dist/esm/redirects.js +0 -16
  307. package/dist/esm/redirects.js.map +0 -1
  308. package/dist/esm/routeInfo.d.ts +0 -33
  309. package/dist/esm/searchParams.d.ts +0 -7
  310. package/dist/esm/searchParams.js +0 -63
  311. package/dist/esm/searchParams.js.map +0 -1
  312. package/src/createServerFn.ts +0 -107
  313. package/src/defer.ts +0 -70
  314. package/src/location.ts +0 -13
  315. package/src/path.ts +0 -280
  316. package/src/qss.ts +0 -53
  317. package/src/redirects.ts +0 -56
  318. package/src/route.ts +0 -1356
  319. package/src/routeInfo.ts +0 -62
  320. package/src/searchParams.ts +0 -79
@@ -1,27 +1,309 @@
1
1
  import * as React from 'react'
2
- import { ReactNode } from './route'
3
2
  import { useRouter } from './useRouter'
4
- import { BlockerFn } from '@tanstack/history'
3
+ import type {
4
+ BlockerFnArgs,
5
+ HistoryAction,
6
+ HistoryLocation,
7
+ } from '@tanstack/history'
8
+ import type {
9
+ AnyRoute,
10
+ AnyRouter,
11
+ ParseRoute,
12
+ RegisteredRouter,
13
+ } from '@tanstack/router-core'
5
14
 
15
+ interface ShouldBlockFnLocation<
16
+ out TRouteId,
17
+ out TFullPath,
18
+ out TAllParams,
19
+ out TFullSearchSchema,
20
+ > {
21
+ routeId: TRouteId
22
+ fullPath: TFullPath
23
+ pathname: string
24
+ params: TAllParams
25
+ search: TFullSearchSchema
26
+ }
27
+
28
+ type AnyShouldBlockFnLocation = ShouldBlockFnLocation<any, any, any, any>
29
+ type MakeShouldBlockFnLocationUnion<
30
+ TRouter extends AnyRouter = RegisteredRouter,
31
+ TRoute extends AnyRoute = ParseRoute<TRouter['routeTree']>,
32
+ > = TRoute extends any
33
+ ? ShouldBlockFnLocation<
34
+ TRoute['id'],
35
+ TRoute['fullPath'],
36
+ TRoute['types']['allParams'],
37
+ TRoute['types']['fullSearchSchema']
38
+ >
39
+ : never
40
+
41
+ type BlockerResolver<TRouter extends AnyRouter = RegisteredRouter> =
42
+ | {
43
+ status: 'blocked'
44
+ current: MakeShouldBlockFnLocationUnion<TRouter>
45
+ next: MakeShouldBlockFnLocationUnion<TRouter>
46
+ action: HistoryAction
47
+ proceed: () => void
48
+ reset: () => void
49
+ }
50
+ | {
51
+ status: 'idle'
52
+ current: undefined
53
+ next: undefined
54
+ action: undefined
55
+ proceed: undefined
56
+ reset: undefined
57
+ }
58
+
59
+ type ShouldBlockFnArgs<TRouter extends AnyRouter = RegisteredRouter> = {
60
+ current: MakeShouldBlockFnLocationUnion<TRouter>
61
+ next: MakeShouldBlockFnLocationUnion<TRouter>
62
+ action: HistoryAction
63
+ }
64
+
65
+ export type ShouldBlockFn<TRouter extends AnyRouter = RegisteredRouter> = (
66
+ args: ShouldBlockFnArgs<TRouter>,
67
+ ) => boolean | Promise<boolean>
68
+ export type UseBlockerOpts<
69
+ TRouter extends AnyRouter = RegisteredRouter,
70
+ TWithResolver extends boolean = boolean,
71
+ > = {
72
+ shouldBlockFn: ShouldBlockFn<TRouter>
73
+ enableBeforeUnload?: boolean | (() => boolean)
74
+ disabled?: boolean
75
+ withResolver?: TWithResolver
76
+ }
77
+
78
+ type LegacyBlockerFn = () => Promise<any> | any
79
+ type LegacyBlockerOpts = {
80
+ blockerFn?: LegacyBlockerFn
81
+ condition?: boolean | any
82
+ }
83
+
84
+ function _resolveBlockerOpts(
85
+ opts?: UseBlockerOpts | LegacyBlockerOpts | LegacyBlockerFn,
86
+ condition?: boolean | any,
87
+ ): UseBlockerOpts {
88
+ if (opts === undefined) {
89
+ return {
90
+ shouldBlockFn: () => true,
91
+ withResolver: false,
92
+ }
93
+ }
94
+
95
+ if ('shouldBlockFn' in opts) {
96
+ return opts
97
+ }
98
+
99
+ if (typeof opts === 'function') {
100
+ const shouldBlock = Boolean(condition ?? true)
101
+
102
+ const _customBlockerFn = async () => {
103
+ if (shouldBlock) return await opts()
104
+ return false
105
+ }
106
+
107
+ return {
108
+ shouldBlockFn: _customBlockerFn,
109
+ enableBeforeUnload: shouldBlock,
110
+ withResolver: false,
111
+ }
112
+ }
113
+
114
+ const shouldBlock = Boolean(opts.condition ?? true)
115
+ const fn = opts.blockerFn
116
+
117
+ const _customBlockerFn = async () => {
118
+ if (shouldBlock && fn !== undefined) {
119
+ return await fn()
120
+ }
121
+ return shouldBlock
122
+ }
123
+
124
+ return {
125
+ shouldBlockFn: _customBlockerFn,
126
+ enableBeforeUnload: shouldBlock,
127
+ withResolver: fn === undefined,
128
+ }
129
+ }
130
+
131
+ export function useBlocker<
132
+ TRouter extends AnyRouter = RegisteredRouter,
133
+ TWithResolver extends boolean = false,
134
+ >(
135
+ opts: UseBlockerOpts<TRouter, TWithResolver>,
136
+ ): TWithResolver extends true ? BlockerResolver<TRouter> : void
137
+
138
+ /**
139
+ * @deprecated Use the shouldBlockFn property instead
140
+ */
141
+ export function useBlocker(blockerFnOrOpts?: LegacyBlockerOpts): BlockerResolver
142
+
143
+ /**
144
+ * @deprecated Use the UseBlockerOpts object syntax instead
145
+ */
6
146
  export function useBlocker(
7
- blockerFn: BlockerFn,
8
- condition: boolean | any = true,
9
- ): void {
10
- const { history } = useRouter()
147
+ blockerFn?: LegacyBlockerFn,
148
+ condition?: boolean | any,
149
+ ): BlockerResolver
11
150
 
12
- React.useEffect(() => {
13
- if (!condition) return
14
- return history.block(blockerFn)
151
+ export function useBlocker(
152
+ opts?: UseBlockerOpts | LegacyBlockerOpts | LegacyBlockerFn,
153
+ condition?: boolean | any,
154
+ ): BlockerResolver | void {
155
+ const {
156
+ shouldBlockFn,
157
+ enableBeforeUnload = true,
158
+ disabled = false,
159
+ withResolver = false,
160
+ } = _resolveBlockerOpts(opts, condition)
161
+
162
+ const router = useRouter()
163
+ const { history } = router
164
+
165
+ const [resolver, setResolver] = React.useState<BlockerResolver>({
166
+ status: 'idle',
167
+ current: undefined,
168
+ next: undefined,
169
+ action: undefined,
170
+ proceed: undefined,
171
+ reset: undefined,
15
172
  })
173
+
174
+ React.useEffect(() => {
175
+ const blockerFnComposed = async (blockerFnArgs: BlockerFnArgs) => {
176
+ function getLocation(
177
+ location: HistoryLocation,
178
+ ): AnyShouldBlockFnLocation {
179
+ const parsedLocation = router.parseLocation(undefined, location)
180
+ const matchedRoutes = router.getMatchedRoutes(
181
+ parsedLocation.pathname,
182
+ undefined,
183
+ )
184
+ if (matchedRoutes.foundRoute === undefined) {
185
+ throw new Error(`No route found for location ${location.href}`)
186
+ }
187
+ return {
188
+ routeId: matchedRoutes.foundRoute.id,
189
+ fullPath: matchedRoutes.foundRoute.fullPath,
190
+ pathname: parsedLocation.pathname,
191
+ params: matchedRoutes.routeParams,
192
+ search: parsedLocation.search,
193
+ }
194
+ }
195
+
196
+ const current = getLocation(blockerFnArgs.currentLocation)
197
+ const next = getLocation(blockerFnArgs.nextLocation)
198
+
199
+ const shouldBlock = await shouldBlockFn({
200
+ action: blockerFnArgs.action,
201
+ current,
202
+ next,
203
+ })
204
+ if (!withResolver) {
205
+ return shouldBlock
206
+ }
207
+
208
+ if (!shouldBlock) {
209
+ return false
210
+ }
211
+
212
+ const promise = new Promise<boolean>((resolve) => {
213
+ setResolver({
214
+ status: 'blocked',
215
+ current,
216
+ next,
217
+ action: blockerFnArgs.action,
218
+ proceed: () => resolve(false),
219
+ reset: () => resolve(true),
220
+ })
221
+ })
222
+
223
+ const canNavigateAsync = await promise
224
+ setResolver({
225
+ status: 'idle',
226
+ current: undefined,
227
+ next: undefined,
228
+ action: undefined,
229
+ proceed: undefined,
230
+ reset: undefined,
231
+ })
232
+
233
+ return canNavigateAsync
234
+ }
235
+
236
+ return disabled
237
+ ? undefined
238
+ : history.block({ blockerFn: blockerFnComposed, enableBeforeUnload })
239
+ }, [
240
+ shouldBlockFn,
241
+ enableBeforeUnload,
242
+ disabled,
243
+ withResolver,
244
+ history,
245
+ router,
246
+ ])
247
+
248
+ return resolver
16
249
  }
17
250
 
18
- export function Block({ blocker, condition, children }: PromptProps) {
19
- useBlocker(blocker, condition)
20
- return (children ?? null) as ReactNode
251
+ const _resolvePromptBlockerArgs = (
252
+ props: PromptProps | LegacyPromptProps,
253
+ ): UseBlockerOpts => {
254
+ if ('shouldBlockFn' in props) {
255
+ return { ...props }
256
+ }
257
+
258
+ const shouldBlock = Boolean(props.condition ?? true)
259
+ const fn = props.blockerFn
260
+
261
+ const _customBlockerFn = async () => {
262
+ if (shouldBlock && fn !== undefined) {
263
+ return await fn()
264
+ }
265
+ return shouldBlock
266
+ }
267
+
268
+ return {
269
+ shouldBlockFn: _customBlockerFn,
270
+ enableBeforeUnload: shouldBlock,
271
+ withResolver: fn === undefined,
272
+ }
21
273
  }
22
274
 
23
- export type PromptProps = {
24
- blocker: BlockerFn
275
+ export function Block<
276
+ TRouter extends AnyRouter = RegisteredRouter,
277
+ TWithResolver extends boolean = boolean,
278
+ >(opts: PromptProps<TRouter, TWithResolver>): React.ReactNode
279
+
280
+ /**
281
+ * @deprecated Use the UseBlockerOpts property instead
282
+ */
283
+ export function Block(opts: LegacyPromptProps): React.ReactNode
284
+
285
+ export function Block(opts: PromptProps | LegacyPromptProps): React.ReactNode {
286
+ const { children, ...rest } = opts
287
+ const args = _resolvePromptBlockerArgs(rest)
288
+
289
+ const resolver = useBlocker(args)
290
+ return children
291
+ ? typeof children === 'function'
292
+ ? children(resolver as any)
293
+ : children
294
+ : null
295
+ }
296
+
297
+ type LegacyPromptProps = {
298
+ blockerFn?: LegacyBlockerFn
25
299
  condition?: boolean | any
26
- children?: ReactNode
300
+ children?: React.ReactNode | ((params: BlockerResolver) => React.ReactNode)
301
+ }
302
+
303
+ type PromptProps<
304
+ TRouter extends AnyRouter = RegisteredRouter,
305
+ TWithResolver extends boolean = boolean,
306
+ TParams = TWithResolver extends true ? BlockerResolver<TRouter> : void,
307
+ > = UseBlockerOpts<TRouter, TWithResolver> & {
308
+ children?: React.ReactNode | ((params: TParams) => React.ReactNode)
27
309
  }
@@ -0,0 +1,5 @@
1
+ import { useRouterState } from './useRouterState'
2
+
3
+ export function useCanGoBack() {
4
+ return useRouterState({ select: (s) => s.location.state.__TSR_index !== 0 })
5
+ }
@@ -0,0 +1,80 @@
1
+ import { useMatch } from './useMatch'
2
+ import type {
3
+ StructuralSharingOption,
4
+ ValidateSelected,
5
+ } from './structuralSharing'
6
+ import type {
7
+ AnyRouter,
8
+ RegisteredRouter,
9
+ ResolveUseLoaderData,
10
+ StrictOrFrom,
11
+ UseLoaderDataResult,
12
+ } from '@tanstack/router-core'
13
+
14
+ export interface UseLoaderDataBaseOptions<
15
+ TRouter extends AnyRouter,
16
+ TFrom,
17
+ TStrict extends boolean,
18
+ TSelected,
19
+ TStructuralSharing,
20
+ > {
21
+ select?: (
22
+ match: ResolveUseLoaderData<TRouter, TFrom, TStrict>,
23
+ ) => ValidateSelected<TRouter, TSelected, TStructuralSharing>
24
+ }
25
+
26
+ export type UseLoaderDataOptions<
27
+ TRouter extends AnyRouter,
28
+ TFrom extends string | undefined,
29
+ TStrict extends boolean,
30
+ TSelected,
31
+ TStructuralSharing,
32
+ > = StrictOrFrom<TRouter, TFrom, TStrict> &
33
+ UseLoaderDataBaseOptions<
34
+ TRouter,
35
+ TFrom,
36
+ TStrict,
37
+ TSelected,
38
+ TStructuralSharing
39
+ > &
40
+ StructuralSharingOption<TRouter, TSelected, TStructuralSharing>
41
+
42
+ export type UseLoaderDataRoute<out TId> = <
43
+ TRouter extends AnyRouter = RegisteredRouter,
44
+ TSelected = unknown,
45
+ TStructuralSharing extends boolean = boolean,
46
+ >(
47
+ opts?: UseLoaderDataBaseOptions<
48
+ TRouter,
49
+ TId,
50
+ true,
51
+ TSelected,
52
+ TStructuralSharing
53
+ > &
54
+ StructuralSharingOption<TRouter, TSelected, TStructuralSharing>,
55
+ ) => UseLoaderDataResult<TRouter, TId, true, TSelected>
56
+
57
+ export function useLoaderData<
58
+ TRouter extends AnyRouter = RegisteredRouter,
59
+ const TFrom extends string | undefined = undefined,
60
+ TStrict extends boolean = true,
61
+ TSelected = unknown,
62
+ TStructuralSharing extends boolean = boolean,
63
+ >(
64
+ opts: UseLoaderDataOptions<
65
+ TRouter,
66
+ TFrom,
67
+ TStrict,
68
+ TSelected,
69
+ TStructuralSharing
70
+ >,
71
+ ): UseLoaderDataResult<TRouter, TFrom, TStrict, TSelected> {
72
+ return useMatch({
73
+ from: opts.from!,
74
+ strict: opts.strict,
75
+ structuralSharing: opts.structuralSharing,
76
+ select: (s: any) => {
77
+ return opts.select ? opts.select(s.loaderData) : s.loaderData
78
+ },
79
+ } as any) as UseLoaderDataResult<TRouter, TFrom, TStrict, TSelected>
80
+ }
@@ -0,0 +1,58 @@
1
+ import { useMatch } from './useMatch'
2
+ import type {
3
+ StructuralSharingOption,
4
+ ValidateSelected,
5
+ } from './structuralSharing'
6
+ import type {
7
+ AnyRouter,
8
+ RegisteredRouter,
9
+ ResolveUseLoaderDeps,
10
+ StrictOrFrom,
11
+ UseLoaderDepsResult,
12
+ } from '@tanstack/router-core'
13
+
14
+ export interface UseLoaderDepsBaseOptions<
15
+ TRouter extends AnyRouter,
16
+ TFrom,
17
+ TSelected,
18
+ TStructuralSharing,
19
+ > {
20
+ select?: (
21
+ deps: ResolveUseLoaderDeps<TRouter, TFrom>,
22
+ ) => ValidateSelected<TRouter, TSelected, TStructuralSharing>
23
+ }
24
+
25
+ export type UseLoaderDepsOptions<
26
+ TRouter extends AnyRouter,
27
+ TFrom extends string | undefined,
28
+ TSelected,
29
+ TStructuralSharing,
30
+ > = StrictOrFrom<TRouter, TFrom> &
31
+ UseLoaderDepsBaseOptions<TRouter, TFrom, TSelected, TStructuralSharing> &
32
+ StructuralSharingOption<TRouter, TSelected, TStructuralSharing>
33
+
34
+ export type UseLoaderDepsRoute<out TId> = <
35
+ TRouter extends AnyRouter = RegisteredRouter,
36
+ TSelected = unknown,
37
+ TStructuralSharing extends boolean = boolean,
38
+ >(
39
+ opts?: UseLoaderDepsBaseOptions<TRouter, TId, TSelected, TStructuralSharing> &
40
+ StructuralSharingOption<TRouter, TSelected, false>,
41
+ ) => UseLoaderDepsResult<TRouter, TId, TSelected>
42
+
43
+ export function useLoaderDeps<
44
+ TRouter extends AnyRouter = RegisteredRouter,
45
+ const TFrom extends string | undefined = undefined,
46
+ TSelected = unknown,
47
+ TStructuralSharing extends boolean = boolean,
48
+ >(
49
+ opts: UseLoaderDepsOptions<TRouter, TFrom, TSelected, TStructuralSharing>,
50
+ ): UseLoaderDepsResult<TRouter, TFrom, TSelected> {
51
+ const { select, ...rest } = opts
52
+ return useMatch({
53
+ ...rest,
54
+ select: (s) => {
55
+ return select ? select(s.loaderDeps) : s.loaderDeps
56
+ },
57
+ }) as UseLoaderDepsResult<TRouter, TFrom, TSelected>
58
+ }
@@ -0,0 +1,41 @@
1
+ import { useRouterState } from './useRouterState'
2
+ import type {
3
+ StructuralSharingOption,
4
+ ValidateSelected,
5
+ } from './structuralSharing'
6
+ import type {
7
+ AnyRouter,
8
+ RegisteredRouter,
9
+ RouterState,
10
+ } from '@tanstack/router-core'
11
+
12
+ export interface UseLocationBaseOptions<
13
+ TRouter extends AnyRouter,
14
+ TSelected,
15
+ TStructuralSharing extends boolean = boolean,
16
+ > {
17
+ select?: (
18
+ state: RouterState<TRouter['routeTree']>['location'],
19
+ ) => ValidateSelected<TRouter, TSelected, TStructuralSharing>
20
+ }
21
+
22
+ export type UseLocationResult<
23
+ TRouter extends AnyRouter,
24
+ TSelected,
25
+ > = unknown extends TSelected
26
+ ? RouterState<TRouter['routeTree']>['location']
27
+ : TSelected
28
+
29
+ export function useLocation<
30
+ TRouter extends AnyRouter = RegisteredRouter,
31
+ TSelected = unknown,
32
+ TStructuralSharing extends boolean = boolean,
33
+ >(
34
+ opts?: UseLocationBaseOptions<TRouter, TSelected, TStructuralSharing> &
35
+ StructuralSharingOption<TRouter, TSelected, TStructuralSharing>,
36
+ ): UseLocationResult<TRouter, TSelected> {
37
+ return useRouterState({
38
+ select: (state: any) =>
39
+ opts?.select ? opts.select(state.location) : state.location,
40
+ } as any) as UseLocationResult<TRouter, TSelected>
41
+ }
@@ -0,0 +1,119 @@
1
+ import * as React from 'react'
2
+ import invariant from 'tiny-invariant'
3
+ import { useRouterState } from './useRouterState'
4
+ import { dummyMatchContext, matchContext } from './matchContext'
5
+ import type {
6
+ StructuralSharingOption,
7
+ ValidateSelected,
8
+ } from './structuralSharing'
9
+ import type {
10
+ AnyRouter,
11
+ MakeRouteMatch,
12
+ MakeRouteMatchUnion,
13
+ RegisteredRouter,
14
+ StrictOrFrom,
15
+ ThrowConstraint,
16
+ ThrowOrOptional,
17
+ } from '@tanstack/router-core'
18
+
19
+ export interface UseMatchBaseOptions<
20
+ TRouter extends AnyRouter,
21
+ TFrom,
22
+ TStrict extends boolean,
23
+ TThrow extends boolean,
24
+ TSelected,
25
+ TStructuralSharing extends boolean,
26
+ > {
27
+ select?: (
28
+ match: MakeRouteMatch<TRouter['routeTree'], TFrom, TStrict>,
29
+ ) => ValidateSelected<TRouter, TSelected, TStructuralSharing>
30
+ shouldThrow?: TThrow
31
+ }
32
+
33
+ export type UseMatchRoute<out TFrom> = <
34
+ TRouter extends AnyRouter = RegisteredRouter,
35
+ TSelected = unknown,
36
+ TStructuralSharing extends boolean = boolean,
37
+ >(
38
+ opts?: UseMatchBaseOptions<
39
+ TRouter,
40
+ TFrom,
41
+ true,
42
+ true,
43
+ TSelected,
44
+ TStructuralSharing
45
+ > &
46
+ StructuralSharingOption<TRouter, TSelected, TStructuralSharing>,
47
+ ) => UseMatchResult<TRouter, TFrom, true, TSelected>
48
+
49
+ export type UseMatchOptions<
50
+ TRouter extends AnyRouter,
51
+ TFrom extends string | undefined,
52
+ TStrict extends boolean,
53
+ TThrow extends boolean,
54
+ TSelected,
55
+ TStructuralSharing extends boolean,
56
+ > = StrictOrFrom<TRouter, TFrom, TStrict> &
57
+ UseMatchBaseOptions<
58
+ TRouter,
59
+ TFrom,
60
+ TStrict,
61
+ TThrow,
62
+ TSelected,
63
+ TStructuralSharing
64
+ > &
65
+ StructuralSharingOption<TRouter, TSelected, TStructuralSharing>
66
+
67
+ export type UseMatchResult<
68
+ TRouter extends AnyRouter,
69
+ TFrom,
70
+ TStrict extends boolean,
71
+ TSelected,
72
+ > = unknown extends TSelected
73
+ ? TStrict extends true
74
+ ? MakeRouteMatch<TRouter['routeTree'], TFrom, TStrict>
75
+ : MakeRouteMatchUnion<TRouter>
76
+ : TSelected
77
+
78
+ export function useMatch<
79
+ TRouter extends AnyRouter = RegisteredRouter,
80
+ const TFrom extends string | undefined = undefined,
81
+ TStrict extends boolean = true,
82
+ TThrow extends boolean = true,
83
+ TSelected = unknown,
84
+ TStructuralSharing extends boolean = boolean,
85
+ >(
86
+ opts: UseMatchOptions<
87
+ TRouter,
88
+ TFrom,
89
+ TStrict,
90
+ ThrowConstraint<TStrict, TThrow>,
91
+ TSelected,
92
+ TStructuralSharing
93
+ >,
94
+ ): ThrowOrOptional<UseMatchResult<TRouter, TFrom, TStrict, TSelected>, TThrow> {
95
+ const nearestMatchId = React.useContext(
96
+ opts.from ? dummyMatchContext : matchContext,
97
+ )
98
+
99
+ const matchSelection = useRouterState({
100
+ select: (state: any) => {
101
+ const match = state.matches.find((d: any) =>
102
+ opts.from ? opts.from === d.routeId : d.id === nearestMatchId,
103
+ )
104
+ invariant(
105
+ !((opts.shouldThrow ?? true) && !match),
106
+ `Could not find ${opts.from ? `an active match from "${opts.from}"` : 'a nearest match!'}`,
107
+ )
108
+
109
+ if (match === undefined) {
110
+ return undefined
111
+ }
112
+
113
+ return opts.select ? opts.select(match) : match
114
+ },
115
+ structuralSharing: opts.structuralSharing,
116
+ } as any)
117
+
118
+ return matchSelection as any
119
+ }