@tanstack/react-router 0.0.1-beta.203 → 0.0.1-beta.205

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 (73) hide show
  1. package/build/cjs/RouterProvider.js +961 -0
  2. package/build/cjs/RouterProvider.js.map +1 -0
  3. package/build/cjs/fileRoute.js +29 -0
  4. package/build/cjs/fileRoute.js.map +1 -0
  5. package/build/cjs/index.js +69 -21
  6. package/build/cjs/index.js.map +1 -1
  7. package/build/cjs/path.js +211 -0
  8. package/build/cjs/path.js.map +1 -0
  9. package/build/cjs/qss.js +65 -0
  10. package/build/cjs/qss.js.map +1 -0
  11. package/build/cjs/react.js +148 -190
  12. package/build/cjs/react.js.map +1 -1
  13. package/build/cjs/redirects.js +27 -0
  14. package/build/cjs/redirects.js.map +1 -0
  15. package/build/cjs/route.js +136 -0
  16. package/build/cjs/route.js.map +1 -0
  17. package/build/cjs/router.js +203 -0
  18. package/build/cjs/router.js.map +1 -0
  19. package/build/cjs/searchParams.js +83 -0
  20. package/build/cjs/searchParams.js.map +1 -0
  21. package/build/cjs/utils.js +196 -0
  22. package/build/cjs/utils.js.map +1 -0
  23. package/build/esm/index.js +1799 -211
  24. package/build/esm/index.js.map +1 -1
  25. package/build/stats-html.html +1 -1
  26. package/build/stats-react.json +385 -164
  27. package/build/types/RouteMatch.d.ts +23 -0
  28. package/build/types/RouterProvider.d.ts +54 -0
  29. package/build/types/awaited.d.ts +0 -8
  30. package/build/types/defer.d.ts +0 -0
  31. package/build/types/fileRoute.d.ts +17 -0
  32. package/build/types/history.d.ts +7 -0
  33. package/build/types/index.d.ts +17 -4
  34. package/build/types/link.d.ts +98 -0
  35. package/build/types/location.d.ts +14 -0
  36. package/build/types/path.d.ts +16 -0
  37. package/build/types/qss.d.ts +2 -0
  38. package/build/types/react.d.ts +23 -83
  39. package/build/types/redirects.d.ts +10 -0
  40. package/build/types/route.d.ts +222 -0
  41. package/build/types/routeInfo.d.ts +22 -0
  42. package/build/types/router.d.ts +115 -0
  43. package/build/types/scroll-restoration.d.ts +0 -3
  44. package/build/types/searchParams.d.ts +7 -0
  45. package/build/types/utils.d.ts +48 -0
  46. package/build/umd/index.development.js +1116 -1540
  47. package/build/umd/index.development.js.map +1 -1
  48. package/build/umd/index.production.js +2 -33
  49. package/build/umd/index.production.js.map +1 -1
  50. package/package.json +4 -4
  51. package/src/RouteMatch.ts +28 -0
  52. package/src/RouterProvider.tsx +1384 -0
  53. package/src/awaited.tsx +40 -40
  54. package/src/defer.ts +55 -0
  55. package/src/fileRoute.ts +143 -0
  56. package/src/history.ts +8 -0
  57. package/src/index.tsx +18 -5
  58. package/src/link.ts +347 -0
  59. package/src/location.ts +14 -0
  60. package/src/path.ts +256 -0
  61. package/src/qss.ts +53 -0
  62. package/src/react.tsx +174 -422
  63. package/src/redirects.ts +31 -0
  64. package/src/route.ts +710 -0
  65. package/src/routeInfo.ts +68 -0
  66. package/src/router.ts +373 -0
  67. package/src/scroll-restoration.tsx +205 -27
  68. package/src/searchParams.ts +78 -0
  69. package/src/utils.ts +257 -0
  70. package/build/cjs/awaited.js +0 -45
  71. package/build/cjs/awaited.js.map +0 -1
  72. package/build/cjs/scroll-restoration.js +0 -56
  73. package/build/cjs/scroll-restoration.js.map +0 -1
@@ -0,0 +1,68 @@
1
+ import { AnyRoute, Route } from './route'
2
+ import { Expand, UnionToIntersection } from './utils'
3
+
4
+ export type ParseRoute<TRouteTree extends AnyRoute> =
5
+ | TRouteTree
6
+ | ParseRouteChildren<TRouteTree>
7
+
8
+ export type ParseRouteChildren<TRouteTree extends AnyRoute> =
9
+ TRouteTree extends Route<
10
+ any,
11
+ any,
12
+ any,
13
+ any,
14
+ any,
15
+ any,
16
+ any,
17
+ any,
18
+ any,
19
+ any,
20
+ any,
21
+ any,
22
+ infer TChildren,
23
+ any
24
+ >
25
+ ? unknown extends TChildren
26
+ ? never
27
+ : TChildren extends AnyRoute[]
28
+ ? {
29
+ [TId in TChildren[number]['id'] as string]: ParseRoute<
30
+ TChildren[number]
31
+ >
32
+ }[string]
33
+ : never
34
+ : never
35
+
36
+ export type RoutesById<TRouteTree extends AnyRoute> = {
37
+ [K in ParseRoute<TRouteTree> as K['id']]: K
38
+ }
39
+
40
+ export type RouteById<TRouteTree extends AnyRoute, TId> = Extract<
41
+ ParseRoute<TRouteTree>,
42
+ { id: TId }
43
+ >
44
+
45
+ export type RouteIds<TRouteTree extends AnyRoute> = ParseRoute<TRouteTree>['id']
46
+
47
+ export type RoutesByPath<TRouteTree extends AnyRoute> = {
48
+ [K in ParseRoute<TRouteTree> as K['fullPath']]: K
49
+ }
50
+
51
+ export type RouteByPath<TRouteTree extends AnyRoute, TPath> = Extract<
52
+ ParseRoute<TRouteTree>,
53
+ { fullPath: TPath }
54
+ >
55
+
56
+ export type RoutePaths<TRouteTree extends AnyRoute> =
57
+ | ParseRoute<TRouteTree>['fullPath']
58
+ | '/'
59
+
60
+ export type FullSearchSchema<TRouteTree extends AnyRoute> = Partial<
61
+ Expand<
62
+ UnionToIntersection<ParseRoute<TRouteTree>['types']['fullSearchSchema']>
63
+ >
64
+ >
65
+
66
+ export type AllParams<TRouteTree extends AnyRoute> = Expand<
67
+ UnionToIntersection<ParseRoute<TRouteTree>['types']['allParams']>
68
+ >
package/src/router.ts ADDED
@@ -0,0 +1,373 @@
1
+ import { RouterHistory } from '@tanstack/history'
2
+
3
+ //
4
+
5
+ import {
6
+ AnySearchSchema,
7
+ AnyRoute,
8
+ AnyContext,
9
+ AnyPathParams,
10
+ RouteMask,
11
+ } from './route'
12
+ import { FullSearchSchema } from './routeInfo'
13
+ import { defaultParseSearch, defaultStringifySearch } from './searchParams'
14
+ import { PickAsRequired, Updater, NonNullableUpdater } from './utils'
15
+ import {
16
+ ErrorRouteComponent,
17
+ PendingRouteComponent,
18
+ RouteComponent,
19
+ } from './react'
20
+ import { RouteMatch } from './RouteMatch'
21
+ import { ParsedLocation } from './location'
22
+ import { LocationState } from './location'
23
+ import { SearchSerializer, SearchParser } from './searchParams'
24
+
25
+ //
26
+
27
+ declare global {
28
+ interface Window {
29
+ __TSR_DEHYDRATED__?: HydrationCtx
30
+ }
31
+ }
32
+
33
+ export interface Register {
34
+ // router: Router
35
+ }
36
+
37
+ export type AnyRouter = Router<any, any>
38
+
39
+ export type RegisteredRouter = Register extends {
40
+ router: infer TRouter extends AnyRouter
41
+ }
42
+ ? TRouter
43
+ : AnyRouter
44
+
45
+ export type HydrationCtx = {
46
+ router: DehydratedRouter
47
+ payload: Record<string, any>
48
+ }
49
+
50
+ export type RouterContextOptions<TRouteTree extends AnyRoute> =
51
+ AnyContext extends TRouteTree['types']['routerMeta']
52
+ ? {
53
+ meta?: TRouteTree['types']['routerMeta']
54
+ }
55
+ : {
56
+ meta: TRouteTree['types']['routerMeta']
57
+ }
58
+
59
+ export interface RouterOptions<
60
+ TRouteTree extends AnyRoute,
61
+ TDehydrated extends Record<string, any> = Record<string, any>,
62
+ > {
63
+ history?: RouterHistory
64
+ stringifySearch?: SearchSerializer
65
+ parseSearch?: SearchParser
66
+ defaultPreload?: false | 'intent'
67
+ defaultPreloadDelay?: number
68
+ defaultComponent?: RouteComponent<AnySearchSchema, AnyPathParams, AnyContext>
69
+ defaultErrorComponent?: ErrorRouteComponent<
70
+ AnySearchSchema,
71
+ AnyPathParams,
72
+ AnyContext
73
+ >
74
+ defaultPendingComponent?: PendingRouteComponent<
75
+ AnySearchSchema,
76
+ AnyPathParams,
77
+ AnyContext
78
+ >
79
+ defaultMaxAge?: number
80
+ defaultGcMaxAge?: number
81
+ defaultPreloadMaxAge?: number
82
+ caseSensitive?: boolean
83
+ routeTree?: TRouteTree
84
+ basepath?: string
85
+ createRoute?: (opts: { route: AnyRoute; router: AnyRouter }) => void
86
+ meta?: TRouteTree['types']['routerMeta']
87
+ // dehydrate?: () => TDehydrated
88
+ // hydrate?: (dehydrated: TDehydrated) => void
89
+ routeMasks?: RouteMask<TRouteTree>[]
90
+ unmaskOnReload?: boolean
91
+ }
92
+
93
+ export interface RouterState<TRouteTree extends AnyRoute = AnyRoute> {
94
+ status: 'idle' | 'pending'
95
+ isFetching: boolean
96
+ matches: RouteMatch<TRouteTree>[]
97
+ pendingMatches: RouteMatch<TRouteTree>[]
98
+ location: ParsedLocation<FullSearchSchema<TRouteTree>>
99
+ resolvedLocation: ParsedLocation<FullSearchSchema<TRouteTree>>
100
+ lastUpdated: number
101
+ }
102
+
103
+ export type ListenerFn<TEvent extends RouterEvent> = (event: TEvent) => void
104
+
105
+ export interface BuildNextOptions {
106
+ to?: string | number | null
107
+ params?: true | Updater<unknown>
108
+ search?: true | Updater<unknown>
109
+ hash?: true | Updater<string>
110
+ state?: true | NonNullableUpdater<LocationState>
111
+ mask?: {
112
+ to?: string | number | null
113
+ params?: true | Updater<unknown>
114
+ search?: true | Updater<unknown>
115
+ hash?: true | Updater<string>
116
+ state?: true | NonNullableUpdater<LocationState>
117
+ unmaskOnReload?: boolean
118
+ }
119
+ from?: string
120
+ }
121
+
122
+ export interface DehydratedRouterState {
123
+ dehydratedMatches: DehydratedRouteMatch[]
124
+ }
125
+
126
+ export type DehydratedRouteMatch = Pick<
127
+ RouteMatch,
128
+ 'fetchedAt' | 'invalid' | 'id' | 'status' | 'updatedAt'
129
+ >
130
+
131
+ export interface DehydratedRouter {
132
+ state: DehydratedRouterState
133
+ }
134
+
135
+ export type RouterConstructorOptions<
136
+ TRouteTree extends AnyRoute,
137
+ TDehydrated extends Record<string, any>,
138
+ > = Omit<RouterOptions<TRouteTree, TDehydrated>, 'context'> &
139
+ RouterContextOptions<TRouteTree>
140
+
141
+ export const componentTypes = [
142
+ 'component',
143
+ 'errorComponent',
144
+ 'pendingComponent',
145
+ ] as const
146
+
147
+ export type RouterEvents = {
148
+ onBeforeLoad: {
149
+ type: 'onBeforeLoad'
150
+ from: ParsedLocation
151
+ to: ParsedLocation
152
+ pathChanged: boolean
153
+ }
154
+ onLoad: {
155
+ type: 'onLoad'
156
+ from: ParsedLocation
157
+ to: ParsedLocation
158
+ pathChanged: boolean
159
+ }
160
+ }
161
+
162
+ export type RouterEvent = RouterEvents[keyof RouterEvents]
163
+
164
+ export type RouterListener<TRouterEvent extends RouterEvent> = {
165
+ eventType: TRouterEvent['type']
166
+ fn: ListenerFn<TRouterEvent>
167
+ }
168
+
169
+ export class Router<
170
+ TRouteTree extends AnyRoute = AnyRoute,
171
+ TDehydrated extends Record<string, any> = Record<string, any>,
172
+ > {
173
+ options: PickAsRequired<
174
+ RouterOptions<TRouteTree, TDehydrated>,
175
+ 'stringifySearch' | 'parseSearch' | 'meta'
176
+ >
177
+ routeTree: TRouteTree
178
+ // dehydratedData?: TDehydrated
179
+ // resetNextScroll = false
180
+ // tempLocationKey = `${Math.round(Math.random() * 10000000)}`
181
+
182
+ constructor(options: RouterConstructorOptions<TRouteTree, TDehydrated>) {
183
+ this.options = {
184
+ defaultPreloadDelay: 50,
185
+ meta: undefined!,
186
+ ...options,
187
+ stringifySearch: options?.stringifySearch ?? defaultStringifySearch,
188
+ parseSearch: options?.parseSearch ?? defaultParseSearch,
189
+ }
190
+
191
+ this.routeTree = this.options.routeTree as TRouteTree
192
+ }
193
+
194
+ subscribers = new Set<RouterListener<RouterEvent>>()
195
+
196
+ subscribe = <TType extends keyof RouterEvents>(
197
+ eventType: TType,
198
+ fn: ListenerFn<RouterEvents[TType]>,
199
+ ) => {
200
+ const listener: RouterListener<any> = {
201
+ eventType,
202
+ fn,
203
+ }
204
+
205
+ this.subscribers.add(listener)
206
+
207
+ return () => {
208
+ this.subscribers.delete(listener)
209
+ }
210
+ }
211
+
212
+ emit = (routerEvent: RouterEvent) => {
213
+ this.subscribers.forEach((listener) => {
214
+ if (listener.eventType === routerEvent.type) {
215
+ listener.fn(routerEvent)
216
+ }
217
+ })
218
+ }
219
+
220
+ // dehydrate = (): DehydratedRouter => {
221
+ // return {
222
+ // state: {
223
+ // dehydratedMatches: state.matches.map((d) =>
224
+ // pick(d, ['fetchedAt', 'invalid', 'id', 'status', 'updatedAt']),
225
+ // ),
226
+ // },
227
+ // }
228
+ // }
229
+
230
+ // hydrate = async (__do_not_use_server_ctx?: HydrationCtx) => {
231
+ // let _ctx = __do_not_use_server_ctx
232
+ // // Client hydrates from window
233
+ // if (typeof document !== 'undefined') {
234
+ // _ctx = window.__TSR_DEHYDRATED__
235
+ // }
236
+
237
+ // invariant(
238
+ // _ctx,
239
+ // 'Expected to find a __TSR_DEHYDRATED__ property on window... but we did not. Did you forget to render <DehydrateRouter /> in your app?',
240
+ // )
241
+
242
+ // const ctx = _ctx
243
+ // this.dehydratedData = ctx.payload as any
244
+ // this.options.hydrate?.(ctx.payload as any)
245
+ // const dehydratedState = ctx.router.state
246
+
247
+ // let matches = this.matchRoutes(
248
+ // state.location.pathname,
249
+ // state.location.search,
250
+ // ).map((match) => {
251
+ // const dehydratedMatch = dehydratedState.dehydratedMatches.find(
252
+ // (d) => d.id === match.id,
253
+ // )
254
+
255
+ // invariant(
256
+ // dehydratedMatch,
257
+ // `Could not find a client-side match for dehydrated match with id: ${match.id}!`,
258
+ // )
259
+
260
+ // if (dehydratedMatch) {
261
+ // return {
262
+ // ...match,
263
+ // ...dehydratedMatch,
264
+ // }
265
+ // }
266
+ // return match
267
+ // })
268
+
269
+ // this.setState((s) => {
270
+ // return {
271
+ // ...s,
272
+ // matches: dehydratedState.dehydratedMatches as any,
273
+ // }
274
+ // })
275
+ // }
276
+
277
+ // TODO:
278
+ // injectedHtml: (string | (() => Promise<string> | string))[] = []
279
+
280
+ // TODO:
281
+ // injectHtml = async (html: string | (() => Promise<string> | string)) => {
282
+ // this.injectedHtml.push(html)
283
+ // }
284
+
285
+ // TODO:
286
+ // dehydrateData = <T>(key: any, getData: T | (() => Promise<T> | T)) => {
287
+ // if (typeof document === 'undefined') {
288
+ // const strKey = typeof key === 'string' ? key : JSON.stringify(key)
289
+
290
+ // this.injectHtml(async () => {
291
+ // const id = `__TSR_DEHYDRATED__${strKey}`
292
+ // const data =
293
+ // typeof getData === 'function' ? await (getData as any)() : getData
294
+ // return `<script id='${id}' suppressHydrationWarning>window["__TSR_DEHYDRATED__${escapeJSON(
295
+ // strKey,
296
+ // )}"] = ${JSON.stringify(data)}
297
+ // ;(() => {
298
+ // var el = document.getElementById('${id}')
299
+ // el.parentElement.removeChild(el)
300
+ // })()
301
+ // </script>`
302
+ // })
303
+
304
+ // return () => this.hydrateData<T>(key)
305
+ // }
306
+
307
+ // return () => undefined
308
+ // }
309
+
310
+ // hydrateData = <T = unknown>(key: any) => {
311
+ // if (typeof document !== 'undefined') {
312
+ // const strKey = typeof key === 'string' ? key : JSON.stringify(key)
313
+
314
+ // return window[`__TSR_DEHYDRATED__${strKey}` as any] as T
315
+ // }
316
+
317
+ // return undefined
318
+ // }
319
+
320
+ // resolveMatchPromise = (matchId: string, key: string, value: any) => {
321
+ // state.matches
322
+ // .find((d) => d.id === matchId)
323
+ // ?.__promisesByKey[key]?.resolve(value)
324
+ // }
325
+
326
+ // setRouteMatch = (
327
+ // id: string,
328
+ // pending: boolean,
329
+ // updater: NonNullableUpdater<RouteMatch<TRouteTree>>,
330
+ // ) => {
331
+ // const key = pending ? 'pendingMatches' : 'matches'
332
+
333
+ // this.setState((prev) => {
334
+ // return {
335
+ // ...prev,
336
+ // [key]: prev[key].map((d) => {
337
+ // if (d.id === id) {
338
+ // return functionalUpdate(updater, d)
339
+ // }
340
+
341
+ // return d
342
+ // }),
343
+ // }
344
+ // })
345
+ // }
346
+
347
+ // setPendingRouteMatch = (
348
+ // id: string,
349
+ // updater: NonNullableUpdater<RouteMatch<TRouteTree>>,
350
+ // ) => {
351
+ // this.setRouteMatch(id, true, updater)
352
+ // }
353
+ }
354
+
355
+ function escapeJSON(jsonString: string) {
356
+ return jsonString
357
+ .replace(/\\/g, '\\\\') // Escape backslashes
358
+ .replace(/'/g, "\\'") // Escape single quotes
359
+ .replace(/"/g, '\\"') // Escape double quotes
360
+ }
361
+
362
+ // A function that takes an import() argument which is a function and returns a new function that will
363
+ // proxy arguments from the caller to the imported function, retaining all type
364
+ // information along the way
365
+ export function lazyFn<
366
+ T extends Record<string, (...args: any[]) => any>,
367
+ TKey extends keyof T = 'default',
368
+ >(fn: () => Promise<T>, key?: TKey) {
369
+ return async (...args: Parameters<T[TKey]>): Promise<ReturnType<T[TKey]>> => {
370
+ const imported = await fn()
371
+ return imported[key || 'default'](...args)
372
+ }
373
+ }
@@ -1,27 +1,205 @@
1
- import * as React from 'react'
2
- import {
3
- ScrollRestorationOptions,
4
- restoreScrollPositions,
5
- watchScrollPositions,
6
- } from '@tanstack/router-core'
7
- import { useRouter } from './react'
8
-
9
- const useLayoutEffect =
10
- typeof window !== 'undefined' ? React.useLayoutEffect : React.useEffect
11
-
12
- export function useScrollRestoration(options?: ScrollRestorationOptions) {
13
- const router = useRouter()
14
-
15
- useLayoutEffect(() => {
16
- return watchScrollPositions(router, options)
17
- }, [])
18
-
19
- useLayoutEffect(() => {
20
- restoreScrollPositions(router, options)
21
- })
22
- }
23
-
24
- export function ScrollRestoration(props: ScrollRestorationOptions) {
25
- useScrollRestoration(props)
26
- return null
27
- }
1
+ // import * as React from 'react'
2
+ // import { useRouter } from './react'
3
+
4
+ // const useLayoutEffect =
5
+ // typeof window !== 'undefined' ? React.useLayoutEffect : React.useEffect
6
+
7
+ // import { AnyRouter, RouterState } from './router'
8
+ // import { ParsedLocation } from './location'
9
+
10
+ // const windowKey = 'window'
11
+ // const delimiter = '___'
12
+
13
+ // let weakScrolledElementsByRestoreKey: Record<string, WeakSet<any>> = {}
14
+
15
+ // type CacheValue = Record<string, { scrollX: number; scrollY: number }>
16
+
17
+ // type Cache = {
18
+ // current: CacheValue
19
+ // set: (key: string, value: any) => void
20
+ // }
21
+
22
+ // let cache: Cache
23
+
24
+ // let pathDidChange = false
25
+
26
+ // const sessionsStorage = typeof window !== 'undefined' && window.sessionStorage
27
+
28
+ // export type ScrollRestorationOptions = {
29
+ // getKey?: (location: ParsedLocation) => string
30
+ // }
31
+
32
+ // const defaultGetKey = (location: ParsedLocation) => location.state.key!
33
+
34
+ // export function watchScrollPositions(
35
+ // router: AnyRouter,
36
+ // state: RouterState,
37
+ // opts?: ScrollRestorationOptions,
38
+ // ) {
39
+ // const getKey = opts?.getKey || defaultGetKey
40
+
41
+ // if (sessionsStorage) {
42
+ // if (!cache) {
43
+ // cache = (() => {
44
+ // const storageKey = 'tsr-scroll-restoration-v1'
45
+
46
+ // const current: CacheValue = JSON.parse(
47
+ // window.sessionStorage.getItem(storageKey) || '{}',
48
+ // )
49
+
50
+ // return {
51
+ // current,
52
+ // set: (key: string, value: any) => {
53
+ // current[key] = value
54
+ // window.sessionStorage.setItem(storageKey, JSON.stringify(cache))
55
+ // },
56
+ // }
57
+ // })()
58
+ // }
59
+ // }
60
+
61
+ // const { history } = window
62
+ // if (history.scrollRestoration) {
63
+ // history.scrollRestoration = 'manual'
64
+ // }
65
+
66
+ // const onScroll = (event: Event) => {
67
+ // const restoreKey = getKey(state.resolvedLocation)
68
+
69
+ // if (!weakScrolledElementsByRestoreKey[restoreKey]) {
70
+ // weakScrolledElementsByRestoreKey[restoreKey] = new WeakSet()
71
+ // }
72
+
73
+ // const set = weakScrolledElementsByRestoreKey[restoreKey]!
74
+
75
+ // if (set.has(event.target)) return
76
+ // set.add(event.target)
77
+
78
+ // const cacheKey = [
79
+ // restoreKey,
80
+ // event.target === document || event.target === window
81
+ // ? windowKey
82
+ // : getCssSelector(event.target),
83
+ // ].join(delimiter)
84
+
85
+ // if (!cache.current[cacheKey]) {
86
+ // cache.set(cacheKey, {
87
+ // scrollX: NaN,
88
+ // scrollY: NaN,
89
+ // })
90
+ // }
91
+ // }
92
+
93
+ // const getCssSelector = (el: any): string => {
94
+ // let path = [],
95
+ // parent
96
+ // while ((parent = el.parentNode)) {
97
+ // path.unshift(
98
+ // `${el.tagName}:nth-child(${
99
+ // ([].indexOf as any).call(parent.children, el) + 1
100
+ // })`,
101
+ // )
102
+ // el = parent
103
+ // }
104
+ // return `${path.join(' > ')}`.toLowerCase()
105
+ // }
106
+
107
+ // const onPathWillChange = (from: ParsedLocation) => {
108
+ // const restoreKey = getKey(from)
109
+ // for (const cacheKey in cache.current) {
110
+ // const entry = cache.current[cacheKey]!
111
+ // const [key, elementSelector] = cacheKey.split(delimiter)
112
+ // if (restoreKey === key) {
113
+ // if (elementSelector === windowKey) {
114
+ // entry.scrollX = window.scrollX || 0
115
+ // entry.scrollY = window.scrollY || 0
116
+ // } else if (elementSelector) {
117
+ // const element = document.querySelector(elementSelector)
118
+ // entry.scrollX = element?.scrollLeft || 0
119
+ // entry.scrollY = element?.scrollTop || 0
120
+ // }
121
+
122
+ // cache.set(cacheKey, entry)
123
+ // }
124
+ // }
125
+ // }
126
+
127
+ // const onPathChange = () => {
128
+ // pathDidChange = true
129
+ // }
130
+
131
+ // if (typeof document !== 'undefined') {
132
+ // document.addEventListener('scroll', onScroll, true)
133
+ // }
134
+
135
+ // const unsubOnBeforeLoad = router.subscribe('onBeforeLoad', (event) => {
136
+ // if (event.pathChanged) onPathWillChange(event.from)
137
+ // })
138
+
139
+ // const unsubOnLoad = router.subscribe('onLoad', (event) => {
140
+ // if (event.pathChanged) onPathChange()
141
+ // })
142
+
143
+ // return () => {
144
+ // document.removeEventListener('scroll', onScroll)
145
+ // unsubOnBeforeLoad()
146
+ // unsubOnLoad()
147
+ // }
148
+ // }
149
+
150
+ // export function restoreScrollPositions(
151
+ // router: AnyRouter,
152
+ // state: RouterState,
153
+ // opts?: ScrollRestorationOptions,
154
+ // ) {
155
+ // if (pathDidChange) {
156
+ // if (!router.resetNextScroll) {
157
+ // return
158
+ // }
159
+
160
+ // const getKey = opts?.getKey || defaultGetKey
161
+
162
+ // pathDidChange = false
163
+
164
+ // const restoreKey = getKey(state.location)
165
+ // let windowRestored = false
166
+
167
+ // for (const cacheKey in cache.current) {
168
+ // const entry = cache.current[cacheKey]!
169
+ // const [key, elementSelector] = cacheKey.split(delimiter)
170
+ // if (key === restoreKey) {
171
+ // if (elementSelector === windowKey) {
172
+ // windowRestored = true
173
+ // window.scrollTo(entry.scrollX, entry.scrollY)
174
+ // } else if (elementSelector) {
175
+ // const element = document.querySelector(elementSelector)
176
+ // if (element) {
177
+ // element.scrollLeft = entry.scrollX
178
+ // element.scrollTop = entry.scrollY
179
+ // }
180
+ // }
181
+ // }
182
+ // }
183
+
184
+ // if (!windowRestored) {
185
+ // window.scrollTo(0, 0)
186
+ // }
187
+ // }
188
+ // }
189
+
190
+ // export function useScrollRestoration(options?: ScrollRestorationOptions) {
191
+ // const { router, state } = useRouter()
192
+
193
+ // useLayoutEffect(() => {
194
+ // return watchScrollPositions(router, state, options)
195
+ // }, [])
196
+
197
+ // useLayoutEffect(() => {
198
+ // restoreScrollPositions(router, state, options)
199
+ // })
200
+ // }
201
+
202
+ // export function ScrollRestoration(props: ScrollRestorationOptions) {
203
+ // useScrollRestoration(props)
204
+ // return null
205
+ // }