tanstack-router-cache 0.1.7 → 0.1.9

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 (50) hide show
  1. package/dist/components/cached-outlet.cjs +12 -0
  2. package/dist/components/cached-outlet.js +12 -0
  3. package/dist/components/off-screen-in.cjs +130 -0
  4. package/dist/components/off-screen-in.js +130 -0
  5. package/dist/components/off-screen.cjs +8 -0
  6. package/dist/components/off-screen.js +8 -0
  7. package/dist/components/restore-cached-href.cjs +28 -0
  8. package/dist/components/restore-cached-href.js +28 -0
  9. package/dist/components/route-cache-manager.cjs +485 -0
  10. package/dist/components/route-cache-manager.js +485 -0
  11. package/dist/components/router-cache-outlet.cjs +9 -0
  12. package/dist/components/router-cache-outlet.js +9 -0
  13. package/dist/contexts/router-cache.cjs +237 -0
  14. package/dist/contexts/router-cache.d.ts +40 -0
  15. package/dist/contexts/router-cache.js +235 -0
  16. package/dist/dom/dismiss-transient-ui.cjs +230 -0
  17. package/dist/dom/dismiss-transient-ui.js +228 -0
  18. package/dist/hooks/use-event-listener.cjs +76 -0
  19. package/dist/hooks/use-event-listener.js +76 -0
  20. package/dist/hooks/use-route-cache-active.cjs +19 -0
  21. package/dist/hooks/use-route-cache-active.js +19 -0
  22. package/dist/hooks/use-route-cache-activity.cjs +12 -0
  23. package/dist/hooks/use-route-cache-activity.js +12 -0
  24. package/dist/hooks/use-route-cache-effect.cjs +38 -0
  25. package/dist/hooks/use-route-cache-effect.js +38 -0
  26. package/dist/hooks/use-route-cache-error-boundary.cjs +23 -0
  27. package/dist/hooks/use-route-cache-error-boundary.js +23 -0
  28. package/dist/hooks/use-route-cache-navigation.cjs +36 -0
  29. package/dist/hooks/use-route-cache-navigation.js +36 -0
  30. package/dist/hooks/use-router-cache-debug.cjs +85 -0
  31. package/dist/hooks/use-router-cache-debug.js +85 -0
  32. package/dist/hooks/use-router-cache.cjs +32 -0
  33. package/dist/hooks/use-router-cache.js +32 -0
  34. package/dist/hooks/use-update.cjs +8 -0
  35. package/dist/hooks/use-update.js +8 -0
  36. package/dist/index.cjs +18 -1402
  37. package/dist/index.d.ts +9 -1
  38. package/dist/index.js +10 -1395
  39. package/dist/pathname.cjs +8 -0
  40. package/dist/pathname.js +8 -0
  41. package/dist/route-cache-static-data.cjs +43 -0
  42. package/dist/route-cache-static-data.d.ts +45 -0
  43. package/dist/route-cache-static-data.js +41 -0
  44. package/dist/types.d.ts +28 -0
  45. package/docs/architecture.md +8 -5
  46. package/docs/cache-behavior.md +17 -0
  47. package/docs/components.md +1 -2
  48. package/docs/getting-started.md +38 -3
  49. package/docs/types.md +6 -0
  50. package/package.json +2 -2
@@ -0,0 +1,485 @@
1
+ const require_pathname = require("../pathname.cjs");
2
+ const require_route_cache_static_data = require("../route-cache-static-data.cjs");
3
+ const require_router_cache = require("../contexts/router-cache.cjs");
4
+ const require_use_event_listener = require("../hooks/use-event-listener.cjs");
5
+ const require_use_router_cache_debug = require("../hooks/use-router-cache-debug.cjs");
6
+ const require_cached_outlet = require("./cached-outlet.cjs");
7
+ const require_off_screen = require("./off-screen.cjs");
8
+ const require_restore_cached_href = require("./restore-cached-href.cjs");
9
+ let _tanstack_react_router = require("@tanstack/react-router");
10
+ let react = require("react");
11
+ let react_jsx_runtime = require("react/jsx-runtime");
12
+ //#region src/components/route-cache-manager.tsx
13
+ const LIVE_ROUTER_METHODS = [
14
+ "buildLocation",
15
+ "commitLocation",
16
+ "invalidate",
17
+ "loadRouteChunk",
18
+ "navigate",
19
+ "preloadRoute"
20
+ ];
21
+ const routerSnapshotUpdaters = /* @__PURE__ */ new WeakMap();
22
+ function createSnapshotStore(value) {
23
+ let currentValue = value;
24
+ const listeners = /* @__PURE__ */ new Set();
25
+ return {
26
+ get: () => currentValue,
27
+ set: (nextValue) => {
28
+ if (Object.is(currentValue, nextValue)) return;
29
+ currentValue = nextValue;
30
+ for (const listener of listeners) listener(currentValue);
31
+ },
32
+ subscribe: (listener) => {
33
+ if (listener) listeners.add(listener);
34
+ return { unsubscribe: listener ? () => {
35
+ listeners.delete(listener);
36
+ } : () => void 0 };
37
+ }
38
+ };
39
+ }
40
+ function createRouterSnapshotData({ matches, router, routerLocation, routerResolvedLocation }) {
41
+ const snapshotMatches = matches.reduce((snapshot, match) => {
42
+ const nextMatch = snapshotMatch(match, routerLocation);
43
+ if (isRouterMatch(nextMatch)) snapshot.push(nextMatch);
44
+ return snapshot;
45
+ }, []);
46
+ return {
47
+ matches: snapshotMatches,
48
+ state: {
49
+ ...router.stores.__store.get(),
50
+ matches: snapshotMatches,
51
+ location: routerLocation,
52
+ resolvedLocation: routerResolvedLocation
53
+ }
54
+ };
55
+ }
56
+ function createMatchStore(match) {
57
+ return Object.assign(createSnapshotStore(match), { routeId: match.routeId });
58
+ }
59
+ function syncRouterSnapshot(routerSnapshot, input) {
60
+ const update = routerSnapshotUpdaters.get(routerSnapshot);
61
+ if (!update) return false;
62
+ update(input);
63
+ return true;
64
+ }
65
+ function getLiveRouterMethodDescriptors(router) {
66
+ return Object.fromEntries(LIVE_ROUTER_METHODS.flatMap((methodName) => {
67
+ const method = router[methodName];
68
+ if (typeof method !== "function") return [];
69
+ return [[methodName, { value: method.bind(router) }]];
70
+ }));
71
+ }
72
+ function toRouterLocation(location) {
73
+ return { ...location };
74
+ }
75
+ function isReadyCachedRoute(route) {
76
+ return Boolean(route && require_route_cache_static_data.isRouteCacheEnabled(route.staticData) && !require_route_cache_static_data.isCachedRouteStale(route) && route.ready && route.matchId && route.routerSnapshot);
77
+ }
78
+ function hasErroredRouteMatch(matches) {
79
+ return matches.some((match) => match?.status === "error");
80
+ }
81
+ function hasRetainedRouteError(erroredRouteCounts, pathname) {
82
+ return (erroredRouteCounts[pathname] ?? 0) > 0;
83
+ }
84
+ function hasCurrentRouterMatchError({ matches, resolvedPathname, routerPathname }) {
85
+ return routerPathname === resolvedPathname && hasErroredRouteMatch(matches);
86
+ }
87
+ function hasCurrentRouteError({ erroredRouteCounts, matches, resolvedPathname, routerPathname }) {
88
+ return hasRetainedRouteError(erroredRouteCounts, routerPathname) || hasCurrentRouterMatchError({
89
+ matches,
90
+ resolvedPathname,
91
+ routerPathname
92
+ });
93
+ }
94
+ function isRouterMatch(match) {
95
+ return Boolean(match?.id && match.routeId);
96
+ }
97
+ function snapshotMatch(match, routerLocation) {
98
+ if (!isRouterMatch(match)) return;
99
+ const isLocationMatch = match.pathname ? require_pathname.normalizeCachedRoutePathname(match.pathname) === require_pathname.normalizeCachedRoutePathname(routerLocation.pathname) : false;
100
+ return {
101
+ ...match,
102
+ ...isLocationMatch ? {
103
+ _strictSearch: routerLocation.search,
104
+ search: routerLocation.search
105
+ } : {},
106
+ _nonReactive: { ...match._nonReactive }
107
+ };
108
+ }
109
+ function isCurrentUnmanagedCachedRoute(route, routerHref) {
110
+ return Boolean(route && require_route_cache_static_data.isRouteCacheEnabled(route.staticData) && route.ready && route.routerSnapshot && route.href === routerHref);
111
+ }
112
+ function syncReadyCachedRoute({ matchId, matches, routeId, route, routerLocation, router, routerResolvedLocation, routerHref, routerPathname, setCachedRoutes, staticData }) {
113
+ const routerSnapshotInput = {
114
+ matches,
115
+ router,
116
+ routerLocation,
117
+ routerResolvedLocation
118
+ };
119
+ let routerSnapshot = matchId ? route?.routerSnapshot : void 0;
120
+ if (routerSnapshot && !syncRouterSnapshot(routerSnapshot, routerSnapshotInput)) {
121
+ if (isCurrentUnmanagedCachedRoute(route, routerHref)) return;
122
+ routerSnapshot = void 0;
123
+ }
124
+ if (matchId && !routerSnapshot) routerSnapshot = createRouterSnapshot(routerSnapshotInput);
125
+ setCachedRoutes(routerPathname, {
126
+ href: routerHref,
127
+ matchId,
128
+ routeId,
129
+ ready: true,
130
+ routerSnapshot,
131
+ staticData
132
+ });
133
+ }
134
+ function syncCachedRouteState({ isCurrentMatchReady, isCurrentMatchResolved, deleteCachedRoutes, isCurrentRouteErrored, matchId, matches, route, routeId, router, routerHref, routerLocation, routerPathname, routerResolvedLocation, setCachedRoutes, staticData }) {
135
+ if (isCurrentRouteErrored) {
136
+ if (route) deleteCachedRoutes([routerPathname]);
137
+ return;
138
+ }
139
+ if (!isCurrentMatchResolved) return;
140
+ if (staticData && require_route_cache_static_data.isRouteCacheEnabled(staticData)) {
141
+ if (!isCurrentMatchReady) return;
142
+ syncReadyCachedRoute({
143
+ matchId,
144
+ matches,
145
+ routeId,
146
+ route,
147
+ routerLocation,
148
+ router,
149
+ routerResolvedLocation,
150
+ routerHref,
151
+ routerPathname,
152
+ setCachedRoutes,
153
+ staticData
154
+ });
155
+ return;
156
+ }
157
+ if (route) deleteCachedRoutes([routerPathname]);
158
+ }
159
+ function createRouterSnapshot(input) {
160
+ const { router, routerLocation, routerResolvedLocation } = input;
161
+ const snapshotData = createRouterSnapshotData(input);
162
+ const snapshotMatches = snapshotData.matches;
163
+ const matchStores = new Map(snapshotMatches.map((match) => [match.id, createMatchStore(match)]));
164
+ const routeMatchStoreCache = /* @__PURE__ */ new Map();
165
+ const stores = {
166
+ ...router.stores,
167
+ status: createSnapshotStore(router.stores.status.get()),
168
+ loadedAt: createSnapshotStore(router.stores.loadedAt.get()),
169
+ isLoading: createSnapshotStore(router.stores.isLoading.get()),
170
+ isTransitioning: createSnapshotStore(router.stores.isTransitioning.get()),
171
+ location: createSnapshotStore(routerLocation),
172
+ resolvedLocation: createSnapshotStore(routerResolvedLocation),
173
+ statusCode: createSnapshotStore(router.stores.statusCode.get()),
174
+ redirect: createSnapshotStore(router.stores.redirect.get()),
175
+ matchesId: createSnapshotStore(snapshotMatches.map((match) => match.id)),
176
+ pendingIds: createSnapshotStore([]),
177
+ cachedIds: createSnapshotStore([]),
178
+ matches: createSnapshotStore(snapshotMatches),
179
+ pendingMatches: createSnapshotStore([]),
180
+ cachedMatches: createSnapshotStore([]),
181
+ firstId: createSnapshotStore(snapshotMatches[0]?.id),
182
+ hasPending: createSnapshotStore(snapshotMatches.some((match) => match.status === "pending")),
183
+ matchRouteDeps: createSnapshotStore({
184
+ locationHref: routerLocation.href,
185
+ resolvedLocationHref: routerResolvedLocation?.href,
186
+ status: snapshotData.state.status
187
+ }),
188
+ __store: createSnapshotStore(snapshotData.state),
189
+ matchStores,
190
+ pendingMatchStores: /* @__PURE__ */ new Map(),
191
+ cachedMatchStores: /* @__PURE__ */ new Map(),
192
+ getRouteMatchStore: (routeId) => {
193
+ let cached = routeMatchStoreCache.get(routeId);
194
+ if (!cached) {
195
+ cached = createSnapshotStore(snapshotMatches.find((match) => match.routeId === routeId));
196
+ routeMatchStoreCache.set(routeId, cached);
197
+ }
198
+ return cached;
199
+ },
200
+ setMatches: () => void 0,
201
+ setPending: () => void 0,
202
+ setCached: () => void 0
203
+ };
204
+ const updateSnapshot = (nextInput) => {
205
+ const nextData = createRouterSnapshotData(nextInput);
206
+ const nextMatches = nextData.matches;
207
+ const nextMatchIds = new Set(nextMatches.map((match) => match.id));
208
+ const nextMatchesByRouteId = new Map(nextMatches.map((match) => [match.routeId, match]));
209
+ for (const match of nextMatches) {
210
+ const store = matchStores.get(match.id);
211
+ if (store) {
212
+ store.set(match);
213
+ continue;
214
+ }
215
+ matchStores.set(match.id, createMatchStore(match));
216
+ }
217
+ for (const [matchId] of matchStores) if (!nextMatchIds.has(matchId)) matchStores.delete(matchId);
218
+ stores.status.set(nextInput.router.stores.status.get());
219
+ stores.loadedAt.set(nextInput.router.stores.loadedAt.get());
220
+ stores.isLoading.set(nextInput.router.stores.isLoading.get());
221
+ stores.isTransitioning.set(nextInput.router.stores.isTransitioning.get());
222
+ stores.location.set(nextInput.routerLocation);
223
+ stores.resolvedLocation.set(nextInput.routerResolvedLocation);
224
+ stores.statusCode.set(nextInput.router.stores.statusCode.get());
225
+ stores.redirect.set(nextInput.router.stores.redirect.get());
226
+ stores.matchesId.set(nextMatches.map((match) => match.id));
227
+ stores.pendingIds.set([]);
228
+ stores.cachedIds.set([]);
229
+ stores.matches.set(nextMatches);
230
+ stores.pendingMatches.set([]);
231
+ stores.cachedMatches.set([]);
232
+ stores.firstId.set(nextMatches[0]?.id);
233
+ stores.hasPending.set(nextMatches.some((match) => match.status === "pending"));
234
+ stores.matchRouteDeps.set({
235
+ locationHref: nextInput.routerLocation.href,
236
+ resolvedLocationHref: nextInput.routerResolvedLocation?.href,
237
+ status: nextData.state.status
238
+ });
239
+ stores.__store.set(nextData.state);
240
+ for (const [routeId, store] of routeMatchStoreCache) store.set(nextMatchesByRouteId.get(routeId));
241
+ };
242
+ const routerSnapshot = Object.create(router);
243
+ Object.defineProperties(routerSnapshot, {
244
+ stores: { value: stores },
245
+ latestLocation: { get: () => stores.location.get() },
246
+ getMatch: { value: (matchId) => matchStores.get(matchId)?.get() },
247
+ updateMatch: { value: () => void 0 },
248
+ ...getLiveRouterMethodDescriptors(router)
249
+ });
250
+ routerSnapshotUpdaters.set(routerSnapshot, updateSnapshot);
251
+ return routerSnapshot;
252
+ }
253
+ function getRouterCacheStaticData(childMatches, isCurrentMatchResolved) {
254
+ if (!isCurrentMatchResolved) return;
255
+ for (let i = childMatches.length - 1; i >= 0; i--) {
256
+ const match = childMatches[i];
257
+ if (match?.staticData && require_route_cache_static_data.isRouteCacheEnabled(match.staticData)) return match.staticData;
258
+ }
259
+ }
260
+ function restoreCachedHref(router, href) {
261
+ router.navigate({
262
+ href,
263
+ replace: true,
264
+ resetScroll: false
265
+ }).catch(() => void 0);
266
+ }
267
+ function renderCachedRoute({ bypassCachedPathname, pathname, route, routerPathname }) {
268
+ if (pathname === bypassCachedPathname) return null;
269
+ if (require_route_cache_static_data.isCachedRouteStale(route)) return null;
270
+ const content = route.matchId && route.routerSnapshot ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_cached_outlet.default, {
271
+ matchId: route.matchId,
272
+ routerSnapshot: route.routerSnapshot
273
+ }) : null;
274
+ if (!content) return null;
275
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_off_screen.default, {
276
+ mode: routerPathname === pathname ? "visible" : "hidden",
277
+ pathname,
278
+ children: content
279
+ }, pathname);
280
+ }
281
+ function getStaleCachedRoutePathnames(cachedRoutes) {
282
+ const now = Date.now();
283
+ return Object.entries(cachedRoutes).flatMap(([pathname, route]) => require_route_cache_static_data.isCachedRouteStale(route, now) ? [pathname] : []);
284
+ }
285
+ function buildRouteCacheModes(cachedRoutes, routerPathname) {
286
+ const nextModes = /* @__PURE__ */ new Map();
287
+ for (const pathname of Object.keys(cachedRoutes)) nextModes.set(pathname, routerPathname === pathname ? "visible" : "hidden");
288
+ return nextModes;
289
+ }
290
+ function syncCachedRouteActivityEvents(params) {
291
+ const nextModes = buildRouteCacheModes(params.cachedRoutes, params.routerPathname);
292
+ for (const [pathname, mode] of nextModes) {
293
+ const previousMode = params.previousRouteCacheModes.get(pathname);
294
+ if (previousMode === void 0 && mode === "hidden") continue;
295
+ if (previousMode === mode) continue;
296
+ params.eventListener.emit("activeChange", {
297
+ pathname,
298
+ mode
299
+ });
300
+ }
301
+ for (const [pathname] of params.previousRouteCacheModes) {
302
+ if (nextModes.has(pathname)) continue;
303
+ params.eventListener.emit("activeChange", {
304
+ pathname,
305
+ mode: "hidden"
306
+ });
307
+ }
308
+ return nextModes;
309
+ }
310
+ function RouteCacheManager() {
311
+ const { cachedRoutes, deleteCachedRoutes, erroredRouteCounts, setCachedRoutes, touchCachedRoutes } = require_router_cache.useRouterCacheContext();
312
+ const { eventListener } = require_use_event_listener.useEventListener();
313
+ const pendingCachedNavigationRef = (0, react.useRef)(null);
314
+ const previousPathnameRef = (0, react.useRef)(void 0);
315
+ const previousHrefRef = (0, react.useRef)(void 0);
316
+ const previousRouteCacheModesRef = (0, react.useRef)(null);
317
+ previousRouteCacheModesRef.current ??= /* @__PURE__ */ new Map();
318
+ const previousVisiblePathnameRef = (0, react.useRef)(void 0);
319
+ const routerLocation = (0, _tanstack_react_router.useRouterState)({ select: (state) => toRouterLocation(state.location) });
320
+ const routerHref = routerLocation.href;
321
+ const routerPathname = require_pathname.normalizeCachedRoutePathname(routerLocation.pathname);
322
+ const routerResolvedLocation = (0, _tanstack_react_router.useRouterState)({ select: (state) => state.resolvedLocation ? toRouterLocation(state.resolvedLocation) : void 0 });
323
+ const resolvedPathname = require_pathname.normalizeCachedRoutePathname(routerResolvedLocation?.pathname ?? routerPathname);
324
+ const destinationRoute = cachedRoutes[routerPathname];
325
+ const matches = (0, _tanstack_react_router.useMatches)();
326
+ const childMatches = (0, _tanstack_react_router.useChildMatches)();
327
+ const router = (0, _tanstack_react_router.useRouter)();
328
+ const currentMatch = matches.length ? matches.at(-1) : void 0;
329
+ const outletRootMatch = childMatches.length ? childMatches[0] : currentMatch;
330
+ const isCurrentMatchResolved = (currentMatch?.pathname ? require_pathname.normalizeCachedRoutePathname(currentMatch.pathname) : void 0) === routerPathname;
331
+ const isCurrentMatchReady = isCurrentMatchResolved && currentMatch?.status === "success";
332
+ const staticData = getRouterCacheStaticData(childMatches, isCurrentMatchResolved);
333
+ const matchId = isCurrentMatchResolved && outletRootMatch ? outletRootMatch.id : void 0;
334
+ const routeId = isCurrentMatchResolved && outletRootMatch ? outletRootMatch.routeId : void 0;
335
+ const currentCachedRoute = cachedRoutes[routerPathname];
336
+ const isCurrentRouteErrored = hasCurrentRouteError({
337
+ erroredRouteCounts,
338
+ matches,
339
+ resolvedPathname,
340
+ routerPathname
341
+ });
342
+ const bypassCachedPathname = isCurrentRouteErrored ? routerPathname : void 0;
343
+ const previousPathname = previousPathnameRef.current;
344
+ previousHrefRef.current;
345
+ const shouldRestoreDestinationHref = require_restore_cached_href.shouldRestoreCachedHref({
346
+ cachedHref: destinationRoute?.href,
347
+ currentHref: routerHref,
348
+ currentPathname: routerPathname,
349
+ isRouteCacheEnabled: require_route_cache_static_data.isRouteCacheEnabled(destinationRoute?.staticData),
350
+ previousPathname
351
+ });
352
+ (0, react.useLayoutEffect)(() => {
353
+ const stalePathnames = getStaleCachedRoutePathnames(cachedRoutes);
354
+ if (stalePathnames.length > 0) deleteCachedRoutes(stalePathnames);
355
+ }, [cachedRoutes, deleteCachedRoutes]);
356
+ (0, react.useLayoutEffect)(() => {
357
+ if (shouldRestoreDestinationHref) return;
358
+ syncCachedRouteState({
359
+ isCurrentMatchReady,
360
+ isCurrentMatchResolved,
361
+ isCurrentRouteErrored,
362
+ matchId,
363
+ matches,
364
+ routeId,
365
+ route: currentCachedRoute,
366
+ routerLocation,
367
+ router,
368
+ routerResolvedLocation,
369
+ routerHref,
370
+ routerPathname,
371
+ deleteCachedRoutes,
372
+ setCachedRoutes,
373
+ staticData
374
+ });
375
+ }, [
376
+ currentCachedRoute,
377
+ deleteCachedRoutes,
378
+ isCurrentRouteErrored,
379
+ isCurrentMatchReady,
380
+ isCurrentMatchResolved,
381
+ matchId,
382
+ matches,
383
+ routeId,
384
+ router,
385
+ routerLocation,
386
+ routerResolvedLocation,
387
+ routerHref,
388
+ routerPathname,
389
+ staticData,
390
+ setCachedRoutes,
391
+ shouldRestoreDestinationHref
392
+ ]);
393
+ (0, react.useLayoutEffect)(() => {
394
+ const lastVisitedPathname = previousPathnameRef.current;
395
+ const pendingNavigation = pendingCachedNavigationRef.current;
396
+ if (pendingNavigation && pendingNavigation.pathname !== routerPathname) {
397
+ eventListener.emit("cachedNavigationCancel", pendingNavigation);
398
+ pendingCachedNavigationRef.current = null;
399
+ }
400
+ if (!lastVisitedPathname || lastVisitedPathname === routerPathname) return;
401
+ if (!isReadyCachedRoute(destinationRoute)) return;
402
+ if (pendingCachedNavigationRef.current?.pathname === routerPathname) return;
403
+ const nextNavigation = {
404
+ pathname: routerPathname,
405
+ startedAt: performance.now()
406
+ };
407
+ pendingCachedNavigationRef.current = nextNavigation;
408
+ eventListener.emit("cachedNavigationStart", nextNavigation);
409
+ }, [
410
+ destinationRoute,
411
+ eventListener,
412
+ routerPathname
413
+ ]);
414
+ (0, react.useLayoutEffect)(() => {
415
+ previousRouteCacheModesRef.current ??= /* @__PURE__ */ new Map();
416
+ previousRouteCacheModesRef.current = syncCachedRouteActivityEvents({
417
+ cachedRoutes,
418
+ eventListener,
419
+ previousRouteCacheModes: previousRouteCacheModesRef.current,
420
+ routerPathname
421
+ });
422
+ }, [
423
+ cachedRoutes,
424
+ eventListener,
425
+ routerPathname
426
+ ]);
427
+ (0, react.useLayoutEffect)(() => {
428
+ if (previousVisiblePathnameRef.current === routerPathname || !cachedRoutes[routerPathname]) {
429
+ previousVisiblePathnameRef.current = routerPathname;
430
+ return;
431
+ }
432
+ previousVisiblePathnameRef.current = routerPathname;
433
+ touchCachedRoutes([routerPathname]);
434
+ }, [
435
+ cachedRoutes,
436
+ touchCachedRoutes,
437
+ routerPathname
438
+ ]);
439
+ (0, react.useEffect)(() => {
440
+ const pendingNavigation = pendingCachedNavigationRef.current;
441
+ if (routerPathname !== pendingNavigation?.pathname) return;
442
+ let firstFrameId = 0;
443
+ let secondFrameId = 0;
444
+ firstFrameId = globalThis.requestAnimationFrame(() => {
445
+ const visibleAt = performance.now();
446
+ secondFrameId = globalThis.requestAnimationFrame(() => {
447
+ const paintedAt = performance.now();
448
+ if (pendingCachedNavigationRef.current?.pathname !== pendingNavigation.pathname) return;
449
+ pendingCachedNavigationRef.current = null;
450
+ eventListener.emit("cachedNavigationComplete", {
451
+ ...pendingNavigation,
452
+ duration: paintedAt - pendingNavigation.startedAt,
453
+ paintedAt,
454
+ visibleAt
455
+ });
456
+ });
457
+ });
458
+ return () => {
459
+ globalThis.cancelAnimationFrame(firstFrameId);
460
+ globalThis.cancelAnimationFrame(secondFrameId);
461
+ };
462
+ }, [eventListener, routerPathname]);
463
+ (0, react.useLayoutEffect)(() => {
464
+ if (!(shouldRestoreDestinationHref && destinationRoute?.href)) return;
465
+ restoreCachedHref(router, destinationRoute.href);
466
+ }, [
467
+ destinationRoute?.href,
468
+ router,
469
+ shouldRestoreDestinationHref
470
+ ]);
471
+ (0, react.useEffect)(() => {
472
+ previousPathnameRef.current = routerPathname;
473
+ previousHrefRef.current = routerHref;
474
+ }, [routerHref, routerPathname]);
475
+ const shouldRenderLiveOutlet = routerPathname === bypassCachedPathname || !isReadyCachedRoute(destinationRoute);
476
+ require_use_router_cache_debug.useRouterCacheDebug(cachedRoutes, routerPathname);
477
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [Object.entries(cachedRoutes).map(([pathname, route]) => renderCachedRoute({
478
+ bypassCachedPathname,
479
+ pathname,
480
+ route,
481
+ routerPathname
482
+ })), shouldRenderLiveOutlet ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_tanstack_react_router.Outlet, {}, `live-${routerPathname}`) : null] });
483
+ }
484
+ //#endregion
485
+ exports.default = RouteCacheManager;