@tanstack/router-core 1.171.2 → 1.171.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/dist/cjs/index.cjs +0 -3
- package/dist/cjs/index.d.cts +2 -3
- package/dist/cjs/rewrite.cjs +1 -6
- package/dist/cjs/rewrite.cjs.map +1 -1
- package/dist/cjs/rewrite.d.cts +0 -4
- package/dist/cjs/router.cjs +9 -2
- package/dist/cjs/router.cjs.map +1 -1
- package/dist/cjs/router.d.cts +5 -1
- package/dist/cjs/scroll-restoration-inline.cjs +1 -1
- package/dist/cjs/scroll-restoration-inline.cjs.map +1 -1
- package/dist/cjs/scroll-restoration-inline.d.cts +0 -2
- package/dist/cjs/scroll-restoration-script/server.cjs +2 -6
- package/dist/cjs/scroll-restoration-script/server.cjs.map +1 -1
- package/dist/cjs/scroll-restoration.cjs +113 -107
- package/dist/cjs/scroll-restoration.cjs.map +1 -1
- package/dist/cjs/scroll-restoration.d.cts +0 -10
- package/dist/cjs/ssr/ssr-server.cjs +4 -3
- package/dist/cjs/ssr/ssr-server.cjs.map +1 -1
- package/dist/esm/index.d.ts +2 -3
- package/dist/esm/index.js +2 -3
- package/dist/esm/rewrite.d.ts +0 -4
- package/dist/esm/rewrite.js +1 -6
- package/dist/esm/rewrite.js.map +1 -1
- package/dist/esm/router.d.ts +5 -1
- package/dist/esm/router.js +9 -3
- package/dist/esm/router.js.map +1 -1
- package/dist/esm/scroll-restoration-inline.d.ts +0 -2
- package/dist/esm/scroll-restoration-inline.js +1 -1
- package/dist/esm/scroll-restoration-inline.js.map +1 -1
- package/dist/esm/scroll-restoration-script/server.js +2 -6
- package/dist/esm/scroll-restoration-script/server.js.map +1 -1
- package/dist/esm/scroll-restoration.d.ts +0 -10
- package/dist/esm/scroll-restoration.js +114 -107
- package/dist/esm/scroll-restoration.js.map +1 -1
- package/dist/esm/ssr/ssr-server.js +4 -3
- package/dist/esm/ssr/ssr-server.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +1 -3
- package/src/rewrite.ts +1 -8
- package/src/router.ts +28 -4
- package/src/scroll-restoration-inline.ts +7 -16
- package/src/scroll-restoration-script/server.ts +1 -10
- package/src/scroll-restoration.ts +188 -167
- package/src/ssr/ssr-server.ts +12 -8
- package/dist/cjs/hash-scroll.cjs +0 -20
- package/dist/cjs/hash-scroll.cjs.map +0 -1
- package/dist/cjs/hash-scroll.d.cts +0 -7
- package/dist/esm/hash-scroll.d.ts +0 -7
- package/dist/esm/hash-scroll.js +0 -20
- package/dist/esm/hash-scroll.js.map +0 -1
- package/src/hash-scroll.ts +0 -21
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { isServer } from '@tanstack/router-core/isServer'
|
|
2
|
-
import {
|
|
2
|
+
import { locationHistoryActions } from './router'
|
|
3
3
|
import type { AnyRouter } from './router'
|
|
4
4
|
import type { ParsedLocation } from './location'
|
|
5
|
-
import type { NonNullableUpdater } from './utils'
|
|
6
5
|
|
|
7
6
|
export type ScrollRestorationEntry = { scrollX: number; scrollY: number }
|
|
8
7
|
|
|
@@ -10,12 +9,6 @@ type ScrollRestorationByElement = Record<string, ScrollRestorationEntry>
|
|
|
10
9
|
|
|
11
10
|
type ScrollRestorationByKey = Record<string, ScrollRestorationByElement>
|
|
12
11
|
|
|
13
|
-
type ScrollRestorationCache = {
|
|
14
|
-
readonly state: ScrollRestorationByKey
|
|
15
|
-
set: (updater: NonNullableUpdater<ScrollRestorationByKey>) => void
|
|
16
|
-
persist: () => void
|
|
17
|
-
}
|
|
18
|
-
|
|
19
12
|
export type ScrollRestorationOptions = {
|
|
20
13
|
getKey?: (location: ParsedLocation) => string
|
|
21
14
|
scrollBehavior?: ScrollToOptions['behavior']
|
|
@@ -23,60 +16,46 @@ export type ScrollRestorationOptions = {
|
|
|
23
16
|
|
|
24
17
|
function getSafeSessionStorage() {
|
|
25
18
|
try {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
: undefined
|
|
19
|
+
// Accessing sessionStorage itself can throw SecurityError in locked-down
|
|
20
|
+
// contexts, e.g. sandboxed/opaque origins or blocked storage policies.
|
|
21
|
+
return sessionStorage
|
|
30
22
|
} catch {
|
|
31
|
-
|
|
32
|
-
return undefined
|
|
23
|
+
return
|
|
33
24
|
}
|
|
34
25
|
}
|
|
35
26
|
|
|
36
27
|
// SessionStorage key used to store scroll positions across navigations.
|
|
37
28
|
export const storageKey = 'tsr-scroll-restoration-v1_3'
|
|
29
|
+
const safeSessionStorage = getSafeSessionStorage()
|
|
38
30
|
|
|
39
|
-
function createScrollRestorationCache()
|
|
40
|
-
const safeSessionStorage = getSafeSessionStorage()
|
|
41
|
-
if (!safeSessionStorage) {
|
|
42
|
-
return null
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
let state: ScrollRestorationByKey = {}
|
|
46
|
-
|
|
31
|
+
function createScrollRestorationCache() {
|
|
47
32
|
try {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
}
|
|
33
|
+
return JSON.parse(
|
|
34
|
+
safeSessionStorage?.getItem(storageKey) || '{}',
|
|
35
|
+
) as ScrollRestorationByKey
|
|
52
36
|
} catch {
|
|
53
37
|
// ignore invalid session storage payloads
|
|
38
|
+
return {}
|
|
54
39
|
}
|
|
40
|
+
}
|
|
55
41
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
42
|
+
function persistScrollRestorationCache() {
|
|
43
|
+
try {
|
|
44
|
+
safeSessionStorage?.setItem(
|
|
45
|
+
storageKey,
|
|
46
|
+
JSON.stringify(scrollRestorationCache),
|
|
47
|
+
)
|
|
48
|
+
} catch {
|
|
49
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
50
|
+
console.warn(
|
|
51
|
+
'[ts-router] Could not persist scroll restoration state to sessionStorage.',
|
|
52
|
+
)
|
|
65
53
|
}
|
|
66
54
|
}
|
|
67
|
-
|
|
68
|
-
return {
|
|
69
|
-
get state() {
|
|
70
|
-
return state
|
|
71
|
-
},
|
|
72
|
-
set: (updater) => {
|
|
73
|
-
state = functionalUpdate(updater, state) || state
|
|
74
|
-
},
|
|
75
|
-
persist,
|
|
76
|
-
}
|
|
77
55
|
}
|
|
78
56
|
|
|
79
|
-
|
|
57
|
+
const scrollRestorationCache = /* @__PURE__ */ createScrollRestorationCache()
|
|
58
|
+
const scrollRestorationIdAttribute = 'data-scroll-restoration-id'
|
|
80
59
|
|
|
81
60
|
/**
|
|
82
61
|
* The default `getKey` function for `useScrollRestoration`.
|
|
@@ -88,16 +67,29 @@ export const defaultGetScrollRestorationKey = (location: ParsedLocation) => {
|
|
|
88
67
|
return location.state.__TSR_key! || location.href
|
|
89
68
|
}
|
|
90
69
|
|
|
91
|
-
function
|
|
92
|
-
const
|
|
70
|
+
function getScrollRestorationSelector(element: Element): string {
|
|
71
|
+
const attrId = element.getAttribute(scrollRestorationIdAttribute)
|
|
72
|
+
if (attrId) {
|
|
73
|
+
return `[${scrollRestorationIdAttribute}="${attrId}"]`
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
let selector = ''
|
|
77
|
+
let el: any = element
|
|
93
78
|
let parent: HTMLElement
|
|
79
|
+
|
|
94
80
|
while ((parent = el.parentNode)) {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
)
|
|
81
|
+
let index = 1
|
|
82
|
+
let sibling = el
|
|
83
|
+
while ((sibling = sibling.previousElementSibling)) {
|
|
84
|
+
index++
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const part = `${el.localName}:nth-child(${index})`
|
|
88
|
+
selector = selector ? `${part} > ${selector}` : part
|
|
98
89
|
el = parent
|
|
99
90
|
}
|
|
100
|
-
|
|
91
|
+
|
|
92
|
+
return selector
|
|
101
93
|
}
|
|
102
94
|
|
|
103
95
|
export function getElementScrollRestorationEntry(
|
|
@@ -117,11 +109,14 @@ export function getElementScrollRestorationEntry(
|
|
|
117
109
|
): ScrollRestorationEntry | undefined {
|
|
118
110
|
const getKey = options.getKey || defaultGetScrollRestorationKey
|
|
119
111
|
const restoreKey = getKey(router.latestLocation)
|
|
112
|
+
const entries = scrollRestorationCache[restoreKey]
|
|
113
|
+
|
|
114
|
+
if (!entries) {
|
|
115
|
+
return
|
|
116
|
+
}
|
|
120
117
|
|
|
121
118
|
if (options.id) {
|
|
122
|
-
return
|
|
123
|
-
`[${scrollRestorationIdAttribute}="${options.id}"]`
|
|
124
|
-
]
|
|
119
|
+
return entries[`[${scrollRestorationIdAttribute}="${options.id}"]`]
|
|
125
120
|
}
|
|
126
121
|
|
|
127
122
|
const element = options.getElement?.()
|
|
@@ -129,35 +124,55 @@ export function getElementScrollRestorationEntry(
|
|
|
129
124
|
return
|
|
130
125
|
}
|
|
131
126
|
|
|
132
|
-
return
|
|
133
|
-
element
|
|
127
|
+
return entries[
|
|
128
|
+
element === window
|
|
129
|
+
? windowScrollTarget
|
|
130
|
+
: getScrollRestorationSelector(element as Element)
|
|
134
131
|
]
|
|
135
132
|
}
|
|
136
133
|
|
|
137
134
|
let ignoreScroll = false
|
|
138
135
|
const windowScrollTarget = 'window'
|
|
139
|
-
const scrollRestorationIdAttribute = 'data-scroll-restoration-id'
|
|
140
136
|
type ScrollTarget = typeof windowScrollTarget | Element
|
|
141
137
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
return
|
|
138
|
+
function getElement(selector: string | (() => Element | null | undefined)) {
|
|
139
|
+
try {
|
|
140
|
+
return typeof selector === 'function'
|
|
141
|
+
? selector()
|
|
142
|
+
: document.querySelector(selector)
|
|
143
|
+
} catch {}
|
|
144
|
+
return
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function getScrollToTopElements(
|
|
148
|
+
scrollToTopSelectors: NonNullable<
|
|
149
|
+
AnyRouter['options']['scrollToTopSelectors']
|
|
150
|
+
>,
|
|
151
|
+
): Array<Element> {
|
|
152
|
+
const elements: Array<Element> = []
|
|
153
|
+
|
|
154
|
+
for (const selector of scrollToTopSelectors) {
|
|
155
|
+
if (selector === windowScrollTarget) {
|
|
156
|
+
continue
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const element = getElement(selector)
|
|
160
|
+
if (element) {
|
|
161
|
+
elements.push(element)
|
|
162
|
+
}
|
|
145
163
|
}
|
|
146
164
|
|
|
147
|
-
|
|
165
|
+
return elements
|
|
166
|
+
}
|
|
148
167
|
|
|
149
|
-
|
|
150
|
-
|
|
168
|
+
export function setupScrollRestoration(router: AnyRouter, force?: boolean) {
|
|
169
|
+
// Keep hash/top scrolling active even when sessionStorage is unavailable.
|
|
151
170
|
|
|
152
|
-
if (
|
|
171
|
+
if (force ?? router.options.scrollRestoration) {
|
|
153
172
|
router.isScrollRestoring = true
|
|
154
173
|
}
|
|
155
174
|
|
|
156
|
-
if (
|
|
157
|
-
(isServer ?? router.isServer) ||
|
|
158
|
-
router.isScrollRestorationSetup ||
|
|
159
|
-
!cache
|
|
160
|
-
) {
|
|
175
|
+
if ((isServer ?? router.isServer) || router.isScrollRestorationSetup) {
|
|
161
176
|
return
|
|
162
177
|
}
|
|
163
178
|
|
|
@@ -167,88 +182,77 @@ export function setupScrollRestoration(router: AnyRouter, force?: boolean) {
|
|
|
167
182
|
const getKey =
|
|
168
183
|
router.options.getScrollRestorationKey || defaultGetScrollRestorationKey
|
|
169
184
|
const trackedScrollEntries = new Map<ScrollTarget, ScrollRestorationEntry>()
|
|
185
|
+
const setTrackedScrollEntry = (
|
|
186
|
+
target: ScrollTarget,
|
|
187
|
+
scrollX: number,
|
|
188
|
+
scrollY: number,
|
|
189
|
+
) => {
|
|
190
|
+
const entry =
|
|
191
|
+
trackedScrollEntries.get(target) || ({} as ScrollRestorationEntry)
|
|
192
|
+
entry.scrollX = scrollX
|
|
193
|
+
entry.scrollY = scrollY
|
|
194
|
+
trackedScrollEntries.set(target, entry)
|
|
195
|
+
}
|
|
170
196
|
|
|
171
|
-
|
|
197
|
+
history.scrollRestoration = 'manual'
|
|
172
198
|
|
|
173
199
|
const onScroll = (event: Event) => {
|
|
174
200
|
if (ignoreScroll || !router.isScrollRestoring) {
|
|
175
201
|
return
|
|
176
202
|
}
|
|
177
203
|
|
|
178
|
-
if (event.target === document
|
|
179
|
-
|
|
180
|
-
scrollX: window.scrollX || 0,
|
|
181
|
-
scrollY: window.scrollY || 0,
|
|
182
|
-
})
|
|
204
|
+
if (event.target === document) {
|
|
205
|
+
setTrackedScrollEntry(windowScrollTarget, scrollX, scrollY)
|
|
183
206
|
} else {
|
|
184
207
|
const target = event.target as Element
|
|
185
|
-
|
|
186
|
-
scrollX: target.scrollLeft || 0,
|
|
187
|
-
scrollY: target.scrollTop || 0,
|
|
188
|
-
})
|
|
208
|
+
setTrackedScrollEntry(target, target.scrollLeft, target.scrollTop)
|
|
189
209
|
}
|
|
190
210
|
}
|
|
191
211
|
|
|
192
212
|
// Snapshot the current page's tracked scroll targets before navigation or unload.
|
|
193
|
-
const snapshotCurrentScrollTargets = (restoreKey
|
|
194
|
-
if (
|
|
195
|
-
!router.isScrollRestoring ||
|
|
196
|
-
!restoreKey ||
|
|
197
|
-
trackedScrollEntries.size === 0 ||
|
|
198
|
-
!cache
|
|
199
|
-
) {
|
|
213
|
+
const snapshotCurrentScrollTargets = (restoreKey: string) => {
|
|
214
|
+
if (!router.isScrollRestoring) {
|
|
200
215
|
return
|
|
201
216
|
}
|
|
202
217
|
|
|
203
|
-
const keyEntry = (
|
|
218
|
+
const keyEntry = (scrollRestorationCache[restoreKey] ||=
|
|
204
219
|
{} as ScrollRestorationByElement)
|
|
205
220
|
|
|
206
221
|
for (const [target, position] of trackedScrollEntries) {
|
|
207
|
-
let selector: string | undefined
|
|
208
|
-
|
|
209
222
|
if (target === windowScrollTarget) {
|
|
210
|
-
|
|
223
|
+
keyEntry[windowScrollTarget] = position
|
|
211
224
|
} else if (target.isConnected) {
|
|
212
|
-
|
|
213
|
-
selector = attrId
|
|
214
|
-
? `[${scrollRestorationIdAttribute}="${attrId}"]`
|
|
215
|
-
: getCssSelector(target)
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
if (!selector) {
|
|
219
|
-
continue
|
|
225
|
+
keyEntry[getScrollRestorationSelector(target)] = position
|
|
220
226
|
}
|
|
221
|
-
|
|
222
|
-
keyEntry[selector] = position
|
|
223
227
|
}
|
|
224
228
|
}
|
|
225
229
|
|
|
226
230
|
document.addEventListener('scroll', onScroll, true)
|
|
227
231
|
router.subscribe('onBeforeLoad', (event) => {
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
232
|
+
if (event.fromLocation) {
|
|
233
|
+
snapshotCurrentScrollTargets(getKey(event.fromLocation))
|
|
234
|
+
}
|
|
231
235
|
trackedScrollEntries.clear()
|
|
232
236
|
})
|
|
233
|
-
|
|
237
|
+
addEventListener('pagehide', () => {
|
|
234
238
|
snapshotCurrentScrollTargets(
|
|
235
239
|
getKey(
|
|
236
240
|
router.stores.resolvedLocation.get() ?? router.stores.location.get(),
|
|
237
241
|
),
|
|
238
242
|
)
|
|
239
|
-
|
|
243
|
+
persistScrollRestorationCache()
|
|
240
244
|
})
|
|
241
245
|
|
|
242
246
|
// Restore destination scroll after the new route has rendered.
|
|
243
247
|
router.subscribe('onRendered', (event) => {
|
|
244
|
-
const cacheKey = getKey(event.toLocation)
|
|
245
248
|
const behavior = router.options.scrollRestorationBehavior
|
|
246
249
|
const scrollToTopSelectors = router.options.scrollToTopSelectors
|
|
250
|
+
const shouldResetScroll = router.resetNextScroll
|
|
251
|
+
let scrollToTopElements: Array<Element> | undefined
|
|
247
252
|
trackedScrollEntries.clear()
|
|
248
253
|
|
|
249
|
-
if (!
|
|
254
|
+
if (!shouldResetScroll) {
|
|
250
255
|
router.resetNextScroll = true
|
|
251
|
-
return
|
|
252
256
|
}
|
|
253
257
|
|
|
254
258
|
if (
|
|
@@ -258,68 +262,98 @@ export function setupScrollRestoration(router: AnyRouter, force?: boolean) {
|
|
|
258
262
|
return
|
|
259
263
|
}
|
|
260
264
|
|
|
265
|
+
const cacheKey = getKey(event.toLocation)
|
|
266
|
+
const fromCacheKey = event.fromLocation && getKey(event.fromLocation)
|
|
267
|
+
|
|
268
|
+
if (router.isScrollRestoring && fromCacheKey && fromCacheKey !== cacheKey) {
|
|
269
|
+
const fromElementEntries = scrollRestorationCache[fromCacheKey]
|
|
270
|
+
|
|
271
|
+
if (fromElementEntries) {
|
|
272
|
+
let toElementEntries = scrollRestorationCache[cacheKey]
|
|
273
|
+
|
|
274
|
+
for (const elementSelector in fromElementEntries) {
|
|
275
|
+
if (elementSelector === windowScrollTarget) {
|
|
276
|
+
if (shouldResetScroll) {
|
|
277
|
+
continue
|
|
278
|
+
}
|
|
279
|
+
} else {
|
|
280
|
+
const element = getElement(elementSelector)
|
|
281
|
+
if (!element) {
|
|
282
|
+
continue
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
if (shouldResetScroll && scrollToTopSelectors) {
|
|
286
|
+
scrollToTopElements ??=
|
|
287
|
+
getScrollToTopElements(scrollToTopSelectors)
|
|
288
|
+
if (scrollToTopElements.includes(element)) {
|
|
289
|
+
continue
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
if (!toElementEntries) {
|
|
295
|
+
toElementEntries = scrollRestorationCache[cacheKey] =
|
|
296
|
+
{} as ScrollRestorationByElement
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
toElementEntries[elementSelector] ??=
|
|
300
|
+
fromElementEntries[elementSelector]!
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
if (!shouldResetScroll) {
|
|
306
|
+
return
|
|
307
|
+
}
|
|
308
|
+
|
|
261
309
|
ignoreScroll = true
|
|
262
310
|
|
|
263
311
|
try {
|
|
312
|
+
const hash = event.toLocation.hash
|
|
313
|
+
const hashScrollIntoViewOptions =
|
|
314
|
+
event.toLocation.state.__hashScrollIntoViewOptions ?? true
|
|
315
|
+
const action = locationHistoryActions.get(event.toLocation)
|
|
316
|
+
const skipWindowRestore =
|
|
317
|
+
hash &&
|
|
318
|
+
hashScrollIntoViewOptions &&
|
|
319
|
+
(action === 'PUSH' || action === 'REPLACE')
|
|
320
|
+
|
|
264
321
|
const elementEntries = router.isScrollRestoring
|
|
265
|
-
?
|
|
322
|
+
? scrollRestorationCache[cacheKey]
|
|
266
323
|
: undefined
|
|
267
|
-
let
|
|
324
|
+
let windowRestored = false
|
|
268
325
|
|
|
269
326
|
if (elementEntries) {
|
|
270
327
|
for (const elementSelector in elementEntries) {
|
|
271
|
-
const
|
|
272
|
-
|
|
273
|
-
if (!isPlainObject(entry)) {
|
|
274
|
-
continue
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
const { scrollX, scrollY } = entry as {
|
|
278
|
-
scrollX?: unknown
|
|
279
|
-
scrollY?: unknown
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
if (!Number.isFinite(scrollX) || !Number.isFinite(scrollY)) {
|
|
283
|
-
continue
|
|
284
|
-
}
|
|
328
|
+
const { scrollX, scrollY } = elementEntries[elementSelector]!
|
|
285
329
|
|
|
286
330
|
if (elementSelector === windowScrollTarget) {
|
|
287
|
-
|
|
288
|
-
top: scrollY as number,
|
|
289
|
-
left: scrollX as number,
|
|
290
|
-
behavior,
|
|
291
|
-
})
|
|
292
|
-
restored = true
|
|
293
|
-
} else if (elementSelector) {
|
|
294
|
-
let element
|
|
295
|
-
|
|
296
|
-
try {
|
|
297
|
-
element = document.querySelector(elementSelector)
|
|
298
|
-
} catch {
|
|
331
|
+
if (skipWindowRestore) {
|
|
299
332
|
continue
|
|
300
333
|
}
|
|
301
334
|
|
|
335
|
+
scrollTo({
|
|
336
|
+
top: scrollY,
|
|
337
|
+
left: scrollX,
|
|
338
|
+
behavior,
|
|
339
|
+
})
|
|
340
|
+
windowRestored = true
|
|
341
|
+
} else {
|
|
342
|
+
const element = getElement(elementSelector)
|
|
302
343
|
if (element) {
|
|
303
|
-
element.scrollLeft = scrollX
|
|
304
|
-
element.scrollTop = scrollY
|
|
305
|
-
restored = true
|
|
344
|
+
element.scrollLeft = scrollX
|
|
345
|
+
element.scrollTop = scrollY
|
|
306
346
|
}
|
|
307
347
|
}
|
|
308
348
|
}
|
|
309
349
|
}
|
|
310
350
|
|
|
311
|
-
if (!
|
|
312
|
-
const hash = router.history.location.hash.slice(1)
|
|
313
|
-
|
|
351
|
+
if (!windowRestored) {
|
|
314
352
|
if (hash) {
|
|
315
|
-
const hashScrollIntoViewOptions =
|
|
316
|
-
window.history.state?.__hashScrollIntoViewOptions ?? true
|
|
317
|
-
|
|
318
353
|
if (hashScrollIntoViewOptions) {
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
}
|
|
354
|
+
document
|
|
355
|
+
.getElementById(hash)
|
|
356
|
+
?.scrollIntoView(hashScrollIntoViewOptions)
|
|
323
357
|
}
|
|
324
358
|
} else {
|
|
325
359
|
const scrollOptions = {
|
|
@@ -328,17 +362,11 @@ export function setupScrollRestoration(router: AnyRouter, force?: boolean) {
|
|
|
328
362
|
behavior,
|
|
329
363
|
}
|
|
330
364
|
|
|
331
|
-
|
|
365
|
+
scrollTo(scrollOptions)
|
|
332
366
|
if (scrollToTopSelectors) {
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
typeof selector === 'function'
|
|
337
|
-
? selector()
|
|
338
|
-
: document.querySelector(selector)
|
|
339
|
-
if (element) {
|
|
340
|
-
element.scrollTo(scrollOptions)
|
|
341
|
-
}
|
|
367
|
+
scrollToTopElements ??= getScrollToTopElements(scrollToTopSelectors)
|
|
368
|
+
for (const element of scrollToTopElements) {
|
|
369
|
+
element.scrollTo(scrollOptions)
|
|
342
370
|
}
|
|
343
371
|
}
|
|
344
372
|
}
|
|
@@ -346,12 +374,5 @@ export function setupScrollRestoration(router: AnyRouter, force?: boolean) {
|
|
|
346
374
|
} finally {
|
|
347
375
|
ignoreScroll = false
|
|
348
376
|
}
|
|
349
|
-
|
|
350
|
-
if (router.isScrollRestoring) {
|
|
351
|
-
cache.set((state) => {
|
|
352
|
-
state[cacheKey] ||= {} as ScrollRestorationByElement
|
|
353
|
-
return state
|
|
354
|
-
})
|
|
355
|
-
}
|
|
356
377
|
})
|
|
357
378
|
}
|
package/src/ssr/ssr-server.ts
CHANGED
|
@@ -292,23 +292,27 @@ export function attachRouterServerSsrUtils({
|
|
|
292
292
|
}) {
|
|
293
293
|
router.ssr = {
|
|
294
294
|
get manifest() {
|
|
295
|
+
if (!manifest) return manifest
|
|
296
|
+
|
|
295
297
|
const requestAssets = getRequestAssets?.()
|
|
296
|
-
const
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
)
|
|
300
|
-
|
|
298
|
+
const matches = router.stores.matches.get()
|
|
299
|
+
const inlineCssAsset = getInlineCssAssetForMatches(manifest, matches)
|
|
300
|
+
|
|
301
|
+
if (!requestAssets?.length && !inlineCssAsset) {
|
|
302
|
+
return manifest
|
|
303
|
+
}
|
|
304
|
+
|
|
301
305
|
// Merge request-scoped assets into root route without mutating cached manifest
|
|
302
306
|
return {
|
|
303
307
|
...manifest,
|
|
304
308
|
routes: {
|
|
305
|
-
...manifest
|
|
309
|
+
...manifest.routes,
|
|
306
310
|
[rootRouteId]: {
|
|
307
|
-
...manifest
|
|
311
|
+
...manifest.routes[rootRouteId],
|
|
308
312
|
assets: [
|
|
309
313
|
...(requestAssets ?? []),
|
|
310
314
|
...(inlineCssAsset ? [inlineCssAsset] : []),
|
|
311
|
-
...(manifest
|
|
315
|
+
...(manifest.routes[rootRouteId]?.assets ?? []),
|
|
312
316
|
],
|
|
313
317
|
},
|
|
314
318
|
},
|
package/dist/cjs/hash-scroll.cjs
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
//#region src/hash-scroll.ts
|
|
2
|
-
/**
|
|
3
|
-
* @private
|
|
4
|
-
* Handles hash-based scrolling after navigation completes.
|
|
5
|
-
* To be used in framework-specific <Transitioner> components during the onResolved event.
|
|
6
|
-
*/
|
|
7
|
-
function handleHashScroll(router) {
|
|
8
|
-
if (typeof document !== "undefined" && document.querySelector) {
|
|
9
|
-
const location = router.stores.location.get();
|
|
10
|
-
const hashScrollIntoViewOptions = location.state.__hashScrollIntoViewOptions ?? true;
|
|
11
|
-
if (hashScrollIntoViewOptions && location.hash !== "") {
|
|
12
|
-
const el = document.getElementById(location.hash);
|
|
13
|
-
if (el) el.scrollIntoView(hashScrollIntoViewOptions);
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
//#endregion
|
|
18
|
-
exports.handleHashScroll = handleHashScroll;
|
|
19
|
-
|
|
20
|
-
//# sourceMappingURL=hash-scroll.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"hash-scroll.cjs","names":[],"sources":["../../src/hash-scroll.ts"],"sourcesContent":["import type { AnyRouter } from './router'\n\n/**\n * @private\n * Handles hash-based scrolling after navigation completes.\n * To be used in framework-specific <Transitioner> components during the onResolved event.\n */\nexport function handleHashScroll(router: AnyRouter) {\n if (typeof document !== 'undefined' && (document as any).querySelector) {\n const location = router.stores.location.get()\n const hashScrollIntoViewOptions =\n location.state.__hashScrollIntoViewOptions ?? true\n\n if (hashScrollIntoViewOptions && location.hash !== '') {\n const el = document.getElementById(location.hash)\n if (el) {\n el.scrollIntoView(hashScrollIntoViewOptions)\n }\n }\n }\n}\n"],"mappings":";;;;;;AAOA,SAAgB,iBAAiB,QAAmB;AAClD,KAAI,OAAO,aAAa,eAAgB,SAAiB,eAAe;EACtE,MAAM,WAAW,OAAO,OAAO,SAAS,KAAK;EAC7C,MAAM,4BACJ,SAAS,MAAM,+BAA+B;AAEhD,MAAI,6BAA6B,SAAS,SAAS,IAAI;GACrD,MAAM,KAAK,SAAS,eAAe,SAAS,KAAK;AACjD,OAAI,GACF,IAAG,eAAe,0BAA0B"}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { AnyRouter } from './router.cjs';
|
|
2
|
-
/**
|
|
3
|
-
* @private
|
|
4
|
-
* Handles hash-based scrolling after navigation completes.
|
|
5
|
-
* To be used in framework-specific <Transitioner> components during the onResolved event.
|
|
6
|
-
*/
|
|
7
|
-
export declare function handleHashScroll(router: AnyRouter): void;
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { AnyRouter } from './router.js';
|
|
2
|
-
/**
|
|
3
|
-
* @private
|
|
4
|
-
* Handles hash-based scrolling after navigation completes.
|
|
5
|
-
* To be used in framework-specific <Transitioner> components during the onResolved event.
|
|
6
|
-
*/
|
|
7
|
-
export declare function handleHashScroll(router: AnyRouter): void;
|
package/dist/esm/hash-scroll.js
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
//#region src/hash-scroll.ts
|
|
2
|
-
/**
|
|
3
|
-
* @private
|
|
4
|
-
* Handles hash-based scrolling after navigation completes.
|
|
5
|
-
* To be used in framework-specific <Transitioner> components during the onResolved event.
|
|
6
|
-
*/
|
|
7
|
-
function handleHashScroll(router) {
|
|
8
|
-
if (typeof document !== "undefined" && document.querySelector) {
|
|
9
|
-
const location = router.stores.location.get();
|
|
10
|
-
const hashScrollIntoViewOptions = location.state.__hashScrollIntoViewOptions ?? true;
|
|
11
|
-
if (hashScrollIntoViewOptions && location.hash !== "") {
|
|
12
|
-
const el = document.getElementById(location.hash);
|
|
13
|
-
if (el) el.scrollIntoView(hashScrollIntoViewOptions);
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
//#endregion
|
|
18
|
-
export { handleHashScroll };
|
|
19
|
-
|
|
20
|
-
//# sourceMappingURL=hash-scroll.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"hash-scroll.js","names":[],"sources":["../../src/hash-scroll.ts"],"sourcesContent":["import type { AnyRouter } from './router'\n\n/**\n * @private\n * Handles hash-based scrolling after navigation completes.\n * To be used in framework-specific <Transitioner> components during the onResolved event.\n */\nexport function handleHashScroll(router: AnyRouter) {\n if (typeof document !== 'undefined' && (document as any).querySelector) {\n const location = router.stores.location.get()\n const hashScrollIntoViewOptions =\n location.state.__hashScrollIntoViewOptions ?? true\n\n if (hashScrollIntoViewOptions && location.hash !== '') {\n const el = document.getElementById(location.hash)\n if (el) {\n el.scrollIntoView(hashScrollIntoViewOptions)\n }\n }\n }\n}\n"],"mappings":";;;;;;AAOA,SAAgB,iBAAiB,QAAmB;AAClD,KAAI,OAAO,aAAa,eAAgB,SAAiB,eAAe;EACtE,MAAM,WAAW,OAAO,OAAO,SAAS,KAAK;EAC7C,MAAM,4BACJ,SAAS,MAAM,+BAA+B;AAEhD,MAAI,6BAA6B,SAAS,SAAS,IAAI;GACrD,MAAM,KAAK,SAAS,eAAe,SAAS,KAAK;AACjD,OAAI,GACF,IAAG,eAAe,0BAA0B"}
|
package/src/hash-scroll.ts
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import type { AnyRouter } from './router'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* @private
|
|
5
|
-
* Handles hash-based scrolling after navigation completes.
|
|
6
|
-
* To be used in framework-specific <Transitioner> components during the onResolved event.
|
|
7
|
-
*/
|
|
8
|
-
export function handleHashScroll(router: AnyRouter) {
|
|
9
|
-
if (typeof document !== 'undefined' && (document as any).querySelector) {
|
|
10
|
-
const location = router.stores.location.get()
|
|
11
|
-
const hashScrollIntoViewOptions =
|
|
12
|
-
location.state.__hashScrollIntoViewOptions ?? true
|
|
13
|
-
|
|
14
|
-
if (hashScrollIntoViewOptions && location.hash !== '') {
|
|
15
|
-
const el = document.getElementById(location.hash)
|
|
16
|
-
if (el) {
|
|
17
|
-
el.scrollIntoView(hashScrollIntoViewOptions)
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
}
|