@godxjp/ui 31.16.0 → 31.17.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.
- package/agent/START-HERE.md +4 -4
- package/agent/components/Badge.json +2 -2
- package/agent/components/DataTable.json +3 -3
- package/agent/components/Table.json +1 -1
- package/agent/components/Text.json +1 -1
- package/agent/components-index.json +1 -1
- package/agent/components.json +7 -7
- package/agent/index.json +4 -4
- package/agent/llms.txt +5 -5
- package/agent/tokens.json +18 -0
- package/dist/components/data-display/badge.js +50 -45
- package/dist/components/data-display/data-table.js +1 -1
- package/dist/components/data-display/image.js +6 -1
- package/dist/components/data-display/table.js +3 -2
- package/dist/components/feedback/tooltip.js +2 -1
- package/dist/components/general/typography.js +3 -3
- package/dist/contracts/measurement.json +1 -1
- package/dist/props/registry.d.ts +1 -1
- package/dist/props/registry.js +1 -1
- package/dist/props/vocabulary/data.prop.d.ts +6 -0
- package/dist/props/vocabulary/interaction.prop.d.ts +1 -0
- package/dist/styles/badge-layout.css +12 -0
- package/dist/styles/layers.json +2 -1
- package/dist/styles/navigation-layout.css +3 -0
- package/dist/styles/table-layout.css +45 -0
- package/dist/styles/text-layout.css +4 -0
- package/dist/tokens/components/navigation.css +2 -0
- package/dist/tokens/components/table.css +4 -0
- package/docs/data-display/badge.tsx +15 -0
- package/docs/i18n/messages/en.json +7 -0
- package/docs/i18n/messages/ja.json +7 -0
- package/docs/i18n/messages/vi.json +7 -0
- 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.17.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.
|
|
@@ -56,10 +56,10 @@ Then ask it: `search_components`, `get_component`, `get_tokens`, `get_rule`, `li
|
|
|
56
56
|
its `importPath`, and its examples. Fetch only the handful you picked in step 1.
|
|
57
57
|
3. `rules.json` — 50 cardinal rules. The ones about raw HTML and hardcoded colour are not
|
|
58
58
|
style advice.
|
|
59
|
-
4. `tokens.json` —
|
|
59
|
+
4. `tokens.json` — 2129 design tokens, each tagged with its `tier`. **If you were handed a
|
|
60
60
|
brand, read the 211 `foundation` entries first** — `--primary`, `--background`,
|
|
61
61
|
`--radius`, `--font-size-base` are the handful everything else derives from. The
|
|
62
|
-
|
|
62
|
+
1814 `component` entries are per-part knobs; reach for one only when a role is
|
|
63
63
|
right everywhere except one component.
|
|
64
64
|
5. `anti-ai-tells.json` — 26 shapes that make generated UI look generated, each with the
|
|
65
65
|
fix. Read before you reach for a gradient hero or a wall of coloured chips.
|
|
@@ -145,7 +145,7 @@ has stopped following the brand.
|
|
|
145
145
|
|---|---|---|---|
|
|
146
146
|
| `foundation` | 211 | the seeds — `--primary`, `--background`, `--foreground`, `--radius`, `--font-size-base`, `--shadow-color`. Everything below is derived from these | **yes — this is the main road.** Handed a brand colour, this is where it goes: `:root { --primary: <H> <S>% <L>%; }` (HSL components, no `hsl()` wrapper) |
|
|
147
147
|
| `semantic` | 104 | named roles that follow the seeds — `--ring`, `--text-link`, `--primary-hover`, `--overlay-background` | only when the seed is right and ONE role must differ. That role then stops following a later brand change |
|
|
148
|
-
| `component` |
|
|
148
|
+
| `component` | 1814 | per-part knobs, `--{component}-{part}-{property}` | rarely. Most are declared `initial` with the real default at the call site — deliberate, so a scoped override re-resolves instead of freezing at `:root` |
|
|
149
149
|
|
|
150
150
|
A token whose `value` is `initial` is not empty and not broken: `initial` is the guaranteed-invalid
|
|
151
151
|
value, so the real default is computed where the element paints it. Set it and yours wins.
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"type": "React.ComponentType<{ className?: string }> | null"
|
|
50
50
|
},
|
|
51
51
|
{
|
|
52
|
-
"description": "Badge label. When omitted with status, Badge renders the translated lifecycle label or raw status.",
|
|
52
|
+
"description": "Badge label. When omitted with status, Badge renders the translated lifecycle label or raw status. LONG LABEL CONTRACT (gh#1101): the chip is `max-inline-size: 100%` of its container and never wraps; the label ellipsizes and, when it was cut, opens the full text in the same tooltip as `Text ellipsis={{ tooltip: true }}` — on pointer hover of the label and on keyboard focus of the nearest focusable control around the chip (a row link, a treeitem, a cell button), only while it is actually cut; the chip never becomes a tab stop (gh#1105). A caller's own `title` on the Badge turns the tooltip off. So a Badge in a fixed-width DataTable cell or a narrow Card stays inside it with no extra props; `<Badge><Text ellipsis>` also works. Do not reach for `Text break=\"anywhere\"` to make a chip wrap.",
|
|
53
53
|
"name": "children",
|
|
54
54
|
"type": "ReactNode"
|
|
55
55
|
},
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
"subParts": [
|
|
75
75
|
"StatusBadge"
|
|
76
76
|
],
|
|
77
|
-
"tagline": "Plain or lifecycle badge. Use `variant` for static chips, or `status` to auto-map lifecycle keys to semantic tone + icon. Labels never wrap.",
|
|
77
|
+
"tagline": "Plain or lifecycle badge. Use `variant` for static chips, or `status` to auto-map lifecycle keys to semantic tone + icon. Labels never wrap: a label wider than its container ellipsizes, and its full text opens in a tooltip on hover or on keyboard focus of the control around the chip (gh#1101, gh#1105).",
|
|
78
78
|
"usage": [
|
|
79
79
|
"DO pick the correct variant semantically: `success` (approved/paid), `warning` (pending/overdue), `destructive` (rejected/error), `secondary` (neutral category), `outline` (subtle label), `default` (primary accent). Never force a colour just for aesthetics — agents and screen readers read the variant as intent.",
|
|
80
80
|
"DO use `status` for entity lifecycle statuses (active, draft, pending, cancelled, failed, scheduled, etc.) so the component resolves the correct tone, icon, and i18n label.",
|
|
@@ -86,7 +86,7 @@
|
|
|
86
86
|
},
|
|
87
87
|
{
|
|
88
88
|
"defaultValue": "'default'",
|
|
89
|
-
"description": "Named collection contract — the SAME preset the Table primitive owns, forwarded to the table DataTable renders. 'default' emits NO attribute and matches no selector, so an existing DataTable is byte-identical. 'action-collection' is the canonical dense approval/action queue: below collapseBelow the desktop INTRINSIC column widths give way to the token-owned column-PRIORITY measures (--table-action-collection-*) under table-layout: fixed, cells wrap, and the bordered surface drops its --table-surface-min-inline-size floor — so requester · target · reason · requested date · row actions all stay inside a 390px frame with no horizontal scroll. Mark each column with `priority` on its ColumnDef. Semantics are untouched (no display change, no role rewriting, no card swap), so header association, aria-sort and screen-reader table navigation are identical at 390 and 1440. Measured: table 1182 / 766 / 388px at 1440 / 1024 / 390, document scrollWidth === clientWidth at every width, LTR and RTL. 'stacked-record-collection' is the other direction, for a WIDE, HETEROGENEOUS record set that has no sensible narrow column measure: below collapseBelow the <thead> hides and every <tr> becomes a bordered key-value card (--table-stacked-collection-*). Each cell then carries its column's header inline above the value, DERIVED from the same ColumnDef.header the <th> uses — so the card cannot drift from the table, and a column with a deliberately empty header names itself with ariaLabel (gh#864). The labels are aria-hidden: the real <th> is still in the DOM and remains the accessible-name source, so screen-reader table navigation is unchanged at every width. Reach for this instead of building a parallel Card tree beside the table; two trees for one dataset means two sets of labels to keep in sync.",
|
|
89
|
+
"description": "Named collection contract — the SAME preset the Table primitive owns, forwarded to the table DataTable renders. 'default' emits NO attribute and matches no selector, so an existing DataTable is byte-identical. 'action-collection' is the canonical dense approval/action queue: below collapseBelow the desktop INTRINSIC column widths give way to the token-owned column-PRIORITY measures (--table-action-collection-*) under table-layout: fixed, cells wrap, and the bordered surface drops its --table-surface-min-inline-size floor — so requester · target · reason · requested date · row actions all stay inside a 390px frame with no horizontal scroll. Mark each column with `priority` on its ColumnDef. Semantics are untouched (no display change, no role rewriting, no card swap), so header association, aria-sort and screen-reader table navigation are identical at 390 and 1440. Measured: table 1182 / 766 / 388px at 1440 / 1024 / 390, document scrollWidth === clientWidth at every width, LTR and RTL. 'stacked-record-collection' is the other direction, for a WIDE, HETEROGENEOUS record set that has no sensible narrow column measure: below collapseBelow the <thead> hides and every <tr> becomes a bordered key-value card (--table-stacked-collection-*). Each cell then carries its column's header inline above the value, DERIVED from the same ColumnDef.header the <th> uses — so the card cannot drift from the table, and a column with a deliberately empty header names itself with ariaLabel (gh#864). In card mode the CARD owns the inline inset: a folded cell has no inline padding of its own (--table-stacked-collection-cell-padding-x, default 0), and an EMPTY cell (content null) prints no label and drops out of the card (gh#1102). The labels are aria-hidden: the real <th> is still in the DOM and remains the accessible-name source, so screen-reader table navigation is unchanged at every width. Reach for this instead of building a parallel Card tree beside the table; two trees for one dataset means two sets of labels to keep in sync.",
|
|
90
90
|
"name": "preset",
|
|
91
91
|
"type": "'default' | 'action-collection' | 'stacked-record-collection'"
|
|
92
92
|
},
|
|
@@ -164,9 +164,9 @@
|
|
|
164
164
|
"type": "{ type?: 'checkbox'|'radio'; selectedRowKeys?: string[]; defaultSelectedRowKeys?: string[]; onChange?: (keys, rows) => void; getCheckboxProps?: (row) => { disabled?, 'aria-label'? }; preserveSelectedRowKeys?: boolean; selections?: true | ({ key, text, onSelect } | DataTable.SELECTION_ALL | DataTable.SELECTION_INVERT | DataTable.SELECTION_NONE)[]; hideSelectAll?: boolean; columnTitle?: ReactNode; selectAllLabel?: string; matching?: { total: number; selected: boolean; onSelectedChange: (selected: boolean) => void } }"
|
|
165
165
|
},
|
|
166
166
|
{
|
|
167
|
-
"description": "Expandable detail rows (antd expandable). Supplying expandedRowRender adds a leading expand column before the selection column and renders the panel in a real <tr> spanning every column, so the table's grid semantics survive. rowExpandable gates the affordance per row; expandedRowKeys + onExpandedRowsChange make it controlled.",
|
|
167
|
+
"description": "Expandable detail rows (antd expandable). Supplying expandedRowRender adds a leading expand column before the selection column and renders the panel in a real <tr> spanning every column, so the table's grid semantics survive. rowExpandable gates the affordance per row; expandedRowKeys + onExpandedRowsChange make it controlled. The detail cell is inset like any cell (antd) and wraps (white-space: normal) — retune the inset with --table-row-expanded-padding; flush: true drops it for a detail that owns its inset (a nested table, a ListRow list). Do NOT wrap the detail in Card/CardContent or Flex pad for spacing (gh#1083).",
|
|
168
168
|
"name": "expandable",
|
|
169
|
-
"type": "{ expandedRowRender?: (row, index, expanded) => ReactNode; rowExpandable?: (row) => boolean; defaultExpandAllRows?: boolean; expandedRowKeys?: string[]; onExpandedRowsChange?: (keys) => void; expandRowByClick?: boolean; columnTitle?: ReactNode }"
|
|
169
|
+
"type": "{ expandedRowRender?: (row, index, expanded) => ReactNode; rowExpandable?: (row) => boolean; defaultExpandAllRows?: boolean; expandedRowKeys?: string[]; onExpandedRowsChange?: (keys) => void; expandRowByClick?: boolean; columnTitle?: ReactNode; flush?: boolean }"
|
|
170
170
|
},
|
|
171
171
|
{
|
|
172
172
|
"description": "Footer totals row (antd summary), rendered in a real <tfoot> so it keeps the column widths and the screen-reader row navigation. Receives the rows currently rendered (post sort/filter/page), so a page total and a grand total are both expressible. Compose the return with <TableRow>/<TableCell> from the Table primitive.",
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
},
|
|
70
70
|
{
|
|
71
71
|
"defaultValue": "\"default\"",
|
|
72
|
-
"description": "Named collection contract. \"default\" emits no attribute and keeps the plain table. \"action-collection\" is the canonical dense approval/action queue: the desktop INTRINSIC column widths (which make a five-column queue wider than its card and force a horizontal scroll at 390) are replaced by table-layout: fixed plus the token-owned column PRIORITY measures (--table-action-collection-*), and cells wrap. Mark each column with `priority` on its TableHead AND its TableCell. Semantics are untouched — no display change, no role rewriting, no card transformation — so header association, aria-sort and screen-reader table navigation are identical at 390 and 1440. \"stacked-record-collection\" is the other direction, for a WIDE, HETEROGENEOUS record set with no sensible narrow column measure: below collapseBelow the <thead> hides and every <tr> becomes a bordered key-value card (--table-stacked-collection-*). Give each TableCell a `label` — its column header — because the <th> association it normally reads from is the thing that just went away; DataTable derives that label from ColumnDef.header for you (gh#864). The label is aria-hidden and the real <th> stays in the DOM, so the accessible name and table navigation are unchanged.",
|
|
72
|
+
"description": "Named collection contract. \"default\" emits no attribute and keeps the plain table. \"action-collection\" is the canonical dense approval/action queue: the desktop INTRINSIC column widths (which make a five-column queue wider than its card and force a horizontal scroll at 390) are replaced by table-layout: fixed plus the token-owned column PRIORITY measures (--table-action-collection-*), and cells wrap. Mark each column with `priority` on its TableHead AND its TableCell. Semantics are untouched — no display change, no role rewriting, no card transformation — so header association, aria-sort and screen-reader table navigation are identical at 390 and 1440. \"stacked-record-collection\" is the other direction, for a WIDE, HETEROGENEOUS record set with no sensible narrow column measure: below collapseBelow the <thead> hides and every <tr> becomes a bordered key-value card (--table-stacked-collection-*). Give each TableCell a `label` — its column header — because the <th> association it normally reads from is the thing that just went away; DataTable derives that label from ColumnDef.header for you (gh#864). In card mode the CARD owns the inline inset: a folded cell has no inline padding of its own (--table-stacked-collection-cell-padding-x, default 0), and an EMPTY cell (content null) prints no label and drops out of the card (gh#1102). The label is aria-hidden and the real <th> stays in the DOM, so the accessible name and table navigation are unchanged.",
|
|
73
73
|
"name": "preset",
|
|
74
74
|
"type": "\"default\" | \"action-collection\" | \"stacked-record-collection\""
|
|
75
75
|
},
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
},
|
|
50
50
|
{
|
|
51
51
|
"defaultValue": "\"normal\"",
|
|
52
|
-
"description": "Whitespace handling. 'normal' is CSS's own behaviour (newlines and space runs collapse) and stays the default. 'pre-wrap' is for text a PERSON typed — a plain-text note, an issue description, a pasted log — where the line breaks and the indentation are CONTENT: it keeps both, still wraps long lines at the container edge, and breaks an over-long unbroken token (a URL, an id) instead of overflowing. Use it INSTEAD of `className=\"whitespace-pre-wrap\"`. Precedence is explicit: `truncate` is a single-line contract and wins (dev builds warn); `clamp` COMPOSES with it, showing the first N preserved lines. Not for rendered Markdown/HTML — that is `Prose`, which styles rendered elements and does nothing to whitespace.",
|
|
52
|
+
"description": "Whitespace handling. 'normal' is CSS's own behaviour (newlines and space runs collapse) and stays the default; passed explicitly it also releases a `nowrap` the text inherits (a table cell's, gh#1083). 'pre-wrap' is for text a PERSON typed — a plain-text note, an issue description, a pasted log — where the line breaks and the indentation are CONTENT: it keeps both, still wraps long lines at the container edge, and breaks an over-long unbroken token (a URL, an id) instead of overflowing. Use it INSTEAD of `className=\"whitespace-pre-wrap\"`. Precedence is explicit: `truncate` is a single-line contract and wins (dev builds warn); `clamp` COMPOSES with it, showing the first N preserved lines. Not for rendered Markdown/HTML — that is `Prose`, which styles rendered elements and does nothing to whitespace.",
|
|
53
53
|
"name": "whitespace",
|
|
54
54
|
"type": "\"normal\" | \"pre-wrap\""
|
|
55
55
|
},
|
|
@@ -239,7 +239,7 @@
|
|
|
239
239
|
{
|
|
240
240
|
"group": "data-display",
|
|
241
241
|
"name": "Badge",
|
|
242
|
-
"tagline": "Plain or lifecycle badge. Use `variant` for static chips, or `status` to auto-map lifecycle keys to semantic tone + icon. Labels never wrap."
|
|
242
|
+
"tagline": "Plain or lifecycle badge. Use `variant` for static chips, or `status` to auto-map lifecycle keys to semantic tone + icon. Labels never wrap: a label wider than its container ellipsizes, and its full text opens in a tooltip on hover or on keyboard focus of the control around the chip (gh#1101, gh#1105)."
|
|
243
243
|
},
|
|
244
244
|
{
|
|
245
245
|
"group": "data-display",
|
package/agent/components.json
CHANGED
|
@@ -2668,7 +2668,7 @@
|
|
|
2668
2668
|
},
|
|
2669
2669
|
{
|
|
2670
2670
|
"defaultValue": "\"normal\"",
|
|
2671
|
-
"description": "Whitespace handling. 'normal' is CSS's own behaviour (newlines and space runs collapse) and stays the default. 'pre-wrap' is for text a PERSON typed — a plain-text note, an issue description, a pasted log — where the line breaks and the indentation are CONTENT: it keeps both, still wraps long lines at the container edge, and breaks an over-long unbroken token (a URL, an id) instead of overflowing. Use it INSTEAD of `className=\"whitespace-pre-wrap\"`. Precedence is explicit: `truncate` is a single-line contract and wins (dev builds warn); `clamp` COMPOSES with it, showing the first N preserved lines. Not for rendered Markdown/HTML — that is `Prose`, which styles rendered elements and does nothing to whitespace.",
|
|
2671
|
+
"description": "Whitespace handling. 'normal' is CSS's own behaviour (newlines and space runs collapse) and stays the default; passed explicitly it also releases a `nowrap` the text inherits (a table cell's, gh#1083). 'pre-wrap' is for text a PERSON typed — a plain-text note, an issue description, a pasted log — where the line breaks and the indentation are CONTENT: it keeps both, still wraps long lines at the container edge, and breaks an over-long unbroken token (a URL, an id) instead of overflowing. Use it INSTEAD of `className=\"whitespace-pre-wrap\"`. Precedence is explicit: `truncate` is a single-line contract and wins (dev builds warn); `clamp` COMPOSES with it, showing the first N preserved lines. Not for rendered Markdown/HTML — that is `Prose`, which styles rendered elements and does nothing to whitespace.",
|
|
2672
2672
|
"name": "whitespace",
|
|
2673
2673
|
"type": "\"normal\" | \"pre-wrap\""
|
|
2674
2674
|
},
|
|
@@ -3465,7 +3465,7 @@
|
|
|
3465
3465
|
},
|
|
3466
3466
|
{
|
|
3467
3467
|
"defaultValue": "'default'",
|
|
3468
|
-
"description": "Named collection contract — the SAME preset the Table primitive owns, forwarded to the table DataTable renders. 'default' emits NO attribute and matches no selector, so an existing DataTable is byte-identical. 'action-collection' is the canonical dense approval/action queue: below collapseBelow the desktop INTRINSIC column widths give way to the token-owned column-PRIORITY measures (--table-action-collection-*) under table-layout: fixed, cells wrap, and the bordered surface drops its --table-surface-min-inline-size floor — so requester · target · reason · requested date · row actions all stay inside a 390px frame with no horizontal scroll. Mark each column with `priority` on its ColumnDef. Semantics are untouched (no display change, no role rewriting, no card swap), so header association, aria-sort and screen-reader table navigation are identical at 390 and 1440. Measured: table 1182 / 766 / 388px at 1440 / 1024 / 390, document scrollWidth === clientWidth at every width, LTR and RTL. 'stacked-record-collection' is the other direction, for a WIDE, HETEROGENEOUS record set that has no sensible narrow column measure: below collapseBelow the <thead> hides and every <tr> becomes a bordered key-value card (--table-stacked-collection-*). Each cell then carries its column's header inline above the value, DERIVED from the same ColumnDef.header the <th> uses — so the card cannot drift from the table, and a column with a deliberately empty header names itself with ariaLabel (gh#864). The labels are aria-hidden: the real <th> is still in the DOM and remains the accessible-name source, so screen-reader table navigation is unchanged at every width. Reach for this instead of building a parallel Card tree beside the table; two trees for one dataset means two sets of labels to keep in sync.",
|
|
3468
|
+
"description": "Named collection contract — the SAME preset the Table primitive owns, forwarded to the table DataTable renders. 'default' emits NO attribute and matches no selector, so an existing DataTable is byte-identical. 'action-collection' is the canonical dense approval/action queue: below collapseBelow the desktop INTRINSIC column widths give way to the token-owned column-PRIORITY measures (--table-action-collection-*) under table-layout: fixed, cells wrap, and the bordered surface drops its --table-surface-min-inline-size floor — so requester · target · reason · requested date · row actions all stay inside a 390px frame with no horizontal scroll. Mark each column with `priority` on its ColumnDef. Semantics are untouched (no display change, no role rewriting, no card swap), so header association, aria-sort and screen-reader table navigation are identical at 390 and 1440. Measured: table 1182 / 766 / 388px at 1440 / 1024 / 390, document scrollWidth === clientWidth at every width, LTR and RTL. 'stacked-record-collection' is the other direction, for a WIDE, HETEROGENEOUS record set that has no sensible narrow column measure: below collapseBelow the <thead> hides and every <tr> becomes a bordered key-value card (--table-stacked-collection-*). Each cell then carries its column's header inline above the value, DERIVED from the same ColumnDef.header the <th> uses — so the card cannot drift from the table, and a column with a deliberately empty header names itself with ariaLabel (gh#864). In card mode the CARD owns the inline inset: a folded cell has no inline padding of its own (--table-stacked-collection-cell-padding-x, default 0), and an EMPTY cell (content null) prints no label and drops out of the card (gh#1102). The labels are aria-hidden: the real <th> is still in the DOM and remains the accessible-name source, so screen-reader table navigation is unchanged at every width. Reach for this instead of building a parallel Card tree beside the table; two trees for one dataset means two sets of labels to keep in sync.",
|
|
3469
3469
|
"name": "preset",
|
|
3470
3470
|
"type": "'default' | 'action-collection' | 'stacked-record-collection'"
|
|
3471
3471
|
},
|
|
@@ -3543,9 +3543,9 @@
|
|
|
3543
3543
|
"type": "{ type?: 'checkbox'|'radio'; selectedRowKeys?: string[]; defaultSelectedRowKeys?: string[]; onChange?: (keys, rows) => void; getCheckboxProps?: (row) => { disabled?, 'aria-label'? }; preserveSelectedRowKeys?: boolean; selections?: true | ({ key, text, onSelect } | DataTable.SELECTION_ALL | DataTable.SELECTION_INVERT | DataTable.SELECTION_NONE)[]; hideSelectAll?: boolean; columnTitle?: ReactNode; selectAllLabel?: string; matching?: { total: number; selected: boolean; onSelectedChange: (selected: boolean) => void } }"
|
|
3544
3544
|
},
|
|
3545
3545
|
{
|
|
3546
|
-
"description": "Expandable detail rows (antd expandable). Supplying expandedRowRender adds a leading expand column before the selection column and renders the panel in a real <tr> spanning every column, so the table's grid semantics survive. rowExpandable gates the affordance per row; expandedRowKeys + onExpandedRowsChange make it controlled.",
|
|
3546
|
+
"description": "Expandable detail rows (antd expandable). Supplying expandedRowRender adds a leading expand column before the selection column and renders the panel in a real <tr> spanning every column, so the table's grid semantics survive. rowExpandable gates the affordance per row; expandedRowKeys + onExpandedRowsChange make it controlled. The detail cell is inset like any cell (antd) and wraps (white-space: normal) — retune the inset with --table-row-expanded-padding; flush: true drops it for a detail that owns its inset (a nested table, a ListRow list). Do NOT wrap the detail in Card/CardContent or Flex pad for spacing (gh#1083).",
|
|
3547
3547
|
"name": "expandable",
|
|
3548
|
-
"type": "{ expandedRowRender?: (row, index, expanded) => ReactNode; rowExpandable?: (row) => boolean; defaultExpandAllRows?: boolean; expandedRowKeys?: string[]; onExpandedRowsChange?: (keys) => void; expandRowByClick?: boolean; columnTitle?: ReactNode }"
|
|
3548
|
+
"type": "{ expandedRowRender?: (row, index, expanded) => ReactNode; rowExpandable?: (row) => boolean; defaultExpandAllRows?: boolean; expandedRowKeys?: string[]; onExpandedRowsChange?: (keys) => void; expandRowByClick?: boolean; columnTitle?: ReactNode; flush?: boolean }"
|
|
3549
3549
|
},
|
|
3550
3550
|
{
|
|
3551
3551
|
"description": "Footer totals row (antd summary), rendered in a real <tfoot> so it keeps the column widths and the screen-reader row navigation. Receives the rows currently rendered (post sort/filter/page), so a page total and a grand total are both expressible. Compose the return with <TableRow>/<TableCell> from the Table primitive.",
|
|
@@ -4081,7 +4081,7 @@
|
|
|
4081
4081
|
"type": "React.ComponentType<{ className?: string }> | null"
|
|
4082
4082
|
},
|
|
4083
4083
|
{
|
|
4084
|
-
"description": "Badge label. When omitted with status, Badge renders the translated lifecycle label or raw status.",
|
|
4084
|
+
"description": "Badge label. When omitted with status, Badge renders the translated lifecycle label or raw status. LONG LABEL CONTRACT (gh#1101): the chip is `max-inline-size: 100%` of its container and never wraps; the label ellipsizes and, when it was cut, opens the full text in the same tooltip as `Text ellipsis={{ tooltip: true }}` — on pointer hover of the label and on keyboard focus of the nearest focusable control around the chip (a row link, a treeitem, a cell button), only while it is actually cut; the chip never becomes a tab stop (gh#1105). A caller's own `title` on the Badge turns the tooltip off. So a Badge in a fixed-width DataTable cell or a narrow Card stays inside it with no extra props; `<Badge><Text ellipsis>` also works. Do not reach for `Text break=\"anywhere\"` to make a chip wrap.",
|
|
4085
4085
|
"name": "children",
|
|
4086
4086
|
"type": "ReactNode"
|
|
4087
4087
|
},
|
|
@@ -4106,7 +4106,7 @@
|
|
|
4106
4106
|
"subParts": [
|
|
4107
4107
|
"StatusBadge"
|
|
4108
4108
|
],
|
|
4109
|
-
"tagline": "Plain or lifecycle badge. Use `variant` for static chips, or `status` to auto-map lifecycle keys to semantic tone + icon. Labels never wrap.",
|
|
4109
|
+
"tagline": "Plain or lifecycle badge. Use `variant` for static chips, or `status` to auto-map lifecycle keys to semantic tone + icon. Labels never wrap: a label wider than its container ellipsizes, and its full text opens in a tooltip on hover or on keyboard focus of the control around the chip (gh#1101, gh#1105).",
|
|
4110
4110
|
"usage": [
|
|
4111
4111
|
"DO pick the correct variant semantically: `success` (approved/paid), `warning` (pending/overdue), `destructive` (rejected/error), `secondary` (neutral category), `outline` (subtle label), `default` (primary accent). Never force a colour just for aesthetics — agents and screen readers read the variant as intent.",
|
|
4112
4112
|
"DO use `status` for entity lifecycle statuses (active, draft, pending, cancelled, failed, scheduled, etc.) so the component resolves the correct tone, icon, and i18n label.",
|
|
@@ -5261,7 +5261,7 @@
|
|
|
5261
5261
|
},
|
|
5262
5262
|
{
|
|
5263
5263
|
"defaultValue": "\"default\"",
|
|
5264
|
-
"description": "Named collection contract. \"default\" emits no attribute and keeps the plain table. \"action-collection\" is the canonical dense approval/action queue: the desktop INTRINSIC column widths (which make a five-column queue wider than its card and force a horizontal scroll at 390) are replaced by table-layout: fixed plus the token-owned column PRIORITY measures (--table-action-collection-*), and cells wrap. Mark each column with `priority` on its TableHead AND its TableCell. Semantics are untouched — no display change, no role rewriting, no card transformation — so header association, aria-sort and screen-reader table navigation are identical at 390 and 1440. \"stacked-record-collection\" is the other direction, for a WIDE, HETEROGENEOUS record set with no sensible narrow column measure: below collapseBelow the <thead> hides and every <tr> becomes a bordered key-value card (--table-stacked-collection-*). Give each TableCell a `label` — its column header — because the <th> association it normally reads from is the thing that just went away; DataTable derives that label from ColumnDef.header for you (gh#864). The label is aria-hidden and the real <th> stays in the DOM, so the accessible name and table navigation are unchanged.",
|
|
5264
|
+
"description": "Named collection contract. \"default\" emits no attribute and keeps the plain table. \"action-collection\" is the canonical dense approval/action queue: the desktop INTRINSIC column widths (which make a five-column queue wider than its card and force a horizontal scroll at 390) are replaced by table-layout: fixed plus the token-owned column PRIORITY measures (--table-action-collection-*), and cells wrap. Mark each column with `priority` on its TableHead AND its TableCell. Semantics are untouched — no display change, no role rewriting, no card transformation — so header association, aria-sort and screen-reader table navigation are identical at 390 and 1440. \"stacked-record-collection\" is the other direction, for a WIDE, HETEROGENEOUS record set with no sensible narrow column measure: below collapseBelow the <thead> hides and every <tr> becomes a bordered key-value card (--table-stacked-collection-*). Give each TableCell a `label` — its column header — because the <th> association it normally reads from is the thing that just went away; DataTable derives that label from ColumnDef.header for you (gh#864). In card mode the CARD owns the inline inset: a folded cell has no inline padding of its own (--table-stacked-collection-cell-padding-x, default 0), and an EMPTY cell (content null) prints no label and drops out of the card (gh#1102). The label is aria-hidden and the real <th> stays in the DOM, so the accessible name and table navigation are unchanged.",
|
|
5265
5265
|
"name": "preset",
|
|
5266
5266
|
"type": "\"default\" | \"action-collection\" | \"stacked-record-collection\""
|
|
5267
5267
|
},
|
package/agent/index.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"components": 179,
|
|
5
5
|
"patterns": 21,
|
|
6
6
|
"rules": 50,
|
|
7
|
-
"tokens":
|
|
7
|
+
"tokens": 2129,
|
|
8
8
|
"vocabulary": 14
|
|
9
9
|
},
|
|
10
10
|
"files": [
|
|
@@ -48,19 +48,19 @@
|
|
|
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.17.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",
|
|
55
55
|
"tokenTiers": {
|
|
56
56
|
"component": "per-part knobs, --{component}-{part}-{property}; usually leave these alone",
|
|
57
57
|
"counts": {
|
|
58
|
-
"component":
|
|
58
|
+
"component": 1814,
|
|
59
59
|
"foundation": 211,
|
|
60
60
|
"semantic": 104
|
|
61
61
|
},
|
|
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.17.1"
|
|
66
66
|
}
|
package/agent/llms.txt
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# @godxjp/ui
|
|
2
2
|
|
|
3
|
-
> A Japanese-enterprise React design system: 179 components,
|
|
4
|
-
> 50 cardinal rules. This file is the entry point for AI agents. Catalog version 31.
|
|
3
|
+
> A Japanese-enterprise React design system: 179 components, 2129 design tokens,
|
|
4
|
+
> 50 cardinal rules. This file is the entry point for AI agents. Catalog version 31.17.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.
|
|
7
|
+
(`npx @godxjp/ui-mcp@31.17.1`). It is searchable and version-locked. These files exist for agents
|
|
8
8
|
that can only fetch URLs.
|
|
9
9
|
|
|
10
10
|
## Start
|
|
@@ -18,7 +18,7 @@ that can only fetch URLs.
|
|
|
18
18
|
- [components-index.json](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/components-index.json): 48 KB — all 179 components as name, group, tagline, plus `absorbed`: the names that do NOT exist and map to it (`Combobox` → `Select`).
|
|
19
19
|
- [components/<Name>.json](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/components/Select.json): one file per component (1 KB–36 KB, median 6 KB). Read the index, then fetch only the ones you chose — this is the selective route, and the reason you do not need the blob.
|
|
20
20
|
- [components.json](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/components.json): 1.2 MB — every entry in one file. Most URL fetchers truncate a response this size without saying so; prefer the per-component files.
|
|
21
|
-
- [tokens.json](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/tokens.json): every design token with its value, the reason it exists, and its `tier` — 211 `foundation` seeds (`--primary`, `--background`, `--radius`: set these when you are handed a brand), 104 `semantic` roles,
|
|
21
|
+
- [tokens.json](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/tokens.json): every design token with its value, the reason it exists, and its `tier` — 211 `foundation` seeds (`--primary`, `--background`, `--radius`: set these when you are handed a brand), 104 `semantic` roles, 1814 `component` knobs.
|
|
22
22
|
- [vocabulary.json](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/vocabulary.json): the controlled prop vocabulary — which prop name means what, across every component.
|
|
23
23
|
- [rules.json](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/rules.json): 50 cardinal rules.
|
|
24
24
|
- [anti-ai-tells.json](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/anti-ai-tells.json): 26 shapes that make generated UI look generated, each with its fix.
|
|
@@ -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.17.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
|
@@ -9089,6 +9089,12 @@
|
|
|
9089
9089
|
"tier": "component",
|
|
9090
9090
|
"value": "8rem"
|
|
9091
9091
|
},
|
|
9092
|
+
{
|
|
9093
|
+
"description": "Ceiling of the menu surface's intrinsic width (gh#1103). The surface is `width: max-content` so its width never depends on the provisional `left` it is first laid out at; this keeps a long label inside the viewport, less React Aria's default 12px container padding each side.",
|
|
9094
|
+
"name": "--dropdown-content-max-width",
|
|
9095
|
+
"tier": "component",
|
|
9096
|
+
"value": "calc(100vw - 1.5rem)"
|
|
9097
|
+
},
|
|
9092
9098
|
{
|
|
9093
9099
|
"description": "THE MENU SURFACE (gh#880). `.ui-dropdown-menu-content` painted `hsl(var(--popover))` with no knob, while `.ui-popover-content` — the same kind of floating panel, in the same portal — had `--popover-surface-background`. That asymmetry is the shape of defect this repo keeps paying for: the theme reaches two of the three menu surfaces and the third silently stays opaque. A DROPDOWN IS THE MOST OPAQUE MEMBER OF THE FAMILY, by the standard's own rule (docs/GLASSMORPHISM-STANDARD.md §4): it is small, it sits over arbitrary content, and a 7-line menu over a photograph is unreadable at a card's alpha. It therefore gets its OWN fill knob rather than sharing the popover's — the two are meant to be able to differ. default = hsl(var(--popover)) at the call site",
|
|
9094
9100
|
"name": "--dropdown-content-background",
|
|
@@ -11699,6 +11705,12 @@
|
|
|
11699
11705
|
"tier": "component",
|
|
11700
11706
|
"value": "initial"
|
|
11701
11707
|
},
|
|
11708
|
+
{
|
|
11709
|
+
"description": "Inset of the expanded detail cell (gh#1083). `initial` so the default — the cell's own padding, var(--table-cell-padding-y) var(--table-cell-space-x), which follows density — re-resolves at the call site. `expandable.flush` drops it.",
|
|
11710
|
+
"name": "--table-row-expanded-padding",
|
|
11711
|
+
"tier": "component",
|
|
11712
|
+
"value": "initial"
|
|
11713
|
+
},
|
|
11702
11714
|
{
|
|
11703
11715
|
"description": "Gap between the header checkbox and the `selections` dropdown trigger beside it.",
|
|
11704
11716
|
"name": "--table-selection-menu-gap",
|
|
@@ -11867,6 +11879,12 @@
|
|
|
11867
11879
|
"tier": "component",
|
|
11868
11880
|
"value": "var(--space-stack-xs)"
|
|
11869
11881
|
},
|
|
11882
|
+
{
|
|
11883
|
+
"description": "Inline inset of a folded cell inside its card (gh#1102). 0: the card's own --table-stacked-collection-card-padding-x is the inset, so a value line gets the card's full content width instead of losing the table's cell padding on both sides.",
|
|
11884
|
+
"name": "--table-stacked-collection-cell-padding-x",
|
|
11885
|
+
"tier": "component",
|
|
11886
|
+
"value": "0"
|
|
11887
|
+
},
|
|
11870
11888
|
{
|
|
11871
11889
|
"description": "Table component tokens: row height, cell padding.",
|
|
11872
11890
|
"name": "--table-stacked-collection-label-font-size",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import { cva } from "class-variance-authority";
|
|
5
5
|
import {
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
XCircle
|
|
15
15
|
} from "lucide-react";
|
|
16
16
|
import { useTranslation } from "../../i18n/use-translation.js";
|
|
17
|
+
import { EllipsisTooltip } from "../feedback/tooltip.js";
|
|
17
18
|
import { cn } from "../../lib/utils.js";
|
|
18
19
|
import {
|
|
19
20
|
toneDestructiveClass,
|
|
@@ -140,50 +141,54 @@ function Badge({
|
|
|
140
141
|
const removeLabel = stringLabel ?? (deriveFromDom ? renderedLabel : void 0);
|
|
141
142
|
const named = props["aria-label"] != null || props["aria-labelledby"] != null;
|
|
142
143
|
const nameRole = named && props.role === void 0 && !onRemove ? "img" : void 0;
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
"
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
144
|
+
const labelTooltip = resolvedChildren != null && props.title == null;
|
|
145
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
146
|
+
/* @__PURE__ */ jsxs(
|
|
147
|
+
Element,
|
|
148
|
+
{
|
|
149
|
+
"data-slot": "badge",
|
|
150
|
+
role: nameRole,
|
|
151
|
+
"data-tone": tinted ? void 0 : resolvedTone,
|
|
152
|
+
"data-tinted": tinted ? "" : void 0,
|
|
153
|
+
"data-shape": shape ?? "default",
|
|
154
|
+
"data-tabular": tabular ? "" : void 0,
|
|
155
|
+
"data-removable": onRemove ? "" : void 0,
|
|
156
|
+
className: cn(
|
|
157
|
+
badgeVariants({
|
|
158
|
+
// A status tone paints the chip itself (`badgeToneClass` below), so the variant must not
|
|
159
|
+
// also paint one — see the `toned` variant. An EXPLICIT `variant` still wins, which is
|
|
160
|
+
// how `<Badge variant="outline" tone="success">` keeps its border treatment.
|
|
161
|
+
variant: tinted ? "tinted" : variant ?? (resolvedTone === "default" ? "default" : "toned"),
|
|
162
|
+
shape: shape ?? "default"
|
|
163
|
+
}),
|
|
164
|
+
tinted ? void 0 : badgeToneClass[resolvedTone],
|
|
165
|
+
className
|
|
166
|
+
),
|
|
167
|
+
style: tinted ? { ...style, ["--badge-color"]: color } : style,
|
|
168
|
+
...props,
|
|
169
|
+
children: [
|
|
170
|
+
ResolvedIcon ? /* @__PURE__ */ jsx(ResolvedIcon, { "data-slot": "badge-icon", "aria-hidden": "true" }) : null,
|
|
171
|
+
resolvedChildren != null ? /* @__PURE__ */ jsx("span", { ref: labelRef, "data-slot": "badge-label", children: resolvedChildren }) : null,
|
|
172
|
+
onRemove ? /* @__PURE__ */ jsx(
|
|
173
|
+
"button",
|
|
174
|
+
{
|
|
175
|
+
type: "button",
|
|
176
|
+
"data-slot": "badge-remove",
|
|
177
|
+
className: "ui-control-inline-affix-action ui-badge-remove",
|
|
178
|
+
"aria-label": removeLabelProp ?? (removeLabel != null ? t("navigation.filterBar.removeFilter", { label: removeLabel }) : t("common.delete")),
|
|
179
|
+
onClick: (event) => {
|
|
180
|
+
event.stopPropagation();
|
|
181
|
+
onRemove();
|
|
182
|
+
},
|
|
183
|
+
disabled: removeDisabled,
|
|
184
|
+
children: /* @__PURE__ */ jsx(X, { "aria-hidden": "true" })
|
|
185
|
+
}
|
|
186
|
+
) : null
|
|
187
|
+
]
|
|
188
|
+
}
|
|
189
|
+
),
|
|
190
|
+
labelTooltip ? /* @__PURE__ */ jsx(EllipsisTooltip, { anchorRef: labelRef, title: resolvedChildren }) : null
|
|
191
|
+
] });
|
|
187
192
|
}
|
|
188
193
|
const StatusBadge = Badge;
|
|
189
194
|
export {
|
|
@@ -1356,7 +1356,7 @@ DataTable.Content = function DataTableContent() {
|
|
|
1356
1356
|
{
|
|
1357
1357
|
className: "ui-data-table-expanded-row hover:bg-transparent",
|
|
1358
1358
|
"data-expanded-row": "",
|
|
1359
|
-
children: /* @__PURE__ */ jsx(TableCell, { colSpan: emptyColSpan, flush:
|
|
1359
|
+
children: /* @__PURE__ */ jsx(TableCell, { colSpan: emptyColSpan, flush: expandable.flush, children: expandable.expandedRowRender(original, rowIndex, true) })
|
|
1360
1360
|
}
|
|
1361
1361
|
) : null
|
|
1362
1362
|
] }, row.id);
|
|
@@ -412,7 +412,12 @@ const ImageRoot = React.forwardRef(function Image({
|
|
|
412
412
|
status: "loading"
|
|
413
413
|
});
|
|
414
414
|
const status = load.src === src ? load.status : "loading";
|
|
415
|
-
const setStatus = React.useCallback(
|
|
415
|
+
const setStatus = React.useCallback(
|
|
416
|
+
(next) => setLoad(
|
|
417
|
+
(prev) => prev.src === src && prev.status === "error" ? prev : { src, status: next }
|
|
418
|
+
),
|
|
419
|
+
[src]
|
|
420
|
+
);
|
|
416
421
|
const imgRef = React.useRef(null);
|
|
417
422
|
const setImgRef = React.useCallback(
|
|
418
423
|
(node) => {
|
|
@@ -228,6 +228,7 @@ const TableCell = React.forwardRef(
|
|
|
228
228
|
...props
|
|
229
229
|
}, ref) => {
|
|
230
230
|
const preset = React.useContext(TablePresetContext);
|
|
231
|
+
const body = priority === "actions" && preset === "action-collection" ? /* @__PURE__ */ jsx("span", { className: "ui-table-actions-content", children }) : children;
|
|
231
232
|
return /* @__PURE__ */ jsxs(
|
|
232
233
|
"td",
|
|
233
234
|
{
|
|
@@ -247,8 +248,8 @@ const TableCell = React.forwardRef(
|
|
|
247
248
|
},
|
|
248
249
|
...props,
|
|
249
250
|
children: [
|
|
250
|
-
label !== void 0 ? /* @__PURE__ */ jsx("span", { className: "ui-table-stacked-collection-label", "aria-hidden": "true", children: label }) : null,
|
|
251
|
-
|
|
251
|
+
label !== void 0 && children != null && children !== false && children !== "" ? /* @__PURE__ */ jsx("span", { className: "ui-table-stacked-collection-label", "aria-hidden": "true", children: label }) : null,
|
|
252
|
+
label !== void 0 ? /* @__PURE__ */ jsx("span", { className: "ui-table-stacked-collection-value", children: body }) : body
|
|
252
253
|
]
|
|
253
254
|
}
|
|
254
255
|
);
|
|
@@ -125,7 +125,8 @@ function TooltipContent({
|
|
|
125
125
|
const FOCUS_HOST = 'a[href], button, input, select, textarea, summary, [tabindex]:is([role="treeitem"], [role="gridcell"], [role="row"], [role="option"], [role="menuitem"], [role="menuitemcheckbox"], [role="menuitemradio"], [role="tab"], [role="link"], [role="button"], [role="checkbox"], [role="radio"], [role="switch"])';
|
|
126
126
|
function isClipping(node) {
|
|
127
127
|
const box = node.querySelector(':scope > [data-slot="typography-content"]') ?? node;
|
|
128
|
-
|
|
128
|
+
if (box.scrollWidth > box.clientWidth) return true;
|
|
129
|
+
return box.scrollHeight > box.clientHeight && getComputedStyle(box).overflowY !== "visible";
|
|
129
130
|
}
|
|
130
131
|
function isFocusVisible(node) {
|
|
131
132
|
try {
|
|
@@ -469,9 +469,9 @@ const TextBase = React.forwardRef((props, ref) => {
|
|
|
469
469
|
// always been, on the element itself.
|
|
470
470
|
"data-truncate": truncating && !block.wrapsContent ? "" : void 0,
|
|
471
471
|
"data-clamp": effectiveClamp !== void 0 && !block.wrapsContent ? "" : void 0,
|
|
472
|
-
//
|
|
473
|
-
//
|
|
474
|
-
"data-whitespace": whitespace
|
|
472
|
+
// Unset emits nothing. An EXPLICIT `normal` is emitted (gh#1083): it releases a `nowrap` the
|
|
473
|
+
// Text inherits, e.g. from a table cell. `truncate` still wins by emitting nothing.
|
|
474
|
+
"data-whitespace": whitespace && !truncating ? whitespace : void 0,
|
|
475
475
|
// Same shape and the same precedence as `whitespace`: `normal` is inert, and one line has
|
|
476
476
|
// nowhere to break to, so `truncate` simply does not emit it (gh#927).
|
|
477
477
|
"data-break": breakMode === "anywhere" && !truncating ? "anywhere" : void 0,
|
|
@@ -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.17.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,
|
package/dist/props/registry.d.ts
CHANGED
|
@@ -322,7 +322,7 @@ export declare const VOCABULARY_REGISTRY: {
|
|
|
322
322
|
readonly TableExpandableProp: {
|
|
323
323
|
readonly file: "vocabulary/data.prop.ts";
|
|
324
324
|
readonly category: "data";
|
|
325
|
-
readonly description: "DataTable expandable-row config — expandedRowRender | rowExpandable | defaultExpandAllRows | expandedRowKeys | onExpandedRowsChange | expandRowByClick (antd/rc-table ExpandableConfig)";
|
|
325
|
+
readonly description: "DataTable expandable-row config — expandedRowRender | rowExpandable | defaultExpandAllRows | expandedRowKeys | onExpandedRowsChange | expandRowByClick | flush (antd/rc-table ExpandableConfig; the detail cell is padded by default, gh#1083)";
|
|
326
326
|
};
|
|
327
327
|
readonly TableSummaryProp: {
|
|
328
328
|
readonly file: "vocabulary/data.prop.ts";
|
package/dist/props/registry.js
CHANGED
|
@@ -320,7 +320,7 @@ const VOCABULARY_REGISTRY = {
|
|
|
320
320
|
TableExpandableProp: {
|
|
321
321
|
file: "vocabulary/data.prop.ts",
|
|
322
322
|
category: "data",
|
|
323
|
-
description: "DataTable expandable-row config \u2014 expandedRowRender | rowExpandable | defaultExpandAllRows | expandedRowKeys | onExpandedRowsChange | expandRowByClick (antd/rc-table ExpandableConfig)"
|
|
323
|
+
description: "DataTable expandable-row config \u2014 expandedRowRender | rowExpandable | defaultExpandAllRows | expandedRowKeys | onExpandedRowsChange | expandRowByClick | flush (antd/rc-table ExpandableConfig; the detail cell is padded by default, gh#1083)"
|
|
324
324
|
},
|
|
325
325
|
TableSummaryProp: {
|
|
326
326
|
file: "vocabulary/data.prop.ts",
|
|
@@ -271,6 +271,12 @@ export type TableExpandableProp<T> = {
|
|
|
271
271
|
/** Clicking anywhere on the row toggles it (antd `expandRowByClick`). */
|
|
272
272
|
expandRowByClick?: boolean;
|
|
273
273
|
columnTitle?: React.ReactNode;
|
|
274
|
+
/**
|
|
275
|
+
* The detail reaches the cell edges: no inset (gh#1083). Off by default — the expanded cell is
|
|
276
|
+
* padded like any other cell (antd), retuned by `--table-row-expanded-padding`. Set it for a
|
|
277
|
+
* detail that owns its inset, such as a nested table or a `ListRow` list.
|
|
278
|
+
*/
|
|
279
|
+
flush?: FlushProp;
|
|
274
280
|
};
|
|
275
281
|
/** Footer totals row — receives the rows currently rendered (antd/rc-table `summary`). */
|
|
276
282
|
export type TableSummaryProp<T> = (rows: readonly T[]) => React.ReactNode;
|
|
@@ -90,6 +90,7 @@ export type TextAlignProp = "start" | "center" | "end";
|
|
|
90
90
|
* `normal` is CSS's own behaviour and the default: newlines and runs of spaces collapse. That is
|
|
91
91
|
* right for a label and wrong for text a PERSON typed into a textarea — a plain-text note, a
|
|
92
92
|
* pasted log, an issue description — where the line breaks and the indentation ARE content.
|
|
93
|
+
* Passed explicitly, `normal` also releases a `nowrap` the text inherits (a table cell's, gh#1083).
|
|
93
94
|
*
|
|
94
95
|
* `pre-wrap` keeps both and still wraps at the container's edge, so the block cannot force a
|
|
95
96
|
* horizontal scrollbar the way `pre` would. It is a closed union rather than a boolean because the
|
|
@@ -5,6 +5,11 @@
|
|
|
5
5
|
display: inline-flex;
|
|
6
6
|
|
|
7
7
|
inline-size: fit-content;
|
|
8
|
+
|
|
9
|
+
max-inline-size: 100%;
|
|
10
|
+
min-inline-size: 0;
|
|
11
|
+
|
|
12
|
+
box-sizing: border-box;
|
|
8
13
|
align-items: center;
|
|
9
14
|
|
|
10
15
|
vertical-align: middle;
|
|
@@ -21,6 +26,13 @@
|
|
|
21
26
|
white-space: nowrap;
|
|
22
27
|
}
|
|
23
28
|
|
|
29
|
+
[data-slot="badge-label"] {
|
|
30
|
+
min-inline-size: 0;
|
|
31
|
+
overflow-x: clip;
|
|
32
|
+
overflow-y: visible;
|
|
33
|
+
text-overflow: ellipsis;
|
|
34
|
+
}
|
|
35
|
+
|
|
24
36
|
@supports (text-box-trim: trim-both) and (text-box-edge: cap alphabetic) {
|
|
25
37
|
[data-slot="badge-label"] {
|
|
26
38
|
text-box-trim: trim-both;
|
package/dist/styles/layers.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "31.
|
|
2
|
+
"version": "31.17.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",
|
|
@@ -196,6 +196,7 @@
|
|
|
196
196
|
},
|
|
197
197
|
"Badge": {
|
|
198
198
|
"layers": [
|
|
199
|
+
"dialog-layout.css",
|
|
199
200
|
"badge-layout.css"
|
|
200
201
|
]
|
|
201
202
|
},
|
|
@@ -719,6 +719,9 @@
|
|
|
719
719
|
|
|
720
720
|
z-index: var(--overlay-z-index);
|
|
721
721
|
min-width: var(--menu-content-min-width);
|
|
722
|
+
|
|
723
|
+
width: max-content;
|
|
724
|
+
max-width: var(--dropdown-content-max-width);
|
|
722
725
|
border-radius: var(--radius-md, calc(var(--radius) / var(--radius-ratio)));
|
|
723
726
|
border: var(--stroke-hairline) solid hsl(var(--border));
|
|
724
727
|
|
|
@@ -546,6 +546,22 @@
|
|
|
546
546
|
);
|
|
547
547
|
}
|
|
548
548
|
|
|
549
|
+
.ui-data-table-expanded-row > [data-slot="table-cell"]:not([data-flush]) {
|
|
550
|
+
white-space: normal;
|
|
551
|
+
padding: var(
|
|
552
|
+
--table-row-expanded-padding,
|
|
553
|
+
var(--table-cell-padding-y) var(--table-cell-space-x, var(--space-section-active))
|
|
554
|
+
);
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
.ui-data-table-expanded-row > [data-slot="table-cell"][data-flush] {
|
|
558
|
+
white-space: normal;
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
.ui-table-stacked-collection-value {
|
|
562
|
+
display: contents;
|
|
563
|
+
}
|
|
564
|
+
|
|
549
565
|
.ui-data-table-summary {
|
|
550
566
|
background-color: var(--table-summary-background, hsl(var(--muted)));
|
|
551
567
|
font-weight: var(--font-weight-medium);
|
|
@@ -914,10 +930,18 @@
|
|
|
914
930
|
[data-collapse-below="sm"] [data-slot="table-cell"] {
|
|
915
931
|
display: block;
|
|
916
932
|
padding-block: var(--table-stacked-collection-cell-padding-y);
|
|
933
|
+
|
|
934
|
+
padding-inline: var(--table-stacked-collection-cell-padding-x);
|
|
917
935
|
white-space: normal;
|
|
918
936
|
overflow-wrap: anywhere;
|
|
919
937
|
}
|
|
920
938
|
|
|
939
|
+
[data-collapse-below="sm"] [data-slot="table-cell"]:empty,
|
|
940
|
+
[data-collapse-below="sm"]
|
|
941
|
+
[data-slot="table-cell"]:has(> .ui-table-stacked-collection-value:empty) {
|
|
942
|
+
display: none;
|
|
943
|
+
}
|
|
944
|
+
|
|
921
945
|
[data-collapse-below="sm"] .ui-table-stacked-collection-label {
|
|
922
946
|
display: block;
|
|
923
947
|
font-size: var(--table-stacked-collection-label-font-size);
|
|
@@ -958,10 +982,17 @@
|
|
|
958
982
|
[data-collapse-below="md"] [data-slot="table-cell"] {
|
|
959
983
|
display: block;
|
|
960
984
|
padding-block: var(--table-stacked-collection-cell-padding-y);
|
|
985
|
+
padding-inline: var(--table-stacked-collection-cell-padding-x);
|
|
961
986
|
white-space: normal;
|
|
962
987
|
overflow-wrap: anywhere;
|
|
963
988
|
}
|
|
964
989
|
|
|
990
|
+
[data-collapse-below="md"] [data-slot="table-cell"]:empty,
|
|
991
|
+
[data-collapse-below="md"]
|
|
992
|
+
[data-slot="table-cell"]:has(> .ui-table-stacked-collection-value:empty) {
|
|
993
|
+
display: none;
|
|
994
|
+
}
|
|
995
|
+
|
|
965
996
|
[data-collapse-below="md"] .ui-table-stacked-collection-label {
|
|
966
997
|
display: block;
|
|
967
998
|
font-size: var(--table-stacked-collection-label-font-size);
|
|
@@ -1002,10 +1033,17 @@
|
|
|
1002
1033
|
[data-collapse-below="lg"] [data-slot="table-cell"] {
|
|
1003
1034
|
display: block;
|
|
1004
1035
|
padding-block: var(--table-stacked-collection-cell-padding-y);
|
|
1036
|
+
padding-inline: var(--table-stacked-collection-cell-padding-x);
|
|
1005
1037
|
white-space: normal;
|
|
1006
1038
|
overflow-wrap: anywhere;
|
|
1007
1039
|
}
|
|
1008
1040
|
|
|
1041
|
+
[data-collapse-below="lg"] [data-slot="table-cell"]:empty,
|
|
1042
|
+
[data-collapse-below="lg"]
|
|
1043
|
+
[data-slot="table-cell"]:has(> .ui-table-stacked-collection-value:empty) {
|
|
1044
|
+
display: none;
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1009
1047
|
[data-collapse-below="lg"] .ui-table-stacked-collection-label {
|
|
1010
1048
|
display: block;
|
|
1011
1049
|
font-size: var(--table-stacked-collection-label-font-size);
|
|
@@ -1046,10 +1084,17 @@
|
|
|
1046
1084
|
[data-collapse-below="xl"] [data-slot="table-cell"] {
|
|
1047
1085
|
display: block;
|
|
1048
1086
|
padding-block: var(--table-stacked-collection-cell-padding-y);
|
|
1087
|
+
padding-inline: var(--table-stacked-collection-cell-padding-x);
|
|
1049
1088
|
white-space: normal;
|
|
1050
1089
|
overflow-wrap: anywhere;
|
|
1051
1090
|
}
|
|
1052
1091
|
|
|
1092
|
+
[data-collapse-below="xl"] [data-slot="table-cell"]:empty,
|
|
1093
|
+
[data-collapse-below="xl"]
|
|
1094
|
+
[data-slot="table-cell"]:has(> .ui-table-stacked-collection-value:empty) {
|
|
1095
|
+
display: none;
|
|
1096
|
+
}
|
|
1097
|
+
|
|
1053
1098
|
[data-collapse-below="xl"] .ui-table-stacked-collection-label {
|
|
1054
1099
|
display: block;
|
|
1055
1100
|
font-size: var(--table-stacked-collection-label-font-size);
|
|
@@ -41,6 +41,8 @@
|
|
|
41
41
|
|
|
42
42
|
--table-row-expanded-background: initial;
|
|
43
43
|
|
|
44
|
+
--table-row-expanded-padding: initial;
|
|
45
|
+
|
|
44
46
|
--table-selection-menu-gap: var(--space-1);
|
|
45
47
|
|
|
46
48
|
--table-row-striped-background: initial;
|
|
@@ -85,6 +87,8 @@
|
|
|
85
87
|
--table-stacked-collection-card-padding-x: var(--space-inline-md);
|
|
86
88
|
--table-stacked-collection-card-gap: var(--space-stack-sm);
|
|
87
89
|
--table-stacked-collection-cell-padding-y: var(--space-stack-xs);
|
|
90
|
+
|
|
91
|
+
--table-stacked-collection-cell-padding-x: 0;
|
|
88
92
|
--table-stacked-collection-label-font-size: var(
|
|
89
93
|
--font-size-xs,
|
|
90
94
|
calc(var(--font-size-base) / var(--font-size-ratio))
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
StatusBadge,
|
|
9
9
|
} from "@godxjp/ui/data-display";
|
|
10
10
|
import { Text } from "@godxjp/ui/general";
|
|
11
|
+
import { useTranslation } from "@godxjp/ui/i18n";
|
|
11
12
|
import { Flex, PageContainer } from "@godxjp/ui/layout";
|
|
12
13
|
import { Star } from "lucide-react";
|
|
13
14
|
|
|
@@ -91,6 +92,7 @@ const statusBadgeTones = [
|
|
|
91
92
|
];
|
|
92
93
|
|
|
93
94
|
export default function Demo() {
|
|
95
|
+
const { t } = useTranslation();
|
|
94
96
|
return (
|
|
95
97
|
<PageContainer
|
|
96
98
|
title="Badge"
|
|
@@ -299,6 +301,19 @@ export default function Demo() {
|
|
|
299
301
|
</CardContent>
|
|
300
302
|
</Card>
|
|
301
303
|
|
|
304
|
+
<Card>
|
|
305
|
+
<CardHeader>
|
|
306
|
+
<CardTitle level={2}>{t("badgeDocs.longLabels.title")}</CardTitle>
|
|
307
|
+
<CardDescription>{t("badgeDocs.longLabels.description")}</CardDescription>
|
|
308
|
+
</CardHeader>
|
|
309
|
+
<CardContent>
|
|
310
|
+
<Flex direction="col" align="start" gap="xs">
|
|
311
|
+
<Badge tone="info">{t("badgeDocs.longLabels.sample")}</Badge>
|
|
312
|
+
<Badge status="active" />
|
|
313
|
+
</Flex>
|
|
314
|
+
</CardContent>
|
|
315
|
+
</Card>
|
|
316
|
+
|
|
302
317
|
<Card>
|
|
303
318
|
<CardHeader>
|
|
304
319
|
<CardTitle level={2}>Icon overrides</CardTitle>
|
|
@@ -1566,5 +1566,12 @@
|
|
|
1566
1566
|
"title": "Alphabetic text, word by word",
|
|
1567
1567
|
"description": "Languages that separate words with spaces are compared per word. Pass granularity=\"line\" to compare whole lines."
|
|
1568
1568
|
}
|
|
1569
|
+
},
|
|
1570
|
+
"badgeDocs": {
|
|
1571
|
+
"longLabels": {
|
|
1572
|
+
"title": "Long labels",
|
|
1573
|
+
"description": "A chip never wraps: a label wider than its container ends in an ellipsis (gh#1101), and when it was cut the full text opens in a tooltip on hover and on keyboard focus of the link or row around the chip (gh#1105). No extra props in a table cell or a Card.",
|
|
1574
|
+
"sample": "Via team · Platform infrastructure operations (East Japan region, night-shift rotation group 2)"
|
|
1575
|
+
}
|
|
1569
1576
|
}
|
|
1570
1577
|
}
|
|
@@ -1559,5 +1559,12 @@
|
|
|
1559
1559
|
"title": "英文は単語単位で",
|
|
1560
1560
|
"description": "スペースで区切られる言語は単語ごとに比べます。行単位にしたい場合は granularity=\"line\" を指定します。"
|
|
1561
1561
|
}
|
|
1562
|
+
},
|
|
1563
|
+
"badgeDocs": {
|
|
1564
|
+
"longLabels": {
|
|
1565
|
+
"title": "長いラベル",
|
|
1566
|
+
"description": "チップは折り返さず、コンテナより広いラベルは省略記号で切れます(gh#1101)。切れたときは、ホバーでも、チップを囲むリンクや行へのキーボードフォーカスでも、全文がツールチップに出ます(gh#1105)。表のセルでも Card でも追加の指定は要りません。",
|
|
1567
|
+
"sample": "チーム経由 · プラットフォーム基盤運用チーム(東日本リージョン・夜間当番ローテーション第二班)"
|
|
1568
|
+
}
|
|
1562
1569
|
}
|
|
1563
1570
|
}
|
|
@@ -1559,5 +1559,12 @@
|
|
|
1559
1559
|
"title": "Văn bản chữ Latinh, theo từng từ",
|
|
1560
1560
|
"description": "Ngôn ngữ tách từ bằng dấu cách được so theo từng từ. Truyền granularity=\"line\" để so cả dòng."
|
|
1561
1561
|
}
|
|
1562
|
+
},
|
|
1563
|
+
"badgeDocs": {
|
|
1564
|
+
"longLabels": {
|
|
1565
|
+
"title": "Nhãn dài",
|
|
1566
|
+
"description": "Chip không bao giờ xuống dòng: nhãn rộng hơn khung chứa sẽ kết thúc bằng dấu ba chấm (gh#1101), và khi bị cắt thì toàn văn hiện trong tooltip khi rê chuột hoặc khi focus bàn phím vào liên kết/hàng chứa chip (gh#1105). Trong ô bảng hay Card đều không cần thêm prop.",
|
|
1567
|
+
"sample": "Qua nhóm · Đội vận hành hạ tầng nền tảng (vùng Đông Nhật Bản, ca trực đêm nhóm 2)"
|
|
1568
|
+
}
|
|
1562
1569
|
}
|
|
1563
1570
|
}
|