clear-react-router 1.8.8 → 1.9.1
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 +20 -123
- package/dist/cell.d.ts +0 -3
- package/dist/components/Router.d.ts +1 -1
- package/dist/config/routerConfig.d.ts +2 -1
- package/dist/hooks/usePreserveScroll.d.ts +2 -1
- package/dist/index.d.ts +1 -3
- package/dist/index.js +83 -191
- package/dist/types.d.ts +9 -13
- package/dist/utils/commitNavigation.d.ts +3 -3
- package/dist/utils/commitState.d.ts +1 -1
- package/dist/utils/revalidateCache.d.ts +1 -1
- package/package.json +1 -1
- package/dist/hooks/useLatest.d.ts +0 -1
- package/dist/hooks/useQueryParam.d.ts +0 -2
- package/dist/utils/adapter.d.ts +0 -51
package/README.md
CHANGED
|
@@ -48,10 +48,11 @@ It provides first-class support for:
|
|
|
48
48
|
| `defaultLoaderFallback` | `ReactElement \| () => ReactElement` | `optional` | Default loading fallback for every route loader |
|
|
49
49
|
| `defaultErrorElement` | `ReactElement \| () => ReactElement` | `optional` | Default error fallback for every route |
|
|
50
50
|
| `defaultRetry` | `number \| { count: number; delay: number }` | `optional` | Default cache revalidation retry policy for all routes |
|
|
51
|
+
| `defaultStaleTime` | `number` | `optional` | Default time in milliseconds before cached loader data is considered stale |
|
|
51
52
|
| `beforeLoad` | `({ params, context, redirect, setContext }) => Promise<unknown> \| undefined \| void` | `undefined` | Runs before every navigation. Useful for authentication, analytics, or updating shared context. |
|
|
52
53
|
| `afterLoad` | `({ params, context, setContext }) => Promise<void>` | `undefined` | Runs after every successful navigation. Useful for analytics, page tracking, or other global side effects. |
|
|
53
54
|
| `spinner` | `boolean \| undefined` | `true` | Show a small spinner in the corner while loading data (only when `isAnimated` is enabled) |
|
|
54
|
-
| `
|
|
55
|
+
| `defaultPreserveScroll` | `boolean \| undefined` | `true` | Default value for save and restore scroll position when navigating between pages |
|
|
55
56
|
| `showFallbackOnAnimation` | `boolean \| undefined` | `false` | Show `loaderFallback` even when `isAnimated` is `true` (instead of spinner) |
|
|
56
57
|
| `prefetch` | `'hover' \| 'render' \| 'viewport' \| 'none'` | `'hover'` | Default prefetch strategy for all `<Link>` components |
|
|
57
58
|
| `hoverPrefetchDelay` | `number` | `150` | Delay in milliseconds before prefetching on hover (only for `'hover'` strategy) |
|
|
@@ -76,15 +77,27 @@ Normalizes route configuration. Extracts dynamic params, builds nested paths.
|
|
|
76
77
|
|----------|------|-------------|
|
|
77
78
|
| `path` | `string` | Route path, e.g., `/user/:userId` |
|
|
78
79
|
| `element` | `ReactElement \| () => ReactElement \| LazyComponent` | Component to render |
|
|
79
|
-
| `beforeLoad` | `({ params, context, redirect, setContext }) => Promise<unknown> \| undefined \| void` | Auth checks and redirects. Can update context via `setContext`. `redirect` is provided by the router |
|
|
80
|
-
| `loader` | `({ params, context, setContext }) => Promise<unknown>` | Fetch data using route params and context. Can update context via `setContext` |
|
|
81
|
-
| `afterLoad` | `({ params, context, setContext }) => Promise<void>` | Analytics, side effects after data is loaded. Can update context via `setContext` |
|
|
80
|
+
| `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 |
|
|
81
|
+
| `loader` | `({ params, context, setContext, searchParams }) => Promise<unknown>` | Fetch data using route params, search params, and context. Can update context via `setContext` |
|
|
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 }` | `undefined` | Overrides the global cache revalidation retry policy for this route |
|
|
85
86
|
| `errorElement` | `ReactElement \| () => ReactElement` | Error fallback for the route. Overrides the global `defaultErrorElement` set in `Router` |
|
|
86
|
-
| `staleTime` | `number` | Time in
|
|
87
|
-
| `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
|
|
87
|
+
| `staleTime` | `number` | Time in milliseconds before cached loader data is considered stale. Overrides Router.defaultStaleTime. If neither value is provided, cached data never expires |
|
|
88
|
+
| `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` |
|
|
89
|
+
| `pollingInterval` | `number \| undefined` | `undefined` | Polling interval (in milliseconds) for automatically revalidating data while the route is active |
|
|
90
|
+
| `preserveScroll` | `boolean \| undefined` | `undefined` | Save and restore route scroll position when navigating between pages |
|
|
91
|
+
|
|
92
|
+
Loader arguments:
|
|
93
|
+
```ts
|
|
94
|
+
{
|
|
95
|
+
params: Record<string, string>; // Route parameters
|
|
96
|
+
context: Record<string, unknown>; // Router context
|
|
97
|
+
setContext: Dispatch<SetStateAction<Record<string, unknown>>>; // Updates the router context
|
|
98
|
+
searchParams: Record<string, string>; // URL search parameters
|
|
99
|
+
}
|
|
100
|
+
```
|
|
88
101
|
|
|
89
102
|
### `Link`
|
|
90
103
|
|
|
@@ -632,122 +645,6 @@ useEffect(() => {
|
|
|
632
645
|
}, [state, process, reset]);
|
|
633
646
|
```
|
|
634
647
|
|
|
635
|
-
### `useQueryParam()`
|
|
636
|
-
|
|
637
|
-
A flexible hook for working with typed query parameters. You provide an adapter object with `parse` and `serialize` functions, and it returns the parsed value and a setter.
|
|
638
|
-
|
|
639
|
-
```tsx
|
|
640
|
-
import { useQueryParam, adapter } from 'clear-react-router';
|
|
641
|
-
|
|
642
|
-
const ProductPage = () => {
|
|
643
|
-
// String parameter
|
|
644
|
-
const [brand, setBrand] = useQueryParam('brand', adapter.string, 'nike');
|
|
645
|
-
|
|
646
|
-
// Number parameter
|
|
647
|
-
const [page, setPage] = useQueryParam('page', adapter.integer, 1);
|
|
648
|
-
|
|
649
|
-
// Date parameter
|
|
650
|
-
const [date, setDate] = useQueryParam('date', adapter.date, new Date());
|
|
651
|
-
|
|
652
|
-
// Array of numbers
|
|
653
|
-
const [prices, setPrices] = useQueryParam('prices', adapter.floatArray);
|
|
654
|
-
|
|
655
|
-
return (
|
|
656
|
-
<div>
|
|
657
|
-
<p>Brand: {brand}</p>
|
|
658
|
-
<p>Page: {page}</p>
|
|
659
|
-
<button onClick={() => setPage(page + 1)}>Next</button>
|
|
660
|
-
</div>
|
|
661
|
-
);
|
|
662
|
-
}
|
|
663
|
-
```
|
|
664
|
-
type Adapter<T> = {
|
|
665
|
-
parse: (params: string[]) => T;
|
|
666
|
-
serialize?: (params: T) => string | string[];
|
|
667
|
-
}
|
|
668
|
-
|
|
669
|
-
**Signature:** `useQueryParam<T>(field: string, adapter: Adapter<T>, defaultValue?: T): [T, (arg: T | null) => void]`
|
|
670
|
-
|
|
671
|
-
| Argument | Type | Description |
|
|
672
|
-
|----------|------|-------------|
|
|
673
|
-
| `field` | `string` | The query parameter key (e.g., `'page'`, `'brand'`) |
|
|
674
|
-
| `adapter` | `Adapter<T>` | Parser and optional serializer for params (serializer String is used in case of serializer not passed) |
|
|
675
|
-
| `defaultValue` | `T` (optional) | Default value returned when the parameter is missing or empty |
|
|
676
|
-
|
|
677
|
-
**Returns:**
|
|
678
|
-
|
|
679
|
-
| Element | Type | Description |
|
|
680
|
-
|---------|------|-------------|
|
|
681
|
-
| `value` | `T` | The parsed value from the query parameter |
|
|
682
|
-
| `setValue` | `(arg: T \| null) => void` | Function to update the query parameter. Null is passed to remove the parameter. |
|
|
683
|
-
|
|
684
|
-
### Built-in Adapters
|
|
685
|
-
|
|
686
|
-
| Adapter | Input | Output | Description |
|
|
687
|
-
|---------|-------|--------|-------------|
|
|
688
|
-
| `adapter.string` | `string[]` | `string` | First value or empty string |
|
|
689
|
-
| `adapter.stringArray` | `string[]` | `string[]` | All values as array |
|
|
690
|
-
| `adapter.integer` | `string[]` | `number` | First value parsed as integer (default: `0`) |
|
|
691
|
-
| `adapter.integerArray` | `string[]` | `number[]` | All values parsed as integers |
|
|
692
|
-
| `adapter.float` | `string[]` | `number` | First value parsed as float (default: `0`) |
|
|
693
|
-
| `adapter.floatArray` | `string[]` | `number[]` | All values parsed as floats |
|
|
694
|
-
| `adapter.boolean` | `string[]` | `boolean` | First value parsed as boolean (`'true'` → `true`) |
|
|
695
|
-
| `adapter.booleanArray` | `string[]` | `boolean[]` | All values parsed as booleans |
|
|
696
|
-
| `adapter.date` | `string[]` | `Date` | First value parsed as Date from timestamp |
|
|
697
|
-
| `adapter.dateArray` | `string[]` | `Date[]` | All values parsed as Dates from timestamps |
|
|
698
|
-
| `adapter.zodSchema` | `string[]` | `T` | Validates JSON string against Zod schema |
|
|
699
|
-
|
|
700
|
-
### Using Zod Schemas
|
|
701
|
-
`useQueryParam` works seamlessly with Zod for complex validation:
|
|
702
|
-
|
|
703
|
-
```tsx
|
|
704
|
-
import { z } from 'zod';
|
|
705
|
-
import { useQueryParam, adapter } from 'clear-react-router';
|
|
706
|
-
|
|
707
|
-
const filterSchema = z.object({
|
|
708
|
-
name: z.string(),
|
|
709
|
-
age: z.number().min(0),
|
|
710
|
-
active: z.boolean().optional(),
|
|
711
|
-
});
|
|
712
|
-
|
|
713
|
-
function ProductFilter() {
|
|
714
|
-
const [filter, setFilter] = useQueryParam(
|
|
715
|
-
'filter',
|
|
716
|
-
adapter.zodSchema(filterSchema),
|
|
717
|
-
{ name: '', age: 0 }
|
|
718
|
-
);
|
|
719
|
-
|
|
720
|
-
return (
|
|
721
|
-
<div>
|
|
722
|
-
<p>Name: {filter.name}</p>
|
|
723
|
-
<p>Age: {filter.age}</p>
|
|
724
|
-
<button onClick={() => setFilter({ ...filter, age: filter.age + 1 })}>
|
|
725
|
-
Increment Age
|
|
726
|
-
</button>
|
|
727
|
-
</div>
|
|
728
|
-
);
|
|
729
|
-
}
|
|
730
|
-
```
|
|
731
|
-
|
|
732
|
-
### Custom Adapters
|
|
733
|
-
You can write your own adapter for any format:
|
|
734
|
-
|
|
735
|
-
```tsx
|
|
736
|
-
// Custom adapter for comma-separated values
|
|
737
|
-
const csvAdapter = {
|
|
738
|
-
parse: (params: string[]): string[] => {
|
|
739
|
-
const value = params[0] || '';
|
|
740
|
-
return value ? value.split(',').map(v => v.trim()) : [];
|
|
741
|
-
},
|
|
742
|
-
serialize: (value: string[]): string[] => value
|
|
743
|
-
}
|
|
744
|
-
|
|
745
|
-
const TagsFilter() {
|
|
746
|
-
const [tags, setTags] = useQueryParam('tags', csvAdapter, []);
|
|
747
|
-
// tags: string[]
|
|
748
|
-
}
|
|
749
|
-
```
|
|
750
|
-
|
|
751
648
|
### `useRouterContext()`
|
|
752
649
|
|
|
753
650
|
Returns the router context object and a function to update it. Useful for accessing or modifying global state (like user authentication, theme, etc.) from anywhere in your app.
|
package/dist/cell.d.ts
CHANGED
|
@@ -4,6 +4,3 @@ export declare class Cell<T> {
|
|
|
4
4
|
get value(): T;
|
|
5
5
|
set(action: T | ((prev: T) => T)): void;
|
|
6
6
|
}
|
|
7
|
-
export declare const loaderStateRef: Cell<import("./types").LoaderState>;
|
|
8
|
-
export declare const prevPathnameRef: Cell<string>;
|
|
9
|
-
export declare const timestampMap: Map<string, number>;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { RouterProps } from '../types';
|
|
2
|
-
export declare const Router: ({ routes, beforeLoad, afterLoad, animationDuration, isAnimated, spinner,
|
|
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;
|
|
@@ -3,11 +3,12 @@ declare class RouterConfig {
|
|
|
3
3
|
routes: RouterProps['routes'];
|
|
4
4
|
prefetch: RouterProps['prefetch'];
|
|
5
5
|
isAnimated: RouterProps['isAnimated'];
|
|
6
|
-
showFallbackOnAnimation: RouterProps['showFallbackOnAnimation'];
|
|
7
6
|
hoverPrefetchDelay: number;
|
|
8
7
|
beforeLoad?: ClientRouteItem['beforeLoad'];
|
|
9
8
|
afterLoad?: ClientRouteItem['afterLoad'];
|
|
10
9
|
defaultRetry?: RouterProps['defaultRetry'];
|
|
10
|
+
defaultStaleTime?: RouterProps['defaultStaleTime'];
|
|
11
|
+
defaultPreserveScroll?: RouterProps['defaultPreserveScroll'];
|
|
11
12
|
configure(config: Partial<RouterConfig>): void;
|
|
12
13
|
}
|
|
13
14
|
export declare const routerConfig: RouterConfig;
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
import { RouteItemData } from '../types';
|
|
2
|
+
export declare const usePreserveScroll: ({ routeItem, location: { pathname } }: RouteItemData) => void;
|
package/dist/index.d.ts
CHANGED
|
@@ -9,9 +9,7 @@ export { useInvalidate } from './hooks/useInvalidate';
|
|
|
9
9
|
export { useBlocker } from './hooks/useBlocker';
|
|
10
10
|
export { useAction } from './hooks/useAction';
|
|
11
11
|
export { useRouterContext } from './hooks/useRouterContext';
|
|
12
|
-
export { useQueryParam } from './hooks/useQueryParam';
|
|
13
12
|
export { useSearchParams } from './hooks/useSearchParams';
|
|
14
13
|
export { useFormContext } from './hooks/useFormContext';
|
|
15
|
-
export { adapter } from './utils/adapter';
|
|
16
14
|
export { createRouter } from './utils/utils';
|
|
17
|
-
export type { RouteItem, BlockerState, Location,
|
|
15
|
+
export type { RouteItem, BlockerState, Location, RouterProps } from './types';
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Suspense, createContext, lazy, useCallback, useContext, useEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
|
|
1
|
+
import { Suspense, createContext, lazy, useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
|
|
2
2
|
//#region \0rolldown/runtime.js
|
|
3
3
|
var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
|
|
4
4
|
//#endregion
|
|
@@ -30,15 +30,12 @@ var useGlobalState = ({ subscribe, getState, setState }) => {
|
|
|
30
30
|
};
|
|
31
31
|
//#endregion
|
|
32
32
|
//#region utils/commitState.ts
|
|
33
|
-
var createCommitState = ({
|
|
33
|
+
var createCommitState = ({ routeItemDataState, pendingState }) => (nextLocation, routeItem) => {
|
|
34
34
|
routeItemDataState.setState({
|
|
35
35
|
routeItem,
|
|
36
36
|
location: nextLocation
|
|
37
37
|
});
|
|
38
|
-
|
|
39
|
-
isLoadingState.setState(false);
|
|
40
|
-
loaderFallbackState.setState(void 0);
|
|
41
|
-
prevPathnameRef.set(nextLocation.pathname);
|
|
38
|
+
pendingState.setState(void 0);
|
|
42
39
|
const fullPath = nextLocation.search ? `${nextLocation.pathname}${nextLocation.search}` : nextLocation.pathname;
|
|
43
40
|
if (fullPath === window.location.pathname + window.location.search) return;
|
|
44
41
|
history.pushState(null, "", fullPath);
|
|
@@ -91,11 +88,12 @@ var RouterConfig = class {
|
|
|
91
88
|
_defineProperty(this, "routes", []);
|
|
92
89
|
_defineProperty(this, "prefetch", "hover");
|
|
93
90
|
_defineProperty(this, "isAnimated", false);
|
|
94
|
-
_defineProperty(this, "showFallbackOnAnimation", false);
|
|
95
91
|
_defineProperty(this, "hoverPrefetchDelay", 150);
|
|
96
92
|
_defineProperty(this, "beforeLoad", void 0);
|
|
97
93
|
_defineProperty(this, "afterLoad", void 0);
|
|
98
94
|
_defineProperty(this, "defaultRetry", void 0);
|
|
95
|
+
_defineProperty(this, "defaultStaleTime", void 0);
|
|
96
|
+
_defineProperty(this, "defaultPreserveScroll", void 0);
|
|
99
97
|
}
|
|
100
98
|
configure(config) {
|
|
101
99
|
Object.assign(this, config);
|
|
@@ -104,12 +102,9 @@ var RouterConfig = class {
|
|
|
104
102
|
var routerConfig = new RouterConfig();
|
|
105
103
|
//#endregion
|
|
106
104
|
//#region utils/commitNavigation.ts
|
|
107
|
-
var createCommitNavigation = (navigationExecutor,
|
|
108
|
-
const
|
|
109
|
-
if (!isAnimated ||
|
|
110
|
-
navigationExecutor(nextLocation, routeItem);
|
|
111
|
-
return;
|
|
112
|
-
}
|
|
105
|
+
var createCommitNavigation = (navigationExecutor, routeItemDataState) => (nextLocation, routeItem) => {
|
|
106
|
+
const isFirstLoad = !routeItemDataState.getState().location.pathname;
|
|
107
|
+
if (!routerConfig.isAnimated || isFirstLoad) return navigationExecutor(nextLocation, routeItem);
|
|
113
108
|
try {
|
|
114
109
|
document.startViewTransition(() => navigationExecutor(nextLocation, routeItem));
|
|
115
110
|
} catch {
|
|
@@ -120,10 +115,11 @@ var createCommitNavigation = (navigationExecutor, prevPathnameRef) => (nextLocat
|
|
|
120
115
|
//#region utils/isCacheItemFresh.ts
|
|
121
116
|
var createIsCacheItemFresh = (timestampMap) => ({ routeItem, pathname }) => {
|
|
122
117
|
if (!routeItem) return true;
|
|
123
|
-
const
|
|
124
|
-
if (
|
|
125
|
-
|
|
126
|
-
|
|
118
|
+
const timestamp = timestampMap.get(pathname);
|
|
119
|
+
if (timestamp === void 0) return false;
|
|
120
|
+
const staleTime = routeItem.staleTime ?? routerConfig.defaultStaleTime;
|
|
121
|
+
if (staleTime === void 0) return true;
|
|
122
|
+
return Date.now() - timestamp <= staleTime;
|
|
127
123
|
};
|
|
128
124
|
//#endregion
|
|
129
125
|
//#region ../../node_modules/react/cjs/react-jsx-runtime.production.js
|
|
@@ -218,9 +214,10 @@ var findRoute = (pathname, includeAll) => {
|
|
|
218
214
|
//#endregion
|
|
219
215
|
//#region runtime/navigate.ts
|
|
220
216
|
var navigationSeq = 0;
|
|
217
|
+
var interval = 0;
|
|
221
218
|
var createNavigate = (routerState, revalidateCache) => {
|
|
222
|
-
const { loaderStateRef, scrollMapState,
|
|
223
|
-
const commitNavigation = createCommitNavigation(createCommitState(routerState),
|
|
219
|
+
const { loaderStateRef, scrollMapState, pendingState, contextState, timestampMap, routeItemDataState } = routerState;
|
|
220
|
+
const commitNavigation = createCommitNavigation(createCommitState(routerState), routeItemDataState);
|
|
224
221
|
const isCacheItemFresh = createIsCacheItemFresh(timestampMap);
|
|
225
222
|
const getContext = () => ({
|
|
226
223
|
context: contextState.getState(),
|
|
@@ -259,29 +256,40 @@ var createNavigate = (routerState, revalidateCache) => {
|
|
|
259
256
|
if (routeItem?.beforeLoad) await runBeforeLoad(routeItem?.beforeLoad);
|
|
260
257
|
};
|
|
261
258
|
const prepareNavigation = (routeItem, location) => {
|
|
262
|
-
const { isAnimated, showFallbackOnAnimation: showFallback } = routerConfig;
|
|
263
259
|
scrollMapState.setState((prevState) => {
|
|
264
260
|
const scrollPosition = document.scrollingElement?.scrollTop ?? 0;
|
|
265
|
-
|
|
261
|
+
const prevPathname = routeItemDataState.getState().location.pathname;
|
|
262
|
+
if (!scrollPosition || prevState[prevPathname] === scrollPosition) return prevState;
|
|
266
263
|
return {
|
|
267
264
|
...prevState,
|
|
268
|
-
[
|
|
265
|
+
[prevPathname]: scrollPosition
|
|
269
266
|
};
|
|
270
267
|
});
|
|
271
|
-
|
|
268
|
+
const pendingShouldExist = routeItem?.loader && !isCacheItemFresh({
|
|
272
269
|
routeItem,
|
|
273
270
|
pathname: location.pathname
|
|
274
|
-
})
|
|
271
|
+
});
|
|
272
|
+
pendingState.setState(pendingShouldExist ? {
|
|
273
|
+
routeItem,
|
|
274
|
+
location
|
|
275
|
+
} : void 0);
|
|
276
|
+
};
|
|
277
|
+
const afterEachLoad = (routeItem) => {
|
|
278
|
+
if (!routeItem?.pollingInterval) return;
|
|
279
|
+
interval = window.setInterval(() => revalidateCache({
|
|
280
|
+
routeItem,
|
|
281
|
+
pathname: location.pathname
|
|
282
|
+
}), routeItem.pollingInterval);
|
|
275
283
|
};
|
|
276
284
|
const loader = async (routeItem, location) => {
|
|
277
285
|
if (!routeItem?.loader) return;
|
|
278
|
-
|
|
279
|
-
pendingPathRef.set(location.pathname);
|
|
286
|
+
window.clearInterval(interval);
|
|
280
287
|
await revalidateCache({
|
|
281
288
|
routeItem,
|
|
282
|
-
pathname: location.pathname
|
|
289
|
+
pathname: location.pathname,
|
|
290
|
+
search: location.search
|
|
283
291
|
});
|
|
284
|
-
|
|
292
|
+
afterEachLoad(routeItem);
|
|
285
293
|
};
|
|
286
294
|
const afterLoad = async (routeItem, params) => {
|
|
287
295
|
const { afterLoad } = routerConfig;
|
|
@@ -399,7 +407,7 @@ var getRetry = (routeItem) => {
|
|
|
399
407
|
var sleep = async (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
400
408
|
var createRevalidateCache = (routerState) => {
|
|
401
409
|
const { loaderStateRef, timestampMap, contextState } = routerState;
|
|
402
|
-
const revalidateCache = async ({ routeItem, pathname }, retried = 0) => {
|
|
410
|
+
const revalidateCache = async ({ routeItem, pathname, search = "" }, retried = 0) => {
|
|
403
411
|
if (!routeItem?.loader) return;
|
|
404
412
|
const isCacheItemFresh = createIsCacheItemFresh(timestampMap);
|
|
405
413
|
if (loadingPromises.has(pathname)) return loadingPromises.get(pathname);
|
|
@@ -416,18 +424,20 @@ var createRevalidateCache = (routerState) => {
|
|
|
416
424
|
const context = contextState.getState();
|
|
417
425
|
const setContext = contextState.setState;
|
|
418
426
|
const params = getParamsObject(routeItem, pathname);
|
|
427
|
+
const searchParams = Object.fromEntries(new URLSearchParams(search).entries());
|
|
419
428
|
const result = await routeItem?.loader({
|
|
420
429
|
params,
|
|
421
430
|
context,
|
|
422
|
-
setContext
|
|
431
|
+
setContext,
|
|
432
|
+
searchParams
|
|
423
433
|
});
|
|
424
|
-
timestampMap.set(pathname
|
|
434
|
+
timestampMap.set(`${pathname}${search}`, Date.now());
|
|
425
435
|
loaderStateRef.set((prev) => ({
|
|
426
436
|
...prev,
|
|
427
437
|
data: result,
|
|
428
438
|
loaderError: null
|
|
429
439
|
}));
|
|
430
|
-
loaderMapRef[pathname] = loaderStateRef.value;
|
|
440
|
+
loaderMapRef[`${pathname}${search}`] = loaderStateRef.value;
|
|
431
441
|
return {
|
|
432
442
|
data: result,
|
|
433
443
|
error: null
|
|
@@ -435,7 +445,7 @@ var createRevalidateCache = (routerState) => {
|
|
|
435
445
|
} catch (error) {
|
|
436
446
|
const retry = getRetry(routeItem);
|
|
437
447
|
if (retry && retry.count > retried) {
|
|
438
|
-
loadingPromises.delete(pathname);
|
|
448
|
+
loadingPromises.delete(`${pathname}${search}`);
|
|
439
449
|
if (retry.delay) await sleep(retry.delay);
|
|
440
450
|
await revalidateCache({
|
|
441
451
|
routeItem,
|
|
@@ -457,10 +467,10 @@ var createRevalidateCache = (routerState) => {
|
|
|
457
467
|
};
|
|
458
468
|
}
|
|
459
469
|
} finally {
|
|
460
|
-
loadingPromises.delete(pathname);
|
|
470
|
+
loadingPromises.delete(`${pathname}${search}`);
|
|
461
471
|
}
|
|
462
472
|
})();
|
|
463
|
-
loadingPromises.set(pathname
|
|
473
|
+
loadingPromises.set(`${pathname}${search}`, promise);
|
|
464
474
|
return promise;
|
|
465
475
|
};
|
|
466
476
|
return revalidateCache;
|
|
@@ -479,18 +489,15 @@ var Cell = class {
|
|
|
479
489
|
this._value = typeof action === "function" ? action(this._value) : action;
|
|
480
490
|
}
|
|
481
491
|
};
|
|
482
|
-
new Cell(emptyLoaderState);
|
|
483
|
-
new Cell("");
|
|
484
492
|
//#endregion
|
|
485
493
|
//#region utils/createRouterInstance.ts
|
|
486
494
|
var createRouterInstance = () => {
|
|
487
495
|
const routerState = {
|
|
488
|
-
isLoadingState: create(false),
|
|
489
|
-
loaderFallbackState: create(void 0),
|
|
490
496
|
routeItemDataState: create({
|
|
491
497
|
routeItem: void 0,
|
|
492
498
|
location: {}
|
|
493
499
|
}),
|
|
500
|
+
pendingState: create(void 0),
|
|
494
501
|
currentLoaderState: create(emptyLoaderState),
|
|
495
502
|
scrollMapState: create({}),
|
|
496
503
|
contextState: create({}),
|
|
@@ -499,13 +506,11 @@ var createRouterInstance = () => {
|
|
|
499
506
|
to: ""
|
|
500
507
|
}),
|
|
501
508
|
loaderStateRef: new Cell(emptyLoaderState),
|
|
502
|
-
prevPathnameRef: new Cell(""),
|
|
503
|
-
pendingPathRef: new Cell(""),
|
|
504
509
|
timestampMap: /* @__PURE__ */ new Map()
|
|
505
510
|
};
|
|
506
511
|
const revalidateCache = createRevalidateCache(routerState);
|
|
507
|
-
const navigate = createNavigate(routerState, revalidateCache);
|
|
508
512
|
const invalidate = createInvalidate(routerState, revalidateCache);
|
|
513
|
+
const navigate = createNavigate(routerState, revalidateCache);
|
|
509
514
|
const prefetch = createPrefetch(revalidateCache);
|
|
510
515
|
const useGetAction = (actionKey) => {
|
|
511
516
|
const { routeItem } = routerState.routeItemDataState.getState();
|
|
@@ -527,29 +532,17 @@ var createRouterInstance = () => {
|
|
|
527
532
|
};
|
|
528
533
|
};
|
|
529
534
|
return {
|
|
530
|
-
state:
|
|
531
|
-
isLoadingState: routerState.isLoadingState,
|
|
532
|
-
loaderFallbackState: routerState.loaderFallbackState,
|
|
533
|
-
routeItemDataState: routerState.routeItemDataState,
|
|
534
|
-
currentLoaderState: routerState.currentLoaderState,
|
|
535
|
-
scrollMapState: routerState.scrollMapState,
|
|
536
|
-
contextState: routerState.contextState,
|
|
537
|
-
blockedRouteState: routerState.blockedRouteState,
|
|
538
|
-
prevPathnameRef: routerState.prevPathnameRef,
|
|
539
|
-
pendingPathRef: routerState.pendingPathRef
|
|
540
|
-
},
|
|
535
|
+
state: routerState,
|
|
541
536
|
runtime: {
|
|
542
537
|
navigate,
|
|
543
538
|
invalidate,
|
|
544
539
|
prefetch
|
|
545
540
|
},
|
|
546
541
|
hooks: {
|
|
547
|
-
useIsLoading: () => useGlobalState(routerState.isLoadingState),
|
|
548
542
|
useBlockedRoute: () => useGlobalState(routerState.blockedRouteState),
|
|
549
|
-
useLoaderFallback: () => useGlobalState(routerState.loaderFallbackState),
|
|
550
543
|
useRouteItemData: () => useGlobalState(routerState.routeItemDataState),
|
|
551
|
-
useCurrentLoaderState: () => useGlobalState(routerState.currentLoaderState),
|
|
552
544
|
useScrollMap: () => useGlobalState(routerState.scrollMapState),
|
|
545
|
+
usePendingState: () => useGlobalState(routerState.pendingState),
|
|
553
546
|
useContextState: () => useGlobalState(routerState.contextState),
|
|
554
547
|
useParams: () => getParamsObject(),
|
|
555
548
|
useNavigate: () => {
|
|
@@ -602,16 +595,16 @@ var router = createRouterInstance();
|
|
|
602
595
|
//#endregion
|
|
603
596
|
//#region hooks/useNavigation.ts
|
|
604
597
|
var useNavigation = () => {
|
|
605
|
-
const { state: {
|
|
598
|
+
const { state: { routeItemDataState, blockedRouteState }, runtime: { navigate } } = router;
|
|
606
599
|
useEffect(() => {
|
|
607
600
|
const handler = async (event) => {
|
|
608
601
|
const newLocation = parseWindowLocation(event.target.location);
|
|
609
|
-
if (
|
|
602
|
+
if (routeItemDataState.getState().location.pathname === blockedRouteState.getState().from) {
|
|
610
603
|
blockedRouteState.setState({
|
|
611
|
-
from:
|
|
604
|
+
from: routeItemDataState.getState().location.pathname,
|
|
612
605
|
to: newLocation.pathname
|
|
613
606
|
});
|
|
614
|
-
history.pushState(null, "",
|
|
607
|
+
history.pushState(null, "", routeItemDataState.getState().location.pathname);
|
|
615
608
|
} else navigate(newLocation);
|
|
616
609
|
};
|
|
617
610
|
window.addEventListener("popstate", handler);
|
|
@@ -619,13 +612,11 @@ var useNavigation = () => {
|
|
|
619
612
|
}, [
|
|
620
613
|
blockedRouteState,
|
|
621
614
|
navigate,
|
|
622
|
-
|
|
615
|
+
routeItemDataState
|
|
623
616
|
]);
|
|
624
617
|
useEffect(() => {
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
prevPathnameRef.set(currentLocation.pathname);
|
|
628
|
-
}, [navigate, prevPathnameRef]);
|
|
618
|
+
navigate(parseWindowLocation(window.location));
|
|
619
|
+
}, [navigate]);
|
|
629
620
|
};
|
|
630
621
|
//#endregion
|
|
631
622
|
//#region hooks/useApplyCustomAnimation.ts
|
|
@@ -665,16 +656,10 @@ var useApplyCustomAnimation = (animationDuration) => {
|
|
|
665
656
|
}, [animationDuration]);
|
|
666
657
|
};
|
|
667
658
|
//#endregion
|
|
668
|
-
//#region hooks/useLocation.ts
|
|
669
|
-
var useLocation = () => {
|
|
670
|
-
const [routeItemData] = router.hooks.useRouteItemData();
|
|
671
|
-
return routeItemData.location;
|
|
672
|
-
};
|
|
673
|
-
//#endregion
|
|
674
659
|
//#region hooks/usePreserveScroll.ts
|
|
675
|
-
var usePreserveScroll = (
|
|
660
|
+
var usePreserveScroll = ({ routeItem, location: { pathname } }) => {
|
|
661
|
+
const preserveScroll = routeItem?.preserveScroll === void 0 ? routerConfig.defaultPreserveScroll : routeItem.preserveScroll;
|
|
676
662
|
const restoreScroll = router.hooks.useRestoreScroll();
|
|
677
|
-
const { pathname } = useLocation();
|
|
678
663
|
useEffect(() => {
|
|
679
664
|
if (preserveScroll) restoreScroll();
|
|
680
665
|
}, [
|
|
@@ -686,7 +671,7 @@ var usePreserveScroll = (preserveScroll) => {
|
|
|
686
671
|
//#endregion
|
|
687
672
|
//#region hooks/useSetRouterConfig.ts
|
|
688
673
|
var useSetRouterConfig = (routerProps) => {
|
|
689
|
-
|
|
674
|
+
useLayoutEffect(() => routerConfig.configure(routerProps), [routerProps]);
|
|
690
675
|
};
|
|
691
676
|
//#endregion
|
|
692
677
|
//#region hooks/useSetInitialContext.ts
|
|
@@ -708,31 +693,32 @@ var renderElement = (Component) => {
|
|
|
708
693
|
//#endregion
|
|
709
694
|
//#region components/Router.tsx
|
|
710
695
|
var EmptyBoundary = ({ children }) => children;
|
|
711
|
-
var Router = ({ routes, beforeLoad, afterLoad, animationDuration, isAnimated = false, spinner = true,
|
|
712
|
-
const {
|
|
713
|
-
const [isLoading] = useIsLoading();
|
|
714
|
-
const [currentLoaderFallback] = useLoaderFallback();
|
|
696
|
+
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 }) => {
|
|
697
|
+
const { useRouteItemData, usePendingState } = router.hooks;
|
|
715
698
|
const [routeItemData] = useRouteItemData();
|
|
716
|
-
const [
|
|
699
|
+
const [pendingState] = usePendingState();
|
|
700
|
+
const loaderState = router.state.loaderStateRef.value;
|
|
701
|
+
const isLoading = Boolean(pendingState);
|
|
717
702
|
useNavigation();
|
|
718
703
|
useSetRouterConfig({
|
|
719
704
|
routes,
|
|
720
705
|
isAnimated,
|
|
721
706
|
prefetch,
|
|
722
707
|
hoverPrefetchDelay,
|
|
723
|
-
showFallbackOnAnimation,
|
|
724
708
|
beforeLoad,
|
|
725
709
|
afterLoad,
|
|
726
|
-
defaultRetry
|
|
710
|
+
defaultRetry,
|
|
711
|
+
defaultStaleTime,
|
|
712
|
+
defaultPreserveScroll
|
|
727
713
|
});
|
|
728
714
|
useApplyCustomAnimation(animationDuration);
|
|
729
715
|
useSetInitialContext(initialContext);
|
|
730
|
-
usePreserveScroll(
|
|
716
|
+
usePreserveScroll(routeItemData);
|
|
717
|
+
const { routeItem, location } = routeItemData;
|
|
731
718
|
const showErrorElement = !isLoading && Boolean(loaderState.loaderError || loaderState.beforeLoadError);
|
|
732
719
|
const showSpinner = spinner && isAnimated && isLoading;
|
|
733
720
|
const loadingContent = !showErrorElement && isLoading;
|
|
734
|
-
|
|
735
|
-
if ((showFallbackOnAnimation || !isAnimated) && loadingContent) return renderElement(currentLoaderFallback || defaultLoaderFallback);
|
|
721
|
+
if ((showFallbackOnAnimation || !isAnimated) && loadingContent) return renderElement(pendingState?.routeItem?.loaderFallback || defaultLoaderFallback);
|
|
736
722
|
if (!showFallbackOnAnimation && isAnimated && loadingContent) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Spinner, {});
|
|
737
723
|
if (!routeItem) return null;
|
|
738
724
|
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, {})] });
|
|
@@ -744,14 +730,20 @@ var Router = ({ routes, beforeLoad, afterLoad, animationDuration, isAnimated = f
|
|
|
744
730
|
//#endregion
|
|
745
731
|
//#region hooks/useIsRoutePending.ts
|
|
746
732
|
var useIsRoutePending = (routePath) => {
|
|
747
|
-
const {
|
|
748
|
-
const [
|
|
749
|
-
return
|
|
733
|
+
const { usePendingState } = router.hooks;
|
|
734
|
+
const [pendingState] = usePendingState();
|
|
735
|
+
return pendingState?.location.pathname === routePath;
|
|
750
736
|
};
|
|
751
737
|
//#endregion
|
|
752
738
|
//#region hooks/useNavigate.ts
|
|
753
739
|
var useNavigate = router.hooks.useNavigate;
|
|
754
740
|
//#endregion
|
|
741
|
+
//#region hooks/useLocation.ts
|
|
742
|
+
var useLocation = () => {
|
|
743
|
+
const [routeItemData] = router.hooks.useRouteItemData();
|
|
744
|
+
return routeItemData.location;
|
|
745
|
+
};
|
|
746
|
+
//#endregion
|
|
755
747
|
//#region components/Link.tsx
|
|
756
748
|
var Link = ({ children, to, prefetch: prefetchLink, hoverPrefetchDelay, className, style, onClick, activeClassName = "active-link", pendingClassName = "pending-link" }) => {
|
|
757
749
|
const isPending = useIsRoutePending(to);
|
|
@@ -867,10 +859,7 @@ var Form = ({ children, action, onSuccess, onError, autoReset = true }) => {
|
|
|
867
859
|
var useParams = router.hooks.useParams;
|
|
868
860
|
//#endregion
|
|
869
861
|
//#region hooks/useLoaderState.ts
|
|
870
|
-
var useLoaderState = () =>
|
|
871
|
-
const [loaderState] = router.hooks.useCurrentLoaderState();
|
|
872
|
-
return loaderState;
|
|
873
|
-
};
|
|
862
|
+
var useLoaderState = () => router.state.loaderStateRef.value;
|
|
874
863
|
//#endregion
|
|
875
864
|
//#region hooks/useInvalidate.ts
|
|
876
865
|
var useInvalidate = () => router.runtime.invalidate;
|
|
@@ -960,19 +949,9 @@ var useSearch = () => {
|
|
|
960
949
|
return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
961
950
|
};
|
|
962
951
|
//#endregion
|
|
963
|
-
//#region hooks/useLatest.ts
|
|
964
|
-
var useLatest = (value) => {
|
|
965
|
-
const ref = useRef(value);
|
|
966
|
-
useEffect(() => {
|
|
967
|
-
ref.current = value;
|
|
968
|
-
}, [value]);
|
|
969
|
-
return ref;
|
|
970
|
-
};
|
|
971
|
-
//#endregion
|
|
972
952
|
//#region hooks/useSearchParams.ts
|
|
973
953
|
var useSearchParams = () => {
|
|
974
954
|
const search = useSearch();
|
|
975
|
-
const searchRef = useLatest(search);
|
|
976
955
|
const searchString = search ? search.replace("?", "") : window.location.pathname.split("?")?.[1] ?? "";
|
|
977
956
|
const searchParams = useMemo(() => new URLSearchParams(searchString), [searchString]);
|
|
978
957
|
const getSearchParams = useCallback((param) => {
|
|
@@ -989,105 +968,18 @@ var useSearchParams = () => {
|
|
|
989
968
|
searchParams,
|
|
990
969
|
getSearchParams,
|
|
991
970
|
setSearchParams: useCallback((param, value) => {
|
|
992
|
-
const currentParams = new URLSearchParams(
|
|
971
|
+
const currentParams = new URLSearchParams(search);
|
|
993
972
|
if (typeof param === "string" && value !== void 0) {
|
|
994
973
|
currentParams.delete(param);
|
|
995
974
|
(Array.isArray(value) ? value : [value]).forEach((v) => currentParams.append(param, v));
|
|
996
975
|
navigateWithSearchParams(currentParams);
|
|
997
976
|
} else if (typeof param === "function") navigateWithSearchParams(param(currentParams));
|
|
998
977
|
else throw new Error("useSearchParams first argument must be either function or string");
|
|
999
|
-
}, [navigateWithSearchParams,
|
|
978
|
+
}, [navigateWithSearchParams, search])
|
|
1000
979
|
};
|
|
1001
980
|
};
|
|
1002
981
|
//#endregion
|
|
1003
|
-
//#region hooks/useQueryParam.ts
|
|
1004
|
-
function useQueryParam(field, adapter, defaultValue) {
|
|
1005
|
-
const { searchParams, setSearchParams } = useSearchParams();
|
|
1006
|
-
return [useMemo(() => {
|
|
1007
|
-
const params = searchParams.getAll(field);
|
|
1008
|
-
const result = adapter.parse(params);
|
|
1009
|
-
const isValid = !(result instanceof Date) || result instanceof Date && !isNaN(result.getTime());
|
|
1010
|
-
if (result !== void 0 && result !== null && result !== "" && isValid) return result;
|
|
1011
|
-
if (defaultValue !== void 0) return defaultValue;
|
|
1012
|
-
return result;
|
|
1013
|
-
}, [
|
|
1014
|
-
field,
|
|
1015
|
-
adapter,
|
|
1016
|
-
searchParams,
|
|
1017
|
-
defaultValue
|
|
1018
|
-
]), useCallback((value) => {
|
|
1019
|
-
if (!value) return setSearchParams(field, []);
|
|
1020
|
-
setSearchParams(field, (adapter.serialize || String)(value));
|
|
1021
|
-
}, [
|
|
1022
|
-
field,
|
|
1023
|
-
adapter.serialize,
|
|
1024
|
-
setSearchParams
|
|
1025
|
-
])];
|
|
1026
|
-
}
|
|
1027
|
-
//#endregion
|
|
1028
982
|
//#region hooks/useFormContext.ts
|
|
1029
983
|
var useFormContext = () => useContext(FormContext);
|
|
1030
984
|
//#endregion
|
|
1031
|
-
|
|
1032
|
-
var adapter = {
|
|
1033
|
-
string: { parse: (params) => params[0] || "" },
|
|
1034
|
-
stringArray: {
|
|
1035
|
-
parse: (params) => params,
|
|
1036
|
-
serialize: (value) => value
|
|
1037
|
-
},
|
|
1038
|
-
integer: { parse: (params) => {
|
|
1039
|
-
const result = parseInt(params[0] || "");
|
|
1040
|
-
return isNaN(result) ? 0 : result;
|
|
1041
|
-
} },
|
|
1042
|
-
integerArray: {
|
|
1043
|
-
parse: (params) => params.map((el) => {
|
|
1044
|
-
const result = parseInt(el);
|
|
1045
|
-
return isNaN(result) ? 0 : result;
|
|
1046
|
-
}),
|
|
1047
|
-
serialize: (value) => value.map(String)
|
|
1048
|
-
},
|
|
1049
|
-
float: { parse: (params) => {
|
|
1050
|
-
const result = parseFloat(params[0] || "");
|
|
1051
|
-
return isNaN(result) ? 0 : result;
|
|
1052
|
-
} },
|
|
1053
|
-
floatArray: {
|
|
1054
|
-
parse: (params) => params.map((el) => {
|
|
1055
|
-
const result = parseFloat(el);
|
|
1056
|
-
return isNaN(result) ? 0 : result;
|
|
1057
|
-
}),
|
|
1058
|
-
serialize: (value) => value.map(String)
|
|
1059
|
-
},
|
|
1060
|
-
boolean: {
|
|
1061
|
-
parse: (params) => params[0]?.toLowerCase() === "true",
|
|
1062
|
-
serialize: String
|
|
1063
|
-
},
|
|
1064
|
-
booleanArray: {
|
|
1065
|
-
parse: (params) => params.map((el) => el.toLowerCase() === "true"),
|
|
1066
|
-
serialize: (value) => value.map(String)
|
|
1067
|
-
},
|
|
1068
|
-
date: {
|
|
1069
|
-
parse: (params) => new Date(Number(params[0])),
|
|
1070
|
-
serialize: (arg) => String(arg.getTime())
|
|
1071
|
-
},
|
|
1072
|
-
dateArray: {
|
|
1073
|
-
parse: (params) => params.map((param) => new Date(Number(param))),
|
|
1074
|
-
serialize: (args) => args.map((arg) => String(arg.getTime()))
|
|
1075
|
-
},
|
|
1076
|
-
zodSchema: (schema) => ({
|
|
1077
|
-
parse: (params) => {
|
|
1078
|
-
let parsed;
|
|
1079
|
-
try {
|
|
1080
|
-
parsed = params[0] ? JSON.parse(params[0]) : void 0;
|
|
1081
|
-
} catch {
|
|
1082
|
-
throw new Error("Invalid JSON");
|
|
1083
|
-
}
|
|
1084
|
-
if (parsed === void 0) return void 0;
|
|
1085
|
-
const result = schema.safeParse(parsed);
|
|
1086
|
-
if (!result.success) throw new Error("Invalid schema");
|
|
1087
|
-
return result.data;
|
|
1088
|
-
},
|
|
1089
|
-
serialize: JSON.stringify
|
|
1090
|
-
})
|
|
1091
|
-
};
|
|
1092
|
-
//#endregion
|
|
1093
|
-
export { Form, Link, Router, adapter, createRouter, useAction, useBlocker, useFormContext, useInvalidate, useLoaderState, useLocation, useNavigate, useParams, useQueryParam, useRouterContext, useSearchParams };
|
|
985
|
+
export { Form, Link, Router, createRouter, useAction, useBlocker, useFormContext, useInvalidate, useLoaderState, useLocation, useNavigate, useParams, useRouterContext, useSearchParams };
|
package/dist/types.d.ts
CHANGED
|
@@ -18,13 +18,16 @@ export type ClientRouteItem = {
|
|
|
18
18
|
params: Record<string, string>;
|
|
19
19
|
context: Record<string, unknown>;
|
|
20
20
|
setContext: Dispatch<SetStateAction<Record<string, unknown>>>;
|
|
21
|
+
searchParams: Record<string, string>;
|
|
21
22
|
}): Promise<unknown>;
|
|
22
23
|
loaderFallback?: RenderElement;
|
|
23
24
|
errorElement?: RenderElement;
|
|
24
25
|
fallback?: RenderElement;
|
|
25
26
|
children?: ClientRouteItem[];
|
|
26
27
|
staleTime?: number;
|
|
28
|
+
pollingInterval?: number;
|
|
27
29
|
retry?: Retry;
|
|
30
|
+
preserveScroll?: boolean;
|
|
28
31
|
beforeLoad?: BeforeLoad;
|
|
29
32
|
afterLoad?: (arg: {
|
|
30
33
|
context: Record<string, unknown>;
|
|
@@ -55,16 +58,13 @@ export type BlockerState = 'blocked' | 'unblocked' | 'charged';
|
|
|
55
58
|
export type RevalidateCacheArgs = {
|
|
56
59
|
pathname: string;
|
|
57
60
|
routeItem?: RouteItem;
|
|
61
|
+
search?: string;
|
|
58
62
|
};
|
|
59
63
|
export type LoaderState<T = unknown> = {
|
|
60
64
|
data: T;
|
|
61
65
|
loaderError: Error | null;
|
|
62
66
|
beforeLoadError: Error | null;
|
|
63
67
|
};
|
|
64
|
-
export type Adapter<T> = {
|
|
65
|
-
parse: (params: string[]) => T;
|
|
66
|
-
serialize?: (params: T) => string | string[];
|
|
67
|
-
};
|
|
68
68
|
export type RouteItemData = {
|
|
69
69
|
location: Location;
|
|
70
70
|
routeItem: RouteItem | undefined;
|
|
@@ -79,8 +79,9 @@ export type RouterProps = {
|
|
|
79
79
|
isAnimated?: boolean;
|
|
80
80
|
animationDuration?: number;
|
|
81
81
|
spinner?: boolean;
|
|
82
|
-
|
|
82
|
+
defaultPreserveScroll?: boolean;
|
|
83
83
|
defaultRetry?: Retry;
|
|
84
|
+
defaultStaleTime?: number;
|
|
84
85
|
defaultLoaderFallback?: RenderElement;
|
|
85
86
|
defaultErrorElement?: RenderElement;
|
|
86
87
|
showFallbackOnAnimation?: boolean;
|
|
@@ -94,9 +95,8 @@ export type RouterProps = {
|
|
|
94
95
|
context?: Record<string, unknown>;
|
|
95
96
|
};
|
|
96
97
|
export type RouterState = {
|
|
97
|
-
isLoadingState: Store<boolean>;
|
|
98
|
-
loaderFallbackState: Store<RouteItem['loaderFallback']>;
|
|
99
98
|
routeItemDataState: Store<RouteItemData>;
|
|
99
|
+
pendingState: Store<RouteItemData | undefined>;
|
|
100
100
|
currentLoaderState: Store<LoaderState>;
|
|
101
101
|
scrollMapState: Store<Record<string, number>>;
|
|
102
102
|
contextState: Store<Record<string, unknown>>;
|
|
@@ -105,27 +105,23 @@ export type RouterState = {
|
|
|
105
105
|
to: string;
|
|
106
106
|
}>;
|
|
107
107
|
loaderStateRef: Cell<LoaderState>;
|
|
108
|
-
prevPathnameRef: Cell<string>;
|
|
109
|
-
pendingPathRef: Cell<string>;
|
|
110
108
|
timestampMap: Map<string, number>;
|
|
111
109
|
};
|
|
112
110
|
export type RouterType = {
|
|
113
|
-
state: Omit<RouterState, '
|
|
111
|
+
state: Omit<RouterState, 'timestampMap'>;
|
|
114
112
|
runtime: {
|
|
115
113
|
navigate(arg: Location): Promise<void>;
|
|
116
114
|
invalidate(pathList?: string | string[], options?: InvalidateOptions): Promise<InvalidateResult[]>;
|
|
117
115
|
prefetch(pathname: string): Promise<void>;
|
|
118
116
|
};
|
|
119
117
|
hooks: {
|
|
120
|
-
useIsLoading: () => ReturnType<typeof useGlobalState<boolean>>;
|
|
121
118
|
useBlockedRoute: () => ReturnType<typeof useGlobalState<{
|
|
122
119
|
from: string;
|
|
123
120
|
to: string;
|
|
124
121
|
}>>;
|
|
125
|
-
useLoaderFallback: () => ReturnType<typeof useGlobalState<RenderElement | undefined>>;
|
|
126
122
|
useRouteItemData: () => ReturnType<typeof useGlobalState<RouteItemData>>;
|
|
127
|
-
useCurrentLoaderState: () => ReturnType<typeof useGlobalState<LoaderState>>;
|
|
128
123
|
useScrollMap: () => ReturnType<typeof useGlobalState<Record<string, number>>>;
|
|
124
|
+
usePendingState: () => ReturnType<typeof useGlobalState<RouteItemData | undefined>>;
|
|
129
125
|
useContextState: () => ReturnType<typeof useGlobalState<Record<string, unknown>>>;
|
|
130
126
|
useParams: <T>() => T;
|
|
131
127
|
useNavigate: () => (arg: Location | string | -1) => Promise<void>;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { Location, RouteItem } from '../types';
|
|
3
|
-
export declare const createCommitNavigation: (navigationExecutor: (arg: Location, routeItem: RouteItem | undefined) => void,
|
|
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,2 +1,2 @@
|
|
|
1
1
|
import { Location, RouteItem, RouterState } from '../types';
|
|
2
|
-
export declare const createCommitState: ({
|
|
2
|
+
export declare const createCommitState: ({ routeItemDataState, pendingState }: RouterState) => (nextLocation: Location, routeItem: RouteItem | undefined) => void;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { RevalidateCacheArgs, RouterState } from '../types';
|
|
2
|
-
export declare const createRevalidateCache: (routerState: RouterState) => ({ routeItem, pathname }: RevalidateCacheArgs, retried?: number) => Promise<any>;
|
|
2
|
+
export declare const createRevalidateCache: (routerState: RouterState) => ({ routeItem, pathname, search }: RevalidateCacheArgs, retried?: number) => Promise<any>;
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const useLatest: <T>(value: T) => import("react").RefObject<T>;
|
package/dist/utils/adapter.d.ts
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import { Adapter } from '../types';
|
|
2
|
-
type ZodInterface<T> = {
|
|
3
|
-
safeParse(input: unknown): {
|
|
4
|
-
success: true;
|
|
5
|
-
data: T;
|
|
6
|
-
} | {
|
|
7
|
-
success: false;
|
|
8
|
-
error: unknown;
|
|
9
|
-
};
|
|
10
|
-
};
|
|
11
|
-
export declare const adapter: {
|
|
12
|
-
string: {
|
|
13
|
-
parse: (params: string[]) => string;
|
|
14
|
-
};
|
|
15
|
-
stringArray: {
|
|
16
|
-
parse: (params: string[]) => string[];
|
|
17
|
-
serialize: (value: string[]) => string[];
|
|
18
|
-
};
|
|
19
|
-
integer: {
|
|
20
|
-
parse: (params: string[]) => number;
|
|
21
|
-
};
|
|
22
|
-
integerArray: {
|
|
23
|
-
parse: (params: string[]) => number[];
|
|
24
|
-
serialize: (value: number[]) => string[];
|
|
25
|
-
};
|
|
26
|
-
float: {
|
|
27
|
-
parse: (params: string[]) => number;
|
|
28
|
-
};
|
|
29
|
-
floatArray: {
|
|
30
|
-
parse: (params: string[]) => number[];
|
|
31
|
-
serialize: (value: number[]) => string[];
|
|
32
|
-
};
|
|
33
|
-
boolean: {
|
|
34
|
-
parse: (params: string[]) => boolean;
|
|
35
|
-
serialize: StringConstructor;
|
|
36
|
-
};
|
|
37
|
-
booleanArray: {
|
|
38
|
-
parse: (params: string[]) => boolean[];
|
|
39
|
-
serialize: (value: boolean[]) => string[];
|
|
40
|
-
};
|
|
41
|
-
date: {
|
|
42
|
-
parse: (params: string[]) => Date;
|
|
43
|
-
serialize: (arg: Date) => string;
|
|
44
|
-
};
|
|
45
|
-
dateArray: {
|
|
46
|
-
parse: (params: string[]) => Date[];
|
|
47
|
-
serialize: (args: Date[]) => string[];
|
|
48
|
-
};
|
|
49
|
-
zodSchema: <T>(schema: ZodInterface<T>) => Adapter<T>;
|
|
50
|
-
};
|
|
51
|
-
export {};
|