@godxjp/ui 31.9.0 → 31.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.
@@ -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` 31.9.0.** If the project you are editing has a different
6
+ **This catalog describes `@godxjp/ui` 31.10.1.** If the project you are editing has a different
7
7
  version in its `package.json`, read the pinned catalog for THAT version instead
8
8
  (`…/v<their-version>/agent/…`). A catalog newer than the installed package describes props that do
9
9
  not exist yet; older, and it hides props that do. Neither failure announces itself.
@@ -246,7 +246,7 @@
246
246
  "DO use DataTable.Toolbar as the immediate child that wraps search/filter controls on the left and DataTable.DensityToggle/action buttons on the right. DataTable.BulkActions inside the toolbar auto-hides when selection count is 0; it accepts either plain ReactNode children (built-in 'N selected' status bar) or a (count)=>node render-prop (you own the whole bar).",
247
247
  "DO reach for the grid chrome (DataTable.Search, DataTable.ViewOptions, DataTable.Pagination pageSizeOptions) when you need global search, a column 'set view' picker, or numbered pagination — these are the merged former-DataGrid features, now on the one DataTable. Drive them client-side by default; pass the matching state + manual* flag for a server query.",
248
248
  "DataTable.Pagination OWNS ITS OWN INSET. The footer is a self-contained slot: it declares `padding-block` + `padding-inline` from `--table-pagination-padding-{y,x}` (block default = `--space-stack-sm`, inline default = `--table-cell-space-x`, so the 'rows per page' label lands on the same optical axis as the first column's text). Before the fix it declared `padding-top` only, so inside the documented flush container (`<Card><CardContent flush><DataTable/>`) the label and page-size Select sat flush against the container edge and border. DON'T ship a local `.ui-data-table-pagination { padding: … }` override in an app — retune the two tokens in your theme instead.",
249
- "RESPONSIVE APPROVAL / ACTION QUEUE: reach for `preset=\"action-collection\"` when a dense five-column queue (requester · target · reason · requested date · row actions) must stay readable at 390px, and give every column a `priority` on its ColumnDef — `primary` (the row subject), `secondary` (its target), `meta` (a timestamp/id), `actions` (the row-action affordance, whose measure is reserved FIRST so it can never be pushed off-screen). Leave the free-text column unmarked; it takes the remaining space. This is the SAME contract, the SAME `--table-action-collection-*` tokens and the SAME container query as `Table preset=\"action-collection\"` — there is no separate DataTable family. Never add a consumer width, a hidden column, `hiddenOnMobile` or a page-local breakpoint to make a table fit: retune the tokens instead.",
249
+ "RESPONSIVE APPROVAL / ACTION QUEUE: reach for `preset=\"action-collection\"` when a dense five-column queue (requester · target · reason · requested date · row actions) must stay readable at 390px, and give every column a `priority` on its ColumnDef — `primary` (the row subject), `secondary` (its target), `meta` (a timestamp/id), `actions` (the row-action affordance, whose measure is reserved FIRST so it can never be pushed off-screen, and which grows to its content when a text action + `…` menu does not fit the icon-sized token — gh#1067). Leave the free-text column unmarked; it takes the remaining space. This is the SAME contract, the SAME `--table-action-collection-*` tokens and the SAME container query as `Table preset=\"action-collection\"` — there is no separate DataTable family. Never add a consumer width, a hidden column, `hiddenOnMobile` or a page-local breakpoint to make a table fit: retune the tokens instead.",
250
250
  "DON'T set `width` on a column that also has a `priority` — an explicit width utility wins the cascade over the priority measure and re-opens the horizontal scroll. Under the preset, `pin: 'end'` is also redundant: nothing scrolls sideways, so the actions column is already in frame.",
251
251
  "The DataTable surface's narrow-viewport width floor is `--table-surface-min-inline-size` (default 640px, released at the `sm` viewport step). It used to be a hard-coded `min-w-[640px] sm:min-w-0` utility pair on the surface — the literal that forced the horizontal scroll at 390. Retune (or zero) the token in your theme; `preset=\"action-collection\"` already opts out of it.",
252
252
  "DO use ColumnDef.render for custom cell content (Badge, Link, RowActions). For plain string/number fields render can be omitted — DataTable falls back to String(row[key]).",
@@ -13,7 +13,7 @@
13
13
  "name": "Select",
14
14
  "props": [
15
15
  {
16
- "description": "Select several options; value/defaultValue become string arrays. `tags` additionally ACCEPTS what was typed (a value that is not in the list), which is antd's own split between the two. The popup list of either mode renders as `Command split` (rows ruled, list padding 0, gh#699); retune it with --command-item-divider-color / --command-item-divider-width.",
16
+ "description": "Select several options; value/defaultValue become string arrays. `tags` additionally ACCEPTS what was typed (a value that is not in the list), which is antd's own split between the two. `tags` needs no `options` (`<Select mode=\"tags\" />` works) and only an explicit `disabled` disables it (gh#1063). While text is typed the tags list reads create row, then an exact (case-folded) match, then options, then held values — the first enabled row is the Enter target, never a held tag (gh#1064). The popup list of either mode renders as `Command split` (rows ruled, list padding 0, gh#699); retune it with --command-item-divider-color / --command-item-divider-width.",
17
17
  "name": "mode",
18
18
  "type": "\"multiple\" | \"tags\""
19
19
  },
@@ -18,7 +18,7 @@
18
18
  },
19
19
  {
20
20
  "defaultValue": "false",
21
- "description": "The row fills its parent's inline size (antd `block`, renamed to match Button.fullWidth — the same rename, the same reason: this library's controlled vocabulary wins on values).",
21
+ "description": "The row fills its parent's inline size (antd `block`, renamed to match Button.fullWidth — the same rename, the same reason: this library's controlled vocabulary wins on values). Field children grow to fill it; a Button keeps its content width.",
22
22
  "name": "fullWidth",
23
23
  "type": "boolean"
24
24
  },
@@ -50,7 +50,7 @@
50
50
  "DON'T reach for `className=\"rounded-none\"` / `[&>*:not(:first-child)]` utilities to join controls yourself — `ui-audit`'s `no-utility-layout` rule blocks exactly that, and it is precisely the corner-radius seam this component owns.",
51
51
  "DO set `size` on each CHILD individually, not on SpaceCompact — the row has no size prop of its own by design (see `density`); every control already owns its own `size` axis (`xs|sm|md|lg`).",
52
52
  "DO use `fullWidth` inside a narrow form card so the joined row spans the field column, exactly like a lone Input would.",
53
- "`fullWidth` gives EVERY child an equal share of the row — each item carries `flex: 1 1 0%`, so the split is even no matter what the children would size to on their own. Measured at a 1169px row: NumberInput+Select 585/585, and Select+Button ALSO 585/585, i.e. a Button under `fullWidth` is stretched to half the row, not left at its content width. Want the Button at content width and the field absorbing the rest? Omit `fullWidth` — the row is then `inline-flex` and sizes to content (measured 223/40). Do NOT remove the per-child `flex` to chase antd's block style: without it the items collapse to their content and the row stops filling at all (measured 203/73.6 in a 1169px column), which defeats `fullWidth`.",
53
+ "`fullWidth` is antd `Space.Compact block` (gh#1062): in a row, a FIELD child (Input and its affix/Password/Search forms, NumberInput, Textarea, TagInput, the Date/Time pickers, and the Select/Cascader/TreeSelect/SearchSelect trigger) grows to fill the row, and every other child — a Button, an icon button — keeps its content width. So `[Input][+ Add]` is a full-width field with its submit at content width, and two fields (NumberInput + Select) share the row evenly between them. Deviation from antd, written down: antd grows only its Input family (`width: 100%`); Select/InputNumber/DatePicker keep their own width there. Here every field grows, so two fields never leave an empty tail. `orientation=\"vertical\"` + `fullWidth` stacks full-width children as before.",
54
54
  "DON'T expect corner-radius welding on `orientation=\"vertical\"` yet — the shared border still collapses, but each child keeps all four of its own corners rounded until a block-axis radius knob exists on the Input/trigger families (documented gap, not a silent one)."
55
55
  ],
56
56
  "useCases": [
@@ -108,7 +108,7 @@
108
108
  "DO use `striped` on dense list tables so a row is easy to follow across its columns; to turn it on for EVERY Table and DataTable at once, set `:root { --table-row-striped-alpha: 100%; }` in the theme rather than passing the prop everywhere (`striped={false}` opts one table out). A detail row under a record is `<TableRow data-expanded-row=\"\">` so the stripe counts records, not DOM rows — never stripe with `:nth-child` page CSS or row utilities.",
109
109
  "DO NOT hand-roll empty-state handling inside a Table composition. When data can be empty, switch to `DataTable` (which has a built-in empty state) or wrap the `<Table>` with a conditional that renders `<EmptyState>` — never leave a table with only a header and zero rows.",
110
110
  "DO NOT use Table for lists that need sorting, filtering, pagination, or row selection — those features are only in `DataTable`. Table is intentionally stateless: it owns no TanStack Table instance, no column definitions, and no toolbar.",
111
- "DO reach for `preset=\"action-collection\"` for a dense approval / action queue (requester · target · reason · requested date · row actions) that must stay readable at 390px, and mark every column with `priority` on BOTH its `TableHead` and its `TableCell`: `primary` (the row subject), `secondary` (its target), `meta` (a timestamp/id), `actions` (the row-action affordance, whose measure is reserved first so it can never be pushed off-screen). Leave the free-text column unmarked — it takes the remaining space. For text actions such as 対応する, set ColumnDef.width (or TableHead width) to reserve the label measure; leave a content column fluid. The default actions token is sized for icon actions. Do not add a hidden column or page-local breakpoint to make a table fit. The IDENTICAL preset exists on `DataTable` (`preset` + `collapseBelow` on the table, `priority` on the `ColumnDef`) sharing these same tokens — use DataTable when the queue is data-driven and needs sorting/selection/pagination, and reach for the raw `Table` only for a hand-authored queue.",
111
+ "DO reach for `preset=\"action-collection\"` for a dense approval / action queue (requester · target · reason · requested date · row actions) that must stay readable at 390px, and mark every column with `priority` on BOTH its `TableHead` and its `TableCell`: `primary` (the row subject), `secondary` (its target), `meta` (a timestamp/id), `actions` (the row-action affordance, whose measure is reserved first so it can never be pushed off-screen). Leave the free-text column unmarked — it takes the remaining space. The `actions` token measure is a FLOOR sized for an icon trigger: a text action (対応する, Retry) plus a `…` menu grows the column to its content on its own (gh#1067), so it never paints over the previous column and needs no ColumnDef.width; an explicit width still wins. Leave a content column fluid. Do not add a hidden column or page-local breakpoint to make a table fit. The IDENTICAL preset exists on `DataTable` (`preset` + `collapseBelow` on the table, `priority` on the `ColumnDef`) sharing these same tokens — use DataTable when the queue is data-driven and needs sorting/selection/pagination, and reach for the raw `Table` only for a hand-authored queue.",
112
112
  "DO reach for `<TableCell flush>` when the cell's CONTENT owns its inset — an expanded detail panel under a row (`<TableCell flush colSpan={n}>`), a nested table, a full-bleed media strip. It drops the cell's own padding so the child spans the whole cell; without it the panel is indented by `--table-cell-space-x` and the only route was a `p-0` utility, which no service theme can reach.",
113
113
  "DO express hierarchy with `<TableCell indent={depth}>` — a grouped table's detail rows under their subtotal header, or a tree row under its parent. The measure is `--table-cell-space-x + depth x --table-cell-indent-space-step`, so level 0 sits on the column's own text axis and a service retunes (or flattens) the step in one token. Never hand-roll `style={{ paddingInlineStart }}` at the call site — that is a per-page constant no theme can reach, and it breaks in RTL unless you remember the logical property.",
114
114
  "DO place `<Table>` inside a `<CardContent flush>` (or `p-0` card) when embedding in a Card, so the built-in `overflow-auto` wrapper sits flush to the card edges. Wrapping with plain `<CardContent>` adds padding that clips the horizontal scroll shadow."
@@ -964,7 +964,7 @@
964
964
  },
965
965
  {
966
966
  "defaultValue": "false",
967
- "description": "The row fills its parent's inline size (antd `block`, renamed to match Button.fullWidth — the same rename, the same reason: this library's controlled vocabulary wins on values).",
967
+ "description": "The row fills its parent's inline size (antd `block`, renamed to match Button.fullWidth — the same rename, the same reason: this library's controlled vocabulary wins on values). Field children grow to fill it; a Button keeps its content width.",
968
968
  "name": "fullWidth",
969
969
  "type": "boolean"
970
970
  },
@@ -996,7 +996,7 @@
996
996
  "DON'T reach for `className=\"rounded-none\"` / `[&>*:not(:first-child)]` utilities to join controls yourself — `ui-audit`'s `no-utility-layout` rule blocks exactly that, and it is precisely the corner-radius seam this component owns.",
997
997
  "DO set `size` on each CHILD individually, not on SpaceCompact — the row has no size prop of its own by design (see `density`); every control already owns its own `size` axis (`xs|sm|md|lg`).",
998
998
  "DO use `fullWidth` inside a narrow form card so the joined row spans the field column, exactly like a lone Input would.",
999
- "`fullWidth` gives EVERY child an equal share of the row — each item carries `flex: 1 1 0%`, so the split is even no matter what the children would size to on their own. Measured at a 1169px row: NumberInput+Select 585/585, and Select+Button ALSO 585/585, i.e. a Button under `fullWidth` is stretched to half the row, not left at its content width. Want the Button at content width and the field absorbing the rest? Omit `fullWidth` — the row is then `inline-flex` and sizes to content (measured 223/40). Do NOT remove the per-child `flex` to chase antd's block style: without it the items collapse to their content and the row stops filling at all (measured 203/73.6 in a 1169px column), which defeats `fullWidth`.",
999
+ "`fullWidth` is antd `Space.Compact block` (gh#1062): in a row, a FIELD child (Input and its affix/Password/Search forms, NumberInput, Textarea, TagInput, the Date/Time pickers, and the Select/Cascader/TreeSelect/SearchSelect trigger) grows to fill the row, and every other child — a Button, an icon button — keeps its content width. So `[Input][+ Add]` is a full-width field with its submit at content width, and two fields (NumberInput + Select) share the row evenly between them. Deviation from antd, written down: antd grows only its Input family (`width: 100%`); Select/InputNumber/DatePicker keep their own width there. Here every field grows, so two fields never leave an empty tail. `orientation=\"vertical\"` + `fullWidth` stacks full-width children as before.",
1000
1000
  "DON'T expect corner-radius welding on `orientation=\"vertical\"` yet — the shared border still collapses, but each child keeps all four of its own corners rounded until a block-axis radius knob exists on the Input/trigger families (documented gap, not a silent one)."
1001
1001
  ],
1002
1002
  "useCases": [
@@ -3625,7 +3625,7 @@
3625
3625
  "DO use DataTable.Toolbar as the immediate child that wraps search/filter controls on the left and DataTable.DensityToggle/action buttons on the right. DataTable.BulkActions inside the toolbar auto-hides when selection count is 0; it accepts either plain ReactNode children (built-in 'N selected' status bar) or a (count)=>node render-prop (you own the whole bar).",
3626
3626
  "DO reach for the grid chrome (DataTable.Search, DataTable.ViewOptions, DataTable.Pagination pageSizeOptions) when you need global search, a column 'set view' picker, or numbered pagination — these are the merged former-DataGrid features, now on the one DataTable. Drive them client-side by default; pass the matching state + manual* flag for a server query.",
3627
3627
  "DataTable.Pagination OWNS ITS OWN INSET. The footer is a self-contained slot: it declares `padding-block` + `padding-inline` from `--table-pagination-padding-{y,x}` (block default = `--space-stack-sm`, inline default = `--table-cell-space-x`, so the 'rows per page' label lands on the same optical axis as the first column's text). Before the fix it declared `padding-top` only, so inside the documented flush container (`<Card><CardContent flush><DataTable/>`) the label and page-size Select sat flush against the container edge and border. DON'T ship a local `.ui-data-table-pagination { padding: … }` override in an app — retune the two tokens in your theme instead.",
3628
- "RESPONSIVE APPROVAL / ACTION QUEUE: reach for `preset=\"action-collection\"` when a dense five-column queue (requester · target · reason · requested date · row actions) must stay readable at 390px, and give every column a `priority` on its ColumnDef — `primary` (the row subject), `secondary` (its target), `meta` (a timestamp/id), `actions` (the row-action affordance, whose measure is reserved FIRST so it can never be pushed off-screen). Leave the free-text column unmarked; it takes the remaining space. This is the SAME contract, the SAME `--table-action-collection-*` tokens and the SAME container query as `Table preset=\"action-collection\"` — there is no separate DataTable family. Never add a consumer width, a hidden column, `hiddenOnMobile` or a page-local breakpoint to make a table fit: retune the tokens instead.",
3628
+ "RESPONSIVE APPROVAL / ACTION QUEUE: reach for `preset=\"action-collection\"` when a dense five-column queue (requester · target · reason · requested date · row actions) must stay readable at 390px, and give every column a `priority` on its ColumnDef — `primary` (the row subject), `secondary` (its target), `meta` (a timestamp/id), `actions` (the row-action affordance, whose measure is reserved FIRST so it can never be pushed off-screen, and which grows to its content when a text action + `…` menu does not fit the icon-sized token — gh#1067). Leave the free-text column unmarked; it takes the remaining space. This is the SAME contract, the SAME `--table-action-collection-*` tokens and the SAME container query as `Table preset=\"action-collection\"` — there is no separate DataTable family. Never add a consumer width, a hidden column, `hiddenOnMobile` or a page-local breakpoint to make a table fit: retune the tokens instead.",
3629
3629
  "DON'T set `width` on a column that also has a `priority` — an explicit width utility wins the cascade over the priority measure and re-opens the horizontal scroll. Under the preset, `pin: 'end'` is also redundant: nothing scrolls sideways, so the actions column is already in frame.",
3630
3630
  "The DataTable surface's narrow-viewport width floor is `--table-surface-min-inline-size` (default 640px, released at the `sm` viewport step). It used to be a hard-coded `min-w-[640px] sm:min-w-0` utility pair on the surface — the literal that forced the horizontal scroll at 390. Retune (or zero) the token in your theme; `preset=\"action-collection\"` already opts out of it.",
3631
3631
  "DO use ColumnDef.render for custom cell content (Badge, Link, RowActions). For plain string/number fields render can be omitted — DataTable falls back to String(row[key]).",
@@ -5207,7 +5207,7 @@
5207
5207
  "DO use `striped` on dense list tables so a row is easy to follow across its columns; to turn it on for EVERY Table and DataTable at once, set `:root { --table-row-striped-alpha: 100%; }` in the theme rather than passing the prop everywhere (`striped={false}` opts one table out). A detail row under a record is `<TableRow data-expanded-row=\"\">` so the stripe counts records, not DOM rows — never stripe with `:nth-child` page CSS or row utilities.",
5208
5208
  "DO NOT hand-roll empty-state handling inside a Table composition. When data can be empty, switch to `DataTable` (which has a built-in empty state) or wrap the `<Table>` with a conditional that renders `<EmptyState>` — never leave a table with only a header and zero rows.",
5209
5209
  "DO NOT use Table for lists that need sorting, filtering, pagination, or row selection — those features are only in `DataTable`. Table is intentionally stateless: it owns no TanStack Table instance, no column definitions, and no toolbar.",
5210
- "DO reach for `preset=\"action-collection\"` for a dense approval / action queue (requester · target · reason · requested date · row actions) that must stay readable at 390px, and mark every column with `priority` on BOTH its `TableHead` and its `TableCell`: `primary` (the row subject), `secondary` (its target), `meta` (a timestamp/id), `actions` (the row-action affordance, whose measure is reserved first so it can never be pushed off-screen). Leave the free-text column unmarked — it takes the remaining space. For text actions such as 対応する, set ColumnDef.width (or TableHead width) to reserve the label measure; leave a content column fluid. The default actions token is sized for icon actions. Do not add a hidden column or page-local breakpoint to make a table fit. The IDENTICAL preset exists on `DataTable` (`preset` + `collapseBelow` on the table, `priority` on the `ColumnDef`) sharing these same tokens — use DataTable when the queue is data-driven and needs sorting/selection/pagination, and reach for the raw `Table` only for a hand-authored queue.",
5210
+ "DO reach for `preset=\"action-collection\"` for a dense approval / action queue (requester · target · reason · requested date · row actions) that must stay readable at 390px, and mark every column with `priority` on BOTH its `TableHead` and its `TableCell`: `primary` (the row subject), `secondary` (its target), `meta` (a timestamp/id), `actions` (the row-action affordance, whose measure is reserved first so it can never be pushed off-screen). Leave the free-text column unmarked — it takes the remaining space. The `actions` token measure is a FLOOR sized for an icon trigger: a text action (対応する, Retry) plus a `…` menu grows the column to its content on its own (gh#1067), so it never paints over the previous column and needs no ColumnDef.width; an explicit width still wins. Leave a content column fluid. Do not add a hidden column or page-local breakpoint to make a table fit. The IDENTICAL preset exists on `DataTable` (`preset` + `collapseBelow` on the table, `priority` on the `ColumnDef`) sharing these same tokens — use DataTable when the queue is data-driven and needs sorting/selection/pagination, and reach for the raw `Table` only for a hand-authored queue.",
5211
5211
  "DO reach for `<TableCell flush>` when the cell's CONTENT owns its inset — an expanded detail panel under a row (`<TableCell flush colSpan={n}>`), a nested table, a full-bleed media strip. It drops the cell's own padding so the child spans the whole cell; without it the panel is indented by `--table-cell-space-x` and the only route was a `p-0` utility, which no service theme can reach.",
5212
5212
  "DO express hierarchy with `<TableCell indent={depth}>` — a grouped table's detail rows under their subtotal header, or a tree row under its parent. The measure is `--table-cell-space-x + depth x --table-cell-indent-space-step`, so level 0 sits on the column's own text axis and a service retunes (or flattens) the step in one token. Never hand-roll `style={{ paddingInlineStart }}` at the call site — that is a per-page constant no theme can reach, and it breaks in RTL unless you remember the logical property.",
5213
5213
  "DO place `<Table>` inside a `<CardContent flush>` (or `p-0` card) when embedding in a Card, so the built-in `overflow-auto` wrapper sits flush to the card edges. Wrapping with plain `<CardContent>` adds padding that clips the horizontal scroll shadow."
@@ -6201,7 +6201,7 @@
6201
6201
  "name": "Select",
6202
6202
  "props": [
6203
6203
  {
6204
- "description": "Select several options; value/defaultValue become string arrays. `tags` additionally ACCEPTS what was typed (a value that is not in the list), which is antd's own split between the two. The popup list of either mode renders as `Command split` (rows ruled, list padding 0, gh#699); retune it with --command-item-divider-color / --command-item-divider-width.",
6204
+ "description": "Select several options; value/defaultValue become string arrays. `tags` additionally ACCEPTS what was typed (a value that is not in the list), which is antd's own split between the two. `tags` needs no `options` (`<Select mode=\"tags\" />` works) and only an explicit `disabled` disables it (gh#1063). While text is typed the tags list reads create row, then an exact (case-folded) match, then options, then held values — the first enabled row is the Enter target, never a held tag (gh#1064). The popup list of either mode renders as `Command split` (rows ruled, list padding 0, gh#699); retune it with --command-item-divider-color / --command-item-divider-width.",
6205
6205
  "name": "mode",
6206
6206
  "type": "\"multiple\" | \"tags\""
6207
6207
  },
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/v31.9.0/agent/index.json"
51
+ "pinned": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/v31.10.1/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": "31.9.0"
65
+ "version": "31.10.1"
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: 177 components, 2104 design tokens,
4
- > 50 cardinal rules. This file is the entry point for AI agents. Catalog version 31.9.0.
4
+ > 50 cardinal rules. This file is the entry point for AI agents. Catalog version 31.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@31.9.0`). It is searchable and version-locked. These files exist for agents
7
+ (`npx @godxjp/ui-mcp@31.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
@@ -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/v31.9.0/agent/...`. A catalog that does not match the installed
29
+ the tag: `.../godx-jp/godxjp-ui/v31.10.1/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.
package/agent/tokens.json CHANGED
@@ -11640,7 +11640,7 @@
11640
11640
  "value": "12%"
11641
11641
  },
11642
11642
  {
11643
- "description": "row-action affordance, never clipped",
11643
+ "description": "row-action affordance: a FLOOR, not a cap — Table grows the column to a wider actions cell content (a text button + `…` menu), gh#1067",
11644
11644
  "name": "--table-action-collection-actions-width",
11645
11645
  "tier": "component",
11646
11646
  "value": "3.5rem"
@@ -680,6 +680,7 @@ DataTable.BulkActions = function DataTableBulkActions({
680
680
  direction: "row",
681
681
  align: "center",
682
682
  gap: "sm",
683
+ wrap: true,
683
684
  role: "region",
684
685
  "aria-label": t("dataTable.bulkActions"),
685
686
  className,
@@ -8,6 +8,89 @@ import { cn } from "../../lib/utils.js";
8
8
  function scrollRegionLabel(label, t) {
9
9
  return typeof label === "string" && label.trim() !== "" ? label : t("dataTable.scrollRegion");
10
10
  }
11
+ const ACTIONS_CONTENT_WIDTH = "--table-action-collection-actions-content-width";
12
+ function useActionsColumnFit(ref, enabled) {
13
+ React.useLayoutEffect(() => {
14
+ const box = ref.current;
15
+ if (!enabled || !box || typeof ResizeObserver === "undefined") return void 0;
16
+ const measuredWidths = /* @__PURE__ */ new WeakMap();
17
+ const observedContents = /* @__PURE__ */ new Set();
18
+ const measure = () => {
19
+ box.style.removeProperty(ACTIONS_CONTENT_WIDTH);
20
+ let needed = 0;
21
+ box.querySelectorAll(".ui-table-actions-content").forEach((content) => {
22
+ const cell = content.parentElement;
23
+ if (!cell) return;
24
+ const style = getComputedStyle(cell);
25
+ const inset = parseFloat(style.paddingInlineStart) + parseFloat(style.paddingInlineEnd);
26
+ const width = content.getBoundingClientRect().width;
27
+ measuredWidths.set(content, width);
28
+ if (width <= cell.clientWidth + 0.5) return;
29
+ const edges = style.boxSizing === "border-box" ? inset + parseFloat(style.borderInlineStartWidth) + parseFloat(style.borderInlineEndWidth) : 0;
30
+ needed = Math.max(needed, Math.ceil(width + edges));
31
+ });
32
+ if (needed > 0) box.style.setProperty(ACTIONS_CONTENT_WIDTH, `${needed}px`);
33
+ };
34
+ let frame = 0;
35
+ let rowsChanged = false;
36
+ const schedule = () => {
37
+ if (frame !== 0) return;
38
+ frame = requestAnimationFrame(() => {
39
+ frame = 0;
40
+ if (rowsChanged) {
41
+ rowsChanged = false;
42
+ observeStructure();
43
+ observeContents();
44
+ }
45
+ measure();
46
+ });
47
+ };
48
+ const resize = new ResizeObserver((entries) => {
49
+ if (entries.some((entry) => measuredWidths.get(entry.target) !== entry.contentRect.width)) {
50
+ schedule();
51
+ }
52
+ });
53
+ const observeContents = () => {
54
+ observedContents.forEach((content) => {
55
+ if (content.isConnected) return;
56
+ resize.unobserve(content);
57
+ observedContents.delete(content);
58
+ });
59
+ box.querySelectorAll(".ui-table-actions-content").forEach((content) => {
60
+ if (observedContents.has(content)) return;
61
+ observedContents.add(content);
62
+ resize.observe(content);
63
+ });
64
+ };
65
+ const mutations = new MutationObserver(() => {
66
+ rowsChanged = true;
67
+ schedule();
68
+ });
69
+ const observeStructure = () => {
70
+ mutations.disconnect();
71
+ const table = box.querySelector(":scope > table");
72
+ if (!table) return;
73
+ mutations.observe(table, { childList: true });
74
+ for (const section of Array.from(table.children)) {
75
+ mutations.observe(section, { childList: true });
76
+ for (const row of Array.from(section.children)) {
77
+ mutations.observe(row, { childList: true });
78
+ }
79
+ }
80
+ };
81
+ resize.observe(box);
82
+ observeStructure();
83
+ observeContents();
84
+ measure();
85
+ return () => {
86
+ if (frame !== 0) cancelAnimationFrame(frame);
87
+ resize.disconnect();
88
+ mutations.disconnect();
89
+ box.style.removeProperty(ACTIONS_CONTENT_WIDTH);
90
+ };
91
+ }, [ref, enabled]);
92
+ }
93
+ const TablePresetContext = React.createContext("default");
11
94
  const Table = React.forwardRef(
12
95
  ({
13
96
  className,
@@ -23,6 +106,7 @@ const Table = React.forwardRef(
23
106
  const { t } = useTranslation();
24
107
  const scrollRef = React.useRef(null);
25
108
  const scrolls = useScrollsHorizontally(scrollRef, scrollable);
109
+ useActionsColumnFit(scrollRef, preset === "action-collection");
26
110
  return (
27
111
  // A table wider than its container scrolls horizontally in this wrapper; keep it
28
112
  // keyboard-reachable so it can be scrolled without a pointer (WCAG 2.1.1 / axe
@@ -53,7 +137,7 @@ const Table = React.forwardRef(
53
137
  "--table-action-collection-min-inline-size-compact": columnWidths.minInlineSizeCompact
54
138
  } : void 0,
55
139
  ...scrolls ? { role: "group", "aria-label": scrollRegionLabel(label, t), tabIndex: 0 } : {},
56
- children: /* @__PURE__ */ jsx(
140
+ children: /* @__PURE__ */ jsx(TablePresetContext.Provider, { value: preset, children: /* @__PURE__ */ jsx(
57
141
  "table",
58
142
  {
59
143
  ref,
@@ -62,7 +146,7 @@ const Table = React.forwardRef(
62
146
  className: cn("w-full caption-bottom", bordered && "ui-table-bordered", className),
63
147
  ...props
64
148
  }
65
- )
149
+ ) })
66
150
  }
67
151
  )
68
152
  );
@@ -142,30 +226,33 @@ const TableCell = React.forwardRef(
142
226
  children,
143
227
  style,
144
228
  ...props
145
- }, ref) => /* @__PURE__ */ jsxs(
146
- "td",
147
- {
148
- ref,
149
- "data-slot": "table-cell",
150
- "data-priority": priority,
151
- "data-flush": flush ? "" : void 0,
152
- "data-indent": indent === void 0 ? void 0 : indent,
153
- "data-align": align,
154
- "data-numeric": numeric ? "" : void 0,
155
- "data-wrap": wrap ? "" : void 0,
156
- className: cn(className),
157
- style: indent === void 0 && width === void 0 ? style : {
158
- ...style,
159
- ...indent === void 0 ? null : { "--table-cell-indent-level": indent },
160
- ...width === void 0 ? null : { inlineSize: cellWidth(width) }
161
- },
162
- ...props,
163
- children: [
164
- label !== void 0 ? /* @__PURE__ */ jsx("span", { className: "ui-table-stacked-collection-label", "aria-hidden": "true", children: label }) : null,
165
- children
166
- ]
167
- }
168
- )
229
+ }, ref) => {
230
+ const preset = React.useContext(TablePresetContext);
231
+ return /* @__PURE__ */ jsxs(
232
+ "td",
233
+ {
234
+ ref,
235
+ "data-slot": "table-cell",
236
+ "data-priority": priority,
237
+ "data-flush": flush ? "" : void 0,
238
+ "data-indent": indent === void 0 ? void 0 : indent,
239
+ "data-align": align,
240
+ "data-numeric": numeric ? "" : void 0,
241
+ "data-wrap": wrap ? "" : void 0,
242
+ className: cn(className),
243
+ style: indent === void 0 && width === void 0 ? style : {
244
+ ...style,
245
+ ...indent === void 0 ? null : { "--table-cell-indent-level": indent },
246
+ ...width === void 0 ? null : { inlineSize: cellWidth(width) }
247
+ },
248
+ ...props,
249
+ children: [
250
+ label !== void 0 ? /* @__PURE__ */ jsx("span", { className: "ui-table-stacked-collection-label", "aria-hidden": "true", children: label }) : null,
251
+ priority === "actions" && preset === "action-collection" ? /* @__PURE__ */ jsx("span", { className: "ui-table-actions-content", children }) : children
252
+ ]
253
+ }
254
+ );
255
+ }
169
256
  );
170
257
  TableCell.displayName = "TableCell";
171
258
  export {
@@ -161,22 +161,26 @@ function SearchSelect(props) {
161
161
  const isSelected = (optionValue) => multiple ? values.includes(optionValue) : value === optionValue;
162
162
  const hasSelection = multiple ? values.length > 0 : Boolean(value);
163
163
  const reqId = React.useRef(0);
164
+ const [freshPage, setFreshPage] = React.useState(0);
165
+ const matchesQuery = React.useCallback(
166
+ (option, needle) => {
167
+ if (filterOption) return filterOption(option, needle);
168
+ const haystack = optionFilterProp ? [String(option[optionFilterProp] ?? "")] : [option.label, option.value];
169
+ return haystack.some((field) => fold(String(field)).includes(fold(needle)));
170
+ },
171
+ [filterOption, optionFilterProp, fold]
172
+ );
164
173
  const resolvedLoad = React.useMemo(
165
174
  () => loadOptions ?? (async ({ query: search }) => {
166
175
  const needle = search.trim();
167
176
  const list = staticOptions ?? [];
168
- const matches = (option) => {
169
- if (filterOption) return filterOption(option, needle);
170
- const haystack = optionFilterProp ? [String(option[optionFilterProp] ?? "")] : [option.label, option.value];
171
- return haystack.some((field) => fold(String(field)).includes(fold(needle)));
172
- };
173
- const kept = needle ? list.filter(matches) : list;
177
+ const kept = needle ? list.filter((option) => matchesQuery(option, needle)) : list;
174
178
  return {
175
179
  options: filterSort ? [...kept].sort((a, b) => filterSort(a, b, { searchValue: needle })) : kept,
176
180
  hasMore: false
177
181
  };
178
182
  }),
179
- [loadOptions, staticOptions, filterOption, optionFilterProp, filterSort, fold]
183
+ [loadOptions, staticOptions, matchesQuery, filterSort]
180
184
  );
181
185
  React.useEffect(() => {
182
186
  const handle = window.setTimeout(() => setDebouncedQuery(query.trim()), DEBOUNCE_MS);
@@ -191,10 +195,7 @@ function SearchSelect(props) {
191
195
  const result = await resolvedLoad({ query: search, page: nextPage });
192
196
  if (ticket !== reqId.current) return;
193
197
  setLoaded((prev) => append ? [...prev, ...result.options] : result.options);
194
- if (!append) {
195
- const firstEnabled = result.options.findIndex((option) => !option.disabled);
196
- setActiveIndex(firstEnabled >= 0 ? firstEnabled : 0);
197
- }
198
+ if (!append) setFreshPage((tick) => tick + 1);
198
199
  setHasMore(Boolean(result.hasMore));
199
200
  setPage(nextPage);
200
201
  } catch {
@@ -221,18 +222,33 @@ function SearchSelect(props) {
221
222
  for (const entry of values) {
222
223
  if (known.has(entry)) continue;
223
224
  known.add(entry);
224
- extras.push(pickedOptions[entry] ?? { value: entry, label: entry });
225
+ const held = pickedOptions[entry] ?? { value: entry, label: entry };
226
+ if (!typedText || matchesQuery(held, typedText)) extras.push(held);
225
227
  }
226
228
  const typed = fold(typedText);
227
229
  const exists = [...known].some((entry) => fold(entry) === typed) || [...staticOptions ?? [], ...loaded].some(
228
230
  (option) => fold(option.value) === typed || fold(option.label) === typed
229
231
  );
230
232
  const create = typedText && !exists && canCreate(typedText) ? { value: typedText, label: typedText } : void 0;
233
+ const exact = typedText ? loaded.find(
234
+ (option) => !values.includes(option.value) && (fold(option.value) === typed || fold(option.label) === typed)
235
+ ) : void 0;
236
+ const rest = exact ? loaded.filter((option) => option !== exact) : loaded;
231
237
  return {
232
- displayOptions: create || extras.length ? [...create ? [create] : [], ...extras, ...loaded] : loaded,
238
+ displayOptions: create || exact || extras.length ? [...create ? [create] : [], ...exact ? [exact] : [], ...rest, ...extras] : loaded,
233
239
  createOption: create
234
240
  };
235
- }, [tagsMode, loaded, values, typedText, pickedOptions, staticOptions, fold, canCreate]);
241
+ }, [
242
+ tagsMode,
243
+ loaded,
244
+ values,
245
+ typedText,
246
+ pickedOptions,
247
+ staticOptions,
248
+ fold,
249
+ canCreate,
250
+ matchesQuery
251
+ ]);
236
252
  const grouped = React.useMemo(() => {
237
253
  const order = [];
238
254
  const buckets = /* @__PURE__ */ new Map();
@@ -254,6 +270,17 @@ function SearchSelect(props) {
254
270
  () => grouped.flatMap((group) => group.items.map((entry) => entry.option)),
255
271
  [grouped]
256
272
  );
273
+ const lastTypedRef = React.useRef(typedText);
274
+ const lastFreshPageRef = React.useRef(freshPage);
275
+ React.useEffect(() => {
276
+ const typedChanged = lastTypedRef.current !== typedText;
277
+ const pageChanged = lastFreshPageRef.current !== freshPage;
278
+ lastTypedRef.current = typedText;
279
+ lastFreshPageRef.current = freshPage;
280
+ if (!typedChanged && !pageChanged) return;
281
+ const firstEnabled = flatOrdered.findIndex((option) => !option.disabled);
282
+ setActiveIndex(firstEnabled >= 0 ? firstEnabled : 0);
283
+ }, [flatOrdered, typedText, freshPage]);
257
284
  const resolvedPlaceholder = placeholder ?? t("dataEntry.searchSelect.placeholder");
258
285
  const optionFor = (optionValue) => pickedOptions[optionValue] ?? (staticOptions ?? []).find((option) => option.value === optionValue) ?? loaded.find((option) => option.value === optionValue) ?? null;
259
286
  const selectedOption = value ? optionFor(value) : null;
@@ -30,7 +30,7 @@ import { SearchSelect } from "./search-select.js";
30
30
  import { useTranslation } from "../../i18n/use-translation.js";
31
31
  import { normalizeSelectOptions } from "../../lib/select-options.js";
32
32
  function isDataSelect(props) {
33
- return "options" in props || "loadOptions" in props;
33
+ return "options" in props || "loadOptions" in props || props.mode !== void 0;
34
34
  }
35
35
  const SelectFieldA11yContext = React.createContext(null);
36
36
  function toKey(value) {
@@ -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": "31.9.0",
3
+ "version": "31.10.1",
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,
@@ -1572,7 +1572,10 @@ export type SearchSelectSingleProp = {
1572
1572
  export type SearchSelectMultipleProp = {
1573
1573
  /**
1574
1574
  * `multiple` picks from the list; `tags` also ACCEPTS what was typed, so a value that is not in
1575
- * the list can still be committed (antd's own distinction between the two).
1575
+ * the list can still be committed (antd's own distinction between the two). A `tags` Select
1576
+ * needs no `options` at all and is never disabled for having none (gh#1063). While text is
1577
+ * typed its list reads create row → exact match → options → held values, and the first enabled
1578
+ * row is the active (Enter) row (gh#1064).
1576
1579
  */
1577
1580
  mode: "multiple" | "tags";
1578
1581
  /** @see SelectLabelInValueMultipleProp for the `{value,label}` dialect. */
@@ -378,7 +378,10 @@ export type SpaceCompactProp = Omit<React.HTMLAttributes<HTMLDivElement>, "child
378
378
  orientation?: OrientationProp;
379
379
  /** antd's boolean spelling of `orientation="vertical"`. `orientation` wins when both are set. */
380
380
  vertical?: boolean;
381
- /** Row fills its parent's inline size (antd `block`, renamed to match `Button.fullWidth`). */
381
+ /**
382
+ * Row fills its parent's inline size (antd `block`, renamed to match `Button.fullWidth`). Field
383
+ * children grow to fill it; a Button (any non-field child) keeps its content width (gh#1062).
384
+ */
382
385
  fullWidth?: boolean;
383
386
  /** Scoped control density for the whole row (antd `Space.Compact` `size`). */
384
387
  density?: DensityProp;
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "31.9.0",
2
+ "version": "31.10.1",
3
3
  "generatedBy": "scripts/gen-style-layers.mjs — do not edit by hand; run `pnpm gen:style-layers`",
4
4
  "base": "base.css",
5
5
  "fonts": "fonts.css",
@@ -138,6 +138,10 @@
138
138
  min-inline-size: 0;
139
139
  }
140
140
 
141
+ .ui-space-compact[data-orientation="horizontal"][data-full-width="true"] > [data-slot="space-compact-item"]:not(:has(.ui-control, .ui-control-multiline, .ui-tag-input)) {
142
+ flex: none;
143
+ }
144
+
141
145
  .ui-space-compact[data-orientation="vertical"] {
142
146
  flex-direction: column;
143
147
  }
@@ -231,6 +231,7 @@
231
231
 
232
232
  .ui-data-table-bulk {
233
233
  display: flex;
234
+ flex-wrap: wrap;
234
235
  align-items: center;
235
236
  gap: var(--space-inline-sm);
236
237
  font-size: var(--font-size-base);
@@ -238,6 +239,7 @@
238
239
 
239
240
  .ui-data-table-bulk-actions {
240
241
  display: flex;
242
+ flex-wrap: wrap;
241
243
  align-items: center;
242
244
  gap: var(--space-inline-sm);
243
245
  }
@@ -642,9 +644,19 @@
642
644
  }
643
645
 
644
646
  .ui-table-collection [data-priority="actions"] {
645
- --table-action-collection-column-width: var(--table-action-collection-actions-width);
647
+
648
+ --table-action-collection-column-width: var(
649
+ --table-action-collection-actions-content-width,
650
+ var(--table-action-collection-actions-width)
651
+ );
646
652
  text-align: end;
647
653
  }
654
+
655
+ .ui-table-collection .ui-table-actions-content {
656
+ display: inline-block;
657
+ white-space: nowrap;
658
+ vertical-align: top;
659
+ }
648
660
  }
649
661
 
650
662
  @layer components {
@@ -56,6 +56,7 @@
56
56
  --table-action-collection-primary-width: 18%;
57
57
  --table-action-collection-secondary-width: 22%;
58
58
  --table-action-collection-meta-width: 12%;
59
+
59
60
  --table-action-collection-actions-width: 3.5rem;
60
61
 
61
62
  --table-action-collection-primary-width-compact: 24%;
@@ -156,7 +156,7 @@ export default function Demo() {
156
156
  key: "action",
157
157
  header: "操作",
158
158
  priority: "actions",
159
- width: "104px",
159
+ // No width: the actions column grows to the text button on its own (gh#1067).
160
160
  render: () => (
161
161
  <Button size="sm" variant="ghost">
162
162
  対応する
@@ -546,7 +546,7 @@
546
546
  },
547
547
  "select": {
548
548
  "createTitle": "Tags: create row, onCreate and case-insensitive matching",
549
- "createDescription": "Typed text that matches no option is offered as an explicit “Create” row. onCreate reports only invented text, never an option id. Typing “bug” finds “Bug” instead of creating a duplicate (caseSensitive restores exact matching). Unlike antd, the create row is labelled and text longer than 12 characters is refused through allowCreate.",
549
+ "createDescription": "Typed text that matches no option is offered as an explicit “Create” row. onCreate reports only invented text, never an option id. Typing “bug” finds “Bug” instead of creating a duplicate (caseSensitive restores exact matching). Unlike antd, the create row is labelled and text longer than 12 characters is refused through allowCreate. While you type, the create row (or an option that exactly matches) is the first and active row, so Enter never takes off a tag you already picked; also unlike antd, that exact match is lifted to the top.",
550
550
  "createField": "Labels",
551
551
  "createdHelper": "Created in this session: {list}",
552
552
  "createdNone": "Nothing created yet"
@@ -1267,7 +1267,7 @@
1267
1267
  },
1268
1268
  "search": {
1269
1269
  "title": "Search and its button",
1270
- "body": "Typing and running are one continuous action, so the seam goes. The button is still a real Button — focus ring and disabled keep working.",
1270
+ "body": "Typing and running are one continuous action, so the seam goes. The button is still a real Button — focus ring and disabled keep working. With `fullWidth` the field fills the row and the button keeps its own width (antd `block`).",
1271
1271
  "row": "Search employees",
1272
1272
  "term": "Search term",
1273
1273
  "run": "Run the search",
@@ -540,7 +540,7 @@
540
540
  },
541
541
  "select": {
542
542
  "createTitle": "タグ: 作成行・onCreate・大文字小文字を区別しない照合",
543
- "createDescription": "どの選択肢にも一致しない入力は「作成」行として明示されます。onCreate は新しく作られたテキストだけを通知し、選択肢の ID では発火しません。「bug」と入力すると「Bug」が見つかり、重複は作られません(caseSensitive で完全一致に戻せます)。antd と異なり作成行にはラベルが付き、12 文字を超える入力は allowCreate で拒否しています。",
543
+ "createDescription": "どの選択肢にも一致しない入力は「作成」行として明示されます。onCreate は新しく作られたテキストだけを通知し、選択肢の ID では発火しません。「bug」と入力すると「Bug」が見つかり、重複は作られません(caseSensitive で完全一致に戻せます)。antd と異なり作成行にはラベルが付き、12 文字を超える入力は allowCreate で拒否しています。入力中は作成行(または完全一致する選択肢)が先頭のアクティブ行になるため、Enter で選択済みのタグが外れることはありません。完全一致を先頭に上げる点も antd と異なります。",
544
544
  "createField": "ラベル",
545
545
  "createdHelper": "このセッションで作成: {list}",
546
546
  "createdNone": "まだ作成されていません"
@@ -1261,7 +1261,7 @@
1261
1261
  },
1262
1262
  "search": {
1263
1263
  "title": "検索とボタン",
1264
- "body": "入力と実行は一続きの操作なので継ぎ目をなくします。ボタンは本物の Button のままなので、フォーカスリングも disabled もそのまま効きます。",
1264
+ "body": "入力と実行は一続きの操作なので継ぎ目をなくします。ボタンは本物の Button のままなので、フォーカスリングも disabled もそのまま効きます。`fullWidth` では入力欄が行の残りを埋め、ボタンは自分の幅のままです(antd の `block`)。",
1265
1265
  "row": "社員を検索",
1266
1266
  "term": "検索語",
1267
1267
  "run": "検索する",
@@ -540,7 +540,7 @@
540
540
  },
541
541
  "select": {
542
542
  "createTitle": "Tags: dòng tạo mới, onCreate và so khớp không phân biệt hoa thường",
543
- "createDescription": "Văn bản gõ vào không khớp tùy chọn nào được đưa ra thành dòng “Tạo” rõ ràng. onCreate chỉ báo văn bản mới tạo, không bao giờ báo id của tùy chọn. Gõ “bug” sẽ tìm thấy “Bug” thay vì tạo bản trùng (caseSensitive trả lại so khớp chính xác). Khác antd, dòng tạo có nhãn và văn bản dài hơn 12 ký tự bị allowCreate từ chối.",
543
+ "createDescription": "Văn bản gõ vào không khớp tùy chọn nào được đưa ra thành dòng “Tạo” rõ ràng. onCreate chỉ báo văn bản mới tạo, không bao giờ báo id của tùy chọn. Gõ “bug” sẽ tìm thấy “Bug” thay vì tạo bản trùng (caseSensitive trả lại so khớp chính xác). Khác antd, dòng tạo có nhãn và văn bản dài hơn 12 ký tự bị allowCreate từ chối. Khi đang gõ, dòng tạo (hoặc tùy chọn khớp chính xác) là dòng đầu tiên và đang được chọn, nên Enter không bao giờ gỡ một thẻ đã chọn; cũng khác antd, tùy chọn khớp chính xác được đưa lên đầu.",
544
544
  "createField": "Nhãn",
545
545
  "createdHelper": "Đã tạo trong phiên này: {list}",
546
546
  "createdNone": "Chưa tạo gì"
@@ -1261,7 +1261,7 @@
1261
1261
  },
1262
1262
  "search": {
1263
1263
  "title": "Tìm kiếm và nút của nó",
1264
- "body": "Gõ và chạy là một thao tác liền mạch nên bỏ đường nối. Nút vẫn là Button thật — vòng focus và disabled vẫn hoạt động.",
1264
+ "body": "Gõ và chạy là một thao tác liền mạch nên bỏ đường nối. Nút vẫn là Button thật — vòng focus và disabled vẫn hoạt động. Với `fullWidth`, ô nhập lấp phần còn lại của hàng, nút giữ đúng bề rộng của nó (antd `block`).",
1265
1265
  "row": "Tìm nhân viên",
1266
1266
  "term": "Từ khoá",
1267
1267
  "run": "Chạy tìm kiếm",
@@ -110,7 +110,7 @@ export default function SpaceCompactShowcase() {
110
110
  <CardDescription>{t("spaceCompactDocs.search.body")}</CardDescription>
111
111
  </CardHeader>
112
112
  <CardContent>
113
- <SpaceCompact aria-label={t("spaceCompactDocs.search.row")}>
113
+ <SpaceCompact fullWidth aria-label={t("spaceCompactDocs.search.row")}>
114
114
  <SearchInput
115
115
  value={query}
116
116
  onValueChange={setQuery}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@godxjp/ui",
3
- "version": "31.9.0",
4
- "godxUiMcp": "31.9.0",
3
+ "version": "31.10.1",
4
+ "godxUiMcp": "31.10.1",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
7
7
  "type": "git",