@iyulab/router 0.14.0 → 0.15.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 CHANGED
@@ -1,5 +1,56 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.15.0] - 2026-09-16
4
+
5
+ ### Changed
6
+
7
+ - **`<u-outlet>` now grows when a screen overflows a fixed-height parent.** 0.14.0 declared
8
+ `display: block; height: 100%`, which gives a screen the height it needs to fill a sized
9
+ parent but also pins the outlet to exactly that height. A screen taller than the parent
10
+ therefore overflowed the outlet's box instead of growing it, and a scrolling ancestor adds
11
+ its end padding to the scrollable area of its *in-flow children*, not of what those children
12
+ overflow with. The end gutter dropped out of the scrollable area: scrolling to the bottom of
13
+ a long screen left the content flush against the container's edge, while the gutter survived
14
+ on the other three sides.
15
+
16
+ Swapping `height` for `min-height` is not the fix. A percentage height only resolves against
17
+ a parent whose `height` is specified, and a minimum does not satisfy that — so on a block (or
18
+ flex) box a descendant's `height: 100%` computes to `auto`, and every layout built to fill the
19
+ viewport collapses to its content height.
20
+
21
+ A grid container gives both behaviors at once. A grid item stretches to its area by default,
22
+ which fills without resolving a percentage, so the chain survives while the container's own
23
+ height is indefinite — and because that height is `auto`, the box grows past the minimum when
24
+ content demands it. The rule is now:
25
+
26
+ ```css
27
+ :where(u-outlet) { display: grid; min-height: 100%; }
28
+ ```
29
+
30
+ Multiple children behave as before: a track stretches, but an item with a definite height does
31
+ not. The rule deliberately omits `align-content` and relies on the initial `normal` — setting
32
+ `align-content: start` stops the track from stretching and silently voids the fill chain.
33
+
34
+ Specificity is still zero, so an application's own `u-outlet { … }` rule wins without
35
+ `!important`, exactly as in 0.14.0. `u-outlet { display: block; height: 100% }` restores the
36
+ 0.14.0 box model and `u-outlet { display: inline }` restores the pre-0.14.0 one.
37
+
38
+ ### Contract addition
39
+
40
+ - **Making the outlet *smaller* now takes two declarations.** `min-height` is a floor, so
41
+ `u-outlet { height: 200px }` on its own still measures the parent's height. Write
42
+ `u-outlet { min-height: 0; height: 200px }`. Making the outlet larger, or replacing its
43
+ `display`, needs nothing extra. This is the only behavioral difference for an application
44
+ that was already overriding the rule.
45
+
46
+ ### Tests
47
+
48
+ - The browser suite covering the outlet's box model grows from 9 cases to 15. The overflow
49
+ topology — a parent with a definite height holding a taller child — was not covered before,
50
+ which is why the previous rule shipped green: the suite pinned "an auto-height parent leaves
51
+ the outlet auto" but never its opposite. Also pinned now: the two-declaration override above,
52
+ multiple children keeping their own heights, and `align-content` breaking the fill chain.
53
+
3
54
  ## [0.14.0] - 2026-09-16
4
55
 
5
56
  ### Changed
package/README.md CHANGED
@@ -143,33 +143,62 @@ const routes = [
143
143
 
144
144
  ## Outlet Layout
145
145
 
146
- `<u-outlet>` declares its own `display: block`. A custom element's UA default is
147
- `inline`, which would put a route's block-level screen inside an inline box — so the
148
- outlet adopts a single rule on whichever tree it is connected to (the document, or the
149
- shadow root if it lives in one):
146
+ `<u-outlet>` declares its own box model. A custom element's UA default is `inline`, which
147
+ would put a route's block-level screen inside an inline box — so the outlet adopts a single
148
+ rule on whichever tree it is connected to (the document, or the shadow root if it lives in
149
+ one):
150
150
 
151
151
  ```css
152
- :where(u-outlet) { display: block; height: 100%; }
152
+ :where(u-outlet) { display: grid; min-height: 100%; }
153
153
  ```
154
154
 
155
- `height: 100%` is part of the same rule for a reason. A percentage height resolves against
156
- the nearest block container, so making the outlet a block moves that reference from the box
157
- *above* the outlet onto the outlet itself — and an `auto` height there voids the percentage
158
- silently, collapsing a full-height screen to its content height. Declaring `height: 100%`
159
- keeps the chain intact, and resolves to `auto` whenever the parent's height is `auto`, so
160
- ordinary document flow and printing are unaffected.
155
+ The outlet has to be two things at once, and no single declaration gives both:
161
156
 
162
- The `:where()` wrapper makes the rule's specificity zero, so **any** `u-outlet { }`
163
- rule your application writes wins, regardless of sheet order and without `!important`:
157
+ 1. **It passes a sized parent's height down**, so a screen's `height: 100%` resolves here.
158
+ 2. **It grows with a screen taller than the parent**, so the overflow stays inside the
159
+ outlet's box rather than escaping it.
160
+
161
+ `height: 100%` gives only the first. It pins the outlet to the parent's height, so a taller
162
+ screen overflows the outlet — and a scrolling ancestor adds its end padding to the scrollable
163
+ area of its in-flow children, not of what those children overflow with. The end gutter drops
164
+ out: scrolling to the bottom of a long screen leaves the content flush against the container's
165
+ edge while the gutter survives on the other three sides.
166
+
167
+ `min-height: 100%` alone breaks the first. A percentage height only resolves against a parent
168
+ whose `height` is specified, and a minimum does not satisfy that — so on a block (or flex) box
169
+ a descendant's `height: 100%` computes to `auto` and every fill-the-viewport layout collapses
170
+ to its content height.
171
+
172
+ A grid container gives both. A grid item stretches to its area by default, which fills without
173
+ resolving a percentage, so the chain survives while the container's own height is indefinite —
174
+ and because that height is `auto`, the box grows past the minimum when content demands it.
175
+ Multiple children are unaffected: a track stretches, but an item with a definite height does not.
176
+
177
+ The rule deliberately omits `align-content`; it relies on the initial `normal`. Setting
178
+ `align-content: start` stops the track from stretching and silently voids case 1.
179
+
180
+ When the parent's own height is `auto`, `min-height: 100%` resolves to `auto` too, so ordinary
181
+ document flow and printing are unaffected.
182
+
183
+ ### Overriding it
184
+
185
+ The `:where()` wrapper makes the rule's specificity zero, so **any** `u-outlet { … }` rule your
186
+ application writes wins, regardless of sheet order and without `!important`:
164
187
 
165
188
  ```css
166
- u-outlet { display: flex; } /* wins */
167
- u-outlet { height: auto; } /* keep the box, drop the fill */
168
- u-outlet { display: inline; } /* restores the pre-0.14.0 behavior */
169
- @media print { u-outlet { } } /* wins */
189
+ u-outlet { display: flex; } /* wins */
190
+ u-outlet { display: contents; } /* remove the box entirely */
191
+ u-outlet { display: block; height: 100%; } /* restores the 0.14.0 behavior */
192
+ u-outlet { display: inline; } /* restores the pre-0.14.0 behavior */
193
+ @media print { u-outlet { … } } /* wins */
170
194
  ```
171
195
 
172
- The rule is not media-scoped: the outlet is a block box on screen and in print alike.
196
+ > **Making the outlet *smaller* takes two declarations, not one.** `min-height` is a floor, so
197
+ > `u-outlet { height: 200px }` on its own still measures the parent's height. Write
198
+ > `u-outlet { min-height: 0; height: 200px }`. Making it *larger*, or replacing `display`, needs
199
+ > nothing extra. This is the only contract addition in 0.15.0.
200
+
201
+ The rule is not media-scoped: the outlet is a block-level box on screen and in print alike.
173
202
 
174
203
  `<u-link>` supports `href`, `target`, `rel`, and `navigate`.
175
204
 
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-tRZgJ1SR.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-RyrbTDel.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
package/dist/react.js CHANGED
@@ -1,4 +1,4 @@
1
- import { s as UOutlet$1, t as ULink$1 } from "./share-tRZgJ1SR.js";
1
+ import { s as UOutlet$1, t as ULink$1 } from "./share-RyrbTDel.js";
2
2
  import React from "react";
3
3
  import { createComponent } from "@lit/react";
4
4
  //#region src/react.ts
@@ -15,17 +15,49 @@ import { ifDefined } from "lit/directives/if-defined.js";
15
15
  * ⚠매체를 가르지 않는다 — 인라인 컨테이너는 화면에서도 의도된 적이 없다(라인 박스 때문에
16
16
  * 높이를 줄 수도, 백분율로 채울 수도 없었다). 인쇄에만 한정하면 화면·인쇄가 서로 다른
17
17
  * 상자 모델을 갖게 되어 같은 부류의 차이가 다음에 또 난다.
18
- * 🔴`height: 100%` 가 함께 있어야 한다 — `display` 만 바꾸면 **백분율 높이의 기준 상자가
19
- * 바뀐다.** 종전(inline)에는 아웃렛이 블록 컨테이너가 아니라, 라우트 화면의 `height: 100%`
20
- * 가 그 «위» 의 블록(셸의 본문 영역)에 대해 풀렸다. 아웃렛을 block 으로 만들면 기준이
21
- * 아웃렛 자신이 되는데 높이가 `auto` 라 백분율이 무효가 되고, 화면을 채우도록 만들어진
22
- * 레이아웃(`u-master-detail-layout` 의 `:host{height:100%}` 등)이 내용 높이로 무너진다.
23
- * 실측(chromium): 같은 화면이 inline 747px block 60px block+height:100% 747px.
24
- * ⚠부모 높이가 `auto` 면 `100%` 는 `auto` 로 풀리므로 인쇄(셸이 높이를 놓는다)와 일반
25
- * 문서 흐름에는 영향이 없다 선언이 «채우기» 강요하는 것은 부모가 높이를 가진
26
- * 경우뿐이고, 그것이 종전 동작이다.
18
+ *
19
+ * ## `grid` + `min-height` 인가 요구가 한 선언으로는 안 된다
20
+ *
21
+ * 아웃렛은 **동시에 가지**여야 한다:
22
+ * ⑴부모가 높이를 가지면 **그 높이를 자손에게 물려준다**(자손의 `height:100%` 여기서 풀린다)
23
+ * ⑵화면이 부모보다 크면 **자기도 함께 자란다**(넘침이 아웃렛 «밖» 으로 새지 않는다)
24
+ *
25
+ * 🔴`height: 100%` ⑴만 준다. 0.14.0 판이었다 콘텐츠 영역이 고정 높이일
26
+ * 아웃렛이 높이로 **못 박히고**
27
+ * 화면이 밖으로 넘쳐, 스크롤 컨테이너의 끝 패딩이 스크롤 영역에서 빠진다 — 긴 화면을 끝까지
28
+ * 내리면 **내용이 바닥에 붙는다**(거터가 위·좌·우에만 남는다).
29
+ * 🔴`min-height: 100%` 만으로는 ⑴이 깨진다. 백분율 높이는 부모의 **`height`** 가 명시됐을 때만
30
+ * 풀리고 `min-height` 는 그 조건을 만족시키지 않는다(CSS2.1 §10.5) — 그래서 `block` 이든
31
+ * `flex` 든 `min-height` 로 바꾸면 자손의 `height:100%` 가 `auto` 로 풀려 화면이 무너진다.
32
+ * ✅`grid` 만 둘을 함께 준다. 그리드 항목의 기본 `align-self: stretch` 가 «백분율을 푸는 것» 이
33
+ * 아니라 **영역을 채우는 것**이라, 컨테이너 높이가 부정(indefinite)이어도 ⑴이 성립한다.
34
+ * 그리고 컨테이너 높이가 `auto` 라 내용이 크면 ⑵대로 자란다.
35
+ *
36
+ * 실측(chromium · 셸 본문 720px `padding:32px` `overflow:auto` / 화면 1588px):
37
+ *
38
+ * | 규칙 | 전체높이: 표 | 넘침: `scrollHeight` | 아웃렛 박스 |
39
+ * |----------------------------------|-------------:|---------------------:|------------:|
40
+ * | `inline`(0.13.0 이전) | 616 | — | — |
41
+ * | `block; height:100%`(0.14.0) | 616 | 🔴 1620 | 656(고정) |
42
+ * | `contents` | 616 | 1652 | 0(박스 없음)|
43
+ * | **`grid; min-height:100%`** | **616** | **1652** | **1588** |
44
+ * | `flex column; min-height:100%` | 🔴 0 | 1652 | 1588 |
45
+ * | `block; min-height:100%` | 🔴 0 | 1652 | 1588 |
46
+ *
47
+ * ⚠**`contents` 를 택하지 않은 이유는 수치가 아니라 박스다** — 박스가 사라지면 소비자의
48
+ * `u-outlet { padding }`·`{ background }` 와 `getBoundingClientRect()` 가 **오류 없이 아무 일도
49
+ * 안 하게** 된다. 아웃렛이 높이를 끊는 증상 자체가 「내 CSS 가 안 먹는다」로 나타나므로,
50
+ * 그 부류를 새로 만들지 않는다. grid 는 `contents` 의 두 수치를 내면서 박스를 남긴다.
51
+ * ⚠**`align-content` 를 선언하지 말 것** — `start` 를 주면 트랙이 늘어나지 않아 ⑴이 조용히
52
+ * 깨진다(실측: 자손 400px → 0px). 기본값 `normal` 이어야 한다.
53
+ * ⚠**자식이 둘 이상이어도 block 과 같다**(실측: 20px·30px 자식이 각각 20·30 그대로) — 트랙은
54
+ * 늘어나지만 높이가 정해진 항목은 `stretch` 대상이 아니다.
55
+ * ⚠**부모 높이가 `auto` 면 `min-height:100%` 도 `auto` 로 풀린다** — 일반 문서 흐름과 인쇄를
56
+ * 가두지 않는다.
57
+ * 🔴**소비자가 아웃렛을 «줄이려면» `height` 만으로는 부족하고 `min-height: 0` 이 함께 필요하다**
58
+ * — 0.14.0 대비 유일한 계약 추가이며 README·CHANGELOG·참조 문서에 적혀 있다.
27
59
  */
28
- var OUTLET_DISPLAY_CSS = ":where(u-outlet) { display: block; height: 100%; }";
60
+ var OUTLET_DISPLAY_CSS = ":where(u-outlet) { display: grid; min-height: 100%; }";
29
61
  /** 시트를 이미 채택한 트리 — 같은 트리에 두 번 넣지 않는다. */
30
62
  var styledRoots = /* @__PURE__ */ new WeakSet();
31
63
  /**
@@ -1114,12 +1146,12 @@ function catchBasepath(basepath) {
1114
1146
  return basepath;
1115
1147
  }
1116
1148
  //#endregion
1117
- //#region \0@oxc-project+runtime@0.149.0/helpers/esm/decorateMetadata.js
1149
+ //#region \0@oxc-project+runtime@0.150.0/helpers/esm/decorateMetadata.js
1118
1150
  function __decorateMetadata(k, v) {
1119
1151
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
1120
1152
  }
1121
1153
  //#endregion
1122
- //#region \0@oxc-project+runtime@0.149.0/helpers/esm/decorate.js
1154
+ //#region \0@oxc-project+runtime@0.150.0/helpers/esm/decorate.js
1123
1155
  function __decorate(decorators, target, key, desc) {
1124
1156
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1125
1157
  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.14.0",
3
+ "version": "0.15.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",
@@ -40,33 +40,63 @@ export function AppRoot() {
40
40
 
41
41
  ## Outlet Layout
42
42
 
43
- `<u-outlet>` declares its own `display: block`. A custom element's UA default is
44
- `inline`, which would put a route's block-level screen inside an inline box — so the
45
- outlet adopts a single rule on whichever tree it is connected to (the document, or the
46
- shadow root if it lives in one):
43
+ `<u-outlet>` declares its own box model. A custom element's UA default is `inline`, which
44
+ would put a route's block-level screen inside an inline box — so the outlet adopts a single
45
+ rule on whichever tree it is connected to (the document, or the shadow root if it lives in
46
+ one):
47
47
 
48
48
  ```css
49
- :where(u-outlet) { display: block; height: 100%; }
49
+ :where(u-outlet) { display: grid; min-height: 100%; }
50
50
  ```
51
51
 
52
- `height: 100%` is part of the same rule for a reason. A percentage height resolves against
53
- the nearest block container, so making the outlet a block moves that reference from the box
54
- *above* the outlet onto the outlet itself — and an `auto` height there voids the percentage
55
- silently, collapsing a full-height screen to its content height. Declaring `height: 100%`
56
- keeps the chain intact, and resolves to `auto` whenever the parent's height is `auto`, so
57
- ordinary document flow and printing are unaffected.
52
+ The outlet has to be two things at once, and no single declaration gives both:
58
53
 
59
- The `:where()` wrapper makes the rule's specificity zero, so **any** `u-outlet { }`
60
- rule your application writes wins, regardless of sheet order and without `!important`:
54
+ 1. **It passes a sized parent's height down**, so a screen's `height: 100%` resolves here.
55
+ 2. **It grows with a screen taller than the parent**, so the overflow stays inside the
56
+ outlet's box rather than escaping it.
57
+
58
+ `height: 100%` gives only the first. It pins the outlet to the parent's height, so a taller
59
+ screen overflows the outlet — and a scrolling ancestor adds its end padding to the scrollable
60
+ area of its in-flow children, not of what those children overflow with. The end gutter drops
61
+ out: scrolling to the bottom of a long screen leaves the content flush against the container's
62
+ edge while the gutter survives on the other three sides.
63
+
64
+ `min-height: 100%` alone breaks the first. A percentage height only resolves against a parent
65
+ whose `height` is specified, and a minimum does not satisfy that — so on a block (or flex) box
66
+ a descendant's `height: 100%` computes to `auto` and every fill-the-viewport layout collapses
67
+ to its content height.
68
+
69
+ A grid container gives both. A grid item stretches to its area by default, which fills without
70
+ resolving a percentage, so the chain survives while the container's own height is indefinite —
71
+ and because that height is `auto`, the box grows past the minimum when content demands it.
72
+ Multiple children are unaffected: a track stretches, but an item with a definite height does not.
73
+
74
+ The rule deliberately omits `align-content`; it relies on the initial `normal`. Setting
75
+ `align-content: start` stops the track from stretching and silently voids case 1.
76
+
77
+ When the parent's own height is `auto`, `min-height: 100%` resolves to `auto` too, so ordinary
78
+ document flow and printing are unaffected.
79
+
80
+ ### Overriding it
81
+
82
+ The `:where()` wrapper makes the rule's specificity zero, so **any** `u-outlet { … }` rule your
83
+ application writes wins, regardless of sheet order and without `!important`:
61
84
 
62
85
  ```css
63
- u-outlet { display: flex; } /* wins */
64
- u-outlet { height: auto; } /* keep the box, drop the fill */
65
- u-outlet { display: inline; } /* restores the pre-0.14.0 behavior */
66
- @media print { u-outlet { } } /* wins */
86
+ u-outlet { display: flex; } /* wins */
87
+ u-outlet { display: contents; } /* remove the box entirely */
88
+ u-outlet { display: block; height: 100%; } /* restores the 0.14.0 behavior */
89
+ u-outlet { display: inline; } /* restores the pre-0.14.0 behavior */
90
+ @media print { u-outlet { … } } /* wins */
67
91
  ```
68
92
 
69
- The rule is not media-scoped: the outlet is a block box on screen and in print alike.
93
+ > **Making the outlet *smaller* takes two declarations, not one.** `min-height` is a floor, so
94
+ > `u-outlet { height: 200px }` on its own still measures the parent's height. Write
95
+ > `u-outlet { min-height: 0; height: 200px }`. Making it *larger*, or replacing `display`, needs
96
+ > nothing extra. This is the only contract addition in 0.15.0.
97
+
98
+ The rule is not media-scoped: the outlet is a block-level box on screen and in print alike.
99
+
70
100
 
71
101
  ## Nested Outlet Rule
72
102