clear-react-router 2.0.5 → 2.0.6

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
@@ -46,10 +46,10 @@ It provides first-class support for:
46
46
  | `maxCacheSize` | `number \| undefined` | 60 for mobile, 150 for desktop | Maximum number of cached loader entries. Once the limit is reached, the least recently used entries are evicted |
47
47
  | `isAnimated` | `boolean \| undefined` | `false` | Enable smooth page fade transitions |
48
48
  | `animationDuration` | `number` | `optional` | Animation duration in milliseconds (browser default is used if not set) |
49
- | `spinner` | `boolean \| undefined` | `true` | Show a small spinner in the corner while loading data (only when `isAnimated` is enabled) |
49
+ | `optimisticSpinner` | `boolean \| undefined` | `true` | Show a small spinner in the corner while optimistic route data revalidates in the background |
50
50
  | `context` | `object` | `{}` | Initial context (user, theme, etc.) |
51
51
  | `errorBoundary` | `ComponentType<{ children: ReactNode }>` | `undefined` | Custom error boundary component for catching render errors in route components |
52
- | `showFallbackOnAnimation` | `boolean \| undefined` | `false` | Show `loaderFallback` even when `isAnimated` is `true` (instead of spinner) |
52
+ | `defaultMinLoaderDuration` | `number \| undefined` | `0` | Default minimum time the loader fallback stays visible, to avoid flickering |
53
53
  | `defaultLoaderFallback` | `ReactElement \| () => ReactElement` | `optional` | Default loading fallback for every route loader |
54
54
  | `defaultErrorElement` | `ReactElement \| () => ReactElement` | `optional` | Default error fallback for every route |
55
55
  | `defaultRetry` | `number \| { count: number; delay: number }` | `optional` | Default cache revalidation retry policy for all routes |
@@ -63,14 +63,6 @@ It provides first-class support for:
63
63
 
64
64
  > **Note:** Global lifecycle hooks wrap every route navigation. The global `defaultBeforeLoad` runs **before** the route-specific beforeLoad, while the global `defaultAfterLoad` runs **after** the route-specific afterLoad.
65
65
 
66
- ```tsx
67
- <div>
68
- <Navbar />
69
- <Router routes={routes} spinner={false} isAnimated /> {/* disable the spinner */}
70
- </div>
71
- ```
72
- > **Note:** When `isAnimated` is enabled, `loaderFallback` is not shown. Instead, a small spinner appears (if `spinner={true}`). On the initial page load, however, the route's loaderFallback is rendered if available.
73
-
74
66
  ### `createRouter(routes)`
75
67
 
76
68
  Normalizes route configuration. Extracts dynamic params, builds nested paths.
@@ -82,6 +74,7 @@ Normalizes route configuration. Extracts dynamic params, builds nested paths.
82
74
  | `beforeLoad` | `({ params, context, redirect, setContext }) => Promise<unknown> \| undefined \| void` | Runs before every route navigation. Auth checks and redirects. Can update context via `setContext`. `redirect` is provided by the router |
83
75
  | `loader` | `({ params, context, setContext, searchParams, signal }) => Promise<unknown>` | Fetch data using route params, search params, abort controller signal and context. Can update context via `setContext` |
84
76
  | `afterLoad` | `({ params, context, setContext }) => Promise<void>` | Runs after a successful navigation once the route has finished loading. Analytics, side effects after data is loaded. Can update context via `setContext` |
77
+ | `minLoaderDuration` | `number \| undefined` | `undefined` | Minimum time the loader fallback stays visible, to avoid flickering |
85
78
  | `fallback` | `ReactElement \| () => ReactElement` | Loading fallback (for lazy loading) |
86
79
  | `loaderFallback` | `ReactElement \| () => ReactElement` | Loading fallback for the route's `loader`. Overrides the global `defaultLoaderFallback` set in `Router` |
87
80
  | `retry` | `number \| { count: number; delay: number }` | Overrides the global cache revalidation retry policy for this route |
@@ -816,8 +809,6 @@ Clear Router supports smooth page transitions using the native View Transitions
816
809
  ## How It Works
817
810
 
818
811
  - **Data loads first** — All `loader` and `beforeLoad` hooks complete before animation starts
819
- - **No `loaderFallback`** — The `loaderFallback` is not shown during animated transitions
820
- - **Subtle spinner** — A small spinner appears in the top-left corner while data is loading and `spinner` prop of `Router` component is on, so users know the app is responsive
821
812
  - **Native API** — Uses `document.startViewTransition` for smooth, hardware-accelerated animations
822
813
 
823
814
  ## Browser Support
@@ -1,2 +1,2 @@
1
1
  import { RouterProps } from '../types';
2
- export declare const Router: ({ routes, defaultBeforeLoad, defaultAfterLoad, animationDuration, defaultLoaderFallback, defaultErrorElement, defaultRetry, defaultStaleTime, context: initialContext, isAnimated, spinner, defaultPreserveScroll, showFallbackOnAnimation, maxCacheSize, defaultPrefetch, defaultHoverPrefetchDelay, errorBoundary: ErrorBoundary, }: RouterProps) => import("react/jsx-runtime").JSX.Element | null;
2
+ export declare const Router: ({ routes, defaultBeforeLoad, defaultAfterLoad, animationDuration, defaultLoaderFallback, defaultErrorElement, defaultRetry, defaultStaleTime, context: initialContext, isAnimated, optimisticSpinner, defaultPreserveScroll, defaultMinLoaderDuration, maxCacheSize, defaultPrefetch, defaultHoverPrefetchDelay, errorBoundary: ErrorBoundary, }: RouterProps) => import("react/jsx-runtime").JSX.Element | null;
@@ -10,6 +10,7 @@ declare class RouterConfig {
10
10
  defaultRetry?: RouterProps['defaultRetry'];
11
11
  defaultStaleTime?: RouterProps['defaultStaleTime'];
12
12
  defaultPreserveScroll?: RouterProps['defaultPreserveScroll'];
13
+ defaultMinLoaderDuration?: RouterProps['defaultMinLoaderDuration'];
13
14
  configure(config: Partial<RouterConfig>): void;
14
15
  }
15
16
  export declare const routerConfig: RouterConfig;
package/dist/index.js CHANGED
@@ -30,12 +30,13 @@ var useGlobalState = ({ subscribe, getState, setState }) => {
30
30
  };
31
31
  //#endregion
32
32
  //#region utils/commitState.ts
33
- var createCommitState = ({ routeItemDataState, pendingState }) => (nextLocation, routeItem) => {
33
+ var createCommitState = ({ routeItemDataState, pendingState, isOptimisticLoading }) => (nextLocation, routeItem) => {
34
34
  routeItemDataState.setState({
35
35
  routeItem,
36
36
  location: nextLocation
37
37
  });
38
38
  pendingState.setState(void 0);
39
+ isOptimisticLoading.setState(false);
39
40
  const fullPath = nextLocation.search ? `${nextLocation.pathname}${nextLocation.search}` : nextLocation.pathname;
40
41
  if (fullPath === window.location.pathname + window.location.search) return;
41
42
  history.pushState(null, "", fullPath);
@@ -95,6 +96,7 @@ var RouterConfig = class {
95
96
  _defineProperty(this, "defaultRetry", void 0);
96
97
  _defineProperty(this, "defaultStaleTime", void 0);
97
98
  _defineProperty(this, "defaultPreserveScroll", void 0);
99
+ _defineProperty(this, "defaultMinLoaderDuration", void 0);
98
100
  }
99
101
  configure(config) {
100
102
  Object.assign(this, config);
@@ -103,13 +105,12 @@ var RouterConfig = class {
103
105
  var routerConfig = new RouterConfig();
104
106
  //#endregion
105
107
  //#region utils/commitNavigation.ts
106
- var createCommitNavigation = (navigationExecutor, routeItemDataState) => (nextLocation, routeItem) => {
107
- const isFirstLoad = !routeItemDataState.getState().location.pathname;
108
- if (!routerConfig.isAnimated || isFirstLoad) return navigationExecutor(nextLocation, routeItem);
108
+ var commitNavigation = (callback) => {
109
+ if (!routerConfig.isAnimated) return callback();
109
110
  try {
110
- document.startViewTransition(() => navigationExecutor(nextLocation, routeItem));
111
+ document.startViewTransition(callback);
111
112
  } catch {
112
- navigationExecutor(nextLocation, routeItem);
113
+ callback();
113
114
  }
114
115
  };
115
116
  //#endregion
@@ -133,7 +134,7 @@ var createIsCacheItemFresh = (loaderMap) => (path) => {
133
134
  * LICENSE file in the root directory of this source tree.
134
135
  */
135
136
  var require_react_jsx_runtime_production = /* @__PURE__ */ __commonJSMin(((exports) => {
136
- var REACT_ELEMENT_TYPE = Symbol.for("react.transitional.element"), REACT_FRAGMENT_TYPE = Symbol.for("react.fragment");
137
+ var REACT_ELEMENT_TYPE = Symbol.for("react.transitional.element");
137
138
  function jsxProd(type, config, maybeKey) {
138
139
  var key = null;
139
140
  void 0 !== maybeKey && (key = "" + maybeKey);
@@ -151,7 +152,6 @@ var require_react_jsx_runtime_production = /* @__PURE__ */ __commonJSMin(((expor
151
152
  props: maybeKey
152
153
  };
153
154
  }
154
- exports.Fragment = REACT_FRAGMENT_TYPE;
155
155
  exports.jsx = jsxProd;
156
156
  exports.jsxs = jsxProd;
157
157
  }));
@@ -215,6 +215,7 @@ var isMobile = () => {
215
215
  const isSmallScreen = window.matchMedia("(max-width: 768px)").matches;
216
216
  return hasCoarsePointer && isSmallScreen;
217
217
  };
218
+ var sleep = async (ms) => new Promise((resolve) => setTimeout(resolve, ms));
218
219
  var findRoute = (pathname, includeAll) => {
219
220
  if (includeAll) return routerConfig.routes.find((el) => el.path === "*" || comparePaths(el, pathname));
220
221
  return routerConfig.routes.find((el) => comparePaths(el, pathname));
@@ -225,14 +226,15 @@ var createNavigate = (routerState, revalidateCache) => {
225
226
  let navigationSeq = 0;
226
227
  let interval = 0;
227
228
  let abortController = null;
228
- const { loaderStateRef, scrollMapState, pendingState, contextState, loaderMap, routeItemDataState } = routerState;
229
- const commitNavigation = createCommitNavigation(createCommitState(routerState), routeItemDataState);
229
+ const { loaderStateRef, scrollMapState, pendingState, contextState, loaderMap, routeItemDataState, isOptimisticLoading } = routerState;
230
+ const navigationExecutor = createCommitState(routerState);
230
231
  const isCacheItemFresh = createIsCacheItemFresh(loaderMap);
231
232
  const createSignal = () => {
232
233
  abortController?.abort();
233
234
  abortController = new AbortController();
234
235
  return abortController.signal;
235
236
  };
237
+ const getPath = (nextLocation) => `${nextLocation.pathname}${nextLocation.search ?? ""}`;
236
238
  const getContext = () => ({
237
239
  context: contextState.getState(),
238
240
  setContext: contextState.setState
@@ -279,44 +281,47 @@ var createNavigate = (routerState, revalidateCache) => {
279
281
  [prevPathname]: scrollPosition
280
282
  };
281
283
  });
282
- const path = `${location.pathname}${location.search}`;
284
+ const path = getPath(location);
283
285
  if (routeItem?.optimistic && loaderMap.has(path)) {
284
286
  routeItemDataState.setState({
285
287
  routeItem,
286
288
  location
287
289
  });
290
+ isOptimisticLoading.setState(true);
288
291
  const currentLoaderState = loaderMap.get(path)?.state;
289
292
  if (currentLoaderState) loaderStateRef.set(currentLoaderState);
290
- } else {
291
- const pendingShouldExist = routeItem?.loader && !isCacheItemFresh(path);
292
- pendingState.setState(pendingShouldExist ? {
293
- routeItem,
294
- location
295
- } : void 0);
296
- }
293
+ } else if (routeItem?.loader && !isCacheItemFresh(path)) commitNavigation(() => pendingState.setState({
294
+ routeItem,
295
+ location
296
+ }));
297
+ else pendingState.setState(void 0);
297
298
  };
298
- const polling = (routeItem, location) => {
299
+ const polling = (routeItem, nextLocation) => {
299
300
  if (!routeItem?.pollingInterval) return;
300
301
  const signal = createSignal();
301
302
  interval = window.setInterval(() => revalidateCache({
302
303
  routeItem,
303
- pathname: location.pathname,
304
- search: location.search,
304
+ pathname: nextLocation.pathname,
305
+ search: nextLocation.search,
305
306
  signal
306
307
  }), routeItem.pollingInterval);
307
308
  };
308
- const loader = async (routeItem, location, seq) => {
309
+ const getLoaderDurationPromise = (routeItem, nextLocation) => {
310
+ const minLoaderDuration = routeItem?.minLoaderDuration ?? routerConfig.defaultMinLoaderDuration ?? 0;
311
+ return minLoaderDuration && !isCacheItemFresh(getPath(nextLocation)) ? sleep(minLoaderDuration) : Promise.resolve;
312
+ };
313
+ const loader = async (routeItem, nextLocation, seq) => {
309
314
  if (!routeItem?.loader) return;
310
315
  window.clearInterval(interval);
311
316
  const signal = createSignal();
312
- await revalidateCache({
317
+ await Promise.all([revalidateCache({
313
318
  routeItem,
314
- pathname: location.pathname,
315
- search: location.search,
319
+ pathname: nextLocation.pathname,
320
+ search: nextLocation.search,
316
321
  signal
317
- });
322
+ }), getLoaderDurationPromise(routeItem, nextLocation)]);
318
323
  if (seq !== navigationSeq) return;
319
- polling(routeItem, location);
324
+ polling(routeItem, nextLocation);
320
325
  };
321
326
  const afterLoad = async (routeItem, params) => {
322
327
  const { defaultAfterLoad } = routerConfig;
@@ -338,7 +343,7 @@ var createNavigate = (routerState, revalidateCache) => {
338
343
  prepareNavigation(nextItem, nextLocation);
339
344
  await loader(nextItem, nextLocation, seq);
340
345
  if (seq !== navigationSeq) return;
341
- commitNavigation(nextLocation, nextItem);
346
+ commitNavigation(() => navigationExecutor(nextLocation, nextItem));
342
347
  await afterLoad(nextItem, params);
343
348
  };
344
349
  return navigate;
@@ -430,16 +435,8 @@ var getRetry = (routeItem) => {
430
435
  delay: routeRetry ? routeRetry.delay : globalRetry?.delay || 0
431
436
  };
432
437
  };
433
- var sleep = async (ms) => new Promise((resolve) => setTimeout(resolve, ms));
434
438
  var createRevalidateCache = (routerState) => {
435
439
  const { loaderStateRef, contextState, loaderMap, loadingPromises } = routerState;
436
- const removeStaleItems = () => {
437
- const deletedItems = [...loaderMap.entries()].filter(([, item]) => {
438
- const staleTime = item.staleTime ?? routerConfig.defaultStaleTime;
439
- return staleTime && staleTime + item.timestamp < Date.now();
440
- });
441
- if (deletedItems.length) deletedItems.forEach((item) => loaderMap.delete(item[0]));
442
- };
443
440
  const evict = () => {
444
441
  if (loaderMap.size <= routerConfig.maxCacheSize) return;
445
442
  const oldestKey = loaderMap.keys().next().value;
@@ -456,7 +453,6 @@ var createRevalidateCache = (routerState) => {
456
453
  const revalidateCache = async ({ routeItem, pathname, search = "", signal }, retried = 0) => {
457
454
  if (!routeItem?.loader) return;
458
455
  const isCacheItemFresh = createIsCacheItemFresh(loaderMap);
459
- removeStaleItems();
460
456
  const path = `${pathname}${search}`;
461
457
  if (loadingPromises.has(path)) {
462
458
  moveItemToLastPosition(path);
@@ -566,6 +562,7 @@ var createRouterInstance = () => {
566
562
  from: "",
567
563
  to: ""
568
564
  }),
565
+ isOptimisticLoading: create(false),
569
566
  loaderStateRef: new Cell(emptyLoaderState),
570
567
  loaderMap: /* @__PURE__ */ new Map(),
571
568
  loadingPromises: /* @__PURE__ */ new Map()
@@ -606,6 +603,7 @@ var createRouterInstance = () => {
606
603
  useScrollMap: () => useGlobalState(routerState.scrollMapState),
607
604
  usePendingState: () => useGlobalState(routerState.pendingState),
608
605
  useContextState: () => useGlobalState(routerState.contextState),
606
+ useOptimisticLoading: () => useGlobalState(routerState.isOptimisticLoading),
609
607
  useParams: () => getParamsObject(),
610
608
  useNavigate: () => {
611
609
  const { blockedRouteState } = routerState;
@@ -758,12 +756,13 @@ var EmptyBoundary = ({ children }) => children;
758
756
  var IS_MOBILE = isMobile();
759
757
  var MOBILE_CACHE_SIZE = 60;
760
758
  var DESKTOP_CACHE_SIZE = 150;
761
- var Router = ({ routes, defaultBeforeLoad, defaultAfterLoad, animationDuration, defaultLoaderFallback, defaultErrorElement, defaultRetry, defaultStaleTime, context: initialContext, isAnimated = false, spinner = true, defaultPreserveScroll = true, showFallbackOnAnimation = false, maxCacheSize = IS_MOBILE ? MOBILE_CACHE_SIZE : DESKTOP_CACHE_SIZE, defaultPrefetch = IS_MOBILE ? "viewport" : "hover", defaultHoverPrefetchDelay = 150, errorBoundary: ErrorBoundary = EmptyBoundary }) => {
762
- const { useRouteItemData, usePendingState } = router.hooks;
759
+ var Router = ({ routes, defaultBeforeLoad, defaultAfterLoad, animationDuration, defaultLoaderFallback, defaultErrorElement, defaultRetry, defaultStaleTime, context: initialContext, isAnimated = false, optimisticSpinner = true, defaultPreserveScroll = true, defaultMinLoaderDuration = 0, maxCacheSize = IS_MOBILE ? MOBILE_CACHE_SIZE : DESKTOP_CACHE_SIZE, defaultPrefetch = IS_MOBILE ? "viewport" : "hover", defaultHoverPrefetchDelay = 150, errorBoundary: ErrorBoundary = EmptyBoundary }) => {
760
+ const { useRouteItemData, usePendingState, useOptimisticLoading } = router.hooks;
763
761
  const [routeItemData] = useRouteItemData();
764
- const [pendingState] = usePendingState();
762
+ const [pendingRouteData] = usePendingState();
763
+ const [isOptimisticLoading] = useOptimisticLoading();
765
764
  const loaderState = router.state.loaderStateRef.value;
766
- const isLoading = Boolean(pendingState);
765
+ const isLoading = Boolean(pendingRouteData);
767
766
  useNavigation();
768
767
  useSetRouterConfig({
769
768
  routes,
@@ -775,6 +774,7 @@ var Router = ({ routes, defaultBeforeLoad, defaultAfterLoad, animationDuration,
775
774
  defaultRetry,
776
775
  defaultStaleTime,
777
776
  defaultPreserveScroll,
777
+ defaultMinLoaderDuration,
778
778
  maxCacheSize
779
779
  });
780
780
  useApplyCustomAnimation(animationDuration);
@@ -782,15 +782,12 @@ var Router = ({ routes, defaultBeforeLoad, defaultAfterLoad, animationDuration,
782
782
  usePreserveScroll(routeItemData);
783
783
  const { routeItem, location } = routeItemData;
784
784
  const showErrorElement = !isLoading && Boolean(loaderState.loaderError || loaderState.beforeLoadError);
785
- const showSpinner = spinner && isAnimated && isLoading;
786
- const loadingContent = !showErrorElement && isLoading;
787
- if ((showFallbackOnAnimation || !isAnimated) && loadingContent) return renderElement(pendingState?.routeItem?.loaderFallback || defaultLoaderFallback);
788
- if (!showFallbackOnAnimation && isAnimated && loadingContent) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Spinner, {});
785
+ if (!showErrorElement && isLoading) return renderElement(pendingRouteData?.routeItem?.loaderFallback || defaultLoaderFallback);
789
786
  if (!routeItem) return null;
790
- if (showErrorElement) return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [renderElement(routeItem.errorElement || defaultErrorElement), showSpinner && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Spinner, {})] });
787
+ if (showErrorElement) return renderElement(routeItem.errorElement || defaultErrorElement);
791
788
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
792
789
  style: { viewTransitionName: "page" },
793
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ErrorBoundary, { children: renderElement(routeItem.element) }, location.pathname), showSpinner && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Spinner, {})]
790
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ErrorBoundary, { children: renderElement(routeItem.element) }, location.pathname), optimisticSpinner && isOptimisticLoading && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Spinner, {})]
794
791
  });
795
792
  };
796
793
  //#endregion
package/dist/types.d.ts CHANGED
@@ -33,6 +33,7 @@ export type ClientRouteItem = {
33
33
  optimistic?: boolean;
34
34
  pollingInterval?: number;
35
35
  retry?: Retry;
36
+ minLoaderDuration?: number;
36
37
  preserveScroll?: boolean;
37
38
  beforeLoad?: BeforeLoad;
38
39
  afterLoad?: (arg: {
@@ -85,15 +86,15 @@ export type RouterProps = {
85
86
  routes: RouteItem[];
86
87
  isAnimated?: boolean;
87
88
  animationDuration?: number;
88
- spinner?: boolean;
89
+ optimisticSpinner?: boolean;
89
90
  defaultPreserveScroll?: boolean;
90
91
  defaultRetry?: Retry;
91
92
  defaultStaleTime?: number;
92
93
  defaultLoaderFallback?: RenderElement;
93
94
  defaultErrorElement?: RenderElement;
94
- showFallbackOnAnimation?: boolean;
95
95
  defaultPrefetch?: 'hover' | 'render' | 'viewport' | 'none';
96
96
  defaultHoverPrefetchDelay?: number;
97
+ defaultMinLoaderDuration?: number;
97
98
  maxCacheSize?: number;
98
99
  errorBoundary?: ComponentType<{
99
100
  children: ReactNode;
@@ -124,6 +125,7 @@ export type RouterState = {
124
125
  from: string;
125
126
  to: string;
126
127
  }>;
128
+ isOptimisticLoading: Store<boolean>;
127
129
  loaderStateRef: Cell<LoaderState>;
128
130
  loaderMap: Map<string, LoaderStateItem>;
129
131
  loadingPromises: Map<string, LoadingPromise>;
@@ -144,6 +146,7 @@ export type RouterType = {
144
146
  useScrollMap: () => ReturnType<typeof useGlobalState<Record<string, number>>>;
145
147
  usePendingState: () => ReturnType<typeof useGlobalState<RouteItemData | undefined>>;
146
148
  useContextState: () => ReturnType<typeof useGlobalState<Record<string, unknown>>>;
149
+ useOptimisticLoading: () => ReturnType<typeof useGlobalState<boolean>>;
147
150
  useParams: <T>() => T;
148
151
  useNavigate: () => (arg: Location | string | -1) => Promise<void>;
149
152
  useGetAction: (actionKey: string) => {
@@ -1,3 +1 @@
1
- import { Store } from '../create';
2
- import { Location, RouteItem, RouteItemData } from '../types';
3
- export declare const createCommitNavigation: (navigationExecutor: (arg: Location, routeItem: RouteItem | undefined) => void, routeItemDataState: Store<RouteItemData>) => (nextLocation: Location, routeItem: RouteItem | undefined) => void;
1
+ export declare const commitNavigation: (callback: () => void) => void;
@@ -1,2 +1,2 @@
1
1
  import { Location, RouteItem, RouterState } from '../types';
2
- export declare const createCommitState: ({ routeItemDataState, pendingState }: RouterState) => (nextLocation: Location, routeItem: RouteItem | undefined) => void;
2
+ export declare const createCommitState: ({ routeItemDataState, pendingState, isOptimisticLoading }: RouterState) => (nextLocation: Location, routeItem: RouteItem | undefined) => void;
@@ -4,3 +4,4 @@ export declare const getParamsObject: (nextItem?: RouteItem, nextPathname?: stri
4
4
  export declare const parseWindowLocation: (location: typeof window.location) => Location;
5
5
  export declare const comparePaths: (route: RouteItem, pathname: string) => boolean;
6
6
  export declare const isMobile: () => boolean;
7
+ export declare const sleep: (ms: number) => Promise<unknown>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clear-react-router",
3
- "version": "2.0.5",
3
+ "version": "2.0.6",
4
4
  "description": "A lightweight, type-safe routing library for React applications",
5
5
  "author": "Andrew Bubnov",
6
6
  "scripts": {