@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.
- package/build/cjs/history.js +11 -11
- package/build/cjs/history.js.map +1 -1
- package/build/cjs/index.js +3 -0
- package/build/cjs/index.js.map +1 -1
- package/build/cjs/route.js.map +1 -1
- package/build/cjs/router.js +47 -29
- package/build/cjs/router.js.map +1 -1
- package/build/cjs/scroll-restoration.js +136 -0
- package/build/cjs/scroll-restoration.js.map +1 -0
- package/build/esm/index.js +178 -41
- package/build/esm/index.js.map +1 -1
- package/build/stats-html.html +1 -1
- package/build/stats-react.json +143 -118
- package/build/types/index.d.ts +30 -12
- package/build/umd/index.development.js +179 -40
- 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 +2 -2
- package/src/history.ts +14 -14
- package/src/index.ts +1 -0
- package/src/route.ts +1 -10
- package/src/router.ts +82 -39
- package/src/scroll-restoration.ts +175 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scroll-restoration.js","sources":["../../src/scroll-restoration.ts"],"sourcesContent":["import { AnyRouter, ParsedLocation } from './router'\n\nconst windowKey = 'window'\nconst delimiter = '___'\n\nlet weakScrolledElementsByRestoreKey: Record<string, WeakSet<any>> = {}\n\ntype CacheValue = Record<string, { scrollX: number; scrollY: number }>\n\ntype Cache = {\n current: CacheValue\n set: (key: string, value: any) => void\n}\n\nlet cache: Cache\n\nlet pathDidChange = false\n\nconst sessionsStorage = typeof window !== 'undefined' && window.sessionStorage\n\nexport type ScrollRestorationOptions = {\n getKey?: (location: ParsedLocation) => string\n}\n\nconst defaultGetKey = (location: ParsedLocation) => location.key!\n\nexport function watchScrollPositions(\n router: AnyRouter,\n opts?: ScrollRestorationOptions,\n) {\n const getKey = opts?.getKey || defaultGetKey\n\n if (sessionsStorage) {\n if (!cache) {\n cache = (() => {\n const storageKey = 'tsr-scroll-restoration-v1'\n\n const current: CacheValue = JSON.parse(\n window.sessionStorage.getItem(storageKey) || '{}',\n )\n\n return {\n current,\n set: (key: string, value: any) => {\n current[key] = value\n window.sessionStorage.setItem(storageKey, JSON.stringify(cache))\n },\n }\n })()\n }\n }\n\n const { history } = window\n if (history.scrollRestoration) {\n history.scrollRestoration = 'manual'\n }\n\n const onScroll = (event: Event) => {\n const restoreKey = getKey(router.state.resolvedLocation)\n\n if (!weakScrolledElementsByRestoreKey[restoreKey]) {\n weakScrolledElementsByRestoreKey[restoreKey] = new WeakSet()\n }\n\n const set = weakScrolledElementsByRestoreKey[restoreKey]!\n\n if (set.has(event.target)) return\n set.add(event.target)\n\n const cacheKey = [\n restoreKey,\n event.target === document || event.target === window\n ? windowKey\n : getCssSelector(event.target),\n ].join(delimiter)\n\n if (!cache.current[cacheKey]) {\n cache.set(cacheKey, {\n scrollX: NaN,\n scrollY: NaN,\n })\n }\n }\n\n const getCssSelector = (el: any): string => {\n let path = [],\n parent\n while ((parent = el.parentNode)) {\n path.unshift(\n `${el.tagName}:nth-child(${\n ([].indexOf as any).call(parent.children, el) + 1\n })`,\n )\n el = parent\n }\n return `${path.join(' > ')}`.toLowerCase()\n }\n\n const onPathWillChange = (from: ParsedLocation) => {\n const restoreKey = getKey(from)\n for (const cacheKey in cache.current) {\n const entry = cache.current[cacheKey]!\n const [key, elementSelector] = cacheKey.split(delimiter)\n if (restoreKey === key) {\n if (elementSelector === windowKey) {\n entry.scrollX = window.scrollX || 0\n entry.scrollY = window.scrollY || 0\n } else if (elementSelector) {\n const element = document.querySelector(elementSelector)\n entry.scrollX = element?.scrollLeft || 0\n entry.scrollY = element?.scrollTop || 0\n }\n\n cache.set(cacheKey, entry)\n }\n }\n }\n\n const onPathChange = () => {\n pathDidChange = true\n }\n\n if (typeof document !== 'undefined') {\n document.addEventListener('scroll', onScroll, true)\n }\n\n const unsubOnBeforeLoad = router.subscribe('onBeforeLoad', (event) => {\n if (event.pathChanged) onPathWillChange(event.from)\n })\n\n const unsubOnLoad = router.subscribe('onLoad', (event) => {\n if (event.pathChanged) onPathChange()\n })\n\n return () => {\n document.removeEventListener('scroll', onScroll)\n unsubOnBeforeLoad()\n unsubOnLoad()\n }\n}\n\nexport function restoreScrollPositions(\n router: AnyRouter,\n opts?: ScrollRestorationOptions,\n) {\n if (pathDidChange) {\n const getKey = opts?.getKey || defaultGetKey\n\n pathDidChange = false\n\n const restoreKey = getKey(router.state.location)\n let windowRestored = false\n\n for (const cacheKey in cache.current) {\n const entry = cache.current[cacheKey]!\n const [key, elementSelector] = cacheKey.split(delimiter)\n if (key === restoreKey) {\n if (elementSelector === windowKey) {\n windowRestored = true\n window.scrollTo(entry.scrollX, entry.scrollY)\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\n if (!windowRestored) {\n window.scrollTo(0, 0)\n }\n }\n}\n"],"names":["windowKey","delimiter","weakScrolledElementsByRestoreKey","cache","pathDidChange","sessionsStorage","window","sessionStorage","defaultGetKey","location","key","watchScrollPositions","router","opts","getKey","storageKey","current","JSON","parse","getItem","set","value","setItem","stringify","history","scrollRestoration","onScroll","event","restoreKey","state","resolvedLocation","WeakSet","has","target","add","cacheKey","document","getCssSelector","join","scrollX","NaN","scrollY","el","path","parent","parentNode","unshift","tagName","indexOf","call","children","toLowerCase","onPathWillChange","from","entry","elementSelector","split","element","querySelector","scrollLeft","scrollTop","onPathChange","addEventListener","unsubOnBeforeLoad","subscribe","pathChanged","unsubOnLoad","removeEventListener","restoreScrollPositions","windowRestored","scrollTo"],"mappings":"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"}
|
package/build/esm/index.js
CHANGED
|
@@ -33,7 +33,7 @@ const stopBlocking = () => {
|
|
|
33
33
|
function createHistory(opts) {
|
|
34
34
|
let location = opts.getLocation();
|
|
35
35
|
let unsub = () => {};
|
|
36
|
-
let
|
|
36
|
+
let subscribers = new Set();
|
|
37
37
|
let blockers = [];
|
|
38
38
|
let queue = [];
|
|
39
39
|
const tryFlush = () => {
|
|
@@ -47,7 +47,7 @@ function createHistory(opts) {
|
|
|
47
47
|
while (queue.length) {
|
|
48
48
|
queue.shift()?.();
|
|
49
49
|
}
|
|
50
|
-
if (!opts.
|
|
50
|
+
if (!opts.subscriber) {
|
|
51
51
|
onUpdate();
|
|
52
52
|
}
|
|
53
53
|
};
|
|
@@ -57,20 +57,20 @@ function createHistory(opts) {
|
|
|
57
57
|
};
|
|
58
58
|
const onUpdate = () => {
|
|
59
59
|
location = opts.getLocation();
|
|
60
|
-
|
|
60
|
+
subscribers.forEach(subscriber => subscriber());
|
|
61
61
|
};
|
|
62
62
|
return {
|
|
63
63
|
get location() {
|
|
64
64
|
return location;
|
|
65
65
|
},
|
|
66
|
-
|
|
67
|
-
if (
|
|
68
|
-
unsub = typeof opts.
|
|
66
|
+
subscribe: cb => {
|
|
67
|
+
if (subscribers.size === 0) {
|
|
68
|
+
unsub = typeof opts.subscriber === 'function' ? opts.subscriber(onUpdate) : () => {};
|
|
69
69
|
}
|
|
70
|
-
|
|
70
|
+
subscribers.add(cb);
|
|
71
71
|
return () => {
|
|
72
|
-
|
|
73
|
-
if (
|
|
72
|
+
subscribers.delete(cb);
|
|
73
|
+
if (subscribers.size === 0) {
|
|
74
74
|
unsub();
|
|
75
75
|
}
|
|
76
76
|
};
|
|
@@ -123,7 +123,7 @@ function createBrowserHistory(opts) {
|
|
|
123
123
|
const getLocation = () => parseLocation(getHref(), history.state);
|
|
124
124
|
return createHistory({
|
|
125
125
|
getLocation,
|
|
126
|
-
|
|
126
|
+
subscriber: onUpdate => {
|
|
127
127
|
window.addEventListener(pushStateEvent, onUpdate);
|
|
128
128
|
window.addEventListener(popStateEvent, onUpdate);
|
|
129
129
|
var pushState = window.history.pushState;
|
|
@@ -178,7 +178,7 @@ function createMemoryHistory(opts = {
|
|
|
178
178
|
const getLocation = () => parseLocation(entries[index], currentState);
|
|
179
179
|
return createHistory({
|
|
180
180
|
getLocation,
|
|
181
|
-
|
|
181
|
+
subscriber: false,
|
|
182
182
|
pushState: (path, state) => {
|
|
183
183
|
currentState = {
|
|
184
184
|
...state,
|
|
@@ -753,6 +753,24 @@ class Router {
|
|
|
753
753
|
});
|
|
754
754
|
}
|
|
755
755
|
}
|
|
756
|
+
subscribers = new Set();
|
|
757
|
+
subscribe = (eventType, fn) => {
|
|
758
|
+
const listener = {
|
|
759
|
+
eventType,
|
|
760
|
+
fn
|
|
761
|
+
};
|
|
762
|
+
this.subscribers.add(listener);
|
|
763
|
+
return () => {
|
|
764
|
+
this.subscribers.delete(listener);
|
|
765
|
+
};
|
|
766
|
+
};
|
|
767
|
+
#emit = routerEvent => {
|
|
768
|
+
this.subscribers.forEach(listener => {
|
|
769
|
+
if (listener.eventType === routerEvent.type) {
|
|
770
|
+
listener.fn(routerEvent);
|
|
771
|
+
}
|
|
772
|
+
});
|
|
773
|
+
};
|
|
756
774
|
reset = () => {
|
|
757
775
|
this.__store.setState(s => Object.assign(s, getInitialRouterState()));
|
|
758
776
|
};
|
|
@@ -783,7 +801,7 @@ class Router {
|
|
|
783
801
|
resolvedLocation: parsedLocation,
|
|
784
802
|
location: parsedLocation
|
|
785
803
|
}));
|
|
786
|
-
this.#unsubHistory = this.history.
|
|
804
|
+
this.#unsubHistory = this.history.subscribe(() => {
|
|
787
805
|
this.safeLoad({
|
|
788
806
|
next: this.#parseLocation(this.state.location)
|
|
789
807
|
});
|
|
@@ -825,6 +843,8 @@ class Router {
|
|
|
825
843
|
latestLoadPromise = Promise.resolve();
|
|
826
844
|
load = async opts => {
|
|
827
845
|
const promise = new Promise(async (resolve, reject) => {
|
|
846
|
+
const prevLocation = this.state.resolvedLocation;
|
|
847
|
+
const pathDidChange = !!(opts?.next && prevLocation.href !== opts.next.href);
|
|
828
848
|
let latestPromise;
|
|
829
849
|
const checkLatest = () => {
|
|
830
850
|
return this.latestLoadPromise !== promise ? this.latestLoadPromise : undefined;
|
|
@@ -834,6 +854,12 @@ class Router {
|
|
|
834
854
|
// this.cancelMatches()
|
|
835
855
|
|
|
836
856
|
let pendingMatches;
|
|
857
|
+
this.#emit({
|
|
858
|
+
type: 'onBeforeLoad',
|
|
859
|
+
from: prevLocation,
|
|
860
|
+
to: opts?.next ?? this.state.location,
|
|
861
|
+
pathChanged: pathDidChange
|
|
862
|
+
});
|
|
837
863
|
this.__store.batch(() => {
|
|
838
864
|
if (opts?.next) {
|
|
839
865
|
// Ingest the new location
|
|
@@ -868,7 +894,6 @@ class Router {
|
|
|
868
894
|
if (latestPromise = checkLatest()) {
|
|
869
895
|
return latestPromise;
|
|
870
896
|
}
|
|
871
|
-
const prevLocation = this.state.resolvedLocation;
|
|
872
897
|
this.__store.setState(s => ({
|
|
873
898
|
...s,
|
|
874
899
|
status: 'idle',
|
|
@@ -876,9 +901,12 @@ class Router {
|
|
|
876
901
|
matchIds: s.pendingMatchIds,
|
|
877
902
|
pendingMatchIds: []
|
|
878
903
|
}));
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
904
|
+
this.#emit({
|
|
905
|
+
type: 'onLoad',
|
|
906
|
+
from: prevLocation,
|
|
907
|
+
to: this.state.location,
|
|
908
|
+
pathChanged: pathDidChange
|
|
909
|
+
});
|
|
882
910
|
resolve();
|
|
883
911
|
} catch (err) {
|
|
884
912
|
// Only apply the latest transition
|
|
@@ -1128,14 +1156,14 @@ class Router {
|
|
|
1128
1156
|
try {
|
|
1129
1157
|
for (const [index, match] of resolvedMatches.entries()) {
|
|
1130
1158
|
const route = this.getRoute(match.routeId);
|
|
1131
|
-
const handleError = (err,
|
|
1159
|
+
const handleError = (err, code) => {
|
|
1160
|
+
err.routerCode = code;
|
|
1132
1161
|
firstBadMatchIndex = firstBadMatchIndex ?? index;
|
|
1133
|
-
handler = handler || route.options.onError;
|
|
1134
1162
|
if (isRedirect(err)) {
|
|
1135
1163
|
throw err;
|
|
1136
1164
|
}
|
|
1137
1165
|
try {
|
|
1138
|
-
|
|
1166
|
+
route.options.onError?.(err);
|
|
1139
1167
|
} catch (errorHandlerErr) {
|
|
1140
1168
|
err = errorHandlerErr;
|
|
1141
1169
|
if (isRedirect(errorHandlerErr)) {
|
|
@@ -1150,10 +1178,10 @@ class Router {
|
|
|
1150
1178
|
}));
|
|
1151
1179
|
};
|
|
1152
1180
|
if (match.paramsError) {
|
|
1153
|
-
handleError(match.paramsError,
|
|
1181
|
+
handleError(match.paramsError, 'PARSE_PARAMS');
|
|
1154
1182
|
}
|
|
1155
1183
|
if (match.searchError) {
|
|
1156
|
-
handleError(match.searchError,
|
|
1184
|
+
handleError(match.searchError, 'VALIDATE_SEARCH');
|
|
1157
1185
|
}
|
|
1158
1186
|
let didError = false;
|
|
1159
1187
|
try {
|
|
@@ -1162,7 +1190,7 @@ class Router {
|
|
|
1162
1190
|
preload: !!opts?.preload
|
|
1163
1191
|
});
|
|
1164
1192
|
} catch (err) {
|
|
1165
|
-
handleError(err,
|
|
1193
|
+
handleError(err, 'BEFORE_LOAD');
|
|
1166
1194
|
didError = true;
|
|
1167
1195
|
}
|
|
1168
1196
|
|
|
@@ -1220,28 +1248,18 @@ class Router {
|
|
|
1220
1248
|
const [_, loader] = await Promise.all([componentsPromise, loaderPromise]);
|
|
1221
1249
|
if (latestPromise = checkLatest()) return await latestPromise;
|
|
1222
1250
|
this.setRouteMatchData(match.id, () => loader, opts);
|
|
1223
|
-
} catch (
|
|
1224
|
-
let latestError = loaderError;
|
|
1251
|
+
} catch (error) {
|
|
1225
1252
|
if (latestPromise = checkLatest()) return await latestPromise;
|
|
1226
|
-
if (handleIfRedirect(
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
if (handleIfRedirect(onLoadError)) return;
|
|
1233
|
-
}
|
|
1234
|
-
}
|
|
1235
|
-
if ((!route.options.onLoadError || latestError !== loaderError) && route.options.onError) {
|
|
1236
|
-
try {
|
|
1237
|
-
route.options.onError(latestError);
|
|
1238
|
-
} catch (onErrorError) {
|
|
1239
|
-
if (handleIfRedirect(onErrorError)) return;
|
|
1240
|
-
}
|
|
1253
|
+
if (handleIfRedirect(error)) return;
|
|
1254
|
+
try {
|
|
1255
|
+
route.options.onError?.(error);
|
|
1256
|
+
} catch (onErrorError) {
|
|
1257
|
+
error = onErrorError;
|
|
1258
|
+
if (handleIfRedirect(onErrorError)) return;
|
|
1241
1259
|
}
|
|
1242
1260
|
this.setRouteMatch(match.id, s => ({
|
|
1243
1261
|
...s,
|
|
1244
|
-
error
|
|
1262
|
+
error,
|
|
1245
1263
|
status: 'error',
|
|
1246
1264
|
isFetching: false,
|
|
1247
1265
|
updatedAt: Date.now()
|
|
@@ -1798,5 +1816,124 @@ function lazyFn(fn, key) {
|
|
|
1798
1816
|
};
|
|
1799
1817
|
}
|
|
1800
1818
|
|
|
1801
|
-
|
|
1819
|
+
const windowKey = 'window';
|
|
1820
|
+
const delimiter = '___';
|
|
1821
|
+
let weakScrolledElementsByRestoreKey = {};
|
|
1822
|
+
let cache;
|
|
1823
|
+
let pathDidChange = false;
|
|
1824
|
+
const sessionsStorage = typeof window !== 'undefined' && window.sessionStorage;
|
|
1825
|
+
const defaultGetKey = location => location.key;
|
|
1826
|
+
function watchScrollPositions(router, opts) {
|
|
1827
|
+
const getKey = opts?.getKey || defaultGetKey;
|
|
1828
|
+
if (sessionsStorage) {
|
|
1829
|
+
if (!cache) {
|
|
1830
|
+
cache = (() => {
|
|
1831
|
+
const storageKey = 'tsr-scroll-restoration-v1';
|
|
1832
|
+
const current = JSON.parse(window.sessionStorage.getItem(storageKey) || '{}');
|
|
1833
|
+
return {
|
|
1834
|
+
current,
|
|
1835
|
+
set: (key, value) => {
|
|
1836
|
+
current[key] = value;
|
|
1837
|
+
window.sessionStorage.setItem(storageKey, JSON.stringify(cache));
|
|
1838
|
+
}
|
|
1839
|
+
};
|
|
1840
|
+
})();
|
|
1841
|
+
}
|
|
1842
|
+
}
|
|
1843
|
+
const {
|
|
1844
|
+
history
|
|
1845
|
+
} = window;
|
|
1846
|
+
if (history.scrollRestoration) {
|
|
1847
|
+
history.scrollRestoration = 'manual';
|
|
1848
|
+
}
|
|
1849
|
+
const onScroll = event => {
|
|
1850
|
+
const restoreKey = getKey(router.state.resolvedLocation);
|
|
1851
|
+
if (!weakScrolledElementsByRestoreKey[restoreKey]) {
|
|
1852
|
+
weakScrolledElementsByRestoreKey[restoreKey] = new WeakSet();
|
|
1853
|
+
}
|
|
1854
|
+
const set = weakScrolledElementsByRestoreKey[restoreKey];
|
|
1855
|
+
if (set.has(event.target)) return;
|
|
1856
|
+
set.add(event.target);
|
|
1857
|
+
const cacheKey = [restoreKey, event.target === document || event.target === window ? windowKey : getCssSelector(event.target)].join(delimiter);
|
|
1858
|
+
if (!cache.current[cacheKey]) {
|
|
1859
|
+
cache.set(cacheKey, {
|
|
1860
|
+
scrollX: NaN,
|
|
1861
|
+
scrollY: NaN
|
|
1862
|
+
});
|
|
1863
|
+
}
|
|
1864
|
+
};
|
|
1865
|
+
const getCssSelector = el => {
|
|
1866
|
+
let path = [],
|
|
1867
|
+
parent;
|
|
1868
|
+
while (parent = el.parentNode) {
|
|
1869
|
+
path.unshift(`${el.tagName}:nth-child(${[].indexOf.call(parent.children, el) + 1})`);
|
|
1870
|
+
el = parent;
|
|
1871
|
+
}
|
|
1872
|
+
return `${path.join(' > ')}`.toLowerCase();
|
|
1873
|
+
};
|
|
1874
|
+
const onPathWillChange = from => {
|
|
1875
|
+
const restoreKey = getKey(from);
|
|
1876
|
+
for (const cacheKey in cache.current) {
|
|
1877
|
+
const entry = cache.current[cacheKey];
|
|
1878
|
+
const [key, elementSelector] = cacheKey.split(delimiter);
|
|
1879
|
+
if (restoreKey === key) {
|
|
1880
|
+
if (elementSelector === windowKey) {
|
|
1881
|
+
entry.scrollX = window.scrollX || 0;
|
|
1882
|
+
entry.scrollY = window.scrollY || 0;
|
|
1883
|
+
} else if (elementSelector) {
|
|
1884
|
+
const element = document.querySelector(elementSelector);
|
|
1885
|
+
entry.scrollX = element?.scrollLeft || 0;
|
|
1886
|
+
entry.scrollY = element?.scrollTop || 0;
|
|
1887
|
+
}
|
|
1888
|
+
cache.set(cacheKey, entry);
|
|
1889
|
+
}
|
|
1890
|
+
}
|
|
1891
|
+
};
|
|
1892
|
+
const onPathChange = () => {
|
|
1893
|
+
pathDidChange = true;
|
|
1894
|
+
};
|
|
1895
|
+
if (typeof document !== 'undefined') {
|
|
1896
|
+
document.addEventListener('scroll', onScroll, true);
|
|
1897
|
+
}
|
|
1898
|
+
const unsubOnBeforeLoad = router.subscribe('onBeforeLoad', event => {
|
|
1899
|
+
if (event.pathChanged) onPathWillChange(event.from);
|
|
1900
|
+
});
|
|
1901
|
+
const unsubOnLoad = router.subscribe('onLoad', event => {
|
|
1902
|
+
if (event.pathChanged) onPathChange();
|
|
1903
|
+
});
|
|
1904
|
+
return () => {
|
|
1905
|
+
document.removeEventListener('scroll', onScroll);
|
|
1906
|
+
unsubOnBeforeLoad();
|
|
1907
|
+
unsubOnLoad();
|
|
1908
|
+
};
|
|
1909
|
+
}
|
|
1910
|
+
function restoreScrollPositions(router, opts) {
|
|
1911
|
+
if (pathDidChange) {
|
|
1912
|
+
const getKey = opts?.getKey || defaultGetKey;
|
|
1913
|
+
pathDidChange = false;
|
|
1914
|
+
const restoreKey = getKey(router.state.location);
|
|
1915
|
+
let windowRestored = false;
|
|
1916
|
+
for (const cacheKey in cache.current) {
|
|
1917
|
+
const entry = cache.current[cacheKey];
|
|
1918
|
+
const [key, elementSelector] = cacheKey.split(delimiter);
|
|
1919
|
+
if (key === restoreKey) {
|
|
1920
|
+
if (elementSelector === windowKey) {
|
|
1921
|
+
windowRestored = true;
|
|
1922
|
+
window.scrollTo(entry.scrollX, entry.scrollY);
|
|
1923
|
+
} else if (elementSelector) {
|
|
1924
|
+
const element = document.querySelector(elementSelector);
|
|
1925
|
+
if (element) {
|
|
1926
|
+
element.scrollLeft = entry.scrollX;
|
|
1927
|
+
element.scrollTop = entry.scrollY;
|
|
1928
|
+
}
|
|
1929
|
+
}
|
|
1930
|
+
}
|
|
1931
|
+
}
|
|
1932
|
+
if (!windowRestored) {
|
|
1933
|
+
window.scrollTo(0, 0);
|
|
1934
|
+
}
|
|
1935
|
+
}
|
|
1936
|
+
}
|
|
1937
|
+
|
|
1938
|
+
export { FileRoute, PathParamError, RootRoute, Route, Router, RouterContext, SearchParamError, 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 };
|
|
1802
1939
|
//# sourceMappingURL=index.js.map
|