clear-react-router 1.7.0 → 1.7.2
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 +23 -54
- package/dist/components/Form.d.ts +1 -1
- package/dist/components/Router.d.ts +1 -1
- package/dist/config/routerConfig.d.ts +0 -2
- package/dist/hooks/useGetAction.d.ts +4 -0
- package/dist/hooks/useNavigation.d.ts +3 -1
- package/dist/hooks/useRuntime.d.ts +5 -0
- package/dist/hooks/useSetRouterConfig.d.ts +1 -1
- package/dist/hooks/useSetRuntime.d.ts +7 -0
- package/dist/index.d.ts +0 -1
- package/dist/index.js +279 -289
- package/dist/state/state.d.ts +8 -1
- package/dist/types/global.d.ts +1 -0
- package/package.json +1 -1
- package/dist/components/RouterProvider.d.ts +0 -8
- package/dist/context/RouterProviderContext.d.ts +0 -7
- package/dist/hooks/useActionParams.d.ts +0 -7
- package/dist/hooks/useServiceContext.d.ts +0 -1
- package/dist/provider/Provider.d.ts +0 -7
package/README.md
CHANGED
|
@@ -1,17 +1,23 @@
|
|
|
1
1
|
[](https://www.npmjs.com/package/clear-react-router)
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
# Clear Router
|
|
4
|
+
|
|
5
|
+
A lightweight, type-safe routing library for React applications with nested routes, data loading, navigation blocking, prefetching, and route actions.
|
|
4
6
|
|
|
5
7
|
## Why Clear Router?
|
|
6
8
|
|
|
7
|
-
Most React routers focus on flexibility and ecosystem integrations.
|
|
8
|
-
|
|
9
|
+
Most React routers focus on flexibility and ecosystem integrations. Clear Router focuses on predictable navigation with a small, explicit API and minimal setup.
|
|
10
|
+
|
|
11
|
+
There is no `RouterProvider` or provider hierarchy to manage. Simply render `<Router />` once, and use router hooks anywhere in your application.
|
|
9
12
|
|
|
10
13
|
It provides first-class support for:
|
|
11
14
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
+
* Predictable routing
|
|
16
|
+
* Built-in data loading
|
|
17
|
+
* Route actions and forms
|
|
18
|
+
* Simple, provider-free architecture
|
|
19
|
+
* Small, explicit API
|
|
20
|
+
|
|
15
21
|
|
|
16
22
|
## Features
|
|
17
23
|
|
|
@@ -49,36 +55,11 @@ Normalizes route configuration. Handles wildcard `*` routes, extracts dynamic pa
|
|
|
49
55
|
| `staleTime` | `number` | Time in ms before cached data is considered stale and re-fetched in the background. If not provided, data never expires (cached forever) |
|
|
50
56
|
| `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 refresh loader data using the router-provided `invalidate`. |
|
|
51
57
|
|
|
52
|
-
|
|
53
|
-
### `RouterProvider`
|
|
54
|
-
|
|
55
|
-
The root component that provides routing context to the application. Place static UI elements (like navbar or footer) outside `<Router />` to prevent unnecessary re-renders.
|
|
56
|
-
|
|
57
|
-
| Prop | Type | Default | Description |
|
|
58
|
-
|------|------|---------|-------------|
|
|
59
|
-
| `routes` | `RouteItem[]` | required | Array of route configurations |
|
|
60
|
-
| `children` | `ReactNode` | required | App content (must include `<Router />`) |
|
|
61
|
-
|
|
62
|
-
```tsx
|
|
63
|
-
function App() {
|
|
64
|
-
return (
|
|
65
|
-
<RouterProvider routeList={routes}>
|
|
66
|
-
<Navbar /> {/* Static */}
|
|
67
|
-
<main>
|
|
68
|
-
<Router isAnimated animationDuration={800} /> {/* Dynamic — renders current page */}
|
|
69
|
-
</main>
|
|
70
|
-
<Footer /> {/* Static */}
|
|
71
|
-
</RouterProvider>
|
|
72
|
-
);
|
|
73
|
-
}
|
|
74
|
-
```
|
|
75
|
-
|
|
76
58
|
### `Router`
|
|
77
59
|
|
|
78
|
-
Renders the current route's component. Must be placed inside `<RouterProvider>`.
|
|
79
|
-
|
|
80
60
|
| Prop | Type | Default | Description |
|
|
81
61
|
|------|------|---------|-------------|
|
|
62
|
+
| `routes` | `RouteItem[]` | required | Array of route configurations |
|
|
82
63
|
| `isAnimated` | `boolean \| undefined` | `false` | Enable smooth page fade transitions |
|
|
83
64
|
| `animationDuration` | `number` | `optional` | Animation duration in milliseconds (browser default is used if not set) |
|
|
84
65
|
| `spinner` | `boolean \| undefined` | `true` | Show a small spinner in the corner while loading data (only when `isAnimated` is enabled) |
|
|
@@ -90,10 +71,10 @@ Renders the current route's component. Must be placed inside `<RouterProvider>`.
|
|
|
90
71
|
| `errorBoundary` | `ComponentType<{ children: ReactNode }>` | `undefined` | Custom error boundary component for catching render errors in route components |
|
|
91
72
|
|
|
92
73
|
```tsx
|
|
93
|
-
<
|
|
74
|
+
<div>
|
|
94
75
|
<Navbar />
|
|
95
|
-
<Router spinner={false} isAnimated /> {/* disable the spinner */}
|
|
96
|
-
</
|
|
76
|
+
<Router routes={routes} spinner={false} isAnimated /> {/* disable the spinner */}
|
|
77
|
+
</div>
|
|
97
78
|
```
|
|
98
79
|
|
|
99
80
|
> **Note:** When `isAnimated` is enabled, `loaderFallback` is not shown. Instead, a small spinner appears (if `spinner={true}`). On the initial page load, however, the route's loaderFallback is rendered if available.
|
|
@@ -121,12 +102,10 @@ Component for client-side navigation with prefetch support.
|
|
|
121
102
|
**Example:**
|
|
122
103
|
|
|
123
104
|
```tsx
|
|
124
|
-
import {
|
|
105
|
+
import { Router, Link } from 'clear-react-router';
|
|
125
106
|
|
|
126
107
|
// Global prefetch: hover with 100ms delay
|
|
127
|
-
<
|
|
128
|
-
<Router />
|
|
129
|
-
</RouterProvider>
|
|
108
|
+
<Router routes={routes} prefetch="hover" hoverPrefetchDelay={100} />
|
|
130
109
|
|
|
131
110
|
// Override for a specific link
|
|
132
111
|
<Link to="/heavy-page" prefetch="viewport">
|
|
@@ -264,12 +243,12 @@ Actions can be executed declaratively with `<Form />` or imperatively with `useA
|
|
|
264
243
|
|
|
265
244
|
## Form
|
|
266
245
|
|
|
267
|
-
`Form` automatically creates a `FormData` object, executes the specified route action, invalidates the current route, and optionally resets the form.
|
|
246
|
+
`Form` automatically creates a `FormData` object on submit event, executes the specified route action, invalidates the current route, and optionally resets the form, if fields are uncontrolled.
|
|
268
247
|
|
|
269
248
|
`isSubmitting` value available inside the `Form` component from the `useFormContext` hook
|
|
270
249
|
|
|
271
250
|
```tsx
|
|
272
|
-
import { Form, useFormContext } from '
|
|
251
|
+
import { Form, useFormContext } from 'clear-react-router';
|
|
273
252
|
|
|
274
253
|
const SubmitButton = () => {
|
|
275
254
|
const {isSubmitting} = useFormContext()
|
|
@@ -317,17 +296,11 @@ const save = useAction('save');
|
|
|
317
296
|
|
|
318
297
|
const handleClick = async () => {
|
|
319
298
|
const data = new FormData();
|
|
320
|
-
|
|
321
299
|
data.append('title', 'Hello');
|
|
322
|
-
|
|
323
300
|
await save(data);
|
|
324
301
|
};
|
|
325
|
-
```
|
|
326
302
|
|
|
327
|
-
|
|
328
|
-
<button onClick={handleClick}>
|
|
329
|
-
Save
|
|
330
|
-
</button>
|
|
303
|
+
<button onClick={handleClick}>Save</button>
|
|
331
304
|
```
|
|
332
305
|
|
|
333
306
|
`useAction` automatically invalidates the current route after a successful action, causing both `beforeLoad` and `loader` to run again in the background.
|
|
@@ -340,15 +313,11 @@ This hook is useful when the mutation is triggered programmatically, such as fro
|
|
|
340
313
|
You can provide a custom error boundary to catch rendering errors in route components. This is useful for preventing the entire app from crashing when a specific route fails to render.
|
|
341
314
|
|
|
342
315
|
```tsx
|
|
343
|
-
import {
|
|
316
|
+
import { Router } from 'clear-react-router';
|
|
344
317
|
import { routes } from './routes';
|
|
345
318
|
import { ErrorBoundary } from './components/ErrorBoundary';
|
|
346
319
|
|
|
347
|
-
const App = () =>
|
|
348
|
-
<RouterProvider routes={routes}>
|
|
349
|
-
<Router errorBoundary={ErrorBoundary} />
|
|
350
|
-
</RouterProvider>
|
|
351
|
-
);
|
|
320
|
+
const App = () => <Router routes={routes} errorBoundary={ErrorBoundary} />
|
|
352
321
|
```
|
|
353
322
|
**Note:** The `errorBoundary` prop only catches render-time errors in route components. It does not catch errors in `loader` or `beforeLoad` — those are handled by the router's `errorElement` mechanism.
|
|
354
323
|
|
|
@@ -5,5 +5,5 @@ type FormProps = {
|
|
|
5
5
|
onError?(arg: unknown): void;
|
|
6
6
|
autoReset?: boolean;
|
|
7
7
|
};
|
|
8
|
-
export declare const Form: ({ children, action
|
|
8
|
+
export declare const Form: ({ children, action, onSuccess, onError, autoReset }: PropsWithChildren<FormProps>) => import("react/jsx-runtime").JSX.Element;
|
|
9
9
|
export {};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { RouterProps } from '../types/global';
|
|
2
|
-
export declare const Router: ({
|
|
2
|
+
export declare const Router: ({ routes, animationDuration, isAnimated, spinner, preserveScroll, showFallbackOnAnimation, prefetch, hoverPrefetchDelay, errorBoundary: ErrorBoundary, context: initialContext, }: RouterProps) => import("react/jsx-runtime").JSX.Element | null;
|
|
@@ -8,6 +8,8 @@ type UseHandleNavigation = {
|
|
|
8
8
|
pathname: string;
|
|
9
9
|
}): boolean;
|
|
10
10
|
loaderStateRef: RefObject<LoaderState>;
|
|
11
|
+
isAnimated: boolean;
|
|
12
|
+
showFallbackOnAnimation: boolean;
|
|
11
13
|
};
|
|
12
|
-
export declare const useNavigation: ({ routes, revalidateCache, isCacheItemFresh, loaderStateRef }: UseHandleNavigation) => (nextLocation: Location) => Promise<void>;
|
|
14
|
+
export declare const useNavigation: ({ routes, revalidateCache, isCacheItemFresh, loaderStateRef, isAnimated, showFallbackOnAnimation: showFallback, }: UseHandleNavigation) => (nextLocation: Location) => Promise<void>;
|
|
13
15
|
export {};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { RouterProps } from '../types/global';
|
|
2
|
-
export declare const useSetRouterConfig: (routerProps: RouterProps) => void;
|
|
2
|
+
export declare const useSetRouterConfig: (routerProps: Omit<RouterProps, "routes">) => void;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
type UseSetRuntime = {
|
|
2
|
+
updateLocation(arg: Location): Promise<void>;
|
|
3
|
+
prefetchLoader(arg: string): Promise<void>;
|
|
4
|
+
invalidate(arg?: string): Promise<void>;
|
|
5
|
+
};
|
|
6
|
+
export declare const useSetRouterRuntime: ({ updateLocation, prefetchLoader, invalidate }: UseSetRuntime) => void;
|
|
7
|
+
export {};
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -2,67 +2,6 @@ import { Suspense, createContext, lazy, useCallback, useContext, useEffect, useM
|
|
|
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
|
|
5
|
-
//#region context/RouterProviderContext.ts
|
|
6
|
-
var ActionsContext = createContext({});
|
|
7
|
-
//#endregion
|
|
8
|
-
//#region ../../node_modules/react/cjs/react-jsx-runtime.production.js
|
|
9
|
-
/**
|
|
10
|
-
* @license React
|
|
11
|
-
* react-jsx-runtime.production.js
|
|
12
|
-
*
|
|
13
|
-
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
14
|
-
*
|
|
15
|
-
* This source code is licensed under the MIT license found in the
|
|
16
|
-
* LICENSE file in the root directory of this source tree.
|
|
17
|
-
*/
|
|
18
|
-
var require_react_jsx_runtime_production = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
19
|
-
var REACT_ELEMENT_TYPE = Symbol.for("react.transitional.element"), REACT_FRAGMENT_TYPE = Symbol.for("react.fragment");
|
|
20
|
-
function jsxProd(type, config, maybeKey) {
|
|
21
|
-
var key = null;
|
|
22
|
-
void 0 !== maybeKey && (key = "" + maybeKey);
|
|
23
|
-
void 0 !== config.key && (key = "" + config.key);
|
|
24
|
-
if ("key" in config) {
|
|
25
|
-
maybeKey = {};
|
|
26
|
-
for (var propName in config) "key" !== propName && (maybeKey[propName] = config[propName]);
|
|
27
|
-
} else maybeKey = config;
|
|
28
|
-
config = maybeKey.ref;
|
|
29
|
-
return {
|
|
30
|
-
$$typeof: REACT_ELEMENT_TYPE,
|
|
31
|
-
type,
|
|
32
|
-
key,
|
|
33
|
-
ref: void 0 !== config ? config : null,
|
|
34
|
-
props: maybeKey
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
exports.Fragment = REACT_FRAGMENT_TYPE;
|
|
38
|
-
exports.jsx = jsxProd;
|
|
39
|
-
exports.jsxs = jsxProd;
|
|
40
|
-
}));
|
|
41
|
-
//#endregion
|
|
42
|
-
//#region provider/Provider.tsx
|
|
43
|
-
var import_jsx_runtime = (/* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
44
|
-
module.exports = require_react_jsx_runtime_production();
|
|
45
|
-
})))();
|
|
46
|
-
var Provider = ({ children, updateLocation, prefetchLoader, invalidate }) => {
|
|
47
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ActionsContext.Provider, {
|
|
48
|
-
value: {
|
|
49
|
-
updateLocation,
|
|
50
|
-
prefetchLoader,
|
|
51
|
-
invalidate
|
|
52
|
-
},
|
|
53
|
-
children
|
|
54
|
-
});
|
|
55
|
-
};
|
|
56
|
-
//#endregion
|
|
57
|
-
//#region hooks/useLatest.ts
|
|
58
|
-
var useLatest = (value) => {
|
|
59
|
-
const ref = useRef(value);
|
|
60
|
-
useEffect(() => {
|
|
61
|
-
ref.current = value;
|
|
62
|
-
}, [value]);
|
|
63
|
-
return ref;
|
|
64
|
-
};
|
|
65
|
-
//#endregion
|
|
66
5
|
//#region state/createState.ts
|
|
67
6
|
var create = (initialState) => {
|
|
68
7
|
let state = initialState;
|
|
@@ -111,60 +50,55 @@ var useRouteItemData = createState({
|
|
|
111
50
|
var useCurrentLoaderState = createState(emptyLoaderState);
|
|
112
51
|
var useScrollMap = createState({});
|
|
113
52
|
var useContextState = createState({});
|
|
53
|
+
var useActionState = createState({});
|
|
114
54
|
//#endregion
|
|
115
|
-
//#region
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
}
|
|
124
|
-
//#endregion
|
|
125
|
-
//#region \0@oxc-project+runtime@0.133.0/helpers/esm/toPrimitive.js
|
|
126
|
-
function toPrimitive(t, r) {
|
|
127
|
-
if ("object" != _typeof(t) || !t) return t;
|
|
128
|
-
var e = t[Symbol.toPrimitive];
|
|
129
|
-
if (void 0 !== e) {
|
|
130
|
-
var i = e.call(t, r || "default");
|
|
131
|
-
if ("object" != _typeof(i)) return i;
|
|
132
|
-
throw new TypeError("@@toPrimitive must return a primitive value.");
|
|
133
|
-
}
|
|
134
|
-
return ("string" === r ? String : Number)(t);
|
|
135
|
-
}
|
|
136
|
-
//#endregion
|
|
137
|
-
//#region \0@oxc-project+runtime@0.133.0/helpers/esm/toPropertyKey.js
|
|
138
|
-
function toPropertyKey(t) {
|
|
139
|
-
var i = toPrimitive(t, "string");
|
|
140
|
-
return "symbol" == _typeof(i) ? i : i + "";
|
|
141
|
-
}
|
|
142
|
-
//#endregion
|
|
143
|
-
//#region \0@oxc-project+runtime@0.133.0/helpers/esm/defineProperty.js
|
|
144
|
-
function _defineProperty(e, r, t) {
|
|
145
|
-
return (r = toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
|
|
146
|
-
value: t,
|
|
147
|
-
enumerable: !0,
|
|
148
|
-
configurable: !0,
|
|
149
|
-
writable: !0
|
|
150
|
-
}) : e[r] = t, e;
|
|
151
|
-
}
|
|
55
|
+
//#region hooks/useLatest.ts
|
|
56
|
+
var useLatest = (value) => {
|
|
57
|
+
const ref = useRef(value);
|
|
58
|
+
useEffect(() => {
|
|
59
|
+
ref.current = value;
|
|
60
|
+
}, [value]);
|
|
61
|
+
return ref;
|
|
62
|
+
};
|
|
152
63
|
//#endregion
|
|
153
|
-
//#region
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
64
|
+
//#region ../../node_modules/react/cjs/react-jsx-runtime.production.js
|
|
65
|
+
/**
|
|
66
|
+
* @license React
|
|
67
|
+
* react-jsx-runtime.production.js
|
|
68
|
+
*
|
|
69
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
70
|
+
*
|
|
71
|
+
* This source code is licensed under the MIT license found in the
|
|
72
|
+
* LICENSE file in the root directory of this source tree.
|
|
73
|
+
*/
|
|
74
|
+
var require_react_jsx_runtime_production = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
75
|
+
var REACT_ELEMENT_TYPE = Symbol.for("react.transitional.element"), REACT_FRAGMENT_TYPE = Symbol.for("react.fragment");
|
|
76
|
+
function jsxProd(type, config, maybeKey) {
|
|
77
|
+
var key = null;
|
|
78
|
+
void 0 !== maybeKey && (key = "" + maybeKey);
|
|
79
|
+
void 0 !== config.key && (key = "" + config.key);
|
|
80
|
+
if ("key" in config) {
|
|
81
|
+
maybeKey = {};
|
|
82
|
+
for (var propName in config) "key" !== propName && (maybeKey[propName] = config[propName]);
|
|
83
|
+
} else maybeKey = config;
|
|
84
|
+
config = maybeKey.ref;
|
|
85
|
+
return {
|
|
86
|
+
$$typeof: REACT_ELEMENT_TYPE,
|
|
87
|
+
type,
|
|
88
|
+
key,
|
|
89
|
+
ref: void 0 !== config ? config : null,
|
|
90
|
+
props: maybeKey
|
|
91
|
+
};
|
|
163
92
|
}
|
|
164
|
-
|
|
165
|
-
|
|
93
|
+
exports.Fragment = REACT_FRAGMENT_TYPE;
|
|
94
|
+
exports.jsx = jsxProd;
|
|
95
|
+
exports.jsxs = jsxProd;
|
|
96
|
+
}));
|
|
166
97
|
//#endregion
|
|
167
98
|
//#region utils/createLazyComponent.tsx
|
|
99
|
+
var import_jsx_runtime = (/* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
100
|
+
module.exports = require_react_jsx_runtime_production();
|
|
101
|
+
})))();
|
|
168
102
|
var createLazyComponent = (importFn, fallback) => {
|
|
169
103
|
const LazyComp = lazy(() => importFn().then((module) => ({ default: module.default || module })));
|
|
170
104
|
return () => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Suspense, {
|
|
@@ -215,9 +149,125 @@ var comparePaths = (el, pathname) => {
|
|
|
215
149
|
return splitElementPath.every((item, index) => item === splitPathname[index + (index ? 1 : 0)]) && splitPathname.length === splitElementPath.length + paramsLength;
|
|
216
150
|
};
|
|
217
151
|
//#endregion
|
|
152
|
+
//#region hooks/useLoader.ts
|
|
153
|
+
var useLoader = (routes) => {
|
|
154
|
+
const [, setLoaderState] = useCurrentLoaderState();
|
|
155
|
+
const [routeItemData] = useRouteItemData();
|
|
156
|
+
const [context, setContext] = useContextState();
|
|
157
|
+
const loaderStateRef = useRef(emptyLoaderState);
|
|
158
|
+
const latestPathname = useLatest(routeItemData.location.pathname);
|
|
159
|
+
const timestampMapRef = useRef(/* @__PURE__ */ new Map());
|
|
160
|
+
const loaderMapRef = useRef({});
|
|
161
|
+
const loadingPromises = useRef(/* @__PURE__ */ new Map());
|
|
162
|
+
const isCacheItemFresh = useCallback(({ routeItem, pathname }) => {
|
|
163
|
+
if (!routeItem) return true;
|
|
164
|
+
const currentCacheTimestamp = timestampMapRef.current.get(pathname);
|
|
165
|
+
if (!currentCacheTimestamp) return false;
|
|
166
|
+
if (!routeItem.staleTime) return true;
|
|
167
|
+
return Date.now() - currentCacheTimestamp < routeItem.staleTime;
|
|
168
|
+
}, []);
|
|
169
|
+
const revalidateCache = useCallback(async ({ routeItem, pathname }) => {
|
|
170
|
+
if (!routeItem?.loader) return;
|
|
171
|
+
if (loadingPromises.current.has(pathname)) return loadingPromises.current.get(pathname);
|
|
172
|
+
if (isCacheItemFresh({
|
|
173
|
+
routeItem,
|
|
174
|
+
pathname
|
|
175
|
+
})) {
|
|
176
|
+
loaderStateRef.current = loaderMapRef.current[pathname];
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
const promise = (async () => {
|
|
180
|
+
if (!routeItem?.loader) return;
|
|
181
|
+
try {
|
|
182
|
+
const params = getParamsObject({
|
|
183
|
+
params: routeItem.params,
|
|
184
|
+
pathname
|
|
185
|
+
});
|
|
186
|
+
const result = await routeItem?.loader({
|
|
187
|
+
params,
|
|
188
|
+
context,
|
|
189
|
+
setContext
|
|
190
|
+
});
|
|
191
|
+
timestampMapRef.current.set(pathname, Date.now());
|
|
192
|
+
loaderStateRef.current = {
|
|
193
|
+
...loaderStateRef?.current,
|
|
194
|
+
data: result,
|
|
195
|
+
loaderError: null
|
|
196
|
+
};
|
|
197
|
+
loaderMapRef.current[pathname] = loaderStateRef.current;
|
|
198
|
+
} catch (error) {
|
|
199
|
+
loaderStateRef.current = {
|
|
200
|
+
...loaderStateRef?.current,
|
|
201
|
+
data: null,
|
|
202
|
+
loaderError: error
|
|
203
|
+
};
|
|
204
|
+
} finally {
|
|
205
|
+
loadingPromises.current.delete(pathname);
|
|
206
|
+
}
|
|
207
|
+
})();
|
|
208
|
+
loadingPromises.current.set(pathname, promise);
|
|
209
|
+
return promise;
|
|
210
|
+
}, [
|
|
211
|
+
context,
|
|
212
|
+
isCacheItemFresh,
|
|
213
|
+
setContext
|
|
214
|
+
]);
|
|
215
|
+
return {
|
|
216
|
+
prefetchLoader: useCallback(async (pathname) => {
|
|
217
|
+
const item = routes.find((el) => comparePaths(el, pathname));
|
|
218
|
+
if (item) await revalidateCache({
|
|
219
|
+
routeItem: item,
|
|
220
|
+
pathname
|
|
221
|
+
});
|
|
222
|
+
}, [revalidateCache, routes]),
|
|
223
|
+
revalidateCache,
|
|
224
|
+
isCacheItemFresh,
|
|
225
|
+
loaderStateRef,
|
|
226
|
+
invalidate: useCallback(async (pathname = latestPathname.current) => {
|
|
227
|
+
if (typeof pathname !== "string") return;
|
|
228
|
+
const routeItem = routes.find((el) => comparePaths(el, pathname));
|
|
229
|
+
const resultParams = getParamsObject({
|
|
230
|
+
params: routeItem?.params,
|
|
231
|
+
pathname
|
|
232
|
+
});
|
|
233
|
+
timestampMapRef.current.delete(pathname);
|
|
234
|
+
try {
|
|
235
|
+
if (routeItem?.beforeLoad) await routeItem.beforeLoad({
|
|
236
|
+
context,
|
|
237
|
+
redirect: () => Promise.resolve(),
|
|
238
|
+
params: resultParams,
|
|
239
|
+
setContext
|
|
240
|
+
});
|
|
241
|
+
loaderStateRef.current = {
|
|
242
|
+
...loaderStateRef.current,
|
|
243
|
+
beforeLoadError: null
|
|
244
|
+
};
|
|
245
|
+
} catch (error) {
|
|
246
|
+
loaderStateRef.current = {
|
|
247
|
+
...loaderStateRef.current,
|
|
248
|
+
beforeLoadError: error
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
await revalidateCache({
|
|
252
|
+
routeItem,
|
|
253
|
+
pathname
|
|
254
|
+
});
|
|
255
|
+
if (pathname === latestPathname.current) setLoaderState(loaderStateRef.current);
|
|
256
|
+
}, [
|
|
257
|
+
context,
|
|
258
|
+
loaderStateRef,
|
|
259
|
+
revalidateCache,
|
|
260
|
+
latestPathname,
|
|
261
|
+
routes,
|
|
262
|
+
setContext,
|
|
263
|
+
setLoaderState
|
|
264
|
+
])
|
|
265
|
+
};
|
|
266
|
+
};
|
|
267
|
+
//#endregion
|
|
218
268
|
//#region hooks/useNavigation.ts
|
|
219
269
|
var ALL_LOCATIONS = "*";
|
|
220
|
-
var useNavigation = ({ routes, revalidateCache, isCacheItemFresh, loaderStateRef }) => {
|
|
270
|
+
var useNavigation = ({ routes, revalidateCache, isCacheItemFresh, loaderStateRef, isAnimated, showFallbackOnAnimation: showFallback }) => {
|
|
221
271
|
const [, setIsLoading] = useIsLoading();
|
|
222
272
|
const [, setScrollMap] = useScrollMap();
|
|
223
273
|
const [, setRouteItemData] = useRouteItemData();
|
|
@@ -225,7 +275,6 @@ var useNavigation = ({ routes, revalidateCache, isCacheItemFresh, loaderStateRef
|
|
|
225
275
|
const [, setCurrentLoaderFallback] = useLoaderFallback();
|
|
226
276
|
const [context, setContext] = useContextState();
|
|
227
277
|
const [blockedRoute, setBlockedRoute] = useBlockedRoute();
|
|
228
|
-
const { isAnimated, showFallbackOnAnimation: showFallback } = routerConfig;
|
|
229
278
|
const prevPathname = useRef("");
|
|
230
279
|
const navigationSeq = useRef(0);
|
|
231
280
|
const navigation = useCallback((nextLocation, routeItem) => {
|
|
@@ -248,7 +297,7 @@ var useNavigation = ({ routes, revalidateCache, isCacheItemFresh, loaderStateRef
|
|
|
248
297
|
setRouteItemData
|
|
249
298
|
]);
|
|
250
299
|
const transitionedNavigation = useCallback((nextLocation, routeItem) => {
|
|
251
|
-
if (!isAnimated) {
|
|
300
|
+
if (!isAnimated || !prevPathname.current) {
|
|
252
301
|
navigation(nextLocation, routeItem);
|
|
253
302
|
return;
|
|
254
303
|
}
|
|
@@ -357,136 +406,21 @@ var useNavigation = ({ routes, revalidateCache, isCacheItemFresh, loaderStateRef
|
|
|
357
406
|
return updateLocation;
|
|
358
407
|
};
|
|
359
408
|
//#endregion
|
|
360
|
-
//#region hooks/
|
|
361
|
-
var
|
|
362
|
-
const [,
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
const loadingPromises = useRef(/* @__PURE__ */ new Map());
|
|
370
|
-
const isCacheItemFresh = useCallback(({ routeItem, pathname }) => {
|
|
371
|
-
if (!routeItem) return true;
|
|
372
|
-
const currentCacheTimestamp = timestampMapRef.current.get(pathname);
|
|
373
|
-
if (!currentCacheTimestamp) return false;
|
|
374
|
-
if (!routeItem.staleTime) return true;
|
|
375
|
-
return Date.now() - currentCacheTimestamp < routeItem.staleTime;
|
|
376
|
-
}, []);
|
|
377
|
-
const revalidateCache = useCallback(async ({ routeItem, pathname }) => {
|
|
378
|
-
if (!routeItem?.loader) return;
|
|
379
|
-
if (loadingPromises.current.has(pathname)) return loadingPromises.current.get(pathname);
|
|
380
|
-
if (isCacheItemFresh({
|
|
381
|
-
routeItem,
|
|
382
|
-
pathname
|
|
383
|
-
})) {
|
|
384
|
-
loaderStateRef.current = loaderMapRef.current[pathname];
|
|
385
|
-
return;
|
|
386
|
-
}
|
|
387
|
-
const promise = (async () => {
|
|
388
|
-
if (!routeItem?.loader) return;
|
|
389
|
-
try {
|
|
390
|
-
const params = getParamsObject({
|
|
391
|
-
params: routeItem.params,
|
|
392
|
-
pathname
|
|
393
|
-
});
|
|
394
|
-
const result = await routeItem?.loader({
|
|
395
|
-
params,
|
|
396
|
-
context,
|
|
397
|
-
setContext
|
|
398
|
-
});
|
|
399
|
-
timestampMapRef.current.set(pathname, Date.now());
|
|
400
|
-
loaderStateRef.current = {
|
|
401
|
-
...loaderStateRef?.current,
|
|
402
|
-
data: result,
|
|
403
|
-
loaderError: null
|
|
404
|
-
};
|
|
405
|
-
loaderMapRef.current[pathname] = loaderStateRef.current;
|
|
406
|
-
} catch (error) {
|
|
407
|
-
loaderStateRef.current = {
|
|
408
|
-
...loaderStateRef?.current,
|
|
409
|
-
data: null,
|
|
410
|
-
loaderError: error
|
|
411
|
-
};
|
|
412
|
-
} finally {
|
|
413
|
-
loadingPromises.current.delete(pathname);
|
|
414
|
-
}
|
|
415
|
-
})();
|
|
416
|
-
loadingPromises.current.set(pathname, promise);
|
|
417
|
-
return promise;
|
|
409
|
+
//#region hooks/useSetRuntime.ts
|
|
410
|
+
var useSetRouterRuntime = ({ updateLocation, prefetchLoader, invalidate }) => {
|
|
411
|
+
const [, setCallbackState] = useActionState();
|
|
412
|
+
useEffect(() => {
|
|
413
|
+
setCallbackState({
|
|
414
|
+
updateLocation,
|
|
415
|
+
prefetchLoader,
|
|
416
|
+
invalidate
|
|
417
|
+
});
|
|
418
418
|
}, [
|
|
419
|
-
context,
|
|
420
|
-
isCacheItemFresh,
|
|
421
|
-
setContext
|
|
422
|
-
]);
|
|
423
|
-
return {
|
|
424
|
-
prefetchLoader: useCallback(async (pathname) => {
|
|
425
|
-
const item = routes.find((el) => comparePaths(el, pathname));
|
|
426
|
-
if (item) await revalidateCache({
|
|
427
|
-
routeItem: item,
|
|
428
|
-
pathname
|
|
429
|
-
});
|
|
430
|
-
}, [revalidateCache, routes]),
|
|
431
|
-
revalidateCache,
|
|
432
|
-
isCacheItemFresh,
|
|
433
|
-
loaderStateRef,
|
|
434
|
-
invalidate: useCallback(async (pathname = latestPathname.current) => {
|
|
435
|
-
if (typeof pathname !== "string") return;
|
|
436
|
-
const routeItem = routes.find((el) => comparePaths(el, pathname));
|
|
437
|
-
const resultParams = getParamsObject({
|
|
438
|
-
params: routeItem?.params,
|
|
439
|
-
pathname
|
|
440
|
-
});
|
|
441
|
-
timestampMapRef.current.delete(pathname);
|
|
442
|
-
try {
|
|
443
|
-
if (routeItem?.beforeLoad) await routeItem.beforeLoad({
|
|
444
|
-
context,
|
|
445
|
-
redirect: () => Promise.resolve(),
|
|
446
|
-
params: resultParams,
|
|
447
|
-
setContext
|
|
448
|
-
});
|
|
449
|
-
loaderStateRef.current = {
|
|
450
|
-
...loaderStateRef.current,
|
|
451
|
-
beforeLoadError: null
|
|
452
|
-
};
|
|
453
|
-
} catch (error) {
|
|
454
|
-
loaderStateRef.current = {
|
|
455
|
-
...loaderStateRef.current,
|
|
456
|
-
beforeLoadError: error
|
|
457
|
-
};
|
|
458
|
-
}
|
|
459
|
-
await revalidateCache({
|
|
460
|
-
routeItem,
|
|
461
|
-
pathname
|
|
462
|
-
});
|
|
463
|
-
if (pathname === latestPathname.current) setLoaderState(loaderStateRef.current);
|
|
464
|
-
}, [
|
|
465
|
-
context,
|
|
466
|
-
loaderStateRef,
|
|
467
|
-
revalidateCache,
|
|
468
|
-
latestPathname,
|
|
469
|
-
routes,
|
|
470
|
-
setContext,
|
|
471
|
-
setLoaderState
|
|
472
|
-
])
|
|
473
|
-
};
|
|
474
|
-
};
|
|
475
|
-
//#endregion
|
|
476
|
-
//#region components/RouterProvider.tsx
|
|
477
|
-
var RouterProvider = ({ children, routes }) => {
|
|
478
|
-
const { prefetchLoader, revalidateCache, isCacheItemFresh, loaderStateRef, invalidate } = useLoader(routes);
|
|
479
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Provider, {
|
|
480
|
-
updateLocation: useNavigation({
|
|
481
|
-
routes,
|
|
482
|
-
revalidateCache,
|
|
483
|
-
isCacheItemFresh,
|
|
484
|
-
loaderStateRef
|
|
485
|
-
}),
|
|
486
419
|
invalidate,
|
|
487
420
|
prefetchLoader,
|
|
488
|
-
|
|
489
|
-
|
|
421
|
+
setCallbackState,
|
|
422
|
+
updateLocation
|
|
423
|
+
]);
|
|
490
424
|
};
|
|
491
425
|
//#endregion
|
|
492
426
|
//#region hooks/useApplyCustomAnimation.ts
|
|
@@ -549,6 +483,56 @@ var usePreserveScroll = (preserveScroll) => {
|
|
|
549
483
|
]);
|
|
550
484
|
};
|
|
551
485
|
//#endregion
|
|
486
|
+
//#region \0@oxc-project+runtime@0.133.0/helpers/esm/typeof.js
|
|
487
|
+
function _typeof(o) {
|
|
488
|
+
"@babel/helpers - typeof";
|
|
489
|
+
return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(o) {
|
|
490
|
+
return typeof o;
|
|
491
|
+
} : function(o) {
|
|
492
|
+
return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
|
|
493
|
+
}, _typeof(o);
|
|
494
|
+
}
|
|
495
|
+
//#endregion
|
|
496
|
+
//#region \0@oxc-project+runtime@0.133.0/helpers/esm/toPrimitive.js
|
|
497
|
+
function toPrimitive(t, r) {
|
|
498
|
+
if ("object" != _typeof(t) || !t) return t;
|
|
499
|
+
var e = t[Symbol.toPrimitive];
|
|
500
|
+
if (void 0 !== e) {
|
|
501
|
+
var i = e.call(t, r || "default");
|
|
502
|
+
if ("object" != _typeof(i)) return i;
|
|
503
|
+
throw new TypeError("@@toPrimitive must return a primitive value.");
|
|
504
|
+
}
|
|
505
|
+
return ("string" === r ? String : Number)(t);
|
|
506
|
+
}
|
|
507
|
+
//#endregion
|
|
508
|
+
//#region \0@oxc-project+runtime@0.133.0/helpers/esm/toPropertyKey.js
|
|
509
|
+
function toPropertyKey(t) {
|
|
510
|
+
var i = toPrimitive(t, "string");
|
|
511
|
+
return "symbol" == _typeof(i) ? i : i + "";
|
|
512
|
+
}
|
|
513
|
+
//#endregion
|
|
514
|
+
//#region \0@oxc-project+runtime@0.133.0/helpers/esm/defineProperty.js
|
|
515
|
+
function _defineProperty(e, r, t) {
|
|
516
|
+
return (r = toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
|
|
517
|
+
value: t,
|
|
518
|
+
enumerable: !0,
|
|
519
|
+
configurable: !0,
|
|
520
|
+
writable: !0
|
|
521
|
+
}) : e[r] = t, e;
|
|
522
|
+
}
|
|
523
|
+
//#endregion
|
|
524
|
+
//#region config/routerConfig.ts
|
|
525
|
+
var RouterConfig = class {
|
|
526
|
+
constructor() {
|
|
527
|
+
_defineProperty(this, "prefetch", "hover");
|
|
528
|
+
_defineProperty(this, "hoverPrefetchDelay", 150);
|
|
529
|
+
}
|
|
530
|
+
configure(config) {
|
|
531
|
+
Object.assign(this, config);
|
|
532
|
+
}
|
|
533
|
+
};
|
|
534
|
+
var routerConfig = new RouterConfig();
|
|
535
|
+
//#endregion
|
|
552
536
|
//#region hooks/useSetRouterConfig.ts
|
|
553
537
|
var useSetRouterConfig = (routerProps) => {
|
|
554
538
|
useEffect(() => routerConfig.configure(routerProps), [routerProps]);
|
|
@@ -573,20 +557,33 @@ var renderElement = (Component) => {
|
|
|
573
557
|
//#endregion
|
|
574
558
|
//#region components/Router.tsx
|
|
575
559
|
var EmptyBoundary = ({ children }) => children;
|
|
576
|
-
var Router = ({
|
|
560
|
+
var Router = ({ routes, animationDuration, isAnimated = false, spinner = true, preserveScroll = true, showFallbackOnAnimation = false, prefetch = "hover", hoverPrefetchDelay = 150, errorBoundary: ErrorBoundary = EmptyBoundary, context: initialContext }) => {
|
|
577
561
|
const [isLoading] = useIsLoading();
|
|
578
562
|
const [currentLoaderFallback] = useLoaderFallback();
|
|
579
563
|
const [routeItemData] = useRouteItemData();
|
|
580
564
|
const [loaderState] = useCurrentLoaderState();
|
|
581
|
-
|
|
582
|
-
|
|
565
|
+
const { prefetchLoader, revalidateCache, isCacheItemFresh, loaderStateRef, invalidate } = useLoader(routes);
|
|
566
|
+
useSetRouterRuntime({
|
|
567
|
+
updateLocation: useNavigation({
|
|
568
|
+
routes,
|
|
569
|
+
revalidateCache,
|
|
570
|
+
isCacheItemFresh,
|
|
571
|
+
loaderStateRef,
|
|
572
|
+
isAnimated,
|
|
573
|
+
showFallbackOnAnimation
|
|
574
|
+
}),
|
|
575
|
+
prefetchLoader,
|
|
576
|
+
invalidate
|
|
577
|
+
});
|
|
583
578
|
useSetRouterConfig({
|
|
584
579
|
isAnimated,
|
|
585
580
|
showFallbackOnAnimation,
|
|
586
581
|
prefetch,
|
|
587
582
|
hoverPrefetchDelay
|
|
588
583
|
});
|
|
584
|
+
useApplyCustomAnimation(animationDuration);
|
|
589
585
|
useSetInitialContext(initialContext);
|
|
586
|
+
usePreserveScroll(preserveScroll);
|
|
590
587
|
const showErrorElement = !isLoading && Boolean(loaderState.loaderError || loaderState.beforeLoadError);
|
|
591
588
|
const showSpinner = spinner && isAnimated && isLoading;
|
|
592
589
|
const loadingContent = !showErrorElement && isLoading;
|
|
@@ -601,13 +598,20 @@ var Router = ({ isAnimated, animationDuration, spinner = true, preserveScroll =
|
|
|
601
598
|
});
|
|
602
599
|
};
|
|
603
600
|
//#endregion
|
|
604
|
-
//#region hooks/
|
|
605
|
-
var
|
|
606
|
-
const
|
|
607
|
-
|
|
608
|
-
return
|
|
601
|
+
//#region hooks/useRuntime.ts
|
|
602
|
+
var useRuntime = () => {
|
|
603
|
+
const [callbackState] = useActionState();
|
|
604
|
+
const { updateLocation, prefetchLoader, invalidate } = callbackState;
|
|
605
|
+
return useMemo(() => ({
|
|
606
|
+
updateLocation,
|
|
607
|
+
prefetchLoader,
|
|
608
|
+
invalidate
|
|
609
|
+
}), [
|
|
610
|
+
updateLocation,
|
|
611
|
+
prefetchLoader,
|
|
612
|
+
invalidate
|
|
613
|
+
]);
|
|
609
614
|
};
|
|
610
|
-
var useRouterActions = () => useServiceState(ActionsContext);
|
|
611
615
|
//#endregion
|
|
612
616
|
//#region hooks/useLocation.ts
|
|
613
617
|
var useLocation = () => {
|
|
@@ -618,10 +622,11 @@ var useLocation = () => {
|
|
|
618
622
|
//#region hooks/useNavigate.ts
|
|
619
623
|
var useNavigate = () => {
|
|
620
624
|
const [blockedRoute, setBlockedRoute] = useBlockedRoute();
|
|
621
|
-
const { updateLocation } =
|
|
625
|
+
const { updateLocation } = useRuntime();
|
|
622
626
|
const locationRef = useLatest(useLocation());
|
|
623
627
|
const blockedRouteRef = useLatest(blockedRoute);
|
|
624
628
|
return useCallback(async (arg) => {
|
|
629
|
+
if (!updateLocation) throw new Error("Router has not been initialized. Did you forget to render <Router />?");
|
|
625
630
|
if (arg !== -1 && blockedRouteRef.current.from) {
|
|
626
631
|
const to = typeof arg === "object" ? arg.pathname : arg;
|
|
627
632
|
setBlockedRoute((prevState) => ({
|
|
@@ -647,7 +652,7 @@ var Link = ({ children, to, prefetch: prefetchLink, hoverPrefetchDelay }) => {
|
|
|
647
652
|
const { prefetch: configPrefetch, hoverPrefetchDelay: configPrefetchDelay } = routerConfig;
|
|
648
653
|
const prefetch = prefetchLink || configPrefetch;
|
|
649
654
|
const prefetchDelay = hoverPrefetchDelay ?? configPrefetchDelay;
|
|
650
|
-
const { prefetchLoader } =
|
|
655
|
+
const { prefetchLoader } = useRuntime();
|
|
651
656
|
const navigate = useNavigate();
|
|
652
657
|
const timeout = useRef(0);
|
|
653
658
|
const ref = useRef(null);
|
|
@@ -715,7 +720,7 @@ var FormProvider = ({ children, isSubmitting }) => /* @__PURE__ */ (0, import_js
|
|
|
715
720
|
//#endregion
|
|
716
721
|
//#region hooks/useInvalidate.ts
|
|
717
722
|
var useInvalidate = () => {
|
|
718
|
-
const { invalidate } =
|
|
723
|
+
const { invalidate } = useRuntime();
|
|
719
724
|
return invalidate;
|
|
720
725
|
};
|
|
721
726
|
//#endregion
|
|
@@ -729,40 +734,38 @@ var useParams = () => {
|
|
|
729
734
|
}) : void 0, [pathname, routeItem]);
|
|
730
735
|
};
|
|
731
736
|
//#endregion
|
|
732
|
-
//#region hooks/
|
|
733
|
-
var
|
|
737
|
+
//#region hooks/useGetAction.ts
|
|
738
|
+
var useGetAction = (actionKey) => {
|
|
734
739
|
const invalidate = useInvalidate();
|
|
735
740
|
const [routeItemData] = useRouteItemData();
|
|
736
741
|
const [context, setContext] = useContextState();
|
|
737
742
|
const params = useParams();
|
|
738
743
|
const { routeItem } = routeItemData;
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
744
|
+
const latestContext = useLatest(context);
|
|
745
|
+
if (!routeItem) throw new Error("Route not found");
|
|
746
|
+
if (!routeItem.actions) throw new Error("Route action creator not found");
|
|
747
|
+
const action = routeItem.actions({
|
|
748
|
+
context: latestContext.current,
|
|
749
|
+
setContext,
|
|
743
750
|
params,
|
|
744
|
-
|
|
751
|
+
invalidate
|
|
752
|
+
})[actionKey];
|
|
753
|
+
if (!action) throw new Error(`Action "${actionKey}" not found`);
|
|
754
|
+
return {
|
|
755
|
+
currentAction: action,
|
|
756
|
+
invalidate
|
|
745
757
|
};
|
|
746
758
|
};
|
|
747
759
|
//#endregion
|
|
748
760
|
//#region components/Form.tsx
|
|
749
|
-
var Form = ({ children, action
|
|
750
|
-
const {
|
|
761
|
+
var Form = ({ children, action, onSuccess, onError, autoReset = true }) => {
|
|
762
|
+
const { currentAction, invalidate } = useGetAction(action);
|
|
751
763
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
752
764
|
const onSubmit = async (evt) => {
|
|
753
765
|
evt.preventDefault();
|
|
754
|
-
if (!routeItem) throw new Error("Route not found");
|
|
755
|
-
if (!routeItem.actions) throw new Error("Route action creator not found");
|
|
756
|
-
const action = routeItem.actions({
|
|
757
|
-
context: latestContext.current,
|
|
758
|
-
setContext,
|
|
759
|
-
params,
|
|
760
|
-
invalidate
|
|
761
|
-
})[actionKey];
|
|
762
|
-
if (!action) throw new Error(`Action "${actionKey}" not found`);
|
|
763
766
|
try {
|
|
764
767
|
setIsSubmitting(true);
|
|
765
|
-
const result = await
|
|
768
|
+
const result = await currentAction(new FormData(evt.target));
|
|
766
769
|
await invalidate();
|
|
767
770
|
if (autoReset) evt.target.reset();
|
|
768
771
|
onSuccess?.(result);
|
|
@@ -790,7 +793,7 @@ var useLoaderState = () => {
|
|
|
790
793
|
//#region hooks/useBlocker.ts
|
|
791
794
|
var useBlocker = (blockerFn) => {
|
|
792
795
|
const [blockedRoute, setBlockedRoute] = useBlockedRoute();
|
|
793
|
-
const { updateLocation } =
|
|
796
|
+
const { updateLocation } = useRuntime();
|
|
794
797
|
const [routeItemData] = useRouteItemData();
|
|
795
798
|
const { location: { pathname } } = routeItemData;
|
|
796
799
|
const updateBlockedRoute = useCallback(({ type, payload = "" }) => setBlockedRoute((prevState) => {
|
|
@@ -833,19 +836,10 @@ var useBlocker = (blockerFn) => {
|
|
|
833
836
|
//#endregion
|
|
834
837
|
//#region hooks/useAction.ts
|
|
835
838
|
var useAction = (action, options = {}) => {
|
|
836
|
-
const {
|
|
839
|
+
const { currentAction, invalidate } = useGetAction(action);
|
|
837
840
|
const latestOnSuccess = useLatest(options?.onSuccess);
|
|
838
841
|
const latestOnError = useLatest(options?.onError);
|
|
839
842
|
return useCallback(async (formData) => {
|
|
840
|
-
if (!routeItem) throw new Error("Route not found");
|
|
841
|
-
if (!routeItem.actions) throw new Error("Route action creator not found");
|
|
842
|
-
const currentAction = routeItem.actions({
|
|
843
|
-
context: latestContext.current,
|
|
844
|
-
setContext,
|
|
845
|
-
params,
|
|
846
|
-
invalidate
|
|
847
|
-
})[action];
|
|
848
|
-
if (!currentAction) throw new Error(`Action "${action}" not found`);
|
|
849
843
|
try {
|
|
850
844
|
const result = await currentAction(formData);
|
|
851
845
|
await invalidate();
|
|
@@ -854,14 +848,10 @@ var useAction = (action, options = {}) => {
|
|
|
854
848
|
latestOnError.current?.(error);
|
|
855
849
|
}
|
|
856
850
|
}, [
|
|
857
|
-
|
|
851
|
+
currentAction,
|
|
858
852
|
invalidate,
|
|
859
|
-
latestContext,
|
|
860
853
|
latestOnError,
|
|
861
|
-
latestOnSuccess
|
|
862
|
-
params,
|
|
863
|
-
routeItem,
|
|
864
|
-
setContext
|
|
854
|
+
latestOnSuccess
|
|
865
855
|
]);
|
|
866
856
|
};
|
|
867
857
|
//#endregion
|
|
@@ -1024,4 +1014,4 @@ var adapter = {
|
|
|
1024
1014
|
})
|
|
1025
1015
|
};
|
|
1026
1016
|
//#endregion
|
|
1027
|
-
export { Form, Link, Router,
|
|
1017
|
+
export { Form, Link, Router, adapter, createRouter, useAction, useBlocker, useFormContext, useInvalidate, useLoaderState, useLocation, useNavigate, useParams, useQueryParam, useRouterContext, useSearchParams };
|
package/dist/state/state.d.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import { LoaderState, RouteItemData } from '../types/global';
|
|
1
|
+
import { LoaderState, Location, RouteItemData } from '../types/global';
|
|
2
|
+
type Runtime = {
|
|
3
|
+
updateLocation(route: Location): Promise<void>;
|
|
4
|
+
prefetchLoader(arg: string): Promise<void>;
|
|
5
|
+
invalidate(path?: string): Promise<void>;
|
|
6
|
+
};
|
|
2
7
|
export declare const useIsLoading: () => readonly [boolean, (action: boolean | ((prevState: boolean) => boolean)) => void];
|
|
3
8
|
export declare const useBlockedRoute: () => readonly [{
|
|
4
9
|
from: string;
|
|
@@ -18,3 +23,5 @@ export declare const useRouteItemData: () => readonly [RouteItemData, (action: R
|
|
|
18
23
|
export declare const useCurrentLoaderState: () => readonly [LoaderState, (action: LoaderState | ((prevState: LoaderState) => LoaderState)) => void];
|
|
19
24
|
export declare const useScrollMap: () => readonly [Record<string, number>, (action: Record<string, number> | ((prevState: Record<string, number>) => Record<string, number>)) => void];
|
|
20
25
|
export declare const useContextState: () => readonly [Record<string, unknown>, (action: Record<string, unknown> | ((prevState: Record<string, unknown>) => Record<string, unknown>)) => void];
|
|
26
|
+
export declare const useActionState: () => readonly [Runtime, (action: Runtime | ((prevState: Runtime) => Runtime)) => void];
|
|
27
|
+
export {};
|
package/dist/types/global.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { ReactNode } from 'react';
|
|
2
|
-
import { RouteItem } from '../types/global';
|
|
3
|
-
type RouteProviderProps = {
|
|
4
|
-
children: ReactNode;
|
|
5
|
-
routes: RouteItem[];
|
|
6
|
-
};
|
|
7
|
-
export declare const RouterProvider: ({ children, routes }: RouteProviderProps) => import("react/jsx-runtime").JSX.Element;
|
|
8
|
-
export {};
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { Location } from '../types/global';
|
|
2
|
-
export type ActionsContextValue = {
|
|
3
|
-
updateLocation(route: Location): Promise<void>;
|
|
4
|
-
prefetchLoader(arg: string): Promise<void>;
|
|
5
|
-
invalidate(path?: string): Promise<void>;
|
|
6
|
-
};
|
|
7
|
-
export declare const ActionsContext: import("react").Context<ActionsContextValue>;
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
export declare const useActionParams: () => {
|
|
2
|
-
invalidate: (path?: string) => Promise<void>;
|
|
3
|
-
routeItem: import("..").RouteItem | undefined;
|
|
4
|
-
latestContext: import("react").RefObject<Record<string, unknown>>;
|
|
5
|
-
params: Record<string, string>;
|
|
6
|
-
setContext: (action: Record<string, unknown> | ((prevState: Record<string, unknown>) => Record<string, unknown>)) => void;
|
|
7
|
-
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const useRouterActions: () => import("../context/RouterProviderContext").ActionsContextValue;
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { type ReactNode } from 'react';
|
|
2
|
-
import { type ActionsContextValue } from '../context/RouterProviderContext';
|
|
3
|
-
type ProviderProps = ActionsContextValue & {
|
|
4
|
-
children: ReactNode;
|
|
5
|
-
};
|
|
6
|
-
export declare const Provider: ({ children, updateLocation, prefetchLoader, invalidate }: ProviderProps) => import("react/jsx-runtime").JSX.Element;
|
|
7
|
-
export {};
|