@iyulab/router 0.10.4 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +32 -0
- package/README.md +20 -1
- package/dist/components/ULink.d.ts +21 -0
- package/dist/index.js +2 -1
- package/dist/react.js +1 -1
- package/dist/{share-CZzCH0Yf.js → share-BaGC5VOl.js} +5 -2
- package/package.json +13 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,37 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.11.0] - 2026-08-07
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- **`<u-link navigate="document">` — link to a same-origin path the router does not own.**
|
|
8
|
+
Whether a link was "external" was decided by an origin comparison alone, so there was no way to
|
|
9
|
+
point at a same-origin path that is not a SPA route: a static docs site, a server-rendered page,
|
|
10
|
+
a download endpoint, an auth redirect. The router intercepted the click and, with no matching
|
|
11
|
+
route, the screen fell through to not-found.
|
|
12
|
+
|
|
13
|
+
The three available escapes all meant something else: a different origin (the requirement is the
|
|
14
|
+
*same* origin — cookies, session, reverse proxy), `target="_blank"` (forces a new tab; same-tab
|
|
15
|
+
navigation was unexpressible), and a `#` fragment (not another document).
|
|
16
|
+
|
|
17
|
+
`navigate` defaults to `router`, so existing behaviour is unchanged. The rendered anchor carries
|
|
18
|
+
`data-navigate="document"`, which the router's global anchor delegation also honours — the
|
|
19
|
+
element handler alone is not enough, since a link pointing at a *registered* route would
|
|
20
|
+
otherwise be intercepted there instead.
|
|
21
|
+
|
|
22
|
+
The name is deliberately not `external`: this module already uses `isExternalUrl`/`isExternal`
|
|
23
|
+
with origin semantics, and the question here is about the document, not the origin.
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
|
|
27
|
+
- **`sideEffects` omitted the source-resolved entry barrel.** The allowlist covered the built
|
|
28
|
+
artifacts with a directory-wide glob, but the source-form barrel and the `react` wrapper entry
|
|
29
|
+
were outside it. The published artifacts
|
|
30
|
+
were unaffected — the shipped allowlist already covered them — but a consumer resolving this
|
|
31
|
+
package from source (a workspace sibling) could have the barrel elided, dropping the element
|
|
32
|
+
registrations it pulls in. The failure is silent: no error, and unregistered custom elements
|
|
33
|
+
render nothing. The source-form entry points are now declared alongside the artifact ones.
|
|
34
|
+
|
|
3
35
|
## [0.10.4] - 2026-08-01
|
|
4
36
|
|
|
5
37
|
### Documentation
|
package/README.md
CHANGED
|
@@ -141,13 +141,32 @@ const routes = [
|
|
|
141
141
|
- `<u-link>`: SPA-aware anchor element
|
|
142
142
|
- `<u-outlet>`: render target for matched route output
|
|
143
143
|
|
|
144
|
-
`<u-link>` supports `href`, `target`, and `
|
|
144
|
+
`<u-link>` supports `href`, `target`, `rel`, and `navigate`.
|
|
145
145
|
|
|
146
146
|
```html
|
|
147
147
|
<u-link href="/docs">Docs</u-link>
|
|
148
148
|
<u-link href="https://example.com" target="_blank" rel="noopener noreferrer">External</u-link>
|
|
149
149
|
```
|
|
150
150
|
|
|
151
|
+
### Linking to a path the router does not own
|
|
152
|
+
|
|
153
|
+
Not every path on your origin is a SPA route. A static docs site, a server-rendered
|
|
154
|
+
page, a report endpoint, an auth redirect — these live alongside your routes and must
|
|
155
|
+
open as documents, in the same tab. Declare that with `navigate="document"`:
|
|
156
|
+
|
|
157
|
+
```html
|
|
158
|
+
<u-link href="/help/" navigate="document">Help</u-link>
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
The router leaves the click alone and the browser navigates normally. The same works
|
|
162
|
+
on a plain anchor via `data-navigate="document"`, which is what the element renders.
|
|
163
|
+
|
|
164
|
+
`navigate` defaults to `router`: same-origin links are handled as SPA navigation, as
|
|
165
|
+
before. Note that `navigate` asks a different question than the automatic origin check
|
|
166
|
+
— not *"is this another origin?"* but *"is this another document?"* Without it the only
|
|
167
|
+
escapes were a different origin, `target="_blank"` (which forces a new tab), or a `#`
|
|
168
|
+
fragment (which is not another document at all).
|
|
169
|
+
|
|
151
170
|
React wrappers:
|
|
152
171
|
|
|
153
172
|
```tsx
|
|
@@ -38,6 +38,27 @@ export declare class ULink extends LitElement {
|
|
|
38
38
|
* - #으로 시작하면 브라우저 기본 동작을 사용합니다.
|
|
39
39
|
*/
|
|
40
40
|
href?: string;
|
|
41
|
+
/**
|
|
42
|
+
* 이 링크를 라우터가 처리할지, 브라우저의 문서 이동에 맡길지.
|
|
43
|
+
*
|
|
44
|
+
* - `router`(기본): 종전 동작 그대로 — 같은 오리진이면 SPA 이동, 아니면 브라우저에 맡긴다.
|
|
45
|
+
* - `document`: 라우터가 **가로채지 않는다.** 같은 오리진이지만 SPA 라우트가 아닌 경로
|
|
46
|
+
* (정적 문서 사이트, 서버 렌더 페이지, 파일 다운로드 엔드포인트, 인증 리다이렉트)를 가리킬 때 쓴다.
|
|
47
|
+
*
|
|
48
|
+
* ⚠**「외부 오리진」이 아니라 「다른 문서」다.** 종전에는 이 구분이 **오리진 비교 하나**로만
|
|
49
|
+
* 결정돼서, 같은 오리진의 비-SPA 경로를 가리킬 수단이 없었다 — 라우터가 클릭을 가로채고
|
|
50
|
+
* 등록되지 않은 라우트이므로 화면이 not-found 로 떨어졌다. 빠져나갈 길이 셋뿐이었고
|
|
51
|
+
* (다른 오리진 · `target="_blank"` · `#` 프래그먼트) 셋 다 요구와 다르다:
|
|
52
|
+
* 같은 오리진이어야 하고(쿠키·세션·역방향 프록시), **같은 탭**이어야 하며, 다른 문서다.
|
|
53
|
+
*
|
|
54
|
+
* ```html
|
|
55
|
+
* <u-link href="/help/" navigate="document">Help</u-link>
|
|
56
|
+
* ```
|
|
57
|
+
*
|
|
58
|
+
* ⚠**자동 판정을 넓히지 않는다.** 「등록된 라우트와 대조해 미등록이면 문서 이동」도 가능하지만
|
|
59
|
+
* 라우트가 늦게 등록되면 판정이 **시점에 의존**하게 된다. 명시 선언이 예측 가능하다.
|
|
60
|
+
*/
|
|
61
|
+
navigate?: "router" | "document";
|
|
41
62
|
connectedCallback(): void;
|
|
42
63
|
disconnectedCallback(): void;
|
|
43
64
|
protected willUpdate(changedProperties: PropertyValues): void;
|
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-
|
|
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-BaGC5VOl.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
|
|
@@ -401,6 +401,7 @@ var Router = class {
|
|
|
401
401
|
if (isExternalUrl(href)) return;
|
|
402
402
|
if (anchor.hasAttribute("download")) return;
|
|
403
403
|
if (anchor.getAttribute("rel") === "external") return;
|
|
404
|
+
if (anchor.getAttribute("data-navigate") === "document") return;
|
|
404
405
|
if (anchor.target && anchor.target !== "") return;
|
|
405
406
|
const pathname = new URL(anchor.href).pathname;
|
|
406
407
|
if (this._basepath !== "/" && !pathname.startsWith(this._basepath)) return;
|
package/dist/react.js
CHANGED
|
@@ -126,12 +126,12 @@ function catchBasepath(basepath) {
|
|
|
126
126
|
return basepath;
|
|
127
127
|
}
|
|
128
128
|
//#endregion
|
|
129
|
-
//#region \0@oxc-project+runtime@0.
|
|
129
|
+
//#region \0@oxc-project+runtime@0.143.0/helpers/esm/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.
|
|
134
|
+
//#region \0@oxc-project+runtime@0.143.0/helpers/esm/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);
|
|
@@ -149,6 +149,7 @@ var ULink = class ULink extends LitElement {
|
|
|
149
149
|
if (event.button !== 0) return;
|
|
150
150
|
if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return;
|
|
151
151
|
if (this.target && this.target.toLowerCase() !== "_self") return;
|
|
152
|
+
if (this.navigate === "document") return;
|
|
152
153
|
const basepath = this.getBasepath();
|
|
153
154
|
if (!this.href) {
|
|
154
155
|
event.preventDefault();
|
|
@@ -193,6 +194,7 @@ var ULink = class ULink extends LitElement {
|
|
|
193
194
|
href=${this.compute(this.href)}
|
|
194
195
|
target=${ifDefined(this.target)}
|
|
195
196
|
rel=${ifDefined(this.rel)}
|
|
197
|
+
data-navigate=${ifDefined(this.navigate)}
|
|
196
198
|
>
|
|
197
199
|
<slot></slot>
|
|
198
200
|
</a>
|
|
@@ -237,6 +239,7 @@ var ULink = class ULink extends LitElement {
|
|
|
237
239
|
__decorate([property({ type: String }), __decorateMetadata("design:type", String)], ULink.prototype, "target", void 0);
|
|
238
240
|
__decorate([property({ type: String }), __decorateMetadata("design:type", String)], ULink.prototype, "rel", void 0);
|
|
239
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);
|
|
240
243
|
ULink = __decorate([customElement("u-link")], ULink);
|
|
241
244
|
//#endregion
|
|
242
245
|
export { isExternalUrl as a, absolutePath as i, __decorate as n, parseUrl as o, __decorateMetadata as r, UOutlet as s, ULink as t };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@iyulab/router",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "A modern client-side router for web applications with support for Lit and React components",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"lit",
|
|
@@ -27,6 +27,15 @@
|
|
|
27
27
|
],
|
|
28
28
|
"type": "module",
|
|
29
29
|
"types": "dist/index.d.ts",
|
|
30
|
+
"engines": {
|
|
31
|
+
"node": ">=20"
|
|
32
|
+
},
|
|
33
|
+
"sideEffects": [
|
|
34
|
+
"./dist/*.js",
|
|
35
|
+
"./src/components/*.ts",
|
|
36
|
+
"./src/index.ts",
|
|
37
|
+
"./src/react.ts"
|
|
38
|
+
],
|
|
30
39
|
"exports": {
|
|
31
40
|
".": {
|
|
32
41
|
"types": "./dist/index.d.ts",
|
|
@@ -39,8 +48,9 @@
|
|
|
39
48
|
},
|
|
40
49
|
"scripts": {
|
|
41
50
|
"test": "vitest run",
|
|
42
|
-
"build": "vite build",
|
|
43
|
-
"test:watch": "vitest"
|
|
51
|
+
"build": "npm run typecheck && vite build",
|
|
52
|
+
"test:watch": "vitest",
|
|
53
|
+
"typecheck": "tsc --noEmit"
|
|
44
54
|
},
|
|
45
55
|
"dependencies": {
|
|
46
56
|
"@lit/react": "^1.0.8",
|