@godxjp/ui 19.6.0 → 20.1.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 (326) hide show
  1. package/README.md +8 -2
  2. package/dist/app/theme-axes.d.ts +2 -0
  3. package/dist/app/theme-axes.js +45 -0
  4. package/dist/components/charts/chart-cartesian.d.ts +2 -1
  5. package/dist/components/charts/chart-cartesian.js +52 -3
  6. package/dist/components/charts/chart-category-axis.d.ts +55 -0
  7. package/dist/components/charts/chart-category-axis.js +93 -0
  8. package/dist/components/charts/chart-frame.d.ts +10 -1
  9. package/dist/components/charts/chart-frame.js +19 -3
  10. package/dist/components/charts/compact-bar-trend.d.ts +1 -1
  11. package/dist/components/charts/compact-bar-trend.js +2 -0
  12. package/dist/components/charts/pie-chart.d.ts +1 -1
  13. package/dist/components/charts/pie-chart.js +12 -1
  14. package/dist/components/charts/recharts-peer.d.ts +49 -0
  15. package/dist/components/charts/recharts-peer.js +45 -0
  16. package/dist/components/data-display/card.d.ts +14 -3
  17. package/dist/components/data-display/card.js +22 -4
  18. package/dist/components/data-display/code-block.js +6 -2
  19. package/dist/components/data-display/collapsible.d.ts +23 -4
  20. package/dist/components/data-display/collapsible.js +119 -4
  21. package/dist/components/data-display/data-table.d.ts +39 -4
  22. package/dist/components/data-display/data-table.js +802 -270
  23. package/dist/components/data-display/descriptions.d.ts +27 -6
  24. package/dist/components/data-display/descriptions.js +58 -17
  25. package/dist/components/data-display/index.d.ts +5 -1
  26. package/dist/components/data-display/index.js +4 -0
  27. package/dist/components/data-display/legend.d.ts +15 -0
  28. package/dist/components/data-display/legend.js +11 -0
  29. package/dist/components/data-display/list-row.d.ts +10 -1
  30. package/dist/components/data-display/list-row.js +8 -2
  31. package/dist/components/data-display/popover.d.ts +60 -7
  32. package/dist/components/data-display/popover.js +268 -39
  33. package/dist/components/data-display/progress.d.ts +50 -2
  34. package/dist/components/data-display/progress.js +57 -9
  35. package/dist/components/data-display/range-timeline.d.ts +38 -0
  36. package/dist/components/data-display/range-timeline.js +161 -0
  37. package/dist/components/data-display/scroll-area.js +13 -2
  38. package/dist/components/data-display/service-launcher-card.js +10 -10
  39. package/dist/components/data-display/table.d.ts +11 -3
  40. package/dist/components/data-display/table.js +48 -18
  41. package/dist/components/data-display/tree-list.js +4 -9
  42. package/dist/components/data-entry/calendar.d.ts +2 -2
  43. package/dist/components/data-entry/calendar.js +79 -33
  44. package/dist/components/data-entry/cascader.d.ts +1 -1
  45. package/dist/components/data-entry/cascader.js +188 -24
  46. package/dist/components/data-entry/checkbox.d.ts +19 -6
  47. package/dist/components/data-entry/checkbox.js +55 -16
  48. package/dist/components/data-entry/choice-option.d.ts +1 -1
  49. package/dist/components/data-entry/color-picker.d.ts +1 -1
  50. package/dist/components/data-entry/color-picker.js +17 -5
  51. package/dist/components/data-entry/control-appearance.d.ts +64 -0
  52. package/dist/components/data-entry/control-appearance.js +39 -0
  53. package/dist/components/data-entry/control-surface.d.ts +61 -0
  54. package/dist/components/data-entry/control-surface.js +39 -0
  55. package/dist/components/data-entry/date-picker.d.ts +1 -1
  56. package/dist/components/data-entry/date-picker.js +344 -113
  57. package/dist/components/data-entry/date-range-picker.d.ts +2 -2
  58. package/dist/components/data-entry/date-range-picker.js +278 -140
  59. package/dist/components/data-entry/field.js +0 -1
  60. package/dist/components/data-entry/form-field.d.ts +1 -1
  61. package/dist/components/data-entry/form-field.js +39 -4
  62. package/dist/components/data-entry/form.d.ts +4 -0
  63. package/dist/components/data-entry/form.js +5 -3
  64. package/dist/components/data-entry/index.d.ts +7 -3
  65. package/dist/components/data-entry/index.js +10 -1
  66. package/dist/components/data-entry/input-otp.d.ts +1 -1
  67. package/dist/components/data-entry/input.d.ts +12 -34
  68. package/dist/components/data-entry/input.js +92 -24
  69. package/dist/components/data-entry/label.d.ts +3 -2
  70. package/dist/components/data-entry/label.js +23 -10
  71. package/dist/components/data-entry/month-picker.d.ts +2 -2
  72. package/dist/components/data-entry/month-picker.js +47 -10
  73. package/dist/components/data-entry/month-range-picker.d.ts +2 -2
  74. package/dist/components/data-entry/month-range-picker.js +51 -11
  75. package/dist/components/data-entry/number-input.d.ts +7 -0
  76. package/dist/components/data-entry/number-input.js +147 -98
  77. package/dist/components/data-entry/password-input.d.ts +1 -1
  78. package/dist/components/data-entry/radio.d.ts +1 -1
  79. package/dist/components/data-entry/radio.js +61 -13
  80. package/dist/components/data-entry/search-input.d.ts +1 -1
  81. package/dist/components/data-entry/search-input.js +16 -2
  82. package/dist/components/data-entry/search-select.d.ts +2 -2
  83. package/dist/components/data-entry/search-select.js +209 -78
  84. package/dist/components/data-entry/select.d.ts +22 -4
  85. package/dist/components/data-entry/select.js +215 -163
  86. package/dist/components/data-entry/slider.d.ts +9 -1
  87. package/dist/components/data-entry/slider.js +87 -9
  88. package/dist/components/data-entry/switch.d.ts +3 -0
  89. package/dist/components/data-entry/switch.js +29 -3
  90. package/dist/components/data-entry/textarea.d.ts +14 -56
  91. package/dist/components/data-entry/textarea.js +80 -33
  92. package/dist/components/data-entry/time-picker.d.ts +2 -2
  93. package/dist/components/data-entry/time-picker.js +333 -109
  94. package/dist/components/data-entry/time-range-picker.d.ts +5 -0
  95. package/dist/components/data-entry/time-range-picker.js +89 -0
  96. package/dist/components/data-entry/transfer.d.ts +1 -1
  97. package/dist/components/data-entry/transfer.js +99 -31
  98. package/dist/components/data-entry/tree-select-strategy.d.ts +1 -1
  99. package/dist/components/data-entry/tree-select.d.ts +1 -1
  100. package/dist/components/data-entry/tree-select.js +197 -92
  101. package/dist/components/data-entry/tree-utils.d.ts +1 -1
  102. package/dist/components/data-entry/tree-utils.js +7 -14
  103. package/dist/components/data-entry/upload-files.d.ts +2 -0
  104. package/dist/components/data-entry/upload-files.js +31 -0
  105. package/dist/components/data-entry/upload-request.d.ts +4 -0
  106. package/dist/components/data-entry/upload-request.js +53 -0
  107. package/dist/components/data-entry/upload-types.d.ts +28 -0
  108. package/dist/components/data-entry/upload-types.js +2 -0
  109. package/dist/components/data-entry/upload.d.ts +2 -2
  110. package/dist/components/data-entry/upload.js +482 -117
  111. package/dist/components/feedback/dialog.d.ts +105 -38
  112. package/dist/components/feedback/dialog.js +268 -193
  113. package/dist/components/feedback/overlay-close-focus.d.ts +31 -0
  114. package/dist/components/feedback/overlay-close-focus.js +31 -0
  115. package/dist/components/feedback/overlay-header-tone.d.ts +1 -1
  116. package/dist/components/feedback/sheet.d.ts +53 -11
  117. package/dist/components/feedback/sheet.js +150 -81
  118. package/dist/components/feedback/tooltip.d.ts +51 -7
  119. package/dist/components/feedback/tooltip.js +107 -25
  120. package/dist/components/general/button.d.ts +1 -1
  121. package/dist/components/general/button.js +7 -3
  122. package/dist/components/general/index.d.ts +1 -0
  123. package/dist/components/general/index.js +2 -0
  124. package/dist/components/general/logo.d.ts +17 -0
  125. package/dist/components/general/logo.js +22 -16
  126. package/dist/components/general/typography.d.ts +3 -0
  127. package/dist/components/general/typography.js +15 -1
  128. package/dist/components/general/visually-hidden.d.ts +3 -0
  129. package/dist/components/general/visually-hidden.js +9 -0
  130. package/dist/components/layout/app-launcher.d.ts +34 -0
  131. package/dist/components/layout/app-launcher.js +228 -0
  132. package/dist/components/layout/app-shell.d.ts +3 -1
  133. package/dist/components/layout/app-shell.js +69 -12
  134. package/dist/components/layout/aspect-ratio.js +0 -1
  135. package/dist/components/layout/auth-divider.js +0 -1
  136. package/dist/components/layout/breadcrumb.d.ts +14 -2
  137. package/dist/components/layout/breadcrumb.js +46 -4
  138. package/dist/components/layout/flex.d.ts +1 -1
  139. package/dist/components/layout/flex.js +41 -3
  140. package/dist/components/layout/index.d.ts +3 -0
  141. package/dist/components/layout/index.js +5 -1
  142. package/dist/components/layout/nav-surface.d.ts +26 -0
  143. package/dist/components/layout/nav-surface.js +17 -0
  144. package/dist/components/layout/org-switcher.d.ts +5 -1
  145. package/dist/components/layout/org-switcher.js +25 -4
  146. package/dist/components/layout/page-container.d.ts +1 -1
  147. package/dist/components/layout/page-container.js +5 -3
  148. package/dist/components/layout/responsive-grid.d.ts +16 -2
  149. package/dist/components/layout/responsive-grid.js +29 -2
  150. package/dist/components/layout/separator.js +0 -1
  151. package/dist/components/layout/sidebar.js +4 -1
  152. package/dist/components/layout/split-pane.d.ts +14 -1
  153. package/dist/components/layout/split-pane.js +26 -13
  154. package/dist/components/layout/topbar-item.d.ts +3 -0
  155. package/dist/components/layout/topbar-item.js +19 -5
  156. package/dist/components/layout/topbar.d.ts +1 -1
  157. package/dist/components/layout/topbar.js +27 -6
  158. package/dist/components/navigation/app-setting-picker.js +21 -2
  159. package/dist/components/navigation/app-setting-toggle.d.ts +16 -0
  160. package/dist/components/navigation/app-setting-toggle.js +96 -0
  161. package/dist/components/navigation/dropdown-menu.d.ts +227 -18
  162. package/dist/components/navigation/dropdown-menu.js +402 -118
  163. package/dist/components/navigation/index.d.ts +2 -0
  164. package/dist/components/navigation/index.js +2 -0
  165. package/dist/components/navigation/pagination-utils.d.ts +2 -1
  166. package/dist/components/navigation/pagination.d.ts +2 -2
  167. package/dist/components/navigation/pagination.js +155 -83
  168. package/dist/components/navigation/steps.d.ts +2 -2
  169. package/dist/components/navigation/steps.js +29 -4
  170. package/dist/components/navigation/tabs.d.ts +29 -16
  171. package/dist/components/navigation/tabs.js +374 -144
  172. package/dist/components/ui/accordion.d.ts +50 -5
  173. package/dist/components/ui/accordion.js +239 -33
  174. package/dist/components/ui/aspect-ratio.d.ts +23 -2
  175. package/dist/components/ui/aspect-ratio.js +15 -13
  176. package/dist/components/ui/avatar.d.ts +29 -4
  177. package/dist/components/ui/avatar.js +111 -25
  178. package/dist/components/ui/hover-card.d.ts +42 -4
  179. package/dist/components/ui/hover-card.js +183 -27
  180. package/dist/components/ui/input-otp.d.ts +26 -28
  181. package/dist/components/ui/input-otp.js +50 -7
  182. package/dist/components/ui/label.js +0 -1
  183. package/dist/components/ui/password-input.d.ts +36 -2
  184. package/dist/components/ui/password-input.js +27 -7
  185. package/dist/components/ui/rating.d.ts +25 -0
  186. package/dist/components/ui/rating.js +67 -27
  187. package/dist/components/ui/segmented.d.ts +12 -3
  188. package/dist/components/ui/segmented.js +17 -2
  189. package/dist/components/ui/separator.d.ts +12 -2
  190. package/dist/components/ui/separator.js +30 -9
  191. package/dist/components/ui/tag-input.d.ts +45 -0
  192. package/dist/components/ui/tag-input.js +109 -27
  193. package/dist/components/ui/toggle-group.d.ts +50 -5
  194. package/dist/components/ui/toggle-group.js +79 -20
  195. package/dist/components/ui/toggle.d.ts +31 -5
  196. package/dist/components/ui/toggle.js +42 -3
  197. package/dist/form/form-context.d.ts +29 -0
  198. package/dist/form/form-context.js +44 -4
  199. package/dist/form/form-field-array.d.ts +22 -0
  200. package/dist/form/form-field-array.js +50 -0
  201. package/dist/form/form-field-control.d.ts +2 -1
  202. package/dist/form/form-field-control.js +116 -40
  203. package/dist/form/form-root.d.ts +2 -1
  204. package/dist/form/form-root.js +142 -23
  205. package/dist/form/index.d.ts +3 -1
  206. package/dist/form/index.js +12 -1
  207. package/dist/i18n/messages/en.json +64 -5
  208. package/dist/i18n/messages/ja.json +64 -5
  209. package/dist/i18n/messages/vi.json +64 -5
  210. package/dist/inertia/index.d.ts +20 -0
  211. package/dist/inertia/index.js +60 -1
  212. package/dist/lib/control-styles.d.ts +25 -3
  213. package/dist/lib/control-styles.js +9 -3
  214. package/dist/lib/datetime/picker-format.d.ts +8 -0
  215. package/dist/lib/datetime/picker-format.js +54 -0
  216. package/dist/lib/slot.d.ts +32 -0
  217. package/dist/lib/slot.js +22 -0
  218. package/dist/lib/variants.d.ts +22 -3
  219. package/dist/lib/variants.js +56 -1
  220. package/dist/props/components/app.prop.d.ts +25 -1
  221. package/dist/props/components/charts.prop.d.ts +21 -0
  222. package/dist/props/components/data-display.prop.d.ts +72 -4
  223. package/dist/props/components/data-entry.prop.d.ts +718 -46
  224. package/dist/props/components/form.prop.d.ts +142 -4
  225. package/dist/props/components/general.prop.d.ts +17 -1
  226. package/dist/props/components/index.d.ts +3 -3
  227. package/dist/props/components/layout.prop.d.ts +281 -11
  228. package/dist/props/components/navigation.prop.d.ts +114 -4
  229. package/dist/props/registry.d.ts +397 -11
  230. package/dist/props/registry.js +526 -11
  231. package/dist/props/vocabulary/content.prop.d.ts +1 -1
  232. package/dist/props/vocabulary/data.prop.d.ts +179 -1
  233. package/dist/props/vocabulary/index.d.ts +5 -5
  234. package/dist/props/vocabulary/interaction.prop.d.ts +68 -3
  235. package/dist/props/vocabulary/layout.prop.d.ts +57 -1
  236. package/dist/props/vocabulary/navigation.prop.d.ts +40 -0
  237. package/dist/props/vocabulary/shared.prop.d.ts +33 -0
  238. package/dist/styles/badge-layout.css +2 -1
  239. package/dist/styles/card-layout.css +26 -4
  240. package/dist/styles/chart-layout.css +15 -0
  241. package/dist/styles/control.css +657 -15
  242. package/dist/styles/core.css +5 -2
  243. package/dist/styles/data-display-layout.css +313 -6
  244. package/dist/styles/data-entry-layout.css +13 -0
  245. package/dist/styles/focus-ring.css +4 -0
  246. package/dist/styles/index.css +5 -2
  247. package/dist/styles/layout.css +327 -4
  248. package/dist/styles/navigation-layout.css +227 -0
  249. package/dist/styles/shell-layout.css +369 -13
  250. package/dist/styles/table-layout.css +95 -6
  251. package/dist/styles/text-layout.css +10 -4
  252. package/dist/tokens/base.css +2 -1
  253. package/dist/tokens/components/badge.css +1 -0
  254. package/dist/tokens/components/chart.css +6 -0
  255. package/dist/tokens/components/control.css +79 -2
  256. package/dist/tokens/components/data-display.css +20 -0
  257. package/dist/tokens/components/descriptions.css +11 -0
  258. package/dist/tokens/components/flex.css +8 -0
  259. package/dist/tokens/components/navigation.css +55 -0
  260. package/dist/tokens/components/shell.css +53 -3
  261. package/dist/tokens/components/table.css +14 -0
  262. package/dist/tokens/foundation.css +2 -0
  263. package/dist/tokens/semantic/layout.css +9 -0
  264. package/docs/COMPONENTS.md +9 -3
  265. package/docs/CONSUMER-RULES.md +13 -0
  266. package/docs/DESIGN-AUTHORITY.md +145 -83
  267. package/docs/DEVELOPMENT.md +4 -3
  268. package/docs/FORMS.md +151 -6
  269. package/docs/FRAME-COVERAGE-REPORT.md +32 -17
  270. package/docs/README.md +15 -15
  271. package/docs/STANDARDS-vocabulary-tokens.md +1 -1
  272. package/docs/TESTING.md +15 -6
  273. package/docs/WHAT-BELONGS-HERE.md +179 -0
  274. package/docs/charts/cjk-category-axis.tsx +81 -0
  275. package/docs/data-display/card/index.tsx +22 -0
  276. package/docs/data-display/data-table/examples/antd-parity.tsx +257 -0
  277. package/docs/data-display/data-table/index.tsx +23 -0
  278. package/docs/data-display/descriptions.tsx +41 -0
  279. package/docs/data-display/legend.tsx +145 -0
  280. package/docs/data-display/progress.tsx +32 -0
  281. package/docs/data-display/scroll-area.tsx +31 -25
  282. package/docs/data-display/table.tsx +104 -45
  283. package/docs/data-display/timeline.tsx +41 -0
  284. package/docs/data-entry/date-picker.tsx +85 -0
  285. package/docs/data-entry/date-range-picker.tsx +26 -0
  286. package/docs/data-entry/form-dynamic-fields.tsx +199 -0
  287. package/docs/data-entry/form.tsx +74 -4
  288. package/docs/data-entry/input-otp.tsx +24 -0
  289. package/docs/data-entry/input.tsx +46 -1
  290. package/docs/data-entry/month-range-picker.tsx +1 -1
  291. package/docs/data-entry/segmented.tsx +1 -1
  292. package/docs/data-entry/select.tsx +29 -2
  293. package/docs/data-entry/switch.tsx +41 -0
  294. package/docs/data-entry/textarea.tsx +38 -0
  295. package/docs/data-entry/time-picker.tsx +85 -1
  296. package/docs/data-entry/time-range-picker.tsx +55 -0
  297. package/docs/data-entry/transfer.tsx +17 -0
  298. package/docs/data-entry/upload.tsx +56 -12
  299. package/docs/feedback/sheet.tsx +1 -1
  300. package/docs/feedback/tooltip.tsx +1 -1
  301. package/docs/general/activity.tsx +2 -2
  302. package/docs/general/button/index.tsx +14 -1
  303. package/docs/general/typography.tsx +14 -1
  304. package/docs/layout/app-launcher.tsx +151 -0
  305. package/docs/layout/app-shell-arrangements.tsx +225 -0
  306. package/docs/layout/app-shell.tsx +11 -0
  307. package/docs/layout/aspect-ratio.tsx +1 -1
  308. package/docs/layout/flex.tsx +50 -0
  309. package/docs/layout/responsive-grid.tsx +21 -1
  310. package/docs/layout/topbar.tsx +5 -9
  311. package/docs/navigation/app-setting-picker.tsx +37 -1
  312. package/docs/navigation/app-setting-toggle.tsx +111 -0
  313. package/docs/navigation/breadcrumb.tsx +48 -0
  314. package/docs/navigation/dropdown-menu.tsx +21 -0
  315. package/docs/navigation/pagination.tsx +52 -0
  316. package/docs/navigation/steps.tsx +37 -0
  317. package/docs/navigation/tabs.tsx +97 -1
  318. package/docs/query/button-refetch.tsx +1 -0
  319. package/package.json +28 -8
  320. package/scripts/_agent-setup.mjs +182 -3
  321. package/scripts/consumer-rule.md +98 -0
  322. package/scripts/guinea-pig-skill.md +322 -0
  323. package/scripts/init-guinea-pig.mjs +84 -0
  324. package/scripts/postinstall.mjs +13 -2
  325. package/scripts/ui-audit.mjs +351 -37
  326. /package/dist/tokens/{antd.generated.css → derived.css} +0 -0
package/docs/README.md CHANGED
@@ -1,26 +1,26 @@
1
1
  # @godxjp/ui Documentation
2
2
 
3
- | Doc | Purpose |
4
- | -------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
5
- | [CONSUMER-RULES.md](./CONSUMER-RULES.md) | **Start here if you build an app with @godxjp/ui** — the ten rules the audit enforces (styles entry, layout owners, real primitives, tokens) |
6
- | [DEVELOPMENT.md](./DEVELOPMENT.md) | **Contributor guideline** — role/boundary, architecture, how to add/extend, verify |
7
- | [COMPONENTS.md](./COMPONENTS.md) | Component catalog by Ant Design group |
8
- | [PROPS-VOCABULARY.md](./PROPS-VOCABULARY.md) | Atomic prop types (`*Prop` suffix) |
9
- | [PROPS-REGISTRY.md](./PROPS-REGISTRY.md) | Machine-readable registry + forbidden aliases |
10
- | [DATETIME.md](./DATETIME.md) | **Mandatory** `formatDate` — all date/time display |
11
- | [DESIGN-AUTHORITY.md](./DESIGN-AUTHORITY.md) | **Which external standard owns which decision** — APG, Radix, shadcn, Ant Design groups, SmartHR colour, Carbon geometry. Read before inventing a spacing/density/layout answer |
12
- | [SPACING.md](./SPACING.md) | Golden ratio (φ) macro spacing — PageContainer sections, Flex gap, Card rhythm |
13
- | [FORMS.md](./FORMS.md) | **Mandatory** react-hook-form + Zod 4 |
14
- | [TESTING.md](./TESTING.md) | **Mandatory** Vitest per component |
15
- | [FRAME-A11Y-CI.md](./FRAME-A11Y-CI.md) | Per-frame axe a11y + geometry + coverage CI gates — how to run/regenerate locally |
16
- | [../README.md](../README.md) | Setup, workspace wiring, theme |
3
+ | Doc | Purpose |
4
+ | -------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
5
+ | [CONSUMER-RULES.md](./CONSUMER-RULES.md) | **Start here if you build an app with @godxjp/ui** — the ten rules the audit enforces (styles entry, layout owners, real primitives, tokens) |
6
+ | [DEVELOPMENT.md](./DEVELOPMENT.md) | **Contributor guideline** — role/boundary, architecture, how to add/extend, verify |
7
+ | [COMPONENTS.md](./COMPONENTS.md) | Component catalog by taxonomy group |
8
+ | [PROPS-VOCABULARY.md](./PROPS-VOCABULARY.md) | Atomic prop types (`*Prop` suffix) |
9
+ | [PROPS-REGISTRY.md](./PROPS-REGISTRY.md) | Machine-readable registry + forbidden aliases |
10
+ | [DATETIME.md](./DATETIME.md) | **Mandatory** `formatDate` — all date/time display |
11
+ | [DESIGN-AUTHORITY.md](./DESIGN-AUTHORITY.md) | **Which external standard owns which decision** — APG, Radix, shadcn, Ant Design groups, SmartHR colour, Carbon geometry, measured contrast for derived colour. Read before inventing a spacing/density/layout answer |
12
+ | [SPACING.md](./SPACING.md) | Golden ratio (φ) macro spacing — PageContainer sections, Flex gap, Card rhythm |
13
+ | [FORMS.md](./FORMS.md) | **Mandatory** react-hook-form + Zod 4 |
14
+ | [TESTING.md](./TESTING.md) | **Mandatory** Vitest per component |
15
+ | [FRAME-A11Y-CI.md](./FRAME-A11Y-CI.md) | Per-frame axe a11y + geometry + coverage CI gates — how to run/regenerate locally |
16
+ | [../README.md](../README.md) | Setup, workspace wiring, theme |
17
17
 
18
18
  ## Preview
19
19
 
20
20
  ```bash
21
21
  cd packages/ui
22
22
  pnpm preview # http://localhost:6008
23
- pnpm preview:build # static site → preview/dist/
23
+ pnpm preview:build # static site → preview/dist/ — heavy; CI's job, run at most once pre-PR
24
24
  ```
25
25
 
26
26
  ### Preview doc format
@@ -1,6 +1,6 @@
1
1
  # Prop Vocabulary + Design Token Standards
2
2
 
3
- These rules are normative for @godxjp/ui 8.0.0. They mirror `debate/props-vocab-token-consistency/04-Decision.md`.
3
+ These rules are normative for @godxjp/ui. They came out of the props-vocabulary / token-consistency debate, whose record lived in `debate/` until that directory was removed — this file is now the normative source, not a mirror of one.
4
4
 
5
5
  1. Prop vocabulary: every exported `*Prop` type in `src/props/components/` MUST have exactly one `COMPONENT_PROP_REGISTRY` entry.
6
6
  2. Prop vocabulary: every public property in an exported component prop type MUST map to one `VOCABULARY_REGISTRY` entry or to a `local: true` registry record with a non-empty `reason`.
package/docs/TESTING.md CHANGED
@@ -5,10 +5,16 @@ Every component **must** ship with a Vitest suite before merge.
5
5
  ## Run
6
6
 
7
7
  ```bash
8
- cd packages/ui
9
- pnpm test # single run
10
- pnpm test:watch # watch mode
11
- pnpm test:coverage # v8 coverage report
8
+ # While working — ONLY the tests for what you touched. Tests sit beside the
9
+ # component in `src/components/<group>/__tests__/`, so scope to that folder.
10
+ pnpm vitest run src/components/<group>/__tests__ --maxWorkers=2
11
+ pnpm vitest watch src/components/<group>/__tests__ # watch one component
12
+
13
+ # CI only — 506 files / 3700+ tests. Do NOT run these from an agent loop or with
14
+ # other agents on the machine: measured 70 vitest workers at load 90, an overheating
15
+ # laptop and a burnt monthly API budget.
16
+ pnpm test # single run — CI
17
+ pnpm test:coverage # v8 coverage report — CI
12
18
  ```
13
19
 
14
20
  ## File location
@@ -68,7 +74,7 @@ import "@testing-library/jest-dom/vitest";
68
74
  | `react-hooks/set-state-in-effect` | sync setState in effects |
69
75
  | `RenderLoopGuard` in tests | runaway re-renders during Vitest |
70
76
 
71
- Run `pnpm lint` before `pnpm test` — official React Compiler rules align with test guard.
77
+ Run `pnpm lint` before your scoped test run — official React Compiler rules align with test guard.
72
78
 
73
79
  ## Forms testing
74
80
 
@@ -83,7 +89,10 @@ Never test forms with raw `useState` — mirror production `FormRoot` + `FormFie
83
89
 
84
90
  ## CI gate
85
91
 
86
- `pnpm test` in `packages/ui` must pass with zero failures before any UI PR merges.
92
+ The full suite must pass with zero failures before any UI PR merges — **and that run belongs
93
+ to CI, not to you.** Locally you run only the tests for the files you changed; CI runs
94
+ everything on the PR. `tal --help` states the same rule for the agent loop: *FULL SUITE KHÔNG
95
+ THUỘC VỀ VÒNG LẶP.*
87
96
 
88
97
  ## When tests fail
89
98
 
@@ -0,0 +1,179 @@
1
+ # Cái gì đáng đưa vào @godxjp/ui
2
+
3
+ Một design system hỏng theo hai hướng ngược nhau, và cả hai đều hỏng thật:
4
+
5
+ - **Quá hẹp** — thiếu prop, nên consumer buộc phải lách bằng class hoặc mã màu
6
+ gõ tay. Đây là hướng đang hỏng: một lượt kiểm trên godx-chat (08/09/2026) ra
7
+ **51 lỗi, 42 trong đó đến từ ĐÚNG MỘT prop còn thiếu** (đệm trên primitive bố
8
+ cục).
9
+ - **Quá rộng** — nhận mọi yêu cầu, thành một đống prop không ai nhớ, và mỗi
10
+ prop là một mảnh DOM nội bộ bị đóng băng thành API công khai.
11
+
12
+ Tài liệu này là bộ lọc giữa hai hướng đó. Nó cố tình viết thành câu hỏi **trả
13
+ lời được bằng có/không**, không phải nguyên tắc để cảm nhận.
14
+
15
+ ---
16
+
17
+ ## Ba câu hỏi — phải ĐỦ CẢ BA
18
+
19
+ ### 1. Có phải consumer KHÔNG CÓ nước đi hợp lệ nào không?
20
+
21
+ Không phải "bất tiện". Là **bất khả**: mọi prop và token đang có đều không nói
22
+ được điều cần nói, và mọi đường còn lại đều bị `ui-audit` chặn.
23
+
24
+ - ✅ Thiết kế cần 12px giữa hai phần tử trên một HÀNG. Thang bậc tên đọc trục
25
+ dọc nên `md` = 16px; làm tròn thì lệch bố cục; viết `gap: 12px` thì
26
+ `no-arbitrary-spacing` chặn. **Không có nước đi.** → gh#401, đã vá.
27
+ - ❌ "Viết `<Flex gap={3}>` dài hơn `gap-3`." Có nước đi, chỉ là dài hơn.
28
+
29
+ Cách kiểm: viết ra đoạn mã bạn _muốn_ viết, chạy `ui-audit` lên nó. Nếu nó
30
+ xanh, bạn đã có nước đi.
31
+
32
+ ### 2. Nó thuộc về HÌNH DẠNG của component, hay thuộc về NỘI DUNG của một màn?
33
+
34
+ Design system sở hữu hình dạng. Màn hình sở hữu nội dung.
35
+
36
+ - ✅ `Flex` không có đệm. Mọi hàng/cột trong mọi ứng dụng đều có thể cần đệm.
37
+ - ✅ `TableHead` không có trục căn lề. Mọi bảng có cột số đều cần.
38
+ - ❌ "Bảng quản trị thành viên cần cột vai trò rộng 8rem." Đó là màn hình ấy.
39
+ - ❌ "Dashboard cần bốn thẻ chỉ số xếp ngang." Đó là bố cục của một trang.
40
+
41
+ Câu hỏi phụ khi phân vân: **consumer thứ hai có gặp không?** Nếu câu trả lời là
42
+ "chắc là không" thì gần như luôn là nội dung, không phải hình dạng.
43
+
44
+ ### 3. Diễn đạt được thành một TRỤC CÓ TÊN không?
45
+
46
+ Một prop phải gọi được **ý định**, không chỉ mở một lỗ.
47
+
48
+ - ✅ `pad={{ blockStart: 3 }}` — trục logic, bậc thang, đọc ra nghĩa.
49
+ - ❌ `styles={{ body: {...}, header: {...} }}` — không phải một trục; nó là một
50
+ lỗ tự do, và nó đóng băng tên khe DOM nội bộ thành API công khai. Xem mục
51
+ "Không đáng" bên dưới.
52
+
53
+ ---
54
+
55
+ ## Bốn dấu hiệu MẠNH — một cái là đủ để ưu tiên làm ngay
56
+
57
+ Ba câu trên quyết định _có thuộc về đây không_. Bốn dấu hiệu này quyết định
58
+ _làm trước hay sau_.
59
+
60
+ ### a. Nó chặn một yêu cầu TIẾP CẬN
61
+
62
+ Không thương lượng, làm trước.
63
+ Ví dụ đã gặp: vòng tiêu điểm của Input là 1px (hạ xuống có chủ ý), không
64
+ đạt WCAG 2.4.11 vốn đòi vùng chỉ báo tương đương đường 2px. Và `FormRoot` không
65
+ có móc `onInvalid`, nên không đưa được tiêu điểm về trường lỗi đầu tiên — WCAG
66
+ 3.3.1 / 2.4.3.
67
+
68
+ ### b. Nó hỏng IM LẶNG
69
+
70
+ Không lỗi biên dịch, không test đỏ, không cảnh báo — chỉ sai.
71
+ Ví dụ đã gặp: `AppShell` nhận cả `logo` lẫn `topbar` nhưng `resolvedTopbar` trả
72
+ thẳng `topbar`, nên `logo` **không bao giờ được vẽ**. godx-chat truyền cả hai
73
+ suốt nhiều tháng và không ai phát hiện.
74
+
75
+ Lớp lỗi này đắt gấp nhiều lần lớp lỗi ồn ào, vì nó không có ai báo.
76
+
77
+ ### c. Đếm được
78
+
79
+ Một khoảng trống đẻ ra N lỗi audit là một khoảng trống có số đo, không phải một
80
+ ý kiến. 42 lỗi từ một prop thiếu là một ưu tiên; một lỗi từ một prop thiếu thì
81
+ chưa chắc.
82
+
83
+ ### d. Nó BẤT ĐỐI XỨNG với thứ đã có
84
+
85
+ Nếu trục dọc có `xl` mà trục ngang không có, khoảng trống ấy gần như luôn là
86
+ **quên**, không phải quyết định. Sửa cho cân là rẻ và không tranh cãi.
87
+
88
+ ---
89
+
90
+ ## Cái KHÔNG đáng vào — và vì sao
91
+
92
+ **Bố cục của một màn hình cụ thể.** Nó thuộc về màn hình đó. Nếu ba màn cùng
93
+ cần, lúc ấy nó đã thành hình dạng và quay lại câu hỏi 2.
94
+
95
+ **Một giá trị dùng đúng một lần.** Đừng đẻ prop cho nó — dùng cửa thoát
96
+ (`gapRaw`, `padRaw`). Cửa thoát để lại `data-*-raw` trên DOM nên đếm được; khi
97
+ số đếm ấy lớn lên, ĐÓ mới là lúc nó thành một trục đáng có tên.
98
+
99
+ **Lỗ kiểu dáng tự do** (`styles={{ slot }}`, `classNames={{ slot }}`). Nó đóng
100
+ băng cấu trúc DOM nội bộ thành API công khai, và audit **không đếm được** nó
101
+ (một object style dựng ở đâu cũng được rồi spread vào). Nó cũng ngược hẳn với
102
+ `style: 0/289` — lập trường nhất quán hiện nay là cho prop ý định, không cho lỗ
103
+ kiểu dáng.
104
+
105
+ **Gu thẩm mỹ.** "Dùng nhiều khoảng trắng", "hai màu nhấn là đủ", "tránh lưới
106
+ bento". Không kiểm chứng được, không cổng nào canh, và khi nó tới tay agent
107
+ TRƯỚC luật cứng thì kết quả là mã đẹp mà sai hợp đồng.
108
+
109
+ **Thứ chỉ tiết kiệm vài dòng ở call site.** Nếu đường hiện tại đã hợp lệ và
110
+ đọc được, việc rút ngắn nó không phải việc của design system.
111
+
112
+ ---
113
+
114
+ ## Thêm rồi thì NỢ gì
115
+
116
+ Một prop mới chưa xong khi nó biên dịch được. Ba việc bắt buộc, và cả ba đều đã
117
+ có cổng CI:
118
+
119
+ 1. **Vào catalog.** Chạy `node scripts/gen-component-api-manifest.mjs`.
120
+ `check:component-api-manifest` canh việc này. **Không vào catalog thì agent
121
+ không biết nó tồn tại** — và đó không phải giả thuyết: `pad`/`padRaw` được
122
+ thêm vào gói nhưng catalog phát hành chưa có, nên một agent tra MCP đúng quy
123
+ trình vẫn kết luận "Flex chỉ có gap" và bỏ cuộc trước 21 lỗi mà nó có thể
124
+ sửa.
125
+
126
+ 2. **Có bằng chứng phủ từng nhánh giá trị.** `component-case-evidence.json` +
127
+ `check:frame-coverage-ledger`. Bằng chứng phải trỏ vào test THẬT SỰ chạy qua
128
+ nhánh ấy, không phải một tệp cho có.
129
+
130
+ 3. **Có ví dụ BIÊN DỊCH ĐƯỢC.** Hậu quả đo được khi không kiểm: pattern
131
+ `confirm-destructive` truyền cho `Dialog` một prop `mode` không tồn tại,
132
+ hướng dẫn DataTable dùng `variant="success"` (chính thứ luật
133
+ `status-tone-not-variant` cấm), và ví dụ `Input` gọi một prop
134
+ `onValueChange` không có thật. Agent chép chúng và viết ra mã hỏng.
135
+
136
+ Ba chỗ ấy đã sửa, và `check:doc-prop-existence` nay bắt được lớp lỗi đó.
137
+ Lưu ý khi viết tài liệu: cổng ấy đọc mọi đoạn JSX trong `docs/**` như mã
138
+ THẬT, nên **trích dẫn một API sai để làm ví dụ cũng bị bắt**. Mô tả bằng lời
139
+ như đoạn trên, đừng dán một thẻ JSX hoàn chỉnh vào.
140
+
141
+ ---
142
+
143
+ ## Một lợi ích ẩn của việc rời Radix, đo được
144
+
145
+ `check:doc-prop-existence` canh chiều "mọi prop dùng trong ví dụ đều phải tồn
146
+ tại" — chính lớp lỗi khiến agent chép ví dụ rồi viết ra mã hỏng (prop `mode`
147
+ trên `Dialog`, prop `onValueChange` trên `Input`). Nhưng nó **bỏ qua mọi
148
+ component bọc primitive bên thứ ba**, vì với chúng manifest chỉ là cận dưới:
149
+ prop thật nằm trong types của Radix, generator không mở ra được.
150
+
151
+ Số đo (08/09/2026):
152
+
153
+ | | component KHÔNG kiểm được |
154
+ | --------------------------------------------- | ------------------------- |
155
+ | `main` | **139 / 289** |
156
+ | `feat/v20-react-aria` (6 primitive đã chuyển) | **126 / 289** |
157
+
158
+ Mỗi primitive rời Radix là `declaredIn` chuyển từ `node_modules` vào `src/`, và
159
+ component đó **bước vào vùng kiểm được**. Sáu primitive đầu đã gỡ rào cho 13
160
+ component.
161
+
162
+ Nên đợt đổi nền không chỉ là thay thư viện. Nó là cách duy nhất làm cho 126
163
+ component còn lại có thể được canh — và trong số đó có `Dialog`, `Input`,
164
+ `Badge`, tức đúng những component mà ví dụ sai đã lọt qua.
165
+
166
+ ## Khi câu trả lời là "không thuộc về đây"
167
+
168
+ Nói ra ở chỗ gặp nó, bằng mã:
169
+
170
+ ```tsx
171
+ /*
172
+ * KHÔNG thuộc về design system: bề rộng này là số đo của riêng màn hình
173
+ * quản trị thành viên, không phải một trục của Table. Nếu màn thứ hai cần
174
+ * cùng thứ, lúc đó mở issue.
175
+ */
176
+ ```
177
+
178
+ Một dòng như thế đáng giá hơn một issue mở rồi bỏ đấy — nó nói cho người sau
179
+ biết ai đã cân nhắc, và cân nhắc ra sao.
@@ -0,0 +1,81 @@
1
+ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@godxjp/ui/data-display";
2
+ import { Flex, PageContainer } from "@godxjp/ui/layout";
3
+ import { BarChart } from "@godxjp/ui/charts";
4
+
5
+ /**
6
+ * 横棒グラフの分類軸と、カードの見出しとの重複 — gh#409 · 1 と 2。
7
+ *
8
+ * 監理団体の実習実施者(受入企業)名は「株式会社」を含む 8〜10 文字の全角で、幅は 100〜125px に
9
+ * なります。分類軸の幅を固定にすると、名前の**先頭**、つまり識別に必要な部分から切り落とされます。
10
+ * BarChart は実際に描画される字形で各目盛りを実測し、いちばん広い目盛りに合わせて軸を確保します。
11
+ * 上限はトークン `--chart-category-axis-max-fraction` が持ち、これを超える名前だけが**末尾**で
12
+ * 省略され、全文は目盛りの `<title>` と図の代替テキストに残ります。
13
+ *
14
+ * 下段のカードは `showCaption={false}`。`CardTitle` が見出しを担うので、キャプションは
15
+ * `sr-only` として DOM に残り、`role="img"` の名前は失われません。
16
+ */
17
+
18
+ /** 実習実施者ごとの受入人数。企業名は 8〜10 文字の全角で、固定幅の軸では先頭が消えていました。 */
19
+ const acceptances = [
20
+ { company: "株式会社山田製作所", trainees: 42 },
21
+ { company: "佐藤食品株式会社", trainees: 35 },
22
+ { company: "株式会社中村建設", trainees: 28 },
23
+ { company: "東海精密工業株式会社", trainees: 24 },
24
+ { company: "みどり農産株式会社", trainees: 18 },
25
+ { company: "大和金属加工株式会社", trainees: 12 },
26
+ ];
27
+
28
+ export default function Demo() {
29
+ return (
30
+ <PageContainer
31
+ title="CJK category axis"
32
+ subtitle="横棒グラフの分類軸を実測で確保し、見出しの重複をなくす"
33
+ >
34
+ <Flex direction="col" gap="lg">
35
+ <Card>
36
+ <CardHeader>
37
+ <CardTitle level={2}>横棒 BarChart · 分類軸は目盛りの実測で決まる</CardTitle>
38
+ <CardDescription>
39
+ いちばん広い目盛りに合わせて軸幅を確保します。キャプションは既定どおり表示。
40
+ </CardDescription>
41
+ </CardHeader>
42
+ <CardContent>
43
+ <BarChart
44
+ id="cjk-axis-chart"
45
+ label="実習実施者別 受入人数"
46
+ data={acceptances}
47
+ categoryKey="company"
48
+ series={[{ dataKey: "trainees", label: "受入人数" }]}
49
+ showLegend={false}
50
+ size="md"
51
+ horizontal
52
+ />
53
+ </CardContent>
54
+ </Card>
55
+
56
+ <Card>
57
+ <CardHeader>
58
+ <CardTitle level={2}>実習実施者別 受入人数</CardTitle>
59
+ <CardDescription>
60
+ `showCaption={"{false}"}` — 見出しは CardTitle が担い、キャプションは sr-only
61
+ として残るのでアクセシブルな名前は保たれます。
62
+ </CardDescription>
63
+ </CardHeader>
64
+ <CardContent>
65
+ <BarChart
66
+ id="cjk-axis-chart-no-caption"
67
+ label="実習実施者別 受入人数"
68
+ data={acceptances}
69
+ categoryKey="company"
70
+ series={[{ dataKey: "trainees", label: "受入人数" }]}
71
+ showLegend={false}
72
+ showCaption={false}
73
+ size="md"
74
+ horizontal
75
+ />
76
+ </CardContent>
77
+ </Card>
78
+ </Flex>
79
+ </PageContainer>
80
+ );
81
+ }
@@ -281,6 +281,28 @@ export default function Demo() {
281
281
  </Card>
282
282
  </ResponsiveGrid>
283
283
  </Flex>
284
+
285
+ <Card>
286
+ <CardHeader>
287
+ <CardTitle level={2}>連続したツールバー</CardTitle>
288
+ </CardHeader>
289
+ <CardContent>
290
+ <Text>本文</Text>
291
+ </CardContent>
292
+ <CardBar pad={{ block: 1, inline: 3 }} surface="muted" border="block-start" gap="sm">
293
+ <Button variant="ghost" size="sm">
294
+ 添付
295
+ </Button>
296
+ </CardBar>
297
+ <CardBar
298
+ pad={{ block: 2, inline: 3 }}
299
+ border="block-start"
300
+ gap="sm"
301
+ extra={<Button>送信</Button>}
302
+ >
303
+ <Text tone="muted">下書きを保存しました</Text>
304
+ </CardBar>
305
+ </Card>
284
306
  </Flex>
285
307
  </PageContainer>
286
308
  );
@@ -0,0 +1,257 @@
1
+ import { useState } from "react";
2
+
3
+ import {
4
+ Card,
5
+ CardContent,
6
+ Badge,
7
+ DataTable,
8
+ Descriptions,
9
+ TableCell,
10
+ TableRow,
11
+ type ColumnDef,
12
+ } from "@godxjp/ui/data-display";
13
+ import { Text } from "@godxjp/ui/general";
14
+ import { Flex, PageContainer } from "@godxjp/ui/layout";
15
+
16
+ /**
17
+ * DataTable / Descriptions — the Ant Design 6.6.2 parity surface on one screen: frozen columns
18
+ * (`fixed`), truncation (`ellipsis`), multi-column sort (`sorter.multiple`), header filters
19
+ * (`filters` + `onFilter`), the full `rowSelection` object, `expandable` detail rows, a `summary`
20
+ * totals row, a `scroll` envelope and a bordered `Descriptions` on a responsive column ladder.
21
+ *
22
+ * It is also the MEASUREMENT surface: the frozen columns and the scroll envelope are geometry, and
23
+ * geometry is verified against this page in a browser, not by eye.
24
+ */
25
+ type Line = {
26
+ id: string;
27
+ code: string;
28
+ partner: string;
29
+ note: string;
30
+ status: "active" | "pending" | "failed";
31
+ region: string;
32
+ owner: string;
33
+ updated: string;
34
+ amount: number;
35
+ };
36
+
37
+ const STATUS_TONE = { active: "success", pending: "warning", failed: "destructive" } as const;
38
+ const STATUS_LABEL = { active: "有効", pending: "保留", failed: "失敗" } as const;
39
+
40
+ const BASE_ROWS: Line[] = [
41
+ {
42
+ id: "L-1",
43
+ code: "INV-0312",
44
+ partner: "株式会社ベトヤ",
45
+ note: "四月分の請求。検収は完了しているが振込確認が未了のため保留にしている。",
46
+ status: "active",
47
+ region: "関東",
48
+ owner: "田中",
49
+ updated: "2024-04-12",
50
+ amount: 482000,
51
+ },
52
+ {
53
+ id: "L-2",
54
+ code: "INV-0311",
55
+ partner: "ハノイ物流",
56
+ note: "越境輸送分。通関書類の差し替えを依頼済み。",
57
+ status: "pending",
58
+ region: "海外",
59
+ owner: "佐藤",
60
+ updated: "2024-04-11",
61
+ amount: 128400,
62
+ },
63
+ {
64
+ id: "L-3",
65
+ code: "INV-0310",
66
+ partner: "GMO決済",
67
+ note: "決済手数料。月次で自動計上される。",
68
+ status: "active",
69
+ region: "関東",
70
+ owner: "田中",
71
+ updated: "2024-04-10",
72
+ amount: 64800,
73
+ },
74
+ {
75
+ id: "L-4",
76
+ code: "INV-0309",
77
+ partner: "東京ロジ",
78
+ note: "再送分。前回の請求が差し戻されたため再発行している。",
79
+ status: "failed",
80
+ region: "関東",
81
+ owner: "鈴木",
82
+ updated: "2024-04-09",
83
+ amount: 312000,
84
+ },
85
+ {
86
+ id: "L-5",
87
+ code: "INV-0308",
88
+ partner: "大阪商事",
89
+ note: "年間契約の四半期按分。",
90
+ status: "pending",
91
+ region: "関西",
92
+ owner: "鈴木",
93
+ updated: "2024-04-08",
94
+ amount: 900500,
95
+ },
96
+ ];
97
+
98
+ /**
99
+ * Enough rows for the `scroll.y` envelope to actually bite — five rows never reach an 18rem cap,
100
+ * and a cap that never clips proves nothing.
101
+ */
102
+ const ROWS: Line[] = [
103
+ ...BASE_ROWS,
104
+ ...BASE_ROWS.map((row, i) => ({
105
+ ...row,
106
+ id: `${row.id}-b`,
107
+ code: `INV-02${String(10 + i).padStart(2, "0")}`,
108
+ updated: `2024-03-${String(10 + i).padStart(2, "0")}`,
109
+ })),
110
+ ];
111
+
112
+ const yen = new Intl.NumberFormat("ja-JP", {
113
+ style: "currency",
114
+ currency: "JPY",
115
+ maximumFractionDigits: 0,
116
+ });
117
+
118
+ const columns: ColumnDef<Line>[] = [
119
+ // Frozen to the inline start — the identity column stays put while the grid scrolls.
120
+ { key: "code", header: "伝票番号", fixed: "start", width: "150px", sorter: { multiple: 2 } },
121
+ { key: "partner", header: "取引先", width: "220px" },
122
+ // One line, truncated, with the full text kept as the cell's title.
123
+ { key: "note", header: "備考", ellipsis: true, width: "260px" },
124
+ {
125
+ key: "status",
126
+ header: "状態",
127
+ width: "140px",
128
+ filters: [
129
+ { text: "有効", value: "active" },
130
+ { text: "保留", value: "pending" },
131
+ { text: "失敗", value: "failed" },
132
+ ],
133
+ onFilter: (value, row) => row.status === value,
134
+ render: (row) => <Badge tone={STATUS_TONE[row.status]}>{STATUS_LABEL[row.status]}</Badge>,
135
+ },
136
+ {
137
+ key: "region",
138
+ header: "地域",
139
+ width: "140px",
140
+ filters: [
141
+ { text: "関東", value: "関東" },
142
+ { text: "関西", value: "関西" },
143
+ { text: "海外", value: "海外" },
144
+ ],
145
+ filterMultiple: false,
146
+ onFilter: (value, row) => row.region === value,
147
+ },
148
+ { key: "owner", header: "担当", width: "140px", sorter: { multiple: 1 } },
149
+ {
150
+ key: "updated",
151
+ header: "更新日",
152
+ width: "160px",
153
+ sorter: true,
154
+ sortDirections: ["desc", "asc"],
155
+ },
156
+ // Frozen to the inline end — the amount stays readable at any scroll position.
157
+ {
158
+ key: "amount",
159
+ header: "金額",
160
+ align: "right",
161
+ fixed: "end",
162
+ width: "160px",
163
+ sorter: (a, b) => a.amount - b.amount,
164
+ render: (row) => yen.format(row.amount),
165
+ },
166
+ ];
167
+
168
+ export default function AntdParityDemo() {
169
+ const [selected, setSelected] = useState<string[]>([]);
170
+
171
+ return (
172
+ <PageContainer title="Ant Design パリティ" subtitle="DataTable / Descriptions">
173
+ <Flex direction="col" gap="lg">
174
+ <Card>
175
+ <CardContent flush>
176
+ <DataTable
177
+ data={ROWS}
178
+ columns={columns}
179
+ getRowId={(row) => row.id}
180
+ bordered
181
+ showSorterTooltip
182
+ scroll={{ x: 1400, y: "18rem" }}
183
+ sticky
184
+ rowSelection={{
185
+ selectedRowKeys: selected,
186
+ onChange: (keys) => {
187
+ setSelected(keys);
188
+ },
189
+ selections: true,
190
+ getCheckboxProps: (row) => ({ disabled: row.status === "failed" }),
191
+ preserveSelectedRowKeys: true,
192
+ }}
193
+ expandable={{
194
+ expandedRowRender: (row) => (
195
+ <Descriptions bordered columns={{ sm: 2, lg: 3 }} layout="horizontal">
196
+ <Descriptions.Item label="伝票番号" mono>
197
+ {row.code}
198
+ </Descriptions.Item>
199
+ <Descriptions.Item label="担当">{row.owner}</Descriptions.Item>
200
+ <Descriptions.Item label="地域">{row.region}</Descriptions.Item>
201
+ <Descriptions.Item label="備考" span="filled">
202
+ {row.note}
203
+ </Descriptions.Item>
204
+ </Descriptions>
205
+ ),
206
+ rowExpandable: (row) => row.status !== "failed",
207
+ }}
208
+ summary={(rows) => (
209
+ <TableRow>
210
+ <TableCell />
211
+ <TableCell />
212
+ <TableCell>合計</TableCell>
213
+ <TableCell />
214
+ <TableCell />
215
+ <TableCell />
216
+ <TableCell />
217
+ <TableCell />
218
+ <TableCell>
219
+ {yen.format(rows.reduce((sum, row) => sum + row.amount, 0))}
220
+ </TableCell>
221
+ </TableRow>
222
+ )}
223
+ onRow={(row) => ({ "data-row-key": row.id })}
224
+ >
225
+ <DataTable.Toolbar>
226
+ <DataTable.Search />
227
+ <Flex direction="row" gap="sm" align="center">
228
+ <DataTable.ViewOptions />
229
+ <DataTable.DensityToggle />
230
+ </Flex>
231
+ </DataTable.Toolbar>
232
+ <DataTable.Content />
233
+ <DataTable.Pagination />
234
+ </DataTable>
235
+ </CardContent>
236
+ </Card>
237
+
238
+ <Card>
239
+ <CardContent>
240
+ <Text size="sm" tone="muted">
241
+ 選択中: {selected.length} 件
242
+ </Text>
243
+ <Descriptions bordered columns={{ sm: 2, lg: 4 }}>
244
+ <Descriptions.Item label="伝票数">{ROWS.length}</Descriptions.Item>
245
+ <Descriptions.Item label="通貨">JPY</Descriptions.Item>
246
+ <Descriptions.Item label="期間">2024-04-08 ~ 2024-04-12</Descriptions.Item>
247
+ <Descriptions.Item label="ステータス">確定前</Descriptions.Item>
248
+ <Descriptions.Item label="メモ" span="filled">
249
+ Ant Design 6.6.2 の `bordered` と `column` レスポンシブ指定をそのまま受ける。
250
+ </Descriptions.Item>
251
+ </Descriptions>
252
+ </CardContent>
253
+ </Card>
254
+ </Flex>
255
+ </PageContainer>
256
+ );
257
+ }