@godxjp/ui 19.5.0 → 20.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (142) hide show
  1. package/dist/components/data-display/card.d.ts +2 -2
  2. package/dist/components/data-display/collapsible.d.ts +23 -4
  3. package/dist/components/data-display/collapsible.js +119 -4
  4. package/dist/components/data-display/index.d.ts +3 -1
  5. package/dist/components/data-display/index.js +2 -0
  6. package/dist/components/data-display/legend.d.ts +15 -0
  7. package/dist/components/data-display/legend.js +11 -0
  8. package/dist/components/data-display/list-row.js +1 -1
  9. package/dist/components/data-display/popover.d.ts +58 -5
  10. package/dist/components/data-display/popover.js +206 -27
  11. package/dist/components/data-display/progress.d.ts +50 -2
  12. package/dist/components/data-display/progress.js +57 -9
  13. package/dist/components/data-entry/calendar.d.ts +1 -1
  14. package/dist/components/data-entry/calendar.js +67 -32
  15. package/dist/components/data-entry/checkbox.d.ts +19 -6
  16. package/dist/components/data-entry/checkbox.js +55 -16
  17. package/dist/components/data-entry/choice-option.d.ts +1 -1
  18. package/dist/components/data-entry/date-range-picker.d.ts +1 -1
  19. package/dist/components/data-entry/field.js +0 -1
  20. package/dist/components/data-entry/form.js +1 -1
  21. package/dist/components/data-entry/label.d.ts +3 -2
  22. package/dist/components/data-entry/label.js +23 -10
  23. package/dist/components/data-entry/month-picker.d.ts +1 -1
  24. package/dist/components/data-entry/month-range-picker.d.ts +1 -1
  25. package/dist/components/data-entry/transfer.js +16 -6
  26. package/dist/components/data-entry/tree-select-strategy.d.ts +1 -1
  27. package/dist/components/data-entry/tree-select.js +29 -12
  28. package/dist/components/data-entry/tree-utils.d.ts +1 -1
  29. package/dist/components/data-entry/upload.js +7 -2
  30. package/dist/components/feedback/dialog.d.ts +105 -38
  31. package/dist/components/feedback/dialog.js +272 -194
  32. package/dist/components/feedback/overlay-close-focus.d.ts +31 -0
  33. package/dist/components/feedback/overlay-close-focus.js +31 -0
  34. package/dist/components/feedback/overlay-header-tone.d.ts +1 -1
  35. package/dist/components/feedback/sheet.d.ts +53 -11
  36. package/dist/components/feedback/sheet.js +150 -81
  37. package/dist/components/feedback/tooltip.d.ts +51 -7
  38. package/dist/components/feedback/tooltip.js +107 -25
  39. package/dist/components/general/button.js +2 -2
  40. package/dist/components/general/logo.d.ts +17 -0
  41. package/dist/components/general/logo.js +22 -16
  42. package/dist/components/general/typography.d.ts +7 -1
  43. package/dist/components/general/typography.js +20 -5
  44. package/dist/components/layout/app-shell.d.ts +1 -1
  45. package/dist/components/layout/app-shell.js +52 -8
  46. package/dist/components/layout/aspect-ratio.js +0 -1
  47. package/dist/components/layout/auth-divider.js +0 -1
  48. package/dist/components/layout/flex.d.ts +1 -1
  49. package/dist/components/layout/flex.js +19 -2
  50. package/dist/components/layout/nav-surface.d.ts +26 -0
  51. package/dist/components/layout/nav-surface.js +17 -0
  52. package/dist/components/layout/org-switcher.d.ts +5 -1
  53. package/dist/components/layout/org-switcher.js +5 -3
  54. package/dist/components/layout/separator.js +0 -1
  55. package/dist/components/layout/sidebar.js +4 -1
  56. package/dist/components/layout/split-pane.d.ts +14 -1
  57. package/dist/components/layout/split-pane.js +26 -13
  58. package/dist/components/layout/topbar-item.js +1 -2
  59. package/dist/components/navigation/app-setting-picker.js +21 -2
  60. package/dist/components/navigation/app-setting-toggle.d.ts +16 -0
  61. package/dist/components/navigation/app-setting-toggle.js +96 -0
  62. package/dist/components/navigation/dropdown-menu.d.ts +199 -18
  63. package/dist/components/navigation/dropdown-menu.js +344 -117
  64. package/dist/components/navigation/index.d.ts +2 -0
  65. package/dist/components/navigation/index.js +2 -0
  66. package/dist/components/navigation/pagination-utils.d.ts +2 -1
  67. package/dist/components/navigation/tabs.d.ts +47 -6
  68. package/dist/components/navigation/tabs.js +152 -90
  69. package/dist/components/ui/accordion.d.ts +50 -5
  70. package/dist/components/ui/accordion.js +239 -33
  71. package/dist/components/ui/aspect-ratio.d.ts +23 -2
  72. package/dist/components/ui/aspect-ratio.js +15 -13
  73. package/dist/components/ui/avatar.d.ts +29 -4
  74. package/dist/components/ui/avatar.js +111 -25
  75. package/dist/components/ui/hover-card.d.ts +42 -4
  76. package/dist/components/ui/hover-card.js +183 -27
  77. package/dist/components/ui/label.js +0 -1
  78. package/dist/components/ui/segmented.d.ts +3 -3
  79. package/dist/components/ui/separator.d.ts +8 -2
  80. package/dist/components/ui/separator.js +17 -9
  81. package/dist/components/ui/toggle-group.d.ts +50 -5
  82. package/dist/components/ui/toggle-group.js +79 -20
  83. package/dist/components/ui/toggle.d.ts +31 -5
  84. package/dist/components/ui/toggle.js +42 -3
  85. package/dist/i18n/messages/en.json +8 -0
  86. package/dist/i18n/messages/ja.json +8 -0
  87. package/dist/i18n/messages/vi.json +8 -0
  88. package/dist/lib/control-styles.d.ts +1 -1
  89. package/dist/lib/control-styles.js +1 -1
  90. package/dist/lib/slot.d.ts +32 -0
  91. package/dist/lib/slot.js +22 -0
  92. package/dist/lib/variants.d.ts +22 -3
  93. package/dist/lib/variants.js +56 -1
  94. package/dist/props/components/app.prop.d.ts +25 -1
  95. package/dist/props/components/data-display.prop.d.ts +17 -0
  96. package/dist/props/components/data-entry.prop.d.ts +32 -4
  97. package/dist/props/components/general.prop.d.ts +31 -1
  98. package/dist/props/components/index.d.ts +1 -1
  99. package/dist/props/components/layout.prop.d.ts +118 -5
  100. package/dist/props/components/navigation.prop.d.ts +1 -1
  101. package/dist/props/registry.d.ts +22 -2
  102. package/dist/props/registry.js +33 -2
  103. package/dist/props/vocabulary/content.prop.d.ts +1 -1
  104. package/dist/props/vocabulary/index.d.ts +2 -2
  105. package/dist/props/vocabulary/interaction.prop.d.ts +17 -1
  106. package/dist/props/vocabulary/layout.prop.d.ts +57 -1
  107. package/dist/styles/control.css +142 -1
  108. package/dist/styles/core.css +5 -2
  109. package/dist/styles/data-display-layout.css +72 -0
  110. package/dist/styles/focus-ring.css +13 -1
  111. package/dist/styles/index.css +5 -2
  112. package/dist/styles/layout.css +106 -0
  113. package/dist/styles/shell-layout.css +140 -8
  114. package/dist/styles/text-layout.css +16 -4
  115. package/dist/tokens/base.css +2 -1
  116. package/dist/tokens/components/data-display.css +11 -0
  117. package/dist/tokens/components/shell.css +3 -1
  118. package/dist/tokens/components/text.css +7 -0
  119. package/dist/tokens/foundation.css +2 -0
  120. package/docs/COMPONENTS.md +9 -3
  121. package/docs/DESIGN-AUTHORITY.md +96 -71
  122. package/docs/FRAME-COVERAGE-REPORT.md +5 -3
  123. package/docs/README.md +14 -14
  124. package/docs/WHAT-BELONGS-HERE.md +179 -0
  125. package/docs/data-display/legend.tsx +145 -0
  126. package/docs/data-display/progress.tsx +32 -0
  127. package/docs/data-entry/segmented.tsx +1 -1
  128. package/docs/data-entry/select.tsx +2 -2
  129. package/docs/feedback/sheet.tsx +1 -1
  130. package/docs/general/typography.tsx +84 -1
  131. package/docs/layout/app-shell-arrangements.tsx +225 -0
  132. package/docs/layout/aspect-ratio.tsx +1 -1
  133. package/docs/navigation/app-setting-picker.tsx +26 -1
  134. package/docs/navigation/app-setting-toggle.tsx +111 -0
  135. package/package.json +11 -8
  136. package/scripts/_agent-setup.mjs +165 -3
  137. package/scripts/consumer-rule.md +98 -0
  138. package/scripts/guinea-pig-skill.md +322 -0
  139. package/scripts/init-guinea-pig.mjs +62 -0
  140. package/scripts/postinstall.mjs +13 -2
  141. package/scripts/ui-audit.mjs +115 -14
  142. /package/dist/tokens/{antd.generated.css → derived.css} +0 -0
@@ -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,145 @@
1
+ import {
2
+ Card,
3
+ CardAction,
4
+ CardContent,
5
+ CardDescription,
6
+ CardHeader,
7
+ CardTitle,
8
+ Legend,
9
+ Progress,
10
+ } from "@godxjp/ui/data-display";
11
+ import { Text } from "@godxjp/ui/general";
12
+ import { Flex, PageContainer } from "@godxjp/ui/layout";
13
+
14
+ const COMPLIANCE = [
15
+ { name: "株式会社山田製作所", over: 2, near: 3, done: 12 },
16
+ { name: "佐藤食品株式会社", over: 1, near: 2, done: 9 },
17
+ { name: "東海精密工業株式会社", over: 0, near: 3, done: 21 },
18
+ ];
19
+
20
+ const STATUS_KEYS = [
21
+ { tone: "destructive", label: "期限超過" },
22
+ { tone: "warning", label: "期限間近" },
23
+ { tone: "success", label: "対応済" },
24
+ ] as const;
25
+
26
+ /**
27
+ * Legend — the KEY for a colour-coded surface: which tone means what, in words, once.
28
+ * Composed only from real @godxjp/ui components.
29
+ */
30
+ export default function Demo() {
31
+ return (
32
+ <PageContainer title="Legend" subtitle="tone → 意味 のキー · 凡例">
33
+ <Flex direction="col" gap="lg">
34
+ <Card>
35
+ <CardHeader>
36
+ <CardTitle level={2}>Progress の breakdown と組む</CardTitle>
37
+ <CardDescription>
38
+ CardAction に置くと、カード見出しと同じ行に凡例が並びます。色の意味をカードで
39
+ 一度だけ言い、各行では繰り返しません。
40
+ </CardDescription>
41
+ <CardAction>
42
+ <Legend items={[...STATUS_KEYS]} />
43
+ </CardAction>
44
+ </CardHeader>
45
+ <CardContent>
46
+ <Flex direction="col" gapRaw={11}>
47
+ {COMPLIANCE.map((row) => (
48
+ <Flex key={row.name} align="center" gapRaw={14}>
49
+ <Flex width={180}>
50
+ <Text weight="medium" truncate>
51
+ {row.name}
52
+ </Text>
53
+ </Flex>
54
+ <Flex fill direction="col">
55
+ <Progress
56
+ segments={[
57
+ { value: row.over, tone: "destructive", label: "期限超過" },
58
+ { value: row.near, tone: "warning", label: "期限間近" },
59
+ { value: row.done, tone: "success", label: "対応済" },
60
+ ]}
61
+ aria-label={row.name}
62
+ />
63
+ </Flex>
64
+ <Flex width={150} justify="end" align="center" gapRaw={12}>
65
+ <Text tone="destructive" weight="semibold" tabular>
66
+ {row.over}
67
+ </Text>
68
+ <Text tone="warning" weight="semibold" tabular>
69
+ {row.near}
70
+ </Text>
71
+ <Text tone="success" weight="semibold" tabular>
72
+ {row.done}
73
+ </Text>
74
+ <Text tone="muted" tabular>
75
+ 計 {row.over + row.near + row.done}
76
+ </Text>
77
+ </Flex>
78
+ </Flex>
79
+ ))}
80
+ </Flex>
81
+ </CardContent>
82
+ </Card>
83
+
84
+ <Card>
85
+ <CardHeader>
86
+ <CardTitle level={2}>Tones</CardTitle>
87
+ <CardDescription>
88
+ vocabulary の 7 tone すべてに塗りがあります。色だけで意味を運ばないため label
89
+ は必須です(WCAG 1.4.1)。
90
+ </CardDescription>
91
+ </CardHeader>
92
+ <CardContent>
93
+ <Legend
94
+ items={[
95
+ { tone: "default", label: "既定(primary)" },
96
+ { tone: "success", label: "成功" },
97
+ { tone: "warning", label: "注意" },
98
+ { tone: "destructive", label: "危険" },
99
+ { tone: "info", label: "情報" },
100
+ { tone: "muted", label: "控えめ" },
101
+ { tone: "neutral", label: "中立" },
102
+ ]}
103
+ />
104
+ </CardContent>
105
+ </Card>
106
+
107
+ <Card>
108
+ <CardHeader>
109
+ <CardTitle level={2}>Named legend</CardTitle>
110
+ <CardDescription>
111
+ aria-label を渡すと、その凡例が「何のキーか」を読み上げます。項目は list /
112
+ listitem として並びます。
113
+ </CardDescription>
114
+ </CardHeader>
115
+ <CardContent>
116
+ <Legend items={[...STATUS_KEYS]} aria-label="コンプライアンス状況の凡例" />
117
+ </CardContent>
118
+ </Card>
119
+
120
+ <Card>
121
+ <CardHeader>
122
+ <CardTitle level={2}>Wrapping</CardTitle>
123
+ <CardDescription>
124
+ 狭い幅では折り返します(横スクロールしません)。凡例が視界の外に出ると、色の意味
125
+ そのものが失われるためです。
126
+ </CardDescription>
127
+ </CardHeader>
128
+ <CardContent>
129
+ <Flex width={240}>
130
+ <Legend
131
+ items={[
132
+ { tone: "destructive", label: "期限超過" },
133
+ { tone: "warning", label: "期限間近" },
134
+ { tone: "success", label: "対応済" },
135
+ { tone: "info", label: "確認中" },
136
+ { tone: "muted", label: "対象外" },
137
+ ]}
138
+ />
139
+ </Flex>
140
+ </CardContent>
141
+ </Card>
142
+ </Flex>
143
+ </PageContainer>
144
+ );
145
+ }
@@ -33,6 +33,38 @@ export default function Demo() {
33
33
  </CardContent>
34
34
  </Card>
35
35
 
36
+ <Card>
37
+ <CardHeader>
38
+ <CardTitle level={2}>Breakdown(segments)</CardTitle>
39
+ <CardDescription>
40
+ 1 つの合計を状態ごとに分割します。割合ではなく実数を渡すと、各スライスの比率は
41
+ コンポーネントが計算します。メーターより背の高いトラックになるのは、0.5rem の pill
42
+ 上に 3 色を並べると比率が読めなくなるためです。role=&quot;img&quot;
43
+ として、全スライスを 1 つの名前で読み上げます。
44
+ </CardDescription>
45
+ </CardHeader>
46
+ <CardContent>
47
+ <Flex direction="col" gap="md">
48
+ <Progress
49
+ segments={[
50
+ { value: 2, tone: "destructive", label: "期限超過" },
51
+ { value: 3, tone: "warning", label: "期限間近" },
52
+ { value: 12, tone: "success", label: "対応済" },
53
+ ]}
54
+ label="株式会社山田製作所"
55
+ />
56
+ <Progress
57
+ segments={[
58
+ { value: 0, tone: "destructive", label: "期限超過" },
59
+ { value: 1, tone: "warning", label: "期限間近" },
60
+ { value: 6, tone: "success", label: "対応済" },
61
+ ]}
62
+ label="みどり農産株式会社(0 件のスライスは幅 0)"
63
+ />
64
+ </Flex>
65
+ </CardContent>
66
+ </Card>
67
+
36
68
  <Card>
37
69
  <CardHeader>
38
70
  <CardTitle level={2}>Over capacity</CardTitle>
@@ -7,7 +7,7 @@ import { Flex, PageContainer } from "@godxjp/ui/layout";
7
7
  import { CalendarDays, Columns3, LayoutList, Monitor, Moon, Sun } from "lucide-react";
8
8
 
9
9
  /**
10
- * Segmented — one-of-N from a small, closed, always-visible set. antd's Segmented drawn on Radix
10
+ * Segmented — one-of-N from a small, closed, always-visible set. The enterprise Segmented drawn on Radix
11
11
  * RadioGroup: a recessed track with the chosen item as a lifted slab, radiogroup semantics, arrow
12
12
  * keys between members. The track measures exactly --control-height, so it sits level with an
13
13
  * Input or a Button on the same row.
@@ -286,8 +286,8 @@ export default function Demo() {
286
286
  <CardHeader>
287
287
  <CardTitle level={2}>labelRender · custom selected display</CardTitle>
288
288
  <CardDescription>
289
- `labelRender` (Ant Design) customizes the SELECTED value shown on the trigger: here an
290
- avatar + name + a role badge. The placeholder still shows when nothing is selected.
289
+ `labelRender` customizes the SELECTED value shown on the trigger: here an avatar +
290
+ name + a role badge. The placeholder still shows when nothing is selected.
291
291
  </CardDescription>
292
292
  </CardHeader>
293
293
  <CardContent>
@@ -47,7 +47,7 @@ const headerTones = [
47
47
  * Sheet > SheetTrigger (asChild) > SheetContent(side) > SheetHeader >
48
48
  * SheetTitle (a11y required) > scrollable body > SheetFooter.
49
49
  *
50
- * SheetFooter is an Ant-Design-style PINNED action bar: it sticks to the bottom
50
+ * SheetFooter is a PINNED action bar: it sticks to the bottom
51
51
  * via mt-auto, draws a full-bleed top border, and right-aligns its actions with
52
52
  * the PRIMARY button rightmost. A destructive / clear / reset action goes
53
53
  * far-LEFT · give THAT button className="me-auto". Never stack footer buttons
@@ -1,5 +1,17 @@
1
1
  import { Button, Heading, Text } from "@godxjp/ui/general";
2
- import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@godxjp/ui/data-display";
2
+ import {
3
+ Card,
4
+ CardContent,
5
+ CardDescription,
6
+ CardHeader,
7
+ CardTitle,
8
+ Table,
9
+ TableBody,
10
+ TableCell,
11
+ TableHead,
12
+ TableHeader,
13
+ TableRow,
14
+ } from "@godxjp/ui/data-display";
3
15
  import { Flex, PageContainer } from "@godxjp/ui/layout";
4
16
 
5
17
  /**
@@ -146,6 +158,77 @@ export default function Demo() {
146
158
  </Flex>
147
159
  </CardContent>
148
160
  </Card>
161
+
162
+ <Card>
163
+ <CardHeader>
164
+ <CardTitle level={2}>Links in running content</CardTitle>
165
+ <CardDescription>
166
+ link は色ではなく「これはリンクである」という手がかりです。ホバーだけでなく
167
+ キーボードフォーカスでも下線が出るため、hover: だけのユーティリティでは
168
+ 届かない利用者にも伝わります。色は tone のままなので、tone=&quot;destructive&quot;
169
+ のリンクは destructive のまま下線を引きます。
170
+ </CardDescription>
171
+ </CardHeader>
172
+ <CardContent>
173
+ <Flex direction="col" gap="md">
174
+ <Flex direction="row" gap="md" wrap align="center">
175
+ <Text as="a" href="#typography" link>
176
+ 既定 · tone は primary
177
+ </Text>
178
+ <Text as="a" href="#typography" link tone="destructive">
179
+ 取り消す
180
+ </Text>
181
+ <Text as="a" href="#typography" link size="xs" tone="muted">
182
+ すべての通知を見る
183
+ </Text>
184
+ </Flex>
185
+
186
+ {/* The case Button variant="link" cannot serve. `.ui-button` is a control box —
187
+ * white-space: nowrap, flex-shrink: 0, a --control-height tier and inline padding —
188
+ * so in a cell it neither wraps to a second line nor shares the row's line box.
189
+ * `<Text link>` is text, so it does both. */}
190
+ <Table>
191
+ <TableHeader>
192
+ <TableRow>
193
+ <TableHead>キー</TableHead>
194
+ <TableHead>件名</TableHead>
195
+ </TableRow>
196
+ </TableHeader>
197
+ <TableBody>
198
+ <TableRow>
199
+ <TableCell>
200
+ <Text size="xs" mono tone="muted">
201
+ PKG-128
202
+ </Text>
203
+ </TableCell>
204
+ <TableCell>
205
+ <Text as="a" href="#typography" link>
206
+ ログイン画面の余白が狭く、パスワード再設定リンクが本文と重なって見える
207
+ </Text>
208
+ </TableCell>
209
+ </TableRow>
210
+ <TableRow>
211
+ <TableCell>
212
+ <Text size="xs" mono tone="muted">
213
+ PKG-129
214
+ </Text>
215
+ </TableCell>
216
+ <TableCell>
217
+ <Text as="a" href="#typography" link>
218
+ 請求書PDFの明細行
219
+ </Text>
220
+ </TableCell>
221
+ </TableRow>
222
+ </TableBody>
223
+ </Table>
224
+
225
+ <Text size="xs" tone="muted">
226
+ アクション(送信・展開)にはリンク風の Button variant=&quot;link&quot;
227
+ を使います。本文の中のリンクは Text link です。
228
+ </Text>
229
+ </Flex>
230
+ </CardContent>
231
+ </Card>
149
232
  </Flex>
150
233
  </PageContainer>
151
234
  );