@iyulab/router 0.5.1 → 0.5.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 +162 -108
- package/dist/index.js +154 -100
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -18,22 +18,38 @@ declare interface BaseRouteConfig {
|
|
|
18
18
|
*/
|
|
19
19
|
title?: string;
|
|
20
20
|
/**
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
* @
|
|
21
|
+
* 라우터 경로는 string 또는 URLPattern을 사용할 수 있습니다.
|
|
22
|
+
* string일 경우 자동으로 URLPattern으로 변환됩니다.
|
|
23
|
+
* @default '/'
|
|
24
|
+
* @example
|
|
25
|
+
* - "/user/:id/:name"
|
|
26
|
+
* - "/user/:id/:name?"
|
|
27
|
+
* - "/user/:id/:name*"
|
|
28
|
+
* - "/user/:id/:name+"
|
|
29
|
+
* - "/user/:id/:name{1,3}"
|
|
30
|
+
* @link
|
|
31
|
+
* https://developer.mozilla.org/en-US/docs/Web/API/URLPattern
|
|
32
|
+
*/
|
|
33
|
+
path?: string | URLPattern;
|
|
34
|
+
/**
|
|
35
|
+
* 라우트 정보를 받아 렌더링 결과를 반환합니다.
|
|
36
|
+
* @param ctx 현재 라우팅 정보 및, 진행 상태 콜백을 포함하는 Context 객체가 인자로 전달됩니다.
|
|
24
37
|
* @example
|
|
25
38
|
* ```typescript
|
|
26
39
|
* const route = {
|
|
27
|
-
* path: '/user',
|
|
28
|
-
* render: (
|
|
40
|
+
* path: '/user:id',
|
|
41
|
+
* render: async (ctx) => {
|
|
42
|
+
* // 사용자 정보를 비동기로 가져오는 예시
|
|
43
|
+
* const userId = ctx.params.id;
|
|
44
|
+
* ctx.progress(30);
|
|
45
|
+
* const userData = await fetchUserData(userId);
|
|
46
|
+
* ctx.progress(70);
|
|
47
|
+
* return html`<user-profile .data=${userData}></user-profile>`;
|
|
48
|
+
* }
|
|
29
49
|
* }
|
|
30
50
|
* ```
|
|
31
51
|
*/
|
|
32
|
-
render?: (
|
|
33
|
-
/**
|
|
34
|
-
* 중첩 라우트
|
|
35
|
-
*/
|
|
36
|
-
children?: RouteConfig[];
|
|
52
|
+
render?: (ctx: RouteContext) => Promise<RenderResult> | RenderResult;
|
|
37
53
|
/**
|
|
38
54
|
* 라우터 URL 변경시 렌더링을 강제할지 여부
|
|
39
55
|
* - 기본값으로 children을 가질때 false로 설정되며, children이 없을 경우 true로 설정됩니다.
|
|
@@ -56,20 +72,47 @@ export declare class ContentRenderError extends RouteError {
|
|
|
56
72
|
constructor(original?: Error | any);
|
|
57
73
|
}
|
|
58
74
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
declare interface IndexRouteConfig extends BaseRouteConfig {
|
|
75
|
+
export declare type FallbackRenderResult = HTMLElement | ReactElement | TemplateResult<1>;
|
|
76
|
+
|
|
77
|
+
export declare interface FallbackRouteConfig {
|
|
63
78
|
/**
|
|
64
|
-
*
|
|
65
|
-
* path는 강제로 빈 문자열로 설정됩니다.
|
|
79
|
+
* 브라우저의 타이틀이 설정에 따라 변경됩니다.
|
|
66
80
|
*/
|
|
67
|
-
|
|
81
|
+
title?: string;
|
|
68
82
|
/**
|
|
69
|
-
*
|
|
70
|
-
*
|
|
83
|
+
* 라우팅 실패 시 표시할 렌더링 결과를 반환합니다.
|
|
84
|
+
* - 오류가 발생할 경우 또는 렌더링 결과가 false일 경우 호출됩니다.
|
|
85
|
+
* @param ctx 현재 라우팅 정보 및 오류 정보를 포함하는 Context 객체가 인자로 전달됩니다.
|
|
86
|
+
* @example
|
|
87
|
+
* ```typescript
|
|
88
|
+
* const fallbackRoute = {
|
|
89
|
+
* title: 'Not Found',
|
|
90
|
+
* render: (ctx) => {
|
|
91
|
+
* if (ctx.error) {
|
|
92
|
+
* return html`<error-page .error=${ctx.error}></error-page>`;
|
|
93
|
+
* }
|
|
94
|
+
* return html`<not-found-page></not-found-page>`;
|
|
95
|
+
* }
|
|
96
|
+
* }
|
|
97
|
+
* ```
|
|
71
98
|
*/
|
|
72
|
-
|
|
99
|
+
render?: (ctx: FallbackRouteContext) => Promise<FallbackRenderResult> | FallbackRenderResult;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export declare interface FallbackRouteContext extends RouteContext {
|
|
103
|
+
/**
|
|
104
|
+
* 라우팅 에러 정보
|
|
105
|
+
* - 라우팅 중 발생한 에러 정보를 포함합니다.
|
|
106
|
+
*/
|
|
107
|
+
error: RouteError;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
declare interface IndexRouteConfig extends BaseRouteConfig {
|
|
111
|
+
/**
|
|
112
|
+
* 현재 경로의 인덱스 라우트임을 나타냅니다.
|
|
113
|
+
* - 인덱스 라우트는 부모 경로와 동일한 경로를 가지며, path는 자동으로 설정됩니다.
|
|
114
|
+
*/
|
|
115
|
+
index: true;
|
|
73
116
|
}
|
|
74
117
|
|
|
75
118
|
/**
|
|
@@ -113,6 +156,18 @@ export declare class Link extends LitElement {
|
|
|
113
156
|
static styles: CSSResult;
|
|
114
157
|
}
|
|
115
158
|
|
|
159
|
+
declare interface NonIndexRouteConfig extends BaseRouteConfig {
|
|
160
|
+
/**
|
|
161
|
+
* 인덱스 라우트가 아님을 나타냅니다.
|
|
162
|
+
*/
|
|
163
|
+
index?: false;
|
|
164
|
+
/**
|
|
165
|
+
* 하위 라우트 설정, 재귀적으로 RouteConfig 배열을 가질 수 있습니다.
|
|
166
|
+
* - 하위 라우트가 있는 경우, 부모 라우트의 경로를 기준으로 매칭됩니다.
|
|
167
|
+
*/
|
|
168
|
+
children?: RouteConfig[];
|
|
169
|
+
}
|
|
170
|
+
|
|
116
171
|
/**
|
|
117
172
|
* 페이지를 찾을 수 없을 때 발생하는 에러
|
|
118
173
|
*/
|
|
@@ -149,101 +204,27 @@ export declare class OutletMissingError extends RouteError {
|
|
|
149
204
|
constructor();
|
|
150
205
|
}
|
|
151
206
|
|
|
152
|
-
/**
|
|
153
|
-
* 경로 라우트 타입
|
|
154
|
-
*/
|
|
155
|
-
declare interface PathRouteConfig extends BaseRouteConfig {
|
|
156
|
-
/**
|
|
157
|
-
* 라우터 경로는 string 또는 URLPattern을 사용할 수 있습니다.
|
|
158
|
-
* string일 경우 자동으로 URLPattern으로 변환됩니다.
|
|
159
|
-
* @example
|
|
160
|
-
* - "/user/:id/:name"
|
|
161
|
-
* - "/user/:id/:name?"
|
|
162
|
-
* - "/user/:id/:name*"
|
|
163
|
-
* - "/user/:id/:name+"
|
|
164
|
-
* - "/user/:id/:name{1,3}"
|
|
165
|
-
* @link
|
|
166
|
-
* https://developer.mozilla.org/en-US/docs/Web/API/URLPattern
|
|
167
|
-
*/
|
|
168
|
-
path: string | URLPattern;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
207
|
declare interface RenderOption {
|
|
172
208
|
id?: string;
|
|
173
209
|
force?: boolean;
|
|
174
210
|
content: RenderResult;
|
|
175
211
|
}
|
|
176
212
|
|
|
177
|
-
declare type RenderResult = HTMLElement | ReactElement | TemplateResult<1
|
|
213
|
+
export declare type RenderResult = HTMLElement | ReactElement | TemplateResult<1> | false;
|
|
178
214
|
|
|
179
215
|
/**
|
|
180
216
|
* 라우트 시작 이벤트
|
|
181
217
|
*/
|
|
182
218
|
export declare class RouteBeginEvent extends RouteEvent {
|
|
183
|
-
constructor(
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
/**
|
|
187
|
-
* 라우트 타입 (인덱스 라우트 또는 경로 라우트)
|
|
188
|
-
*/
|
|
189
|
-
export declare type RouteConfig = IndexRouteConfig | PathRouteConfig;
|
|
190
|
-
|
|
191
|
-
/**
|
|
192
|
-
* 라우트 완료 이벤트
|
|
193
|
-
*/
|
|
194
|
-
export declare class RouteDoneEvent extends RouteEvent {
|
|
195
|
-
constructor(routeInfo: RouteInfo);
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
/**
|
|
199
|
-
* 라우팅 에러 정보
|
|
200
|
-
*/
|
|
201
|
-
export declare class RouteError extends Error {
|
|
202
|
-
/**
|
|
203
|
-
* 에러 코드
|
|
204
|
-
* - HTTP 상태 코드 또는 커스텀 에러 코드
|
|
205
|
-
* @example 404, 500, 'ROUTE_NOT_FOUND'
|
|
206
|
-
*/
|
|
207
|
-
code: number | string;
|
|
208
|
-
/**
|
|
209
|
-
* 원본 에러 객체
|
|
210
|
-
* - 원본 Error 객체 또는 예외 정보
|
|
211
|
-
*/
|
|
212
|
-
original?: Error | any;
|
|
213
|
-
/**
|
|
214
|
-
* 에러 발생 시간
|
|
215
|
-
* - 에러가 발생한 시간 (ISO 8601 형식)
|
|
216
|
-
*/
|
|
217
|
-
timestamp: string;
|
|
218
|
-
constructor(code: number | string, message: string, original?: Error | any);
|
|
219
|
+
constructor(context: RouteContext);
|
|
219
220
|
}
|
|
220
221
|
|
|
221
|
-
|
|
222
|
-
* 라우트 에러 이벤트
|
|
223
|
-
*/
|
|
224
|
-
export declare class RouteErrorEvent extends RouteEvent {
|
|
225
|
-
/** 에러 정보 */
|
|
226
|
-
readonly error: RouteError;
|
|
227
|
-
constructor(error: RouteError, routeInfo: RouteInfo);
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
/** 라우터 이벤트 기본 클래스 */
|
|
231
|
-
declare abstract class RouteEvent extends Event {
|
|
232
|
-
/** 라우팅 정보 */
|
|
233
|
-
readonly routeInfo: RouteInfo;
|
|
234
|
-
/** 이벤트 발생 시간 */
|
|
235
|
-
readonly timestamp: string;
|
|
236
|
-
constructor(type: string, routeInfo: RouteInfo, cancelable?: boolean);
|
|
237
|
-
/** 이벤트가 취소되었는지 확인 */
|
|
238
|
-
get cancelled(): boolean;
|
|
239
|
-
/** 이벤트 취소 */
|
|
240
|
-
cancel(): void;
|
|
241
|
-
}
|
|
222
|
+
export declare type RouteConfig = IndexRouteConfig | NonIndexRouteConfig;
|
|
242
223
|
|
|
243
224
|
/**
|
|
244
225
|
* 라우터 정보
|
|
245
226
|
*/
|
|
246
|
-
export declare interface
|
|
227
|
+
export declare interface RouteContext {
|
|
247
228
|
/**
|
|
248
229
|
* 전체 URL 정보
|
|
249
230
|
* - 도메인 이름을 포함한 URL의 전체 경로입니다.
|
|
@@ -305,6 +286,73 @@ export declare interface RouteInfo {
|
|
|
305
286
|
* @example #profile
|
|
306
287
|
*/
|
|
307
288
|
hash?: string;
|
|
289
|
+
/**
|
|
290
|
+
* 현재 라우팅의 진행 상태를 업데이트하여, window 객체의 'route-progress' 이벤트를 트리거합니다.
|
|
291
|
+
* 여러 라우팅이 호출되는 경우, 가장 최근의 라우팅의 진행 상태만 반영되며, 나머지는 무시됩니다.
|
|
292
|
+
* @param value 진행 상태 값 (0~100)
|
|
293
|
+
*/
|
|
294
|
+
progress: (value: number) => void;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* 라우트 완료 이벤트
|
|
299
|
+
*/
|
|
300
|
+
export declare class RouteDoneEvent extends RouteEvent {
|
|
301
|
+
constructor(context: RouteContext);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* 라우팅 에러 정보
|
|
306
|
+
*/
|
|
307
|
+
export declare class RouteError extends Error {
|
|
308
|
+
/**
|
|
309
|
+
* 에러 코드
|
|
310
|
+
* - HTTP 상태 코드 또는 커스텀 에러 코드
|
|
311
|
+
* @example 404, 500, 'ROUTE_NOT_FOUND'
|
|
312
|
+
*/
|
|
313
|
+
code: number | string;
|
|
314
|
+
/**
|
|
315
|
+
* 원본 에러 객체
|
|
316
|
+
* - 원본 Error 객체 또는 예외 정보
|
|
317
|
+
*/
|
|
318
|
+
original?: Error | any;
|
|
319
|
+
/**
|
|
320
|
+
* 에러 발생 시간
|
|
321
|
+
* - 에러가 발생한 시간 (ISO 8601 형식)
|
|
322
|
+
*/
|
|
323
|
+
timestamp: string;
|
|
324
|
+
constructor(code: number | string, message: string, original?: Error | any);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* 라우트 에러 이벤트
|
|
329
|
+
*/
|
|
330
|
+
export declare class RouteErrorEvent extends RouteEvent {
|
|
331
|
+
/** 에러 정보 */
|
|
332
|
+
readonly error: RouteError;
|
|
333
|
+
constructor(context: RouteContext, error: RouteError);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/** 라우터 이벤트 기본 클래스 */
|
|
337
|
+
declare abstract class RouteEvent extends Event {
|
|
338
|
+
/** 라우팅 정보 */
|
|
339
|
+
readonly context: RouteContext;
|
|
340
|
+
/** 이벤트 발생 시간 */
|
|
341
|
+
readonly timestamp: string;
|
|
342
|
+
constructor(type: string, context: RouteContext, cancelable?: boolean);
|
|
343
|
+
/** 이벤트가 취소되었는지 확인 */
|
|
344
|
+
get cancelled(): boolean;
|
|
345
|
+
/** 이벤트 취소 */
|
|
346
|
+
cancel(): void;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* 라우트 진행 이벤트
|
|
351
|
+
*/
|
|
352
|
+
export declare class RouteProgressEvent extends RouteEvent {
|
|
353
|
+
/** 진행 상태 값 (0~100) */
|
|
354
|
+
readonly progress: number;
|
|
355
|
+
constructor(context: RouteContext, progress: number);
|
|
308
356
|
}
|
|
309
357
|
|
|
310
358
|
/**
|
|
@@ -314,21 +362,20 @@ export declare class Router {
|
|
|
314
362
|
private readonly _rootElement;
|
|
315
363
|
private readonly _basepath;
|
|
316
364
|
private readonly _routes;
|
|
365
|
+
private readonly _fallback?;
|
|
317
366
|
/** 현재 라우팅 요청 ID */
|
|
318
367
|
private _requestID?;
|
|
319
368
|
/** 현재 라우팅 정보 */
|
|
320
|
-
private
|
|
369
|
+
private _context?;
|
|
321
370
|
constructor(config: RouterConfig);
|
|
322
|
-
/** 초기 라우팅 처리, TODO: 제거 */
|
|
323
|
-
private waitConnected;
|
|
324
371
|
/** 객체를 정리하고 이벤트 리스너를 제거합니다. */
|
|
325
372
|
destroy(): void;
|
|
326
373
|
/** 라우터의 기본 경로 반환 */
|
|
327
374
|
get basepath(): string;
|
|
328
|
-
/** 등록된 라우트 반환 */
|
|
375
|
+
/** 등록된 라우트 정보 반환 */
|
|
329
376
|
get routes(): RouteConfig[];
|
|
330
377
|
/** 현재 라우팅 정보 반환 */
|
|
331
|
-
get
|
|
378
|
+
get context(): RouteContext | undefined;
|
|
332
379
|
/**
|
|
333
380
|
* 지정한 경로의 클라이언트 라우팅을 수행합니다. 상대경로일 경우 basepath와 조합되어 이동합니다.
|
|
334
381
|
* @param href 이동할 경로
|
|
@@ -360,12 +407,22 @@ export declare interface RouterConfig {
|
|
|
360
407
|
* - 라우트는 URLPattern을 사용하여 경로를 탐색합니다.
|
|
361
408
|
* - 라우트는 렌더링할 엘리먼트 또는 컴포넌트를 지정합니다.
|
|
362
409
|
*/
|
|
363
|
-
routes
|
|
410
|
+
routes?: RouteConfig[];
|
|
411
|
+
/**
|
|
412
|
+
* 라우트 매칭 실패 또는 오류 발생 시 대체 라우트 설정
|
|
413
|
+
* - 지정된 설정이 없을 경우, 기본 오류 페이지가 렌더링됩니다.
|
|
414
|
+
*/
|
|
415
|
+
fallback?: FallbackRouteConfig;
|
|
364
416
|
/**
|
|
365
417
|
* `a` 태그 클릭 시 클라이언트 라우팅을 수행할지 여부를 설정합니다.
|
|
366
418
|
* @default true
|
|
367
419
|
*/
|
|
368
420
|
useIntercept?: boolean;
|
|
421
|
+
/**
|
|
422
|
+
* 초기 로드 시 현재 URL로 라우팅을 자동으로 수행할지 여부를 설정합니다.
|
|
423
|
+
* @default true
|
|
424
|
+
*/
|
|
425
|
+
initialLoad?: boolean;
|
|
369
426
|
}
|
|
370
427
|
|
|
371
428
|
export declare const ULink: ReactWebComponent<Link, {}>;
|
|
@@ -375,12 +432,9 @@ export declare const UOutlet: ReactWebComponent<Outlet, {}>;
|
|
|
375
432
|
export { }
|
|
376
433
|
|
|
377
434
|
declare global {
|
|
378
|
-
interface Window {
|
|
379
|
-
route: RouteInfo;
|
|
380
|
-
}
|
|
381
|
-
|
|
382
435
|
interface WindowEventMap {
|
|
383
436
|
'route-begin': RouteBeginEvent;
|
|
437
|
+
'route-progress': RouteProgressEvent;
|
|
384
438
|
'route-done': RouteDoneEvent;
|
|
385
439
|
'route-error': RouteErrorEvent;
|
|
386
440
|
}
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import React from "react";
|
|
|
2
2
|
import { LitElement, html, css, render } from "lit";
|
|
3
3
|
import { state, property, customElement } from "lit/decorators.js";
|
|
4
4
|
import { createRoot } from "react-dom/client";
|
|
5
|
-
import {
|
|
5
|
+
import { unsafeHTML } from "lit-html/directives/unsafe-html.js";
|
|
6
6
|
const e = /* @__PURE__ */ new Set(["children", "localName", "ref", "style", "className"]), n = /* @__PURE__ */ new WeakMap(), t = (e2, t2, o2, l, a) => {
|
|
7
7
|
const s = a?.[t2];
|
|
8
8
|
void 0 === s ? (e2[t2] = o2, null == o2 && t2 in HTMLElement.prototype && e2.removeAttribute(t2)) : o2 !== l && ((e3, t3, o3) => {
|
|
@@ -65,7 +65,9 @@ function parseUrl(url, basepath) {
|
|
|
65
65
|
pathname: urlObj.pathname,
|
|
66
66
|
query: new URLSearchParams(urlObj.search),
|
|
67
67
|
hash: urlObj.hash,
|
|
68
|
-
params: {}
|
|
68
|
+
params: {},
|
|
69
|
+
progress: () => {
|
|
70
|
+
}
|
|
69
71
|
};
|
|
70
72
|
}
|
|
71
73
|
function absolutePath(...paths) {
|
|
@@ -214,7 +216,10 @@ class Outlet extends LitElement {
|
|
|
214
216
|
this.routeId = id;
|
|
215
217
|
this.clear();
|
|
216
218
|
if (!this.container) {
|
|
217
|
-
throw new Error("
|
|
219
|
+
throw new Error("Outlet container is not initialized.");
|
|
220
|
+
}
|
|
221
|
+
if (content === false) {
|
|
222
|
+
throw new Error("Content is false, cannot render.");
|
|
218
223
|
}
|
|
219
224
|
if (content instanceof HTMLElement) {
|
|
220
225
|
this.container.appendChild(content);
|
|
@@ -292,9 +297,9 @@ class ContentRenderError extends RouteError {
|
|
|
292
297
|
}
|
|
293
298
|
}
|
|
294
299
|
class RouteEvent extends Event {
|
|
295
|
-
constructor(type,
|
|
300
|
+
constructor(type, context, cancelable = false) {
|
|
296
301
|
super(type, { bubbles: true, composed: true, cancelable });
|
|
297
|
-
this.
|
|
302
|
+
this.context = context;
|
|
298
303
|
this.timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
299
304
|
}
|
|
300
305
|
/** 이벤트가 취소되었는지 확인 */
|
|
@@ -309,30 +314,72 @@ class RouteEvent extends Event {
|
|
|
309
314
|
}
|
|
310
315
|
}
|
|
311
316
|
class RouteBeginEvent extends RouteEvent {
|
|
312
|
-
constructor(
|
|
313
|
-
super("route-begin",
|
|
317
|
+
constructor(context) {
|
|
318
|
+
super("route-begin", context, false);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
class RouteProgressEvent extends RouteEvent {
|
|
322
|
+
constructor(context, progress) {
|
|
323
|
+
super("route-progress", context, false);
|
|
324
|
+
this.progress = progress;
|
|
314
325
|
}
|
|
315
326
|
}
|
|
316
327
|
class RouteDoneEvent extends RouteEvent {
|
|
317
|
-
constructor(
|
|
318
|
-
super("route-done",
|
|
328
|
+
constructor(context) {
|
|
329
|
+
super("route-done", context, false);
|
|
319
330
|
}
|
|
320
331
|
}
|
|
321
332
|
class RouteErrorEvent extends RouteEvent {
|
|
322
|
-
constructor(
|
|
323
|
-
super("route-error",
|
|
333
|
+
constructor(context, error) {
|
|
334
|
+
super("route-error", context, false);
|
|
324
335
|
this.error = error;
|
|
325
336
|
}
|
|
326
337
|
}
|
|
327
|
-
const
|
|
328
|
-
const
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
const
|
|
333
|
-
const
|
|
334
|
-
|
|
335
|
-
|
|
338
|
+
const ban = '<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="currentColor" 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>';
|
|
339
|
+
const __vite_glob_0_0 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
340
|
+
__proto__: null,
|
|
341
|
+
default: ban
|
|
342
|
+
}, Symbol.toStringTag, { value: "Module" }));
|
|
343
|
+
const boxSeam = '<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="currentColor" 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>';
|
|
344
|
+
const __vite_glob_0_1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
345
|
+
__proto__: null,
|
|
346
|
+
default: boxSeam
|
|
347
|
+
}, Symbol.toStringTag, { value: "Module" }));
|
|
348
|
+
const exclamationTriangle = '<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="currentColor" 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>';
|
|
349
|
+
const __vite_glob_0_2 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
350
|
+
__proto__: null,
|
|
351
|
+
default: exclamationTriangle
|
|
352
|
+
}, Symbol.toStringTag, { value: "Module" }));
|
|
353
|
+
const palette = '<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="currentColor" 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>';
|
|
354
|
+
const __vite_glob_0_3 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
355
|
+
__proto__: null,
|
|
356
|
+
default: palette
|
|
357
|
+
}, Symbol.toStringTag, { value: "Module" }));
|
|
358
|
+
const personLock = '<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="currentColor" 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>';
|
|
359
|
+
const __vite_glob_0_4 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
360
|
+
__proto__: null,
|
|
361
|
+
default: personLock
|
|
362
|
+
}, Symbol.toStringTag, { value: "Module" }));
|
|
363
|
+
const search = '<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="currentColor" 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>';
|
|
364
|
+
const __vite_glob_0_5 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
365
|
+
__proto__: null,
|
|
366
|
+
default: search
|
|
367
|
+
}, Symbol.toStringTag, { value: "Module" }));
|
|
368
|
+
const stopwatch = '<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="currentColor" 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>';
|
|
369
|
+
const __vite_glob_0_6 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
370
|
+
__proto__: null,
|
|
371
|
+
default: stopwatch
|
|
372
|
+
}, Symbol.toStringTag, { value: "Module" }));
|
|
373
|
+
const wifiOff = '<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="currentColor" 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>';
|
|
374
|
+
const __vite_glob_0_7 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
375
|
+
__proto__: null,
|
|
376
|
+
default: wifiOff
|
|
377
|
+
}, Symbol.toStringTag, { value: "Module" }));
|
|
378
|
+
const wrenchAdjustable = '<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="currentColor" 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>';
|
|
379
|
+
const __vite_glob_0_8 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
380
|
+
__proto__: null,
|
|
381
|
+
default: wrenchAdjustable
|
|
382
|
+
}, Symbol.toStringTag, { value: "Module" }));
|
|
336
383
|
const styles = css`
|
|
337
384
|
:host {
|
|
338
385
|
display: flex;
|
|
@@ -392,9 +439,19 @@ var __decorateClass = (decorators, target, key, kind) => {
|
|
|
392
439
|
if (kind && result) __defProp(target, key, result);
|
|
393
440
|
return result;
|
|
394
441
|
};
|
|
395
|
-
const icons = Object.entries(/* @__PURE__ */ Object.assign({
|
|
442
|
+
const icons = Object.entries(/* @__PURE__ */ Object.assign({
|
|
443
|
+
"../assets/ban.svg": __vite_glob_0_0,
|
|
444
|
+
"../assets/box-seam.svg": __vite_glob_0_1,
|
|
445
|
+
"../assets/exclamation-triangle.svg": __vite_glob_0_2,
|
|
446
|
+
"../assets/palette.svg": __vite_glob_0_3,
|
|
447
|
+
"../assets/person-lock.svg": __vite_glob_0_4,
|
|
448
|
+
"../assets/search.svg": __vite_glob_0_5,
|
|
449
|
+
"../assets/stopwatch.svg": __vite_glob_0_6,
|
|
450
|
+
"../assets/wifi-off.svg": __vite_glob_0_7,
|
|
451
|
+
"../assets/wrench-adjustable.svg": __vite_glob_0_8
|
|
452
|
+
})).reduce((acc, [path, content]) => {
|
|
396
453
|
const name = path.split("/").pop()?.replace(".svg", "") || "";
|
|
397
|
-
acc[name] = content;
|
|
454
|
+
acc[name] = content.default;
|
|
398
455
|
return acc;
|
|
399
456
|
}, {});
|
|
400
457
|
let ErrorPage = class extends LitElement {
|
|
@@ -402,7 +459,7 @@ let ErrorPage = class extends LitElement {
|
|
|
402
459
|
const error = this.error || this.getDefaultError();
|
|
403
460
|
const icon = this.getErrorIcon(error.code);
|
|
404
461
|
return html`
|
|
405
|
-
<div class="icon">${icon}</div>
|
|
462
|
+
<div class="icon">${unsafeHTML(icon)}</div>
|
|
406
463
|
<div class="code">${error.code}</div>
|
|
407
464
|
<div class="message">${error.message}</div>
|
|
408
465
|
`;
|
|
@@ -417,25 +474,25 @@ let ErrorPage = class extends LitElement {
|
|
|
417
474
|
const numericCode = typeof code === "string" ? parseInt(code) : code;
|
|
418
475
|
switch (codeStr) {
|
|
419
476
|
case "OUTLET_NOT_FOUND":
|
|
420
|
-
return
|
|
477
|
+
return icons["box-seam"] || "📦";
|
|
421
478
|
case "CONTENT_LOAD_FAILED":
|
|
422
|
-
return
|
|
479
|
+
return icons["wifi-off"] || "📡";
|
|
423
480
|
case "RENDER_FAILED":
|
|
424
|
-
return
|
|
481
|
+
return icons["palette"] || "🎨";
|
|
425
482
|
}
|
|
426
483
|
switch (numericCode) {
|
|
427
484
|
case 404:
|
|
428
|
-
return
|
|
485
|
+
return icons["search"] || "🔍";
|
|
429
486
|
case 403:
|
|
430
|
-
return
|
|
487
|
+
return icons["ban"] || "🚫";
|
|
431
488
|
case 401:
|
|
432
|
-
return
|
|
489
|
+
return icons["person-lock"] || "🔐";
|
|
433
490
|
case 429:
|
|
434
|
-
return
|
|
491
|
+
return icons["stopwatch"] || "⏱️";
|
|
435
492
|
case 503:
|
|
436
|
-
return
|
|
493
|
+
return icons["wrench-adjustable"] || "🛠️";
|
|
437
494
|
default:
|
|
438
|
-
return
|
|
495
|
+
return icons["exclamation-triangle"] || "⚠️";
|
|
439
496
|
}
|
|
440
497
|
}
|
|
441
498
|
};
|
|
@@ -491,51 +548,41 @@ function findAnchorFromEvent(e2) {
|
|
|
491
548
|
function setRoutes(routes, basepath) {
|
|
492
549
|
for (const route of routes) {
|
|
493
550
|
route.id ||= getRandomID();
|
|
494
|
-
if (
|
|
551
|
+
if (route.index === true) {
|
|
495
552
|
route.path = new URLPattern({ pathname: `${basepath}{/}?` });
|
|
496
|
-
|
|
553
|
+
route.force ||= true;
|
|
554
|
+
} else {
|
|
497
555
|
if (typeof route.path === "string") {
|
|
498
556
|
const absolutePathStr = absolutePath(basepath, route.path);
|
|
499
557
|
route.path = new URLPattern({ pathname: `${absolutePathStr}{/}?` });
|
|
558
|
+
} else if (route.path instanceof URLPattern) ;
|
|
559
|
+
else {
|
|
560
|
+
route.path = new URLPattern({ pathname: `${basepath}{/}?` });
|
|
500
561
|
}
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
let childBasepath;
|
|
506
|
-
if ("index" in route) {
|
|
507
|
-
childBasepath = basepath;
|
|
562
|
+
if (route.children && route.children.length > 0) {
|
|
563
|
+
const childBasepath = route.path.pathname.replace("{/}?", "");
|
|
564
|
+
route.children = setRoutes(route.children, childBasepath);
|
|
565
|
+
route.force ||= false;
|
|
508
566
|
} else {
|
|
509
|
-
|
|
510
|
-
childBasepath = absolutePath(basepath, route.path);
|
|
511
|
-
} else {
|
|
512
|
-
childBasepath = route.path.pathname.replace("{/}?", "");
|
|
513
|
-
}
|
|
567
|
+
route.force ||= true;
|
|
514
568
|
}
|
|
515
|
-
route.children = setRoutes(route.children, childBasepath);
|
|
516
|
-
route.force ||= false;
|
|
517
|
-
} else {
|
|
518
|
-
route.force ||= true;
|
|
519
569
|
}
|
|
520
570
|
}
|
|
521
571
|
return routes;
|
|
522
572
|
}
|
|
523
573
|
function getRoutes(pathname, routes) {
|
|
524
574
|
for (const route of routes) {
|
|
525
|
-
if (route.children) {
|
|
575
|
+
if (route.index !== true && route.children && route.children.length > 0) {
|
|
526
576
|
const childRoutes = getRoutes(pathname, route.children);
|
|
527
577
|
if (childRoutes.length > 0) {
|
|
528
578
|
return [route, ...childRoutes];
|
|
529
579
|
}
|
|
530
580
|
}
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
} else
|
|
535
|
-
|
|
536
|
-
}
|
|
537
|
-
if (matches) {
|
|
538
|
-
return [route];
|
|
581
|
+
if (route.path instanceof URLPattern) {
|
|
582
|
+
const isMatch = route.path.test({ pathname });
|
|
583
|
+
if (isMatch) return [route];
|
|
584
|
+
} else {
|
|
585
|
+
throw new Error("Route path must be an instance of URLPattern, Something wrong in setRoutes function.");
|
|
539
586
|
}
|
|
540
587
|
}
|
|
541
588
|
return [];
|
|
@@ -565,44 +612,36 @@ class Router {
|
|
|
565
612
|
};
|
|
566
613
|
this._rootElement = config.root;
|
|
567
614
|
this._basepath = absolutePath(config.basepath || "/");
|
|
568
|
-
this._routes = setRoutes(config.routes, this._basepath);
|
|
569
|
-
this.
|
|
615
|
+
this._routes = setRoutes(config.routes || [], this._basepath);
|
|
616
|
+
this._fallback = config.fallback;
|
|
570
617
|
window.removeEventListener("popstate", this.handleWindowPopstate);
|
|
571
618
|
window.addEventListener("popstate", this.handleWindowPopstate);
|
|
572
619
|
if (config.useIntercept !== false) {
|
|
573
620
|
this._rootElement.removeEventListener("click", this.handleRootClick);
|
|
574
621
|
this._rootElement.addEventListener("click", this.handleRootClick);
|
|
575
622
|
}
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
async waitConnected() {
|
|
579
|
-
let outlet = findOutlet(this._rootElement);
|
|
580
|
-
let count = 0;
|
|
581
|
-
while (!outlet && count < 20) {
|
|
582
|
-
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
583
|
-
outlet = findOutlet(this._rootElement);
|
|
584
|
-
count++;
|
|
623
|
+
if (config.initialLoad !== false) {
|
|
624
|
+
void this.go(window.location.href);
|
|
585
625
|
}
|
|
586
|
-
this.handleWindowPopstate();
|
|
587
626
|
}
|
|
588
627
|
/** 객체를 정리하고 이벤트 리스너를 제거합니다. */
|
|
589
628
|
destroy() {
|
|
590
629
|
window.removeEventListener("popstate", this.handleWindowPopstate);
|
|
591
630
|
this._rootElement.removeEventListener("click", this.handleRootClick);
|
|
592
|
-
this._routeInfo = void 0;
|
|
593
631
|
this._requestID = void 0;
|
|
632
|
+
this._context = void 0;
|
|
594
633
|
}
|
|
595
634
|
/** 라우터의 기본 경로 반환 */
|
|
596
635
|
get basepath() {
|
|
597
636
|
return this._basepath;
|
|
598
637
|
}
|
|
599
|
-
/** 등록된 라우트 반환 */
|
|
638
|
+
/** 등록된 라우트 정보 반환 */
|
|
600
639
|
get routes() {
|
|
601
640
|
return this._routes;
|
|
602
641
|
}
|
|
603
642
|
/** 현재 라우팅 정보 반환 */
|
|
604
|
-
get
|
|
605
|
-
return this.
|
|
643
|
+
get context() {
|
|
644
|
+
return this._context;
|
|
606
645
|
}
|
|
607
646
|
/**
|
|
608
647
|
* 지정한 경로의 클라이언트 라우팅을 수행합니다. 상대경로일 경우 basepath와 조합되어 이동합니다.
|
|
@@ -611,34 +650,48 @@ class Router {
|
|
|
611
650
|
async go(href) {
|
|
612
651
|
const requestID = getRandomID();
|
|
613
652
|
this._requestID = requestID;
|
|
614
|
-
const
|
|
615
|
-
if (
|
|
653
|
+
const context = parseUrl(href, this._basepath);
|
|
654
|
+
if (context.href === this._context?.href) return;
|
|
655
|
+
const progressCallback = (value) => {
|
|
656
|
+
if (this._requestID !== requestID) return;
|
|
657
|
+
const progress = Math.max(0, Math.min(100, Math.round(value)));
|
|
658
|
+
window.dispatchEvent(new RouteProgressEvent(context, progress));
|
|
659
|
+
};
|
|
660
|
+
context.progress = progressCallback;
|
|
661
|
+
if (context.href !== window.location.href) {
|
|
662
|
+
window.history.pushState({ basepath: context.basepath }, "", context.href);
|
|
663
|
+
} else {
|
|
664
|
+
window.history.replaceState({ basepath: context.basepath }, "", context.href);
|
|
665
|
+
}
|
|
616
666
|
let outlet = void 0;
|
|
617
667
|
try {
|
|
618
668
|
if (this._requestID !== requestID) return;
|
|
619
|
-
window.dispatchEvent(new RouteBeginEvent(
|
|
620
|
-
const routes = getRoutes(
|
|
669
|
+
window.dispatchEvent(new RouteBeginEvent(context));
|
|
670
|
+
const routes = getRoutes(context.pathname, this._routes);
|
|
621
671
|
const lastRoute = routes[routes.length - 1];
|
|
622
|
-
if (lastRoute &&
|
|
623
|
-
|
|
672
|
+
if (lastRoute && lastRoute.path instanceof URLPattern) {
|
|
673
|
+
context.params = lastRoute.path.exec({ pathname: context.pathname })?.pathname.groups || {};
|
|
624
674
|
}
|
|
625
|
-
this.
|
|
626
|
-
window.route = routeInfo;
|
|
675
|
+
this._context = context;
|
|
627
676
|
outlet = findOutletOrThrow(this._rootElement);
|
|
628
677
|
let title = void 0;
|
|
629
678
|
let content = null;
|
|
630
679
|
let element = null;
|
|
631
680
|
if (routes.length === 0) {
|
|
632
|
-
throw new NotFoundError(
|
|
681
|
+
throw new NotFoundError(context.href);
|
|
633
682
|
}
|
|
634
683
|
for (const route of routes) {
|
|
635
684
|
if (this._requestID !== requestID) return;
|
|
636
685
|
if (!route.render) continue;
|
|
637
686
|
try {
|
|
638
|
-
content = await route.render(
|
|
687
|
+
content = await route.render(context);
|
|
688
|
+
if (content === false || content === null) {
|
|
689
|
+
throw new Error("Failed to load content for the route.");
|
|
690
|
+
}
|
|
639
691
|
} catch (LoadError) {
|
|
640
692
|
throw new ContentLoadError(LoadError);
|
|
641
693
|
}
|
|
694
|
+
if (this._requestID !== requestID) return;
|
|
642
695
|
try {
|
|
643
696
|
element = await outlet.renderContent({ id: route.id, content, force: route.force });
|
|
644
697
|
} catch (renderError) {
|
|
@@ -648,29 +701,29 @@ class Router {
|
|
|
648
701
|
title = route.title || title;
|
|
649
702
|
}
|
|
650
703
|
document.title = title || document.title;
|
|
651
|
-
|
|
652
|
-
if (routeInfo.href !== window.location.href) {
|
|
653
|
-
window.history.pushState({ basepath: routeInfo.basepath }, "", routeInfo.href);
|
|
654
|
-
} else {
|
|
655
|
-
window.history.replaceState({ basepath: routeInfo.basepath }, "", routeInfo.href);
|
|
656
|
-
}
|
|
657
|
-
window.dispatchEvent(new RouteDoneEvent(routeInfo));
|
|
704
|
+
window.dispatchEvent(new RouteDoneEvent(context));
|
|
658
705
|
} catch (error) {
|
|
659
706
|
const routeError = error instanceof RouteError ? error : new RouteError(
|
|
660
707
|
error.status || error.code || "UNKNOWN_ERROR",
|
|
661
708
|
error.message || "An unexpected error occurred",
|
|
662
709
|
error
|
|
663
710
|
);
|
|
664
|
-
window.dispatchEvent(new RouteErrorEvent(
|
|
665
|
-
console.error("Routing error:",
|
|
711
|
+
window.dispatchEvent(new RouteErrorEvent(context, routeError));
|
|
712
|
+
console.error("Routing error:", routeError.original);
|
|
666
713
|
try {
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
714
|
+
if (this._fallback && this._fallback.render && outlet) {
|
|
715
|
+
const fallbackContent = await this._fallback.render({ ...context, error: routeError });
|
|
716
|
+
outlet.renderContent({ id: "#fallback", content: fallbackContent, force: true });
|
|
717
|
+
document.title = this._fallback.title || document.title;
|
|
671
718
|
} else {
|
|
672
|
-
|
|
673
|
-
|
|
719
|
+
const errorContent = new ErrorPage();
|
|
720
|
+
errorContent.error = error;
|
|
721
|
+
if (outlet) {
|
|
722
|
+
outlet.renderContent({ id: "#error", content: errorContent, force: true });
|
|
723
|
+
} else {
|
|
724
|
+
document.body.innerHTML = "";
|
|
725
|
+
document.body.appendChild(errorContent);
|
|
726
|
+
}
|
|
674
727
|
}
|
|
675
728
|
} catch (pageError) {
|
|
676
729
|
console.error("Failed to render error component:", pageError);
|
|
@@ -690,6 +743,7 @@ export {
|
|
|
690
743
|
RouteDoneEvent,
|
|
691
744
|
RouteError,
|
|
692
745
|
RouteErrorEvent,
|
|
746
|
+
RouteProgressEvent,
|
|
693
747
|
Router,
|
|
694
748
|
ULink,
|
|
695
749
|
UOutlet
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@iyulab/router",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.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",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@lit/react": "^1.0.8",
|
|
44
44
|
"@types/node": "^24.10.1",
|
|
45
|
-
"@types/react": "^19.2.
|
|
45
|
+
"@types/react": "^19.2.5",
|
|
46
46
|
"@types/react-dom": "^19.2.3",
|
|
47
47
|
"typescript": "^5.9.3",
|
|
48
48
|
"vite": "^7.2.2",
|