@tanstack/react-router 1.42.0 → 1.43.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/ScriptOnce.cjs +2 -1
- package/dist/cjs/ScriptOnce.cjs.map +1 -1
- package/dist/cjs/router.cjs +18 -14
- package/dist/cjs/router.cjs.map +1 -1
- package/dist/cjs/router.d.cts +5 -0
- package/dist/cjs/scroll-restoration.cjs.map +1 -1
- package/dist/esm/ScriptOnce.js +2 -1
- package/dist/esm/ScriptOnce.js.map +1 -1
- package/dist/esm/router.d.ts +5 -0
- package/dist/esm/router.js +18 -14
- package/dist/esm/router.js.map +1 -1
- package/dist/esm/scroll-restoration.js.map +1 -1
- package/package.json +1 -1
- package/src/ScriptOnce.tsx +3 -1
- package/src/router.ts +26 -21
- package/src/scroll-restoration.tsx +3 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scroll-restoration.cjs","sources":["../../src/scroll-restoration.tsx"],"sourcesContent":["import * as React from 'react'\
|
|
1
|
+
{"version":3,"file":"scroll-restoration.cjs","sources":["../../src/scroll-restoration.tsx"],"sourcesContent":["import * as React from 'react'\nimport { useRouter } from './useRouter'\nimport { functionalUpdate } from './utils'\nimport type { ParsedLocation } from './location'\nimport type { NonNullableUpdater } from './utils'\n\nconst useLayoutEffect =\n typeof window !== 'undefined' ? React.useLayoutEffect : React.useEffect\n\nconst windowKey = 'window'\nconst delimiter = '___'\n\nlet weakScrolledElements = new WeakSet<any>()\n\ntype CacheValue = Record<string, { scrollX: number; scrollY: number }>\ntype CacheState = {\n cached: CacheValue\n next: CacheValue\n}\n\ntype Cache = {\n state: CacheState\n set: (updater: NonNullableUpdater<CacheState>) => void\n}\n\nconst sessionsStorage = typeof window !== 'undefined' && window.sessionStorage\n\nconst cache: Cache = sessionsStorage\n ? (() => {\n const storageKey = 'tsr-scroll-restoration-v2'\n\n const state: CacheState = JSON.parse(\n window.sessionStorage.getItem(storageKey) || 'null',\n ) || { cached: {}, next: {} }\n\n return {\n state,\n set: (updater) => {\n cache.state = functionalUpdate(updater, cache.state)\n window.sessionStorage.setItem(storageKey, JSON.stringify(cache.state))\n },\n }\n })()\n : (undefined as any)\n\nexport type ScrollRestorationOptions = {\n getKey?: (location: ParsedLocation) => string\n}\n\nconst defaultGetKey = (location: ParsedLocation) => location.state.key!\n\nexport function useScrollRestoration(options?: ScrollRestorationOptions) {\n const router = useRouter()\n\n useLayoutEffect(() => {\n const getKey = options?.getKey || defaultGetKey\n\n const { history } = window\n history.scrollRestoration = 'manual'\n\n const onScroll = (event: Event) => {\n if (weakScrolledElements.has(event.target)) return\n weakScrolledElements.add(event.target)\n\n let elementSelector = ''\n\n if (event.target === document || event.target === window) {\n elementSelector = windowKey\n } else {\n const attrId = (event.target as Element).getAttribute(\n 'data-scroll-restoration-id',\n )\n\n if (attrId) {\n elementSelector = `[data-scroll-restoration-id=\"${attrId}\"]`\n } else {\n elementSelector = getCssSelector(event.target)\n }\n }\n\n if (!cache.state.next[elementSelector]) {\n cache.set((c) => ({\n ...c,\n next: {\n ...c.next,\n [elementSelector]: {\n scrollX: NaN,\n scrollY: NaN,\n },\n },\n }))\n }\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) {\n const restoreKey = getKey(event.fromLocation)\n for (const elementSelector in cache.state.next) {\n const entry = cache.state.next[elementSelector]!\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((c) => {\n const next = { ...c.next }\n delete next[elementSelector]\n\n return {\n ...c,\n next,\n cached: {\n ...c.cached,\n [[restoreKey, elementSelector].join(delimiter)]: entry,\n },\n }\n })\n }\n }\n })\n\n const unsubOnResolved = router.subscribe('onResolved', (event) => {\n if (event.pathChanged) {\n if (!router.resetNextScroll) {\n return\n }\n\n router.resetNextScroll = true\n\n const restoreKey = getKey(event.toLocation)\n let windowRestored = false\n\n for (const cacheKey in cache.state.cached) {\n const entry = cache.state.cached[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 cache.set((c) => ({ ...c, next: {} }))\n weakScrolledElements = new WeakSet<any>()\n }\n })\n\n return () => {\n document.removeEventListener('scroll', onScroll)\n unsubOnBeforeLoad()\n unsubOnResolved()\n }\n }, [options?.getKey, router])\n}\n\nexport function ScrollRestoration(props: ScrollRestorationOptions) {\n useScrollRestoration(props)\n return null\n}\n\nexport function useElementScrollRestoration(\n options: (\n | {\n id: string\n getElement?: () => Element | undefined | null\n }\n | {\n id?: string\n getElement: () => Element | undefined | null\n }\n ) & {\n getKey?: (location: ParsedLocation) => string\n },\n) {\n const router = useRouter()\n const getKey = options.getKey || defaultGetKey\n\n let elementSelector = ''\n\n if (options.id) {\n elementSelector = `[data-scroll-restoration-id=\"${options.id}\"]`\n } else {\n const element = options.getElement?.()\n if (!element) {\n return\n }\n elementSelector = getCssSelector(element)\n }\n\n const restoreKey = getKey(router.latestLocation)\n const cacheKey = [restoreKey, elementSelector].join(delimiter)\n return cache.state.cached[cacheKey]\n}\n\nfunction getCssSelector(el: any): string {\n const path = []\n let 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"],"names":["React","functionalUpdate","useRouter"],"mappings":"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"}
|
package/dist/esm/ScriptOnce.js
CHANGED
|
@@ -16,7 +16,8 @@ function ScriptOnce({
|
|
|
16
16
|
dangerouslySetInnerHTML: {
|
|
17
17
|
__html: [
|
|
18
18
|
children,
|
|
19
|
-
(log ?? true) && process.env.NODE_ENV === "development" ? `console.info(
|
|
19
|
+
(log ?? true) && process.env.NODE_ENV === "development" ? `console.info(\`Injected From Server:
|
|
20
|
+
${children}\`)` : ""
|
|
20
21
|
].filter(Boolean).join("\n")
|
|
21
22
|
}
|
|
22
23
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ScriptOnce.js","sources":["../../src/ScriptOnce.tsx"],"sourcesContent":["
|
|
1
|
+
{"version":3,"file":"ScriptOnce.js","sources":["../../src/ScriptOnce.tsx"],"sourcesContent":["/* eslint-disable @eslint-react/dom/no-dangerously-set-innerhtml */\nexport function ScriptOnce({\n className,\n children,\n log,\n ...rest\n}: { children: string; log?: boolean } & React.HTMLProps<HTMLScriptElement>) {\n if (typeof document !== 'undefined') {\n return null\n }\n\n return (\n <script\n {...rest}\n className={`tsr-once ${className || ''}`}\n dangerouslySetInnerHTML={{\n __html: [\n children,\n (log ?? true) && process.env.NODE_ENV === 'development'\n ? `console.info(\\`Injected From Server:\n${children}\\`)`\n : '',\n ]\n .filter(Boolean)\n .join('\\n'),\n }}\n />\n )\n}\n"],"names":[],"mappings":";AACO,SAAS,WAAW;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAA6E;AACvE,MAAA,OAAO,aAAa,aAAa;AAC5B,WAAA;AAAA,EACT;AAGE,SAAA;AAAA,IAAC;AAAA,IAAA;AAAA,MACE,GAAG;AAAA,MACJ,WAAW,YAAY,aAAa,EAAE;AAAA,MACtC,yBAAyB;AAAA,QACvB,QAAQ;AAAA,UACN;AAAA,WACC,OAAO,SAAS,QAAQ,IAAI,aAAa,gBACtC;AAAA,EACZ,QAAQ,QACI;AAAA,QAEH,EAAA,OAAO,OAAO,EACd,KAAK,IAAI;AAAA,MACd;AAAA,IAAA;AAAA,EAAA;AAGN;"}
|
package/dist/esm/router.d.ts
CHANGED
|
@@ -17,6 +17,7 @@ declare global {
|
|
|
17
17
|
interface Window {
|
|
18
18
|
__TSR__?: {
|
|
19
19
|
matches: Array<any>;
|
|
20
|
+
streamedValues: Record<string, any>;
|
|
20
21
|
cleanScripts: () => void;
|
|
21
22
|
dehydrated?: any;
|
|
22
23
|
};
|
|
@@ -353,6 +354,7 @@ export declare class Router<in out TRouteTree extends AnyRoute, in out TTrailing
|
|
|
353
354
|
router: AnyRouter;
|
|
354
355
|
match: AnyRouteMatch;
|
|
355
356
|
}) => any;
|
|
357
|
+
serializer?: (data: any) => string;
|
|
356
358
|
__store: Store<RouterState<TRouteTree>>;
|
|
357
359
|
options: PickAsRequired<Omit<RouterOptions<TRouteTree, TTrailingSlashOption, TDehydrated, TSerializedError>, 'transformer'> & {
|
|
358
360
|
transformer: RouterTransformer;
|
|
@@ -405,6 +407,9 @@ export declare class Router<in out TRouteTree extends AnyRoute, in out TTrailing
|
|
|
405
407
|
matchRoute: <TFrom extends RoutePaths<TRouteTree> = "/", TTo extends string = "", TResolved = ResolveRelativePath<TFrom, NoInfer<TTo>>>(location: ToOptions<Router<TRouteTree, TTrailingSlashOption, TDehydrated, TSerializedError>, TFrom, TTo>, opts?: MatchRouteOptions) => false | RouteById<TRouteTree, TResolved>['types']['allParams'];
|
|
406
408
|
dehydrate: () => DehydratedRouter;
|
|
407
409
|
hydrate: (__do_not_use_server_ctx?: string) => Promise<void>;
|
|
410
|
+
injectedHtml: Array<string>;
|
|
411
|
+
getStreamedValue: <T>(key: string) => T | undefined;
|
|
412
|
+
streamValue: (key: string, value: any) => void;
|
|
408
413
|
handleNotFound: (matches: Array<AnyRouteMatch>, err: NotFoundError) => void;
|
|
409
414
|
hasNotFoundMatch: () => boolean;
|
|
410
415
|
}
|
package/dist/esm/router.js
CHANGED
|
@@ -1213,8 +1213,7 @@ class Router {
|
|
|
1213
1213
|
const matches = this.matchRoutes(
|
|
1214
1214
|
this.state.location.pathname,
|
|
1215
1215
|
this.state.location.search
|
|
1216
|
-
).map((match
|
|
1217
|
-
var _a2, _b2, _c2, _d, _e, _f;
|
|
1216
|
+
).map((match) => {
|
|
1218
1217
|
const dehydratedMatch = dehydratedState.dehydratedMatches.find(
|
|
1219
1218
|
(d) => d.id === match.id
|
|
1220
1219
|
);
|
|
@@ -1222,20 +1221,9 @@ class Router {
|
|
|
1222
1221
|
dehydratedMatch,
|
|
1223
1222
|
`Could not find a client-side match for dehydrated match with id: ${match.id}!`
|
|
1224
1223
|
);
|
|
1225
|
-
const route = this.looseRoutesById[match.routeId];
|
|
1226
|
-
const assets = dehydratedMatch.status === "notFound" || dehydratedMatch.status === "redirected" ? {} : {
|
|
1227
|
-
meta: (_b2 = (_a2 = route.options).meta) == null ? void 0 : _b2.call(_a2, {
|
|
1228
|
-
matches: allMatches,
|
|
1229
|
-
params: match.params,
|
|
1230
|
-
loaderData: dehydratedMatch.loaderData
|
|
1231
|
-
}),
|
|
1232
|
-
links: (_d = (_c2 = route.options).links) == null ? void 0 : _d.call(_c2),
|
|
1233
|
-
scripts: (_f = (_e = route.options).scripts) == null ? void 0 : _f.call(_e)
|
|
1234
|
-
};
|
|
1235
1224
|
return {
|
|
1236
1225
|
...match,
|
|
1237
|
-
...dehydratedMatch
|
|
1238
|
-
...assets
|
|
1226
|
+
...dehydratedMatch
|
|
1239
1227
|
};
|
|
1240
1228
|
});
|
|
1241
1229
|
this.__store.setState((s) => {
|
|
@@ -1246,6 +1234,22 @@ class Router {
|
|
|
1246
1234
|
});
|
|
1247
1235
|
this.manifest = ctx.router.manifest;
|
|
1248
1236
|
};
|
|
1237
|
+
this.injectedHtml = [];
|
|
1238
|
+
this.getStreamedValue = (key) => {
|
|
1239
|
+
var _a;
|
|
1240
|
+
if (this.isServer) {
|
|
1241
|
+
return void 0;
|
|
1242
|
+
}
|
|
1243
|
+
return (_a = window.__TSR__) == null ? void 0 : _a.streamedValues[key];
|
|
1244
|
+
};
|
|
1245
|
+
this.streamValue = (key, value) => {
|
|
1246
|
+
var _a;
|
|
1247
|
+
const children = `window.__TSR__.streamedValues['${key}'] = ${(_a = this.serializer) == null ? void 0 : _a.call(this, value)}`;
|
|
1248
|
+
this.injectedHtml.push(
|
|
1249
|
+
`<script class='tsr-once'>${children}${process.env.NODE_ENV === "development" ? `; console.info(\`Injected From Server:
|
|
1250
|
+
${children}\`)` : ""}<\/script>`
|
|
1251
|
+
);
|
|
1252
|
+
};
|
|
1249
1253
|
this.handleNotFound = (matches, err) => {
|
|
1250
1254
|
const matchesByRouteId = Object.fromEntries(
|
|
1251
1255
|
matches.map((match2) => [match2.routeId, match2])
|