clear-react-router 1.3.7 → 1.3.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.
@@ -1,5 +1,5 @@
1
1
  import { Dispatch, SetStateAction } from 'react';
2
- import { BlockerState, Location, RouteItem, UpdateBlockedRouteProps } from '../types/global';
2
+ import { BlockerState, LoaderState, Location, RouteItem, UpdateBlockedRouteProps } from '../types/global';
3
3
  export type PropsContextValue = {
4
4
  routeList: RouteItem[];
5
5
  isAnimated: boolean;
@@ -8,7 +8,6 @@ export type NavigationContextValue = {
8
8
  location: Location;
9
9
  blockerState: BlockerState;
10
10
  isLoading: boolean;
11
- shouldErrorElementShown: boolean;
12
11
  };
13
12
  export type ActionsContextValue = {
14
13
  setLocation: Dispatch<SetStateAction<Location>>;
@@ -18,7 +17,7 @@ export type ActionsContextValue = {
18
17
  setContext(arg: object): void;
19
18
  };
20
19
  export type DataContextValue = {
21
- loaderCache: unknown;
20
+ loaderState: LoaderState;
22
21
  context: Record<string, unknown>;
23
22
  };
24
23
  export declare const PropsContext: import("react").Context<PropsContextValue>;
@@ -1,5 +1,5 @@
1
1
  import { type Dispatch, type SetStateAction } from 'react';
2
- import type { BlockerState, Location, RevalidateCacheArgs, RouteItem, UpdateBlockedRouteProps } from '../types/global';
2
+ import type { BlockerState, LoaderState, Location, RevalidateCacheArgs, RouteItem, UpdateBlockedRouteProps } from '../types/global';
3
3
  type UseHandleNavigation = {
4
4
  routeList: RouteItem[];
5
5
  setLocation: (arg: Location) => void;
@@ -8,11 +8,11 @@ type UseHandleNavigation = {
8
8
  isAnimated: boolean;
9
9
  setContext: Dispatch<SetStateAction<Record<string, unknown>>>;
10
10
  setScrollMap: Dispatch<SetStateAction<Record<string, number>>>;
11
+ setLoaderState: Dispatch<SetStateAction<LoaderState>>;
11
12
  };
12
- export declare const useHandleNavigation: ({ setLocation, routeList, context, revalidateCache, isAnimated, setContext, setScrollMap, }: UseHandleNavigation) => {
13
+ export declare const useHandleNavigation: ({ setLocation, routeList, context, revalidateCache, isAnimated, setContext, setScrollMap, setLoaderState, }: UseHandleNavigation) => {
13
14
  blockerState: BlockerState;
14
15
  updateLocation: (nextLocation: Location) => Promise<void>;
15
16
  updateBlockedRoute: ({ type, payload }: UpdateBlockedRouteProps) => void;
16
- beforeLoadError: boolean;
17
17
  };
18
18
  export {};
@@ -1,13 +1,12 @@
1
1
  import { type Dispatch, type SetStateAction } from 'react';
2
- import type { RevalidateCacheArgs, RouteItem } from '../types/global';
2
+ import type { LoaderState, RevalidateCacheArgs, RouteItem } from '../types/global';
3
3
  type UseLoaderParams = {
4
4
  routeList: RouteItem[];
5
5
  context: Record<string, unknown>;
6
6
  setContext: Dispatch<SetStateAction<Record<string, unknown>>>;
7
+ setLoaderState: Dispatch<SetStateAction<LoaderState>>;
7
8
  };
8
- export declare const useLoader: ({ routeList, context, setContext }: UseLoaderParams) => {
9
- loaderCache: unknown;
10
- loaderError: boolean;
9
+ export declare const useLoader: ({ routeList, context, setContext, setLoaderState }: UseLoaderParams) => {
11
10
  prefetchLoader: (pathname: string) => Promise<void>;
12
11
  revalidateCache: ({ routeItem, isCurrentRoute, pathname }: RevalidateCacheArgs) => Promise<void>;
13
12
  isLoading: boolean;
package/dist/index.js CHANGED
@@ -45,7 +45,7 @@ var require_react_jsx_runtime_production = /* @__PURE__ */ __commonJSMin(((expor
45
45
  var import_jsx_runtime = (/* @__PURE__ */ __commonJSMin(((exports, module) => {
46
46
  module.exports = require_react_jsx_runtime_production();
47
47
  })))();
48
- var Provider = ({ children, setContext, context, updateBlockedRoute, updateLocation, location, setLocation, prefetchLoader, loaderCache, blockerState, routeList, shouldErrorElementShown, isLoading, isAnimated }) => {
48
+ var Provider = ({ children, setContext, context, updateBlockedRoute, updateLocation, location, setLocation, prefetchLoader, loaderState, blockerState, routeList, isLoading, isAnimated }) => {
49
49
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PropsContext.Provider, {
50
50
  value: {
51
51
  routeList,
@@ -62,13 +62,12 @@ var Provider = ({ children, setContext, context, updateBlockedRoute, updateLocat
62
62
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DataContext.Provider, {
63
63
  value: {
64
64
  context,
65
- loaderCache
65
+ loaderState
66
66
  },
67
67
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(NavigationContext.Provider, {
68
68
  value: {
69
69
  blockerState,
70
70
  location,
71
- shouldErrorElementShown,
72
71
  isLoading
73
72
  },
74
73
  children
@@ -139,12 +138,11 @@ var comparePaths = (el, pathname) => {
139
138
  };
140
139
  //#endregion
141
140
  //#region hooks/useHandleNavigation.ts
142
- var useHandleNavigation = ({ setLocation, routeList, context, revalidateCache, isAnimated, setContext, setScrollMap }) => {
141
+ var useHandleNavigation = ({ setLocation, routeList, context, revalidateCache, isAnimated, setContext, setScrollMap, setLoaderState }) => {
143
142
  const [blockedRoute, setBlockedRoute] = useState({
144
143
  from: "",
145
144
  to: ""
146
145
  });
147
- const [beforeLoadError, setBeforeLoadError] = useState(false);
148
146
  const prevPathname = useRef("");
149
147
  const navigationSeq = useRef(0);
150
148
  const updateScrollMap = useCallback(() => setScrollMap((prevState) => {
@@ -187,8 +185,21 @@ var useHandleNavigation = ({ setLocation, routeList, context, revalidateCache, i
187
185
  params,
188
186
  setContext
189
187
  });
190
- } catch {
191
- setBeforeLoadError(true);
188
+ setLoaderState((prevState) => ({
189
+ ...prevState,
190
+ [nextLocation.pathname]: {
191
+ ...prevState[nextLocation.pathname],
192
+ beforeLoadError: null
193
+ }
194
+ }));
195
+ } catch (error) {
196
+ setLoaderState((prevState) => ({
197
+ ...prevState,
198
+ [nextLocation.pathname]: {
199
+ ...prevState[nextLocation.pathname],
200
+ beforeLoadError: error
201
+ }
202
+ }));
192
203
  transitionedNavigation({
193
204
  nextLocation,
194
205
  isAnimated: false
@@ -207,7 +218,6 @@ var useHandleNavigation = ({ setLocation, routeList, context, revalidateCache, i
207
218
  isFirstCall,
208
219
  isAnimated
209
220
  });
210
- setBeforeLoadError(false);
211
221
  if (nextItem?.afterLoad) await nextItem.afterLoad({
212
222
  context,
213
223
  params,
@@ -220,7 +230,8 @@ var useHandleNavigation = ({ setLocation, routeList, context, revalidateCache, i
220
230
  transitionedNavigation,
221
231
  isAnimated,
222
232
  setContext,
223
- updateScrollMap
233
+ updateScrollMap,
234
+ setLoaderState
224
235
  ]);
225
236
  const setNextLocationRef = useLatest(navigationHandler);
226
237
  const updateBlockedRoute = useCallback(({ type, payload = "" }) => setBlockedRoute((prevState) => {
@@ -273,18 +284,14 @@ var useHandleNavigation = ({ setLocation, routeList, context, revalidateCache, i
273
284
  return "unblocked";
274
285
  }, [blockedRoute]),
275
286
  updateLocation,
276
- updateBlockedRoute,
277
- beforeLoadError
287
+ updateBlockedRoute
278
288
  };
279
289
  };
280
290
  //#endregion
281
291
  //#region hooks/useLoader.ts
282
- var useLoader = ({ routeList, context, setContext }) => {
283
- const [loaderCache, setLoaderCache] = useState();
284
- const [loaderError, setLoaderError] = useState(false);
292
+ var useLoader = ({ routeList, context, setContext, setLoaderState }) => {
285
293
  const [isLoading, setIsLoading] = useState(false);
286
294
  const cacheTimestampsRef = useRef({});
287
- const loaderCacheRef = useRef({});
288
295
  const isCacheItemFresh = useCallback(({ routeItem, pathname }) => {
289
296
  if (!routeItem) return true;
290
297
  const currentCacheTimestamp = cacheTimestampsRef.current[pathname];
@@ -294,21 +301,12 @@ var useLoader = ({ routeList, context, setContext }) => {
294
301
  }, []);
295
302
  const revalidateCache = useCallback(async ({ routeItem, isCurrentRoute, pathname }) => {
296
303
  if (!routeItem?.loader) return;
297
- if (isCacheItemFresh({
298
- routeItem,
299
- pathname
300
- }) && isCurrentRoute) setLoaderCache(loaderCacheRef.current[pathname]);
301
304
  if (isCacheItemFresh({
302
305
  routeItem,
303
306
  pathname
304
307
  })) return;
305
308
  if (isCurrentRoute) setIsLoading(true);
306
- loaderCacheRef.current = Object.keys(loaderCacheRef.current).filter((el) => el !== routeItem.path).reduce((acc, cur) => ({
307
- ...acc,
308
- [cur]: loaderCacheRef.current[cur]
309
- }), {});
310
309
  try {
311
- if (isCurrentRoute) setLoaderError(false);
312
310
  const params = getParamsObject({
313
311
  routeItem,
314
312
  pathname
@@ -322,13 +320,23 @@ var useLoader = ({ routeList, context, setContext }) => {
322
320
  ...cacheTimestampsRef.current,
323
321
  [pathname]: Date.now()
324
322
  };
325
- loaderCacheRef.current = {
326
- ...loaderCacheRef.current,
327
- [pathname]: result
328
- };
329
- if (isCurrentRoute) setLoaderCache(result);
330
- } catch {
331
- if (isCurrentRoute) setLoaderError(true);
323
+ if (isCurrentRoute) setLoaderState((prevState) => ({
324
+ ...prevState,
325
+ [pathname]: {
326
+ ...prevState[pathname],
327
+ data: result,
328
+ loaderError: null
329
+ }
330
+ }));
331
+ } catch (error) {
332
+ if (isCurrentRoute) setLoaderState((prevState) => ({
333
+ ...prevState,
334
+ [pathname]: {
335
+ ...prevState[pathname],
336
+ data: null,
337
+ loaderError: error
338
+ }
339
+ }));
332
340
  } finally {
333
341
  if (isCurrentRoute) setIsLoading(false);
334
342
  }
@@ -338,8 +346,6 @@ var useLoader = ({ routeList, context, setContext }) => {
338
346
  setContext
339
347
  ]);
340
348
  return {
341
- loaderCache,
342
- loaderError,
343
349
  prefetchLoader: useCallback(async (pathname) => {
344
350
  const item = routeList.find((el) => comparePaths(el, pathname));
345
351
  if (item) await revalidateCache({
@@ -410,31 +416,34 @@ var useApplyCustomAnimation = (animationDuration) => {
410
416
  var RouterProvider = ({ children, routeList, context: initialContext = {}, isAnimated = false, animationDuration, preserveScroll = true }) => {
411
417
  const [location, setLocation] = useState({});
412
418
  const [context, setContext] = useState(initialContext);
419
+ const [loaderState, setLoaderState] = useState({});
413
420
  useApplyCustomAnimation(animationDuration);
414
421
  const setScrollMap = usePreserveScroll({
415
422
  pathname: location.pathname,
416
423
  preserveScroll
417
424
  });
418
- const { loaderError, loaderCache, prefetchLoader, revalidateCache, isLoading } = useLoader({
425
+ const { prefetchLoader, revalidateCache, isLoading } = useLoader({
419
426
  routeList,
420
427
  context,
421
- setContext
428
+ setContext,
429
+ setLoaderState
422
430
  });
423
- const { blockerState, updateLocation, updateBlockedRoute, beforeLoadError } = useHandleNavigation({
431
+ const { blockerState, updateLocation, updateBlockedRoute } = useHandleNavigation({
424
432
  setLocation,
425
433
  routeList,
426
434
  context,
427
435
  setContext,
428
436
  revalidateCache,
429
437
  isAnimated,
430
- setScrollMap
438
+ setScrollMap,
439
+ setLoaderState
431
440
  });
432
441
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Provider, {
433
442
  ...useMemo(() => ({
434
443
  location,
435
444
  setLocation,
436
445
  updateLocation,
437
- loaderCache,
446
+ loaderState,
438
447
  prefetchLoader,
439
448
  updateBlockedRoute,
440
449
  blockerState,
@@ -442,15 +451,12 @@ var RouterProvider = ({ children, routeList, context: initialContext = {}, isAni
442
451
  setContext,
443
452
  routeList,
444
453
  isLoading,
445
- shouldErrorElementShown: loaderError || beforeLoadError,
446
454
  isAnimated
447
455
  }), [
448
- beforeLoadError,
449
456
  blockerState,
450
457
  context,
451
458
  isLoading,
452
- loaderCache,
453
- loaderError,
459
+ loaderState,
454
460
  location,
455
461
  prefetchLoader,
456
462
  routeList,
@@ -462,15 +468,6 @@ var RouterProvider = ({ children, routeList, context: initialContext = {}, isAni
462
468
  });
463
469
  };
464
470
  //#endregion
465
- //#region components/Spinner.tsx
466
- var Spinner = () => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "cr-spinner" });
467
- //#endregion
468
- //#region utils/renderElement.tsx
469
- var renderElement = (Component) => {
470
- if (!Component) return null;
471
- return typeof Component === "function" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Component, {}) : Component;
472
- };
473
- //#endregion
474
471
  //#region hooks/useServiceContext.ts
475
472
  var useServiceState = (reactContext) => {
476
473
  const context = useContext(reactContext);
@@ -493,12 +490,22 @@ var ViewProvider = ({ children, params }) => {
493
490
  });
494
491
  };
495
492
  //#endregion
493
+ //#region components/Spinner.tsx
494
+ var Spinner = () => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "cr-spinner" });
495
+ //#endregion
496
+ //#region utils/renderElement.tsx
497
+ var renderElement = (Component) => {
498
+ if (!Component) return null;
499
+ return typeof Component === "function" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Component, {}) : Component;
500
+ };
501
+ //#endregion
496
502
  //#region components/Router.tsx
497
503
  var PAGE_NOT_FOUND = "error 404. Page not found";
498
504
  var ALL_LOCATIONS = "*";
499
505
  var Router = ({ spinner = true }) => {
500
- const { location, isLoading, shouldErrorElementShown } = useNavigationState();
506
+ const { location, isLoading } = useNavigationState();
501
507
  const { routeList, isAnimated } = usePropsData();
508
+ const { loaderState } = useRouterData();
502
509
  const routeItem = useMemo(() => {
503
510
  if (!location.pathname) return void 0;
504
511
  return routeList.find((el) => el.path === ALL_LOCATIONS || comparePaths(el, location.pathname));
@@ -507,6 +514,7 @@ var Router = ({ spinner = true }) => {
507
514
  routeItem,
508
515
  pathname: window.location.pathname
509
516
  }), [routeItem]);
517
+ const shouldErrorElementShown = useMemo(() => Boolean(loaderState[location.pathname]?.loaderError || loaderState[location.pathname]?.beforeLoadError), [loaderState, location.pathname]);
510
518
  if (spinner && !routeItem && isLoading) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Spinner, {});
511
519
  if (!routeItem && isLoading) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Spinner, {});
512
520
  if (!routeItem) return null;
@@ -581,8 +589,9 @@ var useParams = () => {
581
589
  //#endregion
582
590
  //#region hooks/useLoaderState.ts
583
591
  var useLoaderState = () => {
584
- const { loaderCache } = useRouterData();
585
- return loaderCache;
592
+ const { pathname } = useLocation();
593
+ const { loaderState } = useRouterData();
594
+ return loaderState[pathname];
586
595
  };
587
596
  //#endregion
588
597
  //#region hooks/useBlocker.ts
@@ -3,5 +3,5 @@ import { type ActionsContextValue, type DataContextValue, type NavigationContext
3
3
  type ProviderProps = PropsContextValue & NavigationContextValue & ActionsContextValue & DataContextValue & {
4
4
  children: ReactNode;
5
5
  };
6
- export declare const Provider: ({ children, setContext, context, updateBlockedRoute, updateLocation, location, setLocation, prefetchLoader, loaderCache, blockerState, routeList, shouldErrorElementShown, isLoading, isAnimated, }: ProviderProps) => import("react/jsx-runtime").JSX.Element;
6
+ export declare const Provider: ({ children, setContext, context, updateBlockedRoute, updateLocation, location, setLocation, prefetchLoader, loaderState, blockerState, routeList, isLoading, isAnimated, }: ProviderProps) => import("react/jsx-runtime").JSX.Element;
7
7
  export {};
@@ -50,3 +50,8 @@ export type RevalidateCacheArgs = {
50
50
  routeItem?: RouteItem;
51
51
  isCurrentRoute?: boolean;
52
52
  };
53
+ export type LoaderState = Record<string, {
54
+ data: unknown;
55
+ loaderError: Error | null;
56
+ beforeLoadError: Error | null;
57
+ }>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clear-react-router",
3
- "version": "1.3.7",
3
+ "version": "1.3.9",
4
4
  "description": "A lightweight, type-safe routing library for React applications",
5
5
  "author": "Andrew Bubnov",
6
6
  "scripts": {