@iyulab/modern-app 0.53.0 → 0.54.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/dist/components/ActionBar.d.ts +8 -3
- package/dist/components/ActionBar.js +7 -2
- package/dist/components/ActionBar.styles.js +14 -2
- package/dist/components/InfoField.d.ts +5 -0
- package/dist/components/InfoField.js +2 -1
- package/dist/components/InfoField.styles.js +8 -0
- package/dist/components/InfoSection.d.ts +9 -0
- package/dist/components/InfoSection.js +5 -2
- package/dist/components/InfoSection.styles.js +18 -0
- package/dist/components/SidebarButton.styles.js +5 -4
- package/dist/components/SidebarGroup.styles.js +4 -3
- package/dist/unsaved.d.ts +1 -1
- package/package.json +1 -1
- package/skills/modern-app/SKILL.md +1 -1
- package/skills/modern-app/references/components/action-bar.md +15 -7
- package/skills/modern-app/references/components/info-field.md +2 -0
- package/skills/modern-app/references/components/info-section.md +14 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,37 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.54.0] - 2026-10-14
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- **`u-action-bar` `summary` slot** — what the main action will do («1 change · Order number»). It follows the
|
|
8
|
+
danger actions and fills the free width; below 420px it takes its own line between the main actions (on top) and
|
|
9
|
+
the danger actions. Label-size, weak text.
|
|
10
|
+
- `--action-bar-padding-inline` — inline padding for a bar that runs to a side sheet's edges (default `0`).
|
|
11
|
+
- **`u-info-section layout="strip"` — a stat strip.** The totals of a result as cells on one bordered surface, split
|
|
12
|
+
by 1px dividers: all side by side, or all stacked once the strip is narrower than 640px — never three plus one.
|
|
13
|
+
- `u-info-field` `description` — a supporting line below the value (its basis, or the same amount in another unit).
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
|
|
17
|
+
- The `u-action-bar` skill reference placed the main actions at the leading edge and the danger actions at the
|
|
18
|
+
trailing edge — the reverse of what the bar does. It now describes the actual layout.
|
|
19
|
+
|
|
20
|
+
## [0.53.1] - 2026-10-13
|
|
21
|
+
|
|
22
|
+
### Fixed
|
|
23
|
+
|
|
24
|
+
- **Group headers and sidebar buttons follow the navigation item tokens.** `--app-sidebar-item-gap`,
|
|
25
|
+
`--app-sidebar-item-padding` and `--app-sidebar-item-radius` were read by links only, and `--app-sidebar-icon-size` by
|
|
26
|
+
links and group headers — a theme that set them got three different label starts in one sidebar (links, group
|
|
27
|
+
headers, and footer buttons such as a theme toggle). All three item kinds now read all four. Without the tokens the
|
|
28
|
+
defaults are unchanged.
|
|
29
|
+
|
|
30
|
+
### Documentation
|
|
31
|
+
|
|
32
|
+
- The unsaved-changes examples are complete snippets for Lit and React, and hold `UnsavedChangesController` in a
|
|
33
|
+
`readonly` field (a `private` one is flagged by `noUnusedLocals`).
|
|
34
|
+
|
|
3
35
|
## [0.53.0] - 2026-10-13
|
|
4
36
|
|
|
5
37
|
### Added
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { StyledElement } from '../internals/StyledElement.js';
|
|
2
|
-
type ElementParts = 'host' | 'danger' | 'main';
|
|
2
|
+
type ElementParts = 'host' | 'danger' | 'summary' | 'main';
|
|
3
3
|
/**
|
|
4
4
|
* 푸터 액션 바 — 상세·편집 화면 맨 아래의 같은 골격.
|
|
5
5
|
*
|
|
@@ -17,10 +17,13 @@ type ElementParts = 'host' | 'danger' | 'main';
|
|
|
17
17
|
* ```
|
|
18
18
|
*
|
|
19
19
|
* 배치 규칙: **위험 액션은 왼쪽 끝, 주 액션은 오른쪽 끝** — 거리가 안전장치다.
|
|
20
|
-
* 좁아지면
|
|
20
|
+
* 좁아지면 무리마다 한 줄을 갖고 **주 액션이 위로** 온다(엄지 위치에 위험 액션을
|
|
21
21
|
* 두지 않기 위해서다).
|
|
22
22
|
*
|
|
23
|
-
*
|
|
23
|
+
* `summary` 슬롯은 주 액션이 무엇을 할지 말하는 글이다(«변경 1건 · 주문 번호») — 위험 액션 뒤에서
|
|
24
|
+
* 남는 폭을 채운다. 시트 가장자리에 붙는 바닥이면 `--action-bar-padding-inline` 으로 안쪽 여백을 준다.
|
|
25
|
+
*
|
|
26
|
+
* 오버라이드: `part`(host·danger·summary·main) + slot 치환.
|
|
24
27
|
*/
|
|
25
28
|
export declare class ActionBar extends StyledElement<ElementParts> {
|
|
26
29
|
static styles: import('lit').CSSResultGroup[];
|
|
@@ -35,6 +38,8 @@ export declare class ActionBar extends StyledElement<ElementParts> {
|
|
|
35
38
|
* (`internals/slotted.ts` 참조). 빈 래퍼가 남으면 주 액션이 가운데로 밀린다.
|
|
36
39
|
*/
|
|
37
40
|
private hasDanger;
|
|
41
|
+
/** 요약 슬롯 배정 상태 — 비면 래퍼를 접는다(위와 같은 이유). */
|
|
42
|
+
private hasSummary;
|
|
38
43
|
render(): import('lit-html').TemplateResult<1>;
|
|
39
44
|
}
|
|
40
45
|
declare global {
|
|
@@ -8,7 +8,7 @@ import { customElement as o, property as s, state as c } from "lit/decorators.js
|
|
|
8
8
|
//#region src/components/ActionBar.ts
|
|
9
9
|
var l = class extends n {
|
|
10
10
|
constructor(...e) {
|
|
11
|
-
super(...e), this.sticky = !1, this.hasDanger = !1;
|
|
11
|
+
super(...e), this.sticky = !1, this.hasDanger = !1, this.hasSummary = !1;
|
|
12
12
|
}
|
|
13
13
|
static {
|
|
14
14
|
this.styles = [super.styles, i];
|
|
@@ -20,6 +20,11 @@ var l = class extends n {
|
|
|
20
20
|
@slotchange=${(e) => this.hasDanger = r(e.target)}
|
|
21
21
|
></slot>
|
|
22
22
|
</div>
|
|
23
|
+
<div class="summary ${this.hasSummary ? "" : "empty"}" part="summary">
|
|
24
|
+
<slot name="summary"
|
|
25
|
+
@slotchange=${(e) => this.hasSummary = r(e.target)}
|
|
26
|
+
></slot>
|
|
27
|
+
</div>
|
|
23
28
|
<div class="main" part="main"><slot></slot></div>
|
|
24
29
|
`;
|
|
25
30
|
}
|
|
@@ -27,6 +32,6 @@ var l = class extends n {
|
|
|
27
32
|
t([s({
|
|
28
33
|
type: Boolean,
|
|
29
34
|
reflect: !0
|
|
30
|
-
}), e("design:type", Object)], l.prototype, "sticky", void 0), t([c(), e("design:type", Object)], l.prototype, "hasDanger", void 0), l = t([o("u-action-bar")], l);
|
|
35
|
+
}), e("design:type", Object)], l.prototype, "sticky", void 0), t([c(), e("design:type", Object)], l.prototype, "hasDanger", void 0), t([c(), e("design:type", Object)], l.prototype, "hasSummary", void 0), l = t([o("u-action-bar")], l);
|
|
31
36
|
//#endregion
|
|
32
37
|
export { l as ActionBar };
|
|
@@ -5,7 +5,7 @@ var t = e`
|
|
|
5
5
|
display: flex;
|
|
6
6
|
align-items: center;
|
|
7
7
|
gap: var(--u-space-sm, 8px);
|
|
8
|
-
padding: var(--u-space-md, 12px) 0;
|
|
8
|
+
padding: var(--u-space-md, 12px) var(--action-bar-padding-inline, 0);
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
|
|
@@ -36,6 +36,18 @@ var t = e`
|
|
|
36
36
|
display: none;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
.summary {
|
|
42
|
+
flex: 1 1 calc((420px - 100%) * 999);
|
|
43
|
+
min-width: 0;
|
|
44
|
+
font-size: var(--u-text-label-size, 13px);
|
|
45
|
+
color: var(--u-txt-color-weak, #616161);
|
|
46
|
+
}
|
|
47
|
+
.summary.empty {
|
|
48
|
+
display: none;
|
|
49
|
+
}
|
|
50
|
+
|
|
39
51
|
.main {
|
|
40
52
|
display: flex;
|
|
41
53
|
align-items: center;
|
|
@@ -56,7 +68,7 @@ var t = e`
|
|
|
56
68
|
bottom: 0;
|
|
57
69
|
background-color: var(--u-bg-color, #FFFFFF);
|
|
58
70
|
border-top: 1px solid var(--u-border-color-weak, #EEEEEE);
|
|
59
|
-
padding: var(--u-space-md, 12px) 0;
|
|
71
|
+
padding: var(--u-space-md, 12px) var(--action-bar-padding-inline, 0);
|
|
60
72
|
}
|
|
61
73
|
`;
|
|
62
74
|
//#endregion
|
|
@@ -97,6 +97,11 @@ export declare class InfoField extends StyledElement<ElementParts> {
|
|
|
97
97
|
* `--u-success|danger|warning-color-strong`.
|
|
98
98
|
*/
|
|
99
99
|
tone?: InfoFieldTone;
|
|
100
|
+
/**
|
|
101
|
+
* 값 아래의 보조 줄 — 그 값의 근거나 다른 단위의 같은 양(«1,764,211 units» · «Settled ₩743,188,120»).
|
|
102
|
+
* 추세 문구는 `trendLabel` 이다(방향과 색을 갖는다).
|
|
103
|
+
*/
|
|
104
|
+
description?: string;
|
|
100
105
|
/** 라벨을 이름으로 준 슬롯 위젯과 그때의 라벨 — 소비자가 바꾼 이름은 우리 것이 아니다. */
|
|
101
106
|
private readonly namedWidgets;
|
|
102
107
|
/**
|
|
@@ -48,12 +48,13 @@ var f = class extends n {
|
|
|
48
48
|
${a ? i`<span aria-hidden="true">${a}</span> ` : ""}${this.trendLabel ?? ""}
|
|
49
49
|
</div>
|
|
50
50
|
` : ""}
|
|
51
|
+
${this.description ? i`<div class="description" part="description">${this.description}</div>` : ""}
|
|
51
52
|
`;
|
|
52
53
|
}
|
|
53
54
|
};
|
|
54
55
|
t([o({ type: String }), e("design:type", Object)], f.prototype, "label", void 0), t([o({ type: String }), e("design:type", Object)], f.prototype, "value", void 0), t([o({ type: String }), e("design:type", Object)], f.prototype, "blank", void 0), t([o({ type: Boolean }), e("design:type", Object)], f.prototype, "numeric", void 0), t([o({ type: String }), e("design:type", Object)], f.prototype, "format", void 0), t([o({ type: String }), e("design:type", String)], f.prototype, "currency", void 0), t([o({ type: String }), e("design:type", String)], f.prototype, "unit", void 0), t([o({
|
|
55
56
|
type: String,
|
|
56
57
|
reflect: !0
|
|
57
|
-
}), e("design:type", Object)], f.prototype, "size", void 0), t([o({ type: String }), e("design:type", Object)], f.prototype, "trend", void 0), t([o({ type: String }), e("design:type", String)], f.prototype, "trendLabel", void 0), t([o({ type: String }), e("design:type", Object)], f.prototype, "tone", void 0), f = t([a("u-info-field")], f);
|
|
58
|
+
}), e("design:type", Object)], f.prototype, "size", void 0), t([o({ type: String }), e("design:type", Object)], f.prototype, "trend", void 0), t([o({ type: String }), e("design:type", String)], f.prototype, "trendLabel", void 0), t([o({ type: String }), e("design:type", Object)], f.prototype, "tone", void 0), t([o({ type: String }), e("design:type", String)], f.prototype, "description", void 0), f = t([a("u-info-field")], f);
|
|
58
59
|
//#endregion
|
|
59
60
|
export { f as InfoField, d as isBlank };
|
|
@@ -82,6 +82,14 @@ var t = e`
|
|
|
82
82
|
margin-top: var(--u-space-3xs, 2px);
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
+
|
|
86
|
+
.description {
|
|
87
|
+
font-size: var(--u-text-caption-size, 12px);
|
|
88
|
+
line-height: var(--u-text-caption-leading, 1.5);
|
|
89
|
+
color: var(--u-txt-color-weaker, #757575);
|
|
90
|
+
margin-top: var(--u-space-3xs, 2px);
|
|
91
|
+
}
|
|
92
|
+
|
|
85
93
|
.trend.tone-positive {
|
|
86
94
|
color: var(--u-success-color-strong, #1B5E20);
|
|
87
95
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { StyledElement } from '../internals/StyledElement.js';
|
|
2
2
|
type ElementParts = 'host' | 'grid';
|
|
3
|
+
/** 배치 — `grid` 라벨-값 칸의 반응형 그리드 · `strip` 지표 띠(구분선으로 나뉜 한 면의 칸). */
|
|
4
|
+
export type InfoSectionLayout = 'grid' | 'strip';
|
|
3
5
|
/**
|
|
4
6
|
* 정보 섹션 — `u-info-field` 들의 반응형 그리드.
|
|
5
7
|
*
|
|
@@ -16,11 +18,18 @@ type ElementParts = 'host' | 'grid';
|
|
|
16
18
|
* ```
|
|
17
19
|
*
|
|
18
20
|
* `min` 으로 한 칸의 최소 폭을 조절한다(기본 160px). 라벨이 긴 도메인은 값을 올린다.
|
|
21
|
+
*
|
|
22
|
+
* `layout="strip"` 은 지표 띠다 — 결과의 합계를 문장이 아니라 칸으로(목록 위 «주문 962 · 청구 ₩…»).
|
|
23
|
+
* 한 면 위에 1px 구분선으로 나뉜 칸들이 **전부 나란히, 아니면 전부 쌓인다**(띠 폭 640px 미만 — 들쭉날쭉한 줄을
|
|
24
|
+
* 만들지 않는다). 임계는 크기 containment 가 아니라 칸의 flex-basis 가 건다(«Holy Albatross» — u-action-bar 와 같은
|
|
25
|
+
* 근거). 구분선은 칸 사이 1px 간격으로 비치는 면의 테두리 색이라 가로·세로가 저절로 바뀐다. 이 배치에서 `min` 은 쓰지 않는다.
|
|
19
26
|
*/
|
|
20
27
|
export declare class InfoSection extends StyledElement<ElementParts> {
|
|
21
28
|
static styles: import('lit').CSSResultGroup[];
|
|
22
29
|
/** 한 칸의 최소 폭(px). 이 값보다 좁아지면 열 수가 줄어든다. */
|
|
23
30
|
min: number;
|
|
31
|
+
/** 배치 — `grid`(기본) · `strip`(지표 띠). */
|
|
32
|
+
layout: InfoSectionLayout;
|
|
24
33
|
render(): import('lit-html').TemplateResult<1>;
|
|
25
34
|
}
|
|
26
35
|
declare global {
|
|
@@ -7,7 +7,7 @@ import { customElement as a, property as o } from "lit/decorators.js";
|
|
|
7
7
|
//#region src/components/InfoSection.ts
|
|
8
8
|
var s = class extends n {
|
|
9
9
|
constructor(...e) {
|
|
10
|
-
super(...e), this.min = 160;
|
|
10
|
+
super(...e), this.min = 160, this.layout = "grid";
|
|
11
11
|
}
|
|
12
12
|
static {
|
|
13
13
|
this.styles = [super.styles, r];
|
|
@@ -18,6 +18,9 @@ var s = class extends n {
|
|
|
18
18
|
`;
|
|
19
19
|
}
|
|
20
20
|
};
|
|
21
|
-
t([o({ type: Number }), e("design:type", Object)], s.prototype, "min", void 0),
|
|
21
|
+
t([o({ type: Number }), e("design:type", Object)], s.prototype, "min", void 0), t([o({
|
|
22
|
+
type: String,
|
|
23
|
+
reflect: !0
|
|
24
|
+
}), e("design:type", Object)], s.prototype, "layout", void 0), s = t([a("u-info-section")], s);
|
|
22
25
|
//#endregion
|
|
23
26
|
export { s as InfoSection };
|
|
@@ -13,6 +13,24 @@ var t = e`
|
|
|
13
13
|
grid-template-columns: repeat(auto-fit, minmax(var(--info-min, 160px), 1fr));
|
|
14
14
|
gap: var(--u-space-lg, 16px) var(--u-space-xl, 20px);
|
|
15
15
|
}
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
:host([layout="strip"]) .grid {
|
|
20
|
+
display: flex;
|
|
21
|
+
flex-wrap: wrap;
|
|
22
|
+
gap: 1px;
|
|
23
|
+
background: var(--u-border-color, #E0E0E0);
|
|
24
|
+
border: 1px solid var(--u-border-color, #E0E0E0);
|
|
25
|
+
border-radius: var(--u-radius-xl, 8px);
|
|
26
|
+
overflow: hidden;
|
|
27
|
+
}
|
|
28
|
+
:host([layout="strip"]) ::slotted(*) {
|
|
29
|
+
flex: 1 1 calc((640px - 100%) * 999);
|
|
30
|
+
min-width: 0;
|
|
31
|
+
padding: var(--u-space-md, 12px) var(--u-space-lg, 16px);
|
|
32
|
+
background: var(--u-bg-color, #FFFFFF);
|
|
33
|
+
}
|
|
16
34
|
`;
|
|
17
35
|
//#endregion
|
|
18
36
|
export { t as styles };
|
|
@@ -7,7 +7,7 @@ var t = e`
|
|
|
7
7
|
color: var(--app-sidebar-fg, var(--u-txt-color, #212121));
|
|
8
8
|
background-color: transparent;
|
|
9
9
|
border: none;
|
|
10
|
-
border-radius: 8px;
|
|
10
|
+
border-radius: var(--app-sidebar-item-radius, 8px);
|
|
11
11
|
transition: all var(--u-duration-normal, 220ms) ease;
|
|
12
12
|
cursor: pointer;
|
|
13
13
|
}
|
|
@@ -34,8 +34,9 @@ var t = e`
|
|
|
34
34
|
flex-direction: row;
|
|
35
35
|
align-items: center;
|
|
36
36
|
justify-content: flex-start;
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
|
|
38
|
+
gap: var(--app-sidebar-item-gap, 12px);
|
|
39
|
+
padding: var(--app-sidebar-item-padding, 8px 12px);
|
|
39
40
|
|
|
40
41
|
min-height: var(--u-target-size, 0px);
|
|
41
42
|
}
|
|
@@ -52,7 +53,7 @@ var t = e`
|
|
|
52
53
|
u-icon {
|
|
53
54
|
flex-shrink: 0;
|
|
54
55
|
color: inherit;
|
|
55
|
-
font-size: 20px;
|
|
56
|
+
font-size: var(--app-sidebar-icon-size, 20px);
|
|
56
57
|
}
|
|
57
58
|
|
|
58
59
|
|
|
@@ -17,13 +17,14 @@ var t = e`
|
|
|
17
17
|
flex-direction: row;
|
|
18
18
|
align-items: center;
|
|
19
19
|
justify-content: space-between;
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
|
|
21
|
+
gap: var(--app-sidebar-item-gap, 12px);
|
|
22
|
+
padding: var(--app-sidebar-item-padding, 8px 12px);
|
|
22
23
|
|
|
23
24
|
min-height: var(--u-target-size, 0px);
|
|
24
25
|
background-color: transparent;
|
|
25
26
|
border: none;
|
|
26
|
-
border-radius: 8px;
|
|
27
|
+
border-radius: var(--app-sidebar-item-radius, 8px);
|
|
27
28
|
transition: all var(--u-duration-normal, 220ms) ease;
|
|
28
29
|
cursor: pointer;
|
|
29
30
|
}
|
package/dist/unsaved.d.ts
CHANGED
|
@@ -36,7 +36,7 @@ export declare function unsavedChangesGuard(_ctx?: RouteLeaveContext): boolean |
|
|
|
36
36
|
* @example
|
|
37
37
|
* ```ts
|
|
38
38
|
* class OrderPage extends LitElement {
|
|
39
|
-
*
|
|
39
|
+
* readonly unsaved = new UnsavedChangesController(this, () => this.form.dirty);
|
|
40
40
|
* }
|
|
41
41
|
* ```
|
|
42
42
|
*/
|
package/package.json
CHANGED
|
@@ -244,7 +244,7 @@ Back/Forward included) and the browser asks before the document is left (`before
|
|
|
244
244
|
```ts
|
|
245
245
|
import { UnsavedChangesController, confirmDiscardChanges } from '@iyulab/modern-app';
|
|
246
246
|
// Lit
|
|
247
|
-
|
|
247
|
+
readonly unsaved = new UnsavedChangesController(this, () => this.form.dirty);
|
|
248
248
|
// React: useUnsavedChanges(dirty) from '@iyulab/modern-app/react'
|
|
249
249
|
// Plain: const release = trackUnsavedChanges(() => dirty);
|
|
250
250
|
// A modal drawer's close is not a navigation — ask from its cancellable `hide` event:
|
|
@@ -2,23 +2,29 @@
|
|
|
2
2
|
|
|
3
3
|
**Tag:** `u-action-bar`
|
|
4
4
|
|
|
5
|
-
The row of actions that closes a form or a detail screen:
|
|
6
|
-
|
|
5
|
+
The row of actions that closes a form or a detail screen: destructive actions at the leading edge, the main
|
|
6
|
+
actions at the trailing edge — the distance between them is the safeguard. Below 420px each group takes its own
|
|
7
|
+
line with the main actions on top, so a destructive action never sits under the thumb.
|
|
7
8
|
|
|
8
9
|
```html
|
|
9
10
|
<u-action-bar sticky>
|
|
10
|
-
<u-button appearance="
|
|
11
|
+
<u-button slot="danger" color="danger" appearance="plain">Delete</u-button>
|
|
12
|
+
<span slot="summary">1 change · Order number</span>
|
|
11
13
|
<u-button appearance="outlined">Cancel</u-button>
|
|
12
|
-
<u-button
|
|
14
|
+
<u-button>Save</u-button>
|
|
13
15
|
</u-action-bar>
|
|
14
16
|
```
|
|
15
17
|
|
|
18
|
+
A side sheet's footer runs to the sheet's edges — give it the sheet's inset with `--action-bar-padding-inline`
|
|
19
|
+
rather than negative margins (the bar cannot know its parent's padding).
|
|
20
|
+
|
|
16
21
|
## Slots
|
|
17
22
|
|
|
18
23
|
| Name | Description |
|
|
19
24
|
|------|-------------|
|
|
20
|
-
| *(default)* |
|
|
21
|
-
| `danger` | Destructive actions,
|
|
25
|
+
| *(default)* | Main actions, at the trailing edge |
|
|
26
|
+
| `danger` | Destructive actions, at the leading edge |
|
|
27
|
+
| `summary` | What the main action will do — «1 change · Order number». Follows the danger actions and fills the free width |
|
|
22
28
|
|
|
23
29
|
## Properties
|
|
24
30
|
|
|
@@ -30,8 +36,9 @@ destructive ones separated on the trailing edge.
|
|
|
30
36
|
|
|
31
37
|
| Part | Description |
|
|
32
38
|
|------|-------------|
|
|
33
|
-
| `main` |
|
|
39
|
+
| `main` | Main action group |
|
|
34
40
|
| `danger` | Destructive action group |
|
|
41
|
+
| `summary` | Summary text wrapper |
|
|
35
42
|
|
|
36
43
|
## CSS Custom Properties
|
|
37
44
|
|
|
@@ -41,6 +48,7 @@ destructive ones separated on the trailing edge.
|
|
|
41
48
|
| `--u-border-color-weak` | Top border when `sticky` |
|
|
42
49
|
| `--u-space-sm` | Gap between actions within a group |
|
|
43
50
|
| `--u-space-md` | Host and sticky-mode vertical padding |
|
|
51
|
+
| `--action-bar-padding-inline` | Inline padding (default `0`) — the sheet inset for a footer that runs edge to edge |
|
|
44
52
|
|
|
45
53
|
⚠ `sticky` adds **vertical** padding only. It deliberately does not stretch to the container
|
|
46
54
|
edges with negative margins — that would assume the parent has exactly that much horizontal
|
|
@@ -40,6 +40,7 @@ and those are different states of the business. So the component owns the rule.
|
|
|
40
40
|
| `size` | `'default'\|'lg'` | `'default'` | ✓ | `'lg'` renders the value at the `title` type-scale step — for dashboard KPI tiles composed inside `u-info-section` |
|
|
41
41
|
| `trend` | `'up'\|'down'\|'flat'` | — | | Trend direction; renders a trend indicator when set, alongside `trendLabel`; pair with trendLabel for an accessible name — trend alone conveys direction by color only |
|
|
42
42
|
| `trendLabel` | `string` | — | | Trend copy, e.g. `"+12% vs last month"` — wording is the consumer's responsibility |
|
|
43
|
+
| `description` | `string` | — | | A supporting line below the value — its basis, or the same amount in another unit (`"1,764,211 units"`). Trend copy belongs in `trendLabel` |
|
|
43
44
|
| `tone` | `'positive'\|'negative'\|'warning'\|'neutral'` | — | | Explicit tone override; resolves from `trend` when unset (`up→positive`, `down→negative`, `flat`/unset→`neutral`) but always wins over inference. Colors the value text itself, independent of `trend` — a static figure (e.g. a balance due) can be toned `negative` with no trend arrow. `warning` means "needs attention, not wrong" (a deadline coming up, a rate under target but within limits) and is never inferred |
|
|
44
45
|
|
|
45
46
|
⚠ `numeric` no longer right-aligns (it did before 0.25.0). A field is a label/value pair that owns
|
|
@@ -83,6 +84,7 @@ as well once it exists.
|
|
|
83
84
|
|------|-------------|
|
|
84
85
|
| `label` · `value` · `trend` | The label, the value, and the (optional) trend indicator |
|
|
85
86
|
| `unit` | The unit, inside `value` (only when `unit` is set and the value is not blank) |
|
|
87
|
+
| `description` | The supporting line (only when `description` is set) |
|
|
86
88
|
|
|
87
89
|
## CSS Custom Properties
|
|
88
90
|
|
|
@@ -16,6 +16,16 @@ markup works inside a side panel.
|
|
|
16
16
|
</u-info-section>
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
+
A stat strip — the totals above a list, as cells rather than a sentence:
|
|
20
|
+
|
|
21
|
+
```html
|
|
22
|
+
<u-info-section layout="strip">
|
|
23
|
+
<u-info-field label="Orders" value="962" unit="orders" description="1,764,211 units" size="lg"></u-info-field>
|
|
24
|
+
<u-info-field label="Due in 7 days" value="14" tone="warning" description="3 not started" size="lg"></u-info-field>
|
|
25
|
+
<u-info-field label="Overdue" value="₩0" tone="negative" description="0 orders" size="lg"></u-info-field>
|
|
26
|
+
</u-info-section>
|
|
27
|
+
```
|
|
28
|
+
|
|
19
29
|
## Slots
|
|
20
30
|
|
|
21
31
|
| Name | Description |
|
|
@@ -26,7 +36,8 @@ markup works inside a side panel.
|
|
|
26
36
|
|
|
27
37
|
| Property | Type | Default | Reflect | Description |
|
|
28
38
|
|----------|------|---------|---------|-------------|
|
|
29
|
-
| `min` | `number` | `160` | | Minimum column width in px. Raise it for domains with long labels |
|
|
39
|
+
| `min` | `number` | `160` | | Minimum column width in px. Raise it for domains with long labels. Not used by `layout="strip"` |
|
|
40
|
+
| `layout` | `'grid'\|'strip'` | `'grid'` | ✓ | `grid` — label-value cells in a responsive grid · `strip` — a stat strip: cells on one bordered surface split by 1px dividers, all side by side or all stacked once the strip is narrower than 640px (never a ragged row) |
|
|
30
41
|
|
|
31
42
|
## CSS Parts
|
|
32
43
|
|
|
@@ -39,6 +50,8 @@ markup works inside a side panel.
|
|
|
39
50
|
| Property | Description |
|
|
40
51
|
|----------|-------------|
|
|
41
52
|
| `--u-space-lg` / `--u-space-xl` | Grid gap (row / column) |
|
|
53
|
+
| `--u-border-color` · `--u-radius-xl` · `--u-bg-color` | Strip surface, dividers and corner; cell background |
|
|
54
|
+
| `--u-space-md` / `--u-space-lg` | Strip cell padding (block / inline) |
|
|
42
55
|
|
|
43
56
|
⚠ Column width is set via the `min` property, not a custom property — it's applied as an inline
|
|
44
57
|
style per instance, so a `--info-min` override in a stylesheet would lose to it.
|