clear-react-router 1.3.8 → 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,15 +185,27 @@ 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
195
206
  });
196
207
  return;
197
208
  }
198
- else setBeforeLoadError(false);
199
209
  if (seq !== navigationSeq.current) return;
200
210
  await revalidateCache({
201
211
  routeItem: nextItem,
@@ -208,7 +218,6 @@ var useHandleNavigation = ({ setLocation, routeList, context, revalidateCache, i
208
218
  isFirstCall,
209
219
  isAnimated
210
220
  });
211
- setBeforeLoadError(false);
212
221
  if (nextItem?.afterLoad) await nextItem.afterLoad({
213
222
  context,
214
223
  params,
@@ -221,7 +230,8 @@ var useHandleNavigation = ({ setLocation, routeList, context, revalidateCache, i
221
230
  transitionedNavigation,
222
231
  isAnimated,
223
232
  setContext,
224
- updateScrollMap
233
+ updateScrollMap,
234
+ setLoaderState
225
235
  ]);
226
236
  const setNextLocationRef = useLatest(navigationHandler);
227
237
  const updateBlockedRoute = useCallback(({ type, payload = "" }) => setBlockedRoute((prevState) => {
@@ -274,18 +284,14 @@ var useHandleNavigation = ({ setLocation, routeList, context, revalidateCache, i
274
284
  return "unblocked";
275
285
  }, [blockedRoute]),
276
286
  updateLocation,
277
- updateBlockedRoute,
278
- beforeLoadError
287
+ updateBlockedRoute
279
288
  };
280
289
  };
281
290
  //#endregion
282
291
  //#region hooks/useLoader.ts
283
- var useLoader = ({ routeList, context, setContext }) => {
284
- const [loaderCache, setLoaderCache] = useState();
285
- const [loaderError, setLoaderError] = useState(false);
292
+ var useLoader = ({ routeList, context, setContext, setLoaderState }) => {
286
293
  const [isLoading, setIsLoading] = useState(false);
287
294
  const cacheTimestampsRef = useRef({});
288
- const loaderCacheRef = useRef({});
289
295
  const isCacheItemFresh = useCallback(({ routeItem, pathname }) => {
290
296
  if (!routeItem) return true;
291
297
  const currentCacheTimestamp = cacheTimestampsRef.current[pathname];
@@ -294,28 +300,13 @@ var useLoader = ({ routeList, context, setContext }) => {
294
300
  return Date.now() - currentCacheTimestamp < routeItem.staleTime;
295
301
  }, []);
296
302
  const revalidateCache = useCallback(async ({ routeItem, isCurrentRoute, pathname }) => {
297
- if (!routeItem?.loader) {
298
- setLoaderError(false);
299
- return;
300
- }
301
- if (isCacheItemFresh({
302
- routeItem,
303
- pathname
304
- }) && isCurrentRoute) {
305
- setLoaderCache(loaderCacheRef.current[pathname]);
306
- setLoaderError(false);
307
- }
303
+ if (!routeItem?.loader) return;
308
304
  if (isCacheItemFresh({
309
305
  routeItem,
310
306
  pathname
311
307
  })) return;
312
308
  if (isCurrentRoute) setIsLoading(true);
313
- loaderCacheRef.current = Object.keys(loaderCacheRef.current).filter((el) => el !== routeItem.path).reduce((acc, cur) => ({
314
- ...acc,
315
- [cur]: loaderCacheRef.current[cur]
316
- }), {});
317
309
  try {
318
- if (isCurrentRoute) setLoaderError(false);
319
310
  const params = getParamsObject({
320
311
  routeItem,
321
312
  pathname
@@ -329,13 +320,23 @@ var useLoader = ({ routeList, context, setContext }) => {
329
320
  ...cacheTimestampsRef.current,
330
321
  [pathname]: Date.now()
331
322
  };
332
- loaderCacheRef.current = {
333
- ...loaderCacheRef.current,
334
- [pathname]: result
335
- };
336
- if (isCurrentRoute) setLoaderCache(result);
337
- } catch {
338
- 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
+ }));
339
340
  } finally {
340
341
  if (isCurrentRoute) setIsLoading(false);
341
342
  }
@@ -345,8 +346,6 @@ var useLoader = ({ routeList, context, setContext }) => {
345
346
  setContext
346
347
  ]);
347
348
  return {
348
- loaderCache,
349
- loaderError,
350
349
  prefetchLoader: useCallback(async (pathname) => {
351
350
  const item = routeList.find((el) => comparePaths(el, pathname));
352
351
  if (item) await revalidateCache({
@@ -417,31 +416,34 @@ var useApplyCustomAnimation = (animationDuration) => {
417
416
  var RouterProvider = ({ children, routeList, context: initialContext = {}, isAnimated = false, animationDuration, preserveScroll = true }) => {
418
417
  const [location, setLocation] = useState({});
419
418
  const [context, setContext] = useState(initialContext);
419
+ const [loaderState, setLoaderState] = useState({});
420
420
  useApplyCustomAnimation(animationDuration);
421
421
  const setScrollMap = usePreserveScroll({
422
422
  pathname: location.pathname,
423
423
  preserveScroll
424
424
  });
425
- const { loaderError, loaderCache, prefetchLoader, revalidateCache, isLoading } = useLoader({
425
+ const { prefetchLoader, revalidateCache, isLoading } = useLoader({
426
426
  routeList,
427
427
  context,
428
- setContext
428
+ setContext,
429
+ setLoaderState
429
430
  });
430
- const { blockerState, updateLocation, updateBlockedRoute, beforeLoadError } = useHandleNavigation({
431
+ const { blockerState, updateLocation, updateBlockedRoute } = useHandleNavigation({
431
432
  setLocation,
432
433
  routeList,
433
434
  context,
434
435
  setContext,
435
436
  revalidateCache,
436
437
  isAnimated,
437
- setScrollMap
438
+ setScrollMap,
439
+ setLoaderState
438
440
  });
439
441
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Provider, {
440
442
  ...useMemo(() => ({
441
443
  location,
442
444
  setLocation,
443
445
  updateLocation,
444
- loaderCache,
446
+ loaderState,
445
447
  prefetchLoader,
446
448
  updateBlockedRoute,
447
449
  blockerState,
@@ -449,15 +451,12 @@ var RouterProvider = ({ children, routeList, context: initialContext = {}, isAni
449
451
  setContext,
450
452
  routeList,
451
453
  isLoading,
452
- shouldErrorElementShown: loaderError || beforeLoadError,
453
454
  isAnimated
454
455
  }), [
455
- beforeLoadError,
456
456
  blockerState,
457
457
  context,
458
458
  isLoading,
459
- loaderCache,
460
- loaderError,
459
+ loaderState,
461
460
  location,
462
461
  prefetchLoader,
463
462
  routeList,
@@ -469,15 +468,6 @@ var RouterProvider = ({ children, routeList, context: initialContext = {}, isAni
469
468
  });
470
469
  };
471
470
  //#endregion
472
- //#region components/Spinner.tsx
473
- var Spinner = () => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "cr-spinner" });
474
- //#endregion
475
- //#region utils/renderElement.tsx
476
- var renderElement = (Component) => {
477
- if (!Component) return null;
478
- return typeof Component === "function" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Component, {}) : Component;
479
- };
480
- //#endregion
481
471
  //#region hooks/useServiceContext.ts
482
472
  var useServiceState = (reactContext) => {
483
473
  const context = useContext(reactContext);
@@ -500,12 +490,22 @@ var ViewProvider = ({ children, params }) => {
500
490
  });
501
491
  };
502
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
503
502
  //#region components/Router.tsx
504
503
  var PAGE_NOT_FOUND = "error 404. Page not found";
505
504
  var ALL_LOCATIONS = "*";
506
505
  var Router = ({ spinner = true }) => {
507
- const { location, isLoading, shouldErrorElementShown } = useNavigationState();
506
+ const { location, isLoading } = useNavigationState();
508
507
  const { routeList, isAnimated } = usePropsData();
508
+ const { loaderState } = useRouterData();
509
509
  const routeItem = useMemo(() => {
510
510
  if (!location.pathname) return void 0;
511
511
  return routeList.find((el) => el.path === ALL_LOCATIONS || comparePaths(el, location.pathname));
@@ -514,6 +514,7 @@ var Router = ({ spinner = true }) => {
514
514
  routeItem,
515
515
  pathname: window.location.pathname
516
516
  }), [routeItem]);
517
+ const shouldErrorElementShown = useMemo(() => Boolean(loaderState[location.pathname]?.loaderError || loaderState[location.pathname]?.beforeLoadError), [loaderState, location.pathname]);
517
518
  if (spinner && !routeItem && isLoading) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Spinner, {});
518
519
  if (!routeItem && isLoading) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Spinner, {});
519
520
  if (!routeItem) return null;
@@ -588,8 +589,9 @@ var useParams = () => {
588
589
  //#endregion
589
590
  //#region hooks/useLoaderState.ts
590
591
  var useLoaderState = () => {
591
- const { loaderCache } = useRouterData();
592
- return loaderCache;
592
+ const { pathname } = useLocation();
593
+ const { loaderState } = useRouterData();
594
+ return loaderState[pathname];
593
595
  };
594
596
  //#endregion
595
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.8",
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": {