jong-router 0.1.14 → 0.1.15

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
@@ -12,7 +12,7 @@ Designed for developers who want a simple router for Web Components without brin
12
12
  ## Features
13
13
 
14
14
  * SPA Navigation
15
- Navigate without reloading the page using the router-link attribute.
15
+ Navigate without reloading the page using the `router-link` attribute.
16
16
  * Route Guards
17
17
  Protect routes with custom guard logic before navigation.
18
18
  * Nested Routing
@@ -154,6 +154,8 @@ Go to About
154
154
  4. Programmatic Navigation
155
155
  Components can navigate programmatically.
156
156
 
157
+ Example outside component
158
+
157
159
  ```js
158
160
  import { router } from "../router-instance"
159
161
 
@@ -166,7 +168,7 @@ this.shadowRoot
166
168
  .getElementById("btn")
167
169
  .addEventListener("click", () => {
168
170
 
169
- router.navigateTo("/profile/admin")
171
+ this.navigateTo("/profile/admin")
170
172
 
171
173
  })
172
174
  ```
@@ -180,7 +182,7 @@ Implement guards for route conditions
180
182
 
181
183
 
182
184
 
183
- ```javascript
185
+ ```js
184
186
 
185
187
  const router = new JongRouter([
186
188
 
@@ -270,29 +272,66 @@ const data = JSON.parse(
270
272
  ```
271
273
 
272
274
 
273
- 8. **Nested Routes**
274
- JongRouter supports child routers inside components.
275
+ 8. **Nested Routes & Sub-Outlest**
276
+
277
+ JongRouter supports hierarchical routing. This allows you to render a "Shell" or "Layout" component and then inject sub-pages into it dynamically.
278
+
279
+ Step 1: Define Child Routes
280
+ Create a separate file for your sub-navigation.
275
281
 
276
282
  Example
277
- ```bash
278
- /nested
279
- ├─ /nested/c1
280
- ├─ /nested/c2
281
- └─ /nested/c3
283
+ ```ts
284
+ // samples/nested/nested-routes.ts
285
+ import { IRoute } from "../../src/jong-router"
286
+
287
+ const routes: IRoute[] = [
288
+ { pattern: "/nested/c1", html: "<p>Child Page 1</p>" },
289
+ { pattern: "/nested/c2", html: "<p>Child Page 2</p>" },
290
+ { pattern: "/nested/c3", html: "<p>Child Page 3</p>" }
291
+ ]
292
+
293
+ export default routes
294
+
282
295
  ```
283
296
 
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
- )
297
+ Step 2: Prepare the Parent Component
298
+ Your parent component must contain an element with the router-outlet attribute. This is where the child routes will be rendered.
299
+
300
+ A parent component can create its own router instance w children routes
301
+ ```ts
302
+ // samples/nested/sample-nested.ts
303
+ export default class SampleNested extends HTMLElement {
304
+ connectedCallback() {
305
+ this.innerHTML = `
306
+ <div class="layout">
307
+ <nav>
308
+ <a href="/nested/c1" router-link>Go to C1</a>
309
+ <a href="/nested/c2" router-link>Go to C2</a>
310
+ </nav>
311
+ <!-- Child routes will appear here -->
312
+ <div router-outlet></div>
313
+ </div>
314
+ `;
315
+ }
316
+ }
317
+
318
+ ```
319
+
320
+ Step 3: Register Nested Routes
321
+ Pass the children to the parent route. You can use a static array or a function for Lazy Loading.
322
+ ```ts
323
+ const routes: IRoute[] = [
324
+ {
325
+ pattern: '/nested',
326
+ component: import('./samples/nested/sample-nested'),
327
+ // Lazy-load the child route definitions
328
+ children: () => import("./samples/nested/nested-routes")
329
+ }
330
+ ]
292
331
 
293
- childRouter.init()
294
332
  ```
295
333
 
334
+
296
335
  ## Playground & Examples
297
336
  Playground & Examples
298
337
  The repository contains a Playground demonstrating:
@@ -1,14 +1,22 @@
1
+ /**
2
+ * Context passed to Route Guards to decide if a user can access a route.
3
+ */
1
4
  export interface GuardContext {
2
5
  path?: string;
3
6
  params?: Record<string, string>;
4
7
  query?: URLSearchParams;
5
8
  data?: any;
6
9
  }
10
+ /**
11
+ * Definition of a single Route.
12
+ */
7
13
  export interface IRoute {
8
14
  pattern: string;
9
15
  component?: Promise<any>;
10
16
  html?: string;
11
- children?: IRoute[];
17
+ children?: IRoute[] | (() => Promise<{
18
+ default: IRoute[];
19
+ }>);
12
20
  guards?: ((ctx?: any) => boolean)[];
13
21
  redirect?: string;
14
22
  data?: Record<string, any>;
@@ -16,15 +24,34 @@ export interface IRoute {
16
24
  declare class JongRouter {
17
25
  private routes;
18
26
  private outlet;
19
- private basePath;
20
- private isRoot;
21
- constructor(routes: IRoute[], outlet: HTMLElement, basePath?: string, isRoot?: boolean);
27
+ constructor(routes: IRoute[], outlet: HTMLElement);
28
+ /**
29
+ * Starts the router by listening to browser events and initial navigation.
30
+ */
22
31
  init(): void;
32
+ /**
33
+ * Intercepts clicks to handle internal navigation without refreshing the page.
34
+ */
23
35
  private handleClick;
36
+ /**
37
+ * Matches the current browser URL against the route table and triggers rendering.
38
+ */
24
39
  private navigate;
40
+ /**
41
+ * Handles Guards, Component instantiation, and Nested routes.
42
+ */
25
43
  private renderRoute;
44
+ /**
45
+ * Basic string matching. Supports ':param' wildcards and '**' catch-all.
46
+ */
26
47
  private matchRoute;
48
+ /**
49
+ * Maps URL values to parameter names based on the pattern.
50
+ */
27
51
  private extractRouteParams;
52
+ /**
53
+ * Programmatic navigation (e.g., router.navigateTo('/dashboard'))
54
+ */
28
55
  navigateTo(route: string): void;
29
56
  }
30
57
  export default JongRouter;
@@ -1,2 +1,2 @@
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};
1
+ var l=class{routes;outlet;constructor(t,i){this.routes=t,this.outlet=i}init(){window.addEventListener("popstate",()=>this.navigate()),document.addEventListener("click",t=>this.handleClick(t)),this.navigate()}handleClick(t){let a=t.composedPath().find(n=>(n instanceof HTMLAnchorElement||n instanceof HTMLButtonElement)&&n.hasAttribute("router-link"));if(!a)return;let e=a.getAttribute("href");!e||e.startsWith("http")||t instanceof MouseEvent&&(t.metaKey||t.ctrlKey||t.shiftKey||t.altKey)||(t.preventDefault(),this.navigateTo(e))}navigate(){let t=window.location.pathname,i=this.routes.sort((e,n)=>n.pattern.length-e.pattern.length).find(e=>this.matchRoute(e.pattern,t));if(!i)return;let a=this.extractRouteParams(i.pattern,t);this.renderRoute(i,a)}async renderRoute(t,i,a=this.outlet){if(t.guards){let n={path:window.location.pathname,params:i,query:new URLSearchParams(window.location.search),data:t.data};if(!t.guards.every(o=>o(n))){t.redirect&&this.navigateTo(t.redirect);return}}let e=null;if(t.component){let r=(await t.component).default;e=new r,e.setAttribute("route-params",JSON.stringify(i)),e.router=this,a.innerHTML="",a.appendChild(e)}else t.html&&(a.innerHTML=t.html);if(t.children){let n;typeof t.children=="function"?n=(await t.children()).default:n=t.children;let r=e?.shadowRoot?.querySelector("[router-outlet]")||e?.querySelector("[router-outlet]")||a,o=window.location.pathname,c=n.sort((s,h)=>h.pattern.length-s.pattern.length).find(s=>this.matchRoute(s.pattern,o));if(c){let s=this.extractRouteParams(c.pattern,o);await this.renderRoute(c,s,r)}}}matchRoute(t,i){if(t==="**")return!0;let a=t.split("/").filter(Boolean),e=i.split("/").filter(Boolean);return a.length>e.length?!1:a.every((n,r)=>n.startsWith(":")||n===e[r])}extractRouteParams(t,i){let a={},e=t.split("/").filter(Boolean),n=i.split("/").filter(Boolean);return e.forEach((r,o)=>{r.startsWith(":")&&(a[r.slice(1)]=n[o])}),a}navigateTo(t){window.history.pushState({},"",t),this.navigate()}},u=l;export{u as default};
2
2
  //# sourceMappingURL=jong-router.min.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jong-router",
3
- "version": "0.1.14",
3
+ "version": "0.1.15",
4
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
6
  "redgin",
@@ -1,6 +1,6 @@
1
1
  // index.ts
2
2
  import JongRouter, { IRoute } from './src/jong-router'
3
- import { authencationGuard } from './src/guard'
3
+ import { authencationGuard } from './samples/guards/guard'
4
4
 
5
5
  const routes: IRoute[] = [
6
6
  { pattern: '/about', html: `<h2>About Page</h2>` },
@@ -15,16 +15,13 @@ const routes: IRoute[] = [
15
15
  {
16
16
  pattern: '/nested',
17
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
- },
18
+ children: () => import("./samples/nested/nested-routes")
19
+ },
25
20
  { pattern: '**', html: `<h2>404 Page</h2>` }
26
21
  ]
27
22
 
28
- export const router = new JongRouter(routes, document.getElementById('app')!, '', true)
23
+ export const router = new JongRouter(routes, document.getElementById('app')!)
29
24
  router.init()
30
25
 
26
+
27
+