@godxjp/ui 28.12.0 → 29.0.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/agent/START-HERE.md +29 -10
- package/agent/components/Anchor.json +6 -1
- package/agent/components/AppLauncher.json +10 -0
- package/agent/components/AppShell.json +1 -1
- package/agent/components/AreaChart.json +19 -1
- package/agent/components/Attachments.json +26 -1
- package/agent/components/BarChart.json +11 -1
- package/agent/components/BranchScopePicker.json +10 -0
- package/agent/components/Cascader.json +6 -1
- package/agent/components/Checkbox.json +6 -0
- package/agent/components/CompactBarTrend.json +1 -1
- package/agent/components/CredentialReveal.json +21 -0
- package/agent/components/DataState.json +1 -1
- package/agent/components/DataTable.json +4 -4
- package/agent/components/FormField.json +1 -1
- package/agent/components/InfiniteQueryState.json +1 -1
- package/agent/components/Input.json +1 -1
- package/agent/components/InputOTP.json +35 -0
- package/agent/components/LineChart.json +20 -2
- package/agent/components/ListRow.json +1 -1
- package/agent/components/Masonry.json +1 -1
- package/agent/components/MasterDetail.json +1 -1
- package/agent/components/PasswordStrength.json +1 -1
- package/agent/components/PermissionMatrix.json +6 -1
- package/agent/components/SearchInput.json +5 -0
- package/agent/components/Select.json +1 -0
- package/agent/components/ServiceRolePanel.json +5 -0
- package/agent/components/Sidebar.json +1 -1
- package/agent/components/Switch.json +6 -0
- package/agent/components/Table.json +8 -3
- package/agent/components/Tabs.json +10 -0
- package/agent/components/ThemeScope.json +49 -0
- package/agent/components/TimeRangePicker.json +5 -0
- package/agent/components/Topbar.json +1 -0
- package/agent/components/TopbarItem.json +2 -1
- package/agent/components/Transfer.json +6 -1
- package/agent/components/TreeSelect.json +1 -1
- package/agent/components/Upload.json +5 -0
- package/agent/components/UploadCropDialog.json +1 -1
- package/agent/components/formatDate.json +1 -1
- package/agent/components-index.json +5 -0
- package/agent/components.json +297 -31
- package/agent/index.json +19 -9
- package/agent/llms.txt +10 -10
- package/agent/patterns/tenant-brand-color.json +28 -0
- package/agent/patterns-index.json +27 -0
- package/agent/patterns.json +28 -0
- package/agent/rules.json +15 -0
- package/agent/tokens.json +4965 -970
- package/dist/app/index.d.ts +3 -0
- package/dist/app/index.js +3 -0
- package/dist/app/tenant-theme.d.ts +80 -0
- package/dist/app/tenant-theme.js +154 -0
- package/dist/app/theme-axes.d.ts +14 -1
- package/dist/app/theme-axes.js +24 -31
- package/dist/components/charts/chart-cartesian.d.ts +5 -1
- package/dist/components/charts/chart-cartesian.js +15 -8
- package/dist/components/data-display/badge.d.ts +1 -1
- package/dist/components/data-display/badge.js +20 -2
- package/dist/components/data-display/carousel.js +4 -4
- package/dist/components/data-display/data-table.js +13 -2
- package/dist/components/data-display/permission-matrix.js +1 -1
- package/dist/components/data-display/table.d.ts +11 -2
- package/dist/components/data-display/table.js +18 -2
- package/dist/components/data-entry/control-appearance.d.ts +12 -6
- package/dist/components/data-entry/control-appearance.js +1 -1
- package/dist/components/data-entry/select.js +4 -3
- package/dist/components/feedback/dialog.js +6 -3
- package/dist/components/feedback/overlay-header-tone.d.ts +7 -0
- package/dist/components/feedback/overlay-header-tone.js +4 -4
- package/dist/components/feedback/sheet.d.ts +1 -1
- package/dist/components/feedback/sheet.js +6 -9
- package/dist/components/feedback/sonner.js +16 -3
- package/dist/components/general/button.js +22 -5
- package/dist/components/layout/affix.js +15 -1
- package/dist/components/layout/sidebar.js +7 -1
- package/dist/components/navigation/anchor.d.ts +1 -1
- package/dist/components/navigation/anchor.js +5 -4
- package/dist/components/navigation/app-setting-picker.js +1 -1
- package/dist/components/navigation/pagination.js +1 -1
- package/dist/components/navigation/tabs.js +15 -2
- package/dist/components/query/infinite-query-state.d.ts +22 -6
- package/dist/contracts/measurement.json +1 -1
- package/dist/i18n/messages/en.json +0 -697
- package/dist/i18n/messages/ja.json +0 -691
- package/dist/i18n/messages/vi.json +0 -691
- package/dist/lib/control-styles.d.ts +31 -11
- package/dist/lib/control-styles.js +6 -6
- package/dist/lib/overlay-portal.d.ts +20 -0
- package/dist/lib/overlay-portal.js +93 -0
- package/dist/props/components/app.prop.d.ts +12 -0
- package/dist/props/components/charts.prop.d.ts +30 -0
- package/dist/props/components/index.d.ts +1 -1
- package/dist/props/components/navigation.prop.d.ts +21 -2
- package/dist/props/components/query.prop.d.ts +36 -2
- package/dist/props/registry.d.ts +46 -1
- package/dist/props/registry.js +38 -3
- package/dist/styles/alert-layout.css +34 -14
- package/dist/styles/badge-layout.css +10 -6
- package/dist/styles/base.css +14 -5
- package/dist/styles/card-layout.css +19 -8
- package/dist/styles/chart-layout.css +22 -3
- package/dist/styles/control.css +165 -59
- package/dist/styles/data-display-layout.css +129 -36
- package/dist/styles/data-entry-layout.css +23 -87
- package/dist/styles/dialog-layout.css +49 -19
- package/dist/styles/float-button-layout.css +5 -5
- package/dist/styles/focus-ring.css +9 -5
- package/dist/styles/layout.css +42 -15
- package/dist/styles/logo-layout.css +1 -1
- package/dist/styles/motion.css +1 -1
- package/dist/styles/navigation-layout.css +90 -29
- package/dist/styles/shell-layout.css +63 -40
- package/dist/styles/table-layout.css +56 -17
- package/dist/styles/text-layout.css +13 -4
- package/dist/styles/toggle.css +8 -2
- package/dist/tokens/components/actions.css +1 -1
- package/dist/tokens/components/attachments.css +4 -4
- package/dist/tokens/components/badge.css +4 -4
- package/dist/tokens/components/callout.css +1 -1
- package/dist/tokens/components/card.css +9 -4
- package/dist/tokens/components/chart.css +10 -1
- package/dist/tokens/components/chat-bubble.css +1 -1
- package/dist/tokens/components/control.css +28 -10
- package/dist/tokens/components/conversations.css +2 -1
- package/dist/tokens/components/data-display.css +12 -7
- package/dist/tokens/components/descriptions.css +1 -1
- package/dist/tokens/components/draggable-panel.css +1 -1
- package/dist/tokens/components/feedback.css +28 -8
- package/dist/tokens/components/float-button.css +1 -1
- package/dist/tokens/components/legal-document.css +1 -1
- package/dist/tokens/components/logo.css +1 -1
- package/dist/tokens/components/mega-menu.css +5 -3
- package/dist/tokens/components/navigation.css +21 -7
- package/dist/tokens/components/segmented.css +8 -3
- package/dist/tokens/components/shell.css +19 -5
- package/dist/tokens/components/table.css +9 -1
- package/dist/tokens/components/thought-chain.css +1 -1
- package/dist/tokens/components/toggle.css +2 -0
- package/dist/tokens/components/tree.css +3 -1
- package/dist/tokens/components/upload.css +6 -6
- package/dist/tokens/components/welcome.css +1 -1
- package/dist/tokens/foundation.css +28 -1
- package/docs/COMPOSITION-VS-COMPONENT.md +31 -0
- package/docs/CUSTOMER-THEMING.md +637 -1
- package/docs/DESIGN-AUTHORITY.md +13 -0
- package/docs/FRAME-COVERAGE-REPORT.md +3 -2
- package/docs/GLASSMORPHISM-STANDARD.md +196 -0
- package/docs/THEME-API-COVERAGE.md +538 -0
- package/docs/TOKEN-RESOLUTION.md +195 -0
- package/docs/TOKENS.md +63 -24
- package/docs/asset-modules.d.ts +7 -0
- package/docs/data-display/charts.tsx +80 -0
- package/docs/data-display/data-table/index.tsx +30 -0
- package/docs/data-display/popover.tsx +1 -1
- package/docs/data-display/table.tsx +52 -0
- package/docs/feedback/sheet.tsx +10 -10
- package/docs/foundation/density.tsx +4 -4
- package/docs/i18n/messages/en.json +1201 -0
- package/docs/i18n/messages/ja.json +1195 -0
- package/docs/i18n/messages/vi.json +1195 -0
- package/docs/layout/account-chip.tsx +2 -2
- package/docs/layout/responsive-grid.tsx +1 -1
- package/docs/navigation/toolbar.tsx +20 -12
- package/docs/providers/theme-scope.tsx +186 -0
- package/docs/showcase/caimono-price-comparison.tsx +911 -0
- package/docs/showcase/case4-login.tsx +2 -2
- package/docs/showcase/marketing-page.tsx +3 -2
- package/docs/showcase/permission-matrix.tsx +13 -5
- package/docs/showcase/table-pagination.tsx +2 -1
- package/docs/showcase/tenant-brand-color.tsx +338 -0
- package/docs/showcase/theme-customization.tsx +2 -1
- package/docs/showcase/theme-lab.tsx +2125 -0
- package/docs/themes/flat.css +462 -0
- package/docs/themes/glassmorphism.css +958 -0
- package/docs/themes/index.ts +200 -0
- package/package.json +4 -3
- package/scripts/explain-token.mjs +382 -0
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`
|
|
6
|
+
**This catalog describes `@godxjp/ui` 29.0.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.
|
|
@@ -43,24 +43,28 @@ Then ask it: `search_components`, `get_component`, `get_tokens`, `get_rule`, `li
|
|
|
43
43
|
**You cannot run a process** (ChatGPT web · Claude.ai · anything fetching URLs)
|
|
44
44
|
→ These files are for you. Fetch in this order:
|
|
45
45
|
|
|
46
|
-
0. `patterns-index.json` —
|
|
46
|
+
0. `patterns-index.json` — 20 whole-task patterns as name + tagline + tags. **If your
|
|
47
47
|
task is a task** — "build a settings page", "confirm a destructive delete", "a list page with
|
|
48
48
|
filters" — start HERE, not at the components. Then fetch `patterns/<name>.json` for complete,
|
|
49
49
|
copy-paste-ready code. A component index answers "does X exist"; it cannot answer "build Y".
|
|
50
|
-
1. `components-index.json` — 45 KB, all
|
|
50
|
+
1. `components-index.json` — 45 KB, all 171 components as name + group +
|
|
51
51
|
tagline. Read this when you already know the SHAPE you need. Each entry may carry `absorbed`:
|
|
52
52
|
names that **do not exist** and map to it — `Combobox`, `Autocomplete`, `CountrySelect` and
|
|
53
53
|
`SearchSelect` are all `Select`. If you are about to hand-roll something, search this field
|
|
54
54
|
first; it exists because that is the mistake.
|
|
55
|
-
2. `components/<Name>.json` — one file per component (1 KB–
|
|
55
|
+
2. `components/<Name>.json` — one file per component (1 KB–34 KB, median 6 KB), carrying its props,
|
|
56
56
|
its `importPath`, and its examples. Fetch only the handful you picked in step 1.
|
|
57
|
-
3. `rules.json` —
|
|
57
|
+
3. `rules.json` — 50 cardinal rules. The ones about raw HTML and hardcoded colour are not
|
|
58
58
|
style advice.
|
|
59
|
-
4. `tokens.json` —
|
|
59
|
+
4. `tokens.json` — 2070 design tokens, each tagged with its `tier`. **If you were handed a
|
|
60
|
+
brand, read the 211 `foundation` entries first** — `--primary`, `--background`,
|
|
61
|
+
`--radius`, `--font-size-base` are the handful everything else derives from. The
|
|
62
|
+
1756 `component` entries are per-part knobs; reach for one only when a role is
|
|
63
|
+
right everywhere except one component.
|
|
60
64
|
5. `anti-ai-tells.json` — 26 shapes that make generated UI look generated, each with the
|
|
61
65
|
fix. Read before you reach for a gradient hero or a wall of coloured chips.
|
|
62
66
|
|
|
63
|
-
**Do not fetch `components.json`.** It is 1.
|
|
67
|
+
**Do not fetch `components.json`.** It is 1.2 MB, and most URL fetchers truncate a
|
|
64
68
|
response that size and return the head without telling you. You get the first few entries, believe
|
|
65
69
|
you read the catalog, and answer the rest from memory — which is the failure this file exists to
|
|
66
70
|
prevent. The per-component files say the same thing without the cliff.
|
|
@@ -131,9 +135,24 @@ So: **build any layout you like out of primitives, and express every visual deci
|
|
|
131
135
|
a documented prop.** You keep full freedom of composition and lose none of the theming. The moment
|
|
132
136
|
you write a literal, that pixel stops following the theme and the tenant override silently skips it.
|
|
133
137
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
138
|
+
### Which token do you actually set — the `tier` field answers it
|
|
139
|
+
|
|
140
|
+
Every entry in `tokens.json` carries a `tier`, and the tier tells you whether you are invited to set
|
|
141
|
+
it. Start at the top and **stop at the first tier that does the job**; each step down is a value that
|
|
142
|
+
has stopped following the brand.
|
|
143
|
+
|
|
144
|
+
| `tier` | count | what it is | set it? |
|
|
145
|
+
|---|---|---|---|
|
|
146
|
+
| `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.** Handed a brand colour, this is where it goes: `:root { --primary: <H> <S>% <L>%; }` (HSL components, no `hsl()` wrapper) |
|
|
147
|
+
| `semantic` | 103 | 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 |
|
|
148
|
+
| `component` | 1756 | 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` |
|
|
149
|
+
|
|
150
|
+
A token whose `value` is `initial` is not empty and not broken: `initial` is the guaranteed-invalid
|
|
151
|
+
value, so the real default is computed where the element paints it. Set it and yours wins.
|
|
152
|
+
|
|
153
|
+
**There is no fourth option.** If a colour, radius or size you need is not in this file, the answer
|
|
154
|
+
is not a hand-written CSS rule — say the token is missing and ask. A literal is invisible to every
|
|
155
|
+
theme, every tenant scope and every audit in this package.
|
|
137
156
|
|
|
138
157
|
---
|
|
139
158
|
|
|
@@ -46,7 +46,12 @@
|
|
|
46
46
|
"type": "number"
|
|
47
47
|
},
|
|
48
48
|
{
|
|
49
|
-
"description": "
|
|
49
|
+
"description": "gh#890. The scroll box the sections are measured in AND `Affix` pins the nav against — one function, both halves. `Affix`'s own name and shape (`AffixTargetProp`), the same lazy getter `FloatButton.BackTop.target` already spells here. `null`, or an absent `target`, means the viewport. Wins over `getContainer` when both are given.",
|
|
50
|
+
"name": "target",
|
|
51
|
+
"type": "() => Window | HTMLElement | null"
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"description": "antd `getContainer`, default `() => window` — the scroll box holding the sections. Superseded by `target` (gh#890), which mirrors `Affix`'s own spelling for the identical idea; kept live for a call site written before `target` existed.",
|
|
50
55
|
"name": "getContainer",
|
|
51
56
|
"type": "() => HTMLElement | Window"
|
|
52
57
|
},
|
|
@@ -60,6 +60,16 @@
|
|
|
60
60
|
"name": "appearance",
|
|
61
61
|
"type": "\"bar\" | \"icon\""
|
|
62
62
|
},
|
|
63
|
+
{
|
|
64
|
+
"description": "Which way the panel opens. DERIVED from `appearance` when unset — `bottom` in a bar (the panel drops below the trigger, the only direction that does not cover the bar itself), `right` otherwise, because a rail is vertical and its panel goes beside it. State it when the chrome can be RE-DOCKED: `appearance` says the trigger is NOT in a bar, and it cannot say which way is out — a rail pinned to the top edge is not a bar and still opens downward. Measured without it, an embedded bar trigger at (2,50) put its panel at (12,90), lying over the host application's sidebar. Not used by `responsive=\"fullscreen\"`, which has no side.",
|
|
65
|
+
"name": "side",
|
|
66
|
+
"type": "\"top\" | \"right\" | \"bottom\" | \"left\""
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"description": "Where the panel sits along the `side` edge — the cross-axis half of the same decision, and derived the same way: `end` in a bar (the Workspace shape, flush with the bar's end), `start` otherwise (aligned to the rail trigger's own start). State it alongside `side` when you state either.",
|
|
70
|
+
"name": "align",
|
|
71
|
+
"type": "\"start\" | \"center\" | \"end\""
|
|
72
|
+
},
|
|
63
73
|
{
|
|
64
74
|
"description": "Controlled open state.",
|
|
65
75
|
"name": "open",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"example": "import { AppShell, Sidebar } from \"@godxjp/ui/layout\";\nimport { LayoutDashboard, Users } from \"lucide-react\";\nimport { router } from \"@inertiajs/react\";\n\nconst sidebar = (\n <Sidebar\n activeId=\"/dashboard\"\n onSelect={(id) => router.visit(id)}\n sections={[{ items: [\n { id: \"/dashboard\", label: \"ダッシュボード\", icon: LayoutDashboard },\n { id: \"/users\", label: \"ユーザー\", icon: Users },\n ] }]}\n product={{ name: \"JOVY CRM\", role: \"本部\", color: \"var(--color-primary)\" }}\n />\n);\n\nexport function CrmLayout({ children }: {
|
|
2
|
+
"example": "import { AppShell, Sidebar } from \"@godxjp/ui/layout\";\nimport { LayoutDashboard, Users } from \"lucide-react\";\nimport { router } from \"@inertiajs/react\";\n\nconst sidebar = (\n <Sidebar\n activeId=\"/dashboard\"\n onSelect={(id) => router.visit(id)}\n sections={[{ items: [\n { id: \"/dashboard\", label: \"ダッシュボード\", icon: LayoutDashboard },\n { id: \"/users\", label: \"ユーザー\", icon: Users },\n ] }]}\n product={{ name: \"JOVY CRM\", role: \"本部\", color: \"var(--color-primary)\" }}\n />\n);\n\nexport function CrmLayout({ children }: { children: React.ReactNode }) {\n return <AppShell sidebar={sidebar}>{children}</AppShell>;\n}",
|
|
3
3
|
"group": "layout",
|
|
4
4
|
"importPath": "@godxjp/ui/layout",
|
|
5
5
|
"name": "AppShell",
|
|
@@ -73,12 +73,28 @@
|
|
|
73
73
|
"name": "stacked",
|
|
74
74
|
"type": "boolean"
|
|
75
75
|
},
|
|
76
|
+
{
|
|
77
|
+
"description": "Explicit [min, max] for the VALUE axis (y vertical, x on a horizontal bar). Omit to let the data set it. A non-zero baseline is a charting-ETHICS call: legitimate where the SHAPE is the message and zero is not a reference (price, temperature, an index, a latency percentile), misleading wherever the reader compares magnitudes — which is every bar chart.",
|
|
78
|
+
"name": "valueDomain",
|
|
79
|
+
"type": "[number, number]"
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"description": "Explicit tick positions on the value axis, in data units. Values outside valueDomain are not drawn.",
|
|
83
|
+
"name": "valueTicks",
|
|
84
|
+
"type": "number[]"
|
|
85
|
+
},
|
|
76
86
|
{
|
|
77
87
|
"defaultValue": "false",
|
|
78
88
|
"description": "Render smooth (monotone) areas instead of straight segments.",
|
|
79
89
|
"name": "curved",
|
|
80
90
|
"type": "boolean"
|
|
81
91
|
},
|
|
92
|
+
{
|
|
93
|
+
"defaultValue": "false",
|
|
94
|
+
"description": "Draw a marker at every data point. Off by default — markers crowd a dense series.",
|
|
95
|
+
"name": "showDots",
|
|
96
|
+
"type": "boolean"
|
|
97
|
+
},
|
|
82
98
|
{
|
|
83
99
|
"description": "Message shown when `data` is empty.",
|
|
84
100
|
"name": "emptyMessage",
|
|
@@ -96,7 +112,9 @@
|
|
|
96
112
|
"DO import from the charts entry: `import { AreaChart } from \"@godxjp/ui/charts\";` (recharts optional peer required).",
|
|
97
113
|
"DO import only the chart a screen uses — `import { AreaChart } from \"@godxjp/ui/charts/area-chart\";` — when the `./charts` barrel should not link the whole chart family. Without the `recharts` peer the build then fails ONCE, naming the package and the fix.",
|
|
98
114
|
"DO use `stacked` to show how parts accumulate into a total over time.",
|
|
99
|
-
"DON'T overlay more than 2-3 unstacked areas — fill opacity makes dense overlays unreadable; switch to LineChart."
|
|
115
|
+
"DON'T overlay more than 2-3 unstacked areas — fill opacity makes dense overlays unreadable; switch to LineChart.",
|
|
116
|
+
"DO split the band's hue from the line's with `series[].fillColor` when a brand specifies both (a dark line over a lighter wash). The band's DENSITY is the `--chart-area-fill-alpha` theme token, not a prop.",
|
|
117
|
+
"DON'T tune the band by dropping a page-local CSS rule on `.recharts-area-area` — `--chart-area-fill-alpha` is the supported knob and it follows a scoped [data-tenant] region."
|
|
100
118
|
],
|
|
101
119
|
"useCases": [
|
|
102
120
|
"Cumulative volume over time (e.g. total transactions per day).",
|
|
@@ -50,6 +50,31 @@
|
|
|
50
50
|
"description": "Child mode: visible trigger; upload runs through a hidden input beside it.",
|
|
51
51
|
"name": "children",
|
|
52
52
|
"type": "ReactElement"
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"description": "antd Upload `onRemove`, narrowed to the attachment row. RETURNING `false` (or a promise of it) VETOES the removal and the card stays — anything else, including `undefined`, lets it go. That is how you gate a removal behind a confirm dialog without owning `items` yourself. It is awaited, so an async guard works.",
|
|
56
|
+
"name": "onRemove",
|
|
57
|
+
"type": "(item: AttachmentsItemProp) => boolean | void | Promise<boolean | void>"
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"description": "Ant Design X `classNames` — per-part classes (root, list, card, file, upload, placeholder). DECLARED AND FORWARDED, and the only semantic part map in this package: docs/DESIGN-AUTHORITY.md rules that antd's `classNames`/`styles` maps are NOT adopted because this library answers that layer with tokens (cardinal rule #45), and Attachments is the one component that carries them anyway. Recorded there as a contradiction, not a pattern — do not copy it onto another component, and retune through `--attachments-*` instead.",
|
|
61
|
+
"name": "classNames",
|
|
62
|
+
"type": "Partial<Record<AttachmentsSemanticProp, string>>"
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"description": "Ant Design X `styles` — the same part map as `classNames`, as inline styles, and under the same standing ruling against it. Inline styles beat every stylesheet rule, so this is the one handle in the package that can take a part off the design system entirely. The `--attachments-*` tokens are the supported route.",
|
|
66
|
+
"name": "styles",
|
|
67
|
+
"type": "Partial<Record<AttachmentsSemanticProp, React.CSSProperties>>"
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"description": "Ant Design X `rootClassName` — the outermost node. It is not a duplicate of `className`: in the full-screen-drop mode (`getDropContainer`) the outermost node is the OVERLAY rather than the inline tray, which is why antd separates the two. Both are applied.",
|
|
71
|
+
"name": "rootClassName",
|
|
72
|
+
"type": "string"
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"description": "ACCEPTED AND INERT. Ant Design X forwards it to its own Image preview; this package has no Image primitive yet, so the prop exists only so an Ant X call site type-checks, and passing it changes nothing on screen. Do not reach for it expecting a preview knob.",
|
|
76
|
+
"name": "imageProps",
|
|
77
|
+
"type": "Record<string, unknown>"
|
|
53
78
|
}
|
|
54
79
|
],
|
|
55
80
|
"related": [
|
|
@@ -67,7 +92,7 @@
|
|
|
67
92
|
"usage": [
|
|
68
93
|
"DO keep antd field names on each item (`thumbUrl`, `originFileObj`, `uid`) — an Ant X call site should compile unchanged.",
|
|
69
94
|
"DO use `ref.select({ accept, multiple })` to open the picker programmatically (Ant X 2.0).",
|
|
70
|
-
"
|
|
95
|
+
"Ant X's `classNames` / `styles` / `rootClassName` ARE declared and forwarded, although docs/DESIGN-AUTHORITY.md rules that antd's semantic part maps are not adopted here. The older note in this slot said not to expect them at all; the type has never agreed with it, so an agent reading only the catalog was told the opposite of what autocomplete offered. Retune through the `--attachments-*` tokens, and treat the maps as a recorded contradiction on this one component rather than a pattern to reuse.",
|
|
71
96
|
"The card is a FIXED box — 268x68 (Ant X's own), from `--attachments-card-size` (inline) and `--attachments-card-block-size`. The block size is also the `+` tile's square and the `overflow=\"scrollY\"` one-row viewport, so retune it once and all three follow. The file input is `sr-only`: never style it visible."
|
|
72
97
|
],
|
|
73
98
|
"useCases": [
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"type": "ChartDatum[]"
|
|
12
12
|
},
|
|
13
13
|
{
|
|
14
|
-
"description": "Plotted series: { dataKey, label?, color? }.",
|
|
14
|
+
"description": "Plotted series: { dataKey, label?, color?, fillColor? }. `fillColor` paints the filled band independently of the line's `color`; it defaults to `color`.",
|
|
15
15
|
"name": "series",
|
|
16
16
|
"required": true,
|
|
17
17
|
"type": "ChartSeriesProp[]"
|
|
@@ -67,6 +67,16 @@
|
|
|
67
67
|
"name": "numberFormat",
|
|
68
68
|
"type": "Intl.NumberFormatOptions"
|
|
69
69
|
},
|
|
70
|
+
{
|
|
71
|
+
"description": "Explicit [min, max] for the VALUE axis (y vertical, x on a horizontal bar). Omit to let the data set it. A non-zero baseline is a charting-ETHICS call: legitimate where the SHAPE is the message and zero is not a reference (price, temperature, an index, a latency percentile), misleading wherever the reader compares magnitudes — which is every bar chart.",
|
|
72
|
+
"name": "valueDomain",
|
|
73
|
+
"type": "[number, number]"
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"description": "Explicit tick positions on the value axis, in data units. Values outside valueDomain are not drawn.",
|
|
77
|
+
"name": "valueTicks",
|
|
78
|
+
"type": "number[]"
|
|
79
|
+
},
|
|
70
80
|
{
|
|
71
81
|
"defaultValue": "false",
|
|
72
82
|
"description": "Stack series into one bar instead of grouping side by side.",
|
|
@@ -63,6 +63,16 @@
|
|
|
63
63
|
"description": "Override the localized radio labels (e.g. domain wording like 全店舗).",
|
|
64
64
|
"name": "allLabel / selectedLabel",
|
|
65
65
|
"type": "ReactNode"
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"description": "Native form name, forwarded to the MODE radio group — the all / selected choice is what submits under it. The checked branch ids are not native fields; they live in the single `{ mode, branchIds }` value and are yours to serialise.",
|
|
69
|
+
"name": "name",
|
|
70
|
+
"type": "string"
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"description": "DOM id on the picker root, and the SEED for the ids beneath it — the validation message is `${id}-error`, which is what `aria-errormessage` points at. Left out, a `useId`-based id is generated, so the association still holds; set it when a server-rendered page needs those ids to be stable.",
|
|
74
|
+
"name": "id",
|
|
75
|
+
"type": "string"
|
|
66
76
|
}
|
|
67
77
|
],
|
|
68
78
|
"related": [
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"example": "{`import { Cascader } from \"@godxjp/ui/data-entry\";\n\nconst REGIONS = [\n {\n value: \"jp\",\n label: \"日本\",\n
|
|
2
|
+
"example": "{`import { Cascader } from \"@godxjp/ui/data-entry\";\n\nconst REGIONS = [\n {\n value: \"jp\",\n label: \"日本\",\n children: [\n {\n value: \"tokyo\",\n label: \"東京都\",\n children: [\n { value: \"shinjuku\", label: \"新宿区\" },\n { value: \"shibuya\", label: \"渋谷区\" },\n ],\n },\n ],\n },\n {\n value: \"vn\",\n label: \"Việt Nam\",\n children: [\n {\n value: \"hcm\",\n label: \"TP. Hồ Chí Minh\",\n children: [\n { value: \"q1\", label: \"Quận 1\" },\n { value: \"q3\", label: \"Quận 3\" },\n ],\n },\n ],\n },\n];\n\n// Controlled single-path\nfunction RegionPicker() {\n const [path, setPath] = React.useState<string[]>([]);\n\n return (\n <Cascader\n options={REGIONS}\n value={path}\n onValueChange={(v) => setPath(v as string[])}\n showSearch\n placeholder=\"Select region…\"\n />\n );\n}\n\n// Multi-path (multiple selection)\nfunction MultiRegionPicker() {\n const [paths, setPaths] = React.useState<string[][]>([]);\n\n return (\n <Cascader\n options={REGIONS}\n multiple\n value={paths}\n onValueChange={(v) => setPaths(v as string[][])}\n showSearch\n />\n );\n}\n\n// With custom field names (data uses 'name'/'id'/'nodes')\n<Cascader\n options={rawApiData}\n fieldNames={{ label: \"name\", value: \"id\", children: \"nodes\" }}\n defaultValue={[\"dept-1\", \"team-3\"]}\n/>\n\n// changeOnSelect: lets user pick a branch node (not only leaves)\n<Cascader\n options={REGIONS}\n changeOnSelect\n onValueChange={(v) => console.log(\"path\", v)}\n/>\n`}",
|
|
3
3
|
"group": "data-entry",
|
|
4
4
|
"importPath": "@godxjp/ui/data-entry",
|
|
5
5
|
"name": "Cascader",
|
|
@@ -175,6 +175,11 @@
|
|
|
175
175
|
"description": "Search query change (antd `showSearch.onSearch`).",
|
|
176
176
|
"name": "onSearchChange",
|
|
177
177
|
"type": "(query: string) => void"
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
"description": "Accessible name for the COMBOBOX TRIGGER — the element a keyboard user lands on, not the panel. Inside a FormField it is injected for you and you do not pass it; on a bare Cascader (a toolbar scope filter, a compact drilldown with no label row) it is the only name the control has, and cardinal rule 227 requires one. Route it through t(). The rest of the field-a11y contract — aria-labelledby / describedby / errormessage / invalid / required — is accepted on every form-capable component here and is FormField's to wire.",
|
|
181
|
+
"name": "aria-label",
|
|
182
|
+
"type": "string"
|
|
178
183
|
}
|
|
179
184
|
],
|
|
180
185
|
"related": [
|
|
@@ -29,6 +29,12 @@
|
|
|
29
29
|
"name": "id",
|
|
30
30
|
"type": "string"
|
|
31
31
|
},
|
|
32
|
+
{
|
|
33
|
+
"defaultValue": "false",
|
|
34
|
+
"description": "Keeps its HTML spelling here and becomes react-aria's `isRequired`, so unlike Switch — where the same prop only ANNOUNCES the requirement — this is real constraint validation on the underlying input: an unchecked box blocks native form submission. The consent checkbox is the case it exists for. It does not render an asterisk; the required MARK belongs to FormField's label.",
|
|
35
|
+
"name": "required",
|
|
36
|
+
"type": "boolean"
|
|
37
|
+
},
|
|
32
38
|
{
|
|
33
39
|
"description": "antd `<Checkbox>label</Checkbox>` — the INLINE label: box first, label at inline-end on the same line, the same markup as a `Checkbox.Group` option. A real `<label for>`: clicking the text toggles the box and the text is its accessible name. `className` then styles the labelled row.",
|
|
34
40
|
"name": "children",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"example": "import { CompactBarTrend } from \"@godxjp/ui/charts/compact-bar-trend\";\n\n<CompactBarTrend\n label={t(\"dashboard.newOrganizations7d\")}\n description={t(\"dashboard.newOrganizationsHint\")}\n data={trend}\n categoryKey=\"date\"\n valueKey=\"count\"\n emphasizedIndex={-1}\n size=\"xs\"\n footer={<Text size=\"xs\" tone=\"muted\">{t(\"dashboard.lastUpdated\", { at })}</Text>}\n/>",
|
|
2
|
+
"example": "import { CompactBarTrend } from \"@godxjp/ui/charts/compact-bar-trend\";\nimport { Text } from \"@godxjp/ui/general\";\n\n<CompactBarTrend\n label={t(\"dashboard.newOrganizations7d\")}\n description={t(\"dashboard.newOrganizationsHint\")}\n data={trend}\n categoryKey=\"date\"\n valueKey=\"count\"\n emphasizedIndex={-1}\n size=\"xs\"\n footer={<Text size=\"xs\" tone=\"muted\">{t(\"dashboard.lastUpdated\", { at: new Date().toISOString() })}</Text>}\n/>",
|
|
3
3
|
"group": "data-display",
|
|
4
4
|
"importPath": "@godxjp/ui/charts/compact-bar-trend",
|
|
5
5
|
"name": "CompactBarTrend",
|
|
@@ -46,12 +46,23 @@
|
|
|
46
46
|
"name": "onAcknowledge",
|
|
47
47
|
"type": "() => void"
|
|
48
48
|
},
|
|
49
|
+
{
|
|
50
|
+
"description": "Copy on the button `onAcknowledge` creates. Defaults to a localized \"I've saved it\" — override it when the confirmation claims something more specific than having read the secret (\"保管しました\", \"Stored in 1Password\"). Consumer-owned wording: route it through t().",
|
|
51
|
+
"name": "acknowledgeLabel",
|
|
52
|
+
"type": "React.ReactNode"
|
|
53
|
+
},
|
|
49
54
|
{
|
|
50
55
|
"defaultValue": "false",
|
|
51
56
|
"description": "Offer a download-as-file button.",
|
|
52
57
|
"name": "downloadable",
|
|
53
58
|
"type": "boolean"
|
|
54
59
|
},
|
|
60
|
+
{
|
|
61
|
+
"defaultValue": "\"credential.txt\"",
|
|
62
|
+
"description": "Name of the file `downloadable` writes. The default is deliberately anonymous; set it when the user will hold several at once (`api-key-prod.txt`) so the saved files are still telling apart in a downloads folder.",
|
|
63
|
+
"name": "downloadFileName",
|
|
64
|
+
"type": "string"
|
|
65
|
+
},
|
|
55
66
|
{
|
|
56
67
|
"defaultValue": "\"md\"",
|
|
57
68
|
"description": "Action button size tier.",
|
|
@@ -63,6 +74,16 @@
|
|
|
63
74
|
"description": "Caution banner severity.",
|
|
64
75
|
"name": "tone",
|
|
65
76
|
"type": "\"warning\" | \"destructive\" | \"info\""
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
"description": "DOM id on the root. Useful here because the surface is usually inside a Dialog: it is what a `aria-describedby` on the dialog, or a deep link back to the issued credential, can point at.",
|
|
80
|
+
"name": "id",
|
|
81
|
+
"type": "string"
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"description": "Accessible name for the credential region when `label` is not set or is a non-string node. `label` is the VISIBLE caption and already names the region when it is a plain string, so reach for this only when the caption is rich content or when the surrounding dialog title is the only thing saying which secret this is.",
|
|
85
|
+
"name": "aria-label",
|
|
86
|
+
"type": "string"
|
|
66
87
|
}
|
|
67
88
|
],
|
|
68
89
|
"related": [
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"example": "import { DataState } from \"@godxjp/ui/query\";\n\n<DataState query={membersQuery} skeleton={<SkeletonTable />} isEmpty={(d) => d.items.length === 0} empty={<EmptyState title=\"会員なし\" />}>\n {(d) => <MemberTable items={d.items} />}\n</DataState>",
|
|
2
|
+
"example": "import { useQuery } from \"@tanstack/react-query\";\nimport { DataState } from \"@godxjp/ui/query\";\n\ntype MembersPage = { items: { id: string; name: string }[] };\n\n// T flows from the query, so `d` is MembersPage in BOTH callbacks. If you find yourself\n// annotating them, the query is untyped — fix that, never write `(d: any)`.\nconst membersQuery = useQuery<MembersPage>({ queryKey: [\"members\"], queryFn: fetchMembers });\n\n<DataState query={membersQuery} skeleton={<SkeletonTable />} isEmpty={(d) => d.items.length === 0} empty={<EmptyState title=\"会員なし\" />}>\n {(d) => <MemberTable items={d.items} />}\n</DataState>",
|
|
3
3
|
"group": "data-display",
|
|
4
4
|
"importPath": "@godxjp/ui/query",
|
|
5
5
|
"name": "DataState",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"absorbed": [
|
|
3
3
|
"DataGrid"
|
|
4
4
|
],
|
|
5
|
-
"example": "import { useState } from \"react\";\nimport { Badge, DataTable, type ColumnDef } from \"@godxjp/ui/data-display\";\nimport { EmptyState } from \"@godxjp/ui/data-display\";\n\ntype Invoice = {\n id: string;\n customer: string;\n amount: number;\n status: \"paid\" | \"pending\" | \"overdue\";\n};\n\nconst columns: ColumnDef<Invoice>[] = [\n { key: \"id\", header: \"Invoice #\", width: \"w-32\" },\n { key: \"customer\", header: \"Customer\" },\n {\n key: \"status\",\n header: \"Status\",\n render: (row) => (\n <Badge\n
|
|
5
|
+
"example": "import { useState } from \"react\";\nimport { Badge, DataTable, type ColumnDef } from \"@godxjp/ui/data-display\";\nimport { EmptyState } from \"@godxjp/ui/data-display\";\n\ntype Invoice = {\n id: string;\n customer: string;\n amount: number;\n status: \"paid\" | \"pending\" | \"overdue\";\n};\n\nconst columns: ColumnDef<Invoice>[] = [\n { key: \"id\", header: \"Invoice #\", width: \"w-32\" },\n { key: \"customer\", header: \"Customer\" },\n {\n key: \"status\",\n header: \"Status\",\n render: (row) => (\n <Badge\n tone={\n row.status === \"paid\" ? \"success\" : row.status === \"overdue\" ? \"destructive\" : \"warning\"\n }\n >\n {row.status}\n </Badge>\n ),\n },\n { key: \"amount\", header: \"Amount\", align: \"right\", sortable: true },\n];\n\nexport default function InvoiceList({\n invoices,\n loading,\n}: {\n invoices: Invoice[];\n loading: boolean;\n}) {\n const [selected, setSelected] = useState<Set<string>>(new Set());\n const [sort, setSort] = useState<{ key: string; direction: \"asc\" | \"desc\" } | undefined>();\n\n return (\n <DataTable\n data={invoices}\n columns={columns}\n getRowId={(row) => row.id}\n selectable\n selected={selected}\n onSelectChange={setSelected}\n sort={sort}\n onSortChange={setSort}\n loading={loading}\n empty={\n <EmptyState\n title=\"No invoices found\"\n description=\"Adjust your filters or create a new invoice.\"\n />\n }\n >\n <DataTable.Toolbar>\n <DataTable.BulkActions>\n <button type=\"button\" onClick={() => setSelected(new Set())}>\n Mark paid\n </button>\n </DataTable.BulkActions>\n <DataTable.DensityToggle />\n </DataTable.Toolbar>\n </DataTable>\n );\n}",
|
|
6
6
|
"group": "data-display",
|
|
7
7
|
"importPath": "@godxjp/ui/data-display",
|
|
8
8
|
"name": "DataTable",
|
|
@@ -86,13 +86,13 @@
|
|
|
86
86
|
},
|
|
87
87
|
{
|
|
88
88
|
"defaultValue": "'default'",
|
|
89
|
-
"description": "Named collection contract — the SAME preset the Table primitive owns, forwarded to the table DataTable renders. 'default' emits NO attribute and matches no selector, so an existing DataTable is byte-identical. 'action-collection' is the canonical dense approval/action queue: below collapseBelow the desktop INTRINSIC column widths give way to the token-owned column-PRIORITY measures (--table-action-collection-*) under table-layout: fixed, cells wrap, and the bordered surface drops its --table-surface-min-inline-size floor — so requester · target · reason · requested date · row actions all stay inside a 390px frame with no horizontal scroll. Mark each column with `priority` on its ColumnDef. Semantics are untouched (no display change, no role rewriting, no card swap), so header association, aria-sort and screen-reader table navigation are identical at 390 and 1440. Measured: table 1182 / 766 / 388px at 1440 / 1024 / 390, document scrollWidth === clientWidth at every width, LTR and RTL.",
|
|
89
|
+
"description": "Named collection contract — the SAME preset the Table primitive owns, forwarded to the table DataTable renders. 'default' emits NO attribute and matches no selector, so an existing DataTable is byte-identical. 'action-collection' is the canonical dense approval/action queue: below collapseBelow the desktop INTRINSIC column widths give way to the token-owned column-PRIORITY measures (--table-action-collection-*) under table-layout: fixed, cells wrap, and the bordered surface drops its --table-surface-min-inline-size floor — so requester · target · reason · requested date · row actions all stay inside a 390px frame with no horizontal scroll. Mark each column with `priority` on its ColumnDef. Semantics are untouched (no display change, no role rewriting, no card swap), so header association, aria-sort and screen-reader table navigation are identical at 390 and 1440. Measured: table 1182 / 766 / 388px at 1440 / 1024 / 390, document scrollWidth === clientWidth at every width, LTR and RTL. 'stacked-record-collection' is the other direction, for a WIDE, HETEROGENEOUS record set that has no sensible narrow column measure: below collapseBelow the <thead> hides and every <tr> becomes a bordered key-value card (--table-stacked-collection-*). Each cell then carries its column's header inline above the value, DERIVED from the same ColumnDef.header the <th> uses — so the card cannot drift from the table, and a column with a deliberately empty header names itself with ariaLabel (gh#864). The labels are aria-hidden: the real <th> is still in the DOM and remains the accessible-name source, so screen-reader table navigation is unchanged at every width. Reach for this instead of building a parallel Card tree beside the table; two trees for one dataset means two sets of labels to keep in sync.",
|
|
90
90
|
"name": "preset",
|
|
91
|
-
"type": "'default' | 'action-collection'"
|
|
91
|
+
"type": "'default' | 'action-collection' | 'stacked-record-collection'"
|
|
92
92
|
},
|
|
93
93
|
{
|
|
94
94
|
"defaultValue": "'sm'",
|
|
95
|
-
"description": "Step at which preset=\"action-collection\" switches to the compact priority measures,
|
|
95
|
+
"description": "Step at which preset=\"action-collection\" switches to the compact priority measures, or preset=\"stacked-record-collection\" folds its rows into cards. Measured against the TABLE'S OWN container (a container query on sm 40rem · md 48rem · lg 64rem · xl 80rem), not the viewport — a table inside a master rail collapses before the page does, and the same table folds by the width it is GIVEN. Ignored while preset is 'default'.",
|
|
96
96
|
"name": "collapseBelow",
|
|
97
97
|
"type": "'sm' | 'md' | 'lg' | 'xl'"
|
|
98
98
|
},
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"example": "import { FormField, Input } from \"@godxjp/ui/data-entry\";\n\n<FormField id=\"coupon-name\" label=\"クーポン名\" required error={errors.name} helper=\"最大50文字\">\n <Input id=\"coupon-name\" placeholder=\"春の花粉症対策15%OFF\" value={name} onValueChange={(
|
|
2
|
+
"example": "import { FormField, Input } from \"@godxjp/ui/data-entry\";\n\n<FormField id=\"coupon-name\" label=\"クーポン名\" required error={errors.name} helper=\"最大50文字\">\n <Input id=\"coupon-name\" placeholder=\"春の花粉症対策15%OFF\" value={name} onValueChange={(v) => setName(v)} />\n</FormField>",
|
|
3
3
|
"group": "data-entry",
|
|
4
4
|
"importPath": "@godxjp/ui/data-entry",
|
|
5
5
|
"name": "FormField",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"example": "import { InfiniteQueryState, flattenItemPages } from \"@godxjp/ui/query\";\n\n<InfiniteQueryState query={q} skeleton={<SkeletonRows />} flatten={flattenItemPages} isEmpty={(it) => it.length === 0}>\n {(items) => items.map((a) => <ActivityRow key={a.id} activity={a} />)}\n</InfiniteQueryState>",
|
|
2
|
+
"example": "import { useInfiniteQuery } from \"@tanstack/react-query\";\nimport { InfiniteQueryState, flattenItemPages } from \"@godxjp/ui/query\";\n\ntype Activity = { id: string; label: string };\n\n// `flattenItemPages` constrains the page to `{ items: TItem[] }`, so the query must be typed:\n// an untyped one makes the page `unknown`, which cannot satisfy that constraint.\nconst q = useInfiniteQuery<{ items: Activity[]; cursor?: string }>({\n queryKey: [\"activity\"],\n queryFn: fetchActivityPage,\n initialPageParam: undefined,\n getNextPageParam: (last) => last.cursor,\n});\n\n<InfiniteQueryState query={q} skeleton={<SkeletonRows />} flatten={flattenItemPages} isEmpty={(it) => it.length === 0}>\n {(items) => items.map((a) => <ActivityRow key={a.id} activity={a} />)}\n</InfiniteQueryState>",
|
|
3
3
|
"group": "data-display",
|
|
4
4
|
"importPath": "@godxjp/ui/query",
|
|
5
5
|
"name": "InfiniteQueryState",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"example": "import { Input } from \"@godxjp/ui/data-entry\";\n\n<Input id=\"qty\" type=\"number\" placeholder=\"例: 500\" value={value} onValueChange={(
|
|
2
|
+
"example": "import { Input } from \"@godxjp/ui/data-entry\";\n\n<Input id=\"qty\" type=\"number\" placeholder=\"例: 500\" value={value} onValueChange={(v) => setValue(v)} />",
|
|
3
3
|
"group": "data-entry",
|
|
4
4
|
"importPath": "@godxjp/ui/data-entry",
|
|
5
5
|
"name": "Input",
|
|
@@ -70,6 +70,41 @@
|
|
|
70
70
|
"description": "Main-axis alignment of the whole code row (groups + separators) inside the field. `center` is the canonical auth challenge. Before this existed, every consumer wrapped the OTP in their own flex-centring div — do not. A service that wants all code fields centred sets `--otp-container-align` once instead.",
|
|
71
71
|
"name": "align",
|
|
72
72
|
"type": "\"start\" | \"center\" | \"end\""
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"description": "Fires ONCE the last slot fills, whether the user typed it or pasted the whole code. This is the auto-submit hook: a 2FA challenge with a visible submit button is a step nobody wants, and the alternative — watching `value.length === maxLength` in an effect — re-fires on every re-render. Keep the submit button anyway for the paste-then-correct case.",
|
|
76
|
+
"name": "onComplete",
|
|
77
|
+
"type": "(value: string) => void"
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"description": "Rewrites CLIPBOARD text before it reaches the field. Distinct from `formatter`, which normalises every value: this one only sees a paste, which is where the junk arrives — `\"123 456\"`, `\"code: 123456\"`, a copied SMS line. Note the order the field applies them: `pattern` is matched against the RAW keystroke first, so a pattern must accept what a user actually types, not only what these two produce.",
|
|
81
|
+
"name": "pasteTransformer",
|
|
82
|
+
"type": "(pasted: string) => string"
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
"description": "Class on the ROW container `input-otp` renders (the slots' flex parent), which `className` cannot reach — `className` lands on the hidden input, because that is the real field. Prefer `align` and the `--otp-*` tokens; this is the vendored escape hatch underneath them.",
|
|
86
|
+
"name": "containerClassName",
|
|
87
|
+
"type": "string"
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
"description": "`input-otp`'s answer to the 1Password / LastPass badge that browsers float over a code field and that covers the last slot. `increase-width` (its default) reserves room so the badge sits beside the row; `none` turns the accommodation off, which is what a row already centred by `align` usually wants. Pure layout — it changes no value and no keyboard behaviour.",
|
|
91
|
+
"name": "pushPasswordManagerStrategy",
|
|
92
|
+
"type": "\"increase-width\" | \"none\""
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"description": "The `<noscript>` stylesheet `input-otp` injects so the slots are still visible with JS disabled. Pass `null` to suppress it — the one real reason being a CSP that forbids inline styles and that `nonce` cannot satisfy. Leave it alone otherwise.",
|
|
96
|
+
"name": "noScriptCSSFallback",
|
|
97
|
+
"type": "string | null"
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
"description": "CSP nonce stamped on the stylesheet `input-otp` injects. Required only under a `style-src 'nonce-…'` policy, where the field otherwise renders unstyled and the console reports a blocked inline style. Pass the same nonce the document was served with.",
|
|
101
|
+
"name": "nonce",
|
|
102
|
+
"type": "string"
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
"description": "`input-otp`'s headless mode: you draw the entire row from the slot state instead of composing InputOTPGroup / InputOTPSlot. It is mutually exclusive with `children` — the vendor types the two as a union and this component keeps that union. Reaching for it means giving up the slot styling, the group outline and the separator this package owns, so it is the last resort, not a customisation point.",
|
|
106
|
+
"name": "render",
|
|
107
|
+
"type": "(props: InputOTPRenderProps) => React.ReactNode"
|
|
73
108
|
}
|
|
74
109
|
],
|
|
75
110
|
"related": [
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"type": "ChartDatum[]"
|
|
12
12
|
},
|
|
13
13
|
{
|
|
14
|
-
"description": "Plotted series: { dataKey, label?, color? }. Colour defaults to the --chart-1..6 palette.",
|
|
14
|
+
"description": "Plotted series: { dataKey, label?, color?, fillColor? }. Colour defaults to the --chart-1..6 palette; fillColor is the AreaChart band only.",
|
|
15
15
|
"name": "series",
|
|
16
16
|
"required": true,
|
|
17
17
|
"type": "ChartSeriesProp[]"
|
|
@@ -67,12 +67,28 @@
|
|
|
67
67
|
"name": "numberFormat",
|
|
68
68
|
"type": "Intl.NumberFormatOptions"
|
|
69
69
|
},
|
|
70
|
+
{
|
|
71
|
+
"description": "Explicit [min, max] for the VALUE axis (y vertical, x on a horizontal bar). Omit to let the data set it. A non-zero baseline is a charting-ETHICS call: legitimate where the SHAPE is the message and zero is not a reference (price, temperature, an index, a latency percentile), misleading wherever the reader compares magnitudes — which is every bar chart.",
|
|
72
|
+
"name": "valueDomain",
|
|
73
|
+
"type": "[number, number]"
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"description": "Explicit tick positions on the value axis, in data units. Values outside valueDomain are not drawn.",
|
|
77
|
+
"name": "valueTicks",
|
|
78
|
+
"type": "number[]"
|
|
79
|
+
},
|
|
70
80
|
{
|
|
71
81
|
"defaultValue": "false",
|
|
72
82
|
"description": "Render smooth (monotone) lines instead of straight segments.",
|
|
73
83
|
"name": "curved",
|
|
74
84
|
"type": "boolean"
|
|
75
85
|
},
|
|
86
|
+
{
|
|
87
|
+
"defaultValue": "false",
|
|
88
|
+
"description": "Draw a marker at every data point. Off by default — markers crowd a dense series.",
|
|
89
|
+
"name": "showDots",
|
|
90
|
+
"type": "boolean"
|
|
91
|
+
},
|
|
76
92
|
{
|
|
77
93
|
"description": "Message shown when `data` is empty (defaults to a localized 'no data').",
|
|
78
94
|
"name": "emptyMessage",
|
|
@@ -93,7 +109,9 @@
|
|
|
93
109
|
"DO install the `recharts` optional peer dependency in the consuming app — charts are the only part of @godxjp/ui that needs it, so apps without charts never pay for it.",
|
|
94
110
|
"DO pass an i18n'd `label` — it is both the visible caption and the accessible name; the component also emits a screen-reader list of the plotted values (WCAG 1.1.1).",
|
|
95
111
|
"DO pre-translate each series' `label`; pass `numberFormat` (e.g. { style: 'currency', currency: 'JPY' }) and the axis/tooltip numbers localize automatically via Intl.",
|
|
96
|
-
"DON'T hand-roll an SVG/canvas chart or drop raw recharts into a page — LineChart owns the colour tokens, locale formatting, empty state, and accessibility wiring."
|
|
112
|
+
"DON'T hand-roll an SVG/canvas chart or drop raw recharts into a page — LineChart owns the colour tokens, locale formatting, empty state, and accessibility wiring.",
|
|
113
|
+
"DO retune the line weight and the grid dash with the `--chart-series-stroke-width` / `--chart-grid-line-dash` theme tokens, globally or on a scoped [data-tenant] region. They are house style; there is no prop for them.",
|
|
114
|
+
"DON'T reach for `valueDomain` to make a flat trend look dramatic — cropping the axis magnifies every wobble and the reader cannot tell a 2% drift from a collapse. Crop only where zero is not a meaningful reference, and say the range."
|
|
97
115
|
],
|
|
98
116
|
"useCases": [
|
|
99
117
|
"Revenue / KPI trend over months in a dashboard.",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"example": "import { Card, CardContent, CardHeader, CardTitle, ListRow, Badge } from \"@godxjp/ui/data-display\";\nimport { Button } from \"@godxjp/ui/general\";\nimport { Smartphone } from \"lucide-react\";\nimport { Flex } from \"@godxjp/ui/layout\";\n\n// The three scenarios below are three CARDS on one page, so they are wrapped in a Flex — the gap\n// between sibling cards belongs to the stack, never to the cards (audit: sibling-cards-need-flex).\n<Flex direction=\"col\" gap=\"lg\">\n<Card>\n <CardHeader>\n <CardTitle>アクティブなセッション</CardTitle>\n </CardHeader>\n <CardContent flush>\n <ListRow\n leading={<Smartphone aria-hidden=\"true\" className=\"size-4\" />}\n title=\"iPhone 15 · Tokyo\"\n description=\"最終アクセス 2分前\"\n trailing={<Badge status=\"active\" />}\n />\n <ListRow\n leading={<Smartphone aria-hidden=\"true\" className=\"size-4\" />}\n title=\"MacBook Pro · Osaka\"\n description=\"最終アクセス 3日前\"\n trailing={<Button size=\"xs\" variant=\"outline\">ログアウト</Button>}\n />\n </CardContent>\n</Card>\n\n// Notifications — unread dot + emphasized surface, wrapping title, two inline actions\n<Card>\n <CardContent flush>\n <ListRow\n unread\n align=\"start\"\n overflow=\"wrap\"\n title=\"組織「グローバル・トランスフォーメーション推進本部」への招待が届いています\"\n description=\"2026-07-30 09:12 JST\"\n trailing={\n <>\n <Button size=\"xs\" variant=\"ghost\">既読にする</Button>\n <Button size=\"xs\" variant=\"outline\">開く</Button>\n </>\n }\n />\n <ListRow unread={false} align=\"start\" overflow=\"wrap\" title=\"請求書が発行されました\" description=\"2026-07-28 18:40 JST\" />\n </CardContent>\n</Card>\n\n
|
|
2
|
+
"example": "import { Card, CardContent, CardHeader, CardTitle, ListRow, Badge } from \"@godxjp/ui/data-display\";\nimport { Button } from \"@godxjp/ui/general\";\nimport { Smartphone } from \"lucide-react\";\nimport { Flex } from \"@godxjp/ui/layout\";\n\n// The three scenarios below are three CARDS on one page, so they are wrapped in a Flex — the gap\n// between sibling cards belongs to the stack, never to the cards (audit: sibling-cards-need-flex).\n<Flex direction=\"col\" gap=\"lg\">\n<Card>\n <CardHeader>\n <CardTitle>アクティブなセッション</CardTitle>\n </CardHeader>\n <CardContent flush>\n <ListRow\n leading={<Smartphone aria-hidden=\"true\" className=\"size-4\" />}\n title=\"iPhone 15 · Tokyo\"\n description=\"最終アクセス 2分前\"\n trailing={<Badge status=\"active\" />}\n />\n <ListRow\n leading={<Smartphone aria-hidden=\"true\" className=\"size-4\" />}\n title=\"MacBook Pro · Osaka\"\n description=\"最終アクセス 3日前\"\n trailing={<Button size=\"xs\" variant=\"outline\">ログアウト</Button>}\n />\n </CardContent>\n</Card>\n\n// Notifications — unread dot + emphasized surface, wrapping title, two inline actions\n<Card>\n <CardContent flush>\n <ListRow\n unread\n align=\"start\"\n overflow=\"wrap\"\n title=\"組織「グローバル・トランスフォーメーション推進本部」への招待が届いています\"\n description=\"2026-07-30 09:12 JST\"\n trailing={\n <>\n <Button size=\"xs\" variant=\"ghost\">既読にする</Button>\n <Button size=\"xs\" variant=\"outline\">開く</Button>\n </>\n }\n />\n <ListRow unread={false} align=\"start\" overflow=\"wrap\" title=\"請求書が発行されました\" description=\"2026-07-28 18:40 JST\" />\n </CardContent>\n</Card>\n\n{/* A list of LINKS — `as=\"li\"` gives the list item, `asChild` gives the whole-row link, and the\n item carries the divider. Never wrap the row in your own li, and never reach for a raw ul:\n `marker=\"none\"` is the semantic list container (no bullet, no indent, gap token). */}\n<Card>\n <CardContent flush>\n <Flex as=\"ul\" marker=\"none\" direction=\"col\" gap=\"none\">\n {projects.map((project) => (\n <ListRow key={project.key} as=\"li\" asChild title={project.name} description={project.key}>\n <Link href={`/projects/${project.key}`} />\n </ListRow>\n ))}\n </Flex>\n </CardContent>\n</Card>\n</Flex>",
|
|
3
3
|
"group": "data-display",
|
|
4
4
|
"importPath": "@godxjp/ui/data-display",
|
|
5
5
|
"name": "ListRow",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"docPath": "layout/masonry.tsx",
|
|
3
|
-
"example": "import { Masonry } from \"@godxjp/ui/layout\";\nimport { Card, CardContent } from \"@godxjp/ui/data-display\";\nimport { Text } from \"@godxjp/ui/general\";\n\n<Masonry\n columns={{ base: 1, sm: 2, lg: 3 }}\n gap=\"md\"\n items={notes.map((note) => ({ key: note.id, data: note }))}\n itemRender={({ data }) => (\n <Card>\n <CardContent>\n <Text>{data
|
|
3
|
+
"example": "import { Masonry } from \"@godxjp/ui/layout\";\nimport { Card, CardContent } from \"@godxjp/ui/data-display\";\nimport { Text } from \"@godxjp/ui/general\";\n\n// T flows from `items`, so `data` in itemRender is whatever you put there — give the\n// collection a shape and the render callback needs no annotation.\ntype Note = { id: string; body: string };\nconst notes: Note[] = useNotes();\n\n<Masonry\n columns={{ base: 1, sm: 2, lg: 3 }}\n gap=\"md\"\n items={notes.map((note) => ({ key: note.id, data: note }))}\n itemRender={({ data }) => (\n <Card>\n <CardContent>\n <Text>{data?.body}</Text>\n </CardContent>\n </Card>\n )}\n onLayoutChange={(layout) => console.log(layout.length, \"tiles placed\")}\n/>",
|
|
4
4
|
"group": "layout",
|
|
5
5
|
"importPath": "@godxjp/ui/layout",
|
|
6
6
|
"name": "Masonry",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"example": "import { MasterDetail } from \"@godxjp/ui/layout\";\n\n// Canonical: fluid list + fixed 320px detail rail (stacks below 40rem).\n<MasterDetail\n masterLabel=\"Teams\"\n detailLabel=\"Selected team\"\n detailId=\"team-detail\"\n master={<TeamTable onRowClick={select} detailId=\"team-detail\" />}\n>\n <TeamDetail team={selected} />\n</MasterDetail>\n\n// Leading navigator rail instead.\n<MasterDetail
|
|
2
|
+
"example": "import { MasterDetail } from \"@godxjp/ui/layout\";\n\n// Canonical: fluid list + fixed 320px detail rail (stacks below 40rem).\n<MasterDetail\n masterLabel=\"Teams\"\n detailLabel=\"Selected team\"\n detailId=\"team-detail\"\n master={<TeamTable onRowClick={select} detailId=\"team-detail\" />}\n>\n <TeamDetail team={selected} />\n</MasterDetail>\n\n// Leading navigator rail instead.\n<MasterDetail\n rail=\"master\"\n railWidth=\"compact\"\n masterLabel=\"Categories\"\n master={<CategoryNav activeId={activeCategory} onSelect={setActiveCategory} />}\n>\n <SettingsForm />\n</MasterDetail>\n\n// A long real collection: bound the master so it scrolls in place and the detail\n// stays near the top of a stacked mobile page.\n<MasterDetail\n masterViewport=\"compact\"\n masterLabel=\"Members\"\n detailLabel=\"Selected member\"\n master={<MemberList onRowClick={select} />}\n>\n <MemberDetail member={selected} />\n</MasterDetail>",
|
|
3
3
|
"group": "layout",
|
|
4
4
|
"importPath": "@godxjp/ui/layout",
|
|
5
5
|
"name": "MasterDetail",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"example": "import { PasswordInput, PasswordStrength } from \"@godxjp/ui/data-entry\";\n\
|
|
2
|
+
"example": "import { PasswordInput, PasswordStrength } from \"@godxjp/ui/data-entry\";\n\nexport default function PasswordBlock() {\n const [value, setValue] = useState(\"\");\n return (\n <div className=\"ui-stack\">\n <PasswordInput value={value} onChange={(event) => setValue(event.target.value)} />\n <PasswordStrength value={value} rules={[\"length\", \"upper\", \"lower\", \"number\", \"symbol\"]} />\n </div>\n );\n}",
|
|
3
3
|
"group": "data-entry",
|
|
4
4
|
"importPath": "@godxjp/ui/data-entry",
|
|
5
5
|
"name": "PasswordStrength",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"docPath": "data-display/permission-matrix.tsx",
|
|
3
|
-
"example": "import { Card, CardContent, PermissionMatrix } from \"@godxjp/ui/data-display\";\nimport { grantKey } from \"@godxjp/ui/lib/permission-grid\";\n\nconst grants = new Set(rolePermissions.map((rp) => grantKey(rp.roleId, rp.permissionId)));\n\n<Card>\n <CardContent flush>\n <PermissionMatrix\n roles={roles}\n permissions={permissions}\n grants={grants}\n onGrantChange={(roleId, permissionId, granted) => mutate({ roleId, permissionId, granted })}\n />\n </CardContent>\n</Card>",
|
|
3
|
+
"example": "import { Card, CardContent, PermissionMatrix } from \"@godxjp/ui/data-display\";\nimport { grantKey } from \"@godxjp/ui/lib/permission-grid\";\n\nconst grants = new Set<string>(rolePermissions.map((rp) => grantKey(rp.roleId, rp.permissionId)));\n\n<Card>\n <CardContent flush>\n <PermissionMatrix\n roles={roles}\n permissions={permissions}\n grants={grants}\n onGrantChange={(roleId, permissionId, granted) => mutate({ roleId, permissionId, granted })}\n />\n </CardContent>\n</Card>",
|
|
4
4
|
"group": "data-display",
|
|
5
5
|
"importPath": "@godxjp/ui/data-display",
|
|
6
6
|
"name": "PermissionMatrix",
|
|
@@ -54,6 +54,11 @@
|
|
|
54
54
|
"description": "Accessible table name (localized default).",
|
|
55
55
|
"name": "label",
|
|
56
56
|
"type": "string"
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"description": "DOM id on the grid root. Worth setting on a permissions page that also renders a summary or a legend elsewhere: it is the anchor those can point at, and the stable handle for an E2E selector that must not depend on the localized `label`.",
|
|
60
|
+
"name": "id",
|
|
61
|
+
"type": "string"
|
|
57
62
|
}
|
|
58
63
|
],
|
|
59
64
|
"related": [
|
|
@@ -67,6 +67,11 @@
|
|
|
67
67
|
"description": "Disable search input and clearing.",
|
|
68
68
|
"name": "disabled",
|
|
69
69
|
"type": "boolean"
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"description": "Class on the `<input>` itself. SearchInput renders a WRAPPER (label, icon, clear button, input), so `className` lands on that wrapper and never reaches the field — this is the second handle, for the case where the field and its chrome need different treatment. Layout and colour still belong to tokens; use it for the rare geometry a token cannot reach.",
|
|
73
|
+
"name": "inputClassName",
|
|
74
|
+
"type": "string"
|
|
70
75
|
}
|
|
71
76
|
],
|
|
72
77
|
"related": [
|