clear-react-router 1.9.2 → 1.9.4
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 +36 -5
- package/dist/components/Link.d.ts +20 -6
- package/dist/index.js +56 -39
- package/dist/runtime/invalidate.d.ts +1 -1
- package/dist/types.d.ts +6 -1
- package/dist/utils/isCacheItemFresh.d.ts +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -31,6 +31,7 @@ It provides first-class support for:
|
|
|
31
31
|
- **Prefetching** - Preload data on hover for instant navigation
|
|
32
32
|
- **Lazy Loading** - Code-split your routes with dynamic imports for optimal performance
|
|
33
33
|
- **Scroll Restoration** — Automatically saves and restores scroll position when navigating back to a page (preserves user's scroll position)
|
|
34
|
+
- **Optimistic navigation** — Instantly renders stale cached data while fresh data is loaded in the background.
|
|
34
35
|
- **Flexible API** - Use components or hooks as you prefer
|
|
35
36
|
- **Browser History** - Full support for browser back/forward buttons
|
|
36
37
|
- **Context-aware** - Pass and update context through routes
|
|
@@ -81,12 +82,13 @@ Normalizes route configuration. Extracts dynamic params, builds nested paths.
|
|
|
81
82
|
| `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` |
|
|
82
83
|
| `fallback` | `ReactElement \| () => ReactElement` | Loading fallback (for lazy loading) |
|
|
83
84
|
| `loaderFallback` | `ReactElement \| () => ReactElement` | Loading fallback for the route's `loader`. Overrides the global `defaultLoaderFallback` set in `Router` |
|
|
84
|
-
| `retry` | `number \| { count: number; delay: number }` |
|
|
85
|
+
| `retry` | `number \| { count: number; delay: number }` | Overrides the global cache revalidation retry policy for this route |
|
|
86
|
+
| `optimistic` | `boolean \| undefined` | Instant navigation using stale data while fresh data is loaded in the background |
|
|
85
87
|
| `errorElement` | `ReactElement \| () => ReactElement` | Error fallback for the route. Overrides the global `defaultErrorElement` set in `Router` |
|
|
86
88
|
| `staleTime` | `number` | Time in milliseconds before cached loader data is considered stale. Overrides Router.defaultStaleTime. If neither value is provided, cached data never expires |
|
|
87
89
|
| `actions` | `({ params, context, invalidate, setContext }) => Record<string, (formData: FormData) => unknown \| Promise<unknown>>` | Defines route actions for data mutations. Actions receive `FormData`, can update context via `setContext`, and can invalidate cached loader data using the router-provided `invalidate` |
|
|
88
|
-
| `pollingInterval` | `number \| undefined` |
|
|
89
|
-
| `preserveScroll` | `boolean \| undefined` |
|
|
90
|
+
| `pollingInterval` | `number \| undefined` | Polling interval (in milliseconds) for automatically revalidating data while the route is active |
|
|
91
|
+
| `preserveScroll` | `boolean \| undefined` | Save and restore route scroll position when navigating between pages |
|
|
90
92
|
|
|
91
93
|
Loader arguments:
|
|
92
94
|
```ts
|
|
@@ -105,6 +107,8 @@ Component for client-side navigation with prefetch support, active state detecti
|
|
|
105
107
|
| Prop | Type | Default | Description |
|
|
106
108
|
|------|------|---------|-------------|
|
|
107
109
|
| `to` | `string` | required | Target path |
|
|
110
|
+
| `as` | `(props: ElementProps<T>) => ReactElement` | renders `<a>` | Render prop for using a custom element/component instead of the default `<a>`. Receives the computed isActive and isPending values, event handlers, and ref to attach to your own element |
|
|
111
|
+
| `exact` | `boolean` | `false` | When `false`, the link is also considered active if the current URL starts with `to` (useful for nested routes) |
|
|
108
112
|
| `prefetch` | `'hover' \| 'render' \| 'viewport' \| 'none'` | `Router` config | Override the global prefetch strategy |
|
|
109
113
|
| `hoverPrefetchDelay` | `number` | `Router` config | Override the global hover delay |
|
|
110
114
|
| `children` | `ReactNode` | required | Content to render inside the link |
|
|
@@ -112,13 +116,13 @@ Component for client-side navigation with prefetch support, active state detecti
|
|
|
112
116
|
| `style` | `CSSProperties \| ({ isActive, isPending }) => CSSProperties` | `undefined` | Inline styles. Can be a function for dynamic styling |
|
|
113
117
|
| `activeClassName` | `string` optional | `'active-link'` | Class name applied when the link matches the current URL |
|
|
114
118
|
| `pendingClassName` | `string` optional | `'pending-link'` | Class name applied when the link's target is loading |
|
|
115
|
-
| `
|
|
119
|
+
| `beforeNavigate` | `() => Promise<void> \| undefined` | `undefined` | Callback fired before navigation |
|
|
116
120
|
|
|
117
121
|
**State values:**
|
|
118
122
|
|
|
119
123
|
| State | Type | Description |
|
|
120
124
|
|-------|------|-------------|
|
|
121
|
-
| `isActive` | `boolean` | `true` when the link's `to` matches the current URL |
|
|
125
|
+
| `isActive` | `boolean` | `true` when the link's `to` matches the current URL considering `exact` value |
|
|
122
126
|
| `isPending` | `boolean` | `true` when the target route is currently loading (loader is running) |
|
|
123
127
|
|
|
124
128
|
### Prefetch Strategies
|
|
@@ -135,6 +139,22 @@ Component for client-side navigation with prefetch support, active state detecti
|
|
|
135
139
|
```tsx
|
|
136
140
|
import { Router, Link } from 'clear-react-router';
|
|
137
141
|
|
|
142
|
+
// Render a custom element/component via `as`. The function receives ref, event handlers, isActive/isPending and must render them itself
|
|
143
|
+
import { Button } from '@mui/material';
|
|
144
|
+
|
|
145
|
+
<Link
|
|
146
|
+
to="/dashboard"
|
|
147
|
+
as={({ isActive, isPending, ...props }) => (
|
|
148
|
+
<Button
|
|
149
|
+
{...props}
|
|
150
|
+
variant={isActive ? 'contained' : 'outlined'}
|
|
151
|
+
sx={{ opacity: isPending ? 0.5 : 1 }}
|
|
152
|
+
/>
|
|
153
|
+
)}
|
|
154
|
+
>
|
|
155
|
+
Dashboard
|
|
156
|
+
</Link>
|
|
157
|
+
|
|
138
158
|
// Global prefetch: hover with 100ms delay
|
|
139
159
|
<Router routes={routes} prefetch="hover" hoverPrefetchDelay={100} />
|
|
140
160
|
|
|
@@ -162,6 +182,17 @@ import { Router, Link } from 'clear-react-router';
|
|
|
162
182
|
<Link to="/profile" style={({ isActive }) => ({ fontWeight: isActive ? 'bold' : 'normal' })}>
|
|
163
183
|
Profile
|
|
164
184
|
</Link>
|
|
185
|
+
|
|
186
|
+
// Use `beforeNavigate`
|
|
187
|
+
<Link to="/details" beforeNavigate={saveDashboardData}>
|
|
188
|
+
Admin Panel
|
|
189
|
+
</Link>
|
|
190
|
+
|
|
191
|
+
// `exact={false}` — active for nested routes too
|
|
192
|
+
// e.g. active when current URL is "/settings" or "/settings/profile"
|
|
193
|
+
<Link to="/settings" exact={false}>
|
|
194
|
+
Settings
|
|
195
|
+
</Link>
|
|
165
196
|
```
|
|
166
197
|
**Important**: prefetch="render" should be used sparingly, as it preloads data immediately when the link is rendered, which may cause unnecessary network requests.
|
|
167
198
|
|
|
@@ -1,19 +1,33 @@
|
|
|
1
|
-
import { type CSSProperties, ReactNode,
|
|
1
|
+
import { type CSSProperties, ReactNode, MouseEvent, ReactElement, Ref } from 'react';
|
|
2
2
|
import { RouterProps } from '../types';
|
|
3
3
|
type States = {
|
|
4
4
|
isActive: boolean;
|
|
5
5
|
isPending: boolean;
|
|
6
6
|
};
|
|
7
|
-
type
|
|
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
|
+
type LinkProps<T extends HTMLElement = HTMLAnchorElement> = {
|
|
8
20
|
to: string;
|
|
9
|
-
children
|
|
21
|
+
children?: ReactNode;
|
|
22
|
+
as?: (props: ElementProps<T>) => ReactElement;
|
|
10
23
|
prefetch?: RouterProps['prefetch'];
|
|
11
24
|
hoverPrefetchDelay?: number;
|
|
12
|
-
style?: CSSProperties | ((arg: States) => CSSProperties);
|
|
13
25
|
className?: string | ((arg: States) => string);
|
|
14
26
|
activeClassName?: string;
|
|
15
27
|
pendingClassName?: string;
|
|
16
|
-
|
|
28
|
+
beforeNavigate?(): Promise<void>;
|
|
29
|
+
style?: CSSProperties | ((arg: States) => CSSProperties);
|
|
30
|
+
exact?: boolean;
|
|
17
31
|
};
|
|
18
|
-
export declare const Link: ({ children, to, prefetch: prefetchLink, hoverPrefetchDelay, className, style,
|
|
32
|
+
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>>;
|
|
19
33
|
export {};
|
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.132.0/helpers/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.132.0/helpers/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.132.0/helpers/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.132.0/helpers/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,
|
|
@@ -113,13 +113,13 @@ var createCommitNavigation = (navigationExecutor, routeItemDataState) => (nextLo
|
|
|
113
113
|
};
|
|
114
114
|
//#endregion
|
|
115
115
|
//#region utils/isCacheItemFresh.ts
|
|
116
|
-
var createIsCacheItemFresh = (
|
|
116
|
+
var createIsCacheItemFresh = (loaderMap) => ({ routeItem, pathname }) => {
|
|
117
117
|
if (!routeItem) return true;
|
|
118
|
-
const
|
|
119
|
-
if (
|
|
118
|
+
const item = loaderMap.get(pathname);
|
|
119
|
+
if (item === void 0) return false;
|
|
120
120
|
const staleTime = routeItem.staleTime ?? routerConfig.defaultStaleTime;
|
|
121
121
|
if (staleTime === void 0) return true;
|
|
122
|
-
return Date.now() - timestamp <= staleTime;
|
|
122
|
+
return Date.now() - item.timestamp <= staleTime;
|
|
123
123
|
};
|
|
124
124
|
//#endregion
|
|
125
125
|
//#region ../../node_modules/react/cjs/react-jsx-runtime.production.js
|
|
@@ -216,9 +216,9 @@ var findRoute = (pathname, includeAll) => {
|
|
|
216
216
|
var navigationSeq = 0;
|
|
217
217
|
var interval = 0;
|
|
218
218
|
var createNavigate = (routerState, revalidateCache) => {
|
|
219
|
-
const { loaderStateRef, scrollMapState, pendingState, contextState,
|
|
219
|
+
const { loaderStateRef, scrollMapState, pendingState, contextState, loaderMap, routeItemDataState } = routerState;
|
|
220
220
|
const commitNavigation = createCommitNavigation(createCommitState(routerState), routeItemDataState);
|
|
221
|
-
const isCacheItemFresh = createIsCacheItemFresh(
|
|
221
|
+
const isCacheItemFresh = createIsCacheItemFresh(loaderMap);
|
|
222
222
|
const getContext = () => ({
|
|
223
223
|
context: contextState.getState(),
|
|
224
224
|
setContext: contextState.setState
|
|
@@ -265,14 +265,23 @@ var createNavigate = (routerState, revalidateCache) => {
|
|
|
265
265
|
[prevPathname]: scrollPosition
|
|
266
266
|
};
|
|
267
267
|
});
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
}
|
|
268
|
+
if (routeItem?.optimistic && loaderMap.has(location.pathname)) {
|
|
269
|
+
routeItemDataState.setState({
|
|
270
|
+
routeItem,
|
|
271
|
+
location
|
|
272
|
+
});
|
|
273
|
+
const currentLoaderState = loaderMap.get(location.pathname)?.state;
|
|
274
|
+
if (currentLoaderState) loaderStateRef.set(currentLoaderState);
|
|
275
|
+
} else {
|
|
276
|
+
const pendingShouldExist = routeItem?.loader && !isCacheItemFresh({
|
|
277
|
+
routeItem,
|
|
278
|
+
pathname: location.pathname
|
|
279
|
+
});
|
|
280
|
+
pendingState.setState(pendingShouldExist ? {
|
|
281
|
+
routeItem,
|
|
282
|
+
location
|
|
283
|
+
} : void 0);
|
|
284
|
+
}
|
|
276
285
|
};
|
|
277
286
|
const afterEachLoad = (routeItem) => {
|
|
278
287
|
if (!routeItem?.pollingInterval) return;
|
|
@@ -319,10 +328,10 @@ var createNavigate = (routerState, revalidateCache) => {
|
|
|
319
328
|
//#endregion
|
|
320
329
|
//#region runtime/invalidate.ts
|
|
321
330
|
var redirect = () => Promise.resolve();
|
|
322
|
-
var createInvalidate = ({ routeItemDataState, loaderStateRef,
|
|
331
|
+
var createInvalidate = ({ routeItemDataState, loaderStateRef, loaderMap, currentLoaderState, contextState }, revalidateCache) => {
|
|
323
332
|
const invalidatePath = async (routeItem, pathname, options) => {
|
|
324
333
|
const routePathname = routeItemDataState.getState().location.pathname;
|
|
325
|
-
|
|
334
|
+
loaderMap.delete(pathname);
|
|
326
335
|
const params = getParamsObject();
|
|
327
336
|
try {
|
|
328
337
|
if (routeItem?.beforeLoad && options?.withBeforeLoad) {
|
|
@@ -359,7 +368,7 @@ var createInvalidate = ({ routeItemDataState, loaderStateRef, timestampMap, curr
|
|
|
359
368
|
const routeItem = findRoute(pathname);
|
|
360
369
|
if (!routeItem) return [];
|
|
361
370
|
const pathnameArray = [];
|
|
362
|
-
for (const [key] of
|
|
371
|
+
for (const [key] of loaderMap) if (comparePaths(routeItem, key)) pathnameArray.push(key);
|
|
363
372
|
const currentResults = await Promise.all(pathnameArray.map((pathname) => invalidatePath(routeItem, pathname, options)));
|
|
364
373
|
if (!options?.withChildren || !routeItem.children?.length) return currentResults;
|
|
365
374
|
const childResults = await Promise.all(routeItem.children.map((child) => invalidateItem(`${pathname}${child.path}`, options)));
|
|
@@ -385,7 +394,6 @@ var createPrefetch = (revalidateCache) => async (pathname) => {
|
|
|
385
394
|
};
|
|
386
395
|
//#endregion
|
|
387
396
|
//#region utils/revalidateCache.ts
|
|
388
|
-
var loaderMapRef = {};
|
|
389
397
|
var loadingPromises = /* @__PURE__ */ new Map();
|
|
390
398
|
var isObjectRetry = (arg) => typeof arg === "object";
|
|
391
399
|
var createRetry = (arg) => {
|
|
@@ -406,16 +414,17 @@ var getRetry = (routeItem) => {
|
|
|
406
414
|
};
|
|
407
415
|
var sleep = async (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
408
416
|
var createRevalidateCache = (routerState) => {
|
|
409
|
-
const { loaderStateRef,
|
|
417
|
+
const { loaderStateRef, contextState, loaderMap } = routerState;
|
|
410
418
|
const revalidateCache = async ({ routeItem, pathname, search = "" }, retried = 0) => {
|
|
411
419
|
if (!routeItem?.loader) return;
|
|
412
|
-
const isCacheItemFresh = createIsCacheItemFresh(
|
|
420
|
+
const isCacheItemFresh = createIsCacheItemFresh(loaderMap);
|
|
413
421
|
if (loadingPromises.has(pathname)) return loadingPromises.get(pathname);
|
|
414
422
|
if (isCacheItemFresh({
|
|
415
423
|
routeItem,
|
|
416
424
|
pathname
|
|
417
425
|
})) {
|
|
418
|
-
|
|
426
|
+
const item = loaderMap.get(pathname);
|
|
427
|
+
if (item?.state) loaderStateRef.set(item.state);
|
|
419
428
|
return;
|
|
420
429
|
}
|
|
421
430
|
const promise = (async () => {
|
|
@@ -431,13 +440,15 @@ var createRevalidateCache = (routerState) => {
|
|
|
431
440
|
setContext,
|
|
432
441
|
searchParams
|
|
433
442
|
});
|
|
434
|
-
timestampMap.set(`${pathname}${search}`, Date.now());
|
|
435
443
|
loaderStateRef.set((prev) => ({
|
|
436
444
|
...prev,
|
|
437
445
|
data: result,
|
|
438
446
|
loaderError: null
|
|
439
447
|
}));
|
|
440
|
-
|
|
448
|
+
loaderMap.set(`${pathname}${search}`, {
|
|
449
|
+
state: loaderStateRef.value,
|
|
450
|
+
timestamp: Date.now()
|
|
451
|
+
});
|
|
441
452
|
return {
|
|
442
453
|
data: result,
|
|
443
454
|
error: null
|
|
@@ -506,7 +517,7 @@ var createRouterInstance = () => {
|
|
|
506
517
|
to: ""
|
|
507
518
|
}),
|
|
508
519
|
loaderStateRef: new Cell(emptyLoaderState),
|
|
509
|
-
|
|
520
|
+
loaderMap: /* @__PURE__ */ new Map()
|
|
510
521
|
};
|
|
511
522
|
const revalidateCache = createRevalidateCache(routerState);
|
|
512
523
|
const invalidate = createInvalidate(routerState, revalidateCache);
|
|
@@ -745,12 +756,13 @@ var useLocation = () => {
|
|
|
745
756
|
};
|
|
746
757
|
//#endregion
|
|
747
758
|
//#region components/Link.tsx
|
|
748
|
-
var
|
|
759
|
+
var defaultAs = ({ isActive, isPending, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", { ...props });
|
|
760
|
+
var Link = ({ children, to, as = defaultAs, prefetch: prefetchLink, hoverPrefetchDelay, className, style, beforeNavigate, exact = false, activeClassName = "active-link", pendingClassName = "pending-link" }) => {
|
|
749
761
|
const isPending = useIsRoutePending(to);
|
|
750
762
|
const { pathname } = useLocation();
|
|
751
763
|
const navigate = useNavigate();
|
|
752
764
|
const timeout = useRef(0);
|
|
753
|
-
const
|
|
765
|
+
const elementRef = useRef(null);
|
|
754
766
|
const { prefetch: configPrefetch, hoverPrefetchDelay: configPrefetchDelay } = routerConfig;
|
|
755
767
|
const prefetch = prefetchLink || configPrefetch;
|
|
756
768
|
const prefetchDelay = hoverPrefetchDelay ?? configPrefetchDelay;
|
|
@@ -778,17 +790,19 @@ var Link = ({ children, to, prefetch: prefetchLink, hoverPrefetchDelay, classNam
|
|
|
778
790
|
}, [prefetch, to]);
|
|
779
791
|
useEffect(() => {
|
|
780
792
|
if (prefetch !== "viewport") return;
|
|
781
|
-
const element =
|
|
793
|
+
const element = elementRef.current;
|
|
794
|
+
if (!element) return;
|
|
782
795
|
const observer = new IntersectionObserver(async () => {
|
|
783
796
|
await router.runtime.prefetch(to);
|
|
784
797
|
observer.disconnect();
|
|
785
798
|
});
|
|
786
|
-
|
|
787
|
-
return () =>
|
|
788
|
-
if (element) observer.disconnect();
|
|
789
|
-
};
|
|
799
|
+
observer.observe(element);
|
|
800
|
+
return () => observer.disconnect();
|
|
790
801
|
}, [prefetch, to]);
|
|
791
|
-
|
|
802
|
+
useEffect(() => () => {
|
|
803
|
+
if (timeout.current) clearTimeout(timeout.current);
|
|
804
|
+
}, []);
|
|
805
|
+
const isActive = to === "/" ? pathname === "/" : exact ? pathname === to : pathname === to || pathname?.startsWith(`${to}/`);
|
|
792
806
|
const normalizedClassName = typeof className === "function" ? className({
|
|
793
807
|
isActive,
|
|
794
808
|
isPending
|
|
@@ -803,18 +817,21 @@ var Link = ({ children, to, prefetch: prefetchLink, hoverPrefetchDelay, classNam
|
|
|
803
817
|
normalizedClassName
|
|
804
818
|
].filter(Boolean).join(" ");
|
|
805
819
|
const clickHandler = async (event) => {
|
|
820
|
+
if (event.defaultPrevented || event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return;
|
|
806
821
|
event.preventDefault();
|
|
807
|
-
|
|
822
|
+
await beforeNavigate?.();
|
|
808
823
|
await navigate(to);
|
|
809
824
|
};
|
|
810
|
-
return
|
|
825
|
+
return as({
|
|
826
|
+
ref: elementRef,
|
|
811
827
|
href: to,
|
|
812
|
-
ref,
|
|
813
828
|
style: normalizedStyle,
|
|
814
829
|
className: resultClassName,
|
|
815
830
|
onClick: clickHandler,
|
|
816
831
|
onMouseEnter,
|
|
817
832
|
onMouseLeave,
|
|
833
|
+
isActive,
|
|
834
|
+
isPending,
|
|
818
835
|
children
|
|
819
836
|
});
|
|
820
837
|
};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { type InvalidateOptions, InvalidateResult, RevalidateCache, RouterState } from '../types';
|
|
2
|
-
export declare const createInvalidate: ({ routeItemDataState, loaderStateRef,
|
|
2
|
+
export declare const createInvalidate: ({ routeItemDataState, loaderStateRef, loaderMap, currentLoaderState, contextState }: RouterState, revalidateCache: RevalidateCache) => (pathList?: string | string[], options?: InvalidateOptions) => Promise<InvalidateResult[]>;
|
package/dist/types.d.ts
CHANGED
|
@@ -25,6 +25,7 @@ export type ClientRouteItem = {
|
|
|
25
25
|
fallback?: RenderElement;
|
|
26
26
|
children?: ClientRouteItem[];
|
|
27
27
|
staleTime?: number;
|
|
28
|
+
optimistic?: boolean;
|
|
28
29
|
pollingInterval?: number;
|
|
29
30
|
retry?: Retry;
|
|
30
31
|
preserveScroll?: boolean;
|
|
@@ -94,6 +95,10 @@ export type RouterProps = {
|
|
|
94
95
|
afterLoad?: ClientRouteItem['afterLoad'];
|
|
95
96
|
context?: Record<string, unknown>;
|
|
96
97
|
};
|
|
98
|
+
export type LoaderStateItem = {
|
|
99
|
+
state: LoaderState;
|
|
100
|
+
timestamp: number;
|
|
101
|
+
};
|
|
97
102
|
export type RouterState = {
|
|
98
103
|
routeItemDataState: Store<RouteItemData>;
|
|
99
104
|
pendingState: Store<RouteItemData | undefined>;
|
|
@@ -105,7 +110,7 @@ export type RouterState = {
|
|
|
105
110
|
to: string;
|
|
106
111
|
}>;
|
|
107
112
|
loaderStateRef: Cell<LoaderState>;
|
|
108
|
-
|
|
113
|
+
loaderMap: Map<string, LoaderStateItem>;
|
|
109
114
|
};
|
|
110
115
|
export type RouterType = {
|
|
111
116
|
state: Omit<RouterState, 'timestampMap'>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
export declare const createIsCacheItemFresh: (
|
|
1
|
+
import { LoaderStateItem, RouteItem } from '../types';
|
|
2
|
+
export declare const createIsCacheItemFresh: (loaderMap: Map<string, LoaderStateItem>) => ({ routeItem, pathname }: {
|
|
3
3
|
routeItem?: RouteItem;
|
|
4
4
|
pathname: string;
|
|
5
5
|
}) => boolean;
|