jong-router 0.1.13 → 0.1.14
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 +151 -51
- package/dist/about-component.d.ts +4 -0
- package/dist/guard.d.ts +2 -0
- package/dist/home-component.d.ts +4 -0
- package/dist/jong-router.d.ts +15 -11
- package/dist/jong-router.min.js +1 -1
- package/dist/notfound-component.d.ts +4 -0
- package/dist/profile-component.d.ts +6 -0
- package/dist/team-component.d.ts +5 -0
- package/package.json +17 -3
- package/router-instance.ts +30 -0
package/README.md
CHANGED
|
@@ -1,30 +1,36 @@
|
|
|
1
|
-
|
|
1
|
+
[](https://nodei.co/npm/jong-router/)
|
|
2
2
|
|
|
3
|
+
# JongRouter
|
|
3
4
|
|
|
4
5
|
|
|
5
|
-
A lightweight and simple-to-use web components router in Vanilla JavaScript with support for guards, nested routes, page not found, passing query parameters to components, passing route parameters to components, passing route data to components, and a router link for single-page application navigation without reloading the page.
|
|
6
6
|
|
|
7
|
+
JongRouter is a lightweight client-side router for Web Components, built with Vanilla JavaScript.
|
|
8
|
+
It enables Single Page Application (SPA) navigation without page reloads while staying framework-agnostic.
|
|
9
|
+
Designed for developers who want a simple router for Web Components without bringing in a heavy framework.
|
|
7
10
|
|
|
8
11
|
|
|
9
12
|
## Features
|
|
10
13
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
14
|
+
* SPA Navigation
|
|
15
|
+
Navigate without reloading the page using the router-link attribute.
|
|
16
|
+
* Route Guards
|
|
17
|
+
Protect routes with custom guard logic before navigation.
|
|
18
|
+
* Nested Routing
|
|
19
|
+
Easily compose child routers inside Web Components.
|
|
20
|
+
* Shadow DOM Support
|
|
21
|
+
Works seamlessly with Web Components using Shadow DOM.
|
|
22
|
+
* Route Parameters
|
|
23
|
+
Dynamic routes like `/profile/:username`.
|
|
24
|
+
* Query Parameters
|
|
25
|
+
Access query strings like `/profile/jong?tab=settings`.
|
|
26
|
+
* Route Data
|
|
27
|
+
Pass static metadata to components.
|
|
28
|
+
* Programmatic Navigation
|
|
29
|
+
Navigate using `router.navigateTo()`.
|
|
30
|
+
* 404 Page Handling
|
|
31
|
+
Built-in fallback route using **.
|
|
32
|
+
* Buttons & Links Support
|
|
33
|
+
Works with both <a> and <button> elements.
|
|
28
34
|
|
|
29
35
|
|
|
30
36
|
|
|
@@ -71,19 +77,23 @@ npm i jong-router
|
|
|
71
77
|
|
|
72
78
|
```javascript
|
|
73
79
|
|
|
74
|
-
const
|
|
80
|
+
const routes = [
|
|
75
81
|
|
|
76
82
|
{ pattern: '/', component: import('./components/HomeComponent') },
|
|
77
83
|
|
|
78
84
|
{ pattern: '/about', component: import('./components/AboutComponent') },
|
|
79
85
|
|
|
80
|
-
|
|
86
|
+
{ pattern: '**', html: `<h2>Page not found</h2>` }
|
|
81
87
|
|
|
82
|
-
]
|
|
88
|
+
]
|
|
83
89
|
|
|
90
|
+
const router = new JongRouter(
|
|
91
|
+
routes,
|
|
92
|
+
document.getElementById('app')
|
|
93
|
+
)
|
|
84
94
|
|
|
95
|
+
router.init()
|
|
85
96
|
|
|
86
|
-
router.init();
|
|
87
97
|
|
|
88
98
|
```
|
|
89
99
|
|
|
@@ -99,22 +109,19 @@ Create your web components for each route.
|
|
|
99
109
|
|
|
100
110
|
```javascript
|
|
101
111
|
|
|
102
|
-
// Example: HomeComponent.js
|
|
103
|
-
|
|
104
112
|
class HomeComponent extends HTMLElement {
|
|
105
113
|
|
|
106
114
|
connectedCallback() {
|
|
107
115
|
|
|
108
|
-
this.innerHTML =
|
|
116
|
+
this.innerHTML = `<h1>Home Page</h1>`
|
|
109
117
|
|
|
110
118
|
}
|
|
111
119
|
|
|
112
120
|
}
|
|
113
121
|
|
|
122
|
+
customElements.define('home-component', HomeComponent)
|
|
114
123
|
|
|
115
124
|
|
|
116
|
-
customElements.define('home-component', HomeComponent);
|
|
117
|
-
|
|
118
125
|
```
|
|
119
126
|
|
|
120
127
|
|
|
@@ -137,9 +144,35 @@ Use the `router-link` attribute to create navigation links.
|
|
|
137
144
|
|
|
138
145
|
```
|
|
139
146
|
|
|
147
|
+
Buttons also work with router-link
|
|
148
|
+
```html
|
|
149
|
+
<button router-link href="/about">
|
|
150
|
+
Go to About
|
|
151
|
+
</button>
|
|
152
|
+
```
|
|
140
153
|
|
|
154
|
+
4. Programmatic Navigation
|
|
155
|
+
Components can navigate programmatically.
|
|
141
156
|
|
|
142
|
-
|
|
157
|
+
```js
|
|
158
|
+
import { router } from "../router-instance"
|
|
159
|
+
|
|
160
|
+
router.navigateTo("/profile/admin")
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Example inside a component
|
|
164
|
+
```js
|
|
165
|
+
this.shadowRoot
|
|
166
|
+
.getElementById("btn")
|
|
167
|
+
.addEventListener("click", () => {
|
|
168
|
+
|
|
169
|
+
router.navigateTo("/profile/admin")
|
|
170
|
+
|
|
171
|
+
})
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
5. **Guards**
|
|
143
176
|
|
|
144
177
|
|
|
145
178
|
|
|
@@ -170,9 +203,11 @@ const router = new JongRouter([
|
|
|
170
203
|
|
|
171
204
|
|
|
172
205
|
|
|
173
|
-
function isAuthenticated() {
|
|
206
|
+
function isAuthenticated(ctx) {
|
|
174
207
|
|
|
175
208
|
// Your authentication logic here
|
|
209
|
+
console.log(ctx.path)
|
|
210
|
+
console.log(ctx.params)
|
|
176
211
|
|
|
177
212
|
return true;
|
|
178
213
|
|
|
@@ -182,44 +217,109 @@ function isAuthenticated() {
|
|
|
182
217
|
|
|
183
218
|
|
|
184
219
|
|
|
185
|
-
|
|
186
|
-
|
|
220
|
+
6. **Handle Route Parameters and Query Parameters:**
|
|
187
221
|
|
|
188
222
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
class UserComponent extends HTMLElement {
|
|
198
|
-
|
|
199
|
-
connectedCallback() {
|
|
200
|
-
|
|
201
|
-
const routeParams = JSON.parse(this.getAttribute('route-params'));
|
|
223
|
+
Define dynamic routes Parameter:
|
|
224
|
+
```js
|
|
225
|
+
{
|
|
226
|
+
pattern: "/profile/:username",
|
|
227
|
+
component: import("./ProfileComponent")
|
|
228
|
+
}
|
|
229
|
+
```
|
|
202
230
|
|
|
203
|
-
|
|
231
|
+
Access inside the component
|
|
232
|
+
```js
|
|
233
|
+
const params = JSON.parse(
|
|
234
|
+
this.getAttribute("route-params")
|
|
235
|
+
)
|
|
204
236
|
|
|
237
|
+
console.log(params.username)
|
|
238
|
+
```
|
|
205
239
|
|
|
206
240
|
|
|
207
|
-
|
|
241
|
+
Define query parameter
|
|
242
|
+
```js
|
|
243
|
+
/profile/jong?tab=settings
|
|
244
|
+
```
|
|
208
245
|
|
|
209
|
-
|
|
246
|
+
Inside component
|
|
247
|
+
```js
|
|
248
|
+
const query = JSON.parse(
|
|
249
|
+
this.getAttribute("query-params")
|
|
250
|
+
)
|
|
210
251
|
|
|
211
|
-
|
|
252
|
+
console.log(query.tab)
|
|
253
|
+
```
|
|
212
254
|
|
|
213
|
-
|
|
255
|
+
7. **Route Data**
|
|
256
|
+
Attach metadata to routes
|
|
214
257
|
|
|
258
|
+
```js
|
|
259
|
+
{
|
|
260
|
+
pattern: "/profile/:username",
|
|
261
|
+
component: import("./ProfileComponent"),
|
|
262
|
+
data: { role: "admin" }
|
|
215
263
|
}
|
|
264
|
+
```
|
|
265
|
+
Access in component
|
|
266
|
+
```js
|
|
267
|
+
const data = JSON.parse(
|
|
268
|
+
this.getAttribute("route-data")
|
|
269
|
+
)
|
|
270
|
+
```
|
|
216
271
|
|
|
217
272
|
|
|
273
|
+
8. **Nested Routes**
|
|
274
|
+
JongRouter supports child routers inside components.
|
|
218
275
|
|
|
219
|
-
|
|
276
|
+
Example
|
|
277
|
+
```bash
|
|
278
|
+
/nested
|
|
279
|
+
├─ /nested/c1
|
|
280
|
+
├─ /nested/c2
|
|
281
|
+
└─ /nested/c3
|
|
282
|
+
```
|
|
220
283
|
|
|
284
|
+
A parent component can create its own router instance
|
|
285
|
+
```js
|
|
286
|
+
const childRouter = new JongRouter(
|
|
287
|
+
childRoutes,
|
|
288
|
+
this.shadowRoot.getElementById("outlet"),
|
|
289
|
+
"/nested",
|
|
290
|
+
true
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
childRouter.init()
|
|
221
294
|
```
|
|
222
295
|
|
|
296
|
+
## Playground & Examples
|
|
297
|
+
Playground & Examples
|
|
298
|
+
The repository contains a Playground demonstrating:
|
|
299
|
+
* Basic routing
|
|
300
|
+
* Guarded routes
|
|
301
|
+
* Nested routes
|
|
302
|
+
* Query parameters
|
|
303
|
+
* Route parameters
|
|
304
|
+
* Programmatic navigation
|
|
305
|
+
* Buttons & router-link navigation
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
# Why JongRouter?
|
|
309
|
+
JongRouter focuses on simplicity and Web Component compatibility.
|
|
310
|
+
Unlike many routers, it:
|
|
311
|
+
* Works without frameworks
|
|
312
|
+
* Supports Shadow DOM
|
|
313
|
+
* Keeps the API extremely small
|
|
314
|
+
* Is easy to embed in micro-frontend architectures
|
|
315
|
+
|
|
316
|
+
Perfect for:
|
|
317
|
+
* Web Component apps
|
|
318
|
+
* Micro-frontends
|
|
319
|
+
* Lightweight SPAs
|
|
320
|
+
* Vanilla JS projects
|
|
321
|
+
|
|
322
|
+
|
|
223
323
|
## How to run development server?
|
|
224
324
|
```
|
|
225
325
|
git clone git@github.com:josnin/jong-router.git
|
package/dist/guard.d.ts
ADDED
package/dist/jong-router.d.ts
CHANGED
|
@@ -1,26 +1,30 @@
|
|
|
1
|
-
interface
|
|
1
|
+
export interface GuardContext {
|
|
2
|
+
path?: string;
|
|
3
|
+
params?: Record<string, string>;
|
|
4
|
+
query?: URLSearchParams;
|
|
5
|
+
data?: any;
|
|
6
|
+
}
|
|
7
|
+
export interface IRoute {
|
|
2
8
|
pattern: string;
|
|
3
9
|
component?: Promise<any>;
|
|
4
10
|
html?: string;
|
|
5
|
-
|
|
11
|
+
children?: IRoute[];
|
|
12
|
+
guards?: ((ctx?: any) => boolean)[];
|
|
6
13
|
redirect?: string;
|
|
7
|
-
data?: any
|
|
14
|
+
data?: Record<string, any>;
|
|
8
15
|
}
|
|
9
16
|
declare class JongRouter {
|
|
10
17
|
private routes;
|
|
11
18
|
private outlet;
|
|
12
|
-
private
|
|
13
|
-
|
|
19
|
+
private basePath;
|
|
20
|
+
private isRoot;
|
|
21
|
+
constructor(routes: IRoute[], outlet: HTMLElement, basePath?: string, isRoot?: boolean);
|
|
14
22
|
init(): void;
|
|
15
|
-
private setupNavigation;
|
|
16
|
-
private navigate;
|
|
17
|
-
private loadContent;
|
|
18
|
-
private loadComponent;
|
|
19
23
|
private handleClick;
|
|
24
|
+
private navigate;
|
|
25
|
+
private renderRoute;
|
|
20
26
|
private matchRoute;
|
|
21
|
-
private extractQueryParams;
|
|
22
27
|
private extractRouteParams;
|
|
23
28
|
navigateTo(route: string): void;
|
|
24
29
|
}
|
|
25
|
-
export { IRoute };
|
|
26
30
|
export default JongRouter;
|
package/dist/jong-router.min.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var
|
|
1
|
+
var s=class c{routes;outlet;basePath;isRoot;constructor(t,a,i="",n=!1){this.routes=t,this.outlet=a,this.basePath=i,this.isRoot=n}init(){this.isRoot&&(window.addEventListener("popstate",()=>this.navigate()),document.addEventListener("click",t=>this.handleClick(t))),this.navigate()}handleClick(t){let i=t.composedPath().find(e=>(e instanceof HTMLAnchorElement||e instanceof HTMLButtonElement)&&e.hasAttribute("router-link"));if(!i)return;let n=i.getAttribute("href");!n||n.startsWith("http")||t instanceof MouseEvent&&(t.metaKey||t.ctrlKey||t.shiftKey||t.altKey)||(t.preventDefault(),this.navigateTo(n))}navigate(){let t=window.location.pathname,a=this.routes.find(n=>this.matchRoute(n.pattern,t));if(!a)return;let i=this.extractRouteParams(a.pattern,t);this.renderRoute(a,i)}async renderRoute(t,a){if(t.guards){let i={path:window.location.pathname,params:a,query:new URLSearchParams(window.location.search),data:t.data};if(!t.guards.every(e=>e(i))){t.redirect&&this.navigateTo(t.redirect);return}}if(t.component){let n=(await t.component).default,e=new n;if(e.setAttribute("route-params",JSON.stringify(a)),e.router=this,this.outlet.innerHTML="",this.outlet.appendChild(e),t.children){let o=e.shadowRoot?.querySelector("[router-outlet]")||e.querySelector("[router-outlet]");o&&new c(t.children,o,t.pattern).navigate()}}else t.html&&(this.outlet.innerHTML=t.html)}matchRoute(t,a){if(t==="**")return!0;let i=t.split("/").filter(Boolean),n=a.split("/").filter(Boolean);return i.length>n.length?!1:i.every((e,o)=>e.startsWith(":")||e===n[o])}extractRouteParams(t,a){let i={},n=t.split("/").filter(Boolean),e=a.split("/").filter(Boolean);return n.forEach((o,r)=>{o.startsWith(":")&&(i[o.slice(1)]=e[r])}),i}navigateTo(t){window.history.pushState({},"",t),this.navigate()}},h=s;export{h as default};
|
|
2
2
|
//# sourceMappingURL=jong-router.min.js.map
|
package/package.json
CHANGED
|
@@ -1,11 +1,25 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jong-router",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.1.14",
|
|
4
|
+
"description": "JongRouter is a lightweight client-side router for Web Components, built with Vanilla JavaScript. It enables Single Page Application (SPA) navigation without page reloads while staying framework-agnostic.Designed for developers who want a simple router for Web Components without bringing in a heavy framework",
|
|
5
5
|
"keywords": [
|
|
6
|
+
"redgin",
|
|
7
|
+
"ScalpelJS",
|
|
6
8
|
"jong-router",
|
|
9
|
+
"web-components",
|
|
7
10
|
"web components router",
|
|
8
|
-
"custom elements"
|
|
11
|
+
"custom elements",
|
|
12
|
+
"vanilla javascript",
|
|
13
|
+
"spa",
|
|
14
|
+
"single-page application",
|
|
15
|
+
"client-side router",
|
|
16
|
+
"frontend router",
|
|
17
|
+
"nested routes",
|
|
18
|
+
"route guards",
|
|
19
|
+
"query parameters",
|
|
20
|
+
"route parameters",
|
|
21
|
+
"javascript router",
|
|
22
|
+
"microfrontend"
|
|
9
23
|
],
|
|
10
24
|
"main": "dist/jong-router.min.js",
|
|
11
25
|
"types": "dist/jong-router.d.ts",
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// index.ts
|
|
2
|
+
import JongRouter, { IRoute } from './src/jong-router'
|
|
3
|
+
import { authencationGuard } from './src/guard'
|
|
4
|
+
|
|
5
|
+
const routes: IRoute[] = [
|
|
6
|
+
{ pattern: '/about', html: `<h2>About Page</h2>` },
|
|
7
|
+
{ pattern: '/profile/:username', component: import('./samples/profile/profile-component') },
|
|
8
|
+
{ pattern: '/tryguard1/:teamId', component: import('./samples/guards/team-component'), guards: [authencationGuard], redirect: '/login' },
|
|
9
|
+
{ pattern: '/login', html: `<h2>Login Page</h2>` },
|
|
10
|
+
{
|
|
11
|
+
pattern: "/programmatic",
|
|
12
|
+
component: import("./samples/programmatic/programmatic-navigation"),
|
|
13
|
+
},
|
|
14
|
+
|
|
15
|
+
{
|
|
16
|
+
pattern: '/nested',
|
|
17
|
+
component: import('./samples/nested/sample-nested'),
|
|
18
|
+
children: [
|
|
19
|
+
{ pattern: '/nested/c1', html: '<p>Nested C1 Page</p>' },
|
|
20
|
+
{ pattern: '/nested/c2', html: '<p>Nested C2 Page</p>' },
|
|
21
|
+
{ pattern: '/nested/c3', html: '<p>Nested C3 Page</p>' },
|
|
22
|
+
{ pattern: '**', html: '<p>Nested 404</p>' }
|
|
23
|
+
]
|
|
24
|
+
},
|
|
25
|
+
{ pattern: '**', html: `<h2>404 Page</h2>` }
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
export const router = new JongRouter(routes, document.getElementById('app')!, '', true)
|
|
29
|
+
router.init()
|
|
30
|
+
|