@godxjp/ui 21.0.0 → 23.0.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 (154) hide show
  1. package/README.md +4 -4
  2. package/dist/app/app-provider.js +2 -1
  3. package/dist/components/data-display/badge.d.ts +28 -1
  4. package/dist/components/data-display/badge.js +2 -0
  5. package/dist/components/data-display/data-table.d.ts +18 -2
  6. package/dist/components/data-display/data-table.js +4 -0
  7. package/dist/components/data-display/index.d.ts +1 -1
  8. package/dist/components/data-display/popover.d.ts +19 -1
  9. package/dist/components/data-display/popover.js +9 -1
  10. package/dist/components/data-display/progress.d.ts +37 -0
  11. package/dist/components/data-display/progress.js +57 -5
  12. package/dist/components/data-display/scroll-area.d.ts +24 -4
  13. package/dist/components/data-display/scroll-area.js +34 -72
  14. package/dist/components/data-entry/cascader.js +8 -6
  15. package/dist/components/data-entry/checkbox.js +2 -0
  16. package/dist/components/data-entry/choice-hit-target.d.ts +24 -0
  17. package/dist/components/data-entry/choice-hit-target.js +12 -0
  18. package/dist/components/data-entry/control-surface.d.ts +8 -0
  19. package/dist/components/data-entry/control-surface.js +10 -1
  20. package/dist/components/data-entry/date-picker.d.ts +10 -3
  21. package/dist/components/data-entry/date-picker.js +503 -238
  22. package/dist/components/data-entry/form-field.d.ts +1 -1
  23. package/dist/components/data-entry/form-field.js +7 -3
  24. package/dist/components/data-entry/form.js +10 -1
  25. package/dist/components/data-entry/index.d.ts +0 -6
  26. package/dist/components/data-entry/index.js +0 -6
  27. package/dist/components/data-entry/label.d.ts +14 -1
  28. package/dist/components/data-entry/label.js +6 -1
  29. package/dist/components/data-entry/radio.d.ts +27 -6
  30. package/dist/components/data-entry/radio.js +89 -43
  31. package/dist/components/data-entry/search-select.js +226 -89
  32. package/dist/components/data-entry/select.d.ts +76 -14
  33. package/dist/components/data-entry/select.js +497 -163
  34. package/dist/components/data-entry/slider.d.ts +3 -11
  35. package/dist/components/data-entry/slider.js +582 -93
  36. package/dist/components/data-entry/switch.d.ts +6 -3
  37. package/dist/components/data-entry/switch.js +36 -11
  38. package/dist/components/layout/mobile-shell.d.ts +1 -1
  39. package/dist/components/layout/mobile-shell.js +2 -0
  40. package/dist/components/navigation/dropdown-menu.d.ts +11 -3
  41. package/dist/components/navigation/dropdown-menu.js +190 -15
  42. package/dist/components/navigation/index.d.ts +0 -3
  43. package/dist/components/navigation/index.js +0 -78
  44. package/dist/components/navigation/steps.d.ts +1 -1
  45. package/dist/components/navigation/steps.js +3 -1
  46. package/dist/components/navigation/tabs-scroll.d.ts +27 -0
  47. package/dist/components/navigation/tabs-scroll.js +52 -1
  48. package/dist/components/navigation/tabs.d.ts +2 -2
  49. package/dist/components/navigation/tabs.js +88 -23
  50. package/dist/components/ui/index.d.ts +0 -4
  51. package/dist/components/ui/index.js +0 -4
  52. package/dist/components/ui/input-otp.d.ts +1 -1
  53. package/dist/components/ui/segmented.d.ts +15 -1
  54. package/dist/components/ui/segmented.js +15 -6
  55. package/dist/components/ui/tag-input.js +3 -5
  56. package/dist/i18n/messages/en.json +3 -2
  57. package/dist/i18n/messages/ja.json +3 -2
  58. package/dist/i18n/messages/vi.json +3 -2
  59. package/dist/lib/datetime/picker-format.d.ts +18 -0
  60. package/dist/lib/datetime/picker-format.js +35 -1
  61. package/dist/lib/field-a11y.d.ts +12 -0
  62. package/dist/lib/field-a11y.js +14 -1
  63. package/dist/lib/select-options.d.ts +21 -0
  64. package/dist/lib/select-options.js +46 -0
  65. package/dist/props/components/data-display.prop.d.ts +16 -6
  66. package/dist/props/components/data-entry.prop.d.ts +503 -129
  67. package/dist/props/components/index.d.ts +2 -2
  68. package/dist/props/components/layout.prop.d.ts +12 -1
  69. package/dist/props/components/navigation.prop.d.ts +93 -1
  70. package/dist/props/registry.d.ts +79 -16
  71. package/dist/props/registry.js +85 -15
  72. package/dist/props/vocabulary/data.prop.d.ts +12 -0
  73. package/dist/props/vocabulary/index.d.ts +2 -2
  74. package/dist/props/vocabulary/layout.prop.d.ts +11 -0
  75. package/dist/styles/badge-layout.css +4 -0
  76. package/dist/styles/card-layout.css +6 -6
  77. package/dist/styles/control.css +220 -29
  78. package/dist/styles/data-display-layout.css +94 -23
  79. package/dist/styles/focus-ring.css +6 -4
  80. package/dist/styles/fonts.css +88 -4
  81. package/dist/styles/navigation-layout.css +36 -236
  82. package/dist/styles/shell-layout.css +149 -139
  83. package/dist/styles/table-layout.css +41 -3
  84. package/dist/tokens/components/control.css +4 -0
  85. package/dist/tokens/components/data-display.css +9 -5
  86. package/dist/tokens/components/navigation.css +9 -5
  87. package/dist/tokens/components/scroll-area.css +7 -0
  88. package/dist/tokens/components/segmented.css +0 -2
  89. package/dist/tokens/components/shell.css +2 -0
  90. package/dist/tokens/components/table.css +3 -0
  91. package/dist/tokens/foundation.css +7 -0
  92. package/docs/COMPONENTS.md +14 -14
  93. package/docs/CONSUMER-RULES.md +24 -1
  94. package/docs/CUSTOMER-THEMING.md +7 -1
  95. package/docs/FRAME-COVERAGE-REPORT.md +5 -11
  96. package/docs/TOKENS.md +65 -0
  97. package/docs/data-display/badge.tsx +37 -0
  98. package/docs/data-display/data-table/index.tsx +45 -1
  99. package/docs/data-display/popover.tsx +43 -5
  100. package/docs/data-display/progress.tsx +28 -0
  101. package/docs/data-display/scroll-area.tsx +51 -45
  102. package/docs/data-entry/calendar.tsx +2 -2
  103. package/docs/data-entry/date-picker.tsx +144 -5
  104. package/docs/data-entry/form/examples/invoice-form.tsx +2 -2
  105. package/docs/data-entry/form-field/examples/a11y-contract.tsx +3 -5
  106. package/docs/data-entry/form.tsx +4 -4
  107. package/docs/data-entry/input-otp.tsx +5 -2
  108. package/docs/data-entry/number-input.tsx +31 -0
  109. package/docs/data-entry/segmented.tsx +143 -2
  110. package/docs/data-entry/select-matrix.tsx +1 -2
  111. package/docs/data-entry/select.tsx +108 -3
  112. package/docs/data-entry/slider.tsx +125 -47
  113. package/docs/feedback/dialog.tsx +1 -2
  114. package/docs/feedback/sheet.tsx +1 -2
  115. package/docs/layout/app-shell-states.tsx +143 -0
  116. package/docs/layout/mobile-shell.tsx +5 -0
  117. package/docs/navigation/dropdown-menu.tsx +75 -4
  118. package/docs/navigation/tabs.tsx +149 -0
  119. package/docs/roadmap/antd-parity.md +35 -34
  120. package/docs/roadmap/parity-audit-data-entry.md +196 -172
  121. package/docs/roadmap/parity-audit-layout-navigation-general.md +304 -310
  122. package/docs/roadmap/parity-backlog.md +8 -10
  123. package/docs/showcase/acme-portal.tsx +7 -0
  124. package/package.json +28 -64
  125. package/scripts/ui-audit.mjs +18 -5
  126. package/scripts/visual-audit-rules.mjs +0 -7
  127. package/scripts/visual-audit.mjs +6 -27
  128. package/dist/components/data-entry/date-range-picker.d.ts +0 -11
  129. package/dist/components/data-entry/date-range-picker.js +0 -349
  130. package/dist/components/data-entry/month-picker.d.ts +0 -10
  131. package/dist/components/data-entry/month-picker.js +0 -241
  132. package/dist/components/data-entry/month-range-picker.d.ts +0 -10
  133. package/dist/components/data-entry/month-range-picker.js +0 -301
  134. package/dist/components/navigation/context-menu.d.ts +0 -21
  135. package/dist/components/navigation/context-menu.js +0 -149
  136. package/dist/components/navigation/menubar.d.ts +0 -21
  137. package/dist/components/navigation/menubar.js +0 -136
  138. package/dist/components/navigation/navigation-menu.d.ts +0 -10
  139. package/dist/components/navigation/navigation-menu.js +0 -91
  140. package/dist/components/ui/context-menu.d.ts +0 -1
  141. package/dist/components/ui/context-menu.js +0 -2
  142. package/dist/components/ui/date-range-picker.d.ts +0 -1
  143. package/dist/components/ui/date-range-picker.js +0 -2
  144. package/dist/components/ui/menubar.d.ts +0 -1
  145. package/dist/components/ui/menubar.js +0 -2
  146. package/dist/components/ui/navigation-menu.d.ts +0 -1
  147. package/dist/components/ui/navigation-menu.js +0 -2
  148. package/docs/FRAME-A11Y-CI.md +0 -349
  149. package/docs/data-entry/date-range-picker.tsx +0 -175
  150. package/docs/data-entry/month-picker.tsx +0 -101
  151. package/docs/data-entry/month-range-picker.tsx +0 -115
  152. package/docs/navigation/context-menu.tsx +0 -128
  153. package/docs/navigation/menubar.tsx +0 -141
  154. package/docs/navigation/navigation-menu.tsx +0 -158
@@ -56,7 +56,13 @@ overwrites `--font-sans-base` (and `--font-sans-vi`) with the bundled stack —
56
56
  Noto Sans JP + Montserrat; v18.12.0–18.12.19 bundled M PLUS 2 + Noto Sans JP;
57
57
  v18.12.20+ bundles Noto Sans JP + M PLUS 2 (product override, direct
58
58
  instruction). If your design spec named an earlier bundle's faces, set the
59
- tokens yourself rather than relying on the bundle.) Headings read
59
+ tokens yourself rather than relying on the bundle.) Second in that stack is
60
+ `"Noto Sans JP Fallback"`: local faces (Arial / Liberation Sans for Latin, the
61
+ platform's gothic face for Japanese) with `size-adjust` and ascent/descent
62
+ overrides tuned to Noto Sans JP. The bundled faces are `font-display: swap`, so
63
+ a cold visit paints in this fallback first; because it occupies the same line
64
+ boxes and nearly the same advances, the swap does not reflow the page (#475).
65
+ If you restate the stack yourself, keep it directly after "Noto Sans JP". Headings read
60
66
  `--font-family-display` and body reads `--font-family-body`, both defaulting to
61
67
  `--font-family-sans` — override them for a dual-font (display + body) brand.
62
68
 
@@ -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: **141**
7
- - With ≥1 frame: **136** · zero-frame: **5**
6
+ - Public components: **135**
7
+ - With ≥1 frame: **130** · zero-frame: **5**
8
8
  - Fully covered (every contract axis declared): **0**
9
9
 
10
10
  ## UNTESTED — no `/frame/**` route
@@ -60,7 +60,7 @@ Legend: ✓ covered · N/A reasoned skip · · UNTESTED (blank cell = UNTESTED).
60
60
  | QrCode | ✓ | ✓ | N/A | · | · | · | · | · | · | · |
61
61
  | Descriptions | ✓ | N/A | N/A | N/A | · | · | · | · | · | · |
62
62
  | EmptyState | ✓ | ✓ | N/A | N/A | · | · | · | · | · | · |
63
- | Progress | ✓ | | N/A | · | · | · | · | · | · | · |
63
+ | Progress | ✓ | · | N/A | · | · | · | · | · | · | · |
64
64
  | CodeBlock | ✓ | · | N/A | N/A | · | · | · | · | · | · |
65
65
  | Prose | ✓ | · | N/A | N/A | · | · | · | · | · | · |
66
66
  | Timeline | ✓ | ✓ | N/A | N/A | · | · | · | · | · | · |
@@ -74,14 +74,12 @@ Legend: ✓ covered · N/A reasoned skip · · UNTESTED (blank cell = UNTESTED).
74
74
  | Input | ✓ | ✓ | · | · | · | · | · | · | · | · |
75
75
  | NumberInput | ✓ | ✓ | · | · | · | · | · | · | · | · |
76
76
  | SearchInput | ✓ | ✓ | · | · | · | · | · | · | · | · |
77
- | Select | ✓ | N/A | · | · | · | · | · | · | · | · |
77
+ | Select | ✓ | · | · | · | · | · | · | · | · | · |
78
78
  | Switch | ✓ | ✓ | · | · | · | · | · | · | · | · |
79
79
  | Textarea | ✓ | ✓ | · | · | · | · | · | · | · | · |
80
80
  | Label | ✓ | N/A | N/A | N/A | · | · | · | · | · | · |
81
81
  | Checkbox | ✓ | N/A | · | · | · | · | · | · | · | · |
82
82
  | RadioGroup | ✓ | N/A | · | · | · | · | · | · | · | · |
83
- | MonthPicker | ✓ | · | · | · | · | · | · | · | · | · |
84
- | MonthRangePicker | ✓ | · | · | · | · | · | · | · | · | · |
85
83
  | DatePicker | ✓ | · | · | · | · | · | · | · | · | · |
86
84
  | Dialog | ✓ | N/A | N/A | · | · | · | · | · | · | · |
87
85
  | AlertDialog | ✓ | ✓ | · | · | · | · | · | · | · | · |
@@ -93,13 +91,12 @@ Legend: ✓ covered · N/A reasoned skip · · UNTESTED (blank cell = UNTESTED).
93
91
  | Toaster | ✓ | N/A | N/A | N/A | · | · | · | · | · | · |
94
92
  | Tabs | ✓ | ✓ | N/A | · | · | · | · | · | · | · |
95
93
  | Pagination | ✓ | · | · | · | · | · | · | · | · | · |
96
- | DropdownMenu | ✓ | N/A | N/A | · | · | · | · | · | · | · |
94
+ | DropdownMenu | ✓ | N/A | · | · | · | · | · | · | · | · |
97
95
  | Steps | ✓ | ✓ | N/A | · | · | · | · | · | · | · |
98
96
  | Toolbar | ✓ | N/A | · | N/A | · | · | · | · | · | · |
99
97
  | AppProvider | ✓ | · | · | · | · | · | · | · | · | · |
100
98
  | formatDate | ✓ | · | · | · | · | · | · | · | · | · |
101
99
  | TimePicker | ✓ | · | · | · | · | · | · | · | · | · |
102
- | DateRangePicker | ✓ | · | · | · | · | · | · | · | · | · |
103
100
  | Cascader | ✓ | ✓ | · | · | · | · | · | · | · | · |
104
101
  | TreeSelect | ✓ | ✓ | · | · | · | · | · | · | · | · |
105
102
  | Transfer | ✓ | N/A | · | · | · | · | · | · | · | · |
@@ -131,9 +128,6 @@ Legend: ✓ covered · N/A reasoned skip · · UNTESTED (blank cell = UNTESTED).
131
128
  | Rating | ✓ | N/A | · | · | · | · | · | · | · | · |
132
129
  | Segmented | ✓ | ✓ | · | · | · | · | · | · | · | · |
133
130
  | TagInput | ✓ | ✓ | · | · | · | · | · | · | · | · |
134
- | ContextMenu | ✓ | N/A | N/A | · | · | · | · | · | · | · |
135
- | Menubar | ✓ | N/A | N/A | · | · | · | · | · | · | · |
136
- | NavigationMenu | ✓ | N/A | N/A | · | · | · | · | · | · | · |
137
131
  | ResizablePanel | ✓ | N/A | · | N/A | · | · | · | · | · | · |
138
132
  | Carousel | ✓ | N/A | N/A | · | · | · | · | · | · | · |
139
133
  | AppSettingPicker | ✓ | N/A | · | · | · | · | · | · | · | · |
package/docs/TOKENS.md CHANGED
@@ -44,6 +44,71 @@ src/styles/
44
44
 
45
45
  Default brand tokens use the GodX Agent Portal palette: navy primary, 朱 orange focus/accent, warm neutral surfaces. App or customer identity colors belong in the consuming app theme, not in package tokens.
46
46
 
47
+ #### The three tone tiers — FILL, TEXT, MARK
48
+
49
+ A status tone can be painted three ways, and each way is judged against a different thing. Reading
50
+ the wrong tier is this palette's most expensive recurring bug, because nothing about it looks wrong
51
+ in the source.
52
+
53
+ | Tier | Tokens | What it paints | Contrast bar |
54
+ | -------- | ------------------------------------------- | ------------------------------------------------------------------ | --------------------------------------------------------- |
55
+ | **FILL** | `--success`, `--warning`, `--info`, `--destructive` | A solid chip, band or bar with a label ON it | AA **4.5:1** against its own `*-foreground` label |
56
+ | **TEXT** | `--text-success`, `--text-warning`, `--text-info`, `--text-error` | Small coloured type — a StatCard delta, an outline badge label | AA **4.5:1** against the surface BEHIND it |
57
+ | **MARK** | `--mark-success`, `--mark-warning`, `--mark-info`, `--mark-destructive`, `--mark-primary`, `--mark-attention` | A thin shape carrying meaning with nothing written on it — a `Card accent` rail, a `DataTable rowTone` rail | SC 1.4.11 **3:1** against the surface it sits on |
58
+
59
+ The MARK tier exists because both rails were reading FILL, and two of them were effectively
60
+ invisible. Measured in Chromium on the light card: `Card accent="warning"` drew its 6px rail at
61
+ **1.74:1**, `accent="success"` at **2.18:1**. `--warning` is a bright 山吹 tuned to carry dark text
62
+ on top of it; on a near-white card it is barely a colour at all.
63
+
64
+ `--mark-*` resolve THROUGH the TEXT tier rather than restating its numbers, so a theme retunes one
65
+ place and both follow — and since 3:1 is looser than 4.5:1, anything legible as text is legible as
66
+ a mark by construction. `--mark-attention` is the exception: there is no `--text-attention`, and
67
+ the fill already clears the floor in both themes (3.32 / 6.75).
68
+
69
+ Two guards, because one was not enough:
70
+ `src/tokens/__tests__/tone-mark-contrast.test.ts` recomputes every tone × ground × theme off the
71
+ committed tokens and reads the alias out of the CSS (so repointing a mark back at FILL fails the
72
+ ratio, not just a name check); and `check:contrast` grew a **rail pass** — its graphic pass only
73
+ ever measured elements ≤24px on both axes, and a rail is 6px by the full height of a card, so no
74
+ gate had ever looked at one.
75
+
76
+ **Progress and Legend joined the tier, and the wa-iro question is settled.** `.ui-legend-swatch`,
77
+ `.ui-progress-bar` and `.ui-progress-segment` all read FILL as standalone graphics and all failed
78
+ the same floor. The floor applies: nothing is written on a progress fill, so *where the colour
79
+ stops* is the entire datum, and a slice of a partition carries its share of the whole with no words
80
+ on it — that is precisely a "graphical object required to understand the content". The hue loses.
81
+ The two moved together because a swatch is a SAMPLE of the bar beside it; a key that is not the
82
+ colour it is a key to is not a key.
83
+
84
+ | surface | tone | ground | FILL (before) | MARK (after) |
85
+ | --- | --- | --- | --- | --- |
86
+ | `.ui-legend-swatch` | warning | light card | **1.74** | **5.90** |
87
+ | `.ui-legend-swatch` | success | light card | **2.18** | **6.84** |
88
+ | `.ui-legend-swatch` | destructive | dark card | **2.95** | **5.52** |
89
+ | `.ui-progress-segment` | warning | light track | **1.60** | **5.41** |
90
+ | `.ui-progress-segment` | success | light track | **2.00** | **6.28** |
91
+ | `.ui-progress-segment` | destructive | dark track | **2.42** | **4.52** |
92
+
93
+ Worst case anywhere on the two routes after the move: **4.52:1**. `.ui-progress-bar` (meter and
94
+ over-capacity) reads the same tokens as the slice, so a `tone="warning"` meter and a `warning`
95
+ slice on one screen stay the same colour.
96
+
97
+ **A theme that repoints `--secondary` owes `--progress-track-background`.** The track defaults to
98
+ `hsl(var(--secondary))`, which is a pale neutral in the stock palette. `docs/showcase/acme-portal`
99
+ repurposes `--secondary` as a navy *button* colour, so its bars were drawn on a near-black track
100
+ and the mark fills measured 2.50 (success) / 2.90 (warning) on it. Naming the track explicitly is
101
+ the fix — 6.49 / 5.59 after — not dragging the tier back.
102
+
103
+ Three guards now, and each sees something the others cannot: the ratio tests in
104
+ `tone-mark-contrast.test.ts` (rails against card/background, progress marks against the track);
105
+ the *same file's* CSS-alias assertions, which fail if a rule is repointed at the fill tier and
106
+ which also pin the swatch and the slice to the **same** token per tone; and `check:contrast`'s
107
+ **thin fill** pass — added because adding `/isolate/data-display-progress` to that gate's route
108
+ list on its own changed nothing at all. The graphic pass wants ≤24px on both axes and the rail
109
+ pass wants a one-sided border; a progress fill is 8px (meter) or 22px (slice) tall by whatever
110
+ width its share makes it, so the sweep printed "AA clean" over a bar sitting at 1.60:1.
111
+
47
112
  #### `--border` vs `--input` — decorative chrome vs control boundary (gh#315)
48
113
 
49
114
  These two look like synonyms and are not. Keep them apart:
@@ -262,6 +262,43 @@ export default function Demo() {
262
262
  </CardContent>
263
263
  </Card>
264
264
 
265
+ <Card>
266
+ <CardHeader>
267
+ <CardTitle level={2}>tabular · 数字を桁で揃える</CardTitle>
268
+ <CardDescription>
269
+ 件数のチップが縦に並ぶときは tabular を。プロポーショナル数字だと 1 が 0
270
+ より狭いので、列で見たときに桁がずれてチップ幅も揺れます。既定はオフ — 語を載せる
271
+ チップまで幅の広い数字を払う必要はありません。
272
+ </CardDescription>
273
+ </CardHeader>
274
+ <CardContent>
275
+ <Flex direction="row" gap="lg">
276
+ <Flex direction="col" align="start" gap="xs">
277
+ <Text size="xs" tone="muted">
278
+ 既定(比例数字)
279
+ </Text>
280
+ <Badge tone="info">11</Badge>
281
+ <Badge tone="info">100</Badge>
282
+ <Badge tone="warning">1811</Badge>
283
+ </Flex>
284
+ <Flex direction="col" align="start" gap="xs">
285
+ <Text size="xs" tone="muted">
286
+ tabular
287
+ </Text>
288
+ <Badge tone="info" tabular>
289
+ 11
290
+ </Badge>
291
+ <Badge tone="info" tabular>
292
+ 100
293
+ </Badge>
294
+ <Badge tone="warning" tabular>
295
+ 1811
296
+ </Badge>
297
+ </Flex>
298
+ </Flex>
299
+ </CardContent>
300
+ </Card>
301
+
265
302
  <Card>
266
303
  <CardHeader>
267
304
  <CardTitle level={2}>Icon overrides</CardTitle>
@@ -1,7 +1,7 @@
1
1
  import { useMemo, useState } from "react";
2
2
 
3
3
  import { AppProvider } from "@godxjp/ui/app";
4
- import { Badge, DataTable, type ColumnDef } from "@godxjp/ui/data-display";
4
+ import { Badge, Card, CardContent, DataTable, type ColumnDef } from "@godxjp/ui/data-display";
5
5
  import { Button, Text } from "@godxjp/ui/general";
6
6
  import { Flex, PageContainer } from "@godxjp/ui/layout";
7
7
  import {
@@ -93,6 +93,16 @@ const columns: ColumnDef<Invoice>[] = [
93
93
  },
94
94
  ];
95
95
 
96
+ /* Five 240px columns: wider than the frame at every viewport the gates sweep, and wide for a
97
+ * reason no font can change — the width is declared, so the overflow is deterministic in CI. */
98
+ const wideColumns: ColumnDef<Invoice>[] = [
99
+ { key: "id", header: "請求書番号", width: "240px" },
100
+ { key: "partner", header: "取引先", width: "240px" },
101
+ { key: "amount", header: "金額", align: "right", width: "240px" },
102
+ { key: "status", header: "状態", width: "240px" },
103
+ { key: "date", header: "期限日", width: "240px" },
104
+ ];
105
+
96
106
  export default function Demo() {
97
107
  const [selected, setSelected] = useState<Set<string>>(new Set(["INV-0311"]));
98
108
  const [sort, setSort] = useState<SortStateProp | undefined>({
@@ -117,6 +127,22 @@ export default function Demo() {
117
127
  subtitle="sortable · selectable · bulk actions · row actions · loading · clickable rows · empty state"
118
128
  >
119
129
  <Flex direction="col" gap="lg">
130
+ {/* A table WIDER than its frame, inside a flush Card — the shape a list page uses. It must
131
+ scroll inside its own box with the fade at the inline end, never cut its last columns
132
+ (WCAG 1.4.10). `check:data-table-overflow` measures this section. */}
133
+ <Flex direction="col" gap="sm" id="wide-overflow" className="max-w-3xl">
134
+ <Text weight="medium">枠より広い表(横スクロール · 列を切らない)</Text>
135
+ <Card>
136
+ <CardContent flush>
137
+ <DataTable
138
+ data={invoices}
139
+ columns={wideColumns}
140
+ getRowId={(row) => row.id}
141
+ selectable
142
+ />
143
+ </CardContent>
144
+ </Card>
145
+ </Flex>
120
146
  <Flex direction="col" gap="sm" id="text-action-width">
121
147
  <Text weight="medium">日本語の行アクション</Text>
122
148
  <DataTable
@@ -140,6 +166,24 @@ export default function Demo() {
140
166
  getRowId={(row) => row.id}
141
167
  />
142
168
  </Flex>
169
+ {/* Row TONE — the leading-edge rail + wash for a row in a named state. The status Badge
170
+ stays in its own cell: the rail makes the row findable, it does not carry the meaning
171
+ (WCAG 1.4.1). */}
172
+ <Flex direction="col" gap="sm" id="row-tone">
173
+ <Text weight="medium">行のトーン(要対応の行)</Text>
174
+ <DataTable
175
+ data={invoices}
176
+ columns={columns}
177
+ getRowId={(row) => row.id}
178
+ rowTone={(row) =>
179
+ row.status === "failed"
180
+ ? "destructive"
181
+ : row.status === "pending"
182
+ ? "attention"
183
+ : undefined
184
+ }
185
+ />
186
+ </Flex>
143
187
  {/* Primary: sorted (amount desc), one row preselected, clickable rows,
144
188
  controlled density (comfortable), kebab row actions, pagination footer. */}
145
189
  <DataTable
@@ -15,7 +15,7 @@ import {
15
15
  PopoverTrigger,
16
16
  } from "@godxjp/ui/data-display";
17
17
  import { Checkbox, FormField, Input, Label } from "@godxjp/ui/data-entry";
18
- import { Button } from "@godxjp/ui/general";
18
+ import { Button, Text } from "@godxjp/ui/general";
19
19
  import { Flex, PageContainer } from "@godxjp/ui/layout";
20
20
  import { Info, SlidersHorizontal } from "lucide-react";
21
21
 
@@ -135,10 +135,7 @@ export default function Demo() {
135
135
  <Flex direction="row" wrap gap="sm">
136
136
  <Popover>
137
137
  <PopoverTrigger asChild>
138
- {/* data-axe-open: opened by check-frame-axe before its overlay scan. */}
139
- <Button data-axe-open variant="outline">
140
- side=top
141
- </Button>
138
+ <Button variant="outline">side=top</Button>
142
139
  </PopoverTrigger>
143
140
  <PopoverContent side="top" aria-label="上側の配置例">
144
141
  <PopoverDescription>上に開きます。</PopoverDescription>
@@ -209,6 +206,47 @@ export default function Demo() {
209
206
  </CardContent>
210
207
  </Card>
211
208
 
209
+ <Card>
210
+ <CardHeader>
211
+ <CardTitle level={2}>width · パネルの測り方</CardTitle>
212
+ <CardDescription>
213
+ 既定の panel は --popover-width(18rem)。auto は中身に測らせます — 自前の幅を持つもの
214
+ (Calendar、チャート、固定幅のプレビュー)はこれ以外に正解がありません。trigger
215
+ はアンカーに合わせます。className に w-*
216
+ を書くのは呼び出し側の定数で、どのテーマからも retune できません。flush が padding
217
+ 側で避けているのと同じ話です。
218
+ </CardDescription>
219
+ </CardHeader>
220
+ <CardContent>
221
+ <Flex direction="row" wrap gap="sm">
222
+ <Popover>
223
+ <PopoverTrigger asChild>
224
+ <Button variant="outline">panel(既定)</Button>
225
+ </PopoverTrigger>
226
+ <PopoverContent aria-label="既定の幅">
227
+ <Text size="sm">18rem のパネル幅。散文や、パネル自身が測るリスト向け。</Text>
228
+ </PopoverContent>
229
+ </Popover>
230
+ <Popover>
231
+ <PopoverTrigger asChild>
232
+ <Button variant="outline">auto</Button>
233
+ </PopoverTrigger>
234
+ <PopoverContent width="auto" aria-label="内容に合わせた幅">
235
+ <Text size="sm">中身が幅を決めます。</Text>
236
+ </PopoverContent>
237
+ </Popover>
238
+ <Popover>
239
+ <PopoverTrigger asChild>
240
+ <Button variant="outline">trigger に合わせる</Button>
241
+ </PopoverTrigger>
242
+ <PopoverContent width="trigger" aria-label="トリガーと同じ幅">
243
+ <Text size="sm">アンカーと同じ幅。</Text>
244
+ </PopoverContent>
245
+ </Popover>
246
+ </Flex>
247
+ </CardContent>
248
+ </Card>
249
+
212
250
  <Card>
213
251
  <CardHeader>
214
252
  <CardTitle level={2}>Modal</CardTitle>
@@ -33,6 +33,34 @@ export default function Demo() {
33
33
  </CardContent>
34
34
  </Card>
35
35
 
36
+ <Card>
37
+ <CardHeader>
38
+ <CardTitle level={2}>shape=&quot;ring&quot;</CardTitle>
39
+ <CardDescription>
40
+ 同じメーターを弧で描きます。バーと同じ value / tone / size / ARIA
41
+ のまま、label がリングの内側に入ります。狭いアプリバーで「18 / 42
42
+ 件」を見出しの横に出したいとき、バー+キャプションの 2
43
+ 段ではなく 1 マスで済むのが理由です。数値が重要なときではなく、
44
+ 場所が正方形のときに選びます。
45
+ </CardDescription>
46
+ </CardHeader>
47
+ <CardContent>
48
+ <Flex direction="row" wrap align="center" gap="lg">
49
+ {/* label はリング内の表示であり、同時に読み上げ名でもあります。「何の 18/42 か」を
50
+ 名前にしたいときは、画面にすでにある見出しを aria-labelledby で指します
51
+ — bar と同じ規約です。 */}
52
+ <Progress shape="ring" value={43} label="18/42" />
53
+ <Progress shape="ring" value={43} size="sm" label="18/42" />
54
+ <Progress shape="ring" value={0} label="0/42" />
55
+ <Progress shape="ring" value={100} label="42/42" />
56
+ <Progress shape="ring" value={62} tone="warning" label="26/42" />
57
+ <Progress shape="ring" value={88} tone="destructive" label="37/42" />
58
+ {/* label なし=読み出しのないリング。名前は aria-label から。 */}
59
+ <Progress shape="ring" value={43} aria-label="実施済みの点検" />
60
+ </Flex>
61
+ </CardContent>
62
+ </Card>
63
+
36
64
  <Card>
37
65
  <CardHeader>
38
66
  <CardTitle level={2}>Breakdown(segments)</CardTitle>
@@ -14,10 +14,10 @@ import { Button, Text } from "@godxjp/ui/general";
14
14
  import { Flex, PageContainer, ResponsiveGrid } from "@godxjp/ui/layout";
15
15
 
16
16
  /**
17
- * ScrollArea — custom scrollbar container. ALWAYS set an explicit height/max-height
18
- * (vertical) or width (horizontal) on the wrapper or the scrollbar never appears.
19
- * `type` controls when the bar is visible; `ScrollArea orientation="horizontal"`
20
- * adds a horizontal bar. Composed only from real @godxjp/ui components.
17
+ * ScrollArea — a native scrolling box. ALWAYS give it an explicit height/max-height
18
+ * (vertical) or width (horizontal), or nothing ever overflows and no scrollbar appears.
19
+ * `orientation` decides which axes may scroll; the browser draws the bar, styled from
20
+ * the --scroll-area-* tokens. Composed only from real @godxjp/ui components.
21
21
  */
22
22
  const entries = Array.from(
23
23
  { length: 18 },
@@ -97,7 +97,7 @@ export default function Demo() {
97
97
  return (
98
98
  <PageContainer
99
99
  title="ScrollArea"
100
- subtitle="Custom scrollbar container · needs an explicit height"
100
+ subtitle="Native scrolling, token-styled scrollbar · needs an explicit height"
101
101
  >
102
102
  <Flex direction="col" gap="lg">
103
103
  <Card>
@@ -115,7 +115,6 @@ export default function Demo() {
115
115
  anchor="bottom"
116
116
  viewportRef={streamViewport}
117
117
  onAnchoredChange={setAnchored}
118
- type="always"
119
118
  >
120
119
  <CardContent>
121
120
  <Flex direction="col">
@@ -173,7 +172,7 @@ export default function Demo() {
173
172
  <CardContent>
174
173
  <Card variant="outline" className="h-40 w-full">
175
174
  <CardContent flush>
176
- <ScrollArea anchor="bottom" anchorOffset={0} type="always">
175
+ <ScrollArea anchor="bottom" anchorOffset={0}>
177
176
  <CardContent>
178
177
  <Flex direction="col" gap="xs">
179
178
  {entries.map((e) => (
@@ -215,40 +214,13 @@ export default function Demo() {
215
214
  </CardContent>
216
215
  </Card>
217
216
 
218
- <Card>
219
- <CardHeader>
220
- <CardTitle level={2}>type=&quot;always&quot;(バーを常時表示)</CardTitle>
221
- <CardDescription>
222
- 既定の hover はホバー時のみバーを表示します。always
223
- は内容が溢れる限りバーを常に表示します。
224
- </CardDescription>
225
- </CardHeader>
226
- <CardContent>
227
- <Card variant="outline" className="h-56 w-full">
228
- <CardContent flush>
229
- <ScrollArea type="always">
230
- <CardContent>
231
- <Flex direction="col" gap="xs">
232
- {entries.map((e) => (
233
- <div key={e} className="text-sm tabular-nums">
234
- {e}
235
- </div>
236
- ))}
237
- </Flex>
238
- </CardContent>
239
- </ScrollArea>
240
- </CardContent>
241
- </Card>
242
- </CardContent>
243
- </Card>
244
-
245
217
  <Card>
246
218
  <CardHeader>
247
219
  <CardTitle level={2}>ScrollArea</CardTitle>
248
220
  <CardDescription>orientation="horizontal"</CardDescription>
249
221
  </CardHeader>
250
222
  <CardContent>
251
- <ScrollArea orientation="horizontal" type="always">
223
+ <ScrollArea orientation="horizontal">
252
224
  <ResponsiveGrid flow="columns">
253
225
  {columns.map((column) => (
254
226
  <Card key={column}>
@@ -264,17 +236,51 @@ export default function Demo() {
264
236
 
265
237
  <Card>
266
238
  <CardHeader>
267
- <CardTitle level={2}>個別の ScrollBar を追加する</CardTitle>
239
+ <CardTitle level={2}>ScrollBar は何も描画しない(非推奨)</CardTitle>
240
+ <CardDescription>
241
+ v22 まではこの要素を置くことが軸を開く方法だったが、スクロールがブラウザ本来のものに
242
+ なったので ScrollBar は何も描画しない。下のカードには ScrollBar
243
+ が置いてあるが、横に動くのは orientation=&quot;both&quot; のおかげで、ScrollBar
244
+ のおかげではない。残っている &lt;ScrollBar&gt; は消して、軸は orientation で宣言する。
245
+ </CardDescription>
246
+ </CardHeader>
247
+ <CardContent>
248
+ <Card variant="outline" className="h-24 w-full">
249
+ <CardContent flush>
250
+ <ScrollArea orientation="both">
251
+ <ResponsiveGrid flow="columns">
252
+ {columns.map((column) => (
253
+ <Text key={column}>{column}</Text>
254
+ ))}
255
+ </ResponsiveGrid>
256
+ <ScrollBar orientation="horizontal" />
257
+ </ScrollArea>
258
+ </CardContent>
259
+ </Card>
260
+ </CardContent>
261
+ </Card>
262
+
263
+ <Card>
264
+ <CardHeader>
265
+ <CardTitle level={2}>両方向スクロール(orientation=&quot;both&quot;)</CardTitle>
266
+ <CardDescription>
267
+ 縦にも横にも溢れうる面は orientation=&quot;both&quot;。以前は縦の ScrollArea に
268
+ ScrollBar を足して横軸を開けていたが、スクロールはブラウザ本来のものになったので、
269
+ 軸を決めるのは orientation だけになった。
270
+ </CardDescription>
268
271
  </CardHeader>
269
272
  <CardContent>
270
- <ScrollArea type="always">
271
- <ResponsiveGrid flow="columns">
272
- {columns.map((column) => (
273
- <Text key={column}>{column}</Text>
274
- ))}
275
- </ResponsiveGrid>
276
- <ScrollBar orientation="horizontal" />
277
- </ScrollArea>
273
+ <Card variant="outline" className="h-32 w-full">
274
+ <CardContent flush>
275
+ <ScrollArea orientation="both">
276
+ <ResponsiveGrid flow="columns">
277
+ {columns.map((column) => (
278
+ <Text key={column}>{column}</Text>
279
+ ))}
280
+ </ResponsiveGrid>
281
+ </ScrollArea>
282
+ </CardContent>
283
+ </Card>
278
284
  </CardContent>
279
285
  </Card>
280
286
 
@@ -288,7 +294,7 @@ export default function Demo() {
288
294
  <CardContent>
289
295
  <Card variant="outline" className="h-56 w-full">
290
296
  <CardContent flush>
291
- <ScrollArea type="always">
297
+ <ScrollArea>
292
298
  <CardContent>
293
299
  <Flex direction="col" gap="xs">
294
300
  {shortEntries.map((e) => (
@@ -20,7 +20,7 @@ import type { DateRange } from "react-day-picker";
20
20
  /**
21
21
  * Calendar — styled react-day-picker grid for single, multiple, or range
22
22
  * selection. Embed inside a Popover for picker UX; use DatePicker /
23
- * DateRangePicker for form-submittable inputs instead. Composed only from
23
+ * `DatePicker range` for form-submittable inputs instead. Composed only from
24
24
  * real @godxjp/ui components.
25
25
  */
26
26
  export default function Demo() {
@@ -71,7 +71,7 @@ export default function Demo() {
71
71
  <CardHeader>
72
72
  <CardTitle level={2}>範囲選択 · Popover 内</CardTitle>
73
73
  <CardDescription>
74
- mode="range" でポップオーバー内に配置。DateRangePicker
74
+ mode="range" でポップオーバー内に配置。DatePicker range
75
75
  はこのパターンにフォーム送信を加えた上位コンポーネント。
76
76
  </CardDescription>
77
77
  </CardHeader>