@tanstack/react-router 0.0.1-beta.24 → 0.0.1-beta.240

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 (108) hide show
  1. package/LICENSE +21 -0
  2. package/build/cjs/CatchBoundary.js +123 -0
  3. package/build/cjs/CatchBoundary.js.map +1 -0
  4. package/build/cjs/Matches.js +232 -0
  5. package/build/cjs/Matches.js.map +1 -0
  6. package/build/cjs/RouterProvider.js +159 -0
  7. package/build/cjs/RouterProvider.js.map +1 -0
  8. package/build/cjs/_virtual/_rollupPluginBabelHelpers.js +2 -22
  9. package/build/cjs/_virtual/_rollupPluginBabelHelpers.js.map +1 -1
  10. package/build/cjs/awaited.js +43 -0
  11. package/build/cjs/awaited.js.map +1 -0
  12. package/build/cjs/defer.js +37 -0
  13. package/build/cjs/defer.js.map +1 -0
  14. package/build/cjs/fileRoute.js +27 -0
  15. package/build/cjs/fileRoute.js.map +1 -0
  16. package/build/cjs/index.js +123 -0
  17. package/build/cjs/index.js.map +1 -0
  18. package/build/cjs/lazyRouteComponent.js +54 -0
  19. package/build/cjs/lazyRouteComponent.js.map +1 -0
  20. package/build/cjs/link.js +148 -0
  21. package/build/cjs/link.js.map +1 -0
  22. package/build/cjs/path.js +209 -0
  23. package/build/cjs/path.js.map +1 -0
  24. package/build/cjs/qss.js +63 -0
  25. package/build/cjs/qss.js.map +1 -0
  26. package/build/cjs/redirects.js +25 -0
  27. package/build/cjs/redirects.js.map +1 -0
  28. package/build/cjs/route.js +134 -0
  29. package/build/cjs/route.js.map +1 -0
  30. package/build/cjs/router.js +1113 -0
  31. package/build/cjs/router.js.map +1 -0
  32. package/build/cjs/scroll-restoration.js +202 -0
  33. package/build/cjs/scroll-restoration.js.map +1 -0
  34. package/build/cjs/searchParams.js +81 -0
  35. package/build/cjs/searchParams.js.map +1 -0
  36. package/build/cjs/useBlocker.js +61 -0
  37. package/build/cjs/useBlocker.js.map +1 -0
  38. package/build/cjs/useNavigate.js +75 -0
  39. package/build/cjs/useNavigate.js.map +1 -0
  40. package/build/cjs/useParams.js +26 -0
  41. package/build/cjs/useParams.js.map +1 -0
  42. package/build/cjs/useSearch.js +25 -0
  43. package/build/cjs/useSearch.js.map +1 -0
  44. package/build/cjs/utils.js +239 -0
  45. package/build/cjs/utils.js.map +1 -0
  46. package/build/esm/index.js +2159 -2534
  47. package/build/esm/index.js.map +1 -1
  48. package/build/stats-html.html +3498 -2694
  49. package/build/stats-react.json +1210 -44
  50. package/build/types/CatchBoundary.d.ts +33 -0
  51. package/build/types/Matches.d.ts +57 -0
  52. package/build/types/RouterProvider.d.ts +36 -0
  53. package/build/types/awaited.d.ts +9 -0
  54. package/build/types/defer.d.ts +19 -0
  55. package/build/types/fileRoute.d.ts +35 -0
  56. package/build/types/history.d.ts +7 -0
  57. package/build/types/index.d.ts +27 -108
  58. package/build/types/injectHtml.d.ts +0 -0
  59. package/build/types/lazyRouteComponent.d.ts +2 -0
  60. package/build/types/link.d.ts +105 -0
  61. package/build/types/location.d.ts +14 -0
  62. package/build/types/path.d.ts +16 -0
  63. package/build/types/qss.d.ts +2 -0
  64. package/build/types/redirects.d.ts +10 -0
  65. package/build/types/route.d.ts +278 -0
  66. package/build/types/routeInfo.d.ts +22 -0
  67. package/build/types/router.d.ts +182 -0
  68. package/build/types/scroll-restoration.d.ts +18 -0
  69. package/build/types/searchParams.d.ts +7 -0
  70. package/build/types/useBlocker.d.ts +8 -0
  71. package/build/types/useNavigate.d.ts +20 -0
  72. package/build/types/useParams.d.ts +7 -0
  73. package/build/types/useSearch.d.ts +7 -0
  74. package/build/types/utils.d.ts +66 -0
  75. package/build/umd/index.development.js +2714 -2485
  76. package/build/umd/index.development.js.map +1 -1
  77. package/build/umd/index.production.js +4 -4
  78. package/build/umd/index.production.js.map +1 -1
  79. package/package.json +11 -10
  80. package/src/CatchBoundary.tsx +98 -0
  81. package/src/Matches.tsx +401 -0
  82. package/src/RouterProvider.tsx +241 -0
  83. package/src/awaited.tsx +40 -0
  84. package/src/defer.ts +55 -0
  85. package/src/fileRoute.ts +154 -0
  86. package/src/history.ts +8 -0
  87. package/src/index.tsx +28 -708
  88. package/src/injectHtml.ts +28 -0
  89. package/src/lazyRouteComponent.tsx +33 -0
  90. package/src/link.tsx +508 -0
  91. package/src/location.ts +15 -0
  92. package/src/path.ts +256 -0
  93. package/src/qss.ts +53 -0
  94. package/src/redirects.ts +31 -0
  95. package/src/route.ts +861 -0
  96. package/src/routeInfo.ts +68 -0
  97. package/src/router.ts +1700 -0
  98. package/src/scroll-restoration.tsx +230 -0
  99. package/src/searchParams.ts +79 -0
  100. package/src/useBlocker.tsx +34 -0
  101. package/src/useNavigate.tsx +109 -0
  102. package/src/useParams.tsx +25 -0
  103. package/src/useSearch.tsx +25 -0
  104. package/src/utils.ts +350 -0
  105. package/build/cjs/react-router/src/index.js +0 -473
  106. package/build/cjs/react-router/src/index.js.map +0 -1
  107. package/build/cjs/router-core/build/esm/index.js +0 -2528
  108. package/build/cjs/router-core/build/esm/index.js.map +0 -1
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@tanstack/react-router",
3
3
  "author": "Tanner Linsley",
4
- "version": "0.0.1-beta.24",
4
+ "version": "0.0.1-beta.240",
5
5
  "license": "MIT",
6
6
  "repository": "tanstack/router",
7
- "homepage": "https://tanstack.com/router/",
7
+ "homepage": "https://tanstack.com/router",
8
8
  "description": "",
9
9
  "publishConfig": {
10
10
  "registry": "https://registry.npmjs.org/"
@@ -12,7 +12,6 @@
12
12
  "keywords": [
13
13
  "react",
14
14
  "location",
15
- "@tanstack/react-router",
16
15
  "router",
17
16
  "routing",
18
17
  "async",
@@ -24,7 +23,7 @@
24
23
  "url": "https://github.com/sponsors/tannerlinsley"
25
24
  },
26
25
  "module": "build/esm/index.js",
27
- "main": "build/cjs/react-router/src/index.js",
26
+ "main": "build/cjs/index.js",
28
27
  "browser": "build/umd/index.production.js",
29
28
  "types": "build/types/index.d.ts",
30
29
  "engines": {
@@ -41,11 +40,13 @@
41
40
  },
42
41
  "dependencies": {
43
42
  "@babel/runtime": "^7.16.7",
44
- "@tanstack/router-core": "0.0.1-beta.24",
45
- "use-sync-external-store": "^1.2.0"
43
+ "@tanstack/react-store": "^0.2.1",
44
+ "@tanstack/store": "^0.1.3",
45
+ "tiny-invariant": "^1.3.1",
46
+ "tiny-warning": "^1.0.3",
47
+ "@tanstack/history": "0.0.1-beta.240"
46
48
  },
47
- "devDependencies": {
48
- "@types/use-sync-external-store": "^0.0.3",
49
- "babel-plugin-transform-async-to-promises": "^0.8.18"
49
+ "scripts": {
50
+ "build": "rollup --config rollup.config.js"
50
51
  }
51
- }
52
+ }
@@ -0,0 +1,98 @@
1
+ import * as React from 'react'
2
+
3
+ export function CatchBoundary(props: {
4
+ resetKey: string
5
+ children: any
6
+ errorComponent?: any
7
+ onCatch: (error: any) => void
8
+ }) {
9
+ const errorComponent = props.errorComponent ?? ErrorComponent
10
+
11
+ return (
12
+ <CatchBoundaryImpl
13
+ resetKey={props.resetKey}
14
+ onCatch={props.onCatch}
15
+ children={({ error }) => {
16
+ if (error) {
17
+ return React.createElement(errorComponent, {
18
+ error,
19
+ })
20
+ }
21
+
22
+ return props.children
23
+ }}
24
+ />
25
+ )
26
+ }
27
+
28
+ export class CatchBoundaryImpl extends React.Component<{
29
+ resetKey: string
30
+ children: (props: { error: any; reset: () => void }) => any
31
+ onCatch?: (error: any) => void
32
+ }> {
33
+ state = { error: null } as any
34
+ static getDerivedStateFromError(error: any) {
35
+ return { error }
36
+ }
37
+ componentDidUpdate(
38
+ prevProps: Readonly<{
39
+ resetKey: string
40
+ children: (props: { error: any; reset: () => void }) => any
41
+ onCatch?: ((error: any, info: any) => void) | undefined
42
+ }>,
43
+ prevState: any,
44
+ ): void {
45
+ if (prevState.error && prevProps.resetKey !== this.props.resetKey) {
46
+ this.setState({ error: null })
47
+ }
48
+ }
49
+ componentDidCatch(error: any) {
50
+ console.error(error)
51
+ this.props.onCatch?.(error)
52
+ }
53
+ render() {
54
+ return this.props.children(this.state)
55
+ }
56
+ }
57
+
58
+ export function ErrorComponent({ error }: { error: any }) {
59
+ const [show, setShow] = React.useState(process.env.NODE_ENV !== 'production')
60
+
61
+ return (
62
+ <div style={{ padding: '.5rem', maxWidth: '100%' }}>
63
+ <div style={{ display: 'flex', alignItems: 'center', gap: '.5rem' }}>
64
+ <strong style={{ fontSize: '1rem' }}>Something went wrong!</strong>
65
+ <button
66
+ style={{
67
+ appearance: 'none',
68
+ fontSize: '.6em',
69
+ border: '1px solid currentColor',
70
+ padding: '.1rem .2rem',
71
+ fontWeight: 'bold',
72
+ borderRadius: '.25rem',
73
+ }}
74
+ onClick={() => setShow((d) => !d)}
75
+ >
76
+ {show ? 'Hide Error' : 'Show Error'}
77
+ </button>
78
+ </div>
79
+ <div style={{ height: '.25rem' }} />
80
+ {show ? (
81
+ <div>
82
+ <pre
83
+ style={{
84
+ fontSize: '.7em',
85
+ border: '1px solid red',
86
+ borderRadius: '.25rem',
87
+ padding: '.3rem',
88
+ color: 'red',
89
+ overflow: 'auto',
90
+ }}
91
+ >
92
+ {error.message ? <code>{error.message}</code> : null}
93
+ </pre>
94
+ </div>
95
+ ) : null}
96
+ </div>
97
+ )
98
+ }
@@ -0,0 +1,401 @@
1
+ import * as React from 'react'
2
+ import invariant from 'tiny-invariant'
3
+ import warning from 'tiny-warning'
4
+ import { CatchBoundary, ErrorComponent } from './CatchBoundary'
5
+ import { useRouter, useRouterState } from './RouterProvider'
6
+ import { ResolveRelativePath, ToOptions } from './link'
7
+ import { AnyRoute, ReactNode, rootRouteId } from './route'
8
+ import {
9
+ FullSearchSchema,
10
+ ParseRoute,
11
+ RouteById,
12
+ RouteByPath,
13
+ RouteIds,
14
+ RoutePaths,
15
+ } from './routeInfo'
16
+ import { RegisteredRouter } from './router'
17
+ import { NoInfer, StrictOrFrom, pick } from './utils'
18
+
19
+ export interface RouteMatch<
20
+ TRouteTree extends AnyRoute = AnyRoute,
21
+ TRouteId extends RouteIds<TRouteTree> = ParseRoute<TRouteTree>['id'],
22
+ > {
23
+ id: string
24
+ routeId: TRouteId
25
+ pathname: string
26
+ params: RouteById<TRouteTree, TRouteId>['types']['allParams']
27
+ status: 'pending' | 'success' | 'error'
28
+ isFetching: boolean
29
+ showPending: boolean
30
+ invalid: boolean
31
+ error: unknown
32
+ paramsError: unknown
33
+ searchError: unknown
34
+ updatedAt: number
35
+ loadPromise?: Promise<void>
36
+ loaderData?: RouteById<TRouteTree, TRouteId>['types']['loaderData']
37
+ __resolveLoadPromise?: () => void
38
+ context: RouteById<TRouteTree, TRouteId>['types']['allContext']
39
+ search: FullSearchSchema<TRouteTree> &
40
+ RouteById<TRouteTree, TRouteId>['types']['fullSearchSchema']
41
+ fetchedAt: number
42
+ shouldReloadDeps: any
43
+ abortController: AbortController
44
+ cause: 'enter' | 'stay'
45
+ }
46
+
47
+ export type AnyRouteMatch = RouteMatch<any>
48
+
49
+ export function Matches() {
50
+ const router = useRouter()
51
+ const routerState = useRouterState()
52
+ const matches = routerState.pendingMatches?.some((d) => d.showPending)
53
+ ? routerState.pendingMatches
54
+ : routerState.matches
55
+ const locationKey = routerState.resolvedLocation.state.key
56
+ const route = router.routesById[rootRouteId]!
57
+
58
+ const errorComponent = React.useCallback(
59
+ (props: any) => {
60
+ return React.createElement(ErrorComponent, {
61
+ ...props,
62
+ useMatch: route.useMatch,
63
+ useRouteContext: route.useRouteContext,
64
+ useSearch: route.useSearch,
65
+ useParams: route.useParams,
66
+ })
67
+ },
68
+ [route],
69
+ )
70
+
71
+ return (
72
+ <matchesContext.Provider value={matches}>
73
+ <CatchBoundary
74
+ resetKey={locationKey}
75
+ errorComponent={errorComponent}
76
+ onCatch={() => {
77
+ warning(
78
+ false,
79
+ `Error in router! Consider setting an 'errorComponent' in your RootRoute! 👍`,
80
+ )
81
+ }}
82
+ >
83
+ {matches.length ? <Match matches={matches} /> : null}
84
+ </CatchBoundary>
85
+ </matchesContext.Provider>
86
+ )
87
+ }
88
+
89
+ function SafeFragment(props: any) {
90
+ return <>{props.children}</>
91
+ }
92
+
93
+ export function Match({ matches }: { matches: RouteMatch[] }) {
94
+ const { options, routesById } = useRouter()
95
+ const match = matches[0]!
96
+ const routeId = match?.routeId
97
+ const route = routesById[routeId]!
98
+ const router = useRouter()
99
+ const locationKey = useRouterState().resolvedLocation.state?.key
100
+
101
+ const PendingComponent = (route.options.pendingComponent ??
102
+ options.defaultPendingComponent) as any
103
+
104
+ const pendingElement = PendingComponent
105
+ ? React.createElement(PendingComponent, {
106
+ useMatch: route.useMatch,
107
+ useRouteContext: route.useRouteContext,
108
+ useSearch: route.useSearch,
109
+ useParams: route.useParams,
110
+ })
111
+ : undefined
112
+
113
+ const routeErrorComponent =
114
+ route.options.errorComponent ??
115
+ options.defaultErrorComponent ??
116
+ ErrorComponent
117
+
118
+ const ResolvedSuspenseBoundary =
119
+ route.options.wrapInSuspense ?? pendingElement
120
+ ? React.Suspense
121
+ : SafeFragment
122
+
123
+ const errorComponent = routeErrorComponent
124
+ ? React.useCallback(
125
+ (props: any) => {
126
+ return React.createElement(routeErrorComponent, {
127
+ ...props,
128
+ useMatch: route.useMatch,
129
+ useRouteContext: route.useRouteContext,
130
+ useSearch: route.useSearch,
131
+ useParams: route.useParams,
132
+ })
133
+ },
134
+ [route],
135
+ )
136
+ : undefined
137
+
138
+ const ResolvedCatchBoundary = errorComponent ? CatchBoundary : SafeFragment
139
+
140
+ return (
141
+ <matchesContext.Provider value={matches}>
142
+ <ResolvedSuspenseBoundary fallback={pendingElement}>
143
+ <ResolvedCatchBoundary
144
+ resetKey={locationKey}
145
+ errorComponent={errorComponent}
146
+ onCatch={() => {
147
+ warning(false, `Error in route match: ${match.id}`)
148
+ }}
149
+ >
150
+ <MatchInner match={match} pendingElement={pendingElement} />
151
+ </ResolvedCatchBoundary>
152
+ </ResolvedSuspenseBoundary>
153
+ </matchesContext.Provider>
154
+ )
155
+ }
156
+ function MatchInner({
157
+ match,
158
+ pendingElement,
159
+ }: {
160
+ match: RouteMatch
161
+ pendingElement: any
162
+ }): any {
163
+ const { options, routesById } = useRouter()
164
+ const route = routesById[match.routeId]!
165
+
166
+ if (match.status === 'error') {
167
+ throw match.error
168
+ }
169
+
170
+ if (match.status === 'pending') {
171
+ if (match.showPending) {
172
+ return pendingElement || null
173
+ }
174
+ throw match.loadPromise
175
+ }
176
+
177
+ if (match.status === 'success') {
178
+ let comp = route.options.component ?? options.defaultComponent
179
+
180
+ if (comp) {
181
+ return React.createElement(comp, {
182
+ useMatch: route.useMatch,
183
+ useRouteContext: route.useRouteContext as any,
184
+ useSearch: route.useSearch,
185
+ useParams: route.useParams as any,
186
+ useLoaderData: route.useLoaderData,
187
+ })
188
+ }
189
+
190
+ return <Outlet />
191
+ }
192
+
193
+ invariant(
194
+ false,
195
+ 'Idle routeMatch status encountered during rendering! You should never see this. File an issue!',
196
+ )
197
+ }
198
+
199
+ export function Outlet() {
200
+ const matches = React.useContext(matchesContext).slice(1)
201
+
202
+ if (!matches[0]) {
203
+ return null
204
+ }
205
+
206
+ return <Match matches={matches} />
207
+ }
208
+
209
+ export interface MatchRouteOptions {
210
+ pending?: boolean
211
+ caseSensitive?: boolean
212
+ includeSearch?: boolean
213
+ fuzzy?: boolean
214
+ }
215
+
216
+ export type MakeUseMatchRouteOptions<
217
+ TRouteTree extends AnyRoute = RegisteredRouter['routeTree'],
218
+ TFrom extends RoutePaths<TRouteTree> = '/',
219
+ TTo extends string = '',
220
+ TMaskFrom extends RoutePaths<TRouteTree> = '/',
221
+ TMaskTo extends string = '',
222
+ > = ToOptions<AnyRoute, TFrom, TTo, TMaskFrom, TMaskTo> & MatchRouteOptions
223
+
224
+ export function useMatchRoute<
225
+ TRouteTree extends AnyRoute = RegisteredRouter['routeTree'],
226
+ >() {
227
+ const { matchRoute } = useRouter()
228
+
229
+ return React.useCallback(
230
+ <
231
+ TFrom extends RoutePaths<TRouteTree> = '/',
232
+ TTo extends string = '',
233
+ TMaskFrom extends RoutePaths<TRouteTree> = '/',
234
+ TMaskTo extends string = '',
235
+ TResolved extends string = ResolveRelativePath<TFrom, NoInfer<TTo>>,
236
+ >(
237
+ opts: MakeUseMatchRouteOptions<
238
+ TRouteTree,
239
+ TFrom,
240
+ TTo,
241
+ TMaskFrom,
242
+ TMaskTo
243
+ >,
244
+ ): false | RouteById<TRouteTree, TResolved>['types']['allParams'] => {
245
+ const { pending, caseSensitive, ...rest } = opts
246
+
247
+ return matchRoute(rest as any, {
248
+ pending,
249
+ caseSensitive,
250
+ })
251
+ },
252
+ [],
253
+ )
254
+ }
255
+
256
+ export type MakeMatchRouteOptions<
257
+ TRouteTree extends AnyRoute = RegisteredRouter['routeTree'],
258
+ TFrom extends RoutePaths<TRouteTree> = '/',
259
+ TTo extends string = '',
260
+ TMaskFrom extends RoutePaths<TRouteTree> = '/',
261
+ TMaskTo extends string = '',
262
+ > = ToOptions<TRouteTree, TFrom, TTo, TMaskFrom, TMaskTo> &
263
+ MatchRouteOptions & {
264
+ // If a function is passed as a child, it will be given the `isActive` boolean to aid in further styling on the element it returns
265
+ children?:
266
+ | ((
267
+ params?: RouteByPath<
268
+ TRouteTree,
269
+ ResolveRelativePath<TFrom, NoInfer<TTo>>
270
+ >['types']['allParams'],
271
+ ) => ReactNode)
272
+ | React.ReactNode
273
+ }
274
+
275
+ export function MatchRoute<
276
+ TRouteTree extends AnyRoute = RegisteredRouter['routeTree'],
277
+ TFrom extends RoutePaths<TRouteTree> = '/',
278
+ TTo extends string = '',
279
+ TMaskFrom extends RoutePaths<TRouteTree> = '/',
280
+ TMaskTo extends string = '',
281
+ >(
282
+ props: MakeMatchRouteOptions<TRouteTree, TFrom, TTo, TMaskFrom, TMaskTo>,
283
+ ): any {
284
+ const matchRoute = useMatchRoute()
285
+ const params = matchRoute(props as any)
286
+
287
+ if (typeof props.children === 'function') {
288
+ return (props.children as any)(params)
289
+ }
290
+
291
+ return !!params ? props.children : null
292
+ }
293
+
294
+ export function useMatch<
295
+ TRouteTree extends AnyRoute = RegisteredRouter['routeTree'],
296
+ TFrom extends RouteIds<TRouteTree> = RouteIds<TRouteTree>,
297
+ TStrict extends boolean = true,
298
+ TRouteMatchState = RouteMatch<TRouteTree, TFrom>,
299
+ TSelected = TRouteMatchState,
300
+ >(
301
+ opts: StrictOrFrom<TFrom> & {
302
+ select?: (match: TRouteMatchState) => TSelected
303
+ },
304
+ ): TStrict extends true ? TSelected : TSelected | undefined {
305
+ const nearestMatch = React.useContext(matchesContext)[0]!
306
+ const nearestMatchRouteId = nearestMatch?.routeId
307
+
308
+ const matchRouteId = useRouterState({
309
+ select: (state) => {
310
+ const matches = state.pendingMatches?.some((d) => d.showPending)
311
+ ? state.pendingMatches
312
+ : state.matches
313
+
314
+ const match = opts?.from
315
+ ? matches.find((d) => d.routeId === opts?.from)
316
+ : matches.find((d) => d.id === nearestMatch.id)
317
+
318
+ return match!.routeId
319
+ },
320
+ })
321
+
322
+ if (opts?.strict ?? true) {
323
+ invariant(
324
+ nearestMatchRouteId == matchRouteId,
325
+ `useMatch("${
326
+ matchRouteId as string
327
+ }") is being called in a component that is meant to render the '${nearestMatchRouteId}' route. Did you mean to 'useMatch("${
328
+ matchRouteId as string
329
+ }", { strict: false })' or 'useRoute("${
330
+ matchRouteId as string
331
+ }")' instead?`,
332
+ )
333
+ }
334
+
335
+ const matchSelection = useRouterState({
336
+ select: (state) => {
337
+ const matches = state.pendingMatches?.some((d) => d.showPending)
338
+ ? state.pendingMatches
339
+ : state.matches
340
+
341
+ const match = opts?.from
342
+ ? matches.find((d) => d.routeId === opts?.from)
343
+ : matches.find((d) => d.id === nearestMatch.id)
344
+
345
+ invariant(
346
+ match,
347
+ `Could not find ${
348
+ opts?.from
349
+ ? `an active match from "${opts.from}"`
350
+ : 'a nearest match!'
351
+ }`,
352
+ )
353
+
354
+ return opts?.select ? opts.select(match as any) : match
355
+ },
356
+ })
357
+
358
+ return matchSelection as any
359
+ }
360
+
361
+ export const matchesContext = React.createContext<RouteMatch[]>(null!)
362
+
363
+ export function useMatches<T = RouteMatch[]>(opts?: {
364
+ select?: (matches: RouteMatch[]) => T
365
+ }): T {
366
+ const contextMatches = React.useContext(matchesContext)
367
+
368
+ return useRouterState({
369
+ select: (state) => {
370
+ let matches = state.pendingMatches?.some((d) => d.showPending)
371
+ ? state.pendingMatches
372
+ : state.matches
373
+
374
+ matches = matches.slice(
375
+ matches.findIndex((d) => d.id === contextMatches[0]?.id),
376
+ )
377
+ return opts?.select ? opts.select(matches) : (matches as T)
378
+ },
379
+ })
380
+ }
381
+
382
+ export function useLoaderData<
383
+ TRouteTree extends AnyRoute = RegisteredRouter['routeTree'],
384
+ TFrom extends RouteIds<TRouteTree> = RouteIds<TRouteTree>,
385
+ TStrict extends boolean = true,
386
+ TRouteMatch extends RouteMatch<TRouteTree, TFrom> = RouteMatch<
387
+ TRouteTree,
388
+ TFrom
389
+ >,
390
+ TSelected = TRouteMatch['loaderData'],
391
+ >(
392
+ opts: StrictOrFrom<TFrom> & {
393
+ select?: (match: TRouteMatch) => TSelected
394
+ },
395
+ ): TStrict extends true ? TSelected : TSelected | undefined {
396
+ const match = useMatch({ ...opts, select: undefined })!
397
+
398
+ return typeof opts.select === 'function'
399
+ ? opts.select(match?.loaderData)
400
+ : match?.loaderData
401
+ }