@godxjp/ui 30.9.0 → 31.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/agent/START-HERE.md +1 -1
- package/agent/components/PrefetchLink.json +3 -3
- package/agent/components-index.json +1 -1
- package/agent/components.json +3 -3
- package/agent/index.json +2 -2
- package/agent/llms.txt +3 -3
- package/agent/patterns/settings-page-responsive.json +1 -1
- package/agent/patterns.json +1 -1
- package/dist/components/query/index.d.ts +0 -2
- package/dist/components/query/index.js +0 -2
- package/dist/components/react-router/index.d.ts +2 -0
- package/dist/components/react-router/index.js +4 -0
- package/dist/contracts/measurement.json +1 -1
- package/dist/styles/alert-layout.css +4 -2
- package/dist/styles/layers.json +1 -1
- package/docs/CONSUMER-RULES.md +1 -1
- package/docs/data-display/permission-matrix.tsx +30 -28
- package/docs/data-entry/cascader.tsx +22 -20
- package/docs/data-entry/date-picker.tsx +47 -43
- package/docs/data-entry/form-field/examples/a11y-contract.tsx +80 -76
- package/docs/data-entry/form-field/examples/create-form.tsx +33 -31
- package/docs/data-entry/form-field/index.tsx +61 -57
- package/docs/data-entry/form.tsx +112 -106
- package/docs/data-entry/input.tsx +297 -270
- package/docs/data-entry/label.tsx +11 -9
- package/docs/data-entry/number-input.tsx +86 -78
- package/docs/data-entry/radio-group.tsx +33 -26
- package/docs/data-entry/rating.tsx +29 -25
- package/docs/data-entry/select-matrix.tsx +49 -47
- package/docs/data-entry/select.tsx +38 -35
- package/docs/data-entry/slider.tsx +45 -41
- package/docs/data-entry/textarea.tsx +44 -42
- package/docs/data-entry/time-picker.tsx +51 -47
- package/docs/feedback/sheet.tsx +84 -79
- package/docs/foundation/theme-editor.tsx +133 -124
- package/docs/general/button/examples/form-actions.tsx +17 -15
- package/docs/layout/auth-recovery/examples/password-recovery.tsx +31 -29
- package/docs/layout/auth-shell-registration.tsx +75 -72
- package/docs/layout/auth-shell-variants.tsx +55 -51
- package/docs/layout/space-compact.tsx +11 -8
- package/docs/{query → react-router}/prefetch-link.tsx +1 -1
- package/docs/showcase/caimono-price-comparison.tsx +59 -51
- package/docs/showcase/case3-approval-workflow.tsx +27 -25
- package/docs/showcase/case4-login.tsx +37 -34
- package/docs/showcase/permission-matrix.tsx +44 -42
- package/docs/showcase/theme-customization.tsx +108 -99
- package/package.json +6 -2
- package/scripts/consumer-rule.md +14 -0
- package/scripts/ui-audit.mjs +99 -2
- /package/dist/components/{query → react-router}/prefetch-link.d.ts +0 -0
- /package/dist/components/{query → react-router}/prefetch-link.js +0 -0
package/README.md
CHANGED
|
@@ -112,7 +112,8 @@ A value is defined **once** as a CSS var (`--primary`), mapped to a utility in t
|
|
|
112
112
|
| **Data Entry** | `@godxjp/ui/data-entry` | `Input`, `Select`, `FormField`, `Field`, `DatePicker`, `TimePicker`, `Combobox`, `Switch`, `Toggle`, `Upload`, `Cascader`, `TreeSelect`, `ColorPicker`, `Slider`, `PasswordInput`, `PasswordStrength`, `InputOTP`, `Rating`, `TagInput` |
|
|
113
113
|
| **Data Display** | `@godxjp/ui/data-display` | `Table`, `DataTable`, `Card`, `StatCard`, `Badge`, `Avatar`, `Descriptions`, `Timeline`, `EmptyState`, `Progress`, `QrCode`, `CredentialReveal`, `Accordion`, `HoverCard`, `Carousel`, `Popover`, `Collapsible` |
|
|
114
114
|
| **Feedback** | `@godxjp/ui/feedback` | `Dialog`, `AlertDialog`, `Sheet` (side), `Drawer` (bottom-sheet), `Toast`, `Skeleton`, `Alert`, `Tooltip` |
|
|
115
|
-
| **Query** | `@godxjp/ui/query` | `DataState`, `InfiniteQueryState
|
|
115
|
+
| **Query** | `@godxjp/ui/query` | `DataState`, `InfiniteQueryState` (adapter subpath — pulls TanStack Query; no router) |
|
|
116
|
+
| **React Router** | `@godxjp/ui/react-router` | `PrefetchLink` — imports the optional `react-router-dom` peer, so it is kept out of `/query` (gh#996) |
|
|
116
117
|
| **Navigation** | `@godxjp/ui/navigation` | `Tabs`, `Toolbar`, `DropdownMenu`, `Steps`, `Pagination`, `Breadcrumb`, `AppSettingPicker` |
|
|
117
118
|
| **App** | `@godxjp/ui/app` | `AppProvider`, `useDateTime` (adapter — i18n/datetime singleton) |
|
|
118
119
|
| **Datetime** | `@godxjp/ui/datetime` | `formatDate` (mandatory for display) |
|
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` 31.0.2.** If the project you are editing has a different
|
|
7
7
|
version in its `package.json`, read the pinned catalog for THAT version instead
|
|
8
8
|
(`…/v<their-version>/agent/…`). A catalog newer than the installed package describes props that do
|
|
9
9
|
not exist yet; older, and it hides props that do. Neither failure announces itself.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
|
-
"example": "import { PrefetchLink } from \"@godxjp/ui/
|
|
2
|
+
"example": "import { PrefetchLink } from \"@godxjp/ui/react-router\";\nimport { fetchInvoice } from \"@/api/invoices\";\n\n// Inside a table row or list item:\n<PrefetchLink\n to={`/invoices/${invoice.id}`}\n queryKey={[\"invoice\", invoice.id]}\n queryFn={() => fetchInvoice(invoice.id)}\n staleTime={60_000}\n className=\"font-medium hover:underline\"\n>\n {invoice.number}\n</PrefetchLink>\n\n// Disable prefetch for rows where data is not yet stable:\n<PrefetchLink\n to={`/invoices/${invoice.id}`}\n queryKey={[\"invoice\", invoice.id]}\n queryFn={() => fetchInvoice(invoice.id)}\n prefetchOn=\"none\"\n>\n {invoice.number}\n</PrefetchLink>",
|
|
3
3
|
"group": "data-display",
|
|
4
|
-
"importPath": "@godxjp/ui/
|
|
4
|
+
"importPath": "@godxjp/ui/react-router",
|
|
5
5
|
"name": "PrefetchLink",
|
|
6
6
|
"props": [
|
|
7
7
|
{
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
31
|
|
47
47
|
],
|
|
48
48
|
"storyPath": "data-display/PrefetchLink.stories.tsx",
|
|
49
|
-
"tagline": "React Router Link that fires prefetchQuery on hover/focus so detail pages feel instant — requires a TanStack Query QueryClient in context.",
|
|
49
|
+
"tagline": "React Router Link that fires prefetchQuery on hover/focus so detail pages feel instant — requires a TanStack Query QueryClient in context. Imported from `@godxjp/ui/react-router` (not `/query`) because it imports the optional `react-router-dom` peer; in `/query` it broke every router-less app's build (gh#996).",
|
|
50
50
|
"usage": [
|
|
51
51
|
"DO: provide a queryKey that exactly matches the destination page's useQuery key — a mismatch means the prefetch populates a different cache slot and the page still loads cold.",
|
|
52
52
|
"DO: keep queryFn lightweight and side-effect-free; it runs speculatively on hover. Avoid mutations or write operations inside queryFn.",
|
|
@@ -590,7 +590,7 @@
|
|
|
590
590
|
{
|
|
591
591
|
"group": "data-display",
|
|
592
592
|
"name": "PrefetchLink",
|
|
593
|
-
"tagline": "React Router Link that fires prefetchQuery on hover/focus so detail pages feel instant — requires a TanStack Query QueryClient in context."
|
|
593
|
+
"tagline": "React Router Link that fires prefetchQuery on hover/focus so detail pages feel instant — requires a TanStack Query QueryClient in context. Imported from `@godxjp/ui/react-router` (not `/query`) because it imports the optional `react-router-dom` peer; in `/query` it broke every router-less app's build (gh#996)."
|
|
594
594
|
},
|
|
595
595
|
{
|
|
596
596
|
"group": "data-display",
|
package/agent/components.json
CHANGED
|
@@ -11201,9 +11201,9 @@
|
|
|
11201
11201
|
]
|
|
11202
11202
|
},
|
|
11203
11203
|
{
|
|
11204
|
-
"example": "import { PrefetchLink } from \"@godxjp/ui/
|
|
11204
|
+
"example": "import { PrefetchLink } from \"@godxjp/ui/react-router\";\nimport { fetchInvoice } from \"@/api/invoices\";\n\n// Inside a table row or list item:\n<PrefetchLink\n to={`/invoices/${invoice.id}`}\n queryKey={[\"invoice\", invoice.id]}\n queryFn={() => fetchInvoice(invoice.id)}\n staleTime={60_000}\n className=\"font-medium hover:underline\"\n>\n {invoice.number}\n</PrefetchLink>\n\n// Disable prefetch for rows where data is not yet stable:\n<PrefetchLink\n to={`/invoices/${invoice.id}`}\n queryKey={[\"invoice\", invoice.id]}\n queryFn={() => fetchInvoice(invoice.id)}\n prefetchOn=\"none\"\n>\n {invoice.number}\n</PrefetchLink>",
|
|
11205
11205
|
"group": "data-display",
|
|
11206
|
-
"importPath": "@godxjp/ui/
|
|
11206
|
+
"importPath": "@godxjp/ui/react-router",
|
|
11207
11207
|
"name": "PrefetchLink",
|
|
11208
11208
|
"props": [
|
|
11209
11209
|
{
|
|
@@ -11248,7 +11248,7 @@
|
|
|
11248
11248
|
31
|
|
11249
11249
|
],
|
|
11250
11250
|
"storyPath": "data-display/PrefetchLink.stories.tsx",
|
|
11251
|
-
"tagline": "React Router Link that fires prefetchQuery on hover/focus so detail pages feel instant — requires a TanStack Query QueryClient in context.",
|
|
11251
|
+
"tagline": "React Router Link that fires prefetchQuery on hover/focus so detail pages feel instant — requires a TanStack Query QueryClient in context. Imported from `@godxjp/ui/react-router` (not `/query`) because it imports the optional `react-router-dom` peer; in `/query` it broke every router-less app's build (gh#996).",
|
|
11252
11252
|
"usage": [
|
|
11253
11253
|
"DO: provide a queryKey that exactly matches the destination page's useQuery key — a mismatch means the prefetch populates a different cache slot and the page still loads cold.",
|
|
11254
11254
|
"DO: keep queryFn lightweight and side-effect-free; it runs speculatively on hover. Avoid mutations or write operations inside queryFn.",
|
package/agent/index.json
CHANGED
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"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.",
|
|
49
49
|
"read": {
|
|
50
50
|
"live": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/index.json",
|
|
51
|
-
"pinned": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/
|
|
51
|
+
"pinned": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/v31.0.2/agent/index.json"
|
|
52
52
|
},
|
|
53
53
|
"source": "mcp/src/data — the same data @godxjp/ui-mcp serves — plus the foundation and semantic token tiers, read from src/tokens/*.css",
|
|
54
54
|
"start": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/START-HERE.md",
|
|
@@ -62,5 +62,5 @@
|
|
|
62
62
|
"foundation": "the seeds a consumer is invited to set — --primary, --background, --radius",
|
|
63
63
|
"semantic": "named roles that follow the seeds — --ring, --text-link, --overlay-background"
|
|
64
64
|
},
|
|
65
|
-
"version": "
|
|
65
|
+
"version": "31.0.2"
|
|
66
66
|
}
|
package/agent/llms.txt
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# @godxjp/ui
|
|
2
2
|
|
|
3
3
|
> A Japanese-enterprise React design system: 175 components, 2074 design tokens,
|
|
4
|
-
> 50 cardinal rules. This file is the entry point for AI agents. Catalog version
|
|
4
|
+
> 50 cardinal rules. This file is the entry point for AI agents. Catalog version 31.0.2.
|
|
5
5
|
|
|
6
6
|
If your client can run a process, do not read these files — run the MCP server instead
|
|
7
|
-
(`npx @godxjp/ui-mcp@
|
|
7
|
+
(`npx @godxjp/ui-mcp@31.0.2`). It is searchable and version-locked. These files exist for agents
|
|
8
8
|
that can only fetch URLs.
|
|
9
9
|
|
|
10
10
|
## Start
|
|
@@ -26,7 +26,7 @@ that can only fetch URLs.
|
|
|
26
26
|
## Pinning
|
|
27
27
|
|
|
28
28
|
Every URL above tracks `main`. To pin to the release a project actually installed, swap `main` for
|
|
29
|
-
the tag: `.../godx-jp/godxjp-ui/
|
|
29
|
+
the tag: `.../godx-jp/godxjp-ui/v31.0.2/agent/...`. A catalog that does not match the installed
|
|
30
30
|
package describes props that are absent, or hides props that are present, and says nothing either way.
|
|
31
31
|
|
|
32
32
|
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.
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"settings-page",
|
|
5
5
|
"settings-layout"
|
|
6
6
|
],
|
|
7
|
-
"code": "// Research basis: GitHub, Google Account, Microsoft Account, Atlassian Account settings +\n// the IBM Carbon form grid. Every destination is a URL, so deep links and browser back/forward\n// work for free and the active item is derived from the route — never from local tab state.\n//\n// Desktop (>= lg): persistent vertical local nav on the left + bounded content on the right.\n// Mobile (< lg): the SAME routes become a horizontal, scrollable tab strip above the content.\n// Styling uses ONLY real semantic token classes (bg-muted / text-foreground / text-muted-foreground)\n// and responsive/visibility utilities — the library ships NO bespoke settings shell/nav CSS classes.\nimport { NavLink, Outlet, Navigate } from \"react-router-dom\";\nimport { Flex } from \"@godxjp/ui/layout\";\nimport { FormField, Input } from \"@godxjp/ui/data-entry\";\nimport { Button } from \"@godxjp/ui/general\";\n\nconst SECTIONS = [\n { to: \"general\", label: \"基本情報\" },\n { to: \"security\", label: \"セキュリティ\" },\n { to: \"notifications\", label: \"通知\" },\n] as const;\n\n// One link renderer for BOTH breakpoints. NavLink gives us the active state (and sets\n// aria-current=\"page\") straight from the URL; semantic tokens only, no invented classes.\nconst link = ({ isActive }: { isActive: boolean }) =>\n [\n \"rounded-md px-3 py-2 text-sm no-underline transition-colors whitespace-nowrap\",\n isActive\n ? \"bg-muted text-foreground font-medium\"\n : \"text-muted-foreground hover:text-foreground\",\n ].join(\" \");\n\nexport function SettingsLayout() {\n return (\n <Flex direction=\"col\" gap=\"lg\" className=\"lg:flex-row lg:items-start\">\n {/* < lg: horizontal, scrollable route tabs. Flex owns the row and the gap — hideFrom /\n hideBelow own the breakpoint, so neither nav needs a hand-rolled flex or gap utility. */}\n <Flex as=\"nav\" aria-label=\"設定\" gap={1} hideFrom=\"lg\" className=\"overflow-x-auto\">\n {SECTIONS.map((s) => (\n <NavLink key={s.to} to={s.to} className={link} end>{s.label}</NavLink>\n ))}\n </Flex>\n {/* >= lg: persistent vertical local nav (bounded width, does not shrink). */}\n <Flex as=\"nav\" aria-label=\"設定\" direction=\"col\" gap={1} hideBelow=\"lg\" width={224} shrink={false}>\n {SECTIONS.map((s) => (\n <NavLink key={s.to} to={s.to} className={link} end>{s.label}</NavLink>\n ))}\n </Flex>\n {/* Bounded content region (~42rem) — the routed section renders here. min-w-0 lets it shrink. */}\n <main className=\"min-w-0 max-w-2xl flex-1\"><Outlet /></main>\n </Flex>\n );\n}\n\n// A settings section. Horizontal label/control rows on desktop (collapse to stacked on mobile),\n// controls bounded to a semantic width. FormField OWNS the label↔control relationship — do NOT
|
|
7
|
+
"code": "// Research basis: GitHub, Google Account, Microsoft Account, Atlassian Account settings +\n// the IBM Carbon form grid. Every destination is a URL, so deep links and browser back/forward\n// work for free and the active item is derived from the route — never from local tab state.\n//\n// Desktop (>= lg): persistent vertical local nav on the left + bounded content on the right.\n// Mobile (< lg): the SAME routes become a horizontal, scrollable tab strip above the content.\n// Styling uses ONLY real semantic token classes (bg-muted / text-foreground / text-muted-foreground)\n// and responsive/visibility utilities — the library ships NO bespoke settings shell/nav CSS classes.\nimport { NavLink, Outlet, Navigate } from \"react-router-dom\";\nimport { Flex } from \"@godxjp/ui/layout\";\nimport { Form, FormField, Input } from \"@godxjp/ui/data-entry\";\nimport { Button } from \"@godxjp/ui/general\";\n\nconst SECTIONS = [\n { to: \"general\", label: \"基本情報\" },\n { to: \"security\", label: \"セキュリティ\" },\n { to: \"notifications\", label: \"通知\" },\n] as const;\n\n// One link renderer for BOTH breakpoints. NavLink gives us the active state (and sets\n// aria-current=\"page\") straight from the URL; semantic tokens only, no invented classes.\nconst link = ({ isActive }: { isActive: boolean }) =>\n [\n \"rounded-md px-3 py-2 text-sm no-underline transition-colors whitespace-nowrap\",\n isActive\n ? \"bg-muted text-foreground font-medium\"\n : \"text-muted-foreground hover:text-foreground\",\n ].join(\" \");\n\nexport function SettingsLayout() {\n return (\n <Flex direction=\"col\" gap=\"lg\" className=\"lg:flex-row lg:items-start\">\n {/* < lg: horizontal, scrollable route tabs. Flex owns the row and the gap — hideFrom /\n hideBelow own the breakpoint, so neither nav needs a hand-rolled flex or gap utility. */}\n <Flex as=\"nav\" aria-label=\"設定\" gap={1} hideFrom=\"lg\" className=\"overflow-x-auto\">\n {SECTIONS.map((s) => (\n <NavLink key={s.to} to={s.to} className={link} end>{s.label}</NavLink>\n ))}\n </Flex>\n {/* >= lg: persistent vertical local nav (bounded width, does not shrink). */}\n <Flex as=\"nav\" aria-label=\"設定\" direction=\"col\" gap={1} hideBelow=\"lg\" width={224} shrink={false}>\n {SECTIONS.map((s) => (\n <NavLink key={s.to} to={s.to} className={link} end>{s.label}</NavLink>\n ))}\n </Flex>\n {/* Bounded content region (~42rem) — the routed section renders here. min-w-0 lets it shrink. */}\n <main className=\"min-w-0 max-w-2xl flex-1\"><Outlet /></main>\n </Flex>\n );\n}\n\n// A settings section. Horizontal label/control rows on desktop (collapse to stacked on mobile),\n// controls bounded to a semantic width — set ONCE on the <Form>, which every FormField reads\n// (gh#998). FormField OWNS the label↔control relationship — do NOT hand-roll <Label> + <input>. Save feedback = Button loading prop + a toast in onSuccess.\nexport function GeneralSettingsSection({\n defaults, onSave, saving, error,\n}: { defaults: { name: string; email: string }; onSave: (v: FormData) => void; saving: boolean; error?: string }) {\n return (\n <Form layout=\"horizontal\" controlWidth=\"24rem\"\n onSubmit={(e) => { e.preventDefault(); onSave(new FormData(e.currentTarget)); }}>\n <FormField id=\"ws-name\" label=\"ワークスペース名\"\n helper=\"請求書や共有リンクに表示されます。\" error={error}>\n <Input id=\"ws-name\" name=\"name\" defaultValue={defaults.name} />\n </FormField>\n <FormField id=\"ws-email\" label=\"連絡先メール\">\n <Input id=\"ws-email\" name=\"email\" type=\"email\" defaultValue={defaults.email} />\n </FormField>\n <Flex gap=\"sm\"><Button type=\"submit\" loading={saving}>変更を保存</Button></Flex>\n </Form>\n );\n}\n\n// Router wiring — each destination is addressable, so deep links + back/forward just work:\n// <Route path=\"settings\" element={<SettingsLayout/>}>\n// <Route index element={<Navigate to=\"general\" replace/>} />\n// <Route path=\"general\" element={<GeneralSettingsSection .../>} />\n// <Route path=\"security\" element={<SecuritySection/>} />\n// <Route path=\"notifications\" element={<NotificationsSection/>} />\n// </Route>\n\n// ── DO / DON'T ────────────────────────────────────────────────────────────────────────────\n// ✅ Tabs (navigation) are fine for a SMALL number (2–4) of PEER views inside ONE task/section\n// — e.g. \"プロフィール\" ⇄ \"環境設定\" within a single account page — where losing the URL is OK.\n// ⛔ Tabs as the PRIMARY IA for broad settings (Account / Security / Billing / Members / …):\n// use route-backed local navigation so every area is deep-linkable and back/forward works.\n// ⛔ Do NOT wrap the whole settings page in a Card, and do NOT make desktop a horizontal tab bar\n// — persistent local nav scales to many sections; a tab strip does not.\n// ⛔ Do NOT invent CSS class names for the shell/nav/content — compose Flex + semantic tokens.",
|
|
8
8
|
"name": "settings-page-responsive",
|
|
9
9
|
"tagline": "Route-backed settings: persistent desktop local navigation, compact mobile tab strip, deep links + browser history, and bounded form content — NO Card wrapper, NO undefined CSS.",
|
|
10
10
|
"tags": [
|
package/agent/patterns.json
CHANGED
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"settings-page",
|
|
35
35
|
"settings-layout"
|
|
36
36
|
],
|
|
37
|
-
"code": "// Research basis: GitHub, Google Account, Microsoft Account, Atlassian Account settings +\n// the IBM Carbon form grid. Every destination is a URL, so deep links and browser back/forward\n// work for free and the active item is derived from the route — never from local tab state.\n//\n// Desktop (>= lg): persistent vertical local nav on the left + bounded content on the right.\n// Mobile (< lg): the SAME routes become a horizontal, scrollable tab strip above the content.\n// Styling uses ONLY real semantic token classes (bg-muted / text-foreground / text-muted-foreground)\n// and responsive/visibility utilities — the library ships NO bespoke settings shell/nav CSS classes.\nimport { NavLink, Outlet, Navigate } from \"react-router-dom\";\nimport { Flex } from \"@godxjp/ui/layout\";\nimport { FormField, Input } from \"@godxjp/ui/data-entry\";\nimport { Button } from \"@godxjp/ui/general\";\n\nconst SECTIONS = [\n { to: \"general\", label: \"基本情報\" },\n { to: \"security\", label: \"セキュリティ\" },\n { to: \"notifications\", label: \"通知\" },\n] as const;\n\n// One link renderer for BOTH breakpoints. NavLink gives us the active state (and sets\n// aria-current=\"page\") straight from the URL; semantic tokens only, no invented classes.\nconst link = ({ isActive }: { isActive: boolean }) =>\n [\n \"rounded-md px-3 py-2 text-sm no-underline transition-colors whitespace-nowrap\",\n isActive\n ? \"bg-muted text-foreground font-medium\"\n : \"text-muted-foreground hover:text-foreground\",\n ].join(\" \");\n\nexport function SettingsLayout() {\n return (\n <Flex direction=\"col\" gap=\"lg\" className=\"lg:flex-row lg:items-start\">\n {/* < lg: horizontal, scrollable route tabs. Flex owns the row and the gap — hideFrom /\n hideBelow own the breakpoint, so neither nav needs a hand-rolled flex or gap utility. */}\n <Flex as=\"nav\" aria-label=\"設定\" gap={1} hideFrom=\"lg\" className=\"overflow-x-auto\">\n {SECTIONS.map((s) => (\n <NavLink key={s.to} to={s.to} className={link} end>{s.label}</NavLink>\n ))}\n </Flex>\n {/* >= lg: persistent vertical local nav (bounded width, does not shrink). */}\n <Flex as=\"nav\" aria-label=\"設定\" direction=\"col\" gap={1} hideBelow=\"lg\" width={224} shrink={false}>\n {SECTIONS.map((s) => (\n <NavLink key={s.to} to={s.to} className={link} end>{s.label}</NavLink>\n ))}\n </Flex>\n {/* Bounded content region (~42rem) — the routed section renders here. min-w-0 lets it shrink. */}\n <main className=\"min-w-0 max-w-2xl flex-1\"><Outlet /></main>\n </Flex>\n );\n}\n\n// A settings section. Horizontal label/control rows on desktop (collapse to stacked on mobile),\n// controls bounded to a semantic width. FormField OWNS the label↔control relationship — do NOT
|
|
37
|
+
"code": "// Research basis: GitHub, Google Account, Microsoft Account, Atlassian Account settings +\n// the IBM Carbon form grid. Every destination is a URL, so deep links and browser back/forward\n// work for free and the active item is derived from the route — never from local tab state.\n//\n// Desktop (>= lg): persistent vertical local nav on the left + bounded content on the right.\n// Mobile (< lg): the SAME routes become a horizontal, scrollable tab strip above the content.\n// Styling uses ONLY real semantic token classes (bg-muted / text-foreground / text-muted-foreground)\n// and responsive/visibility utilities — the library ships NO bespoke settings shell/nav CSS classes.\nimport { NavLink, Outlet, Navigate } from \"react-router-dom\";\nimport { Flex } from \"@godxjp/ui/layout\";\nimport { Form, FormField, Input } from \"@godxjp/ui/data-entry\";\nimport { Button } from \"@godxjp/ui/general\";\n\nconst SECTIONS = [\n { to: \"general\", label: \"基本情報\" },\n { to: \"security\", label: \"セキュリティ\" },\n { to: \"notifications\", label: \"通知\" },\n] as const;\n\n// One link renderer for BOTH breakpoints. NavLink gives us the active state (and sets\n// aria-current=\"page\") straight from the URL; semantic tokens only, no invented classes.\nconst link = ({ isActive }: { isActive: boolean }) =>\n [\n \"rounded-md px-3 py-2 text-sm no-underline transition-colors whitespace-nowrap\",\n isActive\n ? \"bg-muted text-foreground font-medium\"\n : \"text-muted-foreground hover:text-foreground\",\n ].join(\" \");\n\nexport function SettingsLayout() {\n return (\n <Flex direction=\"col\" gap=\"lg\" className=\"lg:flex-row lg:items-start\">\n {/* < lg: horizontal, scrollable route tabs. Flex owns the row and the gap — hideFrom /\n hideBelow own the breakpoint, so neither nav needs a hand-rolled flex or gap utility. */}\n <Flex as=\"nav\" aria-label=\"設定\" gap={1} hideFrom=\"lg\" className=\"overflow-x-auto\">\n {SECTIONS.map((s) => (\n <NavLink key={s.to} to={s.to} className={link} end>{s.label}</NavLink>\n ))}\n </Flex>\n {/* >= lg: persistent vertical local nav (bounded width, does not shrink). */}\n <Flex as=\"nav\" aria-label=\"設定\" direction=\"col\" gap={1} hideBelow=\"lg\" width={224} shrink={false}>\n {SECTIONS.map((s) => (\n <NavLink key={s.to} to={s.to} className={link} end>{s.label}</NavLink>\n ))}\n </Flex>\n {/* Bounded content region (~42rem) — the routed section renders here. min-w-0 lets it shrink. */}\n <main className=\"min-w-0 max-w-2xl flex-1\"><Outlet /></main>\n </Flex>\n );\n}\n\n// A settings section. Horizontal label/control rows on desktop (collapse to stacked on mobile),\n// controls bounded to a semantic width — set ONCE on the <Form>, which every FormField reads\n// (gh#998). FormField OWNS the label↔control relationship — do NOT hand-roll <Label> + <input>. Save feedback = Button loading prop + a toast in onSuccess.\nexport function GeneralSettingsSection({\n defaults, onSave, saving, error,\n}: { defaults: { name: string; email: string }; onSave: (v: FormData) => void; saving: boolean; error?: string }) {\n return (\n <Form layout=\"horizontal\" controlWidth=\"24rem\"\n onSubmit={(e) => { e.preventDefault(); onSave(new FormData(e.currentTarget)); }}>\n <FormField id=\"ws-name\" label=\"ワークスペース名\"\n helper=\"請求書や共有リンクに表示されます。\" error={error}>\n <Input id=\"ws-name\" name=\"name\" defaultValue={defaults.name} />\n </FormField>\n <FormField id=\"ws-email\" label=\"連絡先メール\">\n <Input id=\"ws-email\" name=\"email\" type=\"email\" defaultValue={defaults.email} />\n </FormField>\n <Flex gap=\"sm\"><Button type=\"submit\" loading={saving}>変更を保存</Button></Flex>\n </Form>\n );\n}\n\n// Router wiring — each destination is addressable, so deep links + back/forward just work:\n// <Route path=\"settings\" element={<SettingsLayout/>}>\n// <Route index element={<Navigate to=\"general\" replace/>} />\n// <Route path=\"general\" element={<GeneralSettingsSection .../>} />\n// <Route path=\"security\" element={<SecuritySection/>} />\n// <Route path=\"notifications\" element={<NotificationsSection/>} />\n// </Route>\n\n// ── DO / DON'T ────────────────────────────────────────────────────────────────────────────\n// ✅ Tabs (navigation) are fine for a SMALL number (2–4) of PEER views inside ONE task/section\n// — e.g. \"プロフィール\" ⇄ \"環境設定\" within a single account page — where losing the URL is OK.\n// ⛔ Tabs as the PRIMARY IA for broad settings (Account / Security / Billing / Members / …):\n// use route-backed local navigation so every area is deep-linkable and back/forward works.\n// ⛔ Do NOT wrap the whole settings page in a Card, and do NOT make desktop a horizontal tab bar\n// — persistent local nav scales to many sections; a tab strip does not.\n// ⛔ Do NOT invent CSS class names for the shell/nav/content — compose Flex + semantic tokens.",
|
|
38
38
|
"name": "settings-page-responsive",
|
|
39
39
|
"tagline": "Route-backed settings: persistent desktop local navigation, compact mobile tab strip, deep links + browser history, and bounded form content — NO Card wrapper, NO undefined CSS.",
|
|
40
40
|
"tags": [
|
|
@@ -6,7 +6,5 @@ export { ButtonRefetch } from "./query-refetch-button.js";
|
|
|
6
6
|
export type { ButtonRefetchProp, ButtonRefetchProps } from "./query-refetch-button.js";
|
|
7
7
|
export { InfiniteQueryState, flattenItemPages } from "./infinite-query-state.js";
|
|
8
8
|
export type { InfiniteQueryStateProp, InfiniteQueryStateProps } from "./infinite-query-state.js";
|
|
9
|
-
export { PrefetchLink } from "./prefetch-link.js";
|
|
10
|
-
export type { PrefetchLinkProp, PrefetchLinkProps } from "./prefetch-link.js";
|
|
11
9
|
export { classifyQueryError, isRetryableQueryError } from "../../lib/query-error.js";
|
|
12
10
|
export type { QueryErrorCategory, QueryErrorInfo } from "../../lib/query-error.js";
|
|
@@ -2,14 +2,12 @@ import { DataState } from "./data-state.js";
|
|
|
2
2
|
import { AlertMutationFeedback } from "./mutation-feedback.js";
|
|
3
3
|
import { ButtonRefetch } from "./query-refetch-button.js";
|
|
4
4
|
import { InfiniteQueryState, flattenItemPages } from "./infinite-query-state.js";
|
|
5
|
-
import { PrefetchLink } from "./prefetch-link.js";
|
|
6
5
|
import { classifyQueryError, isRetryableQueryError } from "../../lib/query-error.js";
|
|
7
6
|
export {
|
|
8
7
|
AlertMutationFeedback,
|
|
9
8
|
ButtonRefetch,
|
|
10
9
|
DataState,
|
|
11
10
|
InfiniteQueryState,
|
|
12
|
-
PrefetchLink,
|
|
13
11
|
classifyQueryError,
|
|
14
12
|
flattenItemPages,
|
|
15
13
|
isRetryableQueryError
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$comment": "AUTO-GENERATED by scripts/gen-measurement-contract.mjs — do not edit. Read this instead of guessing: docs/MEASUREMENT-CONTRACT.md.",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "31.0.2",
|
|
4
4
|
"targetSize": {
|
|
5
5
|
"standard": "WCAG 2.2 SC 2.5.8 Target Size (Minimum), level AA — 24×24 CSS px",
|
|
6
6
|
"min": 24,
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
@layer components {
|
|
4
4
|
[data-slot="alert"] {
|
|
5
|
+
|
|
6
|
+
container: alert / inline-size;
|
|
5
7
|
position: relative;
|
|
6
8
|
display: flex;
|
|
7
9
|
align-items: flex-start;
|
|
@@ -133,7 +135,7 @@
|
|
|
133
135
|
gap: var(--alert-inner-space-gap);
|
|
134
136
|
}
|
|
135
137
|
|
|
136
|
-
@
|
|
138
|
+
@container alert (min-width: 40rem) {
|
|
137
139
|
[data-slot="alert-body"]:has(> [data-slot="alert-actions"]) {
|
|
138
140
|
display: grid;
|
|
139
141
|
grid-template-columns: minmax(0, 1fr) auto;
|
|
@@ -190,7 +192,7 @@
|
|
|
190
192
|
width: 100%;
|
|
191
193
|
}
|
|
192
194
|
|
|
193
|
-
@
|
|
195
|
+
@container alert (min-width: 40rem) {
|
|
194
196
|
[data-slot="alert-actions"] {
|
|
195
197
|
width: auto;
|
|
196
198
|
justify-content: flex-end;
|
package/dist/styles/layers.json
CHANGED
package/docs/CONSUMER-RULES.md
CHANGED
|
@@ -6,7 +6,7 @@ Read this once; the audit enforces it. Everything else in `docs/` is for contrib
|
|
|
6
6
|
2. Every page is `<PageContainer title subtitle extra footer>`; its sections are spaced by the page. Group items inside a section with `<Flex direction="col" gap>` or `<ResponsiveGrid>`.
|
|
7
7
|
3. No Tailwind layout on your own elements: no `flex`, `grid`, `gap-*`, `p-*`, `m-*`, `space-*`. Rows are `<Flex>` (default row), stacks are `<Flex direction="col">`, grids are `<ResponsiveGrid>`.
|
|
8
8
|
4. No hand-rolled surfaces: no `rounded-* border bg-*` divs. A box is `Card`, a pill is `Badge`, a person is `Avatar`, a row is `ListRow`, a label/value pair is `Descriptions`, an empty area is `EmptyState`, a read-only sample of a colour the USER chose is `Swatch`. A LIST of those rows is `<Flex as="ul" marker="none" direction="col" gap="none">` with `<ListRow as="li">` children — `marker="none"` keeps the `<ul>`, the `<li>` semantics and the gap token while dropping the bullet and the indent. Never a raw `<ul>`/`<ol>` (it carries no gap token), never `<div role="list">` + `<div role="listitem">`, and never a wrapper around each row: the divider is `:not(:last-child)` among siblings, so a row alone in its own wrapper is always the last one and EVERY divider disappears silently. A bulleted prose list is the same `<Flex as="ul">` without `marker`.
|
|
9
|
-
5. Real controls only: `Button`, `Input`, `Select`, `Textarea`, `Checkbox`… never raw `<button>`/`<input>`; a labelled control lives in `<FormField label>`. A Select outside a form takes `width="auto"`. **A disabled control's reason is visible text, never a tooltip** — see below.
|
|
9
|
+
5. Real controls only: `Button`, `Input`, `Select`, `Textarea`, `Checkbox`… never raw `<button>`/`<input>`; a labelled control lives in `<FormField label>`. A Select outside a form takes `width="auto"`. **A disabled control's reason is visible text, never a tooltip** — see below. **Fields live in a `<Form layout="horizontal" labelWidth controlWidth>`** — never a group of `FormField`s without one, never a hand-rolled `<Flex>` row of fields (a row that belongs together is `<SpaceCompact>` or `<Form columns>`); size each control for its content with `controlWidth` (GOV.UK text-input width: a port ~7rem, a short enum ~10rem); three or more fields is a page, not a Dialog. The audit rules are `formfield-needs-form`, `dialog-form-too-big` and `select-width-hint`. **A case the kit cannot express is an issue, not a hand-roll:** open it on godx-jp/godxjp-ui, use the nearest valid composition, and mark it `// TODO(godxjp-ui#<n>)` (gh#998).
|
|
10
10
|
6. Text is `<Text>` / `<Heading>` with `tone`, `size`, `weight`, `truncate`, `mono` — not `className="text-muted-foreground font-semibold"`. A STANDALONE glyph is `<Icon as={Lock} size="sm" tone="muted" />` from `@godxjp/ui/general`: a bare lucide icon carries its own `width="24" height="24"` and only four places re-size it for you (`Button`, a `DropdownMenuItem`, a `TopbarItem`, a `ListRow` leading slot), so everywhere else — in a `Text`, a table cell, an `<a>` — it draws at 24px beside 14px type. `size-4` and `w-[16px]` are closed to you by rules 3 and 8, and `size={16}` hard-codes a number the theme owns; `Icon` puts the glyph on the `--icon-size-*` scale (`2xs…4xl`) instead, and is `aria-hidden` unless you give it a `label` (then it is `role="img"` with that name). The audit rule is `lucide-icon-needs-size`.
|
|
11
11
|
7. Colours are semantic tokens (`tone="destructive"`, `bg-primary`), never palette names, hex, or `bg-black` / `text-white`.
|
|
12
12
|
8. Sizes come from props (`size`, `width`, `columns`), never `w-[240px]` / `max-h-[420px]`.
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
CardTitle,
|
|
18
18
|
PermissionMatrix,
|
|
19
19
|
} from "@godxjp/ui/data-display";
|
|
20
|
-
import { FormField, Label, Select, Switch } from "@godxjp/ui/data-entry";
|
|
20
|
+
import { Form, FormField, Label, Select, Switch } from "@godxjp/ui/data-entry";
|
|
21
21
|
import { Flex, PageContainer } from "@godxjp/ui/layout";
|
|
22
22
|
import { grantKey } from "@godxjp/ui/lib/permission-grid";
|
|
23
23
|
|
|
@@ -114,35 +114,37 @@ export default function Demo() {
|
|
|
114
114
|
</CardHeader>
|
|
115
115
|
<CardContent>
|
|
116
116
|
<Flex direction="col" gap="md">
|
|
117
|
-
<
|
|
118
|
-
|
|
117
|
+
<Form>
|
|
118
|
+
<Flex direction="row" wrap align="end" gap="md">
|
|
119
|
+
{/* Bare Select has NO accessible name (axe button-name) — the compare
|
|
119
120
|
pickers are labelled through FormField, exactly as the showcase does. */}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
121
|
+
<FormField label="比較 A">
|
|
122
|
+
<Select
|
|
123
|
+
value={compareA}
|
|
124
|
+
onValueChange={setCompareA}
|
|
125
|
+
options={roleOptions}
|
|
126
|
+
className="w-40"
|
|
127
|
+
/>
|
|
128
|
+
</FormField>
|
|
129
|
+
<FormField label="比較 B">
|
|
130
|
+
<Select
|
|
131
|
+
value={compareB}
|
|
132
|
+
onValueChange={setCompareB}
|
|
133
|
+
options={roleOptions}
|
|
134
|
+
className="w-40"
|
|
135
|
+
/>
|
|
136
|
+
</FormField>
|
|
137
|
+
<Flex direction="row" align="center" gap="sm">
|
|
138
|
+
<Switch
|
|
139
|
+
id="pm-doc-diff-only"
|
|
140
|
+
size="sm"
|
|
141
|
+
checked={diffOnly}
|
|
142
|
+
onCheckedChange={setDiffOnly}
|
|
143
|
+
/>
|
|
144
|
+
<Label htmlFor="pm-doc-diff-only">差分のみ</Label>
|
|
145
|
+
</Flex>
|
|
144
146
|
</Flex>
|
|
145
|
-
</
|
|
147
|
+
</Form>
|
|
146
148
|
<Card variant="outline" className="overflow-hidden">
|
|
147
149
|
<CardContent flush>
|
|
148
150
|
<div>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useState } from "react";
|
|
2
2
|
|
|
3
3
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@godxjp/ui/data-display";
|
|
4
|
-
import { Cascader, FormField } from "@godxjp/ui/data-entry";
|
|
4
|
+
import { Form, Cascader, FormField } from "@godxjp/ui/data-entry";
|
|
5
5
|
import { Flex, PageContainer } from "@godxjp/ui/layout";
|
|
6
6
|
import type { TreeOptionProp } from "@godxjp/ui/props";
|
|
7
7
|
|
|
@@ -351,25 +351,27 @@ export default function Demo() {
|
|
|
351
351
|
</CardDescription>
|
|
352
352
|
</CardHeader>
|
|
353
353
|
<CardContent>
|
|
354
|
-
<
|
|
355
|
-
<
|
|
356
|
-
<
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
<
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
354
|
+
<Form>
|
|
355
|
+
<Flex direction="col" gap="md">
|
|
356
|
+
<FormField id="disabled-empty" label="無効(未選択)">
|
|
357
|
+
<Cascader
|
|
358
|
+
id="disabled-empty"
|
|
359
|
+
options={EXPENSE_CATEGORIES}
|
|
360
|
+
disabled
|
|
361
|
+
placeholder="カテゴリを選択..."
|
|
362
|
+
/>
|
|
363
|
+
</FormField>
|
|
364
|
+
<FormField id="disabled-selected" label="無効(選択済み)">
|
|
365
|
+
<Cascader
|
|
366
|
+
id="disabled-selected"
|
|
367
|
+
options={EXPENSE_CATEGORIES}
|
|
368
|
+
disabled
|
|
369
|
+
defaultValue={["operating", "admin", "salary"]}
|
|
370
|
+
placeholder="カテゴリを選択..."
|
|
371
|
+
/>
|
|
372
|
+
</FormField>
|
|
373
|
+
</Flex>
|
|
374
|
+
</Form>
|
|
373
375
|
</CardContent>
|
|
374
376
|
</Card>
|
|
375
377
|
</Flex>
|
|
@@ -2,7 +2,7 @@ import { useState } from "react";
|
|
|
2
2
|
import { ja } from "date-fns/locale";
|
|
3
3
|
|
|
4
4
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@godxjp/ui/data-display";
|
|
5
|
-
import { DatePicker, FormField } from "@godxjp/ui/data-entry";
|
|
5
|
+
import { Form, DatePicker, FormField } from "@godxjp/ui/data-entry";
|
|
6
6
|
import { Flex, PageContainer } from "@godxjp/ui/layout";
|
|
7
7
|
import type { DateRange } from "react-day-picker";
|
|
8
8
|
|
|
@@ -65,23 +65,25 @@ export default function Demo() {
|
|
|
65
65
|
</CardDescription>
|
|
66
66
|
</CardHeader>
|
|
67
67
|
<CardContent>
|
|
68
|
-
<
|
|
69
|
-
<
|
|
70
|
-
<
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
<
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
68
|
+
<Form>
|
|
69
|
+
<Flex gap="lg" wrap>
|
|
70
|
+
<FormField id="ruled-date" label="罫線あり (既定)">
|
|
71
|
+
<DatePicker
|
|
72
|
+
id="ruled-date"
|
|
73
|
+
name="ruled_date"
|
|
74
|
+
defaultValue={new Date(2026, 0, 15)}
|
|
75
|
+
/>
|
|
76
|
+
</FormField>
|
|
77
|
+
<FormField id="unruled-date" label="罫線なし (bordered={false})">
|
|
78
|
+
<DatePicker
|
|
79
|
+
id="unruled-date"
|
|
80
|
+
name="unruled_date"
|
|
81
|
+
defaultValue={new Date(2026, 0, 15)}
|
|
82
|
+
bordered={false}
|
|
83
|
+
/>
|
|
84
|
+
</FormField>
|
|
85
|
+
</Flex>
|
|
86
|
+
</Form>
|
|
85
87
|
</CardContent>
|
|
86
88
|
</Card>
|
|
87
89
|
|
|
@@ -231,31 +233,33 @@ export default function Demo() {
|
|
|
231
233
|
<CardTitle level={2}>表示形式と元号</CardTitle>
|
|
232
234
|
</CardHeader>
|
|
233
235
|
<CardContent>
|
|
234
|
-
<
|
|
235
|
-
<
|
|
236
|
-
<
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
<
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
236
|
+
<Form>
|
|
237
|
+
<Flex direction="col" gap="md">
|
|
238
|
+
<FormField id="formatted-date" label="契約日">
|
|
239
|
+
<DatePicker
|
|
240
|
+
id="formatted-date"
|
|
241
|
+
name="contract"
|
|
242
|
+
defaultValue={new Date(2026, 8, 9)}
|
|
243
|
+
format="yyyy年MM月dd日"
|
|
244
|
+
/>
|
|
245
|
+
</FormField>
|
|
246
|
+
<FormField id="era-date" label="和暦">
|
|
247
|
+
<DatePicker
|
|
248
|
+
id="era-date"
|
|
249
|
+
name="era"
|
|
250
|
+
defaultValue={new Date(2026, 8, 9)}
|
|
251
|
+
format={{
|
|
252
|
+
calendar: "japanese",
|
|
253
|
+
era: "long",
|
|
254
|
+
year: "numeric",
|
|
255
|
+
month: "long",
|
|
256
|
+
day: "numeric",
|
|
257
|
+
}}
|
|
258
|
+
inputReadOnly
|
|
259
|
+
/>
|
|
260
|
+
</FormField>
|
|
261
|
+
</Flex>
|
|
262
|
+
</Form>
|
|
259
263
|
</CardContent>
|
|
260
264
|
</Card>
|
|
261
265
|
<Card>
|