@iyulab/router 0.13.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 +89 -0
- package/README.md +59 -0
- package/dist/components/UOutlet.d.ts +1 -0
- package/dist/index.js +1 -1
- package/dist/react.js +1 -1
- package/dist/{share-A3Fla8oW.js → share-RyrbTDel.js} +89 -2
- package/package.json +3 -2
- package/skills/iyulab-router/SKILL.md +1 -1
- package/skills/iyulab-router/references/components.md +60 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,94 @@
|
|
|
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
|
+
|
|
54
|
+
## [0.14.0] - 2026-09-16
|
|
55
|
+
|
|
56
|
+
### Changed
|
|
57
|
+
|
|
58
|
+
- **`<u-outlet>` now declares its own `display: block`.** A custom element's UA default is
|
|
59
|
+
`inline`, and the outlet had no styles of its own — so a container meant to hold a route's
|
|
60
|
+
block-level screen generated an inline box. Consumers had to restate `u-outlet { display: block }`
|
|
61
|
+
in every application that cared, which is a rule only the package that defines the element can
|
|
62
|
+
reasonably own.
|
|
63
|
+
|
|
64
|
+
Two independent applications reported this from opposite directions on the same day — one
|
|
65
|
+
through printing (a short document gaining a blank trailing page), one through screen layout
|
|
66
|
+
(a table not reaching the bottom of the viewport). Both traced it to the same missing
|
|
67
|
+
declaration.
|
|
68
|
+
|
|
69
|
+
The declaration is `display: block; height: 100%`. The height half is not cosmetic: changing
|
|
70
|
+
`display` alone also changes which box a percentage height resolves against. While the outlet
|
|
71
|
+
was inline it was not a block container, so a screen's `height: 100%` resolved against the
|
|
72
|
+
block above it; making the outlet a block moves that reference onto the outlet itself, whose
|
|
73
|
+
height is `auto`, which silently voids the percentage and collapses full-height layouts to
|
|
74
|
+
their content height (measured: 747px → 60px for a screen built on
|
|
75
|
+
`@iyulab/modern-app`'s master-detail layout). `height: 100%` restores the chain, and resolves
|
|
76
|
+
to `auto` whenever the parent's height is `auto` — so ordinary document flow and printing,
|
|
77
|
+
where the shell releases its height, are unaffected.
|
|
78
|
+
|
|
79
|
+
The rule is adopted as a constructable stylesheet on whichever tree the outlet is connected to
|
|
80
|
+
(the document, or the shadow root when the outlet lives in one), written as
|
|
81
|
+
`:where(u-outlet)` so its specificity is zero — any `u-outlet { … }` rule an application writes
|
|
82
|
+
still wins without `!important`, regardless of sheet order. Where constructable sheets are not
|
|
83
|
+
available the rule is added as a `<style>` element instead.
|
|
84
|
+
|
|
85
|
+
**This changes layout in normal flow**, not only when printing: an inline box and a block box
|
|
86
|
+
differ in margin collapsing, and a block outlet can be given a height or a percentage size,
|
|
87
|
+
which an inline one silently ignored. Applications that place the outlet inside a flex or grid
|
|
88
|
+
container see no change — flex and grid items were already blockified. To keep the previous
|
|
89
|
+
behavior, set `u-outlet { display: inline }`; to keep the box but not the height, set
|
|
90
|
+
`u-outlet { height: auto }`. Neither needs `!important`.
|
|
91
|
+
|
|
3
92
|
## [0.13.0] - 2026-09-13
|
|
4
93
|
|
|
5
94
|
### Removed
|
package/README.md
CHANGED
|
@@ -141,6 +141,65 @@ const routes = [
|
|
|
141
141
|
- `<u-link>`: SPA-aware anchor element
|
|
142
142
|
- `<u-outlet>`: render target for matched route output
|
|
143
143
|
|
|
144
|
+
## Outlet Layout
|
|
145
|
+
|
|
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
|
+
|
|
151
|
+
```css
|
|
152
|
+
:where(u-outlet) { display: grid; min-height: 100%; }
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
The outlet has to be two things at once, and no single declaration gives both:
|
|
156
|
+
|
|
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`:
|
|
187
|
+
|
|
188
|
+
```css
|
|
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 */
|
|
194
|
+
```
|
|
195
|
+
|
|
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.
|
|
202
|
+
|
|
144
203
|
`<u-link>` supports `href`, `target`, `rel`, and `navigate`.
|
|
145
204
|
|
|
146
205
|
```html
|
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-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
|
@@ -3,9 +3,96 @@ import { customElement, property } from "lit/decorators.js";
|
|
|
3
3
|
import { ifDefined } from "lit/directives/if-defined.js";
|
|
4
4
|
//#region src/components/UOutlet.ts
|
|
5
5
|
/**
|
|
6
|
+
* `<u-outlet>` 의 기본 표시 방식.
|
|
7
|
+
*
|
|
8
|
+
* ★커스텀 엘리먼트의 UA 기본값은 `inline` 이다 — 라우트 화면(블록 요소들)을 인라인 상자에
|
|
9
|
+
* 담으면 block-in-inline 분할이 생겨, 인쇄에서 짧은 문서에 빈 꼬리 쪽이 붙는다. 컨테이너
|
|
10
|
+
* 요소의 표시 방식은 그것을 정의한 쪽이 선언해야 하고, 그 쪽은 이 패키지다.
|
|
11
|
+
* ★`:where(u-outlet)` 로 특이도를 0 으로 둔다 — 소비자의 `u-outlet { … }` 규칙이 시트 순서와
|
|
12
|
+
* 무관하게 `!important` 없이 이긴다.
|
|
13
|
+
* ⚠constructable 시트(`adoptedStyleSheets`)를 쓴다 — `<style>` 요소와 달리 CSP 의 인라인
|
|
14
|
+
* 스타일 제한에 걸리지 않는다. 지원하지 않는 환경에서는 `<style>` 로 대신한다.
|
|
15
|
+
* ⚠매체를 가르지 않는다 — 인라인 컨테이너는 화면에서도 의도된 적이 없다(라인 박스 때문에
|
|
16
|
+
* 높이를 줄 수도, 백분율로 채울 수도 없었다). 인쇄에만 한정하면 화면·인쇄가 서로 다른
|
|
17
|
+
* 상자 모델을 갖게 되어 같은 부류의 차이가 다음에 또 난다.
|
|
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·참조 문서에 적혀 있다.
|
|
59
|
+
*/
|
|
60
|
+
var OUTLET_DISPLAY_CSS = ":where(u-outlet) { display: grid; min-height: 100%; }";
|
|
61
|
+
/** 시트를 이미 채택한 트리 — 같은 트리에 두 번 넣지 않는다. */
|
|
62
|
+
var styledRoots = /* @__PURE__ */ new WeakSet();
|
|
63
|
+
/**
|
|
64
|
+
* 아웃렛이 실제로 속한 트리에 표시 규칙을 채택한다.
|
|
65
|
+
*
|
|
66
|
+
* ⚠`document` 로 못박지 않는다 — 섀도 루트 안의 `<u-outlet>` 은 문서 시트가 닿지 않아
|
|
67
|
+
* 기본 `inline` 그대로 남는다. 아웃렛을 라이트 DOM 에 두는 것이 이 생태계의 관례이지만,
|
|
68
|
+
* 그 관례를 어긴 배치에서 조용히 규칙이 사라지는 쪽이 더 나쁘다.
|
|
69
|
+
*/
|
|
70
|
+
function adoptOutletDisplay(node) {
|
|
71
|
+
const isDocument = node.nodeType === 9;
|
|
72
|
+
const isShadowRoot = node.nodeType === 11 && "host" in node;
|
|
73
|
+
if (!isDocument && !isShadowRoot) return;
|
|
74
|
+
const root = node;
|
|
75
|
+
if (styledRoots.has(root)) return;
|
|
76
|
+
styledRoots.add(root);
|
|
77
|
+
if ("adoptedStyleSheets" in root && typeof CSSStyleSheet !== "undefined" && typeof CSSStyleSheet.prototype.replaceSync === "function") {
|
|
78
|
+
const sheet = new CSSStyleSheet();
|
|
79
|
+
sheet.replaceSync(OUTLET_DISPLAY_CSS);
|
|
80
|
+
root.adoptedStyleSheets = [...root.adoptedStyleSheets, sheet];
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
const ownerDocument = isDocument ? root : node.ownerDocument;
|
|
84
|
+
if (!ownerDocument) return;
|
|
85
|
+
const style = ownerDocument.createElement("style");
|
|
86
|
+
style.textContent = OUTLET_DISPLAY_CSS;
|
|
87
|
+
(isDocument ? root.head : root)?.prepend(style);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
6
90
|
* LitElement 또는 React 컴포넌트를 렌더링해주는 웹컴포넌트 입니다.
|
|
7
91
|
*/
|
|
8
92
|
var UOutlet = class extends HTMLElement {
|
|
93
|
+
connectedCallback() {
|
|
94
|
+
adoptOutletDisplay(this.getRootNode());
|
|
95
|
+
}
|
|
9
96
|
/**
|
|
10
97
|
* 주어진 렌더링 옵션에 따라 컨텐츠를 렌더링합니다.
|
|
11
98
|
*
|
|
@@ -1059,12 +1146,12 @@ function catchBasepath(basepath) {
|
|
|
1059
1146
|
return basepath;
|
|
1060
1147
|
}
|
|
1061
1148
|
//#endregion
|
|
1062
|
-
//#region \0@oxc-project+runtime@0.
|
|
1149
|
+
//#region \0@oxc-project+runtime@0.150.0/helpers/esm/decorateMetadata.js
|
|
1063
1150
|
function __decorateMetadata(k, v) {
|
|
1064
1151
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
1065
1152
|
}
|
|
1066
1153
|
//#endregion
|
|
1067
|
-
//#region \0@oxc-project+runtime@0.
|
|
1154
|
+
//#region \0@oxc-project+runtime@0.150.0/helpers/esm/decorate.js
|
|
1068
1155
|
function __decorate(decorators, target, key, desc) {
|
|
1069
1156
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1070
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.
|
|
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",
|
|
@@ -71,6 +71,7 @@
|
|
|
71
71
|
}
|
|
72
72
|
},
|
|
73
73
|
"devDependencies": {
|
|
74
|
+
"@vitest/browser-playwright": "^5.0.0",
|
|
74
75
|
"@types/node": "^26.1.1",
|
|
75
76
|
"@types/react": "^19.2.17",
|
|
76
77
|
"@types/react-dom": "^19.2.3",
|
|
@@ -80,6 +81,6 @@
|
|
|
80
81
|
"typescript": "^6.0.2",
|
|
81
82
|
"vite": "^8.1.4",
|
|
82
83
|
"vite-plugin-dts": "^5.0.3",
|
|
83
|
-
"vitest": "^
|
|
84
|
+
"vitest": "^5.0.0"
|
|
84
85
|
}
|
|
85
86
|
}
|
|
@@ -27,7 +27,7 @@ npm install @iyulab/router
|
|
|
27
27
|
| `RouterConfig` | Constructor config type |
|
|
28
28
|
| `RouteContext` | Passed to every `render()` call |
|
|
29
29
|
| `FallbackRouteConfig` | Error/404 fallback definition |
|
|
30
|
-
| `<u-outlet>` | Renders the matched route output |
|
|
30
|
+
| `<u-outlet>` | Renders the matched route output (a block box — see `references/components.md`) |
|
|
31
31
|
| `<u-link>` | Client-side navigation anchor |
|
|
32
32
|
| `UOutlet`, `ULink` | React wrappers (from `@iyulab/router/react`) |
|
|
33
33
|
|
|
@@ -38,6 +38,66 @@ export function AppRoot() {
|
|
|
38
38
|
}
|
|
39
39
|
```
|
|
40
40
|
|
|
41
|
+
## Outlet Layout
|
|
42
|
+
|
|
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
|
+
|
|
48
|
+
```css
|
|
49
|
+
:where(u-outlet) { display: grid; min-height: 100%; }
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
The outlet has to be two things at once, and no single declaration gives both:
|
|
53
|
+
|
|
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`:
|
|
84
|
+
|
|
85
|
+
```css
|
|
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 */
|
|
91
|
+
```
|
|
92
|
+
|
|
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
|
+
|
|
100
|
+
|
|
41
101
|
## Nested Outlet Rule
|
|
42
102
|
|
|
43
103
|
A parent route must render `<u-outlet>` to host child route content.
|