@godxjp/ui 32.8.0 → 32.10.1

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.
Files changed (48) hide show
  1. package/DESIGN.md +11 -3
  2. package/README.md +5 -5
  3. package/agent/DESIGN.md +11 -3
  4. package/agent/START-HERE.md +9 -7
  5. package/agent/components/AppShell.json +1 -0
  6. package/agent/components/BlockEditor.json +1 -0
  7. package/agent/components/PageContainer.json +1 -0
  8. package/agent/components/Progress.json +3 -3
  9. package/agent/components/SearchInput.json +1 -0
  10. package/agent/components/Topbar.json +2 -0
  11. package/agent/components/TopbarItem.json +1 -0
  12. package/agent/components/TopbarSearch.json +49 -0
  13. package/agent/components/Tree.json +1 -0
  14. package/agent/components-index.json +5 -0
  15. package/agent/components.json +60 -3
  16. package/agent/index.json +7 -7
  17. package/agent/llms.txt +7 -7
  18. package/agent/tokens.json +39 -3
  19. package/dist/components/data-display/progress.d.ts +12 -6
  20. package/dist/components/data-display/progress.js +1 -1
  21. package/dist/components/data-display/tree.js +39 -0
  22. package/dist/components/layout/breadcrumb.js +2 -2
  23. package/dist/components/layout/index.d.ts +2 -0
  24. package/dist/components/layout/index.js +2 -0
  25. package/dist/components/layout/page-container.js +2 -2
  26. package/dist/components/layout/topbar-search.d.ts +12 -0
  27. package/dist/components/layout/topbar-search.js +87 -0
  28. package/dist/contracts/measurement.json +1 -1
  29. package/dist/i18n/messages/en.json +1 -0
  30. package/dist/i18n/messages/ja.json +1 -0
  31. package/dist/i18n/messages/vi.json +1 -0
  32. package/dist/props/components/layout.prop.d.ts +22 -0
  33. package/dist/props/registry.d.ts +9 -0
  34. package/dist/props/registry.js +16 -0
  35. package/dist/styles/card-layout.css +1 -1
  36. package/dist/styles/data-display-layout.css +37 -2
  37. package/dist/styles/dialog-layout.css +2 -0
  38. package/dist/styles/layers.json +7 -1
  39. package/dist/styles/navigation-layout.css +3 -0
  40. package/dist/styles/shell-layout.css +123 -2
  41. package/dist/styles.css +1 -1
  42. package/dist/tokens/components/card.css +3 -1
  43. package/dist/tokens/components/data-display.css +2 -0
  44. package/dist/tokens/components/shell.css +7 -0
  45. package/package.json +2 -2
  46. package/scripts/_agent-setup.mjs +10 -5
  47. package/scripts/cli.mjs +16 -7
  48. package/scripts/visual-audit.mjs +1412 -92
package/DESIGN.md CHANGED
@@ -193,19 +193,27 @@ A list whose rows are decisions. Show requester, target, reason, submitted time;
193
193
  - `DataTable` hides `hiddenOnMobile` columns and can stack rows (`collapseBelow`); `Table preset="action-collection"` keeps the actions column visible at 390.
194
194
  - `ResponsiveGrid` columns follow its container. `AppShell` turns the sidebar into a drawer on narrow screens.
195
195
  - Header `extra` wraps under the title; a toolbar wraps its filters. Touch targets 44px at `comfortable`.
196
+ - Below 640px: at most 2 direct actions in `extra` plus one overflow `DropdownMenu` for the rest; it wraps but never prioritises for you.
197
+ - Bar search is `TopbarSearch`, never a bare `SearchInput`: it folds to a named search cell below 640px. To share the content keyline, keep the default `topbarSpan="content"` and put it first in `Topbar start`.
198
+ - Account cell: `TopbarItem icon={<Avatar/>} labelHideBelow="sm"` with the name repeated in the menu's `DropdownMenuLabel`, so a phone shows the avatar only.
199
+ - A sidebar collapse toggle goes in `Sidebar action` (it receives `collapsed`), not in the bar beside the brand. The phone drawer has its own trigger.
196
200
 
197
201
  ## Iteration Guide
198
202
 
199
203
  1. Pick the archetype, call `get_exemplar` and build from that screen, not from memory.
200
- 2. Run `node node_modules/@godxjp/ui/scripts/ui-audit.mjs` until it is clean.
201
- 3. Screenshot at 390, 768 and 1280 next to the exemplar's live preview.
202
- 4. List the differences, fix the top 3 (structure before styling). Stop after 3 rounds.
204
+ 2. `npx @godxjp/ui audit <files>` — zero errors.
205
+ 3. `npx @godxjp/ui visual-audit <url> <routes>` — runs every route at 320, 390, 768, 1024, 1280 and 844×390 (landscape phone) and measures what a screenshot glance misses: clipped or squeezed controls (WCAG 1.4.10 has two halves — no two-way scrolling AND no lost information; page overflow alone checks only the first), compact search, avatar-only identity, editor inset, action count and target size, rail and search keylines, tiny tracked capitals. Zero machine failures at every width; an "unmapped" result is not a pass. Signed-in routes: `--storage-state state.json` (Playwright storageState).
206
+ 4. Inspect every screenshot at every width, region by region — top bar, page header, body, aside or rail, menus and drawers — against the checklist the report prints. A region you were told not to change is still inspected; a defect there becomes an issue, not a silent pass.
207
+ 5. No top-N and no round cap. Stop only when every width has zero machine failures and every checklist row is pass or a written N/A.
208
+ 6. The builder does not accept its own screen. Report "probes passed; independent acceptance pending" with the report JSON, the screenshots per width and the checklist; acceptance comes from someone who did not build it (a person, or a separate agent given only the build and the artifacts). Never call a screen done on self-review.
203
209
 
204
210
  ## Known Gaps
205
211
 
206
212
  - The default primary is neutral by design; a product without a brand colour looks monochrome until one is set.
207
213
  - `ui-audit` checks primitives and tokens, not structure: a page can pass it and still show every Don't above.
214
+ - No edge-mounted rail toggle (a control straddling the sidebar border); `Sidebar action` is the supported place. Under `topbarSpan="full"` the bar shares no keyline with the content column.
208
215
  - `card-per-section` counts Cards per file, so a screen split across components can pass with a Card around every section.
209
216
  - Exemplar previews deploy on release tags, so they can lag `main`. On GitHub Pages a showcase URL answers HTTP 404 and renders through `404.html`, so open it in a browser; a plain fetch sees the 404.
210
217
  - Dark theme (`data-theme="dark"`) is supported; the exemplars are reviewed in light.
218
+ - From 640px up, `BlockEditor` text does not share the keyline of the `Input` above it: measured at 768/1024/1280, input text 13px inside its frame, editor text 57px inside (Δ44px), because the ⋮⋮/+ handles (two 24px targets) sit in a start gutter inside the frame. Aligning the text would put the handles outside the field border, where a content column 24px from the viewport edge has no room. Below 640px the gutter collapses (C05). Accepted, not a defect to fix in the app.
211
219
  - On narrow screens the `PageContainer` title steps down (≈17.6px) while body h2 stays ≈15.7px — one step apart. A document page not built on `LegalDocumentShell` keeps only that step on phones; there is no intermediate page-title size yet.
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 — 161 components, 2197 tokens, 43 cardinal rules — is published in two forms from one
21
+ The catalog — 162 components, 2203 tokens, 43 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
 
@@ -51,12 +51,12 @@ static files straight from this public repo — no hosting, no deploy step:
51
51
  | --- | --- | --- |
52
52
  | [`agent/START-HERE.md`](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/START-HERE.md) | 11 KB | **read first** — self-contained: the four rules, the token override model, a page that passes review |
53
53
  | [`agent/llms.txt`](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/llms.txt) | 3 KB | the [llms.txt](https://llmstxt.org/) entry point |
54
- | [`agent/DESIGN.md`](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/DESIGN.md) | 14 KB | the visual spec: tokens, colour scarcity, admin screen anatomy, do/don't |
54
+ | [`agent/DESIGN.md`](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/DESIGN.md) | 16 KB | the visual spec: tokens, colour scarcity, admin screen anatomy, do/don't |
55
55
  | [`agent/index.json`](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/index.json) | 3 KB | manifest: version, counts, every file's URL |
56
- | [`agent/components-index.json`](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/components-index.json) | 47 KB | all 161 as name + group + tagline — **fetch this first** |
56
+ | [`agent/components-index.json`](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/components-index.json) | 48 KB | all 162 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–37 KB | one file per component, each with its `importPath` — **this is the route to take** |
58
- | [`agent/components.json`](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/components.json) | 1.2 MB | all 161 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) | 846 KB | all 2197 design tokens, their values and why they exist |
58
+ | [`agent/components.json`](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/components.json) | 1.2 MB | all 162 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) | 848 KB | all 2203 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) | 21 KB | the 43 cardinal rules |
62
62
  <!-- prettier-ignore-end -->
package/agent/DESIGN.md CHANGED
@@ -193,19 +193,27 @@ A list whose rows are decisions. Show requester, target, reason, submitted time;
193
193
  - `DataTable` hides `hiddenOnMobile` columns and can stack rows (`collapseBelow`); `Table preset="action-collection"` keeps the actions column visible at 390.
194
194
  - `ResponsiveGrid` columns follow its container. `AppShell` turns the sidebar into a drawer on narrow screens.
195
195
  - Header `extra` wraps under the title; a toolbar wraps its filters. Touch targets 44px at `comfortable`.
196
+ - Below 640px: at most 2 direct actions in `extra` plus one overflow `DropdownMenu` for the rest; it wraps but never prioritises for you.
197
+ - Bar search is `TopbarSearch`, never a bare `SearchInput`: it folds to a named search cell below 640px. To share the content keyline, keep the default `topbarSpan="content"` and put it first in `Topbar start`.
198
+ - Account cell: `TopbarItem icon={<Avatar/>} labelHideBelow="sm"` with the name repeated in the menu's `DropdownMenuLabel`, so a phone shows the avatar only.
199
+ - A sidebar collapse toggle goes in `Sidebar action` (it receives `collapsed`), not in the bar beside the brand. The phone drawer has its own trigger.
196
200
 
197
201
  ## Iteration Guide
198
202
 
199
203
  1. Pick the archetype, call `get_exemplar` and build from that screen, not from memory.
200
- 2. Run `node node_modules/@godxjp/ui/scripts/ui-audit.mjs` until it is clean.
201
- 3. Screenshot at 390, 768 and 1280 next to the exemplar's live preview.
202
- 4. List the differences, fix the top 3 (structure before styling). Stop after 3 rounds.
204
+ 2. `npx @godxjp/ui audit <files>` — zero errors.
205
+ 3. `npx @godxjp/ui visual-audit <url> <routes>` — runs every route at 320, 390, 768, 1024, 1280 and 844×390 (landscape phone) and measures what a screenshot glance misses: clipped or squeezed controls (WCAG 1.4.10 has two halves — no two-way scrolling AND no lost information; page overflow alone checks only the first), compact search, avatar-only identity, editor inset, action count and target size, rail and search keylines, tiny tracked capitals. Zero machine failures at every width; an "unmapped" result is not a pass. Signed-in routes: `--storage-state state.json` (Playwright storageState).
206
+ 4. Inspect every screenshot at every width, region by region — top bar, page header, body, aside or rail, menus and drawers — against the checklist the report prints. A region you were told not to change is still inspected; a defect there becomes an issue, not a silent pass.
207
+ 5. No top-N and no round cap. Stop only when every width has zero machine failures and every checklist row is pass or a written N/A.
208
+ 6. The builder does not accept its own screen. Report "probes passed; independent acceptance pending" with the report JSON, the screenshots per width and the checklist; acceptance comes from someone who did not build it (a person, or a separate agent given only the build and the artifacts). Never call a screen done on self-review.
203
209
 
204
210
  ## Known Gaps
205
211
 
206
212
  - The default primary is neutral by design; a product without a brand colour looks monochrome until one is set.
207
213
  - `ui-audit` checks primitives and tokens, not structure: a page can pass it and still show every Don't above.
214
+ - No edge-mounted rail toggle (a control straddling the sidebar border); `Sidebar action` is the supported place. Under `topbarSpan="full"` the bar shares no keyline with the content column.
208
215
  - `card-per-section` counts Cards per file, so a screen split across components can pass with a Card around every section.
209
216
  - Exemplar previews deploy on release tags, so they can lag `main`. On GitHub Pages a showcase URL answers HTTP 404 and renders through `404.html`, so open it in a browser; a plain fetch sees the 404.
210
217
  - Dark theme (`data-theme="dark"`) is supported; the exemplars are reviewed in light.
218
+ - From 640px up, `BlockEditor` text does not share the keyline of the `Input` above it: measured at 768/1024/1280, input text 13px inside its frame, editor text 57px inside (Δ44px), because the ⋮⋮/+ handles (two 24px targets) sit in a start gutter inside the frame. Aligning the text would put the handles outside the field border, where a content column 24px from the viewport edge has no room. Below 640px the gutter collapses (C05). Accepted, not a defect to fix in the app.
211
219
  - On narrow screens the `PageContainer` title steps down (≈17.6px) while body h2 stays ≈15.7px — one step apart. A document page not built on `LegalDocumentShell` keeps only that step on phones; there is no intermediate page-title size yet.
@@ -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` 32.8.0.** If the project you are editing has a different
6
+ **This catalog describes `@godxjp/ui` 32.10.1.** 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.
@@ -39,8 +39,10 @@ disk, and costs far fewer tokens than fetching a 1 MB JSON.
39
39
  ```
40
40
 
41
41
  Then, before any JSX: `get_design` (the visual target), `route_consumer_task`, `get_exemplar` for
42
- the closest screen, `search_components` → `get_component`. After building, screenshot at
43
- 390 / 768 / 1280 beside the exemplar and fix the top 3 differences, at most 3 rounds.
42
+ the closest screen, `search_components` → `get_component`. After building, run
43
+ `npx @godxjp/ui visual-audit` at 320 / 390 / 768 / 1024 / 1280 / 844×390 to zero failures,
44
+ inspect every screenshot at every width region by region (no top-N cap), and hand over as
45
+ "probes passed; independent acceptance pending" — the builder does not accept its own screen.
44
46
 
45
47
  **You cannot run a process** (ChatGPT web · Claude.ai · anything fetching URLs)
46
48
  → These files are for you. Read `DESIGN.md` (in this folder) first: tokens, scarcity rules and
@@ -50,7 +52,7 @@ screen anatomy, the visual target the rules below do not give you. Then fetch in
50
52
  task is a task** — "build a settings page", "confirm a destructive delete", "a list page with
51
53
  filters" — start HERE, not at the components. Then fetch `patterns/<name>.json` for complete,
52
54
  copy-paste-ready code. A component index answers "does X exist"; it cannot answer "build Y".
53
- 1. `components-index.json` — 47 KB, all 161 components as name + group +
55
+ 1. `components-index.json` — 48 KB, all 162 components as name + group +
54
56
  tagline. Read this when you already know the SHAPE you need. Each entry may carry `absorbed`:
55
57
  names that **do not exist** and map to it — `Combobox`, `Autocomplete`, `CountrySelect` and
56
58
  `SearchSelect` are all `Select`. If you are about to hand-roll something, search this field
@@ -59,10 +61,10 @@ screen anatomy, the visual target the rules below do not give you. Then fetch in
59
61
  its `importPath`, and its examples. Fetch only the handful you picked in step 1.
60
62
  3. `rules.json` — 43 cardinal rules. The ones about raw HTML and hardcoded colour are not
61
63
  style advice.
62
- 4. `tokens.json` — 2197 design tokens, each tagged with its `tier`. **If you were handed a
64
+ 4. `tokens.json` — 2203 design tokens, each tagged with its `tier`. **If you were handed a
63
65
  brand, read the 211 `foundation` entries first** — `--primary`, `--background`,
64
66
  `--radius`, `--font-size-base` are the handful everything else derives from. The
65
- 1874 `component` entries are per-part knobs; reach for one only when a role is
67
+ 1880 `component` entries are per-part knobs; reach for one only when a role is
66
68
  right everywhere except one component.
67
69
  5. `anti-ai-tells.json` — 35 shapes that make generated UI look generated, each with the
68
70
  fix. Read before you reach for a gradient hero or a wall of coloured chips.
@@ -148,7 +150,7 @@ has stopped following the brand.
148
150
  |---|---|---|---|
149
151
  | `foundation` | 211 | 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` |
150
152
  | `semantic` | 112 | 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 |
151
- | `component` | 1874 | 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` | 1880 | 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` |
152
154
 
153
155
  A token whose `value` is `initial` is not empty and not broken: `initial` is the guaranteed-invalid
154
156
  value, so the real default is computed where the element paints it. Set it and yours wins.
@@ -137,6 +137,7 @@
137
137
  "storyPath": "layout/app-shell.tsx",
138
138
  "tagline": "Root application shell — composes sidebar, topbar rail, main content area, and optional footer.",
139
139
  "usage": [
140
+ "DO put a sidebar collapse toggle IN the rail, not floating in the bar (ADR C10): the shell does not render one, so pass it through `Sidebar action={(collapsed) => <Button variant=\"ghost\" size=\"icon\" aria-label={t(\"toggleSidebar\")} aria-expanded={!collapsed} …/>}` (or the `footer` render-prop), which keeps it attached to the rail in both states. A toggle in `Topbar start` under `topbarSpan=\"full\"` lands beside the brand, detached from the rail it controls. The shell has no edge-mounted toggle (a control straddling the rail border); `Sidebar action` keeps it inside the rail head, which is the supported placement. Below the navigation boundary the drawer has its own trigger; render no collapse toggle there.",
140
141
  "useAppShellNavigationMode() returns drawer/docked at the same 56.25rem boundary as AppShell. The root also publishes data-navigation. Use this instead of a consumer media query.",
141
142
  "DO pass a <Sidebar> node to `sidebar` (required) and page content to `children` (required) — these are the only two required props. Everything else is optional and omitting optional slots simply removes that zone from the rendered DOM.",
142
143
  "DO rely on AppShell's OWNED mobile drawer at or below 900px (NOT the Tailwind `lg` 1024px step — the shipped media query is `width <= 56.25rem`): it renders a hamburger trigger in the topbar and a focus-trapped Sheet (Esc + overlay close, focus returns to the trigger). `mobileNav` defaults to the `sidebar` node, so the same nav is reachable on mobile with no wiring — never hide the sidebar without providing this. Pass a tailored `mobileNav`, or `mobileNav={null}` only when navigation lives elsewhere (e.g. a bottom bar).",
@@ -80,6 +80,7 @@
80
80
  "storyPath": "data-entry/block-editor.tsx",
81
81
  "tagline": "Notion / note.com style block editor (sibling package `@godxjp/block-editor`, versioned with the kit) that reads and writes MARKDOWN through `@godxjp/markdown/codec`: what onValueChange returns is byte-for-byte normalize(body). `/` block menu at the caret, ⋮⋮ handle (drag, turn into, duplicate, move, delete), floating format toolbar, `[[` wikilink suggestions, paste / drop uploads through the host, IME-safe, ja / en / vi (gh#1156).",
82
82
  "usage": [
83
+ "Below 40rem the handle gutter collapses to `--block-editor-compact-gutter-inline-size` (the frame inset, 12px) and the + / ⋮⋮ handle rises above the caret's block at its inline end (ADR C05): first line 56px → 12px from the inner edge at 390px. Touch: tap a block to show its handle; ⋮⋮ opens Move up / Move down / Duplicate / Delete. Keyboard: Mod+/ opens the same menu, Alt+Shift+↑↓ moves the block.",
83
84
  "Clicking a link (or Mod+K) opens a settings drawer: text, URL, title, open / remove. Clicking an image opens one for src, alt, title, replace (pickMedia / upload) and remove. Markdown stores no link target, so there is no target field. A link in the editor never navigates mid-edit.",
84
85
  "YAML front matter shows as a Properties block at the top and round-trips verbatim; read it with frontmatterOf() from @godxjp/markdown/codec.",
85
86
  "DO store the Markdown it emits — it is already canonical; compute `normalize()` server-side from the same codec to verify.",
@@ -157,6 +157,7 @@
157
157
  "storyPath": "layout/page-container.tsx",
158
158
  "tagline": "Mandatory page shell — EVERY page wraps its content in PageContainer (title/subtitle/extra/footer/breadcrumb).",
159
159
  "usage": [
160
+ "DO keep at most 2 direct actions plus ONE overflow `DropdownMenu` in `extra` when the page is used on a phone (ADR C06, compact = below 40rem): `extra={<><Button variant=\"outline\">Share</Button><Button>Edit</Button><DropdownMenu><DropdownMenuTrigger asChild><Button variant=\"outline\" size=\"icon\" aria-label={t(\"more\")}><MoreHorizontal /></Button></DropdownMenuTrigger>…</DropdownMenu></>}`. A favourite toggle, a copy-link and the rest go in the menu. The header wraps `extra` under the title but never prioritises it for you.",
160
161
  "DO: Always wrap every page's content in PageContainer — it is the mandatory page shell. Pass `title` (required, rendered as `<h1>`) for every page; omitting it leaves the page without an accessible heading.",
161
162
  "CANONICAL PAGE-HEADER CONTRACT: PageContainer's embedded header IS the DXS `PageHeader` — there is deliberately NO separate PageHeader export, so the page header cannot be re-created or nested. It owns breadcrumbs (`breadcrumb`), title (`title`), subtitle/description (`subtitle`), status/meta (`status`), actions (`extra`) and responsive overflow (`headerLayout` + `measure`). Loading/error/denied are compositions of siblings, never hand-rolls: skeleton `title`/`subtitle` content or `SkeletonDetail` body while a detail loads; `ErrorSurface` (from @godxjp/ui/layout) REPLACES the page for denied (403) / not-found (404) / failed (5xx) whole-page states; `Alert.QueryError` / `DataState` own an in-body query failure.",
162
163
  "DO: Use the `extra` prop (not a sibling div, not a wrapper) for action buttons or controls that sit right of the title row — e.g. `extra={<Button>新規作成</Button>}`. Use the `footer` prop for a pinned action bar below the body (e.g. Save/Cancel on a form page); combine with `stickyFooter` to pin it to the viewport bottom on scroll.",
@@ -31,10 +31,10 @@
31
31
  "type": "string"
32
32
  },
33
33
  {
34
- "defaultValue": "\"success\"",
35
- "description": "Bar colour tone. Over-capacity defaults to destructive.",
34
+ "defaultValue": "\"primary\"",
35
+ "description": "Bar colour tone. `primary` (default since gh#1308) is the brand role for ordinary progress — a reading position, an upload; pass a status tone only when the bar reports that status (ADR C09: `success` for a completed/healthy state, `warning`/`destructive` for limits). Over-capacity defaults to destructive.",
36
36
  "name": "tone",
37
- "type": "\"success\" | \"warning\" | \"destructive\""
37
+ "type": "\"primary\" | \"success\" | \"warning\" | \"destructive\""
38
38
  },
39
39
  {
40
40
  "defaultValue": "false",
@@ -92,6 +92,7 @@
92
92
  "storyPath": "data-entry/search-input.tsx",
93
93
  "tagline": "Debounced search box with a clear button. Fires onSearch (NOT onChange) after the debounce. Controlled (value) or uncontrolled (defaultValue).",
94
94
  "usage": [
95
+ "DON'T drop a bare SearchInput into a Topbar slot — use `TopbarSearch` (layout), which passes every SearchInput prop through and folds to a search cell below 40rem instead of shrinking under 8ch (ADR C02).",
95
96
  "DO: listen to `onSearch`, not `onChange`. The component debounces internally (default 250 ms) and fires `onSearch(q)` after the delay — never wire your filter logic to `onChange` on SearchInput because it does not expose one.",
96
97
  "DO: choose controlled vs uncontrolled deliberately. Pass `value` + `onValueChange` together for controlled mode; optionally add `onSearch` for debounced effects (e.g. when search state lives in a URL param or shared parent). For local-only ephemeral search pass only `defaultValue` + `onSearch` — omitting `value` puts the component in uncontrolled mode.",
97
98
  "DO: supply an `ariaLabel` (or visible `label`) when no adjacent label exists. Without either prop, SearchInput falls back to the i18n key `common.search` rendered as a visually-hidden `<Label>` — still accessible, but providing a context-specific string (e.g. `ariaLabel='請求書を検索'`) is more descriptive for screen readers.",
@@ -65,6 +65,8 @@
65
65
  "storyPath": "layout/topbar.tsx",
66
66
  "tagline": "A PURE SLOT bar for the app shell — positions three clusters (start / center / end) and owns ONLY the bar layout. It bakes NO chrome: no product switcher, no search box, no notification bell, no language picker. The CONSUMER composes those from real primitives and drops them into a slot; whether a control is icon-only / labelled / bordered is that control's own config, never the shell's.",
67
67
  "usage": [
68
+ "DO use `TopbarSearch`, not a bare `SearchInput`, for the bar's search (ADR C02): a SearchInput in a slot shrinks with the cluster — measured at 390px in a consumer bar its text area was 0ch. TopbarSearch keeps at least 8ch from 40rem up and folds to a named search cell below it.",
69
+ "DO align the bar's search with the content column (ADR C11) by composition: keep AppShell's default `topbarSpan=\"content\"` and put `TopbarSearch` FIRST in `start` — the bar then starts on the rail edge with the same inset as PageContainer, measured 0px apart at 1024/1280/1440. Under `topbarSpan=\"full\"` the bar starts at the window edge after the brand, so no keyline is shared; there, put the search in `end` deliberately rather than near a column it cannot meet.",
68
70
  "DO compose the bar yourself: a brand mark (an `Avatar`) + sidebar toggle in `start`, a search trigger in `center`, settings pickers + notifications + user menu in `end`. The shell only positions; it never decides WHICH controls exist.",
69
71
  "DO build the sidebar toggle as a `TopbarItem` with a `PanelLeftClose`/`PanelLeftOpen` icon and your own `t()` aria-label, wired to AppShell's `sidebarCollapsed`. There is no baked toggle — but there IS a bar CELL, and it is not a Button: a Button in a slot is a --control-height pill floating in a taller bar, with its own hover fill and a ring drawn around the pill instead of the cell. The same holds for the notifications bell and the account trigger.",
70
72
  "DO put a locale/theme switcher in `end` using `AppSettingPicker` (or your own control) — icon-only vs labelled, bordered vs not, is THAT component's prop, not Topbar's. Topbar does not ship or force a language picker.",
@@ -65,6 +65,7 @@
65
65
  "storyPath": "layout/topbar-item.tsx",
66
66
  "tagline": "ONE interactive cell of a Topbar slot — the account button, a settings or notifications trigger. Full bar height, the bar's own hover surface, and the focus mark hosted INSIDE the cell. Use it INSTEAD OF a Button in a Topbar slot: a Button there is a --control-height pill floating in a taller bar, with its own hover fill and a ring drawn around the pill.",
67
67
  "usage": [
68
+ "DO collapse the account cell to its avatar on a phone (ADR C04): `<DropdownMenuTrigger asChild><TopbarItem aria-label={t(\"account\")} icon={<Avatar>…</Avatar>} labelHideBelow=\"sm\">{name}</TopbarItem></DropdownMenuTrigger>` and repeat the name (and email) in the menu's `DropdownMenuLabel`. Measured at 390px: without `labelHideBelow` the name took 74px of a 390px bar; with it the cell is 48x47, named, and the name is read in the open menu.",
68
69
  "DO put bar triggers in a Topbar slot as TopbarItem, not as Button — that is the difference between chrome and a control that landed in the chrome.",
69
70
  "DO wrap it in a DropdownMenuTrigger asChild for a user menu; the open state lights the cell via [data-state=open].",
70
71
  "DON'T set a height: the cell stretches to whatever the bar is (AppShell's grid row, --topbar-height, or the coarse-pointer bar), which is why there is no height knob.",
@@ -0,0 +1,49 @@
1
+ {
2
+ "example": "import { Topbar, TopbarSearch } from \"@godxjp/ui/layout\";\n\n<Topbar\n start={\n <TopbarSearch\n ariaLabel={t(\"searchInCollection\")}\n placeholder={t(\"searchInCollection\")}\n onSearch={(q) => navigate({ to: \"/search\", search: { q } })}\n />\n }\n/>",
3
+ "group": "layout",
4
+ "importPath": "@godxjp/ui/layout",
5
+ "name": "TopbarSearch",
6
+ "props": [
7
+ {
8
+ "defaultValue": "\"sm\"",
9
+ "description": "The step below which the field folds to a TopbarItem search cell (sm 40rem · md 48rem · lg 64rem · xl 80rem). CSS decides at the step, so SSR and the first paint agree and the typed query survives a resize.",
10
+ "name": "collapseBelow",
11
+ "type": "BreakpointProp"
12
+ },
13
+ {
14
+ "description": "The search's accessible name — the field's AND the folded cell's. Defaults to the localized \"Search\". Name the scope (\"Search this collection\").",
15
+ "name": "ariaLabel",
16
+ "type": "string"
17
+ },
18
+ {
19
+ "description": "Every SearchInput prop passes through unchanged: value / defaultValue / onValueChange, onSearch, placeholder, debounce, shortcut, status, disabled.",
20
+ "name": "…SearchInputProp",
21
+ "type": "SearchInputProp"
22
+ }
23
+ ],
24
+ "related": [
25
+ "SearchInput (the field it renders)",
26
+ "TopbarItem (the folded cell)",
27
+ "Topbar (the slot bar it belongs to)",
28
+ "CommandPalette (⌘K jump-to; a different task from searching content)"
29
+ ],
30
+ "rules": [
31
+ 2,
32
+ 3,
33
+ 5,
34
+ 6
35
+ ],
36
+ "storyPath": "layout/topbar-search.tsx",
37
+ "tagline": "The bar's one search box. From 40rem up an inline SearchInput whose text area never shrinks below 8ch; below it a named search cell that opens the field across the whole bar (Material 3 search bar → search view). Escape or the close cell folds it and returns focus to the cell.",
38
+ "usage": [
39
+ "DO use it for the search in a Topbar slot instead of a bare SearchInput: a SearchInput there shrinks with the cluster (0ch of text at 390px, measured in a consumer bar).",
40
+ "DO name the scope in `ariaLabel`; it is the folded cell's only name.",
41
+ "DO put it FIRST in `Topbar start` under the default `topbarSpan=\"content\"` when the search belongs to the page column: it then starts on the content keyline (0px apart at 1280).",
42
+ "DON'T also render a separate search icon button for phones — the folded cell IS that button.",
43
+ "Keyboard: Enter/Space on the cell opens and focuses the field; Escape closes and returns focus; Tab out of the open field folds it and leaves focus where it went. The cell is an APG disclosure (aria-expanded / aria-controls)."
44
+ ],
45
+ "useCases": [
46
+ "A collection or workspace search in the app bar",
47
+ "A global search that must survive a 320–390px phone bar"
48
+ ]
49
+ }
@@ -209,6 +209,7 @@
209
209
  "tagline": "The standalone WAI-ARIA tree view on a page (antd `Tree` / `DirectoryTree`) — nested `treeData`, a disclosure triangle per branch, roving-tabindex arrow navigation, optional tri-state checkboxes, async `loadData` and `draggable` reorder/reparent (antd `onDrop`). Reach for it whenever nodes expand, collapse or are navigated by keyboard; TreeSelect is the same hierarchy inside a Popover.",
210
210
  "usage": [
211
211
  "DO name the tree — pass `aria-label` (through your own `t()`) or `aria-labelledby`. A tree with no name is an unlabelled landmark for every screen reader user.",
212
+ "DO rely on Tree for a cut label (gh#1308): a label that is actually truncated gets its full text as a `title` and unfolds while its row holds keyboard focus (not in a windowed tree, whose rows share one height — the `title` stays). No `titleRender` wrapper with a hand-set `title` is needed; one you set is kept.",
212
213
  "DO keep SELECTION and CHECKS apart: `value`/`onValueChange` is which node is open in the detail pane; `checkedValues`/`onCheckedValuesChange` is which nodes are ticked. They are two axes, exactly as in antd — never drive one from the other.",
213
214
  "DO keep SELECTION and EXPANSION apart too — this is the THIRD axis and the one gh#910 tripped on. `onValueChange` says which node a detail pane should show; `onExpandedValuesChange` says which branches are unfolded. A sibling pane listens to the first and ignores the second, so unfolding a branch cannot reload it. If your pane reloads when a branch opens, it is being driven from the wrong event — not from a missing feature.",
214
215
  "DO let the keyboard work: the tree ships the full APG contract (Up/Down through visible nodes, Right expands then descends, Left collapses then climbs, Home/End, Enter/Space, `*` to expand the current level, type-ahead). Do not add your own key handling on top.",
@@ -103,6 +103,11 @@
103
103
  "name": "TopbarItem",
104
104
  "tagline": "ONE interactive cell of a Topbar slot — the account button, a settings or notifications trigger. Full bar height, the bar's own hover surface, and the focus mark hosted INSIDE the cell. Use it INSTEAD OF a Button in a Topbar slot: a Button there is a --control-height pill floating in a taller bar, with its own hover fill and a ring drawn around the pill."
105
105
  },
106
+ {
107
+ "group": "layout",
108
+ "name": "TopbarSearch",
109
+ "tagline": "The bar's one search box. From 40rem up an inline SearchInput whose text area never shrinks below 8ch; below it a named search cell that opens the field across the whole bar (Material 3 search bar → search view). Escape or the close cell folds it and returns focus to the cell."
110
+ },
106
111
  {
107
112
  "group": "layout",
108
113
  "name": "NavList",
@@ -802,6 +802,7 @@
802
802
  "storyPath": "layout/page-container.tsx",
803
803
  "tagline": "Mandatory page shell — EVERY page wraps its content in PageContainer (title/subtitle/extra/footer/breadcrumb).",
804
804
  "usage": [
805
+ "DO keep at most 2 direct actions plus ONE overflow `DropdownMenu` in `extra` when the page is used on a phone (ADR C06, compact = below 40rem): `extra={<><Button variant=\"outline\">Share</Button><Button>Edit</Button><DropdownMenu><DropdownMenuTrigger asChild><Button variant=\"outline\" size=\"icon\" aria-label={t(\"more\")}><MoreHorizontal /></Button></DropdownMenuTrigger>…</DropdownMenu></>}`. A favourite toggle, a copy-link and the rest go in the menu. The header wraps `extra` under the title but never prioritises it for you.",
805
806
  "DO: Always wrap every page's content in PageContainer — it is the mandatory page shell. Pass `title` (required, rendered as `<h1>`) for every page; omitting it leaves the page without an accessible heading.",
806
807
  "CANONICAL PAGE-HEADER CONTRACT: PageContainer's embedded header IS the DXS `PageHeader` — there is deliberately NO separate PageHeader export, so the page header cannot be re-created or nested. It owns breadcrumbs (`breadcrumb`), title (`title`), subtitle/description (`subtitle`), status/meta (`status`), actions (`extra`) and responsive overflow (`headerLayout` + `measure`). Loading/error/denied are compositions of siblings, never hand-rolls: skeleton `title`/`subtitle` content or `SkeletonDetail` body while a detail loads; `ErrorSurface` (from @godxjp/ui/layout) REPLACES the page for denied (403) / not-found (404) / failed (5xx) whole-page states; `Alert.QueryError` / `DataState` own an in-body query failure.",
807
808
  "DO: Use the `extra` prop (not a sibling div, not a wrapper) for action buttons or controls that sit right of the title row — e.g. `extra={<Button>新規作成</Button>}`. Use the `footer` prop for a pinned action bar below the body (e.g. Save/Cancel on a form page); combine with `stickyFooter` to pin it to the viewport bottom on scroll.",
@@ -1322,6 +1323,7 @@
1322
1323
  "storyPath": "layout/app-shell.tsx",
1323
1324
  "tagline": "Root application shell — composes sidebar, topbar rail, main content area, and optional footer.",
1324
1325
  "usage": [
1326
+ "DO put a sidebar collapse toggle IN the rail, not floating in the bar (ADR C10): the shell does not render one, so pass it through `Sidebar action={(collapsed) => <Button variant=\"ghost\" size=\"icon\" aria-label={t(\"toggleSidebar\")} aria-expanded={!collapsed} …/>}` (or the `footer` render-prop), which keeps it attached to the rail in both states. A toggle in `Topbar start` under `topbarSpan=\"full\"` lands beside the brand, detached from the rail it controls. The shell has no edge-mounted toggle (a control straddling the rail border); `Sidebar action` keeps it inside the rail head, which is the supported placement. Below the navigation boundary the drawer has its own trigger; render no collapse toggle there.",
1325
1327
  "useAppShellNavigationMode() returns drawer/docked at the same 56.25rem boundary as AppShell. The root also publishes data-navigation. Use this instead of a consumer media query.",
1326
1328
  "DO pass a <Sidebar> node to `sidebar` (required) and page content to `children` (required) — these are the only two required props. Everything else is optional and omitting optional slots simply removes that zone from the rendered DOM.",
1327
1329
  "DO rely on AppShell's OWNED mobile drawer at or below 900px (NOT the Tailwind `lg` 1024px step — the shipped media query is `width <= 56.25rem`): it renders a hamburger trigger in the topbar and a focus-trapped Sheet (Esc + overlay close, focus returns to the trigger). `mobileNav` defaults to the `sidebar` node, so the same nav is reachable on mobile with no wiring — never hide the sidebar without providing this. Pass a tailored `mobileNav`, or `mobileNav={null}` only when navigation lives elsewhere (e.g. a bottom bar).",
@@ -1746,6 +1748,8 @@
1746
1748
  "storyPath": "layout/topbar.tsx",
1747
1749
  "tagline": "A PURE SLOT bar for the app shell — positions three clusters (start / center / end) and owns ONLY the bar layout. It bakes NO chrome: no product switcher, no search box, no notification bell, no language picker. The CONSUMER composes those from real primitives and drops them into a slot; whether a control is icon-only / labelled / bordered is that control's own config, never the shell's.",
1748
1750
  "usage": [
1751
+ "DO use `TopbarSearch`, not a bare `SearchInput`, for the bar's search (ADR C02): a SearchInput in a slot shrinks with the cluster — measured at 390px in a consumer bar its text area was 0ch. TopbarSearch keeps at least 8ch from 40rem up and folds to a named search cell below it.",
1752
+ "DO align the bar's search with the content column (ADR C11) by composition: keep AppShell's default `topbarSpan=\"content\"` and put `TopbarSearch` FIRST in `start` — the bar then starts on the rail edge with the same inset as PageContainer, measured 0px apart at 1024/1280/1440. Under `topbarSpan=\"full\"` the bar starts at the window edge after the brand, so no keyline is shared; there, put the search in `end` deliberately rather than near a column it cannot meet.",
1749
1753
  "DO compose the bar yourself: a brand mark (an `Avatar`) + sidebar toggle in `start`, a search trigger in `center`, settings pickers + notifications + user menu in `end`. The shell only positions; it never decides WHICH controls exist.",
1750
1754
  "DO build the sidebar toggle as a `TopbarItem` with a `PanelLeftClose`/`PanelLeftOpen` icon and your own `t()` aria-label, wired to AppShell's `sidebarCollapsed`. There is no baked toggle — but there IS a bar CELL, and it is not a Button: a Button in a slot is a --control-height pill floating in a taller bar, with its own hover fill and a ring drawn around the pill instead of the cell. The same holds for the notifications bell and the account trigger.",
1751
1755
  "DO put a locale/theme switcher in `end` using `AppSettingPicker` (or your own control) — icon-only vs labelled, bordered vs not, is THAT component's prop, not Topbar's. Topbar does not ship or force a language picker.",
@@ -1830,6 +1834,7 @@
1830
1834
  "storyPath": "layout/topbar-item.tsx",
1831
1835
  "tagline": "ONE interactive cell of a Topbar slot — the account button, a settings or notifications trigger. Full bar height, the bar's own hover surface, and the focus mark hosted INSIDE the cell. Use it INSTEAD OF a Button in a Topbar slot: a Button there is a --control-height pill floating in a taller bar, with its own hover fill and a ring drawn around the pill.",
1832
1836
  "usage": [
1837
+ "DO collapse the account cell to its avatar on a phone (ADR C04): `<DropdownMenuTrigger asChild><TopbarItem aria-label={t(\"account\")} icon={<Avatar>…</Avatar>} labelHideBelow=\"sm\">{name}</TopbarItem></DropdownMenuTrigger>` and repeat the name (and email) in the menu's `DropdownMenuLabel`. Measured at 390px: without `labelHideBelow` the name took 74px of a 390px bar; with it the cell is 48x47, named, and the name is read in the open menu.",
1833
1838
  "DO put bar triggers in a Topbar slot as TopbarItem, not as Button — that is the difference between chrome and a control that landed in the chrome.",
1834
1839
  "DO wrap it in a DropdownMenuTrigger asChild for a user menu; the open state lights the cell via [data-state=open].",
1835
1840
  "DON'T set a height: the cell stretches to whatever the bar is (AppShell's grid row, --topbar-height, or the coarse-pointer bar), which is why there is no height knob.",
@@ -1843,6 +1848,55 @@
1843
1848
  "Sidebar collapse toggle in the topbar start slot"
1844
1849
  ]
1845
1850
  },
1851
+ {
1852
+ "example": "import { Topbar, TopbarSearch } from \"@godxjp/ui/layout\";\n\n<Topbar\n start={\n <TopbarSearch\n ariaLabel={t(\"searchInCollection\")}\n placeholder={t(\"searchInCollection\")}\n onSearch={(q) => navigate({ to: \"/search\", search: { q } })}\n />\n }\n/>",
1853
+ "group": "layout",
1854
+ "importPath": "@godxjp/ui/layout",
1855
+ "name": "TopbarSearch",
1856
+ "props": [
1857
+ {
1858
+ "defaultValue": "\"sm\"",
1859
+ "description": "The step below which the field folds to a TopbarItem search cell (sm 40rem · md 48rem · lg 64rem · xl 80rem). CSS decides at the step, so SSR and the first paint agree and the typed query survives a resize.",
1860
+ "name": "collapseBelow",
1861
+ "type": "BreakpointProp"
1862
+ },
1863
+ {
1864
+ "description": "The search's accessible name — the field's AND the folded cell's. Defaults to the localized \"Search\". Name the scope (\"Search this collection\").",
1865
+ "name": "ariaLabel",
1866
+ "type": "string"
1867
+ },
1868
+ {
1869
+ "description": "Every SearchInput prop passes through unchanged: value / defaultValue / onValueChange, onSearch, placeholder, debounce, shortcut, status, disabled.",
1870
+ "name": "…SearchInputProp",
1871
+ "type": "SearchInputProp"
1872
+ }
1873
+ ],
1874
+ "related": [
1875
+ "SearchInput (the field it renders)",
1876
+ "TopbarItem (the folded cell)",
1877
+ "Topbar (the slot bar it belongs to)",
1878
+ "CommandPalette (⌘K jump-to; a different task from searching content)"
1879
+ ],
1880
+ "rules": [
1881
+ 2,
1882
+ 3,
1883
+ 5,
1884
+ 6
1885
+ ],
1886
+ "storyPath": "layout/topbar-search.tsx",
1887
+ "tagline": "The bar's one search box. From 40rem up an inline SearchInput whose text area never shrinks below 8ch; below it a named search cell that opens the field across the whole bar (Material 3 search bar → search view). Escape or the close cell folds it and returns focus to the cell.",
1888
+ "usage": [
1889
+ "DO use it for the search in a Topbar slot instead of a bare SearchInput: a SearchInput there shrinks with the cluster (0ch of text at 390px, measured in a consumer bar).",
1890
+ "DO name the scope in `ariaLabel`; it is the folded cell's only name.",
1891
+ "DO put it FIRST in `Topbar start` under the default `topbarSpan=\"content\"` when the search belongs to the page column: it then starts on the content keyline (0px apart at 1280).",
1892
+ "DON'T also render a separate search icon button for phones — the folded cell IS that button.",
1893
+ "Keyboard: Enter/Space on the cell opens and focuses the field; Escape closes and returns focus; Tab out of the open field folds it and leaves focus where it went. The cell is an APG disclosure (aria-expanded / aria-controls)."
1894
+ ],
1895
+ "useCases": [
1896
+ "A collection or workspace search in the app bar",
1897
+ "A global search that must survive a 320–390px phone bar"
1898
+ ]
1899
+ },
1846
1900
  {
1847
1901
  "example": "<NavList\n label=\"Settings\"\n activeId={route}\n linkComponent={Link}\n items={[\n // A GROUP: one NavList, one <nav>, however many groups (gh#815).\n {\n id: \"account\",\n label: \"Account\",\n icon: User,\n children: [\n { id: \"profile\", label: \"Profile\", href: \"/settings/profile\" },\n { id: \"organization\", label: \"Organization\", href: \"/settings/organization\" },\n ],\n },\n // A LEAF, at the same level. `icon` takes the COMPONENT, never an element, and is optional.\n { id: \"appearance\", label: \"Appearance\", icon: Palette, href: \"/settings/appearance\" },\n ]}\n/>",
1848
1902
  "group": "layout",
@@ -4738,10 +4792,10 @@
4738
4792
  "type": "string"
4739
4793
  },
4740
4794
  {
4741
- "defaultValue": "\"success\"",
4742
- "description": "Bar colour tone. Over-capacity defaults to destructive.",
4795
+ "defaultValue": "\"primary\"",
4796
+ "description": "Bar colour tone. `primary` (default since gh#1308) is the brand role for ordinary progress — a reading position, an upload; pass a status tone only when the bar reports that status (ADR C09: `success` for a completed/healthy state, `warning`/`destructive` for limits). Over-capacity defaults to destructive.",
4743
4797
  "name": "tone",
4744
- "type": "\"success\" | \"warning\" | \"destructive\""
4798
+ "type": "\"primary\" | \"success\" | \"warning\" | \"destructive\""
4745
4799
  },
4746
4800
  {
4747
4801
  "defaultValue": "false",
@@ -5104,6 +5158,7 @@
5104
5158
  "storyPath": "data-entry/block-editor.tsx",
5105
5159
  "tagline": "Notion / note.com style block editor (sibling package `@godxjp/block-editor`, versioned with the kit) that reads and writes MARKDOWN through `@godxjp/markdown/codec`: what onValueChange returns is byte-for-byte normalize(body). `/` block menu at the caret, ⋮⋮ handle (drag, turn into, duplicate, move, delete), floating format toolbar, `[[` wikilink suggestions, paste / drop uploads through the host, IME-safe, ja / en / vi (gh#1156).",
5106
5160
  "usage": [
5161
+ "Below 40rem the handle gutter collapses to `--block-editor-compact-gutter-inline-size` (the frame inset, 12px) and the + / ⋮⋮ handle rises above the caret's block at its inline end (ADR C05): first line 56px → 12px from the inner edge at 390px. Touch: tap a block to show its handle; ⋮⋮ opens Move up / Move down / Duplicate / Delete. Keyboard: Mod+/ opens the same menu, Alt+Shift+↑↓ moves the block.",
5107
5162
  "Clicking a link (or Mod+K) opens a settings drawer: text, URL, title, open / remove. Clicking an image opens one for src, alt, title, replace (pickMedia / upload) and remove. Markdown stores no link target, so there is no target field. A link in the editor never navigates mid-edit.",
5108
5163
  "YAML front matter shows as a Properties block at the top and round-trips verbatim; read it with frontmatterOf() from @godxjp/markdown/codec.",
5109
5164
  "DO store the Markdown it emits — it is already canonical; compute `normalize()` server-side from the same codec to verify.",
@@ -6284,6 +6339,7 @@
6284
6339
  "storyPath": "data-entry/search-input.tsx",
6285
6340
  "tagline": "Debounced search box with a clear button. Fires onSearch (NOT onChange) after the debounce. Controlled (value) or uncontrolled (defaultValue).",
6286
6341
  "usage": [
6342
+ "DON'T drop a bare SearchInput into a Topbar slot — use `TopbarSearch` (layout), which passes every SearchInput prop through and folds to a search cell below 40rem instead of shrinking under 8ch (ADR C02).",
6287
6343
  "DO: listen to `onSearch`, not `onChange`. The component debounces internally (default 250 ms) and fires `onSearch(q)` after the delay — never wire your filter logic to `onChange` on SearchInput because it does not expose one.",
6288
6344
  "DO: choose controlled vs uncontrolled deliberately. Pass `value` + `onValueChange` together for controlled mode; optionally add `onSearch` for debounced effects (e.g. when search state lives in a URL param or shared parent). For local-only ephemeral search pass only `defaultValue` + `onSearch` — omitting `value` puts the component in uncontrolled mode.",
6289
6345
  "DO: supply an `ariaLabel` (or visible `label`) when no adjacent label exists. Without either prop, SearchInput falls back to the i18n key `common.search` rendered as a visually-hidden `<Label>` — still accessible, but providing a context-specific string (e.g. `ariaLabel='請求書を検索'`) is more descriptive for screen readers.",
@@ -11373,6 +11429,7 @@
11373
11429
  "tagline": "The standalone WAI-ARIA tree view on a page (antd `Tree` / `DirectoryTree`) — nested `treeData`, a disclosure triangle per branch, roving-tabindex arrow navigation, optional tri-state checkboxes, async `loadData` and `draggable` reorder/reparent (antd `onDrop`). Reach for it whenever nodes expand, collapse or are navigated by keyboard; TreeSelect is the same hierarchy inside a Popover.",
11374
11430
  "usage": [
11375
11431
  "DO name the tree — pass `aria-label` (through your own `t()`) or `aria-labelledby`. A tree with no name is an unlabelled landmark for every screen reader user.",
11432
+ "DO rely on Tree for a cut label (gh#1308): a label that is actually truncated gets its full text as a `title` and unfolds while its row holds keyboard focus (not in a windowed tree, whose rows share one height — the `title` stays). No `titleRender` wrapper with a hand-set `title` is needed; one you set is kept.",
11376
11433
  "DO keep SELECTION and CHECKS apart: `value`/`onValueChange` is which node is open in the detail pane; `checkedValues`/`onCheckedValuesChange` is which nodes are ticked. They are two axes, exactly as in antd — never drive one from the other.",
11377
11434
  "DO keep SELECTION and EXPANSION apart too — this is the THIRD axis and the one gh#910 tripped on. `onValueChange` says which node a detail pane should show; `onExpandedValuesChange` says which branches are unfolded. A sibling pane listens to the first and ignores the second, so unfolding a branch cannot reload it. If your pane reloads when a branch opens, it is being driven from the wrong event — not from a missing feature.",
11378
11435
  "DO let the keyboard work: the tree ships the full APG contract (Up/Down through visible nodes, Right expands then descends, Left collapses then climbs, Home/End, Enter/Space, `*` to expand the current level, type-ahead). Do not add your own key handling on top.",
package/agent/index.json CHANGED
@@ -1,22 +1,22 @@
1
1
  {
2
2
  "counts": {
3
3
  "anti-ai-tells": 35,
4
- "components": 161,
4
+ "components": 162,
5
5
  "patterns": 24,
6
6
  "rules": 43,
7
- "tokens": 2197,
7
+ "tokens": 2203,
8
8
  "vocabulary": 14
9
9
  },
10
10
  "design": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/DESIGN.md",
11
11
  "files": [
12
12
  {
13
13
  "file": "DESIGN.md",
14
- "note": "14 KB — the visual spec: tokens, colour scarcity, admin screen anatomy (list, detail, form, settings, dashboard), do/don't. Read before composing a screen.",
14
+ "note": "16 KB — the visual spec: tokens, colour scarcity, admin screen anatomy (list, detail, form, settings, dashboard), do/don't. Read before composing a screen.",
15
15
  "url": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/DESIGN.md"
16
16
  },
17
17
  {
18
18
  "file": "components-index.json",
19
- "note": "47 KB — name + group + tagline for all 161. FETCH THIS FIRST, then fetch only the components you chose.",
19
+ "note": "48 KB — name + group + tagline for all 162. FETCH THIS FIRST, then fetch only the components you chose.",
20
20
  "url": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/components-index.json"
21
21
  },
22
22
  {
@@ -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/v32.8.0/agent/index.json"
57
+ "pinned": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/v32.10.1/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": 1874,
64
+ "component": 1880,
65
65
  "foundation": 211,
66
66
  "semantic": 112
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": "32.8.0"
71
+ "version": "32.10.1"
72
72
  }
package/agent/llms.txt CHANGED
@@ -1,25 +1,25 @@
1
1
  # @godxjp/ui
2
2
 
3
- > A Japanese-enterprise React design system: 161 components, 2197 design tokens,
4
- > 43 cardinal rules. This file is the entry point for AI agents. Catalog version 32.8.0.
3
+ > A Japanese-enterprise React design system: 162 components, 2203 design tokens,
4
+ > 43 cardinal rules. This file is the entry point for AI agents. Catalog version 32.10.1.
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@32.8.0`). It is searchable and version-locked. These files exist for agents
7
+ (`npx @godxjp/ui-mcp@32.10.1`). It is searchable and version-locked. These files exist for agents
8
8
  that can only fetch URLs.
9
9
 
10
10
  ## Start
11
11
 
12
12
  - [START-HERE.md](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/START-HERE.md): the whole contract — the four rules, the token override model, a page that passes review. Read this first; it is self-contained.
13
13
  - [index.json](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/index.json): version, counts, and the URL of every file.
14
- - [DESIGN.md](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/DESIGN.md): 14 KB — the visual spec: tokens, colour scarcity, admin screen anatomy (list, detail, form, settings, dashboard), do/don't. Read it before composing a screen.
14
+ - [DESIGN.md](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/DESIGN.md): 16 KB — the visual spec: tokens, colour scarcity, admin screen anatomy (list, detail, form, settings, dashboard), do/don't. Read it before composing a screen.
15
15
 
16
16
  ## Catalog
17
17
 
18
18
  - [patterns-index.json](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/patterns-index.json): 24 whole-task patterns (name, tagline, tags). Start here when the task is a TASK — "build a settings page" — then fetch `patterns/<name>.json` for complete code.
19
- - [components-index.json](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/components-index.json): 47 KB — all 161 components as name, group, tagline, plus `absorbed`: the names that do NOT exist and map to it (`Combobox` → `Select`).
19
+ - [components-index.json](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/components-index.json): 48 KB — all 162 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–37 KB, median 6 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.2 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` — 211 `foundation` seeds (`--primary`, `--background`, `--radius`: set these when you are handed a brand), 112 `semantic` roles, 1874 `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` — 211 `foundation` seeds (`--primary`, `--background`, `--radius`: set these when you are handed a brand), 112 `semantic` roles, 1880 `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): 43 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/v32.8.0/agent/...`. A catalog that does not match the installed
30
+ the tag: `.../godx-jp/godxjp-ui/v32.10.1/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.