@godxjp/ui 23.2.1 → 23.4.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 (101) hide show
  1. package/dist/app/timezones.js +2 -1
  2. package/dist/components/charts/chart-cartesian.js +2 -4
  3. package/dist/components/charts/chart-frame.js +2 -1
  4. package/dist/components/data-display/card.d.ts +87 -1
  5. package/dist/components/data-display/card.js +88 -15
  6. package/dist/components/data-display/index.d.ts +5 -1
  7. package/dist/components/data-display/index.js +5 -0
  8. package/dist/components/data-display/thought-chain.d.ts +42 -0
  9. package/dist/components/data-display/thought-chain.js +177 -0
  10. package/dist/components/data-display/welcome.d.ts +26 -0
  11. package/dist/components/data-display/welcome.js +37 -0
  12. package/dist/components/data-entry/attachments.d.ts +19 -0
  13. package/dist/components/data-entry/attachments.js +322 -0
  14. package/dist/components/data-entry/date-picker.js +12 -14
  15. package/dist/components/data-entry/index.d.ts +2 -0
  16. package/dist/components/data-entry/index.js +2 -0
  17. package/dist/components/data-entry/number-input.js +2 -1
  18. package/dist/components/feedback/dialog.d.ts +10 -7
  19. package/dist/components/feedback/dialog.js +40 -17
  20. package/dist/components/feedback/index.d.ts +3 -3
  21. package/dist/components/feedback/index.js +2 -0
  22. package/dist/components/feedback/skeleton.d.ts +11 -2
  23. package/dist/components/feedback/skeleton.js +8 -0
  24. package/dist/components/general/actions.d.ts +59 -0
  25. package/dist/components/general/actions.js +253 -0
  26. package/dist/components/general/activity.js +1 -0
  27. package/dist/components/general/button.js +2 -1
  28. package/dist/components/general/float-button.d.ts +41 -0
  29. package/dist/components/general/float-button.js +336 -0
  30. package/dist/components/general/index.d.ts +6 -2
  31. package/dist/components/general/index.js +12 -1
  32. package/dist/components/general/typography.d.ts +79 -4
  33. package/dist/components/general/typography.js +598 -54
  34. package/dist/components/layout/draggable-panel.d.ts +18 -0
  35. package/dist/components/layout/draggable-panel.js +189 -0
  36. package/dist/components/layout/error-surface.js +3 -2
  37. package/dist/components/layout/index.d.ts +2 -0
  38. package/dist/components/layout/index.js +2 -0
  39. package/dist/components/navigation/conversations.d.ts +39 -0
  40. package/dist/components/navigation/conversations.js +371 -0
  41. package/dist/components/navigation/index.d.ts +2 -0
  42. package/dist/components/navigation/index.js +2 -0
  43. package/dist/components/ui/card.js +1 -0
  44. package/dist/components/ui/toggle.js +2 -1
  45. package/dist/i18n/messages/en.json +53 -0
  46. package/dist/i18n/messages/ja.json +53 -0
  47. package/dist/i18n/messages/vi.json +53 -0
  48. package/dist/i18n/translate.js +3 -2
  49. package/dist/lib/datetime/picker-format.js +2 -1
  50. package/dist/lib/format.js +3 -2
  51. package/dist/lib/intl-cache.d.ts +32 -0
  52. package/dist/lib/intl-cache.js +29 -0
  53. package/dist/props/components/data-display.prop.d.ts +143 -1
  54. package/dist/props/components/data-entry.prop.d.ts +87 -0
  55. package/dist/props/components/feedback.prop.d.ts +53 -1
  56. package/dist/props/components/general.prop.d.ts +440 -3
  57. package/dist/props/components/index.d.ts +2 -2
  58. package/dist/props/components/layout.prop.d.ts +63 -1
  59. package/dist/props/components/navigation.prop.d.ts +150 -0
  60. package/dist/props/registry.d.ts +431 -0
  61. package/dist/props/registry.js +551 -0
  62. package/dist/props/vocabulary/index.d.ts +1 -1
  63. package/dist/props/vocabulary/interaction.prop.d.ts +113 -0
  64. package/dist/styles/alert-layout.css +22 -0
  65. package/dist/styles/card-layout.css +34 -0
  66. package/dist/styles/core.css +1 -0
  67. package/dist/styles/data-display-layout.css +236 -0
  68. package/dist/styles/float-button-layout.css +168 -0
  69. package/dist/styles/form-layout.css +11 -1
  70. package/dist/styles/index.css +1 -0
  71. package/dist/styles/layout.css +196 -0
  72. package/dist/styles/navigation-layout.css +139 -0
  73. package/dist/styles/text-layout.css +156 -0
  74. package/dist/tokens/axes.css +5 -0
  75. package/dist/tokens/base.css +7 -0
  76. package/dist/tokens/components/actions.css +14 -0
  77. package/dist/tokens/components/attachments.css +15 -0
  78. package/dist/tokens/components/conversations.css +28 -0
  79. package/dist/tokens/components/draggable-panel.css +25 -0
  80. package/dist/tokens/components/float-button.css +39 -0
  81. package/dist/tokens/components/text.css +13 -0
  82. package/dist/tokens/components/thought-chain.css +31 -0
  83. package/dist/tokens/components/welcome.css +19 -0
  84. package/dist/tokens/foundation.css +6 -4
  85. package/docs/DESIGN-AUTHORITY.md +133 -20
  86. package/docs/FRAME-COVERAGE-REPORT.md +5 -2
  87. package/docs/data-display/card/examples/tab-list.tsx +97 -0
  88. package/docs/data-display/thought-chain.tsx +176 -0
  89. package/docs/data-display/welcome.tsx +115 -0
  90. package/docs/data-entry/attachments.tsx +160 -0
  91. package/docs/feedback/dialog.tsx +50 -0
  92. package/docs/general/actions.tsx +175 -0
  93. package/docs/general/float-button.tsx +133 -0
  94. package/docs/general/typography.tsx +63 -1
  95. package/docs/layout/draggable-panel.tsx +127 -0
  96. package/docs/navigation/conversations.tsx +176 -0
  97. package/docs/roadmap/parity-audit-layout-navigation-general.md +17 -16
  98. package/package.json +20 -4
  99. package/scripts/_agent-setup.mjs +36 -5
  100. package/scripts/guinea-pig-skill.md +14 -0
  101. package/scripts/ui-audit.mjs +69 -9
@@ -0,0 +1,19 @@
1
+
2
+ :root {
3
+
4
+ --welcome-gap: var(--space-4);
5
+
6
+ --welcome-content-gap: var(--space-1);
7
+
8
+ --welcome-title-gap: var(--space-3);
9
+
10
+ --welcome-padding-block: var(--space-4);
11
+ --welcome-padding-inline: var(--space-4);
12
+ --welcome-radius: var(--radius-lg);
13
+
14
+ --welcome-icon-size: var(--icon-size-xl);
15
+
16
+ --welcome-filled-background: initial;
17
+
18
+ --welcome-filled-border: initial;
19
+ }
@@ -108,9 +108,10 @@
108
108
  transparent 70%
109
109
  );
110
110
 
111
- --focus-outline: 0;
111
+ --focus-outline: 1;
112
112
  --focus-outline-weight: var(--stroke-hairline);
113
113
  --focus-outline-color: var(--focus-ring-color, var(--ring));
114
+
114
115
  --control-outline-width: calc(var(--stroke-md) * var(--focus-outline));
115
116
  --focus-outline-offset: 0px;
116
117
 
@@ -125,7 +126,8 @@
125
126
  --focus-ring-glow-color: var(--control-outline);
126
127
  --focus-ring-glow-alpha: var(--control-outline-alpha);
127
128
 
128
- --focus-field-shadow: none;
129
+ --focus-field-shadow: 0 0 0 var(--focus-ring-glow-width)
130
+ hsl(var(--focus-ring-glow-color) / var(--focus-ring-glow-alpha));
129
131
 
130
132
  --focus-ring-offset: var(--focus-outline-offset);
131
133
 
@@ -179,6 +181,8 @@
179
181
  --heading-h3: var(--font-size-base);
180
182
  --heading-h4: var(--font-size-xs);
181
183
 
184
+ --heading-h5: var(--font-size-2xs);
185
+
182
186
  --font-weight-normal: 400;
183
187
  --font-weight-medium: 500;
184
188
 
@@ -255,7 +259,6 @@
255
259
  --activity-interval: var(--duration-loop);
256
260
 
257
261
  --activity-stagger-step: 160ms;
258
-
259
262
  }
260
263
 
261
264
  .ui-scale-fixed {
@@ -306,7 +309,6 @@
306
309
  --space-chrome-y: var(--space-4);
307
310
  --space-chrome-gap: var(--space-2);
308
311
  --field-label-gap: var(--space-2);
309
-
310
312
  }
311
313
 
312
314
  .dark,
@@ -12,17 +12,17 @@ It changes no code by itself. It is the tie-breaker a reviewer points at.
12
12
 
13
13
  ## The layers, and who owns each
14
14
 
15
- | Layer | Authority | Status in this repo |
16
- | ------------------------------------------------------------------ | --------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
17
- | Interaction semantics, keyboard, ARIA | **WAI-ARIA APG** | already followed — 33 references in `src/` |
18
- | Behaviour primitives | **Radix** | already the implementation — 193 references |
19
- | Component composition shape | **shadcn** | already the structural convention — 23 references |
20
- | Component taxonomy / grouping | **Ant Design** groups | already the catalog shape: `data-entry`, `data-display`, `layout`, `feedback`, `navigation`, `general` — a naming precedent, nothing is installed |
21
- | Colour foundation | **SmartHR** | already the palette source — `--primary` = SmartHR MAIN `#0071bd`, `--foreground` = TEXT_BLACK, `--border` = BORDER |
22
- | **Derived colour — the interaction states hanging off each seed** | **Measured contrast (WCAG 2.2 / JIS X 8341-3)** | Authored in `src/tokens/derived.css`; no algorithm derives them. Four contrast suites read that file and hold every value to a threshold — see below |
23
- | **Japanese UI convention — density, JP typography, form patterns** | **SmartHR** | **NEW — this decision.** Extends SmartHR from "where the colours came from" to the authority for how a JP business screen behaves |
24
- | **Japanese accessibility / public-sector convention** | **デジタル庁 Design System** (Digital Agency) | **NEW — this decision.** The reference when a JP customer asks which standard a screen meets (JIS X 8341-3) |
25
- | **Spacing, density, type scale, information architecture** | **IBM Carbon** | **NEW — this decision** |
15
+ | Layer | Authority | Status in this repo |
16
+ | ------------------------------------------------------------------ | ----------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
17
+ | Interaction semantics, keyboard, ARIA | **WAI-ARIA APG** | already followed — 33 references in `src/` |
18
+ | Behaviour primitives | **Radix** | already the implementation — 193 references |
19
+ | Component composition shape | **shadcn** | already the structural convention — 23 references |
20
+ | Component taxonomy / grouping | **Ant Design** groups | already the catalog shape: `data-entry`, `data-display`, `layout`, `feedback`, `navigation`, `general` — a naming precedent, nothing is installed |
21
+ | Colour foundation | **SmartHR** | already the palette source — `--primary` = SmartHR MAIN `#0071bd`, `--foreground` = TEXT_BLACK, `--border` = BORDER |
22
+ | **Derived colour — the interaction states hanging off each seed** | **Measured contrast (WCAG 2.2 / JIS X 8341-3)** | Authored in `src/tokens/derived.css`; no algorithm derives them. Four contrast suites read that file and hold every value to a threshold — see below |
23
+ | **Japanese UI convention — density, JP typography, form patterns** | **SmartHR** | **NEW — this decision.** Extends SmartHR from "where the colours came from" to the authority for how a JP business screen behaves |
24
+ | **Japanese accessibility / public-sector convention** | **デジタル庁 Design System** (Digital Agency) | **NEW — this decision.** The reference when a JP customer asks which standard a screen meets (JIS X 8341-3) |
25
+ | **Spacing, density, type scale, information architecture** | **IBM Carbon** | **NEW — this decision** |
26
26
 
27
27
  The first five were already true and merely unwritten. The last three are the choices being made
28
28
  here. Carbon fills the one layer that had no outside answer at all: page rhythm, table density, form layout,
@@ -197,10 +197,34 @@ rows or a totals row — which is how a consumer ends up hand-rolling a `<tfoot>
197
197
  in page CSS.
198
198
 
199
199
  **The rule: where antd names a capability, this library takes antd's name and antd's semantics.**
200
- The gap is read out of the INSTALLED types (`antd/es/table/interface.d.ts`,
201
- `antd/es/table/InternalTable.d.ts` and the `@rc-component/table` interface they extend) never
202
- from memory, because antd's own names move between majors (`fixed: 'left'` is deprecated in favour
203
- of `start` inside rc-table itself).
200
+
201
+ > **Restated and widened by the repo owner on 2026-09-12, because the rule above was being read as
202
+ > advice rather than as the standard it is: Ant Design IS the standard. A missing capability is
203
+ > ported from antd 100% FIRST — its names, its props, its semantics — and improved afterwards.
204
+ > Not redesigned first, and not half-ported.**
205
+ >
206
+ > Two things forced the restatement, both measured rather than felt:
207
+ >
208
+ > - `Dialog` + `AlertDialog` ship **26** exports with **12 name-for-name pairs and 0 parts unique
209
+ > to `AlertDialog`**, whose entire difference is `role="alertdialog"` plus `isDismissable={false}`
210
+ > — two props the shell already takes. antd has exactly one `Modal`, where danger is `okType`
211
+ > and `Modal.confirm()`. The shape here came from Radix, silently, against this very rule
212
+ > (gh#567). A package-wide sweep over all 272 public exports found this is the ONLY such pair:
213
+ > `Skeleton.Avatar/Button/Input/Image/Node` looks identical in shape but is antd's own naming,
214
+ > so it is compliance, not drift.
215
+ > - Whole families arrived half-ported: Ant Design X without `Conversations`, `Attachments`,
216
+ > `ThoughtChain`, `Welcome` or `Actions` (gh#559); `FloatButton` never at all (gh#558);
217
+ > `Typography` reduced to `Text` + `Heading`, with `Paragraph`, `Link`, `copyable`, `editable`,
218
+ > `mark`, `keyboard` and `italic` simply absent.
219
+ >
220
+ > A deviation from antd is still allowed — the three below are — but it must be WRITTEN DOWN at
221
+ > the point of deviation. An undocumented deviation is a bug, and gh#567 is what that bug costs:
222
+ > a consumer forced to pick between the right ARIA role and a form it needs, and an accessibility
223
+ > decision pushed onto the party least able to make it.
224
+ > The gap is read out of the INSTALLED types (`antd/es/table/interface.d.ts`,
225
+ > `antd/es/table/InternalTable.d.ts` and the `@rc-component/table` interface they extend) — never
226
+ > from memory, because antd's own names move between majors (`fixed: 'left'` is deprecated in favour
227
+ > of `start` inside rc-table itself).
204
228
 
205
229
  > Đọc sau 20.0.0: bản major ấy đã **gỡ `antd` khỏi devDependencies** cùng máy sinh màu của nó, và
206
230
  > `check:no-antd-runtime` canh cho nó không quay lại. Câu trên mô tả cách bề mặt prop này ĐƯỢC ĐỌC
@@ -224,6 +248,95 @@ of `start` inside rc-table itself).
224
248
  replace the rendered markup. This library answers that layer with tokens (cardinal rule #45), so
225
249
  those are deliberately NOT adopted — adopting them would re-open the hole the token tiers close.
226
250
 
251
+ ## One `Dialog`, not two families — and the rule a consumer picks by
252
+
253
+ **Status:** accepted · 2026-09-12 · gh#567
254
+
255
+ ### The measurement that forced it
256
+
257
+ On `dist/components/feedback/dialog.d.ts` at `23.2.0`, the feedback group published **26** things:
258
+ **14** `Dialog*`, **12** `AlertDialog*`, **12 name-pairs**, **0** parts that only `AlertDialog`
259
+ had, and 2 that only `Dialog` had (`DialogBody`, `DialogClose`). `AlertDialog` carried no part of
260
+ its own; it was a full mirror minus two.
261
+
262
+ The real difference was two internal props on one shared shell — `role` and `isDismissable` — and
263
+ `AlertDialogRoot` is literally that shell with `role="alertdialog"` and `isDismissable={false}`.
264
+ Twelve exports were the price of publishing one ARIA attribute.
265
+
266
+ **A sweep of the whole public surface says this was the only place it happened.** Scanning the 270
267
+ callable exports in `component-api-manifest.json` for a prefixed mirror of another export
268
+ (`Alert*`, `Compact*`, `Simple*`, `Mini*`, `Basic*`, `Confirm*`, `Destructive*`) returns **11
269
+ pairs, all 11 of them this one family**. There is no second drifted pair to find.
270
+
271
+ ### Why antd wins here
272
+
273
+ antd has **one** `Modal`. Danger is a prop — `okType="danger"`, `okButtonProps`, with
274
+ `Modal.confirm()` as the flat preset alongside `info/success/error/warning`. antd has no
275
+ `AlertModal`. The split came from Radix, which ships `@radix-ui/react-dialog` and
276
+ `@radix-ui/react-alert-dialog` as two packages — and this library no longer runs on Radix.
277
+ react-aria-components has a single `Dialog` whose `role` is an ordinary prop, so the shape that
278
+ made two families necessary is gone from the implementation as well as from the authority.
279
+
280
+ ### The decision
281
+
282
+ `Dialog` takes **`variant`** (`"default" | "destructive"`), on the root or on `DialogContent`, and
283
+ that one prop decides three things that always travel together in practice:
284
+
285
+ | `variant` | ARIA role | outside click | primary action |
286
+ | --------------------- | ------------- | ------------- | --------------------------------------------- |
287
+ | `"default"` (default) | `dialog` | dismisses | default emphasis |
288
+ | `"destructive"` | `alertdialog` | ignored | destructive emphasis (antd `okType="danger"`) |
289
+
290
+ The 12 `AlertDialog*` exports **stay and keep working unchanged**. Deleting them is a breaking
291
+ change and belongs in a major; nothing here retints or re-roles an existing tree, because the new
292
+ prop defaults to `"default"` and no existing `AlertDialog*` call site passes it.
293
+
294
+ ### The rule for choosing — answer these in order
295
+
296
+ 1. **Is it dangerous or irreversible?** No → plain `Dialog`, no `variant`. Yes → keep going.
297
+ 2. **Does the flat preset cover it?** Title, description, confirm/cancel labels, an optional typed
298
+ challenge, an optional step-up re-auth, a pending state, and nothing else in the body → use the
299
+ `AlertDialog` **preset**. It is one element and it already forces the destructive tone.
300
+ 3. **Does the body need anything else** — a required reason field, a summary table, a diff, a
301
+ nested list? → `Dialog` with `variant="destructive"`. You get `role="alertdialog"` and the
302
+ non-dismissable scrim, plus `DialogBody` and `DialogClose`, which the `AlertDialog*` family
303
+ never had.
304
+ 4. **Are you writing new code with the `AlertDialog*` compound parts?** Don't. They are the legacy
305
+ spelling of step 3. Existing code stays valid.
306
+
307
+ That third row is the reported case: a destructive confirmation with a **required free-text reason**
308
+ that still has to be announced as an alert dialog. Before this, `Dialog` gave the form and lost the
309
+ role, `AlertDialog` gave the role and forced the footer to be rebuilt, and either way it was a
310
+ rewrite rather than a prop.
311
+
312
+ ### Four places this deliberately departs from the issue's proposal
313
+
314
+ 1. **The prop is `variant`, not `severity`.** antd has no name for a one-knob-three-effects switch,
315
+ so there is nothing to port verbatim. But the axis already exists here as `ConfirmVariantProp`
316
+ and the `AlertDialog` preset already spells it `variant` — and "this library's controlled
317
+ vocabulary wins on values" is the rule two sections up. `check:prop-vocabulary` maps a field
318
+ named `variant` to a `*VariantProp` type for exactly this reason.
319
+ 2. **Escape still closes a `destructive` dialog.** The issue wanted the prop to govern Escape too.
320
+ It does not, because Escape-closes-an-alertdialog is the behaviour the 12 existing exports have
321
+ today, with a test measuring it (`dialog-alert-primitives.test.tsx` · "closes on Escape and
322
+ restores focus"). Making the new prop disable Escape would make `variant="destructive"` differ
323
+ from `AlertDialogContent`, which is the one thing it must not do. antd agrees: `keyboard`
324
+ defaults to `true`. The prop governs the outside click; `maskClosable` is antd's name for that
325
+ same switch.
326
+ 3. **The corner ✕ defaults off under `destructive`.** It is a fourth effect, and it follows from
327
+ the second: a ✕ is an accidental-dismiss affordance like the scrim. It keeps
328
+ `DialogContent variant="destructive"` byte-identical to `AlertDialogContent`, and
329
+ `showCloseButton` still overrides it either way.
330
+ 4. **The header band tone is NOT forced.** `DialogHeader tone` is a separate published axis with
331
+ seven values; the preset is where a destructive tone is imposed on both the band and the button
332
+ at once. Forcing it from `variant` would put two props on the same pixel.
333
+
334
+ ### And the `Sheet` question in the same issue
335
+
336
+ Asked, measured, no change. antd keeps `Drawer` and `Modal` as two components and splits them by
337
+ **where the surface comes from**, not by danger — which is exactly the `Sheet` / `Dialog` boundary
338
+ here. That pair never drifted from the authority, so there is nothing to merge.
339
+
227
340
  ## Derived colour is AUTHORED, and MEASUREMENT is what makes it authoritative
228
341
 
229
342
  **Twenty values, in `src/tokens/derived.css`:** `--primary-hover`, `--primary-active`,
@@ -240,12 +353,12 @@ to trust them had to.
240
353
  **The authority is now the measurement, not the derivation.** Four suites read `derived.css`
241
354
  directly and hold every value in it to a threshold this repo has already committed to:
242
355
 
243
- | suite | what it holds |
244
- | ------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
356
+ | suite | what it holds |
357
+ | -------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
245
358
  | `src/tokens/__tests__/focus-ring-contrast.test.ts` | the focus mark in both switch positions — ≥3:1 (WCAG 2.2 SC 1.4.11) on every surface a control sits on, and the halo proven to be decoration rather than the indicator |
246
- | `src/tokens/__tests__/interactive-fill-contrast.test.ts` | an interactive fill must clear **4.5:1** against the label sitting on it |
247
- | `src/tokens/__tests__/destructive-contrast.test.ts` | `--destructive-hover` / `--destructive-active` against the same bar |
248
- | `src/lib/__tests__/theme-tokens-css.test.ts` | the tier is actually loaded, and complete in both themes |
359
+ | `src/tokens/__tests__/interactive-fill-contrast.test.ts` | an interactive fill must clear **4.5:1** against the label sitting on it |
360
+ | `src/tokens/__tests__/destructive-contrast.test.ts` | `--destructive-hover` / `--destructive-active` against the same bar |
361
+ | `src/lib/__tests__/theme-tokens-css.test.ts` | the tier is actually loaded, and complete in both themes |
249
362
 
250
363
  The first three also pin each value as a literal, so an edit to `derived.css` alone turns CI red
251
364
  rather than quietly retinting the library. **That is a stronger claim than the generator made, not
@@ -3,8 +3,8 @@
3
3
  > Generated by `scripts/frame-coverage.mjs` (issue #163). Do not edit by hand — run `pnpm check:frame-coverage`.
4
4
  > Standard: [FRAME-COVERAGE-STANDARD.md](./FRAME-COVERAGE-STANDARD.md). A missing dimension is **UNTESTED**, never a pass.
5
5
 
6
- - Public components: **150**
7
- - With ≥1 frame: **134** · zero-frame: **16**
6
+ - Public components: **152**
7
+ - With ≥1 frame: **135** · zero-frame: **17**
8
8
  - Fully covered (every contract axis declared): **0**
9
9
 
10
10
  ## UNTESTED — no `/frame/**` route
@@ -22,6 +22,7 @@
22
22
  - [ ] `SkeletonAvatar`
23
23
  - [ ] `SkeletonButton`
24
24
  - [ ] `SkeletonInput`
25
+ - [ ] `SkeletonForm`
25
26
  - [ ] `SkeletonNode`
26
27
  - [ ] `SkeletonImage`
27
28
  - [ ] `ChatBubbleList`
@@ -57,6 +58,7 @@ Legend: ✓ covered · N/A reasoned skip · · UNTESTED (blank cell = UNTESTED).
57
58
  | ErrorSurface | ✓ | ✓ | N/A | N/A | · | · | · | · | · | · |
58
59
  | LegalDocumentShell | ✓ | N/A | N/A | N/A | · | · | · | · | · | · |
59
60
  | Breadcrumb | ✓ | N/A | N/A | N/A | · | · | · | · | · | · |
61
+ | FloatButton | ✓ | · | · | · | · | · | · | · | · | · |
60
62
  | Button | ✓ | ✓ | · | · | · | · | · | · | · | · |
61
63
  | Text | ✓ | ✓ | N/A | N/A | · | · | · | · | · | · |
62
64
  | Heading | ✓ | ✓ | N/A | N/A | · | · | · | · | · | · |
@@ -141,6 +143,7 @@ Legend: ✓ covered · N/A reasoned skip · · UNTESTED (blank cell = UNTESTED).
141
143
  | SkeletonAvatar | **✗** | ✓ | N/A | N/A | · | · | · | · | · | · |
142
144
  | SkeletonButton | **✗** | ✓ | N/A | N/A | · | · | · | · | · | · |
143
145
  | SkeletonInput | **✗** | ✓ | N/A | N/A | · | · | · | · | · | · |
146
+ | SkeletonForm | **✗** | N/A | N/A | N/A | · | · | · | · | · | · |
144
147
  | SkeletonNode | **✗** | N/A | N/A | N/A | · | · | · | · | · | · |
145
148
  | SkeletonImage | **✗** | N/A | N/A | N/A | · | · | · | · | · | · |
146
149
  | Toggle | ✓ | ✓ | · | N/A | · | · | · | · | · | · |
@@ -0,0 +1,97 @@
1
+ import { useState } from "react";
2
+
3
+ import {
4
+ Badge,
5
+ Card,
6
+ CardContent,
7
+ CardFooter,
8
+ CardHeader,
9
+ CardTitle,
10
+ DataTable,
11
+ Descriptions,
12
+ type CardTabItemProp,
13
+ } from "@godxjp/ui/data-display";
14
+ import { Button, Text } from "@godxjp/ui/general";
15
+ import { Flex, PageContainer } from "@godxjp/ui/layout";
16
+
17
+ /**
18
+ * Card `tabList` — Ant Design's card-head tab strip.
19
+ *
20
+ * The strip lives INSIDE the card's head: under the title, on the same surface, inside the same
21
+ * border, so the card and its tabs read as one object. The card's children are the selected tab's
22
+ * body — here a `DataTable` in a `CardContent flush`, which is what lets the table reach the card
23
+ * edge instead of sitting in a second, narrower frame.
24
+ *
25
+ * What NOT to reach for instead: a `Tabs` parked on the page above a card (the strip floats off
26
+ * the card and the two read as two objects), or a `Card` repeated inside every tab (the same
27
+ * header and body shell copied once per view).
28
+ */
29
+ const tabList: CardTabItemProp[] = [
30
+ { key: "members", tab: "メンバー" },
31
+ { key: "invitations", tab: "招待" },
32
+ { key: "settings", tab: "設定" },
33
+ ];
34
+
35
+ const members = [
36
+ { id: "1", name: "佐藤 花子", email: "sato@example.co.jp", role: "管理者" },
37
+ { id: "2", name: "鈴木 一郎", email: "suzuki@example.co.jp", role: "編集者" },
38
+ { id: "3", name: "高橋 美咲", email: "takahashi@example.co.jp", role: "閲覧者" },
39
+ ];
40
+
41
+ const invitations = [{ id: "4", name: "田中 健", email: "tanaka@example.co.jp", role: "編集者" }];
42
+
43
+ export default function Demo() {
44
+ const [activeTabKey, setActiveTabKey] = useState("members");
45
+
46
+ return (
47
+ <PageContainer title="組織設定" subtitle="株式会社ベトヤ">
48
+ <Card
49
+ tabList={tabList}
50
+ activeTabKey={activeTabKey}
51
+ onTabChange={setActiveTabKey}
52
+ extra={<Button size="sm">メンバーを招待</Button>}
53
+ >
54
+ <CardHeader>
55
+ <CardTitle level={2}>チーム</CardTitle>
56
+ </CardHeader>
57
+
58
+ {activeTabKey === "settings" ? (
59
+ <CardContent>
60
+ <Descriptions>
61
+ <Descriptions.Item label="組織名">株式会社ベトヤ</Descriptions.Item>
62
+ <Descriptions.Item label="ドメイン">example.co.jp</Descriptions.Item>
63
+ <Descriptions.Item label="既定の権限">閲覧者</Descriptions.Item>
64
+ </Descriptions>
65
+ </CardContent>
66
+ ) : (
67
+ <CardContent flush>
68
+ <DataTable
69
+ data={activeTabKey === "members" ? members : invitations}
70
+ getRowId={(row) => row.id}
71
+ columns={[
72
+ { key: "name", header: "名前" },
73
+ { key: "email", header: "メール" },
74
+ {
75
+ key: "role",
76
+ header: "権限",
77
+ render: (row) => <Badge tone="info">{row.role}</Badge>,
78
+ },
79
+ ]}
80
+ />
81
+ </CardContent>
82
+ )}
83
+
84
+ <CardFooter separated>
85
+ <Flex direction="row" justify="between" align="center" gap="sm">
86
+ <Text tone="muted" size="sm">
87
+ {activeTabKey === "invitations" ? "1件の保留中の招待" : "3名のメンバー"}
88
+ </Text>
89
+ <Button variant="outline" size="sm">
90
+ CSV で書き出す
91
+ </Button>
92
+ </Flex>
93
+ </CardFooter>
94
+ </Card>
95
+ </PageContainer>
96
+ );
97
+ }
@@ -0,0 +1,176 @@
1
+ import { useState } from "react";
2
+
3
+ import { ChatBubble, ThoughtChain, ThoughtChainItem } from "@godxjp/ui/data-display";
4
+ import { Text } from "@godxjp/ui/general";
5
+ import {
6
+ AppShell,
7
+ Flex,
8
+ PageContainer,
9
+ Sidebar,
10
+ type SidebarSectionProp,
11
+ Topbar,
12
+ } from "@godxjp/ui/layout";
13
+ import { Bot, MessageSquare, Search, Settings, Users } from "lucide-react";
14
+
15
+ /**
16
+ * ThoughtChain — the assistant's reasoning, step by step (Ant Design X `ThoughtChain`).
17
+ *
18
+ * Each card is one axis at rest: the chain as it appears above an answer, the four statuses, the
19
+ * three connector strokes, and the standalone `ThoughtChainItem` chip in its three variants.
20
+ *
21
+ * The step that collapses is a real disclosure button, so this page is drivable from the keyboard
22
+ * alone; Ant X's own step is a `<div onClick>`.
23
+ *
24
+ * Composed only from real @godxjp/ui components.
25
+ */
26
+ const sections: SidebarSectionProp[] = [
27
+ {
28
+ label: "アシスタント",
29
+ items: [
30
+ { id: "chat", label: "チャット", icon: MessageSquare },
31
+ { id: "agents", label: "エージェント", icon: Bot },
32
+ { id: "members", label: "メンバー", icon: Users },
33
+ ],
34
+ },
35
+ { label: "管理", items: [{ id: "settings", label: "設定", icon: Settings }] },
36
+ ];
37
+
38
+ export default function ThoughtChainDoc() {
39
+ const [open, setOpen] = useState<string[]>(["search"]);
40
+
41
+ return (
42
+ <AppShell
43
+ sidebar={
44
+ <Sidebar
45
+ activeId="chat"
46
+ sections={sections}
47
+ onSelect={() => {}}
48
+ product={{ name: "CoreDesk", role: "アシスタント", color: "hsl(var(--primary))" }}
49
+ />
50
+ }
51
+ topbar={<Topbar />}
52
+ >
53
+ <PageContainer
54
+ title="思考の手順"
55
+ subtitle="ThoughtChain · 回答の前に何をしたのか。畳める手順は本物の開閉ボタン。"
56
+ >
57
+ {/* IN PLACE: above the answer it explains. */}
58
+ <Flex direction="col" gap="sm">
59
+ <Text size="sm" weight="medium">
60
+ in place · 回答の前
61
+ </Text>
62
+ <ThoughtChain
63
+ label="思考の手順"
64
+ expandedKeys={open}
65
+ onExpand={setOpen}
66
+ items={[
67
+ {
68
+ key: "read",
69
+ title: "添付の請求書を読む",
70
+ description: "3件",
71
+ status: "success",
72
+ },
73
+ {
74
+ key: "search",
75
+ title: "社内規程を検索",
76
+ description: "「支払期日」",
77
+ status: "success",
78
+ collapsible: true,
79
+ content: (
80
+ <Text size="xs" tone="muted">
81
+ 第4章 支払 — 請求書の支払期日は受領月の翌月末日とする。
82
+ </Text>
83
+ ),
84
+ },
85
+ {
86
+ key: "write",
87
+ title: "差分をまとめる",
88
+ status: "loading",
89
+ blink: true,
90
+ },
91
+ ]}
92
+ />
93
+ <ChatBubble placement="start" variant="filled">
94
+ 差分は3件でした。金額、支払期日、宛名のうちどれから直しますか。
95
+ </ChatBubble>
96
+ </Flex>
97
+
98
+ {/* THE FOUR STATUSES. */}
99
+ <Flex direction="col" gap="sm">
100
+ <Text size="sm" weight="medium">
101
+ status · loading · success · error · abort
102
+ </Text>
103
+ <Text size="xs" tone="muted">
104
+ 状態は字にもなる。読み上げでは各手順のあとに「完了」「失敗」などが続く。
105
+ </Text>
106
+ <ThoughtChain
107
+ label="状態の一覧"
108
+ items={[
109
+ { key: "a", title: "実行中の手順", status: "loading" },
110
+ { key: "b", title: "終わった手順", status: "success" },
111
+ { key: "c", title: "失敗した手順", status: "error" },
112
+ { key: "d", title: "中断した手順", status: "abort" },
113
+ ]}
114
+ />
115
+ </Flex>
116
+
117
+ {/* THE CONNECTOR. */}
118
+ <Flex direction="col" gap="sm">
119
+ <Text size="sm" weight="medium">
120
+ line · solid · dashed · none
121
+ </Text>
122
+ <ThoughtChain
123
+ label="実線"
124
+ line="solid"
125
+ items={[
126
+ { key: "a", title: "一歩目" },
127
+ { key: "b", title: "二歩目" },
128
+ ]}
129
+ />
130
+ <ThoughtChain
131
+ label="破線"
132
+ line="dashed"
133
+ items={[
134
+ { key: "a", title: "一歩目" },
135
+ { key: "b", title: "二歩目" },
136
+ ]}
137
+ />
138
+ <ThoughtChain
139
+ label="線なし"
140
+ line={false}
141
+ items={[
142
+ { key: "a", title: "一歩目" },
143
+ { key: "b", title: "二歩目" },
144
+ ]}
145
+ />
146
+ </Flex>
147
+
148
+ {/* THE STANDALONE CHIP. */}
149
+ <Flex direction="col" gap="sm">
150
+ <Text size="sm" weight="medium">
151
+ ThoughtChainItem · solid · outlined · text
152
+ </Text>
153
+ <Text size="xs" tone="muted">
154
+ 押せる手順は本物のボタンとして描かれる。押せないものは div のまま。要素が実体に従う。
155
+ </Text>
156
+ <Flex gap="sm">
157
+ <ThoughtChainItem
158
+ variant="solid"
159
+ icon={<Search />}
160
+ title="社内規程を検索"
161
+ description="3件ヒット"
162
+ status="success"
163
+ />
164
+ <ThoughtChainItem variant="outlined" icon={<Search />} title="再検索" />
165
+ <ThoughtChainItem
166
+ variant="text"
167
+ icon={<Search />}
168
+ title="詳細を見る"
169
+ onClick={() => setOpen(["search"])}
170
+ />
171
+ </Flex>
172
+ </Flex>
173
+ </PageContainer>
174
+ </AppShell>
175
+ );
176
+ }