intentx-react-router 0.1.1 → 0.1.2

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
@@ -39,14 +39,22 @@ navigateIntent("edit-user", 42)
39
39
  # Installation
40
40
 
41
41
  ```bash
42
- npm install intentx-react-router eventbus-z react-router
42
+ npm install intentx-react-router eventbus-z react-router@^7 react-router-dom@^7
43
43
  ```
44
44
 
45
+ ## Recommended Versions
46
+
47
+ - react: >=18
48
+ - react-dom: >=18
49
+ - react-router: >=7
50
+ - react-router-dom: >=7
51
+ - eventbus-z: ^2.4.0
52
+
45
53
  ---
46
54
 
47
55
  # Basic Setup
48
56
 
49
- ## Define intents
57
+ ## 1. Define intents
50
58
 
51
59
  ``` ts
52
60
  import { createIntentRouter } from "intentx-react-router"
@@ -54,31 +62,124 @@ import { createIntentRouter } from "intentx-react-router"
54
62
  createIntentRouter({
55
63
  "view-user": "/users/:userId/name/:page",
56
64
  "edit-user": "/users/:userId/edit",
57
- "open-cart": "/cart",
58
65
  "checkout": "/checkout"
59
66
  })
60
67
  ```
61
68
 
62
69
  ---
63
70
 
64
- ## Bind React Router navigate
71
+ ## 2. Bind React Router navigate
65
72
 
66
73
  ``` ts
74
+ import React from "react"
75
+ import { useNavigate } from "react-router-dom"
67
76
  import { bindNavigate } from "intentx-react-router"
68
77
 
69
- import { useNavigate } from "react-router"
70
-
71
- function RouterBinder() {
78
+ export function RouterBinder() {
72
79
  const navigate = useNavigate()
73
-
74
80
  bindNavigate(navigate)
75
-
76
81
  return null
77
82
  }
78
83
  ```
79
84
 
80
85
  ---
81
86
 
87
+ ## 3. IntentLink
88
+
89
+ ```ts
90
+ import React from "react"
91
+ import { Link } from "react-router-dom"
92
+ import { generatePathFromIntent } from "intentx-react-router"
93
+
94
+ export function IntentLink({ intent, params, query, children }) {
95
+ let path = generatePathFromIntent(intent, params)
96
+ if (query) {
97
+ const qs = new URLSearchParams(query).toString()
98
+ if (qs) path += "?" + qs
99
+ }
100
+ return <Link to={path}>{children}</Link>
101
+ }
102
+ ```
103
+
104
+ ---
105
+
106
+ ## 4. IntentRoute
107
+
108
+ ---
109
+
110
+ ```ts
111
+ import React from "react"
112
+ import { Route } from "react-router-dom"
113
+ import { generatePathFromIntent } from "intentx-react-router"
114
+
115
+ export function IntentRoute({ intent, component: Component }) {
116
+ const path = generatePathFromIntent(intent)
117
+ return <Route path={path} render={(props) => <Component {...props} />} />
118
+ }
119
+ ```
120
+
121
+ ---
122
+
123
+ ## 5. Use in App
124
+
125
+ ```ts
126
+ import React from "react"
127
+ import { BrowserRouter, Switch } from "react-router-dom"
128
+ import { RouterBinder, IntentLink, IntentRoute } from "./router"
129
+
130
+ import { UserPage } from "./pages/UserPage"
131
+ import { EditUserPage } from "./pages/EditUserPage"
132
+ import { CheckoutPage } from "./pages/CheckoutPage"
133
+
134
+ export default function App() {
135
+ return (
136
+ <BrowserRouter>
137
+ <RouterBinder />
138
+
139
+ <nav style={{ marginBottom: 20 }}>
140
+ <IntentLink intent="view-user" params={[1, 2]}>View User</IntentLink>{" "}
141
+ | <IntentLink intent="edit-user" params={1}>Edit User</IntentLink>{" "}
142
+ | <IntentLink intent="checkout">Checkout</IntentLink>
143
+ </nav>
144
+
145
+ <Switch>
146
+ <IntentRoute intent="view-user" component={UserPage} />
147
+ <IntentRoute intent="edit-user" component={EditUserPage} />
148
+ <IntentRoute intent="checkout" component={CheckoutPage} />
149
+ </Switch>
150
+ </BrowserRouter>
151
+ )
152
+ }
153
+ ```
154
+
155
+ ---
156
+
157
+ ## 6. useIntent Hook
158
+
159
+ ```ts
160
+ import { useLocation } from "react-router-dom"
161
+ import { resolveIntentFromUrl } from "intentx-react-router"
162
+
163
+ export function useIntent() {
164
+ const location = useLocation()
165
+ const resolved = resolveIntentFromUrl(location.pathname)
166
+
167
+ const searchParams = new URLSearchParams(location.search)
168
+ const query = {}
169
+ searchParams.forEach((value, key) => {
170
+ query[key] = value
171
+ })
172
+
173
+ return {
174
+ intent: resolved?.intent ?? null,
175
+ params: resolved?.params ?? {},
176
+ query
177
+ }
178
+ }
179
+ ```
180
+
181
+ ---
182
+
82
183
  # Navigation
83
184
 
84
185
  ## Object params
@@ -1,2 +1 @@
1
1
  export * from "./intentCore";
2
- export * from "./IntentRoute";
@@ -1 +1 @@
1
- import{createEventBus as n}from"eventbus-z";import{jsx as t}from"react/jsx-runtime";import{useLocation as r,Link as o,useNavigate as e}from"react-router";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(){var n,t;const o=r(),e=N(o.pathname),i=new URLSearchParams(o.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 R({intent:n,component:r}){const o=P();return o.intent!==n?null:t(r,{...o})}function S({intent:n,params:r,query:e,children:i}){let c=x(n,r);if(e){const n=new URLSearchParams(e).toString();n&&(c+="?"+n)}return t(o,{to:c,children:i})}function T(){const n=e();return i(()=>{v(n)},[n]),d}export{S as IntentLink,R as IntentRoute,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,P as useIntent,T as useNavigateIntent};
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 d(n){f=n,a||(c.$onMultiple(u,E),a=!0)}function v(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(n){const t=e();return d(n||t),null}function U(){const n=e();return i(()=>{d(n)},[n]),v}export{P as IntentLink,S as IntentRoute,T as RouterBinder,g as addIntentGuard,y as addIntentGuardFor,A as addIntentPreload,d as bindNavigate,h as createIntentRouter,x as generatePathFromIntent,v as navigateIntent,w as preloadIntent,N as resolveIntentFromUrl,R as useIntent,U 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"),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,h),c=!0)}function d(n,t){o.$emit(i,{intent:n,params:t})}function h(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))}v(n.intent);const o=x(t,e);null==s||s(o)}function v(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.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){v(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(),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(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};
@@ -0,0 +1 @@
1
+ export declare function RouterBinder(navigate?: any): null;
@@ -1,3 +1,5 @@
1
1
  export * from "./IntentLink";
2
+ export * from "./IntentRoute";
3
+ export * from "./RouterBinder";
2
4
  export * from "./useIntent";
3
5
  export * from "./useNavigateIntent";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "intentx-react-router",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Intent-based routing for React. Navigate by intent instead of URLs.",
5
5
  "author": "Delpi.Kye",
6
6
  "license": "MIT",
@@ -55,7 +55,9 @@
55
55
 
56
56
  "peerDependencies": {
57
57
  "react": ">=18",
58
- "react-router": ">=6"
58
+ "react-dom": ">=18",
59
+ "react-router": "^7.0.0",
60
+ "react-router-dom": "^7.0.0"
59
61
  },
60
62
  "dependencies": {
61
63
  "eventbus-z": "^2.4.0"
@@ -68,6 +70,8 @@
68
70
  "@types/react-dom": "^18.0.0",
69
71
  "react": "^18.0.0",
70
72
  "react-dom": "^18.0.0",
73
+ "react-router": "^7.13.1",
74
+ "react-router-dom": "^7.13.1",
71
75
  "rimraf": "^5.0.5",
72
76
  "rollup": "^3.29.4",
73
77
  "rollup-plugin-peer-deps-external": "^2.2.4",
File without changes