@tanstack/history 1.87.6 → 1.95.0
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 +196 -70
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +33 -12
- package/dist/esm/index.d.ts +33 -12
- package/dist/esm/index.js +196 -70
- package/dist/esm/index.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +278 -89
package/src/index.ts
CHANGED
|
@@ -5,21 +5,37 @@
|
|
|
5
5
|
export interface NavigateOptions {
|
|
6
6
|
ignoreBlocker?: boolean
|
|
7
7
|
}
|
|
8
|
+
|
|
9
|
+
type SubscriberHistoryAction =
|
|
10
|
+
| {
|
|
11
|
+
type: HistoryAction
|
|
12
|
+
}
|
|
13
|
+
| {
|
|
14
|
+
type: 'GO'
|
|
15
|
+
index: number
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
type SubscriberArgs = {
|
|
19
|
+
location: HistoryLocation
|
|
20
|
+
action: SubscriberHistoryAction
|
|
21
|
+
}
|
|
22
|
+
|
|
8
23
|
export interface RouterHistory {
|
|
9
24
|
location: HistoryLocation
|
|
10
25
|
length: number
|
|
11
|
-
subscribers: Set<(opts:
|
|
12
|
-
subscribe: (cb: (opts:
|
|
26
|
+
subscribers: Set<(opts: SubscriberArgs) => void>
|
|
27
|
+
subscribe: (cb: (opts: SubscriberArgs) => void) => () => void
|
|
13
28
|
push: (path: string, state?: any, navigateOpts?: NavigateOptions) => void
|
|
14
29
|
replace: (path: string, state?: any, navigateOpts?: NavigateOptions) => void
|
|
15
30
|
go: (index: number, navigateOpts?: NavigateOptions) => void
|
|
16
31
|
back: (navigateOpts?: NavigateOptions) => void
|
|
17
32
|
forward: (navigateOpts?: NavigateOptions) => void
|
|
33
|
+
canGoBack: () => boolean
|
|
18
34
|
createHref: (href: string) => string
|
|
19
|
-
block: (blocker:
|
|
35
|
+
block: (blocker: NavigationBlocker) => () => void
|
|
20
36
|
flush: () => void
|
|
21
37
|
destroy: () => void
|
|
22
|
-
notify: () => void
|
|
38
|
+
notify: (action: SubscriberHistoryAction) => void
|
|
23
39
|
_ignoreSubscribers?: boolean
|
|
24
40
|
}
|
|
25
41
|
|
|
@@ -36,62 +52,101 @@ export interface ParsedPath {
|
|
|
36
52
|
|
|
37
53
|
export interface HistoryState {
|
|
38
54
|
key?: string
|
|
55
|
+
__TSR_index: number
|
|
39
56
|
}
|
|
40
57
|
|
|
41
58
|
type ShouldAllowNavigation = any
|
|
42
59
|
|
|
43
|
-
export type
|
|
44
|
-
| Promise<ShouldAllowNavigation>
|
|
45
|
-
| ShouldAllowNavigation
|
|
46
|
-
|
|
47
|
-
const pushStateEvent = 'pushstate'
|
|
48
|
-
const popStateEvent = 'popstate'
|
|
49
|
-
const beforeUnloadEvent = 'beforeunload'
|
|
60
|
+
export type HistoryAction = 'PUSH' | 'REPLACE' | 'FORWARD' | 'BACK' | 'GO'
|
|
50
61
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
62
|
+
export type BlockerFnArgs = {
|
|
63
|
+
currentLocation: HistoryLocation
|
|
64
|
+
nextLocation: HistoryLocation
|
|
65
|
+
action: HistoryAction
|
|
55
66
|
}
|
|
56
67
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
68
|
+
export type BlockerFn = (
|
|
69
|
+
args: BlockerFnArgs,
|
|
70
|
+
) => Promise<ShouldAllowNavigation> | ShouldAllowNavigation
|
|
71
|
+
|
|
72
|
+
export type NavigationBlocker = {
|
|
73
|
+
blockerFn: BlockerFn
|
|
74
|
+
enableBeforeUnload?: (() => boolean) | boolean
|
|
61
75
|
}
|
|
62
76
|
|
|
77
|
+
type TryNavigateArgs = {
|
|
78
|
+
task: () => void
|
|
79
|
+
type: 'PUSH' | 'REPLACE' | 'BACK' | 'FORWARD' | 'GO'
|
|
80
|
+
navigateOpts?: NavigateOptions
|
|
81
|
+
} & (
|
|
82
|
+
| {
|
|
83
|
+
type: 'PUSH' | 'REPLACE'
|
|
84
|
+
path: string
|
|
85
|
+
state: any
|
|
86
|
+
}
|
|
87
|
+
| {
|
|
88
|
+
type: 'BACK' | 'FORWARD' | 'GO'
|
|
89
|
+
}
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
const stateIndexKey = '__TSR_index'
|
|
93
|
+
const popStateEvent = 'popstate'
|
|
94
|
+
const beforeUnloadEvent = 'beforeunload'
|
|
95
|
+
|
|
63
96
|
export function createHistory(opts: {
|
|
64
97
|
getLocation: () => HistoryLocation
|
|
65
98
|
getLength: () => number
|
|
66
99
|
pushState: (path: string, state: any) => void
|
|
67
100
|
replaceState: (path: string, state: any) => void
|
|
68
101
|
go: (n: number) => void
|
|
69
|
-
back: () => void
|
|
70
|
-
forward: () => void
|
|
102
|
+
back: (ignoreBlocker: boolean) => void
|
|
103
|
+
forward: (ignoreBlocker: boolean) => void
|
|
71
104
|
createHref: (path: string) => string
|
|
72
105
|
flush?: () => void
|
|
73
106
|
destroy?: () => void
|
|
74
|
-
onBlocked?: (
|
|
107
|
+
onBlocked?: () => void
|
|
108
|
+
getBlockers?: () => Array<NavigationBlocker>
|
|
109
|
+
setBlockers?: (blockers: Array<NavigationBlocker>) => void
|
|
110
|
+
// Avoid notifying on forward/back/go, used for browser history as we already get notified by the popstate event
|
|
111
|
+
notifyOnIndexChange?: boolean
|
|
75
112
|
}): RouterHistory {
|
|
76
113
|
let location = opts.getLocation()
|
|
77
|
-
const subscribers = new Set<(opts:
|
|
78
|
-
let blockers: Array<BlockerFn> = []
|
|
114
|
+
const subscribers = new Set<(opts: SubscriberArgs) => void>()
|
|
79
115
|
|
|
80
|
-
const notify = () => {
|
|
116
|
+
const notify = (action: SubscriberHistoryAction) => {
|
|
81
117
|
location = opts.getLocation()
|
|
82
|
-
subscribers.forEach((subscriber) => subscriber({ location }))
|
|
118
|
+
subscribers.forEach((subscriber) => subscriber({ location, action }))
|
|
83
119
|
}
|
|
84
120
|
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
121
|
+
const handleIndexChange = (action: SubscriberHistoryAction) => {
|
|
122
|
+
if (opts.notifyOnIndexChange ?? true) notify(action)
|
|
123
|
+
else location = opts.getLocation()
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const tryNavigation = async ({
|
|
127
|
+
task,
|
|
128
|
+
navigateOpts,
|
|
129
|
+
...actionInfo
|
|
130
|
+
}: TryNavigateArgs) => {
|
|
89
131
|
const ignoreBlocker = navigateOpts?.ignoreBlocker ?? false
|
|
90
|
-
if (
|
|
132
|
+
if (ignoreBlocker) {
|
|
133
|
+
task()
|
|
134
|
+
return
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const blockers = opts.getBlockers?.() ?? []
|
|
138
|
+
const isPushOrReplace =
|
|
139
|
+
actionInfo.type === 'PUSH' || actionInfo.type === 'REPLACE'
|
|
140
|
+
if (typeof document !== 'undefined' && blockers.length && isPushOrReplace) {
|
|
91
141
|
for (const blocker of blockers) {
|
|
92
|
-
const
|
|
93
|
-
|
|
94
|
-
|
|
142
|
+
const nextLocation = parseHref(actionInfo.path, actionInfo.state)
|
|
143
|
+
const isBlocked = await blocker.blockerFn({
|
|
144
|
+
currentLocation: location,
|
|
145
|
+
nextLocation,
|
|
146
|
+
action: actionInfo.type,
|
|
147
|
+
})
|
|
148
|
+
if (isBlocked) {
|
|
149
|
+
opts.onBlocked?.()
|
|
95
150
|
return
|
|
96
151
|
}
|
|
97
152
|
}
|
|
@@ -108,7 +163,7 @@ export function createHistory(opts: {
|
|
|
108
163
|
return opts.getLength()
|
|
109
164
|
},
|
|
110
165
|
subscribers,
|
|
111
|
-
subscribe: (cb: (opts:
|
|
166
|
+
subscribe: (cb: (opts: SubscriberArgs) => void) => {
|
|
112
167
|
subscribers.add(cb)
|
|
113
168
|
|
|
114
169
|
return () => {
|
|
@@ -116,53 +171,73 @@ export function createHistory(opts: {
|
|
|
116
171
|
}
|
|
117
172
|
},
|
|
118
173
|
push: (path, state, navigateOpts) => {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
174
|
+
const currentIndex = location.state[stateIndexKey]
|
|
175
|
+
state = assignKeyAndIndex(currentIndex + 1, state)
|
|
176
|
+
tryNavigation({
|
|
177
|
+
task: () => {
|
|
178
|
+
opts.pushState(path, state)
|
|
179
|
+
notify({ type: 'PUSH' })
|
|
180
|
+
},
|
|
181
|
+
navigateOpts,
|
|
182
|
+
type: 'PUSH',
|
|
183
|
+
path,
|
|
184
|
+
state,
|
|
185
|
+
})
|
|
124
186
|
},
|
|
125
187
|
replace: (path, state, navigateOpts) => {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
188
|
+
const currentIndex = location.state[stateIndexKey]
|
|
189
|
+
state = assignKeyAndIndex(currentIndex, state)
|
|
190
|
+
tryNavigation({
|
|
191
|
+
task: () => {
|
|
192
|
+
opts.replaceState(path, state)
|
|
193
|
+
notify({ type: 'REPLACE' })
|
|
194
|
+
},
|
|
195
|
+
navigateOpts,
|
|
196
|
+
type: 'REPLACE',
|
|
197
|
+
path,
|
|
198
|
+
state,
|
|
199
|
+
})
|
|
131
200
|
},
|
|
132
201
|
go: (index, navigateOpts) => {
|
|
133
|
-
tryNavigation(
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
202
|
+
tryNavigation({
|
|
203
|
+
task: () => {
|
|
204
|
+
opts.go(index)
|
|
205
|
+
handleIndexChange({ type: 'GO', index })
|
|
206
|
+
},
|
|
207
|
+
navigateOpts,
|
|
208
|
+
type: 'GO',
|
|
209
|
+
})
|
|
137
210
|
},
|
|
138
211
|
back: (navigateOpts) => {
|
|
139
|
-
tryNavigation(
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
212
|
+
tryNavigation({
|
|
213
|
+
task: () => {
|
|
214
|
+
opts.back(navigateOpts?.ignoreBlocker ?? false)
|
|
215
|
+
handleIndexChange({ type: 'BACK' })
|
|
216
|
+
},
|
|
217
|
+
navigateOpts,
|
|
218
|
+
type: 'BACK',
|
|
219
|
+
})
|
|
143
220
|
},
|
|
144
221
|
forward: (navigateOpts) => {
|
|
145
|
-
tryNavigation(
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
222
|
+
tryNavigation({
|
|
223
|
+
task: () => {
|
|
224
|
+
opts.forward(navigateOpts?.ignoreBlocker ?? false)
|
|
225
|
+
handleIndexChange({ type: 'FORWARD' })
|
|
226
|
+
},
|
|
227
|
+
navigateOpts,
|
|
228
|
+
type: 'FORWARD',
|
|
229
|
+
})
|
|
149
230
|
},
|
|
231
|
+
canGoBack: () => location.state[stateIndexKey] !== 0,
|
|
150
232
|
createHref: (str) => opts.createHref(str),
|
|
151
233
|
block: (blocker) => {
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
addEventListener(beforeUnloadEvent, beforeUnloadListener, {
|
|
156
|
-
capture: true,
|
|
157
|
-
})
|
|
158
|
-
}
|
|
234
|
+
if (!opts.setBlockers) return () => {}
|
|
235
|
+
const blockers = opts.getBlockers?.() ?? []
|
|
236
|
+
opts.setBlockers([...blockers, blocker])
|
|
159
237
|
|
|
160
238
|
return () => {
|
|
161
|
-
blockers =
|
|
162
|
-
|
|
163
|
-
if (!blockers.length) {
|
|
164
|
-
stopBlocking()
|
|
165
|
-
}
|
|
239
|
+
const blockers = opts.getBlockers?.() ?? []
|
|
240
|
+
opts.setBlockers?.(blockers.filter((b) => b !== blocker))
|
|
166
241
|
}
|
|
167
242
|
},
|
|
168
243
|
flush: () => opts.flush?.(),
|
|
@@ -171,13 +246,14 @@ export function createHistory(opts: {
|
|
|
171
246
|
}
|
|
172
247
|
}
|
|
173
248
|
|
|
174
|
-
function
|
|
249
|
+
function assignKeyAndIndex(index: number, state: HistoryState | undefined) {
|
|
175
250
|
if (!state) {
|
|
176
251
|
state = {} as HistoryState
|
|
177
252
|
}
|
|
178
253
|
return {
|
|
179
254
|
...state,
|
|
180
255
|
key: createRandomKey(),
|
|
256
|
+
[stateIndexKey]: index,
|
|
181
257
|
}
|
|
182
258
|
}
|
|
183
259
|
|
|
@@ -209,6 +285,11 @@ export function createBrowserHistory(opts?: {
|
|
|
209
285
|
const originalPushState = win.history.pushState
|
|
210
286
|
const originalReplaceState = win.history.replaceState
|
|
211
287
|
|
|
288
|
+
let blockers: Array<NavigationBlocker> = []
|
|
289
|
+
const _getBlockers = () => blockers
|
|
290
|
+
const _setBlockers = (newBlockers: Array<NavigationBlocker>) =>
|
|
291
|
+
(blockers = newBlockers)
|
|
292
|
+
|
|
212
293
|
const createHref = opts?.createHref ?? ((path) => path)
|
|
213
294
|
const parseLocation =
|
|
214
295
|
opts?.parseLocation ??
|
|
@@ -221,6 +302,11 @@ export function createBrowserHistory(opts?: {
|
|
|
221
302
|
let currentLocation = parseLocation()
|
|
222
303
|
let rollbackLocation: HistoryLocation | undefined
|
|
223
304
|
|
|
305
|
+
let nextPopIsGo = false
|
|
306
|
+
let ignoreNextPop = false
|
|
307
|
+
let skipBlockerNextPop = false
|
|
308
|
+
let ignoreNextBeforeUnload = false
|
|
309
|
+
|
|
224
310
|
const getLocation = () => currentLocation
|
|
225
311
|
|
|
226
312
|
let next:
|
|
@@ -291,9 +377,94 @@ export function createBrowserHistory(opts?: {
|
|
|
291
377
|
}
|
|
292
378
|
}
|
|
293
379
|
|
|
294
|
-
|
|
380
|
+
// NOTE: this function can probably be removed
|
|
381
|
+
const onPushPop = (type: 'PUSH' | 'REPLACE') => {
|
|
295
382
|
currentLocation = parseLocation()
|
|
296
|
-
history.notify()
|
|
383
|
+
history.notify({ type })
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
const onPushPopEvent = async () => {
|
|
387
|
+
if (ignoreNextPop) {
|
|
388
|
+
ignoreNextPop = false
|
|
389
|
+
return
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
const nextLocation = parseLocation()
|
|
393
|
+
const delta =
|
|
394
|
+
nextLocation.state[stateIndexKey] - currentLocation.state[stateIndexKey]
|
|
395
|
+
const isForward = delta === 1
|
|
396
|
+
const isBack = delta === -1
|
|
397
|
+
const isGo = (!isForward && !isBack) || nextPopIsGo
|
|
398
|
+
nextPopIsGo = false
|
|
399
|
+
|
|
400
|
+
const action = isGo ? 'GO' : isBack ? 'BACK' : 'FORWARD'
|
|
401
|
+
const notify: SubscriberHistoryAction = isGo
|
|
402
|
+
? {
|
|
403
|
+
type: 'GO',
|
|
404
|
+
index: delta,
|
|
405
|
+
}
|
|
406
|
+
: {
|
|
407
|
+
type: isBack ? 'BACK' : 'FORWARD',
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
if (skipBlockerNextPop) {
|
|
411
|
+
skipBlockerNextPop = false
|
|
412
|
+
} else {
|
|
413
|
+
const blockers = _getBlockers()
|
|
414
|
+
if (typeof document !== 'undefined' && blockers.length) {
|
|
415
|
+
for (const blocker of blockers) {
|
|
416
|
+
const isBlocked = await blocker.blockerFn({
|
|
417
|
+
currentLocation,
|
|
418
|
+
nextLocation,
|
|
419
|
+
action,
|
|
420
|
+
})
|
|
421
|
+
if (isBlocked) {
|
|
422
|
+
ignoreNextPop = true
|
|
423
|
+
win.history.go(1)
|
|
424
|
+
history.notify(notify)
|
|
425
|
+
return
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
currentLocation = parseLocation()
|
|
432
|
+
history.notify(notify)
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
const onBeforeUnload = (e: BeforeUnloadEvent) => {
|
|
436
|
+
if (ignoreNextBeforeUnload) {
|
|
437
|
+
ignoreNextBeforeUnload = false
|
|
438
|
+
return
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
let shouldBlock = false
|
|
442
|
+
|
|
443
|
+
// If one blocker has a non-disabled beforeUnload, we should block
|
|
444
|
+
const blockers = _getBlockers()
|
|
445
|
+
if (typeof document !== 'undefined' && blockers.length) {
|
|
446
|
+
for (const blocker of blockers) {
|
|
447
|
+
const shouldHaveBeforeUnload = blocker.enableBeforeUnload ?? true
|
|
448
|
+
if (shouldHaveBeforeUnload === true) {
|
|
449
|
+
shouldBlock = true
|
|
450
|
+
break
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
if (
|
|
454
|
+
typeof shouldHaveBeforeUnload === 'function' &&
|
|
455
|
+
shouldHaveBeforeUnload() === true
|
|
456
|
+
) {
|
|
457
|
+
shouldBlock = true
|
|
458
|
+
break
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
if (shouldBlock) {
|
|
464
|
+
e.preventDefault()
|
|
465
|
+
return (e.returnValue = '')
|
|
466
|
+
}
|
|
467
|
+
return
|
|
297
468
|
}
|
|
298
469
|
|
|
299
470
|
const history = createHistory({
|
|
@@ -301,40 +472,54 @@ export function createBrowserHistory(opts?: {
|
|
|
301
472
|
getLength: () => win.history.length,
|
|
302
473
|
pushState: (href, state) => queueHistoryAction('push', href, state),
|
|
303
474
|
replaceState: (href, state) => queueHistoryAction('replace', href, state),
|
|
304
|
-
back: () =>
|
|
305
|
-
|
|
306
|
-
|
|
475
|
+
back: (ignoreBlocker) => {
|
|
476
|
+
if (ignoreBlocker) skipBlockerNextPop = true
|
|
477
|
+
ignoreNextBeforeUnload = true
|
|
478
|
+
return win.history.back()
|
|
479
|
+
},
|
|
480
|
+
forward: (ignoreBlocker) => {
|
|
481
|
+
if (ignoreBlocker) skipBlockerNextPop = true
|
|
482
|
+
ignoreNextBeforeUnload = true
|
|
483
|
+
win.history.forward()
|
|
484
|
+
},
|
|
485
|
+
go: (n) => {
|
|
486
|
+
nextPopIsGo = true
|
|
487
|
+
win.history.go(n)
|
|
488
|
+
},
|
|
307
489
|
createHref: (href) => createHref(href),
|
|
308
490
|
flush,
|
|
309
491
|
destroy: () => {
|
|
310
492
|
win.history.pushState = originalPushState
|
|
311
493
|
win.history.replaceState = originalReplaceState
|
|
312
|
-
win.removeEventListener(
|
|
313
|
-
|
|
494
|
+
win.removeEventListener(beforeUnloadEvent, onBeforeUnload, {
|
|
495
|
+
capture: true,
|
|
496
|
+
})
|
|
497
|
+
win.removeEventListener(popStateEvent, onPushPopEvent)
|
|
314
498
|
},
|
|
315
|
-
onBlocked: (
|
|
499
|
+
onBlocked: () => {
|
|
316
500
|
// If a navigation is blocked, we need to rollback the location
|
|
317
501
|
// that we optimistically updated in memory.
|
|
318
502
|
if (rollbackLocation && currentLocation !== rollbackLocation) {
|
|
319
503
|
currentLocation = rollbackLocation
|
|
320
|
-
// Notify subscribers
|
|
321
|
-
onUpdate()
|
|
322
504
|
}
|
|
323
505
|
},
|
|
506
|
+
getBlockers: _getBlockers,
|
|
507
|
+
setBlockers: _setBlockers,
|
|
508
|
+
notifyOnIndexChange: false,
|
|
324
509
|
})
|
|
325
510
|
|
|
326
|
-
win.addEventListener(
|
|
327
|
-
win.addEventListener(popStateEvent,
|
|
511
|
+
win.addEventListener(beforeUnloadEvent, onBeforeUnload, { capture: true })
|
|
512
|
+
win.addEventListener(popStateEvent, onPushPopEvent)
|
|
328
513
|
|
|
329
514
|
win.history.pushState = function (...args: Array<any>) {
|
|
330
|
-
const res = originalPushState.apply(win.history, args)
|
|
331
|
-
if (!history._ignoreSubscribers) onPushPop()
|
|
515
|
+
const res = originalPushState.apply(win.history, args as any)
|
|
516
|
+
if (!history._ignoreSubscribers) onPushPop('PUSH')
|
|
332
517
|
return res
|
|
333
518
|
}
|
|
334
519
|
|
|
335
520
|
win.history.replaceState = function (...args: Array<any>) {
|
|
336
|
-
const res = originalReplaceState.apply(win.history, args)
|
|
337
|
-
if (!history._ignoreSubscribers) onPushPop()
|
|
521
|
+
const res = originalReplaceState.apply(win.history, args as any)
|
|
522
|
+
if (!history._ignoreSubscribers) onPushPop('REPLACE')
|
|
338
523
|
return res
|
|
339
524
|
}
|
|
340
525
|
|
|
@@ -365,8 +550,12 @@ export function createMemoryHistory(
|
|
|
365
550
|
},
|
|
366
551
|
): RouterHistory {
|
|
367
552
|
const entries = opts.initialEntries
|
|
368
|
-
let index = opts.initialIndex
|
|
369
|
-
|
|
553
|
+
let index = opts.initialIndex
|
|
554
|
+
? Math.min(Math.max(opts.initialIndex, 0), entries.length - 1)
|
|
555
|
+
: entries.length - 1
|
|
556
|
+
const states = entries.map<HistoryState>((_entry, index) =>
|
|
557
|
+
assignKeyAndIndex(index, undefined),
|
|
558
|
+
)
|
|
370
559
|
|
|
371
560
|
const getLocation = () => parseHref(entries[index]!, states[index])
|
|
372
561
|
|
|
@@ -424,7 +613,7 @@ export function parseHref(
|
|
|
424
613
|
searchIndex > -1
|
|
425
614
|
? href.slice(searchIndex, hashIndex === -1 ? undefined : hashIndex)
|
|
426
615
|
: '',
|
|
427
|
-
state: state || {},
|
|
616
|
+
state: state || { [stateIndexKey]: 0 },
|
|
428
617
|
}
|
|
429
618
|
}
|
|
430
619
|
|