@tanstack/react-router 0.0.1-beta.219 → 0.0.1-beta.220
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/Matches.js.map +1 -1
- package/build/cjs/RouterProvider.js +51 -17
- package/build/cjs/RouterProvider.js.map +1 -1
- package/build/cjs/awaited.js +45 -0
- package/build/cjs/awaited.js.map +1 -0
- package/build/cjs/defer.js +39 -0
- package/build/cjs/defer.js.map +1 -0
- package/build/cjs/index.js +7 -0
- package/build/cjs/index.js.map +1 -1
- package/build/cjs/router.js +0 -43
- package/build/cjs/router.js.map +1 -1
- package/build/cjs/utils.js +6 -0
- package/build/cjs/utils.js.map +1 -1
- package/build/esm/index.js +602 -559
- package/build/esm/index.js.map +1 -1
- package/build/stats-html.html +1 -1
- package/build/stats-react.json +392 -329
- package/build/types/RouterProvider.d.ts +5 -0
- package/build/types/awaited.d.ts +8 -0
- package/build/types/defer.d.ts +19 -0
- package/build/types/index.d.ts +2 -0
- package/build/types/utils.d.ts +1 -0
- package/build/umd/index.development.js +606 -558
- 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/Matches.tsx +1 -1
- package/src/RouterProvider.tsx +85 -24
- package/src/awaited.tsx +40 -40
- package/src/defer.ts +48 -48
- package/src/index.tsx +2 -2
- package/src/router.ts +0 -50
- package/src/utils.ts +7 -0
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-beta.
|
|
4
|
+
"version": "0.0.1-beta.220",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": "tanstack/router",
|
|
7
7
|
"homepage": "https://tanstack.com/router",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"@babel/runtime": "^7.16.7",
|
|
43
43
|
"tiny-invariant": "^1.3.1",
|
|
44
44
|
"tiny-warning": "^1.0.3",
|
|
45
|
-
"@tanstack/history": "0.0.1-beta.
|
|
45
|
+
"@tanstack/history": "0.0.1-beta.220"
|
|
46
46
|
},
|
|
47
47
|
"scripts": {
|
|
48
48
|
"build": "rollup --config rollup.config.js"
|
package/src/Matches.tsx
CHANGED
|
@@ -8,7 +8,7 @@ import { ResolveRelativePath, ToOptions } from './link'
|
|
|
8
8
|
import { AnyRoute, ReactNode, rootRouteId } from './route'
|
|
9
9
|
import { RouteById, RouteByPath, RouteIds, RoutePaths } from './routeInfo'
|
|
10
10
|
import { RegisteredRouter } from './router'
|
|
11
|
-
import { NoInfer, StrictOrFrom
|
|
11
|
+
import { NoInfer, StrictOrFrom } from './utils'
|
|
12
12
|
|
|
13
13
|
export function Matches() {
|
|
14
14
|
const { routesById, state } = useRouter()
|
package/src/RouterProvider.tsx
CHANGED
|
@@ -61,6 +61,7 @@ import {
|
|
|
61
61
|
pick,
|
|
62
62
|
replaceEqualDeep,
|
|
63
63
|
useStableCallback,
|
|
64
|
+
escapeJSON,
|
|
64
65
|
} from './utils'
|
|
65
66
|
import { MatchRouteOptions } from './Matches'
|
|
66
67
|
|
|
@@ -116,6 +117,8 @@ export type BuildLocationFn<TRouteTree extends AnyRoute> = (
|
|
|
116
117
|
opts: BuildNextOptions,
|
|
117
118
|
) => ParsedLocation
|
|
118
119
|
|
|
120
|
+
export type InjectedHtmlEntry = string | (() => Promise<string> | string)
|
|
121
|
+
|
|
119
122
|
export type RouterContext<
|
|
120
123
|
TRouteTree extends AnyRoute,
|
|
121
124
|
// TDehydrated extends Record<string, any>,
|
|
@@ -132,6 +135,13 @@ export type RouterContext<
|
|
|
132
135
|
buildLocation: BuildLocationFn<TRouteTree>
|
|
133
136
|
subscribe: Router<TRouteTree>['subscribe']
|
|
134
137
|
resetNextScrollRef: React.MutableRefObject<boolean>
|
|
138
|
+
injectedHtmlRef: React.MutableRefObject<InjectedHtmlEntry[]>
|
|
139
|
+
injectHtml: (entry: InjectedHtmlEntry) => void
|
|
140
|
+
dehydrateData: <T>(
|
|
141
|
+
key: any,
|
|
142
|
+
getData: T | (() => Promise<T> | T),
|
|
143
|
+
) => () => void
|
|
144
|
+
hydrateData: <T>(key: any) => T | undefined
|
|
135
145
|
}
|
|
136
146
|
|
|
137
147
|
export const routerContext = React.createContext<RouterContext<any>>(null!)
|
|
@@ -986,21 +996,24 @@ export function RouterProvider<
|
|
|
986
996
|
|
|
987
997
|
// Default to reloading the route all the time
|
|
988
998
|
let shouldReload = true
|
|
989
|
-
let shouldReloadDeps =
|
|
990
|
-
typeof route.options.shouldReload === 'function'
|
|
991
|
-
? route.options.shouldReload?.(loaderContext)
|
|
992
|
-
: !!route.options.shouldReload
|
|
993
|
-
|
|
994
|
-
if (typeof shouldReloadDeps === 'object') {
|
|
995
|
-
// compare the deps to see if they've changed
|
|
996
|
-
shouldReload = !deepEqual(
|
|
997
|
-
shouldReloadDeps,
|
|
998
|
-
match.shouldReloadDeps,
|
|
999
|
-
)
|
|
1000
999
|
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1000
|
+
if (cause !== 'enter') {
|
|
1001
|
+
let shouldReloadDeps =
|
|
1002
|
+
typeof route.options.shouldReload === 'function'
|
|
1003
|
+
? route.options.shouldReload?.(loaderContext)
|
|
1004
|
+
: !!(route.options.shouldReload ?? true)
|
|
1005
|
+
|
|
1006
|
+
if (typeof shouldReloadDeps === 'object') {
|
|
1007
|
+
// compare the deps to see if they've changed
|
|
1008
|
+
shouldReload = !deepEqual(
|
|
1009
|
+
shouldReloadDeps,
|
|
1010
|
+
match.shouldReloadDeps,
|
|
1011
|
+
)
|
|
1012
|
+
|
|
1013
|
+
match.shouldReloadDeps = shouldReloadDeps
|
|
1014
|
+
} else {
|
|
1015
|
+
shouldReload = !!shouldReloadDeps
|
|
1016
|
+
}
|
|
1004
1017
|
}
|
|
1005
1018
|
|
|
1006
1019
|
// If the user doesn't want the route to reload, just
|
|
@@ -1377,16 +1390,6 @@ export function RouterProvider<
|
|
|
1377
1390
|
}
|
|
1378
1391
|
}, [history])
|
|
1379
1392
|
|
|
1380
|
-
React.useLayoutEffect(() => {
|
|
1381
|
-
startReactTransition(() => {
|
|
1382
|
-
try {
|
|
1383
|
-
load()
|
|
1384
|
-
} catch (err) {
|
|
1385
|
-
console.error(err)
|
|
1386
|
-
}
|
|
1387
|
-
})
|
|
1388
|
-
}, [])
|
|
1389
|
-
|
|
1390
1393
|
const matchRoute = useStableCallback<MatchRouteFn<TRouteTree>>(
|
|
1391
1394
|
(location, opts) => {
|
|
1392
1395
|
location = {
|
|
@@ -1429,6 +1432,60 @@ export function RouterProvider<
|
|
|
1429
1432
|
},
|
|
1430
1433
|
)
|
|
1431
1434
|
|
|
1435
|
+
const injectedHtmlRef = React.useRef<InjectedHtmlEntry[]>([])
|
|
1436
|
+
|
|
1437
|
+
const injectHtml = useStableCallback(
|
|
1438
|
+
async (html: string | (() => Promise<string> | string)) => {
|
|
1439
|
+
injectedHtmlRef.current.push(html)
|
|
1440
|
+
},
|
|
1441
|
+
)
|
|
1442
|
+
|
|
1443
|
+
const dehydrateData = useStableCallback(
|
|
1444
|
+
<T,>(key: any, getData: T | (() => Promise<T> | T)) => {
|
|
1445
|
+
if (typeof document === 'undefined') {
|
|
1446
|
+
const strKey = typeof key === 'string' ? key : JSON.stringify(key)
|
|
1447
|
+
|
|
1448
|
+
injectHtml(async () => {
|
|
1449
|
+
const id = `__TSR_DEHYDRATED__${strKey}`
|
|
1450
|
+
const data =
|
|
1451
|
+
typeof getData === 'function' ? await (getData as any)() : getData
|
|
1452
|
+
return `<script id='${id}' suppressHydrationWarning>window["__TSR_DEHYDRATED__${escapeJSON(
|
|
1453
|
+
strKey,
|
|
1454
|
+
)}"] = ${JSON.stringify(data)}
|
|
1455
|
+
;(() => {
|
|
1456
|
+
var el = document.getElementById('${id}')
|
|
1457
|
+
el.parentElement.removeChild(el)
|
|
1458
|
+
})()
|
|
1459
|
+
</script>`
|
|
1460
|
+
})
|
|
1461
|
+
|
|
1462
|
+
return () => hydrateData<T>(key)
|
|
1463
|
+
}
|
|
1464
|
+
|
|
1465
|
+
return () => undefined
|
|
1466
|
+
},
|
|
1467
|
+
)
|
|
1468
|
+
|
|
1469
|
+
const hydrateData = useStableCallback(<T extends any = unknown>(key: any) => {
|
|
1470
|
+
if (typeof document !== 'undefined') {
|
|
1471
|
+
const strKey = typeof key === 'string' ? key : JSON.stringify(key)
|
|
1472
|
+
|
|
1473
|
+
return window[`__TSR_DEHYDRATED__${strKey}` as any] as T
|
|
1474
|
+
}
|
|
1475
|
+
|
|
1476
|
+
return undefined
|
|
1477
|
+
})
|
|
1478
|
+
|
|
1479
|
+
React.useLayoutEffect(() => {
|
|
1480
|
+
startReactTransition(() => {
|
|
1481
|
+
try {
|
|
1482
|
+
load()
|
|
1483
|
+
} catch (err) {
|
|
1484
|
+
console.error(err)
|
|
1485
|
+
}
|
|
1486
|
+
})
|
|
1487
|
+
}, [])
|
|
1488
|
+
|
|
1432
1489
|
const routerContextValue: RouterContext<TRouteTree> = {
|
|
1433
1490
|
routeTree: router.routeTree,
|
|
1434
1491
|
navigate,
|
|
@@ -1442,6 +1499,10 @@ export function RouterProvider<
|
|
|
1442
1499
|
buildLocation,
|
|
1443
1500
|
subscribe: router.subscribe,
|
|
1444
1501
|
resetNextScrollRef,
|
|
1502
|
+
injectedHtmlRef,
|
|
1503
|
+
injectHtml,
|
|
1504
|
+
dehydrateData,
|
|
1505
|
+
hydrateData,
|
|
1445
1506
|
}
|
|
1446
1507
|
|
|
1447
1508
|
return (
|
package/src/awaited.tsx
CHANGED
|
@@ -1,40 +1,40 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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 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
CHANGED
|
@@ -1,55 +1,55 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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
17
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
export type DeferredPromise<T> = Promise<T> & {
|
|
19
|
+
__deferredState: DeferredPromiseState<T>
|
|
20
|
+
}
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
export function defer<T>(_promise: Promise<T>) {
|
|
23
|
+
const promise = _promise as DeferredPromise<T>
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
25
|
+
if (!promise.__deferredState) {
|
|
26
|
+
promise.__deferredState = {
|
|
27
|
+
uid: Math.random().toString(36).slice(2),
|
|
28
|
+
status: 'pending',
|
|
29
|
+
}
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
const state = promise.__deferredState
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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
43
|
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
return promise
|
|
45
|
+
}
|
|
46
46
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
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/index.tsx
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
export * from '@tanstack/history'
|
|
3
3
|
export { default as invariant } from 'tiny-invariant'
|
|
4
4
|
export { default as warning } from 'tiny-warning'
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
export * from './awaited'
|
|
6
|
+
export * from './defer'
|
|
7
7
|
export * from './CatchBoundary'
|
|
8
8
|
export * from './fileRoute'
|
|
9
9
|
export * from './history'
|
package/src/router.ts
CHANGED
|
@@ -281,49 +281,6 @@ export class Router<
|
|
|
281
281
|
// })
|
|
282
282
|
// }
|
|
283
283
|
|
|
284
|
-
// TODO:
|
|
285
|
-
// injectedHtml: (string | (() => Promise<string> | string))[] = []
|
|
286
|
-
|
|
287
|
-
// TODO:
|
|
288
|
-
// injectHtml = async (html: string | (() => Promise<string> | string)) => {
|
|
289
|
-
// this.injectedHtml.push(html)
|
|
290
|
-
// }
|
|
291
|
-
|
|
292
|
-
// TODO:
|
|
293
|
-
// dehydrateData = <T>(key: any, getData: T | (() => Promise<T> | T)) => {
|
|
294
|
-
// if (typeof document === 'undefined') {
|
|
295
|
-
// const strKey = typeof key === 'string' ? key : JSON.stringify(key)
|
|
296
|
-
|
|
297
|
-
// this.injectHtml(async () => {
|
|
298
|
-
// const id = `__TSR_DEHYDRATED__${strKey}`
|
|
299
|
-
// const data =
|
|
300
|
-
// typeof getData === 'function' ? await (getData as any)() : getData
|
|
301
|
-
// return `<script id='${id}' suppressHydrationWarning>window["__TSR_DEHYDRATED__${escapeJSON(
|
|
302
|
-
// strKey,
|
|
303
|
-
// )}"] = ${JSON.stringify(data)}
|
|
304
|
-
// ;(() => {
|
|
305
|
-
// var el = document.getElementById('${id}')
|
|
306
|
-
// el.parentElement.removeChild(el)
|
|
307
|
-
// })()
|
|
308
|
-
// </script>`
|
|
309
|
-
// })
|
|
310
|
-
|
|
311
|
-
// return () => this.hydrateData<T>(key)
|
|
312
|
-
// }
|
|
313
|
-
|
|
314
|
-
// return () => undefined
|
|
315
|
-
// }
|
|
316
|
-
|
|
317
|
-
// hydrateData = <T = unknown>(key: any) => {
|
|
318
|
-
// if (typeof document !== 'undefined') {
|
|
319
|
-
// const strKey = typeof key === 'string' ? key : JSON.stringify(key)
|
|
320
|
-
|
|
321
|
-
// return window[`__TSR_DEHYDRATED__${strKey}` as any] as T
|
|
322
|
-
// }
|
|
323
|
-
|
|
324
|
-
// return undefined
|
|
325
|
-
// }
|
|
326
|
-
|
|
327
284
|
// resolveMatchPromise = (matchId: string, key: string, value: any) => {
|
|
328
285
|
// state.matches
|
|
329
286
|
// .find((d) => d.id === matchId)
|
|
@@ -359,13 +316,6 @@ export class Router<
|
|
|
359
316
|
// }
|
|
360
317
|
}
|
|
361
318
|
|
|
362
|
-
function escapeJSON(jsonString: string) {
|
|
363
|
-
return jsonString
|
|
364
|
-
.replace(/\\/g, '\\\\') // Escape backslashes
|
|
365
|
-
.replace(/'/g, "\\'") // Escape single quotes
|
|
366
|
-
.replace(/"/g, '\\"') // Escape double quotes
|
|
367
|
-
}
|
|
368
|
-
|
|
369
319
|
// A function that takes an import() argument which is a function and returns a new function that will
|
|
370
320
|
// proxy arguments from the caller to the imported function, retaining all type
|
|
371
321
|
// information along the way
|
package/src/utils.ts
CHANGED
|
@@ -341,3 +341,10 @@ export function useRouteContext<
|
|
|
341
341
|
|
|
342
342
|
export const useLayoutEffect =
|
|
343
343
|
typeof window !== 'undefined' ? React.useLayoutEffect : React.useEffect
|
|
344
|
+
|
|
345
|
+
export function escapeJSON(jsonString: string) {
|
|
346
|
+
return jsonString
|
|
347
|
+
.replace(/\\/g, '\\\\') // Escape backslashes
|
|
348
|
+
.replace(/'/g, "\\'") // Escape single quotes
|
|
349
|
+
.replace(/"/g, '\\"') // Escape double quotes
|
|
350
|
+
}
|