@godxjp/ui 31.6.0 → 31.8.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.
Files changed (61) hide show
  1. package/agent/START-HERE.md +4 -4
  2. package/agent/components/Breadcrumb.json +1 -1
  3. package/agent/components/ColorPicker.json +16 -8
  4. package/agent/components/PageContainer.json +1 -1
  5. package/agent/components/Progress.json +12 -1
  6. package/agent/components/Select.json +22 -0
  7. package/agent/components/Text.json +1 -1
  8. package/agent/components.json +53 -12
  9. package/agent/index.json +4 -4
  10. package/agent/llms.txt +5 -5
  11. package/agent/tokens.json +30 -0
  12. package/dist/components/data-display/progress.d.ts +16 -0
  13. package/dist/components/data-display/progress.js +17 -3
  14. package/dist/components/data-entry/chat-composer.js +11 -4
  15. package/dist/components/data-entry/chat-suggestion.js +2 -0
  16. package/dist/components/data-entry/color-picker.d.ts +2 -2
  17. package/dist/components/data-entry/color-picker.js +150 -37
  18. package/dist/components/data-entry/command-palette.js +2 -1
  19. package/dist/components/data-entry/date-picker.js +2 -0
  20. package/dist/components/data-entry/index.d.ts +1 -1
  21. package/dist/components/data-entry/number-input.js +2 -1
  22. package/dist/components/data-entry/search-select.js +55 -17
  23. package/dist/components/data-entry/select.js +1 -1
  24. package/dist/components/data-entry/time-picker.js +3 -0
  25. package/dist/components/feedback/non-modal-layer.js +2 -1
  26. package/dist/components/feedback/tooltip.d.ts +21 -0
  27. package/dist/components/feedback/tooltip.js +101 -0
  28. package/dist/components/general/typography.js +35 -12
  29. package/dist/components/layout/breadcrumb-ellipsis.d.ts +16 -0
  30. package/dist/components/layout/breadcrumb-ellipsis.js +28 -0
  31. package/dist/components/layout/breadcrumb.js +16 -7
  32. package/dist/components/layout/page-container.js +29 -20
  33. package/dist/components/navigation/pagination.js +2 -1
  34. package/dist/components/ui/tag-input.js +2 -1
  35. package/dist/contracts/measurement.json +1 -1
  36. package/dist/i18n/messages/en.json +6 -3
  37. package/dist/i18n/messages/ja.json +6 -3
  38. package/dist/i18n/messages/vi.json +6 -3
  39. package/dist/lib/ime.d.ts +12 -0
  40. package/dist/lib/ime.js +7 -0
  41. package/dist/props/components/data-entry.prop.d.ts +66 -1
  42. package/dist/props/components/index.d.ts +1 -1
  43. package/dist/props/registry.d.ts +20 -0
  44. package/dist/props/registry.js +22 -0
  45. package/dist/props/vocabulary/index.d.ts +1 -1
  46. package/dist/props/vocabulary/navigation.prop.d.ts +14 -0
  47. package/dist/styles/control.css +79 -0
  48. package/dist/styles/layers.json +3 -2
  49. package/dist/styles/layout.css +22 -0
  50. package/dist/styles/table-layout.css +8 -0
  51. package/dist/tokens/components/control.css +8 -0
  52. package/dist/tokens/components/navigation.css +2 -0
  53. package/docs/data-display/progress.tsx +24 -6
  54. package/docs/data-entry/color-picker.tsx +72 -0
  55. package/docs/data-entry/select.tsx +38 -0
  56. package/docs/general/typography.tsx +84 -1
  57. package/docs/i18n/messages/en.json +47 -1
  58. package/docs/i18n/messages/ja.json +47 -1
  59. package/docs/i18n/messages/vi.json +47 -1
  60. package/docs/navigation/breadcrumb.tsx +24 -0
  61. package/package.json +2 -2
@@ -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.0.** If the project you are editing has a different
6
+ **This catalog describes `@godxjp/ui` 31.8.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.
@@ -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` — 2099 design tokens, each tagged with its `tier`. **If you were handed a
59
+ 4. `tokens.json` — 2104 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
- 1784 `component` entries are per-part knobs; reach for one only when a role is
62
+ 1789 `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` | 1784 | 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` |
148
+ | `component` | 1789 | 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.
@@ -5,7 +5,7 @@
5
5
  "name": "Breadcrumb",
6
6
  "props": [
7
7
  {
8
- "description": "Array of { label, to?, menu? } — omit `to` on the last (current) segment. `menu` (Ant Design `BreadcrumbItemType.menu`) hangs a sibling picker off that segment: `{ items: { value, label, to?, disabled? }[], onSelect? }`. The segment then renders as a menu button, not a link — an entry with `to` becomes a real anchor inside the menu while keeping `role=\"menuitem\"`.",
8
+ "description": "Array of { label, to?, menu?, ellipsis? } — omit `to` on the last (current) segment. `ellipsis` (`boolean | { tooltip?: ReactNode }`, gh#1046; antd Breadcrumb has none, the shape is antd Typography's) keeps the trail on one line and cuts that segment's label with an ellipsis, showing the full label in a tooltip on hover and on keyboard focus of the crumb link; `{ tooltip: false }` drops the tooltip. Link and current segments only. `--breadcrumb-item-max-inline-size` (default `none`) caps such a segment. `menu` (Ant Design `BreadcrumbItemType.menu`) hangs a sibling picker off that segment: `{ items: { value, label, to?, disabled? }[], onSelect? }`. The segment then renders as a menu button, not a link — an entry with `to` becomes a real anchor inside the menu while keeping `role=\"menuitem\"`.",
9
9
  "name": "items",
10
10
  "required": true,
11
11
  "type": "BreadcrumbItemProp[]"
@@ -1,5 +1,5 @@
1
1
  {
2
- "example": "import { useState } from \"react\";\nimport { ColorPicker, FormField } from \"@godxjp/ui/data-entry\";\n\nexport function BrandColorField() {\n const [color, setColor] = useState(\"#2563eb\");\n\n return (\n <FormField id=\"brand-color\" label=\"Brand color\" className=\"max-w-xs\">\n <ColorPicker\n id=\"brand-color\"\n value={color}\n onValueChange={setColor}\n />\n </FormField>\n );\n}\n\n// Compact swatch-only variant (no hex input)\nexport function SwatchOnly() {\n const [color, setColor] = useState(\"#16a34a\");\n return <ColorPicker value={color} onValueChange={setColor} showHexInput={false} />;\n}\n\n// Disabled state\nexport function DisabledColor() {\n return <ColorPicker value=\"#6b7280\" disabled />;\n}",
2
+ "example": "import { useState } from \"react\";\nimport { ColorPicker, Form, FormField } from \"@godxjp/ui/data-entry\";\n\nexport function BrandColorField() {\n const [color, setColor] = useState(\"#2563eb\");\n\n return (\n <Form>\n <FormField id=\"brand-color\" label=\"Brand color\">\n <ColorPicker id=\"brand-color\" value={color} onValueChange={setColor} />\n </FormField>\n </Form>\n );\n}\n\n// Compact swatch-only variant (no hex input)\nexport function SwatchOnly() {\n const [color, setColor] = useState(\"#16a34a\");\n return <ColorPicker value={color} onValueChange={setColor} showHexInput={false} />;\n}\n\n// Fixed palette only (gh#1055): tags pick from presets, never free hex\nexport function TagColorField() {\n const [color, setColor] = useState(\"#2563eb\");\n return (\n <Form>\n <FormField id=\"tag-color\" label=\"Tag colour\">\n <ColorPicker\n id=\"tag-color\"\n value={color}\n onValueChange={setColor}\n presets={[{ label: \"Palette\", colors: [\"#dc2626\", \"#16a34a\", \"#2563eb\", \"#9333ea\"] }]}\n panelRender={(_, { components: { Presets } }) => <Presets />}\n />\n </FormField>\n </Form>\n );\n}\n\n// Disabled state\nexport function DisabledColor() {\n return <ColorPicker value=\"#6b7280\" disabled />;\n}",
3
3
  "group": "data-entry",
4
4
  "importPath": "@godxjp/ui/data-entry",
5
5
  "name": "ColorPicker",
@@ -23,7 +23,7 @@
23
23
  {
24
24
  "defaultValue": "undefined",
25
25
  "description": "Called with the normalized, validated hex string whenever the user commits a new color — via the native swatch picker or by pressing Enter / blurring the hex input. Not called for invalid hex drafts.",
26
- "name": "onChange",
26
+ "name": "onValueChange",
27
27
  "type": "(hex: string) => void"
28
28
  },
29
29
  {
@@ -51,14 +51,21 @@
51
51
  "type": "string"
52
52
  },
53
53
  {
54
- "description": "Fires with the committed hex string.",
55
- "name": "onValueChange",
56
- "type": "(value: string) => void"
54
+ "defaultValue": "undefined",
55
+ "description": "antd `presets` (gh#1055) — named groups of fixed hex swatches under the picker. Each group is collapsible (`defaultOpen`, default true) and is an APG radio group: one tab stop, arrow keys move and select, each swatch is named by its hex and the one equal to `value` is checked. An empty `colors` shows the localized 'Empty' line. Hex only (#rgb/#rrggbb) — antd also accepts colour objects and gradients, which this picker has no model for.",
56
+ "name": "presets",
57
+ "type": "{ label: ReactNode; colors: string[]; defaultOpen?: boolean; key?: Key }[]"
58
+ },
59
+ {
60
+ "defaultValue": "undefined",
61
+ "description": "antd `panelRender` — replaces the picker body. `panel` is the default (swatch + hex row, then presets). PRESETS-ONLY mode (a fixed palette, no free hex): `panelRender={(_, { components: { Presets } }) => <Presets />}`. The hidden `name` input always renders outside the panel.",
62
+ "name": "panelRender",
63
+ "type": "(panel: ReactNode, extra: { components: { Picker: FC; Presets: FC } }) => ReactNode"
57
64
  }
58
65
  ],
59
66
  "related": [
60
67
  "Input — use for plain text/number entry; use ColorPicker when the value is specifically a color hex code and you want a visual swatch.",
61
- "Select / SearchSelect — use for choosing from a fixed palette of named colors (e.g. 'Red', 'Blue'); use ColorPicker for freeform hex color entry."
68
+ "Select / SearchSelect — use for choosing from a list of colour NAMES (e.g. 'Red', 'Blue'); for a fixed palette of visible swatches use ColorPicker `presets` (presets-only via `panelRender`)."
62
69
  ],
63
70
  "rules": [
64
71
  2,
@@ -70,10 +77,11 @@
70
77
  "tagline": "Native color-swatch picker with an optional editable hex input — always pass a valid 3- or 6-digit hex `value`; invalid hex is silently ignored and the previous value is restored.",
71
78
  "usage": [
72
79
  "DO wrap in FormField when a label or validation message is needed — pass the same id to both FormField and ColorPicker so htmlFor wires up correctly: `<FormField id='brand' label='Brand color'><ColorPicker id='brand' value={v} onValueChange={setV} /></FormField>`.",
73
- "DO use controlled mode (value + onChange) — there is no defaultValue/uncontrolled path; always supply value.",
80
+ "Use it controlled (value + onValueChange) or uncontrolled (defaultValue + onValueChange); both paths commit only validated hex.",
74
81
  "DON'T pass an invalid or empty string to value — the component will flash the invalid color on the preview swatch. Always initialize state to a valid 3- or 6-digit hex (e.g. '#2563eb').",
75
- "The hex Input is a live draft field — onChange is NOT called until the user presses Enter or blurs; only then is the value validated and the parent notified. Do not rely on onChange firing on every keystroke.",
82
+ "The hex Input is a live draft field — onValueChange is NOT called until the user presses Enter or blurs; only then is the value validated and the parent notified. Do not rely on onValueChange firing on every keystroke.",
76
83
  "Set showHexInput={false} only for compact/inline contexts (icon pickers, table cells) where space is tight and keyboard hex entry is not needed.",
84
+ "DO use `presets` when the value must come from a fixed palette (tag / label colours) — add `panelRender={(_, { components: { Presets } }) => <Presets />}` to remove free hex entry entirely. NEVER rebuild a palette from a ToggleGroup of swatches.",
77
85
  "NEVER hand-roll a color picker with raw <input type='color'> — always use this component; it normalizes hex, debounces draft state, and respects the design-token control styles."
78
86
  ],
79
87
  "useCases": [
@@ -56,7 +56,7 @@
56
56
  "type": "ReactNode"
57
57
  },
58
58
  {
59
- "description": "Ordered trail of { label, to? } segments above the title.",
59
+ "description": "Ordered trail of { label, to?, ellipsis? } segments above the title. `ellipsis: true` on a segment keeps the trail on one line and cuts that label with an ellipsis, the full label in a tooltip on hover and on keyboard focus of the crumb link — same contract as `Breadcrumb` items.",
60
60
  "name": "breadcrumb",
61
61
  "type": "BreadcrumbItemProp[]"
62
62
  },
@@ -1,5 +1,5 @@
1
1
  {
2
- "example": "import { Progress } from \"@godxjp/ui/data-display\";\n\n<Progress value={pct} label={pct + \"% 使用中\"} tone={pct >= 80 ? \"warning\" : \"success\"} />\n<Progress value={252} over label=\"252% 積載\" />\n<Progress\n segments={[\n { value: 2, tone: \"destructive\", label: \"期限超過\" },\n { value: 3, tone: \"warning\", label: \"期限間近\" },\n { value: 12, tone: \"success\", label: \"対応済\" },\n ]}\n aria-labelledby={companyNameId}\n/>",
2
+ "example": "import { Progress } from \"@godxjp/ui/data-display\";\n\n<Progress value={pct} label={pct + \"% 使用中\"} tone={pct >= 80 ? \"warning\" : \"success\"} />\n<Progress value={252} over label=\"252% 積載\" />\n<Progress\n segments={[\n { value: 2, tone: \"destructive\", label: \"期限超過\" },\n { value: 3, tone: \"warning\", label: \"期限間近\" },\n { value: 12, tone: \"success\", label: \"対応済\" },\n ]}\n aria-labelledby={companyNameId}\n/>\n<Progress\n segments={[\n { value: 3, tone: \"success\", label: \"合格\" },\n { value: 1, tone: \"destructive\", label: \"失敗\" },\n ]}\n total={400}\n remainderLabel=\"未実施\"\n/>",
3
3
  "group": "data-display",
4
4
  "importPath": "@godxjp/ui/data-display",
5
5
  "name": "Progress",
@@ -15,6 +15,16 @@
15
15
  "name": "segments",
16
16
  "type": "{ value: number; tone: \"success\" | \"warning\" | \"destructive\"; label: string }[]"
17
17
  },
18
+ {
19
+ "description": "BREAKDOWN mode: the WHOLE the slices are drawn against, in the same unit as their values. Omit it and the whole is the sum of the slices (the bar is always full). Pass it when part of the whole has no state yet — 3 passed of 400 test cases — and the rest stays the neutral TRACK, the antd `percent` model where the unfilled track is the remainder. The remainder is spoken in the role=\"img\" name, Intl-formatted in the active locale. A total below the slice sum is ignored (the sum wins), so slices never overflow.",
20
+ "name": "total",
21
+ "type": "number"
22
+ },
23
+ {
24
+ "description": "BREAKDOWN mode, with `total`: what the remainder is called in the spoken breakdown (e.g. 未実施). Defaults to the catalogue's Remaining / 残り / Còn lại.",
25
+ "name": "remainderLabel",
26
+ "type": "string"
27
+ },
18
28
  {
19
29
  "description": "Text label beside/below the bar; it also becomes the accessible name. Pass `aria-labelledby` instead when the name is ALREADY on screen (a row's company name, a card heading) — the bar then borrows it rather than repeating it.",
20
30
  "name": "label",
@@ -64,6 +74,7 @@
64
74
  "DON'T pass children or sub-components — Progress is a single self-contained element (track + bar + label). The `label` prop is the only text injection point; don't wrap it in a custom parent div to add a label alongside it.",
65
75
  "DON'T hand-roll a stacked bar out of three divs to show a part-to-whole split — pass `segments`. Hand-rolled slices need a hex fill, an arbitrary height and an arbitrary radius, which ui-audit blocks three ways (no-arbitrary-hex, no-arbitrary-size, no-arbitrary-radius), and they leave the picture with no accessible name at all.",
66
76
  "DON'T convert segment amounts to percentages yourself — pass the raw counts. The component divides by the total, so the slices always sum to the whole; pre-rounded percentages do not.",
77
+ "DO pass `total` when part of the whole has no state yet (a test run: 合格 3 · 失敗 1 of 400) — the rest stays track and is read out as `remainderLabel` (e.g. \"未実施\"). Leaving it out makes 3 passed of 400 fill the whole bar green.",
67
78
  "DO pair a breakdown with `Legend` so each tone is spelled out in words once, instead of repeating the labels on every bar.",
68
79
  "DON'T use Progress for editable numeric input or range selection — it has no callbacks, no interactivity, and no form `name` prop. Use Slider (bounded range input) or Input (free-form number) for data-entry scenarios."
69
80
  ],
@@ -321,6 +321,28 @@
321
321
  "name": "tokenSeparators",
322
322
  "type": "string[]"
323
323
  },
324
+ {
325
+ "defaultValue": "true",
326
+ "description": "mode=\"tags\" — whether typed text may become a NEW value (gh#1052). false, or a predicate returning false for the text, hides the create row and drops unknown tokenSeparators tokens; values already held stay listed so they can be removed. Not an antd prop.",
327
+ "name": "allowCreate",
328
+ "type": "boolean | ((text: string) => boolean)"
329
+ },
330
+ {
331
+ "description": "mode=\"tags\" — the create row's content (gh#1052). Default is the localised Create “text” / 「text」を作成 / Tạo “text”. The committed value is the typed text either way. antd shows the bare text instead — a documented deviation.",
332
+ "name": "createLabel",
333
+ "type": "(text: string) => React.ReactNode"
334
+ },
335
+ {
336
+ "description": "mode=\"tags\" — fires when a value that NO option carries joins the selection (create row, Enter on it, or a tokenSeparators run), beside onSelect/onValueChange. The way to tell invented text from an option id. Not an antd prop.",
337
+ "name": "onCreate",
338
+ "type": "(text: string) => void"
339
+ },
340
+ {
341
+ "defaultValue": "false",
342
+ "description": "Compare typed text case-sensitively (gh#1053). Default false: the built-in filter, the tags create row and a tokenSeparators run all case-fold, so typing \"bug\" when \"Bug\" exists finds Bug instead of offering a duplicate. antd folds its filter but compares the create row exactly; true restores that. A custom filterOption is unaffected.",
343
+ "name": "caseSensitive",
344
+ "type": "boolean"
345
+ },
324
346
  {
325
347
  "description": "antd `maxTagTextLength` (multiple/tags) — cut each chip's TEXT to this many characters (an ellipsis marks the cut). The value keeps its whole label.",
326
348
  "name": "maxTagTextLength",
@@ -132,7 +132,7 @@
132
132
  "type": "boolean | { text, editing, icon, tooltip, onStart, onChange, onCancel, onEnd, maxLength, autoSize, triggerType, enterIcon, tabIndex }"
133
133
  },
134
134
  {
135
- "description": "Single-line truncation, antd's spelling. antd drops `rows` / `expandable` / `onExpand` on `Text` — an inline run has no second line to expand into — and that omission is ported; reach for `Paragraph` when you want them. It is the SAME axis as `truncate` / `clamp` and OUTRANKS both (dev builds warn), because it is the only spelling that can also carry a suffix or a tooltip.",
135
+ "description": "Single-line truncation, antd's spelling. antd drops `rows` / `expandable` / `onExpand` on `Text` — an inline run has no second line to expand into — and that omission is ported; reach for `Paragraph` when you want them. It is the SAME axis as `truncate` / `clamp` and OUTRANKS both (dev builds warn), because it is the only spelling that can also carry a suffix or a tooltip. `tooltip: true` (the children) or a node shows the full text in a Tooltip ONLY while the run is actually clipped — on pointer hover, and on keyboard focus of the Text itself (`asChild` link) or of the nearest focusable control around it (a Tree `treeitem`, a DataTable sort button, a link); the Text never becomes a tab stop of its own and its accessible name stays the full text. With `asChild` the child element is the truncated box (one `<a>`, not `<a><a>`). A `<Text ellipsis>` in `ColumnDef.header` truncates inside its column like a cell.",
136
136
  "name": "ellipsis",
137
137
  "type": "boolean | { suffix, symbol, defaultExpanded, expanded, onEllipsis, tooltip }"
138
138
  },
@@ -668,7 +668,7 @@
668
668
  "type": "ReactNode"
669
669
  },
670
670
  {
671
- "description": "Ordered trail of { label, to? } segments above the title.",
671
+ "description": "Ordered trail of { label, to?, ellipsis? } segments above the title. `ellipsis: true` on a segment keeps the trail on one line and cuts that label with an ellipsis, the full label in a tooltip on hover and on keyboard focus of the crumb link — same contract as `Breadcrumb` items.",
672
672
  "name": "breadcrumb",
673
673
  "type": "BreadcrumbItemProp[]"
674
674
  },
@@ -2339,7 +2339,7 @@
2339
2339
  "name": "Breadcrumb",
2340
2340
  "props": [
2341
2341
  {
2342
- "description": "Array of { label, to?, menu? } — omit `to` on the last (current) segment. `menu` (Ant Design `BreadcrumbItemType.menu`) hangs a sibling picker off that segment: `{ items: { value, label, to?, disabled? }[], onSelect? }`. The segment then renders as a menu button, not a link — an entry with `to` becomes a real anchor inside the menu while keeping `role=\"menuitem\"`.",
2342
+ "description": "Array of { label, to?, menu?, ellipsis? } — omit `to` on the last (current) segment. `ellipsis` (`boolean | { tooltip?: ReactNode }`, gh#1046; antd Breadcrumb has none, the shape is antd Typography's) keeps the trail on one line and cuts that segment's label with an ellipsis, showing the full label in a tooltip on hover and on keyboard focus of the crumb link; `{ tooltip: false }` drops the tooltip. Link and current segments only. `--breadcrumb-item-max-inline-size` (default `none`) caps such a segment. `menu` (Ant Design `BreadcrumbItemType.menu`) hangs a sibling picker off that segment: `{ items: { value, label, to?, disabled? }[], onSelect? }`. The segment then renders as a menu button, not a link — an entry with `to` becomes a real anchor inside the menu while keeping `role=\"menuitem\"`.",
2343
2343
  "name": "items",
2344
2344
  "required": true,
2345
2345
  "type": "BreadcrumbItemProp[]"
@@ -2744,7 +2744,7 @@
2744
2744
  "type": "boolean | { text, editing, icon, tooltip, onStart, onChange, onCancel, onEnd, maxLength, autoSize, triggerType, enterIcon, tabIndex }"
2745
2745
  },
2746
2746
  {
2747
- "description": "Single-line truncation, antd's spelling. antd drops `rows` / `expandable` / `onExpand` on `Text` — an inline run has no second line to expand into — and that omission is ported; reach for `Paragraph` when you want them. It is the SAME axis as `truncate` / `clamp` and OUTRANKS both (dev builds warn), because it is the only spelling that can also carry a suffix or a tooltip.",
2747
+ "description": "Single-line truncation, antd's spelling. antd drops `rows` / `expandable` / `onExpand` on `Text` — an inline run has no second line to expand into — and that omission is ported; reach for `Paragraph` when you want them. It is the SAME axis as `truncate` / `clamp` and OUTRANKS both (dev builds warn), because it is the only spelling that can also carry a suffix or a tooltip. `tooltip: true` (the children) or a node shows the full text in a Tooltip ONLY while the run is actually clipped — on pointer hover, and on keyboard focus of the Text itself (`asChild` link) or of the nearest focusable control around it (a Tree `treeitem`, a DataTable sort button, a link); the Text never becomes a tab stop of its own and its accessible name stays the full text. With `asChild` the child element is the truncated box (one `<a>`, not `<a><a>`). A `<Text ellipsis>` in `ColumnDef.header` truncates inside its column like a cell.",
2748
2748
  "name": "ellipsis",
2749
2749
  "type": "boolean | { suffix, symbol, defaultExpanded, expanded, onEllipsis, tooltip }"
2750
2750
  },
@@ -4735,7 +4735,7 @@
4735
4735
  ]
4736
4736
  },
4737
4737
  {
4738
- "example": "import { Progress } from \"@godxjp/ui/data-display\";\n\n<Progress value={pct} label={pct + \"% 使用中\"} tone={pct >= 80 ? \"warning\" : \"success\"} />\n<Progress value={252} over label=\"252% 積載\" />\n<Progress\n segments={[\n { value: 2, tone: \"destructive\", label: \"期限超過\" },\n { value: 3, tone: \"warning\", label: \"期限間近\" },\n { value: 12, tone: \"success\", label: \"対応済\" },\n ]}\n aria-labelledby={companyNameId}\n/>",
4738
+ "example": "import { Progress } from \"@godxjp/ui/data-display\";\n\n<Progress value={pct} label={pct + \"% 使用中\"} tone={pct >= 80 ? \"warning\" : \"success\"} />\n<Progress value={252} over label=\"252% 積載\" />\n<Progress\n segments={[\n { value: 2, tone: \"destructive\", label: \"期限超過\" },\n { value: 3, tone: \"warning\", label: \"期限間近\" },\n { value: 12, tone: \"success\", label: \"対応済\" },\n ]}\n aria-labelledby={companyNameId}\n/>\n<Progress\n segments={[\n { value: 3, tone: \"success\", label: \"合格\" },\n { value: 1, tone: \"destructive\", label: \"失敗\" },\n ]}\n total={400}\n remainderLabel=\"未実施\"\n/>",
4739
4739
  "group": "data-display",
4740
4740
  "importPath": "@godxjp/ui/data-display",
4741
4741
  "name": "Progress",
@@ -4751,6 +4751,16 @@
4751
4751
  "name": "segments",
4752
4752
  "type": "{ value: number; tone: \"success\" | \"warning\" | \"destructive\"; label: string }[]"
4753
4753
  },
4754
+ {
4755
+ "description": "BREAKDOWN mode: the WHOLE the slices are drawn against, in the same unit as their values. Omit it and the whole is the sum of the slices (the bar is always full). Pass it when part of the whole has no state yet — 3 passed of 400 test cases — and the rest stays the neutral TRACK, the antd `percent` model where the unfilled track is the remainder. The remainder is spoken in the role=\"img\" name, Intl-formatted in the active locale. A total below the slice sum is ignored (the sum wins), so slices never overflow.",
4756
+ "name": "total",
4757
+ "type": "number"
4758
+ },
4759
+ {
4760
+ "description": "BREAKDOWN mode, with `total`: what the remainder is called in the spoken breakdown (e.g. 未実施). Defaults to the catalogue's Remaining / 残り / Còn lại.",
4761
+ "name": "remainderLabel",
4762
+ "type": "string"
4763
+ },
4754
4764
  {
4755
4765
  "description": "Text label beside/below the bar; it also becomes the accessible name. Pass `aria-labelledby` instead when the name is ALREADY on screen (a row's company name, a card heading) — the bar then borrows it rather than repeating it.",
4756
4766
  "name": "label",
@@ -4800,6 +4810,7 @@
4800
4810
  "DON'T pass children or sub-components — Progress is a single self-contained element (track + bar + label). The `label` prop is the only text injection point; don't wrap it in a custom parent div to add a label alongside it.",
4801
4811
  "DON'T hand-roll a stacked bar out of three divs to show a part-to-whole split — pass `segments`. Hand-rolled slices need a hex fill, an arbitrary height and an arbitrary radius, which ui-audit blocks three ways (no-arbitrary-hex, no-arbitrary-size, no-arbitrary-radius), and they leave the picture with no accessible name at all.",
4802
4812
  "DON'T convert segment amounts to percentages yourself — pass the raw counts. The component divides by the total, so the slices always sum to the whole; pre-rounded percentages do not.",
4813
+ "DO pass `total` when part of the whole has no state yet (a test run: 合格 3 · 失敗 1 of 400) — the rest stays track and is read out as `remainderLabel` (e.g. \"未実施\"). Leaving it out makes 3 passed of 400 fill the whole bar green.",
4803
4814
  "DO pair a breakdown with `Legend` so each tone is spelled out in words once, instead of repeating the labels on every bar.",
4804
4815
  "DON'T use Progress for editable numeric input or range selection — it has no callbacks, no interactivity, and no form `name` prop. Use Slider (bounded range input) or Input (free-form number) for data-entry scenarios."
4805
4816
  ],
@@ -6491,6 +6502,28 @@
6491
6502
  "name": "tokenSeparators",
6492
6503
  "type": "string[]"
6493
6504
  },
6505
+ {
6506
+ "defaultValue": "true",
6507
+ "description": "mode=\"tags\" — whether typed text may become a NEW value (gh#1052). false, or a predicate returning false for the text, hides the create row and drops unknown tokenSeparators tokens; values already held stay listed so they can be removed. Not an antd prop.",
6508
+ "name": "allowCreate",
6509
+ "type": "boolean | ((text: string) => boolean)"
6510
+ },
6511
+ {
6512
+ "description": "mode=\"tags\" — the create row's content (gh#1052). Default is the localised Create “text” / 「text」を作成 / Tạo “text”. The committed value is the typed text either way. antd shows the bare text instead — a documented deviation.",
6513
+ "name": "createLabel",
6514
+ "type": "(text: string) => React.ReactNode"
6515
+ },
6516
+ {
6517
+ "description": "mode=\"tags\" — fires when a value that NO option carries joins the selection (create row, Enter on it, or a tokenSeparators run), beside onSelect/onValueChange. The way to tell invented text from an option id. Not an antd prop.",
6518
+ "name": "onCreate",
6519
+ "type": "(text: string) => void"
6520
+ },
6521
+ {
6522
+ "defaultValue": "false",
6523
+ "description": "Compare typed text case-sensitively (gh#1053). Default false: the built-in filter, the tags create row and a tokenSeparators run all case-fold, so typing \"bug\" when \"Bug\" exists finds Bug instead of offering a duplicate. antd folds its filter but compares the create row exactly; true restores that. A custom filterOption is unaffected.",
6524
+ "name": "caseSensitive",
6525
+ "type": "boolean"
6526
+ },
6494
6527
  {
6495
6528
  "description": "antd `maxTagTextLength` (multiple/tags) — cut each chip's TEXT to this many characters (an ellipsis marks the cut). The value keeps its whole label.",
6496
6529
  "name": "maxTagTextLength",
@@ -9829,7 +9862,7 @@
9829
9862
  ]
9830
9863
  },
9831
9864
  {
9832
- "example": "import { useState } from \"react\";\nimport { ColorPicker, FormField } from \"@godxjp/ui/data-entry\";\n\nexport function BrandColorField() {\n const [color, setColor] = useState(\"#2563eb\");\n\n return (\n <FormField id=\"brand-color\" label=\"Brand color\" className=\"max-w-xs\">\n <ColorPicker\n id=\"brand-color\"\n value={color}\n onValueChange={setColor}\n />\n </FormField>\n );\n}\n\n// Compact swatch-only variant (no hex input)\nexport function SwatchOnly() {\n const [color, setColor] = useState(\"#16a34a\");\n return <ColorPicker value={color} onValueChange={setColor} showHexInput={false} />;\n}\n\n// Disabled state\nexport function DisabledColor() {\n return <ColorPicker value=\"#6b7280\" disabled />;\n}",
9865
+ "example": "import { useState } from \"react\";\nimport { ColorPicker, Form, FormField } from \"@godxjp/ui/data-entry\";\n\nexport function BrandColorField() {\n const [color, setColor] = useState(\"#2563eb\");\n\n return (\n <Form>\n <FormField id=\"brand-color\" label=\"Brand color\">\n <ColorPicker id=\"brand-color\" value={color} onValueChange={setColor} />\n </FormField>\n </Form>\n );\n}\n\n// Compact swatch-only variant (no hex input)\nexport function SwatchOnly() {\n const [color, setColor] = useState(\"#16a34a\");\n return <ColorPicker value={color} onValueChange={setColor} showHexInput={false} />;\n}\n\n// Fixed palette only (gh#1055): tags pick from presets, never free hex\nexport function TagColorField() {\n const [color, setColor] = useState(\"#2563eb\");\n return (\n <Form>\n <FormField id=\"tag-color\" label=\"Tag colour\">\n <ColorPicker\n id=\"tag-color\"\n value={color}\n onValueChange={setColor}\n presets={[{ label: \"Palette\", colors: [\"#dc2626\", \"#16a34a\", \"#2563eb\", \"#9333ea\"] }]}\n panelRender={(_, { components: { Presets } }) => <Presets />}\n />\n </FormField>\n </Form>\n );\n}\n\n// Disabled state\nexport function DisabledColor() {\n return <ColorPicker value=\"#6b7280\" disabled />;\n}",
9833
9866
  "group": "data-entry",
9834
9867
  "importPath": "@godxjp/ui/data-entry",
9835
9868
  "name": "ColorPicker",
@@ -9853,7 +9886,7 @@
9853
9886
  {
9854
9887
  "defaultValue": "undefined",
9855
9888
  "description": "Called with the normalized, validated hex string whenever the user commits a new color — via the native swatch picker or by pressing Enter / blurring the hex input. Not called for invalid hex drafts.",
9856
- "name": "onChange",
9889
+ "name": "onValueChange",
9857
9890
  "type": "(hex: string) => void"
9858
9891
  },
9859
9892
  {
@@ -9881,14 +9914,21 @@
9881
9914
  "type": "string"
9882
9915
  },
9883
9916
  {
9884
- "description": "Fires with the committed hex string.",
9885
- "name": "onValueChange",
9886
- "type": "(value: string) => void"
9917
+ "defaultValue": "undefined",
9918
+ "description": "antd `presets` (gh#1055) — named groups of fixed hex swatches under the picker. Each group is collapsible (`defaultOpen`, default true) and is an APG radio group: one tab stop, arrow keys move and select, each swatch is named by its hex and the one equal to `value` is checked. An empty `colors` shows the localized 'Empty' line. Hex only (#rgb/#rrggbb) — antd also accepts colour objects and gradients, which this picker has no model for.",
9919
+ "name": "presets",
9920
+ "type": "{ label: ReactNode; colors: string[]; defaultOpen?: boolean; key?: Key }[]"
9921
+ },
9922
+ {
9923
+ "defaultValue": "undefined",
9924
+ "description": "antd `panelRender` — replaces the picker body. `panel` is the default (swatch + hex row, then presets). PRESETS-ONLY mode (a fixed palette, no free hex): `panelRender={(_, { components: { Presets } }) => <Presets />}`. The hidden `name` input always renders outside the panel.",
9925
+ "name": "panelRender",
9926
+ "type": "(panel: ReactNode, extra: { components: { Picker: FC; Presets: FC } }) => ReactNode"
9887
9927
  }
9888
9928
  ],
9889
9929
  "related": [
9890
9930
  "Input — use for plain text/number entry; use ColorPicker when the value is specifically a color hex code and you want a visual swatch.",
9891
- "Select / SearchSelect — use for choosing from a fixed palette of named colors (e.g. 'Red', 'Blue'); use ColorPicker for freeform hex color entry."
9931
+ "Select / SearchSelect — use for choosing from a list of colour NAMES (e.g. 'Red', 'Blue'); for a fixed palette of visible swatches use ColorPicker `presets` (presets-only via `panelRender`)."
9892
9932
  ],
9893
9933
  "rules": [
9894
9934
  2,
@@ -9900,10 +9940,11 @@
9900
9940
  "tagline": "Native color-swatch picker with an optional editable hex input — always pass a valid 3- or 6-digit hex `value`; invalid hex is silently ignored and the previous value is restored.",
9901
9941
  "usage": [
9902
9942
  "DO wrap in FormField when a label or validation message is needed — pass the same id to both FormField and ColorPicker so htmlFor wires up correctly: `<FormField id='brand' label='Brand color'><ColorPicker id='brand' value={v} onValueChange={setV} /></FormField>`.",
9903
- "DO use controlled mode (value + onChange) — there is no defaultValue/uncontrolled path; always supply value.",
9943
+ "Use it controlled (value + onValueChange) or uncontrolled (defaultValue + onValueChange); both paths commit only validated hex.",
9904
9944
  "DON'T pass an invalid or empty string to value — the component will flash the invalid color on the preview swatch. Always initialize state to a valid 3- or 6-digit hex (e.g. '#2563eb').",
9905
- "The hex Input is a live draft field — onChange is NOT called until the user presses Enter or blurs; only then is the value validated and the parent notified. Do not rely on onChange firing on every keystroke.",
9945
+ "The hex Input is a live draft field — onValueChange is NOT called until the user presses Enter or blurs; only then is the value validated and the parent notified. Do not rely on onValueChange firing on every keystroke.",
9906
9946
  "Set showHexInput={false} only for compact/inline contexts (icon pickers, table cells) where space is tight and keyboard hex entry is not needed.",
9947
+ "DO use `presets` when the value must come from a fixed palette (tag / label colours) — add `panelRender={(_, { components: { Presets } }) => <Presets />}` to remove free hex entry entirely. NEVER rebuild a palette from a ToggleGroup of swatches.",
9907
9948
  "NEVER hand-roll a color picker with raw <input type='color'> — always use this component; it normalizes hex, debounces draft state, and respects the design-token control styles."
9908
9949
  ],
9909
9950
  "useCases": [
package/agent/index.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "components": 177,
5
5
  "patterns": 21,
6
6
  "rules": 50,
7
- "tokens": 2099,
7
+ "tokens": 2104,
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.6.0/agent/index.json"
51
+ "pinned": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/v31.8.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",
55
55
  "tokenTiers": {
56
56
  "component": "per-part knobs, --{component}-{part}-{property}; usually leave these alone",
57
57
  "counts": {
58
- "component": 1784,
58
+ "component": 1789,
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.6.0"
65
+ "version": "31.8.0"
66
66
  }
package/agent/llms.txt CHANGED
@@ -1,10 +1,10 @@
1
1
  # @godxjp/ui
2
2
 
3
- > A Japanese-enterprise React design system: 177 components, 2099 design tokens,
4
- > 50 cardinal rules. This file is the entry point for AI agents. Catalog version 31.6.0.
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.8.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.6.0`). It is searchable and version-locked. These files exist for agents
7
+ (`npx @godxjp/ui-mcp@31.8.0`). 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): 47 KB — all 177 components as name, group, tagline, plus `absorbed`: the names that do NOT exist and map to it (`Combobox` → `Select`).
19
19
  - [components/&lt;Name&gt;.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, 1784 `component` knobs.
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, 1789 `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.6.0/agent/...`. A catalog that does not match the installed
29
+ the tag: `.../godx-jp/godxjp-ui/v31.8.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
@@ -3647,6 +3647,24 @@
3647
3647
  "tier": "component",
3648
3648
  "value": "6.5rem"
3649
3649
  },
3650
+ {
3651
+ "description": "ColorPicker `presets` (gh#1055). The swatch box IS the radio's pointer target, so it sits on the WCAG 2.2 SC 2.5.8 floor (antd's own preset block is 24px too) and never rides --scaling below it. The gap leaves room for the checked ring, which is drawn outside the box.",
3652
+ "name": "--color-picker-preset-size",
3653
+ "tier": "component",
3654
+ "value": "var(--touch-target-min)"
3655
+ },
3656
+ {
3657
+ "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
3658
+ "name": "--color-picker-preset-gap",
3659
+ "tier": "component",
3660
+ "value": "var(--space-2)"
3661
+ },
3662
+ {
3663
+ "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
3664
+ "name": "--color-picker-presets-gap",
3665
+ "tier": "component",
3666
+ "value": "var(--space-1)"
3667
+ },
3650
3668
  {
3651
3669
  "description": "Command / CommandPalette — list height, inner paddings and the palette's own box.",
3652
3670
  "name": "--command-list-max-height",
@@ -3773,6 +3791,12 @@
3773
3791
  "tier": "component",
3774
3792
  "value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
3775
3793
  },
3794
+ {
3795
+ "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
3796
+ "name": "--color-picker-presets-font-size",
3797
+ "tier": "component",
3798
+ "value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
3799
+ },
3776
3800
  {
3777
3801
  "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
3778
3802
  "name": "--command-group-heading-font-size",
@@ -8417,6 +8441,12 @@
8417
8441
  "tier": "component",
8418
8442
  "value": "var(--space-inline-xs)"
8419
8443
  },
8444
+ {
8445
+ "description": "`BreadcrumbItemProp.ellipsis` (gh#1046) — the widest a truncating crumb may grow. `none` = it only cuts when the one-line trail runs out of room; a theme may cap it (e.g. `16em`).",
8446
+ "name": "--breadcrumb-item-max-inline-size",
8447
+ "tier": "component",
8448
+ "value": "none"
8449
+ },
8420
8450
  {
8421
8451
  "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
8422
8452
  "name": "--menu-shortcut-font-size",
@@ -89,6 +89,22 @@ type ProgressMeterProps = ProgressBase & {
89
89
  */
90
90
  type ProgressBreakdownProps = ProgressBase & {
91
91
  segments: ProgressSegment[];
92
+ /**
93
+ * The WHOLE the slices are drawn against, in the same unit as their `value`s. Omit it and the
94
+ * whole is the sum of the slices (the bar is always full). Pass it when part of the whole has
95
+ * no state yet — 3 passed of 400 test cases — and the rest stays the TRACK, exactly as antd's
96
+ * `percent` leaves the unfilled track as the remainder of 100. A `total` below the sum is
97
+ * ignored (the sum wins), so the slices never overflow the bar.
98
+ *
99
+ * The remainder is spoken as part of the `role="img"` name, Intl-formatted in the active
100
+ * locale, under `remainderLabel`.
101
+ */
102
+ total?: number;
103
+ /**
104
+ * What the remainder is called in the spoken breakdown (e.g. `未実施`). Defaults to the
105
+ * catalogue's "Remaining" / 残り / Còn lại. Only read when `total` is set.
106
+ */
107
+ remainderLabel?: string;
92
108
  value?: never;
93
109
  tone?: never;
94
110
  over?: never;
@@ -2,18 +2,21 @@
2
2
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
4
  import { useTranslation } from "../../i18n/use-translation.js";
5
+ import { numberFormat } from "../../lib/intl-cache.js";
5
6
  import { cn } from "../../lib/utils.js";
6
7
  const RING_BOX = 40;
7
8
  const RING_CENTRE = RING_BOX / 2;
8
9
  const RING_RADIUS = 16;
9
10
  const RING_ROTATION = `rotate(-90 ${RING_CENTRE} ${RING_CENTRE})`;
10
11
  function Progress(props) {
11
- const { t } = useTranslation();
12
+ const { t, locale } = useTranslation();
12
13
  const labelId = React.useId();
13
14
  const {
14
15
  label,
15
16
  className,
16
17
  segments,
18
+ total: wholeTotal,
19
+ remainderLabel,
17
20
  value,
18
21
  tone,
19
22
  size,
@@ -28,9 +31,20 @@ function Progress(props) {
28
31
  const caption = label !== void 0 ? /* @__PURE__ */ jsx("div", { className: "ui-progress-label", id: labelId, children: label }) : null;
29
32
  if (segments !== void 0) {
30
33
  const amounts = segments.map((segment) => Math.max(0, segment.value));
31
- const total = amounts.reduce((sum, amount) => sum + amount, 0);
34
+ const sliceSum = amounts.reduce((sum, amount) => sum + amount, 0);
35
+ const hasWhole = wholeTotal !== void 0;
36
+ const total = hasWhole ? Math.max(sliceSum, wholeTotal) : sliceSum;
37
+ const formatAmount = hasWhole ? (amount) => numberFormat(locale).format(amount) : (amount) => String(amount);
32
38
  const separator = t("dataDisplay.progress.breakdownSeparator");
33
- const spoken = segments.map((segment, index) => `${segment.label} ${amounts[index]}`).join(separator);
39
+ const parts = segments.map(
40
+ (segment, index) => `${segment.label} ${formatAmount(amounts[index])}`
41
+ );
42
+ if (hasWhole) {
43
+ parts.push(
44
+ `${remainderLabel ?? t("dataDisplay.progress.remainder")} ${formatAmount(total - sliceSum)}`
45
+ );
46
+ }
47
+ const spoken = parts.join(separator);
34
48
  return /* @__PURE__ */ jsxs(
35
49
  "div",
36
50
  {
@@ -9,6 +9,7 @@ import { omitFieldA11y, pickFieldA11y, useFieldIdentity } from "../../lib/field-
9
9
  import { Button } from "../general/button.js";
10
10
  import { Textarea } from "./textarea.js";
11
11
  import { controlSurfaceAttrs, resolveAriaInvalid } from "./control-surface.js";
12
+ import { isImeComposing } from "../../lib/ime.js";
12
13
  function isSendable(text) {
13
14
  return text.trim().length > 0;
14
15
  }
@@ -70,9 +71,7 @@ const ChatComposer = React.forwardRef(
70
71
  onKeyDown?.(event);
71
72
  if (event.defaultPrevented) return;
72
73
  if (event.key !== "Enter") return;
73
- if (composing.current || event.nativeEvent.isComposing || event.nativeEvent.keyCode === 229) {
74
- return;
75
- }
74
+ if (composing.current || isImeComposing(event)) return;
76
75
  const wantsSend = submitType === "modEnter" ? (
77
76
  // ⌘ on Apple platforms, Ctrl everywhere else — the other one is left alone, because
78
77
  // Ctrl+Enter on a Mac is not the convention a Mac user reaches for.
@@ -85,7 +84,15 @@ const ChatComposer = React.forwardRef(
85
84
  const sendName = submitLabel ?? t("dataEntry.chatComposer.send");
86
85
  const cancelName = cancelLabel ?? t("dataEntry.chatComposer.cancel");
87
86
  const actionSize = size === "xs" ? "icon-xs" : size === "sm" ? "icon-sm" : size === "lg" ? "icon-lg" : "icon";
88
- const liveRef = React.useRef({ actionSize, sendName, cancelName, submit, onCancel, canSubmit, disabled });
87
+ const liveRef = React.useRef({
88
+ actionSize,
89
+ sendName,
90
+ cancelName,
91
+ submit,
92
+ onCancel,
93
+ canSubmit,
94
+ disabled
95
+ });
89
96
  liveRef.current = { actionSize, sendName, cancelName, submit, onCancel, canSubmit, disabled };
90
97
  const SubmitButton = React.useMemo(
91
98
  () => function SubmitButton2(buttonProps) {
@@ -6,6 +6,7 @@ import { cn } from "../../lib/utils.js";
6
6
  import { VisuallyHidden } from "../general/visually-hidden.js";
7
7
  import { Popover, PopoverAnchor, PopoverContent } from "../data-display/popover.js";
8
8
  import { Command, CommandEmpty, CommandItem, CommandList } from "./command.js";
9
+ import { isImeComposing } from "../../lib/ime.js";
9
10
  function matchTrigger(text, caret, trigger) {
10
11
  if (!trigger) return null;
11
12
  const before = text.slice(0, caret);
@@ -154,6 +155,7 @@ function ChatSuggestion({
154
155
  );
155
156
  const onKeyDown = React.useCallback(
156
157
  (event) => {
158
+ if (isImeComposing(event)) return;
157
159
  if (!openRef.current) {
158
160
  if (event.key.startsWith("Arrow") || event.key === "Home" || event.key === "End") {
159
161
  window.setTimeout(evaluate, 0);
@@ -1,4 +1,4 @@
1
1
  import * as React from "react";
2
2
  import type { ColorPickerProp } from "../../props/components/data-entry.prop.js";
3
- export type { ColorPickerProp, ColorPickerProp as ColorPickerProps, } from "../../props/components/data-entry.prop.js";
4
- export declare function ColorPicker({ value: valueProp, defaultValue, onValueChange, disabled, name, className, id, showHexInput, ...ariaProps }: ColorPickerProp): React.JSX.Element;
3
+ export type { ColorPickerProp, ColorPickerProp as ColorPickerProps, ColorPickerPresetProp, ColorPickerPresetProp as ColorPickerPresetProps, } from "../../props/components/data-entry.prop.js";
4
+ export declare function ColorPicker({ value: valueProp, defaultValue, onValueChange, disabled, name, className, id, showHexInput, presets, panelRender, ...ariaProps }: ColorPickerProp): React.JSX.Element;