@iyulab/router 0.6.1 → 0.7.0
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/LICENSE +20 -20
- package/README.md +272 -149
- package/dist/index.d.ts +56 -35
- package/dist/index.js +45 -110
- package/dist/react.d.ts +34 -27
- package/dist/react.js +4 -29
- package/dist/{share-SPj-xl6y.js → share-B5lysqp2.js} +55 -89
- package/package.json +56 -56
|
@@ -1,89 +1,54 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { customElement, property } from "lit/decorators.js";
|
|
1
|
+
import { render, css, LitElement, html } from "lit";
|
|
3
2
|
import { createRoot } from "react-dom/client";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
8
|
-
if (decorator = decorators[i])
|
|
9
|
-
result = decorator(result) || result;
|
|
10
|
-
return result;
|
|
11
|
-
};
|
|
12
|
-
let UOutlet = class extends LitElement {
|
|
13
|
-
/** 외부 스타일을 적용하기 위해 라이트 돔을사용 합니다. */
|
|
14
|
-
createRenderRoot() {
|
|
15
|
-
return this;
|
|
16
|
-
}
|
|
17
|
-
/** 컴포넌트가 DOM에 연결될 때 초기화 작업 수행 */
|
|
18
|
-
connectedCallback() {
|
|
19
|
-
super.connectedCallback();
|
|
20
|
-
this.dispatchEvent(new CustomEvent("outlet-load", {
|
|
21
|
-
bubbles: true,
|
|
22
|
-
composed: true
|
|
23
|
-
}));
|
|
24
|
-
}
|
|
25
|
-
render() {
|
|
26
|
-
return html`${this.container}`;
|
|
27
|
-
}
|
|
3
|
+
import { property, customElement } from "lit/decorators.js";
|
|
4
|
+
import { ifDefined } from "lit/directives/if-defined.js";
|
|
5
|
+
class UOutlet extends HTMLElement {
|
|
28
6
|
/**
|
|
29
|
-
*
|
|
30
|
-
* - HTMLElement, ReactElement, TemplateResult를 모두 처리할 수 있습니다.
|
|
7
|
+
* 주어진 렌더링 옵션에 따라 컨텐츠를 렌더링합니다.
|
|
31
8
|
*/
|
|
32
|
-
|
|
33
|
-
if (this.routeId === id && force === false
|
|
34
|
-
return this.container;
|
|
35
|
-
}
|
|
9
|
+
render({ id, value, force }) {
|
|
10
|
+
if (this.routeId === id && force === false) return;
|
|
36
11
|
this.routeId = id;
|
|
37
|
-
this.
|
|
38
|
-
if (
|
|
39
|
-
throw new Error("Outlet container is not initialized.");
|
|
40
|
-
}
|
|
41
|
-
if (typeof content !== "object") {
|
|
12
|
+
this.reset();
|
|
13
|
+
if (typeof value !== "object") {
|
|
42
14
|
throw new Error("Content is not a valid renderable object.");
|
|
43
15
|
}
|
|
44
|
-
if (
|
|
45
|
-
this.
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
this.
|
|
16
|
+
if (value instanceof HTMLElement) {
|
|
17
|
+
this.replaceChildren(value);
|
|
18
|
+
this.root = void 0;
|
|
19
|
+
} else if ("_$litType$" in value) {
|
|
20
|
+
this.root = render(value, this);
|
|
21
|
+
} else if ("$$typeof" in value) {
|
|
22
|
+
this.root = createRoot(this);
|
|
23
|
+
this.root.render(value);
|
|
51
24
|
} else {
|
|
52
25
|
throw new Error("not supported content type for Outlet rendering.");
|
|
53
26
|
}
|
|
54
|
-
this.requestUpdate();
|
|
55
|
-
await this.updateComplete;
|
|
56
|
-
return this.container;
|
|
57
27
|
}
|
|
58
28
|
/**
|
|
59
|
-
* 기존 DOM을
|
|
29
|
+
* 기존 DOM을 삭제하여, 초기 상태로 되돌립니다.
|
|
60
30
|
*/
|
|
61
|
-
|
|
62
|
-
if (this.
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
this.content.setConnected(false);
|
|
68
|
-
}
|
|
69
|
-
this.content = void 0;
|
|
31
|
+
reset() {
|
|
32
|
+
if (this.root && "_$litPart$" in this) {
|
|
33
|
+
delete this._$litPart$;
|
|
34
|
+
}
|
|
35
|
+
if (this.root && "unmount" in this.root) {
|
|
36
|
+
this.root.unmount();
|
|
70
37
|
}
|
|
71
|
-
this.
|
|
72
|
-
this.
|
|
38
|
+
this.root = void 0;
|
|
39
|
+
this.innerHTML = "";
|
|
73
40
|
}
|
|
74
|
-
}
|
|
75
|
-
UOutlet
|
|
76
|
-
customElement("u-outlet")
|
|
77
|
-
], UOutlet);
|
|
41
|
+
}
|
|
42
|
+
customElements.define("u-outlet", UOutlet);
|
|
78
43
|
function isExternalUrl(url) {
|
|
79
44
|
if (!url) return false;
|
|
80
|
-
|
|
81
|
-
if (/^(?:mailto:|tel:|javascript:)/i.test(
|
|
82
|
-
if (
|
|
45
|
+
url = url.trim();
|
|
46
|
+
if (/^(?:mailto:|tel:|javascript:)/i.test(url)) return true;
|
|
47
|
+
if (url.startsWith("//")) return true;
|
|
83
48
|
try {
|
|
84
49
|
const base = typeof window !== "undefined" ? window.location.origin : "http://localhost";
|
|
85
|
-
const parsed = new URL(
|
|
86
|
-
if (/^(?:ftp:|ftps:|
|
|
50
|
+
const parsed = new URL(url, base);
|
|
51
|
+
if (/^(?:ftp:|ftps:|ws:|wss:)/i.test(parsed.protocol)) return true;
|
|
87
52
|
return parsed.origin !== new URL(base).origin;
|
|
88
53
|
} catch {
|
|
89
54
|
return false;
|
|
@@ -91,7 +56,7 @@ function isExternalUrl(url) {
|
|
|
91
56
|
}
|
|
92
57
|
function parseUrl(url, basepath) {
|
|
93
58
|
let urlObj;
|
|
94
|
-
basepath =
|
|
59
|
+
basepath = catchBasepath(basepath);
|
|
95
60
|
if (url.startsWith("http")) {
|
|
96
61
|
urlObj = new URL(url);
|
|
97
62
|
} else if (url.startsWith("/")) {
|
|
@@ -113,7 +78,8 @@ function parseUrl(url, basepath) {
|
|
|
113
78
|
hash: urlObj.hash,
|
|
114
79
|
params: {},
|
|
115
80
|
progress: () => {
|
|
116
|
-
}
|
|
81
|
+
},
|
|
82
|
+
meta: {}
|
|
117
83
|
};
|
|
118
84
|
}
|
|
119
85
|
function absolutePath(...paths) {
|
|
@@ -121,7 +87,7 @@ function absolutePath(...paths) {
|
|
|
121
87
|
if (paths.length === 0) return "/";
|
|
122
88
|
return "/" + paths.join("/");
|
|
123
89
|
}
|
|
124
|
-
function
|
|
90
|
+
function catchBasepath(basepath) {
|
|
125
91
|
if (basepath === "/") return basepath;
|
|
126
92
|
let pattern = new URLPattern({ pathname: basepath + "/*" });
|
|
127
93
|
let match = pattern.exec({ pathname: window.location.pathname });
|
|
@@ -151,12 +117,11 @@ let ULink = class extends LitElement {
|
|
|
151
117
|
constructor() {
|
|
152
118
|
super(...arguments);
|
|
153
119
|
this.isExternal = false;
|
|
154
|
-
this.
|
|
120
|
+
this.handleClick = (event) => {
|
|
155
121
|
if (event.defaultPrevented) return;
|
|
156
122
|
if (event.button !== 0) return;
|
|
157
123
|
if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return;
|
|
158
|
-
|
|
159
|
-
if (target && target.toLowerCase() !== "_self") return;
|
|
124
|
+
if (this.target && this.target.toLowerCase() !== "_self") return;
|
|
160
125
|
const basepath = this.getBasepath();
|
|
161
126
|
if (!this.href) {
|
|
162
127
|
event.preventDefault();
|
|
@@ -183,6 +148,14 @@ let ULink = class extends LitElement {
|
|
|
183
148
|
this.dispatchPopstate(basepath, url);
|
|
184
149
|
};
|
|
185
150
|
}
|
|
151
|
+
connectedCallback() {
|
|
152
|
+
super.connectedCallback();
|
|
153
|
+
this.addEventListener("click", this.handleClick);
|
|
154
|
+
}
|
|
155
|
+
disconnectedCallback() {
|
|
156
|
+
this.removeEventListener("click", this.handleClick);
|
|
157
|
+
super.disconnectedCallback();
|
|
158
|
+
}
|
|
186
159
|
willUpdate(changedProperties) {
|
|
187
160
|
super.willUpdate(changedProperties);
|
|
188
161
|
if (changedProperties.has("href")) {
|
|
@@ -191,27 +164,18 @@ let ULink = class extends LitElement {
|
|
|
191
164
|
}
|
|
192
165
|
render() {
|
|
193
166
|
return html`
|
|
194
|
-
<a
|
|
195
|
-
target=${this.target ?? "_self"}
|
|
196
|
-
href=${this.computeHref(this.href)}
|
|
197
|
-
@click=${this.handleAnchorClick}>
|
|
167
|
+
<a target=${ifDefined(this.target)} href=${this.compute(this.href)}>
|
|
198
168
|
<slot></slot>
|
|
199
169
|
</a>
|
|
200
170
|
`;
|
|
201
171
|
}
|
|
202
|
-
/** basepath를 state에서 꺼내는 헬퍼 */
|
|
203
|
-
getBasepath() {
|
|
204
|
-
return window.history.state?.basepath || "";
|
|
205
|
-
}
|
|
206
172
|
/** a 태그에 주입할 href 값을 계산합니다. */
|
|
207
|
-
|
|
173
|
+
compute(href) {
|
|
208
174
|
const basepath = this.getBasepath();
|
|
209
|
-
if (!href)
|
|
210
|
-
return window.location.origin + basepath;
|
|
211
|
-
}
|
|
175
|
+
if (!href) return window.location.origin + basepath;
|
|
212
176
|
if (this.isExternal) return href;
|
|
213
|
-
if (href.startsWith("#") || href.startsWith("?")) return href;
|
|
214
177
|
if (href.startsWith("/")) return href;
|
|
178
|
+
if (href.startsWith("#") || href.startsWith("?")) return href;
|
|
215
179
|
return absolutePath(basepath, href);
|
|
216
180
|
}
|
|
217
181
|
/** 클라이언트 라우팅을 위해 popstate 이벤트를 발생시킵니다. */
|
|
@@ -219,15 +183,17 @@ let ULink = class extends LitElement {
|
|
|
219
183
|
window.history.pushState({ basepath }, "", url);
|
|
220
184
|
window.dispatchEvent(new PopStateEvent("popstate"));
|
|
221
185
|
}
|
|
186
|
+
/** basepath를 state에서 꺼내는 헬퍼 */
|
|
187
|
+
getBasepath() {
|
|
188
|
+
return window.history.state?.basepath || "";
|
|
189
|
+
}
|
|
222
190
|
};
|
|
223
191
|
ULink.styles = css`
|
|
224
192
|
:host {
|
|
225
|
-
display: inline-flex;
|
|
226
193
|
cursor: pointer;
|
|
227
194
|
}
|
|
228
195
|
|
|
229
196
|
a {
|
|
230
|
-
display: contents;
|
|
231
197
|
text-decoration: none;
|
|
232
198
|
|
|
233
199
|
font-size: inherit;
|
package/package.json
CHANGED
|
@@ -1,56 +1,56 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@iyulab/router",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "A modern client-side router for web applications with support for Lit and React components",
|
|
5
|
-
"keywords": [
|
|
6
|
-
"lit",
|
|
7
|
-
"react",
|
|
8
|
-
"router",
|
|
9
|
-
"routing",
|
|
10
|
-
"spa",
|
|
11
|
-
"navigation",
|
|
12
|
-
"client-side"
|
|
13
|
-
],
|
|
14
|
-
"license": "MIT",
|
|
15
|
-
"author": "iyulab",
|
|
16
|
-
"repository": {
|
|
17
|
-
"type": "git",
|
|
18
|
-
"url": "https://github.com/iyulab/node-router.git"
|
|
19
|
-
},
|
|
20
|
-
"files": [
|
|
21
|
-
"dist",
|
|
22
|
-
"package.json",
|
|
23
|
-
"README.md",
|
|
24
|
-
"LICENSE"
|
|
25
|
-
],
|
|
26
|
-
"type": "module",
|
|
27
|
-
"types": "dist/index.d.ts",
|
|
28
|
-
"exports": {
|
|
29
|
-
".": {
|
|
30
|
-
"types": "./
|
|
31
|
-
"import": "./
|
|
32
|
-
},
|
|
33
|
-
"./react": {
|
|
34
|
-
"types": "./dist/react.d.ts",
|
|
35
|
-
"import": "./dist/react.js"
|
|
36
|
-
}
|
|
37
|
-
},
|
|
38
|
-
"scripts": {
|
|
39
|
-
"test": "vite",
|
|
40
|
-
"build": "vite build"
|
|
41
|
-
},
|
|
42
|
-
"dependencies": {
|
|
43
|
-
"lit": "^
|
|
44
|
-
"
|
|
45
|
-
"react
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
"@types/node": "^25.0.9",
|
|
50
|
-
"@types/react": "^19.2.
|
|
51
|
-
"@types/react-dom": "^19.2.3",
|
|
52
|
-
"typescript": "^5.9.3",
|
|
53
|
-
"vite": "^7.3.1",
|
|
54
|
-
"vite-plugin-dts": "^4.5.4"
|
|
55
|
-
}
|
|
56
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@iyulab/router",
|
|
3
|
+
"version": "0.7.0",
|
|
4
|
+
"description": "A modern client-side router for web applications with support for Lit and React components",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"lit",
|
|
7
|
+
"react",
|
|
8
|
+
"router",
|
|
9
|
+
"routing",
|
|
10
|
+
"spa",
|
|
11
|
+
"navigation",
|
|
12
|
+
"client-side"
|
|
13
|
+
],
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"author": "iyulab",
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "https://github.com/iyulab/node-router.git"
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"dist",
|
|
22
|
+
"package.json",
|
|
23
|
+
"README.md",
|
|
24
|
+
"LICENSE"
|
|
25
|
+
],
|
|
26
|
+
"type": "module",
|
|
27
|
+
"types": "dist/index.d.ts",
|
|
28
|
+
"exports": {
|
|
29
|
+
".": {
|
|
30
|
+
"types": "./src/index.d.ts",
|
|
31
|
+
"import": "./src/index.js"
|
|
32
|
+
},
|
|
33
|
+
"./react": {
|
|
34
|
+
"types": "./dist/react.d.ts",
|
|
35
|
+
"import": "./dist/react.js"
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"scripts": {
|
|
39
|
+
"test": "vite",
|
|
40
|
+
"build": "vite build"
|
|
41
|
+
},
|
|
42
|
+
"dependencies": {
|
|
43
|
+
"@lit/react": "^1.0.8",
|
|
44
|
+
"lit": "^3.3.2",
|
|
45
|
+
"react": "^19.2.3",
|
|
46
|
+
"react-dom": "^19.2.3"
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@types/node": "^25.0.9",
|
|
50
|
+
"@types/react": "^19.2.9",
|
|
51
|
+
"@types/react-dom": "^19.2.3",
|
|
52
|
+
"typescript": "^5.9.3",
|
|
53
|
+
"vite": "^7.3.1",
|
|
54
|
+
"vite-plugin-dts": "^4.5.4"
|
|
55
|
+
}
|
|
56
|
+
}
|