clear-react-router 1.9.6 → 1.9.7

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
@@ -45,21 +45,22 @@ It provides first-class support for:
45
45
  | `routes` | `RouteItem[]` | required | Array of route configurations |
46
46
  | `isAnimated` | `boolean \| undefined` | `false` | Enable smooth page fade transitions |
47
47
  | `animationDuration` | `number` | `optional` | Animation duration in milliseconds (browser default is used if not set) |
48
+ | `spinner` | `boolean \| undefined` | `true` | Show a small spinner in the corner while loading data (only when `isAnimated` is enabled) |
49
+ | `context` | `object` | `{}` | Initial context (user, theme, etc.) |
50
+ | `errorBoundary` | `ComponentType<{ children: ReactNode }>` | `undefined` | Custom error boundary component for catching render errors in route components |
51
+ | `showFallbackOnAnimation` | `boolean \| undefined` | `false` | Show `loaderFallback` even when `isAnimated` is `true` (instead of spinner) |
48
52
  | `defaultLoaderFallback` | `ReactElement \| () => ReactElement` | `optional` | Default loading fallback for every route loader |
49
53
  | `defaultErrorElement` | `ReactElement \| () => ReactElement` | `optional` | Default error fallback for every route |
50
54
  | `defaultRetry` | `number \| { count: number; delay: number }` | `optional` | Default cache revalidation retry policy for all routes |
51
55
  | `defaultStaleTime` | `number` | `optional` | Default time in milliseconds before cached loader data is considered stale |
52
- | `beforeLoad` | `({ params, context, redirect, setContext }) => Promise<unknown> \| undefined \| void` | `undefined` | Runs before every navigation. Useful for authentication, analytics, or updating shared context. |
53
- | `afterLoad` | `({ params, context, setContext }) => Promise<void>` | `undefined` | Runs after every successful navigation. Useful for analytics, page tracking, or other global side effects. |
54
- | `spinner` | `boolean \| undefined` | `true` | Show a small spinner in the corner while loading data (only when `isAnimated` is enabled) |
56
+ | `defaultBeforeLoad` | `({ params, context, redirect, setContext }) => Promise<unknown> \| undefined \| void` | `undefined` | Runs before every navigation. Useful for authentication, analytics, or updating shared context. |
57
+ | `defaultAfterLoad` | `({ params, context, setContext }) => Promise<void>` | `undefined` | Runs after every successful navigation. Useful for analytics, page tracking, or other global side effects. |
55
58
  | `defaultPreserveScroll` | `boolean \| undefined` | `true` | Default value for save and restore scroll position when navigating between pages |
56
- | `showFallbackOnAnimation` | `boolean \| undefined` | `false` | Show `loaderFallback` even when `isAnimated` is `true` (instead of spinner) |
57
- | `prefetch` | `'hover' \| 'render' \| 'viewport' \| 'none'` | `'hover'` | Default prefetch strategy for all `<Link>` components |
58
- | `hoverPrefetchDelay` | `number` | `150` | Delay in milliseconds before prefetching on hover (only for `'hover'` strategy) |
59
- | `context` | `object` | `{}` | Initial context (user, theme, etc.) |
60
- | `errorBoundary` | `ComponentType<{ children: ReactNode }>` | `undefined` | Custom error boundary component for catching render errors in route components |
59
+ | `defaultPrefetch` | `'hover' \| 'render' \| 'viewport' \| 'none'` | `'hover'` for desktop, `'viewport'` for mobile | Default prefetch strategy for all `<Link>` components |
60
+ | `defaultHoverPrefetchDelay` | `number` | `150` | Default delay in milliseconds before prefetching on hover (only for `'hover'` strategy) |
61
+
61
62
 
62
- > **Note:** Global lifecycle hooks wrap every route navigation. The global beforeLoad runs **before** the route-specific beforeLoad, while the global afterLoad runs **after** the route-specific afterLoad.
63
+ > **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.
63
64
 
64
65
  ```tsx
65
66
  <div>
@@ -8,7 +8,7 @@ type LinkProps<T extends HTMLElement = HTMLAnchorElement> = {
8
8
  to: string;
9
9
  children?: ReactNode;
10
10
  as?: (props: ElementProps<T>, state: ElementState) => ReactElement;
11
- prefetch?: RouterProps['prefetch'];
11
+ prefetch?: RouterProps['defaultPrefetch'];
12
12
  hoverPrefetchDelay?: number;
13
13
  className?: string | ((arg: ElementState) => string);
14
14
  activeClassName?: string;
@@ -17,5 +17,5 @@ type LinkProps<T extends HTMLElement = HTMLAnchorElement> = {
17
17
  style?: CSSProperties | ((arg: ElementState) => CSSProperties);
18
18
  exact?: boolean;
19
19
  };
20
- export declare const Link: <T extends HTMLElement = HTMLAnchorElement>({ children, to, as, prefetch: prefetchLink, hoverPrefetchDelay, className, style, beforeNavigate, exact, activeClassName, pendingClassName, }: LinkProps<T>) => ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
20
+ export declare const Link: <T extends HTMLElement = HTMLAnchorElement>({ children, to, as, prefetch: linkPrefetch, hoverPrefetchDelay, className, style, beforeNavigate, exact, activeClassName, pendingClassName, }: LinkProps<T>) => ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
21
21
  export {};
@@ -1,2 +1,2 @@
1
1
  import { RouterProps } from '../types';
2
- export declare const Router: ({ routes, beforeLoad, afterLoad, animationDuration, isAnimated, spinner, defaultPreserveScroll, showFallbackOnAnimation, prefetch, hoverPrefetchDelay, errorBoundary: ErrorBoundary, context: initialContext, defaultLoaderFallback, defaultErrorElement, defaultRetry, defaultStaleTime, }: RouterProps) => import("react/jsx-runtime").JSX.Element | null;
2
+ export declare const Router: ({ routes, defaultBeforeLoad, defaultAfterLoad, animationDuration, defaultLoaderFallback, defaultErrorElement, defaultRetry, defaultStaleTime, context: initialContext, isAnimated, spinner, defaultPreserveScroll, showFallbackOnAnimation, defaultPrefetch, defaultHoverPrefetchDelay, errorBoundary: ErrorBoundary, }: RouterProps) => import("react/jsx-runtime").JSX.Element | null;
@@ -1,11 +1,11 @@
1
1
  import { ClientRouteItem, RouterProps } from '../types';
2
2
  declare class RouterConfig {
3
3
  routes: RouterProps['routes'];
4
- prefetch: RouterProps['prefetch'];
4
+ defaultPrefetch: RouterProps['defaultPrefetch'];
5
5
  isAnimated: RouterProps['isAnimated'];
6
- hoverPrefetchDelay: number;
7
- beforeLoad?: ClientRouteItem['beforeLoad'];
8
- afterLoad?: ClientRouteItem['afterLoad'];
6
+ defaultHoverPrefetchDelay: number;
7
+ defaultBeforeLoad?: ClientRouteItem['beforeLoad'];
8
+ defaultAfterLoad?: ClientRouteItem['afterLoad'];
9
9
  defaultRetry?: RouterProps['defaultRetry'];
10
10
  defaultStaleTime?: RouterProps['defaultStaleTime'];
11
11
  defaultPreserveScroll?: RouterProps['defaultPreserveScroll'];
package/dist/index.js CHANGED
@@ -44,7 +44,7 @@ var createCommitState = ({ routeItemDataState, pendingState }) => (nextLocation,
44
44
  //#region constants.ts
45
45
  var emptyLoaderState = {};
46
46
  //#endregion
47
- //#region \0@oxc-project+runtime@0.143.0/helpers/esm/typeof.js
47
+ //#region \0@oxc-project+runtime@0.133.0/helpers/esm/typeof.js
48
48
  function _typeof(o) {
49
49
  "@babel/helpers - typeof";
50
50
  return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(o) {
@@ -54,7 +54,7 @@ function _typeof(o) {
54
54
  }, _typeof(o);
55
55
  }
56
56
  //#endregion
57
- //#region \0@oxc-project+runtime@0.143.0/helpers/esm/toPrimitive.js
57
+ //#region \0@oxc-project+runtime@0.133.0/helpers/esm/toPrimitive.js
58
58
  function toPrimitive(t, r) {
59
59
  if ("object" != _typeof(t) || !t) return t;
60
60
  var e = t[Symbol.toPrimitive];
@@ -66,13 +66,13 @@ function toPrimitive(t, r) {
66
66
  return ("string" === r ? String : Number)(t);
67
67
  }
68
68
  //#endregion
69
- //#region \0@oxc-project+runtime@0.143.0/helpers/esm/toPropertyKey.js
69
+ //#region \0@oxc-project+runtime@0.133.0/helpers/esm/toPropertyKey.js
70
70
  function toPropertyKey(t) {
71
71
  var i = toPrimitive(t, "string");
72
72
  return "symbol" == _typeof(i) ? i : i + "";
73
73
  }
74
74
  //#endregion
75
- //#region \0@oxc-project+runtime@0.143.0/helpers/esm/defineProperty.js
75
+ //#region \0@oxc-project+runtime@0.133.0/helpers/esm/defineProperty.js
76
76
  function _defineProperty(e, r, t) {
77
77
  return (r = toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
78
78
  value: t,
@@ -86,11 +86,11 @@ function _defineProperty(e, r, t) {
86
86
  var RouterConfig = class {
87
87
  constructor() {
88
88
  _defineProperty(this, "routes", []);
89
- _defineProperty(this, "prefetch", "hover");
89
+ _defineProperty(this, "defaultPrefetch", "hover");
90
90
  _defineProperty(this, "isAnimated", false);
91
- _defineProperty(this, "hoverPrefetchDelay", 150);
92
- _defineProperty(this, "beforeLoad", void 0);
93
- _defineProperty(this, "afterLoad", void 0);
91
+ _defineProperty(this, "defaultHoverPrefetchDelay", 150);
92
+ _defineProperty(this, "defaultBeforeLoad", void 0);
93
+ _defineProperty(this, "defaultAfterLoad", void 0);
94
94
  _defineProperty(this, "defaultRetry", void 0);
95
95
  _defineProperty(this, "defaultStaleTime", void 0);
96
96
  _defineProperty(this, "defaultPreserveScroll", void 0);
@@ -133,8 +133,7 @@ var createIsCacheItemFresh = (loaderMap) => ({ routeItem, pathname }) => {
133
133
  * LICENSE file in the root directory of this source tree.
134
134
  */
135
135
  var require_react_jsx_runtime_production = /* @__PURE__ */ __commonJSMin(((exports) => {
136
- var REACT_ELEMENT_TYPE = Symbol.for("react.transitional.element");
137
- var REACT_FRAGMENT_TYPE = Symbol.for("react.fragment");
136
+ var REACT_ELEMENT_TYPE = Symbol.for("react.transitional.element"), REACT_FRAGMENT_TYPE = Symbol.for("react.fragment");
138
137
  function jsxProd(type, config, maybeKey) {
139
138
  var key = null;
140
139
  void 0 !== maybeKey && (key = "" + maybeKey);
@@ -208,6 +207,11 @@ var comparePaths = (route, pathname) => {
208
207
  const current = pathname.split("/").filter(Boolean);
209
208
  return pattern.length === current.length ? pattern.every((segment, index) => segment.startsWith(":") || segment === current[index]) : false;
210
209
  };
210
+ var isMobile = () => {
211
+ const hasCoarsePointer = window.matchMedia("(pointer: coarse)").matches;
212
+ const isSmallScreen = window.matchMedia("(max-width: 768px)").matches;
213
+ return hasCoarsePointer && isSmallScreen;
214
+ };
211
215
  var findRoute = (pathname, includeAll) => {
212
216
  if (includeAll) return routerConfig.routes.find((el) => el.path === "*" || comparePaths(el, pathname));
213
217
  return routerConfig.routes.find((el) => comparePaths(el, pathname));
@@ -233,7 +237,7 @@ var createNavigate = (routerState, revalidateCache) => {
233
237
  };
234
238
  };
235
239
  const beforeLoad = async (routeItem, params) => {
236
- const { beforeLoad } = routerConfig;
240
+ const { defaultBeforeLoad } = routerConfig;
237
241
  const runBeforeLoad = async (loaderFn) => {
238
242
  const redirect = async (redirected) => await navigate(typeof redirected === "string" ? { pathname: redirected } : redirected);
239
243
  try {
@@ -253,7 +257,7 @@ var createNavigate = (routerState, revalidateCache) => {
253
257
  }));
254
258
  }
255
259
  };
256
- if (beforeLoad) await runBeforeLoad(beforeLoad);
260
+ if (defaultBeforeLoad) await runBeforeLoad(defaultBeforeLoad);
257
261
  if (routeItem?.beforeLoad) await runBeforeLoad(routeItem?.beforeLoad);
258
262
  };
259
263
  const prepareNavigation = (routeItem, location) => {
@@ -302,12 +306,12 @@ var createNavigate = (routerState, revalidateCache) => {
302
306
  afterEachLoad(routeItem);
303
307
  };
304
308
  const afterLoad = async (routeItem, params) => {
305
- const { afterLoad } = routerConfig;
309
+ const { defaultAfterLoad } = routerConfig;
306
310
  if (routeItem?.afterLoad) await routeItem.afterLoad({
307
311
  ...getContext(),
308
312
  params
309
313
  });
310
- if (afterLoad) await afterLoad({
314
+ if (defaultAfterLoad) await defaultAfterLoad({
311
315
  ...getContext(),
312
316
  params
313
317
  });
@@ -705,7 +709,7 @@ var renderElement = (Component) => {
705
709
  //#endregion
706
710
  //#region components/Router.tsx
707
711
  var EmptyBoundary = ({ children }) => children;
708
- var Router = ({ routes, beforeLoad, afterLoad, animationDuration, isAnimated = false, spinner = true, defaultPreserveScroll = true, showFallbackOnAnimation = false, prefetch = "hover", hoverPrefetchDelay = 150, errorBoundary: ErrorBoundary = EmptyBoundary, context: initialContext, defaultLoaderFallback, defaultErrorElement, defaultRetry, defaultStaleTime }) => {
712
+ var Router = ({ routes, defaultBeforeLoad, defaultAfterLoad, animationDuration, defaultLoaderFallback, defaultErrorElement, defaultRetry, defaultStaleTime, context: initialContext, isAnimated = false, spinner = true, defaultPreserveScroll = true, showFallbackOnAnimation = false, defaultPrefetch = isMobile() ? "viewport" : "hover", defaultHoverPrefetchDelay = 150, errorBoundary: ErrorBoundary = EmptyBoundary }) => {
709
713
  const { useRouteItemData, usePendingState } = router.hooks;
710
714
  const [routeItemData] = useRouteItemData();
711
715
  const [pendingState] = usePendingState();
@@ -715,10 +719,10 @@ var Router = ({ routes, beforeLoad, afterLoad, animationDuration, isAnimated = f
715
719
  useSetRouterConfig({
716
720
  routes,
717
721
  isAnimated,
718
- prefetch,
719
- hoverPrefetchDelay,
720
- beforeLoad,
721
- afterLoad,
722
+ defaultPrefetch,
723
+ defaultHoverPrefetchDelay,
724
+ defaultBeforeLoad,
725
+ defaultAfterLoad,
722
726
  defaultRetry,
723
727
  defaultStaleTime,
724
728
  defaultPreserveScroll
@@ -758,14 +762,14 @@ var useLocation = () => {
758
762
  //#endregion
759
763
  //#region components/Link.tsx
760
764
  var defaultAs = (props) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", { ...props });
761
- var Link = ({ children, to, as = defaultAs, prefetch: prefetchLink, hoverPrefetchDelay, className, style, beforeNavigate, exact = false, activeClassName = "active-link", pendingClassName = "pending-link" }) => {
765
+ var Link = ({ children, to, as = defaultAs, prefetch: linkPrefetch, hoverPrefetchDelay, className, style, beforeNavigate, exact = false, activeClassName = "active-link", pendingClassName = "pending-link" }) => {
762
766
  const isPending = useIsRoutePending(to);
763
767
  const { pathname } = useLocation();
764
768
  const navigate = useNavigate();
765
769
  const timeout = useRef(0);
766
770
  const elementRef = useRef(null);
767
- const { prefetch: configPrefetch, hoverPrefetchDelay: configPrefetchDelay } = routerConfig;
768
- const prefetch = prefetchLink || configPrefetch;
771
+ const { defaultPrefetch: configPrefetch, defaultHoverPrefetchDelay: configPrefetchDelay } = routerConfig;
772
+ const prefetch = linkPrefetch || configPrefetch;
769
773
  const prefetchDelay = hoverPrefetchDelay ?? configPrefetchDelay;
770
774
  const onMouseEnter = useCallback(() => {
771
775
  if (prefetch !== "hover" || !prefetchDelay) return;
@@ -993,10 +997,8 @@ var useSearchParams = () => {
993
997
  currentParams.delete(param);
994
998
  (Array.isArray(value) ? value : [value]).forEach((v) => currentParams.append(param, v));
995
999
  navigateWithSearchParams(currentParams);
996
- } else if (typeof param === "function") {
997
- const newParams = param(currentParams);
998
- navigateWithSearchParams(newParams);
999
- } else throw new Error("useSearchParams first argument must be either function or string");
1000
+ } else if (typeof param === "function") navigateWithSearchParams(param(currentParams));
1001
+ else throw new Error("useSearchParams first argument must be either function or string");
1000
1002
  }, [navigateWithSearchParams, search])
1001
1003
  };
1002
1004
  };
package/dist/types.d.ts CHANGED
@@ -86,13 +86,13 @@ export type RouterProps = {
86
86
  defaultLoaderFallback?: RenderElement;
87
87
  defaultErrorElement?: RenderElement;
88
88
  showFallbackOnAnimation?: boolean;
89
- prefetch?: 'hover' | 'render' | 'viewport' | 'none';
90
- hoverPrefetchDelay?: number;
89
+ defaultPrefetch?: 'hover' | 'render' | 'viewport' | 'none';
90
+ defaultHoverPrefetchDelay?: number;
91
91
  errorBoundary?: ComponentType<{
92
92
  children: ReactNode;
93
93
  }>;
94
- beforeLoad?: ClientRouteItem['beforeLoad'];
95
- afterLoad?: ClientRouteItem['afterLoad'];
94
+ defaultBeforeLoad?: ClientRouteItem['beforeLoad'];
95
+ defaultAfterLoad?: ClientRouteItem['afterLoad'];
96
96
  context?: Record<string, unknown>;
97
97
  };
98
98
  export type LoaderStateItem = {
@@ -3,3 +3,4 @@ export declare const createRouter: (clientList: ClientRouteItem[]) => RouteItem[
3
3
  export declare const getParamsObject: (nextItem?: RouteItem, nextPathname?: string) => Record<string, string>;
4
4
  export declare const parseWindowLocation: (location: typeof window.location) => Location;
5
5
  export declare const comparePaths: (route: RouteItem, pathname: string) => boolean;
6
+ export declare const isMobile: () => boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clear-react-router",
3
- "version": "1.9.6",
3
+ "version": "1.9.7",
4
4
  "description": "A lightweight, type-safe routing library for React applications",
5
5
  "author": "Andrew Bubnov",
6
6
  "scripts": {