router-kit 1.3.3 → 2.0.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 +123 -373
- package/dist/components/Link.d.ts +23 -6
- package/dist/components/Link.js +51 -6
- package/dist/components/NavLink.d.ts +44 -7
- package/dist/components/NavLink.js +111 -10
- package/dist/components/Outlet.d.ts +66 -0
- package/dist/components/Outlet.js +69 -0
- package/dist/components/Router.d.ts +69 -0
- package/dist/components/Router.js +109 -0
- package/dist/components/route.d.ts +77 -0
- package/dist/components/route.js +51 -0
- package/dist/context/OutletContext.d.ts +41 -0
- package/dist/context/OutletContext.js +31 -0
- package/dist/context/RouterContext.d.ts +9 -0
- package/dist/context/RouterContext.js +21 -1
- package/dist/context/RouterProvider.d.ts +15 -4
- package/dist/context/RouterProvider.js +321 -84
- package/dist/core/createRouter.d.ts +65 -0
- package/dist/core/createRouter.js +126 -7
- package/dist/hooks/useBlocker.d.ts +65 -0
- package/dist/hooks/useBlocker.js +152 -0
- package/dist/hooks/useDynamicComponents.d.ts +61 -2
- package/dist/hooks/useDynamicComponents.js +89 -17
- package/dist/hooks/useLoaderData.d.ts +98 -0
- package/dist/hooks/useLoaderData.js +107 -0
- package/dist/hooks/useLocation.d.ts +37 -0
- package/dist/hooks/useLocation.js +106 -1
- package/dist/hooks/useMatches.d.ts +99 -0
- package/dist/hooks/useMatches.js +114 -0
- package/dist/hooks/useNavigate.d.ts +59 -0
- package/dist/hooks/useNavigate.js +70 -0
- package/dist/hooks/useParams.d.ts +57 -2
- package/dist/hooks/useParams.js +60 -14
- package/dist/hooks/useQuery.d.ts +53 -3
- package/dist/hooks/useQuery.js +107 -8
- package/dist/hooks/useRouter.d.ts +34 -0
- package/dist/hooks/useRouter.js +35 -1
- package/dist/index.d.ts +19 -5
- package/dist/index.js +23 -4
- package/dist/ssr/StaticRouter.d.ts +65 -0
- package/dist/ssr/StaticRouter.js +292 -0
- package/dist/ssr/hydrateRouter.d.ts +44 -0
- package/dist/ssr/hydrateRouter.js +60 -0
- package/dist/ssr/index.d.ts +92 -0
- package/dist/ssr/index.js +92 -0
- package/dist/ssr/serverUtils.d.ts +107 -0
- package/dist/ssr/serverUtils.js +263 -0
- package/dist/types/index.d.ts +201 -2
- package/package.json +14 -2
package/README.md
CHANGED
|
@@ -1,459 +1,209 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Router-Kit
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A professional React routing library with guards, loaders, and navigation blocking.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
**Version:** 2.0.0 | **License:** MIT
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
9
|
-
##
|
|
9
|
+
## ✨ Features
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
- **
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
- **
|
|
19
|
-
|
|
20
|
-
### For Developers
|
|
21
|
-
|
|
22
|
-
- **[Architecture](./ARCHITECTURE.md)** - Internal implementation details
|
|
23
|
-
- **[Contributing Guide](#contributing)** - How to contribute to Router-Kit
|
|
11
|
+
- 🛡️ **Route Guards** - Authentication & authorization
|
|
12
|
+
- 📦 **Data Loaders** - Pre-fetch route data
|
|
13
|
+
- 🚫 **Navigation Blocking** - Protect unsaved changes
|
|
14
|
+
- 📜 **Scroll Restoration** - Auto scroll management
|
|
15
|
+
- ⚡ **Lazy Loading** - Code splitting support
|
|
16
|
+
- 🎯 **TypeScript** - Full type safety
|
|
17
|
+
- 🎭 **Outlet** - Professional nested layouts
|
|
18
|
+
- 🪝 **10 Hooks** - Complete routing control
|
|
24
19
|
|
|
25
20
|
---
|
|
26
21
|
|
|
27
|
-
##
|
|
28
|
-
|
|
29
|
-
### Installation
|
|
22
|
+
## 📦 Installation
|
|
30
23
|
|
|
31
24
|
```bash
|
|
32
25
|
npm install router-kit
|
|
33
26
|
```
|
|
34
27
|
|
|
35
|
-
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## 🚀 Quick Start
|
|
31
|
+
|
|
32
|
+
### Programmatic Approach
|
|
36
33
|
|
|
37
34
|
```tsx
|
|
38
|
-
import
|
|
39
|
-
|
|
35
|
+
import {
|
|
36
|
+
createRouter,
|
|
37
|
+
RouterProvider,
|
|
38
|
+
Link,
|
|
39
|
+
useNavigate,
|
|
40
|
+
useParams,
|
|
41
|
+
} from "router-kit";
|
|
40
42
|
|
|
41
|
-
|
|
42
|
-
const
|
|
43
|
-
const
|
|
43
|
+
const Home = () => <h1>Home</h1>;
|
|
44
|
+
const User = () => {
|
|
45
|
+
const { id } = useParams();
|
|
46
|
+
return <h1>User {id}</h1>;
|
|
47
|
+
};
|
|
44
48
|
|
|
45
|
-
// 2. Create routes
|
|
46
49
|
const routes = createRouter([
|
|
47
|
-
{ path: "/", component: <Home
|
|
48
|
-
{ path: "
|
|
50
|
+
{ path: "/", component: <Home />, meta: { title: "Home" } },
|
|
51
|
+
{ path: "users/:id", component: <User /> },
|
|
52
|
+
{ path: "/404", component: <h1>Not Found</h1> },
|
|
49
53
|
]);
|
|
50
54
|
|
|
51
|
-
// 3. Wrap your app with RouterProvider
|
|
52
55
|
function App() {
|
|
53
56
|
return <RouterProvider routes={routes} />;
|
|
54
57
|
}
|
|
55
|
-
|
|
56
|
-
export default App;
|
|
57
58
|
```
|
|
58
59
|
|
|
59
|
-
###
|
|
60
|
+
### Declarative Approach
|
|
60
61
|
|
|
61
62
|
```tsx
|
|
62
|
-
import {
|
|
63
|
+
import { Router, Route, Link } from "router-kit";
|
|
63
64
|
|
|
64
|
-
function
|
|
65
|
+
function App() {
|
|
65
66
|
return (
|
|
66
|
-
<
|
|
67
|
-
<
|
|
68
|
-
<
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
</nav>
|
|
67
|
+
<Router>
|
|
68
|
+
<Route path="/" component={<Home />} />
|
|
69
|
+
<Route path="/users/:id" component={<User />} />
|
|
70
|
+
<Route path="/404" component={<NotFound />} />
|
|
71
|
+
</Router>
|
|
72
72
|
);
|
|
73
73
|
}
|
|
74
74
|
```
|
|
75
75
|
|
|
76
|
-
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## 🛡️ Route Guards
|
|
77
79
|
|
|
78
80
|
```tsx
|
|
79
|
-
|
|
81
|
+
const authGuard = async () => {
|
|
82
|
+
const isAuth = await checkAuth();
|
|
83
|
+
return isAuth || { redirect: "/login" };
|
|
84
|
+
};
|
|
80
85
|
|
|
81
|
-
// Route: /users/:id
|
|
82
86
|
const routes = createRouter([
|
|
83
|
-
{
|
|
87
|
+
{
|
|
88
|
+
path: "dashboard",
|
|
89
|
+
component: <Dashboard />,
|
|
90
|
+
guard: authGuard,
|
|
91
|
+
},
|
|
84
92
|
]);
|
|
85
|
-
|
|
86
|
-
function UserProfile() {
|
|
87
|
-
const { id } = useParams();
|
|
88
|
-
return <h1>User {id}</h1>;
|
|
89
|
-
}
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
### Programmatic Navigation
|
|
93
|
-
|
|
94
|
-
```tsx
|
|
95
|
-
import { useRouter } from "router-kit";
|
|
96
|
-
|
|
97
|
-
function LoginForm() {
|
|
98
|
-
const { navigate } = useRouter();
|
|
99
|
-
|
|
100
|
-
const handleLogin = () => {
|
|
101
|
-
// After successful login
|
|
102
|
-
navigate("/dashboard");
|
|
103
|
-
};
|
|
104
|
-
|
|
105
|
-
return <button onClick={handleLogin}>Login</button>;
|
|
106
|
-
}
|
|
107
93
|
```
|
|
108
94
|
|
|
109
95
|
---
|
|
110
96
|
|
|
111
|
-
##
|
|
112
|
-
|
|
113
|
-
### [DOCUMENTATION.md](./DOCUMENTATION.md)
|
|
114
|
-
|
|
115
|
-
**Complete user guide covering:**
|
|
116
|
-
|
|
117
|
-
- Introduction and key features
|
|
118
|
-
- Installation instructions
|
|
119
|
-
- Core concepts explained
|
|
120
|
-
- API reference with examples
|
|
121
|
-
- Advanced usage patterns
|
|
122
|
-
- Error handling strategies
|
|
123
|
-
- TypeScript support
|
|
124
|
-
- Best practices
|
|
125
|
-
- Migration guide from other routers
|
|
126
|
-
- Real-world examples
|
|
127
|
-
|
|
128
|
-
**Best for:** Learning Router-Kit from scratch, understanding concepts, and finding usage examples.
|
|
129
|
-
|
|
130
|
-
### [API_REFERENCE.md](./API_REFERENCE.md)
|
|
131
|
-
|
|
132
|
-
**Comprehensive API documentation including:**
|
|
133
|
-
|
|
134
|
-
- `createRouter()` function
|
|
135
|
-
- `RouterProvider` component
|
|
136
|
-
- `Link` and `NavLink` components
|
|
137
|
-
- `useRouter()` hook
|
|
138
|
-
- `useParams()` hook
|
|
139
|
-
- `useQuery()` hook
|
|
140
|
-
- `useLocation()` hook
|
|
141
|
-
- `useDynamicComponents()` hook
|
|
142
|
-
- Type definitions
|
|
143
|
-
- Error system reference
|
|
144
|
-
|
|
145
|
-
**Best for:** Looking up specific APIs, understanding function signatures, and exploring available options.
|
|
146
|
-
|
|
147
|
-
### [EXAMPLES.md](./EXAMPLES.md)
|
|
148
|
-
|
|
149
|
-
**Practical examples featuring:**
|
|
150
|
-
|
|
151
|
-
- Basic routing examples
|
|
152
|
-
- E-commerce application
|
|
153
|
-
- Blog platform
|
|
154
|
-
- Dashboard application
|
|
155
|
-
- Multi-language website
|
|
156
|
-
- Authentication flow
|
|
157
|
-
- Advanced patterns (lazy loading, modals, breadcrumbs, animations)
|
|
158
|
-
|
|
159
|
-
**Best for:** Finding real-world implementation patterns and copy-paste solutions.
|
|
160
|
-
|
|
161
|
-
### [ARCHITECTURE.md](./ARCHITECTURE.md)
|
|
162
|
-
|
|
163
|
-
**Technical implementation details including:**
|
|
164
|
-
|
|
165
|
-
- System architecture overview
|
|
166
|
-
- Core component implementations
|
|
167
|
-
- Route matching algorithm
|
|
168
|
-
- History management
|
|
169
|
-
- Context system
|
|
170
|
-
- Error handling system
|
|
171
|
-
- Type system
|
|
172
|
-
- Performance considerations
|
|
173
|
-
- Build and distribution
|
|
174
|
-
|
|
175
|
-
**Best for:** Understanding internals, contributing to the project, or debugging complex issues.
|
|
176
|
-
|
|
177
|
-
---
|
|
178
|
-
|
|
179
|
-
## Common Use Cases
|
|
180
|
-
|
|
181
|
-
### Simple Website
|
|
97
|
+
## 📦 Data Loaders
|
|
182
98
|
|
|
183
99
|
```tsx
|
|
184
100
|
const routes = createRouter([
|
|
185
|
-
{
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
101
|
+
{
|
|
102
|
+
path: "users/:id",
|
|
103
|
+
component: <UserProfile />,
|
|
104
|
+
loader: async ({ params }) => {
|
|
105
|
+
return fetch(`/api/users/${params.id}`).then((r) => r.json());
|
|
106
|
+
},
|
|
107
|
+
},
|
|
189
108
|
]);
|
|
109
|
+
|
|
110
|
+
function UserProfile() {
|
|
111
|
+
const user = useLoaderData();
|
|
112
|
+
return <h1>{user.name}</h1>;
|
|
113
|
+
}
|
|
190
114
|
```
|
|
191
115
|
|
|
192
|
-
|
|
116
|
+
---
|
|
193
117
|
|
|
194
|
-
|
|
118
|
+
## 🪝 Hooks
|
|
195
119
|
|
|
196
120
|
```tsx
|
|
197
|
-
const
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
121
|
+
const navigate = useNavigate(); // Navigation
|
|
122
|
+
const { id } = useParams(); // Route params
|
|
123
|
+
const { page } = useQuery(); // Query params
|
|
124
|
+
const location = useLocation(); // Location object
|
|
125
|
+
const matches = useMatches(); // Route matches
|
|
126
|
+
const data = useLoaderData(); // Loader data
|
|
127
|
+
const blocker = useBlocker(isDirty); // Block navigation
|
|
128
|
+
const outlet = useOutlet(); // Child route element
|
|
129
|
+
const ctx = useOutletContext(); // Outlet context
|
|
202
130
|
```
|
|
203
131
|
|
|
204
|
-
|
|
132
|
+
---
|
|
205
133
|
|
|
206
|
-
|
|
134
|
+
## 🎭 Outlet (Nested Layouts)
|
|
207
135
|
|
|
208
136
|
```tsx
|
|
209
|
-
|
|
210
|
-
{ path: "dashboard/:view", component: <Dashboard /> },
|
|
211
|
-
]);
|
|
137
|
+
import { Outlet, useOutletContext } from "router-kit";
|
|
212
138
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
analytics: <AnalyticsView />,
|
|
217
|
-
settings: <SettingsView />,
|
|
218
|
-
};
|
|
139
|
+
// Parent layout with Outlet
|
|
140
|
+
function DashboardLayout() {
|
|
141
|
+
const [user] = useState({ name: "John" });
|
|
219
142
|
|
|
220
|
-
return
|
|
143
|
+
return (
|
|
144
|
+
<div className="dashboard">
|
|
145
|
+
<Sidebar />
|
|
146
|
+
<main>
|
|
147
|
+
<Outlet context={{ user, theme: "dark" }} />
|
|
148
|
+
</main>
|
|
149
|
+
</div>
|
|
150
|
+
);
|
|
221
151
|
}
|
|
222
|
-
```
|
|
223
|
-
|
|
224
|
-
📖 **See:** [Dashboard Application in EXAMPLES.md](./EXAMPLES.md#dashboard-application)
|
|
225
152
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
{ path: "products", component: <ProductList /> },
|
|
232
|
-
{ path: "products/:id", component: <ProductDetail /> },
|
|
233
|
-
{ path: "cart", component: <Cart /> },
|
|
234
|
-
{ path: "checkout", component: <Checkout /> },
|
|
235
|
-
]);
|
|
153
|
+
// Child route accesses context
|
|
154
|
+
function Settings() {
|
|
155
|
+
const { user, theme } = useOutletContext<{ user: User; theme: string }>();
|
|
156
|
+
return <div className={theme}>Settings for {user.name}</div>;
|
|
157
|
+
}
|
|
236
158
|
```
|
|
237
159
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
### Protected Routes
|
|
160
|
+
### Programmatic Config
|
|
241
161
|
|
|
242
162
|
```tsx
|
|
243
163
|
const routes = createRouter([
|
|
244
|
-
{ path: "/", component: <PublicHome /> },
|
|
245
164
|
{
|
|
246
165
|
path: "dashboard",
|
|
247
|
-
component:
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
166
|
+
component: <DashboardLayout />,
|
|
167
|
+
children: [
|
|
168
|
+
{ index: true, component: <Overview /> },
|
|
169
|
+
{ path: "settings", component: <Settings /> },
|
|
170
|
+
{ path: "profile", component: <Profile /> },
|
|
171
|
+
],
|
|
252
172
|
},
|
|
253
173
|
]);
|
|
254
174
|
```
|
|
255
175
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
---
|
|
259
|
-
|
|
260
|
-
## Feature Matrix
|
|
261
|
-
|
|
262
|
-
| Feature | Status | Documentation |
|
|
263
|
-
| --------------------- | ------ | ------------------------------------------------ |
|
|
264
|
-
| Static Routes | ✅ | [Docs](./DOCUMENTATION.md#routes) |
|
|
265
|
-
| Dynamic Routes | ✅ | [Docs](./DOCUMENTATION.md#useparams) |
|
|
266
|
-
| Nested Routes | ✅ | [Docs](./DOCUMENTATION.md#nested-routes) |
|
|
267
|
-
| Multiple Path Aliases | ✅ | [Docs](./DOCUMENTATION.md#multiple-path-aliases) |
|
|
268
|
-
| Query Parameters | ✅ | [Docs](./DOCUMENTATION.md#usequery) |
|
|
269
|
-
| Navigation State | ✅ | [Docs](./DOCUMENTATION.md#navigation-state) |
|
|
270
|
-
| Custom 404 Pages | ✅ | [Docs](./DOCUMENTATION.md#custom-404-pages) |
|
|
271
|
-
| TypeScript Support | ✅ | [Docs](./DOCUMENTATION.md#typescript-support) |
|
|
272
|
-
| Error Handling | ✅ | [Docs](./DOCUMENTATION.md#error-handling) |
|
|
273
|
-
| Dynamic Components | ✅ | [Docs](./API_REFERENCE.md#usedynamiccomponents) |
|
|
274
|
-
| Hash Routing | ⏳ | Planned |
|
|
275
|
-
| Regex Routes | ⏳ | Planned |
|
|
276
|
-
|
|
277
|
-
---
|
|
278
|
-
|
|
279
|
-
## Quick Reference
|
|
280
|
-
|
|
281
|
-
### Imports
|
|
282
|
-
|
|
283
|
-
```tsx
|
|
284
|
-
// Core
|
|
285
|
-
import { createRouter, RouterProvider } from "router-kit";
|
|
286
|
-
|
|
287
|
-
// Components
|
|
288
|
-
import { Link, NavLink } from "router-kit";
|
|
289
|
-
|
|
290
|
-
// Hooks
|
|
291
|
-
import {
|
|
292
|
-
useRouter,
|
|
293
|
-
useParams,
|
|
294
|
-
useQuery,
|
|
295
|
-
useLocation,
|
|
296
|
-
useDynamicComponents,
|
|
297
|
-
} from "router-kit";
|
|
298
|
-
|
|
299
|
-
// Types
|
|
300
|
-
import type {
|
|
301
|
-
Route,
|
|
302
|
-
RouterContextType,
|
|
303
|
-
NavigateOptions,
|
|
304
|
-
Location,
|
|
305
|
-
RouterKitError,
|
|
306
|
-
} from "router-kit";
|
|
307
|
-
|
|
308
|
-
// Error System
|
|
309
|
-
import { RouterErrorCode, RouterErrors, createRouterError } from "router-kit";
|
|
310
|
-
```
|
|
311
|
-
|
|
312
|
-
### Route Patterns
|
|
313
|
-
|
|
314
|
-
```tsx
|
|
315
|
-
// Static route
|
|
316
|
-
{ path: "about", component: <About /> }
|
|
317
|
-
|
|
318
|
-
// Dynamic parameter
|
|
319
|
-
{ path: "users/:id", component: <UserProfile /> }
|
|
320
|
-
|
|
321
|
-
// Multiple parameters
|
|
322
|
-
{ path: "posts/:category/:slug", component: <BlogPost /> }
|
|
323
|
-
|
|
324
|
-
// Multiple paths
|
|
325
|
-
{ path: ["about", "about-us"], component: <About /> }
|
|
326
|
-
|
|
327
|
-
// Nested routes
|
|
328
|
-
{
|
|
329
|
-
path: "dashboard",
|
|
330
|
-
component: <Dashboard />,
|
|
331
|
-
children: [
|
|
332
|
-
{ path: "settings", component: <Settings /> }
|
|
333
|
-
]
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
// 404 page
|
|
337
|
-
{ path: "/404", component: <NotFound /> }
|
|
338
|
-
```
|
|
339
|
-
|
|
340
|
-
### Hook Usage
|
|
176
|
+
### Declarative Config
|
|
341
177
|
|
|
342
178
|
```tsx
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
const { search, page } = useQuery();
|
|
351
|
-
|
|
352
|
-
// Get location details
|
|
353
|
-
const { pathname, search, hash, state } = useLocation();
|
|
354
|
-
|
|
355
|
-
// Dynamic components
|
|
356
|
-
const component = useDynamicComponents(viewsObject, "paramName");
|
|
179
|
+
<Router>
|
|
180
|
+
<Route path="dashboard" component={<DashboardLayout />}>
|
|
181
|
+
<Route index component={<Overview />} />
|
|
182
|
+
<Route path="settings" component={<Settings />} />
|
|
183
|
+
<Route path="profile" component={<Profile />} />
|
|
184
|
+
</Route>
|
|
185
|
+
</Router>
|
|
357
186
|
```
|
|
358
187
|
|
|
359
188
|
---
|
|
360
189
|
|
|
361
|
-
##
|
|
190
|
+
## 📚 Documentation
|
|
362
191
|
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
192
|
+
| Document | Description |
|
|
193
|
+
| ---------------------------------------- | ----------------- |
|
|
194
|
+
| [Documentation](./docs/DOCUMENTATION.md) | Complete guide |
|
|
195
|
+
| [API Reference](./docs/API_REFERENCE.md) | Full API docs |
|
|
196
|
+
| [Examples](./docs/EXAMPLES.md) | Code examples |
|
|
197
|
+
| [Architecture](./docs/ARCHITECTURE.md) | Technical details |
|
|
198
|
+
| [Changelog](./docs/CHANGELOG.md) | Version history |
|
|
367
199
|
|
|
368
200
|
---
|
|
369
201
|
|
|
370
|
-
##
|
|
371
|
-
|
|
372
|
-
- **Website:** [routerkit.com](https://routerkit.com/)
|
|
373
|
-
- **GitHub Repository:** [github.com/Mohammed-Ben-Cheikh/router-kit](https://github.com/Mohammed-Ben-Cheikh/router-kit)
|
|
374
|
-
- **Issues:** [Report bugs or request features](https://github.com/Mohammed-Ben-Cheikh/router-kit/issues)
|
|
375
|
-
- **Author:** Mohammed Ben Cheikh
|
|
376
|
-
- **Email:** mohammed.bencheikh.dev@gmail.com
|
|
377
|
-
- **Website:** [mohammedbencheikh.com](https://mohammedbencheikh.com/)
|
|
378
|
-
|
|
379
|
-
---
|
|
380
|
-
|
|
381
|
-
## Contributing
|
|
382
|
-
|
|
383
|
-
We welcome contributions! Here's how to get started:
|
|
384
|
-
|
|
385
|
-
1. **Fork the repository**
|
|
386
|
-
2. **Create a feature branch:** `git checkout -b feature/amazing-feature`
|
|
387
|
-
3. **Make your changes**
|
|
388
|
-
4. **Run tests and type checks:** `npm run typecheck`
|
|
389
|
-
5. **Commit your changes:** `git commit -m 'Add amazing feature'`
|
|
390
|
-
6. **Push to your fork:** `git push origin feature/amazing-feature`
|
|
391
|
-
7. **Open a Pull Request**
|
|
392
|
-
|
|
393
|
-
**See:** [ARCHITECTURE.md](./ARCHITECTURE.md) for implementation details.
|
|
394
|
-
|
|
395
|
-
---
|
|
396
|
-
|
|
397
|
-
## Changelog
|
|
398
|
-
|
|
399
|
-
### v1.3.1 (Current)
|
|
400
|
-
|
|
401
|
-
- Full TypeScript support with comprehensive types
|
|
402
|
-
- Enhanced error handling system with detailed context
|
|
403
|
-
- New `useDynamicComponents` hook
|
|
404
|
-
- New `useLocation` hook with state support
|
|
405
|
-
- Improved type exports
|
|
406
|
-
- Better error messages
|
|
407
|
-
|
|
408
|
-
### Previous Versions
|
|
409
|
-
|
|
410
|
-
See [GitHub Releases](https://github.com/Mohammed-Ben-Cheikh/router-kit/releases) for full changelog.
|
|
411
|
-
|
|
412
|
-
---
|
|
413
|
-
|
|
414
|
-
## FAQ
|
|
415
|
-
|
|
416
|
-
### How does Router-Kit compare to React Router?
|
|
417
|
-
|
|
418
|
-
Router-Kit is simpler and lighter. It's perfect for small to medium projects that don't need the full complexity of React Router.
|
|
419
|
-
|
|
420
|
-
📖 **See:** [Migration Guide in DOCUMENTATION.md](./DOCUMENTATION.md#migration-guide)
|
|
421
|
-
|
|
422
|
-
### Can I use Router-Kit with TypeScript?
|
|
423
|
-
|
|
424
|
-
Yes! Router-Kit is written in TypeScript and provides full type definitions.
|
|
425
|
-
|
|
426
|
-
📖 **See:** [TypeScript Support in DOCUMENTATION.md](./DOCUMENTATION.md#typescript-support)
|
|
427
|
-
|
|
428
|
-
### How do I handle authentication?
|
|
429
|
-
|
|
430
|
-
Use the ProtectedRoute pattern with useRouter and useLocation hooks.
|
|
431
|
-
|
|
432
|
-
📖 **See:** [Authentication Flow in EXAMPLES.md](./EXAMPLES.md#authentication-flow)
|
|
433
|
-
|
|
434
|
-
### How do I create nested routes?
|
|
435
|
-
|
|
436
|
-
Use the `children` property in route configuration.
|
|
437
|
-
|
|
438
|
-
📖 **See:** [Nested Routes in DOCUMENTATION.md](./DOCUMENTATION.md#nested-routes)
|
|
439
|
-
|
|
440
|
-
### What about 404 pages?
|
|
441
|
-
|
|
442
|
-
Add a route with `path: "/404"` and Router-Kit will use it automatically.
|
|
443
|
-
|
|
444
|
-
📖 **See:** [Custom 404 Pages in DOCUMENTATION.md](./DOCUMENTATION.md#custom-404-pages)
|
|
445
|
-
|
|
446
|
-
---
|
|
447
|
-
|
|
448
|
-
## Learn More
|
|
449
|
-
|
|
450
|
-
Ready to dive deeper? Start with the [Complete Documentation](./DOCUMENTATION.md) or explore specific topics:
|
|
202
|
+
## 🔗 Links
|
|
451
203
|
|
|
452
|
-
-
|
|
453
|
-
-
|
|
454
|
-
- Want examples? → [EXAMPLES.md](./EXAMPLES.md)
|
|
455
|
-
- Curious about internals? → [ARCHITECTURE.md](./ARCHITECTURE.md)
|
|
204
|
+
- **GitHub:** [github.com/Mohammed-Ben-Cheikh/router-kit](https://github.com/Mohammed-Ben-Cheikh/router-kit)
|
|
205
|
+
- **Author:** [Mohammed Ben Cheikh](https://mohammedbencheikh.com/)
|
|
456
206
|
|
|
457
207
|
---
|
|
458
208
|
|
|
459
|
-
|
|
209
|
+
Made with ❤️ by Mohammed Ben Cheikh
|
|
@@ -1,7 +1,24 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
import type { LinkProps } from "../types";
|
|
2
|
+
/**
|
|
3
|
+
* Link component for client-side navigation
|
|
4
|
+
*
|
|
5
|
+
* Provides seamless navigation without full page reloads.
|
|
6
|
+
* Supports all standard anchor attributes and navigation options.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```tsx
|
|
10
|
+
* // Basic usage
|
|
11
|
+
* <Link to="/about">About Us</Link>
|
|
12
|
+
*
|
|
13
|
+
* // With state
|
|
14
|
+
* <Link to="/profile" state={{ from: 'dashboard' }}>Profile</Link>
|
|
15
|
+
*
|
|
16
|
+
* // Replace history entry
|
|
17
|
+
* <Link to="/login" replace>Login</Link>
|
|
18
|
+
*
|
|
19
|
+
* // External link (opens normally)
|
|
20
|
+
* <Link to="https://example.com" target="_blank">External</Link>
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
declare const Link: import("react").ForwardRefExoticComponent<LinkProps & import("react").RefAttributes<HTMLAnchorElement>>;
|
|
7
24
|
export default Link;
|
package/dist/components/Link.js
CHANGED
|
@@ -1,10 +1,55 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef } from "react";
|
|
2
3
|
import { useRouter } from "../hooks/useRouter";
|
|
3
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Checks if a link should trigger navigation or default browser behavior
|
|
6
|
+
*/
|
|
7
|
+
const shouldNavigate = (event, target) => {
|
|
8
|
+
return (!event.defaultPrevented &&
|
|
9
|
+
event.button === 0 && // Left click
|
|
10
|
+
(!target || target === "_self") &&
|
|
11
|
+
!event.metaKey &&
|
|
12
|
+
!event.altKey &&
|
|
13
|
+
!event.ctrlKey &&
|
|
14
|
+
!event.shiftKey);
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Link component for client-side navigation
|
|
18
|
+
*
|
|
19
|
+
* Provides seamless navigation without full page reloads.
|
|
20
|
+
* Supports all standard anchor attributes and navigation options.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```tsx
|
|
24
|
+
* // Basic usage
|
|
25
|
+
* <Link to="/about">About Us</Link>
|
|
26
|
+
*
|
|
27
|
+
* // With state
|
|
28
|
+
* <Link to="/profile" state={{ from: 'dashboard' }}>Profile</Link>
|
|
29
|
+
*
|
|
30
|
+
* // Replace history entry
|
|
31
|
+
* <Link to="/login" replace>Login</Link>
|
|
32
|
+
*
|
|
33
|
+
* // External link (opens normally)
|
|
34
|
+
* <Link to="https://example.com" target="_blank">External</Link>
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
const Link = forwardRef(({ to, children, className, replace = false, state, preventScrollReset = false, target, rel, title, onClick, ...rest }, ref) => {
|
|
4
38
|
const { navigate } = useRouter();
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
39
|
+
// Determine if link is external
|
|
40
|
+
const isExternal = /^https?:\/\//i.test(to);
|
|
41
|
+
const handleClick = (event) => {
|
|
42
|
+
// Call user's onClick handler first
|
|
43
|
+
onClick === null || onClick === void 0 ? void 0 : onClick(event);
|
|
44
|
+
// Handle internal navigation
|
|
45
|
+
if (!isExternal && shouldNavigate(event, target)) {
|
|
46
|
+
event.preventDefault();
|
|
47
|
+
navigate(to, { replace, state, preventScrollReset });
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
// Auto-add security attributes for external links
|
|
51
|
+
const computedRel = isExternal && target === "_blank" ? rel || "noopener noreferrer" : rel;
|
|
52
|
+
return (_jsx("a", { ref: ref, href: to, onClick: handleClick, className: className, target: target, rel: computedRel, title: title, ...rest, children: children }));
|
|
53
|
+
});
|
|
54
|
+
Link.displayName = "Link";
|
|
10
55
|
export default Link;
|