@tanstack/router-core 1.132.0-alpha.2 → 1.132.0-alpha.20
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/Matches.cjs.map +1 -1
- package/dist/cjs/Matches.d.cts +2 -2
- package/dist/cjs/config.cjs +10 -0
- package/dist/cjs/config.cjs.map +1 -0
- package/dist/cjs/config.d.cts +17 -0
- package/dist/cjs/fileRoute.d.cts +3 -2
- package/dist/cjs/index.cjs +15 -3
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +11 -4
- package/dist/cjs/load-matches.cjs +636 -0
- package/dist/cjs/load-matches.cjs.map +1 -0
- package/dist/cjs/load-matches.d.cts +16 -0
- package/dist/cjs/location.d.cts +38 -0
- package/dist/cjs/path.cjs +7 -49
- package/dist/cjs/path.cjs.map +1 -1
- package/dist/cjs/path.d.cts +3 -6
- package/dist/cjs/qss.cjs +19 -19
- package/dist/cjs/qss.cjs.map +1 -1
- package/dist/cjs/qss.d.cts +6 -4
- package/dist/cjs/redirect.cjs +3 -3
- package/dist/cjs/redirect.cjs.map +1 -1
- package/dist/cjs/rewrite.cjs +63 -0
- package/dist/cjs/rewrite.cjs.map +1 -0
- package/dist/cjs/rewrite.d.cts +22 -0
- package/dist/cjs/route.cjs.map +1 -1
- package/dist/cjs/route.d.cts +42 -37
- package/dist/cjs/router.cjs +134 -780
- package/dist/cjs/router.cjs.map +1 -1
- package/dist/cjs/router.d.cts +68 -36
- package/dist/cjs/scroll-restoration.cjs +32 -29
- package/dist/cjs/scroll-restoration.cjs.map +1 -1
- package/dist/cjs/scroll-restoration.d.cts +1 -1
- package/dist/cjs/searchParams.cjs +7 -15
- package/dist/cjs/searchParams.cjs.map +1 -1
- package/dist/cjs/ssr/constants.cjs +5 -0
- package/dist/cjs/ssr/constants.cjs.map +1 -0
- package/dist/cjs/ssr/constants.d.cts +1 -0
- package/dist/cjs/ssr/{seroval-plugins.cjs → serializer/ShallowErrorPlugin.cjs} +2 -2
- package/dist/cjs/ssr/serializer/ShallowErrorPlugin.cjs.map +1 -0
- package/dist/cjs/ssr/{seroval-plugins.d.cts → serializer/ShallowErrorPlugin.d.cts} +1 -2
- package/dist/cjs/ssr/serializer/seroval-plugins.cjs +11 -0
- package/dist/cjs/ssr/serializer/seroval-plugins.cjs.map +1 -0
- package/dist/cjs/ssr/serializer/seroval-plugins.d.cts +2 -0
- package/dist/cjs/ssr/serializer/transformer.cjs +52 -0
- package/dist/cjs/ssr/serializer/transformer.cjs.map +1 -0
- package/dist/cjs/ssr/serializer/transformer.d.cts +56 -0
- package/dist/cjs/ssr/server.d.cts +5 -0
- package/dist/cjs/ssr/ssr-client.cjs +15 -1
- package/dist/cjs/ssr/ssr-client.cjs.map +1 -1
- package/dist/cjs/ssr/ssr-client.d.cts +5 -1
- package/dist/cjs/ssr/ssr-server.cjs +12 -10
- package/dist/cjs/ssr/ssr-server.cjs.map +1 -1
- package/dist/cjs/ssr/ssr-server.d.cts +0 -1
- package/dist/cjs/ssr/tsrScript.cjs +1 -1
- package/dist/cjs/ssr/tsrScript.cjs.map +1 -1
- package/dist/cjs/utils.cjs +8 -7
- package/dist/cjs/utils.cjs.map +1 -1
- package/dist/cjs/utils.d.cts +1 -1
- package/dist/esm/Matches.d.ts +2 -2
- package/dist/esm/Matches.js.map +1 -1
- package/dist/esm/config.d.ts +17 -0
- package/dist/esm/config.js +10 -0
- package/dist/esm/config.js.map +1 -0
- package/dist/esm/fileRoute.d.ts +3 -2
- package/dist/esm/index.d.ts +11 -4
- package/dist/esm/index.js +17 -5
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/load-matches.d.ts +16 -0
- package/dist/esm/load-matches.js +636 -0
- package/dist/esm/load-matches.js.map +1 -0
- package/dist/esm/location.d.ts +38 -0
- package/dist/esm/path.d.ts +3 -6
- package/dist/esm/path.js +7 -49
- package/dist/esm/path.js.map +1 -1
- package/dist/esm/qss.d.ts +6 -4
- package/dist/esm/qss.js +19 -19
- package/dist/esm/qss.js.map +1 -1
- package/dist/esm/redirect.js +3 -3
- package/dist/esm/redirect.js.map +1 -1
- package/dist/esm/rewrite.d.ts +22 -0
- package/dist/esm/rewrite.js +63 -0
- package/dist/esm/rewrite.js.map +1 -0
- package/dist/esm/route.d.ts +42 -37
- package/dist/esm/route.js.map +1 -1
- package/dist/esm/router.d.ts +68 -36
- package/dist/esm/router.js +136 -782
- package/dist/esm/router.js.map +1 -1
- package/dist/esm/scroll-restoration.d.ts +1 -1
- package/dist/esm/scroll-restoration.js +32 -29
- package/dist/esm/scroll-restoration.js.map +1 -1
- package/dist/esm/searchParams.js +7 -15
- package/dist/esm/searchParams.js.map +1 -1
- package/dist/esm/ssr/constants.d.ts +1 -0
- package/dist/esm/ssr/constants.js +5 -0
- package/dist/esm/ssr/constants.js.map +1 -0
- package/dist/esm/ssr/{seroval-plugins.d.ts → serializer/ShallowErrorPlugin.d.ts} +1 -2
- package/dist/esm/ssr/{seroval-plugins.js → serializer/ShallowErrorPlugin.js} +2 -2
- package/dist/esm/ssr/serializer/ShallowErrorPlugin.js.map +1 -0
- package/dist/esm/ssr/serializer/seroval-plugins.d.ts +2 -0
- package/dist/esm/ssr/serializer/seroval-plugins.js +11 -0
- package/dist/esm/ssr/serializer/seroval-plugins.js.map +1 -0
- package/dist/esm/ssr/serializer/transformer.d.ts +56 -0
- package/dist/esm/ssr/serializer/transformer.js +52 -0
- package/dist/esm/ssr/serializer/transformer.js.map +1 -0
- package/dist/esm/ssr/server.d.ts +5 -0
- package/dist/esm/ssr/ssr-client.d.ts +5 -1
- package/dist/esm/ssr/ssr-client.js +15 -1
- package/dist/esm/ssr/ssr-client.js.map +1 -1
- package/dist/esm/ssr/ssr-server.d.ts +0 -1
- package/dist/esm/ssr/ssr-server.js +12 -10
- package/dist/esm/ssr/ssr-server.js.map +1 -1
- package/dist/esm/ssr/tsrScript.js +1 -1
- package/dist/esm/ssr/tsrScript.js.map +1 -1
- package/dist/esm/utils.d.ts +1 -1
- package/dist/esm/utils.js +8 -7
- package/dist/esm/utils.js.map +1 -1
- package/package.json +1 -1
- package/src/Matches.ts +2 -2
- package/src/config.ts +42 -0
- package/src/fileRoute.ts +15 -3
- package/src/index.ts +32 -3
- package/src/load-matches.ts +955 -0
- package/src/location.ts +38 -0
- package/src/path.ts +9 -66
- package/src/qss.ts +27 -24
- package/src/redirect.ts +3 -3
- package/src/rewrite.ts +70 -0
- package/src/route.ts +136 -33
- package/src/router.ts +271 -1170
- package/src/scroll-restoration.ts +42 -37
- package/src/searchParams.ts +8 -19
- package/src/ssr/constants.ts +1 -0
- package/src/ssr/{seroval-plugins.ts → serializer/ShallowErrorPlugin.ts} +2 -2
- package/src/ssr/serializer/seroval-plugins.ts +9 -0
- package/src/ssr/serializer/transformer.ts +215 -0
- package/src/ssr/server.ts +6 -0
- package/src/ssr/ssr-client.ts +30 -3
- package/src/ssr/ssr-server.ts +18 -10
- package/src/ssr/tsrScript.ts +5 -1
- package/src/utils.ts +11 -10
- package/dist/cjs/ssr/seroval-plugins.cjs.map +0 -1
- package/dist/esm/ssr/seroval-plugins.js.map +0 -1
package/dist/cjs/router.d.cts
CHANGED
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
import { Store } from '@tanstack/store';
|
|
2
|
+
import { loadRouteChunk } from './load-matches.cjs';
|
|
2
3
|
import { ParsePathnameCache } from './path.cjs';
|
|
3
4
|
import { SearchParser, SearchSerializer } from './searchParams.cjs';
|
|
4
5
|
import { AnyRedirect, ResolvedRedirect } from './redirect.cjs';
|
|
5
6
|
import { HistoryLocation, HistoryState, ParsedHistoryState, RouterHistory } from '@tanstack/history';
|
|
6
|
-
import { Awaitable, ControlledPromise, NoInfer, NonNullableUpdater, PickAsRequired, Updater } from './utils.cjs';
|
|
7
|
+
import { Awaitable, Constrain, ControlledPromise, NoInfer, NonNullableUpdater, PickAsRequired, Updater } from './utils.cjs';
|
|
7
8
|
import { ParsedLocation } from './location.cjs';
|
|
8
9
|
import { AnyContext, AnyRoute, AnyRouteWithContext, MakeRemountDepsOptionsUnion, RouteMask } from './route.cjs';
|
|
9
10
|
import { FullSearchSchema, RouteById, RoutePaths, RoutesById, RoutesByPath } from './routeInfo.cjs';
|
|
10
|
-
import { AnyRouteMatch,
|
|
11
|
+
import { AnyRouteMatch, MakeRouteMatchUnion, MatchRouteOptions } from './Matches.cjs';
|
|
11
12
|
import { BuildLocationFn, CommitLocationOptions, NavigateFn } from './RouterProvider.cjs';
|
|
12
13
|
import { Manifest } from './manifest.cjs';
|
|
13
14
|
import { AnySchema } from './validators.cjs';
|
|
14
15
|
import { NavigateOptions, ResolveRelativePath, ToOptions } from './link.cjs';
|
|
16
|
+
import { AnySerializationAdapter, ValidateSerializableInput } from './ssr/serializer/transformer.cjs';
|
|
17
|
+
import { AnyRouterConfig } from './config.cjs';
|
|
15
18
|
export type ControllablePromise<T = any> = Promise<T> & {
|
|
16
19
|
resolve: (value: T) => void;
|
|
17
20
|
reject: (value?: any) => void;
|
|
@@ -19,6 +22,8 @@ export type ControllablePromise<T = any> = Promise<T> & {
|
|
|
19
22
|
export type InjectedHtmlEntry = Promise<string>;
|
|
20
23
|
export interface DefaultRegister {
|
|
21
24
|
router: AnyRouter;
|
|
25
|
+
config: AnyRouterConfig;
|
|
26
|
+
ssr: SSROption;
|
|
22
27
|
}
|
|
23
28
|
export interface Register extends DefaultRegister {
|
|
24
29
|
}
|
|
@@ -28,7 +33,8 @@ export interface DefaultRouterOptionsExtensions {
|
|
|
28
33
|
}
|
|
29
34
|
export interface RouterOptionsExtensions extends DefaultRouterOptionsExtensions {
|
|
30
35
|
}
|
|
31
|
-
export
|
|
36
|
+
export type SSROption = boolean | 'data-only';
|
|
37
|
+
export interface RouterOptions<TRouteTree extends AnyRoute, TTrailingSlashOption extends TrailingSlashOption, TDefaultStructuralSharingOption extends boolean = false, TRouterHistory extends RouterHistory = RouterHistory, TDehydrated = undefined> extends RouterOptionsExtensions {
|
|
32
38
|
/**
|
|
33
39
|
* The history object that will be used to manage the browser history.
|
|
34
40
|
*
|
|
@@ -172,6 +178,18 @@ export interface RouterOptions<TRouteTree extends AnyRoute, TTrailingSlashOption
|
|
|
172
178
|
/**
|
|
173
179
|
* The basepath for then entire router. This is useful for mounting a router instance at a subpath.
|
|
174
180
|
*
|
|
181
|
+
* @deprecated - use `rewrite.input` with the new `rewriteBasepath` utility instead:
|
|
182
|
+
* ```ts
|
|
183
|
+
* const router = createRouter({
|
|
184
|
+
* routeTree,
|
|
185
|
+
* rewrite: rewriteBasepath('/basepath')
|
|
186
|
+
* // Or wrap existing rewrite functionality
|
|
187
|
+
* rewrite: rewriteBasepath('/basepath', {
|
|
188
|
+
* output: ({ url }) => {...},
|
|
189
|
+
* input: ({ url }) => {...},
|
|
190
|
+
* })
|
|
191
|
+
* })
|
|
192
|
+
* ```
|
|
175
193
|
* @default '/'
|
|
176
194
|
* @link [API Docs](https://tanstack.com/router/latest/docs/framework/react/api/router/RouterOptionsType#basepath-property)
|
|
177
195
|
*/
|
|
@@ -195,7 +213,7 @@ export interface RouterOptions<TRouteTree extends AnyRoute, TTrailingSlashOption
|
|
|
195
213
|
* @link [API Docs](https://tanstack.com/router/latest/docs/framework/react/api/router/RouterOptionsType#dehydrate-method)
|
|
196
214
|
* @link [Guide](https://tanstack.com/router/latest/docs/framework/react/guide/external-data-loading#critical-dehydrationhydration)
|
|
197
215
|
*/
|
|
198
|
-
dehydrate?: () =>
|
|
216
|
+
dehydrate?: () => Constrain<TDehydrated, ValidateSerializableInput<Register, TDehydrated>>;
|
|
199
217
|
/**
|
|
200
218
|
* A function that will be called when the router is hydrated.
|
|
201
219
|
*
|
|
@@ -261,7 +279,7 @@ export interface RouterOptions<TRouteTree extends AnyRoute, TTrailingSlashOption
|
|
|
261
279
|
*
|
|
262
280
|
* @default true
|
|
263
281
|
*/
|
|
264
|
-
defaultSsr?:
|
|
282
|
+
defaultSsr?: SSROption;
|
|
265
283
|
search?: {
|
|
266
284
|
/**
|
|
267
285
|
* Configures how unknown search params (= not returned by any `validateSearch`) are treated.
|
|
@@ -290,7 +308,9 @@ export interface RouterOptions<TRouteTree extends AnyRoute, TTrailingSlashOption
|
|
|
290
308
|
*
|
|
291
309
|
* @default false
|
|
292
310
|
*/
|
|
293
|
-
scrollRestoration?: boolean
|
|
311
|
+
scrollRestoration?: boolean | ((opts: {
|
|
312
|
+
location: ParsedLocation;
|
|
313
|
+
}) => boolean);
|
|
294
314
|
/**
|
|
295
315
|
* A function that will be called to get the key for the scroll restoration cache.
|
|
296
316
|
*
|
|
@@ -319,7 +339,42 @@ export interface RouterOptions<TRouteTree extends AnyRoute, TTrailingSlashOption
|
|
|
319
339
|
* @default false
|
|
320
340
|
*/
|
|
321
341
|
disableGlobalCatchBoundary?: boolean;
|
|
342
|
+
serializationAdapters?: ReadonlyArray<AnySerializationAdapter>;
|
|
343
|
+
/**
|
|
344
|
+
* Configures how the router will rewrite the location between the actual href and the internal href of the router.
|
|
345
|
+
*
|
|
346
|
+
* @default undefined
|
|
347
|
+
* @description You can provide a custom rewrite pair (in/out) or use the utilities like `rewriteBasepath` as a convenience for common use cases, or even do both!
|
|
348
|
+
* This is useful for basepath rewriting, shifting data from the origin to the path (for things like )
|
|
349
|
+
*/
|
|
350
|
+
rewrite?: LocationRewrite;
|
|
351
|
+
origin?: string;
|
|
322
352
|
}
|
|
353
|
+
export type LocationRewrite = {
|
|
354
|
+
/**
|
|
355
|
+
* A function that will be called to rewrite the URL before it is interpreted by the router from the history instance.
|
|
356
|
+
* Utilities like `rewriteBasepath` are provided as a convenience for common use cases.
|
|
357
|
+
*
|
|
358
|
+
* @default undefined
|
|
359
|
+
*/
|
|
360
|
+
input?: LocationRewriteFunction;
|
|
361
|
+
/**
|
|
362
|
+
* A function that will be called to rewrite the URL before it is committed to the actual history instance from the router.
|
|
363
|
+
* Utilities like `rewriteBasepath` are provided as a convenience for common use cases.
|
|
364
|
+
*
|
|
365
|
+
* @default undefined
|
|
366
|
+
*/
|
|
367
|
+
output?: LocationRewriteFunction;
|
|
368
|
+
};
|
|
369
|
+
/**
|
|
370
|
+
* A function that will be called to rewrite the URL.
|
|
371
|
+
*
|
|
372
|
+
* @param url The URL to rewrite.
|
|
373
|
+
* @returns The rewritten URL (as a URL instance or full href string) or undefined if no rewrite is needed.
|
|
374
|
+
*/
|
|
375
|
+
export type LocationRewriteFunction = ({ url, }: {
|
|
376
|
+
url: URL;
|
|
377
|
+
}) => undefined | string | URL;
|
|
323
378
|
export interface RouterState<in out TRouteTree extends AnyRoute = AnyRoute, in out TRouteMatch = MakeRouteMatchUnion> {
|
|
324
379
|
status: 'pending' | 'idle';
|
|
325
380
|
loadedAt: number;
|
|
@@ -408,7 +463,7 @@ export type InvalidateFn<TRouter extends AnyRouter> = (opts?: {
|
|
|
408
463
|
sync?: boolean;
|
|
409
464
|
forcePending?: boolean;
|
|
410
465
|
}) => Promise<void>;
|
|
411
|
-
export type ParseLocationFn<TRouteTree extends AnyRoute> = (previousLocation?: ParsedLocation<FullSearchSchema<TRouteTree
|
|
466
|
+
export type ParseLocationFn<TRouteTree extends AnyRoute> = (locationToParse: HistoryLocation, previousLocation?: ParsedLocation<FullSearchSchema<TRouteTree>>) => ParsedLocation<FullSearchSchema<TRouteTree>>;
|
|
412
467
|
export type GetMatchRoutesFn = (pathname: string, routePathname: string | undefined) => {
|
|
413
468
|
matchedRoutes: Array<AnyRoute>;
|
|
414
469
|
routeParams: Record<string, string>;
|
|
@@ -486,6 +541,8 @@ export declare class RouterCore<in out TRouteTree extends AnyRoute, in out TTrai
|
|
|
486
541
|
__store: Store<RouterState<TRouteTree>>;
|
|
487
542
|
options: PickAsRequired<RouterOptions<TRouteTree, TTrailingSlashOption, TDefaultStructuralSharingOption, TRouterHistory, TDehydrated>, 'stringifySearch' | 'parseSearch' | 'context'>;
|
|
488
543
|
history: TRouterHistory;
|
|
544
|
+
rewrite?: LocationRewrite;
|
|
545
|
+
origin?: string;
|
|
489
546
|
latestLocation: ParsedLocation<FullSearchSchema<TRouteTree>>;
|
|
490
547
|
basepath: string;
|
|
491
548
|
routeTree: TRouteTree;
|
|
@@ -502,7 +559,8 @@ export declare class RouterCore<in out TRouteTree extends AnyRoute, in out TTrai
|
|
|
502
559
|
isShell(): boolean;
|
|
503
560
|
isPrerendering(): boolean;
|
|
504
561
|
update: UpdateFn<TRouteTree, TTrailingSlashOption, TDefaultStructuralSharingOption, TRouterHistory, TDehydrated>;
|
|
505
|
-
get state(): RouterState<TRouteTree
|
|
562
|
+
get state(): RouterState<TRouteTree>;
|
|
563
|
+
updateLatestLocation: () => void;
|
|
506
564
|
buildRouteTree: () => void;
|
|
507
565
|
subscribe: SubscribeFn;
|
|
508
566
|
emit: EmitFn;
|
|
@@ -527,41 +585,17 @@ export declare class RouterCore<in out TRouteTree extends AnyRoute, in out TTrai
|
|
|
527
585
|
startViewTransition: (fn: () => Promise<void>) => void;
|
|
528
586
|
updateMatch: UpdateMatchFn;
|
|
529
587
|
getMatch: GetMatchFn;
|
|
530
|
-
private triggerOnReady;
|
|
531
|
-
private resolvePreload;
|
|
532
|
-
private handleRedirectAndNotFound;
|
|
533
|
-
private shouldSkipLoader;
|
|
534
|
-
private handleSerialError;
|
|
535
|
-
private isBeforeLoadSsr;
|
|
536
|
-
private setupPendingTimeout;
|
|
537
|
-
private shouldExecuteBeforeLoad;
|
|
538
|
-
private executeBeforeLoad;
|
|
539
|
-
private handleBeforeLoad;
|
|
540
|
-
private executeHead;
|
|
541
|
-
private potentialPendingMinPromise;
|
|
542
|
-
private getLoaderContext;
|
|
543
|
-
private runLoader;
|
|
544
|
-
private loadRouteMatch;
|
|
545
|
-
loadMatches: (baseContext: {
|
|
546
|
-
location: ParsedLocation;
|
|
547
|
-
matches: Array<AnyRouteMatch>;
|
|
548
|
-
preload?: boolean;
|
|
549
|
-
onReady?: () => Promise<void>;
|
|
550
|
-
updateMatch?: UpdateMatchFn;
|
|
551
|
-
sync?: boolean;
|
|
552
|
-
}) => Promise<Array<MakeRouteMatch>>;
|
|
553
588
|
invalidate: InvalidateFn<RouterCore<TRouteTree, TTrailingSlashOption, TDefaultStructuralSharingOption, TRouterHistory, TDehydrated>>;
|
|
554
589
|
resolveRedirect: (redirect: AnyRedirect) => AnyRedirect;
|
|
555
590
|
clearCache: ClearCacheFn<this>;
|
|
556
591
|
clearExpiredCache: () => void;
|
|
557
|
-
loadRouteChunk:
|
|
592
|
+
loadRouteChunk: typeof loadRouteChunk;
|
|
558
593
|
preloadRoute: PreloadRouteFn<TRouteTree, TTrailingSlashOption, TDefaultStructuralSharingOption, TRouterHistory>;
|
|
559
594
|
matchRoute: MatchRouteFn<TRouteTree, TTrailingSlashOption, TDefaultStructuralSharingOption, TRouterHistory>;
|
|
560
595
|
ssr?: {
|
|
561
596
|
manifest: Manifest | undefined;
|
|
562
597
|
};
|
|
563
598
|
serverSsr?: ServerSsr;
|
|
564
|
-
private _handleNotFound;
|
|
565
599
|
hasNotFoundMatch: () => boolean;
|
|
566
600
|
}
|
|
567
601
|
export declare class SearchParamError extends Error {
|
|
@@ -570,7 +604,6 @@ export declare class PathParamError extends Error {
|
|
|
570
604
|
}
|
|
571
605
|
export declare function lazyFn<T extends Record<string, (...args: Array<any>) => any>, TKey extends keyof T = 'default'>(fn: () => Promise<T>, key?: TKey): (...args: Parameters<T[TKey]>) => Promise<Awaited<ReturnType<T[TKey]>>>;
|
|
572
606
|
export declare function getInitialRouterState(location: ParsedLocation): RouterState<any>;
|
|
573
|
-
export declare const componentTypes: readonly ["component", "errorComponent", "pendingComponent", "notFoundComponent"];
|
|
574
607
|
interface RouteLike {
|
|
575
608
|
id: string;
|
|
576
609
|
isRoot?: boolean;
|
|
@@ -592,10 +625,9 @@ export declare function processRouteTree<TRouteLike extends RouteLike>({ routeTr
|
|
|
592
625
|
routeTree: TRouteLike;
|
|
593
626
|
initRoute?: (route: TRouteLike, index: number) => void;
|
|
594
627
|
}): ProcessRouteTreeResult<TRouteLike>;
|
|
595
|
-
export declare function getMatchedRoutes<TRouteLike extends RouteLike>({ pathname, routePathname,
|
|
628
|
+
export declare function getMatchedRoutes<TRouteLike extends RouteLike>({ pathname, routePathname, caseSensitive, routesByPath, routesById, flatRoutes, parseCache, }: {
|
|
596
629
|
pathname: string;
|
|
597
630
|
routePathname?: string;
|
|
598
|
-
basepath: string;
|
|
599
631
|
caseSensitive?: boolean;
|
|
600
632
|
routesByPath: Record<string, TRouteLike>;
|
|
601
633
|
routesById: Record<string, TRouteLike>;
|
|
@@ -7,7 +7,6 @@ function getSafeSessionStorage() {
|
|
|
7
7
|
return window.sessionStorage;
|
|
8
8
|
}
|
|
9
9
|
} catch {
|
|
10
|
-
return void 0;
|
|
11
10
|
}
|
|
12
11
|
return void 0;
|
|
13
12
|
}
|
|
@@ -26,7 +25,7 @@ const throttle = (fn, wait) => {
|
|
|
26
25
|
function createScrollRestorationCache() {
|
|
27
26
|
const safeSessionStorage = getSafeSessionStorage();
|
|
28
27
|
if (!safeSessionStorage) {
|
|
29
|
-
return
|
|
28
|
+
return null;
|
|
30
29
|
}
|
|
31
30
|
const persistedState = safeSessionStorage.getItem(storageKey);
|
|
32
31
|
let state = persistedState ? JSON.parse(persistedState) : {};
|
|
@@ -46,12 +45,12 @@ function getCssSelector(el) {
|
|
|
46
45
|
const path = [];
|
|
47
46
|
let parent;
|
|
48
47
|
while (parent = el.parentNode) {
|
|
49
|
-
path.
|
|
50
|
-
`${el.tagName}:nth-child(${
|
|
48
|
+
path.push(
|
|
49
|
+
`${el.tagName}:nth-child(${Array.prototype.indexOf.call(parent.children, el) + 1})`
|
|
51
50
|
);
|
|
52
51
|
el = parent;
|
|
53
52
|
}
|
|
54
|
-
return `${path.join(" > ")}`.toLowerCase();
|
|
53
|
+
return `${path.reverse().join(" > ")}`.toLowerCase();
|
|
55
54
|
}
|
|
56
55
|
let ignoreScroll = false;
|
|
57
56
|
function restoreScroll({
|
|
@@ -69,10 +68,10 @@ function restoreScroll({
|
|
|
69
68
|
console.error(error);
|
|
70
69
|
return;
|
|
71
70
|
}
|
|
72
|
-
const resolvedKey = key || window.history.state?.
|
|
71
|
+
const resolvedKey = key || window.history.state?.__TSR_key;
|
|
73
72
|
const elementEntries = byKey[resolvedKey];
|
|
74
73
|
ignoreScroll = true;
|
|
75
|
-
|
|
74
|
+
scroll: {
|
|
76
75
|
if (shouldScrollRestoration && elementEntries && Object.keys(elementEntries).length > 0) {
|
|
77
76
|
for (const elementSelector in elementEntries) {
|
|
78
77
|
const entry = elementEntries[elementSelector];
|
|
@@ -90,44 +89,40 @@ function restoreScroll({
|
|
|
90
89
|
}
|
|
91
90
|
}
|
|
92
91
|
}
|
|
93
|
-
|
|
92
|
+
break scroll;
|
|
94
93
|
}
|
|
95
|
-
const hash = (location ?? window.location).hash.split("#")[1];
|
|
94
|
+
const hash = (location ?? window.location).hash.split("#", 2)[1];
|
|
96
95
|
if (hash) {
|
|
97
|
-
const hashScrollIntoViewOptions =
|
|
96
|
+
const hashScrollIntoViewOptions = window.history.state?.__hashScrollIntoViewOptions ?? true;
|
|
98
97
|
if (hashScrollIntoViewOptions) {
|
|
99
98
|
const el = document.getElementById(hash);
|
|
100
99
|
if (el) {
|
|
101
100
|
el.scrollIntoView(hashScrollIntoViewOptions);
|
|
102
101
|
}
|
|
103
102
|
}
|
|
104
|
-
|
|
103
|
+
break scroll;
|
|
105
104
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
element.scrollTo(
|
|
113
|
-
top: 0,
|
|
114
|
-
left: 0,
|
|
115
|
-
behavior
|
|
116
|
-
});
|
|
105
|
+
const scrollOptions = { top: 0, left: 0, behavior };
|
|
106
|
+
window.scrollTo(scrollOptions);
|
|
107
|
+
if (scrollToTopSelectors) {
|
|
108
|
+
for (const selector of scrollToTopSelectors) {
|
|
109
|
+
if (selector === "window") continue;
|
|
110
|
+
const element = typeof selector === "function" ? selector() : document.querySelector(selector);
|
|
111
|
+
if (element) element.scrollTo(scrollOptions);
|
|
117
112
|
}
|
|
118
|
-
}
|
|
119
|
-
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
120
115
|
ignoreScroll = false;
|
|
121
116
|
}
|
|
122
117
|
function setupScrollRestoration(router, force) {
|
|
123
|
-
if (scrollRestorationCache
|
|
118
|
+
if (!scrollRestorationCache && !router.isServer) {
|
|
124
119
|
return;
|
|
125
120
|
}
|
|
126
121
|
const shouldScrollRestoration = force ?? router.options.scrollRestoration ?? false;
|
|
127
122
|
if (shouldScrollRestoration) {
|
|
128
123
|
router.isScrollRestoring = true;
|
|
129
124
|
}
|
|
130
|
-
if (
|
|
125
|
+
if (router.isServer || router.isScrollRestorationSetup || !scrollRestorationCache) {
|
|
131
126
|
return;
|
|
132
127
|
}
|
|
133
128
|
router.isScrollRestorationSetup = true;
|
|
@@ -153,8 +148,8 @@ function setupScrollRestoration(router, force) {
|
|
|
153
148
|
}
|
|
154
149
|
const restoreKey = getKey(router.state.location);
|
|
155
150
|
scrollRestorationCache.set((state) => {
|
|
156
|
-
const keyEntry = state[restoreKey]
|
|
157
|
-
const elementEntry = keyEntry[elementSelector]
|
|
151
|
+
const keyEntry = state[restoreKey] ||= {};
|
|
152
|
+
const elementEntry = keyEntry[elementSelector] ||= {};
|
|
158
153
|
if (elementSelector === "window") {
|
|
159
154
|
elementEntry.scrollX = window.scrollX || 0;
|
|
160
155
|
elementEntry.scrollY = window.scrollY || 0;
|
|
@@ -177,6 +172,14 @@ function setupScrollRestoration(router, force) {
|
|
|
177
172
|
router.resetNextScroll = true;
|
|
178
173
|
return;
|
|
179
174
|
}
|
|
175
|
+
if (typeof router.options.scrollRestoration === "function") {
|
|
176
|
+
const shouldRestore = router.options.scrollRestoration({
|
|
177
|
+
location: router.latestLocation
|
|
178
|
+
});
|
|
179
|
+
if (!shouldRestore) {
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
180
183
|
restoreScroll({
|
|
181
184
|
storageKey,
|
|
182
185
|
key: cacheKey,
|
|
@@ -187,7 +190,7 @@ function setupScrollRestoration(router, force) {
|
|
|
187
190
|
});
|
|
188
191
|
if (router.isScrollRestoring) {
|
|
189
192
|
scrollRestorationCache.set((state) => {
|
|
190
|
-
state[cacheKey]
|
|
193
|
+
state[cacheKey] ||= {};
|
|
191
194
|
return state;
|
|
192
195
|
});
|
|
193
196
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scroll-restoration.cjs","sources":["../../src/scroll-restoration.ts"],"sourcesContent":["import { functionalUpdate } from './utils'\nimport type { AnyRouter } from './router'\nimport type { ParsedLocation } from './location'\nimport type { NonNullableUpdater } from './utils'\nimport type { HistoryLocation } from '@tanstack/history'\n\nexport type ScrollRestorationEntry = { scrollX: number; scrollY: number }\n\nexport type ScrollRestorationByElement = Record<string, ScrollRestorationEntry>\n\nexport type ScrollRestorationByKey = Record<string, ScrollRestorationByElement>\n\nexport type ScrollRestorationCache = {\n state: ScrollRestorationByKey\n set: (updater: NonNullableUpdater<ScrollRestorationByKey>) => void\n}\nexport type ScrollRestorationOptions = {\n getKey?: (location: ParsedLocation) => string\n scrollBehavior?: ScrollToOptions['behavior']\n}\n\nfunction getSafeSessionStorage() {\n try {\n if (\n typeof window !== 'undefined' &&\n typeof window.sessionStorage === 'object'\n ) {\n return window.sessionStorage\n }\n } catch {\n return undefined\n }\n return undefined\n}\n\nexport const storageKey = 'tsr-scroll-restoration-v1_3'\n\nconst throttle = (fn: (...args: Array<any>) => void, wait: number) => {\n let timeout: any\n return (...args: Array<any>) => {\n if (!timeout) {\n timeout = setTimeout(() => {\n fn(...args)\n timeout = null\n }, wait)\n }\n }\n}\n\nfunction createScrollRestorationCache(): ScrollRestorationCache | undefined {\n const safeSessionStorage = getSafeSessionStorage()\n if (!safeSessionStorage) {\n return undefined\n }\n\n const persistedState = safeSessionStorage.getItem(storageKey)\n let state: ScrollRestorationByKey = persistedState\n ? JSON.parse(persistedState)\n : {}\n\n return {\n state,\n // This setter is simply to make sure that we set the sessionStorage right\n // after the state is updated. It doesn't necessarily need to be a functional\n // update.\n set: (updater) => (\n (state = functionalUpdate(updater, state) || state),\n safeSessionStorage.setItem(storageKey, JSON.stringify(state))\n ),\n }\n}\n\nexport const scrollRestorationCache = createScrollRestorationCache()\n\n/**\n * The default `getKey` function for `useScrollRestoration`.\n * It returns the `key` from the location state or the `href` of the location.\n *\n * The `location.href` is used as a fallback to support the use case where the location state is not available like the initial render.\n */\n\nexport const defaultGetScrollRestorationKey = (location: ParsedLocation) => {\n return location.state.__TSR_key! || location.href\n}\n\nexport function getCssSelector(el: any): string {\n const path = []\n let parent\n while ((parent = el.parentNode)) {\n path.unshift(\n `${el.tagName}:nth-child(${([].indexOf as any).call(parent.children, el) + 1})`,\n )\n el = parent\n }\n return `${path.join(' > ')}`.toLowerCase()\n}\n\nlet ignoreScroll = false\n\n// NOTE: This function must remain pure and not use any outside variables\n// unless they are passed in as arguments. Why? Because we need to be able to\n// toString() it into a script tag to execute as early as possible in the browser\n// during SSR. Additionally, we also call it from within the router lifecycle\nexport function restoreScroll({\n storageKey,\n key,\n behavior,\n shouldScrollRestoration,\n scrollToTopSelectors,\n location,\n}: {\n storageKey: string\n key?: string\n behavior?: ScrollToOptions['behavior']\n shouldScrollRestoration?: boolean\n scrollToTopSelectors?: Array<string | (() => Element | null | undefined)>\n location?: HistoryLocation\n}) {\n let byKey: ScrollRestorationByKey\n\n try {\n byKey = JSON.parse(sessionStorage.getItem(storageKey) || '{}')\n } catch (error: any) {\n console.error(error)\n return\n }\n\n const resolvedKey = key || window.history.state?.key\n const elementEntries = byKey[resolvedKey]\n\n //\n ignoreScroll = true\n\n //\n ;(() => {\n // If we have a cached entry for this location state,\n // we always need to prefer that over the hash scroll.\n if (\n shouldScrollRestoration &&\n elementEntries &&\n Object.keys(elementEntries).length > 0\n ) {\n for (const elementSelector in elementEntries) {\n const entry = elementEntries[elementSelector]!\n if (elementSelector === 'window') {\n window.scrollTo({\n top: entry.scrollY,\n left: entry.scrollX,\n behavior,\n })\n } else if (elementSelector) {\n const element = document.querySelector(elementSelector)\n if (element) {\n element.scrollLeft = entry.scrollX\n element.scrollTop = entry.scrollY\n }\n }\n }\n\n return\n }\n\n // If we don't have a cached entry for the hash,\n // Which means we've never seen this location before,\n // we need to check if there is a hash in the URL.\n // If there is, we need to scroll it's ID into view.\n const hash = (location ?? window.location).hash.split('#')[1]\n\n if (hash) {\n const hashScrollIntoViewOptions =\n (window.history.state || {}).__hashScrollIntoViewOptions ?? true\n\n if (hashScrollIntoViewOptions) {\n const el = document.getElementById(hash)\n if (el) {\n el.scrollIntoView(hashScrollIntoViewOptions)\n }\n }\n\n return\n }\n\n // If there is no cached entry for the hash and there is no hash in the URL,\n // we need to scroll to the top of the page for every scrollToTop element\n ;[\n 'window',\n ...(scrollToTopSelectors?.filter((d) => d !== 'window') ?? []),\n ].forEach((selector) => {\n const element =\n selector === 'window'\n ? window\n : typeof selector === 'function'\n ? selector()\n : document.querySelector(selector)\n if (element) {\n element.scrollTo({\n top: 0,\n left: 0,\n behavior,\n })\n }\n })\n })()\n\n //\n ignoreScroll = false\n}\n\nexport function setupScrollRestoration(router: AnyRouter, force?: boolean) {\n if (scrollRestorationCache === undefined) {\n return\n }\n const shouldScrollRestoration =\n force ?? router.options.scrollRestoration ?? false\n\n if (shouldScrollRestoration) {\n router.isScrollRestoring = true\n }\n\n if (typeof document === 'undefined' || router.isScrollRestorationSetup) {\n return\n }\n\n router.isScrollRestorationSetup = true\n\n //\n ignoreScroll = false\n\n const getKey =\n router.options.getScrollRestorationKey || defaultGetScrollRestorationKey\n\n window.history.scrollRestoration = 'manual'\n\n // // Create a MutationObserver to monitor DOM changes\n // const mutationObserver = new MutationObserver(() => {\n // ;ignoreScroll = true\n // requestAnimationFrame(() => {\n // ;ignoreScroll = false\n\n // // Attempt to restore scroll position on each dom\n // // mutation until the user scrolls. We do this\n // // because dynamic content may come in at different\n // // ticks after the initial render and we want to\n // // keep up with that content as much as possible.\n // // As soon as the user scrolls, we no longer need\n // // to attempt router.\n // // console.log('mutation observer restoreScroll')\n // restoreScroll(\n // storageKey,\n // getKey(router.state.location),\n // router.options.scrollRestorationBehavior,\n // )\n // })\n // })\n\n // const observeDom = () => {\n // // Observe changes to the entire document\n // mutationObserver.observe(document, {\n // childList: true, // Detect added or removed child nodes\n // subtree: true, // Monitor all descendants\n // characterData: true, // Detect text content changes\n // })\n // }\n\n // const unobserveDom = () => {\n // mutationObserver.disconnect()\n // }\n\n // observeDom()\n\n const onScroll = (event: Event) => {\n // unobserveDom()\n\n if (ignoreScroll || !router.isScrollRestoring) {\n return\n }\n\n let elementSelector = ''\n\n if (event.target === document || event.target === window) {\n elementSelector = 'window'\n } else {\n const attrId = (event.target as Element).getAttribute(\n 'data-scroll-restoration-id',\n )\n\n if (attrId) {\n elementSelector = `[data-scroll-restoration-id=\"${attrId}\"]`\n } else {\n elementSelector = getCssSelector(event.target)\n }\n }\n\n const restoreKey = getKey(router.state.location)\n\n scrollRestorationCache.set((state) => {\n const keyEntry = (state[restoreKey] =\n state[restoreKey] || ({} as ScrollRestorationByElement))\n\n const elementEntry = (keyEntry[elementSelector] =\n keyEntry[elementSelector] || ({} as ScrollRestorationEntry))\n\n if (elementSelector === 'window') {\n elementEntry.scrollX = window.scrollX || 0\n elementEntry.scrollY = window.scrollY || 0\n } else if (elementSelector) {\n const element = document.querySelector(elementSelector)\n if (element) {\n elementEntry.scrollX = element.scrollLeft || 0\n elementEntry.scrollY = element.scrollTop || 0\n }\n }\n\n return state\n })\n }\n\n // Throttle the scroll event to avoid excessive updates\n if (typeof document !== 'undefined') {\n document.addEventListener('scroll', throttle(onScroll, 100), true)\n }\n\n router.subscribe('onRendered', (event) => {\n // unobserveDom()\n\n const cacheKey = getKey(event.toLocation)\n\n // If the user doesn't want to restore the scroll position,\n // we don't need to do anything.\n if (!router.resetNextScroll) {\n router.resetNextScroll = true\n return\n }\n\n restoreScroll({\n storageKey,\n key: cacheKey,\n behavior: router.options.scrollRestorationBehavior,\n shouldScrollRestoration: router.isScrollRestoring,\n scrollToTopSelectors: router.options.scrollToTopSelectors,\n location: router.history.location,\n })\n\n if (router.isScrollRestoring) {\n // Mark the location as having been seen\n scrollRestorationCache.set((state) => {\n state[cacheKey] = state[cacheKey] || ({} as ScrollRestorationByElement)\n\n return state\n })\n }\n })\n}\n\n/**\n * @internal\n * Handles hash-based scrolling after navigation completes.\n * To be used in framework-specific <Transitioner> components during the onResolved event.\n *\n * Provides hash scrolling for programmatic navigation when default browser handling is prevented.\n * @param router The router instance containing current location and state\n */\nexport function handleHashScroll(router: AnyRouter) {\n if (typeof document !== 'undefined' && (document as any).querySelector) {\n const hashScrollIntoViewOptions =\n router.state.location.state.__hashScrollIntoViewOptions ?? true\n\n if (hashScrollIntoViewOptions && router.state.location.hash !== '') {\n const el = document.getElementById(router.state.location.hash)\n if (el) {\n el.scrollIntoView(hashScrollIntoViewOptions)\n }\n }\n }\n}\n"],"names":["functionalUpdate","storageKey"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"scroll-restoration.cjs","sources":["../../src/scroll-restoration.ts"],"sourcesContent":["import { functionalUpdate } from './utils'\nimport type { AnyRouter } from './router'\nimport type { ParsedLocation } from './location'\nimport type { NonNullableUpdater } from './utils'\nimport type { HistoryLocation } from '@tanstack/history'\n\nexport type ScrollRestorationEntry = { scrollX: number; scrollY: number }\n\nexport type ScrollRestorationByElement = Record<string, ScrollRestorationEntry>\n\nexport type ScrollRestorationByKey = Record<string, ScrollRestorationByElement>\n\nexport type ScrollRestorationCache = {\n state: ScrollRestorationByKey\n set: (updater: NonNullableUpdater<ScrollRestorationByKey>) => void\n}\nexport type ScrollRestorationOptions = {\n getKey?: (location: ParsedLocation) => string\n scrollBehavior?: ScrollToOptions['behavior']\n}\n\nfunction getSafeSessionStorage() {\n try {\n if (\n typeof window !== 'undefined' &&\n typeof window.sessionStorage === 'object'\n ) {\n return window.sessionStorage\n }\n } catch {\n // silent\n }\n return undefined\n}\n\nexport const storageKey = 'tsr-scroll-restoration-v1_3'\n\nconst throttle = (fn: (...args: Array<any>) => void, wait: number) => {\n let timeout: any\n return (...args: Array<any>) => {\n if (!timeout) {\n timeout = setTimeout(() => {\n fn(...args)\n timeout = null\n }, wait)\n }\n }\n}\n\nfunction createScrollRestorationCache(): ScrollRestorationCache | null {\n const safeSessionStorage = getSafeSessionStorage()\n if (!safeSessionStorage) {\n return null\n }\n\n const persistedState = safeSessionStorage.getItem(storageKey)\n let state: ScrollRestorationByKey = persistedState\n ? JSON.parse(persistedState)\n : {}\n\n return {\n state,\n // This setter is simply to make sure that we set the sessionStorage right\n // after the state is updated. It doesn't necessarily need to be a functional\n // update.\n set: (updater) => (\n (state = functionalUpdate(updater, state) || state),\n safeSessionStorage.setItem(storageKey, JSON.stringify(state))\n ),\n }\n}\n\nexport const scrollRestorationCache = createScrollRestorationCache()\n\n/**\n * The default `getKey` function for `useScrollRestoration`.\n * It returns the `key` from the location state or the `href` of the location.\n *\n * The `location.href` is used as a fallback to support the use case where the location state is not available like the initial render.\n */\n\nexport const defaultGetScrollRestorationKey = (location: ParsedLocation) => {\n return location.state.__TSR_key! || location.href\n}\n\nexport function getCssSelector(el: any): string {\n const path = []\n let parent: HTMLElement\n while ((parent = el.parentNode)) {\n path.push(\n `${el.tagName}:nth-child(${Array.prototype.indexOf.call(parent.children, el) + 1})`,\n )\n el = parent\n }\n return `${path.reverse().join(' > ')}`.toLowerCase()\n}\n\nlet ignoreScroll = false\n\n// NOTE: This function must remain pure and not use any outside variables\n// unless they are passed in as arguments. Why? Because we need to be able to\n// toString() it into a script tag to execute as early as possible in the browser\n// during SSR. Additionally, we also call it from within the router lifecycle\nexport function restoreScroll({\n storageKey,\n key,\n behavior,\n shouldScrollRestoration,\n scrollToTopSelectors,\n location,\n}: {\n storageKey: string\n key?: string\n behavior?: ScrollToOptions['behavior']\n shouldScrollRestoration?: boolean\n scrollToTopSelectors?: Array<string | (() => Element | null | undefined)>\n location?: HistoryLocation\n}) {\n let byKey: ScrollRestorationByKey\n\n try {\n byKey = JSON.parse(sessionStorage.getItem(storageKey) || '{}')\n } catch (error) {\n console.error(error)\n return\n }\n\n const resolvedKey = key || window.history.state?.__TSR_key\n const elementEntries = byKey[resolvedKey]\n\n //\n ignoreScroll = true\n\n //\n scroll: {\n // If we have a cached entry for this location state,\n // we always need to prefer that over the hash scroll.\n if (\n shouldScrollRestoration &&\n elementEntries &&\n Object.keys(elementEntries).length > 0\n ) {\n for (const elementSelector in elementEntries) {\n const entry = elementEntries[elementSelector]!\n if (elementSelector === 'window') {\n window.scrollTo({\n top: entry.scrollY,\n left: entry.scrollX,\n behavior,\n })\n } else if (elementSelector) {\n const element = document.querySelector(elementSelector)\n if (element) {\n element.scrollLeft = entry.scrollX\n element.scrollTop = entry.scrollY\n }\n }\n }\n\n break scroll\n }\n\n // If we don't have a cached entry for the hash,\n // Which means we've never seen this location before,\n // we need to check if there is a hash in the URL.\n // If there is, we need to scroll it's ID into view.\n const hash = (location ?? window.location).hash.split('#', 2)[1]\n\n if (hash) {\n const hashScrollIntoViewOptions =\n window.history.state?.__hashScrollIntoViewOptions ?? true\n\n if (hashScrollIntoViewOptions) {\n const el = document.getElementById(hash)\n if (el) {\n el.scrollIntoView(hashScrollIntoViewOptions)\n }\n }\n\n break scroll\n }\n\n // If there is no cached entry for the hash and there is no hash in the URL,\n // we need to scroll to the top of the page for every scrollToTop element\n const scrollOptions = { top: 0, left: 0, behavior }\n window.scrollTo(scrollOptions)\n if (scrollToTopSelectors) {\n for (const selector of scrollToTopSelectors) {\n if (selector === 'window') continue\n const element =\n typeof selector === 'function'\n ? selector()\n : document.querySelector(selector)\n if (element) element.scrollTo(scrollOptions)\n }\n }\n }\n\n //\n ignoreScroll = false\n}\n\nexport function setupScrollRestoration(router: AnyRouter, force?: boolean) {\n if (!scrollRestorationCache && !router.isServer) {\n return\n }\n const shouldScrollRestoration =\n force ?? router.options.scrollRestoration ?? false\n\n if (shouldScrollRestoration) {\n router.isScrollRestoring = true\n }\n\n if (\n router.isServer ||\n router.isScrollRestorationSetup ||\n !scrollRestorationCache\n ) {\n return\n }\n\n router.isScrollRestorationSetup = true\n\n //\n ignoreScroll = false\n\n const getKey =\n router.options.getScrollRestorationKey || defaultGetScrollRestorationKey\n\n window.history.scrollRestoration = 'manual'\n\n // // Create a MutationObserver to monitor DOM changes\n // const mutationObserver = new MutationObserver(() => {\n // ;ignoreScroll = true\n // requestAnimationFrame(() => {\n // ;ignoreScroll = false\n\n // // Attempt to restore scroll position on each dom\n // // mutation until the user scrolls. We do this\n // // because dynamic content may come in at different\n // // ticks after the initial render and we want to\n // // keep up with that content as much as possible.\n // // As soon as the user scrolls, we no longer need\n // // to attempt router.\n // // console.log('mutation observer restoreScroll')\n // restoreScroll(\n // storageKey,\n // getKey(router.state.location),\n // router.options.scrollRestorationBehavior,\n // )\n // })\n // })\n\n // const observeDom = () => {\n // // Observe changes to the entire document\n // mutationObserver.observe(document, {\n // childList: true, // Detect added or removed child nodes\n // subtree: true, // Monitor all descendants\n // characterData: true, // Detect text content changes\n // })\n // }\n\n // const unobserveDom = () => {\n // mutationObserver.disconnect()\n // }\n\n // observeDom()\n\n const onScroll = (event: Event) => {\n // unobserveDom()\n\n if (ignoreScroll || !router.isScrollRestoring) {\n return\n }\n\n let elementSelector = ''\n\n if (event.target === document || event.target === window) {\n elementSelector = 'window'\n } else {\n const attrId = (event.target as Element).getAttribute(\n 'data-scroll-restoration-id',\n )\n\n if (attrId) {\n elementSelector = `[data-scroll-restoration-id=\"${attrId}\"]`\n } else {\n elementSelector = getCssSelector(event.target)\n }\n }\n\n const restoreKey = getKey(router.state.location)\n\n scrollRestorationCache.set((state) => {\n const keyEntry = (state[restoreKey] ||= {} as ScrollRestorationByElement)\n\n const elementEntry = (keyEntry[elementSelector] ||=\n {} as ScrollRestorationEntry)\n\n if (elementSelector === 'window') {\n elementEntry.scrollX = window.scrollX || 0\n elementEntry.scrollY = window.scrollY || 0\n } else if (elementSelector) {\n const element = document.querySelector(elementSelector)\n if (element) {\n elementEntry.scrollX = element.scrollLeft || 0\n elementEntry.scrollY = element.scrollTop || 0\n }\n }\n\n return state\n })\n }\n\n // Throttle the scroll event to avoid excessive updates\n if (typeof document !== 'undefined') {\n document.addEventListener('scroll', throttle(onScroll, 100), true)\n }\n\n router.subscribe('onRendered', (event) => {\n // unobserveDom()\n\n const cacheKey = getKey(event.toLocation)\n\n // If the user doesn't want to restore the scroll position,\n // we don't need to do anything.\n if (!router.resetNextScroll) {\n router.resetNextScroll = true\n return\n }\n if (typeof router.options.scrollRestoration === 'function') {\n const shouldRestore = router.options.scrollRestoration({\n location: router.latestLocation,\n })\n if (!shouldRestore) {\n return\n }\n }\n\n restoreScroll({\n storageKey,\n key: cacheKey,\n behavior: router.options.scrollRestorationBehavior,\n shouldScrollRestoration: router.isScrollRestoring,\n scrollToTopSelectors: router.options.scrollToTopSelectors,\n location: router.history.location,\n })\n\n if (router.isScrollRestoring) {\n // Mark the location as having been seen\n scrollRestorationCache.set((state) => {\n state[cacheKey] ||= {} as ScrollRestorationByElement\n\n return state\n })\n }\n })\n}\n\n/**\n * @internal\n * Handles hash-based scrolling after navigation completes.\n * To be used in framework-specific <Transitioner> components during the onResolved event.\n *\n * Provides hash scrolling for programmatic navigation when default browser handling is prevented.\n * @param router The router instance containing current location and state\n */\nexport function handleHashScroll(router: AnyRouter) {\n if (typeof document !== 'undefined' && (document as any).querySelector) {\n const hashScrollIntoViewOptions =\n router.state.location.state.__hashScrollIntoViewOptions ?? true\n\n if (hashScrollIntoViewOptions && router.state.location.hash !== '') {\n const el = document.getElementById(router.state.location.hash)\n if (el) {\n el.scrollIntoView(hashScrollIntoViewOptions)\n }\n }\n }\n}\n"],"names":["functionalUpdate","storageKey"],"mappings":"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"}
|
|
@@ -17,7 +17,7 @@ export type ScrollRestorationOptions = {
|
|
|
17
17
|
scrollBehavior?: ScrollToOptions['behavior'];
|
|
18
18
|
};
|
|
19
19
|
export declare const storageKey = "tsr-scroll-restoration-v1_3";
|
|
20
|
-
export declare const scrollRestorationCache: ScrollRestorationCache |
|
|
20
|
+
export declare const scrollRestorationCache: ScrollRestorationCache | null;
|
|
21
21
|
/**
|
|
22
22
|
* The default `getKey` function for `useScrollRestoration`.
|
|
23
23
|
* It returns the `key` from the location state or the `href` of the location.
|
|
@@ -8,7 +8,7 @@ const defaultStringifySearch = stringifySearchWith(
|
|
|
8
8
|
);
|
|
9
9
|
function parseSearchWith(parser) {
|
|
10
10
|
return (searchStr) => {
|
|
11
|
-
if (searchStr
|
|
11
|
+
if (searchStr[0] === "?") {
|
|
12
12
|
searchStr = searchStr.substring(1);
|
|
13
13
|
}
|
|
14
14
|
const query = qss.decode(searchStr);
|
|
@@ -17,7 +17,7 @@ function parseSearchWith(parser) {
|
|
|
17
17
|
if (typeof value === "string") {
|
|
18
18
|
try {
|
|
19
19
|
query[key] = parser(value);
|
|
20
|
-
} catch (
|
|
20
|
+
} catch (_err) {
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
23
|
}
|
|
@@ -25,32 +25,24 @@ function parseSearchWith(parser) {
|
|
|
25
25
|
};
|
|
26
26
|
}
|
|
27
27
|
function stringifySearchWith(stringify, parser) {
|
|
28
|
+
const hasParser = typeof parser === "function";
|
|
28
29
|
function stringifyValue(val) {
|
|
29
30
|
if (typeof val === "object" && val !== null) {
|
|
30
31
|
try {
|
|
31
32
|
return stringify(val);
|
|
32
|
-
} catch (
|
|
33
|
+
} catch (_err) {
|
|
33
34
|
}
|
|
34
|
-
} else if (
|
|
35
|
+
} else if (hasParser && typeof val === "string") {
|
|
35
36
|
try {
|
|
36
37
|
parser(val);
|
|
37
38
|
return stringify(val);
|
|
38
|
-
} catch (
|
|
39
|
+
} catch (_err) {
|
|
39
40
|
}
|
|
40
41
|
}
|
|
41
42
|
return val;
|
|
42
43
|
}
|
|
43
44
|
return (search) => {
|
|
44
|
-
|
|
45
|
-
Object.keys(search).forEach((key) => {
|
|
46
|
-
const val = search[key];
|
|
47
|
-
if (typeof val === "undefined" || val === void 0) {
|
|
48
|
-
delete search[key];
|
|
49
|
-
} else {
|
|
50
|
-
search[key] = stringifyValue(val);
|
|
51
|
-
}
|
|
52
|
-
});
|
|
53
|
-
const searchStr = qss.encode(search).toString();
|
|
45
|
+
const searchStr = qss.encode(search, stringifyValue);
|
|
54
46
|
return searchStr ? `?${searchStr}` : "";
|
|
55
47
|
};
|
|
56
48
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"searchParams.cjs","sources":["../../src/searchParams.ts"],"sourcesContent":["import { decode, encode } from './qss'\nimport type { AnySchema } from './validators'\n\nexport const defaultParseSearch = parseSearchWith(JSON.parse)\nexport const defaultStringifySearch = stringifySearchWith(\n JSON.stringify,\n JSON.parse,\n)\n\nexport function parseSearchWith(parser: (str: string) => any) {\n return (searchStr: string): AnySchema => {\n if (searchStr
|
|
1
|
+
{"version":3,"file":"searchParams.cjs","sources":["../../src/searchParams.ts"],"sourcesContent":["import { decode, encode } from './qss'\nimport type { AnySchema } from './validators'\n\nexport const defaultParseSearch = parseSearchWith(JSON.parse)\nexport const defaultStringifySearch = stringifySearchWith(\n JSON.stringify,\n JSON.parse,\n)\n\nexport function parseSearchWith(parser: (str: string) => any) {\n return (searchStr: string): AnySchema => {\n if (searchStr[0] === '?') {\n searchStr = searchStr.substring(1)\n }\n\n const query: Record<string, unknown> = decode(searchStr)\n\n // Try to parse any query params that might be json\n for (const key in query) {\n const value = query[key]\n if (typeof value === 'string') {\n try {\n query[key] = parser(value)\n } catch (_err) {\n // silent\n }\n }\n }\n\n return query\n }\n}\n\nexport function stringifySearchWith(\n stringify: (search: any) => string,\n parser?: (str: string) => any,\n) {\n const hasParser = typeof parser === 'function'\n function stringifyValue(val: any) {\n if (typeof val === 'object' && val !== null) {\n try {\n return stringify(val)\n } catch (_err) {\n // silent\n }\n } else if (hasParser && typeof val === 'string') {\n try {\n // Check if it's a valid parseable string.\n // If it is, then stringify it again.\n parser(val)\n return stringify(val)\n } catch (_err) {\n // silent\n }\n }\n return val\n }\n\n return (search: Record<string, any>) => {\n const searchStr = encode(search, stringifyValue)\n return searchStr ? `?${searchStr}` : ''\n }\n}\n\nexport type SearchSerializer = (searchObj: Record<string, any>) => string\nexport type SearchParser = (searchStr: string) => Record<string, any>\n"],"names":["decode","encode"],"mappings":";;;AAGO,MAAM,qBAAqB,gBAAgB,KAAK,KAAK;AACrD,MAAM,yBAAyB;AAAA,EACpC,KAAK;AAAA,EACL,KAAK;AACP;AAEO,SAAS,gBAAgB,QAA8B;AAC5D,SAAO,CAAC,cAAiC;AACvC,QAAI,UAAU,CAAC,MAAM,KAAK;AACxB,kBAAY,UAAU,UAAU,CAAC;AAAA,IACnC;AAEA,UAAM,QAAiCA,IAAAA,OAAO,SAAS;AAGvD,eAAW,OAAO,OAAO;AACvB,YAAM,QAAQ,MAAM,GAAG;AACvB,UAAI,OAAO,UAAU,UAAU;AAC7B,YAAI;AACF,gBAAM,GAAG,IAAI,OAAO,KAAK;AAAA,QAC3B,SAAS,MAAM;AAAA,QAEf;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AACF;AAEO,SAAS,oBACd,WACA,QACA;AACA,QAAM,YAAY,OAAO,WAAW;AACpC,WAAS,eAAe,KAAU;AAChC,QAAI,OAAO,QAAQ,YAAY,QAAQ,MAAM;AAC3C,UAAI;AACF,eAAO,UAAU,GAAG;AAAA,MACtB,SAAS,MAAM;AAAA,MAEf;AAAA,IACF,WAAW,aAAa,OAAO,QAAQ,UAAU;AAC/C,UAAI;AAGF,eAAO,GAAG;AACV,eAAO,UAAU,GAAG;AAAA,MACtB,SAAS,MAAM;AAAA,MAEf;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAEA,SAAO,CAAC,WAAgC;AACtC,UAAM,YAAYC,IAAAA,OAAO,QAAQ,cAAc;AAC/C,WAAO,YAAY,IAAI,SAAS,KAAK;AAAA,EACvC;AACF;;;;;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.cjs","sources":["../../../src/ssr/constants.ts"],"sourcesContent":["export const GLOBAL_TSR = '$_TSR'\n"],"names":[],"mappings":";;AAAO,MAAM,aAAa;;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const GLOBAL_TSR = "$_TSR";
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
3
|
const seroval = require("seroval");
|
|
4
4
|
const ShallowErrorPlugin = /* @__PURE__ */ seroval.createPlugin({
|
|
5
|
-
tag: "
|
|
5
|
+
tag: "$TSR/Error",
|
|
6
6
|
test(value) {
|
|
7
7
|
return value instanceof Error;
|
|
8
8
|
},
|
|
@@ -31,4 +31,4 @@ const ShallowErrorPlugin = /* @__PURE__ */ seroval.createPlugin({
|
|
|
31
31
|
}
|
|
32
32
|
});
|
|
33
33
|
exports.ShallowErrorPlugin = ShallowErrorPlugin;
|
|
34
|
-
//# sourceMappingURL=
|
|
34
|
+
//# sourceMappingURL=ShallowErrorPlugin.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ShallowErrorPlugin.cjs","sources":["../../../../src/ssr/serializer/ShallowErrorPlugin.ts"],"sourcesContent":["import { createPlugin } from 'seroval'\nimport type { SerovalNode } from 'seroval'\n\nexport interface ErrorNode {\n message: SerovalNode\n}\n\n/**\n * this plugin serializes only the `message` part of an Error\n * this helps with serializing e.g. a ZodError which has functions attached that cannot be serialized\n */\nexport const ShallowErrorPlugin = /* @__PURE__ */ createPlugin<\n Error,\n ErrorNode\n>({\n tag: '$TSR/Error',\n test(value) {\n return value instanceof Error\n },\n parse: {\n sync(value, ctx) {\n return {\n message: ctx.parse(value.message),\n }\n },\n async async(value, ctx) {\n return {\n message: await ctx.parse(value.message),\n }\n },\n stream(value, ctx) {\n return {\n message: ctx.parse(value.message),\n }\n },\n },\n serialize(node, ctx) {\n return 'new Error(' + ctx.serialize(node.message) + ')'\n },\n deserialize(node, ctx) {\n return new Error(ctx.deserialize(node.message) as string)\n },\n})\n"],"names":["createPlugin"],"mappings":";;;AAWO,MAAM,qBAAqCA,wBAAAA,aAGhD;AAAA,EACA,KAAK;AAAA,EACL,KAAK,OAAO;AACV,WAAO,iBAAiB;AAAA,EAC1B;AAAA,EACA,OAAO;AAAA,IACL,KAAK,OAAO,KAAK;AACf,aAAO;AAAA,QACL,SAAS,IAAI,MAAM,MAAM,OAAO;AAAA,MAAA;AAAA,IAEpC;AAAA,IACA,MAAM,MAAM,OAAO,KAAK;AACtB,aAAO;AAAA,QACL,SAAS,MAAM,IAAI,MAAM,MAAM,OAAO;AAAA,MAAA;AAAA,IAE1C;AAAA,IACA,OAAO,OAAO,KAAK;AACjB,aAAO;AAAA,QACL,SAAS,IAAI,MAAM,MAAM,OAAO;AAAA,MAAA;AAAA,IAEpC;AAAA,EAAA;AAAA,EAEF,UAAU,MAAM,KAAK;AACnB,WAAO,eAAe,IAAI,UAAU,KAAK,OAAO,IAAI;AAAA,EACtD;AAAA,EACA,YAAY,MAAM,KAAK;AACrB,WAAO,IAAI,MAAM,IAAI,YAAY,KAAK,OAAO,CAAW;AAAA,EAC1D;AACF,CAAC;;"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { SerovalNode } from 'seroval';
|
|
2
|
-
interface ErrorNode {
|
|
2
|
+
export interface ErrorNode {
|
|
3
3
|
message: SerovalNode;
|
|
4
4
|
}
|
|
5
5
|
/**
|
|
@@ -7,4 +7,3 @@ interface ErrorNode {
|
|
|
7
7
|
* this helps with serializing e.g. a ZodError which has functions attached that cannot be serialized
|
|
8
8
|
*/
|
|
9
9
|
export declare const ShallowErrorPlugin: import('seroval').Plugin<Error, ErrorNode>;
|
|
10
|
-
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const web = require("seroval-plugins/web");
|
|
4
|
+
const ShallowErrorPlugin = require("./ShallowErrorPlugin.cjs");
|
|
5
|
+
const defaultSerovalPlugins = [
|
|
6
|
+
ShallowErrorPlugin.ShallowErrorPlugin,
|
|
7
|
+
// ReadableStreamNode is not exported by seroval
|
|
8
|
+
web.ReadableStreamPlugin
|
|
9
|
+
];
|
|
10
|
+
exports.defaultSerovalPlugins = defaultSerovalPlugins;
|
|
11
|
+
//# sourceMappingURL=seroval-plugins.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seroval-plugins.cjs","sources":["../../../../src/ssr/serializer/seroval-plugins.ts"],"sourcesContent":["import { ReadableStreamPlugin } from 'seroval-plugins/web'\nimport { ShallowErrorPlugin } from './ShallowErrorPlugin'\nimport type { Plugin } from 'seroval'\n\nexport const defaultSerovalPlugins = [\n ShallowErrorPlugin as Plugin<Error, any>,\n // ReadableStreamNode is not exported by seroval\n ReadableStreamPlugin as Plugin<ReadableStream, any>,\n]\n"],"names":["ShallowErrorPlugin","ReadableStreamPlugin"],"mappings":";;;;AAIO,MAAM,wBAAwB;AAAA,EACnCA,mBAAAA;AAAAA;AAAAA,EAEAC,IAAAA;AACF;;"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const seroval = require("seroval");
|
|
4
|
+
const constants = require("../constants.cjs");
|
|
5
|
+
function createSerializationAdapter(opts) {
|
|
6
|
+
return opts;
|
|
7
|
+
}
|
|
8
|
+
function makeSsrSerovalPlugin(serializationAdapter, options) {
|
|
9
|
+
return seroval.createPlugin({
|
|
10
|
+
tag: "$TSR/t/" + serializationAdapter.key,
|
|
11
|
+
test: serializationAdapter.test,
|
|
12
|
+
parse: {
|
|
13
|
+
stream(value, ctx) {
|
|
14
|
+
return ctx.parse(serializationAdapter.toSerializable(value));
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
serialize(node, ctx) {
|
|
18
|
+
options.didRun = true;
|
|
19
|
+
return constants.GLOBAL_TSR + '.t.get("' + serializationAdapter.key + '")(' + ctx.serialize(node) + ")";
|
|
20
|
+
},
|
|
21
|
+
// we never deserialize on the server during SSR
|
|
22
|
+
deserialize: void 0
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
function makeSerovalPlugin(serializationAdapter) {
|
|
26
|
+
return seroval.createPlugin({
|
|
27
|
+
tag: "$TSR/t/" + serializationAdapter.key,
|
|
28
|
+
test: serializationAdapter.test,
|
|
29
|
+
parse: {
|
|
30
|
+
sync(value, ctx) {
|
|
31
|
+
return ctx.parse(serializationAdapter.toSerializable(value));
|
|
32
|
+
},
|
|
33
|
+
async async(value, ctx) {
|
|
34
|
+
return await ctx.parse(serializationAdapter.toSerializable(value));
|
|
35
|
+
},
|
|
36
|
+
stream(value, ctx) {
|
|
37
|
+
return ctx.parse(serializationAdapter.toSerializable(value));
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
// we don't generate JS code outside of SSR (for now)
|
|
41
|
+
serialize: void 0,
|
|
42
|
+
deserialize(node, ctx) {
|
|
43
|
+
return serializationAdapter.fromSerializable(
|
|
44
|
+
ctx.deserialize(node)
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
exports.createSerializationAdapter = createSerializationAdapter;
|
|
50
|
+
exports.makeSerovalPlugin = makeSerovalPlugin;
|
|
51
|
+
exports.makeSsrSerovalPlugin = makeSsrSerovalPlugin;
|
|
52
|
+
//# sourceMappingURL=transformer.cjs.map
|