@iyulab/modern-app 0.41.1 → 0.42.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,15 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.42.0] - 2026-10-07
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- **`u-info-field` names the widget it labels** — an unnamed progress bar or meter in its slot (`u-progress-bar`,
|
|
8
|
+
`u-progress-ring`, native `<progress>`/`<meter>`) takes `label` as its accessible name and follows it when it
|
|
9
|
+
changes. The label sat next to the widget on screen with nothing tying them together, so a "Completion" field
|
|
10
|
+
held an unnamed progressbar (axe `aria-progressbar-name`, WCAG 1.3.1). A widget with its own name — including the
|
|
11
|
+
spinner's default — keeps it; text values are unchanged (they are read right after the label).
|
|
12
|
+
|
|
3
13
|
## [0.41.1] - 2026-10-07
|
|
4
14
|
|
|
5
15
|
### Documentation
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { PropertyValues } from 'lit';
|
|
1
2
|
import { StyledElement } from '../internals/StyledElement.js';
|
|
2
3
|
type ElementParts = 'host' | 'label' | 'value' | 'unit' | 'trend';
|
|
3
4
|
export type InfoFieldFormat = 'number' | 'currency' | 'date';
|
|
@@ -96,6 +97,17 @@ export declare class InfoField extends StyledElement<ElementParts> {
|
|
|
96
97
|
* `--u-success|danger|warning-color-strong`.
|
|
97
98
|
*/
|
|
98
99
|
tone?: InfoFieldTone;
|
|
100
|
+
/** 라벨을 이름으로 준 슬롯 위젯과 그때의 라벨 — 소비자가 바꾼 이름은 우리 것이 아니다. */
|
|
101
|
+
private readonly namedWidgets;
|
|
102
|
+
/**
|
|
103
|
+
* 슬롯에 든 **이름 없는** 진행 막대·계량기(`progressbar`·`meter`, 네이티브 `<progress>`·`<meter>`)에 라벨을 이름으로 준다.
|
|
104
|
+
*
|
|
105
|
+
* 글자 값은 읽는 순서로 라벨 바로 뒤에 들리지만, 이 역할들은 자기 이름이 없으면 «이름 없는 위젯» 이다(axe
|
|
106
|
+
* `aria-progressbar-name` · WCAG 1.3.1 — 화면에서 짝지은 관계는 프로그램으로도 이어져야 한다). 이미 이름을 가진
|
|
107
|
+
* 위젯(`aria-label`·`aria-labelledby` — 스피너의 기본 이름 포함)은 건드리지 않는다.
|
|
108
|
+
*/
|
|
109
|
+
private nameSlottedWidgets;
|
|
110
|
+
protected updated(changed: PropertyValues): void;
|
|
99
111
|
private get hasSlotted();
|
|
100
112
|
private formatValue;
|
|
101
113
|
render(): import('lit-html').TemplateResult<1>;
|
|
@@ -14,11 +14,28 @@ function d(e) {
|
|
|
14
14
|
}
|
|
15
15
|
var f = class extends n {
|
|
16
16
|
constructor(...e) {
|
|
17
|
-
super(...e), this.label = "", this.blank = "—", this.numeric = !1, this.size = "default";
|
|
17
|
+
super(...e), this.label = "", this.blank = "—", this.numeric = !1, this.size = "default", this.namedWidgets = /* @__PURE__ */ new WeakMap();
|
|
18
18
|
}
|
|
19
19
|
static {
|
|
20
20
|
this.styles = [super.styles, r];
|
|
21
21
|
}
|
|
22
|
+
async nameSlottedWidgets() {
|
|
23
|
+
let e = this.shadowRoot?.querySelector("slot");
|
|
24
|
+
if (e) for (let t of e.assignedElements({ flatten: !0 })) {
|
|
25
|
+
await t.updateComplete;
|
|
26
|
+
let e = t.getAttribute("role") ?? (t.localName === "progress" ? "progressbar" : t.localName === "meter" ? "meter" : null);
|
|
27
|
+
if (e !== "progressbar" && e !== "meter") continue;
|
|
28
|
+
let n = this.namedWidgets.get(t), r = t.getAttribute("aria-label");
|
|
29
|
+
if (t.hasAttribute("aria-labelledby") || r !== null && r !== n) {
|
|
30
|
+
this.namedWidgets.delete(t);
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
this.label ? (t.setAttribute("aria-label", this.label), this.namedWidgets.set(t, this.label)) : n !== void 0 && (t.removeAttribute("aria-label"), this.namedWidgets.delete(t));
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
updated(e) {
|
|
37
|
+
super.updated(e), e.has("label") && this.nameSlottedWidgets();
|
|
38
|
+
}
|
|
22
39
|
get hasSlotted() {
|
|
23
40
|
return this.childNodes.length > 0 && [...this.childNodes].some((e) => e.nodeType !== Node.TEXT_NODE || (e.textContent ?? "").trim() !== "");
|
|
24
41
|
}
|
|
@@ -29,7 +46,7 @@ var f = class extends n {
|
|
|
29
46
|
let e = !this.hasSlotted && d(this.value), t = this.numeric || this.format === "number" || this.format === "currency", n = this.trend !== void 0 || this.trendLabel !== void 0, r = this.tone ?? u(this.trend), a = this.trend === "up" ? "▲" : this.trend === "down" ? "▼" : "", o = !e && this.unit ? i`<span class="unit" part="unit">${this.unit}</span>` : "";
|
|
30
47
|
return i`
|
|
31
48
|
<div class="label" part="label">${this.label}</div>
|
|
32
|
-
<div class="value ${t ? "numeric" : ""} ${e ? "blank" : ""} tone-${r}" part="value">${this.hasSlotted ? i`<slot></slot>` : e ? this.blank : this.formatValue()}${o}</div>
|
|
49
|
+
<div class="value ${t ? "numeric" : ""} ${e ? "blank" : ""} tone-${r}" part="value">${this.hasSlotted ? i`<slot @slotchange=${() => void this.nameSlottedWidgets()}></slot>` : e ? this.blank : this.formatValue()}${o}</div>
|
|
33
50
|
${n ? i`
|
|
34
51
|
<div class="trend tone-${r}" part="trend">
|
|
35
52
|
${a ? i`<span aria-hidden="true">${a}</span> ` : ""}${this.trendLabel ?? ""}
|
package/package.json
CHANGED
|
@@ -24,7 +24,7 @@ and those are different states of the business. So the component owns the rule.
|
|
|
24
24
|
|
|
25
25
|
| Name | Description |
|
|
26
26
|
|------|-------------|
|
|
27
|
-
| *(default)* | Value content; takes precedence over `value` |
|
|
27
|
+
| *(default)* | Value content; takes precedence over `value`. An unnamed progress bar or meter here (`u-progress-bar`, `u-progress-ring`, `<progress>`, `<meter>`) is named by `label`; one that has its own `aria-label`/`aria-labelledby` keeps it |
|
|
28
28
|
|
|
29
29
|
## Properties
|
|
30
30
|
|