@iyulab/modern-app 0.26.0 → 0.27.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.27.0] - 2026-09-24
4
+
5
+ ### Added
6
+
7
+ - **`u-group-box[meta]` — secondary text beside the title.** List-like sections of a detail screen
8
+ almost always carry a count (`3 items`, `2/5 done`), and with `title` being a plain string the
9
+ count was drawn at the title's size, weight and color, so the section name and its current
10
+ state read as one heading. `meta` draws that text one step below the title — body size and
11
+ weight, weak color, tabular figures — on the same baseline. It sits inside the heading, so the
12
+ heading's accessible name includes it. It is not drawn without a `title`. New `meta` part.
13
+ - **Korean built-in strings.** 0.26.0 moved the language choice to `Locale.set()`, but the namespace
14
+ held only an English table, so an app that already called `Locale.set('ko')` still got the
15
+ sidebar toggle's and overlay close button's accessible names, the back link, empty-state copy and
16
+ wizard labels in English. A Korean table now ships alongside English — the same scope as
17
+ `@iyulab/flex-table`. English stays the default; a Korean registration of your own overrides only
18
+ the keys it gives.
19
+
3
20
  ## [0.26.0] - 2026-09-23
4
21
 
5
22
  ### Changed
package/README.md CHANGED
@@ -121,23 +121,26 @@ html`<p>${translate('common::greeting')}</p>`;
121
121
  ### Built-in strings
122
122
 
123
123
  The package's own strings — the page header's back link, empty-state copy, the shell's toggle and
124
- close labels, the wizard's buttons and step announcement — are English by default and live in the
125
- `modern-app` namespace of `@iyulab/components`' `Locale`. Register translations there and pick the
126
- language once, with `Locale.set()`; the primitives and `@iyulab/flex-table` follow the same call:
124
+ close labels, the wizard's buttons and step announcement — live in the `modern-app` namespace of
125
+ `@iyulab/components`' `Locale`. English and Korean are built in, English being the default; pick the
126
+ language once, with `Locale.set()` — the primitives and `@iyulab/flex-table` follow the same call.
127
+ Register other languages, or your own wording, in the same namespace:
127
128
 
128
129
  ```typescript
129
130
  import { Locale } from '@iyulab/components';
130
131
  import { modernAppLocale } from '@iyulab/modern-app';
131
132
 
132
- modernAppLocale.register('ko', {
133
- back: '뒤로',
134
- toggleSidebar: '사이드바 접기/펼치기',
135
- wizardStepAnnouncement: '{total}단계 중 {index}단계: {label}',
133
+ Locale.set('ko'); // built-in Korean — nothing to register
134
+
135
+ modernAppLocale.register('ja', {
136
+ back: '戻る',
137
+ toggleSidebar: 'サイドバーの切り替え',
138
+ wizardStepAnnouncement: 'ステップ {index}/{total}: {label}',
136
139
  });
137
- Locale.set('ko');
138
140
  ```
139
141
 
140
- A partial table is enough — untranslated keys fall back to English. An element's own `locale`
142
+ A partial table is enough — untranslated keys fall back to English, and a registration for a
143
+ built-in language overrides only the keys it gives. An element's own `locale`
141
144
  attribute overrides the active language for that element. `registerLocale`/`setDefaultLocale` still
142
145
  work but are deprecated: a `setDefaultLocale()` call takes precedence over `Locale` until it is
143
146
  called with `undefined`.
@@ -1,4 +1,4 @@
1
- //#region \0@oxc-project+runtime@0.150.0/helpers/esm/decorate.js
1
+ //#region \0@oxc-project+runtime@0.151.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.150.0/helpers/esm/decorateMetadata.js
1
+ //#region \0@oxc-project+runtime@0.151.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.150.0/helpers/esm/decorateMetadata.js";
2
- import t from "../_virtual/_@oxc-project_runtime@0.150.0/helpers/esm/decorate.js";
1
+ import e from "../_virtual/_@oxc-project_runtime@0.151.0/helpers/esm/decorateMetadata.js";
2
+ import t from "../_virtual/_@oxc-project_runtime@0.151.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";
@@ -19,7 +19,7 @@ type ElementParts = 'host' | 'icon' | 'title' | 'description' | 'actions';
19
19
  * ```
20
20
  *
21
21
  * ⚠**기본 문구는 영어다** — 이 패키지는 범용 층이라 특정 언어를 기본값으로 가질 수 없다.
22
- * 한국어는 `modernAppLocale.register('ko', …)` 로 소비자가 등록하고(언어는 `Locale.set()`), 화면별로 덮으려면
22
+ * 한국어 표는 내장돼 있고(언어는 `Locale.set()`), 다른 언어는 `modernAppLocale.register(lang, …)` 로 소비자가 등록한다. 화면별로 덮으려면
23
23
  * `title`·`description` 을 준다.
24
24
  *
25
25
  * ★이 줄은 «한국어다»라고 적혀 있었고 **같은 파일의 `locale` 프로퍼티 주석이 «영어다»라고
@@ -37,7 +37,7 @@ export declare class EmptyState extends StyledElement<ElementParts> {
37
37
  /**
38
38
  * 언어 태그 — 이 요소만 문서와 다른 언어로 쓸 때. 비우면 `Locale` 의 활성 로케일.
39
39
  * ⚠기본 문구는 영어다 — 이 패키지는 범용 층이라 특정 언어를 기본값으로 가질 수 없다.
40
- * 한국어는 `modernAppLocale.register('ko', …)` 로 소비자가 등록한다.
40
+ * 한국어 표는 내장돼 있다 — 다른 언어는 `modernAppLocale.register(lang, …)` 로 소비자가 등록한다.
41
41
  */
42
42
  locale: string;
43
43
  /** 액션 슬롯 배정 상태 — CSS `:has()` 로는 알 수 없다(`internals/slotted.ts` 참조). */
@@ -1,5 +1,5 @@
1
- import e from "../_virtual/_@oxc-project_runtime@0.150.0/helpers/esm/decorateMetadata.js";
2
- import t from "../_virtual/_@oxc-project_runtime@0.150.0/helpers/esm/decorate.js";
1
+ import e from "../_virtual/_@oxc-project_runtime@0.151.0/helpers/esm/decorateMetadata.js";
2
+ import t from "../_virtual/_@oxc-project_runtime@0.151.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,6 +1,6 @@
1
1
  import { StyledElement } from '../internals/StyledElement.js';
2
2
  import { default as React } from 'react';
3
- type ElementParts = 'host' | 'header' | 'title' | 'actions' | 'body';
3
+ type ElementParts = 'host' | 'header' | 'title' | 'meta' | 'actions' | 'body';
4
4
  /** 제목 단계 — 페이지 제목(h1)은 `u-page-header` 몫이라 2 부터다. */
5
5
  export type GroupBoxLevel = 2 | 3 | 4 | 5 | 6;
6
6
  /**
@@ -18,13 +18,21 @@ export type GroupBoxLevel = 2 | 3 | 4 | 5 | 6;
18
18
  * </u-group-box>
19
19
  * ```
20
20
  *
21
- * 오버라이드: `part`(host·header·title·actions·body) + slot 치환.
21
+ * 오버라이드: `part`(host·header·title·meta·actions·body) + slot 치환.
22
22
  * `divider` 속성으로 제목과 본문 사이 구분선을 켠다(기본 꺼짐 — 선이 많으면 화면이 시끄럽다).
23
23
  */
24
24
  export declare class GroupBox extends StyledElement<ElementParts> {
25
25
  static styles: import('lit').CSSResultGroup[];
26
26
  /** 카드 제목. 비우면 헤더 자체를 렌더하지 않는다. */
27
27
  title: string;
28
+ /**
29
+ * Secondary text shown after the title — a count, progress or short status
30
+ * (`3 items`, `2/5 done`), drawn one step below the title: body size and weight, weak color.
31
+ *
32
+ * It sits inside the title's heading, so the heading's accessible name reads it too. Not drawn
33
+ * without a `title`: it describes the title.
34
+ */
35
+ meta?: string;
28
36
  /** 제목과 본문 사이에 구분선을 넣는다. */
29
37
  divider: boolean;
30
38
  /** 본문 여백을 없앤다 — 표를 카드 가장자리까지 붙일 때. */
@@ -60,6 +68,7 @@ declare module 'react' {
60
68
  divider?: boolean;
61
69
  flush?: boolean;
62
70
  level?: GroupBoxLevel;
71
+ meta?: string;
63
72
  };
64
73
  }
65
74
  }
@@ -1,5 +1,5 @@
1
- import e from "../_virtual/_@oxc-project_runtime@0.150.0/helpers/esm/decorateMetadata.js";
2
- import t from "../_virtual/_@oxc-project_runtime@0.150.0/helpers/esm/decorate.js";
1
+ import e from "../_virtual/_@oxc-project_runtime@0.151.0/helpers/esm/decorateMetadata.js";
2
+ import t from "../_virtual/_@oxc-project_runtime@0.151.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";
@@ -24,7 +24,7 @@ var d = {
24
24
  let e = !!this.title || this.hasActions;
25
25
  return a`
26
26
  <div class="header ${this.divider ? "divider" : ""} ${e ? "" : "empty"}" part="header">
27
- ${l`<${d[this.level] ?? d[3]} class="title" part="title">${this.title}</${d[this.level] ?? d[3]}>`}
27
+ ${l`<${d[this.level] ?? d[3]} class="title" part="title">${this.title}${this.title && this.meta ? a` <span class="meta" part="meta">${this.meta}</span>` : ""}</${d[this.level] ?? d[3]}>`}
28
28
  <div class="actions ${this.hasActions ? "" : "empty"}" part="actions">
29
29
  <slot name="actions"
30
30
  @slotchange=${(e) => this.hasActions = r(e.target)}
@@ -35,7 +35,7 @@ var d = {
35
35
  `;
36
36
  }
37
37
  };
38
- t([s({ type: String }), e("design:type", Object)], f.prototype, "title", void 0), t([s({ type: Boolean }), e("design:type", Object)], f.prototype, "divider", void 0), t([s({ type: Boolean }), e("design:type", Object)], f.prototype, "flush", void 0), t([s({
38
+ t([s({ type: String }), e("design:type", Object)], f.prototype, "title", void 0), t([s({ type: String }), e("design:type", String)], f.prototype, "meta", void 0), t([s({ type: Boolean }), e("design:type", Object)], f.prototype, "divider", void 0), t([s({ type: Boolean }), e("design:type", Object)], f.prototype, "flush", void 0), t([s({
39
39
  type: Number,
40
40
  reflect: !0
41
41
  }), e("design:type", Object)], f.prototype, "level", void 0), t([c(), e("design:type", Object)], f.prototype, "hasActions", void 0), f = t([o("u-group-box")], f);
@@ -42,6 +42,14 @@ var t = e`
42
42
  letter-spacing: var(--u-text-subtitle-tracking, 0);
43
43
  color: var(--u-txt-color, #212121);
44
44
  }
45
+ /* 제목 옆 보조 메타(건수·진척) — 제목보다 한 단 아래. 헤딩 안의 인라인이라 기준선을 공유하고,
46
+ 접근성 이름에도 함께 읽힌다. 숫자가 바뀌어도 폭이 흔들리지 않게 고정폭 숫자. */
47
+ .meta {
48
+ font-size: var(--u-text-body-size, 14px);
49
+ font-weight: var(--u-text-body-weight, 400);
50
+ color: var(--u-txt-color-weak, #616161);
51
+ font-variant-numeric: tabular-nums;
52
+ }
45
53
 
46
54
  .actions {
47
55
  flex: 0 0 auto;
@@ -1,5 +1,5 @@
1
- import e from "../_virtual/_@oxc-project_runtime@0.150.0/helpers/esm/decorateMetadata.js";
2
- import t from "../_virtual/_@oxc-project_runtime@0.150.0/helpers/esm/decorate.js";
1
+ import e from "../_virtual/_@oxc-project_runtime@0.151.0/helpers/esm/decorateMetadata.js";
2
+ import t from "../_virtual/_@oxc-project_runtime@0.151.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";
@@ -1,5 +1,5 @@
1
- import e from "../_virtual/_@oxc-project_runtime@0.150.0/helpers/esm/decorateMetadata.js";
2
- import t from "../_virtual/_@oxc-project_runtime@0.150.0/helpers/esm/decorate.js";
1
+ import e from "../_virtual/_@oxc-project_runtime@0.151.0/helpers/esm/decorateMetadata.js";
2
+ import t from "../_virtual/_@oxc-project_runtime@0.151.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";
@@ -1,5 +1,5 @@
1
- import e from "../_virtual/_@oxc-project_runtime@0.150.0/helpers/esm/decorateMetadata.js";
2
- import t from "../_virtual/_@oxc-project_runtime@0.150.0/helpers/esm/decorate.js";
1
+ import e from "../_virtual/_@oxc-project_runtime@0.151.0/helpers/esm/decorateMetadata.js";
2
+ import t from "../_virtual/_@oxc-project_runtime@0.151.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";
@@ -33,7 +33,7 @@ export declare class PageHeader extends StyledElement<ElementParts> {
33
33
  /**
34
34
  * 뒤로가기 링크 문구. 비우면 locale 레지스트리 값, 그것도 없으면 **영어**(`Back`).
35
35
  * ⚠이 패키지는 범용 층이라 특정 언어를 기본값으로 가질 수 없다 —
36
- * 한국어는 `modernAppLocale.register('ko', { back: '뒤로' })` 로 소비자가 등록한다.
36
+ * 한국어 표는 내장돼 있다 — 다른 언어는 `modernAppLocale.register(lang, { back: … })` 로 소비자가 등록한다.
37
37
  */
38
38
  backLabel: string;
39
39
  /** 언어 태그 — 이 요소만 문서와 다른 언어로 쓸 때. 비우면 `Locale` 의 활성 로케일. */
@@ -1,5 +1,5 @@
1
- import e from "../_virtual/_@oxc-project_runtime@0.150.0/helpers/esm/decorateMetadata.js";
2
- import t from "../_virtual/_@oxc-project_runtime@0.150.0/helpers/esm/decorate.js";
1
+ import e from "../_virtual/_@oxc-project_runtime@0.151.0/helpers/esm/decorateMetadata.js";
2
+ import t from "../_virtual/_@oxc-project_runtime@0.151.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.150.0/helpers/esm/decorateMetadata.js";
2
- import t from "../_virtual/_@oxc-project_runtime@0.150.0/helpers/esm/decorate.js";
1
+ import e from "../_virtual/_@oxc-project_runtime@0.151.0/helpers/esm/decorateMetadata.js";
2
+ import t from "../_virtual/_@oxc-project_runtime@0.151.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.150.0/helpers/esm/decorateMetadata.js";
2
- import t from "../_virtual/_@oxc-project_runtime@0.150.0/helpers/esm/decorate.js";
1
+ import e from "../_virtual/_@oxc-project_runtime@0.151.0/helpers/esm/decorateMetadata.js";
2
+ import t from "../_virtual/_@oxc-project_runtime@0.151.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.150.0/helpers/esm/decorateMetadata.js";
2
- import t from "../_virtual/_@oxc-project_runtime@0.150.0/helpers/esm/decorate.js";
1
+ import e from "../_virtual/_@oxc-project_runtime@0.151.0/helpers/esm/decorateMetadata.js";
2
+ import t from "../_virtual/_@oxc-project_runtime@0.151.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.150.0/helpers/esm/decorateMetadata.js";
2
- import t from "../_virtual/_@oxc-project_runtime@0.150.0/helpers/esm/decorate.js";
1
+ import e from "../_virtual/_@oxc-project_runtime@0.151.0/helpers/esm/decorateMetadata.js";
2
+ import t from "../_virtual/_@oxc-project_runtime@0.151.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.150.0/helpers/esm/decorateMetadata.js";
2
- import t from "../_virtual/_@oxc-project_runtime@0.150.0/helpers/esm/decorate.js";
1
+ import e from "../_virtual/_@oxc-project_runtime@0.151.0/helpers/esm/decorateMetadata.js";
2
+ import t from "../_virtual/_@oxc-project_runtime@0.151.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.150.0/helpers/esm/decorateMetadata.js";
2
- import t from "../_virtual/_@oxc-project_runtime@0.150.0/helpers/esm/decorate.js";
1
+ import e from "../_virtual/_@oxc-project_runtime@0.151.0/helpers/esm/decorateMetadata.js";
2
+ import t from "../_virtual/_@oxc-project_runtime@0.151.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
@@ -13,7 +13,19 @@ var t = {
13
13
  wizardNext: "Next",
14
14
  wizardStepAnnouncement: "Step {index} of {total}: {label}"
15
15
  }, n = e.namespace("modern-app");
16
- n.register("en", t);
16
+ n.register("en", t), n.register("ko", {
17
+ back: "뒤로",
18
+ noDataTitle: "아직 항목이 없습니다",
19
+ noDataDescription: "",
20
+ noResultsTitle: "일치하는 결과가 없습니다",
21
+ noResultsDescription: "검색어나 필터를 바꿔 보세요.",
22
+ detailClose: "닫기",
23
+ toggleMobileMenu: "메뉴 열고 닫기",
24
+ toggleSidebar: "사이드바 열고 닫기",
25
+ wizardBack: "이전",
26
+ wizardNext: "다음",
27
+ wizardStepAnnouncement: "{total}단계 중 {index}단계: {label}"
28
+ });
17
29
  var r, i = /* @__PURE__ */ new Map(), a = "\0modern-app:announcer:";
18
30
  function o(e, t) {
19
31
  let { wizardStepAnnouncement: r, ...o } = t, s = { ...o };
@@ -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.150.0/helpers/esm/decorateMetadata.js";
4
- import r from "../_virtual/_@oxc-project_runtime@0.150.0/helpers/esm/decorate.js";
3
+ import n from "../_virtual/_@oxc-project_runtime@0.151.0/helpers/esm/decorateMetadata.js";
4
+ import r from "../_virtual/_@oxc-project_runtime@0.151.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 { slotHasContent as o } from "../internals/slotted.js";
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.26.0",
4
+ "version": "0.27.0",
5
5
  "keywords": [
6
6
  "iyulab",
7
7
  "web-framework",
@@ -144,23 +144,26 @@ html`<p>${translate('namespace::greeting')}</p>`;
144
144
  ### Built-in strings (`modernAppLocale`)
145
145
 
146
146
  The package's own strings — the page header's back link, empty-state copy, the shell's toggle and
147
- close labels, the wizard's buttons and step announcement — are English by default and live in the
148
- `modern-app` namespace of `@iyulab/components`' `Locale`. Register translations there and pick the
149
- language once, with `Locale.set()`; the primitives and `@iyulab/flex-table` follow the same call:
147
+ close labels, the wizard's buttons and step announcement — live in the `modern-app` namespace of
148
+ `@iyulab/components`' `Locale`. English and Korean are built in, English being the default; pick the
149
+ language once, with `Locale.set()` — the primitives and `@iyulab/flex-table` follow the same call.
150
+ Register other languages, or your own wording, in the same namespace:
150
151
 
151
152
  ```typescript
152
153
  import { Locale } from '@iyulab/components';
153
154
  import { modernAppLocale } from '@iyulab/modern-app';
154
155
 
155
- modernAppLocale.register('ko', {
156
- back: '뒤로',
157
- toggleSidebar: '사이드바 접기/펼치기',
158
- wizardStepAnnouncement: '{total}단계 중 {index}단계: {label}',
156
+ Locale.set('ko'); // built-in Korean — nothing to register
157
+
158
+ modernAppLocale.register('ja', {
159
+ back: '戻る',
160
+ toggleSidebar: 'サイドバーの切り替え',
161
+ wizardStepAnnouncement: 'ステップ {index}/{total}: {label}',
159
162
  });
160
- Locale.set('ko');
161
163
  ```
162
164
 
163
- A partial table is enough — untranslated keys fall back to English. An element's own `locale`
165
+ A partial table is enough — untranslated keys fall back to English, and a registration for a
166
+ built-in language overrides only the keys it gives. An element's own `locale`
164
167
  attribute overrides the active language for that element. `registerLocale`/`setDefaultLocale` still
165
168
  work but are deprecated: a `setDefaultLocale()` call takes precedence over `Locale` until it is
166
169
  called with `undefined`.
@@ -54,6 +54,6 @@ for both and a user with a filter still applied reads it as *"my data disappeare
54
54
  | `--u-space-lg` | Actions row top spacing |
55
55
  | `--u-space-sm` | Gap between actions |
56
56
 
57
- ⚠ Default wording is **English** — register others with `modernAppLocale.register('ko', …)` and
58
- choose the language with `Locale.set()` of `@iyulab/components`, or pass `title`/`description` per
59
- screen.
57
+ ⚠ Default wording is **English**, with Korean built in — choose the language with `Locale.set()` of
58
+ `@iyulab/components`, register others with `modernAppLocale.register(lang, …)`, or pass
59
+ `title`/`description` per screen.
@@ -9,7 +9,7 @@ trailing actions*, and assembling that by hand is how title sizes, padding, and
9
9
  up different on every screen.
10
10
 
11
11
  ```html
12
- <u-group-box title="Receivables">
12
+ <u-group-box title="Receivables" meta="3 items">
13
13
  <a slot="actions" href="/receivables">Payments</a>
14
14
  …body…
15
15
  </u-group-box>
@@ -30,6 +30,7 @@ a left edge without any consumer CSS.
30
30
  | Property | Type | Default | Reflect | Description |
31
31
  |----------|------|---------|---------|-------------|
32
32
  | `title` | `string` | `''` | | Header title |
33
+ | `meta` | `string` | — | | Secondary text after the title — a count, progress or short status (`3 items`, `2/5 done`), one step below the title: body size and weight, weak color, tabular figures. It sits inside the heading, so the heading's accessible name includes it. Not drawn without `title` |
33
34
  | `divider` | `boolean` | `false` | | Rule between header and body. Off by default — many rules make a screen noisy |
34
35
  | `flush` | `boolean` | `false` | | Remove body padding, for tables and lists that draw their own edges |
35
36
  | `level` | `2|3|4|5|6` | `3` | ✓ | Heading level of the title in the document outline. Set `2` for a box directly under `u-page-header` (the page's `h1`), so the outline does not skip a level. Semantics only — the title looks the same at every level |
@@ -39,6 +40,7 @@ a left edge without any consumer CSS.
39
40
  | Part | Description |
40
41
  |------|-------------|
41
42
  | `header` · `title` · `actions` | Header row |
43
+ | `meta` | Secondary text inside the title |
42
44
  | `body` | Body wrapper |
43
45
 
44
46
  ## CSS Custom Properties
@@ -49,6 +51,7 @@ a left edge without any consumer CSS.
49
51
  | `--u-text-subtitle-weight` | Title font weight |
50
52
  | `--u-text-subtitle-leading` | Title line height |
51
53
  | `--u-text-subtitle-tracking` | Title letter spacing |
54
+ | `--u-text-body-size` / `--u-text-body-weight` / `--u-txt-color-weak` | `meta` size, weight and color |
52
55
  | `--u-bg-color-raised` | Surface background |
53
56
  | `--u-border-color-weak` | Border and header divider color |
54
57
  | `--u-radius-2xl` | Corner radius |
@@ -58,6 +58,5 @@ screens nobody opens.
58
58
  | `--u-space-2xs` | Title-to-subtitle spacing |
59
59
  | `--u-space-3xs` | Back-arrow-to-label spacing |
60
60
 
61
- ⚠ Built-in strings default to **English** — this package is a generic layer and cannot pick a
62
- language. Register others with `modernAppLocale.register('ko', { back: '뒤로' })` and choose the
63
- language with `Locale.set()` of `@iyulab/components`.
61
+ ⚠ Built-in strings default to **English**, with Korean built in — choose the language with
62
+ `Locale.set()` of `@iyulab/components`. Register others with `modernAppLocale.register(lang, { back: … })`.