@tanstack/react-router 0.0.1-alpha.2 → 0.0.1-alpha.4
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/build/cjs/react-router/src/index.js +111 -118
- package/build/cjs/react-router/src/index.js.map +1 -1
- package/build/cjs/router-core/build/esm/index.js +85 -54
- package/build/cjs/router-core/build/esm/index.js.map +1 -1
- package/build/esm/index.js +195 -173
- package/build/esm/index.js.map +1 -1
- package/build/stats-html.html +1 -1
- package/build/stats-react.json +29 -29
- package/build/types/index.d.ts +10 -1
- package/build/umd/index.development.js +190 -170
- package/build/umd/index.development.js.map +1 -1
- package/build/umd/index.production.js +1 -1
- package/build/umd/index.production.js.map +1 -1
- package/package.json +2 -2
- package/src/index.tsx +203 -198
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/react-router",
|
|
3
3
|
"author": "Tanner Linsley",
|
|
4
|
-
"version": "0.0.1-alpha.
|
|
4
|
+
"version": "0.0.1-alpha.4",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": "tanstack/router",
|
|
7
7
|
"homepage": "https://react-router.tanstack.com/",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"@babel/runtime": "^7.16.7",
|
|
43
|
-
"@tanstack/router-core": "0.0.1-alpha.
|
|
43
|
+
"@tanstack/router-core": "0.0.1-alpha.4",
|
|
44
44
|
"use-sync-external-store": "^1.2.0"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
package/src/index.tsx
CHANGED
|
@@ -6,7 +6,6 @@ import {
|
|
|
6
6
|
AnyRoute,
|
|
7
7
|
RootRouteId,
|
|
8
8
|
rootRouteId,
|
|
9
|
-
Route,
|
|
10
9
|
Router,
|
|
11
10
|
} from '@tanstack/router-core'
|
|
12
11
|
import {
|
|
@@ -29,6 +28,7 @@ import {
|
|
|
29
28
|
ResolveRelativePath,
|
|
30
29
|
NoInfer,
|
|
31
30
|
ToOptions,
|
|
31
|
+
invariant,
|
|
32
32
|
} from '@tanstack/router-core'
|
|
33
33
|
|
|
34
34
|
export * from '@tanstack/router-core'
|
|
@@ -55,34 +55,34 @@ declare module '@tanstack/router-core' {
|
|
|
55
55
|
useMatch: <TId extends keyof TAllRouteInfo['routeInfoById']>(
|
|
56
56
|
routeId: TId,
|
|
57
57
|
) => RouteMatch<TAllRouteInfo, TAllRouteInfo['routeInfoById'][TId]>
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
58
|
+
linkProps: <TTo extends string = '.'>(
|
|
59
|
+
props: LinkPropsOptions<TAllRouteInfo, '/', TTo> &
|
|
60
|
+
React.AnchorHTMLAttributes<HTMLAnchorElement>,
|
|
61
|
+
) => React.AnchorHTMLAttributes<HTMLAnchorElement>
|
|
62
|
+
Link: <TTo extends string = '.'>(
|
|
63
|
+
props: LinkPropsOptions<TAllRouteInfo, '/', TTo> &
|
|
64
|
+
React.AnchorHTMLAttributes<HTMLAnchorElement> &
|
|
65
|
+
Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, 'children'> & {
|
|
66
|
+
// 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
|
|
67
|
+
children?:
|
|
68
|
+
| React.ReactNode
|
|
69
|
+
| ((state: { isActive: boolean }) => React.ReactNode)
|
|
70
|
+
},
|
|
71
|
+
) => JSX.Element
|
|
72
|
+
MatchRoute: <TTo extends string = '.'>(
|
|
73
|
+
props: ToOptions<TAllRouteInfo, '/', TTo> &
|
|
74
|
+
MatchRouteOptions & {
|
|
75
|
+
// 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
|
|
76
|
+
children?:
|
|
77
|
+
| React.ReactNode
|
|
78
|
+
| ((
|
|
79
|
+
params: RouteInfoByPath<
|
|
80
|
+
TAllRouteInfo,
|
|
81
|
+
ResolveRelativePath<'/', NoInfer<TTo>>
|
|
82
|
+
>['allParams'],
|
|
83
|
+
) => React.ReactNode)
|
|
84
|
+
},
|
|
85
|
+
) => JSX.Element
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
interface Route<
|
|
@@ -174,6 +174,148 @@ const useRouterSubscription = (router: Router<any, any>) => {
|
|
|
174
174
|
export function createReactRouter<
|
|
175
175
|
TRouteConfig extends AnyRouteConfig = RouteConfig,
|
|
176
176
|
>(opts: RouterOptions<TRouteConfig>): Router<TRouteConfig> {
|
|
177
|
+
const makeRouteExt = (
|
|
178
|
+
route: AnyRoute,
|
|
179
|
+
router: Router<any, any>,
|
|
180
|
+
): Pick<AnyRoute, 'linkProps' | 'Link' | 'MatchRoute'> => {
|
|
181
|
+
return {
|
|
182
|
+
linkProps: (options) => {
|
|
183
|
+
const {
|
|
184
|
+
// custom props
|
|
185
|
+
type,
|
|
186
|
+
children,
|
|
187
|
+
target,
|
|
188
|
+
activeProps = () => ({ className: 'active' }),
|
|
189
|
+
inactiveProps = () => ({}),
|
|
190
|
+
activeOptions,
|
|
191
|
+
disabled,
|
|
192
|
+
// fromCurrent,
|
|
193
|
+
hash,
|
|
194
|
+
search,
|
|
195
|
+
params,
|
|
196
|
+
to,
|
|
197
|
+
preload,
|
|
198
|
+
preloadDelay,
|
|
199
|
+
preloadMaxAge,
|
|
200
|
+
replace,
|
|
201
|
+
// element props
|
|
202
|
+
style,
|
|
203
|
+
className,
|
|
204
|
+
onClick,
|
|
205
|
+
onFocus,
|
|
206
|
+
onMouseEnter,
|
|
207
|
+
onMouseLeave,
|
|
208
|
+
onTouchStart,
|
|
209
|
+
onTouchEnd,
|
|
210
|
+
...rest
|
|
211
|
+
} = options
|
|
212
|
+
|
|
213
|
+
const linkInfo = route.buildLink(options)
|
|
214
|
+
|
|
215
|
+
if (linkInfo.type === 'external') {
|
|
216
|
+
const { href } = linkInfo
|
|
217
|
+
return { href }
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const {
|
|
221
|
+
handleClick,
|
|
222
|
+
handleFocus,
|
|
223
|
+
handleEnter,
|
|
224
|
+
handleLeave,
|
|
225
|
+
isActive,
|
|
226
|
+
next,
|
|
227
|
+
} = linkInfo
|
|
228
|
+
|
|
229
|
+
const composeHandlers =
|
|
230
|
+
(handlers: (undefined | ((e: any) => void))[]) =>
|
|
231
|
+
(e: React.SyntheticEvent) => {
|
|
232
|
+
e.persist()
|
|
233
|
+
handlers.forEach((handler) => {
|
|
234
|
+
if (handler) handler(e)
|
|
235
|
+
})
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Get the active props
|
|
239
|
+
const resolvedActiveProps: React.HTMLAttributes<HTMLAnchorElement> =
|
|
240
|
+
isActive ? functionalUpdate(activeProps) ?? {} : {}
|
|
241
|
+
|
|
242
|
+
// Get the inactive props
|
|
243
|
+
const resolvedInactiveProps: React.HTMLAttributes<HTMLAnchorElement> =
|
|
244
|
+
isActive ? {} : functionalUpdate(inactiveProps) ?? {}
|
|
245
|
+
|
|
246
|
+
return {
|
|
247
|
+
...resolvedActiveProps,
|
|
248
|
+
...resolvedInactiveProps,
|
|
249
|
+
...rest,
|
|
250
|
+
href: disabled ? undefined : next.href,
|
|
251
|
+
onClick: composeHandlers([handleClick, onClick]),
|
|
252
|
+
onFocus: composeHandlers([handleFocus, onFocus]),
|
|
253
|
+
onMouseEnter: composeHandlers([handleEnter, onMouseEnter]),
|
|
254
|
+
onMouseLeave: composeHandlers([handleLeave, onMouseLeave]),
|
|
255
|
+
target,
|
|
256
|
+
style: {
|
|
257
|
+
...style,
|
|
258
|
+
...resolvedActiveProps.style,
|
|
259
|
+
...resolvedInactiveProps.style,
|
|
260
|
+
},
|
|
261
|
+
className:
|
|
262
|
+
[
|
|
263
|
+
className,
|
|
264
|
+
resolvedActiveProps.className,
|
|
265
|
+
resolvedInactiveProps.className,
|
|
266
|
+
]
|
|
267
|
+
.filter(Boolean)
|
|
268
|
+
.join(' ') || undefined,
|
|
269
|
+
...(disabled
|
|
270
|
+
? {
|
|
271
|
+
role: 'link',
|
|
272
|
+
'aria-disabled': true,
|
|
273
|
+
}
|
|
274
|
+
: undefined),
|
|
275
|
+
['data-status']: isActive ? 'active' : undefined,
|
|
276
|
+
}
|
|
277
|
+
},
|
|
278
|
+
Link: React.forwardRef((props: any, ref) => {
|
|
279
|
+
const linkProps = route.linkProps(props)
|
|
280
|
+
|
|
281
|
+
useRouterSubscription(router)
|
|
282
|
+
|
|
283
|
+
return (
|
|
284
|
+
<a
|
|
285
|
+
{...{
|
|
286
|
+
ref: ref as any,
|
|
287
|
+
...linkProps,
|
|
288
|
+
children:
|
|
289
|
+
typeof props.children === 'function'
|
|
290
|
+
? props.children({
|
|
291
|
+
isActive: (linkProps as any)['data-status'] === 'active',
|
|
292
|
+
})
|
|
293
|
+
: props.children,
|
|
294
|
+
}}
|
|
295
|
+
/>
|
|
296
|
+
)
|
|
297
|
+
}) as any,
|
|
298
|
+
MatchRoute: (opts) => {
|
|
299
|
+
const { pending, caseSensitive, children, ...rest } = opts
|
|
300
|
+
|
|
301
|
+
const params = route.matchRoute(rest as any, {
|
|
302
|
+
pending,
|
|
303
|
+
caseSensitive,
|
|
304
|
+
})
|
|
305
|
+
|
|
306
|
+
// useRouterSubscription(router)
|
|
307
|
+
|
|
308
|
+
if (!params) {
|
|
309
|
+
return null
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
return typeof opts.children === 'function'
|
|
313
|
+
? opts.children(params as any)
|
|
314
|
+
: (opts.children as any)
|
|
315
|
+
},
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
177
319
|
const coreRouter = createRouter<TRouteConfig>({
|
|
178
320
|
...opts,
|
|
179
321
|
createRouter: (router) => {
|
|
@@ -181,194 +323,57 @@ export function createReactRouter<
|
|
|
181
323
|
useRoute: (routeId) => {
|
|
182
324
|
const route = router.getRoute(routeId)
|
|
183
325
|
useRouterSubscription(router)
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
}
|
|
326
|
+
invariant(
|
|
327
|
+
route,
|
|
328
|
+
`Could not find a route for route "${
|
|
329
|
+
routeId as string
|
|
330
|
+
}"! Did you forget to add it to your route config?`,
|
|
331
|
+
)
|
|
191
332
|
return route
|
|
192
333
|
},
|
|
193
334
|
useMatch: (routeId) => {
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
335
|
+
invariant(
|
|
336
|
+
routeId !== rootRouteId,
|
|
337
|
+
`"${rootRouteId}" cannot be used with useMatch! Did you mean to useRoute("${rootRouteId}")?`,
|
|
338
|
+
)
|
|
339
|
+
|
|
199
340
|
const runtimeMatch = useMatch()
|
|
200
341
|
const match = router.state.matches.find((d) => d.routeId === routeId)
|
|
201
342
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
}
|
|
343
|
+
invariant(
|
|
344
|
+
match,
|
|
345
|
+
`Could not find a match for route "${
|
|
346
|
+
routeId as string
|
|
347
|
+
}" being rendered in this component!`,
|
|
348
|
+
)
|
|
209
349
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
}
|
|
350
|
+
invariant(
|
|
351
|
+
runtimeMatch.routeId == match?.routeId,
|
|
352
|
+
`useMatch('${
|
|
353
|
+
match?.routeId as string
|
|
354
|
+
}') is being called in a component that is meant to render the '${
|
|
355
|
+
runtimeMatch.routeId
|
|
356
|
+
}' route. Did you mean to 'useRoute(${
|
|
357
|
+
match?.routeId as string
|
|
358
|
+
})' instead?`,
|
|
359
|
+
)
|
|
221
360
|
|
|
222
361
|
useRouterSubscription(router)
|
|
223
362
|
|
|
224
363
|
if (!match) {
|
|
225
|
-
|
|
364
|
+
invariant('Match not found!')
|
|
226
365
|
}
|
|
227
366
|
|
|
228
367
|
return match
|
|
229
368
|
},
|
|
230
369
|
}
|
|
231
370
|
|
|
232
|
-
|
|
371
|
+
const routeExt = makeRouteExt(router.getRoute('/'), router)
|
|
372
|
+
|
|
373
|
+
Object.assign(router, routerExt, routeExt)
|
|
233
374
|
},
|
|
234
375
|
createRoute: ({ router, route }) => {
|
|
235
|
-
const routeExt
|
|
236
|
-
linkProps: (options) => {
|
|
237
|
-
const {
|
|
238
|
-
// custom props
|
|
239
|
-
type,
|
|
240
|
-
children,
|
|
241
|
-
target,
|
|
242
|
-
activeProps = () => ({ className: 'active' }),
|
|
243
|
-
inactiveProps = () => ({}),
|
|
244
|
-
activeOptions,
|
|
245
|
-
disabled,
|
|
246
|
-
// fromCurrent,
|
|
247
|
-
hash,
|
|
248
|
-
search,
|
|
249
|
-
params,
|
|
250
|
-
to,
|
|
251
|
-
preload,
|
|
252
|
-
preloadDelay,
|
|
253
|
-
preloadMaxAge,
|
|
254
|
-
replace,
|
|
255
|
-
// element props
|
|
256
|
-
style,
|
|
257
|
-
className,
|
|
258
|
-
onClick,
|
|
259
|
-
onFocus,
|
|
260
|
-
onMouseEnter,
|
|
261
|
-
onMouseLeave,
|
|
262
|
-
onTouchStart,
|
|
263
|
-
onTouchEnd,
|
|
264
|
-
...rest
|
|
265
|
-
} = options
|
|
266
|
-
|
|
267
|
-
const linkInfo = route.buildLink(options)
|
|
268
|
-
|
|
269
|
-
if (linkInfo.type === 'external') {
|
|
270
|
-
const { href } = linkInfo
|
|
271
|
-
return { href }
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
const {
|
|
275
|
-
handleClick,
|
|
276
|
-
handleFocus,
|
|
277
|
-
handleEnter,
|
|
278
|
-
handleLeave,
|
|
279
|
-
isActive,
|
|
280
|
-
next,
|
|
281
|
-
} = linkInfo
|
|
282
|
-
|
|
283
|
-
const composeHandlers =
|
|
284
|
-
(handlers: (undefined | ((e: any) => void))[]) =>
|
|
285
|
-
(e: React.SyntheticEvent) => {
|
|
286
|
-
e.persist()
|
|
287
|
-
handlers.forEach((handler) => {
|
|
288
|
-
if (handler) handler(e)
|
|
289
|
-
})
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
// Get the active props
|
|
293
|
-
const resolvedActiveProps: React.HTMLAttributes<HTMLAnchorElement> =
|
|
294
|
-
isActive ? functionalUpdate(activeProps) ?? {} : {}
|
|
295
|
-
|
|
296
|
-
// Get the inactive props
|
|
297
|
-
const resolvedInactiveProps: React.HTMLAttributes<HTMLAnchorElement> =
|
|
298
|
-
isActive ? {} : functionalUpdate(inactiveProps) ?? {}
|
|
299
|
-
|
|
300
|
-
return {
|
|
301
|
-
...resolvedActiveProps,
|
|
302
|
-
...resolvedInactiveProps,
|
|
303
|
-
...rest,
|
|
304
|
-
href: disabled ? undefined : next.href,
|
|
305
|
-
onClick: composeHandlers([handleClick, onClick]),
|
|
306
|
-
onFocus: composeHandlers([handleFocus, onFocus]),
|
|
307
|
-
onMouseEnter: composeHandlers([handleEnter, onMouseEnter]),
|
|
308
|
-
onMouseLeave: composeHandlers([handleLeave, onMouseLeave]),
|
|
309
|
-
target,
|
|
310
|
-
style: {
|
|
311
|
-
...style,
|
|
312
|
-
...resolvedActiveProps.style,
|
|
313
|
-
...resolvedInactiveProps.style,
|
|
314
|
-
},
|
|
315
|
-
className:
|
|
316
|
-
[
|
|
317
|
-
className,
|
|
318
|
-
resolvedActiveProps.className,
|
|
319
|
-
resolvedInactiveProps.className,
|
|
320
|
-
]
|
|
321
|
-
.filter(Boolean)
|
|
322
|
-
.join(' ') || undefined,
|
|
323
|
-
...(disabled
|
|
324
|
-
? {
|
|
325
|
-
role: 'link',
|
|
326
|
-
'aria-disabled': true,
|
|
327
|
-
}
|
|
328
|
-
: undefined),
|
|
329
|
-
['data-status']: isActive ? 'active' : undefined,
|
|
330
|
-
}
|
|
331
|
-
},
|
|
332
|
-
Link: React.forwardRef((props: any, ref) => {
|
|
333
|
-
const linkProps = route.linkProps(props)
|
|
334
|
-
|
|
335
|
-
useRouterSubscription(router)
|
|
336
|
-
|
|
337
|
-
return (
|
|
338
|
-
<a
|
|
339
|
-
{...{
|
|
340
|
-
ref: ref as any,
|
|
341
|
-
...linkProps,
|
|
342
|
-
children:
|
|
343
|
-
typeof props.children === 'function'
|
|
344
|
-
? props.children({
|
|
345
|
-
isActive:
|
|
346
|
-
(linkProps as any)['data-status'] === 'active',
|
|
347
|
-
})
|
|
348
|
-
: props.children,
|
|
349
|
-
}}
|
|
350
|
-
/>
|
|
351
|
-
)
|
|
352
|
-
}) as any,
|
|
353
|
-
MatchRoute: (opts) => {
|
|
354
|
-
const { pending, caseSensitive, children, ...rest } = opts
|
|
355
|
-
|
|
356
|
-
const params = route.matchRoute(rest as any, {
|
|
357
|
-
pending,
|
|
358
|
-
caseSensitive,
|
|
359
|
-
})
|
|
360
|
-
|
|
361
|
-
// useRouterSubscription(router)
|
|
362
|
-
|
|
363
|
-
if (!params) {
|
|
364
|
-
return null
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
return typeof opts.children === 'function'
|
|
368
|
-
? opts.children(params as any)
|
|
369
|
-
: (opts.children as any)
|
|
370
|
-
},
|
|
371
|
-
}
|
|
376
|
+
const routeExt = makeRouteExt(route, router)
|
|
372
377
|
|
|
373
378
|
Object.assign(route, routeExt)
|
|
374
379
|
},
|