@iyulab/modern-app 0.18.18 → 0.19.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 +38 -0
- package/dist/_virtual/{_@oxc-project_runtime@0.148.0 → _@oxc-project_runtime@0.149.0}/helpers/esm/decorate.js +1 -1
- package/dist/_virtual/{_@oxc-project_runtime@0.148.0 → _@oxc-project_runtime@0.149.0}/helpers/esm/decorateMetadata.js +1 -1
- package/dist/components/ActionBar.js +2 -2
- package/dist/components/EmptyState.js +2 -2
- package/dist/components/EmptyState.styles.js +1 -1
- package/dist/components/GroupBox.js +2 -2
- package/dist/components/InfoField.js +2 -2
- package/dist/components/InfoField.styles.js +3 -3
- package/dist/components/InfoSection.js +2 -2
- package/dist/components/MasterDetailLayout.d.ts +14 -0
- package/dist/components/MasterDetailLayout.js +7 -5
- package/dist/components/PageHeader.js +2 -2
- package/dist/components/PageHeader.styles.js +1 -1
- package/dist/components/SidebarButton.js +2 -2
- package/dist/components/SidebarGroup.js +2 -2
- package/dist/components/SidebarLink.js +2 -2
- package/dist/components/SidebarSection.js +2 -2
- package/dist/components/Wizard.js +2 -2
- package/dist/components/Wizard.styles.js +1 -1
- package/dist/internals/StyledElement.js +2 -2
- package/dist/layouts/SidebarLayout.d.ts +7 -0
- package/dist/layouts/SidebarLayout.js +8 -3
- package/dist/layouts/SidebarLayout.types.d.ts +9 -0
- package/package.json +3 -3
- package/skills/modern-app/references/api.md +1 -1
- package/skills/modern-app/references/components/master-detail-layout.md +16 -0
- package/skills/modern-app/references/layout.md +31 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,43 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.19.0] - 2026-09-10
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
|
|
7
|
+
- **Fallback literals for `--u-txt-color-weak` follow `@iyulab/components` 1.40.0.** They are
|
|
8
|
+
only used when that stylesheet is not loaded; with it, nothing changes here.
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- **`u-master-detail-layout` ignored a change to `overlayBreakpoint` until the element
|
|
13
|
+
happened to resize.** The overlay decision has two inputs — the component's own width
|
|
14
|
+
and the breakpoint — but it was only ever evaluated inside the `ResizeObserver`
|
|
15
|
+
callback, so setting the prop at runtime left the `overlay` attribute on its previous
|
|
16
|
+
verdict. Setting it once before first render always worked, which is why the gap went
|
|
17
|
+
unnoticed. It is now re-evaluated whenever either input changes.
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
|
|
21
|
+
- **`@iyulab/components` moved from `dependencies` to `peerDependencies`.** It owns
|
|
22
|
+
process-global state — the custom element registry and module-level singletons — so a
|
|
23
|
+
duplicate copy in the install tree splits that state with no error: the notification layer
|
|
24
|
+
stops seeing overlays that a different copy registered, which is exactly the failure the
|
|
25
|
+
1.39.0 toast fix addresses. Consumers already installing `@iyulab/components` are unaffected;
|
|
26
|
+
the declaration now says that this package uses the copy they installed.
|
|
27
|
+
|
|
28
|
+
## [0.18.19] - 2026-09-04
|
|
29
|
+
|
|
30
|
+
### Added
|
|
31
|
+
|
|
32
|
+
- **`SidebarLayout` had no way for a consumer to control scroll position on route
|
|
33
|
+
change, and no official way to reach its scroll container at all** — only an
|
|
34
|
+
undocumented shadow-DOM `part="main"` selector, a style-only CSS hook rather than a
|
|
35
|
+
JS access contract. Added `layout.scrollBehavior(context, main)`, called on every
|
|
36
|
+
`route-done` before focus moves to the container, and a public `mainElement`
|
|
37
|
+
accessor on the element for reading/writing scroll position outside the hook (e.g.
|
|
38
|
+
saving a position from a `route-begin` listener). Unset `scrollBehavior` does
|
|
39
|
+
nothing, matching Vue Router's own default for an unset `scrollBehavior`.
|
|
40
|
+
|
|
3
41
|
## [0.18.18] - 2026-09-04
|
|
4
42
|
|
|
5
43
|
### Fixed
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
//#region \0@oxc-project+runtime@0.
|
|
1
|
+
//#region \0@oxc-project+runtime@0.149.0/helpers/esm/decorate.js
|
|
2
2
|
function e(e, t, n, r) {
|
|
3
3
|
var i = arguments.length, a = i < 3 ? t : r === null ? r = Object.getOwnPropertyDescriptor(t, n) : r, o;
|
|
4
4
|
if (typeof Reflect == "object" && typeof Reflect.decorate == "function") a = Reflect.decorate(e, t, n, r);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
//#region \0@oxc-project+runtime@0.
|
|
1
|
+
//#region \0@oxc-project+runtime@0.149.0/helpers/esm/decorateMetadata.js
|
|
2
2
|
function e(e, t) {
|
|
3
3
|
if (typeof Reflect == "object" && typeof Reflect.metadata == "function") return Reflect.metadata(e, t);
|
|
4
4
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import e from "../_virtual/_@oxc-project_runtime@0.
|
|
2
|
-
import t from "../_virtual/_@oxc-project_runtime@0.
|
|
1
|
+
import e from "../_virtual/_@oxc-project_runtime@0.149.0/helpers/esm/decorateMetadata.js";
|
|
2
|
+
import t from "../_virtual/_@oxc-project_runtime@0.149.0/helpers/esm/decorate.js";
|
|
3
3
|
import { StyledElement as n } from "../internals/StyledElement.js";
|
|
4
4
|
import { slotHasContent as r } from "../internals/slotted.js";
|
|
5
5
|
import { styles as i } from "./ActionBar.styles.js";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import e from "../_virtual/_@oxc-project_runtime@0.
|
|
2
|
-
import t from "../_virtual/_@oxc-project_runtime@0.
|
|
1
|
+
import e from "../_virtual/_@oxc-project_runtime@0.149.0/helpers/esm/decorateMetadata.js";
|
|
2
|
+
import t from "../_virtual/_@oxc-project_runtime@0.149.0/helpers/esm/decorate.js";
|
|
3
3
|
import { StyledElement as n } from "../internals/StyledElement.js";
|
|
4
4
|
import { getLocaleStrings as r } from "../internals/locale.js";
|
|
5
5
|
import { slotHasContent as i } from "../internals/slotted.js";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import e from "../_virtual/_@oxc-project_runtime@0.
|
|
2
|
-
import t from "../_virtual/_@oxc-project_runtime@0.
|
|
1
|
+
import e from "../_virtual/_@oxc-project_runtime@0.149.0/helpers/esm/decorateMetadata.js";
|
|
2
|
+
import t from "../_virtual/_@oxc-project_runtime@0.149.0/helpers/esm/decorate.js";
|
|
3
3
|
import { StyledElement as n } from "../internals/StyledElement.js";
|
|
4
4
|
import { slotHasContent as r } from "../internals/slotted.js";
|
|
5
5
|
import { styles as i } from "./GroupBox.styles.js";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import e from "../_virtual/_@oxc-project_runtime@0.
|
|
2
|
-
import t from "../_virtual/_@oxc-project_runtime@0.
|
|
1
|
+
import e from "../_virtual/_@oxc-project_runtime@0.149.0/helpers/esm/decorateMetadata.js";
|
|
2
|
+
import t from "../_virtual/_@oxc-project_runtime@0.149.0/helpers/esm/decorate.js";
|
|
3
3
|
import { StyledElement as n } from "../internals/StyledElement.js";
|
|
4
4
|
import { styles as r } from "./InfoField.styles.js";
|
|
5
5
|
import { html as i } from "lit";
|
|
@@ -10,7 +10,7 @@ var t = e`
|
|
|
10
10
|
font-size: var(--u-text-caption-size, 12px);
|
|
11
11
|
font-weight: var(--u-text-caption-weight, 400);
|
|
12
12
|
line-height: var(--u-text-caption-leading, 1.5);
|
|
13
|
-
color: var(--u-txt-color-weak, #
|
|
13
|
+
color: var(--u-txt-color-weak, #616161);
|
|
14
14
|
margin-bottom: var(--u-space-3xs, 2px);
|
|
15
15
|
}
|
|
16
16
|
|
|
@@ -37,7 +37,7 @@ var t = e`
|
|
|
37
37
|
⚠더 흐리게 만들고 싶은 유혹이 있는데, 이 자리가 안 읽히면 사용자는 빈 칸인지
|
|
38
38
|
로딩 중인지 구별하지 못한다. */
|
|
39
39
|
.value.blank {
|
|
40
|
-
color: var(--u-txt-color-weak, #
|
|
40
|
+
color: var(--u-txt-color-weak, #616161);
|
|
41
41
|
font-weight: var(--u-text-body-weight, 400);
|
|
42
42
|
}
|
|
43
43
|
|
|
@@ -71,7 +71,7 @@ var t = e`
|
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
.trend.tone-neutral {
|
|
74
|
-
color: var(--u-txt-color-weak, #
|
|
74
|
+
color: var(--u-txt-color-weak, #616161);
|
|
75
75
|
}
|
|
76
76
|
`;
|
|
77
77
|
//#endregion
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import e from "../_virtual/_@oxc-project_runtime@0.
|
|
2
|
-
import t from "../_virtual/_@oxc-project_runtime@0.
|
|
1
|
+
import e from "../_virtual/_@oxc-project_runtime@0.149.0/helpers/esm/decorateMetadata.js";
|
|
2
|
+
import t from "../_virtual/_@oxc-project_runtime@0.149.0/helpers/esm/decorate.js";
|
|
3
3
|
import { StyledElement as n } from "../internals/StyledElement.js";
|
|
4
4
|
import { styles as r } from "./InfoSection.styles.js";
|
|
5
5
|
import { html as i } from "lit";
|
|
@@ -52,6 +52,20 @@ export declare class MasterDetailLayout extends StyledElement<ElementParts> {
|
|
|
52
52
|
private hasDetail;
|
|
53
53
|
private resizeObserver?;
|
|
54
54
|
connectedCallback(): void;
|
|
55
|
+
/**
|
|
56
|
+
* 오버레이 판정 한 곳. **두 입력이 있고 둘 다 바뀔 수 있다** — 자기 폭과
|
|
57
|
+
* `overlayBreakpoint`.
|
|
58
|
+
*
|
|
59
|
+
* 🔴**종전에는 이 판정이 ResizeObserver 콜백 «안에만» 있었다.** 그래서 `overlayBreakpoint`
|
|
60
|
+
* 를 런타임에 바꿔도 **폭이 함께 바뀌지 않으면 아무 일도 일어나지 않았다** — prop 은
|
|
61
|
+
* 새 값을 갖고 있는데 `overlay` 속성은 옛 판정 그대로다. 값에 반응하는 prop 으로
|
|
62
|
+
* 선언·문서화해 놓고 실제로는 리사이즈에만 반응한 셈이라, 이 리포가 「선언 ≠ 동작」이라
|
|
63
|
+
* 부르는 부류다.
|
|
64
|
+
*
|
|
65
|
+
* @param width 0 이면 아직 레이아웃되지 않은 과도 상태일 수 있다(예: 조상이 `display:none`)
|
|
66
|
+
* — 그 순간의 값으로 오버레이를 강제하지 않는다.
|
|
67
|
+
*/
|
|
68
|
+
private applyOverlay;
|
|
55
69
|
disconnectedCallback(): void;
|
|
56
70
|
protected updated(changed: PropertyValues): void;
|
|
57
71
|
/**
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import e from "../_virtual/_@oxc-project_runtime@0.
|
|
2
|
-
import t from "../_virtual/_@oxc-project_runtime@0.
|
|
1
|
+
import e from "../_virtual/_@oxc-project_runtime@0.149.0/helpers/esm/decorateMetadata.js";
|
|
2
|
+
import t from "../_virtual/_@oxc-project_runtime@0.149.0/helpers/esm/decorate.js";
|
|
3
3
|
import { StyledElement as n } from "../internals/StyledElement.js";
|
|
4
4
|
import { getLocaleStrings as r } from "../internals/locale.js";
|
|
5
5
|
import { slotHasContent as i } from "../internals/slotted.js";
|
|
@@ -22,15 +22,17 @@ var u = class extends n {
|
|
|
22
22
|
}
|
|
23
23
|
connectedCallback() {
|
|
24
24
|
super.connectedCallback(), this.resizeObserver = new ResizeObserver((e) => {
|
|
25
|
-
|
|
26
|
-
t !== 0 && this.toggleAttribute("overlay", t < this.overlayBreakpoint);
|
|
25
|
+
this.applyOverlay(e[0]?.contentRect.width ?? 0);
|
|
27
26
|
}), this.resizeObserver.observe(this);
|
|
28
27
|
}
|
|
28
|
+
applyOverlay(e) {
|
|
29
|
+
e !== 0 && this.toggleAttribute("overlay", e < this.overlayBreakpoint);
|
|
30
|
+
}
|
|
29
31
|
disconnectedCallback() {
|
|
30
32
|
super.disconnectedCallback(), this.resizeObserver?.disconnect();
|
|
31
33
|
}
|
|
32
34
|
updated(e) {
|
|
33
|
-
super.updated(e), e.has("masterSize") && this.style.setProperty("--_master-size", this.masterSize);
|
|
35
|
+
super.updated(e), e.has("masterSize") && this.style.setProperty("--_master-size", this.masterSize), e.has("overlayBreakpoint") && this.applyOverlay(this.getBoundingClientRect().width);
|
|
34
36
|
}
|
|
35
37
|
render() {
|
|
36
38
|
return o`
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import e from "../_virtual/_@oxc-project_runtime@0.
|
|
2
|
-
import t from "../_virtual/_@oxc-project_runtime@0.
|
|
1
|
+
import e from "../_virtual/_@oxc-project_runtime@0.149.0/helpers/esm/decorateMetadata.js";
|
|
2
|
+
import t from "../_virtual/_@oxc-project_runtime@0.149.0/helpers/esm/decorate.js";
|
|
3
3
|
import { StyledElement as n } from "../internals/StyledElement.js";
|
|
4
4
|
import { getLocaleStrings as r } from "../internals/locale.js";
|
|
5
5
|
import { slotHasContent as i } from "../internals/slotted.js";
|
|
@@ -37,7 +37,7 @@ var t = e`
|
|
|
37
37
|
font-size: var(--u-text-caption-size, 12px);
|
|
38
38
|
font-weight: var(--u-text-caption-weight, 400);
|
|
39
39
|
line-height: var(--u-text-caption-leading, 1.5);
|
|
40
|
-
color: var(--u-txt-color-weak, #
|
|
40
|
+
color: var(--u-txt-color-weak, #616161);
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
.back {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import e from "../_virtual/_@oxc-project_runtime@0.
|
|
2
|
-
import t from "../_virtual/_@oxc-project_runtime@0.
|
|
1
|
+
import e from "../_virtual/_@oxc-project_runtime@0.149.0/helpers/esm/decorateMetadata.js";
|
|
2
|
+
import t from "../_virtual/_@oxc-project_runtime@0.149.0/helpers/esm/decorate.js";
|
|
3
3
|
import { StyledElement as n } from "../internals/StyledElement.js";
|
|
4
4
|
import { DEFAULT_NAV_ICON as r } from "../internals/nav-icon.js";
|
|
5
5
|
import { styles as i } from "./SidebarButton.styles.js";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import e from "../_virtual/_@oxc-project_runtime@0.
|
|
2
|
-
import t from "../_virtual/_@oxc-project_runtime@0.
|
|
1
|
+
import e from "../_virtual/_@oxc-project_runtime@0.149.0/helpers/esm/decorateMetadata.js";
|
|
2
|
+
import t from "../_virtual/_@oxc-project_runtime@0.149.0/helpers/esm/decorate.js";
|
|
3
3
|
import { StyledElement as n } from "../internals/StyledElement.js";
|
|
4
4
|
import { DEFAULT_NAV_ICON as r } from "../internals/nav-icon.js";
|
|
5
5
|
import { SidebarLink as i } from "./SidebarLink.js";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import e from "../_virtual/_@oxc-project_runtime@0.
|
|
2
|
-
import t from "../_virtual/_@oxc-project_runtime@0.
|
|
1
|
+
import e from "../_virtual/_@oxc-project_runtime@0.149.0/helpers/esm/decorateMetadata.js";
|
|
2
|
+
import t from "../_virtual/_@oxc-project_runtime@0.149.0/helpers/esm/decorate.js";
|
|
3
3
|
import { StyledElement as n } from "../internals/StyledElement.js";
|
|
4
4
|
import { DEFAULT_NAV_ICON as r } from "../internals/nav-icon.js";
|
|
5
5
|
import { styles as i } from "./SidebarLink.styles.js";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import e from "../_virtual/_@oxc-project_runtime@0.
|
|
2
|
-
import t from "../_virtual/_@oxc-project_runtime@0.
|
|
1
|
+
import e from "../_virtual/_@oxc-project_runtime@0.149.0/helpers/esm/decorateMetadata.js";
|
|
2
|
+
import t from "../_virtual/_@oxc-project_runtime@0.149.0/helpers/esm/decorate.js";
|
|
3
3
|
import { StyledElement as n } from "../internals/StyledElement.js";
|
|
4
4
|
import { styles as r } from "./SidebarSection.styles.js";
|
|
5
5
|
import { html as i } from "lit";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import e from "../_virtual/_@oxc-project_runtime@0.
|
|
2
|
-
import t from "../_virtual/_@oxc-project_runtime@0.
|
|
1
|
+
import e from "../_virtual/_@oxc-project_runtime@0.149.0/helpers/esm/decorateMetadata.js";
|
|
2
|
+
import t from "../_virtual/_@oxc-project_runtime@0.149.0/helpers/esm/decorate.js";
|
|
3
3
|
import { StyledElement as n } from "../internals/StyledElement.js";
|
|
4
4
|
import { getLocaleStrings as r } from "../internals/locale.js";
|
|
5
5
|
import { styles as i } from "./Wizard.styles.js";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import e from "../_virtual/_@oxc-project_runtime@0.
|
|
2
|
-
import t from "../_virtual/_@oxc-project_runtime@0.
|
|
1
|
+
import e from "../_virtual/_@oxc-project_runtime@0.149.0/helpers/esm/decorateMetadata.js";
|
|
2
|
+
import t from "../_virtual/_@oxc-project_runtime@0.149.0/helpers/esm/decorate.js";
|
|
3
3
|
import { property as n } from "lit/decorators.js";
|
|
4
4
|
import { UElement as r } from "@iyulab/components/dist/components/UElement.js";
|
|
5
5
|
//#region src/internals/StyledElement.ts
|
|
@@ -14,6 +14,13 @@ export declare class SidebarLayout extends StyledElement<SidebarParts> {
|
|
|
14
14
|
progressBarEl: UProgressBar;
|
|
15
15
|
/** 현재 라우터 컨텍스트 */
|
|
16
16
|
context: RouteContext | null;
|
|
17
|
+
/**
|
|
18
|
+
* 라우트 컨텐츠의 실제 스크롤 컨테이너(섀도 DOM `[part="main"]`). `scrollTop`을 읽어
|
|
19
|
+
* 위치를 저장하거나, 써서 복원한다 — `part="main"`은 스타일링용 CSS 훅일 뿐 JS 접근
|
|
20
|
+
* 계약이 아니었으므로, 소비자가 이 컨테이너에 안정적으로 접근할 공식 수단으로 신설.
|
|
21
|
+
* 아직 렌더 전이면 `null`.
|
|
22
|
+
*/
|
|
23
|
+
get mainElement(): HTMLElement | null;
|
|
17
24
|
connectedCallback(): void;
|
|
18
25
|
disconnectedCallback(): void;
|
|
19
26
|
protected willUpdate(changedProperties: PropertyValues): void;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { app as e } from "../App.js";
|
|
2
2
|
import { filterSidebarItems as t } from "./filterSidebarItems.js";
|
|
3
|
-
import n from "../_virtual/_@oxc-project_runtime@0.
|
|
4
|
-
import r from "../_virtual/_@oxc-project_runtime@0.
|
|
3
|
+
import n from "../_virtual/_@oxc-project_runtime@0.149.0/helpers/esm/decorateMetadata.js";
|
|
4
|
+
import r from "../_virtual/_@oxc-project_runtime@0.149.0/helpers/esm/decorate.js";
|
|
5
5
|
import { StyledElement as i } from "../internals/StyledElement.js";
|
|
6
6
|
import { getLocaleStrings as a } from "../internals/locale.js";
|
|
7
7
|
import "../components/SidebarSection.js";
|
|
@@ -40,7 +40,9 @@ var v = class extends i {
|
|
|
40
40
|
}, this.handleRouteDone = (e) => {
|
|
41
41
|
this.progressBarEl.value = 100, setTimeout(() => {
|
|
42
42
|
this.progressBarEl.removeAttribute("visible");
|
|
43
|
-
}, 300)
|
|
43
|
+
}, 300);
|
|
44
|
+
let t = this.shadowRoot?.querySelector(".main");
|
|
45
|
+
t && (this.config?.scrollBehavior?.(e.context, t), t.focus({ preventScroll: !0 }));
|
|
44
46
|
}, this.handleRouteError = (e) => {
|
|
45
47
|
this.progressBarEl.status = "error", this.progressBarEl.value = 100, setTimeout(() => {
|
|
46
48
|
this.progressBarEl.removeAttribute("visible"), this.progressBarEl.status = "default";
|
|
@@ -82,6 +84,9 @@ var v = class extends i {
|
|
|
82
84
|
static {
|
|
83
85
|
this.styles = [super.styles, o];
|
|
84
86
|
}
|
|
87
|
+
get mainElement() {
|
|
88
|
+
return this.shadowRoot?.querySelector(".main") ?? null;
|
|
89
|
+
}
|
|
85
90
|
connectedCallback() {
|
|
86
91
|
super.connectedCallback(), window.addEventListener("route-begin", this.handleRouteBegin), window.addEventListener("route-done", this.handleRouteDone), window.addEventListener("route-progress", this.handleRouteProgress), window.addEventListener("route-error", this.handleRouteError), window.addEventListener("screen-resize", this.handleScreenResize);
|
|
87
92
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { TemplateResult } from 'lit';
|
|
2
|
+
import { RouteContext } from '@iyulab/router';
|
|
2
3
|
import { StyleMap } from '../internals/StyledElement';
|
|
3
4
|
import { SidebarLinkConfig } from '../components/SidebarLink';
|
|
4
5
|
import { SidebarSectionConfig } from '../components/SidebarSection';
|
|
@@ -55,6 +56,14 @@ export interface SidebarLayoutConfig {
|
|
|
55
56
|
* 미지정 시 필터링하지 않는다(모든 항목 표시). 보통 `@iyulab/enterprise` 의 `hasPermission` 을 넘긴다.
|
|
56
57
|
*/
|
|
57
58
|
hasPermission?: (code: string) => boolean;
|
|
59
|
+
/**
|
|
60
|
+
* 라우트 전환이 끝날 때(`route-done`, 포커스가 메인 스크롤 컨테이너로 옮겨지기 직전)
|
|
61
|
+
* 호출된다 — 새 라우트의 `RouteContext`와 그 스크롤 컨테이너(`SidebarLayout.mainElement`와
|
|
62
|
+
* 동일 엘리먼트)를 받는다. 스크롤 위치를 리셋·저장·복원하는 로직은 이 훅 안에서 직접
|
|
63
|
+
* 구현한다(예: 목록→상세로 갔다가 돌아올 때 스크롤 위치 복원). 미지정 시 기본값은
|
|
64
|
+
* "아무것도 안 함" — Vue Router의 `scrollBehavior` 미지정 기본값과 동일하다(breaking 아님).
|
|
65
|
+
*/
|
|
66
|
+
scrollBehavior?: (context: RouteContext, main: HTMLElement) => void;
|
|
58
67
|
/** 사이드바 스타일 맵 */
|
|
59
68
|
styles?: StyleMap<SidebarParts>;
|
|
60
69
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@iyulab/modern-app",
|
|
3
3
|
"description": "web-framework by iyulab based on lit-element",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.19.0",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"iyulab",
|
|
7
7
|
"web-framework",
|
|
@@ -60,12 +60,12 @@
|
|
|
60
60
|
"typecheck": "tsc --noEmit"
|
|
61
61
|
},
|
|
62
62
|
"dependencies": {
|
|
63
|
-
"@iyulab/components": "^1.27.0",
|
|
64
63
|
"@iyulab/router": "^0.11.0",
|
|
65
64
|
"i18next": "^26.3.6",
|
|
66
65
|
"lit": "^3.3.3"
|
|
67
66
|
},
|
|
68
67
|
"peerDependencies": {
|
|
68
|
+
"@iyulab/components": ">=1.27.0",
|
|
69
69
|
"@lit/react": ">=1.0.8",
|
|
70
70
|
"react": ">=18.0.0"
|
|
71
71
|
},
|
|
@@ -86,7 +86,7 @@
|
|
|
86
86
|
"happy-dom": "^20.10.6",
|
|
87
87
|
"react": "^19.2.7",
|
|
88
88
|
"react-dom": "^19.2.7",
|
|
89
|
-
"typescript": "^
|
|
89
|
+
"typescript": "^6.0.2",
|
|
90
90
|
"vite": "^8.1.4",
|
|
91
91
|
"vite-plugin-dts": "^5.0.3",
|
|
92
92
|
"vitest": "^4.1.10"
|
|
@@ -269,5 +269,5 @@ interface AuthGateContext {
|
|
|
269
269
|
| `router` | `Router \| undefined` | Underlying `@iyulab/router` instance |
|
|
270
270
|
| `screen` | `ScreenSize \| undefined` | Current responsive screen size |
|
|
271
271
|
| `user` | `unknown` | Authenticated user when the `auth` boot gate is used; `undefined` if unauthenticated or unused |
|
|
272
|
-
| `theme` | `Theme` (static) | Theme utility
|
|
272
|
+
| `theme` | `Theme` (static) | Theme utility — `get()`, `set()`, `resolved()`, `accent()`, `isInitialized`. Branch on `resolved()` (always `'light'` or `'dark'`), not `get()`, which can be `'system'` |
|
|
273
273
|
| `i18n` | `i18next` | Raw i18next instance |
|
|
@@ -35,6 +35,22 @@ each pane. CSS container-query conditions cannot read a runtime custom property,
|
|
|
35
35
|
configurable breakpoint means measuring the host's own width in JavaScript and reflecting an
|
|
36
36
|
`overlay` attribute — same self-width philosophy, different mechanism, for a fixed reason.
|
|
37
37
|
|
|
38
|
+
## Sizing
|
|
39
|
+
|
|
40
|
+
This is a shell, not a sized box: `:host` is `height: 100%`, so **the parent decides its height**.
|
|
41
|
+
Inside a page shell that is already constrained (an `app.load()` layout, a grid or flex row with a
|
|
42
|
+
height) there is nothing to do.
|
|
43
|
+
|
|
44
|
+
Put it in a container with no height of its own and `height: 100%` has nothing to resolve against,
|
|
45
|
+
so the panes fall back to their content's height rather than the available space. That renders
|
|
46
|
+
fine — it simply is not the full-height split pane you asked for, and the independent per-pane
|
|
47
|
+
scrolling (`overflow: auto` on `master` and `detail`) only means something once the height is
|
|
48
|
+
constrained.
|
|
49
|
+
|
|
50
|
+
```css
|
|
51
|
+
.page { height: 100%; } /* or any constrained height on the parent */
|
|
52
|
+
```
|
|
53
|
+
|
|
38
54
|
## Slots
|
|
39
55
|
|
|
40
56
|
| Name | Description |
|
|
@@ -24,6 +24,9 @@ interface SidebarLayoutConfig {
|
|
|
24
24
|
/** Permission filter — hides items (and emptied section/groups) whose requirement fails. Unset shows everything. See "권한 기반 메뉴 필터" below. */
|
|
25
25
|
hasPermission?: (code: string) => boolean;
|
|
26
26
|
|
|
27
|
+
/** Called on `route-done` (before focus moves to the container) with the new route's `RouteContext` and the scroll container itself — implement reset/save/restore here. Unset does nothing (same default as Vue Router's unset `scrollBehavior`). Also reachable outside the hook via the element's `.mainElement` accessor. */
|
|
28
|
+
scrollBehavior?: (context: RouteContext, main: HTMLElement) => void;
|
|
29
|
+
|
|
27
30
|
/** Per-part style overrides (CSS custom properties / inline styles). */
|
|
28
31
|
styles?: StyleMap<SidebarParts>;
|
|
29
32
|
}
|
|
@@ -225,13 +228,19 @@ for `for="#id"` anchoring to resolve (see the `id` note above).
|
|
|
225
228
|
}
|
|
226
229
|
```
|
|
227
230
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
231
|
+
**A fixed `placement` is safe as of `@iyulab/components@1.37.1`.** On `mobile`/`mobile-open`
|
|
232
|
+
the sidebar widens to occupy nearly the full screen, so a sideways placement (`right-start`,
|
|
233
|
+
the natural desktop flyout) has room on neither side. `flip()` now falls back **across the**
|
|
234
|
+
**axis** in exactly that case, landing the popover vertically instead of off-screen.
|
|
235
|
+
|
|
236
|
+
⚠ Against an older `components` it did render off-screen and invisible — `flip()` only ever
|
|
237
|
+
considered the opposite side on the same axis, found no room there either, and gave up. If you
|
|
238
|
+
pin below `1.37.1`, keep choosing `placement` from `state` as the snippet above does.
|
|
239
|
+
|
|
240
|
+
Choosing from `state` is still reasonable when you want to *decide* the direction rather than
|
|
241
|
+
let `flip()` pick it. Either way this is not a `strategy="absolute"` vs `"fixed"` distinction —
|
|
242
|
+
switching strategy changes nothing. Both behaviours are pinned in
|
|
243
|
+
`tests/browser/sidebar-popover-submenu.browser.test.ts`.
|
|
235
244
|
|
|
236
245
|
---
|
|
237
246
|
|
|
@@ -252,6 +261,21 @@ Parts available for `styles` overrides on the root layout:
|
|
|
252
261
|
|
|
253
262
|
---
|
|
254
263
|
|
|
264
|
+
## Sizing
|
|
265
|
+
|
|
266
|
+
`<u-sidebar-layout>` is a shell: `:host` is `height: 100%` with `overflow: hidden`, so **its
|
|
267
|
+
height comes from the parent** — it never sizes itself. `app.load()` covers the default case: when
|
|
268
|
+
`root` is `document.body` it sets `margin: 0; width: 100vw; height: 100vh` on the body for you.
|
|
269
|
+
|
|
270
|
+
⚠ **A custom `root` receives no styling.** Hand it a container with no height of its own and
|
|
271
|
+
`height: 100%` has nothing to resolve against: the shell renders at whatever its own chrome
|
|
272
|
+
resolves to (measured: about 133px) instead of filling the screen — with no error and nothing in
|
|
273
|
+
the console. Give that container a height:
|
|
274
|
+
|
|
275
|
+
```css
|
|
276
|
+
#app { height: 100vh; } /* or 100%, inside an already-constrained ancestor */
|
|
277
|
+
```
|
|
278
|
+
|
|
255
279
|
## Responsive behaviour
|
|
256
280
|
|
|
257
281
|
| Screen width | Sidebar state |
|