@esmx/router-react 3.0.0-rc.105
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 +515 -0
- package/dist/context.d.ts +85 -0
- package/dist/context.mjs +23 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.mjs +11 -0
- package/dist/index.test.d.ts +1 -0
- package/dist/index.test.mjs +169 -0
- package/dist/router-link.d.ts +35 -0
- package/dist/router-link.mjs +85 -0
- package/dist/router-provider.d.ts +61 -0
- package/dist/router-provider.mjs +34 -0
- package/dist/router-view.d.ts +63 -0
- package/dist/router-view.mjs +40 -0
- package/dist/types.d.ts +27 -0
- package/dist/types.mjs +0 -0
- package/dist/use-link.d.ts +97 -0
- package/dist/use-link.mjs +40 -0
- package/dist/util.d.ts +13 -0
- package/dist/util.mjs +15 -0
- package/package.json +85 -0
- package/src/context.ts +109 -0
- package/src/index.test.ts +215 -0
- package/src/index.ts +21 -0
- package/src/router-link.ts +222 -0
- package/src/router-provider.ts +104 -0
- package/src/router-view.ts +113 -0
- package/src/types.ts +30 -0
- package/src/use-link.ts +138 -0
- package/src/util.ts +38 -0
package/README.md
ADDED
|
@@ -0,0 +1,515 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
<img src="https://esmx.dev/logo.svg?t=2025" width="120" alt="Esmx Logo" />
|
|
3
|
+
<h1>@esmx/router-react</h1>
|
|
4
|
+
|
|
5
|
+
<div>
|
|
6
|
+
<a href="https://www.npmjs.com/package/@esmx/router-react">
|
|
7
|
+
<img src="https://img.shields.io/npm/v/@esmx/router-react.svg" alt="npm version" />
|
|
8
|
+
</a>
|
|
9
|
+
<a href="https://github.com/esmnext/esmx/actions/workflows/build.yml">
|
|
10
|
+
<img src="https://github.com/esmnext/esmx/actions/workflows/build.yml/badge.svg" alt="Build" />
|
|
11
|
+
</a>
|
|
12
|
+
<a href="https://esmx.dev/coverage/">
|
|
13
|
+
<img src="https://img.shields.io/badge/coverage-live%20report-brightgreen" alt="Coverage Report" />
|
|
14
|
+
</a>
|
|
15
|
+
<a href="https://nodejs.org/">
|
|
16
|
+
<img src="https://img.shields.io/node/v/@esmx/router-react.svg" alt="node version" />
|
|
17
|
+
</a>
|
|
18
|
+
<a href="https://bundlephobia.com/package/@esmx/router-react">
|
|
19
|
+
<img src="https://img.shields.io/bundlephobia/minzip/@esmx/router-react" alt="size" />
|
|
20
|
+
</a>
|
|
21
|
+
</div>
|
|
22
|
+
|
|
23
|
+
<p>React integration for <a href="https://github.com/esmnext/esmx/tree/master/packages/router">@esmx/router</a> - A powerful router with React 18+ support using modern hooks and context patterns.</p>
|
|
24
|
+
|
|
25
|
+
<p>
|
|
26
|
+
English | <a href="https://github.com/esmnext/esmx/blob/master/packages/router-react/README.zh-CN.md">δΈζ</a>
|
|
27
|
+
</p>
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
## π Features
|
|
31
|
+
|
|
32
|
+
β¨ **React 18+ Support** - Built for React 18 and 19 with hooks and concurrent features
|
|
33
|
+
π― **Hooks First** - Modern hook-based API with `useRouter`, `useRoute`, `useLink`
|
|
34
|
+
π **Seamless Integration** - Works with @esmx/router core
|
|
35
|
+
π **TypeScript Ready** - Full TypeScript support with excellent DX
|
|
36
|
+
β‘ **High Performance** - Uses `useSyncExternalStore` for optimal re-renders
|
|
37
|
+
π **SSR Compatible** - Server-side rendering support out of the box
|
|
38
|
+
π¦ **Lightweight** - Minimal bundle size with zero dependencies (except peer deps)
|
|
39
|
+
π§ **Pure TypeScript** - No JSX required, uses React.createElement for maximum compatibility
|
|
40
|
+
|
|
41
|
+
## π¦ Installation
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
# npm
|
|
45
|
+
npm install @esmx/router @esmx/router-react
|
|
46
|
+
|
|
47
|
+
# pnpm
|
|
48
|
+
pnpm add @esmx/router @esmx/router-react
|
|
49
|
+
|
|
50
|
+
# yarn
|
|
51
|
+
yarn add @esmx/router @esmx/router-react
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## π Quick Start
|
|
55
|
+
|
|
56
|
+
```tsx
|
|
57
|
+
import { Router, RouterMode } from '@esmx/router';
|
|
58
|
+
import { RouterProvider, RouterView, RouterLink } from '@esmx/router-react';
|
|
59
|
+
|
|
60
|
+
// Define your routes
|
|
61
|
+
const routes = [
|
|
62
|
+
{ path: '/', component: () => import('./views/Home') },
|
|
63
|
+
{ path: '/about', component: () => import('./views/About') },
|
|
64
|
+
{ path: '/users/:id', component: () => import('./views/UserProfile') }
|
|
65
|
+
];
|
|
66
|
+
|
|
67
|
+
// Create router instance
|
|
68
|
+
const router = new Router({
|
|
69
|
+
routes,
|
|
70
|
+
mode: RouterMode.history
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
// Wrap your app with RouterProvider
|
|
74
|
+
function App() {
|
|
75
|
+
return (
|
|
76
|
+
<RouterProvider router={router}>
|
|
77
|
+
<nav>
|
|
78
|
+
<RouterLink to="/">Home</RouterLink>
|
|
79
|
+
<RouterLink to="/about">About</RouterLink>
|
|
80
|
+
<RouterLink to="/users/123">User Profile</RouterLink>
|
|
81
|
+
</nav>
|
|
82
|
+
|
|
83
|
+
<RouterView />
|
|
84
|
+
</RouterProvider>
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export default App;
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## π API Reference
|
|
92
|
+
|
|
93
|
+
### Components
|
|
94
|
+
|
|
95
|
+
#### RouterProvider
|
|
96
|
+
|
|
97
|
+
Provides router context to the React component tree. Must wrap your application.
|
|
98
|
+
|
|
99
|
+
```tsx
|
|
100
|
+
import { Router } from '@esmx/router';
|
|
101
|
+
import { RouterProvider } from '@esmx/router-react';
|
|
102
|
+
|
|
103
|
+
const router = new Router({ routes });
|
|
104
|
+
|
|
105
|
+
function App() {
|
|
106
|
+
return (
|
|
107
|
+
<RouterProvider router={router}>
|
|
108
|
+
{/* Your app components */}
|
|
109
|
+
</RouterProvider>
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
**Props:**
|
|
115
|
+
|
|
116
|
+
| Prop | Type | Required | Description |
|
|
117
|
+
|------|------|----------|-------------|
|
|
118
|
+
| `router` | `Router` | Yes | Router instance from @esmx/router |
|
|
119
|
+
| `children` | `ReactNode` | Yes | Child components |
|
|
120
|
+
|
|
121
|
+
#### RouterView
|
|
122
|
+
|
|
123
|
+
Renders the matched route component. Supports nested routing with automatic depth tracking.
|
|
124
|
+
|
|
125
|
+
```tsx
|
|
126
|
+
import { RouterView } from '@esmx/router-react';
|
|
127
|
+
|
|
128
|
+
function Layout() {
|
|
129
|
+
return (
|
|
130
|
+
<div>
|
|
131
|
+
<header>My App</header>
|
|
132
|
+
<RouterView />
|
|
133
|
+
<footer>Footer</footer>
|
|
134
|
+
</div>
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
**Props:**
|
|
140
|
+
|
|
141
|
+
| Prop | Type | Default | Description |
|
|
142
|
+
|------|------|---------|-------------|
|
|
143
|
+
| `fallback` | `ReactNode \| ComponentType` | - | Fallback content when no route matches |
|
|
144
|
+
|
|
145
|
+
**Nested Routing Example:**
|
|
146
|
+
|
|
147
|
+
```tsx
|
|
148
|
+
// Routes configuration
|
|
149
|
+
const routes = [
|
|
150
|
+
{
|
|
151
|
+
path: '/users',
|
|
152
|
+
component: UsersLayout,
|
|
153
|
+
children: [
|
|
154
|
+
{ path: '', component: UsersList },
|
|
155
|
+
{ path: ':id', component: UserProfile }
|
|
156
|
+
]
|
|
157
|
+
}
|
|
158
|
+
];
|
|
159
|
+
|
|
160
|
+
// UsersLayout.tsx - Contains nested RouterView
|
|
161
|
+
function UsersLayout() {
|
|
162
|
+
return (
|
|
163
|
+
<div>
|
|
164
|
+
<h1>Users Section</h1>
|
|
165
|
+
<RouterView /> {/* Renders UsersList or UserProfile */}
|
|
166
|
+
</div>
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
#### RouterLink
|
|
172
|
+
|
|
173
|
+
A component for creating navigation links with active state management.
|
|
174
|
+
|
|
175
|
+
```tsx
|
|
176
|
+
import { RouterLink } from '@esmx/router-react';
|
|
177
|
+
|
|
178
|
+
function Navigation() {
|
|
179
|
+
return (
|
|
180
|
+
<nav>
|
|
181
|
+
{/* Basic link */}
|
|
182
|
+
<RouterLink to="/home">Home</RouterLink>
|
|
183
|
+
|
|
184
|
+
{/* With object location */}
|
|
185
|
+
<RouterLink to={{ path: '/search', query: { q: 'react' } }}>
|
|
186
|
+
Search
|
|
187
|
+
</RouterLink>
|
|
188
|
+
|
|
189
|
+
{/* Replace navigation */}
|
|
190
|
+
<RouterLink to="/login" type="replace">Login</RouterLink>
|
|
191
|
+
|
|
192
|
+
{/* Open in new window */}
|
|
193
|
+
<RouterLink to="/docs" type="pushWindow">Docs β</RouterLink>
|
|
194
|
+
|
|
195
|
+
{/* Custom active class */}
|
|
196
|
+
<RouterLink
|
|
197
|
+
to="/dashboard"
|
|
198
|
+
activeClass="nav-active"
|
|
199
|
+
exact="exact"
|
|
200
|
+
>
|
|
201
|
+
Dashboard
|
|
202
|
+
</RouterLink>
|
|
203
|
+
|
|
204
|
+
{/* Custom tag */}
|
|
205
|
+
<RouterLink to="/submit" tag="button" className="btn">
|
|
206
|
+
Submit
|
|
207
|
+
</RouterLink>
|
|
208
|
+
</nav>
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
**Props:**
|
|
214
|
+
|
|
215
|
+
| Prop | Type | Default | Description |
|
|
216
|
+
|------|------|---------|-------------|
|
|
217
|
+
| `to` | `string \| RouteLocationInput` | - | Target route location |
|
|
218
|
+
| `type` | `RouterLinkType` | `'push'` | Navigation type |
|
|
219
|
+
| `exact` | `RouteMatchType` | `'include'` | Active matching mode |
|
|
220
|
+
| `activeClass` | `string` | - | CSS class for active state |
|
|
221
|
+
| `event` | `string \| string[]` | `'click'` | Events triggering navigation |
|
|
222
|
+
| `tag` | `string` | `'a'` | HTML tag to render |
|
|
223
|
+
| `layerOptions` | `RouterLayerOptions` | - | Layer navigation options |
|
|
224
|
+
| `beforeNavigate` | `function` | - | Callback before navigation |
|
|
225
|
+
| `children` | `ReactNode` | - | Link content |
|
|
226
|
+
| `className` | `string` | - | Additional CSS classes |
|
|
227
|
+
| `style` | `CSSProperties` | - | Inline styles |
|
|
228
|
+
|
|
229
|
+
**Navigation Types:**
|
|
230
|
+
|
|
231
|
+
- `'push'` - Add entry to history stack (default)
|
|
232
|
+
- `'replace'` - Replace current history entry
|
|
233
|
+
- `'pushWindow'` - Open in new window/tab
|
|
234
|
+
- `'replaceWindow'` - Replace current window location
|
|
235
|
+
- `'pushLayer'` - Open in layer (modal/dialog routing)
|
|
236
|
+
|
|
237
|
+
### Hooks
|
|
238
|
+
|
|
239
|
+
#### useRouter()
|
|
240
|
+
|
|
241
|
+
Get the router instance for programmatic navigation.
|
|
242
|
+
|
|
243
|
+
```tsx
|
|
244
|
+
import { useRouter } from '@esmx/router-react';
|
|
245
|
+
|
|
246
|
+
function NavigationControls() {
|
|
247
|
+
const router = useRouter();
|
|
248
|
+
|
|
249
|
+
const goHome = () => router.push('/');
|
|
250
|
+
const goBack = () => router.back();
|
|
251
|
+
const goForward = () => router.forward();
|
|
252
|
+
|
|
253
|
+
const goToUser = (id: string) => {
|
|
254
|
+
router.push({
|
|
255
|
+
path: '/users/:id',
|
|
256
|
+
params: { id }
|
|
257
|
+
});
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
const replaceRoute = () => {
|
|
261
|
+
router.replace('/login');
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
return (
|
|
265
|
+
<div>
|
|
266
|
+
<button onClick={goHome}>Home</button>
|
|
267
|
+
<button onClick={goBack}>Back</button>
|
|
268
|
+
<button onClick={goForward}>Forward</button>
|
|
269
|
+
<button onClick={() => goToUser('123')}>User 123</button>
|
|
270
|
+
<button onClick={replaceRoute}>Login (Replace)</button>
|
|
271
|
+
</div>
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
#### useRoute()
|
|
277
|
+
|
|
278
|
+
Get the current route information (reactive).
|
|
279
|
+
|
|
280
|
+
```tsx
|
|
281
|
+
import { useRoute } from '@esmx/router-react';
|
|
282
|
+
import { useEffect } from 'react';
|
|
283
|
+
|
|
284
|
+
function CurrentRoute() {
|
|
285
|
+
const route = useRoute();
|
|
286
|
+
|
|
287
|
+
useEffect(() => {
|
|
288
|
+
console.log('Route changed:', route.path);
|
|
289
|
+
document.title = route.meta?.title || 'My App';
|
|
290
|
+
}, [route.path, route.meta?.title]);
|
|
291
|
+
|
|
292
|
+
return (
|
|
293
|
+
<div>
|
|
294
|
+
<p>Path: {route.path}</p>
|
|
295
|
+
<p>Params: {JSON.stringify(route.params)}</p>
|
|
296
|
+
<p>Query: {JSON.stringify(route.query)}</p>
|
|
297
|
+
<p>Hash: {route.hash}</p>
|
|
298
|
+
<p>Meta: {JSON.stringify(route.meta)}</p>
|
|
299
|
+
</div>
|
|
300
|
+
);
|
|
301
|
+
}
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
#### useLink()
|
|
305
|
+
|
|
306
|
+
Create reactive link helpers for custom navigation components.
|
|
307
|
+
|
|
308
|
+
```tsx
|
|
309
|
+
import { useLink } from '@esmx/router-react';
|
|
310
|
+
|
|
311
|
+
interface CustomNavButtonProps {
|
|
312
|
+
to: string;
|
|
313
|
+
children: React.ReactNode;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
function CustomNavButton({ to, children }: CustomNavButtonProps) {
|
|
317
|
+
const link = useLink({ to, type: 'push', exact: 'include' });
|
|
318
|
+
|
|
319
|
+
return (
|
|
320
|
+
<button
|
|
321
|
+
onClick={(e) => link.navigate(e)}
|
|
322
|
+
className={`nav-button ${link.isActive ? 'active' : ''}`}
|
|
323
|
+
aria-current={link.isExactActive ? 'page' : undefined}
|
|
324
|
+
>
|
|
325
|
+
{children}
|
|
326
|
+
{link.isExternal && <span>β</span>}
|
|
327
|
+
</button>
|
|
328
|
+
);
|
|
329
|
+
}
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
**Return Value (`RouterLinkResolved`):**
|
|
333
|
+
|
|
334
|
+
| Property | Type | Description |
|
|
335
|
+
|----------|------|-------------|
|
|
336
|
+
| `route` | `Route` | Resolved route object |
|
|
337
|
+
| `type` | `RouterLinkType` | Navigation type |
|
|
338
|
+
| `isActive` | `boolean` | Whether link matches current route |
|
|
339
|
+
| `isExactActive` | `boolean` | Whether link exactly matches current route |
|
|
340
|
+
| `isExternal` | `boolean` | Whether link points to external origin |
|
|
341
|
+
| `tag` | `string` | HTML tag to render |
|
|
342
|
+
| `attributes` | `RouterLinkAttributes` | HTML attributes (href, class, target, rel) |
|
|
343
|
+
| `navigate` | `(e: Event) => Promise<void>` | Navigation function |
|
|
344
|
+
| `createEventHandlers` | `function` | Generate event handlers |
|
|
345
|
+
|
|
346
|
+
#### useRouterViewDepth()
|
|
347
|
+
|
|
348
|
+
Get the current RouterView depth (for advanced nested routing scenarios).
|
|
349
|
+
|
|
350
|
+
```tsx
|
|
351
|
+
import { useRouterViewDepth } from '@esmx/router-react';
|
|
352
|
+
|
|
353
|
+
function DebugView() {
|
|
354
|
+
const depth = useRouterViewDepth();
|
|
355
|
+
|
|
356
|
+
return <div>Current depth: {depth}</div>;
|
|
357
|
+
}
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
### Context
|
|
361
|
+
|
|
362
|
+
#### RouterContext
|
|
363
|
+
|
|
364
|
+
Direct access to the router context (for advanced use cases).
|
|
365
|
+
|
|
366
|
+
```tsx
|
|
367
|
+
import { RouterContext } from '@esmx/router-react';
|
|
368
|
+
import { useContext } from 'react';
|
|
369
|
+
|
|
370
|
+
function CustomRouterConsumer() {
|
|
371
|
+
const context = useContext(RouterContext);
|
|
372
|
+
|
|
373
|
+
if (!context) {
|
|
374
|
+
return <div>Not inside RouterProvider</div>;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
const { router, route } = context;
|
|
378
|
+
// Use router and route directly
|
|
379
|
+
}
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
## Advanced Usage
|
|
383
|
+
|
|
384
|
+
### Route Guards
|
|
385
|
+
|
|
386
|
+
```tsx
|
|
387
|
+
import { useRouter, useRoute } from '@esmx/router-react';
|
|
388
|
+
import { useEffect } from 'react';
|
|
389
|
+
|
|
390
|
+
function AuthGuard({ children }: { children: React.ReactNode }) {
|
|
391
|
+
const router = useRouter();
|
|
392
|
+
const route = useRoute();
|
|
393
|
+
|
|
394
|
+
useEffect(() => {
|
|
395
|
+
// Register beforeEach guard
|
|
396
|
+
const unregister = router.beforeEach((to, from) => {
|
|
397
|
+
if (to.meta?.requiresAuth && !isAuthenticated()) {
|
|
398
|
+
return '/login';
|
|
399
|
+
}
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
return () => unregister();
|
|
403
|
+
}, [router]);
|
|
404
|
+
|
|
405
|
+
return <>{children}</>;
|
|
406
|
+
}
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
### SSR Integration
|
|
410
|
+
|
|
411
|
+
```tsx
|
|
412
|
+
import { Router, RouterMode } from '@esmx/router';
|
|
413
|
+
import { RouterProvider, RouterView } from '@esmx/router-react';
|
|
414
|
+
import { renderToString } from 'react-dom/server';
|
|
415
|
+
|
|
416
|
+
async function renderApp(url: string) {
|
|
417
|
+
const router = new Router({
|
|
418
|
+
routes,
|
|
419
|
+
mode: RouterMode.history,
|
|
420
|
+
url // Pass the request URL
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
// Wait for route resolution
|
|
424
|
+
await router.push(url);
|
|
425
|
+
|
|
426
|
+
const html = renderToString(
|
|
427
|
+
<RouterProvider router={router}>
|
|
428
|
+
<App />
|
|
429
|
+
</RouterProvider>
|
|
430
|
+
);
|
|
431
|
+
|
|
432
|
+
return html;
|
|
433
|
+
}
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
### Custom Link Component with Additional Features
|
|
437
|
+
|
|
438
|
+
```tsx
|
|
439
|
+
import { useLink } from '@esmx/router-react';
|
|
440
|
+
import { forwardRef, type AnchorHTMLAttributes } from 'react';
|
|
441
|
+
|
|
442
|
+
interface NavLinkProps extends AnchorHTMLAttributes<HTMLAnchorElement> {
|
|
443
|
+
to: string;
|
|
444
|
+
icon?: React.ReactNode;
|
|
445
|
+
badge?: number;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
export const NavLink = forwardRef<HTMLAnchorElement, NavLinkProps>(
|
|
449
|
+
({ to, icon, badge, children, className, ...props }, ref) => {
|
|
450
|
+
const link = useLink({ to, exact: 'include' });
|
|
451
|
+
|
|
452
|
+
return (
|
|
453
|
+
<a
|
|
454
|
+
ref={ref}
|
|
455
|
+
href={link.attributes.href}
|
|
456
|
+
onClick={(e) => {
|
|
457
|
+
e.preventDefault();
|
|
458
|
+
link.navigate(e);
|
|
459
|
+
}}
|
|
460
|
+
className={`nav-link ${link.isActive ? 'active' : ''} ${className || ''}`}
|
|
461
|
+
aria-current={link.isExactActive ? 'page' : undefined}
|
|
462
|
+
{...props}
|
|
463
|
+
>
|
|
464
|
+
{icon && <span className="nav-icon">{icon}</span>}
|
|
465
|
+
<span className="nav-label">{children}</span>
|
|
466
|
+
{badge !== undefined && badge > 0 && (
|
|
467
|
+
<span className="nav-badge">{badge}</span>
|
|
468
|
+
)}
|
|
469
|
+
</a>
|
|
470
|
+
);
|
|
471
|
+
}
|
|
472
|
+
);
|
|
473
|
+
|
|
474
|
+
NavLink.displayName = 'NavLink';
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
## TypeScript Support
|
|
478
|
+
|
|
479
|
+
This package provides full TypeScript support. All types are exported and properly documented.
|
|
480
|
+
|
|
481
|
+
```tsx
|
|
482
|
+
import type {
|
|
483
|
+
RouterContextValue,
|
|
484
|
+
RouterProviderProps,
|
|
485
|
+
RouterViewProps,
|
|
486
|
+
RouterLinkComponentProps
|
|
487
|
+
} from '@esmx/router-react';
|
|
488
|
+
|
|
489
|
+
import type {
|
|
490
|
+
Route,
|
|
491
|
+
Router,
|
|
492
|
+
RouterLinkProps,
|
|
493
|
+
RouterLinkResolved,
|
|
494
|
+
RouteLocationInput
|
|
495
|
+
} from '@esmx/router';
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
## Browser Support
|
|
499
|
+
|
|
500
|
+
- **Modern browsers** that support ES modules (`import`/`export`) and React 18+
|
|
501
|
+
- Chrome 64+, Firefox 67+, Safari 11.1+, Edge 79+
|
|
502
|
+
|
|
503
|
+
## Contributing
|
|
504
|
+
|
|
505
|
+
We welcome contributions! Please feel free to submit issues and pull requests.
|
|
506
|
+
|
|
507
|
+
## π License
|
|
508
|
+
|
|
509
|
+
MIT Β© [Esmx Team](https://github.com/esmnext/esmx)
|
|
510
|
+
|
|
511
|
+
## Related Packages
|
|
512
|
+
|
|
513
|
+
- [@esmx/router](https://github.com/esmnext/esmx/tree/master/packages/router) - Core router package
|
|
514
|
+
- [@esmx/router-vue](https://github.com/esmnext/esmx/tree/master/packages/router-vue) - Vue integration
|
|
515
|
+
- [@esmx/core](https://github.com/esmnext/esmx/tree/master/packages/core) - Esmx core framework
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import type { Route, Router } from '@esmx/router';
|
|
2
|
+
import type { RouterContextValue } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* React Context for router state.
|
|
5
|
+
* Contains the router instance and current route.
|
|
6
|
+
* Using null as default to detect missing provider.
|
|
7
|
+
*/
|
|
8
|
+
export declare const RouterContext: import("react").Context<RouterContextValue | null>;
|
|
9
|
+
/**
|
|
10
|
+
* React Context for RouterView depth tracking.
|
|
11
|
+
* Used for nested routing to determine which matched route to render.
|
|
12
|
+
*/
|
|
13
|
+
export declare const RouterViewDepthContext: import("react").Context<number>;
|
|
14
|
+
/**
|
|
15
|
+
* Get the router context value.
|
|
16
|
+
* @throws {Error} If used outside of RouterProvider
|
|
17
|
+
* @internal
|
|
18
|
+
*/
|
|
19
|
+
export declare function useRouterContext(): RouterContextValue;
|
|
20
|
+
/**
|
|
21
|
+
* Get the router instance for navigation.
|
|
22
|
+
* Must be used within a RouterProvider.
|
|
23
|
+
*
|
|
24
|
+
* @returns Router instance with navigation methods
|
|
25
|
+
* @throws {Error} If used outside of RouterProvider
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```tsx
|
|
29
|
+
* import { useRouter } from '@esmx/router-react';
|
|
30
|
+
*
|
|
31
|
+
* function NavigationButton() {
|
|
32
|
+
* const router = useRouter();
|
|
33
|
+
*
|
|
34
|
+
* const handleClick = () => {
|
|
35
|
+
* router.push('/dashboard');
|
|
36
|
+
* };
|
|
37
|
+
*
|
|
38
|
+
* return <button onClick={handleClick}>Go to Dashboard</button>;
|
|
39
|
+
* }
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
export declare function useRouter(): Router;
|
|
43
|
+
/**
|
|
44
|
+
* Get the current route information.
|
|
45
|
+
* Returns a reactive route object that updates when navigation occurs.
|
|
46
|
+
* Must be used within a RouterProvider.
|
|
47
|
+
*
|
|
48
|
+
* @returns Current route object with path, params, query, etc.
|
|
49
|
+
* @throws {Error} If used outside of RouterProvider
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```tsx
|
|
53
|
+
* import { useRoute } from '@esmx/router-react';
|
|
54
|
+
*
|
|
55
|
+
* function CurrentPath() {
|
|
56
|
+
* const route = useRoute();
|
|
57
|
+
*
|
|
58
|
+
* return (
|
|
59
|
+
* <div>
|
|
60
|
+
* <p>Path: {route.path}</p>
|
|
61
|
+
* <p>Params: {JSON.stringify(route.params)}</p>
|
|
62
|
+
* <p>Query: {JSON.stringify(route.query)}</p>
|
|
63
|
+
* </div>
|
|
64
|
+
* );
|
|
65
|
+
* }
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
export declare function useRoute(): Route;
|
|
69
|
+
/**
|
|
70
|
+
* Get the current RouterView depth.
|
|
71
|
+
* Used internally by RouterView for nested routing.
|
|
72
|
+
*
|
|
73
|
+
* @returns Current depth level (0 for root, 1 for first nested, etc.)
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* ```tsx
|
|
77
|
+
* import { useRouterViewDepth } from '@esmx/router-react';
|
|
78
|
+
*
|
|
79
|
+
* function DebugView() {
|
|
80
|
+
* const depth = useRouterViewDepth();
|
|
81
|
+
* return <div>Current depth: {depth}</div>;
|
|
82
|
+
* }
|
|
83
|
+
* ```
|
|
84
|
+
*/
|
|
85
|
+
export declare function useRouterViewDepth(): number;
|
package/dist/context.mjs
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { createContext, useContext } from "react";
|
|
2
|
+
export const RouterContext = createContext(null);
|
|
3
|
+
RouterContext.displayName = "RouterContext";
|
|
4
|
+
export const RouterViewDepthContext = createContext(0);
|
|
5
|
+
RouterViewDepthContext.displayName = "RouterViewDepthContext";
|
|
6
|
+
export function useRouterContext() {
|
|
7
|
+
const context = useContext(RouterContext);
|
|
8
|
+
if (!context) {
|
|
9
|
+
throw new Error(
|
|
10
|
+
"[@esmx/router-react] Router context not found. Please ensure your component is wrapped in a RouterProvider."
|
|
11
|
+
);
|
|
12
|
+
}
|
|
13
|
+
return context;
|
|
14
|
+
}
|
|
15
|
+
export function useRouter() {
|
|
16
|
+
return useRouterContext().router;
|
|
17
|
+
}
|
|
18
|
+
export function useRoute() {
|
|
19
|
+
return useRouterContext().route;
|
|
20
|
+
}
|
|
21
|
+
export function useRouterViewDepth() {
|
|
22
|
+
return useContext(RouterViewDepthContext);
|
|
23
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { RouterContext, RouterViewDepthContext, useRoute, useRouter, useRouterViewDepth } from './context';
|
|
2
|
+
export type { RouterLinkComponentProps } from './router-link';
|
|
3
|
+
export { RouterLink } from './router-link';
|
|
4
|
+
export { RouterProvider } from './router-provider';
|
|
5
|
+
export { RouterView } from './router-view';
|
|
6
|
+
export type { RouterContextValue, RouterProviderProps, RouterViewProps } from './types';
|
|
7
|
+
export { useLink } from './use-link';
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export {
|
|
2
|
+
RouterContext,
|
|
3
|
+
RouterViewDepthContext,
|
|
4
|
+
useRoute,
|
|
5
|
+
useRouter,
|
|
6
|
+
useRouterViewDepth
|
|
7
|
+
} from "./context.mjs";
|
|
8
|
+
export { RouterLink } from "./router-link.mjs";
|
|
9
|
+
export { RouterProvider } from "./router-provider.mjs";
|
|
10
|
+
export { RouterView } from "./router-view.mjs";
|
|
11
|
+
export { useLink } from "./use-link.mjs";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|