@tanstack/vue-router 0.0.1 → 1.140.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (268) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +66 -45
  3. package/dist/esm/Asset.d.ts +2 -0
  4. package/dist/esm/Asset.js +33 -0
  5. package/dist/esm/Asset.js.map +1 -0
  6. package/dist/esm/CatchBoundary.d.ts +19 -0
  7. package/dist/esm/CatchBoundary.js +135 -0
  8. package/dist/esm/CatchBoundary.js.map +1 -0
  9. package/dist/esm/ClientOnly.d.ts +67 -0
  10. package/dist/esm/HeadContent.d.ts +10 -0
  11. package/dist/esm/HeadContent.js +116 -0
  12. package/dist/esm/HeadContent.js.map +1 -0
  13. package/dist/esm/Match.d.ts +25 -0
  14. package/dist/esm/Match.js +262 -0
  15. package/dist/esm/Match.js.map +1 -0
  16. package/dist/esm/Matches.d.ts +39 -0
  17. package/dist/esm/Matches.js +186 -0
  18. package/dist/esm/Matches.js.map +1 -0
  19. package/dist/esm/RouterProvider.d.ts +33 -0
  20. package/dist/esm/RouterProvider.js +65 -0
  21. package/dist/esm/RouterProvider.js.map +1 -0
  22. package/dist/esm/SafeFragment.d.ts +4 -0
  23. package/dist/esm/ScriptOnce.d.ts +5 -0
  24. package/dist/esm/ScriptOnce.js +21 -0
  25. package/dist/esm/ScriptOnce.js.map +1 -0
  26. package/dist/esm/Scripts.d.ts +1 -0
  27. package/dist/esm/Scripts.js +46 -0
  28. package/dist/esm/Scripts.js.map +1 -0
  29. package/dist/esm/ScrollRestoration.d.ts +14 -0
  30. package/dist/esm/ScrollRestoration.js +36 -0
  31. package/dist/esm/ScrollRestoration.js.map +1 -0
  32. package/dist/esm/Transitioner.d.ts +2 -0
  33. package/dist/esm/Transitioner.js +154 -0
  34. package/dist/esm/Transitioner.js.map +1 -0
  35. package/dist/esm/awaited.d.ts +12 -0
  36. package/dist/esm/awaited.js +40 -0
  37. package/dist/esm/awaited.js.map +1 -0
  38. package/dist/esm/fileRoute.d.ts +54 -0
  39. package/dist/esm/fileRoute.js +103 -0
  40. package/dist/esm/fileRoute.js.map +1 -0
  41. package/dist/esm/history.d.ts +8 -0
  42. package/dist/esm/index.d.ts +51 -0
  43. package/dist/esm/index.js +138 -0
  44. package/dist/esm/index.js.map +1 -0
  45. package/dist/esm/lazyRouteComponent.d.ts +8 -0
  46. package/dist/esm/lazyRouteComponent.js +106 -0
  47. package/dist/esm/lazyRouteComponent.js.map +1 -0
  48. package/dist/esm/link.d.ts +61 -0
  49. package/dist/esm/link.js +376 -0
  50. package/dist/esm/link.js.map +1 -0
  51. package/dist/esm/matchContext.d.ts +20 -0
  52. package/dist/esm/matchContext.js +16 -0
  53. package/dist/esm/matchContext.js.map +1 -0
  54. package/dist/esm/not-found.d.ts +12 -0
  55. package/dist/esm/not-found.js +45 -0
  56. package/dist/esm/not-found.js.map +1 -0
  57. package/dist/esm/renderRouteNotFound.d.ts +11 -0
  58. package/dist/esm/renderRouteNotFound.js +19 -0
  59. package/dist/esm/renderRouteNotFound.js.map +1 -0
  60. package/dist/esm/route.d.ts +96 -0
  61. package/dist/esm/route.js +176 -0
  62. package/dist/esm/route.js.map +1 -0
  63. package/dist/esm/router.d.ts +69 -0
  64. package/dist/esm/router.js +14 -0
  65. package/dist/esm/router.js.map +1 -0
  66. package/dist/esm/routerContext.d.ts +21 -0
  67. package/dist/esm/routerContext.js +21 -0
  68. package/dist/esm/routerContext.js.map +1 -0
  69. package/dist/esm/scroll-restoration.d.ts +1 -0
  70. package/dist/esm/scroll-restoration.js +21 -0
  71. package/dist/esm/scroll-restoration.js.map +1 -0
  72. package/dist/esm/typePrimitives.d.ts +10 -0
  73. package/dist/esm/useBlocker.d.ts +66 -0
  74. package/dist/esm/useBlocker.js +295 -0
  75. package/dist/esm/useBlocker.js.map +1 -0
  76. package/dist/esm/useCanGoBack.d.ts +1 -0
  77. package/dist/esm/useCanGoBack.js +8 -0
  78. package/dist/esm/useCanGoBack.js.map +1 -0
  79. package/dist/esm/useLoaderData.d.ts +8 -0
  80. package/dist/esm/useLoaderData.js +14 -0
  81. package/dist/esm/useLoaderData.js.map +1 -0
  82. package/dist/esm/useLoaderDeps.d.ts +7 -0
  83. package/dist/esm/useLoaderDeps.js +17 -0
  84. package/dist/esm/useLoaderDeps.js.map +1 -0
  85. package/dist/esm/useLocation.d.ts +7 -0
  86. package/dist/esm/useLocation.js +10 -0
  87. package/dist/esm/useLocation.js.map +1 -0
  88. package/dist/esm/useMatch.d.ts +10 -0
  89. package/dist/esm/useMatch.js +39 -0
  90. package/dist/esm/useMatch.js.map +1 -0
  91. package/dist/esm/useNavigate.d.ts +5 -0
  92. package/dist/esm/useNavigate.js +29 -0
  93. package/dist/esm/useNavigate.js.map +1 -0
  94. package/dist/esm/useParams.d.ts +9 -0
  95. package/dist/esm/useParams.js +15 -0
  96. package/dist/esm/useParams.js.map +1 -0
  97. package/dist/esm/useRouteContext.d.ts +4 -0
  98. package/dist/esm/useRouteContext.js +11 -0
  99. package/dist/esm/useRouteContext.js.map +1 -0
  100. package/dist/esm/useRouter.d.ts +4 -0
  101. package/dist/esm/useRouter.js +12 -0
  102. package/dist/esm/useRouter.js.map +1 -0
  103. package/dist/esm/useRouterState.d.ts +8 -0
  104. package/dist/esm/useRouterState.js +20 -0
  105. package/dist/esm/useRouterState.js.map +1 -0
  106. package/dist/esm/useSearch.d.ts +9 -0
  107. package/dist/esm/useSearch.js +15 -0
  108. package/dist/esm/useSearch.js.map +1 -0
  109. package/dist/esm/utils.d.ts +40 -0
  110. package/dist/esm/utils.js +44 -0
  111. package/dist/esm/utils.js.map +1 -0
  112. package/dist/source/Asset.d.ts +2 -0
  113. package/dist/source/Asset.jsx +22 -0
  114. package/dist/source/Asset.jsx.map +1 -0
  115. package/dist/source/CatchBoundary.d.ts +19 -0
  116. package/dist/source/CatchBoundary.jsx +134 -0
  117. package/dist/source/CatchBoundary.jsx.map +1 -0
  118. package/dist/source/ClientOnly.d.ts +67 -0
  119. package/dist/source/ClientOnly.jsx +63 -0
  120. package/dist/source/ClientOnly.jsx.map +1 -0
  121. package/dist/source/HeadContent.d.ts +10 -0
  122. package/dist/source/HeadContent.jsx +133 -0
  123. package/dist/source/HeadContent.jsx.map +1 -0
  124. package/dist/source/Match.d.ts +25 -0
  125. package/dist/source/Match.jsx +316 -0
  126. package/dist/source/Match.jsx.map +1 -0
  127. package/dist/source/Matches.d.ts +39 -0
  128. package/dist/source/Matches.jsx +191 -0
  129. package/dist/source/Matches.jsx.map +1 -0
  130. package/dist/source/RouterProvider.d.ts +33 -0
  131. package/dist/source/RouterProvider.jsx +63 -0
  132. package/dist/source/RouterProvider.jsx.map +1 -0
  133. package/dist/source/SafeFragment.d.ts +4 -0
  134. package/dist/source/SafeFragment.jsx +10 -0
  135. package/dist/source/SafeFragment.jsx.map +1 -0
  136. package/dist/source/ScriptOnce.d.ts +5 -0
  137. package/dist/source/ScriptOnce.jsx +17 -0
  138. package/dist/source/ScriptOnce.jsx.map +1 -0
  139. package/dist/source/Scripts.d.ts +1 -0
  140. package/dist/source/Scripts.jsx +49 -0
  141. package/dist/source/Scripts.jsx.map +1 -0
  142. package/dist/source/ScrollRestoration.d.ts +14 -0
  143. package/dist/source/ScrollRestoration.jsx +37 -0
  144. package/dist/source/ScrollRestoration.jsx.map +1 -0
  145. package/dist/source/Transitioner.d.ts +2 -0
  146. package/dist/source/Transitioner.jsx +181 -0
  147. package/dist/source/Transitioner.jsx.map +1 -0
  148. package/dist/source/awaited.d.ts +12 -0
  149. package/dist/source/awaited.jsx +38 -0
  150. package/dist/source/awaited.jsx.map +1 -0
  151. package/dist/source/fileRoute.d.ts +54 -0
  152. package/dist/source/fileRoute.js +98 -0
  153. package/dist/source/fileRoute.js.map +1 -0
  154. package/dist/source/history.d.ts +8 -0
  155. package/dist/source/history.js +2 -0
  156. package/dist/source/history.js.map +1 -0
  157. package/dist/source/index.d.ts +51 -0
  158. package/dist/source/index.jsx +40 -0
  159. package/dist/source/index.jsx.map +1 -0
  160. package/dist/source/lazyRouteComponent.d.ts +8 -0
  161. package/dist/source/lazyRouteComponent.jsx +135 -0
  162. package/dist/source/lazyRouteComponent.jsx.map +1 -0
  163. package/dist/source/link.d.ts +61 -0
  164. package/dist/source/link.jsx +495 -0
  165. package/dist/source/link.jsx.map +1 -0
  166. package/dist/source/matchContext.d.ts +20 -0
  167. package/dist/source/matchContext.jsx +32 -0
  168. package/dist/source/matchContext.jsx.map +1 -0
  169. package/dist/source/not-found.d.ts +12 -0
  170. package/dist/source/not-found.jsx +48 -0
  171. package/dist/source/not-found.jsx.map +1 -0
  172. package/dist/source/renderRouteNotFound.d.ts +11 -0
  173. package/dist/source/renderRouteNotFound.jsx +24 -0
  174. package/dist/source/renderRouteNotFound.jsx.map +1 -0
  175. package/dist/source/route.d.ts +97 -0
  176. package/dist/source/route.js +167 -0
  177. package/dist/source/route.js.map +1 -0
  178. package/dist/source/router.d.ts +70 -0
  179. package/dist/source/router.js +10 -0
  180. package/dist/source/router.js.map +1 -0
  181. package/dist/source/routerContext.d.ts +21 -0
  182. package/dist/source/routerContext.jsx +37 -0
  183. package/dist/source/routerContext.jsx.map +1 -0
  184. package/dist/source/scroll-restoration.d.ts +1 -0
  185. package/dist/source/scroll-restoration.jsx +16 -0
  186. package/dist/source/scroll-restoration.jsx.map +1 -0
  187. package/dist/source/typePrimitives.d.ts +10 -0
  188. package/dist/source/typePrimitives.js +2 -0
  189. package/dist/source/typePrimitives.js.map +1 -0
  190. package/dist/source/useBlocker.d.ts +66 -0
  191. package/dist/source/useBlocker.jsx +308 -0
  192. package/dist/source/useBlocker.jsx.map +1 -0
  193. package/dist/source/useCanGoBack.d.ts +1 -0
  194. package/dist/source/useCanGoBack.js +5 -0
  195. package/dist/source/useCanGoBack.js.map +1 -0
  196. package/dist/source/useLoaderData.d.ts +8 -0
  197. package/dist/source/useLoaderData.jsx +11 -0
  198. package/dist/source/useLoaderData.jsx.map +1 -0
  199. package/dist/source/useLoaderDeps.d.ts +7 -0
  200. package/dist/source/useLoaderDeps.jsx +11 -0
  201. package/dist/source/useLoaderDeps.jsx.map +1 -0
  202. package/dist/source/useLocation.d.ts +7 -0
  203. package/dist/source/useLocation.jsx +7 -0
  204. package/dist/source/useLocation.jsx.map +1 -0
  205. package/dist/source/useMatch.d.ts +10 -0
  206. package/dist/source/useMatch.jsx +46 -0
  207. package/dist/source/useMatch.jsx.map +1 -0
  208. package/dist/source/useNavigate.d.ts +5 -0
  209. package/dist/source/useNavigate.jsx +18 -0
  210. package/dist/source/useNavigate.jsx.map +1 -0
  211. package/dist/source/useParams.d.ts +9 -0
  212. package/dist/source/useParams.jsx +12 -0
  213. package/dist/source/useParams.jsx.map +1 -0
  214. package/dist/source/useRouteContext.d.ts +4 -0
  215. package/dist/source/useRouteContext.js +8 -0
  216. package/dist/source/useRouteContext.js.map +1 -0
  217. package/dist/source/useRouter.d.ts +4 -0
  218. package/dist/source/useRouter.jsx +9 -0
  219. package/dist/source/useRouter.jsx.map +1 -0
  220. package/dist/source/useRouterState.d.ts +8 -0
  221. package/dist/source/useRouterState.jsx +19 -0
  222. package/dist/source/useRouterState.jsx.map +1 -0
  223. package/dist/source/useSearch.d.ts +9 -0
  224. package/dist/source/useSearch.jsx +12 -0
  225. package/dist/source/useSearch.jsx.map +1 -0
  226. package/dist/source/utils.d.ts +40 -0
  227. package/dist/source/utils.js +78 -0
  228. package/dist/source/utils.js.map +1 -0
  229. package/package.json +77 -7
  230. package/src/Asset.tsx +23 -0
  231. package/src/CatchBoundary.tsx +186 -0
  232. package/src/ClientOnly.tsx +75 -0
  233. package/src/HeadContent.tsx +159 -0
  234. package/src/Match.tsx +415 -0
  235. package/src/Matches.tsx +349 -0
  236. package/src/RouterProvider.tsx +117 -0
  237. package/src/SafeFragment.tsx +10 -0
  238. package/src/ScriptOnce.tsx +30 -0
  239. package/src/Scripts.tsx +65 -0
  240. package/src/ScrollRestoration.tsx +69 -0
  241. package/src/Transitioner.tsx +213 -0
  242. package/src/awaited.tsx +54 -0
  243. package/src/fileRoute.ts +271 -0
  244. package/src/history.ts +9 -0
  245. package/src/index.tsx +346 -0
  246. package/src/lazyRouteComponent.tsx +173 -0
  247. package/src/link.tsx +765 -0
  248. package/src/matchContext.tsx +41 -0
  249. package/src/not-found.tsx +55 -0
  250. package/src/renderRouteNotFound.tsx +35 -0
  251. package/src/route.ts +658 -0
  252. package/src/router.ts +103 -0
  253. package/src/routerContext.tsx +53 -0
  254. package/src/scroll-restoration.tsx +29 -0
  255. package/src/typePrimitives.ts +74 -0
  256. package/src/useBlocker.tsx +501 -0
  257. package/src/useCanGoBack.ts +5 -0
  258. package/src/useLoaderData.tsx +50 -0
  259. package/src/useLoaderDeps.tsx +46 -0
  260. package/src/useLocation.tsx +30 -0
  261. package/src/useMatch.tsx +127 -0
  262. package/src/useNavigate.tsx +40 -0
  263. package/src/useParams.tsx +71 -0
  264. package/src/useRouteContext.ts +31 -0
  265. package/src/useRouter.tsx +15 -0
  266. package/src/useRouterState.tsx +43 -0
  267. package/src/useSearch.tsx +71 -0
  268. package/src/utils.ts +111 -0
@@ -0,0 +1,501 @@
1
+ import * as Vue from 'vue'
2
+ import { useRouter } from './useRouter'
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'
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 ? Vue.Ref<BlockerResolver<TRouter>> : void
137
+
138
+ /**
139
+ * @deprecated Use the shouldBlockFn property instead
140
+ */
141
+ export function useBlocker(
142
+ blockerFnOrOpts?: LegacyBlockerOpts,
143
+ ): Vue.Ref<BlockerResolver>
144
+
145
+ /**
146
+ * @deprecated Use the UseBlockerOpts object syntax instead
147
+ */
148
+ export function useBlocker(
149
+ blockerFn?: LegacyBlockerFn,
150
+ condition?: boolean | any,
151
+ ): Vue.Ref<BlockerResolver>
152
+
153
+ export function useBlocker(
154
+ opts?: UseBlockerOpts | LegacyBlockerOpts | LegacyBlockerFn,
155
+ condition?: boolean | any,
156
+ ): Vue.Ref<BlockerResolver> | void {
157
+ const {
158
+ shouldBlockFn,
159
+ enableBeforeUnload = true,
160
+ disabled = false,
161
+ withResolver = false,
162
+ } = _resolveBlockerOpts(opts, condition)
163
+
164
+ const router = useRouter()
165
+ const { history } = router
166
+
167
+ const resolver = Vue.ref<BlockerResolver>({
168
+ status: 'idle',
169
+ current: undefined,
170
+ next: undefined,
171
+ action: undefined,
172
+ proceed: undefined,
173
+ reset: undefined,
174
+ })
175
+
176
+ Vue.watchEffect((onCleanup) => {
177
+ const blockerFnComposed = async (blockerFnArgs: BlockerFnArgs) => {
178
+ function getLocation(
179
+ location: HistoryLocation,
180
+ ): AnyShouldBlockFnLocation {
181
+ const parsedLocation = router.parseLocation(location)
182
+ const matchedRoutes = router.getMatchedRoutes(parsedLocation.pathname)
183
+ if (matchedRoutes.foundRoute === undefined) {
184
+ return {
185
+ routeId: '__notFound__',
186
+ fullPath: parsedLocation.pathname,
187
+ pathname: parsedLocation.pathname,
188
+ params: matchedRoutes.routeParams,
189
+ search: parsedLocation.search,
190
+ }
191
+ }
192
+ return {
193
+ routeId: matchedRoutes.foundRoute.id,
194
+ fullPath: matchedRoutes.foundRoute.fullPath,
195
+ pathname: parsedLocation.pathname,
196
+ params: matchedRoutes.routeParams,
197
+ search: parsedLocation.search,
198
+ }
199
+ }
200
+
201
+ const current = getLocation(blockerFnArgs.currentLocation)
202
+ const next = getLocation(blockerFnArgs.nextLocation)
203
+
204
+ // Allow navigation away from 404 pages to valid routes
205
+ if (
206
+ current.routeId === '__notFound__' &&
207
+ next.routeId !== '__notFound__'
208
+ ) {
209
+ return false
210
+ }
211
+
212
+ const shouldBlock = await shouldBlockFn({
213
+ action: blockerFnArgs.action,
214
+ current,
215
+ next,
216
+ })
217
+ if (!withResolver) {
218
+ return shouldBlock
219
+ }
220
+
221
+ if (!shouldBlock) {
222
+ return false
223
+ }
224
+
225
+ const promise = new Promise<boolean>((resolve) => {
226
+ resolver.value = {
227
+ status: 'blocked',
228
+ current,
229
+ next,
230
+ action: blockerFnArgs.action,
231
+ proceed: () => resolve(false),
232
+ reset: () => resolve(true),
233
+ }
234
+ })
235
+
236
+ const canNavigateAsync = await promise
237
+ resolver.value = {
238
+ status: 'idle',
239
+ current: undefined,
240
+ next: undefined,
241
+ action: undefined,
242
+ proceed: undefined,
243
+ reset: undefined,
244
+ }
245
+
246
+ return canNavigateAsync
247
+ }
248
+
249
+ if (disabled) {
250
+ return
251
+ }
252
+
253
+ const unsubscribe = history.block({
254
+ blockerFn: blockerFnComposed,
255
+ enableBeforeUnload,
256
+ })
257
+
258
+ onCleanup(() => {
259
+ if (unsubscribe) unsubscribe()
260
+ })
261
+ })
262
+
263
+ return withResolver ? resolver : undefined
264
+ }
265
+
266
+ const _resolvePromptBlockerArgs = (
267
+ props: PromptProps | LegacyPromptProps,
268
+ ): UseBlockerOpts => {
269
+ if ('shouldBlockFn' in props) {
270
+ return { ...props }
271
+ }
272
+
273
+ const shouldBlock = Boolean(props.condition ?? true)
274
+ const fn = props.blockerFn
275
+
276
+ const _customBlockerFn = async () => {
277
+ if (shouldBlock && fn !== undefined) {
278
+ return await fn()
279
+ }
280
+ return shouldBlock
281
+ }
282
+
283
+ return {
284
+ shouldBlockFn: _customBlockerFn,
285
+ enableBeforeUnload: shouldBlock,
286
+ withResolver: fn === undefined,
287
+ }
288
+ }
289
+
290
+ // Internal Block implementation as a proper Vue component for reactivity
291
+ const BlockImpl = Vue.defineComponent({
292
+ name: 'Block',
293
+ props: {
294
+ shouldBlockFn: {
295
+ type: Function as Vue.PropType<ShouldBlockFn<any>>,
296
+ required: false,
297
+ },
298
+ enableBeforeUnload: {
299
+ type: [Boolean, Function] as Vue.PropType<boolean | (() => boolean)>,
300
+ default: true,
301
+ },
302
+ disabled: {
303
+ type: Boolean,
304
+ default: false,
305
+ },
306
+ withResolver: {
307
+ type: Boolean,
308
+ default: false,
309
+ },
310
+ // Legacy props
311
+ blockerFn: {
312
+ type: Function as Vue.PropType<LegacyBlockerFn>,
313
+ required: false,
314
+ },
315
+ condition: {
316
+ type: [Boolean, Object] as Vue.PropType<boolean | any>,
317
+ required: false,
318
+ },
319
+ },
320
+ setup(props, { slots }) {
321
+ // Create a computed that resolves the blocker args reactively
322
+ const blockerArgs = Vue.computed<UseBlockerOpts>(() => {
323
+ if (props.shouldBlockFn) {
324
+ return {
325
+ shouldBlockFn: props.shouldBlockFn,
326
+ enableBeforeUnload: props.enableBeforeUnload,
327
+ disabled: props.disabled,
328
+ withResolver: props.withResolver,
329
+ }
330
+ }
331
+
332
+ // Legacy handling
333
+ const shouldBlock = Boolean(props.condition ?? true)
334
+ const fn = props.blockerFn
335
+
336
+ const _customBlockerFn = async () => {
337
+ if (shouldBlock && fn !== undefined) {
338
+ return await fn()
339
+ }
340
+ return shouldBlock
341
+ }
342
+
343
+ return {
344
+ shouldBlockFn: _customBlockerFn,
345
+ enableBeforeUnload: shouldBlock,
346
+ disabled: props.disabled,
347
+ withResolver: fn === undefined,
348
+ }
349
+ })
350
+
351
+ // Use a reactive useBlocker that re-subscribes when args change
352
+ const router = useRouter()
353
+ const { history } = router
354
+
355
+ const resolver = Vue.ref<BlockerResolver>({
356
+ status: 'idle',
357
+ current: undefined,
358
+ next: undefined,
359
+ action: undefined,
360
+ proceed: undefined,
361
+ reset: undefined,
362
+ })
363
+
364
+ Vue.watchEffect((onCleanup) => {
365
+ const args = blockerArgs.value
366
+
367
+ if (args.disabled) {
368
+ return
369
+ }
370
+
371
+ const blockerFnComposed = async (blockerFnArgs: BlockerFnArgs) => {
372
+ function getLocation(
373
+ location: HistoryLocation,
374
+ ): AnyShouldBlockFnLocation {
375
+ const parsedLocation = router.parseLocation(location)
376
+ const matchedRoutes = router.getMatchedRoutes(parsedLocation.pathname)
377
+ if (matchedRoutes.foundRoute === undefined) {
378
+ return {
379
+ routeId: '__notFound__',
380
+ fullPath: parsedLocation.pathname,
381
+ pathname: parsedLocation.pathname,
382
+ params: matchedRoutes.routeParams,
383
+ search: parsedLocation.search,
384
+ }
385
+ }
386
+ return {
387
+ routeId: matchedRoutes.foundRoute.id,
388
+ fullPath: matchedRoutes.foundRoute.fullPath,
389
+ pathname: parsedLocation.pathname,
390
+ params: matchedRoutes.routeParams,
391
+ search: parsedLocation.search,
392
+ }
393
+ }
394
+
395
+ const current = getLocation(blockerFnArgs.currentLocation)
396
+ const next = getLocation(blockerFnArgs.nextLocation)
397
+
398
+ // Allow navigation away from 404 pages to valid routes
399
+ if (
400
+ current.routeId === '__notFound__' &&
401
+ next.routeId !== '__notFound__'
402
+ ) {
403
+ return false
404
+ }
405
+
406
+ const shouldBlock = await args.shouldBlockFn({
407
+ action: blockerFnArgs.action,
408
+ current,
409
+ next,
410
+ })
411
+ if (!args.withResolver) {
412
+ return shouldBlock
413
+ }
414
+
415
+ if (!shouldBlock) {
416
+ return false
417
+ }
418
+
419
+ const promise = new Promise<boolean>((resolve) => {
420
+ resolver.value = {
421
+ status: 'blocked',
422
+ current,
423
+ next,
424
+ action: blockerFnArgs.action,
425
+ proceed: () => resolve(false),
426
+ reset: () => resolve(true),
427
+ }
428
+ })
429
+
430
+ const canNavigateAsync = await promise
431
+ resolver.value = {
432
+ status: 'idle',
433
+ current: undefined,
434
+ next: undefined,
435
+ action: undefined,
436
+ proceed: undefined,
437
+ reset: undefined,
438
+ }
439
+
440
+ return canNavigateAsync
441
+ }
442
+
443
+ const unsubscribe = history.block({
444
+ blockerFn: blockerFnComposed,
445
+ enableBeforeUnload: args.enableBeforeUnload,
446
+ })
447
+
448
+ onCleanup(() => {
449
+ if (unsubscribe) unsubscribe()
450
+ })
451
+ })
452
+
453
+ return () => {
454
+ const defaultSlot = slots.default
455
+ if (!defaultSlot) {
456
+ return Vue.h(Vue.Fragment, null)
457
+ }
458
+
459
+ // If slot is a function that takes resolver, call it with the resolver
460
+ const slotContent = defaultSlot(resolver.value as any)
461
+ return Vue.h(Vue.Fragment, null, slotContent)
462
+ }
463
+ },
464
+ })
465
+
466
+ export function Block<
467
+ TRouter extends AnyRouter = RegisteredRouter,
468
+ TWithResolver extends boolean = boolean,
469
+ >(opts: PromptProps<TRouter, TWithResolver>): Vue.VNode
470
+
471
+ /**
472
+ * @deprecated Use the UseBlockerOpts property instead
473
+ */
474
+ export function Block(opts: LegacyPromptProps): Vue.VNode
475
+
476
+ export function Block(opts: PromptProps | LegacyPromptProps): Vue.VNode {
477
+ const { children, ...rest } = opts
478
+
479
+ // Convert children to slot format for the component
480
+ const slots = children
481
+ ? typeof children === 'function'
482
+ ? { default: children }
483
+ : { default: () => children }
484
+ : undefined
485
+
486
+ return Vue.h(BlockImpl, rest as any, slots)
487
+ }
488
+
489
+ type LegacyPromptProps = {
490
+ blockerFn?: LegacyBlockerFn
491
+ condition?: boolean | any
492
+ children?: Vue.VNode | ((params: BlockerResolver) => Vue.VNode)
493
+ }
494
+
495
+ type PromptProps<
496
+ TRouter extends AnyRouter = RegisteredRouter,
497
+ TWithResolver extends boolean = boolean,
498
+ TParams = TWithResolver extends true ? BlockerResolver<TRouter> : void,
499
+ > = UseBlockerOpts<TRouter, TWithResolver> & {
500
+ children?: Vue.VNode | ((params: TParams) => Vue.VNode)
501
+ }
@@ -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,50 @@
1
+ import { useMatch } from './useMatch'
2
+ import type * as Vue from 'vue'
3
+ import type {
4
+ AnyRouter,
5
+ RegisteredRouter,
6
+ ResolveUseLoaderData,
7
+ StrictOrFrom,
8
+ UseLoaderDataResult,
9
+ } from '@tanstack/router-core'
10
+
11
+ export interface UseLoaderDataBaseOptions<
12
+ TRouter extends AnyRouter,
13
+ TFrom,
14
+ TStrict extends boolean,
15
+ TSelected,
16
+ > {
17
+ select?: (match: ResolveUseLoaderData<TRouter, TFrom, TStrict>) => TSelected
18
+ }
19
+
20
+ export type UseLoaderDataOptions<
21
+ TRouter extends AnyRouter,
22
+ TFrom extends string | undefined,
23
+ TStrict extends boolean,
24
+ TSelected,
25
+ > = StrictOrFrom<TRouter, TFrom, TStrict> &
26
+ UseLoaderDataBaseOptions<TRouter, TFrom, TStrict, TSelected>
27
+
28
+ export type UseLoaderDataRoute<out TId> = <
29
+ TRouter extends AnyRouter = RegisteredRouter,
30
+ TSelected = unknown,
31
+ >(
32
+ opts?: UseLoaderDataBaseOptions<TRouter, TId, true, TSelected>,
33
+ ) => Vue.Ref<UseLoaderDataResult<TRouter, TId, true, TSelected>>
34
+
35
+ export function useLoaderData<
36
+ TRouter extends AnyRouter = RegisteredRouter,
37
+ const TFrom extends string | undefined = undefined,
38
+ TStrict extends boolean = true,
39
+ TSelected = unknown,
40
+ >(
41
+ opts: UseLoaderDataOptions<TRouter, TFrom, TStrict, TSelected>,
42
+ ): Vue.Ref<UseLoaderDataResult<TRouter, TFrom, TStrict, TSelected>> {
43
+ return useMatch({
44
+ from: opts.from!,
45
+ strict: opts.strict,
46
+ select: (s: any) => {
47
+ return opts.select ? opts.select(s.loaderData) : s.loaderData
48
+ },
49
+ } as any) as any
50
+ }
@@ -0,0 +1,46 @@
1
+ import { useMatch } from './useMatch'
2
+ import type {
3
+ AnyRouter,
4
+ RegisteredRouter,
5
+ ResolveUseLoaderDeps,
6
+ StrictOrFrom,
7
+ UseLoaderDepsResult,
8
+ } from '@tanstack/router-core'
9
+
10
+ export interface UseLoaderDepsBaseOptions<
11
+ TRouter extends AnyRouter,
12
+ TFrom,
13
+ TSelected,
14
+ > {
15
+ select?: (deps: ResolveUseLoaderDeps<TRouter, TFrom>) => TSelected
16
+ }
17
+
18
+ export type UseLoaderDepsOptions<
19
+ TRouter extends AnyRouter,
20
+ TFrom extends string | undefined,
21
+ TSelected,
22
+ > = StrictOrFrom<TRouter, TFrom> &
23
+ UseLoaderDepsBaseOptions<TRouter, TFrom, TSelected>
24
+
25
+ export type UseLoaderDepsRoute<out TId> = <
26
+ TRouter extends AnyRouter = RegisteredRouter,
27
+ TSelected = unknown,
28
+ >(
29
+ opts?: UseLoaderDepsBaseOptions<TRouter, TId, TSelected>,
30
+ ) => UseLoaderDepsResult<TRouter, TId, TSelected>
31
+
32
+ export function useLoaderDeps<
33
+ TRouter extends AnyRouter = RegisteredRouter,
34
+ const TFrom extends string | undefined = undefined,
35
+ TSelected = unknown,
36
+ >(
37
+ opts: UseLoaderDepsOptions<TRouter, TFrom, TSelected>,
38
+ ): UseLoaderDepsResult<TRouter, TFrom, TSelected> {
39
+ const { select, ...rest } = opts
40
+ return useMatch({
41
+ ...rest,
42
+ select: (s) => {
43
+ return select ? select(s.loaderDeps) : s.loaderDeps
44
+ },
45
+ }) as UseLoaderDepsResult<TRouter, TFrom, TSelected>
46
+ }
@@ -0,0 +1,30 @@
1
+ import { useRouterState } from './useRouterState'
2
+ import type {
3
+ AnyRouter,
4
+ RegisteredRouter,
5
+ RouterState,
6
+ } from '@tanstack/router-core'
7
+ import type * as Vue from 'vue'
8
+
9
+ export interface UseLocationBaseOptions<TRouter extends AnyRouter, TSelected> {
10
+ select?: (state: RouterState<TRouter['routeTree']>['location']) => TSelected
11
+ }
12
+
13
+ export type UseLocationResult<
14
+ TRouter extends AnyRouter,
15
+ TSelected,
16
+ > = unknown extends TSelected
17
+ ? RouterState<TRouter['routeTree']>['location']
18
+ : TSelected
19
+
20
+ export function useLocation<
21
+ TRouter extends AnyRouter = RegisteredRouter,
22
+ TSelected = unknown,
23
+ >(
24
+ opts?: UseLocationBaseOptions<TRouter, TSelected>,
25
+ ): Vue.Ref<UseLocationResult<TRouter, TSelected>> {
26
+ return useRouterState({
27
+ select: (state: any) =>
28
+ opts?.select ? opts.select(state.location) : state.location,
29
+ } as any) as Vue.Ref<UseLocationResult<TRouter, TSelected>>
30
+ }