@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.
- package/dist/components/data-display/card.d.ts +2 -2
- package/dist/components/data-display/collapsible.d.ts +23 -4
- package/dist/components/data-display/collapsible.js +119 -4
- package/dist/components/data-display/index.d.ts +3 -1
- package/dist/components/data-display/index.js +2 -0
- package/dist/components/data-display/legend.d.ts +15 -0
- package/dist/components/data-display/legend.js +11 -0
- package/dist/components/data-display/list-row.js +1 -1
- package/dist/components/data-display/popover.d.ts +58 -5
- package/dist/components/data-display/popover.js +206 -27
- package/dist/components/data-display/progress.d.ts +50 -2
- package/dist/components/data-display/progress.js +57 -9
- package/dist/components/data-entry/calendar.d.ts +1 -1
- package/dist/components/data-entry/calendar.js +67 -32
- package/dist/components/data-entry/checkbox.d.ts +19 -6
- package/dist/components/data-entry/checkbox.js +55 -16
- package/dist/components/data-entry/choice-option.d.ts +1 -1
- package/dist/components/data-entry/date-range-picker.d.ts +1 -1
- package/dist/components/data-entry/field.js +0 -1
- package/dist/components/data-entry/form.js +1 -1
- package/dist/components/data-entry/label.d.ts +3 -2
- package/dist/components/data-entry/label.js +23 -10
- package/dist/components/data-entry/month-picker.d.ts +1 -1
- package/dist/components/data-entry/month-range-picker.d.ts +1 -1
- package/dist/components/data-entry/transfer.js +16 -6
- package/dist/components/data-entry/tree-select-strategy.d.ts +1 -1
- package/dist/components/data-entry/tree-select.js +29 -12
- package/dist/components/data-entry/tree-utils.d.ts +1 -1
- package/dist/components/data-entry/upload.js +7 -2
- package/dist/components/feedback/dialog.d.ts +105 -38
- package/dist/components/feedback/dialog.js +272 -194
- package/dist/components/feedback/overlay-close-focus.d.ts +31 -0
- package/dist/components/feedback/overlay-close-focus.js +31 -0
- package/dist/components/feedback/overlay-header-tone.d.ts +1 -1
- package/dist/components/feedback/sheet.d.ts +53 -11
- package/dist/components/feedback/sheet.js +150 -81
- package/dist/components/feedback/tooltip.d.ts +51 -7
- package/dist/components/feedback/tooltip.js +107 -25
- package/dist/components/general/button.js +2 -2
- package/dist/components/general/logo.d.ts +17 -0
- package/dist/components/general/logo.js +22 -16
- package/dist/components/general/typography.d.ts +7 -1
- package/dist/components/general/typography.js +20 -5
- package/dist/components/layout/app-shell.d.ts +1 -1
- package/dist/components/layout/app-shell.js +52 -8
- package/dist/components/layout/aspect-ratio.js +0 -1
- package/dist/components/layout/auth-divider.js +0 -1
- package/dist/components/layout/flex.d.ts +1 -1
- package/dist/components/layout/flex.js +19 -2
- package/dist/components/layout/nav-surface.d.ts +26 -0
- package/dist/components/layout/nav-surface.js +17 -0
- package/dist/components/layout/org-switcher.d.ts +5 -1
- package/dist/components/layout/org-switcher.js +5 -3
- package/dist/components/layout/separator.js +0 -1
- package/dist/components/layout/sidebar.js +4 -1
- package/dist/components/layout/split-pane.d.ts +14 -1
- package/dist/components/layout/split-pane.js +26 -13
- package/dist/components/layout/topbar-item.js +1 -2
- package/dist/components/navigation/app-setting-picker.js +21 -2
- package/dist/components/navigation/app-setting-toggle.d.ts +16 -0
- package/dist/components/navigation/app-setting-toggle.js +96 -0
- package/dist/components/navigation/dropdown-menu.d.ts +199 -18
- package/dist/components/navigation/dropdown-menu.js +344 -117
- package/dist/components/navigation/index.d.ts +2 -0
- package/dist/components/navigation/index.js +2 -0
- package/dist/components/navigation/pagination-utils.d.ts +2 -1
- package/dist/components/navigation/tabs.d.ts +47 -6
- package/dist/components/navigation/tabs.js +152 -90
- package/dist/components/ui/accordion.d.ts +50 -5
- package/dist/components/ui/accordion.js +239 -33
- package/dist/components/ui/aspect-ratio.d.ts +23 -2
- package/dist/components/ui/aspect-ratio.js +15 -13
- package/dist/components/ui/avatar.d.ts +29 -4
- package/dist/components/ui/avatar.js +111 -25
- package/dist/components/ui/hover-card.d.ts +42 -4
- package/dist/components/ui/hover-card.js +183 -27
- package/dist/components/ui/label.js +0 -1
- package/dist/components/ui/segmented.d.ts +3 -3
- package/dist/components/ui/separator.d.ts +8 -2
- package/dist/components/ui/separator.js +17 -9
- package/dist/components/ui/toggle-group.d.ts +50 -5
- package/dist/components/ui/toggle-group.js +79 -20
- package/dist/components/ui/toggle.d.ts +31 -5
- package/dist/components/ui/toggle.js +42 -3
- package/dist/i18n/messages/en.json +8 -0
- package/dist/i18n/messages/ja.json +8 -0
- package/dist/i18n/messages/vi.json +8 -0
- package/dist/lib/control-styles.d.ts +1 -1
- package/dist/lib/control-styles.js +1 -1
- package/dist/lib/slot.d.ts +32 -0
- package/dist/lib/slot.js +22 -0
- package/dist/lib/variants.d.ts +22 -3
- package/dist/lib/variants.js +56 -1
- package/dist/props/components/app.prop.d.ts +25 -1
- package/dist/props/components/data-display.prop.d.ts +17 -0
- package/dist/props/components/data-entry.prop.d.ts +32 -4
- package/dist/props/components/general.prop.d.ts +31 -1
- package/dist/props/components/index.d.ts +1 -1
- package/dist/props/components/layout.prop.d.ts +118 -5
- package/dist/props/components/navigation.prop.d.ts +1 -1
- package/dist/props/registry.d.ts +22 -2
- package/dist/props/registry.js +33 -2
- package/dist/props/vocabulary/content.prop.d.ts +1 -1
- package/dist/props/vocabulary/index.d.ts +2 -2
- package/dist/props/vocabulary/interaction.prop.d.ts +17 -1
- package/dist/props/vocabulary/layout.prop.d.ts +57 -1
- package/dist/styles/control.css +142 -1
- package/dist/styles/core.css +5 -2
- package/dist/styles/data-display-layout.css +72 -0
- package/dist/styles/focus-ring.css +13 -1
- package/dist/styles/index.css +5 -2
- package/dist/styles/layout.css +106 -0
- package/dist/styles/shell-layout.css +140 -8
- package/dist/styles/text-layout.css +16 -4
- package/dist/tokens/base.css +2 -1
- package/dist/tokens/components/data-display.css +11 -0
- package/dist/tokens/components/shell.css +3 -1
- package/dist/tokens/components/text.css +7 -0
- package/dist/tokens/foundation.css +2 -0
- package/docs/COMPONENTS.md +9 -3
- package/docs/DESIGN-AUTHORITY.md +96 -71
- package/docs/FRAME-COVERAGE-REPORT.md +5 -3
- package/docs/README.md +14 -14
- package/docs/WHAT-BELONGS-HERE.md +179 -0
- package/docs/data-display/legend.tsx +145 -0
- package/docs/data-display/progress.tsx +32 -0
- package/docs/data-entry/segmented.tsx +1 -1
- package/docs/data-entry/select.tsx +2 -2
- package/docs/feedback/sheet.tsx +1 -1
- package/docs/general/typography.tsx +84 -1
- package/docs/layout/app-shell-arrangements.tsx +225 -0
- package/docs/layout/aspect-ratio.tsx +1 -1
- package/docs/navigation/app-setting-picker.tsx +26 -1
- package/docs/navigation/app-setting-toggle.tsx +111 -0
- package/package.json +11 -8
- package/scripts/_agent-setup.mjs +165 -3
- package/scripts/consumer-rule.md +98 -0
- package/scripts/guinea-pig-skill.md +322 -0
- package/scripts/init-guinea-pig.mjs +62 -0
- package/scripts/postinstall.mjs +13 -2
- package/scripts/ui-audit.mjs +115 -14
- /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="img"
|
|
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.
|
|
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`
|
|
290
|
-
|
|
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>
|
package/docs/feedback/sheet.tsx
CHANGED
|
@@ -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
|
|
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 {
|
|
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="destructive"
|
|
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="link"
|
|
227
|
+
を使います。本文の中のリンクは Text link です。
|
|
228
|
+
</Text>
|
|
229
|
+
</Flex>
|
|
230
|
+
</CardContent>
|
|
231
|
+
</Card>
|
|
149
232
|
</Flex>
|
|
150
233
|
</PageContainer>
|
|
151
234
|
);
|