@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.
- package/LICENSE +21 -0
- package/README.md +66 -45
- package/dist/esm/Asset.d.ts +2 -0
- package/dist/esm/Asset.js +33 -0
- package/dist/esm/Asset.js.map +1 -0
- package/dist/esm/CatchBoundary.d.ts +19 -0
- package/dist/esm/CatchBoundary.js +135 -0
- package/dist/esm/CatchBoundary.js.map +1 -0
- package/dist/esm/ClientOnly.d.ts +67 -0
- package/dist/esm/HeadContent.d.ts +10 -0
- package/dist/esm/HeadContent.js +116 -0
- package/dist/esm/HeadContent.js.map +1 -0
- package/dist/esm/Match.d.ts +25 -0
- package/dist/esm/Match.js +262 -0
- package/dist/esm/Match.js.map +1 -0
- package/dist/esm/Matches.d.ts +39 -0
- package/dist/esm/Matches.js +186 -0
- package/dist/esm/Matches.js.map +1 -0
- package/dist/esm/RouterProvider.d.ts +33 -0
- package/dist/esm/RouterProvider.js +65 -0
- package/dist/esm/RouterProvider.js.map +1 -0
- package/dist/esm/SafeFragment.d.ts +4 -0
- package/dist/esm/ScriptOnce.d.ts +5 -0
- package/dist/esm/ScriptOnce.js +21 -0
- package/dist/esm/ScriptOnce.js.map +1 -0
- package/dist/esm/Scripts.d.ts +1 -0
- package/dist/esm/Scripts.js +46 -0
- package/dist/esm/Scripts.js.map +1 -0
- package/dist/esm/ScrollRestoration.d.ts +14 -0
- package/dist/esm/ScrollRestoration.js +36 -0
- package/dist/esm/ScrollRestoration.js.map +1 -0
- package/dist/esm/Transitioner.d.ts +2 -0
- package/dist/esm/Transitioner.js +154 -0
- package/dist/esm/Transitioner.js.map +1 -0
- package/dist/esm/awaited.d.ts +12 -0
- package/dist/esm/awaited.js +40 -0
- package/dist/esm/awaited.js.map +1 -0
- package/dist/esm/fileRoute.d.ts +54 -0
- package/dist/esm/fileRoute.js +103 -0
- package/dist/esm/fileRoute.js.map +1 -0
- package/dist/esm/history.d.ts +8 -0
- package/dist/esm/index.d.ts +51 -0
- package/dist/esm/index.js +138 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/lazyRouteComponent.d.ts +8 -0
- package/dist/esm/lazyRouteComponent.js +106 -0
- package/dist/esm/lazyRouteComponent.js.map +1 -0
- package/dist/esm/link.d.ts +61 -0
- package/dist/esm/link.js +376 -0
- package/dist/esm/link.js.map +1 -0
- package/dist/esm/matchContext.d.ts +20 -0
- package/dist/esm/matchContext.js +16 -0
- package/dist/esm/matchContext.js.map +1 -0
- package/dist/esm/not-found.d.ts +12 -0
- package/dist/esm/not-found.js +45 -0
- package/dist/esm/not-found.js.map +1 -0
- package/dist/esm/renderRouteNotFound.d.ts +11 -0
- package/dist/esm/renderRouteNotFound.js +19 -0
- package/dist/esm/renderRouteNotFound.js.map +1 -0
- package/dist/esm/route.d.ts +96 -0
- package/dist/esm/route.js +176 -0
- package/dist/esm/route.js.map +1 -0
- package/dist/esm/router.d.ts +69 -0
- package/dist/esm/router.js +14 -0
- package/dist/esm/router.js.map +1 -0
- package/dist/esm/routerContext.d.ts +21 -0
- package/dist/esm/routerContext.js +21 -0
- package/dist/esm/routerContext.js.map +1 -0
- package/dist/esm/scroll-restoration.d.ts +1 -0
- package/dist/esm/scroll-restoration.js +21 -0
- package/dist/esm/scroll-restoration.js.map +1 -0
- package/dist/esm/typePrimitives.d.ts +10 -0
- package/dist/esm/useBlocker.d.ts +66 -0
- package/dist/esm/useBlocker.js +295 -0
- package/dist/esm/useBlocker.js.map +1 -0
- package/dist/esm/useCanGoBack.d.ts +1 -0
- package/dist/esm/useCanGoBack.js +8 -0
- package/dist/esm/useCanGoBack.js.map +1 -0
- package/dist/esm/useLoaderData.d.ts +8 -0
- package/dist/esm/useLoaderData.js +14 -0
- package/dist/esm/useLoaderData.js.map +1 -0
- package/dist/esm/useLoaderDeps.d.ts +7 -0
- package/dist/esm/useLoaderDeps.js +17 -0
- package/dist/esm/useLoaderDeps.js.map +1 -0
- package/dist/esm/useLocation.d.ts +7 -0
- package/dist/esm/useLocation.js +10 -0
- package/dist/esm/useLocation.js.map +1 -0
- package/dist/esm/useMatch.d.ts +10 -0
- package/dist/esm/useMatch.js +39 -0
- package/dist/esm/useMatch.js.map +1 -0
- package/dist/esm/useNavigate.d.ts +5 -0
- package/dist/esm/useNavigate.js +29 -0
- package/dist/esm/useNavigate.js.map +1 -0
- package/dist/esm/useParams.d.ts +9 -0
- package/dist/esm/useParams.js +15 -0
- package/dist/esm/useParams.js.map +1 -0
- package/dist/esm/useRouteContext.d.ts +4 -0
- package/dist/esm/useRouteContext.js +11 -0
- package/dist/esm/useRouteContext.js.map +1 -0
- package/dist/esm/useRouter.d.ts +4 -0
- package/dist/esm/useRouter.js +12 -0
- package/dist/esm/useRouter.js.map +1 -0
- package/dist/esm/useRouterState.d.ts +8 -0
- package/dist/esm/useRouterState.js +20 -0
- package/dist/esm/useRouterState.js.map +1 -0
- package/dist/esm/useSearch.d.ts +9 -0
- package/dist/esm/useSearch.js +15 -0
- package/dist/esm/useSearch.js.map +1 -0
- package/dist/esm/utils.d.ts +40 -0
- package/dist/esm/utils.js +44 -0
- package/dist/esm/utils.js.map +1 -0
- package/dist/source/Asset.d.ts +2 -0
- package/dist/source/Asset.jsx +22 -0
- package/dist/source/Asset.jsx.map +1 -0
- package/dist/source/CatchBoundary.d.ts +19 -0
- package/dist/source/CatchBoundary.jsx +134 -0
- package/dist/source/CatchBoundary.jsx.map +1 -0
- package/dist/source/ClientOnly.d.ts +67 -0
- package/dist/source/ClientOnly.jsx +63 -0
- package/dist/source/ClientOnly.jsx.map +1 -0
- package/dist/source/HeadContent.d.ts +10 -0
- package/dist/source/HeadContent.jsx +133 -0
- package/dist/source/HeadContent.jsx.map +1 -0
- package/dist/source/Match.d.ts +25 -0
- package/dist/source/Match.jsx +316 -0
- package/dist/source/Match.jsx.map +1 -0
- package/dist/source/Matches.d.ts +39 -0
- package/dist/source/Matches.jsx +191 -0
- package/dist/source/Matches.jsx.map +1 -0
- package/dist/source/RouterProvider.d.ts +33 -0
- package/dist/source/RouterProvider.jsx +63 -0
- package/dist/source/RouterProvider.jsx.map +1 -0
- package/dist/source/SafeFragment.d.ts +4 -0
- package/dist/source/SafeFragment.jsx +10 -0
- package/dist/source/SafeFragment.jsx.map +1 -0
- package/dist/source/ScriptOnce.d.ts +5 -0
- package/dist/source/ScriptOnce.jsx +17 -0
- package/dist/source/ScriptOnce.jsx.map +1 -0
- package/dist/source/Scripts.d.ts +1 -0
- package/dist/source/Scripts.jsx +49 -0
- package/dist/source/Scripts.jsx.map +1 -0
- package/dist/source/ScrollRestoration.d.ts +14 -0
- package/dist/source/ScrollRestoration.jsx +37 -0
- package/dist/source/ScrollRestoration.jsx.map +1 -0
- package/dist/source/Transitioner.d.ts +2 -0
- package/dist/source/Transitioner.jsx +181 -0
- package/dist/source/Transitioner.jsx.map +1 -0
- package/dist/source/awaited.d.ts +12 -0
- package/dist/source/awaited.jsx +38 -0
- package/dist/source/awaited.jsx.map +1 -0
- package/dist/source/fileRoute.d.ts +54 -0
- package/dist/source/fileRoute.js +98 -0
- package/dist/source/fileRoute.js.map +1 -0
- package/dist/source/history.d.ts +8 -0
- package/dist/source/history.js +2 -0
- package/dist/source/history.js.map +1 -0
- package/dist/source/index.d.ts +51 -0
- package/dist/source/index.jsx +40 -0
- package/dist/source/index.jsx.map +1 -0
- package/dist/source/lazyRouteComponent.d.ts +8 -0
- package/dist/source/lazyRouteComponent.jsx +135 -0
- package/dist/source/lazyRouteComponent.jsx.map +1 -0
- package/dist/source/link.d.ts +61 -0
- package/dist/source/link.jsx +495 -0
- package/dist/source/link.jsx.map +1 -0
- package/dist/source/matchContext.d.ts +20 -0
- package/dist/source/matchContext.jsx +32 -0
- package/dist/source/matchContext.jsx.map +1 -0
- package/dist/source/not-found.d.ts +12 -0
- package/dist/source/not-found.jsx +48 -0
- package/dist/source/not-found.jsx.map +1 -0
- package/dist/source/renderRouteNotFound.d.ts +11 -0
- package/dist/source/renderRouteNotFound.jsx +24 -0
- package/dist/source/renderRouteNotFound.jsx.map +1 -0
- package/dist/source/route.d.ts +97 -0
- package/dist/source/route.js +167 -0
- package/dist/source/route.js.map +1 -0
- package/dist/source/router.d.ts +70 -0
- package/dist/source/router.js +10 -0
- package/dist/source/router.js.map +1 -0
- package/dist/source/routerContext.d.ts +21 -0
- package/dist/source/routerContext.jsx +37 -0
- package/dist/source/routerContext.jsx.map +1 -0
- package/dist/source/scroll-restoration.d.ts +1 -0
- package/dist/source/scroll-restoration.jsx +16 -0
- package/dist/source/scroll-restoration.jsx.map +1 -0
- package/dist/source/typePrimitives.d.ts +10 -0
- package/dist/source/typePrimitives.js +2 -0
- package/dist/source/typePrimitives.js.map +1 -0
- package/dist/source/useBlocker.d.ts +66 -0
- package/dist/source/useBlocker.jsx +308 -0
- package/dist/source/useBlocker.jsx.map +1 -0
- package/dist/source/useCanGoBack.d.ts +1 -0
- package/dist/source/useCanGoBack.js +5 -0
- package/dist/source/useCanGoBack.js.map +1 -0
- package/dist/source/useLoaderData.d.ts +8 -0
- package/dist/source/useLoaderData.jsx +11 -0
- package/dist/source/useLoaderData.jsx.map +1 -0
- package/dist/source/useLoaderDeps.d.ts +7 -0
- package/dist/source/useLoaderDeps.jsx +11 -0
- package/dist/source/useLoaderDeps.jsx.map +1 -0
- package/dist/source/useLocation.d.ts +7 -0
- package/dist/source/useLocation.jsx +7 -0
- package/dist/source/useLocation.jsx.map +1 -0
- package/dist/source/useMatch.d.ts +10 -0
- package/dist/source/useMatch.jsx +46 -0
- package/dist/source/useMatch.jsx.map +1 -0
- package/dist/source/useNavigate.d.ts +5 -0
- package/dist/source/useNavigate.jsx +18 -0
- package/dist/source/useNavigate.jsx.map +1 -0
- package/dist/source/useParams.d.ts +9 -0
- package/dist/source/useParams.jsx +12 -0
- package/dist/source/useParams.jsx.map +1 -0
- package/dist/source/useRouteContext.d.ts +4 -0
- package/dist/source/useRouteContext.js +8 -0
- package/dist/source/useRouteContext.js.map +1 -0
- package/dist/source/useRouter.d.ts +4 -0
- package/dist/source/useRouter.jsx +9 -0
- package/dist/source/useRouter.jsx.map +1 -0
- package/dist/source/useRouterState.d.ts +8 -0
- package/dist/source/useRouterState.jsx +19 -0
- package/dist/source/useRouterState.jsx.map +1 -0
- package/dist/source/useSearch.d.ts +9 -0
- package/dist/source/useSearch.jsx +12 -0
- package/dist/source/useSearch.jsx.map +1 -0
- package/dist/source/utils.d.ts +40 -0
- package/dist/source/utils.js +78 -0
- package/dist/source/utils.js.map +1 -0
- package/package.json +77 -7
- package/src/Asset.tsx +23 -0
- package/src/CatchBoundary.tsx +186 -0
- package/src/ClientOnly.tsx +75 -0
- package/src/HeadContent.tsx +159 -0
- package/src/Match.tsx +415 -0
- package/src/Matches.tsx +349 -0
- package/src/RouterProvider.tsx +117 -0
- package/src/SafeFragment.tsx +10 -0
- package/src/ScriptOnce.tsx +30 -0
- package/src/Scripts.tsx +65 -0
- package/src/ScrollRestoration.tsx +69 -0
- package/src/Transitioner.tsx +213 -0
- package/src/awaited.tsx +54 -0
- package/src/fileRoute.ts +271 -0
- package/src/history.ts +9 -0
- package/src/index.tsx +346 -0
- package/src/lazyRouteComponent.tsx +173 -0
- package/src/link.tsx +765 -0
- package/src/matchContext.tsx +41 -0
- package/src/not-found.tsx +55 -0
- package/src/renderRouteNotFound.tsx +35 -0
- package/src/route.ts +658 -0
- package/src/router.ts +103 -0
- package/src/routerContext.tsx +53 -0
- package/src/scroll-restoration.tsx +29 -0
- package/src/typePrimitives.ts +74 -0
- package/src/useBlocker.tsx +501 -0
- package/src/useCanGoBack.ts +5 -0
- package/src/useLoaderData.tsx +50 -0
- package/src/useLoaderDeps.tsx +46 -0
- package/src/useLocation.tsx +30 -0
- package/src/useMatch.tsx +127 -0
- package/src/useNavigate.tsx +40 -0
- package/src/useParams.tsx +71 -0
- package/src/useRouteContext.ts +31 -0
- package/src/useRouter.tsx +15 -0
- package/src/useRouterState.tsx +43 -0
- package/src/useSearch.tsx +71 -0
- 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,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
|
+
}
|