clear-react-router 1.1.4 → 1.2.0
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 +92 -12
- package/dist/clear-react-router.css +23 -0
- package/dist/components/Router.d.ts +4 -2
- package/dist/components/Spinner/Spinner.d.ts +1 -0
- package/dist/hooks/useApplyCustomAnimation.d.ts +2 -0
- package/dist/hooks/useHandleNavigation.d.ts +2 -1
- package/dist/hooks/useLocation.d.ts +1 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.js +103 -79
- package/dist/types/global.d.ts +8 -1
- package/package.json +1 -1
- package/dist/utils/redirect.d.ts +0 -7
package/README.md
CHANGED
|
@@ -7,6 +7,7 @@ A lightweight, type-safe routing library for React applications with nested rout
|
|
|
7
7
|
- 🧩 **Nested Routes** - Organize your UI with nested layouts and routes
|
|
8
8
|
- ⚡ **Data Loading** - Built-in loaders with caching and stale-while-revalidate strategy
|
|
9
9
|
- 🔒 **Navigation Blocking** - Prevent accidental navigation with `useBlocker`
|
|
10
|
+
- ✨ **Smooth Animations** - Page transitions with fade and slide effects (customizable type and duration)
|
|
10
11
|
- 🎯 **Type-safe Redirects** - Redirect from loaders and beforeLoad hooks
|
|
11
12
|
- 📦 **Prefetching** - Preload data on hover for instant navigation
|
|
12
13
|
- 🚀 **Lazy Loading** - Code-split your routes with dynamic imports for optimal performance
|
|
@@ -25,7 +26,7 @@ Normalizes route configuration. Handles wildcard `*` routes, extracts dynamic pa
|
|
|
25
26
|
| `path` | `string` | Route path, e.g., `/user/:userId` |
|
|
26
27
|
| `element` | `ReactElement \| () => ReactElement \| LazyComponent` | Component to render |
|
|
27
28
|
| `loader` | `() => Promise<unknown>` | Fetch data |
|
|
28
|
-
| `beforeLoad` | `(context) => Promise<void>` | Auth checks
|
|
29
|
+
| `beforeLoad` | `({ context, redirect }) => Promise<void>` | Auth checks and redirects. `redirect` is provided by the router |
|
|
29
30
|
| `afterLoad` | `(context) => Promise<void>` | Analytics, side effects |
|
|
30
31
|
| `fallback` | `ReactElement \| () => ReactElement` | Loading fallback (for lazy loading) |
|
|
31
32
|
| `loaderFallback` | `ReactElement \| () => ReactElement` | Loading fallback (for loader) |
|
|
@@ -37,10 +38,21 @@ Normalizes route configuration. Handles wildcard `*` routes, extracts dynamic pa
|
|
|
37
38
|
|
|
38
39
|
Main component that renders the application based on current URL.
|
|
39
40
|
|
|
40
|
-
| Prop | Type | Description |
|
|
41
|
-
|
|
42
|
-
| `routeList` | `RouteItem[]` | Array of route configurations |
|
|
43
|
-
| `context` | `object` | Optional initial context (user, theme, etc.) |
|
|
41
|
+
| Prop | Type | Default | Description |
|
|
42
|
+
|------|------|---------|-------------|
|
|
43
|
+
| `routeList` | `RouteItem[]` | required | Array of route configurations |
|
|
44
|
+
| `context` | `object` | `{}` | Optional initial context (user, theme, etc.) |
|
|
45
|
+
| `isAnimated` | `boolean` | `false` | Enable smooth page transitions |
|
|
46
|
+
| `animationOptions` | `AnimationOptions` | `{ duration: 300, name: 'fade' }` | Animation settings (only when `isAnimated` is `true`) |
|
|
47
|
+
|
|
48
|
+
**`AnimationOptions`:**
|
|
49
|
+
|
|
50
|
+
| Property | Type | Default | Description |
|
|
51
|
+
|----------|------|---------|-------------|
|
|
52
|
+
| `duration` | `number` | `300` | Animation duration in milliseconds |
|
|
53
|
+
| `name` | `'fade' \| 'slide-left' \| 'slide-right'` | `'fade'` | Type of transition effect |
|
|
54
|
+
|
|
55
|
+
> **Note:** When `isAnimated` is enabled, the `loaderFallback` is not displayed. Instead, a small spinner appears in the corner while data loads, ensuring smooth transitions without layout shifts.
|
|
44
56
|
|
|
45
57
|
### `Link`
|
|
46
58
|
|
|
@@ -52,13 +64,26 @@ Component for client-side navigation with prefetch support.
|
|
|
52
64
|
| `prefetch` | `boolean` | `true` |
|
|
53
65
|
| `children` | `ReactElement` | required |
|
|
54
66
|
|
|
55
|
-
### `redirect
|
|
67
|
+
### `redirect`
|
|
68
|
+
|
|
69
|
+
Function provided to `beforeLoad` for programmatic redirection.
|
|
70
|
+
|
|
71
|
+
**Type:** `(arg: Location) => Promise<void>`
|
|
56
72
|
|
|
57
|
-
Redirects from `beforeLoad`.
|
|
58
73
|
```
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
74
|
+
import type { Location } from 'clear-react-router';
|
|
75
|
+
|
|
76
|
+
const routes = createRouter([
|
|
77
|
+
{
|
|
78
|
+
path: '/dashboard',
|
|
79
|
+
element: <Dashboard />,
|
|
80
|
+
beforeLoad: ({ context, redirect }) => {
|
|
81
|
+
if (!context.isAuthorized) {
|
|
82
|
+
return redirect({ pathname: '/' });
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
]);
|
|
62
87
|
```
|
|
63
88
|
|
|
64
89
|
## Hooks
|
|
@@ -149,6 +174,14 @@ const onSave = useCallback(() => {
|
|
|
149
174
|
useBeforeUnload(text ? onSave : undefined);
|
|
150
175
|
```
|
|
151
176
|
|
|
177
|
+
### `useRouterContext()`
|
|
178
|
+
|
|
179
|
+
Handles router context.
|
|
180
|
+
```
|
|
181
|
+
const { setContext, context } = useRouterContext();
|
|
182
|
+
const loginHandler = () => setContext({ ...context, user: { name: 'John' } });
|
|
183
|
+
```
|
|
184
|
+
|
|
152
185
|
## Lazy Loading
|
|
153
186
|
|
|
154
187
|
Clear Router supports code-splitting out of the box. Simply pass a function that returns a dynamic import:
|
|
@@ -159,10 +192,57 @@ Clear Router supports code-splitting out of the box. Simply pass a function that
|
|
|
159
192
|
fallback: () => <div>Loading...</div>,
|
|
160
193
|
}
|
|
161
194
|
```
|
|
195
|
+
## Animations
|
|
196
|
+
|
|
197
|
+
Clear Router supports smooth page transitions using the native View Transitions API. When animations are enabled, the router waits for all data to load before starting the transition, ensuring a jank-free experience.
|
|
198
|
+
|
|
199
|
+
### Quick Start
|
|
200
|
+
|
|
201
|
+
```
|
|
202
|
+
import { Router } from 'clear-react-router';
|
|
203
|
+
|
|
204
|
+
// Enable default fade animation
|
|
205
|
+
<Router routeList={routes} isAnimated />
|
|
206
|
+
|
|
207
|
+
// Custom animation
|
|
208
|
+
<Router
|
|
209
|
+
routeList={routes}
|
|
210
|
+
isAnimated
|
|
211
|
+
animationOptions={{
|
|
212
|
+
duration: 500, // milliseconds
|
|
213
|
+
name: 'slide-left' // 'fade' | 'slide-left' | 'slide-right'
|
|
214
|
+
}}
|
|
215
|
+
/>
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
## How It Works
|
|
219
|
+
|
|
220
|
+
- **Data loads first** — All `loader` and `beforeLoad` hooks complete before animation starts
|
|
221
|
+
- **No `loaderFallback`** — The `loaderFallback` is not shown during animated transitions
|
|
222
|
+
- **Subtle spinner** — A small spinner appears in the top-left corner while data is loading, so users know the app is responsive
|
|
223
|
+
- **Native API** — Uses `document.startViewTransition` for smooth, hardware-accelerated animations
|
|
224
|
+
|
|
225
|
+
## Animation Types
|
|
226
|
+
|
|
227
|
+
| Name | Effect |
|
|
228
|
+
|------|--------|
|
|
229
|
+
| `fade` | Cross-fade between pages (default) |
|
|
230
|
+
| `slide-left` | New page slides in from right, old page slides out to left |
|
|
231
|
+
| `slide-right` | New page slides in from left, old page slides out to right |
|
|
232
|
+
|
|
233
|
+
## Browser Support
|
|
234
|
+
|
|
235
|
+
View Transitions API requires modern browsers:
|
|
236
|
+
|
|
237
|
+
- Chrome/Edge 111+
|
|
238
|
+
- Safari 18+
|
|
239
|
+
- Firefox 144+
|
|
240
|
+
|
|
241
|
+
For older browsers, the router gracefully falls back to regular navigation without animation.
|
|
162
242
|
|
|
163
243
|
## Requirements
|
|
164
244
|
- React 16.6+ (for React.lazy and Suspense)
|
|
165
245
|
- Use `default` export for your lazy-loaded components
|
|
166
246
|
|
|
167
|
-
|
|
168
|
-
|
|
247
|
+
## License
|
|
248
|
+
MIT
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
._spinner_1tekw_1 {
|
|
2
|
+
position: fixed;
|
|
3
|
+
top: 5px;
|
|
4
|
+
left: 5px;
|
|
5
|
+
z-index: 9999;
|
|
6
|
+
width: 1rem;
|
|
7
|
+
height: 1rem;
|
|
8
|
+
border: 2px solid gray;
|
|
9
|
+
border-bottom-color: transparent;
|
|
10
|
+
border-radius: 50%;
|
|
11
|
+
display: inline-block;
|
|
12
|
+
box-sizing: border-box;
|
|
13
|
+
animation: _rotation_1tekw_1 1s linear infinite;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
@keyframes _rotation_1tekw_1 {
|
|
17
|
+
0% {
|
|
18
|
+
transform: rotate(0deg);
|
|
19
|
+
}
|
|
20
|
+
100% {
|
|
21
|
+
transform: rotate(360deg);
|
|
22
|
+
}
|
|
23
|
+
}/*$vite$:1*/
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { AnimationOptions, RouteItem } from '../types/global';
|
|
2
2
|
type RouterProps = {
|
|
3
3
|
routeList: RouteItem[];
|
|
4
4
|
context?: Record<string, unknown>;
|
|
5
|
+
isAnimated?: boolean;
|
|
6
|
+
animationOptions?: AnimationOptions;
|
|
5
7
|
};
|
|
6
|
-
export declare const Router: ({ routeList, context: initialContext }: RouterProps) => import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
export declare const Router: ({ routeList, context: initialContext, isAnimated, animationOptions, }: RouterProps) => import("react/jsx-runtime").JSX.Element;
|
|
7
9
|
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const Spinner: () => import("react/jsx-runtime").JSX.Element;
|
|
@@ -4,8 +4,9 @@ type UseHandleNavigation = {
|
|
|
4
4
|
setLocation: (arg: Location) => void;
|
|
5
5
|
context: Record<string, unknown>;
|
|
6
6
|
revalidateCache(routeItem?: RouteItem, isCurrentRoute?: boolean): Promise<void>;
|
|
7
|
+
isAnimated: boolean;
|
|
7
8
|
};
|
|
8
|
-
export declare const useHandleNavigation: ({ setLocation, routeList, context, revalidateCache }: UseHandleNavigation) => {
|
|
9
|
+
export declare const useHandleNavigation: ({ setLocation, routeList, context, revalidateCache, isAnimated, }: UseHandleNavigation) => {
|
|
9
10
|
blockerState: BlockerState;
|
|
10
11
|
updateLocation: (nextLocation: Location) => Promise<void>;
|
|
11
12
|
updateBlockedRoute: ({ type, payload }: UpdateBlockedRouteProps) => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const useLocation: () => import("
|
|
1
|
+
export declare const useLocation: () => import("..").Location;
|
package/dist/index.d.ts
CHANGED
|
@@ -8,5 +8,4 @@ export { useBlocker } from './hooks/useBlocker';
|
|
|
8
8
|
export { useBeforeUnload } from './hooks/useBeforeUnload';
|
|
9
9
|
export { useRouterContext } from './hooks/useRouterContext';
|
|
10
10
|
export { createRouter } from './utils/utils';
|
|
11
|
-
export {
|
|
12
|
-
export type { RouteItem, BlockerState } from './types/global';
|
|
11
|
+
export type { RouteItem, BlockerState, Location } from './types/global';
|
package/dist/index.js
CHANGED
|
@@ -37,6 +37,7 @@ var require_react_jsx_runtime_production = /* @__PURE__ */ __commonJSMin(((expor
|
|
|
37
37
|
};
|
|
38
38
|
}
|
|
39
39
|
exports.jsx = jsxProd;
|
|
40
|
+
exports.jsxs = jsxProd;
|
|
40
41
|
}));
|
|
41
42
|
//#endregion
|
|
42
43
|
//#region provider/RouterProvider.tsx
|
|
@@ -129,37 +130,52 @@ var useLatest = (value) => {
|
|
|
129
130
|
};
|
|
130
131
|
//#endregion
|
|
131
132
|
//#region hooks/useHandleNavigation.ts
|
|
132
|
-
var
|
|
133
|
-
var useHandleNavigation = ({ setLocation, routeList, context, revalidateCache }) => {
|
|
133
|
+
var useHandleNavigation = ({ setLocation, routeList, context, revalidateCache, isAnimated }) => {
|
|
134
134
|
const [blockedRoute, setBlockedRoute] = useState({
|
|
135
135
|
from: "",
|
|
136
136
|
to: ""
|
|
137
137
|
});
|
|
138
138
|
const prevPathname = useRef("");
|
|
139
|
-
const
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
history.replaceState(null, "", redirect.url);
|
|
152
|
-
setLocation({
|
|
153
|
-
pathname: redirect.url,
|
|
154
|
-
search: redirect.search
|
|
155
|
-
});
|
|
139
|
+
const navigationSeq = useRef(0);
|
|
140
|
+
const navigation = useCallback((nextLocation) => {
|
|
141
|
+
setLocation(nextLocation);
|
|
142
|
+
prevPathname.current = nextLocation.pathname;
|
|
143
|
+
if (nextLocation.pathname === window.location.pathname) return;
|
|
144
|
+
history.pushState(null, "", nextLocation.pathname);
|
|
145
|
+
}, [setLocation]);
|
|
146
|
+
const transitionedNavigation = useCallback(({ nextLocation, isFirstCall, isAnimated }) => {
|
|
147
|
+
if (isAnimated && !isFirstCall) try {
|
|
148
|
+
document.startViewTransition(() => navigation(nextLocation));
|
|
149
|
+
} catch {
|
|
150
|
+
navigation(nextLocation);
|
|
156
151
|
}
|
|
152
|
+
else navigation(nextLocation);
|
|
153
|
+
}, [navigation]);
|
|
154
|
+
const setNextLocation = useCallback(async (nextLocation, isFirstCall) => {
|
|
155
|
+
navigationSeq.current = navigationSeq.current + 1;
|
|
156
|
+
const seq = navigationSeq.current;
|
|
157
|
+
const nextItem = routeList.find((el) => comparePaths(el, nextLocation.pathname));
|
|
158
|
+
if (nextItem?.beforeLoad) await nextItem.beforeLoad({
|
|
159
|
+
context,
|
|
160
|
+
redirect: setNextLocation
|
|
161
|
+
});
|
|
162
|
+
if (seq !== navigationSeq.current) return;
|
|
163
|
+
await revalidateCache(nextItem, true);
|
|
164
|
+
if (seq !== navigationSeq.current) return;
|
|
165
|
+
transitionedNavigation({
|
|
166
|
+
nextLocation,
|
|
167
|
+
isAnimated,
|
|
168
|
+
isFirstCall
|
|
169
|
+
});
|
|
170
|
+
if (nextItem?.afterLoad) await nextItem.afterLoad(context);
|
|
157
171
|
}, [
|
|
158
172
|
context,
|
|
173
|
+
isAnimated,
|
|
159
174
|
revalidateCache,
|
|
160
175
|
routeList,
|
|
161
|
-
|
|
162
|
-
])
|
|
176
|
+
transitionedNavigation
|
|
177
|
+
]);
|
|
178
|
+
const setNextLocationRef = useLatest(setNextLocation);
|
|
163
179
|
const updateBlockedRoute = useCallback(({ type, payload = "" }) => setBlockedRoute((prevState) => {
|
|
164
180
|
if (prevState.from === payload && type === "charge") return prevState;
|
|
165
181
|
if (payload && prevState.from !== payload && type === "charge") return {
|
|
@@ -200,7 +216,7 @@ var useHandleNavigation = ({ setLocation, routeList, context, revalidateCache })
|
|
|
200
216
|
}, [blockedRoute.from, setNextLocationRef]);
|
|
201
217
|
useEffect(() => {
|
|
202
218
|
const currentLocation = parseWindowLocation(window.location);
|
|
203
|
-
setNextLocationRef.current(currentLocation);
|
|
219
|
+
setNextLocationRef.current(currentLocation, true);
|
|
204
220
|
prevPathname.current = currentLocation.pathname;
|
|
205
221
|
}, [setNextLocationRef]);
|
|
206
222
|
return {
|
|
@@ -265,6 +281,63 @@ var useLoader = (routeList) => {
|
|
|
265
281
|
};
|
|
266
282
|
};
|
|
267
283
|
//#endregion
|
|
284
|
+
//#region hooks/useApplyCustomAnimation.ts
|
|
285
|
+
var useApplyCustomAnimation = (animationOptions) => {
|
|
286
|
+
useEffect(() => {
|
|
287
|
+
if (!animationOptions?.duration) return;
|
|
288
|
+
const style = document.createElement("style");
|
|
289
|
+
style.id = "dynamic-view-transition-duration-style";
|
|
290
|
+
style.textContent = `::view-transition-group(root) { animation-duration: ${animationOptions.duration}ms; }`;
|
|
291
|
+
document.head.appendChild(style);
|
|
292
|
+
return () => style.remove();
|
|
293
|
+
}, [animationOptions]);
|
|
294
|
+
useEffect(() => {
|
|
295
|
+
if (!animationOptions.name) return;
|
|
296
|
+
const style = document.createElement("style");
|
|
297
|
+
style.id = "dynamic-view-transition-duration-name";
|
|
298
|
+
style.textContent = `
|
|
299
|
+
@keyframes fade-out {
|
|
300
|
+
from { opacity: 1; }
|
|
301
|
+
to { opacity: 0; }
|
|
302
|
+
}
|
|
303
|
+
@keyframes fade-in {
|
|
304
|
+
from { opacity: 0; }
|
|
305
|
+
to { opacity: 1; }
|
|
306
|
+
}
|
|
307
|
+
@keyframes slide-left-out {
|
|
308
|
+
from { transform: translateX(0); }
|
|
309
|
+
to { transform: translateX(-100%); }
|
|
310
|
+
}
|
|
311
|
+
@keyframes slide-left-in {
|
|
312
|
+
from { transform: translateX(100%); }
|
|
313
|
+
to { transform: translateX(0); }
|
|
314
|
+
}
|
|
315
|
+
@keyframes slide-right-out {
|
|
316
|
+
from { transform: translateX(0); }
|
|
317
|
+
to { transform: translateX(100%); }
|
|
318
|
+
}
|
|
319
|
+
@keyframes slide-right-in {
|
|
320
|
+
from { transform: translateX(-100%); }
|
|
321
|
+
to { transform: translateX(0); }
|
|
322
|
+
}
|
|
323
|
+
::view-transition-old(root) {
|
|
324
|
+
animation: ${animationOptions.name}-out ${animationOptions.duration ?? 800}ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
325
|
+
}
|
|
326
|
+
::view-transition-new(root) {
|
|
327
|
+
animation: ${animationOptions.name}-in ${animationOptions.duration ?? 800}ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
328
|
+
}`;
|
|
329
|
+
document.head.appendChild(style);
|
|
330
|
+
return () => style.remove();
|
|
331
|
+
}, [animationOptions]);
|
|
332
|
+
};
|
|
333
|
+
var Spinner_module_default = {
|
|
334
|
+
spinner: "_spinner_1tekw_1",
|
|
335
|
+
rotation: "_rotation_1tekw_1"
|
|
336
|
+
};
|
|
337
|
+
//#endregion
|
|
338
|
+
//#region components/Spinner/Spinner.tsx
|
|
339
|
+
var Spinner = () => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: Spinner_module_default.spinner });
|
|
340
|
+
//#endregion
|
|
268
341
|
//#region utils/renderElement.tsx
|
|
269
342
|
var renderElement = (Component) => {
|
|
270
343
|
if (!Component) return null;
|
|
@@ -274,16 +347,18 @@ var renderElement = (Component) => {
|
|
|
274
347
|
//#region components/Router.tsx
|
|
275
348
|
var PAGE_NOT_FOUND = "error 404. Page not found";
|
|
276
349
|
var ALL_LOCATIONS = "*";
|
|
277
|
-
var Router = ({ routeList, context: initialContext = {} }) => {
|
|
350
|
+
var Router = ({ routeList, context: initialContext = {}, isAnimated = false, animationOptions = {} }) => {
|
|
278
351
|
const [location, setLocation] = useState(parseWindowLocation(window.location));
|
|
279
352
|
const [context, setContext] = useState(initialContext);
|
|
353
|
+
useApplyCustomAnimation(animationOptions);
|
|
280
354
|
const routeItem = useMemo(() => routeList.find((el) => el.path === ALL_LOCATIONS || comparePaths(el, location.pathname)), [location.pathname, routeList]);
|
|
281
355
|
const { loaderError, loaderCache, prefetchLoader, revalidateCache, isLoading } = useLoader(routeList);
|
|
282
356
|
const { blockerState, updateLocation, updateBlockedRoute } = useHandleNavigation({
|
|
283
357
|
setLocation,
|
|
284
358
|
routeList,
|
|
285
359
|
context,
|
|
286
|
-
revalidateCache
|
|
360
|
+
revalidateCache,
|
|
361
|
+
isAnimated
|
|
287
362
|
});
|
|
288
363
|
const params = useMemo(() => routeItem?.params ? getParamsObject(routeItem.params) : {}, [routeItem]);
|
|
289
364
|
const providerProps = useMemo(() => ({
|
|
@@ -306,7 +381,7 @@ var Router = ({ routeList, context: initialContext = {} }) => {
|
|
|
306
381
|
updateBlockedRoute,
|
|
307
382
|
updateLocation
|
|
308
383
|
]);
|
|
309
|
-
if (routeItem?.loader && !loaderError && isLoading) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RouterProvider, {
|
|
384
|
+
if (!isAnimated && routeItem?.loader && !loaderError && isLoading) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RouterProvider, {
|
|
310
385
|
...providerProps,
|
|
311
386
|
children: renderElement(routeItem?.loaderFallback)
|
|
312
387
|
});
|
|
@@ -314,9 +389,9 @@ var Router = ({ routeList, context: initialContext = {} }) => {
|
|
|
314
389
|
...providerProps,
|
|
315
390
|
children: renderElement(routeItem?.errorElement)
|
|
316
391
|
});
|
|
317
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.
|
|
392
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(RouterProvider, {
|
|
318
393
|
...providerProps,
|
|
319
|
-
children: renderElement(routeItem?.element) || PAGE_NOT_FOUND
|
|
394
|
+
children: [renderElement(routeItem?.element) || PAGE_NOT_FOUND, isAnimated && isLoading && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Spinner, {})]
|
|
320
395
|
});
|
|
321
396
|
};
|
|
322
397
|
//#endregion
|
|
@@ -415,55 +490,4 @@ var useRouterContext = () => {
|
|
|
415
490
|
};
|
|
416
491
|
};
|
|
417
492
|
//#endregion
|
|
418
|
-
|
|
419
|
-
function _typeof(o) {
|
|
420
|
-
"@babel/helpers - typeof";
|
|
421
|
-
return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(o) {
|
|
422
|
-
return typeof o;
|
|
423
|
-
} : function(o) {
|
|
424
|
-
return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
|
|
425
|
-
}, _typeof(o);
|
|
426
|
-
}
|
|
427
|
-
//#endregion
|
|
428
|
-
//#region \0@oxc-project+runtime@0.132.0/helpers/toPrimitive.js
|
|
429
|
-
function toPrimitive(t, r) {
|
|
430
|
-
if ("object" != _typeof(t) || !t) return t;
|
|
431
|
-
var e = t[Symbol.toPrimitive];
|
|
432
|
-
if (void 0 !== e) {
|
|
433
|
-
var i = e.call(t, r || "default");
|
|
434
|
-
if ("object" != _typeof(i)) return i;
|
|
435
|
-
throw new TypeError("@@toPrimitive must return a primitive value.");
|
|
436
|
-
}
|
|
437
|
-
return ("string" === r ? String : Number)(t);
|
|
438
|
-
}
|
|
439
|
-
//#endregion
|
|
440
|
-
//#region \0@oxc-project+runtime@0.132.0/helpers/toPropertyKey.js
|
|
441
|
-
function toPropertyKey(t) {
|
|
442
|
-
var i = toPrimitive(t, "string");
|
|
443
|
-
return "symbol" == _typeof(i) ? i : i + "";
|
|
444
|
-
}
|
|
445
|
-
//#endregion
|
|
446
|
-
//#region \0@oxc-project+runtime@0.132.0/helpers/defineProperty.js
|
|
447
|
-
function _defineProperty(e, r, t) {
|
|
448
|
-
return (r = toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
|
|
449
|
-
value: t,
|
|
450
|
-
enumerable: !0,
|
|
451
|
-
configurable: !0,
|
|
452
|
-
writable: !0
|
|
453
|
-
}) : e[r] = t, e;
|
|
454
|
-
}
|
|
455
|
-
//#endregion
|
|
456
|
-
//#region utils/redirect.ts
|
|
457
|
-
var Redirect = class {
|
|
458
|
-
constructor(url, search) {
|
|
459
|
-
_defineProperty(this, "url", void 0);
|
|
460
|
-
_defineProperty(this, "search", void 0);
|
|
461
|
-
_defineProperty(this, "cause", void 0);
|
|
462
|
-
this.url = url;
|
|
463
|
-
this.search = search;
|
|
464
|
-
this.cause = "redirect";
|
|
465
|
-
}
|
|
466
|
-
};
|
|
467
|
-
var redirect = (url, search) => Promise.reject(new Redirect(url, search));
|
|
468
|
-
//#endregion
|
|
469
|
-
export { Link, Router, createRouter, redirect, useBeforeUnload, useBlocker, useLoaderState, useLocation, useNavigate, useParams, useRouterContext };
|
|
493
|
+
export { Link, Router, createRouter, useBeforeUnload, useBlocker, useLoaderState, useLocation, useNavigate, useParams, useRouterContext };
|
package/dist/types/global.d.ts
CHANGED
|
@@ -11,7 +11,10 @@ export type ClientRouteItem = {
|
|
|
11
11
|
fallback?: (() => ReactElement) | ReactElement;
|
|
12
12
|
children?: ClientRouteItem[];
|
|
13
13
|
staleTime?: number;
|
|
14
|
-
beforeLoad?: (
|
|
14
|
+
beforeLoad?: (arg: {
|
|
15
|
+
context: Record<string, unknown>;
|
|
16
|
+
redirect: (arg: Location) => Promise<void>;
|
|
17
|
+
}) => Promise<unknown> | undefined;
|
|
15
18
|
afterLoad?: (context: Record<string, unknown>) => Promise<unknown> | undefined;
|
|
16
19
|
};
|
|
17
20
|
export type RouteItem = ClientRouteItem & {
|
|
@@ -32,3 +35,7 @@ export type UpdateBlockedRouteProps = {
|
|
|
32
35
|
type: 'process' | 'reset' | 'charge' | 'unblock';
|
|
33
36
|
payload?: string;
|
|
34
37
|
};
|
|
38
|
+
export type AnimationOptions = {
|
|
39
|
+
duration?: number;
|
|
40
|
+
name?: 'fade' | 'slide-left' | 'slide-right';
|
|
41
|
+
};
|
package/package.json
CHANGED