@tanstack/router-core 0.0.1-beta.162 → 0.0.1-beta.164

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.
@@ -14,7 +14,7 @@ import { Store } from '@tanstack/react-store';
14
14
 
15
15
  interface RouterHistory {
16
16
  location: RouterLocation;
17
- listen: (cb: () => void) => () => void;
17
+ subscribe: (cb: () => void) => () => void;
18
18
  push: (path: string, state?: any) => void;
19
19
  replace: (path: string, state?: any) => void;
20
20
  go: (index: number) => void;
@@ -201,7 +201,6 @@ interface RouterOptions<TRouteTree extends AnyRoute, TDehydrated extends Record<
201
201
  route: AnyRoute;
202
202
  router: AnyRouter;
203
203
  }) => void;
204
- onRouteChange?: () => void;
205
204
  context?: TRouteTree['types']['routerContext'];
206
205
  Wrap?: React.ComponentType<{
207
206
  children: React.ReactNode;
@@ -222,7 +221,7 @@ interface RouterState<TRouteTree extends AnyRoute = AnyRoute> {
222
221
  resolvedLocation: ParsedLocation<FullSearchSchema<TRouteTree>>;
223
222
  lastUpdated: number;
224
223
  }
225
- type ListenerFn = () => void;
224
+ type ListenerFn<TEvent extends RouterEvent> = (event: TEvent) => void;
226
225
  interface BuildNextOptions {
227
226
  to?: string | number | null;
228
227
  params?: true | Updater<unknown>;
@@ -254,6 +253,25 @@ interface DehydratedRouter {
254
253
  }
255
254
  type RouterConstructorOptions<TRouteTree extends AnyRoute, TDehydrated extends Record<string, any>> = Omit<RouterOptions<TRouteTree, TDehydrated>, 'context'> & RouterContextOptions<TRouteTree>;
256
255
  declare const componentTypes: readonly ["component", "errorComponent", "pendingComponent"];
256
+ type RouterEvents = {
257
+ onBeforeLoad: {
258
+ type: 'onBeforeLoad';
259
+ from: ParsedLocation;
260
+ to: ParsedLocation;
261
+ pathChanged: boolean;
262
+ };
263
+ onLoad: {
264
+ type: 'onLoad';
265
+ from: ParsedLocation;
266
+ to: ParsedLocation;
267
+ pathChanged: boolean;
268
+ };
269
+ };
270
+ type RouterEvent = RouterEvents[keyof RouterEvents];
271
+ type RouterListener<TRouterEvent extends RouterEvent> = {
272
+ eventType: TRouterEvent['type'];
273
+ fn: ListenerFn<TRouterEvent>;
274
+ };
257
275
  declare class Router<TRouteTree extends AnyRoute = AnyRoute, TDehydrated extends Record<string, any> = Record<string, any>> {
258
276
  #private;
259
277
  types: {
@@ -273,6 +291,8 @@ declare class Router<TRouteTree extends AnyRoute = AnyRoute, TDehydrated extends
273
291
  state: RouterState<TRouteTree>;
274
292
  dehydratedData?: TDehydrated;
275
293
  constructor(options: RouterConstructorOptions<TRouteTree, TDehydrated>);
294
+ subscribers: Set<RouterListener<RouterEvent>>;
295
+ subscribe: <TType extends keyof RouterEvents>(eventType: TType, fn: ListenerFn<RouterEvents[TType]>) => () => void;
276
296
  reset: () => void;
277
297
  mount: () => void;
278
298
  update: (opts?: RouterOptions<any, any>) => this;
@@ -437,10 +457,6 @@ type UpdatableRouteOptions<TLoader, TSearchSchema extends AnySearchSchema, TFull
437
457
  maxAge?: number;
438
458
  gcMaxAge?: number;
439
459
  beforeLoad?: (opts: LoaderContext<TSearchSchema, TFullSearchSchema, TAllParams, NoInfer<TRouteContext>, TContext>) => Promise<void> | void;
440
- onBeforeLoadError?: (err: any) => void;
441
- onValidateSearchError?: (err: any) => void;
442
- onParseParamsError?: (err: any) => void;
443
- onLoadError?: (err: any) => void;
444
460
  onError?: (err: any) => void;
445
461
  onLoaded?: (matchContext: {
446
462
  params: TAllParams;
@@ -615,10 +631,6 @@ declare class FileRoute<TFilePath extends keyof FileRoutesByPath, TParentRoute e
615
631
  maxAge?: number | undefined;
616
632
  gcMaxAge?: number | undefined;
617
633
  beforeLoad?: ((opts: LoaderContext<TSearchSchema, TFullSearchSchema, TAllParams, NoInfer<TRouteContext>, TContext>) => void | Promise<void>) | undefined;
618
- onBeforeLoadError?: ((err: any) => void) | undefined;
619
- onValidateSearchError?: ((err: any) => void) | undefined;
620
- onParseParamsError?: ((err: any) => void) | undefined;
621
- onLoadError?: ((err: any) => void) | undefined;
622
634
  onError?: ((err: any) => void) | undefined;
623
635
  onLoaded?: ((matchContext: {
624
636
  params: TAllParams;
@@ -743,4 +755,10 @@ declare const defaultStringifySearch: (search: Record<string, any>) => string;
743
755
  declare function parseSearchWith(parser: (str: string) => any): (searchStr: string) => AnySearchSchema;
744
756
  declare function stringifySearchWith(stringify: (search: any) => string, parser?: (str: string) => any): (search: Record<string, any>) => string;
745
757
 
746
- export { ActiveOptions, AllParams, AnyContext, AnyPathParams, AnyRedirect, AnyRootRoute, AnyRoute, AnyRouteMatch, AnyRouteProps, AnyRouter, AnySearchSchema, BaseRouteOptions, BuildNextOptions, CheckId, CheckIdError, CheckPath, CheckPathError, CheckRelativePath, CleanPath, ComponentFromRoute, ComponentPropsFromRoute, DeepAwaited, DefinedPathParamWarning, DehydratedRouter, DehydratedRouterState, Expand, FileRoute, FileRoutePath, FileRoutesByPath, FromLocation, FullSearchSchema, GetKeyFn, HydrationCtx, InferFullSearchSchema, IsAny, IsAnyBoolean, IsKnown, Join, Last, LinkInfo, LinkOptions, ListenerFn, LoaderContext, LoaderFn, LocationState, MatchLocation, MatchRouteOptions, MergeParamsFromParent, MergeUnion, MetaOptions, NavigateOptions, NoInfer, ParamsFallback, ParentParams, ParseParamsFn, ParseParamsObj, ParseParamsOption, ParsePathParams, ParseRoute, ParseRouteChildren, ParsedLocation, ParsedPath, PathParamError, PathParamMask, PathParamOptions, PickAsPartial, PickAsRequired, PickExclude, PickExtra, PickExtract, PickRequired, PickUnsafe, PreloadableObj, Redirect, Register, RegisterRouteComponent, RegisterRouteErrorComponent, RegisteredRouteComponent, RegisteredRouteErrorComponent, RegisteredRouter, RelativeToPathAutoComplete, RemoveUnderScores, ResolveFilePath, ResolveFullPath, ResolveFullSearchSchema, ResolveId, ResolveRelativePath, RootRoute, RootRouteId, Route, RouteById, RouteByPath, RouteConstraints, RouteContext, RouteIds, RouteLoaderFromRoute, RouteMatch, RouteMeta, RouteOptions, RoutePathOptions, RoutePathOptionsIntersection, RoutePaths, RouteProps, Router, RouterConstructorOptions, RouterContext, RouterContextOptions, RouterHistory, RouterLocation, RouterOptions, RouterState, RoutesById, RoutesByPath, SearchFilter, SearchParamError, SearchParamOptions, SearchParser, SearchSchemaValidator, SearchSchemaValidatorFn, SearchSchemaValidatorObj, SearchSerializer, Segment, Split, StreamedPromise, Timeout, ToIdOption, ToOptions, ToPathOption, Trim, TrimLeft, TrimPath, TrimPathLeft, TrimPathRight, TrimRight, UnionToIntersection, UnloaderFn, UpdatableRouteOptions, Updater, UseLoaderResult, UseLoaderResultPromise, ValueKeys, Values, cleanPath, componentTypes, createBrowserHistory, createHashHistory, createMemoryHistory, decode, defaultParseSearch, defaultStringifySearch, encode, functionalUpdate, interpolatePath, isPlainObject, isRedirect, joinPaths, last, lazyFn, matchByPath, matchPathname, parsePathname, parseSearchWith, partialDeepEqual, pick, redirect, replaceEqualDeep, resolvePath, rootRouteId, stringifySearchWith, trimPath, trimPathLeft, trimPathRight };
758
+ type ScrollRestorationOptions = {
759
+ getKey?: (location: ParsedLocation) => string;
760
+ };
761
+ declare function watchScrollPositions(router: AnyRouter, opts?: ScrollRestorationOptions): () => void;
762
+ declare function restoreScrollPositions(router: AnyRouter, opts?: ScrollRestorationOptions): void;
763
+
764
+ export { ActiveOptions, AllParams, AnyContext, AnyPathParams, AnyRedirect, AnyRootRoute, AnyRoute, AnyRouteMatch, AnyRouteProps, AnyRouter, AnySearchSchema, BaseRouteOptions, BuildNextOptions, CheckId, CheckIdError, CheckPath, CheckPathError, CheckRelativePath, CleanPath, ComponentFromRoute, ComponentPropsFromRoute, DeepAwaited, DefinedPathParamWarning, DehydratedRouter, DehydratedRouterState, Expand, FileRoute, FileRoutePath, FileRoutesByPath, FromLocation, FullSearchSchema, GetKeyFn, HydrationCtx, InferFullSearchSchema, IsAny, IsAnyBoolean, IsKnown, Join, Last, LinkInfo, LinkOptions, ListenerFn, LoaderContext, LoaderFn, LocationState, MatchLocation, MatchRouteOptions, MergeParamsFromParent, MergeUnion, MetaOptions, NavigateOptions, NoInfer, ParamsFallback, ParentParams, ParseParamsFn, ParseParamsObj, ParseParamsOption, ParsePathParams, ParseRoute, ParseRouteChildren, ParsedLocation, ParsedPath, PathParamError, PathParamMask, PathParamOptions, PickAsPartial, PickAsRequired, PickExclude, PickExtra, PickExtract, PickRequired, PickUnsafe, PreloadableObj, Redirect, Register, RegisterRouteComponent, RegisterRouteErrorComponent, RegisteredRouteComponent, RegisteredRouteErrorComponent, RegisteredRouter, RelativeToPathAutoComplete, RemoveUnderScores, ResolveFilePath, ResolveFullPath, ResolveFullSearchSchema, ResolveId, ResolveRelativePath, RootRoute, RootRouteId, Route, RouteById, RouteByPath, RouteConstraints, RouteContext, RouteIds, RouteLoaderFromRoute, RouteMatch, RouteMeta, RouteOptions, RoutePathOptions, RoutePathOptionsIntersection, RoutePaths, RouteProps, Router, RouterConstructorOptions, RouterContext, RouterContextOptions, RouterEvent, RouterEvents, RouterHistory, RouterListener, RouterLocation, RouterOptions, RouterState, RoutesById, RoutesByPath, ScrollRestorationOptions, SearchFilter, SearchParamError, SearchParamOptions, SearchParser, SearchSchemaValidator, SearchSchemaValidatorFn, SearchSchemaValidatorObj, SearchSerializer, Segment, Split, StreamedPromise, Timeout, ToIdOption, ToOptions, ToPathOption, Trim, TrimLeft, TrimPath, TrimPathLeft, TrimPathRight, TrimRight, UnionToIntersection, UnloaderFn, UpdatableRouteOptions, Updater, UseLoaderResult, UseLoaderResultPromise, ValueKeys, Values, cleanPath, componentTypes, createBrowserHistory, createHashHistory, createMemoryHistory, decode, defaultParseSearch, defaultStringifySearch, encode, functionalUpdate, interpolatePath, isPlainObject, isRedirect, joinPaths, last, lazyFn, matchByPath, matchPathname, parsePathname, parseSearchWith, partialDeepEqual, pick, redirect, replaceEqualDeep, resolvePath, restoreScrollPositions, rootRouteId, stringifySearchWith, trimPath, trimPathLeft, trimPathRight, watchScrollPositions };
@@ -62,7 +62,7 @@
62
62
  function createHistory(opts) {
63
63
  let location = opts.getLocation();
64
64
  let unsub = () => {};
65
- let listeners = new Set();
65
+ let subscribers = new Set();
66
66
  let blockers = [];
67
67
  let queue = [];
68
68
  const tryFlush = () => {
@@ -76,7 +76,7 @@
76
76
  while (queue.length) {
77
77
  queue.shift()?.();
78
78
  }
79
- if (!opts.listener) {
79
+ if (!opts.subscriber) {
80
80
  onUpdate();
81
81
  }
82
82
  };
@@ -86,20 +86,20 @@
86
86
  };
87
87
  const onUpdate = () => {
88
88
  location = opts.getLocation();
89
- listeners.forEach(listener => listener());
89
+ subscribers.forEach(subscriber => subscriber());
90
90
  };
91
91
  return {
92
92
  get location() {
93
93
  return location;
94
94
  },
95
- listen: cb => {
96
- if (listeners.size === 0) {
97
- unsub = typeof opts.listener === 'function' ? opts.listener(onUpdate) : () => {};
95
+ subscribe: cb => {
96
+ if (subscribers.size === 0) {
97
+ unsub = typeof opts.subscriber === 'function' ? opts.subscriber(onUpdate) : () => {};
98
98
  }
99
- listeners.add(cb);
99
+ subscribers.add(cb);
100
100
  return () => {
101
- listeners.delete(cb);
102
- if (listeners.size === 0) {
101
+ subscribers.delete(cb);
102
+ if (subscribers.size === 0) {
103
103
  unsub();
104
104
  }
105
105
  };
@@ -152,7 +152,7 @@
152
152
  const getLocation = () => parseLocation(getHref(), history.state);
153
153
  return createHistory({
154
154
  getLocation,
155
- listener: onUpdate => {
155
+ subscriber: onUpdate => {
156
156
  window.addEventListener(pushStateEvent, onUpdate);
157
157
  window.addEventListener(popStateEvent, onUpdate);
158
158
  var pushState = window.history.pushState;
@@ -207,7 +207,7 @@
207
207
  const getLocation = () => parseLocation(entries[index], currentState);
208
208
  return createHistory({
209
209
  getLocation,
210
- listener: false,
210
+ subscriber: false,
211
211
  pushState: (path, state) => {
212
212
  currentState = {
213
213
  ...state,
@@ -848,6 +848,24 @@
848
848
  });
849
849
  }
850
850
  }
851
+ subscribers = new Set();
852
+ subscribe = (eventType, fn) => {
853
+ const listener = {
854
+ eventType,
855
+ fn
856
+ };
857
+ this.subscribers.add(listener);
858
+ return () => {
859
+ this.subscribers.delete(listener);
860
+ };
861
+ };
862
+ #emit = routerEvent => {
863
+ this.subscribers.forEach(listener => {
864
+ if (listener.eventType === routerEvent.type) {
865
+ listener.fn(routerEvent);
866
+ }
867
+ });
868
+ };
851
869
  reset = () => {
852
870
  this.__store.setState(s => Object.assign(s, getInitialRouterState()));
853
871
  };
@@ -878,7 +896,7 @@
878
896
  resolvedLocation: parsedLocation,
879
897
  location: parsedLocation
880
898
  }));
881
- this.#unsubHistory = this.history.listen(() => {
899
+ this.#unsubHistory = this.history.subscribe(() => {
882
900
  this.safeLoad({
883
901
  next: this.#parseLocation(this.state.location)
884
902
  });
@@ -920,6 +938,8 @@
920
938
  latestLoadPromise = Promise.resolve();
921
939
  load = async opts => {
922
940
  const promise = new Promise(async (resolve, reject) => {
941
+ const prevLocation = this.state.resolvedLocation;
942
+ const pathDidChange = !!(opts?.next && prevLocation.href !== opts.next.href);
923
943
  let latestPromise;
924
944
  const checkLatest = () => {
925
945
  return this.latestLoadPromise !== promise ? this.latestLoadPromise : undefined;
@@ -929,6 +949,12 @@
929
949
  // this.cancelMatches()
930
950
 
931
951
  let pendingMatches;
952
+ this.#emit({
953
+ type: 'onBeforeLoad',
954
+ from: prevLocation,
955
+ to: opts?.next ?? this.state.location,
956
+ pathChanged: pathDidChange
957
+ });
932
958
  this.__store.batch(() => {
933
959
  if (opts?.next) {
934
960
  // Ingest the new location
@@ -963,7 +989,6 @@
963
989
  if (latestPromise = checkLatest()) {
964
990
  return latestPromise;
965
991
  }
966
- const prevLocation = this.state.resolvedLocation;
967
992
  this.__store.setState(s => ({
968
993
  ...s,
969
994
  status: 'idle',
@@ -971,9 +996,12 @@
971
996
  matchIds: s.pendingMatchIds,
972
997
  pendingMatchIds: []
973
998
  }));
974
- if (prevLocation.href !== this.state.location.href) {
975
- this.options.onRouteChange?.();
976
- }
999
+ this.#emit({
1000
+ type: 'onLoad',
1001
+ from: prevLocation,
1002
+ to: this.state.location,
1003
+ pathChanged: pathDidChange
1004
+ });
977
1005
  resolve();
978
1006
  } catch (err) {
979
1007
  // Only apply the latest transition
@@ -1223,14 +1251,14 @@
1223
1251
  try {
1224
1252
  for (const [index, match] of resolvedMatches.entries()) {
1225
1253
  const route = this.getRoute(match.routeId);
1226
- const handleError = (err, handler) => {
1254
+ const handleError = (err, code) => {
1255
+ err.routerCode = code;
1227
1256
  firstBadMatchIndex = firstBadMatchIndex ?? index;
1228
- handler = handler || route.options.onError;
1229
1257
  if (isRedirect(err)) {
1230
1258
  throw err;
1231
1259
  }
1232
1260
  try {
1233
- handler?.(err);
1261
+ route.options.onError?.(err);
1234
1262
  } catch (errorHandlerErr) {
1235
1263
  err = errorHandlerErr;
1236
1264
  if (isRedirect(errorHandlerErr)) {
@@ -1245,10 +1273,10 @@
1245
1273
  }));
1246
1274
  };
1247
1275
  if (match.paramsError) {
1248
- handleError(match.paramsError, route.options.onParseParamsError);
1276
+ handleError(match.paramsError, 'PARSE_PARAMS');
1249
1277
  }
1250
1278
  if (match.searchError) {
1251
- handleError(match.searchError, route.options.onValidateSearchError);
1279
+ handleError(match.searchError, 'VALIDATE_SEARCH');
1252
1280
  }
1253
1281
  let didError = false;
1254
1282
  try {
@@ -1257,7 +1285,7 @@
1257
1285
  preload: !!opts?.preload
1258
1286
  });
1259
1287
  } catch (err) {
1260
- handleError(err, route.options.onBeforeLoadError);
1288
+ handleError(err, 'BEFORE_LOAD');
1261
1289
  didError = true;
1262
1290
  }
1263
1291
 
@@ -1315,28 +1343,18 @@
1315
1343
  const [_, loader] = await Promise.all([componentsPromise, loaderPromise]);
1316
1344
  if (latestPromise = checkLatest()) return await latestPromise;
1317
1345
  this.setRouteMatchData(match.id, () => loader, opts);
1318
- } catch (loaderError) {
1319
- let latestError = loaderError;
1346
+ } catch (error) {
1320
1347
  if (latestPromise = checkLatest()) return await latestPromise;
1321
- if (handleIfRedirect(loaderError)) return;
1322
- if (route.options.onLoadError) {
1323
- try {
1324
- route.options.onLoadError(loaderError);
1325
- } catch (onLoadError) {
1326
- latestError = onLoadError;
1327
- if (handleIfRedirect(onLoadError)) return;
1328
- }
1329
- }
1330
- if ((!route.options.onLoadError || latestError !== loaderError) && route.options.onError) {
1331
- try {
1332
- route.options.onError(latestError);
1333
- } catch (onErrorError) {
1334
- if (handleIfRedirect(onErrorError)) return;
1335
- }
1348
+ if (handleIfRedirect(error)) return;
1349
+ try {
1350
+ route.options.onError?.(error);
1351
+ } catch (onErrorError) {
1352
+ error = onErrorError;
1353
+ if (handleIfRedirect(onErrorError)) return;
1336
1354
  }
1337
1355
  this.setRouteMatch(match.id, s => ({
1338
1356
  ...s,
1339
- error: loaderError,
1357
+ error,
1340
1358
  status: 'error',
1341
1359
  isFetching: false,
1342
1360
  updatedAt: Date.now()
@@ -1893,6 +1911,125 @@
1893
1911
  };
1894
1912
  }
1895
1913
 
1914
+ const windowKey = 'window';
1915
+ const delimiter = '___';
1916
+ let weakScrolledElementsByRestoreKey = {};
1917
+ let cache;
1918
+ let pathDidChange = false;
1919
+ const sessionsStorage = typeof window !== 'undefined' && window.sessionStorage;
1920
+ const defaultGetKey = location => location.key;
1921
+ function watchScrollPositions(router, opts) {
1922
+ const getKey = opts?.getKey || defaultGetKey;
1923
+ if (sessionsStorage) {
1924
+ if (!cache) {
1925
+ cache = (() => {
1926
+ const storageKey = 'tsr-scroll-restoration-v1';
1927
+ const current = JSON.parse(window.sessionStorage.getItem(storageKey) || '{}');
1928
+ return {
1929
+ current,
1930
+ set: (key, value) => {
1931
+ current[key] = value;
1932
+ window.sessionStorage.setItem(storageKey, JSON.stringify(cache));
1933
+ }
1934
+ };
1935
+ })();
1936
+ }
1937
+ }
1938
+ const {
1939
+ history
1940
+ } = window;
1941
+ if (history.scrollRestoration) {
1942
+ history.scrollRestoration = 'manual';
1943
+ }
1944
+ const onScroll = event => {
1945
+ const restoreKey = getKey(router.state.resolvedLocation);
1946
+ if (!weakScrolledElementsByRestoreKey[restoreKey]) {
1947
+ weakScrolledElementsByRestoreKey[restoreKey] = new WeakSet();
1948
+ }
1949
+ const set = weakScrolledElementsByRestoreKey[restoreKey];
1950
+ if (set.has(event.target)) return;
1951
+ set.add(event.target);
1952
+ const cacheKey = [restoreKey, event.target === document || event.target === window ? windowKey : getCssSelector(event.target)].join(delimiter);
1953
+ if (!cache.current[cacheKey]) {
1954
+ cache.set(cacheKey, {
1955
+ scrollX: NaN,
1956
+ scrollY: NaN
1957
+ });
1958
+ }
1959
+ };
1960
+ const getCssSelector = el => {
1961
+ let path = [],
1962
+ parent;
1963
+ while (parent = el.parentNode) {
1964
+ path.unshift(`${el.tagName}:nth-child(${[].indexOf.call(parent.children, el) + 1})`);
1965
+ el = parent;
1966
+ }
1967
+ return `${path.join(' > ')}`.toLowerCase();
1968
+ };
1969
+ const onPathWillChange = from => {
1970
+ const restoreKey = getKey(from);
1971
+ for (const cacheKey in cache.current) {
1972
+ const entry = cache.current[cacheKey];
1973
+ const [key, elementSelector] = cacheKey.split(delimiter);
1974
+ if (restoreKey === key) {
1975
+ if (elementSelector === windowKey) {
1976
+ entry.scrollX = window.scrollX || 0;
1977
+ entry.scrollY = window.scrollY || 0;
1978
+ } else if (elementSelector) {
1979
+ const element = document.querySelector(elementSelector);
1980
+ entry.scrollX = element?.scrollLeft || 0;
1981
+ entry.scrollY = element?.scrollTop || 0;
1982
+ }
1983
+ cache.set(cacheKey, entry);
1984
+ }
1985
+ }
1986
+ };
1987
+ const onPathChange = () => {
1988
+ pathDidChange = true;
1989
+ };
1990
+ if (typeof document !== 'undefined') {
1991
+ document.addEventListener('scroll', onScroll, true);
1992
+ }
1993
+ const unsubOnBeforeLoad = router.subscribe('onBeforeLoad', event => {
1994
+ if (event.pathChanged) onPathWillChange(event.from);
1995
+ });
1996
+ const unsubOnLoad = router.subscribe('onLoad', event => {
1997
+ if (event.pathChanged) onPathChange();
1998
+ });
1999
+ return () => {
2000
+ document.removeEventListener('scroll', onScroll);
2001
+ unsubOnBeforeLoad();
2002
+ unsubOnLoad();
2003
+ };
2004
+ }
2005
+ function restoreScrollPositions(router, opts) {
2006
+ if (pathDidChange) {
2007
+ const getKey = opts?.getKey || defaultGetKey;
2008
+ pathDidChange = false;
2009
+ const restoreKey = getKey(router.state.location);
2010
+ let windowRestored = false;
2011
+ for (const cacheKey in cache.current) {
2012
+ const entry = cache.current[cacheKey];
2013
+ const [key, elementSelector] = cacheKey.split(delimiter);
2014
+ if (key === restoreKey) {
2015
+ if (elementSelector === windowKey) {
2016
+ windowRestored = true;
2017
+ window.scrollTo(entry.scrollX, entry.scrollY);
2018
+ } else if (elementSelector) {
2019
+ const element = document.querySelector(elementSelector);
2020
+ if (element) {
2021
+ element.scrollLeft = entry.scrollX;
2022
+ element.scrollTop = entry.scrollY;
2023
+ }
2024
+ }
2025
+ }
2026
+ }
2027
+ if (!windowRestored) {
2028
+ window.scrollTo(0, 0);
2029
+ }
2030
+ }
2031
+ }
2032
+
1896
2033
  exports.FileRoute = FileRoute;
1897
2034
  exports.PathParamError = PathParamError;
1898
2035
  exports.RootRoute = RootRoute;
@@ -1926,12 +2063,14 @@
1926
2063
  exports.redirect = redirect;
1927
2064
  exports.replaceEqualDeep = replaceEqualDeep;
1928
2065
  exports.resolvePath = resolvePath;
2066
+ exports.restoreScrollPositions = restoreScrollPositions;
1929
2067
  exports.rootRouteId = rootRouteId;
1930
2068
  exports.stringifySearchWith = stringifySearchWith;
1931
2069
  exports.trimPath = trimPath;
1932
2070
  exports.trimPathLeft = trimPathLeft;
1933
2071
  exports.trimPathRight = trimPathRight;
1934
2072
  exports.warning = warning;
2073
+ exports.watchScrollPositions = watchScrollPositions;
1935
2074
 
1936
2075
  Object.defineProperty(exports, '__esModule', { value: true });
1937
2076