@tanstack/router-core 0.0.1-beta.163 → 0.0.1-beta.165
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/index.js +3 -0
- package/build/cjs/index.js.map +1 -1
- package/build/cjs/router.js.map +1 -1
- package/build/cjs/scroll-restoration.js +136 -0
- package/build/cjs/scroll-restoration.js.map +1 -0
- package/build/esm/index.js +120 -1
- package/build/esm/index.js.map +1 -1
- package/build/stats-html.html +1 -1
- package/build/stats-react.json +139 -114
- package/build/types/index.d.ts +10 -4
- package/build/umd/index.development.js +121 -0
- package/build/umd/index.development.js.map +1 -1
- package/build/umd/index.production.js +2 -2
- package/build/umd/index.production.js.map +1 -1
- package/package.json +2 -2
- package/src/index.ts +1 -0
- package/src/router.ts +3 -3
- package/src/scroll-restoration.ts +175 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/router-core",
|
|
3
3
|
"author": "Tanner Linsley",
|
|
4
|
-
"version": "0.0.1-beta.
|
|
4
|
+
"version": "0.0.1-beta.165",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": "tanstack/router",
|
|
7
7
|
"homepage": "https://tanstack.com/router",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"tiny-invariant": "^1.3.1",
|
|
44
44
|
"tiny-warning": "^1.0.3",
|
|
45
45
|
"@gisatcz/cross-package-react-context": "^0.2.0",
|
|
46
|
-
"@tanstack/react-store": "0.0.1-beta.
|
|
46
|
+
"@tanstack/react-store": "0.0.1-beta.165"
|
|
47
47
|
},
|
|
48
48
|
"scripts": {
|
|
49
49
|
"build": "rollup --config rollup.config.js",
|
package/src/index.ts
CHANGED
package/src/router.ts
CHANGED
|
@@ -186,11 +186,11 @@ export interface RouterState<
|
|
|
186
186
|
> {
|
|
187
187
|
status: 'idle' | 'pending'
|
|
188
188
|
isFetching: boolean
|
|
189
|
-
matchesById: Record<string, RouteMatch<TRouteTree,
|
|
189
|
+
matchesById: Record<string, RouteMatch<TRouteTree, ParseRoute<TRouteTree>>>
|
|
190
190
|
matchIds: string[]
|
|
191
191
|
pendingMatchIds: string[]
|
|
192
|
-
matches: RouteMatch<TRouteTree,
|
|
193
|
-
pendingMatches: RouteMatch<TRouteTree,
|
|
192
|
+
matches: RouteMatch<TRouteTree, ParseRoute<TRouteTree>>[]
|
|
193
|
+
pendingMatches: RouteMatch<TRouteTree, ParseRoute<TRouteTree>>[]
|
|
194
194
|
location: ParsedLocation<FullSearchSchema<TRouteTree>>
|
|
195
195
|
resolvedLocation: ParsedLocation<FullSearchSchema<TRouteTree>>
|
|
196
196
|
lastUpdated: number
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { AnyRouter, ParsedLocation } from './router'
|
|
2
|
+
|
|
3
|
+
const windowKey = 'window'
|
|
4
|
+
const delimiter = '___'
|
|
5
|
+
|
|
6
|
+
let weakScrolledElementsByRestoreKey: Record<string, WeakSet<any>> = {}
|
|
7
|
+
|
|
8
|
+
type CacheValue = Record<string, { scrollX: number; scrollY: number }>
|
|
9
|
+
|
|
10
|
+
type Cache = {
|
|
11
|
+
current: CacheValue
|
|
12
|
+
set: (key: string, value: any) => void
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
let cache: Cache
|
|
16
|
+
|
|
17
|
+
let pathDidChange = false
|
|
18
|
+
|
|
19
|
+
const sessionsStorage = typeof window !== 'undefined' && window.sessionStorage
|
|
20
|
+
|
|
21
|
+
export type ScrollRestorationOptions = {
|
|
22
|
+
getKey?: (location: ParsedLocation) => string
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const defaultGetKey = (location: ParsedLocation) => location.key!
|
|
26
|
+
|
|
27
|
+
export function watchScrollPositions(
|
|
28
|
+
router: AnyRouter,
|
|
29
|
+
opts?: ScrollRestorationOptions,
|
|
30
|
+
) {
|
|
31
|
+
const getKey = opts?.getKey || defaultGetKey
|
|
32
|
+
|
|
33
|
+
if (sessionsStorage) {
|
|
34
|
+
if (!cache) {
|
|
35
|
+
cache = (() => {
|
|
36
|
+
const storageKey = 'tsr-scroll-restoration-v1'
|
|
37
|
+
|
|
38
|
+
const current: CacheValue = JSON.parse(
|
|
39
|
+
window.sessionStorage.getItem(storageKey) || '{}',
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
return {
|
|
43
|
+
current,
|
|
44
|
+
set: (key: string, value: any) => {
|
|
45
|
+
current[key] = value
|
|
46
|
+
window.sessionStorage.setItem(storageKey, JSON.stringify(cache))
|
|
47
|
+
},
|
|
48
|
+
}
|
|
49
|
+
})()
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const { history } = window
|
|
54
|
+
if (history.scrollRestoration) {
|
|
55
|
+
history.scrollRestoration = 'manual'
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const onScroll = (event: Event) => {
|
|
59
|
+
const restoreKey = getKey(router.state.resolvedLocation)
|
|
60
|
+
|
|
61
|
+
if (!weakScrolledElementsByRestoreKey[restoreKey]) {
|
|
62
|
+
weakScrolledElementsByRestoreKey[restoreKey] = new WeakSet()
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const set = weakScrolledElementsByRestoreKey[restoreKey]!
|
|
66
|
+
|
|
67
|
+
if (set.has(event.target)) return
|
|
68
|
+
set.add(event.target)
|
|
69
|
+
|
|
70
|
+
const cacheKey = [
|
|
71
|
+
restoreKey,
|
|
72
|
+
event.target === document || event.target === window
|
|
73
|
+
? windowKey
|
|
74
|
+
: getCssSelector(event.target),
|
|
75
|
+
].join(delimiter)
|
|
76
|
+
|
|
77
|
+
if (!cache.current[cacheKey]) {
|
|
78
|
+
cache.set(cacheKey, {
|
|
79
|
+
scrollX: NaN,
|
|
80
|
+
scrollY: NaN,
|
|
81
|
+
})
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const getCssSelector = (el: any): string => {
|
|
86
|
+
let path = [],
|
|
87
|
+
parent
|
|
88
|
+
while ((parent = el.parentNode)) {
|
|
89
|
+
path.unshift(
|
|
90
|
+
`${el.tagName}:nth-child(${
|
|
91
|
+
([].indexOf as any).call(parent.children, el) + 1
|
|
92
|
+
})`,
|
|
93
|
+
)
|
|
94
|
+
el = parent
|
|
95
|
+
}
|
|
96
|
+
return `${path.join(' > ')}`.toLowerCase()
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const onPathWillChange = (from: ParsedLocation) => {
|
|
100
|
+
const restoreKey = getKey(from)
|
|
101
|
+
for (const cacheKey in cache.current) {
|
|
102
|
+
const entry = cache.current[cacheKey]!
|
|
103
|
+
const [key, elementSelector] = cacheKey.split(delimiter)
|
|
104
|
+
if (restoreKey === key) {
|
|
105
|
+
if (elementSelector === windowKey) {
|
|
106
|
+
entry.scrollX = window.scrollX || 0
|
|
107
|
+
entry.scrollY = window.scrollY || 0
|
|
108
|
+
} else if (elementSelector) {
|
|
109
|
+
const element = document.querySelector(elementSelector)
|
|
110
|
+
entry.scrollX = element?.scrollLeft || 0
|
|
111
|
+
entry.scrollY = element?.scrollTop || 0
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
cache.set(cacheKey, entry)
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const onPathChange = () => {
|
|
120
|
+
pathDidChange = true
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (typeof document !== 'undefined') {
|
|
124
|
+
document.addEventListener('scroll', onScroll, true)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const unsubOnBeforeLoad = router.subscribe('onBeforeLoad', (event) => {
|
|
128
|
+
if (event.pathChanged) onPathWillChange(event.from)
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
const unsubOnLoad = router.subscribe('onLoad', (event) => {
|
|
132
|
+
if (event.pathChanged) onPathChange()
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
return () => {
|
|
136
|
+
document.removeEventListener('scroll', onScroll)
|
|
137
|
+
unsubOnBeforeLoad()
|
|
138
|
+
unsubOnLoad()
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export function restoreScrollPositions(
|
|
143
|
+
router: AnyRouter,
|
|
144
|
+
opts?: ScrollRestorationOptions,
|
|
145
|
+
) {
|
|
146
|
+
if (pathDidChange) {
|
|
147
|
+
const getKey = opts?.getKey || defaultGetKey
|
|
148
|
+
|
|
149
|
+
pathDidChange = false
|
|
150
|
+
|
|
151
|
+
const restoreKey = getKey(router.state.location)
|
|
152
|
+
let windowRestored = false
|
|
153
|
+
|
|
154
|
+
for (const cacheKey in cache.current) {
|
|
155
|
+
const entry = cache.current[cacheKey]!
|
|
156
|
+
const [key, elementSelector] = cacheKey.split(delimiter)
|
|
157
|
+
if (key === restoreKey) {
|
|
158
|
+
if (elementSelector === windowKey) {
|
|
159
|
+
windowRestored = true
|
|
160
|
+
window.scrollTo(entry.scrollX, entry.scrollY)
|
|
161
|
+
} else if (elementSelector) {
|
|
162
|
+
const element = document.querySelector(elementSelector)
|
|
163
|
+
if (element) {
|
|
164
|
+
element.scrollLeft = entry.scrollX
|
|
165
|
+
element.scrollTop = entry.scrollY
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (!windowRestored) {
|
|
172
|
+
window.scrollTo(0, 0)
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|