@iyulab/router 0.11.0 → 0.11.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/CHANGELOG.md +19 -0
- package/dist/index.js +10 -6
- package/dist/react.js +1 -1
- package/dist/share-Dl02vMhW.js +1142 -0
- package/package.json +3 -2
- package/dist/share-BaGC5VOl.js +0 -245
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@iyulab/router",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.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",
|
|
@@ -54,7 +54,8 @@
|
|
|
54
54
|
},
|
|
55
55
|
"dependencies": {
|
|
56
56
|
"@lit/react": "^1.0.8",
|
|
57
|
-
"lit": "^3.3.3"
|
|
57
|
+
"lit": "^3.3.3",
|
|
58
|
+
"urlpattern-polyfill": "^10.1.0"
|
|
58
59
|
},
|
|
59
60
|
"peerDependencies": {
|
|
60
61
|
"react": ">=18.0.0",
|
package/dist/share-BaGC5VOl.js
DELETED
|
@@ -1,245 +0,0 @@
|
|
|
1
|
-
import { LitElement, css, html, render } from "lit";
|
|
2
|
-
import { customElement, property } from "lit/decorators.js";
|
|
3
|
-
import { ifDefined } from "lit/directives/if-defined.js";
|
|
4
|
-
//#region src/components/UOutlet.ts
|
|
5
|
-
/**
|
|
6
|
-
* LitElement 또는 React 컴포넌트를 렌더링해주는 웹컴포넌트 입니다.
|
|
7
|
-
*/
|
|
8
|
-
var UOutlet = class extends HTMLElement {
|
|
9
|
-
/**
|
|
10
|
-
* 주어진 렌더링 옵션에 따라 컨텐츠를 렌더링합니다.
|
|
11
|
-
*/
|
|
12
|
-
async render(value, options) {
|
|
13
|
-
if (this.routeId === options?.id && options?.force === false) return;
|
|
14
|
-
this.routeId = options?.id;
|
|
15
|
-
this.reset();
|
|
16
|
-
if (value === null) throw new Error("Content is null and cannot be rendered.");
|
|
17
|
-
if (typeof value !== "object") throw new Error("Content is not a valid renderable object.");
|
|
18
|
-
if (value instanceof HTMLElement) {
|
|
19
|
-
this.replaceChildren(value);
|
|
20
|
-
this.root = void 0;
|
|
21
|
-
} else if ("_$litType$" in value) this.root = render(value, this);
|
|
22
|
-
else if ("$$typeof" in value) {
|
|
23
|
-
const { createRoot } = await import("react-dom/client");
|
|
24
|
-
this.root = createRoot(this);
|
|
25
|
-
this.root.render(value);
|
|
26
|
-
} else throw new Error("not supported content type for Outlet rendering.");
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* 기존 DOM을 삭제하여, 초기 상태로 되돌립니다.
|
|
30
|
-
*/
|
|
31
|
-
reset() {
|
|
32
|
-
if (this.root && "_$litPart$" in this) delete this._$litPart$;
|
|
33
|
-
if (this.root && "unmount" in this.root) this.root.unmount();
|
|
34
|
-
this.root = void 0;
|
|
35
|
-
this.innerHTML = "";
|
|
36
|
-
}
|
|
37
|
-
};
|
|
38
|
-
customElements.define("u-outlet", UOutlet);
|
|
39
|
-
//#endregion
|
|
40
|
-
//#region src/internals/url-helpers.ts
|
|
41
|
-
/**
|
|
42
|
-
* 주어진 URL이 외부 링크인지 확인합니다.
|
|
43
|
-
*
|
|
44
|
-
* @param url 확인할 URL 문자열
|
|
45
|
-
* @return 외부 링크인 경우 true, 내부 링크인 경우 false
|
|
46
|
-
*/
|
|
47
|
-
function isExternalUrl(url) {
|
|
48
|
-
if (!url) return false;
|
|
49
|
-
url = url.trim();
|
|
50
|
-
if (/^(?:mailto:|tel:|javascript:)/i.test(url)) return true;
|
|
51
|
-
if (url.startsWith("//")) return true;
|
|
52
|
-
try {
|
|
53
|
-
const base = typeof window !== "undefined" ? window.location.origin : "http://localhost";
|
|
54
|
-
const parsed = new URL(url, base);
|
|
55
|
-
if (/^(?:ftp:|ftps:|ws:|wss:)/i.test(parsed.protocol)) return true;
|
|
56
|
-
return parsed.origin !== new URL(base).origin;
|
|
57
|
-
} catch {
|
|
58
|
-
return false;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
/**
|
|
62
|
-
* URL 문자열을 파싱하여 RouteContext 객체로 반환합니다.
|
|
63
|
-
* - http(s)로 시작하는 절대 URL은 외부 링크로 간주됩니다.
|
|
64
|
-
* - 절대경로(/...)는 그대로 사용됩니다.
|
|
65
|
-
* - 상대경로는 basepath를 기준으로 절대경로로 변환됩니다.
|
|
66
|
-
* - 쿼리스트링(?)로 시작하는 쿼리는 현재 경로와 추가됩니다.
|
|
67
|
-
* - 해시(#)로 시작하는 해시는 현재 경로와 추가됩니다.
|
|
68
|
-
*
|
|
69
|
-
* @param url 파싱할 URL 문자열
|
|
70
|
-
* @param basepath 기준이 되는 basepath 문자열
|
|
71
|
-
* @returns 파싱된 RouteContext 객체
|
|
72
|
-
*/
|
|
73
|
-
function parseUrl(url, basepath) {
|
|
74
|
-
let urlObj;
|
|
75
|
-
basepath = catchBasepath(basepath);
|
|
76
|
-
if (url.startsWith("http")) urlObj = new URL(url);
|
|
77
|
-
else if (url.startsWith("/")) urlObj = new URL(url, window.location.origin);
|
|
78
|
-
else if (url.startsWith("?")) urlObj = new URL(window.location.pathname + url, window.location.origin);
|
|
79
|
-
else if (url.startsWith("#")) urlObj = new URL(window.location.pathname + window.location.search + url, window.location.origin);
|
|
80
|
-
else urlObj = new URL(absolutePath(basepath, url), window.location.origin);
|
|
81
|
-
return {
|
|
82
|
-
href: urlObj.href,
|
|
83
|
-
origin: urlObj.origin,
|
|
84
|
-
basepath,
|
|
85
|
-
path: urlObj.href.replace(urlObj.origin, ""),
|
|
86
|
-
pathname: urlObj.pathname,
|
|
87
|
-
query: new URLSearchParams(urlObj.search),
|
|
88
|
-
hash: urlObj.hash,
|
|
89
|
-
params: {},
|
|
90
|
-
progress: () => {},
|
|
91
|
-
metadata: {}
|
|
92
|
-
};
|
|
93
|
-
}
|
|
94
|
-
/**
|
|
95
|
-
* pathname 경로를 조합하여 절대경로를 반환합니다.
|
|
96
|
-
*
|
|
97
|
-
* @param paths 조합할 경로 문자열들
|
|
98
|
-
* @returns 조합된 절대경로 문자열
|
|
99
|
-
*/
|
|
100
|
-
function absolutePath(...paths) {
|
|
101
|
-
paths = paths.map((p) => p.replace(/^\/|\/$/g, "")).filter((p) => p.length > 0);
|
|
102
|
-
if (paths.length === 0) return "/";
|
|
103
|
-
return "/" + paths.join("/");
|
|
104
|
-
}
|
|
105
|
-
/**
|
|
106
|
-
* basepath가 동적 패턴일 경우(RouteConfig에서 basepath가 :id 등으로 정의된 경우),
|
|
107
|
-
* 현재 경로에서 해당되는 패턴의 basepath를 추출하여 반환합니다.
|
|
108
|
-
*
|
|
109
|
-
* @param basepath 동적 패턴이 포함된 basepath 문자열
|
|
110
|
-
* @return 현재 경로에 매칭되는 basepath 문자열
|
|
111
|
-
* @example
|
|
112
|
-
* catchBasePath('/app/:id') => '/app/123'
|
|
113
|
-
*/
|
|
114
|
-
function catchBasepath(basepath) {
|
|
115
|
-
if (basepath === "/") return basepath;
|
|
116
|
-
let pattern = new URLPattern({ pathname: basepath + "/*" });
|
|
117
|
-
let match = pattern.exec({ pathname: window.location.pathname });
|
|
118
|
-
if (match) {
|
|
119
|
-
const rawPath = match.pathname.input;
|
|
120
|
-
const restPath = match.pathname.groups?.["0"];
|
|
121
|
-
return restPath !== void 0 && restPath !== "" ? rawPath.replace("/" + restPath, "") : rawPath.replace(/\/$/, "");
|
|
122
|
-
}
|
|
123
|
-
pattern = new URLPattern({ pathname: `${basepath}{/}?` });
|
|
124
|
-
match = pattern.exec({ pathname: window.location.pathname });
|
|
125
|
-
if (match) return match.pathname.input;
|
|
126
|
-
return basepath;
|
|
127
|
-
}
|
|
128
|
-
//#endregion
|
|
129
|
-
//#region \0@oxc-project+runtime@0.143.0/helpers/esm/decorateMetadata.js
|
|
130
|
-
function __decorateMetadata(k, v) {
|
|
131
|
-
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
132
|
-
}
|
|
133
|
-
//#endregion
|
|
134
|
-
//#region \0@oxc-project+runtime@0.143.0/helpers/esm/decorate.js
|
|
135
|
-
function __decorate(decorators, target, key, desc) {
|
|
136
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
137
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
138
|
-
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
139
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
140
|
-
}
|
|
141
|
-
//#endregion
|
|
142
|
-
//#region src/components/ULink.ts
|
|
143
|
-
var ULink = class ULink extends LitElement {
|
|
144
|
-
constructor(..._args) {
|
|
145
|
-
super(..._args);
|
|
146
|
-
this.isExternal = false;
|
|
147
|
-
this.handleClick = (event) => {
|
|
148
|
-
if (event.defaultPrevented) return;
|
|
149
|
-
if (event.button !== 0) return;
|
|
150
|
-
if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return;
|
|
151
|
-
if (this.target && this.target.toLowerCase() !== "_self") return;
|
|
152
|
-
if (this.navigate === "document") return;
|
|
153
|
-
const basepath = this.getBasepath();
|
|
154
|
-
if (!this.href) {
|
|
155
|
-
event.preventDefault();
|
|
156
|
-
this.dispatchPopstate(basepath, basepath);
|
|
157
|
-
return;
|
|
158
|
-
}
|
|
159
|
-
if (this.isExternal) return;
|
|
160
|
-
if (this.href.startsWith("#")) return;
|
|
161
|
-
event.preventDefault();
|
|
162
|
-
if (this.href.startsWith("?")) {
|
|
163
|
-
const url = window.location.pathname + this.href;
|
|
164
|
-
this.dispatchPopstate(basepath, url);
|
|
165
|
-
return;
|
|
166
|
-
}
|
|
167
|
-
if (this.href.startsWith("/")) {
|
|
168
|
-
if (!this.href.startsWith(basepath)) {
|
|
169
|
-
window.location.assign(this.href);
|
|
170
|
-
return;
|
|
171
|
-
}
|
|
172
|
-
this.dispatchPopstate(basepath, this.href);
|
|
173
|
-
return;
|
|
174
|
-
}
|
|
175
|
-
const url = absolutePath(basepath, this.href);
|
|
176
|
-
this.dispatchPopstate(basepath, url);
|
|
177
|
-
};
|
|
178
|
-
}
|
|
179
|
-
connectedCallback() {
|
|
180
|
-
super.connectedCallback();
|
|
181
|
-
this.addEventListener("click", this.handleClick);
|
|
182
|
-
}
|
|
183
|
-
disconnectedCallback() {
|
|
184
|
-
this.removeEventListener("click", this.handleClick);
|
|
185
|
-
super.disconnectedCallback();
|
|
186
|
-
}
|
|
187
|
-
willUpdate(changedProperties) {
|
|
188
|
-
super.willUpdate(changedProperties);
|
|
189
|
-
if (changedProperties.has("href")) this.isExternal = isExternalUrl(this.href || "");
|
|
190
|
-
}
|
|
191
|
-
render() {
|
|
192
|
-
return html`
|
|
193
|
-
<a
|
|
194
|
-
href=${this.compute(this.href)}
|
|
195
|
-
target=${ifDefined(this.target)}
|
|
196
|
-
rel=${ifDefined(this.rel)}
|
|
197
|
-
data-navigate=${ifDefined(this.navigate)}
|
|
198
|
-
>
|
|
199
|
-
<slot></slot>
|
|
200
|
-
</a>
|
|
201
|
-
`;
|
|
202
|
-
}
|
|
203
|
-
/** a 태그에 주입할 href 값을 계산합니다. */
|
|
204
|
-
compute(href) {
|
|
205
|
-
const basepath = this.getBasepath();
|
|
206
|
-
if (!href) return window.location.origin + basepath;
|
|
207
|
-
if (this.isExternal) return href;
|
|
208
|
-
if (href.startsWith("/")) return href;
|
|
209
|
-
if (href.startsWith("#") || href.startsWith("?")) return href;
|
|
210
|
-
return absolutePath(basepath, href);
|
|
211
|
-
}
|
|
212
|
-
/** 클라이언트 라우팅을 위해 popstate 이벤트를 발생시킵니다. */
|
|
213
|
-
dispatchPopstate(basepath, url) {
|
|
214
|
-
window.history.pushState({ basepath }, "", url);
|
|
215
|
-
window.dispatchEvent(new PopStateEvent("popstate"));
|
|
216
|
-
}
|
|
217
|
-
/** basepath를 state에서 꺼내는 헬퍼 */
|
|
218
|
-
getBasepath() {
|
|
219
|
-
return window.history.state?.basepath || "/";
|
|
220
|
-
}
|
|
221
|
-
static {
|
|
222
|
-
this.styles = css`
|
|
223
|
-
:host {
|
|
224
|
-
cursor: pointer;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
a {
|
|
228
|
-
text-decoration: none;
|
|
229
|
-
|
|
230
|
-
font-size: inherit;
|
|
231
|
-
font-weight: inherit;
|
|
232
|
-
font-family: inherit;
|
|
233
|
-
color: inherit;
|
|
234
|
-
cursor: inherit;
|
|
235
|
-
}
|
|
236
|
-
`;
|
|
237
|
-
}
|
|
238
|
-
};
|
|
239
|
-
__decorate([property({ type: String }), __decorateMetadata("design:type", String)], ULink.prototype, "target", void 0);
|
|
240
|
-
__decorate([property({ type: String }), __decorateMetadata("design:type", String)], ULink.prototype, "rel", void 0);
|
|
241
|
-
__decorate([property({ type: String }), __decorateMetadata("design:type", String)], ULink.prototype, "href", void 0);
|
|
242
|
-
__decorate([property({ type: String }), __decorateMetadata("design:type", String)], ULink.prototype, "navigate", void 0);
|
|
243
|
-
ULink = __decorate([customElement("u-link")], ULink);
|
|
244
|
-
//#endregion
|
|
245
|
-
export { isExternalUrl as a, absolutePath as i, __decorate as n, parseUrl as o, __decorateMetadata as r, UOutlet as s, ULink as t };
|