@iyulab/router 0.6.1 → 0.6.2
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/dist/index.d.ts +35 -28
- package/dist/index.js +40 -110
- package/dist/react.d.ts +34 -27
- package/dist/react.js +4 -29
- package/dist/{share-SPj-xl6y.js → share-6Zs4TunA.js} +53 -88
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -145,10 +145,14 @@ export declare class OutletMissingError extends RouteError {
|
|
|
145
145
|
constructor();
|
|
146
146
|
}
|
|
147
147
|
|
|
148
|
+
/** 렌더링 옵션 */
|
|
148
149
|
declare interface RenderOption {
|
|
150
|
+
/** 교차 렌더링 방지 ID */
|
|
149
151
|
id?: string;
|
|
152
|
+
/** 강제 렌더링 여부 */
|
|
150
153
|
force?: boolean;
|
|
151
|
-
|
|
154
|
+
/** 렌더링할 값 */
|
|
155
|
+
value: RenderResult;
|
|
152
156
|
}
|
|
153
157
|
|
|
154
158
|
export declare type RenderResult = HTMLElement | ReactElement | TemplateResult<1> | false;
|
|
@@ -297,7 +301,7 @@ export declare class RouteProgressEvent extends RouteEvent {
|
|
|
297
301
|
}
|
|
298
302
|
|
|
299
303
|
/**
|
|
300
|
-
* `lit-element`, `react`를 지원하는 클라이언트
|
|
304
|
+
* `lit-element`, `react`를 지원하는 SPA 클라이언트 라우터 객체입니다.
|
|
301
305
|
*/
|
|
302
306
|
export declare class Router {
|
|
303
307
|
private readonly _rootElement;
|
|
@@ -375,57 +379,60 @@ export declare class ULink extends LitElement {
|
|
|
375
379
|
/** 외부 링크 여부 */
|
|
376
380
|
private isExternal;
|
|
377
381
|
/**
|
|
378
|
-
*
|
|
379
|
-
*
|
|
382
|
+
* 링크 대상 target 속성
|
|
383
|
+
*
|
|
384
|
+
* - `_self`: 현재 창에서 링크 열기 (기본값)
|
|
385
|
+
* - `_blank`: 새 탭/창에서 링크 열기
|
|
386
|
+
* - `_parent`: 부모 프레임에서 링크 열기
|
|
387
|
+
* - `_top`: 최상위 프레임에서 링크 열기
|
|
380
388
|
*/
|
|
381
389
|
target?: string;
|
|
382
390
|
/**
|
|
383
|
-
*
|
|
391
|
+
* 링크 대상 URL, 다음 사항에 따라 SPA 라우팅 또는 브라우저 네비게이션이 결정됩니다.
|
|
392
|
+
*
|
|
393
|
+
* - 속성을 정의하지 않으면 설정에서 지정한 `basepath`로 SPA 라우팅합니다.
|
|
384
394
|
* - http(s)로 시작하면 외부 링크로 간주하고 브라우저 네비게이션을 사용합니다.
|
|
385
|
-
* - 절대경로(/...)
|
|
386
|
-
* - 상대경로는 (basepath + 상대경로)로 SPA
|
|
387
|
-
* - ?로 시작하면 현재
|
|
388
|
-
* - #으로 시작하면
|
|
395
|
+
* - 절대경로(/...)의 경우 `basepath`로 시작하면 SPA 라우팅합니다, 이외 브라우저 네비게이션을 사용합니다.
|
|
396
|
+
* - 상대경로는 (basepath + 상대경로)로 결합하여 SPA 라우팅합니다.
|
|
397
|
+
* - ?로 시작하면 현재 경로에 쿼리스트링을 추가하여 SPA 라우팅합니다.
|
|
398
|
+
* - #으로 시작하면 브라우저 기본 동작을 사용합니다.
|
|
389
399
|
*/
|
|
390
400
|
href?: string;
|
|
401
|
+
connectedCallback(): void;
|
|
402
|
+
disconnectedCallback(): void;
|
|
391
403
|
protected willUpdate(changedProperties: PropertyValues): void;
|
|
392
404
|
render(): TemplateResult_2<1>;
|
|
393
|
-
/** basepath를 state에서 꺼내는 헬퍼 */
|
|
394
|
-
private getBasepath;
|
|
395
405
|
/** a 태그에 주입할 href 값을 계산합니다. */
|
|
396
|
-
private
|
|
406
|
+
private compute;
|
|
397
407
|
/**
|
|
398
|
-
* 클릭 가로채기
|
|
408
|
+
* 클릭 가로채기 핸들러
|
|
399
409
|
* - 좌클릭(0) + 보조키 없음(ctrl/meta/shift/alt 없음) + target이 _self일 때만 SPA 라우팅 고려
|
|
400
410
|
* - 그 외(중클릭/우클릭/보조키/target=_blank 등)는 브라우저 기본 동작 유지
|
|
401
411
|
*/
|
|
402
|
-
private
|
|
412
|
+
private handleClick;
|
|
403
413
|
/** 클라이언트 라우팅을 위해 popstate 이벤트를 발생시킵니다. */
|
|
404
414
|
private dispatchPopstate;
|
|
415
|
+
/** basepath를 state에서 꺼내는 헬퍼 */
|
|
416
|
+
private getBasepath;
|
|
405
417
|
static styles: CSSResult;
|
|
406
418
|
}
|
|
407
419
|
|
|
408
420
|
/**
|
|
409
|
-
*
|
|
421
|
+
* LitElement 또는 React 컴포넌트를 렌더링해주는 웹컴포넌트 입니다.
|
|
410
422
|
*/
|
|
411
|
-
export declare class UOutlet extends
|
|
423
|
+
export declare class UOutlet extends HTMLElement {
|
|
424
|
+
/** 교차 렌더링 방지 id */
|
|
412
425
|
private routeId?;
|
|
413
|
-
|
|
414
|
-
private
|
|
415
|
-
/** 외부 스타일을 적용하기 위해 라이트 돔을사용 합니다. */
|
|
416
|
-
protected createRenderRoot(): this;
|
|
417
|
-
/** 컴포넌트가 DOM에 연결될 때 초기화 작업 수행 */
|
|
418
|
-
connectedCallback(): void;
|
|
419
|
-
render(): TemplateResult<1>;
|
|
426
|
+
/** 실제 렌더링 컨텐츠 */
|
|
427
|
+
private root?;
|
|
420
428
|
/**
|
|
421
|
-
*
|
|
422
|
-
* - HTMLElement, ReactElement, TemplateResult를 모두 처리할 수 있습니다.
|
|
429
|
+
* 주어진 렌더링 옵션에 따라 컨텐츠를 렌더링합니다.
|
|
423
430
|
*/
|
|
424
|
-
|
|
431
|
+
render({ id, value, force }: RenderOption): void;
|
|
425
432
|
/**
|
|
426
|
-
* 기존 DOM을
|
|
433
|
+
* 기존 DOM을 삭제하여, 초기 상태로 되돌립니다.
|
|
427
434
|
*/
|
|
428
|
-
|
|
435
|
+
reset(): void;
|
|
429
436
|
}
|
|
430
437
|
|
|
431
438
|
export { }
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
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-6Zs4TunA.js";
|
|
2
|
+
import { b, U } from "./share-6Zs4TunA.js";
|
|
3
3
|
import { css, LitElement, html } from "lit";
|
|
4
4
|
import { property, customElement } from "lit/decorators.js";
|
|
5
|
-
import { unsafeHTML } from "lit-html/directives/unsafe-html.js";
|
|
6
5
|
class RouteError extends Error {
|
|
7
6
|
constructor(code, message, original) {
|
|
8
7
|
super(message);
|
|
@@ -74,51 +73,6 @@ class RouteErrorEvent extends RouteEvent {
|
|
|
74
73
|
this.error = error;
|
|
75
74
|
}
|
|
76
75
|
}
|
|
77
|
-
const ban = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">\n <path d="M15 8a6.97 6.97 0 0 0-1.71-4.584l-9.874 9.875A7 7 0 0 0 15 8M2.71 12.584l9.874-9.875a7 7 0 0 0-9.874 9.874ZM16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0"/>\n</svg>';
|
|
78
|
-
const __vite_glob_0_0 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
79
|
-
__proto__: null,
|
|
80
|
-
default: ban
|
|
81
|
-
}, Symbol.toStringTag, { value: "Module" }));
|
|
82
|
-
const boxSeam = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">\n <path d="M8.186 1.113a.5.5 0 0 0-.372 0L1.846 3.5l2.404.961L10.404 2zm3.564 1.426L5.596 5 8 5.961 14.154 3.5zm3.25 1.7-6.5 2.6v7.922l6.5-2.6V4.24zM7.5 14.762V6.838L1 4.239v7.923zM7.443.184a1.5 1.5 0 0 1 1.114 0l7.129 2.852A.5.5 0 0 1 16 3.5v8.662a1 1 0 0 1-.629.928l-7.185 2.874a.5.5 0 0 1-.372 0L.63 13.09a1 1 0 0 1-.63-.928V3.5a.5.5 0 0 1 .314-.464z"/>\n</svg>';
|
|
83
|
-
const __vite_glob_0_1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
84
|
-
__proto__: null,
|
|
85
|
-
default: boxSeam
|
|
86
|
-
}, Symbol.toStringTag, { value: "Module" }));
|
|
87
|
-
const exclamationTriangle = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">\n <path d="M7.938 2.016A.13.13 0 0 1 8.002 2a.13.13 0 0 1 .063.016.15.15 0 0 1 .054.057l6.857 11.667c.036.06.035.124.002.183a.2.2 0 0 1-.054.06.1.1 0 0 1-.066.017H1.146a.1.1 0 0 1-.066-.017.2.2 0 0 1-.054-.06.18.18 0 0 1 .002-.183L7.884 2.073a.15.15 0 0 1 .054-.057m1.044-.45a1.13 1.13 0 0 0-1.96 0L.165 13.233c-.457.778.091 1.767.98 1.767h13.713c.889 0 1.438-.99.98-1.767z"/>\n <path d="M7.002 12a1 1 0 1 1 2 0 1 1 0 0 1-2 0M7.1 5.995a.905.905 0 1 1 1.8 0l-.35 3.507a.552.552 0 0 1-1.1 0z"/>\n</svg>';
|
|
88
|
-
const __vite_glob_0_2 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
89
|
-
__proto__: null,
|
|
90
|
-
default: exclamationTriangle
|
|
91
|
-
}, Symbol.toStringTag, { value: "Module" }));
|
|
92
|
-
const palette = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">\n <path d="M8 5a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3m4 3a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3M5.5 7a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0m.5 6a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3"/>\n <path d="M16 8c0 3.15-1.866 2.585-3.567 2.07C11.42 9.763 10.465 9.473 10 10c-.603.683-.475 1.819-.351 2.92C9.826 14.495 9.996 16 8 16a8 8 0 1 1 8-8m-8 7c.611 0 .654-.171.655-.176.078-.146.124-.464.07-1.119-.014-.168-.037-.37-.061-.591-.052-.464-.112-1.005-.118-1.462-.01-.707.083-1.61.704-2.314.369-.417.845-.578 1.272-.618.404-.038.812.026 1.16.104.343.077.702.186 1.025.284l.028.008c.346.105.658.199.953.266.653.148.904.083.991.024C14.717 9.38 15 9.161 15 8a7 7 0 1 0-7 7"/>\n</svg>';
|
|
93
|
-
const __vite_glob_0_3 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
94
|
-
__proto__: null,
|
|
95
|
-
default: palette
|
|
96
|
-
}, Symbol.toStringTag, { value: "Module" }));
|
|
97
|
-
const personLock = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">\n <path d="M11 5a3 3 0 1 1-6 0 3 3 0 0 1 6 0M8 7a2 2 0 1 0 0-4 2 2 0 0 0 0 4m0 5.996V14H3s-1 0-1-1 1-4 6-4q.845.002 1.544.107a4.5 4.5 0 0 0-.803.918A11 11 0 0 0 8 10c-2.29 0-3.516.68-4.168 1.332-.678.678-.83 1.418-.832 1.664zM9 13a1 1 0 0 1 1-1v-1a2 2 0 1 1 4 0v1a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1h-4a1 1 0 0 1-1-1zm3-3a1 1 0 0 0-1 1v1h2v-1a1 1 0 0 0-1-1"/>\n</svg>';
|
|
98
|
-
const __vite_glob_0_4 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
99
|
-
__proto__: null,
|
|
100
|
-
default: personLock
|
|
101
|
-
}, Symbol.toStringTag, { value: "Module" }));
|
|
102
|
-
const search = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">\n <path d="M11.742 10.344a6.5 6.5 0 1 0-1.397 1.398h-.001q.044.06.098.115l3.85 3.85a1 1 0 0 0 1.415-1.414l-3.85-3.85a1 1 0 0 0-.115-.1zM12 6.5a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0"/>\n</svg>';
|
|
103
|
-
const __vite_glob_0_5 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
104
|
-
__proto__: null,
|
|
105
|
-
default: search
|
|
106
|
-
}, Symbol.toStringTag, { value: "Module" }));
|
|
107
|
-
const stopwatch = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">\n <path d="M8.5 5.6a.5.5 0 1 0-1 0v2.9h-3a.5.5 0 0 0 0 1H8a.5.5 0 0 0 .5-.5z"/>\n <path d="M6.5 1A.5.5 0 0 1 7 .5h2a.5.5 0 0 1 0 1v.57c1.36.196 2.594.78 3.584 1.64l.012-.013.354-.354-.354-.353a.5.5 0 0 1 .707-.708l1.414 1.415a.5.5 0 1 1-.707.707l-.353-.354-.354.354-.013.012A7 7 0 1 1 7 2.071V1.5a.5.5 0 0 1-.5-.5M8 3a6 6 0 1 0 .001 12A6 6 0 0 0 8 3"/>\n</svg>';
|
|
108
|
-
const __vite_glob_0_6 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
109
|
-
__proto__: null,
|
|
110
|
-
default: stopwatch
|
|
111
|
-
}, Symbol.toStringTag, { value: "Module" }));
|
|
112
|
-
const wifiOff = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">\n <path d="M10.706 3.294A12.6 12.6 0 0 0 8 3C5.259 3 2.723 3.882.663 5.379a.485.485 0 0 0-.048.736.52.52 0 0 0 .668.05A11.45 11.45 0 0 1 8 4q.946 0 1.852.148zM8 6c-1.905 0-3.68.56-5.166 1.526a.48.48 0 0 0-.063.745.525.525 0 0 0 .652.065 8.45 8.45 0 0 1 3.51-1.27zm2.596 1.404.785-.785q.947.362 1.785.907a.482.482 0 0 1 .063.745.525.525 0 0 1-.652.065 8.5 8.5 0 0 0-1.98-.932zM8 10l.933-.933a6.5 6.5 0 0 1 2.013.637c.285.145.326.524.1.75l-.015.015a.53.53 0 0 1-.611.09A5.5 5.5 0 0 0 8 10m4.905-4.905.747-.747q.886.451 1.685 1.03a.485.485 0 0 1 .047.737.52.52 0 0 1-.668.05 11.5 11.5 0 0 0-1.811-1.07M9.02 11.78c.238.14.236.464.04.66l-.707.706a.5.5 0 0 1-.707 0l-.707-.707c-.195-.195-.197-.518.04-.66A2 2 0 0 1 8 11.5c.374 0 .723.102 1.021.28zm4.355-9.905a.53.53 0 0 1 .75.75l-10.75 10.75a.53.53 0 0 1-.75-.75z"/>\n</svg>';
|
|
113
|
-
const __vite_glob_0_7 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
114
|
-
__proto__: null,
|
|
115
|
-
default: wifiOff
|
|
116
|
-
}, Symbol.toStringTag, { value: "Module" }));
|
|
117
|
-
const wrenchAdjustable = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">\n <path d="M16 4.5a4.5 4.5 0 0 1-1.703 3.526L13 5l2.959-1.11q.04.3.041.61"/>\n <path d="M11.5 9c.653 0 1.273-.139 1.833-.39L12 5.5 11 3l3.826-1.53A4.5 4.5 0 0 0 7.29 6.092l-6.116 5.096a2.583 2.583 0 1 0 3.638 3.638L9.908 8.71A4.5 4.5 0 0 0 11.5 9m-1.292-4.361-.596.893.809-.27a.25.25 0 0 1 .287.377l-.596.893.809-.27.158.475-1.5.5a.25.25 0 0 1-.287-.376l.596-.893-.809.27a.25.25 0 0 1-.287-.377l.596-.893-.809.27-.158-.475 1.5-.5a.25.25 0 0 1 .287.376M3 14a1 1 0 1 1 0-2 1 1 0 0 1 0 2"/>\n</svg>';
|
|
118
|
-
const __vite_glob_0_8 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
119
|
-
__proto__: null,
|
|
120
|
-
default: wrenchAdjustable
|
|
121
|
-
}, Symbol.toStringTag, { value: "Module" }));
|
|
122
76
|
var __defProp = Object.defineProperty;
|
|
123
77
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
124
78
|
var __decorateClass = (decorators, target, key, kind) => {
|
|
@@ -129,27 +83,12 @@ var __decorateClass = (decorators, target, key, kind) => {
|
|
|
129
83
|
if (kind && result) __defProp(target, key, result);
|
|
130
84
|
return result;
|
|
131
85
|
};
|
|
132
|
-
const icons = Object.entries(/* @__PURE__ */ Object.assign({
|
|
133
|
-
"../assets/ban.svg": __vite_glob_0_0,
|
|
134
|
-
"../assets/box-seam.svg": __vite_glob_0_1,
|
|
135
|
-
"../assets/exclamation-triangle.svg": __vite_glob_0_2,
|
|
136
|
-
"../assets/palette.svg": __vite_glob_0_3,
|
|
137
|
-
"../assets/person-lock.svg": __vite_glob_0_4,
|
|
138
|
-
"../assets/search.svg": __vite_glob_0_5,
|
|
139
|
-
"../assets/stopwatch.svg": __vite_glob_0_6,
|
|
140
|
-
"../assets/wifi-off.svg": __vite_glob_0_7,
|
|
141
|
-
"../assets/wrench-adjustable.svg": __vite_glob_0_8
|
|
142
|
-
})).reduce((acc, [path, content]) => {
|
|
143
|
-
const name = path.split("/").pop()?.replace(".svg", "") || "";
|
|
144
|
-
acc[name] = content.default;
|
|
145
|
-
return acc;
|
|
146
|
-
}, {});
|
|
147
86
|
let UErrorPage = class extends LitElement {
|
|
148
87
|
render() {
|
|
149
88
|
const error = this.error || this.getDefaultError();
|
|
150
89
|
const icon = this.getErrorIcon(error.code);
|
|
151
90
|
return html`
|
|
152
|
-
<div class="icon">${
|
|
91
|
+
<div class="icon">${icon}</div>
|
|
153
92
|
<div class="code">${error.code}</div>
|
|
154
93
|
<div class="message">${error.message}</div>
|
|
155
94
|
`;
|
|
@@ -164,45 +103,45 @@ let UErrorPage = class extends LitElement {
|
|
|
164
103
|
const numericCode = typeof code === "string" ? parseInt(code) : code;
|
|
165
104
|
switch (codeStr) {
|
|
166
105
|
case "OUTLET_NOT_FOUND":
|
|
167
|
-
return
|
|
106
|
+
return "📦";
|
|
168
107
|
case "CONTENT_LOAD_FAILED":
|
|
169
|
-
return
|
|
108
|
+
return "📡";
|
|
170
109
|
case "RENDER_FAILED":
|
|
171
|
-
return
|
|
110
|
+
return "🎨";
|
|
172
111
|
}
|
|
173
112
|
switch (numericCode) {
|
|
174
113
|
case 404:
|
|
175
|
-
return
|
|
114
|
+
return "🔍";
|
|
176
115
|
case 403:
|
|
177
|
-
return
|
|
116
|
+
return "🚫";
|
|
178
117
|
case 401:
|
|
179
|
-
return
|
|
118
|
+
return "🔐";
|
|
180
119
|
case 429:
|
|
181
|
-
return
|
|
120
|
+
return "⏱️";
|
|
182
121
|
case 503:
|
|
183
|
-
return
|
|
122
|
+
return "🛠️";
|
|
184
123
|
default:
|
|
185
|
-
return
|
|
124
|
+
return "⚠️";
|
|
186
125
|
}
|
|
187
126
|
}
|
|
188
127
|
};
|
|
189
128
|
UErrorPage.styles = css`
|
|
190
129
|
:host {
|
|
191
|
-
--
|
|
192
|
-
--
|
|
193
|
-
--
|
|
130
|
+
--error-icon-color: #4a5568;
|
|
131
|
+
--error-code-color: #1a202c;
|
|
132
|
+
--error-message-color: #718096;
|
|
194
133
|
}
|
|
195
134
|
:host-context([theme="dark"]) {
|
|
196
|
-
--
|
|
197
|
-
--
|
|
198
|
-
--
|
|
135
|
+
--error-icon-color: #a0aec0;
|
|
136
|
+
--error-code-color: #f7fafc;
|
|
137
|
+
--error-message-color: #cbd5e0;
|
|
199
138
|
}
|
|
200
139
|
|
|
201
140
|
@media (prefers-color-scheme: dark) {
|
|
202
141
|
:host {
|
|
203
|
-
--
|
|
204
|
-
--
|
|
205
|
-
--
|
|
142
|
+
--error-icon-color: #a0aec0;
|
|
143
|
+
--error-code-color: #f7fafc;
|
|
144
|
+
--error-message-color: #cbd5e0;
|
|
206
145
|
}
|
|
207
146
|
}
|
|
208
147
|
|
|
@@ -211,8 +150,8 @@ UErrorPage.styles = css`
|
|
|
211
150
|
flex-direction: column;
|
|
212
151
|
justify-content: center;
|
|
213
152
|
align-items: center;
|
|
214
|
-
min-height: 100vh;
|
|
215
153
|
width: 100%;
|
|
154
|
+
height: 100%;
|
|
216
155
|
text-align: center;
|
|
217
156
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
218
157
|
overflow: auto;
|
|
@@ -220,31 +159,24 @@ UErrorPage.styles = css`
|
|
|
220
159
|
}
|
|
221
160
|
|
|
222
161
|
.icon {
|
|
223
|
-
|
|
162
|
+
color: var(--error-icon-color);
|
|
224
163
|
font-size: 6rem;
|
|
225
|
-
color: var(--route-icon-color);
|
|
226
164
|
opacity: 0.85;
|
|
227
165
|
}
|
|
228
166
|
|
|
229
|
-
svg {
|
|
230
|
-
width: 1em;
|
|
231
|
-
height: 1em;
|
|
232
|
-
fill: currentColor;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
167
|
.code {
|
|
168
|
+
color: var(--error-code-color);
|
|
236
169
|
font-size: 2rem;
|
|
237
170
|
font-weight: 700;
|
|
238
|
-
margin: 1rem 0;
|
|
239
|
-
color: var(--route-code-color);
|
|
240
171
|
letter-spacing: -0.5px;
|
|
172
|
+
margin: 1rem 0;
|
|
241
173
|
}
|
|
242
174
|
|
|
243
175
|
.message {
|
|
176
|
+
color: var(--error-message-color);
|
|
244
177
|
font-size: 1rem;
|
|
245
|
-
color: var(--route-message-color);
|
|
246
|
-
max-width: 600px;
|
|
247
178
|
line-height: 1.6;
|
|
179
|
+
max-width: 600px;
|
|
248
180
|
}
|
|
249
181
|
`;
|
|
250
182
|
__decorateClass([
|
|
@@ -257,6 +189,7 @@ function getRandomID() {
|
|
|
257
189
|
return window.isSecureContext ? window.crypto.randomUUID() : window.crypto.getRandomValues(new Uint32Array(1))[0].toString(16);
|
|
258
190
|
}
|
|
259
191
|
function findOutlet(element) {
|
|
192
|
+
if (!element) return void 0;
|
|
260
193
|
let outlet = void 0;
|
|
261
194
|
if (element.shadowRoot) {
|
|
262
195
|
outlet = element.shadowRoot.querySelector("u-outlet");
|
|
@@ -301,8 +234,7 @@ function findAnchorFrom(event) {
|
|
|
301
234
|
}
|
|
302
235
|
const tgt = event.target;
|
|
303
236
|
if (!tgt) return null;
|
|
304
|
-
|
|
305
|
-
return anchor;
|
|
237
|
+
return tgt.closest("a");
|
|
306
238
|
}
|
|
307
239
|
function setRoutes(routes, basepath) {
|
|
308
240
|
for (const route of routes) {
|
|
@@ -336,10 +268,10 @@ function setRoutes(routes, basepath) {
|
|
|
336
268
|
}
|
|
337
269
|
return routes;
|
|
338
270
|
}
|
|
339
|
-
function getRoutes(
|
|
271
|
+
function getRoutes(routes, pathname) {
|
|
340
272
|
for (const route of routes) {
|
|
341
273
|
if (route.index !== true && route.children && route.children.length > 0) {
|
|
342
|
-
const childRoutes = getRoutes(
|
|
274
|
+
const childRoutes = getRoutes(route.children, pathname);
|
|
343
275
|
if (childRoutes.length > 0) {
|
|
344
276
|
return [route, ...childRoutes];
|
|
345
277
|
}
|
|
@@ -355,11 +287,11 @@ function getRoutes(pathname, routes) {
|
|
|
355
287
|
}
|
|
356
288
|
class Router {
|
|
357
289
|
constructor(config) {
|
|
358
|
-
this.handleWindowPopstate = async () => {
|
|
290
|
+
this.handleWindowPopstate = async (_) => {
|
|
359
291
|
const href = window.location.href;
|
|
360
292
|
await this.go(href);
|
|
361
293
|
};
|
|
362
|
-
this.handleDocumentClick = (e) => {
|
|
294
|
+
this.handleDocumentClick = async (e) => {
|
|
363
295
|
try {
|
|
364
296
|
if (e.defaultPrevented) return;
|
|
365
297
|
if (e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey) return;
|
|
@@ -372,18 +304,17 @@ class Router {
|
|
|
372
304
|
if (anchor.getAttribute("rel") === "external") return;
|
|
373
305
|
if (anchor.target && anchor.target !== "") return;
|
|
374
306
|
e.preventDefault();
|
|
375
|
-
|
|
307
|
+
await this.go(anchor.href);
|
|
376
308
|
} catch {
|
|
377
309
|
}
|
|
378
310
|
};
|
|
311
|
+
this.destroy();
|
|
379
312
|
this._rootElement = config.root;
|
|
380
313
|
this._basepath = absolutePath(config.basepath || "/");
|
|
381
314
|
this._routes = setRoutes(config.routes || [], this._basepath);
|
|
382
315
|
this._fallback = config.fallback;
|
|
383
|
-
window.removeEventListener("popstate", this.handleWindowPopstate);
|
|
384
316
|
window.addEventListener("popstate", this.handleWindowPopstate);
|
|
385
317
|
if (config.useIntercept !== false) {
|
|
386
|
-
document.removeEventListener("click", this.handleDocumentClick);
|
|
387
318
|
document.addEventListener("click", this.handleDocumentClick);
|
|
388
319
|
}
|
|
389
320
|
if (config.initialLoad !== false) {
|
|
@@ -434,7 +365,7 @@ class Router {
|
|
|
434
365
|
try {
|
|
435
366
|
if (this._requestID !== requestID) return;
|
|
436
367
|
window.dispatchEvent(new RouteBeginEvent(context));
|
|
437
|
-
const routes = getRoutes(
|
|
368
|
+
const routes = getRoutes(this._routes, context.pathname);
|
|
438
369
|
const lastRoute = routes[routes.length - 1];
|
|
439
370
|
if (lastRoute && lastRoute.path instanceof URLPattern) {
|
|
440
371
|
context.params = lastRoute.path.exec({ pathname: context.pathname })?.pathname.groups || {};
|
|
@@ -443,7 +374,6 @@ class Router {
|
|
|
443
374
|
outlet = findOutletOrThrow(this._rootElement);
|
|
444
375
|
let title = void 0;
|
|
445
376
|
let content = null;
|
|
446
|
-
let element = null;
|
|
447
377
|
if (routes.length === 0) {
|
|
448
378
|
throw new NotFoundError(context.href);
|
|
449
379
|
}
|
|
@@ -459,11 +389,11 @@ class Router {
|
|
|
459
389
|
throw new ContentLoadError(LoadError);
|
|
460
390
|
}
|
|
461
391
|
try {
|
|
462
|
-
|
|
392
|
+
outlet.render({ id: route.id, value: content, force: route.force });
|
|
463
393
|
} catch (renderError) {
|
|
464
394
|
throw new ContentRenderError(renderError);
|
|
465
395
|
}
|
|
466
|
-
outlet = findOutlet(
|
|
396
|
+
outlet = findOutlet(outlet) || outlet;
|
|
467
397
|
title = route.title || title;
|
|
468
398
|
}
|
|
469
399
|
document.title = title || document.title;
|
|
@@ -479,13 +409,13 @@ class Router {
|
|
|
479
409
|
try {
|
|
480
410
|
if (this._fallback && this._fallback.render && outlet) {
|
|
481
411
|
const fallbackContent = await this._fallback.render({ ...context, error: routeError });
|
|
482
|
-
outlet.
|
|
412
|
+
outlet.render({ id: "#fallback", value: fallbackContent, force: true });
|
|
483
413
|
document.title = this._fallback.title || document.title;
|
|
484
414
|
} else {
|
|
485
415
|
const errorContent = new UErrorPage();
|
|
486
416
|
errorContent.error = error;
|
|
487
417
|
if (outlet) {
|
|
488
|
-
outlet.
|
|
418
|
+
outlet.render({ id: "#error", value: errorContent, force: true });
|
|
489
419
|
} else {
|
|
490
420
|
document.body.innerHTML = "";
|
|
491
421
|
document.body.appendChild(errorContent);
|
package/dist/react.d.ts
CHANGED
|
@@ -6,10 +6,14 @@ import { ReactWebComponent } from '@lit/react';
|
|
|
6
6
|
import { TemplateResult } from 'lit-html';
|
|
7
7
|
import { TemplateResult as TemplateResult_2 } from 'lit';
|
|
8
8
|
|
|
9
|
+
/** 렌더링 옵션 */
|
|
9
10
|
declare interface RenderOption {
|
|
11
|
+
/** 교차 렌더링 방지 ID */
|
|
10
12
|
id?: string;
|
|
13
|
+
/** 강제 렌더링 여부 */
|
|
11
14
|
force?: boolean;
|
|
12
|
-
|
|
15
|
+
/** 렌더링할 값 */
|
|
16
|
+
value: RenderResult;
|
|
13
17
|
}
|
|
14
18
|
|
|
15
19
|
declare type RenderResult = HTMLElement | ReactElement | TemplateResult_2<1> | false;
|
|
@@ -28,33 +32,41 @@ declare class ULink_2 extends LitElement {
|
|
|
28
32
|
/** 외부 링크 여부 */
|
|
29
33
|
private isExternal;
|
|
30
34
|
/**
|
|
31
|
-
*
|
|
32
|
-
*
|
|
35
|
+
* 링크 대상 target 속성
|
|
36
|
+
*
|
|
37
|
+
* - `_self`: 현재 창에서 링크 열기 (기본값)
|
|
38
|
+
* - `_blank`: 새 탭/창에서 링크 열기
|
|
39
|
+
* - `_parent`: 부모 프레임에서 링크 열기
|
|
40
|
+
* - `_top`: 최상위 프레임에서 링크 열기
|
|
33
41
|
*/
|
|
34
42
|
target?: string;
|
|
35
43
|
/**
|
|
36
|
-
*
|
|
44
|
+
* 링크 대상 URL, 다음 사항에 따라 SPA 라우팅 또는 브라우저 네비게이션이 결정됩니다.
|
|
45
|
+
*
|
|
46
|
+
* - 속성을 정의하지 않으면 설정에서 지정한 `basepath`로 SPA 라우팅합니다.
|
|
37
47
|
* - http(s)로 시작하면 외부 링크로 간주하고 브라우저 네비게이션을 사용합니다.
|
|
38
|
-
* - 절대경로(/...)
|
|
39
|
-
* - 상대경로는 (basepath + 상대경로)로 SPA
|
|
40
|
-
* - ?로 시작하면 현재
|
|
41
|
-
* - #으로 시작하면
|
|
48
|
+
* - 절대경로(/...)의 경우 `basepath`로 시작하면 SPA 라우팅합니다, 이외 브라우저 네비게이션을 사용합니다.
|
|
49
|
+
* - 상대경로는 (basepath + 상대경로)로 결합하여 SPA 라우팅합니다.
|
|
50
|
+
* - ?로 시작하면 현재 경로에 쿼리스트링을 추가하여 SPA 라우팅합니다.
|
|
51
|
+
* - #으로 시작하면 브라우저 기본 동작을 사용합니다.
|
|
42
52
|
*/
|
|
43
53
|
href?: string;
|
|
54
|
+
connectedCallback(): void;
|
|
55
|
+
disconnectedCallback(): void;
|
|
44
56
|
protected willUpdate(changedProperties: PropertyValues): void;
|
|
45
57
|
render(): TemplateResult<1>;
|
|
46
|
-
/** basepath를 state에서 꺼내는 헬퍼 */
|
|
47
|
-
private getBasepath;
|
|
48
58
|
/** a 태그에 주입할 href 값을 계산합니다. */
|
|
49
|
-
private
|
|
59
|
+
private compute;
|
|
50
60
|
/**
|
|
51
|
-
* 클릭 가로채기
|
|
61
|
+
* 클릭 가로채기 핸들러
|
|
52
62
|
* - 좌클릭(0) + 보조키 없음(ctrl/meta/shift/alt 없음) + target이 _self일 때만 SPA 라우팅 고려
|
|
53
63
|
* - 그 외(중클릭/우클릭/보조키/target=_blank 등)는 브라우저 기본 동작 유지
|
|
54
64
|
*/
|
|
55
|
-
private
|
|
65
|
+
private handleClick;
|
|
56
66
|
/** 클라이언트 라우팅을 위해 popstate 이벤트를 발생시킵니다. */
|
|
57
67
|
private dispatchPopstate;
|
|
68
|
+
/** basepath를 state에서 꺼내는 헬퍼 */
|
|
69
|
+
private getBasepath;
|
|
58
70
|
static styles: CSSResult;
|
|
59
71
|
}
|
|
60
72
|
|
|
@@ -64,26 +76,21 @@ declare class ULink_2 extends LitElement {
|
|
|
64
76
|
export declare const UOutlet: ReactWebComponent<UOutlet_2, {}>;
|
|
65
77
|
|
|
66
78
|
/**
|
|
67
|
-
*
|
|
79
|
+
* LitElement 또는 React 컴포넌트를 렌더링해주는 웹컴포넌트 입니다.
|
|
68
80
|
*/
|
|
69
|
-
declare class UOutlet_2 extends
|
|
81
|
+
declare class UOutlet_2 extends HTMLElement {
|
|
82
|
+
/** 교차 렌더링 방지 id */
|
|
70
83
|
private routeId?;
|
|
71
|
-
|
|
72
|
-
private
|
|
73
|
-
/** 외부 스타일을 적용하기 위해 라이트 돔을사용 합니다. */
|
|
74
|
-
protected createRenderRoot(): this;
|
|
75
|
-
/** 컴포넌트가 DOM에 연결될 때 초기화 작업 수행 */
|
|
76
|
-
connectedCallback(): void;
|
|
77
|
-
render(): TemplateResult_2<1>;
|
|
84
|
+
/** 실제 렌더링 컨텐츠 */
|
|
85
|
+
private root?;
|
|
78
86
|
/**
|
|
79
|
-
*
|
|
80
|
-
* - HTMLElement, ReactElement, TemplateResult를 모두 처리할 수 있습니다.
|
|
87
|
+
* 주어진 렌더링 옵션에 따라 컨텐츠를 렌더링합니다.
|
|
81
88
|
*/
|
|
82
|
-
|
|
89
|
+
render({ id, value, force }: RenderOption): void;
|
|
83
90
|
/**
|
|
84
|
-
* 기존 DOM을
|
|
91
|
+
* 기존 DOM을 삭제하여, 초기 상태로 되돌립니다.
|
|
85
92
|
*/
|
|
86
|
-
|
|
93
|
+
reset(): void;
|
|
87
94
|
}
|
|
88
95
|
|
|
89
96
|
export { }
|
package/dist/react.js
CHANGED
|
@@ -1,38 +1,13 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
void 0 === s ? (e2[t2] = o2, null == o2 && t2 in HTMLElement.prototype && e2.removeAttribute(t2)) : o2 !== l && ((e3, t3, o3) => {
|
|
6
|
-
let l2 = n.get(e3);
|
|
7
|
-
void 0 === l2 && n.set(e3, l2 = /* @__PURE__ */ new Map());
|
|
8
|
-
let a2 = l2.get(t3);
|
|
9
|
-
void 0 !== o3 ? void 0 === a2 ? (l2.set(t3, a2 = { handleEvent: o3 }), e3.addEventListener(t3, a2)) : a2.handleEvent = o3 : void 0 !== a2 && (l2.delete(t3), e3.removeEventListener(t3, a2));
|
|
10
|
-
})(e2, s, o2);
|
|
11
|
-
}, o = ({ react: n2, tagName: o2, elementClass: l, events: a, displayName: s }) => {
|
|
12
|
-
const c = new Set(Object.keys(a ?? {})), r = n2.forwardRef(((s2, r2) => {
|
|
13
|
-
const i = n2.useRef(/* @__PURE__ */ new Map()), d = n2.useRef(null), f = {}, u = {};
|
|
14
|
-
for (const [n3, t2] of Object.entries(s2)) e.has(n3) ? f["className" === n3 ? "class" : n3] = t2 : c.has(n3) || n3 in l.prototype ? u[n3] = t2 : f[n3] = t2;
|
|
15
|
-
return n2.useLayoutEffect((() => {
|
|
16
|
-
if (null === d.current) return;
|
|
17
|
-
const e2 = /* @__PURE__ */ new Map();
|
|
18
|
-
for (const n3 in u) t(d.current, n3, s2[n3], i.current.get(n3), a), i.current.delete(n3), e2.set(n3, s2[n3]);
|
|
19
|
-
for (const [e3, n3] of i.current) t(d.current, e3, void 0, n3, a);
|
|
20
|
-
i.current = e2;
|
|
21
|
-
})), n2.useLayoutEffect((() => {
|
|
22
|
-
d.current?.removeAttribute("defer-hydration");
|
|
23
|
-
}), []), f.suppressHydrationWarning = true, n2.createElement(o2, { ...f, ref: n2.useCallback(((e2) => {
|
|
24
|
-
d.current = e2, "function" == typeof r2 ? r2(e2) : null !== r2 && (r2.current = e2);
|
|
25
|
-
}), [r2]) });
|
|
26
|
-
}));
|
|
27
|
-
return r.displayName = s ?? l.name, r;
|
|
28
|
-
};
|
|
29
|
-
const ULink = o({
|
|
2
|
+
import { createComponent } from "@lit/react";
|
|
3
|
+
import { b as ULink$1, U as UOutlet$1 } from "./share-6Zs4TunA.js";
|
|
4
|
+
const ULink = createComponent({
|
|
30
5
|
react: React,
|
|
31
6
|
tagName: "u-link",
|
|
32
7
|
elementClass: ULink$1,
|
|
33
8
|
events: {}
|
|
34
9
|
});
|
|
35
|
-
const UOutlet =
|
|
10
|
+
const UOutlet = createComponent({
|
|
36
11
|
react: React,
|
|
37
12
|
tagName: "u-outlet",
|
|
38
13
|
elementClass: UOutlet$1,
|
|
@@ -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
|
-
this.content.unmount();
|
|
65
|
-
}
|
|
66
|
-
if ("setConnected" in this.content) {
|
|
67
|
-
this.content.setConnected(false);
|
|
68
|
-
}
|
|
69
|
-
this.content = void 0;
|
|
31
|
+
reset() {
|
|
32
|
+
if (this.root && "_$litPart$" in this) {
|
|
33
|
+
delete this._$litPart$;
|
|
70
34
|
}
|
|
71
|
-
this.
|
|
72
|
-
|
|
35
|
+
if (this.root && "unmount" in this.root) {
|
|
36
|
+
this.root.unmount();
|
|
37
|
+
}
|
|
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("/")) {
|
|
@@ -121,7 +86,7 @@ function absolutePath(...paths) {
|
|
|
121
86
|
if (paths.length === 0) return "/";
|
|
122
87
|
return "/" + paths.join("/");
|
|
123
88
|
}
|
|
124
|
-
function
|
|
89
|
+
function catchBasepath(basepath) {
|
|
125
90
|
if (basepath === "/") return basepath;
|
|
126
91
|
let pattern = new URLPattern({ pathname: basepath + "/*" });
|
|
127
92
|
let match = pattern.exec({ pathname: window.location.pathname });
|
|
@@ -151,12 +116,11 @@ let ULink = class extends LitElement {
|
|
|
151
116
|
constructor() {
|
|
152
117
|
super(...arguments);
|
|
153
118
|
this.isExternal = false;
|
|
154
|
-
this.
|
|
119
|
+
this.handleClick = (event) => {
|
|
155
120
|
if (event.defaultPrevented) return;
|
|
156
121
|
if (event.button !== 0) return;
|
|
157
122
|
if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return;
|
|
158
|
-
|
|
159
|
-
if (target && target.toLowerCase() !== "_self") return;
|
|
123
|
+
if (this.target && this.target.toLowerCase() !== "_self") return;
|
|
160
124
|
const basepath = this.getBasepath();
|
|
161
125
|
if (!this.href) {
|
|
162
126
|
event.preventDefault();
|
|
@@ -183,6 +147,14 @@ let ULink = class extends LitElement {
|
|
|
183
147
|
this.dispatchPopstate(basepath, url);
|
|
184
148
|
};
|
|
185
149
|
}
|
|
150
|
+
connectedCallback() {
|
|
151
|
+
super.connectedCallback();
|
|
152
|
+
this.addEventListener("click", this.handleClick);
|
|
153
|
+
}
|
|
154
|
+
disconnectedCallback() {
|
|
155
|
+
this.removeEventListener("click", this.handleClick);
|
|
156
|
+
super.disconnectedCallback();
|
|
157
|
+
}
|
|
186
158
|
willUpdate(changedProperties) {
|
|
187
159
|
super.willUpdate(changedProperties);
|
|
188
160
|
if (changedProperties.has("href")) {
|
|
@@ -191,27 +163,18 @@ let ULink = class extends LitElement {
|
|
|
191
163
|
}
|
|
192
164
|
render() {
|
|
193
165
|
return html`
|
|
194
|
-
<a
|
|
195
|
-
target=${this.target ?? "_self"}
|
|
196
|
-
href=${this.computeHref(this.href)}
|
|
197
|
-
@click=${this.handleAnchorClick}>
|
|
166
|
+
<a target=${ifDefined(this.target)} href=${this.compute(this.href)}>
|
|
198
167
|
<slot></slot>
|
|
199
168
|
</a>
|
|
200
169
|
`;
|
|
201
170
|
}
|
|
202
|
-
/** basepath를 state에서 꺼내는 헬퍼 */
|
|
203
|
-
getBasepath() {
|
|
204
|
-
return window.history.state?.basepath || "";
|
|
205
|
-
}
|
|
206
171
|
/** a 태그에 주입할 href 값을 계산합니다. */
|
|
207
|
-
|
|
172
|
+
compute(href) {
|
|
208
173
|
const basepath = this.getBasepath();
|
|
209
|
-
if (!href)
|
|
210
|
-
return window.location.origin + basepath;
|
|
211
|
-
}
|
|
174
|
+
if (!href) return window.location.origin + basepath;
|
|
212
175
|
if (this.isExternal) return href;
|
|
213
|
-
if (href.startsWith("#") || href.startsWith("?")) return href;
|
|
214
176
|
if (href.startsWith("/")) return href;
|
|
177
|
+
if (href.startsWith("#") || href.startsWith("?")) return href;
|
|
215
178
|
return absolutePath(basepath, href);
|
|
216
179
|
}
|
|
217
180
|
/** 클라이언트 라우팅을 위해 popstate 이벤트를 발생시킵니다. */
|
|
@@ -219,15 +182,17 @@ let ULink = class extends LitElement {
|
|
|
219
182
|
window.history.pushState({ basepath }, "", url);
|
|
220
183
|
window.dispatchEvent(new PopStateEvent("popstate"));
|
|
221
184
|
}
|
|
185
|
+
/** basepath를 state에서 꺼내는 헬퍼 */
|
|
186
|
+
getBasepath() {
|
|
187
|
+
return window.history.state?.basepath || "";
|
|
188
|
+
}
|
|
222
189
|
};
|
|
223
190
|
ULink.styles = css`
|
|
224
191
|
:host {
|
|
225
|
-
display: inline-flex;
|
|
226
192
|
cursor: pointer;
|
|
227
193
|
}
|
|
228
194
|
|
|
229
195
|
a {
|
|
230
|
-
display: contents;
|
|
231
196
|
text-decoration: none;
|
|
232
197
|
|
|
233
198
|
font-size: inherit;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@iyulab/router",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.2",
|
|
4
4
|
"description": "A modern client-side router for web applications with support for Lit and React components",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"lit",
|
|
@@ -40,14 +40,14 @@
|
|
|
40
40
|
"build": "vite build"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
+
"@lit/react": "^1.0.8",
|
|
43
44
|
"lit": "^3.3.2",
|
|
44
45
|
"react": "^19.2.3",
|
|
45
46
|
"react-dom": "^19.2.3"
|
|
46
47
|
},
|
|
47
48
|
"devDependencies": {
|
|
48
|
-
"@lit/react": "^1.0.8",
|
|
49
49
|
"@types/node": "^25.0.9",
|
|
50
|
-
"@types/react": "^19.2.
|
|
50
|
+
"@types/react": "^19.2.9",
|
|
51
51
|
"@types/react-dom": "^19.2.3",
|
|
52
52
|
"typescript": "^5.9.3",
|
|
53
53
|
"vite": "^7.3.1",
|