intentx-react-router 1.0.3 → 1.1.0-z
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 +465 -41
- package/build/core/env.d.ts +1 -0
- package/build/core/index.d.ts +1 -0
- package/build/core/intentCore.d.ts +30 -17
- package/build/core/setupIntentRouter.d.ts +9 -0
- package/build/index.esm.js +1 -1
- package/build/index.js +1 -1
- package/build/router/IntentLink.d.ts +1 -1
- package/build/router/IntentRoute.d.ts +2 -1
- package/build/router/RouterBinder.d.ts +4 -3
- package/build/router/index.d.ts +0 -1
- package/package.json +8 -2
- package/build/router/IntentRouter.d.ts +0 -5
package/README.md
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
# 🕹️ intentx-react-router
|
|
2
2
|
|
|
3
|
-
[](https://www.npmjs.com/package/intentx-react-router) 
|
|
3
|
+
[](https://www.npmjs.com/package/intentx-react-router)  
|
|
4
4
|
|
|
5
|
-
<a href="https://codesandbox.io/p/sandbox/
|
|
5
|
+
<a href="https://codesandbox.io/p/sandbox/7x3hqr" target="_blank">LIVE EXAMPLE</a>
|
|
6
6
|
|
|
7
|
-
Intent
|
|
7
|
+
Intent-based navigation layer for React applications.
|
|
8
8
|
|
|
9
|
-
Built on top of
|
|
10
|
-
event‑driven architectures like **eventbus-z**.
|
|
9
|
+
Built on top of React Router and designed for **domain-driven and event-driven navigation**.
|
|
11
10
|
|
|
12
11
|
> Navigate by **intent**, not by URL.
|
|
13
12
|
|
|
@@ -23,6 +22,7 @@ navigate("/users/42/edit")
|
|
|
23
22
|
Intent Router:
|
|
24
23
|
```ts
|
|
25
24
|
navigateIntent("edit-user", 42)
|
|
25
|
+
// → /users/42/edit
|
|
26
26
|
```
|
|
27
27
|
|
|
28
28
|
<b>Benefits:</b>
|
|
@@ -32,7 +32,6 @@ navigateIntent("edit-user", 42)
|
|
|
32
32
|
- 🔧 Easy URL refactor
|
|
33
33
|
- 🧩 Micro‑frontend friendly
|
|
34
34
|
- 📡 Event‑driven navigation support
|
|
35
|
-
- 🪶 Lightweight core (\~200 lines)
|
|
36
35
|
|
|
37
36
|
---
|
|
38
37
|
|
|
@@ -51,44 +50,85 @@ npm install intentx-react-router react-router@^7 react-router-dom@^7
|
|
|
51
50
|
|
|
52
51
|
---
|
|
53
52
|
|
|
53
|
+
# Quick Start
|
|
54
|
+
|
|
55
|
+
```tsx
|
|
56
|
+
import { createIntentRouter, navigateIntent } from "intentx-react-router"
|
|
57
|
+
|
|
58
|
+
createIntentRouter({
|
|
59
|
+
"view-user": "/users/:id",
|
|
60
|
+
"edit-user": "/users/:id/edit"
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
// navigate by intent
|
|
64
|
+
navigateIntent("view-user", 42)
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Result:
|
|
68
|
+
```ts
|
|
69
|
+
/users/42
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
54
74
|
# Basic Setup
|
|
55
75
|
|
|
56
|
-
## 1
|
|
76
|
+
## 1️⃣ Define intents
|
|
57
77
|
|
|
58
78
|
``` ts
|
|
59
|
-
import { createIntentRouter } from "intentx-react-router"
|
|
79
|
+
import { createIntentRouter, NavigateFn } from "intentx-react-router"
|
|
60
80
|
|
|
61
81
|
createIntentRouter({
|
|
62
|
-
"view-user":
|
|
82
|
+
"view-user": {
|
|
83
|
+
path: "/users/:userId/name/:page",
|
|
84
|
+
meta: {
|
|
85
|
+
title: "User Profile"
|
|
86
|
+
}
|
|
87
|
+
},
|
|
63
88
|
"edit-user": "/users/:userId/edit",
|
|
64
89
|
"checkout": "/checkout"
|
|
65
90
|
})
|
|
91
|
+
|
|
92
|
+
// Bind navigate in App
|
|
93
|
+
export function bindRouterNavigate(navigate: NavigateFn) {
|
|
94
|
+
bindNavigate(navigate);
|
|
95
|
+
}
|
|
96
|
+
|
|
66
97
|
```
|
|
67
98
|
|
|
68
99
|
---
|
|
69
100
|
|
|
70
|
-
## 2
|
|
101
|
+
## 2️⃣ Bind React Router
|
|
71
102
|
|
|
72
103
|
``` ts
|
|
73
104
|
import React from "react"
|
|
74
105
|
import { useNavigate } from "react-router-dom"
|
|
75
|
-
import {
|
|
106
|
+
import { bindRouterNavigate } from "./router"
|
|
76
107
|
|
|
77
108
|
export function RouterBinder() {
|
|
78
|
-
const navigate = useNavigate()
|
|
79
|
-
|
|
80
|
-
|
|
109
|
+
const navigate = useNavigate();
|
|
110
|
+
|
|
111
|
+
React.useEffect(() => {
|
|
112
|
+
// require
|
|
113
|
+
bindRouterNavigate(navigate);
|
|
114
|
+
}, [navigate]);
|
|
115
|
+
|
|
116
|
+
return null;
|
|
81
117
|
}
|
|
82
118
|
```
|
|
83
119
|
---
|
|
84
120
|
|
|
85
|
-
## 3
|
|
121
|
+
## 3️⃣ Use in App
|
|
86
122
|
|
|
87
123
|
```ts
|
|
88
124
|
import React from "react"
|
|
89
125
|
import { BrowserRouter, Routes } from "react-router-dom"
|
|
90
126
|
import { IntentLink, IntentRoute } from "intentx-react-router"
|
|
127
|
+
|
|
91
128
|
import { RouterBinder } from "./router"
|
|
129
|
+
// or
|
|
130
|
+
// import "./router"
|
|
131
|
+
// import { RouterBinder } from "intentx-react-router"
|
|
92
132
|
|
|
93
133
|
import { UserPage } from "./pages/UserPage"
|
|
94
134
|
import { EditUserPage } from "./pages/EditUserPage"
|
|
@@ -115,25 +155,127 @@ export default function App() {
|
|
|
115
155
|
}
|
|
116
156
|
```
|
|
117
157
|
|
|
118
|
-
|
|
158
|
+
IntentRoute automatically maps the intent path to a React Router route.
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
# Modular Router Setup
|
|
163
|
+
## 1️⃣ Define intents
|
|
164
|
+
|
|
165
|
+
```ts
|
|
166
|
+
// intents/user-intents.ts
|
|
167
|
+
export const userIntents = {
|
|
168
|
+
home: "/",
|
|
169
|
+
userProfile: "/users/:id",
|
|
170
|
+
settings: "/settings"
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// intents/cart-intents.ts
|
|
174
|
+
export const cartIntents = {
|
|
175
|
+
cart: "/cart",
|
|
176
|
+
checkout: "/checkout"
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## 2️⃣ Setup router
|
|
119
183
|
|
|
120
184
|
```ts
|
|
121
|
-
|
|
122
|
-
|
|
185
|
+
// router/setupRouter.ts
|
|
186
|
+
|
|
187
|
+
import { setupIntentRouter } from "intentx-react-router"
|
|
188
|
+
|
|
189
|
+
import { userIntents } from "../intents/user-intents"
|
|
190
|
+
import { cartIntents } from "../intents/cart-intents"
|
|
191
|
+
|
|
192
|
+
export function setupRouter(navigate) {
|
|
193
|
+
setupIntentRouter({
|
|
194
|
+
intents: [
|
|
195
|
+
userIntents,
|
|
196
|
+
cartIntents
|
|
197
|
+
],
|
|
198
|
+
|
|
199
|
+
guards: [
|
|
200
|
+
(intent, params) => {
|
|
201
|
+
console.log("Navigate:", intent, params)
|
|
202
|
+
}
|
|
203
|
+
],
|
|
204
|
+
|
|
205
|
+
intentGuards: {
|
|
206
|
+
checkout() {
|
|
207
|
+
const cartReady = true
|
|
208
|
+
|
|
209
|
+
if (!cartReady) {
|
|
210
|
+
return "/cart"
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
},
|
|
214
|
+
|
|
215
|
+
navigate
|
|
216
|
+
})
|
|
217
|
+
}
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
## 3️⃣ Bind router to React Router
|
|
223
|
+
|
|
224
|
+
```ts
|
|
225
|
+
// App.tsx
|
|
226
|
+
|
|
227
|
+
import { RouterBinder } from "intentx-react-router"
|
|
228
|
+
import { setupRouter } from "./router/setupRouter"
|
|
229
|
+
|
|
230
|
+
setupRouter()
|
|
123
231
|
|
|
124
232
|
export default function App() {
|
|
125
233
|
return (
|
|
126
|
-
|
|
127
|
-
<
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
234
|
+
<>
|
|
235
|
+
<RouterBinder />
|
|
236
|
+
|
|
237
|
+
{/* your routes */}
|
|
238
|
+
</>
|
|
131
239
|
)
|
|
132
240
|
}
|
|
133
241
|
```
|
|
134
242
|
|
|
135
243
|
---
|
|
136
244
|
|
|
245
|
+
## 4️⃣ Navigate using intent
|
|
246
|
+
|
|
247
|
+
```ts
|
|
248
|
+
import { navigateIntent } from "intentx-react-router"
|
|
249
|
+
|
|
250
|
+
navigateIntent("userProfile", { id: 42 })
|
|
251
|
+
|
|
252
|
+
navigateIntent("checkout")
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
Generated URL:
|
|
256
|
+
|
|
257
|
+
```ts
|
|
258
|
+
/users/42
|
|
259
|
+
/checkout
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
---
|
|
263
|
+
|
|
264
|
+
## 5️⃣ Object navigation
|
|
265
|
+
```ts
|
|
266
|
+
navigateIntentObject("userProfile", {
|
|
267
|
+
params: { id: 10 },
|
|
268
|
+
query: { tab: "posts" }
|
|
269
|
+
})
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
Result:
|
|
273
|
+
```ts
|
|
274
|
+
/users/10?tab=posts
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
---
|
|
278
|
+
|
|
137
279
|
# Navigation
|
|
138
280
|
|
|
139
281
|
## Object params
|
|
@@ -343,7 +485,7 @@ import { IntentRoute } from "intentx-react-router"
|
|
|
343
485
|
|
|
344
486
|
# Guards
|
|
345
487
|
|
|
346
|
-
Global guard
|
|
488
|
+
## Global guard
|
|
347
489
|
|
|
348
490
|
```ts
|
|
349
491
|
addIntentGuard((intent, params) => {
|
|
@@ -355,7 +497,7 @@ addIntentGuard((intent, params) => {
|
|
|
355
497
|
})
|
|
356
498
|
```
|
|
357
499
|
|
|
358
|
-
Per
|
|
500
|
+
## Per-intent guard
|
|
359
501
|
|
|
360
502
|
```ts
|
|
361
503
|
addIntentGuardFor("checkout", () => {
|
|
@@ -369,6 +511,38 @@ addIntentGuardFor("checkout", () => {
|
|
|
369
511
|
|
|
370
512
|
---
|
|
371
513
|
|
|
514
|
+
## Guard inside intent
|
|
515
|
+
|
|
516
|
+
You can attach guards directly to intents.
|
|
517
|
+
|
|
518
|
+
```ts
|
|
519
|
+
createIntentRouter({
|
|
520
|
+
|
|
521
|
+
"checkout": {
|
|
522
|
+
path: "/checkout",
|
|
523
|
+
guard: () => {
|
|
524
|
+
if (!isLoggedIn()) {
|
|
525
|
+
return "/login"
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
},
|
|
529
|
+
|
|
530
|
+
"admin": {
|
|
531
|
+
path: "/admin",
|
|
532
|
+
guard: () => {
|
|
533
|
+
if (!isAdmin()) {
|
|
534
|
+
return "/forbidden"
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
})
|
|
540
|
+
```
|
|
541
|
+
|
|
542
|
+
This keeps route logic close to its definition.
|
|
543
|
+
|
|
544
|
+
---
|
|
545
|
+
|
|
372
546
|
# Preload
|
|
373
547
|
|
|
374
548
|
Preload logic before navigation.
|
|
@@ -472,17 +646,257 @@ This allows:
|
|
|
472
646
|
|
|
473
647
|
---
|
|
474
648
|
|
|
649
|
+
# Why not just use React Router?
|
|
650
|
+
|
|
651
|
+
:contentReference[oaicite:1]{index=1} is an excellent routing library and intentx-react-router **does not replace it**.
|
|
652
|
+
|
|
653
|
+
Instead, it adds a **navigation abstraction layer** on top of React Router.
|
|
654
|
+
|
|
655
|
+
React Router focuses on **URL-driven navigation**, while intentx-react-router focuses on **intent-driven navigation**.
|
|
656
|
+
|
|
657
|
+
---
|
|
658
|
+
|
|
659
|
+
## React Router navigation
|
|
660
|
+
|
|
661
|
+
In React Router, navigation is usually done by URLs:
|
|
662
|
+
|
|
663
|
+
```ts
|
|
664
|
+
navigate("/users/42/edit")
|
|
665
|
+
```
|
|
666
|
+
|
|
667
|
+
The application logic becomes tied to the URL structure.
|
|
668
|
+
|
|
669
|
+
If the URL changes later:
|
|
670
|
+
|
|
671
|
+
```text
|
|
672
|
+
/users/:id/edit
|
|
673
|
+
→
|
|
674
|
+
/profile/:id/edit
|
|
675
|
+
```
|
|
676
|
+
|
|
677
|
+
You must update navigation code across the app.
|
|
678
|
+
|
|
679
|
+
---
|
|
680
|
+
|
|
681
|
+
## Intent navigation
|
|
682
|
+
|
|
683
|
+
intentx-react-router introduces intent-based navigation.
|
|
684
|
+
|
|
685
|
+
Instead of navigating by URL:
|
|
686
|
+
|
|
687
|
+
```ts
|
|
688
|
+
navigateIntent("edit-user", 42)
|
|
689
|
+
```
|
|
690
|
+
|
|
691
|
+
The router resolves the intent into a URL:
|
|
692
|
+
|
|
693
|
+
```text
|
|
694
|
+
/edit-user → /users/42/edit
|
|
695
|
+
```
|
|
696
|
+
|
|
697
|
+
If the URL changes later:
|
|
698
|
+
|
|
699
|
+
```text
|
|
700
|
+
/users/:id/edit
|
|
701
|
+
→
|
|
702
|
+
/profile/:id/edit
|
|
703
|
+
```
|
|
704
|
+
|
|
705
|
+
You only update the router definition:
|
|
706
|
+
|
|
707
|
+
```ts
|
|
708
|
+
createIntentRouter({
|
|
709
|
+
"edit-user": "/profile/:id/edit"
|
|
710
|
+
})
|
|
711
|
+
```
|
|
712
|
+
|
|
713
|
+
---
|
|
714
|
+
|
|
475
715
|
# Comparison
|
|
476
716
|
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
|
484
|
-
|
|
485
|
-
|
|
|
717
|
+
intentx-react-router focuses on **intent-driven navigation** rather than URL-driven navigation.
|
|
718
|
+
|
|
719
|
+
Instead of navigating by path strings, you navigate by **domain intent**.
|
|
720
|
+
|
|
721
|
+
## vs React Router
|
|
722
|
+
|
|
723
|
+
| Criteria | intentx-react-router | React Router |
|
|
724
|
+
|-------------------------|----------------------|--------------|
|
|
725
|
+
| Intent-based navigation | ✅ | ❌ |
|
|
726
|
+
| URL refactor safety | ✅ | ⚠️ |
|
|
727
|
+
| Event-driven navigation | ✅ | ❌ |
|
|
728
|
+
| Micro-frontend friendly | ✅ | ⚠️ |
|
|
729
|
+
| Reverse routing | ✅ | ❌ |
|
|
730
|
+
| Type-safe intent params | ✅ | ⚠️ |
|
|
731
|
+
| Query support | ✅ | ⚠️ |
|
|
732
|
+
|
|
733
|
+
|
|
734
|
+
<br />
|
|
735
|
+
|
|
736
|
+
```ts
|
|
737
|
+
// React Router:
|
|
738
|
+
navigate("/users/42/edit")
|
|
739
|
+
|
|
740
|
+
// intentx-react-router:
|
|
741
|
+
navigateIntent("edit-user", 42)
|
|
742
|
+
```
|
|
743
|
+
|
|
744
|
+
---
|
|
745
|
+
|
|
746
|
+
## vs TanStack Router
|
|
747
|
+
|
|
748
|
+
:contentReference[oaicite:4]{index=4} is a powerful type-safe router with a full route tree and data loading system.
|
|
749
|
+
|
|
750
|
+
| Criteria | intentx-react-router | TanStack Router |
|
|
751
|
+
| ----------------------- | -------------------- | --------------- |
|
|
752
|
+
| Intent navigation | ✅ | ❌ |
|
|
753
|
+
| Route tree system | ❌ | ✅ |
|
|
754
|
+
| Data loaders | ❌ | ✅ |
|
|
755
|
+
| Reverse routing | ✅ | ⚠️ |
|
|
756
|
+
| Guards | ✅ | ⚠️ |
|
|
757
|
+
| Event-driven navigation | ✅ | ❌ |
|
|
758
|
+
| Micro-frontend friendly | ✅ | ⚠️ |
|
|
759
|
+
|
|
760
|
+
<br />
|
|
761
|
+
|
|
762
|
+
Intent Router is designed to be minimal and flexible, especially for event-driven or micro-frontend architectures.
|
|
763
|
+
|
|
764
|
+
---
|
|
765
|
+
|
|
766
|
+
## vs Remix Router
|
|
767
|
+
|
|
768
|
+
:contentReference[oaicite:5]{index=5} provides a full-stack routing system with loaders and server rendering.
|
|
769
|
+
|
|
770
|
+
| Criteria | intentx-react-router | Remix |
|
|
771
|
+
| ------------------------- | --------------------- | -----------|
|
|
772
|
+
| Intent navigation | ✅ | ❌ |
|
|
773
|
+
| Reverse routing | ✅ | ❌ |
|
|
774
|
+
| Guards | ✅ | ⚠️ loaders |
|
|
775
|
+
| Event-driven navigation | ✅ | ❌ |
|
|
776
|
+
| Server loaders | ❌ | ✅ |
|
|
777
|
+
| Full-stack routing | ❌ | ✅ |
|
|
778
|
+
| Lightweight client router | ✅ | ❌ |
|
|
779
|
+
|
|
780
|
+
|
|
781
|
+
<br />
|
|
782
|
+
|
|
783
|
+
Remix focuses on server-first routing, while intentx-react-router focuses on client-side intent navigation.
|
|
784
|
+
|
|
785
|
+
---
|
|
786
|
+
|
|
787
|
+
# Route Meta
|
|
788
|
+
|
|
789
|
+
You can attach metadata to intents.
|
|
790
|
+
|
|
791
|
+
This is useful for:
|
|
792
|
+
|
|
793
|
+
- auth
|
|
794
|
+
- role permission
|
|
795
|
+
- page title
|
|
796
|
+
- layout selection
|
|
797
|
+
- analytics
|
|
798
|
+
|
|
799
|
+
---
|
|
800
|
+
|
|
801
|
+
## Define meta
|
|
802
|
+
|
|
803
|
+
```ts
|
|
804
|
+
createIntentRouter({
|
|
805
|
+
|
|
806
|
+
"home": "/",
|
|
807
|
+
|
|
808
|
+
"dashboard": {
|
|
809
|
+
path: "/dashboard",
|
|
810
|
+
meta: {
|
|
811
|
+
title: "Dashboard",
|
|
812
|
+
auth: true
|
|
813
|
+
}
|
|
814
|
+
},
|
|
815
|
+
|
|
816
|
+
"admin": {
|
|
817
|
+
path: "/admin",
|
|
818
|
+
meta: {
|
|
819
|
+
title: "Admin Panel",
|
|
820
|
+
auth: true,
|
|
821
|
+
role: "admin"
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
})
|
|
826
|
+
```
|
|
827
|
+
|
|
828
|
+
---
|
|
829
|
+
|
|
830
|
+
## Read meta
|
|
831
|
+
|
|
832
|
+
```ts
|
|
833
|
+
import { getIntentMeta } from "intentx-react-router"
|
|
834
|
+
|
|
835
|
+
const meta = getIntentMeta("admin")
|
|
836
|
+
|
|
837
|
+
console.log(meta)
|
|
838
|
+
```
|
|
839
|
+
|
|
840
|
+
Result:
|
|
841
|
+
|
|
842
|
+
```ts
|
|
843
|
+
{
|
|
844
|
+
title: "Admin Panel",
|
|
845
|
+
auth: true,
|
|
846
|
+
role: "admin"
|
|
847
|
+
}
|
|
848
|
+
```
|
|
849
|
+
|
|
850
|
+
---
|
|
851
|
+
|
|
852
|
+
## Meta with guards
|
|
853
|
+
|
|
854
|
+
Meta works perfectly with guards.
|
|
855
|
+
|
|
856
|
+
```ts
|
|
857
|
+
addIntentGuard((intent) => {
|
|
858
|
+
|
|
859
|
+
const meta = getIntentMeta(intent)
|
|
860
|
+
|
|
861
|
+
if (meta?.auth && !isLoggedIn()) {
|
|
862
|
+
return "/login"
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
})
|
|
866
|
+
```
|
|
867
|
+
|
|
868
|
+
Example with role protection:
|
|
869
|
+
|
|
870
|
+
```ts
|
|
871
|
+
addIntentGuard((intent) => {
|
|
872
|
+
|
|
873
|
+
const meta = getIntentMeta(intent)
|
|
874
|
+
|
|
875
|
+
if (meta?.role === "admin" && !isAdmin()) {
|
|
876
|
+
return "/forbidden"
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
})
|
|
880
|
+
```
|
|
881
|
+
|
|
882
|
+
---
|
|
883
|
+
|
|
884
|
+
## Meta in React
|
|
885
|
+
|
|
886
|
+
You can also read meta inside components.
|
|
887
|
+
|
|
888
|
+
```ts
|
|
889
|
+
import { useIntentRouter, getIntentMeta } from "intentx-react-router"
|
|
890
|
+
|
|
891
|
+
function PageHeader() {
|
|
892
|
+
|
|
893
|
+
const { intent } = useIntentRouter()
|
|
894
|
+
|
|
895
|
+
const meta = getIntentMeta(intent)
|
|
896
|
+
|
|
897
|
+
return <h1>{meta?.title}</h1>
|
|
898
|
+
}
|
|
899
|
+
```
|
|
486
900
|
|
|
487
901
|
---
|
|
488
902
|
|
|
@@ -490,16 +904,26 @@ This allows:
|
|
|
490
904
|
|
|
491
905
|
```text
|
|
492
906
|
Component
|
|
493
|
-
|
|
907
|
+
↓
|
|
494
908
|
navigateIntent()
|
|
495
|
-
|
|
496
|
-
eventbus-z
|
|
497
|
-
↓
|
|
909
|
+
↓
|
|
498
910
|
Intent Router
|
|
499
|
-
|
|
911
|
+
↓
|
|
912
|
+
(eventbus-z optional)
|
|
913
|
+
↓
|
|
500
914
|
React Router navigate()
|
|
501
|
-
|
|
502
|
-
URL
|
|
915
|
+
↓
|
|
916
|
+
URL
|
|
917
|
+
```
|
|
918
|
+
|
|
919
|
+
---
|
|
920
|
+
|
|
921
|
+
# Debug Mode
|
|
922
|
+
|
|
923
|
+
Enable debug logs:
|
|
924
|
+
|
|
925
|
+
```js
|
|
926
|
+
window.__INTENT_ROUTER_DEBUG__ = true
|
|
503
927
|
```
|
|
504
928
|
|
|
505
929
|
---
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const __DEV__: boolean;
|
package/build/core/index.d.ts
CHANGED
|
@@ -1,36 +1,49 @@
|
|
|
1
1
|
import type { GlobalBus } from "eventbus-z";
|
|
2
|
+
export type IntentSchema = Record<string, {
|
|
3
|
+
params?: Record<string, any>;
|
|
4
|
+
query?: Record<string, any>;
|
|
5
|
+
}>;
|
|
6
|
+
export type NavigateOptions = {
|
|
7
|
+
replace?: boolean;
|
|
8
|
+
scrollTop?: boolean;
|
|
9
|
+
[key: string]: any;
|
|
10
|
+
};
|
|
2
11
|
export type NavigateIntentOptions<P = any> = {
|
|
3
12
|
params?: P | any[] | string | number;
|
|
4
13
|
query?: Record<string, any>;
|
|
5
|
-
options?:
|
|
6
|
-
replace?: boolean;
|
|
7
|
-
scrollTop?: boolean;
|
|
8
|
-
};
|
|
14
|
+
options?: NavigateOptions;
|
|
9
15
|
};
|
|
10
|
-
type
|
|
11
|
-
type GuardFn = (intent: string, params: any) => boolean | string | void;
|
|
12
|
-
type NavigateFn = (path: string, options?: {
|
|
13
|
-
replace?: boolean;
|
|
14
|
-
scrollTop?: boolean;
|
|
15
|
-
}) => void;
|
|
16
|
+
export type NavigateFn = (path: string, options?: NavigateOptions) => void;
|
|
17
|
+
type GuardFn = ((intent: string, params: any) => boolean | string | void | Promise<boolean | string | void>);
|
|
16
18
|
type PreloadFn = () => Promise<any> | void;
|
|
17
|
-
|
|
19
|
+
type IntentMeta = Record<string, any> | ((params: any) => Record<string, any>);
|
|
20
|
+
type IntentConfig = {
|
|
21
|
+
path: string;
|
|
22
|
+
meta?: IntentMeta;
|
|
23
|
+
guard?: GuardFn;
|
|
24
|
+
preload?: PreloadFn;
|
|
25
|
+
};
|
|
26
|
+
type IntentMapInput = Record<string, string | IntentConfig>;
|
|
27
|
+
export declare function registerIntents(map: IntentMapInput): void;
|
|
28
|
+
export declare function bootstrapRouter(): void;
|
|
29
|
+
export declare function createIntentRouter(map: IntentMapInput): void;
|
|
30
|
+
export declare function getIntentMeta(intent: string, params?: any): any;
|
|
31
|
+
export declare function setIntentMeta(intent: string, meta: IntentMeta): void;
|
|
18
32
|
export declare function bindNavigate(fn: NavigateFn): void;
|
|
19
33
|
export declare function setFallbackPath(path: string): void;
|
|
20
|
-
export declare function
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
}): void;
|
|
24
|
-
export declare function navigateIntentObject<P = any>(intent: string, navigateIntentOption?: NavigateIntentOptions<P>): void;
|
|
34
|
+
export declare function warnRouterNotReady(intent: string): void;
|
|
35
|
+
export declare function navigateIntent(intent: string, params?: any, query?: Record<string, any>, options?: NavigateOptions): void;
|
|
36
|
+
export declare function navigateIntentObject<P = any>(intent: string, args?: NavigateIntentOptions<P>): void;
|
|
25
37
|
export declare function addIntentGuard(fn: GuardFn): void;
|
|
26
38
|
export declare function addIntentGuardFor(intent: string, fn: GuardFn): void;
|
|
27
39
|
export declare function addIntentPreload(intent: string, fn: PreloadFn): void;
|
|
28
40
|
export declare function preloadIntent(intent: string): void;
|
|
29
|
-
export declare function generatePathFromIntent(intent: string, params?:
|
|
41
|
+
export declare function generatePathFromIntent(intent: string, params?: any, query?: Record<string, any>): string;
|
|
30
42
|
export declare function resolveIntentFromUrl(url: string): {
|
|
31
43
|
intent: string;
|
|
32
44
|
params: Record<string, any>;
|
|
33
45
|
query: Record<string, any>;
|
|
34
46
|
} | null;
|
|
47
|
+
export declare function syncIntentFromUrl(url: string): void;
|
|
35
48
|
export declare function setSharedBus(externalBus: GlobalBus): void;
|
|
36
49
|
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
type GuardFn = (intent: string, params: any) => any;
|
|
2
|
+
type SetupOptions = {
|
|
3
|
+
intents?: Record<string, any>[];
|
|
4
|
+
guards?: GuardFn[];
|
|
5
|
+
intentGuards?: Record<string, GuardFn>;
|
|
6
|
+
navigate?: (path: string, options?: any) => void;
|
|
7
|
+
};
|
|
8
|
+
export declare function setupIntentRouter({ intents, guards, intentGuards, navigate }?: SetupOptions): void;
|
|
9
|
+
export {};
|
package/build/index.esm.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createEventBus as n}from"eventbus-z";import{jsx as t,Fragment as
|
|
1
|
+
import{createEventBus as n}from"eventbus-z";import{jsx as t,Fragment as e}from"react/jsx-runtime";import{Link as o,useLocation as r,useNavigate as i}from"react-router-dom";import{useEffect as c,useRef as a}from"react";const u="undefined"!=typeof window&&!0===window.__INTENT_ROUTER_DEBUG__,s=n();let f=null,l=null;const p="INTENT_NAVIGATE_DELPIK";let d={},h={},m={},y={},w=!1;const g=[],R={},E={};let _=null;const I=[];let v=!1;function T(...n){u&&console.log("[IntentRouter]",...n)}function $(n){if(!n)return"";const t=new URLSearchParams;for(const e in n){const o=n[e];null!=o&&(Array.isArray(o)?o.forEach(n=>t.append(e,String(n))):t.append(e,String(o)))}const e=t.toString();return e?`?${e}`:""}function A(n){for(const t in n){u&&d[t]&&console.warn(`[IntentRouter] duplicate intent "${t}"`);const e=n[t];"string"!=typeof e?(d[t]=e.path,e.meta&&(h[t]=e.meta),e.guard&&(m[t]=e.guard),e.preload&&(y[t]=e.preload)):d[t]=e}}function k(n){I.push(n),v&&A(n)}function U(){if(v)return;v=!0;const n={};I.length||console.warn("[IntentRouter] no intents registered");for(const t of I)Object.assign(n,t);A(n),T("intent map",d)}function P(n){k(n),U()}function S(n,t){const e=h[n];return e?"function"==typeof e?e(t):e:{}}function b(n,t){h[n]=t}function q(n){l&&l!==n&&u&&console.warn("IntentRouter navigate replaced"),l=n,w||(s.$onMultiple(p,D),w=!0)}function z(n){_=n}function M(n){u&&(l||console.warn(`[IntentRouter] navigateIntent("${n}") called before router initialized.\nMake sure <RouterBinder /> is mounted.`))}function x(n,t,e,o){M(n);const r={intent:n,params:t,query:e,options:o};T("emit",r),s.$emit(p,r),f&&f!==s&&f.$emit(p,r)}function K(n,t){const{params:e,query:o,options:r}=t||{};x(n,e,o,r)}function N(n){g.push(n)}function j(n,t){R[n]||(R[n]=[]),R[n].push(t)}function C(n,t){E[n]||(E[n]=[]),E[n].push(t)}function L(n){G(n)}async function D(n){if(n.__handled)return;n.__handled=!0;const t=d[n.intent];if(!t)return console.warn("Unknown intent:",n.intent),void(_&&l?.(_));const e=Z(t,n.params),o=S(n.intent,e);for(const t of g){const o=await t(n.intent,e);if(!1===o)return;if("string"==typeof o)return void l?.(o)}const r=R[n.intent]||[];for(const t of r){const o=await t(n.intent,e);if(!1===o)return;if("string"==typeof o)return void l?.(o)}const i=m[n.intent];if(i){const t=await i(n.intent,e);if(!1===t)return;if("string"==typeof t)return void l?.(t)}try{const t=y[n.intent]?.();t instanceof Promise&&t.catch(()=>console.warn(`Preload failed for ${n.intent}`))}catch{}G(n.intent);const c=B(t,e)+$(n.query);T("navigate",{intent:n.intent,params:e,meta:o,url:c});const{scrollTop:a,...u}=n.options||{};("undefined"!=typeof window?window.location.pathname+window.location.search:null)!==c||u?.replace?(l?.(c,u),a&&"undefined"!=typeof window&&window.scrollTo(0,0)):T("skip navigation",c)}function G(n){const t=E[n];if(t)for(const e of t)try{const t=e();t instanceof Promise&&t.catch(()=>console.warn(`Preload failed for ${n}`))}catch{}}const O={};function Z(n,t){const e=function(n){if(O[n])return O[n];const t=[];return n.replace(/:([A-Za-z0-9_]+)/g,(n,e)=>(t.push(e),"")),O[n]=t,t}(n);if(!t)return{};if(Array.isArray(t)){const n={};return e.forEach((e,o)=>{n[e]=t[o]}),n}return"object"==typeof t?t:1===e.length?{[e[0]]:t}:{}}function B(n,t){return n.replace(/:([A-Za-z0-9_]+)/g,(n,e)=>{const o=t[e];return void 0===o?(console.warn(`Missing param "${e}"`),""):encodeURIComponent(o)})}function V(n,t,e){const o=d[n];if(!o)return"";return B(o,Z(o,t))+$(e)}const F={};function H(n){if(F[n])return F[n];const t=[],e=new RegExp("^"+n.replace(/:([A-Za-z0-9_]+)/g,(n,e)=>(t.push(e),"([^/]+)"))+"$");return F[n]={regex:e,keys:t},F[n]}function J(n){const[t,e]=n.split("?"),o=decodeURI(t),r=function(n){if(!n)return{};const t=new URLSearchParams(n),e={};return t.forEach((n,t)=>{e[t]?Array.isArray(e[t])?e[t].push(n):e[t]=[e[t],n]:e[t]=n}),e}(e);for(const n in d){const t=d[n],{regex:e,keys:i}=H(t),c=o.match(e);if(!c)continue;const a={};return i.forEach((n,t)=>{a[n]=decodeURIComponent(c[t+1])}),{intent:n,params:a,query:r}}return null}function Q(n){const t=J(n);t&&x(t.intent,t.params,t.query)}function W(n){f=n,f!==s&&f.$onMultiple(p,D)}let X=!1;function Y({intents:n=[],guards:t=[],intentGuards:e={},navigate:o}={}){if(X)return;X=!0;const r={};for(const t of n)for(const n in t)u&&r[n]&&console.warn(`[IntentRouter] duplicate intent "${n}"`),r[n]=t[n];Object.keys(r).length&&P(r),t.forEach(N);for(const n in e)j(n,e[n]);o&&q(o)}function nn({intent:n,params:r,query:i,scrollTop:c,prefetch:a,onClick:u,onMouseEnter:s,onTouchStart:f,...l}){const p=V(n,r,i);return p?t(o,{to:p,onClick:t=>{t.metaKey||t.ctrlKey||t.shiftKey||t.altKey||0!==t.button||(t.preventDefault(),x(n,r,i,{scrollTop:c}),u?.(t))},onMouseEnter:t=>{a&&L(n),s?.(t)},onTouchStart:t=>{a&&L(n),f?.(t)},...l}):(M(n),t(e,{children:l.children}))}function tn(){const n=r(),t=J(n.pathname),e=new URLSearchParams(n.search),o={};return e.forEach((n,t)=>{o[t]=n}),{intent:t?.intent??null,params:t?.params??{},query:o}}function en({intent:n,component:o,fallback:r=null,loading:i,guard:c}){const a=tn();return a?a.intent!==n?null:c&&!c(a)?t(e,{children:r}):t(o,{...a}):i?t(e,{children:i}):null}function on(n){const t=i();return c(()=>{q(n??t)},[n,t]),x}function rn({initializeRouter:n}){const t=i(),e=r(),o=a(!1);return on(),c(()=>{n&&(o.current||(o.current=!0,n(t)))},[t,n]),c(()=>{Q(e.pathname+e.search)},[e.pathname,e.search]),null}export{nn as IntentLink,en as IntentRoute,rn as RouterBinder,N as addIntentGuard,j as addIntentGuardFor,C as addIntentPreload,q as bindNavigate,U as bootstrapRouter,P as createIntentRouter,V as generatePathFromIntent,S as getIntentMeta,x as navigateIntent,K as navigateIntentObject,L as preloadIntent,k as registerIntents,J as resolveIntentFromUrl,z as setFallbackPath,b as setIntentMeta,W as setSharedBus,Y as setupIntentRouter,Q as syncIntentFromUrl,tn as useIntentRouter,on as useNavigateIntent,M as warnRouterNotReady};
|
package/build/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var n=require("eventbus-z"),t=require("react/jsx-runtime"),e=require("react-router-dom"),
|
|
1
|
+
"use strict";var n=require("eventbus-z"),t=require("react/jsx-runtime"),e=require("react-router-dom"),o=require("react");const r="undefined"!=typeof window&&!0===window.__INTENT_ROUTER_DEBUG__,i=n.createEventBus();let s=null,a=null;const c="INTENT_NAVIGATE_DELPIK";let u={},f={},l={},p={},d=!1;const h=[],g={},m={};let y=null;const x=[];let w=!1;function I(...n){r&&console.log("[IntentRouter]",...n)}function R(n){if(!n)return"";const t=new URLSearchParams;for(const e in n){const o=n[e];null!=o&&(Array.isArray(o)?o.forEach(n=>t.append(e,String(n))):t.append(e,String(o)))}const e=t.toString();return e?`?${e}`:""}function v(n){for(const t in n){r&&u[t]&&console.warn(`[IntentRouter] duplicate intent "${t}"`);const e=n[t];"string"!=typeof e?(u[t]=e.path,e.meta&&(f[t]=e.meta),e.guard&&(l[t]=e.guard),e.preload&&(p[t]=e.preload)):u[t]=e}}function E(n){x.push(n),w&&v(n)}function _(){if(w)return;w=!0;const n={};x.length||console.warn("[IntentRouter] no intents registered");for(const t of x)Object.assign(n,t);v(n),I("intent map",u)}function k(n){E(n),_()}function T(n,t){const e=f[n];return e?"function"==typeof e?e(t):e:{}}function $(n){a&&a!==n&&r&&console.warn("IntentRouter navigate replaced"),a=n,d||(i.$onMultiple(c,j),d=!0)}function b(n){r&&(a||console.warn(`[IntentRouter] navigateIntent("${n}") called before router initialized.\nMake sure <RouterBinder /> is mounted.`))}function q(n,t,e,o){b(n);const r={intent:n,params:t,query:e,options:o};I("emit",r),i.$emit(c,r),s&&s!==i&&s.$emit(c,r)}function A(n){h.push(n)}function P(n,t){g[n]||(g[n]=[]),g[n].push(t)}function U(n){N(n)}async function j(n){if(n.__handled)return;n.__handled=!0;const t=u[n.intent];if(!t)return console.warn("Unknown intent:",n.intent),void(y&&a?.(y));const e=F(t,n.params),o=T(n.intent,e);for(const t of h){const o=await t(n.intent,e);if(!1===o)return;if("string"==typeof o)return void a?.(o)}const r=g[n.intent]||[];for(const t of r){const o=await t(n.intent,e);if(!1===o)return;if("string"==typeof o)return void a?.(o)}const i=l[n.intent];if(i){const t=await i(n.intent,e);if(!1===t)return;if("string"==typeof t)return void a?.(t)}try{const t=p[n.intent]?.();t instanceof Promise&&t.catch(()=>console.warn(`Preload failed for ${n.intent}`))}catch{}N(n.intent);const s=L(t,e)+R(n.query);I("navigate",{intent:n.intent,params:e,meta:o,url:s});const{scrollTop:c,...f}=n.options||{};("undefined"!=typeof window?window.location.pathname+window.location.search:null)!==s||f?.replace?(a?.(s,f),c&&"undefined"!=typeof window&&window.scrollTo(0,0)):I("skip navigation",s)}function N(n){const t=m[n];if(t)for(const e of t)try{const t=e();t instanceof Promise&&t.catch(()=>console.warn(`Preload failed for ${n}`))}catch{}}const S={};function F(n,t){const e=function(n){if(S[n])return S[n];const t=[];return n.replace(/:([A-Za-z0-9_]+)/g,(n,e)=>(t.push(e),"")),S[n]=t,t}(n);if(!t)return{};if(Array.isArray(t)){const n={};return e.forEach((e,o)=>{n[e]=t[o]}),n}return"object"==typeof t?t:1===e.length?{[e[0]]:t}:{}}function L(n,t){return n.replace(/:([A-Za-z0-9_]+)/g,(n,e)=>{const o=t[e];return void 0===o?(console.warn(`Missing param "${e}"`),""):encodeURIComponent(o)})}function M(n,t,e){const o=u[n];if(!o)return"";return L(o,F(o,t))+R(e)}const z={};function B(n){if(z[n])return z[n];const t=[],e=new RegExp("^"+n.replace(/:([A-Za-z0-9_]+)/g,(n,e)=>(t.push(e),"([^/]+)"))+"$");return z[n]={regex:e,keys:t},z[n]}function G(n){const[t,e]=n.split("?"),o=decodeURI(t),r=function(n){if(!n)return{};const t=new URLSearchParams(n),e={};return t.forEach((n,t)=>{e[t]?Array.isArray(e[t])?e[t].push(n):e[t]=[e[t],n]:e[t]=n}),e}(e);for(const n in u){const t=u[n],{regex:e,keys:i}=B(t),s=o.match(e);if(!s)continue;const a={};return i.forEach((n,t)=>{a[n]=decodeURIComponent(s[t+1])}),{intent:n,params:a,query:r}}return null}function K(n){const t=G(n);t&&q(t.intent,t.params,t.query)}let C=!1;function O(){const n=e.useLocation(),t=G(n.pathname),o=new URLSearchParams(n.search),r={};return o.forEach((n,t)=>{r[t]=n}),{intent:t?.intent??null,params:t?.params??{},query:r}}function D(n){const t=e.useNavigate();return o.useEffect(()=>{$(n??t)},[n,t]),q}exports.IntentLink=function({intent:n,params:o,query:r,scrollTop:i,prefetch:s,onClick:a,onMouseEnter:c,onTouchStart:u,...f}){const l=M(n,o,r);return l?t.jsx(e.Link,{to:l,onClick:t=>{t.metaKey||t.ctrlKey||t.shiftKey||t.altKey||0!==t.button||(t.preventDefault(),q(n,o,r,{scrollTop:i}),a?.(t))},onMouseEnter:t=>{s&&U(n),c?.(t)},onTouchStart:t=>{s&&U(n),u?.(t)},...f}):(b(n),t.jsx(t.Fragment,{children:f.children}))},exports.IntentRoute=function({intent:n,component:e,fallback:o=null,loading:r,guard:i}){const s=O();return s?s.intent!==n?null:i&&!i(s)?t.jsx(t.Fragment,{children:o}):t.jsx(e,{...s}):r?t.jsx(t.Fragment,{children:r}):null},exports.RouterBinder=function({initializeRouter:n}){const t=e.useNavigate(),r=e.useLocation(),i=o.useRef(!1);return D(),o.useEffect(()=>{n&&(i.current||(i.current=!0,n(t)))},[t,n]),o.useEffect(()=>{K(r.pathname+r.search)},[r.pathname,r.search]),null},exports.addIntentGuard=A,exports.addIntentGuardFor=P,exports.addIntentPreload=function(n,t){m[n]||(m[n]=[]),m[n].push(t)},exports.bindNavigate=$,exports.bootstrapRouter=_,exports.createIntentRouter=k,exports.generatePathFromIntent=M,exports.getIntentMeta=T,exports.navigateIntent=q,exports.navigateIntentObject=function(n,t){const{params:e,query:o,options:r}=t||{};q(n,e,o,r)},exports.preloadIntent=U,exports.registerIntents=E,exports.resolveIntentFromUrl=G,exports.setFallbackPath=function(n){y=n},exports.setIntentMeta=function(n,t){f[n]=t},exports.setSharedBus=function(n){s=n,s!==i&&s.$onMultiple(c,j)},exports.setupIntentRouter=function({intents:n=[],guards:t=[],intentGuards:e={},navigate:o}={}){if(C)return;C=!0;const i={};for(const t of n)for(const n in t)r&&i[n]&&console.warn(`[IntentRouter] duplicate intent "${n}"`),i[n]=t[n];Object.keys(i).length&&k(i),t.forEach(A);for(const n in e)P(n,e[n]);o&&$(o)},exports.syncIntentFromUrl=K,exports.useIntentRouter=O,exports.useNavigateIntent=D,exports.warnRouterNotReady=b;
|
|
@@ -5,6 +5,6 @@ type Props = {
|
|
|
5
5
|
query?: Record<string, any>;
|
|
6
6
|
scrollTop?: boolean;
|
|
7
7
|
prefetch?: boolean;
|
|
8
|
-
} & Omit<LinkProps, "to"
|
|
8
|
+
} & Omit<LinkProps, "to">;
|
|
9
9
|
export declare function IntentLink({ intent, params, query, scrollTop, prefetch, onClick, onMouseEnter, onTouchStart, ...props }: Props): JSX.Element;
|
|
10
10
|
export {};
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import type { IntentData } from "./useIntentRouter";
|
|
1
2
|
type Props = {
|
|
2
3
|
intent: string;
|
|
3
4
|
component: React.ComponentType<any>;
|
|
4
5
|
fallback?: React.ReactNode;
|
|
5
6
|
loading?: React.ReactNode;
|
|
6
|
-
guard?: (data:
|
|
7
|
+
guard?: (data: IntentData) => boolean;
|
|
7
8
|
};
|
|
8
9
|
export declare function IntentRoute({ intent, component: Component, fallback, loading, guard, }: Props): JSX.Element | null;
|
|
9
10
|
export {};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
type
|
|
2
|
-
|
|
1
|
+
import type { NavigateFn } from "../core/intentCore";
|
|
2
|
+
type RouterBinderProps = {
|
|
3
|
+
initializeRouter?: (navigate: NavigateFn) => void;
|
|
3
4
|
};
|
|
4
|
-
export declare function RouterBinder({
|
|
5
|
+
export declare function RouterBinder({ initializeRouter }: RouterBinderProps): null;
|
|
5
6
|
export {};
|
package/build/router/index.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "intentx-react-router",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0-z",
|
|
4
4
|
"description": "Intent-based routing for React. Navigate by intent instead of URLs.",
|
|
5
5
|
"author": "Delpi.Kye",
|
|
6
6
|
"license": "MIT",
|
|
7
|
+
"sideEffects": false,
|
|
8
|
+
|
|
7
9
|
"type": "module",
|
|
8
10
|
"main": "./build/index.js",
|
|
9
11
|
"module": "./build/index.esm.js",
|
|
10
12
|
"types": "./build/index.d.ts",
|
|
13
|
+
|
|
11
14
|
"exports": {
|
|
12
15
|
".": {
|
|
13
16
|
"types": "./build/index.d.ts",
|
|
@@ -18,13 +21,14 @@
|
|
|
18
21
|
"files": [
|
|
19
22
|
"build"
|
|
20
23
|
],
|
|
21
|
-
|
|
24
|
+
|
|
22
25
|
"scripts": {
|
|
23
26
|
"clean": "rimraf build",
|
|
24
27
|
"build": "rimraf build && rollup -c",
|
|
25
28
|
"watch": "rollup -c -w",
|
|
26
29
|
"typecheck": "tsc --noEmit"
|
|
27
30
|
},
|
|
31
|
+
|
|
28
32
|
"engines": {
|
|
29
33
|
"node": ">=16"
|
|
30
34
|
},
|
|
@@ -36,6 +40,7 @@
|
|
|
36
40
|
"bugs": {
|
|
37
41
|
"url": "https://github.com/delpikye-v/intentx-react-router/issues"
|
|
38
42
|
},
|
|
43
|
+
|
|
39
44
|
"keywords": [
|
|
40
45
|
"react",
|
|
41
46
|
"react-router",
|
|
@@ -48,6 +53,7 @@
|
|
|
48
53
|
"spa",
|
|
49
54
|
"routing"
|
|
50
55
|
],
|
|
56
|
+
|
|
51
57
|
"peerDependencies": {
|
|
52
58
|
"react": ">=18",
|
|
53
59
|
"react-dom": ">=18",
|