@iyulab/modern-app 0.41.0 → 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,22 @@
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
+
13
+ ## [0.41.1] - 2026-10-07
14
+
15
+ ### Documentation
16
+
17
+ - The `level` row of the `u-group-box` reference had unescaped `|` in its type cell, which split the row into extra
18
+ columns and put a stale `3` in the default column — the level is derived when unset.
19
+
3
20
  ## [0.41.0] - 2026-10-07
4
21
 
5
22
  ### Changed
@@ -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
@@ -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.41.0",
4
+ "version": "0.42.0",
5
5
  "keywords": [
6
6
  "iyulab",
7
7
  "web-framework",
@@ -34,7 +34,7 @@ a left edge without any consumer CSS.
34
34
  | `description` | `string` | — | | One line under the title — what the box holds or what its numbers are based on. Caption size, weak color. Opens the header on its own |
35
35
  | `divider` | `boolean` | `false` | | Rule between header and body. Off by default — many rules make a screen noisy |
36
36
  | `flush` | `boolean` | `false` | | Remove body padding, for tables and lists that draw their own edges |
37
- | `level` | `2|3|4|5|6` | derived | ✓ | Heading level of the title in the document outline. Unset: `2` for a box in no other `u-group-box` (directly under `u-page-header`, the page's `h1`), one deeper than the nearest enclosing box otherwise. Set it when the box sits under a heading of your own. Semantics only — the title looks the same at every level |
37
+ | `level` | `2\|3\|4\|5\|6` | — | ✓ | Heading level of the title in the document outline. Unset: `2` for a box in no other `u-group-box` (directly under `u-page-header`, the page's `h1`), one deeper than the nearest enclosing box otherwise. Set it when the box sits under a heading of your own. Semantics only — the title looks the same at every level |
38
38
 
39
39
  ## CSS Parts
40
40
 
@@ -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