@iyulab/router 0.9.1 → 0.9.3

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 CHANGED
@@ -1,5 +1,18 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.9.3] - 2026-04-24
4
+
5
+ ### Fixed
6
+ - Document click handler now scopes interception to the router's `_rootElement` instead of `document`, preventing accidental capture of clicks outside the router's DOM subtree
7
+ - Click handler no longer intercepts same-origin anchors pointing outside `basepath` — when `basepath` is not `/`, links targeting paths outside the basepath are passed through to browser navigation instead of falling through to the fallback route
8
+
9
+ ## [0.9.2] - 2026-04-13
10
+
11
+ ### Fixed
12
+ - Nested route rendering now waits for child outlet readiness after parent render, preventing children from being rendered into the previous outlet when the next `<u-outlet>` is created inside a component shadow root
13
+ - `Router.go()` now awaits `UOutlet.render()` before resolving the next outlet in the matched route chain
14
+ - `waitOutlet()` now prefers component lifecycle-aware readiness checks (`customElements.whenDefined`, `updateComplete`, next animation frame) during outlet discovery
15
+
3
16
  ## [0.9.1] - 2026-04-08
4
17
 
5
18
  ### Fixed
package/dist/index.d.ts CHANGED
@@ -382,7 +382,7 @@ export declare class Router {
382
382
  /** 브라우저 히스토리 이벤트가 발생시 라우팅 처리 */
383
383
  private handleWindowPopstate;
384
384
  /** 클릭 이벤트에서 라우터로 처리할 앵커를 찾아 클라이언트 라우팅 수행 */
385
- private handleDocumentClick;
385
+ private handleRootElementClick;
386
386
  }
387
387
 
388
388
  /**
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { a as isExternalUrl, i as absolutePath, n as __decorate, o as parseUrl, r as __decorateMetadata, s as UOutlet, t as ULink } from "./share-CUGwxZKa.js";
1
+ import { a as isExternalUrl, i as absolutePath, n as __decorate, o as parseUrl, r as __decorateMetadata, s as UOutlet, t as ULink } from "./share-DC0R4F2d.js";
2
2
  import { LitElement, css, html } from "lit";
3
3
  import { customElement, property } from "lit/decorators.js";
4
4
  //#region src/types/RouteError.ts
@@ -240,11 +240,13 @@ function findOutlet(element, skip = false) {
240
240
  * `u-outlet` 엘리먼트를 찾아 반환합니다. 없으면 에러를 던집니다.
241
241
  *
242
242
  * @param element 검색을 시작할 HTMLElement
243
+ * @param skip element 자신을 검사에서 제외할지 여부 (기본값: false)
244
+ *
243
245
  * @returns 찾은 UOutlet 엘리먼트
244
246
  * @throws OutletMissingError `u-outlet` 엘리먼트를 찾지 못한 경우
245
247
  */
246
- function findOutletOrThrow(element) {
247
- const outlet = findOutlet(element);
248
+ function findOutletOrThrow(element, skip = false) {
249
+ const outlet = findOutlet(element, skip);
248
250
  if (!outlet) throw new OutletMissingError();
249
251
  return outlet;
250
252
  }
@@ -253,14 +255,18 @@ function findOutletOrThrow(element) {
253
255
  *
254
256
  * @param element 대기할 엘리먼트
255
257
  * @param timeout 타임아웃 시간(밀리초, 기본값: 10_000ms)
258
+ * @param skip element 자신을 검사에서 제외할지 여부 (기본값: false)
259
+ *
256
260
  * @returns 준비된 `u-outlet` 엘리먼트
257
261
  */
258
- async function waitOutlet(element, timeout = 1e4) {
262
+ async function waitOutlet(element, timeout = 1e4, skip = false) {
259
263
  const start = performance.now();
260
264
  while (performance.now() - start < timeout) {
261
- const outlet = findOutlet(element);
265
+ const outlet = findOutlet(element, skip);
262
266
  if (outlet) return outlet;
263
- await new Promise((r) => setTimeout(r, 50));
267
+ if (element.localName.includes("-")) await customElements.whenDefined(element.localName);
268
+ if ("updateComplete" in element) await element.updateComplete;
269
+ await new Promise((resolve) => requestAnimationFrame(() => resolve()));
264
270
  }
265
271
  throw new Error(`Timed out waiting for <u-outlet> inside <${element.tagName.toLowerCase()}>. Ensure that the router root element contains a <u-outlet> child.`);
266
272
  }
@@ -384,7 +390,7 @@ var Router = class {
384
390
  this.handleWindowPopstate = async (_) => {
385
391
  await this.go(window.location.href);
386
392
  };
387
- this.handleDocumentClick = async (e) => {
393
+ this.handleRootElementClick = async (e) => {
388
394
  try {
389
395
  if (e.defaultPrevented) return;
390
396
  if (e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey) return;
@@ -396,6 +402,7 @@ var Router = class {
396
402
  if (anchor.hasAttribute("download")) return;
397
403
  if (anchor.getAttribute("rel") === "external") return;
398
404
  if (anchor.target && anchor.target !== "") return;
405
+ if (this._basepath !== "/" && !new URL(anchor.href).pathname.startsWith(this._basepath)) return;
399
406
  e.preventDefault();
400
407
  await this.go(anchor.href);
401
408
  } catch {}
@@ -407,7 +414,7 @@ var Router = class {
407
414
  this._fallback = config.fallback;
408
415
  this._enter = config.enter;
409
416
  window.addEventListener("popstate", this.handleWindowPopstate);
410
- if (config.useIntercept !== false) document.addEventListener("click", this.handleDocumentClick);
417
+ if (config.useIntercept !== false) this._rootElement.addEventListener("click", this.handleRootElementClick);
411
418
  if (config.initialLoad !== false) waitOutlet(this._rootElement).then(() => {
412
419
  this.go(window.location.href);
413
420
  });
@@ -415,7 +422,7 @@ var Router = class {
415
422
  /** 객체를 정리하고 이벤트 리스너를 제거합니다. */
416
423
  destroy() {
417
424
  window.removeEventListener("popstate", this.handleWindowPopstate);
418
- document.removeEventListener("click", this.handleDocumentClick);
425
+ this._rootElement?.removeEventListener("click", this.handleRootElementClick);
419
426
  this._requestID = void 0;
420
427
  this._context = void 0;
421
428
  }
@@ -491,14 +498,15 @@ var Router = class {
491
498
  throw new ContentLoadError(e);
492
499
  }
493
500
  try {
494
- outlet.render(content, {
501
+ await outlet.render(content, {
495
502
  id: route.id,
496
503
  force: route.force
497
504
  });
498
505
  } catch (e) {
499
506
  throw new ContentRenderError(e);
500
507
  }
501
- outlet = findOutlet(outlet, true) || outlet;
508
+ if ("children" in route && route.children && route.children.length > 0) outlet = await waitOutlet(outlet, 2e3, true);
509
+ else outlet = findOutlet(outlet, true) || outlet;
502
510
  title = route.title || title;
503
511
  }
504
512
  window.dispatchEvent(new RouteDoneEvent(context));
package/dist/react.js CHANGED
@@ -1,4 +1,4 @@
1
- import { s as UOutlet$1, t as ULink$1 } from "./share-CUGwxZKa.js";
1
+ import { s as UOutlet$1, t as ULink$1 } from "./share-DC0R4F2d.js";
2
2
  import React from "react";
3
3
  import { createComponent } from "@lit/react";
4
4
  //#region src/react.ts
@@ -126,12 +126,12 @@ function catchBasepath(basepath) {
126
126
  return basepath;
127
127
  }
128
128
  //#endregion
129
- //#region \0@oxc-project+runtime@0.123.0/helpers/decorateMetadata.js
129
+ //#region \0@oxc-project+runtime@0.127.0/helpers/decorateMetadata.js
130
130
  function __decorateMetadata(k, v) {
131
131
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
132
132
  }
133
133
  //#endregion
134
- //#region \0@oxc-project+runtime@0.123.0/helpers/decorate.js
134
+ //#region \0@oxc-project+runtime@0.127.0/helpers/decorate.js
135
135
  function __decorate(decorators, target, key, desc) {
136
136
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
137
137
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iyulab/router",
3
- "version": "0.9.1",
3
+ "version": "0.9.3",
4
4
  "description": "A modern client-side router for web applications with support for Lit and React components",
5
5
  "keywords": [
6
6
  "lit",
@@ -58,11 +58,11 @@
58
58
  }
59
59
  },
60
60
  "devDependencies": {
61
- "@types/node": "^25.5.0",
61
+ "@types/node": "^25.6.0",
62
62
  "@types/react": "^19.2.14",
63
63
  "@types/react-dom": "^19.2.3",
64
64
  "typescript": "^5.9.3",
65
- "vite": "^8.0.3",
65
+ "vite": "^8.0.8",
66
66
  "vite-plugin-dts": "^4.5.4"
67
67
  }
68
68
  }
@@ -5,7 +5,7 @@ license: MIT
5
5
  compatibility: Browser environments only (requires URLPattern and History API)
6
6
  metadata:
7
7
  author: iyulab
8
- version: "0.9.1"
8
+ version: "0.9.3"
9
9
  ---
10
10
 
11
11
  # @iyulab/router