clear-react-router 1.3.3 → 1.3.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.
package/README.md
CHANGED
|
@@ -12,6 +12,7 @@ A lightweight, type-safe routing library for React applications with nested rout
|
|
|
12
12
|
- 🎯 **Type-safe Redirects** - Redirect from beforeLoad hook
|
|
13
13
|
- 📦 **Prefetching** - Preload data on hover for instant navigation
|
|
14
14
|
- 🚀 **Lazy Loading** - Code-split your routes with dynamic imports for optimal performance
|
|
15
|
+
- 📍 **Scroll Restoration** — Automatically saves and restores scroll position when navigating back to a page (preserves user's scroll position)
|
|
15
16
|
- 🎨 **Flexible API** - Use components or hooks as you prefer
|
|
16
17
|
- 📱 **Browser History** - Full support for browser back/forward buttons
|
|
17
18
|
- 🧠 **Context-aware** - Pass and update context through routes
|
|
@@ -45,6 +46,7 @@ The root component that provides routing context to the application. Place stati
|
|
|
45
46
|
| `context` | `object` | `{}` | Initial context (user, theme, etc.) |
|
|
46
47
|
| `isAnimated` | `boolean` | `false` | Enable smooth page transitions |
|
|
47
48
|
| `animationDuration` | `number` | `optional` | Animation duration in milliseconds (browser default is used if not set) |
|
|
49
|
+
| `preserveScroll` | `boolean` | `true` | Save and restore scroll position when navigating between pages |
|
|
48
50
|
| `children` | `ReactNode` | required | App content (must include `<Router />`) |
|
|
49
51
|
|
|
50
52
|
```
|
|
@@ -6,6 +6,7 @@ type RouteProviderProps = {
|
|
|
6
6
|
context?: Record<string, unknown>;
|
|
7
7
|
isAnimated?: boolean;
|
|
8
8
|
animationDuration?: number;
|
|
9
|
+
preserveScroll?: boolean;
|
|
9
10
|
};
|
|
10
|
-
export declare const RouterProvider: ({ children, routeList, context: initialContext, isAnimated, animationDuration, }: RouteProviderProps) => import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
export declare const RouterProvider: ({ children, routeList, context: initialContext, isAnimated, animationDuration, preserveScroll, }: RouteProviderProps) => import("react/jsx-runtime").JSX.Element;
|
|
11
12
|
export {};
|
|
@@ -7,8 +7,9 @@ type UseHandleNavigation = {
|
|
|
7
7
|
revalidateCache(arg: RevalidateCacheArgs): Promise<void>;
|
|
8
8
|
isAnimated: boolean;
|
|
9
9
|
setContext: Dispatch<SetStateAction<Record<string, unknown>>>;
|
|
10
|
+
setScrollMap: Dispatch<SetStateAction<Record<string, number>>>;
|
|
10
11
|
};
|
|
11
|
-
export declare const useHandleNavigation: ({ setLocation, routeList, context, revalidateCache, isAnimated, setContext, }: UseHandleNavigation) => {
|
|
12
|
+
export declare const useHandleNavigation: ({ setLocation, routeList, context, revalidateCache, isAnimated, setContext, setScrollMap, }: UseHandleNavigation) => {
|
|
12
13
|
blockerState: BlockerState;
|
|
13
14
|
updateLocation: (nextLocation: Location) => Promise<void>;
|
|
14
15
|
updateBlockedRoute: ({ type, payload }: UpdateBlockedRouteProps) => void;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
type UsePreserveScrollParams = {
|
|
2
|
+
pathname: string;
|
|
3
|
+
preserveScroll: boolean;
|
|
4
|
+
};
|
|
5
|
+
export declare const usePreserveScroll: ({ pathname, preserveScroll }: UsePreserveScrollParams) => import("react").Dispatch<import("react").SetStateAction<Record<string, number>>>;
|
|
6
|
+
export {};
|
package/dist/index.js
CHANGED
|
@@ -138,7 +138,7 @@ var comparePaths = (el, pathname) => {
|
|
|
138
138
|
};
|
|
139
139
|
//#endregion
|
|
140
140
|
//#region hooks/useHandleNavigation.ts
|
|
141
|
-
var useHandleNavigation = ({ setLocation, routeList, context, revalidateCache, isAnimated, setContext }) => {
|
|
141
|
+
var useHandleNavigation = ({ setLocation, routeList, context, revalidateCache, isAnimated, setContext, setScrollMap }) => {
|
|
142
142
|
const [blockedRoute, setBlockedRoute] = useState({
|
|
143
143
|
from: "",
|
|
144
144
|
to: ""
|
|
@@ -146,6 +146,14 @@ var useHandleNavigation = ({ setLocation, routeList, context, revalidateCache, i
|
|
|
146
146
|
const [beforeLoadError, setBeforeLoadError] = useState(false);
|
|
147
147
|
const prevPathname = useRef("");
|
|
148
148
|
const navigationSeq = useRef(0);
|
|
149
|
+
const updateScrollMap = useCallback(() => setScrollMap((prevState) => {
|
|
150
|
+
const scrollPosition = document.scrollingElement?.scrollTop ?? 0;
|
|
151
|
+
if (!scrollPosition || prevState[prevPathname.current] === scrollPosition) return prevState;
|
|
152
|
+
return {
|
|
153
|
+
...prevState,
|
|
154
|
+
[prevPathname.current]: scrollPosition
|
|
155
|
+
};
|
|
156
|
+
}), [setScrollMap]);
|
|
149
157
|
const navigation = useCallback((nextLocation) => {
|
|
150
158
|
setLocation(nextLocation);
|
|
151
159
|
prevPathname.current = nextLocation.pathname;
|
|
@@ -164,6 +172,7 @@ var useHandleNavigation = ({ setLocation, routeList, context, revalidateCache, i
|
|
|
164
172
|
const navigationHandler = useCallback(async (nextLocation, isFirstCall) => {
|
|
165
173
|
navigationSeq.current = navigationSeq.current + 1;
|
|
166
174
|
const seq = navigationSeq.current;
|
|
175
|
+
updateScrollMap();
|
|
167
176
|
const nextItem = routeList.find((el) => comparePaths(el, nextLocation.pathname));
|
|
168
177
|
const params = getParamsObject({
|
|
169
178
|
routeItem: nextItem,
|
|
@@ -209,7 +218,8 @@ var useHandleNavigation = ({ setLocation, routeList, context, revalidateCache, i
|
|
|
209
218
|
routeList,
|
|
210
219
|
transitionedNavigation,
|
|
211
220
|
isAnimated,
|
|
212
|
-
setContext
|
|
221
|
+
setContext,
|
|
222
|
+
updateScrollMap
|
|
213
223
|
]);
|
|
214
224
|
const setNextLocationRef = useLatest(navigationHandler);
|
|
215
225
|
const updateBlockedRoute = useCallback(({ type, payload = "" }) => setBlockedRoute((prevState) => {
|
|
@@ -341,6 +351,23 @@ var useLoader = ({ routeList, context, setContext }) => {
|
|
|
341
351
|
};
|
|
342
352
|
};
|
|
343
353
|
//#endregion
|
|
354
|
+
//#region hooks/usePreserveScroll.ts
|
|
355
|
+
var usePreserveScroll = ({ pathname, preserveScroll }) => {
|
|
356
|
+
const [scrollMap, setScrollMap] = useState({});
|
|
357
|
+
useEffect(() => {
|
|
358
|
+
if (!preserveScroll || !pathname || !scrollMap[pathname]) return;
|
|
359
|
+
document.scrollingElement?.scrollTo({
|
|
360
|
+
top: scrollMap[pathname],
|
|
361
|
+
behavior: "smooth"
|
|
362
|
+
});
|
|
363
|
+
}, [
|
|
364
|
+
pathname,
|
|
365
|
+
scrollMap,
|
|
366
|
+
preserveScroll
|
|
367
|
+
]);
|
|
368
|
+
return setScrollMap;
|
|
369
|
+
};
|
|
370
|
+
//#endregion
|
|
344
371
|
//#region hooks/useApplyCustomAnimation.ts
|
|
345
372
|
var useApplyCustomAnimation = (animationDuration) => {
|
|
346
373
|
useEffect(() => {
|
|
@@ -379,10 +406,14 @@ var useApplyCustomAnimation = (animationDuration) => {
|
|
|
379
406
|
};
|
|
380
407
|
//#endregion
|
|
381
408
|
//#region components/RouterProvider.tsx
|
|
382
|
-
var RouterProvider = ({ children, routeList, context: initialContext = {}, isAnimated = false, animationDuration }) => {
|
|
409
|
+
var RouterProvider = ({ children, routeList, context: initialContext = {}, isAnimated = false, animationDuration, preserveScroll = true }) => {
|
|
383
410
|
const [location, setLocation] = useState({});
|
|
384
411
|
const [context, setContext] = useState(initialContext);
|
|
385
412
|
useApplyCustomAnimation(animationDuration);
|
|
413
|
+
const setScrollMap = usePreserveScroll({
|
|
414
|
+
pathname: location.pathname,
|
|
415
|
+
preserveScroll
|
|
416
|
+
});
|
|
386
417
|
const { loaderError, loaderCache, prefetchLoader, revalidateCache, isLoading } = useLoader({
|
|
387
418
|
routeList,
|
|
388
419
|
context,
|
|
@@ -394,7 +425,8 @@ var RouterProvider = ({ children, routeList, context: initialContext = {}, isAni
|
|
|
394
425
|
context,
|
|
395
426
|
setContext,
|
|
396
427
|
revalidateCache,
|
|
397
|
-
isAnimated
|
|
428
|
+
isAnimated,
|
|
429
|
+
setScrollMap
|
|
398
430
|
});
|
|
399
431
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Provider, {
|
|
400
432
|
...useMemo(() => ({
|