clear-react-router 1.9.5 → 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 +64 -22
- package/dist/components/Link.d.ts +8 -20
- package/dist/components/Router.d.ts +1 -1
- package/dist/config/routerConfig.d.ts +4 -4
- package/dist/index.d.ts +1 -1
- package/dist/index.js +32 -29
- package/dist/types.d.ts +15 -5
- package/dist/utils/utils.d.ts +1 -0
- package/package.json +1 -1
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
|
-
| `
|
|
53
|
-
| `
|
|
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
|
-
| `
|
|
57
|
-
| `
|
|
58
|
-
|
|
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
|
|
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>
|
|
@@ -107,7 +108,7 @@ Component for client-side navigation with prefetch support, active state detecti
|
|
|
107
108
|
| Prop | Type | Default | Description |
|
|
108
109
|
|------|------|---------|-------------|
|
|
109
110
|
| `to` | `string` | required | Target path |
|
|
110
|
-
| `as` | `(props: ElementProps<T
|
|
111
|
+
| `as` | `(props: ElementProps<T>, state: { isActive: boolean; isPending: boolean }) => ReactElement` | renders `<a>` | Render function for using a custom element/component instead of the default <a>. Receives the props to spread onto your element (href, ref, event handlers, className, style, children) as the first argument, and `{ isActive, isPending }` as a separate second argument — kept separate so these values are never accidentally forwarded to the DOM |
|
|
111
112
|
| `exact` | `boolean` | `false` | When `false`, the link is also considered active if the current URL starts with `to` (useful for nested routes) |
|
|
112
113
|
| `prefetch` | `'hover' \| 'render' \| 'viewport' \| 'none'` | `Router` config | Override the global prefetch strategy |
|
|
113
114
|
| `hoverPrefetchDelay` | `number` | `Router` config | Override the global hover delay |
|
|
@@ -134,27 +135,68 @@ Component for client-side navigation with prefetch support, active state detecti
|
|
|
134
135
|
| `'viewport'` | Prefetches when the link enters the viewport (using Intersection Observer) |
|
|
135
136
|
| `'none'` | No prefetching |
|
|
136
137
|
|
|
138
|
+
### Custom elements via `as`
|
|
139
|
+
|
|
140
|
+
When using `as` to render a custom component instead of the default `<a>`, your component **must spread all received props onto the underlying host element** — including `ref`. If any prop is dropped, the corresponding feature silently stops working (no error is thrown):
|
|
141
|
+
|
|
142
|
+
- Missing `ref` → `viewport` prefetch never triggers (the `IntersectionObserver` has nothing to observe).
|
|
143
|
+
- Missing `onClick` → navigation doesn't happen, the link just does nothing.
|
|
144
|
+
- Missing `onMouseEnter`/`onMouseLeave` → `hover` prefetch doesn't trigger.
|
|
145
|
+
- Missing `href` → the link isn't reachable via keyboard, screen readers, "open in new tab", etc.
|
|
146
|
+
|
|
147
|
+
```tsx
|
|
148
|
+
// ✅ correct — every prop is forwarded to the host element
|
|
149
|
+
const Button = ({ children, ...props }: ElementProps<HTMLButtonElement>) => (
|
|
150
|
+
<button {...props}>{children}</button>
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
// ❌ wrong — ref, event handlers, and href are silently dropped
|
|
154
|
+
const Button = ({ children }: { children: ReactNode }) => (
|
|
155
|
+
<button>{children}</button>
|
|
156
|
+
);
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
If you only want to add or override specific props (e.g. add a `variant`), spread the received props first, then apply your own on top:
|
|
160
|
+
|
|
161
|
+
```tsx
|
|
162
|
+
const Button = ({ children, ...props }: ElementProps<HTMLButtonElement>) => (
|
|
163
|
+
<button {...props} className={`btn ${props.className ?? ''}`}>
|
|
164
|
+
{children}
|
|
165
|
+
</button>
|
|
166
|
+
);
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
> **Note:** Because `as` is called as a plain function rather than rendered via JSX, avoid using React hooks (`useState`, `useEffect`, etc.) inside the function you pass to `as` — it isn't tracked by React as a separate component in the fiber tree. A function written for `as` (like `Button` above, which takes a second `state` argument) also isn't a valid standalone React component and shouldn't be rendered directly as `<Button />` elsewhere.
|
|
170
|
+
|
|
137
171
|
**Example:**
|
|
138
172
|
|
|
139
173
|
```tsx
|
|
140
|
-
import {
|
|
174
|
+
import { Link, type ElementProps } from 'clear-react-router';
|
|
175
|
+
|
|
176
|
+
const Button = (
|
|
177
|
+
{ children, ...rest }: ElementProps<HTMLButtonElement>,
|
|
178
|
+
{ isActive }: { isActive: boolean }
|
|
179
|
+
) => (
|
|
180
|
+
<button {...rest} style={{ background: isActive ? 'tomato' : 'green' }}>
|
|
181
|
+
{children}
|
|
182
|
+
</button>
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
<Link to="/about" as={Button}>To about page</Link>
|
|
186
|
+
|
|
187
|
+
For third-party components (MUI, Chakra, etc.), wrap them in an inline arrow function — most of them accept a
|
|
188
|
+
single `props` argument and forward it to the host element themselves:
|
|
141
189
|
|
|
142
|
-
// Render a custom element/component via `as`. The function receives ref, event handlers, isActive/isPending and must render them itself
|
|
143
190
|
import { Button } from '@mui/material';
|
|
144
191
|
|
|
145
192
|
<Link
|
|
146
|
-
to="/
|
|
147
|
-
as={({ isActive
|
|
148
|
-
<Button
|
|
149
|
-
{...props}
|
|
150
|
-
variant={isActive ? 'contained' : 'outlined'}
|
|
151
|
-
sx={{ opacity: isPending ? 0.5 : 1 }}
|
|
152
|
-
/>
|
|
153
|
-
)}
|
|
193
|
+
to="/about"
|
|
194
|
+
as={(props, { isActive }) => <Button {...props} variant={isActive ? 'contained' : 'text'} />}
|
|
154
195
|
>
|
|
155
|
-
|
|
196
|
+
To about page
|
|
156
197
|
</Link>
|
|
157
|
-
|
|
198
|
+
```
|
|
199
|
+
```tsx
|
|
158
200
|
// Global prefetch: hover with 100ms delay
|
|
159
201
|
<Router routes={routes} prefetch="hover" hoverPrefetchDelay={100} />
|
|
160
202
|
|
|
@@ -1,33 +1,21 @@
|
|
|
1
|
-
import { type CSSProperties, ReactNode,
|
|
2
|
-
import { RouterProps } from '../types';
|
|
3
|
-
type
|
|
1
|
+
import { type CSSProperties, ReactNode, ReactElement } from 'react';
|
|
2
|
+
import { ElementProps, RouterProps } from '../types';
|
|
3
|
+
type ElementState = {
|
|
4
4
|
isActive: boolean;
|
|
5
5
|
isPending: boolean;
|
|
6
6
|
};
|
|
7
|
-
type ElementProps<T extends HTMLElement = HTMLElement> = {
|
|
8
|
-
ref: Ref<T>;
|
|
9
|
-
href: string;
|
|
10
|
-
isActive: boolean;
|
|
11
|
-
isPending: boolean;
|
|
12
|
-
onClick(event: MouseEvent): void;
|
|
13
|
-
onMouseEnter(event: MouseEvent): void;
|
|
14
|
-
onMouseLeave(event: MouseEvent): void;
|
|
15
|
-
className?: string;
|
|
16
|
-
style?: CSSProperties;
|
|
17
|
-
children?: ReactNode;
|
|
18
|
-
};
|
|
19
7
|
type LinkProps<T extends HTMLElement = HTMLAnchorElement> = {
|
|
20
8
|
to: string;
|
|
21
9
|
children?: ReactNode;
|
|
22
|
-
as?: (props: ElementProps<T
|
|
23
|
-
prefetch?: RouterProps['
|
|
10
|
+
as?: (props: ElementProps<T>, state: ElementState) => ReactElement;
|
|
11
|
+
prefetch?: RouterProps['defaultPrefetch'];
|
|
24
12
|
hoverPrefetchDelay?: number;
|
|
25
|
-
className?: string | ((arg:
|
|
13
|
+
className?: string | ((arg: ElementState) => string);
|
|
26
14
|
activeClassName?: string;
|
|
27
15
|
pendingClassName?: string;
|
|
28
16
|
beforeNavigate?(): Promise<void>;
|
|
29
|
-
style?: CSSProperties | ((arg:
|
|
17
|
+
style?: CSSProperties | ((arg: ElementState) => CSSProperties);
|
|
30
18
|
exact?: boolean;
|
|
31
19
|
};
|
|
32
|
-
export declare const Link: <T extends HTMLElement = HTMLAnchorElement>({ children, to, as, prefetch:
|
|
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>>;
|
|
33
21
|
export {};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { RouterProps } from '../types';
|
|
2
|
-
export declare const Router: ({ routes,
|
|
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
|
-
|
|
4
|
+
defaultPrefetch: RouterProps['defaultPrefetch'];
|
|
5
5
|
isAnimated: RouterProps['isAnimated'];
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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.d.ts
CHANGED
|
@@ -12,4 +12,4 @@ export { useRouterContext } from './hooks/useRouterContext';
|
|
|
12
12
|
export { useSearchParams } from './hooks/useSearchParams';
|
|
13
13
|
export { useFormContext } from './hooks/useFormContext';
|
|
14
14
|
export { createRouter } from './utils/utils';
|
|
15
|
-
export type { RouteItem, BlockerState, Location, RouterProps } from './types';
|
|
15
|
+
export type { RouteItem, BlockerState, Location, RouterProps, ElementProps } from './types';
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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, "
|
|
89
|
+
_defineProperty(this, "defaultPrefetch", "hover");
|
|
90
90
|
_defineProperty(this, "isAnimated", false);
|
|
91
|
-
_defineProperty(this, "
|
|
92
|
-
_defineProperty(this, "
|
|
93
|
-
_defineProperty(this, "
|
|
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 {
|
|
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 (
|
|
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 {
|
|
309
|
+
const { defaultAfterLoad } = routerConfig;
|
|
306
310
|
if (routeItem?.afterLoad) await routeItem.afterLoad({
|
|
307
311
|
...getContext(),
|
|
308
312
|
params
|
|
309
313
|
});
|
|
310
|
-
if (
|
|
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,
|
|
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
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
+
defaultPrefetch,
|
|
723
|
+
defaultHoverPrefetchDelay,
|
|
724
|
+
defaultBeforeLoad,
|
|
725
|
+
defaultAfterLoad,
|
|
722
726
|
defaultRetry,
|
|
723
727
|
defaultStaleTime,
|
|
724
728
|
defaultPreserveScroll
|
|
@@ -757,15 +761,15 @@ var useLocation = () => {
|
|
|
757
761
|
};
|
|
758
762
|
//#endregion
|
|
759
763
|
//#region components/Link.tsx
|
|
760
|
-
var defaultAs = (
|
|
761
|
-
var Link = ({ children, to, as = defaultAs, prefetch:
|
|
764
|
+
var defaultAs = (props) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", { ...props });
|
|
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 {
|
|
768
|
-
const prefetch =
|
|
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;
|
|
@@ -832,9 +836,10 @@ var Link = ({ children, to, as = defaultAs, prefetch: prefetchLink, hoverPrefetc
|
|
|
832
836
|
onClick: clickHandler,
|
|
833
837
|
onMouseEnter,
|
|
834
838
|
onMouseLeave,
|
|
835
|
-
isActive,
|
|
836
|
-
isPending,
|
|
837
839
|
children
|
|
840
|
+
}, {
|
|
841
|
+
isActive,
|
|
842
|
+
isPending
|
|
838
843
|
});
|
|
839
844
|
};
|
|
840
845
|
//#endregion
|
|
@@ -992,10 +997,8 @@ var useSearchParams = () => {
|
|
|
992
997
|
currentParams.delete(param);
|
|
993
998
|
(Array.isArray(value) ? value : [value]).forEach((v) => currentParams.append(param, v));
|
|
994
999
|
navigateWithSearchParams(currentParams);
|
|
995
|
-
} else if (typeof param === "function")
|
|
996
|
-
|
|
997
|
-
navigateWithSearchParams(newParams);
|
|
998
|
-
} 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");
|
|
999
1002
|
}, [navigateWithSearchParams, search])
|
|
1000
1003
|
};
|
|
1001
1004
|
};
|
package/dist/types.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { ComponentType, type CSSProperties, Dispatch, MouseEvent, ReactElement, ReactNode, Ref, SetStateAction } from 'react';
|
|
2
2
|
import { Store, useGlobalState } from './create';
|
|
3
3
|
import { Cell } from './cell';
|
|
4
4
|
export type LazyComponent = () => Promise<{
|
|
@@ -86,13 +86,13 @@ export type RouterProps = {
|
|
|
86
86
|
defaultLoaderFallback?: RenderElement;
|
|
87
87
|
defaultErrorElement?: RenderElement;
|
|
88
88
|
showFallbackOnAnimation?: boolean;
|
|
89
|
-
|
|
90
|
-
|
|
89
|
+
defaultPrefetch?: 'hover' | 'render' | 'viewport' | 'none';
|
|
90
|
+
defaultHoverPrefetchDelay?: number;
|
|
91
91
|
errorBoundary?: ComponentType<{
|
|
92
92
|
children: ReactNode;
|
|
93
93
|
}>;
|
|
94
|
-
|
|
95
|
-
|
|
94
|
+
defaultBeforeLoad?: ClientRouteItem['beforeLoad'];
|
|
95
|
+
defaultAfterLoad?: ClientRouteItem['afterLoad'];
|
|
96
96
|
context?: Record<string, unknown>;
|
|
97
97
|
};
|
|
98
98
|
export type LoaderStateItem = {
|
|
@@ -154,4 +154,14 @@ export type InvalidateResult = {
|
|
|
154
154
|
path: string;
|
|
155
155
|
data: unknown;
|
|
156
156
|
};
|
|
157
|
+
export type ElementProps<T extends HTMLElement = HTMLElement> = {
|
|
158
|
+
ref: Ref<T>;
|
|
159
|
+
href: string;
|
|
160
|
+
className?: string;
|
|
161
|
+
style?: CSSProperties;
|
|
162
|
+
onClick(event: MouseEvent): void;
|
|
163
|
+
onMouseEnter(event: MouseEvent): void;
|
|
164
|
+
onMouseLeave(event: MouseEvent): void;
|
|
165
|
+
children?: ReactNode;
|
|
166
|
+
};
|
|
157
167
|
export {};
|
package/dist/utils/utils.d.ts
CHANGED
|
@@ -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;
|