@tanstack/react-router 0.0.1-beta.9 → 1.0.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.
- package/LICENSE +21 -0
- package/build/cjs/CatchBoundary.js +128 -0
- package/build/cjs/CatchBoundary.js.map +1 -0
- package/build/cjs/Matches.js +233 -0
- package/build/cjs/Matches.js.map +1 -0
- package/build/cjs/RouterProvider.js +172 -0
- package/build/cjs/RouterProvider.js.map +1 -0
- package/build/cjs/_virtual/_rollupPluginBabelHelpers.js +2 -22
- package/build/cjs/_virtual/_rollupPluginBabelHelpers.js.map +1 -1
- package/build/cjs/awaited.js +43 -0
- package/build/cjs/awaited.js.map +1 -0
- package/build/cjs/defer.js +37 -0
- package/build/cjs/defer.js.map +1 -0
- package/build/cjs/fileRoute.js +27 -0
- package/build/cjs/fileRoute.js.map +1 -0
- package/build/cjs/index.js +130 -0
- package/build/cjs/index.js.map +1 -0
- package/build/cjs/lazyRouteComponent.js +54 -0
- package/build/cjs/lazyRouteComponent.js.map +1 -0
- package/build/cjs/link.js +223 -0
- package/build/cjs/link.js.map +1 -0
- package/build/cjs/path.js +214 -0
- package/build/cjs/path.js.map +1 -0
- package/build/cjs/qss.js +63 -0
- package/build/cjs/qss.js.map +1 -0
- package/build/cjs/redirects.js +28 -0
- package/build/cjs/redirects.js.map +1 -0
- package/build/cjs/route.js +191 -0
- package/build/cjs/route.js.map +1 -0
- package/build/cjs/router.js +1085 -0
- package/build/cjs/router.js.map +1 -0
- package/build/cjs/scroll-restoration.js +202 -0
- package/build/cjs/scroll-restoration.js.map +1 -0
- package/build/cjs/searchParams.js +81 -0
- package/build/cjs/searchParams.js.map +1 -0
- package/build/cjs/useBlocker.js +55 -0
- package/build/cjs/useBlocker.js.map +1 -0
- package/build/cjs/useNavigate.js +86 -0
- package/build/cjs/useNavigate.js.map +1 -0
- package/build/cjs/useParams.js +26 -0
- package/build/cjs/useParams.js.map +1 -0
- package/build/cjs/useSearch.js +25 -0
- package/build/cjs/useSearch.js.map +1 -0
- package/build/cjs/utils.js +241 -0
- package/build/cjs/utils.js.map +1 -0
- package/build/esm/index.js +2302 -2534
- package/build/esm/index.js.map +1 -1
- package/build/stats-html.html +3498 -2694
- package/build/stats-react.json +1204 -44
- package/build/types/CatchBoundary.d.ts +36 -0
- package/build/types/Matches.d.ts +64 -0
- package/build/types/RouterProvider.d.ts +35 -0
- package/build/types/awaited.d.ts +9 -0
- package/build/types/defer.d.ts +19 -0
- package/build/types/fileRoute.d.ts +38 -0
- package/build/types/history.d.ts +7 -0
- package/build/types/index.d.ts +27 -74
- package/build/types/lazyRouteComponent.d.ts +2 -0
- package/build/types/link.d.ts +93 -0
- package/build/types/location.d.ts +12 -0
- package/build/types/path.d.ts +17 -0
- package/build/types/qss.d.ts +2 -0
- package/build/types/redirects.d.ts +11 -0
- package/build/types/route.d.ts +283 -0
- package/build/types/routeInfo.d.ts +31 -0
- package/build/types/router.d.ts +186 -0
- package/build/types/scroll-restoration.d.ts +18 -0
- package/build/types/searchParams.d.ts +7 -0
- package/build/types/useBlocker.d.ts +9 -0
- package/build/types/useNavigate.d.ts +19 -0
- package/build/types/useParams.d.ts +7 -0
- package/build/types/useSearch.d.ts +7 -0
- package/build/types/utils.d.ts +69 -0
- package/build/umd/index.development.js +2899 -2493
- package/build/umd/index.development.js.map +1 -1
- package/build/umd/index.production.js +4 -4
- package/build/umd/index.production.js.map +1 -1
- package/package.json +12 -10
- package/src/CatchBoundary.tsx +101 -0
- package/src/Matches.tsx +423 -0
- package/src/RouterProvider.tsx +254 -0
- package/src/awaited.tsx +40 -0
- package/src/defer.ts +55 -0
- package/src/fileRoute.ts +152 -0
- package/src/history.ts +8 -0
- package/src/index.tsx +28 -619
- package/src/lazyRouteComponent.tsx +33 -0
- package/src/link.tsx +603 -0
- package/src/location.ts +13 -0
- package/src/path.ts +261 -0
- package/src/qss.ts +53 -0
- package/src/redirects.ts +39 -0
- package/src/route.ts +882 -0
- package/src/routeInfo.ts +84 -0
- package/src/router.ts +1671 -0
- package/src/scroll-restoration.tsx +230 -0
- package/src/searchParams.ts +79 -0
- package/src/useBlocker.tsx +27 -0
- package/src/useNavigate.tsx +111 -0
- package/src/useParams.tsx +25 -0
- package/src/useSearch.tsx +25 -0
- package/src/utils.ts +360 -0
- package/build/cjs/react-router/src/index.js +0 -458
- package/build/cjs/react-router/src/index.js.map +0 -1
- package/build/cjs/router-core/build/esm/index.js +0 -2524
- package/build/cjs/router-core/build/esm/index.js.map +0 -1
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
import * as React from 'react'
|
|
2
|
+
import warning from 'tiny-warning'
|
|
3
|
+
import { useStore } from '@tanstack/react-store'
|
|
4
|
+
import { Matches } from './Matches'
|
|
5
|
+
import { NavigateOptions, ResolveRelativePath, ToOptions } from './link'
|
|
6
|
+
import { ParsedLocation } from './location'
|
|
7
|
+
import { AnyRoute } from './route'
|
|
8
|
+
import { RouteById, RoutePaths } from './routeInfo'
|
|
9
|
+
import {
|
|
10
|
+
BuildNextOptions,
|
|
11
|
+
RegisteredRouter,
|
|
12
|
+
Router,
|
|
13
|
+
RouterOptions,
|
|
14
|
+
RouterState,
|
|
15
|
+
} from './router'
|
|
16
|
+
import { NoInfer, pick, useLayoutEffect } from './utils'
|
|
17
|
+
import { MatchRouteOptions } from './Matches'
|
|
18
|
+
import { RouteMatch } from './Matches'
|
|
19
|
+
|
|
20
|
+
export interface CommitLocationOptions {
|
|
21
|
+
replace?: boolean
|
|
22
|
+
resetScroll?: boolean
|
|
23
|
+
startTransition?: boolean
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface MatchLocation {
|
|
27
|
+
to?: string | number | null
|
|
28
|
+
fuzzy?: boolean
|
|
29
|
+
caseSensitive?: boolean
|
|
30
|
+
from?: string
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export type NavigateFn<TRouteTree extends AnyRoute> = <
|
|
34
|
+
TFrom extends RoutePaths<TRouteTree> = '/',
|
|
35
|
+
TTo extends string = '',
|
|
36
|
+
TMaskFrom extends RoutePaths<TRouteTree> = TFrom,
|
|
37
|
+
TMaskTo extends string = '',
|
|
38
|
+
>(
|
|
39
|
+
opts: NavigateOptions<TRouteTree, TFrom, TTo, TMaskFrom, TMaskTo>,
|
|
40
|
+
) => Promise<void>
|
|
41
|
+
|
|
42
|
+
export type MatchRouteFn<TRouteTree extends AnyRoute> = <
|
|
43
|
+
TFrom extends RoutePaths<TRouteTree> = '/',
|
|
44
|
+
TTo extends string = '',
|
|
45
|
+
TResolved = ResolveRelativePath<TFrom, NoInfer<TTo>>,
|
|
46
|
+
>(
|
|
47
|
+
location: ToOptions<TRouteTree, TFrom, TTo>,
|
|
48
|
+
opts?: MatchRouteOptions,
|
|
49
|
+
) => false | RouteById<TRouteTree, TResolved>['types']['allParams']
|
|
50
|
+
|
|
51
|
+
export type BuildLocationFn<TRouteTree extends AnyRoute> = (
|
|
52
|
+
opts: ToOptions<TRouteTree>,
|
|
53
|
+
) => ParsedLocation
|
|
54
|
+
|
|
55
|
+
export type InjectedHtmlEntry = string | (() => Promise<string> | string)
|
|
56
|
+
|
|
57
|
+
export let routerContext = React.createContext<Router<any>>(null!)
|
|
58
|
+
|
|
59
|
+
if (typeof document !== 'undefined') {
|
|
60
|
+
if (window.__TSR_ROUTER_CONTEXT__) {
|
|
61
|
+
routerContext = window.__TSR_ROUTER_CONTEXT__
|
|
62
|
+
} else {
|
|
63
|
+
window.__TSR_ROUTER_CONTEXT__ = routerContext as any
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function RouterProvider<
|
|
68
|
+
TRouteTree extends AnyRoute = RegisteredRouter['routeTree'],
|
|
69
|
+
TDehydrated extends Record<string, any> = Record<string, any>,
|
|
70
|
+
>({ router, ...rest }: RouterProps<TRouteTree, TDehydrated>) {
|
|
71
|
+
// Allow the router to update options on the router instance
|
|
72
|
+
router.update({
|
|
73
|
+
...router.options,
|
|
74
|
+
...rest,
|
|
75
|
+
context: {
|
|
76
|
+
...router.options.context,
|
|
77
|
+
...rest?.context,
|
|
78
|
+
},
|
|
79
|
+
} as any)
|
|
80
|
+
|
|
81
|
+
const matches = router.options.InnerWrap ? (
|
|
82
|
+
<router.options.InnerWrap>
|
|
83
|
+
<Matches />
|
|
84
|
+
</router.options.InnerWrap>
|
|
85
|
+
) : (
|
|
86
|
+
<Matches />
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
const provider = (
|
|
90
|
+
<routerContext.Provider value={router}>
|
|
91
|
+
{matches}
|
|
92
|
+
<Transitioner />
|
|
93
|
+
</routerContext.Provider>
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
if (router.options.Wrap) {
|
|
97
|
+
return <router.options.Wrap>{provider}</router.options.Wrap>
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return provider
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function Transitioner() {
|
|
104
|
+
const mountLoadCount = React.useRef(0)
|
|
105
|
+
const router = useRouter()
|
|
106
|
+
const routerState = useRouterState({
|
|
107
|
+
select: (s) =>
|
|
108
|
+
pick(s, ['isLoading', 'location', 'resolvedLocation', 'isTransitioning']),
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
const [isTransitioning, startReactTransition] = React.useTransition()
|
|
112
|
+
|
|
113
|
+
router.startReactTransition = startReactTransition
|
|
114
|
+
|
|
115
|
+
React.useEffect(() => {
|
|
116
|
+
if (isTransitioning) {
|
|
117
|
+
router.__store.setState((s) => ({
|
|
118
|
+
...s,
|
|
119
|
+
isTransitioning,
|
|
120
|
+
}))
|
|
121
|
+
}
|
|
122
|
+
}, [isTransitioning])
|
|
123
|
+
|
|
124
|
+
const tryLoad = () => {
|
|
125
|
+
const apply = (cb: () => void) => {
|
|
126
|
+
if (!routerState.isTransitioning) {
|
|
127
|
+
startReactTransition(() => cb())
|
|
128
|
+
} else {
|
|
129
|
+
cb()
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
apply(() => {
|
|
134
|
+
try {
|
|
135
|
+
router.load()
|
|
136
|
+
} catch (err) {
|
|
137
|
+
console.error(err)
|
|
138
|
+
}
|
|
139
|
+
})
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
useLayoutEffect(() => {
|
|
143
|
+
const unsub = router.history.subscribe(() => {
|
|
144
|
+
router.latestLocation = router.parseLocation(router.latestLocation)
|
|
145
|
+
if (routerState.location !== router.latestLocation) {
|
|
146
|
+
tryLoad()
|
|
147
|
+
}
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
const nextLocation = router.buildLocation({
|
|
151
|
+
search: true,
|
|
152
|
+
params: true,
|
|
153
|
+
hash: true,
|
|
154
|
+
state: true,
|
|
155
|
+
})
|
|
156
|
+
|
|
157
|
+
if (routerState.location.href !== nextLocation.href) {
|
|
158
|
+
router.commitLocation({ ...nextLocation, replace: true })
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return () => {
|
|
162
|
+
unsub()
|
|
163
|
+
}
|
|
164
|
+
}, [router.history])
|
|
165
|
+
|
|
166
|
+
useLayoutEffect(() => {
|
|
167
|
+
if (
|
|
168
|
+
routerState.isTransitioning &&
|
|
169
|
+
!isTransitioning &&
|
|
170
|
+
!routerState.isLoading &&
|
|
171
|
+
routerState.resolvedLocation !== routerState.location
|
|
172
|
+
) {
|
|
173
|
+
router.emit({
|
|
174
|
+
type: 'onResolved',
|
|
175
|
+
fromLocation: routerState.resolvedLocation,
|
|
176
|
+
toLocation: routerState.location,
|
|
177
|
+
pathChanged:
|
|
178
|
+
routerState.location!.href !== routerState.resolvedLocation?.href,
|
|
179
|
+
})
|
|
180
|
+
|
|
181
|
+
if ((document as any).querySelector) {
|
|
182
|
+
if (routerState.location.hash !== '') {
|
|
183
|
+
const el = document.getElementById(
|
|
184
|
+
routerState.location.hash,
|
|
185
|
+
) as HTMLElement | null
|
|
186
|
+
if (el) {
|
|
187
|
+
el.scrollIntoView()
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
router.__store.setState((s) => ({
|
|
193
|
+
...s,
|
|
194
|
+
isTransitioning: false,
|
|
195
|
+
resolvedLocation: s.location,
|
|
196
|
+
}))
|
|
197
|
+
}
|
|
198
|
+
}, [
|
|
199
|
+
routerState.isTransitioning,
|
|
200
|
+
isTransitioning,
|
|
201
|
+
routerState.isLoading,
|
|
202
|
+
routerState.resolvedLocation,
|
|
203
|
+
routerState.location,
|
|
204
|
+
])
|
|
205
|
+
|
|
206
|
+
useLayoutEffect(() => {
|
|
207
|
+
if (!window.__TSR_DEHYDRATED__ && !mountLoadCount.current) {
|
|
208
|
+
mountLoadCount.current++
|
|
209
|
+
tryLoad()
|
|
210
|
+
}
|
|
211
|
+
}, [])
|
|
212
|
+
|
|
213
|
+
return null
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
export function getRouteMatch<TRouteTree extends AnyRoute>(
|
|
217
|
+
state: RouterState<TRouteTree>,
|
|
218
|
+
id: string,
|
|
219
|
+
): undefined | RouteMatch<TRouteTree> {
|
|
220
|
+
return [
|
|
221
|
+
...state.cachedMatches,
|
|
222
|
+
...(state.pendingMatches ?? []),
|
|
223
|
+
...state.matches,
|
|
224
|
+
].find((d) => d.id === id)
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
export function useRouterState<
|
|
228
|
+
TSelected = RouterState<RegisteredRouter['routeTree']>,
|
|
229
|
+
>(opts?: {
|
|
230
|
+
select: (state: RouterState<RegisteredRouter['routeTree']>) => TSelected
|
|
231
|
+
}): TSelected {
|
|
232
|
+
const router = useRouter()
|
|
233
|
+
return useStore(router.__store, opts?.select as any)
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
export type RouterProps<
|
|
237
|
+
TRouteTree extends AnyRoute = RegisteredRouter['routeTree'],
|
|
238
|
+
TDehydrated extends Record<string, any> = Record<string, any>,
|
|
239
|
+
> = Omit<RouterOptions<TRouteTree, TDehydrated>, 'context'> & {
|
|
240
|
+
router: Router<TRouteTree>
|
|
241
|
+
context?: Partial<RouterOptions<TRouteTree, TDehydrated>['context']>
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
export function useRouter<
|
|
245
|
+
TRouteTree extends AnyRoute = RegisteredRouter['routeTree'],
|
|
246
|
+
>(): Router<TRouteTree> {
|
|
247
|
+
const resolvedContext =
|
|
248
|
+
typeof document !== 'undefined'
|
|
249
|
+
? window.__TSR_ROUTER_CONTEXT__ || routerContext
|
|
250
|
+
: routerContext
|
|
251
|
+
const value = React.useContext(resolvedContext)
|
|
252
|
+
warning(value, 'useRouter must be used inside a <RouterProvider> component!')
|
|
253
|
+
return value as any
|
|
254
|
+
}
|
package/src/awaited.tsx
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { useRouter } from './RouterProvider'
|
|
2
|
+
import { DeferredPromise, isDehydratedDeferred } from './defer'
|
|
3
|
+
|
|
4
|
+
export type AwaitOptions<T> = {
|
|
5
|
+
promise: DeferredPromise<T>
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function useAwaited<T>({ promise }: AwaitOptions<T>): [T] {
|
|
9
|
+
const router = useRouter()
|
|
10
|
+
|
|
11
|
+
let state = promise.__deferredState
|
|
12
|
+
const key = `__TSR__DEFERRED__${state.uid}`
|
|
13
|
+
|
|
14
|
+
if (isDehydratedDeferred(promise)) {
|
|
15
|
+
state = router.hydrateData(key)!
|
|
16
|
+
promise = Promise.resolve(state.data) as DeferredPromise<any>
|
|
17
|
+
promise.__deferredState = state
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (state.status === 'pending') {
|
|
21
|
+
throw new Promise((r) => setTimeout(r, 1)).then(() => promise)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (state.status === 'error') {
|
|
25
|
+
throw state.error
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
router.dehydrateData(key, state)
|
|
29
|
+
|
|
30
|
+
return [state.data]
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function Await<T>(
|
|
34
|
+
props: AwaitOptions<T> & {
|
|
35
|
+
children: (result: T) => JSX.Element
|
|
36
|
+
},
|
|
37
|
+
) {
|
|
38
|
+
const awaited = useAwaited(props)
|
|
39
|
+
return props.children(...awaited)
|
|
40
|
+
}
|
package/src/defer.ts
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
export type DeferredPromiseState<T> = { uid: string } & (
|
|
2
|
+
| {
|
|
3
|
+
status: 'pending'
|
|
4
|
+
data?: T
|
|
5
|
+
error?: unknown
|
|
6
|
+
}
|
|
7
|
+
| {
|
|
8
|
+
status: 'success'
|
|
9
|
+
data: T
|
|
10
|
+
}
|
|
11
|
+
| {
|
|
12
|
+
status: 'error'
|
|
13
|
+
data?: T
|
|
14
|
+
error: unknown
|
|
15
|
+
}
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
export type DeferredPromise<T> = Promise<T> & {
|
|
19
|
+
__deferredState: DeferredPromiseState<T>
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function defer<T>(_promise: Promise<T>) {
|
|
23
|
+
const promise = _promise as DeferredPromise<T>
|
|
24
|
+
|
|
25
|
+
if (!promise.__deferredState) {
|
|
26
|
+
promise.__deferredState = {
|
|
27
|
+
uid: Math.random().toString(36).slice(2),
|
|
28
|
+
status: 'pending',
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const state = promise.__deferredState
|
|
32
|
+
|
|
33
|
+
promise
|
|
34
|
+
.then((data) => {
|
|
35
|
+
state.status = 'success' as any
|
|
36
|
+
state.data = data
|
|
37
|
+
})
|
|
38
|
+
.catch((error) => {
|
|
39
|
+
state.status = 'error' as any
|
|
40
|
+
state.error = error
|
|
41
|
+
})
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return promise
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function isDehydratedDeferred(obj: any): boolean {
|
|
48
|
+
return (
|
|
49
|
+
typeof obj === 'object' &&
|
|
50
|
+
obj !== null &&
|
|
51
|
+
!(obj instanceof Promise) &&
|
|
52
|
+
!obj.then &&
|
|
53
|
+
'__deferredState' in obj
|
|
54
|
+
)
|
|
55
|
+
}
|
package/src/fileRoute.ts
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { ParsePathParams } from './link'
|
|
2
|
+
import {
|
|
3
|
+
AnyRoute,
|
|
4
|
+
ResolveFullPath,
|
|
5
|
+
ResolveFullSearchSchema,
|
|
6
|
+
MergeFromFromParent,
|
|
7
|
+
RouteContext,
|
|
8
|
+
AnyContext,
|
|
9
|
+
RouteOptions,
|
|
10
|
+
UpdatableRouteOptions,
|
|
11
|
+
Route,
|
|
12
|
+
AnyPathParams,
|
|
13
|
+
RootRouteId,
|
|
14
|
+
TrimPathLeft,
|
|
15
|
+
RouteConstraints,
|
|
16
|
+
} from './route'
|
|
17
|
+
import { Assign, Expand, IsAny } from './utils'
|
|
18
|
+
|
|
19
|
+
export interface FileRoutesByPath {
|
|
20
|
+
// '/': {
|
|
21
|
+
// parentRoute: typeof rootRoute
|
|
22
|
+
// }
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
type Replace<
|
|
26
|
+
S extends string,
|
|
27
|
+
From extends string,
|
|
28
|
+
To extends string,
|
|
29
|
+
> = S extends `${infer Start}${From}${infer Rest}`
|
|
30
|
+
? `${Start}${To}${Replace<Rest, From, To>}`
|
|
31
|
+
: S
|
|
32
|
+
|
|
33
|
+
export type TrimLeft<
|
|
34
|
+
T extends string,
|
|
35
|
+
S extends string,
|
|
36
|
+
> = T extends `${S}${infer U}` ? U : T
|
|
37
|
+
|
|
38
|
+
export type TrimRight<
|
|
39
|
+
T extends string,
|
|
40
|
+
S extends string,
|
|
41
|
+
> = T extends `${infer U}${S}` ? U : T
|
|
42
|
+
|
|
43
|
+
export type Trim<T extends string, S extends string> = TrimLeft<
|
|
44
|
+
TrimRight<T, S>,
|
|
45
|
+
S
|
|
46
|
+
>
|
|
47
|
+
|
|
48
|
+
export type RemoveUnderScores<T extends string> = Replace<
|
|
49
|
+
Replace<TrimRight<TrimLeft<T, '/_'>, '_'>, '_/', '/'>,
|
|
50
|
+
'/_',
|
|
51
|
+
'/'
|
|
52
|
+
>
|
|
53
|
+
|
|
54
|
+
export type ResolveFilePath<
|
|
55
|
+
TParentRoute extends AnyRoute,
|
|
56
|
+
TFilePath extends string,
|
|
57
|
+
> = TParentRoute['id'] extends RootRouteId
|
|
58
|
+
? TrimPathLeft<TFilePath>
|
|
59
|
+
: Replace<
|
|
60
|
+
TrimPathLeft<TFilePath>,
|
|
61
|
+
TrimPathLeft<TParentRoute['types']['customId']>,
|
|
62
|
+
''
|
|
63
|
+
>
|
|
64
|
+
|
|
65
|
+
export type FileRoutePath<
|
|
66
|
+
TParentRoute extends AnyRoute,
|
|
67
|
+
TFilePath extends string,
|
|
68
|
+
> = ResolveFilePath<TParentRoute, TFilePath> extends `_${infer _}`
|
|
69
|
+
? string
|
|
70
|
+
: ResolveFilePath<TParentRoute, TFilePath>
|
|
71
|
+
|
|
72
|
+
export class FileRoute<
|
|
73
|
+
TFilePath extends keyof FileRoutesByPath,
|
|
74
|
+
TParentRoute extends AnyRoute = FileRoutesByPath[TFilePath]['parentRoute'],
|
|
75
|
+
TId extends RouteConstraints['TId'] = TFilePath,
|
|
76
|
+
TPath extends RouteConstraints['TPath'] = FileRoutePath<
|
|
77
|
+
TParentRoute,
|
|
78
|
+
TFilePath
|
|
79
|
+
>,
|
|
80
|
+
TFullPath extends RouteConstraints['TFullPath'] = ResolveFullPath<
|
|
81
|
+
TParentRoute,
|
|
82
|
+
RemoveUnderScores<TPath>
|
|
83
|
+
>,
|
|
84
|
+
> {
|
|
85
|
+
constructor(public path: TFilePath) {}
|
|
86
|
+
|
|
87
|
+
createRoute = <
|
|
88
|
+
TSearchSchema extends RouteConstraints['TSearchSchema'] = {},
|
|
89
|
+
TFullSearchSchema extends
|
|
90
|
+
RouteConstraints['TFullSearchSchema'] = ResolveFullSearchSchema<
|
|
91
|
+
TParentRoute,
|
|
92
|
+
TSearchSchema
|
|
93
|
+
>,
|
|
94
|
+
TParams extends RouteConstraints['TParams'] = Expand<
|
|
95
|
+
Record<ParsePathParams<TPath>, string>
|
|
96
|
+
>,
|
|
97
|
+
TAllParams extends RouteConstraints['TAllParams'] = MergeFromFromParent<
|
|
98
|
+
TParentRoute['types']['allParams'],
|
|
99
|
+
TParams
|
|
100
|
+
>,
|
|
101
|
+
TRouteContext extends RouteConstraints['TRouteContext'] = RouteContext,
|
|
102
|
+
TContext extends Expand<
|
|
103
|
+
Assign<IsAny<TParentRoute['types']['allContext'], {}>, TRouteContext>
|
|
104
|
+
> = Expand<
|
|
105
|
+
Assign<IsAny<TParentRoute['types']['allContext'], {}>, TRouteContext>
|
|
106
|
+
>,
|
|
107
|
+
TRouterContext extends RouteConstraints['TRouterContext'] = AnyContext,
|
|
108
|
+
TLoaderDeps extends Record<string, any> = {},
|
|
109
|
+
TLoaderData extends any = unknown,
|
|
110
|
+
TChildren extends RouteConstraints['TChildren'] = unknown,
|
|
111
|
+
TRouteTree extends RouteConstraints['TRouteTree'] = AnyRoute,
|
|
112
|
+
>(
|
|
113
|
+
options?: Omit<
|
|
114
|
+
RouteOptions<
|
|
115
|
+
TParentRoute,
|
|
116
|
+
string,
|
|
117
|
+
TPath,
|
|
118
|
+
TSearchSchema,
|
|
119
|
+
TFullSearchSchema,
|
|
120
|
+
TParams,
|
|
121
|
+
TAllParams,
|
|
122
|
+
TRouteContext,
|
|
123
|
+
TContext,
|
|
124
|
+
TLoaderDeps,
|
|
125
|
+
TLoaderData
|
|
126
|
+
>,
|
|
127
|
+
'getParentRoute' | 'path' | 'id'
|
|
128
|
+
> &
|
|
129
|
+
UpdatableRouteOptions<TFullSearchSchema>,
|
|
130
|
+
): Route<
|
|
131
|
+
TParentRoute,
|
|
132
|
+
TPath,
|
|
133
|
+
TFullPath,
|
|
134
|
+
TFilePath,
|
|
135
|
+
TId,
|
|
136
|
+
TSearchSchema,
|
|
137
|
+
TFullSearchSchema,
|
|
138
|
+
TParams,
|
|
139
|
+
TAllParams,
|
|
140
|
+
TRouteContext,
|
|
141
|
+
TContext,
|
|
142
|
+
TRouterContext,
|
|
143
|
+
TLoaderDeps,
|
|
144
|
+
TLoaderData,
|
|
145
|
+
TChildren,
|
|
146
|
+
TRouteTree
|
|
147
|
+
> => {
|
|
148
|
+
const route = new Route(options as any)
|
|
149
|
+
;(route as any).isRoot = false
|
|
150
|
+
return route as any
|
|
151
|
+
}
|
|
152
|
+
}
|