@iyulab/router 0.6.0 โ 0.6.1
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 +37 -37
- package/dist/index.d.ts +3 -3
- package/dist/index.js +23 -12
- package/dist/react.d.ts +2 -2
- package/dist/react.js +1 -1
- package/dist/{share-ZrQFmsur.js โ share-SPj-xl6y.js} +11 -9
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -6,13 +6,9 @@ A modern, lightweight client-side router for web applications with support for b
|
|
|
6
6
|
|
|
7
7
|
- ๐ **Modern URLPattern-based routing** - Uses native URLPattern API for powerful path matching
|
|
8
8
|
- ๐ง **Unified Framework Support** - Works with both Lit and React components using render functions
|
|
9
|
-
- ๐ฑ **Client-
|
|
9
|
+
- ๐ฑ **Client-Side Navigation** - History API integration with browser back/forward support
|
|
10
10
|
- ๐ฏ **Nested Routing** - Support for deeply nested route hierarchies with index and path routes
|
|
11
|
-
- ๐ **Smart Link Component** - Automatic external link detection and handling
|
|
12
11
|
- ๐ **Route Events** - Track navigation progress with route-begin, route-done, and route-error events
|
|
13
|
-
- ๐จ **Flexible Outlet System** - Unified rendering with renderContent method
|
|
14
|
-
- ๐ **Global Route Access** - Access current route information anywhere via `window.route`
|
|
15
|
-
- ๐ **Force Re-rendering** - Control component re-rendering on route changes
|
|
16
12
|
- โ ๏ธ **Enhanced Error Handling** - Built-in ErrorPage component with improved styling
|
|
17
13
|
|
|
18
14
|
## Installation
|
|
@@ -30,43 +26,18 @@ import { Router } from '@iyulab/router';
|
|
|
30
26
|
import { html } from 'lit';
|
|
31
27
|
|
|
32
28
|
const router = new Router({
|
|
33
|
-
|
|
34
|
-
basepath: '/app',
|
|
29
|
+
basepath: '/',
|
|
35
30
|
routes: [
|
|
36
31
|
{
|
|
37
32
|
index: true,
|
|
38
33
|
render: () => html`<home-page></home-page>`
|
|
39
34
|
},
|
|
40
35
|
{
|
|
41
|
-
path: '/user/:id',
|
|
36
|
+
path: '/user/:id', // URLPattern route
|
|
42
37
|
render: (routeInfo) => html`<user-page .userId=${routeInfo.params.id}></user-page>`
|
|
43
38
|
}
|
|
44
|
-
]
|
|
39
|
+
],
|
|
45
40
|
});
|
|
46
|
-
|
|
47
|
-
// Start routing
|
|
48
|
-
router.go(window.location.href);
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
### Nested Routes
|
|
52
|
-
|
|
53
|
-
```typescript
|
|
54
|
-
const routes = [
|
|
55
|
-
{
|
|
56
|
-
path: '/dashboard',
|
|
57
|
-
render: () => html`<dashboard-layout><u-outlet></u-outlet></dashboard-layout>`,
|
|
58
|
-
children: [
|
|
59
|
-
{
|
|
60
|
-
index: true, // Matches /dashboard exactly
|
|
61
|
-
render: () => html`<dashboard-home></dashboard-home>`
|
|
62
|
-
},
|
|
63
|
-
{
|
|
64
|
-
path: 'settings',
|
|
65
|
-
render: () => html`<dashboard-settings></dashboard-settings>`
|
|
66
|
-
}
|
|
67
|
-
]
|
|
68
|
-
}
|
|
69
|
-
];
|
|
70
41
|
```
|
|
71
42
|
|
|
72
43
|
### Mixed Framework Support
|
|
@@ -78,12 +49,16 @@ const routes = [
|
|
|
78
49
|
// Lit component
|
|
79
50
|
{
|
|
80
51
|
path: '/lit-page',
|
|
81
|
-
render: (routeInfo) =>
|
|
52
|
+
render: (routeInfo) => {
|
|
53
|
+
return html`<my-lit-component .routeInfo=${routeInfo}></my-lit-component>`
|
|
54
|
+
}
|
|
82
55
|
},
|
|
83
56
|
// React component
|
|
84
57
|
{
|
|
85
58
|
path: '/react-page',
|
|
86
|
-
render: (routeInfo) =>
|
|
59
|
+
render: (routeInfo) => {
|
|
60
|
+
return ( <MyComponent></MyComponent> )
|
|
61
|
+
}
|
|
87
62
|
},
|
|
88
63
|
// HTML element
|
|
89
64
|
{
|
|
@@ -97,14 +72,39 @@ const routes = [
|
|
|
97
72
|
];
|
|
98
73
|
```
|
|
99
74
|
|
|
75
|
+
### Nested Routes
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
import { RouteConfig } from '@iyulab/router';
|
|
79
|
+
|
|
80
|
+
const routes: RouteConfig[] = [
|
|
81
|
+
{
|
|
82
|
+
path: '/dashboard',
|
|
83
|
+
render: () => html`<dashboard-layout><u-outlet></u-outlet></dashboard-layout>`,
|
|
84
|
+
children: [
|
|
85
|
+
{
|
|
86
|
+
index: true, // Matches '/dashboard'
|
|
87
|
+
render: () => html`<dashboard-home></dashboard-home>`
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
path: 'settings', // Matches '/dashboard/settings'
|
|
91
|
+
render: () => html`<dashboard-settings></dashboard-settings>`
|
|
92
|
+
}
|
|
93
|
+
]
|
|
94
|
+
}
|
|
95
|
+
];
|
|
96
|
+
```
|
|
97
|
+
|
|
100
98
|
## Usage Examples
|
|
101
99
|
|
|
102
|
-
### Using with Lit
|
|
100
|
+
### Using with Lit Elements
|
|
103
101
|
|
|
104
102
|
```typescript
|
|
105
103
|
import { LitElement, html } from 'lit';
|
|
106
104
|
import { customElement } from 'lit/decorators.js';
|
|
107
105
|
|
|
106
|
+
import "@iyulab/router";
|
|
107
|
+
|
|
108
108
|
@customElement('app-root')
|
|
109
109
|
export class AppRoot extends LitElement {
|
|
110
110
|
render() {
|
|
@@ -146,4 +146,4 @@ export function AppRoot() {
|
|
|
146
146
|
|
|
147
147
|
## License
|
|
148
148
|
|
|
149
|
-
MIT License - see [LICENSE](LICENSE) file for details.
|
|
149
|
+
MIT License - see [LICENSE](LICENSE) file for details.
|
package/dist/index.d.ts
CHANGED
|
@@ -325,7 +325,7 @@ export declare class Router {
|
|
|
325
325
|
/** ๋ธ๋ผ์ฐ์ ํ์คํ ๋ฆฌ ์ด๋ฒคํธ๊ฐ ๋ฐ์์ ๋ผ์ฐํ
์ฒ๋ฆฌ */
|
|
326
326
|
private handleWindowPopstate;
|
|
327
327
|
/** ํด๋ฆญ ์ด๋ฒคํธ์์ ๋ผ์ฐํฐ๋ก ์ฒ๋ฆฌํ ์ต์ปค๋ฅผ ์ฐพ์ ํด๋ผ์ด์ธํธ ๋ผ์ฐํ
์ํ */
|
|
328
|
-
private
|
|
328
|
+
private handleDocumentClick;
|
|
329
329
|
}
|
|
330
330
|
|
|
331
331
|
/**
|
|
@@ -374,8 +374,6 @@ export declare interface RouterConfig {
|
|
|
374
374
|
export declare class ULink extends LitElement {
|
|
375
375
|
/** ์ธ๋ถ ๋งํฌ ์ฌ๋ถ */
|
|
376
376
|
private isExternal;
|
|
377
|
-
/** a ํ๊ทธ์ ์ฃผ์
ํ href ๊ฐ */
|
|
378
|
-
computedHref: string;
|
|
379
377
|
/**
|
|
380
378
|
* a ํ๊ทธ target์ ์ง์ํ๊ณ ์ถ์ผ๋ฉด ์ด์ด๋๋๊ฒ ์ข์ต๋๋ค.
|
|
381
379
|
* - _blank ๋ฑ์ ์ฐ๋ฉด ๋ฌด์กฐ๊ฑด ๋ธ๋ผ์ฐ์ ๊ธฐ๋ณธ ๋์์ ๋ฐ๋ฅด๋๋ก ์ฒ๋ฆฌํฉ๋๋ค.
|
|
@@ -416,6 +414,8 @@ export declare class UOutlet extends LitElement {
|
|
|
416
414
|
private content?;
|
|
417
415
|
/** ์ธ๋ถ ์คํ์ผ์ ์ ์ฉํ๊ธฐ ์ํด ๋ผ์ดํธ ๋์์ฌ์ฉ ํฉ๋๋ค. */
|
|
418
416
|
protected createRenderRoot(): this;
|
|
417
|
+
/** ์ปดํฌ๋ํธ๊ฐ DOM์ ์ฐ๊ฒฐ๋ ๋ ์ด๊ธฐํ ์์
์ํ */
|
|
418
|
+
connectedCallback(): void;
|
|
419
419
|
render(): TemplateResult<1>;
|
|
420
420
|
/**
|
|
421
421
|
* render ํจ์์ ๊ฒฐ๊ณผ๋ฅผ ๋ ๋๋งํฉ๋๋ค.
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { a as absolutePath, i as isExternalUrl, p as parseUrl } from "./share-
|
|
2
|
-
import { b, U } from "./share-
|
|
1
|
+
import { a as absolutePath, i as isExternalUrl, p as parseUrl } from "./share-SPj-xl6y.js";
|
|
2
|
+
import { b, U } from "./share-SPj-xl6y.js";
|
|
3
3
|
import { css, LitElement, html } from "lit";
|
|
4
4
|
import { property, customElement } from "lit/decorators.js";
|
|
5
5
|
import { unsafeHTML } from "lit-html/directives/unsafe-html.js";
|
|
@@ -204,7 +204,7 @@ UErrorPage.styles = css`
|
|
|
204
204
|
--route-code-color: #f7fafc;
|
|
205
205
|
--route-message-color: #cbd5e0;
|
|
206
206
|
}
|
|
207
|
-
}
|
|
207
|
+
}
|
|
208
208
|
|
|
209
209
|
:host {
|
|
210
210
|
display: flex;
|
|
@@ -282,15 +282,24 @@ function findOutletOrThrow(element) {
|
|
|
282
282
|
}
|
|
283
283
|
return outlet;
|
|
284
284
|
}
|
|
285
|
-
function
|
|
286
|
-
const
|
|
285
|
+
async function waitOutlet(element, timeout = 1e4) {
|
|
286
|
+
const start = performance.now();
|
|
287
|
+
while (performance.now() - start < timeout) {
|
|
288
|
+
const outlet = findOutlet(element);
|
|
289
|
+
if (outlet) return outlet;
|
|
290
|
+
await new Promise((r) => setTimeout(r, 50));
|
|
291
|
+
}
|
|
292
|
+
throw new Error("Timed out waiting for u-outlet.");
|
|
293
|
+
}
|
|
294
|
+
function findAnchorFrom(event) {
|
|
295
|
+
const targets = event.composedPath() || [];
|
|
287
296
|
if (targets && targets.length) {
|
|
288
297
|
for (const node of targets) {
|
|
289
298
|
if (!(node instanceof Element)) continue;
|
|
290
299
|
if (node.tagName === "A") return node;
|
|
291
300
|
}
|
|
292
301
|
}
|
|
293
|
-
const tgt =
|
|
302
|
+
const tgt = event.target;
|
|
294
303
|
if (!tgt) return null;
|
|
295
304
|
const anchor = tgt.closest("a");
|
|
296
305
|
return anchor;
|
|
@@ -350,11 +359,11 @@ class Router {
|
|
|
350
359
|
const href = window.location.href;
|
|
351
360
|
await this.go(href);
|
|
352
361
|
};
|
|
353
|
-
this.
|
|
362
|
+
this.handleDocumentClick = (e) => {
|
|
354
363
|
try {
|
|
355
364
|
if (e.defaultPrevented) return;
|
|
356
365
|
if (e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey) return;
|
|
357
|
-
const anchor =
|
|
366
|
+
const anchor = findAnchorFrom(e);
|
|
358
367
|
if (!anchor) return;
|
|
359
368
|
const href = anchor.getAttribute("href") || anchor.href;
|
|
360
369
|
if (!href) return;
|
|
@@ -374,17 +383,19 @@ class Router {
|
|
|
374
383
|
window.removeEventListener("popstate", this.handleWindowPopstate);
|
|
375
384
|
window.addEventListener("popstate", this.handleWindowPopstate);
|
|
376
385
|
if (config.useIntercept !== false) {
|
|
377
|
-
|
|
378
|
-
|
|
386
|
+
document.removeEventListener("click", this.handleDocumentClick);
|
|
387
|
+
document.addEventListener("click", this.handleDocumentClick);
|
|
379
388
|
}
|
|
380
389
|
if (config.initialLoad !== false) {
|
|
381
|
-
void this.
|
|
390
|
+
void waitOutlet(this._rootElement).then(() => {
|
|
391
|
+
this.go(window.location.href);
|
|
392
|
+
});
|
|
382
393
|
}
|
|
383
394
|
}
|
|
384
395
|
/** ๊ฐ์ฒด๋ฅผ ์ ๋ฆฌํ๊ณ ์ด๋ฒคํธ ๋ฆฌ์ค๋๋ฅผ ์ ๊ฑฐํฉ๋๋ค. */
|
|
385
396
|
destroy() {
|
|
386
397
|
window.removeEventListener("popstate", this.handleWindowPopstate);
|
|
387
|
-
|
|
398
|
+
document.removeEventListener("click", this.handleDocumentClick);
|
|
388
399
|
this._requestID = void 0;
|
|
389
400
|
this._context = void 0;
|
|
390
401
|
}
|
package/dist/react.d.ts
CHANGED
|
@@ -27,8 +27,6 @@ export declare const ULink: ReactWebComponent<ULink_2, {}>;
|
|
|
27
27
|
declare class ULink_2 extends LitElement {
|
|
28
28
|
/** ์ธ๋ถ ๋งํฌ ์ฌ๋ถ */
|
|
29
29
|
private isExternal;
|
|
30
|
-
/** a ํ๊ทธ์ ์ฃผ์
ํ href ๊ฐ */
|
|
31
|
-
computedHref: string;
|
|
32
30
|
/**
|
|
33
31
|
* a ํ๊ทธ target์ ์ง์ํ๊ณ ์ถ์ผ๋ฉด ์ด์ด๋๋๊ฒ ์ข์ต๋๋ค.
|
|
34
32
|
* - _blank ๋ฑ์ ์ฐ๋ฉด ๋ฌด์กฐ๊ฑด ๋ธ๋ผ์ฐ์ ๊ธฐ๋ณธ ๋์์ ๋ฐ๋ฅด๋๋ก ์ฒ๋ฆฌํฉ๋๋ค.
|
|
@@ -74,6 +72,8 @@ declare class UOutlet_2 extends LitElement {
|
|
|
74
72
|
private content?;
|
|
75
73
|
/** ์ธ๋ถ ์คํ์ผ์ ์ ์ฉํ๊ธฐ ์ํด ๋ผ์ดํธ ๋์์ฌ์ฉ ํฉ๋๋ค. */
|
|
76
74
|
protected createRenderRoot(): this;
|
|
75
|
+
/** ์ปดํฌ๋ํธ๊ฐ DOM์ ์ฐ๊ฒฐ๋ ๋ ์ด๊ธฐํ ์์
์ํ */
|
|
76
|
+
connectedCallback(): void;
|
|
77
77
|
render(): TemplateResult_2<1>;
|
|
78
78
|
/**
|
|
79
79
|
* render ํจ์์ ๊ฒฐ๊ณผ๋ฅผ ๋ ๋๋งํฉ๋๋ค.
|
package/dist/react.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import { b as ULink$1, U as UOutlet$1 } from "./share-
|
|
2
|
+
import { b as ULink$1, U as UOutlet$1 } from "./share-SPj-xl6y.js";
|
|
3
3
|
const e = /* @__PURE__ */ new Set(["children", "localName", "ref", "style", "className"]), n = /* @__PURE__ */ new WeakMap(), t = (e2, t2, o2, l, a) => {
|
|
4
4
|
const s = a?.[t2];
|
|
5
5
|
void 0 === s ? (e2[t2] = o2, null == o2 && t2 in HTMLElement.prototype && e2.removeAttribute(t2)) : o2 !== l && ((e3, t3, o3) => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { LitElement, html, render, css } from "lit";
|
|
2
|
-
import { customElement,
|
|
2
|
+
import { customElement, property } from "lit/decorators.js";
|
|
3
3
|
import { createRoot } from "react-dom/client";
|
|
4
4
|
var __getOwnPropDesc$1 = Object.getOwnPropertyDescriptor;
|
|
5
5
|
var __decorateClass$1 = (decorators, target, key, kind) => {
|
|
@@ -14,6 +14,14 @@ let UOutlet = class extends LitElement {
|
|
|
14
14
|
createRenderRoot() {
|
|
15
15
|
return this;
|
|
16
16
|
}
|
|
17
|
+
/** ์ปดํฌ๋ํธ๊ฐ DOM์ ์ฐ๊ฒฐ๋ ๋ ์ด๊ธฐํ ์์
์ํ */
|
|
18
|
+
connectedCallback() {
|
|
19
|
+
super.connectedCallback();
|
|
20
|
+
this.dispatchEvent(new CustomEvent("outlet-load", {
|
|
21
|
+
bubbles: true,
|
|
22
|
+
composed: true
|
|
23
|
+
}));
|
|
24
|
+
}
|
|
17
25
|
render() {
|
|
18
26
|
return html`${this.container}`;
|
|
19
27
|
}
|
|
@@ -143,7 +151,6 @@ let ULink = class extends LitElement {
|
|
|
143
151
|
constructor() {
|
|
144
152
|
super(...arguments);
|
|
145
153
|
this.isExternal = false;
|
|
146
|
-
this.computedHref = "#";
|
|
147
154
|
this.handleAnchorClick = (event) => {
|
|
148
155
|
if (event.defaultPrevented) return;
|
|
149
156
|
if (event.button !== 0) return;
|
|
@@ -180,16 +187,14 @@ let ULink = class extends LitElement {
|
|
|
180
187
|
super.willUpdate(changedProperties);
|
|
181
188
|
if (changedProperties.has("href")) {
|
|
182
189
|
this.isExternal = isExternalUrl(this.href || "");
|
|
183
|
-
this.computedHref = this.computeHref(this.href);
|
|
184
190
|
}
|
|
185
191
|
}
|
|
186
192
|
render() {
|
|
187
193
|
return html`
|
|
188
194
|
<a
|
|
189
195
|
target=${this.target ?? "_self"}
|
|
190
|
-
href=${this.
|
|
191
|
-
@click=${this.handleAnchorClick}
|
|
192
|
-
>
|
|
196
|
+
href=${this.computeHref(this.href)}
|
|
197
|
+
@click=${this.handleAnchorClick}>
|
|
193
198
|
<slot></slot>
|
|
194
199
|
</a>
|
|
195
200
|
`;
|
|
@@ -232,9 +237,6 @@ ULink.styles = css`
|
|
|
232
237
|
cursor: inherit;
|
|
233
238
|
}
|
|
234
239
|
`;
|
|
235
|
-
__decorateClass([
|
|
236
|
-
state()
|
|
237
|
-
], ULink.prototype, "computedHref", 2);
|
|
238
240
|
__decorateClass([
|
|
239
241
|
property({ type: String })
|
|
240
242
|
], ULink.prototype, "target", 2);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@iyulab/router",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"description": "A modern client-side router for web applications with support for Lit and React components",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"lit",
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
}
|
|
37
37
|
},
|
|
38
38
|
"scripts": {
|
|
39
|
+
"test": "vite",
|
|
39
40
|
"build": "vite build"
|
|
40
41
|
},
|
|
41
42
|
"dependencies": {
|
|
@@ -45,7 +46,7 @@
|
|
|
45
46
|
},
|
|
46
47
|
"devDependencies": {
|
|
47
48
|
"@lit/react": "^1.0.8",
|
|
48
|
-
"@types/node": "^25.0.
|
|
49
|
+
"@types/node": "^25.0.9",
|
|
49
50
|
"@types/react": "^19.2.8",
|
|
50
51
|
"@types/react-dom": "^19.2.3",
|
|
51
52
|
"typescript": "^5.9.3",
|