intentx-react-router 0.2.1 → 1.0.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 CHANGED
@@ -86,7 +86,8 @@ export function RouterBinder() {
86
86
 
87
87
  ```ts
88
88
  import React from "react"
89
- import { BrowserRouter, Switch, IntentLink, IntentRoute } from "react-router-dom"
89
+ import { BrowserRouter, Routes } from "react-router-dom"
90
+ import { IntentLink, IntentRoute } from "intentx-react-router"
90
91
  import { RouterBinder } from "./router"
91
92
 
92
93
  import { UserPage } from "./pages/UserPage"
@@ -104,16 +105,33 @@ export default function App() {
104
105
  | <IntentLink intent="checkout">Checkout</IntentLink>
105
106
  </nav>
106
107
 
107
- <Switch>
108
+ <Routes>
108
109
  <IntentRoute intent="view-user" component={UserPage} />
109
110
  <IntentRoute intent="edit-user" component={EditUserPage} />
110
111
  <IntentRoute intent="checkout" component={CheckoutPage} />
111
- </Switch>
112
+ </Routes>
112
113
  </BrowserRouter>
113
114
  )
114
115
  }
115
116
  ```
116
117
 
118
+ ## 4. IntentRouter
119
+
120
+ ```ts
121
+ import { IntentRouter } from "intentx-react-router"
122
+ import { Routes } from "react-router-dom"
123
+
124
+ export default function App() {
125
+ return (
126
+ <IntentRouter>
127
+ <Routes>
128
+ <IntentRoute intent="checkout" component={CheckoutPage} />
129
+ </Routes>
130
+ </IntentRouter>
131
+ )
132
+ }
133
+ ```
134
+
117
135
  ---
118
136
 
119
137
  # Navigation
@@ -163,6 +181,82 @@ Result:
163
181
 
164
182
  ---
165
183
 
184
+ ## Query params
185
+
186
+ Intent navigation also supports query parameters.
187
+
188
+ ```ts
189
+ navigateIntent("view-user", {
190
+ userId: 1,
191
+ page: 2
192
+ }, {
193
+ tab: "activity",
194
+ filter: "recent"
195
+ })
196
+ ```
197
+
198
+ ```ts
199
+ /users/1/name/2?tab=activity&filter=recent
200
+ ```
201
+
202
+ ---
203
+
204
+ Query arrays are also supported:
205
+
206
+ ```ts
207
+ navigateIntent("view-user", [1,2], {
208
+ tags: ["admin", "vip"]
209
+ })
210
+ ```
211
+
212
+ Result:
213
+
214
+ ```ts
215
+ /users/1/name/2?tags=admin&tags=vip
216
+ ```
217
+
218
+ ---
219
+
220
+ ## Advanced Navigation
221
+
222
+ options, fallback, microFE
223
+
224
+ ```ts
225
+ import React from "react"
226
+ import { useNavigateIntent, setFallbackPath, setSharedBus } from "intentx-react-router"
227
+ import { createEventBus } from "eventbus-z"
228
+
229
+ // Micro-frontend shared bus
230
+ const externalBus = createEventBus()
231
+ setSharedBus(externalBus)
232
+
233
+ setFallbackPath("/not-found")
234
+
235
+ function Dashboard() {
236
+ const navigateIntent = useNavigateIntent()
237
+
238
+ const handleCheckout = () => {
239
+ navigateIntent("checkout", undefined, { ref: "dashboard" }, { replace: true, scrollTop: true })
240
+ }
241
+
242
+ return (
243
+ <div>
244
+ <h1>Dashboard</h1>
245
+ <button onClick={handleCheckout}>Go to Checkout</button>
246
+ <button
247
+ onClick={() => {
248
+ navigateIntent("unknown-intent")
249
+ }}
250
+ >
251
+ Unknown Intent
252
+ </button>
253
+ </div>
254
+ )
255
+ }
256
+ ```
257
+
258
+ ---
259
+
166
260
  # React Helpers
167
261
 
168
262
  ## useNavigateIntent
@@ -188,7 +282,7 @@ function Button() {
188
282
  ``` tsx
189
283
  import { IntentLink } from "intentx-react-router"
190
284
 
191
- <IntentLink intent="view-user" params={[1,2]}>
285
+ <IntentLink intent="view-user" params={[1,2]} query={{ tab: "profile" }}>
192
286
  Open User
193
287
  </IntentLink>
194
288
  ```
@@ -196,20 +290,20 @@ import { IntentLink } from "intentx-react-router"
196
290
  Equivalent to:
197
291
 
198
292
  ```ts
199
- <Link to="/users/1/name/2" />
293
+ <Link to="/users/1/name/2?tab=profile" />
200
294
  ```
201
295
 
202
296
  ---
203
297
 
204
- ## useIntent
298
+ ## useIntentRouter
205
299
 
206
300
  Reads intent + params from URL.
207
301
 
208
302
  ``` ts
209
- import { useIntent } from "intentx-react-router"
303
+ import { useIntentRouter } from "intentx-react-router"
210
304
 
211
305
  function Page() {
212
- const { intent, params } = useIntent()
306
+ const { intent, params } = useIntentRouter()
213
307
 
214
308
  console.log(intent)
215
309
  console.log(params)
@@ -221,13 +315,13 @@ function Page() {
221
315
  Example result:
222
316
 
223
317
  ```ts
224
- {
225
- intent: "view-user",
226
- params: {
227
- userId: "1",
228
- page: "2"
229
- }
318
+ {
319
+ intent: "view-user",
320
+ params: {
321
+ userId: "1",
322
+ page: "2"
230
323
  }
324
+ }
231
325
  ```
232
326
 
233
327
  ---
@@ -298,32 +392,84 @@ preloadIntent("checkout")
298
392
  Generate path manually.
299
393
 
300
394
  ``` ts
301
- generatePathFromIntent("view-user", [1,2])
395
+ generatePathFromIntent("view-user", [1,2], {
396
+ tab: "activity"
397
+ })
302
398
  ```
303
399
 
304
400
  Result:
305
401
  ```ts
306
- /users/1/name/2
402
+ /users/1/name/2?tab=activity
307
403
  ```
308
404
  ---
309
405
 
310
406
  # Resolve Intent From URL
311
407
 
312
408
  ``` ts
313
- resolveIntentFromUrl("/users/1/name/2")
409
+ resolveIntentFromUrl("/users/1/name/2?tab=activity")
410
+ ```
411
+
412
+ Result:
413
+ ```ts
414
+ {
415
+ intent: "view-user",
416
+ params: {
417
+ userId: "1",
418
+ page: "2"
419
+ },
420
+ query: {
421
+ tab: "activity"
422
+ }
423
+ }
424
+ ```
425
+
426
+ ---
427
+
428
+ # Event-Driven Navigation
429
+
430
+ Example
431
+
432
+ ```ts
433
+ import { createEventBus } from "eventbus-z"
434
+ import { navigateIntent } from "intentx-react-router"
435
+
436
+ const bus = createEventBus()
437
+
438
+ // Somewhere in your app
439
+ bus.$on("CHECKOUT_REQUESTED", (userId) => {
440
+ navigateIntent("checkout", { userId })
441
+ })
442
+ ```
443
+
444
+ Trigger navigation from anywhere:
445
+ ```ts
446
+ bus.$emit("CHECKOUT_REQUESTED", 42)
314
447
  ```
315
448
 
316
449
  Result:
317
450
  ```ts
318
- {
319
- intent: "view-user",
320
- params: {
321
- userId: "1",
322
- page: "2"
323
- }
324
- }
451
+ /checkout?userId=42
452
+ ```
453
+
454
+ Why this is powerful
455
+ - Navigation becomes decoupled from UI components.
456
+
457
+ Instead of:
458
+
459
+ ```ts
460
+ <button onClick={() => navigate("/checkout")} />
325
461
  ```
326
462
 
463
+ You can emit a domain event:
464
+ ```ts
465
+ bus.$emit("CHECKOUT_REQUESTED")
466
+ ```
467
+
468
+ This allows:
469
+ - UI-agnostic navigation
470
+ - better architecture in large apps
471
+ - seamless micro-frontend communication
472
+
327
473
  ---
328
474
 
329
475
  # Comparison
@@ -336,6 +482,7 @@ Result:
336
482
  | Micro-frontend friendly | ✅ | ⚠️ |
337
483
  | Reverse routing | ✅ | ❌ |
338
484
  | Type-safe intent params | ✅ | ⚠️ |
485
+ | Query support | ✅ | ⚠️ |
339
486
 
340
487
  ---
341
488
 
@@ -1,17 +1,27 @@
1
+ import type { GlobalBus } from "eventbus-z";
1
2
  type IntentMap = Record<string, string>;
2
3
  type GuardFn = (intent: string, params: any) => boolean | string | void;
3
- type NavigateFn = (path: string) => void;
4
+ type NavigateFn = (path: string, options?: {
5
+ replace?: boolean;
6
+ scrollTop?: boolean;
7
+ }) => void;
4
8
  type PreloadFn = () => Promise<any> | void;
5
9
  export declare function createIntentRouter(map: IntentMap): void;
6
10
  export declare function bindNavigate(fn: NavigateFn): void;
7
- export declare function navigateIntent(intent: string, params?: Record<string, any> | any[] | string | number): void;
11
+ export declare function setFallbackPath(path: string): void;
12
+ export declare function navigateIntent<P = any>(intent: string, params?: P | any[] | string | number, query?: Record<string, any>, options?: {
13
+ replace?: boolean;
14
+ scrollTop?: boolean;
15
+ }): void;
8
16
  export declare function addIntentGuard(fn: GuardFn): void;
9
17
  export declare function addIntentGuardFor(intent: string, fn: GuardFn): void;
10
18
  export declare function addIntentPreload(intent: string, fn: PreloadFn): void;
11
19
  export declare function preloadIntent(intent: string): void;
12
- export declare function generatePathFromIntent(intent: string, params?: Record<string, any> | any[] | string | number): string;
20
+ export declare function generatePathFromIntent(intent: string, params?: Record<string, any> | any[] | string | number, query?: Record<string, any>): string;
13
21
  export declare function resolveIntentFromUrl(url: string): {
14
22
  intent: string;
15
23
  params: Record<string, any>;
24
+ query: Record<string, any>;
16
25
  } | null;
26
+ export declare function setSharedBus(externalBus: GlobalBus): void;
17
27
  export {};
@@ -1 +1 @@
1
- import{createEventBus as n}from"eventbus-z";import{jsx as t}from"react/jsx-runtime";import{Link as r,useLocation as o,useNavigate as e}from"react-router-dom";import{useEffect as i}from"react";const c=n(),u="INTENT_NAVIGATE";let s={},f=null,a=!1;const l=[],p={},m={};function h(n){s=n}function v(n){f=n,a||(c.$onMultiple(u,E),a=!0)}function d(n,t){c.$emit(u,{intent:n,params:t})}function g(n){l.push(n)}function y(n,t){p[n]||(p[n]=[]),p[n].push(t)}function A(n,t){m[n]||(m[n]=[]),m[n].push(t)}function w(n){z(n)}function E(n){const t=s[n.intent];if(!t)return void console.warn("Unknown intent:",n.intent);const r=$(t,n.params);for(const t of l){const o=t(n.intent,r);if(!1===o)return;if("string"==typeof o)return void(null==f||f(o))}const o=p[n.intent]||[];for(const t of o){const o=t(n.intent,r);if(!1===o)return;if("string"==typeof o)return void(null==f||f(o))}z(n.intent);const e=_(t,r);null==f||f(e)}function z(n){const t=m[n];if(t)for(const n of t)try{const t=n();t instanceof Promise&&t.catch(()=>{})}catch{}}function $(n,t){const r=function(n){const t=[];return n.replace(/:([A-Za-z0-9_]+)/g,(n,r)=>(t.push(r),"")),t}(n);if(!t)return{};if(Array.isArray(t)){const n={};return r.forEach((r,o)=>{void 0===t[o]&&console.warn(`Missing param "${r}"`),n[r]=t[o]}),n}return"object"==typeof t?t:1===r.length?{[r[0]]:t}:{}}function _(n,t){return n.replace(/:([A-Za-z0-9_]+)/g,(n,r)=>{var o;return null!==(o=t[r])&&void 0!==o?o:""})}function x(n,t){const r=s[n];if(!r)return"";return _(r,$(r,t))}function N(n){for(const t in s){const r=s[t],o=[],e=new RegExp("^"+r.replace(/:([A-Za-z0-9_]+)/g,(n,t)=>(o.push(t),"([^/]+)"))+"$"),i=n.match(e);if(!i)continue;const c={};return o.forEach((n,t)=>{c[n]=i[t+1]}),{intent:t,params:c}}return null}function P({intent:n,params:o,query:e,children:i}){let c=x(n,o);if(e){const n=new URLSearchParams(e).toString();n&&(c+="?"+n)}return t(r,{to:c,children:i})}function R(){var n,t;const r=o(),e=N(r.pathname),i=new URLSearchParams(r.search),c={};return i.forEach((n,t)=>{c[t]=n}),{intent:null!==(n=null==e?void 0:e.intent)&&void 0!==n?n:null,params:null!==(t=null==e?void 0:e.params)&&void 0!==t?t:{},query:c}}function S({intent:n,component:r}){const o=R();return o.intent!==n?null:t(r,{...o})}function T({navigate:n}){const t=e();return v(n||t),null}function U(){const n=e();return i(()=>{v(n)},[n]),d}export{P as IntentLink,S as IntentRoute,T as RouterBinder,g as addIntentGuard,y as addIntentGuardFor,A as addIntentPreload,v as bindNavigate,h as createIntentRouter,x as generatePathFromIntent,d as navigateIntent,w as preloadIntent,N as resolveIntentFromUrl,R as useIntent,U as useNavigateIntent};
1
+ import{createEventBus as n}from"eventbus-z";import{jsx as t,Fragment as r,jsxs as o}from"react/jsx-runtime";import{Link as e,useLocation as i,useNavigate as c,BrowserRouter as u}from"react-router-dom";import{useEffect as a}from"react";const s=n();let f=null;let l={},p=null,m=!1;const d=[],h={},y={};let T=null;const A="undefined"!=typeof window&&!0===window.__INTENT_ROUTER_DEBUG__;function E(...n){A&&console.log("[IntentRouter]",...n)}function N(n){if(!n)return"";const t=new URLSearchParams;for(const r in n){const o=n[r];null!=o&&(Array.isArray(o)?o.forEach(n=>t.append(r,String(n))):t.append(r,String(o)))}const r=t.toString();return r?`?${r}`:""}function g(n){l=n,E("intent map loaded",n)}function w(n){p=n,m||(s.$onMultiple("INTENT_NAVIGATE",$),m=!0)}function I(n){T=n}function _(n,t,r,o){E("emit",n,{params:t,query:r});const e={intent:n,params:t,query:r,...o?{options:o}:{}};s.$emit("INTENT_NAVIGATE",e),f&&f.$emit("INTENT_NAVIGATE",e)}function v(n){d.push(n)}function R(n,t){h[n]||(h[n]=[]),h[n].push(t)}function q(n,t){y[n]||(y[n]=[]),y[n].push(t)}function U(n){G(n)}async function $(n){const t=l[n.intent];if(E("receive",n.intent,n),!t)return T&&p?.(T),void console.warn("Unknown intent:",n.intent);const r=S(t,n.params);for(const t of d){const o=await t(n.intent,r);if(!1===o)return;if("string"==typeof o)return void p?.(o,n.options)}const o=h[n.intent]||[];for(const t of o){const o=await t(n.intent,r);if(!1===o)return;if("string"==typeof o)return void p?.(o,n.options)}G(n.intent);const e=V(t,r)+N(n.query);E("navigate",{intent:n.intent,params:r,query:n.query,url:e}),p?.(e,n.options),f&&f.$emit("INTENT_NAVIGATE",n)}function G(n){const t=y[n];if(t)for(const n of t)try{const t=n();t instanceof Promise&&t.catch(()=>{})}catch{}}function S(n,t){const r=function(n){const t=[];return n.replace(/:([A-Za-z0-9_]+)/g,(n,r)=>(t.push(r),"")),t}(n);if(!t)return{};if(Array.isArray(t)){const n={};return r.forEach((r,o)=>{void 0===t[o]&&console.warn(`Missing param "${r}"`),n[r]=t[o]}),n}return"object"==typeof t?t:1===r.length?{[r[0]]:t}:{}}function V(n,t){return n.replace(/:([A-Za-z0-9_]+)/g,(n,r)=>{const o=t[r];return void 0!==o?encodeURIComponent(o):""})}function z(n,t,r){const o=l[n];if(!o)return"";return V(o,S(o,t))+N(r)}function P(n){const[t,r]=n.split("?"),o=function(n){if(!n)return{};const t=new URLSearchParams(n),r={};return t.forEach((n,t)=>{r[t]?Array.isArray(r[t])?r[t].push(n):r[t]=[r[t],n]:r[t]=n}),r}(r);for(const n in l){const r=l[n],e=[],i=new RegExp("^"+r.replace(/:([A-Za-z0-9_]+)/g,(n,t)=>(e.push(t),"([^/]+)"))+"$"),c=t.match(i);if(!c)continue;const u={};return e.forEach((n,t)=>{u[n]=decodeURIComponent(c[t+1])}),{intent:n,params:u,query:o}}return null}function b(n){f=n,f.$onMultiple("INTENT_NAVIGATE",$)}function k({intent:n,params:r,query:o,children:i,replace:c,scrollTop:u}){const a=z(n,r,o);return t(e,{to:a,replace:c,onClick:()=>{u&&window.scrollTo(0,0)},children:i})}function x(){const n=i(),t=P(n.pathname),r=new URLSearchParams(n.search),o={};return r.forEach((n,t)=>{o[t]=n}),{intent:t?.intent??null,params:t?.params??{},query:o}}function C({intent:n,component:o,fallback:e=null,loading:i,guard:c}){const u=x();return u?u.intent!==n?null:c&&!c(u)?t(r,{children:e}):t(o,{...u}):i??null}function L({navigate:n}){const t=c();return w(n||t),null}function M({children:n}){return o(u,{children:[t(L,{}),n]})}function Z(){const n=c();return a(()=>{w(n)},[n]),_}export{k as IntentLink,C as IntentRoute,M as IntentRouter,L as RouterBinder,v as addIntentGuard,R as addIntentGuardFor,q as addIntentPreload,w as bindNavigate,g as createIntentRouter,z as generatePathFromIntent,_ as navigateIntent,U as preloadIntent,P as resolveIntentFromUrl,I as setFallbackPath,b as setSharedBus,x as useIntentRouter,Z as useNavigateIntent};
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"),r=require("react");const o=n.createEventBus(),i="INTENT_NAVIGATE";let u={},s=null,c=!1;const a=[],f={},l={};function p(n){s=n,c||(o.$onMultiple(i,v),c=!0)}function d(n,t){o.$emit(i,{intent:n,params:t})}function v(n){const t=u[n.intent];if(!t)return void console.warn("Unknown intent:",n.intent);const e=m(t,n.params);for(const t of a){const r=t(n.intent,e);if(!1===r)return;if("string"==typeof r)return void(null==s||s(r))}const r=f[n.intent]||[];for(const t of r){const r=t(n.intent,e);if(!1===r)return;if("string"==typeof r)return void(null==s||s(r))}h(n.intent);const o=x(t,e);null==s||s(o)}function h(n){const t=l[n];if(t)for(const n of t)try{const t=n();t instanceof Promise&&t.catch(()=>{})}catch{}}function m(n,t){const e=function(n){const t=[];return n.replace(/:([A-Za-z0-9_]+)/g,(n,e)=>(t.push(e),"")),t}(n);if(!t)return{};if(Array.isArray(t)){const n={};return e.forEach((e,r)=>{void 0===t[r]&&console.warn(`Missing param "${e}"`),n[e]=t[r]}),n}return"object"==typeof t?t:1===e.length?{[e[0]]:t}:{}}function x(n,t){return n.replace(/:([A-Za-z0-9_]+)/g,(n,e)=>{var r;return null!==(r=t[e])&&void 0!==r?r:""})}function g(n,t){const e=u[n];if(!e)return"";return x(e,m(e,t))}function I(n){for(const t in u){const e=u[t],r=[],o=new RegExp("^"+e.replace(/:([A-Za-z0-9_]+)/g,(n,t)=>(r.push(t),"([^/]+)"))+"$"),i=n.match(o);if(!i)continue;const s={};return r.forEach((n,t)=>{s[n]=i[t+1]}),{intent:t,params:s}}return null}function y(){var n,t;const r=e.useLocation(),o=I(r.pathname),i=new URLSearchParams(r.search),u={};return i.forEach((n,t)=>{u[t]=n}),{intent:null!==(n=null==o?void 0:o.intent)&&void 0!==n?n:null,params:null!==(t=null==o?void 0:o.params)&&void 0!==t?t:{},query:u}}exports.IntentLink=function({intent:n,params:r,query:o,children:i}){let u=g(n,r);if(o){const n=new URLSearchParams(o).toString();n&&(u+="?"+n)}return t.jsx(e.Link,{to:u,children:i})},exports.IntentRoute=function({intent:n,component:e}){const r=y();return r.intent!==n?null:t.jsx(e,{...r})},exports.RouterBinder=function({navigate:n}){const t=e.useNavigate();return p(n||t),null},exports.addIntentGuard=function(n){a.push(n)},exports.addIntentGuardFor=function(n,t){f[n]||(f[n]=[]),f[n].push(t)},exports.addIntentPreload=function(n,t){l[n]||(l[n]=[]),l[n].push(t)},exports.bindNavigate=p,exports.createIntentRouter=function(n){u=n},exports.generatePathFromIntent=g,exports.navigateIntent=d,exports.preloadIntent=function(n){h(n)},exports.resolveIntentFromUrl=I,exports.useIntent=y,exports.useNavigateIntent=function(){const n=e.useNavigate();return r.useEffect(()=>{p(n)},[n]),d};
1
+ "use strict";var n=require("eventbus-z"),t=require("react/jsx-runtime"),e=require("react-router-dom"),r=require("react");const o=n.createEventBus();let i=null;let s={},c=null,u=!1;const a=[],p={},f={};let l=null;const d="undefined"!=typeof window&&!0===window.__INTENT_ROUTER_DEBUG__;function h(...n){d&&console.log("[IntentRouter]",...n)}function m(n){if(!n)return"";const t=new URLSearchParams;for(const e in n){const r=n[e];null!=r&&(Array.isArray(r)?r.forEach(n=>t.append(e,String(n))):t.append(e,String(r)))}const e=t.toString();return e?`?${e}`:""}function I(n){c=n,u||(o.$onMultiple("INTENT_NAVIGATE",g),u=!0)}function x(n,t,e,r){h("emit",n,{params:t,query:e});const s={intent:n,params:t,query:e,...r?{options:r}:{}};o.$emit("INTENT_NAVIGATE",s),i&&i.$emit("INTENT_NAVIGATE",s)}async function g(n){const t=s[n.intent];if(h("receive",n.intent,n),!t)return l&&c?.(l),void console.warn("Unknown intent:",n.intent);const e=N(t,n.params);for(const t of a){const r=await t(n.intent,e);if(!1===r)return;if("string"==typeof r)return void c?.(r,n.options)}const r=p[n.intent]||[];for(const t of r){const r=await t(n.intent,e);if(!1===r)return;if("string"==typeof r)return void c?.(r,n.options)}E(n.intent);const o=y(t,e)+m(n.query);h("navigate",{intent:n.intent,params:e,query:n.query,url:o}),c?.(o,n.options),i&&i.$emit("INTENT_NAVIGATE",n)}function E(n){const t=f[n];if(t)for(const n of t)try{const t=n();t instanceof Promise&&t.catch(()=>{})}catch{}}function N(n,t){const e=function(n){const t=[];return n.replace(/:([A-Za-z0-9_]+)/g,(n,e)=>(t.push(e),"")),t}(n);if(!t)return{};if(Array.isArray(t)){const n={};return e.forEach((e,r)=>{void 0===t[r]&&console.warn(`Missing param "${e}"`),n[e]=t[r]}),n}return"object"==typeof t?t:1===e.length?{[e[0]]:t}:{}}function y(n,t){return n.replace(/:([A-Za-z0-9_]+)/g,(n,e)=>{const r=t[e];return void 0!==r?encodeURIComponent(r):""})}function T(n,t,e){const r=s[n];if(!r)return"";return y(r,N(r,t))+m(e)}function A(n){const[t,e]=n.split("?"),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 s){const e=s[n],o=[],i=new RegExp("^"+e.replace(/:([A-Za-z0-9_]+)/g,(n,t)=>(o.push(t),"([^/]+)"))+"$"),c=t.match(i);if(!c)continue;const u={};return o.forEach((n,t)=>{u[n]=decodeURIComponent(c[t+1])}),{intent:n,params:u,query:r}}return null}function v(){const n=e.useLocation(),t=A(n.pathname),r=new URLSearchParams(n.search),o={};return r.forEach((n,t)=>{o[t]=n}),{intent:t?.intent??null,params:t?.params??{},query:o}}function w({navigate:n}){const t=e.useNavigate();return I(n||t),null}exports.IntentLink=function({intent:n,params:r,query:o,children:i,replace:s,scrollTop:c}){const u=T(n,r,o);return t.jsx(e.Link,{to:u,replace:s,onClick:()=>{c&&window.scrollTo(0,0)},children:i})},exports.IntentRoute=function({intent:n,component:e,fallback:r=null,loading:o,guard:i}){const s=v();return s?s.intent!==n?null:i&&!i(s)?t.jsx(t.Fragment,{children:r}):t.jsx(e,{...s}):o??null},exports.IntentRouter=function({children:n}){return t.jsxs(e.BrowserRouter,{children:[t.jsx(w,{}),n]})},exports.RouterBinder=w,exports.addIntentGuard=function(n){a.push(n)},exports.addIntentGuardFor=function(n,t){p[n]||(p[n]=[]),p[n].push(t)},exports.addIntentPreload=function(n,t){f[n]||(f[n]=[]),f[n].push(t)},exports.bindNavigate=I,exports.createIntentRouter=function(n){s=n,h("intent map loaded",n)},exports.generatePathFromIntent=T,exports.navigateIntent=x,exports.preloadIntent=function(n){E(n)},exports.resolveIntentFromUrl=A,exports.setFallbackPath=function(n){l=n},exports.setSharedBus=function(n){i=n,i.$onMultiple("INTENT_NAVIGATE",g)},exports.useIntentRouter=v,exports.useNavigateIntent=function(){const n=e.useNavigate();return r.useEffect(()=>{I(n)},[n]),x};
@@ -1,9 +1,10 @@
1
- import React from "react";
2
1
  type Props = {
3
2
  intent: string;
4
3
  params?: any;
5
4
  query?: Record<string, any>;
6
5
  children: React.ReactNode;
6
+ replace?: boolean;
7
+ scrollTop?: boolean;
7
8
  };
8
- export declare function IntentLink({ intent, params, query, children }: Props): JSX.Element;
9
+ export declare function IntentLink({ intent, params, query, children, replace, scrollTop }: Props): JSX.Element;
9
10
  export {};
@@ -1,7 +1,10 @@
1
- import React from "react";
1
+ import type { IntentData } from "./useIntentRouter";
2
2
  type Props = {
3
3
  intent: string;
4
4
  component: React.ComponentType<any>;
5
+ fallback?: React.ReactNode;
6
+ loading?: React.ReactNode;
7
+ guard?: (data: IntentData) => boolean;
5
8
  };
6
- export declare function IntentRoute({ intent, component: Component }: Props): JSX.Element | null;
9
+ export declare function IntentRoute({ intent, component: Component, fallback, loading, guard, }: Props): React.ReactNode;
7
10
  export {};
@@ -0,0 +1,5 @@
1
+ type Props = {
2
+ children: React.ReactNode;
3
+ };
4
+ export declare function IntentRouter({ children }: Props): JSX.Element;
5
+ export {};
@@ -1,5 +1,6 @@
1
1
  export * from "./IntentLink";
2
2
  export * from "./IntentRoute";
3
+ export * from "./IntentRouter";
3
4
  export * from "./RouterBinder";
4
- export * from "./useIntent";
5
+ export * from "./useIntentRouter";
5
6
  export * from "./useNavigateIntent";
@@ -0,0 +1,6 @@
1
+ export type IntentData<P = any> = {
2
+ intent?: string | null;
3
+ params?: P | any[] | string | number;
4
+ query?: Record<string, any>;
5
+ };
6
+ export declare function useIntentRouter(): IntentData;
package/package.json CHANGED
@@ -1,10 +1,9 @@
1
1
  {
2
2
  "name": "intentx-react-router",
3
- "version": "0.2.1",
3
+ "version": "1.0.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
-
8
7
  "type": "module",
9
8
  "main": "./build/index.js",
10
9
  "module": "./build/index.esm.js",
@@ -16,7 +15,6 @@
16
15
  "require": "./build/index.js"
17
16
  }
18
17
  },
19
-
20
18
  "files": [
21
19
  "build"
22
20
  ],
@@ -27,11 +25,9 @@
27
25
  "watch": "rollup -c -w",
28
26
  "typecheck": "tsc --noEmit"
29
27
  },
30
-
31
28
  "engines": {
32
29
  "node": ">=16"
33
30
  },
34
-
35
31
  "repository": {
36
32
  "type": "git",
37
33
  "url": "https://github.com/delpikye-v/intentx-react-router.git"
@@ -52,7 +48,6 @@
52
48
  "spa",
53
49
  "routing"
54
50
  ],
55
-
56
51
  "peerDependencies": {
57
52
  "react": ">=18",
58
53
  "react-dom": ">=18",
@@ -79,7 +74,6 @@
79
74
  "tslib": "^2.6.2",
80
75
  "typescript": "^5.0.0"
81
76
  },
82
-
83
77
  "publishConfig": {
84
78
  "access": "public"
85
79
  }
@@ -1,5 +0,0 @@
1
- export declare function useIntent(): {
2
- intent: string | null;
3
- params: Record<string, any>;
4
- query: Record<string, string>;
5
- };