@tanstack/router-core 0.0.1-beta.193 → 0.0.1-beta.195
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/fileRoute.js.map +1 -1
- package/build/cjs/history.js +88 -15
- package/build/cjs/history.js.map +1 -1
- package/build/cjs/route.js.map +1 -1
- package/build/cjs/router.js +1 -1
- package/build/cjs/router.js.map +1 -1
- package/build/cjs/utils.js +2 -0
- package/build/cjs/utils.js.map +1 -1
- package/build/esm/index.js +91 -16
- package/build/esm/index.js.map +1 -1
- package/build/stats-html.html +1 -1
- package/build/stats-react.json +128 -128
- package/build/types/fileRoute.d.ts +3 -2
- package/build/types/history.d.ts +17 -0
- package/build/types/route.d.ts +62 -36
- package/build/types/routeInfo.d.ts +2 -2
- package/build/types/router.d.ts +3 -3
- package/build/types/utils.d.ts +1 -1
- package/build/umd/index.development.js +91 -16
- 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 +1 -1
- package/src/fileRoute.ts +10 -17
- package/src/history.ts +113 -15
- package/src/route.ts +54 -121
- package/src/routeInfo.ts +1 -5
- package/src/router.ts +1 -4
- package/src/utils.ts +2 -1
package/package.json
CHANGED
package/src/fileRoute.ts
CHANGED
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
TrimPathLeft,
|
|
16
16
|
RouteConstraints,
|
|
17
17
|
} from './route'
|
|
18
|
+
import { DeepMergeAll, Expand, IsAny } from './utils'
|
|
18
19
|
|
|
19
20
|
export interface FileRoutesByPath {
|
|
20
21
|
// '/': {
|
|
@@ -99,12 +100,15 @@ export class FileRoute<
|
|
|
99
100
|
TParentRoute['types']['allParams'],
|
|
100
101
|
TParams
|
|
101
102
|
>,
|
|
102
|
-
TParentContext extends RouteConstraints['TParentContext'] = TParentRoute['types']['routeContext'],
|
|
103
|
-
TAllParentContext extends RouteConstraints['TAllParentContext'] = TParentRoute['types']['context'],
|
|
104
103
|
TRouteContext extends RouteConstraints['TRouteContext'] = RouteContext,
|
|
105
|
-
TContext extends RouteConstraints['TAllContext'] =
|
|
106
|
-
|
|
107
|
-
|
|
104
|
+
TContext extends RouteConstraints['TAllContext'] = Expand<
|
|
105
|
+
DeepMergeAll<
|
|
106
|
+
[
|
|
107
|
+
IsAny<TParentRoute['types']['context'], {}>,
|
|
108
|
+
TLoaderContext,
|
|
109
|
+
TRouteContext,
|
|
110
|
+
]
|
|
111
|
+
>
|
|
108
112
|
>,
|
|
109
113
|
TRouterContext extends RouteConstraints['TRouterContext'] = AnyContext,
|
|
110
114
|
TChildren extends RouteConstraints['TChildren'] = unknown,
|
|
@@ -121,21 +125,12 @@ export class FileRoute<
|
|
|
121
125
|
TFullSearchSchema,
|
|
122
126
|
TParams,
|
|
123
127
|
TAllParams,
|
|
124
|
-
TParentContext,
|
|
125
|
-
TAllParentContext,
|
|
126
128
|
TRouteContext,
|
|
127
129
|
TContext
|
|
128
130
|
>,
|
|
129
131
|
'getParentRoute' | 'path' | 'id'
|
|
130
132
|
> &
|
|
131
|
-
UpdatableRouteOptions<
|
|
132
|
-
TLoader,
|
|
133
|
-
TSearchSchema,
|
|
134
|
-
TFullSearchSchema,
|
|
135
|
-
TAllParams,
|
|
136
|
-
TRouteContext,
|
|
137
|
-
TContext
|
|
138
|
-
>,
|
|
133
|
+
UpdatableRouteOptions<TLoader, TFullSearchSchema, TAllParams, TContext>,
|
|
139
134
|
): Route<
|
|
140
135
|
TParentRoute,
|
|
141
136
|
TPath,
|
|
@@ -148,8 +143,6 @@ export class FileRoute<
|
|
|
148
143
|
TFullSearchSchema,
|
|
149
144
|
TParams,
|
|
150
145
|
TAllParams,
|
|
151
|
-
TParentContext,
|
|
152
|
-
TAllParentContext,
|
|
153
146
|
TRouteContext,
|
|
154
147
|
TContext,
|
|
155
148
|
TRouterContext,
|
package/src/history.ts
CHANGED
|
@@ -12,6 +12,7 @@ export interface RouterHistory {
|
|
|
12
12
|
forward: () => void
|
|
13
13
|
createHref: (href: string) => string
|
|
14
14
|
block: (blockerFn: BlockerFn) => () => void
|
|
15
|
+
flush: () => void
|
|
15
16
|
}
|
|
16
17
|
|
|
17
18
|
export interface HistoryLocation extends ParsedPath {
|
|
@@ -52,12 +53,13 @@ const stopBlocking = () => {
|
|
|
52
53
|
function createHistory(opts: {
|
|
53
54
|
getLocation: () => HistoryLocation
|
|
54
55
|
subscriber: false | ((onUpdate: () => void) => () => void)
|
|
55
|
-
pushState: (path: string, state: any) => void
|
|
56
|
-
replaceState: (path: string, state: any) => void
|
|
56
|
+
pushState: (path: string, state: any, onUpdate: () => void) => void
|
|
57
|
+
replaceState: (path: string, state: any, onUpdate: () => void) => void
|
|
57
58
|
go: (n: number) => void
|
|
58
59
|
back: () => void
|
|
59
60
|
forward: () => void
|
|
60
61
|
createHref: (path: string) => string
|
|
62
|
+
flush?: () => void
|
|
61
63
|
}): RouterHistory {
|
|
62
64
|
let location = opts.getLocation()
|
|
63
65
|
let unsub = () => {}
|
|
@@ -116,13 +118,13 @@ function createHistory(opts: {
|
|
|
116
118
|
push: (path: string, state: any) => {
|
|
117
119
|
assignKey(state)
|
|
118
120
|
queueTask(() => {
|
|
119
|
-
opts.pushState(path, state)
|
|
121
|
+
opts.pushState(path, state, onUpdate)
|
|
120
122
|
})
|
|
121
123
|
},
|
|
122
124
|
replace: (path: string, state: any) => {
|
|
123
125
|
assignKey(state)
|
|
124
126
|
queueTask(() => {
|
|
125
|
-
opts.replaceState(path, state)
|
|
127
|
+
opts.replaceState(path, state, onUpdate)
|
|
126
128
|
})
|
|
127
129
|
},
|
|
128
130
|
go: (index) => {
|
|
@@ -158,6 +160,7 @@ function createHistory(opts: {
|
|
|
158
160
|
}
|
|
159
161
|
}
|
|
160
162
|
},
|
|
163
|
+
flush: () => opts.flush?.(),
|
|
161
164
|
}
|
|
162
165
|
}
|
|
163
166
|
|
|
@@ -171,6 +174,22 @@ function assignKey(state: HistoryState) {
|
|
|
171
174
|
// }
|
|
172
175
|
}
|
|
173
176
|
|
|
177
|
+
/**
|
|
178
|
+
* Creates a history object that can be used to interact with the browser's
|
|
179
|
+
* navigation. This is a lightweight API wrapping the browser's native methods.
|
|
180
|
+
* It is designed to work with TanStack Router, but could be used as a standalone API as well.
|
|
181
|
+
* IMPORTANT: This API implements history throttling via a microtask to prevent
|
|
182
|
+
* excessive calls to the history API. In some browsers, calling history.pushState or
|
|
183
|
+
* history.replaceState in quick succession can cause the browser to ignore subsequent
|
|
184
|
+
* calls. This API smooths out those differences and ensures that your application
|
|
185
|
+
* state will *eventually* match the browser state. In most cases, this is not a problem,
|
|
186
|
+
* but if you need to ensure that the browser state is up to date, you can use the
|
|
187
|
+
* `history.flush` method to immediately flush all pending state changes to the browser URL.
|
|
188
|
+
* @param opts
|
|
189
|
+
* @param opts.getHref A function that returns the current href (path + search + hash)
|
|
190
|
+
* @param opts.createHref A function that takes a path and returns a href (path + search + hash)
|
|
191
|
+
* @returns A history instance
|
|
192
|
+
*/
|
|
174
193
|
export function createBrowserHistory(opts?: {
|
|
175
194
|
getHref?: () => string
|
|
176
195
|
createHref?: (path: string) => string
|
|
@@ -182,24 +201,104 @@ export function createBrowserHistory(opts?: {
|
|
|
182
201
|
|
|
183
202
|
const createHref = opts?.createHref ?? ((path) => path)
|
|
184
203
|
|
|
185
|
-
|
|
204
|
+
let currentLocation = parseLocation(getHref(), window.history.state)
|
|
205
|
+
|
|
206
|
+
const getLocation = () => currentLocation
|
|
207
|
+
|
|
208
|
+
let next:
|
|
209
|
+
| undefined
|
|
210
|
+
| {
|
|
211
|
+
// This is the latest location that we were attempting to push/replace
|
|
212
|
+
href: string
|
|
213
|
+
// This is the latest state that we were attempting to push/replace
|
|
214
|
+
state: any
|
|
215
|
+
// This is the latest type that we were attempting to push/replace
|
|
216
|
+
isPush: boolean
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Because we are proactively updating the location
|
|
220
|
+
// in memory before actually updating the browser history,
|
|
221
|
+
// we need to track when we are doing this so we don't
|
|
222
|
+
// notify subscribers twice on the last update.
|
|
223
|
+
let tracking = true
|
|
224
|
+
|
|
225
|
+
// We need to track the current scheduled update to prevent
|
|
226
|
+
// multiple updates from being scheduled at the same time.
|
|
227
|
+
let scheduled: Promise<void> | undefined
|
|
228
|
+
|
|
229
|
+
// This function is a wrapper to prevent any of the callback's
|
|
230
|
+
// side effects from causing a subscriber notification
|
|
231
|
+
const untrack = (fn: () => void) => {
|
|
232
|
+
tracking = false
|
|
233
|
+
fn()
|
|
234
|
+
tracking = true
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// This function flushes the next update to the browser history
|
|
238
|
+
const flush = () => {
|
|
239
|
+
// Do not notify subscribers about this push/replace call
|
|
240
|
+
untrack(() => {
|
|
241
|
+
if (!next) return
|
|
242
|
+
window.history[next.isPush ? 'pushState' : 'replaceState'](
|
|
243
|
+
next.state,
|
|
244
|
+
'',
|
|
245
|
+
next.href,
|
|
246
|
+
)
|
|
247
|
+
// Reset the nextIsPush flag and clear the scheduled update
|
|
248
|
+
next = undefined
|
|
249
|
+
scheduled = undefined
|
|
250
|
+
})
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// This function queues up a call to update the browser history
|
|
254
|
+
const queueHistoryAction = (
|
|
255
|
+
type: 'push' | 'replace',
|
|
256
|
+
path: string,
|
|
257
|
+
state: any,
|
|
258
|
+
onUpdate: () => void,
|
|
259
|
+
) => {
|
|
260
|
+
const href = createHref(path)
|
|
261
|
+
|
|
262
|
+
// Update the location in memory
|
|
263
|
+
currentLocation = parseLocation(href, state)
|
|
264
|
+
|
|
265
|
+
// Keep track of the next location we need to flush to the URL
|
|
266
|
+
next = {
|
|
267
|
+
href,
|
|
268
|
+
state,
|
|
269
|
+
isPush: next?.isPush || type === 'push',
|
|
270
|
+
}
|
|
271
|
+
// Notify subscribers
|
|
272
|
+
onUpdate()
|
|
273
|
+
|
|
274
|
+
if (!scheduled) {
|
|
275
|
+
// Schedule an update to the browser history
|
|
276
|
+
scheduled = Promise.resolve().then(() => flush())
|
|
277
|
+
}
|
|
278
|
+
}
|
|
186
279
|
|
|
187
280
|
return createHistory({
|
|
188
281
|
getLocation,
|
|
189
282
|
subscriber: (onUpdate) => {
|
|
190
|
-
window.addEventListener(pushStateEvent,
|
|
191
|
-
|
|
283
|
+
window.addEventListener(pushStateEvent, () => {
|
|
284
|
+
currentLocation = parseLocation(getHref(), window.history.state)
|
|
285
|
+
onUpdate()
|
|
286
|
+
})
|
|
287
|
+
window.addEventListener(popStateEvent, () => {
|
|
288
|
+
currentLocation = parseLocation(getHref(), window.history.state)
|
|
289
|
+
onUpdate()
|
|
290
|
+
})
|
|
192
291
|
|
|
193
292
|
var pushState = window.history.pushState
|
|
194
293
|
window.history.pushState = function () {
|
|
195
294
|
let res = pushState.apply(history, arguments as any)
|
|
196
|
-
onUpdate()
|
|
295
|
+
if (tracking) onUpdate()
|
|
197
296
|
return res
|
|
198
297
|
}
|
|
199
298
|
var replaceState = window.history.replaceState
|
|
200
299
|
window.history.replaceState = function () {
|
|
201
300
|
let res = replaceState.apply(history, arguments as any)
|
|
202
|
-
onUpdate()
|
|
301
|
+
if (tracking) onUpdate()
|
|
203
302
|
return res
|
|
204
303
|
}
|
|
205
304
|
|
|
@@ -210,16 +309,15 @@ export function createBrowserHistory(opts?: {
|
|
|
210
309
|
window.removeEventListener(popStateEvent, onUpdate)
|
|
211
310
|
}
|
|
212
311
|
},
|
|
213
|
-
pushState: (path, state) =>
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
window.history.replaceState(state, '', createHref(path))
|
|
218
|
-
},
|
|
312
|
+
pushState: (path, state, onUpdate) =>
|
|
313
|
+
queueHistoryAction('push', path, state, onUpdate),
|
|
314
|
+
replaceState: (path, state, onUpdate) =>
|
|
315
|
+
queueHistoryAction('replace', path, state, onUpdate),
|
|
219
316
|
back: () => window.history.back(),
|
|
220
317
|
forward: () => window.history.forward(),
|
|
221
318
|
go: (n) => window.history.go(n),
|
|
222
319
|
createHref: (path) => createHref(path),
|
|
320
|
+
flush,
|
|
223
321
|
})
|
|
224
322
|
}
|
|
225
323
|
|