@tanstack/react-router 1.76.1 → 1.77.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/link.cjs +11 -1
- package/dist/cjs/link.cjs.map +1 -1
- package/dist/cjs/link.d.cts +1 -1
- package/dist/cjs/path.cjs +17 -10
- package/dist/cjs/path.cjs.map +1 -1
- package/dist/cjs/path.d.cts +3 -2
- package/dist/cjs/router.cjs +4 -2
- package/dist/cjs/router.cjs.map +1 -1
- package/dist/cjs/router.d.cts +1 -1
- package/dist/esm/link.d.ts +1 -1
- package/dist/esm/link.js +12 -2
- package/dist/esm/link.js.map +1 -1
- package/dist/esm/path.d.ts +3 -2
- package/dist/esm/path.js +17 -10
- package/dist/esm/path.js.map +1 -1
- package/dist/esm/router.d.ts +1 -1
- package/dist/esm/router.js +4 -2
- package/dist/esm/router.js.map +1 -1
- package/package.json +1 -1
- package/src/link.tsx +14 -2
- package/src/path.ts +25 -11
- package/src/router.ts +4 -2
package/package.json
CHANGED
package/src/link.tsx
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
functionalUpdate,
|
|
10
10
|
useForwardedRef,
|
|
11
11
|
useIntersectionObserver,
|
|
12
|
+
useLayoutEffect,
|
|
12
13
|
} from './utils'
|
|
13
14
|
import { exactPathTest, removeTrailingSlash } from './path'
|
|
14
15
|
import type { ParsedLocation } from './location'
|
|
@@ -497,7 +498,7 @@ export interface LinkOptionsProps {
|
|
|
497
498
|
* - `'intent'` - Preload the linked route on hover and cache it for this many milliseconds in hopes that the user will eventually navigate there.
|
|
498
499
|
* - `'viewport'` - Preload the linked route when it enters the viewport
|
|
499
500
|
*/
|
|
500
|
-
preload?: false | 'intent' | 'viewport'
|
|
501
|
+
preload?: false | 'intent' | 'viewport' | 'render'
|
|
501
502
|
/**
|
|
502
503
|
* When a preload strategy is set, this delays the preload by this many milliseconds.
|
|
503
504
|
* If the user exits the link before this delay, the preload will be cancelled.
|
|
@@ -589,6 +590,7 @@ export function useLinkProps<
|
|
|
589
590
|
): React.ComponentPropsWithRef<'a'> {
|
|
590
591
|
const router = useRouter()
|
|
591
592
|
const [isTransitioning, setIsTransitioning] = React.useState(false)
|
|
593
|
+
const hasRenderFetched = React.useRef(false)
|
|
592
594
|
const innerRef = useForwardedRef(forwardedRef)
|
|
593
595
|
|
|
594
596
|
const {
|
|
@@ -722,9 +724,19 @@ export function useLinkProps<
|
|
|
722
724
|
innerRef,
|
|
723
725
|
preloadViewportIoCallback,
|
|
724
726
|
{ rootMargin: '100px' },
|
|
725
|
-
{ disabled: !!disabled || preload
|
|
727
|
+
{ disabled: !!disabled || !(preload === 'viewport') },
|
|
726
728
|
)
|
|
727
729
|
|
|
730
|
+
useLayoutEffect(() => {
|
|
731
|
+
if (hasRenderFetched.current) {
|
|
732
|
+
return
|
|
733
|
+
}
|
|
734
|
+
if (!disabled && preload === 'render') {
|
|
735
|
+
doPreload()
|
|
736
|
+
hasRenderFetched.current = true
|
|
737
|
+
}
|
|
738
|
+
}, [disabled, doPreload, preload])
|
|
739
|
+
|
|
728
740
|
if (type === 'external') {
|
|
729
741
|
return {
|
|
730
742
|
...propsSafeToSpread,
|
package/src/path.ts
CHANGED
|
@@ -87,6 +87,7 @@ interface ResolvePathOptions {
|
|
|
87
87
|
base: string
|
|
88
88
|
to: string
|
|
89
89
|
trailingSlash?: 'always' | 'never' | 'preserve'
|
|
90
|
+
caseSensitive?: boolean
|
|
90
91
|
}
|
|
91
92
|
|
|
92
93
|
export function resolvePath({
|
|
@@ -94,9 +95,10 @@ export function resolvePath({
|
|
|
94
95
|
base,
|
|
95
96
|
to,
|
|
96
97
|
trailingSlash = 'never',
|
|
98
|
+
caseSensitive,
|
|
97
99
|
}: ResolvePathOptions) {
|
|
98
|
-
base = removeBasepath(basepath, base)
|
|
99
|
-
to = removeBasepath(basepath, to)
|
|
100
|
+
base = removeBasepath(basepath, base, caseSensitive)
|
|
101
|
+
to = removeBasepath(basepath, to, caseSensitive)
|
|
100
102
|
|
|
101
103
|
let baseSegments = parsePathname(base)
|
|
102
104
|
const toSegments = parsePathname(to)
|
|
@@ -260,15 +262,23 @@ export function matchPathname(
|
|
|
260
262
|
return pathParams ?? {}
|
|
261
263
|
}
|
|
262
264
|
|
|
263
|
-
export function removeBasepath(
|
|
265
|
+
export function removeBasepath(
|
|
266
|
+
basepath: string,
|
|
267
|
+
pathname: string,
|
|
268
|
+
caseSensitive: boolean = false,
|
|
269
|
+
) {
|
|
270
|
+
// normalize basepath and pathname for case-insensitive comparison if needed
|
|
271
|
+
const normalizedBasepath = caseSensitive ? basepath : basepath.toLowerCase()
|
|
272
|
+
const normalizedPathname = caseSensitive ? pathname : pathname.toLowerCase()
|
|
273
|
+
|
|
264
274
|
switch (true) {
|
|
265
275
|
// default behaviour is to serve app from the root - pathname
|
|
266
276
|
// left untouched
|
|
267
|
-
case
|
|
277
|
+
case normalizedBasepath === '/':
|
|
268
278
|
return pathname
|
|
269
279
|
|
|
270
|
-
// shortcut for removing the basepath
|
|
271
|
-
case
|
|
280
|
+
// shortcut for removing the basepath if it matches the pathname
|
|
281
|
+
case normalizedPathname === normalizedBasepath:
|
|
272
282
|
return ''
|
|
273
283
|
|
|
274
284
|
// in case pathname is shorter than basepath - there is
|
|
@@ -280,11 +290,11 @@ export function removeBasepath(basepath: string, pathname: string) {
|
|
|
280
290
|
// earlier, otherwise, basepath separated from pathname with
|
|
281
291
|
// separator, therefore lack of separator means partial
|
|
282
292
|
// segment match (`/app` should not match `/application`)
|
|
283
|
-
case
|
|
293
|
+
case normalizedPathname[normalizedBasepath.length] !== '/':
|
|
284
294
|
return pathname
|
|
285
295
|
|
|
286
|
-
// remove the basepath from the pathname
|
|
287
|
-
case
|
|
296
|
+
// remove the basepath from the pathname if it starts with it
|
|
297
|
+
case normalizedPathname.startsWith(normalizedBasepath):
|
|
288
298
|
return pathname.slice(basepath.length)
|
|
289
299
|
|
|
290
300
|
// otherwise, return the pathname as is
|
|
@@ -303,9 +313,13 @@ export function matchByPath(
|
|
|
303
313
|
return undefined
|
|
304
314
|
}
|
|
305
315
|
// Remove the base path from the pathname
|
|
306
|
-
from = removeBasepath(basepath, from)
|
|
316
|
+
from = removeBasepath(basepath, from, matchLocation.caseSensitive)
|
|
307
317
|
// Default to to $ (wildcard)
|
|
308
|
-
const to = removeBasepath(
|
|
318
|
+
const to = removeBasepath(
|
|
319
|
+
basepath,
|
|
320
|
+
`${matchLocation.to ?? '$'}`,
|
|
321
|
+
matchLocation.caseSensitive,
|
|
322
|
+
)
|
|
309
323
|
|
|
310
324
|
// Parse the from and to
|
|
311
325
|
const baseSegments = parsePathname(from)
|
package/src/router.ts
CHANGED
|
@@ -211,7 +211,7 @@ export interface RouterOptions<
|
|
|
211
211
|
* @link [API Docs](https://tanstack.com/router/latest/docs/framework/react/api/router/RouterOptionsType#defaultpreload-property)
|
|
212
212
|
* @link [Guide](https://tanstack.com/router/latest/docs/framework/react/guide/preloading)
|
|
213
213
|
*/
|
|
214
|
-
defaultPreload?: false | 'intent' | 'viewport'
|
|
214
|
+
defaultPreload?: false | 'intent' | 'viewport' | 'render'
|
|
215
215
|
/**
|
|
216
216
|
* The delay in milliseconds that a route must be hovered over or touched before it is preloaded.
|
|
217
217
|
*
|
|
@@ -722,6 +722,7 @@ export class Router<
|
|
|
722
722
|
defaultPendingMinMs: 500,
|
|
723
723
|
context: undefined!,
|
|
724
724
|
...options,
|
|
725
|
+
caseSensitive: options.caseSensitive ?? false,
|
|
725
726
|
notFoundMode: options.notFoundMode ?? 'fuzzy',
|
|
726
727
|
stringifySearch: options.stringifySearch ?? defaultStringifySearch,
|
|
727
728
|
parseSearch: options.parseSearch ?? defaultParseSearch,
|
|
@@ -1007,6 +1008,7 @@ export class Router<
|
|
|
1007
1008
|
base: from,
|
|
1008
1009
|
to: cleanPath(path),
|
|
1009
1010
|
trailingSlash: this.options.trailingSlash,
|
|
1011
|
+
caseSensitive: this.options.caseSensitive,
|
|
1010
1012
|
})
|
|
1011
1013
|
return resolvedPath
|
|
1012
1014
|
}
|
|
@@ -1620,7 +1622,7 @@ export class Router<
|
|
|
1620
1622
|
})
|
|
1621
1623
|
|
|
1622
1624
|
if (foundMask) {
|
|
1623
|
-
const { from, ...maskProps } = foundMask
|
|
1625
|
+
const { from: _from, ...maskProps } = foundMask
|
|
1624
1626
|
maskedDest = {
|
|
1625
1627
|
...pick(opts, ['from']),
|
|
1626
1628
|
...maskProps,
|