@godxjp/ui 31.9.0 → 31.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/agent/START-HERE.md +1 -1
- package/agent/components/DataTable.json +1 -1
- package/agent/components/Select.json +1 -1
- package/agent/components/SpaceCompact.json +2 -2
- package/agent/components/Table.json +1 -1
- package/agent/components.json +5 -5
- package/agent/index.json +2 -2
- package/agent/llms.txt +3 -3
- package/agent/tokens.json +1 -1
- package/dist/components/data-display/data-table.js +1 -0
- package/dist/components/data-display/table.js +39 -1
- package/dist/components/data-entry/search-select.js +39 -14
- package/dist/components/data-entry/select.js +1 -1
- package/dist/contracts/measurement.json +1 -1
- package/dist/props/components/data-entry.prop.d.ts +4 -1
- package/dist/props/components/layout.prop.d.ts +4 -1
- package/dist/styles/layers.json +1 -1
- package/dist/styles/layout.css +4 -0
- package/dist/styles/table-layout.css +17 -1
- package/dist/tokens/components/table.css +1 -0
- package/docs/data-display/data-table/index.tsx +1 -1
- package/docs/i18n/messages/en.json +2 -2
- package/docs/i18n/messages/ja.json +2 -2
- package/docs/i18n/messages/vi.json +2 -2
- package/docs/layout/space-compact.tsx +1 -1
- package/package.json +2 -2
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` 31.
|
|
6
|
+
**This catalog describes `@godxjp/ui` 31.10.0.** If the project you are editing has a different
|
|
7
7
|
version in its `package.json`, read the pinned catalog for THAT version instead
|
|
8
8
|
(`…/v<their-version>/agent/…`). A catalog newer than the installed package describes props that do
|
|
9
9
|
not exist yet; older, and it hides props that do. Neither failure announces itself.
|
|
@@ -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`
|
|
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.
|
|
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."
|
package/agent/components.json
CHANGED
|
@@ -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`
|
|
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.
|
|
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.
|
|
51
|
+
"pinned": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/v31.10.0/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.
|
|
65
|
+
"version": "31.10.0"
|
|
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.
|
|
4
|
+
> 50 cardinal rules. This file is the entry point for AI agents. Catalog version 31.10.0.
|
|
5
5
|
|
|
6
6
|
If your client can run a process, do not read these files — run the MCP server instead
|
|
7
|
-
(`npx @godxjp/ui-mcp@31.
|
|
7
|
+
(`npx @godxjp/ui-mcp@31.10.0`). 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.
|
|
29
|
+
the tag: `.../godx-jp/godxjp-ui/v31.10.0/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,
|
|
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"
|
|
@@ -8,6 +8,43 @@ 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 measure = () => {
|
|
17
|
+
box.style.removeProperty(ACTIONS_CONTENT_WIDTH);
|
|
18
|
+
let needed = 0;
|
|
19
|
+
box.querySelectorAll(".ui-table-actions-content").forEach((content) => {
|
|
20
|
+
const cell = content.parentElement;
|
|
21
|
+
if (!cell) return;
|
|
22
|
+
const style = getComputedStyle(cell);
|
|
23
|
+
const inset = parseFloat(style.paddingInlineStart) + parseFloat(style.paddingInlineEnd);
|
|
24
|
+
const width = content.getBoundingClientRect().width;
|
|
25
|
+
if (width <= cell.clientWidth + 0.5) return;
|
|
26
|
+
const edges = style.boxSizing === "border-box" ? inset + parseFloat(style.borderInlineStartWidth) + parseFloat(style.borderInlineEndWidth) : 0;
|
|
27
|
+
needed = Math.max(needed, Math.ceil(width + edges));
|
|
28
|
+
});
|
|
29
|
+
if (needed > 0) box.style.setProperty(ACTIONS_CONTENT_WIDTH, `${needed}px`);
|
|
30
|
+
};
|
|
31
|
+
const resize = new ResizeObserver(measure);
|
|
32
|
+
const observeAll = () => {
|
|
33
|
+
resize.disconnect();
|
|
34
|
+
resize.observe(box);
|
|
35
|
+
box.querySelectorAll(".ui-table-actions-content").forEach((content) => resize.observe(content));
|
|
36
|
+
measure();
|
|
37
|
+
};
|
|
38
|
+
const mutations = new MutationObserver(observeAll);
|
|
39
|
+
mutations.observe(box, { childList: true, subtree: true });
|
|
40
|
+
observeAll();
|
|
41
|
+
return () => {
|
|
42
|
+
resize.disconnect();
|
|
43
|
+
mutations.disconnect();
|
|
44
|
+
box.style.removeProperty(ACTIONS_CONTENT_WIDTH);
|
|
45
|
+
};
|
|
46
|
+
}, [ref, enabled]);
|
|
47
|
+
}
|
|
11
48
|
const Table = React.forwardRef(
|
|
12
49
|
({
|
|
13
50
|
className,
|
|
@@ -23,6 +60,7 @@ const Table = React.forwardRef(
|
|
|
23
60
|
const { t } = useTranslation();
|
|
24
61
|
const scrollRef = React.useRef(null);
|
|
25
62
|
const scrolls = useScrollsHorizontally(scrollRef, scrollable);
|
|
63
|
+
useActionsColumnFit(scrollRef, preset === "action-collection");
|
|
26
64
|
return (
|
|
27
65
|
// A table wider than its container scrolls horizontally in this wrapper; keep it
|
|
28
66
|
// keyboard-reachable so it can be scrolled without a pointer (WCAG 2.1.1 / axe
|
|
@@ -162,7 +200,7 @@ const TableCell = React.forwardRef(
|
|
|
162
200
|
...props,
|
|
163
201
|
children: [
|
|
164
202
|
label !== void 0 ? /* @__PURE__ */ jsx("span", { className: "ui-table-stacked-collection-label", "aria-hidden": "true", children: label }) : null,
|
|
165
|
-
children
|
|
203
|
+
priority === "actions" ? /* @__PURE__ */ jsx("span", { className: "ui-table-actions-content", children }) : children
|
|
166
204
|
]
|
|
167
205
|
}
|
|
168
206
|
)
|
|
@@ -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 resetActiveRef = React.useRef(false);
|
|
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
|
|
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,
|
|
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) resetActiveRef.current = true;
|
|
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
|
-
|
|
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] : [], ...
|
|
238
|
+
displayOptions: create || exact || extras.length ? [...create ? [create] : [], ...exact ? [exact] : [], ...rest, ...extras] : loaded,
|
|
233
239
|
createOption: create
|
|
234
240
|
};
|
|
235
|
-
}, [
|
|
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,15 @@ 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
|
+
React.useEffect(() => {
|
|
275
|
+
const typedChanged = lastTypedRef.current !== typedText;
|
|
276
|
+
lastTypedRef.current = typedText;
|
|
277
|
+
if (!typedChanged && !resetActiveRef.current) return;
|
|
278
|
+
resetActiveRef.current = false;
|
|
279
|
+
const firstEnabled = flatOrdered.findIndex((option) => !option.disabled);
|
|
280
|
+
setActiveIndex(firstEnabled >= 0 ? firstEnabled : 0);
|
|
281
|
+
}, [flatOrdered, typedText]);
|
|
257
282
|
const resolvedPlaceholder = placeholder ?? t("dataEntry.searchSelect.placeholder");
|
|
258
283
|
const optionFor = (optionValue) => pickedOptions[optionValue] ?? (staticOptions ?? []).find((option) => option.value === optionValue) ?? loaded.find((option) => option.value === optionValue) ?? null;
|
|
259
284
|
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.
|
|
3
|
+
"version": "31.10.0",
|
|
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
|
-
/**
|
|
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;
|
package/dist/styles/layers.json
CHANGED
package/dist/styles/layout.css
CHANGED
|
@@ -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,23 @@
|
|
|
642
644
|
}
|
|
643
645
|
|
|
644
646
|
.ui-table-collection [data-priority="actions"] {
|
|
645
|
-
|
|
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-actions-content {
|
|
656
|
+
display: contents;
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
.ui-table-collection .ui-table-actions-content {
|
|
660
|
+
display: inline-block;
|
|
661
|
+
white-space: nowrap;
|
|
662
|
+
vertical-align: top;
|
|
663
|
+
}
|
|
648
664
|
}
|
|
649
665
|
|
|
650
666
|
@layer components {
|
|
@@ -156,7 +156,7 @@ export default function Demo() {
|
|
|
156
156
|
key: "action",
|
|
157
157
|
header: "操作",
|
|
158
158
|
priority: "actions",
|
|
159
|
-
width:
|
|
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}
|