@tanstack/router-core 1.171.2 → 1.171.4

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.
Files changed (51) hide show
  1. package/dist/cjs/index.cjs +0 -3
  2. package/dist/cjs/index.d.cts +2 -3
  3. package/dist/cjs/rewrite.cjs +1 -6
  4. package/dist/cjs/rewrite.cjs.map +1 -1
  5. package/dist/cjs/rewrite.d.cts +0 -4
  6. package/dist/cjs/router.cjs +9 -2
  7. package/dist/cjs/router.cjs.map +1 -1
  8. package/dist/cjs/router.d.cts +5 -1
  9. package/dist/cjs/scroll-restoration-inline.cjs +1 -1
  10. package/dist/cjs/scroll-restoration-inline.cjs.map +1 -1
  11. package/dist/cjs/scroll-restoration-inline.d.cts +0 -2
  12. package/dist/cjs/scroll-restoration-script/server.cjs +2 -6
  13. package/dist/cjs/scroll-restoration-script/server.cjs.map +1 -1
  14. package/dist/cjs/scroll-restoration.cjs +113 -107
  15. package/dist/cjs/scroll-restoration.cjs.map +1 -1
  16. package/dist/cjs/scroll-restoration.d.cts +0 -10
  17. package/dist/cjs/ssr/ssr-server.cjs +4 -3
  18. package/dist/cjs/ssr/ssr-server.cjs.map +1 -1
  19. package/dist/esm/index.d.ts +2 -3
  20. package/dist/esm/index.js +2 -3
  21. package/dist/esm/rewrite.d.ts +0 -4
  22. package/dist/esm/rewrite.js +1 -6
  23. package/dist/esm/rewrite.js.map +1 -1
  24. package/dist/esm/router.d.ts +5 -1
  25. package/dist/esm/router.js +9 -3
  26. package/dist/esm/router.js.map +1 -1
  27. package/dist/esm/scroll-restoration-inline.d.ts +0 -2
  28. package/dist/esm/scroll-restoration-inline.js +1 -1
  29. package/dist/esm/scroll-restoration-inline.js.map +1 -1
  30. package/dist/esm/scroll-restoration-script/server.js +2 -6
  31. package/dist/esm/scroll-restoration-script/server.js.map +1 -1
  32. package/dist/esm/scroll-restoration.d.ts +0 -10
  33. package/dist/esm/scroll-restoration.js +114 -107
  34. package/dist/esm/scroll-restoration.js.map +1 -1
  35. package/dist/esm/ssr/ssr-server.js +4 -3
  36. package/dist/esm/ssr/ssr-server.js.map +1 -1
  37. package/package.json +1 -1
  38. package/src/index.ts +1 -3
  39. package/src/rewrite.ts +1 -8
  40. package/src/router.ts +28 -4
  41. package/src/scroll-restoration-inline.ts +7 -16
  42. package/src/scroll-restoration-script/server.ts +1 -10
  43. package/src/scroll-restoration.ts +188 -167
  44. package/src/ssr/ssr-server.ts +12 -8
  45. package/dist/cjs/hash-scroll.cjs +0 -20
  46. package/dist/cjs/hash-scroll.cjs.map +0 -1
  47. package/dist/cjs/hash-scroll.d.cts +0 -7
  48. package/dist/esm/hash-scroll.d.ts +0 -7
  49. package/dist/esm/hash-scroll.js +0 -20
  50. package/dist/esm/hash-scroll.js.map +0 -1
  51. package/src/hash-scroll.ts +0 -21
@@ -3,7 +3,7 @@ import { LRUCache } from './lru-cache.cjs';
3
3
  import { ProcessRouteTreeResult, ProcessedTree } from './new-process-route-tree.cjs';
4
4
  import { SearchParser, SearchSerializer } from './searchParams.cjs';
5
5
  import { AnyRedirect, ResolvedRedirect } from './redirect.cjs';
6
- import { HistoryLocation, HistoryState, ParsedHistoryState, RouterHistory } from '@tanstack/history';
6
+ import { HistoryAction, HistoryLocation, HistoryState, ParsedHistoryState, RouterHistory } from '@tanstack/history';
7
7
  import { Awaitable, Constrain, ControlledPromise, NoInfer, NonNullableUpdater, PickAsRequired, Updater } from './utils.cjs';
8
8
  import { ParsedLocation } from './location.cjs';
9
9
  import { AnyContext, AnyRoute, AnyRouteWithContext, LoaderStaleReloadMode, MakeRemountDepsOptionsUnion, RouteLike, RouteMask } from './route.cjs';
@@ -483,6 +483,9 @@ export type GetMatchRoutesFn = (pathname: string) => {
483
483
  export type EmitFn = (routerEvent: RouterEvent) => void;
484
484
  export type LoadFn = (opts?: {
485
485
  sync?: boolean;
486
+ action?: {
487
+ type: HistoryAction;
488
+ };
486
489
  }) => Promise<void>;
487
490
  export type CommitLocationFn = ({ viewTransition, ignoreBlocker, ...next }: ParsedLocation & CommitLocationOptions) => Promise<void>;
488
491
  export type StartTransitionFn = (fn: () => void) => void;
@@ -568,6 +571,7 @@ export declare function getLocationChangeInfo(location: ParsedLocation, resolved
568
571
  hrefChanged: boolean;
569
572
  hashChanged: boolean;
570
573
  };
574
+ export declare const locationHistoryActions: WeakMap<ParsedLocation<{}>, HistoryAction>;
571
575
  export type CreateRouterFn = <TRouteTree extends AnyRoute, TTrailingSlashOption extends TrailingSlashOption = 'never', TDefaultStructuralSharingOption extends boolean = false, TRouterHistory extends RouterHistory = RouterHistory, TDehydrated extends Record<string, any> = Record<string, any>>(options: undefined extends number ? 'strictNullChecks must be enabled in tsconfig.json' : RouterConstructorOptions<TRouteTree, TTrailingSlashOption, TDefaultStructuralSharingOption, TRouterHistory, TDehydrated>) => RouterCore<TRouteTree, TTrailingSlashOption, TDefaultStructuralSharingOption, TRouterHistory, TDehydrated>;
572
576
  declare global {
573
577
  var __TSR_CACHE__: {
@@ -1,5 +1,5 @@
1
1
  //#region src/scroll-restoration-inline.ts?script-string
2
- var scroll_restoration_inline_default = "function(t){let s;try{s=JSON.parse(sessionStorage.getItem(t.storageKey)||\"{}\")}catch(e){console.error(e);return}const c=t.key||window.history.state?.__TSR_key,r=c?s[c]:void 0;if(t.shouldScrollRestoration&&r&&typeof r==\"object\"&&Object.keys(r).length>0){for(const e in r){const o=r[e];if(!o||typeof o!=\"object\")continue;const l=o.scrollX,i=o.scrollY;if(!(!Number.isFinite(l)||!Number.isFinite(i))){if(e===\"window\")window.scrollTo({top:i,left:l,behavior:t.behavior});else if(e){let n;try{n=document.querySelector(e)}catch{continue}n&&(n.scrollLeft=l,n.scrollTop=i)}}}return}const a=window.location.hash.split(\"#\",2)[1];if(a){const e=window.history.state?.__hashScrollIntoViewOptions??!0;if(e){const o=document.getElementById(a);o&&o.scrollIntoView(e)}return}window.scrollTo({top:0,left:0,behavior:t.behavior})}";
2
+ var scroll_restoration_inline_default = "function(i){let l;try{l=JSON.parse(sessionStorage.getItem(i.storageKey)||\"{}\")}catch(e){console.error(e);return}const c=i.key||window.history.state?.__TSR_key,o=c?l[c]:void 0;let f=!1;if(o&&typeof o==\"object\")for(const e in o){const t=o[e];if(!t||typeof t!=\"object\")continue;const r=t.scrollX,s=t.scrollY;if(!(!Number.isFinite(r)||!Number.isFinite(s))){if(e===\"window\")window.scrollTo({top:s,left:r}),f=!0;else if(e){let n;try{n=document.querySelector(e)}catch{continue}n&&(n.scrollLeft=r,n.scrollTop=s)}}}if(f)return;const w=window.location.hash.split(\"#\",2)[1];if(w){const e=window.history.state?.__hashScrollIntoViewOptions??!0;if(e){const t=document.getElementById(w);t&&t.scrollIntoView(e)}return}window.scrollTo({top:0,left:0})}";
3
3
  //#endregion
4
4
  exports.default = scroll_restoration_inline_default;
5
5
 
@@ -1 +1 @@
1
- {"version":3,"file":"scroll-restoration-inline.cjs","names":[],"sources":["../../src/scroll-restoration-inline.ts?script-string"],"sourcesContent":["export default function (options: {\n storageKey: string\n key?: string\n behavior?: ScrollToOptions['behavior']\n shouldScrollRestoration?: boolean\n}) {\n let byKey\n\n try {\n byKey = JSON.parse(sessionStorage.getItem(options.storageKey) || '{}')\n } catch (error) {\n console.error(error)\n return\n }\n\n const resolvedKey = options.key || window.history.state?.__TSR_key\n const elementEntries = resolvedKey ? byKey[resolvedKey] : undefined\n\n if (\n options.shouldScrollRestoration &&\n elementEntries &&\n typeof elementEntries === 'object' &&\n Object.keys(elementEntries).length > 0\n ) {\n for (const elementSelector in elementEntries) {\n const entry = elementEntries[elementSelector]\n\n if (!entry || typeof entry !== 'object') {\n continue\n }\n\n const scrollX = entry.scrollX\n const scrollY = entry.scrollY\n\n if (!Number.isFinite(scrollX) || !Number.isFinite(scrollY)) {\n continue\n }\n\n if (elementSelector === 'window') {\n window.scrollTo({\n top: scrollY,\n left: scrollX,\n behavior: options.behavior,\n })\n } else if (elementSelector) {\n let element\n\n try {\n element = document.querySelector(elementSelector)\n } catch {\n continue\n }\n\n if (element) {\n element.scrollLeft = scrollX\n element.scrollTop = scrollY\n }\n }\n }\n\n return\n }\n\n const hash = 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 return\n }\n\n window.scrollTo({ top: 0, left: 0, behavior: options.behavior })\n}\n"],"mappings":";AAAA,IAAA,oCAAe"}
1
+ {"version":3,"file":"scroll-restoration-inline.cjs","names":[],"sources":["../../src/scroll-restoration-inline.ts?script-string"],"sourcesContent":["export default function (options: { storageKey: string; key?: string }) {\n let byKey\n\n try {\n byKey = JSON.parse(sessionStorage.getItem(options.storageKey) || '{}')\n } catch (error) {\n console.error(error)\n return\n }\n\n const resolvedKey = options.key || window.history.state?.__TSR_key\n const elementEntries = resolvedKey ? byKey[resolvedKey] : undefined\n let windowRestored = false\n\n if (elementEntries && typeof elementEntries === 'object') {\n for (const elementSelector in elementEntries) {\n const entry = elementEntries[elementSelector]\n\n if (!entry || typeof entry !== 'object') {\n continue\n }\n\n const scrollX = entry.scrollX\n const scrollY = entry.scrollY\n\n if (!Number.isFinite(scrollX) || !Number.isFinite(scrollY)) {\n continue\n }\n\n if (elementSelector === 'window') {\n window.scrollTo({\n top: scrollY,\n left: scrollX,\n })\n windowRestored = true\n } else if (elementSelector) {\n let element\n\n try {\n element = document.querySelector(elementSelector)\n } catch {\n continue\n }\n\n if (element) {\n element.scrollLeft = scrollX\n element.scrollTop = scrollY\n }\n }\n }\n }\n\n if (windowRestored) return\n\n const hash = 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 return\n }\n\n window.scrollTo({ top: 0, left: 0 })\n}\n"],"mappings":";AAAA,IAAA,oCAAe"}
@@ -1,6 +1,4 @@
1
1
  export default function (options: {
2
2
  storageKey: string;
3
3
  key?: string;
4
- behavior?: ScrollToOptions['behavior'];
5
- shouldScrollRestoration?: boolean;
6
4
  }): void;
@@ -3,12 +3,9 @@ const require_utils = require("../utils.cjs");
3
3
  const require_scroll_restoration = require("../scroll-restoration.cjs");
4
4
  const require_scroll_restoration_inline = require("../scroll-restoration-inline.cjs");
5
5
  //#region src/scroll-restoration-script/server.ts
6
- const defaultInlineScrollRestorationScript = `(${require_scroll_restoration_inline.default})(${require_utils.escapeHtml(JSON.stringify({
7
- storageKey: require_scroll_restoration.storageKey,
8
- shouldScrollRestoration: true
9
- }))})`;
6
+ const defaultInlineScrollRestorationScript = `(${require_scroll_restoration_inline.default})(${require_utils.escapeHtml(JSON.stringify({ storageKey: require_scroll_restoration.storageKey }))})`;
10
7
  function getScrollRestorationScript(options) {
11
- if (options.storageKey === "tsr-scroll-restoration-v1_3" && options.shouldScrollRestoration === true && options.key === void 0 && options.behavior === void 0) return defaultInlineScrollRestorationScript;
8
+ if (options.storageKey === "tsr-scroll-restoration-v1_3" && options.key === void 0) return defaultInlineScrollRestorationScript;
12
9
  return `(${require_scroll_restoration_inline.default})(${require_utils.escapeHtml(JSON.stringify(options))})`;
13
10
  }
14
11
  function getScrollRestorationScriptForRouter(router) {
@@ -20,7 +17,6 @@ function getScrollRestorationScriptForRouter(router) {
20
17
  if (userKey === require_scroll_restoration.defaultGetScrollRestorationKey(location)) return defaultInlineScrollRestorationScript;
21
18
  return getScrollRestorationScript({
22
19
  storageKey: require_scroll_restoration.storageKey,
23
- shouldScrollRestoration: true,
24
20
  key: userKey
25
21
  });
26
22
  }
@@ -1 +1 @@
1
- {"version":3,"file":"server.cjs","names":[],"sources":["../../../src/scroll-restoration-script/server.ts"],"sourcesContent":["import minifiedScrollRestorationScript from '../scroll-restoration-inline?script-string'\nimport {\n defaultGetScrollRestorationKey,\n storageKey,\n} from '../scroll-restoration'\nimport { escapeHtml } from '../utils'\nimport type { AnyRouter } from '../router'\n\ntype InlineScrollRestorationScriptOptions = {\n storageKey: string\n key?: string\n behavior?: ScrollToOptions['behavior']\n shouldScrollRestoration?: boolean\n}\n\nconst defaultInlineScrollRestorationScript = `(${minifiedScrollRestorationScript})(${escapeHtml(\n JSON.stringify({\n storageKey,\n shouldScrollRestoration: true,\n } satisfies InlineScrollRestorationScriptOptions),\n)})`\n\nfunction getScrollRestorationScript(\n options: InlineScrollRestorationScriptOptions,\n) {\n if (\n options.storageKey === storageKey &&\n options.shouldScrollRestoration === true &&\n options.key === undefined &&\n options.behavior === undefined\n ) {\n return defaultInlineScrollRestorationScript\n }\n\n return `(${minifiedScrollRestorationScript})(${escapeHtml(JSON.stringify(options))})`\n}\n\nexport function getScrollRestorationScriptForRouter(router: AnyRouter) {\n if (\n typeof router.options.scrollRestoration === 'function' &&\n !router.options.scrollRestoration({ location: router.latestLocation })\n ) {\n return null\n }\n\n const getKey = router.options.getScrollRestorationKey\n if (!getKey) {\n return defaultInlineScrollRestorationScript\n }\n\n const location = router.latestLocation\n const userKey = getKey(location)\n const defaultKey = defaultGetScrollRestorationKey(location)\n\n if (userKey === defaultKey) {\n return defaultInlineScrollRestorationScript\n }\n\n return getScrollRestorationScript({\n storageKey,\n shouldScrollRestoration: true,\n key: userKey,\n })\n}\n"],"mappings":";;;;;AAeA,MAAM,uCAAuC,IAAI,kCAAA,QAAgC,IAAI,cAAA,WACnF,KAAK,UAAU;CACb,YAAA,2BAAA;CACA,yBAAyB;CAC1B,CAAgD,CAClD,CAAC;AAEF,SAAS,2BACP,SACA;AACA,KACE,QAAQ,eAAA,iCACR,QAAQ,4BAA4B,QACpC,QAAQ,QAAQ,KAAA,KAChB,QAAQ,aAAa,KAAA,EAErB,QAAO;AAGT,QAAO,IAAI,kCAAA,QAAgC,IAAI,cAAA,WAAW,KAAK,UAAU,QAAQ,CAAC,CAAC;;AAGrF,SAAgB,oCAAoC,QAAmB;AACrE,KACE,OAAO,OAAO,QAAQ,sBAAsB,cAC5C,CAAC,OAAO,QAAQ,kBAAkB,EAAE,UAAU,OAAO,gBAAgB,CAAC,CAEtE,QAAO;CAGT,MAAM,SAAS,OAAO,QAAQ;AAC9B,KAAI,CAAC,OACH,QAAO;CAGT,MAAM,WAAW,OAAO;CACxB,MAAM,UAAU,OAAO,SAAS;AAGhC,KAAI,YAFe,2BAAA,+BAA+B,SAAS,CAGzD,QAAO;AAGT,QAAO,2BAA2B;EAChC,YAAA,2BAAA;EACA,yBAAyB;EACzB,KAAK;EACN,CAAC"}
1
+ {"version":3,"file":"server.cjs","names":[],"sources":["../../../src/scroll-restoration-script/server.ts"],"sourcesContent":["import minifiedScrollRestorationScript from '../scroll-restoration-inline?script-string'\nimport {\n defaultGetScrollRestorationKey,\n storageKey,\n} from '../scroll-restoration'\nimport { escapeHtml } from '../utils'\nimport type { AnyRouter } from '../router'\n\ntype InlineScrollRestorationScriptOptions = {\n storageKey: string\n key?: string\n}\n\nconst defaultInlineScrollRestorationScript = `(${minifiedScrollRestorationScript})(${escapeHtml(\n JSON.stringify({\n storageKey,\n } satisfies InlineScrollRestorationScriptOptions),\n)})`\n\nfunction getScrollRestorationScript(\n options: InlineScrollRestorationScriptOptions,\n) {\n if (options.storageKey === storageKey && options.key === undefined) {\n return defaultInlineScrollRestorationScript\n }\n\n return `(${minifiedScrollRestorationScript})(${escapeHtml(JSON.stringify(options))})`\n}\n\nexport function getScrollRestorationScriptForRouter(router: AnyRouter) {\n if (\n typeof router.options.scrollRestoration === 'function' &&\n !router.options.scrollRestoration({ location: router.latestLocation })\n ) {\n return null\n }\n\n const getKey = router.options.getScrollRestorationKey\n if (!getKey) {\n return defaultInlineScrollRestorationScript\n }\n\n const location = router.latestLocation\n const userKey = getKey(location)\n const defaultKey = defaultGetScrollRestorationKey(location)\n\n if (userKey === defaultKey) {\n return defaultInlineScrollRestorationScript\n }\n\n return getScrollRestorationScript({\n storageKey,\n key: userKey,\n })\n}\n"],"mappings":";;;;;AAaA,MAAM,uCAAuC,IAAI,kCAAA,QAAgC,IAAI,cAAA,WACnF,KAAK,UAAU,EACb,YAAA,2BAAA,YACD,CAAgD,CAClD,CAAC;AAEF,SAAS,2BACP,SACA;AACA,KAAI,QAAQ,eAAA,iCAA6B,QAAQ,QAAQ,KAAA,EACvD,QAAO;AAGT,QAAO,IAAI,kCAAA,QAAgC,IAAI,cAAA,WAAW,KAAK,UAAU,QAAQ,CAAC,CAAC;;AAGrF,SAAgB,oCAAoC,QAAmB;AACrE,KACE,OAAO,OAAO,QAAQ,sBAAsB,cAC5C,CAAC,OAAO,QAAQ,kBAAkB,EAAE,UAAU,OAAO,gBAAgB,CAAC,CAEtE,QAAO;CAGT,MAAM,SAAS,OAAO,QAAQ;AAC9B,KAAI,CAAC,OACH,QAAO;CAGT,MAAM,WAAW,OAAO;CACxB,MAAM,UAAU,OAAO,SAAS;AAGhC,KAAI,YAFe,2BAAA,+BAA+B,SAAS,CAGzD,QAAO;AAGT,QAAO,2BAA2B;EAChC,YAAA,2BAAA;EACA,KAAK;EACN,CAAC"}
@@ -1,40 +1,31 @@
1
- const require_utils = require("./utils.cjs");
1
+ const require_router = require("./router.cjs");
2
2
  let _tanstack_router_core_isServer = require("@tanstack/router-core/isServer");
3
3
  //#region src/scroll-restoration.ts
4
4
  function getSafeSessionStorage() {
5
5
  try {
6
- return typeof window !== "undefined" && typeof window.sessionStorage === "object" ? window.sessionStorage : void 0;
6
+ return sessionStorage;
7
7
  } catch {
8
8
  return;
9
9
  }
10
10
  }
11
11
  const storageKey = "tsr-scroll-restoration-v1_3";
12
+ const safeSessionStorage = getSafeSessionStorage();
12
13
  function createScrollRestorationCache() {
13
- const safeSessionStorage = getSafeSessionStorage();
14
- if (!safeSessionStorage) return null;
15
- let state = {};
16
14
  try {
17
- const parsed = JSON.parse(safeSessionStorage.getItem("tsr-scroll-restoration-v1_3") || "{}");
18
- if (require_utils.isPlainObject(parsed)) state = parsed;
19
- } catch {}
20
- const persist = () => {
21
- try {
22
- safeSessionStorage.setItem(storageKey, JSON.stringify(state));
23
- } catch {
24
- if (process.env.NODE_ENV !== "production") console.warn("[ts-router] Could not persist scroll restoration state to sessionStorage.");
25
- }
26
- };
27
- return {
28
- get state() {
29
- return state;
30
- },
31
- set: (updater) => {
32
- state = require_utils.functionalUpdate(updater, state) || state;
33
- },
34
- persist
35
- };
15
+ return JSON.parse(safeSessionStorage?.getItem("tsr-scroll-restoration-v1_3") || "{}");
16
+ } catch {
17
+ return {};
18
+ }
36
19
  }
37
- const scrollRestorationCache = createScrollRestorationCache();
20
+ function persistScrollRestorationCache() {
21
+ try {
22
+ safeSessionStorage?.setItem(storageKey, JSON.stringify(scrollRestorationCache));
23
+ } catch {
24
+ if (process.env.NODE_ENV !== "production") console.warn("[ts-router] Could not persist scroll restoration state to sessionStorage.");
25
+ }
26
+ }
27
+ const scrollRestorationCache = /* @__PURE__ */ createScrollRestorationCache();
28
+ const scrollRestorationIdAttribute = "data-scroll-restoration-id";
38
29
  /**
39
30
  * The default `getKey` function for `useScrollRestoration`.
40
31
  * It returns the `key` from the location state or the `href` of the location.
@@ -44,147 +35,162 @@ const scrollRestorationCache = createScrollRestorationCache();
44
35
  const defaultGetScrollRestorationKey = (location) => {
45
36
  return location.state.__TSR_key || location.href;
46
37
  };
47
- function getCssSelector(el) {
48
- const path = [];
38
+ function getScrollRestorationSelector(element) {
39
+ const attrId = element.getAttribute(scrollRestorationIdAttribute);
40
+ if (attrId) return `[${scrollRestorationIdAttribute}="${attrId}"]`;
41
+ let selector = "";
42
+ let el = element;
49
43
  let parent;
50
44
  while (parent = el.parentNode) {
51
- path.push(`${el.tagName}:nth-child(${Array.prototype.indexOf.call(parent.children, el) + 1})`);
45
+ let index = 1;
46
+ let sibling = el;
47
+ while (sibling = sibling.previousElementSibling) index++;
48
+ const part = `${el.localName}:nth-child(${index})`;
49
+ selector = selector ? `${part} > ${selector}` : part;
52
50
  el = parent;
53
51
  }
54
- return `${path.reverse().join(" > ")}`.toLowerCase();
52
+ return selector;
55
53
  }
56
54
  function getElementScrollRestorationEntry(router, options) {
57
- const restoreKey = (options.getKey || defaultGetScrollRestorationKey)(router.latestLocation);
58
- if (options.id) return scrollRestorationCache?.state[restoreKey]?.[`[${scrollRestorationIdAttribute}="${options.id}"]`];
55
+ const entries = scrollRestorationCache[(options.getKey || defaultGetScrollRestorationKey)(router.latestLocation)];
56
+ if (!entries) return;
57
+ if (options.id) return entries[`[${scrollRestorationIdAttribute}="${options.id}"]`];
59
58
  const element = options.getElement?.();
60
59
  if (!element) return;
61
- return scrollRestorationCache?.state[restoreKey]?.[element instanceof Window ? windowScrollTarget : getCssSelector(element)];
60
+ return entries[element === window ? windowScrollTarget : getScrollRestorationSelector(element)];
62
61
  }
63
62
  let ignoreScroll = false;
64
63
  const windowScrollTarget = "window";
65
- const scrollRestorationIdAttribute = "data-scroll-restoration-id";
64
+ function getElement(selector) {
65
+ try {
66
+ return typeof selector === "function" ? selector() : document.querySelector(selector);
67
+ } catch {}
68
+ }
69
+ function getScrollToTopElements(scrollToTopSelectors) {
70
+ const elements = [];
71
+ for (const selector of scrollToTopSelectors) {
72
+ if (selector === windowScrollTarget) continue;
73
+ const element = getElement(selector);
74
+ if (element) elements.push(element);
75
+ }
76
+ return elements;
77
+ }
66
78
  function setupScrollRestoration(router, force) {
67
- if (!scrollRestorationCache && !(_tanstack_router_core_isServer.isServer ?? router.isServer)) return;
68
- const cache = scrollRestorationCache;
69
- if (force ?? router.options.scrollRestoration ?? false) router.isScrollRestoring = true;
70
- if ((_tanstack_router_core_isServer.isServer ?? router.isServer) || router.isScrollRestorationSetup || !cache) return;
79
+ if (force ?? router.options.scrollRestoration) router.isScrollRestoring = true;
80
+ if ((_tanstack_router_core_isServer.isServer ?? router.isServer) || router.isScrollRestorationSetup) return;
71
81
  router.isScrollRestorationSetup = true;
72
82
  ignoreScroll = false;
73
83
  const getKey = router.options.getScrollRestorationKey || defaultGetScrollRestorationKey;
74
84
  const trackedScrollEntries = /* @__PURE__ */ new Map();
75
- window.history.scrollRestoration = "manual";
85
+ const setTrackedScrollEntry = (target, scrollX, scrollY) => {
86
+ const entry = trackedScrollEntries.get(target) || {};
87
+ entry.scrollX = scrollX;
88
+ entry.scrollY = scrollY;
89
+ trackedScrollEntries.set(target, entry);
90
+ };
91
+ history.scrollRestoration = "manual";
76
92
  const onScroll = (event) => {
77
93
  if (ignoreScroll || !router.isScrollRestoring) return;
78
- if (event.target === document || event.target === window) trackedScrollEntries.set(windowScrollTarget, {
79
- scrollX: window.scrollX || 0,
80
- scrollY: window.scrollY || 0
81
- });
94
+ if (event.target === document) setTrackedScrollEntry(windowScrollTarget, scrollX, scrollY);
82
95
  else {
83
96
  const target = event.target;
84
- trackedScrollEntries.set(target, {
85
- scrollX: target.scrollLeft || 0,
86
- scrollY: target.scrollTop || 0
87
- });
97
+ setTrackedScrollEntry(target, target.scrollLeft, target.scrollTop);
88
98
  }
89
99
  };
90
100
  const snapshotCurrentScrollTargets = (restoreKey) => {
91
- if (!router.isScrollRestoring || !restoreKey || trackedScrollEntries.size === 0 || !cache) return;
92
- const keyEntry = cache.state[restoreKey] ||= {};
93
- for (const [target, position] of trackedScrollEntries) {
94
- let selector;
95
- if (target === windowScrollTarget) selector = windowScrollTarget;
96
- else if (target.isConnected) {
97
- const attrId = target.getAttribute(scrollRestorationIdAttribute);
98
- selector = attrId ? `[${scrollRestorationIdAttribute}="${attrId}"]` : getCssSelector(target);
99
- }
100
- if (!selector) continue;
101
- keyEntry[selector] = position;
102
- }
101
+ if (!router.isScrollRestoring) return;
102
+ const keyEntry = scrollRestorationCache[restoreKey] ||= {};
103
+ for (const [target, position] of trackedScrollEntries) if (target === windowScrollTarget) keyEntry[windowScrollTarget] = position;
104
+ else if (target.isConnected) keyEntry[getScrollRestorationSelector(target)] = position;
103
105
  };
104
106
  document.addEventListener("scroll", onScroll, true);
105
107
  router.subscribe("onBeforeLoad", (event) => {
106
- snapshotCurrentScrollTargets(event.fromLocation ? getKey(event.fromLocation) : void 0);
108
+ if (event.fromLocation) snapshotCurrentScrollTargets(getKey(event.fromLocation));
107
109
  trackedScrollEntries.clear();
108
110
  });
109
- window.addEventListener("pagehide", () => {
111
+ addEventListener("pagehide", () => {
110
112
  snapshotCurrentScrollTargets(getKey(router.stores.resolvedLocation.get() ?? router.stores.location.get()));
111
- cache.persist();
113
+ persistScrollRestorationCache();
112
114
  });
113
115
  router.subscribe("onRendered", (event) => {
114
- const cacheKey = getKey(event.toLocation);
115
116
  const behavior = router.options.scrollRestorationBehavior;
116
117
  const scrollToTopSelectors = router.options.scrollToTopSelectors;
118
+ const shouldResetScroll = router.resetNextScroll;
119
+ let scrollToTopElements;
117
120
  trackedScrollEntries.clear();
118
- if (!router.resetNextScroll) {
119
- router.resetNextScroll = true;
120
- return;
121
- }
121
+ if (!shouldResetScroll) router.resetNextScroll = true;
122
122
  if (typeof router.options.scrollRestoration === "function" && !router.options.scrollRestoration({ location: router.latestLocation })) return;
123
+ const cacheKey = getKey(event.toLocation);
124
+ const fromCacheKey = event.fromLocation && getKey(event.fromLocation);
125
+ if (router.isScrollRestoring && fromCacheKey && fromCacheKey !== cacheKey) {
126
+ const fromElementEntries = scrollRestorationCache[fromCacheKey];
127
+ if (fromElementEntries) {
128
+ let toElementEntries = scrollRestorationCache[cacheKey];
129
+ for (const elementSelector in fromElementEntries) {
130
+ if (elementSelector === windowScrollTarget) {
131
+ if (shouldResetScroll) continue;
132
+ } else {
133
+ const element = getElement(elementSelector);
134
+ if (!element) continue;
135
+ if (shouldResetScroll && scrollToTopSelectors) {
136
+ scrollToTopElements ??= getScrollToTopElements(scrollToTopSelectors);
137
+ if (scrollToTopElements.includes(element)) continue;
138
+ }
139
+ }
140
+ if (!toElementEntries) toElementEntries = scrollRestorationCache[cacheKey] = {};
141
+ toElementEntries[elementSelector] ??= fromElementEntries[elementSelector];
142
+ }
143
+ }
144
+ }
145
+ if (!shouldResetScroll) return;
123
146
  ignoreScroll = true;
124
147
  try {
125
- const elementEntries = router.isScrollRestoring ? cache.state[cacheKey] : void 0;
126
- let restored = false;
148
+ const hash = event.toLocation.hash;
149
+ const hashScrollIntoViewOptions = event.toLocation.state.__hashScrollIntoViewOptions ?? true;
150
+ const action = require_router.locationHistoryActions.get(event.toLocation);
151
+ const skipWindowRestore = hash && hashScrollIntoViewOptions && (action === "PUSH" || action === "REPLACE");
152
+ const elementEntries = router.isScrollRestoring ? scrollRestorationCache[cacheKey] : void 0;
153
+ let windowRestored = false;
127
154
  if (elementEntries) for (const elementSelector in elementEntries) {
128
- const entry = elementEntries[elementSelector];
129
- if (!require_utils.isPlainObject(entry)) continue;
130
- const { scrollX, scrollY } = entry;
131
- if (!Number.isFinite(scrollX) || !Number.isFinite(scrollY)) continue;
155
+ const { scrollX, scrollY } = elementEntries[elementSelector];
132
156
  if (elementSelector === windowScrollTarget) {
133
- window.scrollTo({
157
+ if (skipWindowRestore) continue;
158
+ scrollTo({
134
159
  top: scrollY,
135
160
  left: scrollX,
136
161
  behavior
137
162
  });
138
- restored = true;
139
- } else if (elementSelector) {
140
- let element;
141
- try {
142
- element = document.querySelector(elementSelector);
143
- } catch {
144
- continue;
145
- }
163
+ windowRestored = true;
164
+ } else {
165
+ const element = getElement(elementSelector);
146
166
  if (element) {
147
167
  element.scrollLeft = scrollX;
148
168
  element.scrollTop = scrollY;
149
- restored = true;
150
169
  }
151
170
  }
152
171
  }
153
- if (!restored) {
154
- const hash = router.history.location.hash.slice(1);
155
- if (hash) {
156
- const hashScrollIntoViewOptions = window.history.state?.__hashScrollIntoViewOptions ?? true;
157
- if (hashScrollIntoViewOptions) {
158
- const el = document.getElementById(hash);
159
- if (el) el.scrollIntoView(hashScrollIntoViewOptions);
160
- }
161
- } else {
162
- const scrollOptions = {
163
- top: 0,
164
- left: 0,
165
- behavior
166
- };
167
- window.scrollTo(scrollOptions);
168
- if (scrollToTopSelectors) for (const selector of scrollToTopSelectors) {
169
- if (selector === windowScrollTarget) continue;
170
- const element = typeof selector === "function" ? selector() : document.querySelector(selector);
171
- if (element) element.scrollTo(scrollOptions);
172
- }
172
+ if (!windowRestored) if (hash) {
173
+ if (hashScrollIntoViewOptions) document.getElementById(hash)?.scrollIntoView(hashScrollIntoViewOptions);
174
+ } else {
175
+ const scrollOptions = {
176
+ top: 0,
177
+ left: 0,
178
+ behavior
179
+ };
180
+ scrollTo(scrollOptions);
181
+ if (scrollToTopSelectors) {
182
+ scrollToTopElements ??= getScrollToTopElements(scrollToTopSelectors);
183
+ for (const element of scrollToTopElements) element.scrollTo(scrollOptions);
173
184
  }
174
185
  }
175
186
  } finally {
176
187
  ignoreScroll = false;
177
188
  }
178
- if (router.isScrollRestoring) cache.set((state) => {
179
- state[cacheKey] ||= {};
180
- return state;
181
- });
182
189
  });
183
190
  }
184
191
  //#endregion
185
192
  exports.defaultGetScrollRestorationKey = defaultGetScrollRestorationKey;
186
193
  exports.getElementScrollRestorationEntry = getElementScrollRestorationEntry;
187
- exports.scrollRestorationCache = scrollRestorationCache;
188
194
  exports.setupScrollRestoration = setupScrollRestoration;
189
195
  exports.storageKey = storageKey;
190
196
 
@@ -1 +1 @@
1
- {"version":3,"file":"scroll-restoration.cjs","names":[],"sources":["../../src/scroll-restoration.ts"],"sourcesContent":["import { isServer } from '@tanstack/router-core/isServer'\nimport { functionalUpdate, isPlainObject } from './utils'\nimport type { AnyRouter } from './router'\nimport type { ParsedLocation } from './location'\nimport type { NonNullableUpdater } from './utils'\n\nexport type ScrollRestorationEntry = { scrollX: number; scrollY: number }\n\ntype ScrollRestorationByElement = Record<string, ScrollRestorationEntry>\n\ntype ScrollRestorationByKey = Record<string, ScrollRestorationByElement>\n\ntype ScrollRestorationCache = {\n readonly state: ScrollRestorationByKey\n set: (updater: NonNullableUpdater<ScrollRestorationByKey>) => void\n persist: () => void\n}\n\nexport type ScrollRestorationOptions = {\n getKey?: (location: ParsedLocation) => string\n scrollBehavior?: ScrollToOptions['behavior']\n}\n\nfunction getSafeSessionStorage() {\n try {\n return typeof window !== 'undefined' &&\n typeof window.sessionStorage === 'object'\n ? window.sessionStorage\n : undefined\n } catch {\n // silent\n return undefined\n }\n}\n\n// SessionStorage key used to store scroll positions across navigations.\nexport const storageKey = 'tsr-scroll-restoration-v1_3'\n\nfunction createScrollRestorationCache(): ScrollRestorationCache | null {\n const safeSessionStorage = getSafeSessionStorage()\n if (!safeSessionStorage) {\n return null\n }\n\n let state: ScrollRestorationByKey = {}\n\n try {\n const parsed = JSON.parse(safeSessionStorage.getItem(storageKey) || '{}')\n if (isPlainObject(parsed)) {\n state = parsed as ScrollRestorationByKey\n }\n } catch {\n // ignore invalid session storage payloads\n }\n\n const persist = () => {\n try {\n safeSessionStorage.setItem(storageKey, JSON.stringify(state))\n } catch {\n if (process.env.NODE_ENV !== 'production') {\n console.warn(\n '[ts-router] Could not persist scroll restoration state to sessionStorage.',\n )\n }\n }\n }\n\n return {\n get state() {\n return state\n },\n set: (updater) => {\n state = functionalUpdate(updater, state) || state\n },\n persist,\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 */\nexport const defaultGetScrollRestorationKey = (location: ParsedLocation) => {\n return location.state.__TSR_key! || location.href\n}\n\nfunction 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\nexport function getElementScrollRestorationEntry(\n router: AnyRouter,\n options: (\n | {\n id: string\n getElement?: () => Window | Element | undefined | null\n }\n | {\n id?: string\n getElement: () => Window | Element | undefined | null\n }\n ) & {\n getKey?: (location: ParsedLocation) => string\n },\n): ScrollRestorationEntry | undefined {\n const getKey = options.getKey || defaultGetScrollRestorationKey\n const restoreKey = getKey(router.latestLocation)\n\n if (options.id) {\n return scrollRestorationCache?.state[restoreKey]?.[\n `[${scrollRestorationIdAttribute}=\"${options.id}\"]`\n ]\n }\n\n const element = options.getElement?.()\n if (!element) {\n return\n }\n\n return scrollRestorationCache?.state[restoreKey]?.[\n element instanceof Window ? windowScrollTarget : getCssSelector(element)\n ]\n}\n\nlet ignoreScroll = false\nconst windowScrollTarget = 'window'\nconst scrollRestorationIdAttribute = 'data-scroll-restoration-id'\ntype ScrollTarget = typeof windowScrollTarget | Element\n\nexport function setupScrollRestoration(router: AnyRouter, force?: boolean) {\n if (!scrollRestorationCache && !(isServer ?? router.isServer)) {\n return\n }\n\n const cache = scrollRestorationCache\n\n const shouldScrollRestoration =\n force ?? router.options.scrollRestoration ?? false\n\n if (shouldScrollRestoration) {\n router.isScrollRestoring = true\n }\n\n if (\n (isServer ?? router.isServer) ||\n router.isScrollRestorationSetup ||\n !cache\n ) {\n return\n }\n\n router.isScrollRestorationSetup = true\n ignoreScroll = false\n\n const getKey =\n router.options.getScrollRestorationKey || defaultGetScrollRestorationKey\n const trackedScrollEntries = new Map<ScrollTarget, ScrollRestorationEntry>()\n\n window.history.scrollRestoration = 'manual'\n\n const onScroll = (event: Event) => {\n if (ignoreScroll || !router.isScrollRestoring) {\n return\n }\n\n if (event.target === document || event.target === window) {\n trackedScrollEntries.set(windowScrollTarget, {\n scrollX: window.scrollX || 0,\n scrollY: window.scrollY || 0,\n })\n } else {\n const target = event.target as Element\n trackedScrollEntries.set(target, {\n scrollX: target.scrollLeft || 0,\n scrollY: target.scrollTop || 0,\n })\n }\n }\n\n // Snapshot the current page's tracked scroll targets before navigation or unload.\n const snapshotCurrentScrollTargets = (restoreKey?: string) => {\n if (\n !router.isScrollRestoring ||\n !restoreKey ||\n trackedScrollEntries.size === 0 ||\n !cache\n ) {\n return\n }\n\n const keyEntry = (cache.state[restoreKey] ||=\n {} as ScrollRestorationByElement)\n\n for (const [target, position] of trackedScrollEntries) {\n let selector: string | undefined\n\n if (target === windowScrollTarget) {\n selector = windowScrollTarget\n } else if (target.isConnected) {\n const attrId = target.getAttribute(scrollRestorationIdAttribute)\n selector = attrId\n ? `[${scrollRestorationIdAttribute}=\"${attrId}\"]`\n : getCssSelector(target)\n }\n\n if (!selector) {\n continue\n }\n\n keyEntry[selector] = position\n }\n }\n\n document.addEventListener('scroll', onScroll, true)\n router.subscribe('onBeforeLoad', (event) => {\n snapshotCurrentScrollTargets(\n event.fromLocation ? getKey(event.fromLocation) : undefined,\n )\n trackedScrollEntries.clear()\n })\n window.addEventListener('pagehide', () => {\n snapshotCurrentScrollTargets(\n getKey(\n router.stores.resolvedLocation.get() ?? router.stores.location.get(),\n ),\n )\n cache.persist()\n })\n\n // Restore destination scroll after the new route has rendered.\n router.subscribe('onRendered', (event) => {\n const cacheKey = getKey(event.toLocation)\n const behavior = router.options.scrollRestorationBehavior\n const scrollToTopSelectors = router.options.scrollToTopSelectors\n trackedScrollEntries.clear()\n\n if (!router.resetNextScroll) {\n router.resetNextScroll = true\n return\n }\n\n if (\n typeof router.options.scrollRestoration === 'function' &&\n !router.options.scrollRestoration({ location: router.latestLocation })\n ) {\n return\n }\n\n ignoreScroll = true\n\n try {\n const elementEntries = router.isScrollRestoring\n ? cache.state[cacheKey]\n : undefined\n let restored = false\n\n if (elementEntries) {\n for (const elementSelector in elementEntries) {\n const entry = elementEntries[elementSelector]\n\n if (!isPlainObject(entry)) {\n continue\n }\n\n const { scrollX, scrollY } = entry as {\n scrollX?: unknown\n scrollY?: unknown\n }\n\n if (!Number.isFinite(scrollX) || !Number.isFinite(scrollY)) {\n continue\n }\n\n if (elementSelector === windowScrollTarget) {\n window.scrollTo({\n top: scrollY as number,\n left: scrollX as number,\n behavior,\n })\n restored = true\n } else if (elementSelector) {\n let element\n\n try {\n element = document.querySelector(elementSelector)\n } catch {\n continue\n }\n\n if (element) {\n element.scrollLeft = scrollX as number\n element.scrollTop = scrollY as number\n restored = true\n }\n }\n }\n }\n\n if (!restored) {\n const hash = router.history.location.hash.slice(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 } else {\n const scrollOptions = {\n top: 0,\n left: 0,\n behavior,\n }\n\n window.scrollTo(scrollOptions)\n if (scrollToTopSelectors) {\n for (const selector of scrollToTopSelectors) {\n if (selector === windowScrollTarget) continue\n const element =\n typeof selector === 'function'\n ? selector()\n : document.querySelector(selector)\n if (element) {\n element.scrollTo(scrollOptions)\n }\n }\n }\n }\n }\n } finally {\n ignoreScroll = false\n }\n\n if (router.isScrollRestoring) {\n cache.set((state) => {\n state[cacheKey] ||= {} as ScrollRestorationByElement\n return state\n })\n }\n })\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"scroll-restoration.cjs","names":[],"sources":["../../src/scroll-restoration.ts"],"sourcesContent":["import { isServer } from '@tanstack/router-core/isServer'\nimport { locationHistoryActions } from './router'\nimport type { AnyRouter } from './router'\nimport type { ParsedLocation } from './location'\n\nexport type ScrollRestorationEntry = { scrollX: number; scrollY: number }\n\ntype ScrollRestorationByElement = Record<string, ScrollRestorationEntry>\n\ntype ScrollRestorationByKey = Record<string, ScrollRestorationByElement>\n\nexport type ScrollRestorationOptions = {\n getKey?: (location: ParsedLocation) => string\n scrollBehavior?: ScrollToOptions['behavior']\n}\n\nfunction getSafeSessionStorage() {\n try {\n // Accessing sessionStorage itself can throw SecurityError in locked-down\n // contexts, e.g. sandboxed/opaque origins or blocked storage policies.\n return sessionStorage\n } catch {\n return\n }\n}\n\n// SessionStorage key used to store scroll positions across navigations.\nexport const storageKey = 'tsr-scroll-restoration-v1_3'\nconst safeSessionStorage = getSafeSessionStorage()\n\nfunction createScrollRestorationCache() {\n try {\n return JSON.parse(\n safeSessionStorage?.getItem(storageKey) || '{}',\n ) as ScrollRestorationByKey\n } catch {\n // ignore invalid session storage payloads\n return {}\n }\n}\n\nfunction persistScrollRestorationCache() {\n try {\n safeSessionStorage?.setItem(\n storageKey,\n JSON.stringify(scrollRestorationCache),\n )\n } catch {\n if (process.env.NODE_ENV !== 'production') {\n console.warn(\n '[ts-router] Could not persist scroll restoration state to sessionStorage.',\n )\n }\n }\n}\n\nconst scrollRestorationCache = /* @__PURE__ */ createScrollRestorationCache()\nconst scrollRestorationIdAttribute = 'data-scroll-restoration-id'\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 */\nexport const defaultGetScrollRestorationKey = (location: ParsedLocation) => {\n return location.state.__TSR_key! || location.href\n}\n\nfunction getScrollRestorationSelector(element: Element): string {\n const attrId = element.getAttribute(scrollRestorationIdAttribute)\n if (attrId) {\n return `[${scrollRestorationIdAttribute}=\"${attrId}\"]`\n }\n\n let selector = ''\n let el: any = element\n let parent: HTMLElement\n\n while ((parent = el.parentNode)) {\n let index = 1\n let sibling = el\n while ((sibling = sibling.previousElementSibling)) {\n index++\n }\n\n const part = `${el.localName}:nth-child(${index})`\n selector = selector ? `${part} > ${selector}` : part\n el = parent\n }\n\n return selector\n}\n\nexport function getElementScrollRestorationEntry(\n router: AnyRouter,\n options: (\n | {\n id: string\n getElement?: () => Window | Element | undefined | null\n }\n | {\n id?: string\n getElement: () => Window | Element | undefined | null\n }\n ) & {\n getKey?: (location: ParsedLocation) => string\n },\n): ScrollRestorationEntry | undefined {\n const getKey = options.getKey || defaultGetScrollRestorationKey\n const restoreKey = getKey(router.latestLocation)\n const entries = scrollRestorationCache[restoreKey]\n\n if (!entries) {\n return\n }\n\n if (options.id) {\n return entries[`[${scrollRestorationIdAttribute}=\"${options.id}\"]`]\n }\n\n const element = options.getElement?.()\n if (!element) {\n return\n }\n\n return entries[\n element === window\n ? windowScrollTarget\n : getScrollRestorationSelector(element as Element)\n ]\n}\n\nlet ignoreScroll = false\nconst windowScrollTarget = 'window'\ntype ScrollTarget = typeof windowScrollTarget | Element\n\nfunction getElement(selector: string | (() => Element | null | undefined)) {\n try {\n return typeof selector === 'function'\n ? selector()\n : document.querySelector(selector)\n } catch {}\n return\n}\n\nfunction getScrollToTopElements(\n scrollToTopSelectors: NonNullable<\n AnyRouter['options']['scrollToTopSelectors']\n >,\n): Array<Element> {\n const elements: Array<Element> = []\n\n for (const selector of scrollToTopSelectors) {\n if (selector === windowScrollTarget) {\n continue\n }\n\n const element = getElement(selector)\n if (element) {\n elements.push(element)\n }\n }\n\n return elements\n}\n\nexport function setupScrollRestoration(router: AnyRouter, force?: boolean) {\n // Keep hash/top scrolling active even when sessionStorage is unavailable.\n\n if (force ?? router.options.scrollRestoration) {\n router.isScrollRestoring = true\n }\n\n if ((isServer ?? router.isServer) || router.isScrollRestorationSetup) {\n return\n }\n\n router.isScrollRestorationSetup = true\n ignoreScroll = false\n\n const getKey =\n router.options.getScrollRestorationKey || defaultGetScrollRestorationKey\n const trackedScrollEntries = new Map<ScrollTarget, ScrollRestorationEntry>()\n const setTrackedScrollEntry = (\n target: ScrollTarget,\n scrollX: number,\n scrollY: number,\n ) => {\n const entry =\n trackedScrollEntries.get(target) || ({} as ScrollRestorationEntry)\n entry.scrollX = scrollX\n entry.scrollY = scrollY\n trackedScrollEntries.set(target, entry)\n }\n\n history.scrollRestoration = 'manual'\n\n const onScroll = (event: Event) => {\n if (ignoreScroll || !router.isScrollRestoring) {\n return\n }\n\n if (event.target === document) {\n setTrackedScrollEntry(windowScrollTarget, scrollX, scrollY)\n } else {\n const target = event.target as Element\n setTrackedScrollEntry(target, target.scrollLeft, target.scrollTop)\n }\n }\n\n // Snapshot the current page's tracked scroll targets before navigation or unload.\n const snapshotCurrentScrollTargets = (restoreKey: string) => {\n if (!router.isScrollRestoring) {\n return\n }\n\n const keyEntry = (scrollRestorationCache[restoreKey] ||=\n {} as ScrollRestorationByElement)\n\n for (const [target, position] of trackedScrollEntries) {\n if (target === windowScrollTarget) {\n keyEntry[windowScrollTarget] = position\n } else if (target.isConnected) {\n keyEntry[getScrollRestorationSelector(target)] = position\n }\n }\n }\n\n document.addEventListener('scroll', onScroll, true)\n router.subscribe('onBeforeLoad', (event) => {\n if (event.fromLocation) {\n snapshotCurrentScrollTargets(getKey(event.fromLocation))\n }\n trackedScrollEntries.clear()\n })\n addEventListener('pagehide', () => {\n snapshotCurrentScrollTargets(\n getKey(\n router.stores.resolvedLocation.get() ?? router.stores.location.get(),\n ),\n )\n persistScrollRestorationCache()\n })\n\n // Restore destination scroll after the new route has rendered.\n router.subscribe('onRendered', (event) => {\n const behavior = router.options.scrollRestorationBehavior\n const scrollToTopSelectors = router.options.scrollToTopSelectors\n const shouldResetScroll = router.resetNextScroll\n let scrollToTopElements: Array<Element> | undefined\n trackedScrollEntries.clear()\n\n if (!shouldResetScroll) {\n router.resetNextScroll = true\n }\n\n if (\n typeof router.options.scrollRestoration === 'function' &&\n !router.options.scrollRestoration({ location: router.latestLocation })\n ) {\n return\n }\n\n const cacheKey = getKey(event.toLocation)\n const fromCacheKey = event.fromLocation && getKey(event.fromLocation)\n\n if (router.isScrollRestoring && fromCacheKey && fromCacheKey !== cacheKey) {\n const fromElementEntries = scrollRestorationCache[fromCacheKey]\n\n if (fromElementEntries) {\n let toElementEntries = scrollRestorationCache[cacheKey]\n\n for (const elementSelector in fromElementEntries) {\n if (elementSelector === windowScrollTarget) {\n if (shouldResetScroll) {\n continue\n }\n } else {\n const element = getElement(elementSelector)\n if (!element) {\n continue\n }\n\n if (shouldResetScroll && scrollToTopSelectors) {\n scrollToTopElements ??=\n getScrollToTopElements(scrollToTopSelectors)\n if (scrollToTopElements.includes(element)) {\n continue\n }\n }\n }\n\n if (!toElementEntries) {\n toElementEntries = scrollRestorationCache[cacheKey] =\n {} as ScrollRestorationByElement\n }\n\n toElementEntries[elementSelector] ??=\n fromElementEntries[elementSelector]!\n }\n }\n }\n\n if (!shouldResetScroll) {\n return\n }\n\n ignoreScroll = true\n\n try {\n const hash = event.toLocation.hash\n const hashScrollIntoViewOptions =\n event.toLocation.state.__hashScrollIntoViewOptions ?? true\n const action = locationHistoryActions.get(event.toLocation)\n const skipWindowRestore =\n hash &&\n hashScrollIntoViewOptions &&\n (action === 'PUSH' || action === 'REPLACE')\n\n const elementEntries = router.isScrollRestoring\n ? scrollRestorationCache[cacheKey]\n : undefined\n let windowRestored = false\n\n if (elementEntries) {\n for (const elementSelector in elementEntries) {\n const { scrollX, scrollY } = elementEntries[elementSelector]!\n\n if (elementSelector === windowScrollTarget) {\n if (skipWindowRestore) {\n continue\n }\n\n scrollTo({\n top: scrollY,\n left: scrollX,\n behavior,\n })\n windowRestored = true\n } else {\n const element = getElement(elementSelector)\n if (element) {\n element.scrollLeft = scrollX\n element.scrollTop = scrollY\n }\n }\n }\n }\n\n if (!windowRestored) {\n if (hash) {\n if (hashScrollIntoViewOptions) {\n document\n .getElementById(hash)\n ?.scrollIntoView(hashScrollIntoViewOptions)\n }\n } else {\n const scrollOptions = {\n top: 0,\n left: 0,\n behavior,\n }\n\n scrollTo(scrollOptions)\n if (scrollToTopSelectors) {\n scrollToTopElements ??= getScrollToTopElements(scrollToTopSelectors)\n for (const element of scrollToTopElements) {\n element.scrollTo(scrollOptions)\n }\n }\n }\n }\n } finally {\n ignoreScroll = false\n }\n })\n}\n"],"mappings":";;;AAgBA,SAAS,wBAAwB;AAC/B,KAAI;AAGF,SAAO;SACD;AACN;;;AAKJ,MAAa,aAAa;AAC1B,MAAM,qBAAqB,uBAAuB;AAElD,SAAS,+BAA+B;AACtC,KAAI;AACF,SAAO,KAAK,MACV,oBAAoB,QAAA,8BAAmB,IAAI,KAC5C;SACK;AAEN,SAAO,EAAE;;;AAIb,SAAS,gCAAgC;AACvC,KAAI;AACF,sBAAoB,QAClB,YACA,KAAK,UAAU,uBAAuB,CACvC;SACK;AACN,MAAA,QAAA,IAAA,aAA6B,aAC3B,SAAQ,KACN,4EACD;;;AAKP,MAAM,yBAAyC,8CAA8B;AAC7E,MAAM,+BAA+B;;;;;;;AAQrC,MAAa,kCAAkC,aAA6B;AAC1E,QAAO,SAAS,MAAM,aAAc,SAAS;;AAG/C,SAAS,6BAA6B,SAA0B;CAC9D,MAAM,SAAS,QAAQ,aAAa,6BAA6B;AACjE,KAAI,OACF,QAAO,IAAI,6BAA6B,IAAI,OAAO;CAGrD,IAAI,WAAW;CACf,IAAI,KAAU;CACd,IAAI;AAEJ,QAAQ,SAAS,GAAG,YAAa;EAC/B,IAAI,QAAQ;EACZ,IAAI,UAAU;AACd,SAAQ,UAAU,QAAQ,uBACxB;EAGF,MAAM,OAAO,GAAG,GAAG,UAAU,aAAa,MAAM;AAChD,aAAW,WAAW,GAAG,KAAK,KAAK,aAAa;AAChD,OAAK;;AAGP,QAAO;;AAGT,SAAgB,iCACd,QACA,SAYoC;CAGpC,MAAM,UAAU,wBAFD,QAAQ,UAAU,gCACP,OAAO,eAAe;AAGhD,KAAI,CAAC,QACH;AAGF,KAAI,QAAQ,GACV,QAAO,QAAQ,IAAI,6BAA6B,IAAI,QAAQ,GAAG;CAGjE,MAAM,UAAU,QAAQ,cAAc;AACtC,KAAI,CAAC,QACH;AAGF,QAAO,QACL,YAAY,SACR,qBACA,6BAA6B,QAAmB;;AAIxD,IAAI,eAAe;AACnB,MAAM,qBAAqB;AAG3B,SAAS,WAAW,UAAuD;AACzE,KAAI;AACF,SAAO,OAAO,aAAa,aACvB,UAAU,GACV,SAAS,cAAc,SAAS;SAC9B;;AAIV,SAAS,uBACP,sBAGgB;CAChB,MAAM,WAA2B,EAAE;AAEnC,MAAK,MAAM,YAAY,sBAAsB;AAC3C,MAAI,aAAa,mBACf;EAGF,MAAM,UAAU,WAAW,SAAS;AACpC,MAAI,QACF,UAAS,KAAK,QAAQ;;AAI1B,QAAO;;AAGT,SAAgB,uBAAuB,QAAmB,OAAiB;AAGzE,KAAI,SAAS,OAAO,QAAQ,kBAC1B,QAAO,oBAAoB;AAG7B,MAAK,+BAAA,YAAY,OAAO,aAAa,OAAO,yBAC1C;AAGF,QAAO,2BAA2B;AAClC,gBAAe;CAEf,MAAM,SACJ,OAAO,QAAQ,2BAA2B;CAC5C,MAAM,uCAAuB,IAAI,KAA2C;CAC5E,MAAM,yBACJ,QACA,SACA,YACG;EACH,MAAM,QACJ,qBAAqB,IAAI,OAAO,IAAK,EAAE;AACzC,QAAM,UAAU;AAChB,QAAM,UAAU;AAChB,uBAAqB,IAAI,QAAQ,MAAM;;AAGzC,SAAQ,oBAAoB;CAE5B,MAAM,YAAY,UAAiB;AACjC,MAAI,gBAAgB,CAAC,OAAO,kBAC1B;AAGF,MAAI,MAAM,WAAW,SACnB,uBAAsB,oBAAoB,SAAS,QAAQ;OACtD;GACL,MAAM,SAAS,MAAM;AACrB,yBAAsB,QAAQ,OAAO,YAAY,OAAO,UAAU;;;CAKtE,MAAM,gCAAgC,eAAuB;AAC3D,MAAI,CAAC,OAAO,kBACV;EAGF,MAAM,WAAY,uBAAuB,gBACvC,EAAE;AAEJ,OAAK,MAAM,CAAC,QAAQ,aAAa,qBAC/B,KAAI,WAAW,mBACb,UAAS,sBAAsB;WACtB,OAAO,YAChB,UAAS,6BAA6B,OAAO,IAAI;;AAKvD,UAAS,iBAAiB,UAAU,UAAU,KAAK;AACnD,QAAO,UAAU,iBAAiB,UAAU;AAC1C,MAAI,MAAM,aACR,8BAA6B,OAAO,MAAM,aAAa,CAAC;AAE1D,uBAAqB,OAAO;GAC5B;AACF,kBAAiB,kBAAkB;AACjC,+BACE,OACE,OAAO,OAAO,iBAAiB,KAAK,IAAI,OAAO,OAAO,SAAS,KAAK,CACrE,CACF;AACD,iCAA+B;GAC/B;AAGF,QAAO,UAAU,eAAe,UAAU;EACxC,MAAM,WAAW,OAAO,QAAQ;EAChC,MAAM,uBAAuB,OAAO,QAAQ;EAC5C,MAAM,oBAAoB,OAAO;EACjC,IAAI;AACJ,uBAAqB,OAAO;AAE5B,MAAI,CAAC,kBACH,QAAO,kBAAkB;AAG3B,MACE,OAAO,OAAO,QAAQ,sBAAsB,cAC5C,CAAC,OAAO,QAAQ,kBAAkB,EAAE,UAAU,OAAO,gBAAgB,CAAC,CAEtE;EAGF,MAAM,WAAW,OAAO,MAAM,WAAW;EACzC,MAAM,eAAe,MAAM,gBAAgB,OAAO,MAAM,aAAa;AAErE,MAAI,OAAO,qBAAqB,gBAAgB,iBAAiB,UAAU;GACzE,MAAM,qBAAqB,uBAAuB;AAElD,OAAI,oBAAoB;IACtB,IAAI,mBAAmB,uBAAuB;AAE9C,SAAK,MAAM,mBAAmB,oBAAoB;AAChD,SAAI,oBAAoB;UAClB,kBACF;YAEG;MACL,MAAM,UAAU,WAAW,gBAAgB;AAC3C,UAAI,CAAC,QACH;AAGF,UAAI,qBAAqB,sBAAsB;AAC7C,+BACE,uBAAuB,qBAAqB;AAC9C,WAAI,oBAAoB,SAAS,QAAQ,CACvC;;;AAKN,SAAI,CAAC,iBACH,oBAAmB,uBAAuB,YACxC,EAAE;AAGN,sBAAiB,qBACf,mBAAmB;;;;AAK3B,MAAI,CAAC,kBACH;AAGF,iBAAe;AAEf,MAAI;GACF,MAAM,OAAO,MAAM,WAAW;GAC9B,MAAM,4BACJ,MAAM,WAAW,MAAM,+BAA+B;GACxD,MAAM,SAAS,eAAA,uBAAuB,IAAI,MAAM,WAAW;GAC3D,MAAM,oBACJ,QACA,8BACC,WAAW,UAAU,WAAW;GAEnC,MAAM,iBAAiB,OAAO,oBAC1B,uBAAuB,YACvB,KAAA;GACJ,IAAI,iBAAiB;AAErB,OAAI,eACF,MAAK,MAAM,mBAAmB,gBAAgB;IAC5C,MAAM,EAAE,SAAS,YAAY,eAAe;AAE5C,QAAI,oBAAoB,oBAAoB;AAC1C,SAAI,kBACF;AAGF,cAAS;MACP,KAAK;MACL,MAAM;MACN;MACD,CAAC;AACF,sBAAiB;WACZ;KACL,MAAM,UAAU,WAAW,gBAAgB;AAC3C,SAAI,SAAS;AACX,cAAQ,aAAa;AACrB,cAAQ,YAAY;;;;AAM5B,OAAI,CAAC,eACH,KAAI;QACE,0BACF,UACG,eAAe,KAAK,EACnB,eAAe,0BAA0B;UAE1C;IACL,MAAM,gBAAgB;KACpB,KAAK;KACL,MAAM;KACN;KACD;AAED,aAAS,cAAc;AACvB,QAAI,sBAAsB;AACxB,6BAAwB,uBAAuB,qBAAqB;AACpE,UAAK,MAAM,WAAW,oBACpB,SAAQ,SAAS,cAAc;;;YAK/B;AACR,kBAAe;;GAEjB"}
@@ -1,23 +1,14 @@
1
1
  import { AnyRouter } from './router.cjs';
2
2
  import { ParsedLocation } from './location.cjs';
3
- import { NonNullableUpdater } from './utils.cjs';
4
3
  export type ScrollRestorationEntry = {
5
4
  scrollX: number;
6
5
  scrollY: number;
7
6
  };
8
- type ScrollRestorationByElement = Record<string, ScrollRestorationEntry>;
9
- type ScrollRestorationByKey = Record<string, ScrollRestorationByElement>;
10
- type ScrollRestorationCache = {
11
- readonly state: ScrollRestorationByKey;
12
- set: (updater: NonNullableUpdater<ScrollRestorationByKey>) => void;
13
- persist: () => void;
14
- };
15
7
  export type ScrollRestorationOptions = {
16
8
  getKey?: (location: ParsedLocation) => string;
17
9
  scrollBehavior?: ScrollToOptions['behavior'];
18
10
  };
19
11
  export declare const storageKey = "tsr-scroll-restoration-v1_3";
20
- export declare const scrollRestorationCache: ScrollRestorationCache | null;
21
12
  /**
22
13
  * The default `getKey` function for `useScrollRestoration`.
23
14
  * It returns the `key` from the location state or the `href` of the location.
@@ -35,4 +26,3 @@ export declare function getElementScrollRestorationEntry(router: AnyRouter, opti
35
26
  getKey?: (location: ParsedLocation) => string;
36
27
  }): ScrollRestorationEntry | undefined;
37
28
  export declare function setupScrollRestoration(router: AnyRouter, force?: boolean): void;
38
- export {};
@@ -165,19 +165,20 @@ function stripInlinedStylesheetAssets(manifest, routes, matches) {
165
165
  }
166
166
  function attachRouterServerSsrUtils({ router, manifest, getRequestAssets, includeUnmatchedRouteAssets = true }) {
167
167
  router.ssr = { get manifest() {
168
+ if (!manifest) return manifest;
168
169
  const requestAssets = getRequestAssets?.();
169
170
  const inlineCssAsset = getInlineCssAssetForMatches(manifest, router.stores.matches.get());
170
171
  if (!requestAssets?.length && !inlineCssAsset) return manifest;
171
172
  return {
172
173
  ...manifest,
173
174
  routes: {
174
- ...manifest?.routes,
175
+ ...manifest.routes,
175
176
  [require_root.rootRouteId]: {
176
- ...manifest?.routes?.[require_root.rootRouteId],
177
+ ...manifest.routes[require_root.rootRouteId],
177
178
  assets: [
178
179
  ...requestAssets ?? [],
179
180
  ...inlineCssAsset ? [inlineCssAsset] : [],
180
- ...manifest?.routes?.["__root__"]?.assets ?? []
181
+ ...manifest.routes["__root__"]?.assets ?? []
181
182
  ]
182
183
  }
183
184
  }