clear-react-router 1.9.0 → 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 +0 -116
- package/dist/cell.d.ts +0 -3
- package/dist/config/routerConfig.d.ts +0 -1
- package/dist/index.d.ts +1 -3
- package/dist/index.js +39 -168
- package/dist/types.d.ts +3 -12
- package/dist/utils/commitNavigation.d.ts +3 -3
- package/dist/utils/commitState.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
|
@@ -645,122 +645,6 @@ useEffect(() => {
|
|
|
645
645
|
}, [state, process, reset]);
|
|
646
646
|
```
|
|
647
647
|
|
|
648
|
-
### `useQueryParam()`
|
|
649
|
-
|
|
650
|
-
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.
|
|
651
|
-
|
|
652
|
-
```tsx
|
|
653
|
-
import { useQueryParam, adapter } from 'clear-react-router';
|
|
654
|
-
|
|
655
|
-
const ProductPage = () => {
|
|
656
|
-
// String parameter
|
|
657
|
-
const [brand, setBrand] = useQueryParam('brand', adapter.string, 'nike');
|
|
658
|
-
|
|
659
|
-
// Number parameter
|
|
660
|
-
const [page, setPage] = useQueryParam('page', adapter.integer, 1);
|
|
661
|
-
|
|
662
|
-
// Date parameter
|
|
663
|
-
const [date, setDate] = useQueryParam('date', adapter.date, new Date());
|
|
664
|
-
|
|
665
|
-
// Array of numbers
|
|
666
|
-
const [prices, setPrices] = useQueryParam('prices', adapter.floatArray);
|
|
667
|
-
|
|
668
|
-
return (
|
|
669
|
-
<div>
|
|
670
|
-
<p>Brand: {brand}</p>
|
|
671
|
-
<p>Page: {page}</p>
|
|
672
|
-
<button onClick={() => setPage(page + 1)}>Next</button>
|
|
673
|
-
</div>
|
|
674
|
-
);
|
|
675
|
-
}
|
|
676
|
-
```
|
|
677
|
-
type Adapter<T> = {
|
|
678
|
-
parse: (params: string[]) => T;
|
|
679
|
-
serialize?: (params: T) => string | string[];
|
|
680
|
-
}
|
|
681
|
-
|
|
682
|
-
**Signature:** `useQueryParam<T>(field: string, adapter: Adapter<T>, defaultValue?: T): [T, (arg: T | null) => void]`
|
|
683
|
-
|
|
684
|
-
| Argument | Type | Description |
|
|
685
|
-
|----------|------|-------------|
|
|
686
|
-
| `field` | `string` | The query parameter key (e.g., `'page'`, `'brand'`) |
|
|
687
|
-
| `adapter` | `Adapter<T>` | Parser and optional serializer for params (serializer String is used in case of serializer not passed) |
|
|
688
|
-
| `defaultValue` | `T` (optional) | Default value returned when the parameter is missing or empty |
|
|
689
|
-
|
|
690
|
-
**Returns:**
|
|
691
|
-
|
|
692
|
-
| Element | Type | Description |
|
|
693
|
-
|---------|------|-------------|
|
|
694
|
-
| `value` | `T` | The parsed value from the query parameter |
|
|
695
|
-
| `setValue` | `(arg: T \| null) => void` | Function to update the query parameter. Null is passed to remove the parameter. |
|
|
696
|
-
|
|
697
|
-
### Built-in Adapters
|
|
698
|
-
|
|
699
|
-
| Adapter | Input | Output | Description |
|
|
700
|
-
|---------|-------|--------|-------------|
|
|
701
|
-
| `adapter.string` | `string[]` | `string` | First value or empty string |
|
|
702
|
-
| `adapter.stringArray` | `string[]` | `string[]` | All values as array |
|
|
703
|
-
| `adapter.integer` | `string[]` | `number` | First value parsed as integer (default: `0`) |
|
|
704
|
-
| `adapter.integerArray` | `string[]` | `number[]` | All values parsed as integers |
|
|
705
|
-
| `adapter.float` | `string[]` | `number` | First value parsed as float (default: `0`) |
|
|
706
|
-
| `adapter.floatArray` | `string[]` | `number[]` | All values parsed as floats |
|
|
707
|
-
| `adapter.boolean` | `string[]` | `boolean` | First value parsed as boolean (`'true'` → `true`) |
|
|
708
|
-
| `adapter.booleanArray` | `string[]` | `boolean[]` | All values parsed as booleans |
|
|
709
|
-
| `adapter.date` | `string[]` | `Date` | First value parsed as Date from timestamp |
|
|
710
|
-
| `adapter.dateArray` | `string[]` | `Date[]` | All values parsed as Dates from timestamps |
|
|
711
|
-
| `adapter.zodSchema` | `string[]` | `T` | Validates JSON string against Zod schema |
|
|
712
|
-
|
|
713
|
-
### Using Zod Schemas
|
|
714
|
-
`useQueryParam` works seamlessly with Zod for complex validation:
|
|
715
|
-
|
|
716
|
-
```tsx
|
|
717
|
-
import { z } from 'zod';
|
|
718
|
-
import { useQueryParam, adapter } from 'clear-react-router';
|
|
719
|
-
|
|
720
|
-
const filterSchema = z.object({
|
|
721
|
-
name: z.string(),
|
|
722
|
-
age: z.number().min(0),
|
|
723
|
-
active: z.boolean().optional(),
|
|
724
|
-
});
|
|
725
|
-
|
|
726
|
-
function ProductFilter() {
|
|
727
|
-
const [filter, setFilter] = useQueryParam(
|
|
728
|
-
'filter',
|
|
729
|
-
adapter.zodSchema(filterSchema),
|
|
730
|
-
{ name: '', age: 0 }
|
|
731
|
-
);
|
|
732
|
-
|
|
733
|
-
return (
|
|
734
|
-
<div>
|
|
735
|
-
<p>Name: {filter.name}</p>
|
|
736
|
-
<p>Age: {filter.age}</p>
|
|
737
|
-
<button onClick={() => setFilter({ ...filter, age: filter.age + 1 })}>
|
|
738
|
-
Increment Age
|
|
739
|
-
</button>
|
|
740
|
-
</div>
|
|
741
|
-
);
|
|
742
|
-
}
|
|
743
|
-
```
|
|
744
|
-
|
|
745
|
-
### Custom Adapters
|
|
746
|
-
You can write your own adapter for any format:
|
|
747
|
-
|
|
748
|
-
```tsx
|
|
749
|
-
// Custom adapter for comma-separated values
|
|
750
|
-
const csvAdapter = {
|
|
751
|
-
parse: (params: string[]): string[] => {
|
|
752
|
-
const value = params[0] || '';
|
|
753
|
-
return value ? value.split(',').map(v => v.trim()) : [];
|
|
754
|
-
},
|
|
755
|
-
serialize: (value: string[]): string[] => value
|
|
756
|
-
}
|
|
757
|
-
|
|
758
|
-
const TagsFilter() {
|
|
759
|
-
const [tags, setTags] = useQueryParam('tags', csvAdapter, []);
|
|
760
|
-
// tags: string[]
|
|
761
|
-
}
|
|
762
|
-
```
|
|
763
|
-
|
|
764
648
|
### `useRouterContext()`
|
|
765
649
|
|
|
766
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>;
|
|
@@ -3,7 +3,6 @@ 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'];
|
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
|
@@ -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,7 +88,6 @@ 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);
|
|
@@ -106,12 +102,9 @@ var RouterConfig = class {
|
|
|
106
102
|
var routerConfig = new RouterConfig();
|
|
107
103
|
//#endregion
|
|
108
104
|
//#region utils/commitNavigation.ts
|
|
109
|
-
var createCommitNavigation = (navigationExecutor,
|
|
110
|
-
const
|
|
111
|
-
if (!isAnimated ||
|
|
112
|
-
navigationExecutor(nextLocation, routeItem);
|
|
113
|
-
return;
|
|
114
|
-
}
|
|
105
|
+
var createCommitNavigation = (navigationExecutor, routeItemDataState) => (nextLocation, routeItem) => {
|
|
106
|
+
const isFirstLoad = !routeItemDataState.getState().location.pathname;
|
|
107
|
+
if (!routerConfig.isAnimated || isFirstLoad) return navigationExecutor(nextLocation, routeItem);
|
|
115
108
|
try {
|
|
116
109
|
document.startViewTransition(() => navigationExecutor(nextLocation, routeItem));
|
|
117
110
|
} catch {
|
|
@@ -223,8 +216,8 @@ var findRoute = (pathname, includeAll) => {
|
|
|
223
216
|
var navigationSeq = 0;
|
|
224
217
|
var interval = 0;
|
|
225
218
|
var createNavigate = (routerState, revalidateCache) => {
|
|
226
|
-
const { loaderStateRef, scrollMapState,
|
|
227
|
-
const commitNavigation = createCommitNavigation(createCommitState(routerState),
|
|
219
|
+
const { loaderStateRef, scrollMapState, pendingState, contextState, timestampMap, routeItemDataState } = routerState;
|
|
220
|
+
const commitNavigation = createCommitNavigation(createCommitState(routerState), routeItemDataState);
|
|
228
221
|
const isCacheItemFresh = createIsCacheItemFresh(timestampMap);
|
|
229
222
|
const getContext = () => ({
|
|
230
223
|
context: contextState.getState(),
|
|
@@ -263,27 +256,25 @@ var createNavigate = (routerState, revalidateCache) => {
|
|
|
263
256
|
if (routeItem?.beforeLoad) await runBeforeLoad(routeItem?.beforeLoad);
|
|
264
257
|
};
|
|
265
258
|
const prepareNavigation = (routeItem, location) => {
|
|
266
|
-
const { isAnimated, showFallbackOnAnimation: showFallback } = routerConfig;
|
|
267
259
|
scrollMapState.setState((prevState) => {
|
|
268
260
|
const scrollPosition = document.scrollingElement?.scrollTop ?? 0;
|
|
269
|
-
|
|
261
|
+
const prevPathname = routeItemDataState.getState().location.pathname;
|
|
262
|
+
if (!scrollPosition || prevState[prevPathname] === scrollPosition) return prevState;
|
|
270
263
|
return {
|
|
271
264
|
...prevState,
|
|
272
|
-
[
|
|
265
|
+
[prevPathname]: scrollPosition
|
|
273
266
|
};
|
|
274
267
|
});
|
|
275
|
-
|
|
268
|
+
const pendingShouldExist = routeItem?.loader && !isCacheItemFresh({
|
|
276
269
|
routeItem,
|
|
277
270
|
pathname: location.pathname
|
|
278
|
-
})
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
pendingPathRef.set(location.pathname);
|
|
271
|
+
});
|
|
272
|
+
pendingState.setState(pendingShouldExist ? {
|
|
273
|
+
routeItem,
|
|
274
|
+
location
|
|
275
|
+
} : void 0);
|
|
284
276
|
};
|
|
285
277
|
const afterEachLoad = (routeItem) => {
|
|
286
|
-
pendingPathRef.set("");
|
|
287
278
|
if (!routeItem?.pollingInterval) return;
|
|
288
279
|
interval = window.setInterval(() => revalidateCache({
|
|
289
280
|
routeItem,
|
|
@@ -292,7 +283,7 @@ var createNavigate = (routerState, revalidateCache) => {
|
|
|
292
283
|
};
|
|
293
284
|
const loader = async (routeItem, location) => {
|
|
294
285
|
if (!routeItem?.loader) return;
|
|
295
|
-
|
|
286
|
+
window.clearInterval(interval);
|
|
296
287
|
await revalidateCache({
|
|
297
288
|
routeItem,
|
|
298
289
|
pathname: location.pathname,
|
|
@@ -498,18 +489,15 @@ var Cell = class {
|
|
|
498
489
|
this._value = typeof action === "function" ? action(this._value) : action;
|
|
499
490
|
}
|
|
500
491
|
};
|
|
501
|
-
new Cell(emptyLoaderState);
|
|
502
|
-
new Cell("");
|
|
503
492
|
//#endregion
|
|
504
493
|
//#region utils/createRouterInstance.ts
|
|
505
494
|
var createRouterInstance = () => {
|
|
506
495
|
const routerState = {
|
|
507
|
-
isLoadingState: create(false),
|
|
508
|
-
loaderFallbackState: create(void 0),
|
|
509
496
|
routeItemDataState: create({
|
|
510
497
|
routeItem: void 0,
|
|
511
498
|
location: {}
|
|
512
499
|
}),
|
|
500
|
+
pendingState: create(void 0),
|
|
513
501
|
currentLoaderState: create(emptyLoaderState),
|
|
514
502
|
scrollMapState: create({}),
|
|
515
503
|
contextState: create({}),
|
|
@@ -518,8 +506,6 @@ var createRouterInstance = () => {
|
|
|
518
506
|
to: ""
|
|
519
507
|
}),
|
|
520
508
|
loaderStateRef: new Cell(emptyLoaderState),
|
|
521
|
-
prevPathnameRef: new Cell(""),
|
|
522
|
-
pendingPathRef: new Cell(""),
|
|
523
509
|
timestampMap: /* @__PURE__ */ new Map()
|
|
524
510
|
};
|
|
525
511
|
const revalidateCache = createRevalidateCache(routerState);
|
|
@@ -546,29 +532,17 @@ var createRouterInstance = () => {
|
|
|
546
532
|
};
|
|
547
533
|
};
|
|
548
534
|
return {
|
|
549
|
-
state:
|
|
550
|
-
isLoadingState: routerState.isLoadingState,
|
|
551
|
-
loaderFallbackState: routerState.loaderFallbackState,
|
|
552
|
-
routeItemDataState: routerState.routeItemDataState,
|
|
553
|
-
currentLoaderState: routerState.currentLoaderState,
|
|
554
|
-
scrollMapState: routerState.scrollMapState,
|
|
555
|
-
contextState: routerState.contextState,
|
|
556
|
-
blockedRouteState: routerState.blockedRouteState,
|
|
557
|
-
prevPathnameRef: routerState.prevPathnameRef,
|
|
558
|
-
pendingPathRef: routerState.pendingPathRef
|
|
559
|
-
},
|
|
535
|
+
state: routerState,
|
|
560
536
|
runtime: {
|
|
561
537
|
navigate,
|
|
562
538
|
invalidate,
|
|
563
539
|
prefetch
|
|
564
540
|
},
|
|
565
541
|
hooks: {
|
|
566
|
-
useIsLoading: () => useGlobalState(routerState.isLoadingState),
|
|
567
542
|
useBlockedRoute: () => useGlobalState(routerState.blockedRouteState),
|
|
568
|
-
useLoaderFallback: () => useGlobalState(routerState.loaderFallbackState),
|
|
569
543
|
useRouteItemData: () => useGlobalState(routerState.routeItemDataState),
|
|
570
|
-
useCurrentLoaderState: () => useGlobalState(routerState.currentLoaderState),
|
|
571
544
|
useScrollMap: () => useGlobalState(routerState.scrollMapState),
|
|
545
|
+
usePendingState: () => useGlobalState(routerState.pendingState),
|
|
572
546
|
useContextState: () => useGlobalState(routerState.contextState),
|
|
573
547
|
useParams: () => getParamsObject(),
|
|
574
548
|
useNavigate: () => {
|
|
@@ -621,16 +595,16 @@ var router = createRouterInstance();
|
|
|
621
595
|
//#endregion
|
|
622
596
|
//#region hooks/useNavigation.ts
|
|
623
597
|
var useNavigation = () => {
|
|
624
|
-
const { state: {
|
|
598
|
+
const { state: { routeItemDataState, blockedRouteState }, runtime: { navigate } } = router;
|
|
625
599
|
useEffect(() => {
|
|
626
600
|
const handler = async (event) => {
|
|
627
601
|
const newLocation = parseWindowLocation(event.target.location);
|
|
628
|
-
if (
|
|
602
|
+
if (routeItemDataState.getState().location.pathname === blockedRouteState.getState().from) {
|
|
629
603
|
blockedRouteState.setState({
|
|
630
|
-
from:
|
|
604
|
+
from: routeItemDataState.getState().location.pathname,
|
|
631
605
|
to: newLocation.pathname
|
|
632
606
|
});
|
|
633
|
-
history.pushState(null, "",
|
|
607
|
+
history.pushState(null, "", routeItemDataState.getState().location.pathname);
|
|
634
608
|
} else navigate(newLocation);
|
|
635
609
|
};
|
|
636
610
|
window.addEventListener("popstate", handler);
|
|
@@ -638,13 +612,11 @@ var useNavigation = () => {
|
|
|
638
612
|
}, [
|
|
639
613
|
blockedRouteState,
|
|
640
614
|
navigate,
|
|
641
|
-
|
|
615
|
+
routeItemDataState
|
|
642
616
|
]);
|
|
643
617
|
useEffect(() => {
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
prevPathnameRef.set(currentLocation.pathname);
|
|
647
|
-
}, [navigate, prevPathnameRef]);
|
|
618
|
+
navigate(parseWindowLocation(window.location));
|
|
619
|
+
}, [navigate]);
|
|
648
620
|
};
|
|
649
621
|
//#endregion
|
|
650
622
|
//#region hooks/useApplyCustomAnimation.ts
|
|
@@ -722,18 +694,17 @@ var renderElement = (Component) => {
|
|
|
722
694
|
//#region components/Router.tsx
|
|
723
695
|
var EmptyBoundary = ({ children }) => children;
|
|
724
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 }) => {
|
|
725
|
-
const {
|
|
726
|
-
const [isLoading] = useIsLoading();
|
|
727
|
-
const [currentLoaderFallback] = useLoaderFallback();
|
|
697
|
+
const { useRouteItemData, usePendingState } = router.hooks;
|
|
728
698
|
const [routeItemData] = useRouteItemData();
|
|
729
|
-
const [
|
|
699
|
+
const [pendingState] = usePendingState();
|
|
700
|
+
const loaderState = router.state.loaderStateRef.value;
|
|
701
|
+
const isLoading = Boolean(pendingState);
|
|
730
702
|
useNavigation();
|
|
731
703
|
useSetRouterConfig({
|
|
732
704
|
routes,
|
|
733
705
|
isAnimated,
|
|
734
706
|
prefetch,
|
|
735
707
|
hoverPrefetchDelay,
|
|
736
|
-
showFallbackOnAnimation,
|
|
737
708
|
beforeLoad,
|
|
738
709
|
afterLoad,
|
|
739
710
|
defaultRetry,
|
|
@@ -747,7 +718,7 @@ var Router = ({ routes, beforeLoad, afterLoad, animationDuration, isAnimated = f
|
|
|
747
718
|
const showErrorElement = !isLoading && Boolean(loaderState.loaderError || loaderState.beforeLoadError);
|
|
748
719
|
const showSpinner = spinner && isAnimated && isLoading;
|
|
749
720
|
const loadingContent = !showErrorElement && isLoading;
|
|
750
|
-
if ((showFallbackOnAnimation || !isAnimated) && loadingContent) return renderElement(
|
|
721
|
+
if ((showFallbackOnAnimation || !isAnimated) && loadingContent) return renderElement(pendingState?.routeItem?.loaderFallback || defaultLoaderFallback);
|
|
751
722
|
if (!showFallbackOnAnimation && isAnimated && loadingContent) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Spinner, {});
|
|
752
723
|
if (!routeItem) return null;
|
|
753
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, {})] });
|
|
@@ -759,9 +730,9 @@ var Router = ({ routes, beforeLoad, afterLoad, animationDuration, isAnimated = f
|
|
|
759
730
|
//#endregion
|
|
760
731
|
//#region hooks/useIsRoutePending.ts
|
|
761
732
|
var useIsRoutePending = (routePath) => {
|
|
762
|
-
const {
|
|
763
|
-
const [
|
|
764
|
-
return
|
|
733
|
+
const { usePendingState } = router.hooks;
|
|
734
|
+
const [pendingState] = usePendingState();
|
|
735
|
+
return pendingState?.location.pathname === routePath;
|
|
765
736
|
};
|
|
766
737
|
//#endregion
|
|
767
738
|
//#region hooks/useNavigate.ts
|
|
@@ -888,10 +859,7 @@ var Form = ({ children, action, onSuccess, onError, autoReset = true }) => {
|
|
|
888
859
|
var useParams = router.hooks.useParams;
|
|
889
860
|
//#endregion
|
|
890
861
|
//#region hooks/useLoaderState.ts
|
|
891
|
-
var useLoaderState = () =>
|
|
892
|
-
const [loaderState] = router.hooks.useCurrentLoaderState();
|
|
893
|
-
return loaderState;
|
|
894
|
-
};
|
|
862
|
+
var useLoaderState = () => router.state.loaderStateRef.value;
|
|
895
863
|
//#endregion
|
|
896
864
|
//#region hooks/useInvalidate.ts
|
|
897
865
|
var useInvalidate = () => router.runtime.invalidate;
|
|
@@ -981,19 +949,9 @@ var useSearch = () => {
|
|
|
981
949
|
return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
982
950
|
};
|
|
983
951
|
//#endregion
|
|
984
|
-
//#region hooks/useLatest.ts
|
|
985
|
-
var useLatest = (value) => {
|
|
986
|
-
const ref = useRef(value);
|
|
987
|
-
useEffect(() => {
|
|
988
|
-
ref.current = value;
|
|
989
|
-
}, [value]);
|
|
990
|
-
return ref;
|
|
991
|
-
};
|
|
992
|
-
//#endregion
|
|
993
952
|
//#region hooks/useSearchParams.ts
|
|
994
953
|
var useSearchParams = () => {
|
|
995
954
|
const search = useSearch();
|
|
996
|
-
const searchRef = useLatest(search);
|
|
997
955
|
const searchString = search ? search.replace("?", "") : window.location.pathname.split("?")?.[1] ?? "";
|
|
998
956
|
const searchParams = useMemo(() => new URLSearchParams(searchString), [searchString]);
|
|
999
957
|
const getSearchParams = useCallback((param) => {
|
|
@@ -1010,105 +968,18 @@ var useSearchParams = () => {
|
|
|
1010
968
|
searchParams,
|
|
1011
969
|
getSearchParams,
|
|
1012
970
|
setSearchParams: useCallback((param, value) => {
|
|
1013
|
-
const currentParams = new URLSearchParams(
|
|
971
|
+
const currentParams = new URLSearchParams(search);
|
|
1014
972
|
if (typeof param === "string" && value !== void 0) {
|
|
1015
973
|
currentParams.delete(param);
|
|
1016
974
|
(Array.isArray(value) ? value : [value]).forEach((v) => currentParams.append(param, v));
|
|
1017
975
|
navigateWithSearchParams(currentParams);
|
|
1018
976
|
} else if (typeof param === "function") navigateWithSearchParams(param(currentParams));
|
|
1019
977
|
else throw new Error("useSearchParams first argument must be either function or string");
|
|
1020
|
-
}, [navigateWithSearchParams,
|
|
978
|
+
}, [navigateWithSearchParams, search])
|
|
1021
979
|
};
|
|
1022
980
|
};
|
|
1023
981
|
//#endregion
|
|
1024
|
-
//#region hooks/useQueryParam.ts
|
|
1025
|
-
function useQueryParam(field, adapter, defaultValue) {
|
|
1026
|
-
const { searchParams, setSearchParams } = useSearchParams();
|
|
1027
|
-
return [useMemo(() => {
|
|
1028
|
-
const params = searchParams.getAll(field);
|
|
1029
|
-
const result = adapter.parse(params);
|
|
1030
|
-
const isValid = !(result instanceof Date) || result instanceof Date && !isNaN(result.getTime());
|
|
1031
|
-
if (result !== void 0 && result !== null && result !== "" && isValid) return result;
|
|
1032
|
-
if (defaultValue !== void 0) return defaultValue;
|
|
1033
|
-
return result;
|
|
1034
|
-
}, [
|
|
1035
|
-
field,
|
|
1036
|
-
adapter,
|
|
1037
|
-
searchParams,
|
|
1038
|
-
defaultValue
|
|
1039
|
-
]), useCallback((value) => {
|
|
1040
|
-
if (!value) return setSearchParams(field, []);
|
|
1041
|
-
setSearchParams(field, (adapter.serialize || String)(value));
|
|
1042
|
-
}, [
|
|
1043
|
-
field,
|
|
1044
|
-
adapter.serialize,
|
|
1045
|
-
setSearchParams
|
|
1046
|
-
])];
|
|
1047
|
-
}
|
|
1048
|
-
//#endregion
|
|
1049
982
|
//#region hooks/useFormContext.ts
|
|
1050
983
|
var useFormContext = () => useContext(FormContext);
|
|
1051
984
|
//#endregion
|
|
1052
|
-
|
|
1053
|
-
var adapter = {
|
|
1054
|
-
string: { parse: (params) => params[0] || "" },
|
|
1055
|
-
stringArray: {
|
|
1056
|
-
parse: (params) => params,
|
|
1057
|
-
serialize: (value) => value
|
|
1058
|
-
},
|
|
1059
|
-
integer: { parse: (params) => {
|
|
1060
|
-
const result = parseInt(params[0] || "");
|
|
1061
|
-
return isNaN(result) ? 0 : result;
|
|
1062
|
-
} },
|
|
1063
|
-
integerArray: {
|
|
1064
|
-
parse: (params) => params.map((el) => {
|
|
1065
|
-
const result = parseInt(el);
|
|
1066
|
-
return isNaN(result) ? 0 : result;
|
|
1067
|
-
}),
|
|
1068
|
-
serialize: (value) => value.map(String)
|
|
1069
|
-
},
|
|
1070
|
-
float: { parse: (params) => {
|
|
1071
|
-
const result = parseFloat(params[0] || "");
|
|
1072
|
-
return isNaN(result) ? 0 : result;
|
|
1073
|
-
} },
|
|
1074
|
-
floatArray: {
|
|
1075
|
-
parse: (params) => params.map((el) => {
|
|
1076
|
-
const result = parseFloat(el);
|
|
1077
|
-
return isNaN(result) ? 0 : result;
|
|
1078
|
-
}),
|
|
1079
|
-
serialize: (value) => value.map(String)
|
|
1080
|
-
},
|
|
1081
|
-
boolean: {
|
|
1082
|
-
parse: (params) => params[0]?.toLowerCase() === "true",
|
|
1083
|
-
serialize: String
|
|
1084
|
-
},
|
|
1085
|
-
booleanArray: {
|
|
1086
|
-
parse: (params) => params.map((el) => el.toLowerCase() === "true"),
|
|
1087
|
-
serialize: (value) => value.map(String)
|
|
1088
|
-
},
|
|
1089
|
-
date: {
|
|
1090
|
-
parse: (params) => new Date(Number(params[0])),
|
|
1091
|
-
serialize: (arg) => String(arg.getTime())
|
|
1092
|
-
},
|
|
1093
|
-
dateArray: {
|
|
1094
|
-
parse: (params) => params.map((param) => new Date(Number(param))),
|
|
1095
|
-
serialize: (args) => args.map((arg) => String(arg.getTime()))
|
|
1096
|
-
},
|
|
1097
|
-
zodSchema: (schema) => ({
|
|
1098
|
-
parse: (params) => {
|
|
1099
|
-
let parsed;
|
|
1100
|
-
try {
|
|
1101
|
-
parsed = params[0] ? JSON.parse(params[0]) : void 0;
|
|
1102
|
-
} catch {
|
|
1103
|
-
throw new Error("Invalid JSON");
|
|
1104
|
-
}
|
|
1105
|
-
if (parsed === void 0) return void 0;
|
|
1106
|
-
const result = schema.safeParse(parsed);
|
|
1107
|
-
if (!result.success) throw new Error("Invalid schema");
|
|
1108
|
-
return result.data;
|
|
1109
|
-
},
|
|
1110
|
-
serialize: JSON.stringify
|
|
1111
|
-
})
|
|
1112
|
-
};
|
|
1113
|
-
//#endregion
|
|
1114
|
-
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
|
@@ -65,10 +65,6 @@ export type LoaderState<T = unknown> = {
|
|
|
65
65
|
loaderError: Error | null;
|
|
66
66
|
beforeLoadError: Error | null;
|
|
67
67
|
};
|
|
68
|
-
export type Adapter<T> = {
|
|
69
|
-
parse: (params: string[]) => T;
|
|
70
|
-
serialize?: (params: T) => string | string[];
|
|
71
|
-
};
|
|
72
68
|
export type RouteItemData = {
|
|
73
69
|
location: Location;
|
|
74
70
|
routeItem: RouteItem | undefined;
|
|
@@ -99,9 +95,8 @@ export type RouterProps = {
|
|
|
99
95
|
context?: Record<string, unknown>;
|
|
100
96
|
};
|
|
101
97
|
export type RouterState = {
|
|
102
|
-
isLoadingState: Store<boolean>;
|
|
103
|
-
loaderFallbackState: Store<RouteItem['loaderFallback']>;
|
|
104
98
|
routeItemDataState: Store<RouteItemData>;
|
|
99
|
+
pendingState: Store<RouteItemData | undefined>;
|
|
105
100
|
currentLoaderState: Store<LoaderState>;
|
|
106
101
|
scrollMapState: Store<Record<string, number>>;
|
|
107
102
|
contextState: Store<Record<string, unknown>>;
|
|
@@ -110,27 +105,23 @@ export type RouterState = {
|
|
|
110
105
|
to: string;
|
|
111
106
|
}>;
|
|
112
107
|
loaderStateRef: Cell<LoaderState>;
|
|
113
|
-
prevPathnameRef: Cell<string>;
|
|
114
|
-
pendingPathRef: Cell<string>;
|
|
115
108
|
timestampMap: Map<string, number>;
|
|
116
109
|
};
|
|
117
110
|
export type RouterType = {
|
|
118
|
-
state: Omit<RouterState, '
|
|
111
|
+
state: Omit<RouterState, 'timestampMap'>;
|
|
119
112
|
runtime: {
|
|
120
113
|
navigate(arg: Location): Promise<void>;
|
|
121
114
|
invalidate(pathList?: string | string[], options?: InvalidateOptions): Promise<InvalidateResult[]>;
|
|
122
115
|
prefetch(pathname: string): Promise<void>;
|
|
123
116
|
};
|
|
124
117
|
hooks: {
|
|
125
|
-
useIsLoading: () => ReturnType<typeof useGlobalState<boolean>>;
|
|
126
118
|
useBlockedRoute: () => ReturnType<typeof useGlobalState<{
|
|
127
119
|
from: string;
|
|
128
120
|
to: string;
|
|
129
121
|
}>>;
|
|
130
|
-
useLoaderFallback: () => ReturnType<typeof useGlobalState<RenderElement | undefined>>;
|
|
131
122
|
useRouteItemData: () => ReturnType<typeof useGlobalState<RouteItemData>>;
|
|
132
|
-
useCurrentLoaderState: () => ReturnType<typeof useGlobalState<LoaderState>>;
|
|
133
123
|
useScrollMap: () => ReturnType<typeof useGlobalState<Record<string, number>>>;
|
|
124
|
+
usePendingState: () => ReturnType<typeof useGlobalState<RouteItemData | undefined>>;
|
|
134
125
|
useContextState: () => ReturnType<typeof useGlobalState<Record<string, unknown>>>;
|
|
135
126
|
useParams: <T>() => T;
|
|
136
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;
|
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 {};
|