@godxjp/ui 28.9.0 → 28.12.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 (244) hide show
  1. package/agent/START-HERE.md +193 -0
  2. package/agent/anti-ai-tells.json +158 -0
  3. package/agent/components/Accordion.json +60 -0
  4. package/agent/components/AccountChip.json +59 -0
  5. package/agent/components/Actions.json +78 -0
  6. package/agent/components/Activity.json +80 -0
  7. package/agent/components/Affix.json +78 -0
  8. package/agent/components/Alert.json +65 -0
  9. package/agent/components/AlertDialog.json +109 -0
  10. package/agent/components/AlertDialogRoot.json +52 -0
  11. package/agent/components/Anchor.json +119 -0
  12. package/agent/components/AppLauncher.json +95 -0
  13. package/agent/components/AppProvider.json +105 -0
  14. package/agent/components/AppSettingPicker.json +88 -0
  15. package/agent/components/AppSettingToggle.json +70 -0
  16. package/agent/components/AppShell.json +159 -0
  17. package/agent/components/AreaChart.json +105 -0
  18. package/agent/components/AspectRatio.json +38 -0
  19. package/agent/components/Attachments.json +77 -0
  20. package/agent/components/AuthAccountSummary.json +64 -0
  21. package/agent/components/AuthDivider.json +35 -0
  22. package/agent/components/AuthFooter.json +48 -0
  23. package/agent/components/AuthIdentity.json +42 -0
  24. package/agent/components/AuthShell.json +108 -0
  25. package/agent/components/AuthStack.json +21 -0
  26. package/agent/components/Avatar.json +89 -0
  27. package/agent/components/Badge.json +96 -0
  28. package/agent/components/Banner.json +48 -0
  29. package/agent/components/BarChart.json +108 -0
  30. package/agent/components/BranchScopePicker.json +89 -0
  31. package/agent/components/Breadcrumb.json +54 -0
  32. package/agent/components/Button.json +133 -0
  33. package/agent/components/Calendar.json +259 -0
  34. package/agent/components/Callout.json +46 -0
  35. package/agent/components/Card.json +112 -0
  36. package/agent/components/CardBar.json +49 -0
  37. package/agent/components/CardContent.json +51 -0
  38. package/agent/components/Carousel.json +50 -0
  39. package/agent/components/Cascader.json +209 -0
  40. package/agent/components/CenteredShell.json +66 -0
  41. package/agent/components/ChatBubble.json +100 -0
  42. package/agent/components/ChatBubbleList.json +64 -0
  43. package/agent/components/ChatComposer.json +160 -0
  44. package/agent/components/ChatSuggestion.json +86 -0
  45. package/agent/components/Checkbox.json +68 -0
  46. package/agent/components/CheckboxGroup.json +96 -0
  47. package/agent/components/CodeBlock.json +64 -0
  48. package/agent/components/Collapsible.json +74 -0
  49. package/agent/components/ColorPicker.json +87 -0
  50. package/agent/components/Command.json +168 -0
  51. package/agent/components/CommandPalette.json +84 -0
  52. package/agent/components/CompactBarTrend.json +101 -0
  53. package/agent/components/Conversations.json +82 -0
  54. package/agent/components/CredentialReveal.json +93 -0
  55. package/agent/components/DataState.json +79 -0
  56. package/agent/components/DataTable.json +268 -0
  57. package/agent/components/DatePicker.json +275 -0
  58. package/agent/components/Descriptions.json +67 -0
  59. package/agent/components/Dialog.json +78 -0
  60. package/agent/components/DraggablePanel.json +106 -0
  61. package/agent/components/DropdownMenu.json +102 -0
  62. package/agent/components/EmptyState.json +83 -0
  63. package/agent/components/ErrorSurface.json +128 -0
  64. package/agent/components/FeatureList.json +43 -0
  65. package/agent/components/Field.json +64 -0
  66. package/agent/components/FilterBar.json +99 -0
  67. package/agent/components/Flex.json +153 -0
  68. package/agent/components/FloatButton.json +91 -0
  69. package/agent/components/Form.json +87 -0
  70. package/agent/components/FormErrors.json +51 -0
  71. package/agent/components/FormField.json +137 -0
  72. package/agent/components/FormFieldArray.json +39 -0
  73. package/agent/components/FormFieldControl.json +129 -0
  74. package/agent/components/FormRoot.json +122 -0
  75. package/agent/components/Heading.json +61 -0
  76. package/agent/components/HoverCard.json +55 -0
  77. package/agent/components/Icon.json +60 -0
  78. package/agent/components/InfiniteQueryState.json +58 -0
  79. package/agent/components/Input.json +122 -0
  80. package/agent/components/InputOTP.json +106 -0
  81. package/agent/components/Label.json +43 -0
  82. package/agent/components/LegalDocumentShell.json +102 -0
  83. package/agent/components/Legend.json +42 -0
  84. package/agent/components/LineChart.json +103 -0
  85. package/agent/components/Link.json +41 -0
  86. package/agent/components/ListRow.json +92 -0
  87. package/agent/components/Logo.json +85 -0
  88. package/agent/components/Marquee.json +91 -0
  89. package/agent/components/Masonry.json +82 -0
  90. package/agent/components/MasterDetail.json +95 -0
  91. package/agent/components/MegaMenu.json +120 -0
  92. package/agent/components/MobileShell.json +73 -0
  93. package/agent/components/NavList.json +63 -0
  94. package/agent/components/NumberInput.json +158 -0
  95. package/agent/components/OrgSwitcher.json +89 -0
  96. package/agent/components/OverlayPortalProvider.json +42 -0
  97. package/agent/components/PageContainer.json +181 -0
  98. package/agent/components/Pagination.json +132 -0
  99. package/agent/components/Paragraph.json +40 -0
  100. package/agent/components/PasswordInput.json +79 -0
  101. package/agent/components/PasswordStrength.json +51 -0
  102. package/agent/components/PermissionMatrix.json +81 -0
  103. package/agent/components/PieChart.json +99 -0
  104. package/agent/components/Popover.json +110 -0
  105. package/agent/components/PrefetchLink.json +65 -0
  106. package/agent/components/Progress.json +79 -0
  107. package/agent/components/Prose.json +57 -0
  108. package/agent/components/QrCode.json +62 -0
  109. package/agent/components/Radio.json +98 -0
  110. package/agent/components/RadioGroup.json +91 -0
  111. package/agent/components/RangeTimeline.json +80 -0
  112. package/agent/components/Rating.json +92 -0
  113. package/agent/components/ResizablePanel.json +69 -0
  114. package/agent/components/ResponsiveGrid.json +77 -0
  115. package/agent/components/Reveal.json +70 -0
  116. package/agent/components/ScrollArea.json +104 -0
  117. package/agent/components/SearchInput.json +98 -0
  118. package/agent/components/Segmented.json +96 -0
  119. package/agent/components/Select.json +397 -0
  120. package/agent/components/Separator.json +86 -0
  121. package/agent/components/ServiceCatalogCta.json +46 -0
  122. package/agent/components/ServiceLauncherCard.json +93 -0
  123. package/agent/components/ServiceRolePanel.json +83 -0
  124. package/agent/components/Sheet.json +85 -0
  125. package/agent/components/Sidebar.json +118 -0
  126. package/agent/components/Skeleton.json +57 -0
  127. package/agent/components/SkeletonArticle.json +71 -0
  128. package/agent/components/SkeletonAvatar.json +50 -0
  129. package/agent/components/SkeletonButton.json +57 -0
  130. package/agent/components/SkeletonForm.json +52 -0
  131. package/agent/components/SkeletonImage.json +37 -0
  132. package/agent/components/SkeletonInput.json +51 -0
  133. package/agent/components/SkeletonNode.json +42 -0
  134. package/agent/components/SkeletonRows.json +49 -0
  135. package/agent/components/SkeletonTable.json +45 -0
  136. package/agent/components/Slider.json +160 -0
  137. package/agent/components/SplitPane.json +66 -0
  138. package/agent/components/StatCard.json +83 -0
  139. package/agent/components/Steps.json +95 -0
  140. package/agent/components/Swatch.json +41 -0
  141. package/agent/components/Switch.json +81 -0
  142. package/agent/components/Table.json +112 -0
  143. package/agent/components/Tabs.json +158 -0
  144. package/agent/components/TagInput.json +105 -0
  145. package/agent/components/Text.json +201 -0
  146. package/agent/components/Textarea.json +126 -0
  147. package/agent/components/ThoughtChain.json +76 -0
  148. package/agent/components/Thumbnail.json +70 -0
  149. package/agent/components/TimePicker.json +200 -0
  150. package/agent/components/TimeRangePicker.json +90 -0
  151. package/agent/components/Timeline.json +47 -0
  152. package/agent/components/TimelineGrid.json +92 -0
  153. package/agent/components/Title.json +67 -0
  154. package/agent/components/Toaster.json +42 -0
  155. package/agent/components/Toggle.json +90 -0
  156. package/agent/components/ToggleGroup.json +102 -0
  157. package/agent/components/Toolbar.json +120 -0
  158. package/agent/components/Tooltip.json +110 -0
  159. package/agent/components/Topbar.json +83 -0
  160. package/agent/components/TopbarItem.json +79 -0
  161. package/agent/components/Transfer.json +141 -0
  162. package/agent/components/Tree.json +185 -0
  163. package/agent/components/TreeSelect.json +232 -0
  164. package/agent/components/TwoFactorSetup.json +79 -0
  165. package/agent/components/Typography.json +42 -0
  166. package/agent/components/Upload.json +221 -0
  167. package/agent/components/UploadCropDialog.json +60 -0
  168. package/agent/components/VisuallyHidden.json +20 -0
  169. package/agent/components/Welcome.json +65 -0
  170. package/agent/components/formatDate.json +46 -0
  171. package/agent/components/inertiaUpload.json +32 -0
  172. package/agent/components/useZodForm.json +39 -0
  173. package/agent/components-index.json +884 -0
  174. package/agent/components.json +15515 -0
  175. package/agent/index.json +56 -0
  176. package/agent/llms.txt +32 -0
  177. package/agent/patterns/account-recovery-settings.json +19 -0
  178. package/agent/patterns/async-data-state.json +20 -0
  179. package/agent/patterns/auth-recovery-panels.json +29 -0
  180. package/agent/patterns/badge-coloring.json +14 -0
  181. package/agent/patterns/common-fixes.json +16 -0
  182. package/agent/patterns/confirm-destructive.json +11 -0
  183. package/agent/patterns/data-table-page.json +18 -0
  184. package/agent/patterns/deferred-loading.json +12 -0
  185. package/agent/patterns/error-pages.json +28 -0
  186. package/agent/patterns/inertia-detail-page.json +13 -0
  187. package/agent/patterns/inertia-list-page.json +15 -0
  188. package/agent/patterns/inertia-persistent-layout.json +14 -0
  189. package/agent/patterns/organization-memberships.json +19 -0
  190. package/agent/patterns/page-sections.json +18 -0
  191. package/agent/patterns/settings-page-responsive.json +18 -0
  192. package/agent/patterns/settings-section-rows.json +23 -0
  193. package/agent/patterns/signup-form.json +13 -0
  194. package/agent/patterns/topbar-account-chip.json +18 -0
  195. package/agent/patterns/transactional-email.json +22 -0
  196. package/agent/patterns-index.json +323 -0
  197. package/agent/patterns.json +342 -0
  198. package/agent/rules.json +237 -0
  199. package/agent/tokens.json +8427 -0
  200. package/agent/vocabulary.json +198 -0
  201. package/dist/components/data-display/service-launcher-card.d.ts +19 -0
  202. package/dist/components/data-display/service-launcher-card.js +14 -1
  203. package/dist/components/data-entry/attachments.js +77 -33
  204. package/dist/components/data-entry/input.js +8 -1
  205. package/dist/components/layout/flex.d.ts +2 -2
  206. package/dist/components/layout/flex.js +2 -0
  207. package/dist/components/ui/avatar.d.ts +1 -18
  208. package/dist/components/ui/avatar.js +1 -36
  209. package/dist/components/ui/tag-input.d.ts +10 -0
  210. package/dist/components/ui/tag-input.js +35 -2
  211. package/dist/contracts/measurement.json +1 -1
  212. package/dist/i18n/messages/en.json +190 -1
  213. package/dist/i18n/messages/ja.json +188 -1
  214. package/dist/i18n/messages/vi.json +188 -1
  215. package/dist/lib/image-loading-status.d.ts +25 -0
  216. package/dist/lib/image-loading-status.js +41 -0
  217. package/dist/props/components/data-entry.prop.d.ts +21 -2
  218. package/dist/props/components/layout.prop.d.ts +42 -0
  219. package/dist/props/registry.d.ts +14 -1
  220. package/dist/props/registry.js +18 -1
  221. package/dist/styles/card-layout.css +10 -4
  222. package/dist/styles/control.css +33 -4
  223. package/dist/styles/data-display-layout.css +1 -1
  224. package/dist/styles/data-entry-layout.css +245 -2
  225. package/dist/styles/layout.css +17 -0
  226. package/dist/styles/navigation-layout.css +3 -1
  227. package/dist/styles/shell-layout.css +2 -0
  228. package/dist/styles/table-layout.css +50 -9
  229. package/dist/tokens/components/attachments.css +18 -9
  230. package/dist/tokens/components/segmented.css +7 -3
  231. package/dist/tokens/components/table.css +2 -1
  232. package/docs/COMPOSITION-VS-COMPONENT.md +41 -0
  233. package/docs/DESIGN-AUTHORITY.md +52 -0
  234. package/docs/DEVELOPMENT.md +81 -6
  235. package/docs/assets/service-mark-rose.svg +6 -0
  236. package/docs/assets/service-mark-teal.svg +5 -0
  237. package/docs/data-display/service-launcher-card.tsx +232 -92
  238. package/docs/data-entry/tag-input.tsx +37 -0
  239. package/docs/layout/flex.tsx +40 -0
  240. package/docs/roadmap/website-components.md +34 -0
  241. package/docs/showcase/marketing-page.tsx +54 -45
  242. package/docs/showcase/table-pagination.tsx +99 -18
  243. package/docs/showcase/theme-customization.tsx +25 -2
  244. package/package.json +8 -5
@@ -0,0 +1,66 @@
1
+ {
2
+ "example": "import { SplitPane } from \"@godxjp/ui/layout\";\n\n<SplitPane aside={<DetailPanel />} asideWidth=\"sm\">\n <MainContent />\n</SplitPane>\n\n// Collapsible rail — closing with `null` does NOT remount <MessageList />.\n<SplitPane asideLabel=\"Thread\" aside={threadOpen ? <Thread /> : null}>\n <MessageList />\n</SplitPane>",
3
+ "group": "layout",
4
+ "importPath": "@godxjp/ui/layout",
5
+ "name": "SplitPane",
6
+ "props": [
7
+ {
8
+ "description": "Main (left) content.",
9
+ "name": "children",
10
+ "required": true,
11
+ "type": "ReactNode"
12
+ },
13
+ {
14
+ "description": "Aside (trailing) panel content. `null` means CLOSED: no `<aside>` element is rendered, the grid drops to one full-width column and the gap goes with it. Closing through this prop — instead of dropping SplitPane at the call site — keeps `children` mounted, because the wrappers stay in place and the main column keeps its position in the React tree.",
15
+ "name": "aside",
16
+ "required": true,
17
+ "type": "ReactNode | null"
18
+ },
19
+ {
20
+ "defaultValue": "\"md\"",
21
+ "description": "Width preset for the aside rail: sm 20rem, md 22rem, lg 30rem. `lg` is for a rail that carries a panel rather than a list, and it holds off splitting until the pane is 64rem wide so the main column stays the wider of the two.",
22
+ "name": "asideWidth",
23
+ "type": "\"sm\" | \"md\" | \"lg\""
24
+ },
25
+ {
26
+ "description": "Accessible name for the `<aside>` complementary landmark. Required when more than one complementary landmark shares the document, so a screen-reader landmark list says which rail is which.",
27
+ "name": "asideLabel",
28
+ "type": "string"
29
+ },
30
+ {
31
+ "defaultValue": "false",
32
+ "description": "Take the remaining height of the parent instead of growing with the content. Default false keeps the pane content-height, which is right inside a scrolling page. Set it for an app-shell surface whose columns own their own scrolling — a chat transcript with a pinned composer, a full-height table beside a detail rail: the pane and both columns get a DEFINITE height, so overflow inside a column scrolls that column instead of pushing the page taller. The parent still decides how much height there is to fill: inside a flex column, give the wrapper `flex: 1; min-height: 0`.",
33
+ "name": "fill",
34
+ "type": "boolean"
35
+ }
36
+ ],
37
+ "related": [
38
+ "ResponsiveGrid — use when you need more than two columns, or when both columns must have equal or percentage-based widths rather than a fixed-rem aside. SplitPane always gives main a `1fr` and aside a fixed rem width.",
39
+ "PageContainer — use as the outer scaffold that provides page padding and vertical rhythm; nest SplitPane inside PageContainer, not the other way around.",
40
+ "Sheet — use when the detail/context panel should slide in as an overlay (drawer) rather than sitting permanently beside the main content. Prefer Sheet on mobile or when the aside content is secondary and on-demand.",
41
+ "Flex direction='col' — use when content is purely vertical (single column, sequential sections). SplitPane is the right pick only when a persistent side panel is needed at the same hierarchy level as the main content."
42
+ ],
43
+ "rules": [
44
+ 24
45
+ ],
46
+ "storyPath": "layout/SplitPane.stories.tsx",
47
+ "tagline": "Two-column layout with a main content area and a fixed-width aside panel.",
48
+ "usage": [
49
+ "DO: pass all right-panel content via the `aside` prop — it renders inside a semantic `<aside>` element at a fixed rem width (sm=20rem, md=22rem). The `children` prop fills the main `1fr` column. Both accept any ReactNode.",
50
+ "DO: reach for `fill` when the pane is an app-shell surface rather than a block in a scrolling page — a chat transcript whose composer stays pinned to the bottom, a full-height table beside a detail rail. It is the supported way to say \"be as tall as what is left\"; a consumer that instead styles the pane's wrapper divs from outside (`[&>*]`, `[&>*>*]`) is targeting this component's internal DOM by position and will break the day another wrapper appears.",
51
+ "DO: choose `asideWidth=\"sm\"` for compact detail panels (filters, quick stats, key-value summaries) and the default `asideWidth=\"md\"` for richer panels (forms, timelines, long metadata lists).",
52
+ "DO: wrap SplitPane inside `PageContainer` or `PageContainer.Inset` — SplitPane provides no page padding of its own. It is a grid primitive, not a page scaffold.",
53
+ "DO: close a collapsible rail with `aside={null}` — a Slack-style thread, a Linear-style detail panel — rather than swapping `<SplitPane aside={<Thread />}>{page}</SplitPane>` for a bare `{page}`. Both look the same on screen; only the prop keeps `children` mounted. The conditional swap changes the DEPTH of `{page}` in the React tree, so React remounts it: measured in a consumer as a message list jumping from scrollTop 400 to the bottom the instant a thread opened, losing the reader's place and any component state below it.",
54
+ "DON'T: leave `SplitPane` mounted with an empty `aside={<div />}` to avoid that remount — an empty aside still reserves its rail, leaving a blank 20-30rem column. `aside={null}` removes the element AND the column (the pane sets `data-aside=\"closed\"` on itself, so the collapse is one CSS rule, not a call-site width override).",
55
+ "DON'T: expect two columns below 48rem OF THE PANE'S OWN WIDTH (64rem for `asideWidth=\"lg\"`). The split is a CSS container query on the pane, not a viewport media query, so a narrow embedded pane on a large screen correctly stays single-column and a wide pane on a small screen still splits. Below the threshold it stacks (main on top, aside below); for layouts that must stay side-by-side at any width use CSS Grid or `ResponsiveGrid`.",
56
+ "DON'T: add a CSS `overflow: hidden` or fixed height on the SplitPane wrapper; both columns carry `min-width: 0` to handle overflow correctly, and the grid uses `minmax(0, 1fr)` — adding external constraints will break the overflow contract.",
57
+ "DON'T: hand-roll a two-column div layout with flexbox or CSS Grid when SplitPane already ships — that duplicates the responsive breakpoint logic and the semantic `<aside>` element."
58
+ ],
59
+ "useCases": [
60
+ "Invoice / transaction detail page: list of records in `children` (DataTable), selected-record detail panel in `aside` (Descriptions + Timeline).",
61
+ "Accounting ledger drill-down: account list on the left, chart-of-accounts metadata or running balance breakdown on the right using `asideWidth=\"sm\"`.",
62
+ "Document review workflow: PDF or rich-text viewer in `children`, approval form or annotation panel in `aside`.",
63
+ "Settings page with a category list or Steps navigator in `children` and a live preview or summary card in `aside`.",
64
+ "Kanban or task board where the main area holds the board columns and the aside shows the focused task detail without navigating away."
65
+ ]
66
+ }
@@ -0,0 +1,83 @@
1
+ {
2
+ "example": "import { StatCard } from \"@godxjp/ui/data-display\";\nimport { ResponsiveGrid } from \"@godxjp/ui/layout\";\n\n// ✅ StatCard sits directly in the grid — it draws its own card + border.\n<ResponsiveGrid columns={3}>\n <StatCard label=\"総会員数\" value=\"12,450\" hint=\"先月比 +3%\" />\n <StatCard label=\"月次売上\" value=\"¥8,200,000\" delta=\"+12%\" />\n <StatCard label=\"利用率\" value=\"68.4%\" />\n</ResponsiveGrid>\n\n// ❌ Double border — do NOT wrap StatCard in a Card:\n// <Card><CardContent><StatCard label=\"x\" value=\"1\" /></CardContent></Card>",
3
+ "group": "data-display",
4
+ "importPath": "@godxjp/ui/data-display",
5
+ "name": "StatCard",
6
+ "props": [
7
+ {
8
+ "description": "Metric name.",
9
+ "name": "label",
10
+ "required": true,
11
+ "type": "ReactNode"
12
+ },
13
+ {
14
+ "description": "Metric value (string/number/ReactNode).",
15
+ "name": "value",
16
+ "required": true,
17
+ "type": "ReactNode"
18
+ },
19
+ {
20
+ "description": "Secondary context below the value.",
21
+ "name": "hint",
22
+ "type": "ReactNode"
23
+ },
24
+ {
25
+ "description": "Optional leading icon rendered as a tinted medallion above the metric. Decorative (aria-hidden) — the label carries the meaning. Tint via the --stat-card-icon-{background,foreground} tokens (default a soft brand-primary wash).",
26
+ "name": "icon",
27
+ "type": "LucideIcon"
28
+ },
29
+ {
30
+ "description": "Compact trend text beside the value. Sign-aware tone (+ green / - red).",
31
+ "name": "delta",
32
+ "type": "ReactNode"
33
+ },
34
+ {
35
+ "defaultValue": "\"stacked\"",
36
+ "description": "stacked = label over value; inline = label left / value right.",
37
+ "name": "layout",
38
+ "type": "\"stacked\" | \"inline\""
39
+ },
40
+ {
41
+ "description": "Align the metric group.",
42
+ "name": "align",
43
+ "type": "\"start\" | \"end\""
44
+ },
45
+ {
46
+ "defaultValue": "false",
47
+ "description": "Flip delta tone semantics for metrics where lower is better (cost, error rate): '-' renders green, '+' renders red.",
48
+ "name": "inverse",
49
+ "type": "boolean"
50
+ },
51
+ {
52
+ "description": "Semantic 3px leading-edge rail (forwarded to the underlying Card) — flags a KPI that needs attention (e.g. attention = backlog with a deadline, destructive = overdue).",
53
+ "name": "accent",
54
+ "type": "\"primary\" | \"success\" | \"warning\" | \"info\" | \"attention\" | \"destructive\""
55
+ }
56
+ ],
57
+ "related": [
58
+ "ResponsiveGrid — required layout wrapper for StatCard grids; controls column count and responsive breakpoints. Always pair them together.",
59
+ "SkeletonStat — exact loading placeholder shaped like a StatCard tile; swap in while KPI data is fetching, then replace with the real StatCard.",
60
+ "Descriptions — use instead when displaying multiple label/value metadata pairs on a detail page (not headline KPIs); Descriptions is not card-bordered and does not show delta/hint slots.",
61
+ "Card + CardContent — use when you need a general-purpose content container with a header, footer, or arbitrary body; do NOT wrap StatCard inside these.",
62
+ "LineChart / BarChart / PieChart (@godxjp/ui/charts) — when the trend or composition BEHIND a KPI matters, pair the StatCard headline number with a chart in the same dashboard grid: StatCard states the figure, the chart shows its shape over time or its breakdown."
63
+ ],
64
+ "rules": [],
65
+ "storyPath": "data-display/StatCard.stories.tsx",
66
+ "tagline": "KPI tile. ⚠️ StatCard IS ALREADY a bordered Card — render it DIRECTLY in ResponsiveGrid. NEVER wrap it in <Card>/<CardContent> (that double-borders it → looks too thick). Use `accent` for a semantic leading-edge rail on a KPI needing attention.",
67
+ "usage": [
68
+ "DO place StatCard directly as a child of ResponsiveGrid — it renders its own bordered Card shell internally, so no wrapping <Card> or <CardContent> is needed or allowed. Wrapping creates a double border.",
69
+ "DO pass `delta` as a sign-prefixed string (e.g. '+12%' or '-3%') to get automatic color tone: '+' renders text-success, '-' renders text-destructive. For metrics where a negative delta is good (e.g. cost reduction, error rate), pass `inverse` so the tone is flipped correctly.",
70
+ "DO use `hint` for secondary context (e.g. '先月比 +3%', 'last 30 days'). In the default `stacked` layout hint renders below the value; in `inline` layout it renders beside the label.",
71
+ "DO use `accent` (not a className border) for the semantic leading-edge rail — `attention` for a non-destructive backlog needing action, `destructive` only for overdue/exceeded states. Most tiles in a grid stay rail-less; an all-accented grid says nothing.",
72
+ "DO NOT hand-roll a KPI tile using a plain <Card><CardContent>. StatCard is the correct primitive and token-aligns the label/value/hint/delta slots automatically.",
73
+ "WHILE data is loading, replace each StatCard with a <SkeletonStat /> at the same grid position — never render an empty value string or a spinner inside StatCard itself."
74
+ ],
75
+ "useCases": [
76
+ "Dashboard KPI row: monthly revenue, invoice count, overdue balance, and collection rate displayed side-by-side in a ResponsiveGrid with delta trend vs previous period.",
77
+ "Accounting summary header: total debits, total credits, and net balance for a journal entry list page, each with a hint showing the date range in scope.",
78
+ "Coupon/membership admin overview: active members, live coupons, monthly redemptions, and total discount amount — the canonical example in the catalog.",
79
+ "Inline variant for a narrow sidebar or detail panel where space is constrained: label on the left, large value on the right (layout='inline'), e.g. contract value next to a deal record.",
80
+ "Cost or error-rate metrics where a falling number is positive: pass `inverse` so a '-15%' delta shows green, preventing misleading red-for-good UI.",
81
+ "Loading state for any KPI grid: render the same ResponsiveGrid columns filled with <SkeletonStat /> components while the query is in-flight, then replace with StatCard tiles once data resolves."
82
+ ]
83
+ }
@@ -0,0 +1,95 @@
1
+ {
2
+ "example": "import { Steps } from \"@godxjp/ui/navigation\";\n\n<Steps value={1} items={[{ title: \"申請\" }, { title: \"審査中\" }, { title: \"完了\" }]} />",
3
+ "group": "navigation",
4
+ "importPath": "@godxjp/ui/navigation",
5
+ "name": "Steps",
6
+ "props": [
7
+ {
8
+ "description": "Array of { title, subtitle?, description?, icon?, status? }.",
9
+ "name": "items",
10
+ "type": "StepItemProp[]"
11
+ },
12
+ {
13
+ "defaultValue": "0",
14
+ "description": "Active step index (0-based).",
15
+ "name": "value",
16
+ "type": "number"
17
+ },
18
+ {
19
+ "defaultValue": "0",
20
+ "description": "Base offset for the first rendered step index.",
21
+ "name": "defaultValue",
22
+ "type": "number"
23
+ },
24
+ {
25
+ "defaultValue": "\"horizontal\"",
26
+ "description": "Layout direction.",
27
+ "name": "orientation",
28
+ "type": "\"horizontal\" | \"vertical\""
29
+ },
30
+ {
31
+ "description": "Status of the CURRENT step (drives the active step colour).",
32
+ "name": "status",
33
+ "type": "\"wait\" | \"process\" | \"finish\" | \"error\""
34
+ },
35
+ {
36
+ "description": "Render full markers, compact dots, a numbered inline auth progress row, or Ant Design's `navigation` bar — slab steps with a chevron between them (the default hairline connector is switched off there so it is not drawn through the glyph). `dot` IS antd's `progressDot`; antd 6.6.2 deprecates that prop in favour of exactly this value.",
37
+ "name": "type",
38
+ "type": "\"default\" | \"dot\" | \"inline\" | \"navigation\""
39
+ },
40
+ {
41
+ "description": "Ant Design `percent` — completion of the CURRENT (`process`) step only, 0–100 (out-of-range values are clamped). Draws a determinate arc around that step's marker and exposes it as a real `progressbar` with aria-valuenow/min/max. Ignored by `type=\"inline\"`, which has no marker to draw into.",
42
+ "name": "percent",
43
+ "type": "number"
44
+ },
45
+ {
46
+ "description": "Step size.",
47
+ "name": "size",
48
+ "type": "\"md\" | \"sm\""
49
+ },
50
+ {
51
+ "description": "Lay step titles beside or below the step icons.",
52
+ "name": "titlePlacement",
53
+ "type": "\"horizontal\" | \"vertical\""
54
+ },
55
+ {
56
+ "defaultValue": "\"chevron\"",
57
+ "description": "`chevron` (›) is the breadcrumb-flavoured original; `arrow` (→) is the canonical hosted-identity progression marker — a chevron reads \"drill into\", an arrow reads \"then\", which is what a step row means. Both flip under dir=\"rtl\". Ignored by every other `type`.",
58
+ "name": "separator",
59
+ "type": "\"chevron\" | \"arrow\""
60
+ },
61
+ {
62
+ "description": "Fires with the clicked step index (0-based).",
63
+ "name": "onValueChange",
64
+ "type": "(value: number) => void"
65
+ }
66
+ ],
67
+ "related": [
68
+ "Timeline — use Timeline (from @godxjp/ui) when you need a chronological event log with timestamps and variable content per entry; use Steps when the number of stages is fixed and forward-progress is the semantic.",
69
+ "Tabs / Tabs — use Tabs when each section has its own rendered panel and users switch freely between them; use Steps when stages are ordered and the indicator communicates completion state rather than just selection.",
70
+ "Progress — use Progress for a single continuous percentage (file upload, quota fill); use Steps for discrete named stages with individual pass/fail status.",
71
+ "Breadcrumb — use Breadcrumb for hierarchical location within a page tree; use Steps for sequential workflow progress where order and completion matter."
72
+ ],
73
+ "rules": [],
74
+ "storyPath": "navigation/Steps.stories.tsx",
75
+ "tagline": "Multi-step progress indicator — horizontal or vertical, default or dot style.",
76
+ "usage": [
77
+ "DO: Pass all steps via the `items` array (each `{ title, subtitle?, description?, icon?, status?, disabled? }`) — Steps is a single-component API with no child sub-components to compose manually.",
78
+ "DO: Control the active step with `value` (0-based index). For async operations, set the top-level `status` prop (`'process'|'error'|'finish'`) to override the current step's icon — e.g. `status='error'` turns the active step red without touching `items`.",
79
+ "DO: Use per-item `status` to pin individual steps independently of `value` (e.g. a skipped or already-errored step). Per-item `status` takes precedence over the derived status from `value`.",
80
+ "DO: Use type='inline' for compact hosted-auth/device progress. It retains process/finish/error/wait and aria-current semantics without the tall icon rail; never rebuild the row from Text and arrows in a consumer.",
81
+ "DO: Pick the inline progression marker with `separator` (`\"arrow\"` for the canonical hosted-identity row, `\"chevron\"` for the default), and express the step-number emphasis through `--steps-inline-index-{color,font-weight}` + `--steps-inline-separator-color` in the service theme. The canonical treatment is an accent TINT at normal weight; the library default is bold at the inherited colour. Both are one token away — never fork `.ui-steps-inline-index` in app CSS.",
82
+ "DON'T: Use Steps for navigation that needs URL routing or tab-switching — it has no built-in panel rendering. Pair it with your own conditional panel or a `Tabs`/`Tabs` body; Steps only renders the indicator bar.",
83
+ "DON'T: Wire `onValueChange` unless you actually support non-linear navigation. `onValueChange` makes every non-disabled step clickable (rendered as `<button>`); omitting it makes all steps non-interactive (`cursor-default`). Never set `disabled` on an item without also providing `onValueChange`, or the prop is meaningless.",
84
+ "A11y: The `<ol>` is given `aria-label='Progress'` automatically. Individual steps render as `<button type='button'>` when `onValueChange` is present — ensure each `item.title` is descriptive enough to serve as the button label; avoid icon-only steps without a visible title.",
85
+ "DO: Put a `data-testid` (or an `id`, or any other DOM attribute) straight on `<Steps>` — the rest of an `<ol>`'s attributes ride through to the list element. NEVER bind a test to `.ui-steps-list` or to a `[data-status]` on an item: those are internal names this package renames without notice, and a suite that binds to them breaks on an upgrade that changed nothing about the component's contract. A caller-supplied `aria-label` also wins over the localized default.",
86
+ "NOTE: `type` on Steps is the MARKER APPEARANCE (`default` | `dot` | `inline` | `navigation`), not an `<ol>`'s numbering style — the native attribute of that name is deliberately not forwarded."
87
+ ],
88
+ "useCases": [
89
+ "Multi-step form wizard (entity onboarding, invoice creation): render Steps above a form, drive `current` from local state, advance on validated submit — use `status='error'` on the current step when server validation fails.",
90
+ "Async background job tracker: display steps for a long-running import/export pipeline; poll job status and map job phases to `StepStatusProp` values (`'process'` with spinner for in-flight, `'finish'` for done, `'error'` for failed).",
91
+ "Document approval workflow (accounting, contracts): map approval stages (Draft → Review → Approved → Archived) to `items` with per-item `status` reflecting the real state from the server — use `orientation='vertical'` for a sidebar timeline feel.",
92
+ "Onboarding checklist sidebar: `orientation='vertical'` + `type='dot'` + `size='sm'` for a compact sidebar progress guide alongside a multi-section settings page.",
93
+ "Non-linear step navigation (e.g. revisit a previous step to correct data): provide `onValueChange` and leave only future steps `disabled`; past and current steps become clickable buttons."
94
+ ]
95
+ }
@@ -0,0 +1,41 @@
1
+ {
2
+ "example": "import { Swatch } from \"@godxjp/ui/data-display\";\nimport { Text } from \"@godxjp/ui/general\";\nimport { Flex } from \"@godxjp/ui/layout\";\n\n<Flex align=\"center\" gap=\"sm\">\n <Swatch color={brand.primary_color} aria-label={`プライマリカラー: ${brand.primary_color}`} />\n <Text weight=\"medium\">{brand.name}</Text>\n</Flex>",
3
+ "group": "data-display",
4
+ "importPath": "@godxjp/ui/data-display",
5
+ "name": "Swatch",
6
+ "props": [
7
+ {
8
+ "description": "The colour to show, as any CSS colour value (#7C3AED, rgb(…), oklch(…)). It is DATA, the same axis as Badge's `color`: a value a person picked in a settings screen, so it arrives as a prop and never enters a stylesheet. A colour that MEANS something (success, overdue) is not this prop — use Badge `tone` or Legend, which name the meaning.",
9
+ "name": "color",
10
+ "required": true,
11
+ "type": "string"
12
+ },
13
+ {
14
+ "description": "The sample's accessible NAME, and the reason a swatch can be shown with no visible label: say what the colour is for AND what it is, e.g. `プライマリカラー: #7C3AED`. With it the mark is role=img and announces that sentence; WITHOUT it the mark is aria-hidden, which is correct only when a visible line beside it already states the colour. Colour is never the sole carrier of meaning either way (WCAG 1.4.1).",
15
+ "name": "aria-label",
16
+ "type": "string"
17
+ }
18
+ ],
19
+ "related": [
20
+ "Legend — the KEY for a colour-coded surface: closed semantic tones, each with required words. Swatch is one sample of an arbitrary value and takes its name from aria-label.",
21
+ "ColorPicker — the INPUT for the same value. Swatch displays; ColorPicker chooses.",
22
+ "Badge — a chip that labels a thing (and can carry the entity's own `color` as a wash). Swatch is the colour itself, with no chip around it."
23
+ ],
24
+ "rules": [],
25
+ "storyPath": "data-display/Swatch.stories.tsx",
26
+ "tagline": "A READ-ONLY sample of ONE colour a person chose — a brand's primary_color, a calendar category, a tag tint. The colour is a VALUE on the element, never a token in a stylesheet.",
27
+ "usage": [
28
+ "DO import from `@godxjp/ui/data-display`: `import { Swatch } from \"@godxjp/ui/data-display\";`",
29
+ "DO give it an aria-label whenever it is the only thing on screen saying what the colour is, and omit the label when the row's own text already says it — a swatch that repeats its neighbour announces the same thing twice.",
30
+ "DO let the hairline do its job: it is built in so a white or near-white value is still a visible sample on a white card, and it survives forced-colors (the colour IS the content here, so it is not repainted).",
31
+ "DON'T reach for it for a STATUS colour. success/warning/overdue are meanings, and a meaning belongs on Badge `tone` or in a Legend, which spell the meaning out in words.",
32
+ "DON'T render a disabled ColorPicker to display a colour — that is an input that looks broken. ColorPicker is for CHOOSING the value; Swatch is for showing it.",
33
+ "DON'T size it with a className. The mark's size, radius and hairline are the --swatch-* tokens, so a theme retunes every sample at once."
34
+ ],
35
+ "useCases": [
36
+ "An organisation's brand card: primary_color and secondary_color beside the organisation name, read-only, with the hex in the accessible name.",
37
+ "A list of calendar categories, label colours or tags where each row's own text already names the colour and the mark is purely visual.",
38
+ "A settings screen showing the colour currently saved, next to the ColorPicker that changes it.",
39
+ "A table cell whose column is 'colour' — one sample per row, named by the row header."
40
+ ]
41
+ }
@@ -0,0 +1,81 @@
1
+ {
2
+ "example": "import { Field, Switch } from \"@godxjp/ui/data-entry\";\n\n// Field, not a hand-rolled row: it owns the label-to-control id wiring, the description slot and\n// the row rhythm. A <div className=\"flex items-center gap-2\"> around a bare <Label> loses all three.\n<Field id=\"stackable\" label=\"他クーポンとの併用を許可\" description=\"会計時に自動で合算されます\">\n <Switch id=\"stackable\" checked={stackable} onCheckedChange={setStackable} />\n</Field>",
3
+ "group": "data-entry",
4
+ "importPath": "@godxjp/ui/data-entry",
5
+ "name": "Switch",
6
+ "props": [
7
+ {
8
+ "defaultValue": "false",
9
+ "description": "antd `loading` — the toggle is mid-flight: a spinner replaces the thumb glyph and the control refuses the change. It reports `aria-busy`/`aria-disabled` rather than `disabled`, so a keyboard user's focus is not thrown to the next field the instant they flip a switch that saves over the network.",
10
+ "name": "loading",
11
+ "type": "boolean"
12
+ },
13
+ {
14
+ "description": "antd `checkedChildren` — content shown INSIDE the track while on (`有効`, `ON`, a glyph). Rendered aria-hidden: `role=switch` + `aria-checked` already say on/off.",
15
+ "name": "checkedChildren",
16
+ "type": "React.ReactNode"
17
+ },
18
+ {
19
+ "description": "antd `unCheckedChildren` — the same, shown while off.",
20
+ "name": "unCheckedChildren",
21
+ "type": "React.ReactNode"
22
+ },
23
+ {
24
+ "description": "Controlled checked state.",
25
+ "name": "checked",
26
+ "type": "boolean"
27
+ },
28
+ {
29
+ "defaultValue": "false",
30
+ "description": "Uncontrolled initial state. Switch keeps its own state from here, so an uncontrolled toggle works without Field.",
31
+ "name": "defaultChecked",
32
+ "type": "boolean"
33
+ },
34
+ {
35
+ "description": "Fires when toggled.",
36
+ "name": "onCheckedChange",
37
+ "type": "(checked: boolean) => void"
38
+ },
39
+ {
40
+ "defaultValue": "\"md\"",
41
+ "description": "Thumb size — 'sm' for dense rows.",
42
+ "name": "size",
43
+ "type": "\"sm\" | \"md\""
44
+ },
45
+ {
46
+ "description": "Links to a <Label htmlFor>.",
47
+ "name": "id",
48
+ "type": "string"
49
+ },
50
+ {
51
+ "defaultValue": "false",
52
+ "description": "Disable the toggle.",
53
+ "name": "disabled",
54
+ "type": "boolean"
55
+ }
56
+ ],
57
+ "related": [
58
+ "Field — use this instead of a bare Switch whenever the toggle needs a visible label, a description, a pressable help affordance (`labelAddon`) or a validation message (`error`, which wires aria-invalid / aria-errormessage / aria-describedby for you, gh#812). Native submission is the Switch's own job: give it `name` and it renders the hidden input itself.",
59
+ "Checkbox — use Checkbox (or CheckboxGroup) when the user is selecting one or more items from a set, or when the binary choice semantically means 'agree/select' rather than 'enable/disable'. Switch implies an immediate, persistent state change; Checkbox implies a form choice.",
60
+ "Field — use for a binary or small-set choice rendered as radio-style cards with rich descriptions, when the visual weight of a toggle is insufficient for the decision importance.",
61
+ "RadioGroup — use when the user must choose exactly one option from 2–4 mutually exclusive values; Switch is only appropriate for a single on/off boolean."
62
+ ],
63
+ "rules": [],
64
+ "storyPath": "data-entry/Switch.stories.tsx",
65
+ "tagline": "Toggle switch (bare), on react-aria-components. For a labelled row use Field. `role=\"switch\"` is the real `<input>`; the painted track is the `<label>` around it, and that is where `data-state`/`data-size` live.",
66
+ "usage": [
67
+ "DO use Switch (bare) only when you are building a custom inline toggle without a visible label — e.g., a DataTable row action column. Always pair it with a <Label htmlFor={id}> placed adjacent in the DOM; never leave it label-less for screen readers.",
68
+ "DO pass `name` when the toggle must submit: Switch itself renders `<input type=\"hidden\" name value=\"1|0\">` beside the control, so a native <form> carries the value with no extra wiring. (The old advice here — that a bare Switch drops `name` — was never true of this component.)",
69
+ "DO use the `size` prop ('sm' | 'md') to control thumb size. 'sm' is appropriate in dense DataTable rows or filter bars; omit it (defaults to 'md') everywhere else.",
70
+ "DO wire controlled state: pass both `checked` and `onCheckedChange` together. For uncontrolled use pass `defaultChecked` (or neither) — Switch holds that state itself; Field is not required for it.",
71
+ "DON'T hand-roll a <div> + <label> wrapper with bare Switch to get a labelled field — that is exactly what Field provides, including aria-describedby, aria-invalid, error/helper text, and the hidden input. Reach for Field instead.",
72
+ "DO link the switch to its label via matching `id` on Switch and `htmlFor` on Label. Without this pairing, clicking the label text does not toggle the switch and the a11y association is broken."
73
+ ],
74
+ "useCases": [
75
+ "Inline toggle in a DataTable action cell (e.g., 'Active' column) where the label is already provided by the column header and no form submission is involved.",
76
+ "Settings panel where a React state boolean is toggled immediately via an optimistic API call — no <form> submit, so Field's hidden input is unnecessary.",
77
+ "Custom compound component where you compose Switch + Label yourself and need to put your own aria-* or data-* attributes on the control.",
78
+ "Filter toolbar toggle (e.g., 'Show archived') rendered inline next to other filter controls, using size='sm' for density parity with adjacent inputs.",
79
+ "Preview/demo UI where the switch controls a local display state (dark-mode preview, feature flag preview) with no server persistence."
80
+ ]
81
+ }
@@ -0,0 +1,112 @@
1
+ {
2
+ "example": "import { Table, TableHeader, TableBody, TableRow, TableHead, TableCell } from \"@godxjp/ui/data-display\";\n\n<Table>\n <TableHeader><TableRow><TableHead>項目</TableHead><TableHead numeric>金額</TableHead></TableRow></TableHeader>\n <TableBody>\n <TableRow><TableCell>送料</TableCell><TableCell numeric>¥500</TableCell></TableRow>\n <TableRow><TableCell indent={1}>うち離島加算</TableCell><TableCell numeric>¥200</TableCell></TableRow>\n <TableRow><TableCell flush colSpan={2}><ShippingBreakdown /></TableCell></TableRow>\n </TableBody>\n</Table>",
3
+ "group": "data-display",
4
+ "importPath": "@godxjp/ui/data-display",
5
+ "name": "Table",
6
+ "props": [
7
+ {
8
+ "description": "PER-INSTANCE column measures for preset=\"action-collection\", in place of re-pointing its --table-action-collection-* knobs from a consumer stylesheet. Those knobs are global by design, and that is the problem: two collections on one screen do not share a column budget — a console that widened `actions` globally so a Japanese status badge would stop breaking to one character per line (an SC 1.4.10 reflow failure) collapsed a sibling table's name column to ~15px in the same change. Emitted as inline custom properties, the same contract Flex `width` uses for a call-site measurement, leaving data-column-widths on the DOM so each escape stays countable.",
9
+ "name": "columnWidths",
10
+ "type": "{ actions?: string; actionsCompact?: string; metaCompact?: string; minInlineSizeCompact?: string }"
11
+ },
12
+ {
13
+ "description": "On TableHead/TableCell: logical text alignment.",
14
+ "name": "align",
15
+ "type": "\"start\" | \"center\" | \"end\""
16
+ },
17
+ {
18
+ "description": "On TableHead/TableCell: tabular figures and end alignment; explicit align wins.",
19
+ "name": "numeric",
20
+ "type": "boolean"
21
+ },
22
+ {
23
+ "description": "On TableHead/TableCell: allow text to wrap.",
24
+ "name": "wrap",
25
+ "type": "boolean"
26
+ },
27
+ {
28
+ "description": "On TableHead/TableCell: column measure; numbers mean CSS pixels.",
29
+ "name": "width",
30
+ "type": "WidthProp"
31
+ },
32
+ {
33
+ "description": "TableHeader / TableBody composition.",
34
+ "name": "children",
35
+ "required": true,
36
+ "type": "ReactNode"
37
+ },
38
+ {
39
+ "description": "Extra classes on the table element.",
40
+ "name": "className",
41
+ "type": "string"
42
+ },
43
+ {
44
+ "description": "Whether Table owns its own horizontal-scroll region (default true). Leave true for a standalone table so a table wider than its container scrolls in a keyboard-reachable wrapper. Set false only when an ancestor already provides the scroll region (DataTable does) to avoid a redundant nested scroller + duplicate keyboard tab stop.",
45
+ "name": "scrollable",
46
+ "type": "boolean"
47
+ },
48
+ {
49
+ "defaultValue": "false",
50
+ "description": "Draw the full cell GRID: an outer frame plus vertical rules between columns (the horizontal row rules already come from TableRow). Reach for it whenever the table carries rowSpan/colSpan merged cells — without column rules the merge relationships are unreadable. Colour comes from --table-border-color (default --border). Default false emits nothing.",
51
+ "name": "bordered",
52
+ "type": "boolean"
53
+ },
54
+ {
55
+ "description": "Zebra rows: every EVEN LOGICAL body row paints --table-row-striped-background (default --muted at 0.8 alpha — every text role on it stays at AA). Mark a hand-composed detail row `<TableRow data-expanded-row=\"\">` and it is skipped when counting and wears its record's stripe. OMIT to inherit the theme default (`--table-row-striped-alpha`, 0% unless the service set it); `true` emits data-striped=\"\" (100%), `false` emits data-striped=\"false\" (0%) for this table only.",
56
+ "name": "striped",
57
+ "type": "boolean"
58
+ },
59
+ {
60
+ "defaultValue": "\"default\"",
61
+ "description": "Named collection contract. \"default\" emits no attribute and keeps the plain table. \"action-collection\" is the canonical dense approval/action queue: the desktop INTRINSIC column widths (which make a five-column queue wider than its card and force a horizontal scroll at 390) are replaced by table-layout: fixed plus the token-owned column PRIORITY measures (--table-action-collection-*), and cells wrap. Mark each column with `priority` on its TableHead AND its TableCell. Semantics are untouched — no display change, no role rewriting, no card transformation — so header association, aria-sort and screen-reader table navigation are identical at 390 and 1440.",
62
+ "name": "preset",
63
+ "type": "\"default\" | \"action-collection\""
64
+ },
65
+ {
66
+ "defaultValue": "\"sm\"",
67
+ "description": "Step at which preset=\"action-collection\" switches to the compact priority measures, measured against the TABLE'S OWN container (a container query), not the viewport — a table inside a master rail collapses before the page does. Ignored while preset is \"default\".",
68
+ "name": "collapseBelow",
69
+ "type": "\"sm\" | \"md\" | \"lg\" | \"xl\""
70
+ },
71
+ {
72
+ "description": "Accessible name for the horizontal-scroll REGION — the tabindex=\"0\" wrapper a keyboard user lands on to scroll a table wider than its container — NOT for the <table> element (pass aria-label for that; it still reaches the table). OPTIONAL: left out, the region takes the localized dataTable.scrollRegion default (\"Scrollable table\"), so no consumer has to invent a name for every table. Pass a plain string when the page can say WHICH table; a non-string node cannot be an aria-label and falls back to the default. The wrapper carries role=\"group\" (not \"region\" — a named region is a LANDMARK, and several tables on one page would then collide under axe landmark-unique) and is emitted ONLY while the region actually has overflow to reach, measured at runtime: a table that fits adds no tab stop, no role and no name. (gh#817)",
73
+ "name": "label",
74
+ "type": "LabelProp"
75
+ }
76
+ ],
77
+ "related": [
78
+ "DataTable — choose DataTable for any data array that needs sorting, filtering, pagination, row selection, bulk actions, or density toggle. DataTable internally renders Table primitives, so switching up is non-breaking. Default to DataTable for all admin list pages.",
79
+ "SkeletonTable — use as a loading placeholder before a Table or DataTable mounts. Drop it in the `skeleton` slot of DataState, or render it directly while data is fetching. Do not show a Table with empty rows as a loading state.",
80
+ "Descriptions — choose Descriptions when content is label→value pairs (two columns, no repeated rows of the same type). Table is better when every row shares the same typed columns.",
81
+ "DataState — when your Table's data comes from `useQuery`, wrap it in DataState to handle loading/error/empty states declaratively instead of writing conditional logic around the Table yourself."
82
+ ],
83
+ "rules": [],
84
+ "storyPath": "data-display/Table.stories.tsx",
85
+ "subParts": [
86
+ "TableBody",
87
+ "TableCell",
88
+ "TableHead",
89
+ "TableHeader",
90
+ "TableRow"
91
+ ],
92
+ "tagline": "Primitive table shell (Table/TableHeader/TableBody/TableRow/TableHead/TableCell). Prefer DataTable for admin lists; use these for custom one-off tables.",
93
+ "usage": [
94
+ "DO compose all six sub-parts in order: wrap with `<Table>`, then `<TableHeader>` containing `<TableRow><TableHead>…</TableRow>`, then `<TableBody>` containing one or more `<TableRow><TableCell>…` rows. Skipping any layer (e.g. bare `<th>` inside `<Table>`) bypasses the design tokens and hover/border styles.",
95
+ "DO use `TableHead` (not `TableCell`) for header cells — it renders `<th>` with `data-slot=\"table-head\"` and the `--table-row-height` CSS variable for consistent header sizing across the design system. `TableCell` renders `<td>` with `data-slot=\"table-cell\"` and is for body rows only.",
96
+ "DO use `numeric` on TableHead/TableCell for tabular end-aligned numbers; `align=\"start|center|end\"` overrides alignment, `wrap` allows multi-line text, and `width` sets a CSS column measure. These props replace alignment and width classes.",
97
+ "DO use `striped` on dense list tables so a row is easy to follow across its columns; to turn it on for EVERY Table and DataTable at once, set `:root { --table-row-striped-alpha: 100%; }` in the theme rather than passing the prop everywhere (`striped={false}` opts one table out). A detail row under a record is `<TableRow data-expanded-row=\"\">` so the stripe counts records, not DOM rows — never stripe with `:nth-child` page CSS or row utilities.",
98
+ "DO NOT hand-roll empty-state handling inside a Table composition. When data can be empty, switch to `DataTable` (which has a built-in empty state) or wrap the `<Table>` with a conditional that renders `<EmptyState>` — never leave a table with only a header and zero rows.",
99
+ "DO NOT use Table for lists that need sorting, filtering, pagination, or row selection — those features are only in `DataTable`. Table is intentionally stateless: it owns no TanStack Table instance, no column definitions, and no toolbar.",
100
+ "DO reach for `preset=\"action-collection\"` for a dense approval / action queue (requester · target · reason · requested date · row actions) that must stay readable at 390px, and mark every column with `priority` on BOTH its `TableHead` and its `TableCell`: `primary` (the row subject), `secondary` (its target), `meta` (a timestamp/id), `actions` (the row-action affordance, whose measure is reserved first so it can never be pushed off-screen). Leave the free-text column unmarked — it takes the remaining space. For text actions such as 対応する, set ColumnDef.width (or TableHead width) to reserve the label measure; leave a content column fluid. The default actions token is sized for icon actions. Do not add a hidden column or page-local breakpoint to make a table fit. The IDENTICAL preset exists on `DataTable` (`preset` + `collapseBelow` on the table, `priority` on the `ColumnDef`) sharing these same tokens — use DataTable when the queue is data-driven and needs sorting/selection/pagination, and reach for the raw `Table` only for a hand-authored queue.",
101
+ "DO reach for `<TableCell flush>` when the cell's CONTENT owns its inset — an expanded detail panel under a row (`<TableCell flush colSpan={n}>`), a nested table, a full-bleed media strip. It drops the cell's own padding so the child spans the whole cell; without it the panel is indented by `--table-cell-space-x` and the only route was a `p-0` utility, which no service theme can reach.",
102
+ "DO express hierarchy with `<TableCell indent={depth}>` — a grouped table's detail rows under their subtotal header, or a tree row under its parent. The measure is `--table-cell-space-x + depth x --table-cell-indent-space-step`, so level 0 sits on the column's own text axis and a service retunes (or flattens) the step in one token. Never hand-roll `style={{ paddingInlineStart }}` at the call site — that is a per-page constant no theme can reach, and it breaks in RTL unless you remember the logical property.",
103
+ "DO place `<Table>` inside a `<CardContent flush>` (or `p-0` card) when embedding in a Card, so the built-in `overflow-auto` wrapper sits flush to the card edges. Wrapping with plain `<CardContent>` adds padding that clips the horizontal scroll shadow."
104
+ ],
105
+ "useCases": [
106
+ "Invoice line-item breakdowns — a fixed, read-only list of product/quantity/unit-price/total rows where columns are predefined and will never need sort or filter controls.",
107
+ "Summary/comparison tables inside a detail panel or Dialog, such as showing two payment plans side-by-side, where the structure is hand-authored and not driven by a data array.",
108
+ "Print or PDF-export views where a minimal, stateless `<table>` element with predictable markup is required and DataTable's JS-driven features would interfere with server-side rendering or CSS print rules.",
109
+ "Embedded sub-tables inside a DataTable expanded row (the inner table uses Table primitives because nesting a full DataTable instance inside another is unsupported).",
110
+ "Static reference tables in documentation, onboarding, or settings pages — e.g. a permission matrix or feature comparison — where every cell is literal JSX content, not from a data array."
111
+ ]
112
+ }