tanstack-router-cache 0.1.1 → 0.1.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/README.md +13 -30
- package/dist/index.cjs +77 -21
- package/dist/index.js +77 -21
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -2,21 +2,21 @@
|
|
|
2
2
|
|
|
3
3
|
Route view caching for [`@tanstack/react-router`](https://tanstack.com/router).
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Keep selected route trees mounted while they are hidden, then restore them when the user navigates back.
|
|
6
6
|
|
|
7
7
|
## Install
|
|
8
8
|
|
|
9
9
|
```sh
|
|
10
|
-
|
|
10
|
+
npm install tanstack-router-cache
|
|
11
11
|
```
|
|
12
12
|
|
|
13
13
|
```sh
|
|
14
|
-
|
|
14
|
+
bun add tanstack-router-cache
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
##
|
|
17
|
+
## Requirements
|
|
18
18
|
|
|
19
|
-
Your app should already
|
|
19
|
+
Your app should already install these packages:
|
|
20
20
|
|
|
21
21
|
| Package | Supported versions |
|
|
22
22
|
| --- | --- |
|
|
@@ -24,27 +24,23 @@ Your app should already use React and TanStack Router. This package keeps them a
|
|
|
24
24
|
| `react-dom` | Match your React version. |
|
|
25
25
|
| `@tanstack/react-router` | `>=1.168.14 <2.0.0` |
|
|
26
26
|
|
|
27
|
-
## Maintenance
|
|
28
|
-
|
|
29
|
-
This package is intended to stay compatible with current TanStack Router 1.x releases. The peer dependency floor is tested against the oldest version supported by the current implementation, while development tracks the latest compatible TanStack Router version.
|
|
30
|
-
|
|
31
27
|
## Usage
|
|
32
28
|
|
|
33
|
-
Wrap
|
|
29
|
+
Wrap your route outlet once:
|
|
34
30
|
|
|
35
31
|
```tsx
|
|
36
32
|
import { RouterCacheOutlet, RouterCacheProvider } from "tanstack-router-cache";
|
|
37
33
|
|
|
38
34
|
export function RootRoute() {
|
|
39
35
|
return (
|
|
40
|
-
<RouterCacheProvider
|
|
36
|
+
<RouterCacheProvider>
|
|
41
37
|
<RouterCacheOutlet />
|
|
42
38
|
</RouterCacheProvider>
|
|
43
39
|
);
|
|
44
40
|
}
|
|
45
41
|
```
|
|
46
42
|
|
|
47
|
-
Enable caching on
|
|
43
|
+
Enable caching on any route that should stay mounted:
|
|
48
44
|
|
|
49
45
|
```tsx
|
|
50
46
|
export const Route = createFileRoute("/customers")({
|
|
@@ -55,29 +51,16 @@ export const Route = createFileRoute("/customers")({
|
|
|
55
51
|
});
|
|
56
52
|
```
|
|
57
53
|
|
|
58
|
-
|
|
54
|
+
For the full API, see [docs](./docs).
|
|
59
55
|
|
|
60
|
-
|
|
61
|
-
import { useRouteCacheEffect } from "tanstack-router-cache";
|
|
62
|
-
|
|
63
|
-
function CustomersPage() {
|
|
64
|
-
useRouteCacheEffect(() => {
|
|
65
|
-
const controller = new AbortController();
|
|
66
|
-
|
|
67
|
-
return () => {
|
|
68
|
-
controller.abort();
|
|
69
|
-
};
|
|
70
|
-
}, []);
|
|
71
|
-
|
|
72
|
-
return <CustomersTable />;
|
|
73
|
-
}
|
|
74
|
-
```
|
|
56
|
+
## Examples
|
|
75
57
|
|
|
76
|
-
|
|
58
|
+
- [Basic](https://github.com/santiago-ramos-02/tanstack-router-cache/tree/main/examples/basic): the smallest useful setup. Start here; most apps only need this pattern.
|
|
59
|
+
- [Power-user demo](https://github.com/santiago-ramos-02/tanstack-router-cache/tree/main/examples/power-user-demo): a larger demo with retained forms, filtered lists, cache controls, route lifecycle state, and window scroll restoration. Use it when you need to inspect edge cases.
|
|
77
60
|
|
|
78
61
|
## Acknowledgements
|
|
79
62
|
|
|
80
|
-
This project originated from [`hemengke1997/tanstack-router-keepalive`](https://github.com/hemengke1997/tanstack-router-keepalive)
|
|
63
|
+
This project originated from [`hemengke1997/tanstack-router-keepalive`](https://github.com/hemengke1997/tanstack-router-keepalive), then diverged with current TanStack Router compatibility, a different API, cache limits, error handling, navigation lifecycle tools, dependency updates, and memory-focused eviction.
|
|
81
64
|
|
|
82
65
|
## License
|
|
83
66
|
|
package/dist/index.cjs
CHANGED
|
@@ -131,8 +131,9 @@ function RouterCacheProviderScope({ children, defaultCachedRoutes = EMPTY_CACHED
|
|
|
131
131
|
maxEntries: normalizeLimit(maxEntries),
|
|
132
132
|
maxEntriesPerRouteId: normalizeLimit(maxEntriesPerRouteId)
|
|
133
133
|
});
|
|
134
|
-
const
|
|
135
|
-
|
|
134
|
+
const initialCachedRoutesRef = (0, react.useRef)(null);
|
|
135
|
+
if (initialCachedRoutesRef.current === null) initialCachedRoutesRef.current = applyCachedRouteLimits(filterRouterCacheRoutes(defaultCachedRoutes), cacheConfigRef.current, /* @__PURE__ */ new Set());
|
|
136
|
+
const [cachedRoutes, setCachedRoutes] = (0, react.useState)(() => initialCachedRoutesRef.current ?? EMPTY_CACHED_ROUTES);
|
|
136
137
|
const [erroredRouteCounts, setErroredRouteCounts] = (0, react.useState)({});
|
|
137
138
|
const updateCachedRoutes = (key, value) => {
|
|
138
139
|
setCachedRoutes((state) => getNextCachedRoutesState({
|
|
@@ -340,7 +341,8 @@ function isProduction() {
|
|
|
340
341
|
function useRouterCacheDebug(cachedRoutes, visiblePathname) {
|
|
341
342
|
const warningThresholdRef = (0, react.useRef)(null);
|
|
342
343
|
const lastWarnedCountRef = (0, react.useRef)(null);
|
|
343
|
-
const lastSnapshotRef = (0, react.useRef)(
|
|
344
|
+
const lastSnapshotRef = (0, react.useRef)(null);
|
|
345
|
+
if (lastSnapshotRef.current === null) lastSnapshotRef.current = buildSnapshot(cachedRoutes, visiblePathname);
|
|
344
346
|
const snapshot = (0, react.useMemo)(() => buildSnapshot(cachedRoutes, visiblePathname), [cachedRoutes, visiblePathname]);
|
|
345
347
|
(0, react.useEffect)(() => {
|
|
346
348
|
if (isProduction()) return;
|
|
@@ -351,7 +353,7 @@ function useRouterCacheDebug(cachedRoutes, visiblePathname) {
|
|
|
351
353
|
return lastSnapshotRef.current;
|
|
352
354
|
};
|
|
353
355
|
const api = {
|
|
354
|
-
getSnapshot: () => lastSnapshotRef.current,
|
|
356
|
+
getSnapshot: () => lastSnapshotRef.current ?? snapshot,
|
|
355
357
|
lastSnapshot: snapshot,
|
|
356
358
|
refresh,
|
|
357
359
|
setWarningThreshold: (nextThreshold) => {
|
|
@@ -623,6 +625,30 @@ function dismissTransientUi(container, pathname) {
|
|
|
623
625
|
//#endregion
|
|
624
626
|
//#region src/components/off-screen-in.tsx
|
|
625
627
|
const windowScrollPositions = /* @__PURE__ */ new Map();
|
|
628
|
+
const IMMEDIATE_SCROLL_RESTORE_DELAY = 0;
|
|
629
|
+
const EARLY_SCROLL_RESTORE_DELAY = 80;
|
|
630
|
+
const MIDDLE_SCROLL_RESTORE_DELAY = 240;
|
|
631
|
+
const LATE_SCROLL_RESTORE_DELAY = 600;
|
|
632
|
+
const FINAL_SCROLL_RESTORE_DELAY = 1e3;
|
|
633
|
+
const SCROLL_TRACKING_INTERVAL_MS = 200;
|
|
634
|
+
const SCROLL_KEYS = new Set([
|
|
635
|
+
" ",
|
|
636
|
+
"ArrowDown",
|
|
637
|
+
"ArrowLeft",
|
|
638
|
+
"ArrowRight",
|
|
639
|
+
"ArrowUp",
|
|
640
|
+
"End",
|
|
641
|
+
"Home",
|
|
642
|
+
"PageDown",
|
|
643
|
+
"PageUp"
|
|
644
|
+
]);
|
|
645
|
+
const SCROLL_RESTORE_DELAYS = [
|
|
646
|
+
IMMEDIATE_SCROLL_RESTORE_DELAY,
|
|
647
|
+
EARLY_SCROLL_RESTORE_DELAY,
|
|
648
|
+
MIDDLE_SCROLL_RESTORE_DELAY,
|
|
649
|
+
LATE_SCROLL_RESTORE_DELAY,
|
|
650
|
+
FINAL_SCROLL_RESTORE_DELAY
|
|
651
|
+
];
|
|
626
652
|
function OffScreenIn(props) {
|
|
627
653
|
const { mode, children, containerRef, pathname } = props;
|
|
628
654
|
const localContainerRef = (0, react.useRef)(null);
|
|
@@ -653,26 +679,61 @@ function OffScreenIn(props) {
|
|
|
653
679
|
y: globalThis.scrollY
|
|
654
680
|
});
|
|
655
681
|
};
|
|
656
|
-
if (mode === "hidden")
|
|
657
|
-
saveScrollPosition();
|
|
658
|
-
return;
|
|
659
|
-
}
|
|
682
|
+
if (mode === "hidden") return;
|
|
660
683
|
const savedPosition = windowScrollPositions.get(pathname);
|
|
661
|
-
|
|
684
|
+
let userRequestedScroll = false;
|
|
685
|
+
let scrollTrackingIntervalId;
|
|
686
|
+
const startScrollTracking = () => {
|
|
687
|
+
scrollTrackingIntervalId ??= globalThis.setInterval(saveScrollPosition, SCROLL_TRACKING_INTERVAL_MS);
|
|
688
|
+
};
|
|
689
|
+
const handleScroll = () => {
|
|
690
|
+
if (!savedPosition || userRequestedScroll) saveScrollPosition();
|
|
691
|
+
};
|
|
692
|
+
const markUserRequestedScroll = () => {
|
|
693
|
+
userRequestedScroll = true;
|
|
694
|
+
};
|
|
695
|
+
const handleKeyDown = (event) => {
|
|
696
|
+
if (SCROLL_KEYS.has(event.key)) markUserRequestedScroll();
|
|
697
|
+
};
|
|
662
698
|
globalThis.addEventListener("scroll", handleScroll, { passive: true });
|
|
699
|
+
globalThis.addEventListener("wheel", markUserRequestedScroll, { passive: true });
|
|
700
|
+
globalThis.addEventListener("touchstart", markUserRequestedScroll, { passive: true });
|
|
701
|
+
globalThis.addEventListener("pointerdown", markUserRequestedScroll, { passive: true });
|
|
702
|
+
globalThis.addEventListener("keydown", handleKeyDown);
|
|
663
703
|
if (!savedPosition) {
|
|
704
|
+
startScrollTracking();
|
|
664
705
|
saveScrollPosition();
|
|
665
|
-
return () =>
|
|
706
|
+
return () => {
|
|
707
|
+
if (scrollTrackingIntervalId !== void 0) globalThis.clearInterval(scrollTrackingIntervalId);
|
|
708
|
+
globalThis.removeEventListener("scroll", handleScroll);
|
|
709
|
+
globalThis.removeEventListener("wheel", markUserRequestedScroll);
|
|
710
|
+
globalThis.removeEventListener("touchstart", markUserRequestedScroll);
|
|
711
|
+
globalThis.removeEventListener("pointerdown", markUserRequestedScroll);
|
|
712
|
+
globalThis.removeEventListener("keydown", handleKeyDown);
|
|
713
|
+
};
|
|
666
714
|
}
|
|
715
|
+
const restoreScrollPosition = () => {
|
|
716
|
+
if (userRequestedScroll) return;
|
|
717
|
+
globalThis.scrollTo(savedPosition.x, savedPosition.y);
|
|
718
|
+
saveScrollPosition();
|
|
719
|
+
startScrollTracking();
|
|
720
|
+
};
|
|
721
|
+
const timeoutIds = [];
|
|
667
722
|
let rafId = globalThis.requestAnimationFrame(() => {
|
|
668
723
|
rafId = globalThis.requestAnimationFrame(() => {
|
|
669
|
-
|
|
670
|
-
|
|
724
|
+
restoreScrollPosition();
|
|
725
|
+
for (const delay of SCROLL_RESTORE_DELAYS) timeoutIds.push(globalThis.setTimeout(restoreScrollPosition, delay));
|
|
671
726
|
});
|
|
672
727
|
});
|
|
673
728
|
return () => {
|
|
674
729
|
globalThis.cancelAnimationFrame(rafId);
|
|
730
|
+
for (const timeoutId of timeoutIds) globalThis.clearTimeout(timeoutId);
|
|
731
|
+
if (scrollTrackingIntervalId !== void 0) globalThis.clearInterval(scrollTrackingIntervalId);
|
|
675
732
|
globalThis.removeEventListener("scroll", handleScroll);
|
|
733
|
+
globalThis.removeEventListener("wheel", markUserRequestedScroll);
|
|
734
|
+
globalThis.removeEventListener("touchstart", markUserRequestedScroll);
|
|
735
|
+
globalThis.removeEventListener("pointerdown", markUserRequestedScroll);
|
|
736
|
+
globalThis.removeEventListener("keydown", handleKeyDown);
|
|
676
737
|
};
|
|
677
738
|
}, [mode, pathname]);
|
|
678
739
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react.Activity, {
|
|
@@ -742,15 +803,8 @@ function getLiveRouterMethodDescriptors(router) {
|
|
|
742
803
|
return [[methodName, { value: method.bind(router) }]];
|
|
743
804
|
}));
|
|
744
805
|
}
|
|
745
|
-
function isRouterSearch(value) {
|
|
746
|
-
return typeof value === "object" && value !== null;
|
|
747
|
-
}
|
|
748
806
|
function toRouterLocation(location) {
|
|
749
|
-
return {
|
|
750
|
-
href: location.href,
|
|
751
|
-
pathname: location.pathname,
|
|
752
|
-
search: isRouterSearch(location.search) ? location.search : void 0
|
|
753
|
-
};
|
|
807
|
+
return { ...location };
|
|
754
808
|
}
|
|
755
809
|
function isReadyCachedRoute(route) {
|
|
756
810
|
return Boolean(route && isRouteCacheEnabled(route.staticData) && route.ready && route.matchId && route.routerSnapshot);
|
|
@@ -962,7 +1016,8 @@ function RouteCacheManager() {
|
|
|
962
1016
|
const pendingCachedNavigationRef = (0, react.useRef)(null);
|
|
963
1017
|
const previousPathnameRef = (0, react.useRef)(void 0);
|
|
964
1018
|
const previousHrefRef = (0, react.useRef)(void 0);
|
|
965
|
-
const previousRouteCacheModesRef = (0, react.useRef)(
|
|
1019
|
+
const previousRouteCacheModesRef = (0, react.useRef)(null);
|
|
1020
|
+
if (previousRouteCacheModesRef.current === null) previousRouteCacheModesRef.current = /* @__PURE__ */ new Map();
|
|
966
1021
|
const previousVisiblePathnameRef = (0, react.useRef)(void 0);
|
|
967
1022
|
const routerLocation = (0, _tanstack_react_router.useRouterState)({ select: (state) => toRouterLocation(state.location) });
|
|
968
1023
|
const routerHref = routerLocation.href;
|
|
@@ -1058,6 +1113,7 @@ function RouteCacheManager() {
|
|
|
1058
1113
|
visiblePathname
|
|
1059
1114
|
]);
|
|
1060
1115
|
(0, react.useLayoutEffect)(() => {
|
|
1116
|
+
if (previousRouteCacheModesRef.current === null) previousRouteCacheModesRef.current = /* @__PURE__ */ new Map();
|
|
1061
1117
|
previousRouteCacheModesRef.current = syncCachedRouteActivityEvents({
|
|
1062
1118
|
cachedRoutes,
|
|
1063
1119
|
eventListener,
|
package/dist/index.js
CHANGED
|
@@ -130,8 +130,9 @@ function RouterCacheProviderScope({ children, defaultCachedRoutes = EMPTY_CACHED
|
|
|
130
130
|
maxEntries: normalizeLimit(maxEntries),
|
|
131
131
|
maxEntriesPerRouteId: normalizeLimit(maxEntriesPerRouteId)
|
|
132
132
|
});
|
|
133
|
-
const
|
|
134
|
-
|
|
133
|
+
const initialCachedRoutesRef = useRef(null);
|
|
134
|
+
if (initialCachedRoutesRef.current === null) initialCachedRoutesRef.current = applyCachedRouteLimits(filterRouterCacheRoutes(defaultCachedRoutes), cacheConfigRef.current, /* @__PURE__ */ new Set());
|
|
135
|
+
const [cachedRoutes, setCachedRoutes] = useState(() => initialCachedRoutesRef.current ?? EMPTY_CACHED_ROUTES);
|
|
135
136
|
const [erroredRouteCounts, setErroredRouteCounts] = useState({});
|
|
136
137
|
const updateCachedRoutes = (key, value) => {
|
|
137
138
|
setCachedRoutes((state) => getNextCachedRoutesState({
|
|
@@ -339,7 +340,8 @@ function isProduction() {
|
|
|
339
340
|
function useRouterCacheDebug(cachedRoutes, visiblePathname) {
|
|
340
341
|
const warningThresholdRef = useRef(null);
|
|
341
342
|
const lastWarnedCountRef = useRef(null);
|
|
342
|
-
const lastSnapshotRef = useRef(
|
|
343
|
+
const lastSnapshotRef = useRef(null);
|
|
344
|
+
if (lastSnapshotRef.current === null) lastSnapshotRef.current = buildSnapshot(cachedRoutes, visiblePathname);
|
|
343
345
|
const snapshot = useMemo(() => buildSnapshot(cachedRoutes, visiblePathname), [cachedRoutes, visiblePathname]);
|
|
344
346
|
useEffect(() => {
|
|
345
347
|
if (isProduction()) return;
|
|
@@ -350,7 +352,7 @@ function useRouterCacheDebug(cachedRoutes, visiblePathname) {
|
|
|
350
352
|
return lastSnapshotRef.current;
|
|
351
353
|
};
|
|
352
354
|
const api = {
|
|
353
|
-
getSnapshot: () => lastSnapshotRef.current,
|
|
355
|
+
getSnapshot: () => lastSnapshotRef.current ?? snapshot,
|
|
354
356
|
lastSnapshot: snapshot,
|
|
355
357
|
refresh,
|
|
356
358
|
setWarningThreshold: (nextThreshold) => {
|
|
@@ -622,6 +624,30 @@ function dismissTransientUi(container, pathname) {
|
|
|
622
624
|
//#endregion
|
|
623
625
|
//#region src/components/off-screen-in.tsx
|
|
624
626
|
const windowScrollPositions = /* @__PURE__ */ new Map();
|
|
627
|
+
const IMMEDIATE_SCROLL_RESTORE_DELAY = 0;
|
|
628
|
+
const EARLY_SCROLL_RESTORE_DELAY = 80;
|
|
629
|
+
const MIDDLE_SCROLL_RESTORE_DELAY = 240;
|
|
630
|
+
const LATE_SCROLL_RESTORE_DELAY = 600;
|
|
631
|
+
const FINAL_SCROLL_RESTORE_DELAY = 1e3;
|
|
632
|
+
const SCROLL_TRACKING_INTERVAL_MS = 200;
|
|
633
|
+
const SCROLL_KEYS = new Set([
|
|
634
|
+
" ",
|
|
635
|
+
"ArrowDown",
|
|
636
|
+
"ArrowLeft",
|
|
637
|
+
"ArrowRight",
|
|
638
|
+
"ArrowUp",
|
|
639
|
+
"End",
|
|
640
|
+
"Home",
|
|
641
|
+
"PageDown",
|
|
642
|
+
"PageUp"
|
|
643
|
+
]);
|
|
644
|
+
const SCROLL_RESTORE_DELAYS = [
|
|
645
|
+
IMMEDIATE_SCROLL_RESTORE_DELAY,
|
|
646
|
+
EARLY_SCROLL_RESTORE_DELAY,
|
|
647
|
+
MIDDLE_SCROLL_RESTORE_DELAY,
|
|
648
|
+
LATE_SCROLL_RESTORE_DELAY,
|
|
649
|
+
FINAL_SCROLL_RESTORE_DELAY
|
|
650
|
+
];
|
|
625
651
|
function OffScreenIn(props) {
|
|
626
652
|
const { mode, children, containerRef, pathname } = props;
|
|
627
653
|
const localContainerRef = useRef(null);
|
|
@@ -652,26 +678,61 @@ function OffScreenIn(props) {
|
|
|
652
678
|
y: globalThis.scrollY
|
|
653
679
|
});
|
|
654
680
|
};
|
|
655
|
-
if (mode === "hidden")
|
|
656
|
-
saveScrollPosition();
|
|
657
|
-
return;
|
|
658
|
-
}
|
|
681
|
+
if (mode === "hidden") return;
|
|
659
682
|
const savedPosition = windowScrollPositions.get(pathname);
|
|
660
|
-
|
|
683
|
+
let userRequestedScroll = false;
|
|
684
|
+
let scrollTrackingIntervalId;
|
|
685
|
+
const startScrollTracking = () => {
|
|
686
|
+
scrollTrackingIntervalId ??= globalThis.setInterval(saveScrollPosition, SCROLL_TRACKING_INTERVAL_MS);
|
|
687
|
+
};
|
|
688
|
+
const handleScroll = () => {
|
|
689
|
+
if (!savedPosition || userRequestedScroll) saveScrollPosition();
|
|
690
|
+
};
|
|
691
|
+
const markUserRequestedScroll = () => {
|
|
692
|
+
userRequestedScroll = true;
|
|
693
|
+
};
|
|
694
|
+
const handleKeyDown = (event) => {
|
|
695
|
+
if (SCROLL_KEYS.has(event.key)) markUserRequestedScroll();
|
|
696
|
+
};
|
|
661
697
|
globalThis.addEventListener("scroll", handleScroll, { passive: true });
|
|
698
|
+
globalThis.addEventListener("wheel", markUserRequestedScroll, { passive: true });
|
|
699
|
+
globalThis.addEventListener("touchstart", markUserRequestedScroll, { passive: true });
|
|
700
|
+
globalThis.addEventListener("pointerdown", markUserRequestedScroll, { passive: true });
|
|
701
|
+
globalThis.addEventListener("keydown", handleKeyDown);
|
|
662
702
|
if (!savedPosition) {
|
|
703
|
+
startScrollTracking();
|
|
663
704
|
saveScrollPosition();
|
|
664
|
-
return () =>
|
|
705
|
+
return () => {
|
|
706
|
+
if (scrollTrackingIntervalId !== void 0) globalThis.clearInterval(scrollTrackingIntervalId);
|
|
707
|
+
globalThis.removeEventListener("scroll", handleScroll);
|
|
708
|
+
globalThis.removeEventListener("wheel", markUserRequestedScroll);
|
|
709
|
+
globalThis.removeEventListener("touchstart", markUserRequestedScroll);
|
|
710
|
+
globalThis.removeEventListener("pointerdown", markUserRequestedScroll);
|
|
711
|
+
globalThis.removeEventListener("keydown", handleKeyDown);
|
|
712
|
+
};
|
|
665
713
|
}
|
|
714
|
+
const restoreScrollPosition = () => {
|
|
715
|
+
if (userRequestedScroll) return;
|
|
716
|
+
globalThis.scrollTo(savedPosition.x, savedPosition.y);
|
|
717
|
+
saveScrollPosition();
|
|
718
|
+
startScrollTracking();
|
|
719
|
+
};
|
|
720
|
+
const timeoutIds = [];
|
|
666
721
|
let rafId = globalThis.requestAnimationFrame(() => {
|
|
667
722
|
rafId = globalThis.requestAnimationFrame(() => {
|
|
668
|
-
|
|
669
|
-
|
|
723
|
+
restoreScrollPosition();
|
|
724
|
+
for (const delay of SCROLL_RESTORE_DELAYS) timeoutIds.push(globalThis.setTimeout(restoreScrollPosition, delay));
|
|
670
725
|
});
|
|
671
726
|
});
|
|
672
727
|
return () => {
|
|
673
728
|
globalThis.cancelAnimationFrame(rafId);
|
|
729
|
+
for (const timeoutId of timeoutIds) globalThis.clearTimeout(timeoutId);
|
|
730
|
+
if (scrollTrackingIntervalId !== void 0) globalThis.clearInterval(scrollTrackingIntervalId);
|
|
674
731
|
globalThis.removeEventListener("scroll", handleScroll);
|
|
732
|
+
globalThis.removeEventListener("wheel", markUserRequestedScroll);
|
|
733
|
+
globalThis.removeEventListener("touchstart", markUserRequestedScroll);
|
|
734
|
+
globalThis.removeEventListener("pointerdown", markUserRequestedScroll);
|
|
735
|
+
globalThis.removeEventListener("keydown", handleKeyDown);
|
|
675
736
|
};
|
|
676
737
|
}, [mode, pathname]);
|
|
677
738
|
return /* @__PURE__ */ jsx(Activity, {
|
|
@@ -741,15 +802,8 @@ function getLiveRouterMethodDescriptors(router) {
|
|
|
741
802
|
return [[methodName, { value: method.bind(router) }]];
|
|
742
803
|
}));
|
|
743
804
|
}
|
|
744
|
-
function isRouterSearch(value) {
|
|
745
|
-
return typeof value === "object" && value !== null;
|
|
746
|
-
}
|
|
747
805
|
function toRouterLocation(location) {
|
|
748
|
-
return {
|
|
749
|
-
href: location.href,
|
|
750
|
-
pathname: location.pathname,
|
|
751
|
-
search: isRouterSearch(location.search) ? location.search : void 0
|
|
752
|
-
};
|
|
806
|
+
return { ...location };
|
|
753
807
|
}
|
|
754
808
|
function isReadyCachedRoute(route) {
|
|
755
809
|
return Boolean(route && isRouteCacheEnabled(route.staticData) && route.ready && route.matchId && route.routerSnapshot);
|
|
@@ -961,7 +1015,8 @@ function RouteCacheManager() {
|
|
|
961
1015
|
const pendingCachedNavigationRef = useRef(null);
|
|
962
1016
|
const previousPathnameRef = useRef(void 0);
|
|
963
1017
|
const previousHrefRef = useRef(void 0);
|
|
964
|
-
const previousRouteCacheModesRef = useRef(
|
|
1018
|
+
const previousRouteCacheModesRef = useRef(null);
|
|
1019
|
+
if (previousRouteCacheModesRef.current === null) previousRouteCacheModesRef.current = /* @__PURE__ */ new Map();
|
|
965
1020
|
const previousVisiblePathnameRef = useRef(void 0);
|
|
966
1021
|
const routerLocation = useRouterState({ select: (state) => toRouterLocation(state.location) });
|
|
967
1022
|
const routerHref = routerLocation.href;
|
|
@@ -1057,6 +1112,7 @@ function RouteCacheManager() {
|
|
|
1057
1112
|
visiblePathname
|
|
1058
1113
|
]);
|
|
1059
1114
|
useLayoutEffect(() => {
|
|
1115
|
+
if (previousRouteCacheModesRef.current === null) previousRouteCacheModesRef.current = /* @__PURE__ */ new Map();
|
|
1060
1116
|
previousRouteCacheModesRef.current = syncCachedRouteActivityEvents({
|
|
1061
1117
|
cachedRoutes,
|
|
1062
1118
|
eventListener,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tanstack-router-cache",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Route view caching for TanStack Router.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -46,8 +46,8 @@
|
|
|
46
46
|
"build": "bun run clean && rolldown -c && tsc",
|
|
47
47
|
"typecheck": "tsc --noEmit",
|
|
48
48
|
"clean": "node -e \"fs.rmSync('dist',{recursive:true,force:true})\"",
|
|
49
|
-
"lint": "biome
|
|
50
|
-
"lint:fix": "biome
|
|
49
|
+
"lint": "biome lint src rolldown.config.ts --skip=lint/performance/noBarrelFile --skip=lint/style/useConsistentTypeDefinitions --skip=lint/suspicious/noConsole",
|
|
50
|
+
"lint:fix": "biome lint src rolldown.config.ts --write --skip=lint/performance/noBarrelFile --skip=lint/style/useConsistentTypeDefinitions --skip=lint/suspicious/noConsole",
|
|
51
51
|
"pack:dry-run": "bun pm pack --dry-run",
|
|
52
52
|
"prepack": "bun run build",
|
|
53
53
|
"prepublishOnly": "bun run lint && bun run typecheck"
|