@godxjp/ui 33.21.0 → 33.22.2

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/README.md CHANGED
@@ -18,7 +18,7 @@ npm i @godxjp/ui
18
18
 
19
19
  <!-- agent-catalog-counts:start -->
20
20
 
21
- The catalog — 210 components, 3183 tokens, 44 cardinal rules — is published in two forms from one
21
+ The catalog — 210 components, 3184 tokens, 44 cardinal rules — is published in two forms from one
22
22
  source. **Entry point for either: [`AGENTS.md`](AGENTS.md).**
23
23
  <!-- agent-catalog-counts:end -->
24
24
 
@@ -56,7 +56,7 @@ static files straight from this public repo — no hosting, no deploy step:
56
56
  | [`agent/components-index.json`](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/components-index.json) | 46 KB | all 210 as name + group + tagline — **fetch this first** |
57
57
  | [`agent/components/<Name>.json`](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/components/Select.json) | 1 KB–38 KB | one file per component, each with its `importPath` — **this is the route to take** |
58
58
  | [`agent/components.json`](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/components.json) | 1.4 MB | all 210 entries in one file — most URL fetchers truncate this silently; prefer the per-component files |
59
- | [`agent/tokens.json`](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/tokens.json) | 1.4 MB | all 3183 design tokens, their values and why they exist |
59
+ | [`agent/tokens.json`](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/tokens.json) | 1.4 MB | all 3184 design tokens, their values and why they exist |
60
60
  | [`agent/vocabulary.json`](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/vocabulary.json) | 7 KB | the controlled prop vocabulary |
61
61
  | [`agent/rules.json`](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/rules.json) | 23 KB | the 44 cardinal rules |
62
62
  <!-- prettier-ignore-end -->
@@ -3,7 +3,7 @@
3
3
  You are about to write code against a design system you did not author. This file is the whole
4
4
  contract. Read it before you write JSX.
5
5
 
6
- **This catalog describes `@godxjp/ui` 33.21.0.** If the project you are editing has a different
6
+ **This catalog describes `@godxjp/ui` 33.22.2.** If the project you are editing has a different
7
7
  version in its `package.json`, read the pinned catalog for THAT version instead
8
8
  (`…/v<their-version>/agent/…`). A catalog newer than the installed package describes props that do
9
9
  not exist yet; older, and it hides props that do. Neither failure announces itself.
@@ -61,10 +61,10 @@ screen anatomy, the visual target the rules below do not give you. Then fetch in
61
61
  its `importPath`, and its examples. Fetch only the handful you picked in step 1.
62
62
  3. `rules.json` — 44 cardinal rules. The ones about raw HTML and hardcoded colour are not
63
63
  style advice.
64
- 4. `tokens.json` — 3183 design tokens, each tagged with its `tier`. **If you were handed a
64
+ 4. `tokens.json` — 3184 design tokens, each tagged with its `tier`. **If you were handed a
65
65
  brand, read the 220 `foundation` entries first** — `--primary`, `--background`,
66
66
  `--radius`, `--font-size-base` are the handful everything else derives from. The
67
- 2850 `component` entries are per-part knobs; reach for one only when a role is
67
+ 2851 `component` entries are per-part knobs; reach for one only when a role is
68
68
  right everywhere except one component.
69
69
  5. `anti-ai-tells.json` — 35 shapes that make generated UI look generated, each with the
70
70
  fix. Read before you reach for a gradient hero or a wall of coloured chips.
@@ -150,7 +150,7 @@ has stopped following the brand.
150
150
  |---|---|---|---|
151
151
  | `foundation` | 220 | the seeds — `--primary`, `--background`, `--foreground`, `--radius`, `--font-size-base`, `--shadow-color`. Everything below is derived from these | **yes — this is the main road.** The default `--primary` is a neutral placeholder: set it (`:root { --primary: <H> <S>% <L>%; }`, HSL components, no `hsl()` wrapper) or import a theme preset such as `@godxjp/ui/themes/godx.css` |
152
152
  | `semantic` | 113 | named roles that follow the seeds — `--ring`, `--text-link`, `--primary-hover`, `--overlay-background` | only when the seed is right and ONE role must differ. That role then stops following a later brand change |
153
- | `component` | 2850 | per-part knobs, `--{component}-{part}-{property}` | rarely. Most are declared `initial` with the real default at the call site — deliberate, so a scoped override re-resolves instead of freezing at `:root` |
153
+ | `component` | 2851 | per-part knobs, `--{component}-{part}-{property}` | rarely. Most are declared `initial` with the real default at the call site — deliberate, so a scoped override re-resolves instead of freezing at `:root` |
154
154
 
155
155
  A token whose `value` is `initial` is not empty and not broken: `initial` is the guaranteed-invalid
156
156
  value, so the real default is computed where the element paints it. Set it and yours wins.
@@ -57,10 +57,15 @@
57
57
  "type": "\"framed\" | \"plain\""
58
58
  },
59
59
  {
60
- "description": "Extra `/` rows ({ key, label, icon, keywords?, run(api) }) — `api.insertMarkdown` inserts through the codec.",
60
+ "description": "Extra `/` rows ({ key, label, icon, keywords?, run(api) }) — `api.insertMarkdown` inserts through the codec, so a directive skeleton (`:::poll[Q]{id=x}\\n- A\\n- B\\n:::`) lands as a directive block.",
61
61
  "name": "actions",
62
62
  "type": "BlockEditorAction[]"
63
63
  },
64
+ {
65
+ "description": "Editor previews for directive blocks, by name. A container directive the kit does not model (`:::poll[…]{…}`) is one atomic block — dragged, deleted and inserted whole, its source edited behind Edit source; the preview gets `{ name, label, attributes, source, body }` (canonical). No renderer, or `undefined`: the block shows its source.",
66
+ "name": "directives",
67
+ "type": "Record<string, (block: DirectiveBlock) => ReactNode | undefined>"
68
+ },
64
69
  {
65
70
  "description": "Override any string (defaults: kit ja / en / vi).",
66
71
  "name": "labels",
@@ -59,7 +59,7 @@
59
59
  },
60
60
  {
61
61
  "defaultValue": "false",
62
- "description": "In-flight state — shows a leading `Loader2` spinner (replaces a leading icon if present), sets `aria-busy=\"true\"`, and blocks activation (non-interactive, pointer-events disabled) while keeping the label visible so the width doesn't jump. Prefer this over a hand-rolled `<Loader2 className=\"animate-spin\">` inside the button. Ignored when `asChild` (Slot requires a single child).",
62
+ "description": "In-flight state — shows a leading `Loader2` spinner (replaces a leading icon if present), sets `aria-busy=\"true\"` and `aria-disabled=\"true\"`, and blocks activation (click, Enter/Space and a `type=\"submit\"` form submission are swallowed; pointer-events disabled) while keeping the label visible so the width doesn't jump. It never sets native `disabled`, so the button keeps focus while the request runs — a disabled element drops focus to <body>, which strands a keyboard user outside a dialog after a failed save. Prefer this over a hand-rolled `<Loader2 className=\"animate-spin\">` inside the button. Ignored when `asChild` (Slot requires a single child).",
63
63
  "name": "loading",
64
64
  "type": "boolean"
65
65
  },
@@ -78,6 +78,11 @@
78
78
  "description": "Fenced code in a known language is tokenised at parse time as `<span data-code-token>` with the kit's twelve names, which Prose colours (renderer v6). `false` leaves plain text for a host `pre` with its own highlighter.",
79
79
  "name": "highlight",
80
80
  "type": "boolean"
81
+ },
82
+ {
83
+ "description": "Host renderers for container directives the kit does not model, by name (`{ poll: (b) => <PollCard … /> }`). Each gets `{ name, label, attributes, source, body, children }` — label / source / body as written, `children` the rendered body without the label (a `::::form`'s `:::poll` cards). Return `undefined` to render the block as an unknown directive (its content in `div.ui-prose-directive`), which is also what an unregistered name renders. `toggle` / `columns` / `column` cannot be overridden.",
84
+ "name": "directives",
85
+ "type": "Record<string, (block: DirectiveRenderProps) => ReactNode | undefined>"
81
86
  }
82
87
  ],
83
88
  "related": [
@@ -94,6 +99,7 @@
94
99
  "DO `<Prose><Markdown>{body}</Markdown></Prose>` for every rendered body (wiki page, issue, mail).",
95
100
  "DO record `MARKDOWN_FORMAT` and `RENDERER_VERSION` on stored versions.",
96
101
  "DO `import \"@godxjp/markdown/katex.css\"` once in the app: `$…$`, `$$…$$` and ```math are drawn by KaTeX at parse time (trust: false, renderer v6) and need its stylesheet and fonts. A single `$` follows Pandoc's rule, so `$5 and $10` stays text.",
102
+ "DO import `Markdown` from `@godxjp/markdown/lazy` in a client-rendered app: KaTeX (+ its stylesheet, no global katex.css import needed) and highlight.js load only when a body has math or a fence with a language, then the body re-renders. The default entry stays eager because a server or Worker render is synchronous; a server or a hydrating client using `/lazy` awaits `preloadMarkdownRuntime(body)` first.",
97
103
  "DON'T assemble react-markdown + rehype-sanitize per app, add rehype-raw, or render Mermaid yourself — `checkMermaidSvg` is the gate."
98
104
  ]
99
105
  }
@@ -4749,7 +4749,7 @@
4749
4749
  },
4750
4750
  {
4751
4751
  "defaultValue": "false",
4752
- "description": "In-flight state — shows a leading `Loader2` spinner (replaces a leading icon if present), sets `aria-busy=\"true\"`, and blocks activation (non-interactive, pointer-events disabled) while keeping the label visible so the width doesn't jump. Prefer this over a hand-rolled `<Loader2 className=\"animate-spin\">` inside the button. Ignored when `asChild` (Slot requires a single child).",
4752
+ "description": "In-flight state — shows a leading `Loader2` spinner (replaces a leading icon if present), sets `aria-busy=\"true\"` and `aria-disabled=\"true\"`, and blocks activation (click, Enter/Space and a `type=\"submit\"` form submission are swallowed; pointer-events disabled) while keeping the label visible so the width doesn't jump. It never sets native `disabled`, so the button keeps focus while the request runs — a disabled element drops focus to <body>, which strands a keyboard user outside a dialog after a failed save. Prefer this over a hand-rolled `<Loader2 className=\"animate-spin\">` inside the button. Ignored when `asChild` (Slot requires a single child).",
4753
4753
  "name": "loading",
4754
4754
  "type": "boolean"
4755
4755
  },
@@ -7148,6 +7148,11 @@
7148
7148
  "description": "Fenced code in a known language is tokenised at parse time as `<span data-code-token>` with the kit's twelve names, which Prose colours (renderer v6). `false` leaves plain text for a host `pre` with its own highlighter.",
7149
7149
  "name": "highlight",
7150
7150
  "type": "boolean"
7151
+ },
7152
+ {
7153
+ "description": "Host renderers for container directives the kit does not model, by name (`{ poll: (b) => <PollCard … /> }`). Each gets `{ name, label, attributes, source, body, children }` — label / source / body as written, `children` the rendered body without the label (a `::::form`'s `:::poll` cards). Return `undefined` to render the block as an unknown directive (its content in `div.ui-prose-directive`), which is also what an unregistered name renders. `toggle` / `columns` / `column` cannot be overridden.",
7154
+ "name": "directives",
7155
+ "type": "Record<string, (block: DirectiveRenderProps) => ReactNode | undefined>"
7151
7156
  }
7152
7157
  ],
7153
7158
  "related": [
@@ -7164,6 +7169,7 @@
7164
7169
  "DO `<Prose><Markdown>{body}</Markdown></Prose>` for every rendered body (wiki page, issue, mail).",
7165
7170
  "DO record `MARKDOWN_FORMAT` and `RENDERER_VERSION` on stored versions.",
7166
7171
  "DO `import \"@godxjp/markdown/katex.css\"` once in the app: `$…$`, `$$…$$` and ```math are drawn by KaTeX at parse time (trust: false, renderer v6) and need its stylesheet and fonts. A single `$` follows Pandoc's rule, so `$5 and $10` stays text.",
7172
+ "DO import `Markdown` from `@godxjp/markdown/lazy` in a client-rendered app: KaTeX (+ its stylesheet, no global katex.css import needed) and highlight.js load only when a body has math or a fence with a language, then the body re-renders. The default entry stays eager because a server or Worker render is synchronous; a server or a hydrating client using `/lazy` awaits `preloadMarkdownRuntime(body)` first.",
7167
7173
  "DON'T assemble react-markdown + rehype-sanitize per app, add rehype-raw, or render Mermaid yourself — `checkMermaidSvg` is the gate."
7168
7174
  ]
7169
7175
  },
@@ -7292,10 +7298,15 @@
7292
7298
  "type": "\"framed\" | \"plain\""
7293
7299
  },
7294
7300
  {
7295
- "description": "Extra `/` rows ({ key, label, icon, keywords?, run(api) }) — `api.insertMarkdown` inserts through the codec.",
7301
+ "description": "Extra `/` rows ({ key, label, icon, keywords?, run(api) }) — `api.insertMarkdown` inserts through the codec, so a directive skeleton (`:::poll[Q]{id=x}\\n- A\\n- B\\n:::`) lands as a directive block.",
7296
7302
  "name": "actions",
7297
7303
  "type": "BlockEditorAction[]"
7298
7304
  },
7305
+ {
7306
+ "description": "Editor previews for directive blocks, by name. A container directive the kit does not model (`:::poll[…]{…}`) is one atomic block — dragged, deleted and inserted whole, its source edited behind Edit source; the preview gets `{ name, label, attributes, source, body }` (canonical). No renderer, or `undefined`: the block shows its source.",
7307
+ "name": "directives",
7308
+ "type": "Record<string, (block: DirectiveBlock) => ReactNode | undefined>"
7309
+ },
7299
7310
  {
7300
7311
  "description": "Override any string (defaults: kit ja / en / vi).",
7301
7312
  "name": "labels",
package/agent/index.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "components": 210,
5
5
  "patterns": 28,
6
6
  "rules": 44,
7
- "tokens": 3183,
7
+ "tokens": 3184,
8
8
  "vocabulary": 16
9
9
  },
10
10
  "design": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/DESIGN.md",
@@ -54,19 +54,19 @@
54
54
  "note": "Pin to the tag that matches the @godxjp/ui version you installed. A catalog newer than your package describes props you do not have; older, and it hides props you do.",
55
55
  "read": {
56
56
  "live": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/index.json",
57
- "pinned": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/v33.21.0/agent/index.json"
57
+ "pinned": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/v33.22.2/agent/index.json"
58
58
  },
59
59
  "source": "mcp/src/data — the same data @godxjp/ui-mcp serves — plus the foundation and semantic token tiers, read from src/tokens/*.css",
60
60
  "start": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/START-HERE.md",
61
61
  "tokenTiers": {
62
62
  "component": "per-part knobs, --{component}-{part}-{property}; usually leave these alone",
63
63
  "counts": {
64
- "component": 2850,
64
+ "component": 2851,
65
65
  "foundation": 220,
66
66
  "semantic": 113
67
67
  },
68
68
  "foundation": "the seeds a consumer is invited to set — --primary, --background, --radius",
69
69
  "semantic": "named roles that follow the seeds — --ring, --text-link, --overlay-background"
70
70
  },
71
- "version": "33.21.0"
71
+ "version": "33.22.2"
72
72
  }
package/agent/llms.txt CHANGED
@@ -1,10 +1,10 @@
1
1
  # @godxjp/ui
2
2
 
3
- > A Japanese-enterprise React design system: 210 components, 3183 design tokens,
4
- > 44 cardinal rules. This file is the entry point for AI agents. Catalog version 33.21.0.
3
+ > A Japanese-enterprise React design system: 210 components, 3184 design tokens,
4
+ > 44 cardinal rules. This file is the entry point for AI agents. Catalog version 33.22.2.
5
5
 
6
6
  If your client can run a process, do not read these files — run the MCP server instead
7
- (`npx @godxjp/ui-mcp@33.21.0`). It is searchable and version-locked. These files exist for agents
7
+ (`npx @godxjp/ui-mcp@33.22.2`). It is searchable and version-locked. These files exist for agents
8
8
  that can only fetch URLs.
9
9
 
10
10
  ## Start
@@ -19,7 +19,7 @@ that can only fetch URLs.
19
19
  - [components-index.json](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/components-index.json): 46 KB — all 210 components as name, group, tagline, plus `absorbed`: the names that do NOT exist and map to it (`Combobox` → `Select`).
20
20
  - [components/&lt;Name&gt;.json](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/components/Select.json): one file per component (1 KB–38 KB, median 5 KB). Read the index, then fetch only the ones you chose — this is the selective route, and the reason you do not need the blob.
21
21
  - [components.json](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/components.json): 1.4 MB — every entry in one file. Most URL fetchers truncate a response this size without saying so; prefer the per-component files.
22
- - [tokens.json](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/tokens.json): every design token with its value, the reason it exists, and its `tier` — 220 `foundation` seeds (`--primary`, `--background`, `--radius`: set these when you are handed a brand), 113 `semantic` roles, 2850 `component` knobs.
22
+ - [tokens.json](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/tokens.json): every design token with its value, the reason it exists, and its `tier` — 220 `foundation` seeds (`--primary`, `--background`, `--radius`: set these when you are handed a brand), 113 `semantic` roles, 2851 `component` knobs.
23
23
  - [vocabulary.json](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/vocabulary.json): the controlled prop vocabulary — which prop name means what, across every component.
24
24
  - [rules.json](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/rules.json): 44 cardinal rules.
25
25
  - [anti-ai-tells.json](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/anti-ai-tells.json): 35 shapes that make generated UI look generated, each with its fix.
@@ -27,7 +27,7 @@ that can only fetch URLs.
27
27
  ## Pinning
28
28
 
29
29
  Every URL above tracks `main`. To pin to the release a project actually installed, swap `main` for
30
- the tag: `.../godx-jp/godxjp-ui/v33.21.0/agent/...`. A catalog that does not match the installed
30
+ the tag: `.../godx-jp/godxjp-ui/v33.22.2/agent/...`. A catalog that does not match the installed
31
31
  package describes props that are absent, or hides props that are present, and says nothing either way.
32
32
 
33
33
  Pinned catalogs only exist for releases whose tag actually contains `agent/`. If `…/v<version>/agent/index.json` returns 404, that release predates this catalog: read `…/main/…` instead and compare `index.json` → `version` against the package you have, so you at least know which way it drifted.
package/agent/tokens.json CHANGED
@@ -13895,6 +13895,12 @@
13895
13895
  "tier": "component",
13896
13896
  "value": "-0.21em"
13897
13897
  },
13898
+ {
13899
+ "description": "Where `text-box` is supported the line box is TRIMMED to the band's top and the baseline (styles/logo-layout.css), so the four constants above are not applied. A descender still hangs below that baseline, and the font's `text` descent is not where it ends — Noto Sans JP's is deeper than its `g`, which left g / y / p 1.12–1.37px HIGH at `sm`. So the descender classes trim to the baseline like the others and move up by half a descender instead: measured with `alphabetic` and no offset, g / y / p / gX sat 0.07–0.12em low across xs–lg (Chromium, macOS, Noto Sans JP 700).",
13900
+ "name": "--logo-glyph-descender-trimmed-optical-offset",
13901
+ "tier": "component",
13902
+ "value": "-0.1em"
13903
+ },
13898
13904
  {
13899
13905
  "description": "The escape hatch, for a mark none of the four bands fits — a face with unusual metrics, or a glyph the classifier cannot see (an inline `<svg>`, which is left unclassified on purpose). Set once and it PINS every band to that value. Declared `initial` (guaranteed-invalid) so it is inert by default and the per-band default at the CALL SITE wins — the same pattern as --logo-godx-size (docs/TOKENS.md). Documented default: --logo-glyph-optical-offset = the --logo-glyph-*-optical-offset for the band the glyph was classified into, or 0 when it was not classified.",
13900
13906
  "name": "--logo-glyph-optical-offset",
@@ -429,6 +429,9 @@ const ImageRoot = React.forwardRef(function Image({
429
429
  className,
430
430
  onLoad,
431
431
  onError,
432
+ fetchPriority,
433
+ loading = fetchPriority === "high" ? "eager" : "lazy",
434
+ decoding = "async",
432
435
  ...imgProps
433
436
  }, ref) {
434
437
  const { t } = useTranslation();
@@ -486,6 +489,9 @@ const ImageRoot = React.forwardRef(function Image({
486
489
  "img",
487
490
  {
488
491
  ...imgProps,
492
+ loading,
493
+ decoding,
494
+ fetchPriority,
489
495
  width,
490
496
  height,
491
497
  ref: setImgRef,
@@ -99,11 +99,15 @@ const Button = React.forwardRef(
99
99
  disabled,
100
100
  type,
101
101
  children,
102
+ onClick,
102
103
  ...props
103
104
  }, ref) => {
104
105
  const { locale } = useTranslation();
105
106
  const Comp = asChild ? Slot : "button";
106
107
  const isLoading = !asChild && loading;
108
+ const handleClick = isLoading ? (event) => {
109
+ event.preventDefault();
110
+ } : onClick;
107
111
  const content = isLoading ? /* @__PURE__ */ jsxs(Fragment, { children: [
108
112
  /* @__PURE__ */ jsx(Loader2, { className: "animate-spin", "aria-hidden": "true" }),
109
113
  loadingText ?? children
@@ -132,7 +136,9 @@ const Button = React.forwardRef(
132
136
  "data-loading": isLoading ? "" : void 0,
133
137
  "data-label": labelled ? "" : void 0,
134
138
  "aria-busy": isLoading || void 0,
135
- disabled: isLoading || disabled,
139
+ "aria-disabled": isLoading && !disabled || void 0,
140
+ disabled,
141
+ onClick: handleClick,
136
142
  type: asChild ? void 0 : type ?? "button",
137
143
  className: cn(
138
144
  fullWidth && "w-full",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$comment": "AUTO-GENERATED by scripts/gen-measurement-contract.mjs — do not edit. Read this instead of guessing: docs/MEASUREMENT-CONTRACT.md.",
3
- "version": "33.21.0",
3
+ "version": "33.22.2",
4
4
  "targetSize": {
5
5
  "standard": "WCAG 2.2 SC 2.5.8 Target Size (Minimum), level AA — 24×24 CSS px",
6
6
  "min": 24,
@@ -122,6 +122,8 @@ const LegalDocumentShell = React.forwardRef(
122
122
  target.focus({ preventScroll: true });
123
123
  };
124
124
  const contentsName = contentsLabel ?? t("layout.legalDocumentShell.contents");
125
+ const hasContents = sections.length > 0;
126
+ const hasRail = hasContents || documentNavigation !== void 0;
125
127
  return /* @__PURE__ */ jsx(
126
128
  "div",
127
129
  {
@@ -129,58 +131,66 @@ const LegalDocumentShell = React.forwardRef(
129
131
  id,
130
132
  "data-slot": "legal-document-shell",
131
133
  className: cn("ui-legal-document-scope", className),
132
- children: /* @__PURE__ */ jsxs("article", { className: "ui-legal-document", "aria-labelledby": titleId, children: [
133
- /* @__PURE__ */ jsxs("header", { className: "ui-legal-document-header", children: [
134
- /* @__PURE__ */ jsx(Heading, { level: 1, id: titleId, children: title }),
135
- (version !== void 0 || effectiveDate !== void 0) && /* @__PURE__ */ jsxs("div", { className: "ui-legal-document-meta", children: [
136
- version !== void 0 && /* @__PURE__ */ jsx("span", { children: t("layout.legalDocumentShell.version", { version }) }),
137
- effectiveDate !== void 0 && // <time dateTime> keeps the MACHINE-readable value as the ISO 8601 input while
138
- // the visible text is the Intl-formatted, locale-correct rendering.
139
- /* @__PURE__ */ jsx("time", { dateTime: effectiveDate, children: t(
140
- dateKind === "updated" ? "layout.legalDocumentShell.updatedDate" : "layout.legalDocumentShell.effectiveDate",
134
+ children: /* @__PURE__ */ jsxs(
135
+ "article",
136
+ {
137
+ className: "ui-legal-document",
138
+ "aria-labelledby": titleId,
139
+ "data-rail": hasRail ? void 0 : "none",
140
+ children: [
141
+ /* @__PURE__ */ jsxs("header", { className: "ui-legal-document-header", children: [
142
+ /* @__PURE__ */ jsx(Heading, { level: 1, id: titleId, children: title }),
143
+ (version !== void 0 || effectiveDate !== void 0) && /* @__PURE__ */ jsxs("div", { className: "ui-legal-document-meta", children: [
144
+ version !== void 0 && /* @__PURE__ */ jsx("span", { children: t("layout.legalDocumentShell.version", { version }) }),
145
+ effectiveDate !== void 0 && // <time dateTime> keeps the MACHINE-readable value as the ISO 8601 input while
146
+ // the visible text is the Intl-formatted, locale-correct rendering.
147
+ /* @__PURE__ */ jsx("time", { dateTime: effectiveDate, children: t(
148
+ dateKind === "updated" ? "layout.legalDocumentShell.updatedDate" : "layout.legalDocumentShell.effectiveDate",
149
+ {
150
+ date: formatEffectiveDate(effectiveDate, locale)
151
+ }
152
+ ) })
153
+ ] }),
154
+ summary !== void 0 && // A <div> (not <p>): the summary slot may carry block content, and a <p> inside a <p>
155
+ // is invalid HTML the browser silently un-nests.
156
+ /* @__PURE__ */ jsx("div", { className: "ui-legal-document-summary", children: summary })
157
+ ] }),
158
+ hasRail && /* @__PURE__ */ jsxs("div", { className: "ui-legal-document-rail", children: [
159
+ documentNavigation !== void 0 && /* @__PURE__ */ jsx("div", { "data-slot": "legal-document-navigation", children: documentNavigation }),
160
+ hasContents && /* @__PURE__ */ jsxs("nav", { className: "ui-legal-document-toc", "aria-labelledby": contentsId, children: [
161
+ /* @__PURE__ */ jsx("p", { id: contentsId, className: "ui-legal-document-toc-title", children: contentsName }),
162
+ /* @__PURE__ */ jsx("ol", { className: "ui-legal-document-toc-list", children: sections.map((section) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
163
+ "a",
164
+ {
165
+ href: `#${section.id}`,
166
+ className: "ui-legal-document-toc-link",
167
+ "data-active": section.id === active ? "" : void 0,
168
+ "aria-current": section.id === active ? "location" : void 0,
169
+ onClick: (event) => handleContentsClick(event, section.id),
170
+ children: section.title
171
+ }
172
+ ) }, section.id)) })
173
+ ] })
174
+ ] }),
175
+ /* @__PURE__ */ jsx("div", { className: "ui-legal-document-content", children: sections.map((section) => /* @__PURE__ */ jsxs(
176
+ "section",
141
177
  {
142
- date: formatEffectiveDate(effectiveDate, locale)
143
- }
144
- ) })
145
- ] }),
146
- summary !== void 0 && // A <div> (not <p>): the summary slot may carry block content, and a <p> inside a <p>
147
- // is invalid HTML the browser silently un-nests.
148
- /* @__PURE__ */ jsx("div", { className: "ui-legal-document-summary", children: summary })
149
- ] }),
150
- /* @__PURE__ */ jsxs("div", { className: "ui-legal-document-rail", children: [
151
- documentNavigation !== void 0 && /* @__PURE__ */ jsx("div", { "data-slot": "legal-document-navigation", children: documentNavigation }),
152
- /* @__PURE__ */ jsxs("nav", { className: "ui-legal-document-toc", "aria-labelledby": contentsId, children: [
153
- /* @__PURE__ */ jsx("p", { id: contentsId, className: "ui-legal-document-toc-title", children: contentsName }),
154
- /* @__PURE__ */ jsx("ol", { className: "ui-legal-document-toc-list", children: sections.map((section) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
155
- "a",
156
- {
157
- href: `#${section.id}`,
158
- className: "ui-legal-document-toc-link",
159
- "data-active": section.id === active ? "" : void 0,
160
- "aria-current": section.id === active ? "location" : void 0,
161
- onClick: (event) => handleContentsClick(event, section.id),
162
- children: section.title
163
- }
164
- ) }, section.id)) })
165
- ] })
166
- ] }),
167
- /* @__PURE__ */ jsx("div", { className: "ui-legal-document-content", children: sections.map((section) => /* @__PURE__ */ jsxs(
168
- "section",
169
- {
170
- id: section.id,
171
- tabIndex: -1,
172
- "data-legal-section": section.id,
173
- "aria-labelledby": `${section.id}-heading`,
174
- className: "ui-legal-document-section",
175
- children: [
176
- /* @__PURE__ */ jsx(Heading, { level: 2, id: `${section.id}-heading`, children: section.title }),
177
- /* @__PURE__ */ jsx("div", { className: "ui-legal-document-section-body", children: section.content })
178
- ]
179
- },
180
- section.id
181
- )) }),
182
- footerAction !== void 0 && /* @__PURE__ */ jsx("footer", { className: "ui-legal-document-footer", children: footerAction })
183
- ] })
178
+ id: section.id,
179
+ tabIndex: -1,
180
+ "data-legal-section": section.id,
181
+ "aria-labelledby": `${section.id}-heading`,
182
+ className: "ui-legal-document-section",
183
+ children: [
184
+ /* @__PURE__ */ jsx(Heading, { level: 2, id: `${section.id}-heading`, children: section.title }),
185
+ /* @__PURE__ */ jsx("div", { className: "ui-legal-document-section-body", children: section.content })
186
+ ]
187
+ },
188
+ section.id
189
+ )) }),
190
+ footerAction !== void 0 && /* @__PURE__ */ jsx("footer", { className: "ui-legal-document-footer", children: footerAction })
191
+ ]
192
+ }
193
+ )
184
194
  }
185
195
  );
186
196
  }
@@ -1310,6 +1310,8 @@ export type ImagePreviewGroupConfigProp = Omit<ImagePreviewConfigProp, "src" | "
1310
1310
  /**
1311
1311
  * @see Image — a picture that opens large in a full-viewport preview (antd `Image`): zoom, rotate,
1312
1312
  * flip, and — inside an `ImagePreviewGroup` — prev/next across every picture of the group.
1313
+ * Lazy by default (gh#1454): `loading` defaults to `"lazy"` (`"eager"` with `fetchPriority="high"`,
1314
+ * the page's LCP picture) and `decoding` to `"async"`; explicit values win.
1313
1315
  */
1314
1316
  export type ImageProp = Omit<React.ImgHTMLAttributes<HTMLImageElement>, "alt" | "placeholder"> & {
1315
1317
  /** Image URL. */
@@ -122,7 +122,8 @@
122
122
  pointer-events: none;
123
123
  }
124
124
 
125
- .ui-button:disabled {
125
+ .ui-button:disabled,
126
+ .ui-button[data-loading] {
126
127
  opacity: var(--disabled-opacity);
127
128
  }
128
129
 
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "33.21.0",
2
+ "version": "33.22.2",
3
3
  "generatedBy": "scripts/gen-style-layers.mjs — do not edit by hand; run `pnpm gen:style-layers`",
4
4
  "base": "base.css",
5
5
  "fonts": "fonts.css",
@@ -1826,6 +1826,15 @@
1826
1826
  grid-column: 2;
1827
1827
  grid-row: 3;
1828
1828
  }
1829
+
1830
+ .ui-legal-document[data-rail="none"] {
1831
+ grid-template-columns: minmax(0, var(--legal-document-measure-max-width));
1832
+ }
1833
+
1834
+ .ui-legal-document[data-rail="none"]
1835
+ > :is(.ui-legal-document-header, .ui-legal-document-content, .ui-legal-document-footer) {
1836
+ grid-column: 1;
1837
+ }
1829
1838
  }
1830
1839
  }
1831
1840
 
@@ -71,6 +71,33 @@
71
71
  translate: 0 var(--logo-glyph-optical-offset, var(--logo-glyph-x-descender-optical-offset));
72
72
  }
73
73
 
74
+ @supports (text-box: trim-both cap alphabetic) {
75
+ .ui-logo-glyph[data-ink] {
76
+ translate: 0 var(--logo-glyph-optical-offset, 0em);
77
+ }
78
+
79
+ .ui-logo-glyph[data-ink="cap-baseline"] {
80
+ text-box: trim-both cap alphabetic;
81
+ }
82
+
83
+ .ui-logo-glyph[data-ink="cap-descender"] {
84
+ text-box: trim-both cap alphabetic;
85
+ }
86
+
87
+ .ui-logo-glyph[data-ink="x-baseline"] {
88
+ text-box: trim-both ex alphabetic;
89
+ }
90
+
91
+ .ui-logo-glyph[data-ink="x-descender"] {
92
+ text-box: trim-both ex alphabetic;
93
+ }
94
+
95
+ .ui-logo-glyph:is([data-ink="cap-descender"], [data-ink="x-descender"]) {
96
+ translate: 0
97
+ var(--logo-glyph-optical-offset, var(--logo-glyph-descender-trimmed-optical-offset));
98
+ }
99
+ }
100
+
74
101
  .ui-logo[data-size="xs"] {
75
102
  width: var(--logo-size-xs);
76
103
  height: var(--logo-size-xs);
@@ -793,7 +793,7 @@
793
793
  }
794
794
 
795
795
  .app-topbar-logo,
796
- .app-topbar-logo > a {
796
+ .app-topbar-logo > a:not(.ui-logo) {
797
797
  display: flex;
798
798
  align-items: center;
799
799
  }