@iyulab/modern-app 0.22.0 → 0.23.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,47 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.23.0] - 2026-09-21
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- **Route content no longer paints through an open overlay.** The overlay frame sits at
|
|
8
|
+
`z-index: 1`, while route content routinely holds positioned descendants with a higher one —
|
|
9
|
+
a data grid's sticky header row and pinned columns sit at 2–4. Neither the content area nor
|
|
10
|
+
its wrapper established a stacking context, so those competed with the overlay frame in the
|
|
11
|
+
same context and won: the list showed through the panel meant to cover it. While the overlay
|
|
12
|
+
is open, the wrapper holding route content is now its own stacking context, so no `z-index`
|
|
13
|
+
in route content can outrank the panel. Raising the frame's own `z-index` was rejected as a
|
|
14
|
+
fix — it only moves the finish line, and a larger value in route content would win again.
|
|
15
|
+
The boundary applies only while the overlay is open, so nothing else about how route content
|
|
16
|
+
paints changes.
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
|
|
20
|
+
- **`part="main-content"`** on the wrapper holding route content, so the `inert` the shell
|
|
21
|
+
applies while the overlay is open is visible from outside. It is applied to this wrapper and
|
|
22
|
+
not to `part="main"` — that one is the scroll container and stays interactive — which made it
|
|
23
|
+
easy to read `inert` off `part="main"`, see `false`, and conclude the shell was not applying
|
|
24
|
+
it at all.
|
|
25
|
+
|
|
26
|
+
### Documentation
|
|
27
|
+
|
|
28
|
+
- **The overlay's ownership contract is now written down** — what the shell provides (placement,
|
|
29
|
+
paint order, `inert`, the close affordance, keeping the route mounted) and what stays with the
|
|
30
|
+
consumer (moving and restoring focus, Escape-to-close, any scrim, the panel's accessible
|
|
31
|
+
name). `docs/layout.md` had never documented the overlay slot at all, and its parts table was
|
|
32
|
+
missing `overlay` and `overlay-close`; both now match the skill pack's reference.
|
|
33
|
+
|
|
34
|
+
## [0.22.1] - 2026-09-19
|
|
35
|
+
|
|
36
|
+
### Fixed
|
|
37
|
+
|
|
38
|
+
- **A wide route content no longer pushes the desktop shell past the viewport.** In 0.22.0 the
|
|
39
|
+
scroll region's wrapper lacked a horizontal minimum-size override, so a body wider than the
|
|
40
|
+
available width (a data grid whose columns sum past the viewport) grew the wrapper beyond the
|
|
41
|
+
viewport: the right-hand columns were clipped and neither the content area nor the page scrolled
|
|
42
|
+
horizontally. The wide content now scrolls inside the content area again, as it did before 0.22.0.
|
|
43
|
+
This is the horizontal counterpart of the mobile height fix shipped in 0.22.0.
|
|
44
|
+
|
|
3
45
|
## [0.22.0] - 2026-09-18
|
|
4
46
|
|
|
5
47
|
### Added
|
|
@@ -179,7 +179,7 @@ var T = class extends i {
|
|
|
179
179
|
<div class="main" part="main" scrollable tabindex="-1" @keydown=${this._handleMainKeydown}>
|
|
180
180
|
<u-progress-bar part="progress"></u-progress-bar>
|
|
181
181
|
|
|
182
|
-
<div class="main-content" ?inert=${this.hasOverlay}>
|
|
182
|
+
<div class="main-content" part="main-content" ?inert=${this.hasOverlay}>
|
|
183
183
|
<slot></slot>
|
|
184
184
|
</div>
|
|
185
185
|
</div>
|
|
@@ -186,11 +186,16 @@ var t = e`
|
|
|
186
186
|
.main-region {
|
|
187
187
|
position: relative;
|
|
188
188
|
flex: 1;
|
|
189
|
-
/*
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
189
|
+
/* flex item 의 자동 최소 크기는 콘텐츠 기준(.main 의 min-content)이다 — 이 래퍼는
|
|
190
|
+
overflow 가 visible 이라 그 하한이 그대로 살아, flex-shrink 가 있어도 셸 밖으로
|
|
191
|
+
커진다. 그러면 .main 의 overflow: auto 가 한 번도 발동하지 않는다. 주축이 어느 쪽이든
|
|
192
|
+
같은 원인이라 두 축을 함께 푼다:
|
|
193
|
+
· 높이 — :host([state="mobile"]) 은 flex-direction: column 이라 min-height 가 필요하다.
|
|
194
|
+
없으면 셸 전체가 콘텐츠 높이만큼 부풀어 오른다.
|
|
195
|
+
· 너비 — 데스크톱(row)에서는 min-width 가 필요하다. 없으면 넓은 표 하나가 셸을
|
|
196
|
+
뷰포트 밖으로 밀어 오른쪽 열이 잘리고 가로 스크롤도 생기지 않는다. */
|
|
193
197
|
min-height: 0;
|
|
198
|
+
min-width: 0;
|
|
194
199
|
}
|
|
195
200
|
|
|
196
201
|
.main {
|
|
@@ -206,6 +211,36 @@ var t = e`
|
|
|
206
211
|
height: 100%;
|
|
207
212
|
}
|
|
208
213
|
|
|
214
|
+
/*
|
|
215
|
+
* 오버레이가 열린 동안 «본문 영역»을 스태킹 컨텍스트로 만든다.
|
|
216
|
+
*
|
|
217
|
+
* 오버레이 틀은 z-index: 1 이고, 라우트 본문은 그보다 큰 z 를 일상적으로 쓴다 —
|
|
218
|
+
* 데이터 그리드의 sticky 머리행·고정 열이 2~4 에 있다. .main 도 .main-region 도
|
|
219
|
+
* 스태킹 컨텍스트를 만들지 않으므로 그것들과 오버레이 틀이 «같은 컨텍스트에서 직접
|
|
220
|
+
* 겨루고», 본문이 이긴다 — 덮으라고 띄운 패널을 목록이 뚫고 나온다.
|
|
221
|
+
*
|
|
222
|
+
* ⚠값을 올리는 처방(z-index 를 50 으로)은 소비자의 z 어휘가 커지면 같은 경주를 다시
|
|
223
|
+
* 한다. 경계를 세워야 한다.
|
|
224
|
+
*
|
|
225
|
+
* ⚠경계를 «어디에» 세우는가가 갈린다 — 넷을 픽셀 대조로 실측하고 골랐다:
|
|
226
|
+
* · .overlay 자신을 컨텍스트로 → 자기 z 는 여전히 1 이라 바깥에서 3 에게 진다. ✗
|
|
227
|
+
* · .main-region 을 컨텍스트로 → 본문과 오버레이를 «같은» 새 컨텍스트에 함께
|
|
228
|
+
* 가두므로 그 안에서 순서가 그대로다. ✗
|
|
229
|
+
* · .main / .main-content 를 «상시» 컨텍스트로 → 오버레이는 이기지만 본문 안의
|
|
230
|
+
* position: fixed 팝오버가 사이드바(z 1000) 위로 못 올라간다(상시 동작 변경).
|
|
231
|
+
* .main 쪽은 셸 자신의 진행 막대(z 100)까지 오버레이 아래로 내린다. ✗
|
|
232
|
+
* · 이 규칙 — 오버레이가 열린 동안만 .main-content 를 컨텍스트로 → 세 축 모두 유지. ✓
|
|
233
|
+
*
|
|
234
|
+
* ⇒ 경계가 필요한 조건은 정확히 «오버레이가 열려 있다» 이고, 그때만 세운다. 닫혀 있으면
|
|
235
|
+
* 겨룰 상대가 없다(.overlay.empty 는 display: none 이다).
|
|
236
|
+
* ⚠ .main 이 아니라 .main-content 인 것도 의도다 — 가두는 대상은 «소비자의 라우트 본문»
|
|
237
|
+
* 이지 셸 자신의 chrome 이 아니다. 진행 막대는 .main-content 밖(.main 직속)이라 이
|
|
238
|
+
* 경계에 걸리지 않고, 오버레이가 열린 채로 일어나는 라우트 전환을 계속 보고한다.
|
|
239
|
+
*/
|
|
240
|
+
:host(:state(overlay)) .main-content {
|
|
241
|
+
isolation: isolate;
|
|
242
|
+
}
|
|
243
|
+
|
|
209
244
|
.main u-progress-bar {
|
|
210
245
|
--progress-bar-height: 4px;
|
|
211
246
|
--progress-bar-track-color: transparent;
|
|
@@ -12,7 +12,7 @@ export type { SidebarSectionConfig } from '../components/SidebarSection';
|
|
|
12
12
|
export type { SidebarGroupConfig } from '../components/SidebarGroup';
|
|
13
13
|
export type { SidebarButtonConfig } from '../components/SidebarButton';
|
|
14
14
|
/** 사이드바 레이아웃 컴포넌트의 요소(part) 타입 */
|
|
15
|
-
export type SidebarParts = 'host' | 'mobile-header' | 'sidebar' | 'sidebar-header' | 'sidebar-main' | 'sidebar-footer' | 'main' | 'progress' | 'overlay' | 'overlay-close';
|
|
15
|
+
export type SidebarParts = 'host' | 'mobile-header' | 'sidebar' | 'sidebar-header' | 'sidebar-main' | 'sidebar-footer' | 'main' | 'main-content' | 'progress' | 'overlay' | 'overlay-close';
|
|
16
16
|
/** 사이드바 상태 타입 */
|
|
17
17
|
export type SidebarState = 'default' | 'slim' | 'modal' | 'mobile' | 'mobile-open';
|
|
18
18
|
/** 사이드바 안에 HTML 또는 엘리먼트를 직접 렌더링하는 설정 */
|
package/package.json
CHANGED
|
@@ -256,7 +256,8 @@ Parts available for `styles` overrides on the root layout:
|
|
|
256
256
|
| `sidebar-header` | Logo + title area |
|
|
257
257
|
| `sidebar-main` | Scrollable main nav area |
|
|
258
258
|
| `sidebar-footer` | Pinned footer area |
|
|
259
|
-
| `main` | Main content area |
|
|
259
|
+
| `main` | Main content area (the scroll container) |
|
|
260
|
+
| `main-content` | Wrapper holding route content inside `main` — the shell puts `inert` here while the overlay is open |
|
|
260
261
|
| `progress` | Top progress bar |
|
|
261
262
|
| `overlay` | Route-independent overlay panel above `main` |
|
|
262
263
|
| `overlay-close` | Overlay's close button |
|
|
@@ -334,6 +335,35 @@ To keep the underlying route mounted while a URL parameter drives the overlay op
|
|
|
334
335
|
query-string change doesn't remount the whole screen), give the route a `key` that excludes that
|
|
335
336
|
parameter — see [`docs/routing.md`](../../../docs/routing.md) `RouteConfig.key`.
|
|
336
337
|
|
|
338
|
+
### What the shell owns, and what it does not
|
|
339
|
+
|
|
340
|
+
The overlay is a **layer**, not a modal dialog. Splitting that precisely is what keeps a consumer
|
|
341
|
+
from either re-implementing what the shell already does, or dropping what it does not.
|
|
342
|
+
|
|
343
|
+
| Concern | Owner | How |
|
|
344
|
+
|---|---|---|
|
|
345
|
+
| Placement, size and scrolling of the panel | shell | `part="overlay"` covers the main region and scrolls on its own |
|
|
346
|
+
| Painting above route content | shell | while the overlay is open, `part="main-content"` becomes its own stacking context, so a `z-index` in route content cannot paint through the panel |
|
|
347
|
+
| Making route content non-interactive | shell | `inert` on `part="main-content"`, which propagates through the slot into your route content |
|
|
348
|
+
| A close affordance | shell | `part="overlay-close"`, firing the non-cancelable `overlay-close` event |
|
|
349
|
+
| Keeping the route mounted underneath | shell | the overlay is independent of routing |
|
|
350
|
+
| **Moving focus into the panel when it opens** | **consumer** | focus the panel or its first control yourself |
|
|
351
|
+
| **Restoring focus when it closes** | **consumer** | remember the trigger and re-focus it |
|
|
352
|
+
| **Escape to close** | **consumer** | the shell binds no key; listen for it and empty the slot |
|
|
353
|
+
| **A backdrop / dimmed scrim** | **consumer** | the panel is opaque and full-bleed by design; add a scrim inside your panel if you want one |
|
|
354
|
+
| **Announcing the panel to assistive tech** | **consumer** | put `role`/`aria-label` (or `aria-modal`, if you have made it modal) on *your* panel — the shell does not know what it holds |
|
|
355
|
+
|
|
356
|
+
⚠ **`inert` is applied to `part="main-content"`, not to `part="main"`.** `part="main"` is the scroll
|
|
357
|
+
container and stays interactive so it can keep scrolling; the wrapper inside it is what goes inert.
|
|
358
|
+
Reading `inert` off `part="main"` reports `false` and says nothing about whether the shell applied it.
|
|
359
|
+
There is also no reliable way to check it by enumeration — `querySelectorAll` still returns focusable
|
|
360
|
+
elements inside an inert subtree. Inertness shows up when something tries to *take* focus, not when
|
|
361
|
+
you count what is there.
|
|
362
|
+
|
|
363
|
+
⚠ **Page-level scroll is not locked**, deliberately. In the shell model `part="main"` is the scroller
|
|
364
|
+
and the overlay covers it, so there is nothing behind it to scroll. If your app instead lets the
|
|
365
|
+
document itself scroll, locking that is yours.
|
|
366
|
+
|
|
337
367
|
No `overlayBreakpoint`/responsive toggle exists here — unlike `u-master-detail-layout`, this
|
|
338
368
|
overlay is always an overlay, never a side-by-side pane. Use `u-master-detail-layout` instead
|
|
339
369
|
when you want the panel to sit *beside* content on wide screens.
|