@godxjp/ui 32.7.2 → 32.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/DESIGN.md +10 -3
- package/README.md +5 -5
- package/agent/DESIGN.md +10 -3
- package/agent/START-HERE.md +9 -7
- package/agent/components/AppShell.json +1 -0
- package/agent/components/BlockEditor.json +1 -0
- package/agent/components/PageContainer.json +1 -0
- package/agent/components/Progress.json +2 -2
- package/agent/components/SearchInput.json +1 -0
- package/agent/components/Topbar.json +2 -0
- package/agent/components/TopbarItem.json +1 -0
- package/agent/components/TopbarSearch.json +49 -0
- package/agent/components-index.json +5 -0
- package/agent/components.json +58 -2
- package/agent/index.json +7 -7
- package/agent/llms.txt +7 -7
- package/agent/tokens.json +38 -2
- package/dist/components/data-display/index.d.ts +1 -1
- package/dist/components/data-display/progress.d.ts +8 -1
- package/dist/components/layout/index.d.ts +2 -0
- package/dist/components/layout/index.js +2 -0
- package/dist/components/layout/topbar-search.d.ts +12 -0
- package/dist/components/layout/topbar-search.js +87 -0
- package/dist/contracts/measurement.json +1 -1
- package/dist/i18n/messages/en.json +1 -0
- package/dist/i18n/messages/ja.json +1 -0
- package/dist/i18n/messages/vi.json +1 -0
- package/dist/props/components/layout.prop.d.ts +22 -0
- package/dist/props/registry.d.ts +9 -0
- package/dist/props/registry.js +16 -0
- package/dist/styles/card-layout.css +1 -1
- package/dist/styles/data-display-layout.css +27 -0
- package/dist/styles/layers.json +7 -1
- package/dist/styles/shell-layout.css +123 -2
- package/dist/styles.css +1 -1
- package/dist/tokens/components/card.css +3 -1
- package/dist/tokens/components/data-display.css +2 -0
- package/dist/tokens/components/shell.css +7 -0
- package/package.json +2 -2
- package/scripts/_agent-setup.mjs +10 -5
- package/scripts/cli.mjs +12 -6
- package/scripts/visual-audit.mjs +1367 -90
package/DESIGN.md
CHANGED
|
@@ -193,18 +193,25 @@ 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.
|
|
201
|
-
3.
|
|
202
|
-
4.
|
|
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.
|
|
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.
|
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 —
|
|
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) |
|
|
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) |
|
|
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
|
|
59
|
-
| [`agent/tokens.json`](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/tokens.json) |
|
|
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,18 +193,25 @@ 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.
|
|
201
|
-
3.
|
|
202
|
-
4.
|
|
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.
|
|
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.
|
package/agent/START-HERE.md
CHANGED
|
@@ -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.
|
|
6
|
+
**This catalog describes `@godxjp/ui` 32.9.0.** 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,
|
|
43
|
-
|
|
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` —
|
|
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` —
|
|
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
|
-
|
|
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` |
|
|
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.",
|
|
@@ -11,9 +11,9 @@
|
|
|
11
11
|
"type": "number"
|
|
12
12
|
},
|
|
13
13
|
{
|
|
14
|
-
"description": "BREAKDOWN mode: one total split into slices. Pass ABSOLUTE amounts in one unit (counts, bytes, yen) — the bar computes each share, so three numbers never have to be rounded into 100. Renders role=\"img\" named from every slice (a partition is not three progressbars), on a taller track (--progress-breakdown-block-size 1.375rem, --progress-breakdown-radius var(--radius)) because three abutting fills on the meter's 0.5rem pill read as a coloured hairline. `label` on each slice is REQUIRED — colour alone never carries meaning (WCAG 1.4.1). Mutually exclusive with value/tone/over.",
|
|
14
|
+
"description": "BREAKDOWN mode: one total split into slices. Pass ABSOLUTE amounts in one unit (counts, bytes, yen) — the bar computes each share, so three numbers never have to be rounded into 100. Renders role=\"img\" named from every slice (a partition is not three progressbars), on a taller track (--progress-breakdown-block-size 1.375rem, --progress-breakdown-radius var(--radius)) because three abutting fills on the meter's 0.5rem pill read as a coloured hairline. `label` on each slice is REQUIRED — colour alone never carries meaning (WCAG 1.4.1). Mutually exclusive with value/tone/over. Slice tones add `info` and `neutral` to the three meter tones (gh#1302) — the same fills as the matching `Legend` swatches, so a four-state partition (done · awaiting · in progress · not started) stays distinguishable and keys one-to-one.",
|
|
15
15
|
"name": "segments",
|
|
16
|
-
"type": "{ value: number; tone: \"success\" | \"warning\" | \"destructive\"; label: string }[]"
|
|
16
|
+
"type": "{ value: number; tone: \"success\" | \"warning\" | \"destructive\" | \"info\" | \"neutral\"; label: string }[]"
|
|
17
17
|
},
|
|
18
18
|
{
|
|
19
19
|
"description": "BREAKDOWN mode: the WHOLE the slices are drawn against, in the same unit as their values. Omit it and the whole is the sum of the slices (the bar is always full). Pass it when part of the whole has no state yet — 3 passed of 400 test cases — and the rest stays the neutral TRACK, the antd `percent` model where the unfilled track is the remainder. The remainder is spoken in the role=\"img\" name, Intl-formatted in the active locale. A total below the slice sum is ignored (the sum wins), so slices never overflow.",
|
|
@@ -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
|
+
}
|
|
@@ -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",
|
package/agent/components.json
CHANGED
|
@@ -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",
|
|
@@ -4718,9 +4772,9 @@
|
|
|
4718
4772
|
"type": "number"
|
|
4719
4773
|
},
|
|
4720
4774
|
{
|
|
4721
|
-
"description": "BREAKDOWN mode: one total split into slices. Pass ABSOLUTE amounts in one unit (counts, bytes, yen) — the bar computes each share, so three numbers never have to be rounded into 100. Renders role=\"img\" named from every slice (a partition is not three progressbars), on a taller track (--progress-breakdown-block-size 1.375rem, --progress-breakdown-radius var(--radius)) because three abutting fills on the meter's 0.5rem pill read as a coloured hairline. `label` on each slice is REQUIRED — colour alone never carries meaning (WCAG 1.4.1). Mutually exclusive with value/tone/over.",
|
|
4775
|
+
"description": "BREAKDOWN mode: one total split into slices. Pass ABSOLUTE amounts in one unit (counts, bytes, yen) — the bar computes each share, so three numbers never have to be rounded into 100. Renders role=\"img\" named from every slice (a partition is not three progressbars), on a taller track (--progress-breakdown-block-size 1.375rem, --progress-breakdown-radius var(--radius)) because three abutting fills on the meter's 0.5rem pill read as a coloured hairline. `label` on each slice is REQUIRED — colour alone never carries meaning (WCAG 1.4.1). Mutually exclusive with value/tone/over. Slice tones add `info` and `neutral` to the three meter tones (gh#1302) — the same fills as the matching `Legend` swatches, so a four-state partition (done · awaiting · in progress · not started) stays distinguishable and keys one-to-one.",
|
|
4722
4776
|
"name": "segments",
|
|
4723
|
-
"type": "{ value: number; tone: \"success\" | \"warning\" | \"destructive\"; label: string }[]"
|
|
4777
|
+
"type": "{ value: number; tone: \"success\" | \"warning\" | \"destructive\" | \"info\" | \"neutral\"; label: string }[]"
|
|
4724
4778
|
},
|
|
4725
4779
|
{
|
|
4726
4780
|
"description": "BREAKDOWN mode: the WHOLE the slices are drawn against, in the same unit as their values. Omit it and the whole is the sum of the slices (the bar is always full). Pass it when part of the whole has no state yet — 3 passed of 400 test cases — and the rest stays the neutral TRACK, the antd `percent` model where the unfilled track is the remainder. The remainder is spoken in the role=\"img\" name, Intl-formatted in the active locale. A total below the slice sum is ignored (the sum wins), so slices never overflow.",
|
|
@@ -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.",
|
package/agent/index.json
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"counts": {
|
|
3
3
|
"anti-ai-tells": 35,
|
|
4
|
-
"components":
|
|
4
|
+
"components": 162,
|
|
5
5
|
"patterns": 24,
|
|
6
6
|
"rules": 43,
|
|
7
|
-
"tokens":
|
|
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
|
+
"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": "
|
|
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.
|
|
57
|
+
"pinned": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/v32.9.0/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":
|
|
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.
|
|
71
|
+
"version": "32.9.0"
|
|
72
72
|
}
|
package/agent/llms.txt
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
# @godxjp/ui
|
|
2
2
|
|
|
3
|
-
> A Japanese-enterprise React design system:
|
|
4
|
-
> 43 cardinal rules. This file is the entry point for AI agents. Catalog version 32.
|
|
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.9.0.
|
|
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.
|
|
7
|
+
(`npx @godxjp/ui-mcp@32.9.0`). 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
|
+
- [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):
|
|
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/<Name>.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,
|
|
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.
|
|
30
|
+
the tag: `.../godx-jp/godxjp-ui/v32.9.0/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
|
@@ -2556,10 +2556,16 @@
|
|
|
2556
2556
|
"value": "var(--font-weight-medium)"
|
|
2557
2557
|
},
|
|
2558
2558
|
{
|
|
2559
|
-
"description": "
|
|
2559
|
+
"description": "gh#1305 (ADR C12): sentence case, no tracking by default; a theme opts into small caps.",
|
|
2560
2560
|
"name": "--stat-card-label-letter-spacing",
|
|
2561
2561
|
"tier": "component",
|
|
2562
|
-
"value": "
|
|
2562
|
+
"value": "normal"
|
|
2563
|
+
},
|
|
2564
|
+
{
|
|
2565
|
+
"description": "Card component tokens: card chrome derives from semantic layout tokens.",
|
|
2566
|
+
"name": "--stat-card-label-letter-case",
|
|
2567
|
+
"tier": "component",
|
|
2568
|
+
"value": "none"
|
|
2563
2569
|
},
|
|
2564
2570
|
{
|
|
2565
2571
|
"description": "Card component tokens: card chrome derives from semantic layout tokens.",
|
|
@@ -5387,6 +5393,12 @@
|
|
|
5387
5393
|
"tier": "component",
|
|
5388
5394
|
"value": "calc(2 * var(--control-height-xs) + var(--space-2))"
|
|
5389
5395
|
},
|
|
5396
|
+
{
|
|
5397
|
+
"description": "Below 40rem the gutter collapses to this (ADR C05: first line ≤24px from the inner edge) and the handle rises above the caret's block at its inline end instead of sitting beside it.",
|
|
5398
|
+
"name": "--block-editor-compact-gutter-inline-size",
|
|
5399
|
+
"tier": "component",
|
|
5400
|
+
"value": "var(--block-editor-frame-padding)"
|
|
5401
|
+
},
|
|
5390
5402
|
{
|
|
5391
5403
|
"description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
|
|
5392
5404
|
"name": "--block-editor-min-height",
|
|
@@ -10241,6 +10253,18 @@
|
|
|
10241
10253
|
"tier": "component",
|
|
10242
10254
|
"value": "var( --font-size-2xs, calc(var(--font-size-base) / var(--font-size-ratio) / var(--font-size-ratio)) )"
|
|
10243
10255
|
},
|
|
10256
|
+
{
|
|
10257
|
+
"description": "Section label case and tracking (gh#1305, ADR C12): default sentence case, no tracking — tiny letter-spaced capitals (11px, 0.08em) are the classic \"AI dashboard\" eyebrow. A theme that wants small caps back sets both.",
|
|
10258
|
+
"name": "--sidebar-section-label-letter-case",
|
|
10259
|
+
"tier": "component",
|
|
10260
|
+
"value": "none"
|
|
10261
|
+
},
|
|
10262
|
+
{
|
|
10263
|
+
"description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
|
|
10264
|
+
"name": "--sidebar-section-label-letter-spacing",
|
|
10265
|
+
"tier": "component",
|
|
10266
|
+
"value": "normal"
|
|
10267
|
+
},
|
|
10244
10268
|
{
|
|
10245
10269
|
"description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
|
|
10246
10270
|
"name": "--sidebar-product-tenant-font-size",
|
|
@@ -10709,6 +10733,18 @@
|
|
|
10709
10733
|
"tier": "component",
|
|
10710
10734
|
"value": "none"
|
|
10711
10735
|
},
|
|
10736
|
+
{
|
|
10737
|
+
"description": "TopbarSearch (ADR C02): the inline field's TEXT AREA never shrinks below this — measured after the icon and clear/shortcut padding, in the field's own font. Below its `collapseBelow` step the field folds to a search cell instead of shrinking. 8ch is a repo-chosen policy, not a standard.",
|
|
10738
|
+
"name": "--topbar-search-min-text-inline-size",
|
|
10739
|
+
"tier": "component",
|
|
10740
|
+
"value": "8ch"
|
|
10741
|
+
},
|
|
10742
|
+
{
|
|
10743
|
+
"description": "The inline field's preferred width from the step up; it shrinks toward the floor above.",
|
|
10744
|
+
"name": "--topbar-search-inline-size",
|
|
10745
|
+
"tier": "component",
|
|
10746
|
+
"value": "16rem"
|
|
10747
|
+
},
|
|
10712
10748
|
{
|
|
10713
10749
|
"description": "TOPBAR BAR ITEM — the shape of an interactive cell IN the bar, as opposed to a control dropped into it. The bar's own chrome (Fluent's command bar, SLDS's global header, Atlassian's navigation, and the right-hand action slot of enterprise pro-layouts generally) draws a trigger as a full-height cell whose hover is the bar's surface; a `Button` in the same slot draws a --control-height pill with its own hover fill and its own ring, floating inside a taller strip. NO HEIGHT KNOB, DELIBERATELY. The cell's height IS the bar's, whatever the bar's is — `--app-shell-bar-height` inside AppShell, `--topbar-height` for a standalone Topbar, the coarse-pointer override on a touch device. A knob here would be a second answer that goes stale the moment either of those moves.",
|
|
10714
10750
|
"name": "--topbar-item-padding-inline",
|