@godxjp/ui 33.8.1 → 33.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/DESIGN.md +9 -7
  2. package/README.md +5 -5
  3. package/agent/DESIGN.md +9 -7
  4. package/agent/START-HERE.md +2 -2
  5. package/agent/components/RichTextEditor.json +73 -0
  6. package/agent/components/Tabs.json +9 -2
  7. package/agent/components/TranslatableField.json +69 -0
  8. package/agent/components/TranslatableRichText.json +70 -0
  9. package/agent/components-index.json +15 -0
  10. package/agent/components.json +221 -2
  11. package/agent/index.json +5 -5
  12. package/agent/llms.txt +6 -6
  13. package/agent/tokens.json +35 -35
  14. package/dist/components/data-entry/index.d.ts +2 -2
  15. package/dist/components/data-entry/index.js +2 -1
  16. package/dist/components/data-entry/translatable-input.d.ts +24 -20
  17. package/dist/components/data-entry/translatable-input.js +8 -21
  18. package/dist/components/navigation/tabs-scroll.d.ts +1 -5
  19. package/dist/components/navigation/tabs-scroll.js +31 -8
  20. package/dist/components/navigation/tabs.d.ts +1 -1
  21. package/dist/components/navigation/tabs.js +264 -89
  22. package/dist/contracts/measurement.json +1 -1
  23. package/dist/i18n/messages/en.json +2 -1
  24. package/dist/i18n/messages/ja.json +2 -1
  25. package/dist/i18n/messages/vi.json +2 -1
  26. package/dist/props/components/data-entry.prop.d.ts +49 -5
  27. package/dist/props/components/navigation.prop.d.ts +20 -1
  28. package/dist/props/registry.d.ts +59 -0
  29. package/dist/props/registry.js +86 -0
  30. package/dist/styles/data-display-layout.css +41 -0
  31. package/dist/styles/layers.json +39 -1
  32. package/dist/styles.css +1 -1
  33. package/dist/tokens/components/card.css +3 -3
  34. package/dist/tokens/components/control.css +4 -4
  35. package/dist/tokens/components/form.css +1 -1
  36. package/dist/tokens/components/table.css +1 -1
  37. package/dist/tokens/foundation.css +11 -11
  38. package/dist/tokens/semantic/layout.css +3 -3
  39. package/docs/TOKENS.md +62 -1
  40. package/package.json +2 -2
@@ -5173,6 +5173,149 @@
5173
5173
  "Keyboard: `/` menu (↑↓ Enter Esc), Alt+Shift+↑/↓ moves a block, Mod+/ opens the block menu, Markdown shortcuts (`# `, `- `, `> `, ```` ``` ````, `---`)."
5174
5174
  ]
5175
5175
  },
5176
+ {
5177
+ "docPath": "docs/data-entry/rich-text-editor.tsx",
5178
+ "example": "import { RichTextEditor } from \"@godxjp/block-editor\";\nimport { FormField } from \"@godxjp/ui/data-entry\";\n\n<FormField label=\"説明\" required error={errors.description}>\n <RichTextEditor value={description} onValueChange={setDescription} />\n</FormField>",
5179
+ "group": "data-entry",
5180
+ "importPath": "@godxjp/block-editor",
5181
+ "name": "RichTextEditor",
5182
+ "props": [
5183
+ {
5184
+ "description": "Controlled HTML body (with `onValueChange`). Read through the schema: script, links, images, attributes, styles, h4–h6, tables are dropped to their text.",
5185
+ "name": "value",
5186
+ "type": "string"
5187
+ },
5188
+ {
5189
+ "description": "Uncontrolled initial HTML.",
5190
+ "name": "defaultValue",
5191
+ "type": "string"
5192
+ },
5193
+ {
5194
+ "description": "The schema's HTML after each edit — `\"\"` for an empty body, never `<p></p>`. A new `value` from outside (a reset, a locale tab) replaces the document WITHOUT calling it, and never during an IME composition.",
5195
+ "name": "onValueChange",
5196
+ "type": "(html: string) => void"
5197
+ },
5198
+ {
5199
+ "description": "Shown while the body is empty.",
5200
+ "name": "placeholder",
5201
+ "type": "string"
5202
+ },
5203
+ {
5204
+ "description": "Validation state the frame paints, as on Input; FormField's error arrives as `aria-invalid`.",
5205
+ "name": "status",
5206
+ "type": "\"error\" | \"warning\""
5207
+ },
5208
+ {
5209
+ "description": "BCP-47 tag of the body's language, on the editable.",
5210
+ "name": "lang",
5211
+ "type": "string"
5212
+ },
5213
+ {
5214
+ "description": "Override any toolbar string (defaults: kit ja / en / vi, `blockEditor.*`).",
5215
+ "name": "labels",
5216
+ "type": "Partial<RichTextEditorLabels>"
5217
+ },
5218
+ {
5219
+ "description": "Not editable. readOnly drops the toolbar; disabled keeps it, disabled.",
5220
+ "name": "disabled / readOnly",
5221
+ "type": "boolean"
5222
+ },
5223
+ {
5224
+ "description": "Land on the editable `textbox` — FormField's id, label, helper, required and error wiring reach it directly.",
5225
+ "name": "id / aria-*",
5226
+ "type": "string"
5227
+ }
5228
+ ],
5229
+ "related": [
5230
+ "TranslatableRichText — the same editor holding one HTML value per locale.",
5231
+ "BlockEditor — the Markdown block editor in the same package.",
5232
+ "MarkdownEditor — Markdown in a Textarea."
5233
+ ],
5234
+ "rules": [],
5235
+ "storyPath": "data-entry/rich-text-editor.tsx",
5236
+ "tagline": "A form field that edits HTML (sibling package `@godxjp/block-editor`, gh#1365): a fixed toolbar — bold, italic, strike, inline code · H1–H3, bulleted / numbered list, quote · undo, redo — over a Tiptap surface whose SCHEMA is the sanitiser. `value` / `onValueChange` carry HTML holding only p, br, h1–h3, ul, ol, li, blockquote, strong, em, s, code (`RICH_TEXT_ALLOWED_TAGS`), with one attribute in all (an integer `start` on `<ol>`); anything else in `value` or a paste is kept as its text. For content already stored as HTML; new content belongs in Markdown (BlockEditor / MarkdownEditor).",
5237
+ "usage": [
5238
+ "DO wrap it in FormField, like any field: the label names the editable, `required` and the error reach it as `aria-required` / `aria-invalid` + `aria-errormessage`.",
5239
+ "DO store what onValueChange returns: it is already sanitised by the schema, and render it as HTML. Sanitise again on the server if other clients can write the same column.",
5240
+ "DO use TranslatableRichText for a per-locale `{ ja, en, vi }` map instead of wrapping Tabs around it.",
5241
+ "DON'T pick it for NEW content: Markdown (BlockEditor, MarkdownEditor) is the kit's storage format; this exists for columns that already hold HTML.",
5242
+ "Keyboard: each toolbar group is one tab stop with arrow keys; ⌘/Ctrl+B / I / Z / Shift+Z and the Markdown input rules (`# `, `- `, `1. `, `> `) work in the body."
5243
+ ],
5244
+ "useCases": [
5245
+ "Product, material or recipe description stored as HTML and rendered by a storefront",
5246
+ "Notice or email body column that already holds HTML"
5247
+ ]
5248
+ },
5249
+ {
5250
+ "docPath": "docs/data-entry/rich-text-editor.tsx",
5251
+ "example": "import { TranslatableRichText } from \"@godxjp/block-editor\";\nimport { FormField, type TranslatableValue } from \"@godxjp/ui/data-entry\";\n\nconst [description, setDescription] = React.useState<TranslatableValue>({ ja: \"<p>醤油ラーメン</p>\" });\n\n<FormField label=\"説明\" required>\n <TranslatableRichText\n locales={[\"ja\", \"en\", \"vi\"]}\n fallbackLocale=\"ja\"\n value={description}\n onValueChange={setDescription}\n errors={{ vi: \"ベトナム語の説明を入力してください\" }}\n />\n</FormField>",
5252
+ "group": "data-entry",
5253
+ "importPath": "@godxjp/block-editor",
5254
+ "name": "TranslatableRichText",
5255
+ "props": [
5256
+ {
5257
+ "description": "Controlled per-locale HTML, keyed by BCP-47 tag. A missing key or `\"\"` is an empty locale.",
5258
+ "name": "value",
5259
+ "type": "TranslatableValue"
5260
+ },
5261
+ {
5262
+ "description": "Uncontrolled initial per-locale HTML.",
5263
+ "name": "defaultValue",
5264
+ "type": "TranslatableValue"
5265
+ },
5266
+ {
5267
+ "description": "The WHOLE map after an edit; only the active locale's HTML changes.",
5268
+ "name": "onValueChange",
5269
+ "type": "(value: TranslatableValue) => void"
5270
+ },
5271
+ {
5272
+ "description": "Tab order. Default: AppProvider `contentLocales` when set, else the registered locales.",
5273
+ "name": "locales",
5274
+ "type": "readonly string[]"
5275
+ },
5276
+ {
5277
+ "description": "First tab. Default: the first of `contentLocales` when in `locales`, else the UI locale.",
5278
+ "name": "defaultLocale",
5279
+ "type": "string"
5280
+ },
5281
+ {
5282
+ "description": "Whose text an empty locale shows as its placeholder. Default: AppProvider `fallbackLocale`.",
5283
+ "name": "fallbackLocale",
5284
+ "type": "string"
5285
+ },
5286
+ {
5287
+ "description": "Per-locale messages: tab marks for each (glyph + screen-reader text), `aria-invalid` and FormField's error line for the active one.",
5288
+ "name": "errors",
5289
+ "type": "Partial<Record<string, ReactNode>>"
5290
+ },
5291
+ {
5292
+ "description": "The tab strip's tier, as on TranslatableTextarea.",
5293
+ "name": "size",
5294
+ "type": "\"sm\" | \"md\" | \"lg\""
5295
+ },
5296
+ {
5297
+ "description": "As on RichTextEditor; `ref` is the editor's handle.",
5298
+ "name": "placeholder / disabled / readOnly / labels / id",
5299
+ "type": "—"
5300
+ }
5301
+ ],
5302
+ "related": [
5303
+ "RichTextEditor — the single-locale editor it composes.",
5304
+ "TranslatableTextarea — the same contract over plain text.",
5305
+ "TranslatableField — the engine, for another control."
5306
+ ],
5307
+ "rules": [],
5308
+ "storyPath": "data-entry/rich-text-editor.tsx",
5309
+ "tagline": "ONE RichTextEditor holding an HTML value per locale (`{ ja, en, vi }`), switched by locale tabs (gh#1365). The kit's TranslatableField engine — the same as TranslatableInput / TranslatableTextarea: locales and first tab from AppProvider `contentLocales`, fallback from its `fallbackLocale`, per-locale error marks, the active locale's error in FormField. An empty locale shows the fallback locale's TEXT (not its HTML) as its placeholder; switching tabs swaps the HTML without calling onValueChange.",
5310
+ "usage": [
5311
+ "DO set `<AppProvider contentLocales={[\"ja\", \"en\", \"vi\"]}>` once; the field then needs no `locales` and opens on the source language.",
5312
+ "DO wrap it in FormField and pass your validator's per-locale messages as `errors` (Laravel `description.vi` → `errors.vi`).",
5313
+ "DON'T build Tabs + RichTextEditor yourself: the tab↔panel ARIA, lang, error marks and FormField report are the TranslatableField engine's."
5314
+ ],
5315
+ "useCases": [
5316
+ "Product / material / recipe description stored as per-locale HTML (Astrotomic / Spatie translatable)"
5317
+ ]
5318
+ },
5176
5319
  {
5177
5320
  "example": "import { Prose } from \"@godxjp/ui/data-display\";\nimport Markdown from \"react-markdown\";\nimport remarkGfm from \"remark-gfm\";\n\n<Prose size=\"sm\">\n <Markdown remarkPlugins={[remarkGfm]}>{issue.description}</Markdown>\n</Prose>",
5178
5321
  "group": "data-display",
@@ -7303,6 +7446,75 @@
7303
7446
  "Recipe or notice body stored per locale"
7304
7447
  ]
7305
7448
  },
7449
+ {
7450
+ "example": "import { FormField, TranslatableField, Textarea } from \"@godxjp/ui/data-entry\";\n\n<FormField label=\"説明\">\n <TranslatableField\n locales={[\"ja\", \"en\", \"vi\"]}\n value={description}\n onValueChange={setDescription}\n renderControl={(control) => <Textarea {...control} rows={4} />}\n />\n</FormField>",
7451
+ "group": "data-entry",
7452
+ "importPath": "@godxjp/ui/data-entry",
7453
+ "name": "TranslatableField",
7454
+ "props": [
7455
+ {
7456
+ "description": "Renders the one control in the panel. Spread `control` onto it: `lang`, `value` / `onValueChange` (the active locale's text), the resolved `placeholder`, `status`, `size`, and the field-a11y props (`aria-labelledby` with the locale's name, `aria-invalid`, `aria-errormessage`) plus every prop the field does not own (`id`, `disabled`, …).",
7457
+ "name": "renderControl",
7458
+ "type": "(control: TranslatableFieldControlProp) => ReactNode"
7459
+ },
7460
+ {
7461
+ "description": "Turns the fallback locale's stored text into the plain placeholder an empty locale shows (HTML → text for a rich-text control). Default: the text as stored.",
7462
+ "name": "toPlaceholder",
7463
+ "type": "(fallbackText: string) => string"
7464
+ },
7465
+ {
7466
+ "description": "The per-locale map; onValueChange gets the whole map, only the active key changed.",
7467
+ "name": "value / defaultValue / onValueChange",
7468
+ "type": "TranslatableValue"
7469
+ },
7470
+ {
7471
+ "description": "Exactly as on TranslatableInput.",
7472
+ "name": "locales / defaultLocale / fallbackLocale / errors",
7473
+ "type": "—"
7474
+ },
7475
+ {
7476
+ "description": "Passed to the control; the tab strip uses Tabs `sm` (`md` for `lg`).",
7477
+ "name": "size",
7478
+ "type": "\"xs\" | \"sm\" | \"md\" | \"lg\""
7479
+ },
7480
+ {
7481
+ "description": "Shown when there is no fallback text.",
7482
+ "name": "placeholder",
7483
+ "type": "string"
7484
+ },
7485
+ {
7486
+ "description": "Passed to the control; the active locale's error turns it into `error`.",
7487
+ "name": "status",
7488
+ "type": "\"error\" | \"warning\""
7489
+ },
7490
+ {
7491
+ "description": "Passed to the control, so a FormField label click focuses it.",
7492
+ "name": "id",
7493
+ "type": "string"
7494
+ },
7495
+ {
7496
+ "description": "Root (strip + panel) class override.",
7497
+ "name": "className",
7498
+ "type": "string"
7499
+ }
7500
+ ],
7501
+ "related": [
7502
+ "TranslatableInput — the engine around an Input.",
7503
+ "TranslatableTextarea — the engine around a Textarea.",
7504
+ "TranslatableRichText (@godxjp/block-editor) — the engine around a RichTextEditor."
7505
+ ],
7506
+ "rules": [],
7507
+ "storyPath": "data-entry/translatable-input.tsx",
7508
+ "tagline": "The locale-tab engine behind TranslatableInput, TranslatableTextarea and `@godxjp/block-editor`'s TranslatableRichText (gh#1365): the locale list and first tab (AppProvider `contentLocales`), the per-locale map, the fallback placeholder, the error marks and the FormField error report — around ONE control you render with `renderControl`. Use it only to make another control translatable; for text use TranslatableInput / TranslatableTextarea.",
7509
+ "usage": [
7510
+ "DO render ONE control and spread `control` onto it (`<X {...control} ref={ref} />`): the engine swaps its value per tab, so the ref, FormField id and IME composition stay on one node.",
7511
+ "DO make the control accept `lang`, `status`, `placeholder` and the field-a11y props on its focus target — that is how the locale, the error and the label reach it.",
7512
+ "DON'T use it for a plain text field: TranslatableInput / TranslatableTextarea are this engine with an Input / Textarea already."
7513
+ ],
7514
+ "useCases": [
7515
+ "Making a rich-text, date or custom control hold one value per locale with the kit's tab / error / fallback contract"
7516
+ ]
7517
+ },
7306
7518
  {
7307
7519
  "example": "import { Label } from \"@godxjp/ui/data-entry\";\n\n<Label htmlFor=\"stackable\">併用を許可</Label>",
7308
7520
  "group": "data-entry",
@@ -8233,9 +8445,9 @@
8233
8445
  "name": "Tabs",
8234
8446
  "props": [
8235
8447
  {
8236
- "description": "Optional data-driven tab list. When provided, Tabs renders all triggers and content panels. When Tabs owns the initial selection (no `value`, and no `defaultValue` naming an existing ENABLED item), it falls back to the first item that is NOT `disabled` — never a disabled one — and selects nothing if every item is disabled. `icon` is a leading glyph in the trigger (Ant Design `Tab.icon`). `closable` / `closeIcon` only apply under `variant=\"editable-card\"`; `closable: false` opts one tab out of removal (Ant Design `getRemovable`). `forceRender` (Ant Design `Tab.forceRender`) mounts THAT panel up front and keeps it mounted while another tab is selected, without switching the whole strip over with `destroyOnHidden={false}` — antd's per-item `destroyOnHidden` is deliberately not offered, because on this component \"kept mounted\" is one state and it would be a second spelling of `forceRender`. `count` (+ `overflowCount`, default 99; `showZero`, default true; `countLabel`) draws the counter pill beside the label — 「未対応 12」 — in the SAME vocabulary Button and Toggle publish and through the same helper, formatted with `Intl.NumberFormat` in the active locale. Pass `countLabel` to say what the number is: the pill is `aria-hidden` and an `sr-only` clause carries the digits, so the tab announces \"未対応, 12 件の課題\" and never the concatenated \"未対応12\". Prefer this over antd's answer, which is to put a Badge inside `label` — with the number inside the label the package owns neither its size nor its tone as the tab moves between selected / unselected / disabled, so every consumer aligns it differently.",
8448
+ "description": "Optional data-driven tab list. When provided, Tabs renders all triggers and content panels. When Tabs owns the initial selection (no `value`, and no `defaultValue` naming an existing ENABLED item), it falls back to the first item that is NOT `disabled` — never a disabled one — and selects nothing if every item is disabled. `icon` is a leading glyph in the trigger (Ant Design `Tab.icon`). `closable` / `closeIcon` only apply under `variant=\"editable-card\"`; `closable: false` opts one tab out of removal (Ant Design `getRemovable`). `forceRender` (Ant Design `Tab.forceRender`) mounts THAT panel up front and keeps it mounted while another tab is selected, without switching the whole strip over with `destroyOnHidden={false}` — antd's per-item `destroyOnHidden` is deliberately not offered, because on this component \"kept mounted\" is one state and it would be a second spelling of `forceRender`. `count` (+ `overflowCount`, default 99; `showZero`, default true; `countLabel`) draws the counter pill beside the label — 「未対応 12」 — in the SAME vocabulary Button and Toggle publish and through the same helper, formatted with `Intl.NumberFormat` in the active locale. Pass `countLabel` to say what the number is: the pill is `aria-hidden` and an `sr-only` clause carries the digits, so the tab announces \"未対応, 12 件の課題\" and never the concatenated \"未対応12\". Prefer this over antd's answer, which is to put a Badge inside `label` — with the number inside the label the package owns neither its size nor its tone as the tab moves between selected / unselected / disabled, so every consumer aligns it differently. `href` makes the strip a ROUTE strip (gh#1364) — see `linkComponent`.",
8237
8449
  "name": "items",
8238
- "type": "{ value: string; label: React.ReactNode; content: React.ReactNode; disabled?: boolean; icon?: React.ReactNode; closable?: boolean; closeIcon?: React.ReactNode; forceRender?: boolean; count?: number; overflowCount?: number; showZero?: boolean; countLabel?: string }[]"
8450
+ "type": "{ value: string; label: React.ReactNode; content?: React.ReactNode; href?: string; disabled?: boolean; icon?: React.ReactNode; closable?: boolean; closeIcon?: React.ReactNode; forceRender?: boolean; count?: number; overflowCount?: number; showZero?: boolean; countLabel?: string }[]"
8239
8451
  },
8240
8452
  {
8241
8453
  "description": "Controlled active tab key.",
@@ -8350,6 +8562,11 @@
8350
8562
  "name": "onTabScroll",
8351
8563
  "type": "(info: { direction: \"start\" | \"end\" }) => void"
8352
8564
  },
8565
+ {
8566
+ "description": "ROUTE STRIP (gh#1364). When ANY item carries `href`, Tabs renders a `<nav>` landmark of real links instead of a tablist: each tab is an `<a href>` (middle-click, Ctrl/⌘-click, \"open in new tab\" and the context menu all work — no click is ever `preventDefault`ed), the item whose `value` equals `value` gets `aria-current=\"page\"`, and no tabpanel is rendered (`content` is ignored; the route renders its own page). Pass the CURRENT ROUTE as `value` (derive it from the pathname). `linkComponent` is the SAME contract and the same value as `Sidebar.linkComponent` / `NavList.linkComponent` — Inertia `<Link>`, or `createSidebarLink(Link, \"to\")` for React Router / TanStack — and must forward every prop to its `<a>`. Without it each tab is a plain `<a href>`. Name the nav with `aria-label`. Same variants, sizes and `--tabs-*` tokens as the tablist, and the strip scrolls its overflow exactly like one (`overflow=\"menu\"` additionally exposes hidden routes as native links). Keyboard is the browser's: Tab walks the links, Enter follows one. WHY NOT React Aria link tabs: `<Tab href>` renders `<a role=\"tab\">` (the link role is hidden) and React Aria preventDefaults every real click on it to replay a synthetic one.",
8567
+ "name": "linkComponent",
8568
+ "type": "SidebarLinkComponentProp"
8569
+ },
8353
8570
  {
8354
8571
  "description": "Class on the TRIGGER STRIP (`TabsList`) under the `items` API — the handle that composing the tree manually gives you as `<TabsList className>`. `className` reaches only the root, which holds the strip AND the panels, so anything meant for the bar alone belongs here. Almost always unnecessary: placement, size, centring and the card rail are props and `--tabs-*` tokens.",
8355
8572
  "name": "listClassName",
@@ -8390,6 +8607,7 @@
8390
8607
  "DO put a tab's count in `count` (+ `countLabel`), not inside `label`. A number concatenated into the label loses the pill's size, its tone as the tab is selected/deselected, and — measured on Button in gh#734 — the accessible name: the digits run straight onto the label («未対応12»). With the slot the tab announces \"未対応, 12 件の課題\". DON'T drop a `<Badge>` into `label` to get the same look; there is one counting API and Button, Toggle and Tabs all draw it.",
8391
8608
  "DON'T go looking for antd's `tabBarGutter`, `tabBarStyle`, `renderTabBar`, `classNames`/`styles` or `more.popupRender` — each is declined on the record, not missing. The gutter between triggers is a theme knob (`--tabs-list-line-space-gap`, `--tabs-card-list-space-gap`; the pill strip has no gutter by design) because a px number is a constant, not a semantic axis; the other four exist upstream to let a consumer replace the rendered markup, and this library answers that layer with tokens (docs/DESIGN-AUTHORITY.md refuses them by name).",
8392
8609
  "DON'T re-centre the strip with a `justify-center` utility. `TabsList` aligns with `safe center` on purpose: plain centring splits the overflow across BOTH edges while `scrollLeft` only ever covers the trailing one, so the leading tab ends up permanently outside the scrollport and no gesture reaches it. `safe` keeps the centred look while the tabs fit and falls back to start alignment the moment they don't.",
8610
+ "DO give a strip of sibling ROUTES (a settings area: /settings/cart-timeout, /settings/customer, …) `items[].href` + `linkComponent` and pass the current route as `value`. DON'T hand-roll it from `Link` pills in an `inline-flex rounded-lg bg-muted p-1` div (no `aria-current`, flagged by ui-audit), and DON'T drive a button tablist with `onValueChange` + `router.push` — that loses open-in-new-tab and middle-click (gh#1364).",
8393
8611
  "DON'T draw a list status view as Tabs. A list status view (All / Active / Closed, each with its count) that shows the SAME table — same columns, same row actions, a different query — is a filter, so it is `Segmented` with `count`, placed in the list's `Toolbar`; past 4 statuses it is a `Select`. `Tabs` only when each status is a genuinely different panel (its own columns, actions or empty state), declared as `TabsContent` or pointed at with `controls` (WAI-ARIA APG: a tab selects a panel, a radiogroup selects a value) (gh#1324)."
8394
8612
  ],
8395
8613
  "useCases": [
@@ -8397,6 +8615,7 @@
8397
8615
  "Controlled tabs driven by URL search params (e.g. `?tab=history`) where the parent reads/writes the active key and passes it to `value` / `onValueChange`.",
8398
8616
  "Vertical side-rail navigation inside a `SplitPane` or settings layout where `orientation=\"vertical\"` on the root and `variant=\"line\"` on `TabsList` combine to produce a sidebar-style tab strip.",
8399
8617
  "Lightweight widget tabs on a dashboard card — e.g. a 'Pending' panel (due date, remind action) and a 'Paid' panel (paid date, receipt link), each its own `DataTable` with its own columns — where an uncontrolled `defaultValue` is sufficient and no URL state is needed. Two views of the SAME table are a filter: `Segmented`.",
8618
+ "A settings area with ~14 sibling routes shown as a horizontal strip above the page body — `items[].href` + `linkComponent`, `value` = the current route; it scrolls at phone width (gh#1364).",
8400
8619
  "Admin entity profile pages (company, partner, employee) where each `TabsContent` wraps an Inertia deferred prop panel, lazy-loading expensive data only when the tab is first activated."
8401
8620
  ]
8402
8621
  },
package/agent/index.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "counts": {
3
3
  "anti-ai-tells": 35,
4
- "components": 166,
4
+ "components": 169,
5
5
  "patterns": 28,
6
6
  "rules": 44,
7
7
  "tokens": 2235,
@@ -11,12 +11,12 @@
11
11
  "files": [
12
12
  {
13
13
  "file": "DESIGN.md",
14
- "note": "17 KB — the visual spec: tokens, colour scarcity, admin screen anatomy (list, detail, form, settings, dashboard), do/don't. Read before composing a screen.",
14
+ "note": "18 KB — the visual spec: tokens, colour scarcity, admin screen anatomy (list, detail, form, settings, dashboard), do/don't. Read before composing a screen.",
15
15
  "url": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/DESIGN.md"
16
16
  },
17
17
  {
18
18
  "file": "components-index.json",
19
- "note": "50 KB — name + group + tagline for all 166. FETCH THIS FIRST, then fetch only the components you chose.",
19
+ "note": "52 KB — name + group + tagline for all 169. FETCH THIS FIRST, then fetch only the components you chose.",
20
20
  "url": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/components-index.json"
21
21
  },
22
22
  {
@@ -54,7 +54,7 @@
54
54
  "note": "Pin to the tag that matches the @godxjp/ui version you installed. A catalog newer than your package describes props you do not have; older, and it hides props you do.",
55
55
  "read": {
56
56
  "live": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/index.json",
57
- "pinned": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/v33.8.1/agent/index.json"
57
+ "pinned": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/v33.10.1/agent/index.json"
58
58
  },
59
59
  "source": "mcp/src/data — the same data @godxjp/ui-mcp serves — plus the foundation and semantic token tiers, read from src/tokens/*.css",
60
60
  "start": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/START-HERE.md",
@@ -68,5 +68,5 @@
68
68
  "foundation": "the seeds a consumer is invited to set — --primary, --background, --radius",
69
69
  "semantic": "named roles that follow the seeds — --ring, --text-link, --overlay-background"
70
70
  },
71
- "version": "33.8.1"
71
+ "version": "33.10.1"
72
72
  }
package/agent/llms.txt CHANGED
@@ -1,22 +1,22 @@
1
1
  # @godxjp/ui
2
2
 
3
- > A Japanese-enterprise React design system: 166 components, 2235 design tokens,
4
- > 44 cardinal rules. This file is the entry point for AI agents. Catalog version 33.8.1.
3
+ > A Japanese-enterprise React design system: 169 components, 2235 design tokens,
4
+ > 44 cardinal rules. This file is the entry point for AI agents. Catalog version 33.10.1.
5
5
 
6
6
  If your client can run a process, do not read these files — run the MCP server instead
7
- (`npx @godxjp/ui-mcp@33.8.1`). It is searchable and version-locked. These files exist for agents
7
+ (`npx @godxjp/ui-mcp@33.10.1`). It is searchable and version-locked. These files exist for agents
8
8
  that can only fetch URLs.
9
9
 
10
10
  ## Start
11
11
 
12
12
  - [START-HERE.md](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/START-HERE.md): the whole contract — the four rules, the token override model, a page that passes review. Read this first; it is self-contained.
13
13
  - [index.json](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/index.json): version, counts, and the URL of every file.
14
- - [DESIGN.md](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/DESIGN.md): 17 KB — the visual spec: tokens, colour scarcity, admin screen anatomy (list, detail, form, settings, dashboard), do/don't. Read it before composing a screen.
14
+ - [DESIGN.md](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/DESIGN.md): 18 KB — the visual spec: tokens, colour scarcity, admin screen anatomy (list, detail, form, settings, dashboard), do/don't. Read it before composing a screen.
15
15
 
16
16
  ## Catalog
17
17
 
18
18
  - [patterns-index.json](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/patterns-index.json): 28 whole-task patterns (name, tagline, tags). Start here when the task is a TASK — "build a settings page" — then fetch `patterns/<name>.json` for complete code.
19
- - [components-index.json](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/components-index.json): 50 KB — all 166 components as name, group, tagline, plus `absorbed`: the names that do NOT exist and map to it (`Combobox` → `Select`).
19
+ - [components-index.json](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/components-index.json): 52 KB — all 169 components as name, group, tagline, plus `absorbed`: the names that do NOT exist and map to it (`Combobox` → `Select`).
20
20
  - [components/&lt;Name&gt;.json](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/components/Select.json): one file per component (1 KB–37 KB, median 6 KB). Read the index, then fetch only the ones you chose — this is the selective route, and the reason you do not need the blob.
21
21
  - [components.json](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/components.json): 1.3 MB — every entry in one file. Most URL fetchers truncate a response this size without saying so; prefer the per-component files.
22
22
  - [tokens.json](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/tokens.json): every design token with its value, the reason it exists, and its `tier` — 216 `foundation` seeds (`--primary`, `--background`, `--radius`: set these when you are handed a brand), 113 `semantic` roles, 1906 `component` knobs.
@@ -27,7 +27,7 @@ that can only fetch URLs.
27
27
  ## Pinning
28
28
 
29
29
  Every URL above tracks `main`. To pin to the release a project actually installed, swap `main` for
30
- the tag: `.../godx-jp/godxjp-ui/v33.8.1/agent/...`. A catalog that does not match the installed
30
+ the tag: `.../godx-jp/godxjp-ui/v33.10.1/agent/...`. A catalog that does not match the installed
31
31
  package describes props that are absent, or hides props that are present, and says nothing either way.
32
32
 
33
33
  Pinned catalogs only exist for releases whose tag actually contains `agent/`. If `…/v<version>/agent/index.json` returns 404, that release predates this catalog: read `…/main/…` instead and compare `index.json` → `version` against the package you have, so you at least know which way it drifted.