@godxjp/ui 20.2.1 → 22.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/app/app-provider.js +2 -1
- package/dist/components/data-display/badge.d.ts +28 -1
- package/dist/components/data-display/badge.js +2 -0
- package/dist/components/data-display/chat-bubble.d.ts +30 -0
- package/dist/components/data-display/chat-bubble.js +229 -0
- package/dist/components/data-display/data-table.d.ts +18 -2
- package/dist/components/data-display/data-table.js +4 -0
- package/dist/components/data-display/descriptions.js +4 -1
- package/dist/components/data-display/index.d.ts +5 -3
- package/dist/components/data-display/index.js +5 -2
- package/dist/components/data-display/popover.d.ts +19 -1
- package/dist/components/data-display/popover.js +12 -3
- package/dist/components/data-display/progress.d.ts +37 -0
- package/dist/components/data-display/progress.js +57 -5
- package/dist/components/data-display/scroll-area.js +26 -1
- package/dist/components/data-display/tree.d.ts +8 -0
- package/dist/components/data-display/tree.js +426 -0
- package/dist/components/data-entry/chat-composer.d.ts +50 -0
- package/dist/components/data-entry/chat-composer.js +163 -0
- package/dist/components/data-entry/chat-suggestion.d.ts +28 -0
- package/dist/components/data-entry/chat-suggestion.js +285 -0
- package/dist/components/data-entry/date-picker.d.ts +10 -3
- package/dist/components/data-entry/date-picker.js +503 -238
- package/dist/components/data-entry/form-field.d.ts +1 -1
- package/dist/components/data-entry/form-field.js +4 -1
- package/dist/components/data-entry/form.js +10 -1
- package/dist/components/data-entry/index.d.ts +4 -6
- package/dist/components/data-entry/index.js +4 -6
- package/dist/components/data-entry/label.d.ts +14 -1
- package/dist/components/data-entry/label.js +6 -1
- package/dist/components/data-entry/radio.d.ts +27 -6
- package/dist/components/data-entry/radio.js +88 -43
- package/dist/components/data-entry/search-select.js +8 -1
- package/dist/components/data-entry/select.js +2 -0
- package/dist/components/data-entry/switch.d.ts +6 -3
- package/dist/components/data-entry/switch.js +34 -11
- package/dist/components/data-entry/textarea.js +3 -1
- package/dist/components/data-entry/tree-utils.d.ts +10 -48
- package/dist/components/data-entry/tree-utils.js +1 -154
- package/dist/components/layout/mobile-shell.d.ts +1 -1
- package/dist/components/layout/mobile-shell.js +2 -0
- package/dist/components/navigation/menubar.d.ts +10 -3
- package/dist/components/navigation/steps.d.ts +1 -1
- package/dist/components/navigation/steps.js +3 -1
- package/dist/components/navigation/tabs-scroll.d.ts +27 -0
- package/dist/components/navigation/tabs-scroll.js +52 -1
- package/dist/components/navigation/tabs.d.ts +2 -2
- package/dist/components/navigation/tabs.js +88 -23
- package/dist/components/ui/index.d.ts +0 -1
- package/dist/components/ui/index.js +0 -1
- package/dist/components/ui/segmented.d.ts +15 -1
- package/dist/components/ui/segmented.js +13 -6
- package/dist/i18n/messages/en.json +48 -2
- package/dist/i18n/messages/ja.json +46 -2
- package/dist/i18n/messages/vi.json +47 -2
- package/dist/lib/datetime/picker-format.d.ts +18 -0
- package/dist/lib/datetime/picker-format.js +35 -1
- package/dist/lib/field-a11y.d.ts +12 -0
- package/dist/lib/field-a11y.js +14 -1
- package/dist/lib/tree.d.ts +53 -0
- package/dist/lib/tree.js +155 -0
- package/dist/props/components/data-display.prop.d.ts +194 -1
- package/dist/props/components/data-entry.prop.d.ts +307 -99
- package/dist/props/components/index.d.ts +1 -1
- package/dist/props/components/layout.prop.d.ts +12 -1
- package/dist/props/components/navigation.prop.d.ts +76 -1
- package/dist/props/registry.d.ts +156 -19
- package/dist/props/registry.js +218 -18
- package/dist/props/vocabulary/data.prop.d.ts +12 -0
- package/dist/props/vocabulary/index.d.ts +2 -2
- package/dist/props/vocabulary/layout.prop.d.ts +11 -0
- package/dist/styles/badge-layout.css +4 -0
- package/dist/styles/card-layout.css +6 -6
- package/dist/styles/control.css +22 -6
- package/dist/styles/data-display-layout.css +385 -68
- package/dist/styles/data-entry-layout.css +64 -0
- package/dist/styles/focus-ring.css +4 -2
- package/dist/styles/navigation-layout.css +25 -0
- package/dist/styles/shell-layout.css +7 -1
- package/dist/styles/table-layout.css +34 -0
- package/dist/tokens/base.css +3 -0
- package/dist/tokens/components/chat-bubble.css +36 -0
- package/dist/tokens/components/chat-composer.css +19 -0
- package/dist/tokens/components/data-display.css +9 -6
- package/dist/tokens/components/descriptions.css +4 -0
- package/dist/tokens/components/navigation.css +6 -0
- package/dist/tokens/components/segmented.css +0 -2
- package/dist/tokens/components/shell.css +3 -0
- package/dist/tokens/components/table.css +3 -0
- package/dist/tokens/components/tree.css +27 -0
- package/dist/tokens/foundation.css +7 -0
- package/docs/COMPONENTS.md +14 -14
- package/docs/CONSUMER-RULES.md +24 -1
- package/docs/FRAME-COVERAGE-LEDGER.md +1 -1
- package/docs/FRAME-COVERAGE-REPORT.md +9 -7
- package/docs/TOKENS.md +65 -0
- package/docs/data-display/badge.tsx +37 -0
- package/docs/data-display/chat-bubble.tsx +397 -0
- package/docs/data-display/data-table/index.tsx +18 -0
- package/docs/data-display/popover.tsx +41 -1
- package/docs/data-display/progress.tsx +28 -0
- package/docs/data-display/timeline.tsx +46 -0
- package/docs/data-display/tree.tsx +394 -0
- package/docs/data-entry/calendar.tsx +2 -2
- package/docs/data-entry/chat-composer.tsx +464 -0
- package/docs/data-entry/chat-suggestion.tsx +301 -0
- package/docs/data-entry/date-picker.tsx +143 -3
- package/docs/data-entry/form/examples/invoice-form.tsx +2 -2
- package/docs/data-entry/form-field/examples/a11y-contract.tsx +3 -5
- package/docs/data-entry/form.tsx +4 -4
- package/docs/data-entry/number-input.tsx +31 -0
- package/docs/data-entry/segmented.tsx +103 -1
- package/docs/layout/mobile-shell.tsx +5 -0
- package/docs/navigation/tabs.tsx +149 -0
- package/docs/roadmap/ai-chat-components.md +207 -0
- package/docs/roadmap/antd-parity.md +155 -0
- package/docs/roadmap/badge-tag-chip-count.md +172 -0
- package/docs/roadmap/list-masonry.md +159 -0
- package/docs/roadmap/parity-audit-data-display-feedback.md +567 -0
- package/docs/roadmap/parity-audit-data-entry.md +357 -0
- package/docs/roadmap/parity-audit-layout-navigation-general.md +464 -0
- package/docs/roadmap/parity-backlog.md +78 -0
- package/docs/roadmap/tree-components.md +151 -0
- package/docs/showcase/acme-portal.tsx +7 -0
- package/docs/showcase/table-tree-rows.tsx +4 -4
- package/package.json +13 -23
- package/scripts/ui-audit.mjs +17 -4
- package/dist/components/data-display/tree-list.d.ts +0 -13
- package/dist/components/data-display/tree-list.js +0 -26
- package/dist/components/data-entry/date-range-picker.d.ts +0 -11
- package/dist/components/data-entry/date-range-picker.js +0 -349
- package/dist/components/data-entry/month-picker.d.ts +0 -10
- package/dist/components/data-entry/month-picker.js +0 -241
- package/dist/components/data-entry/month-range-picker.d.ts +0 -10
- package/dist/components/data-entry/month-range-picker.js +0 -301
- package/dist/components/ui/date-range-picker.d.ts +0 -1
- package/dist/components/ui/date-range-picker.js +0 -2
- package/docs/data-display/tree-list.tsx +0 -107
- package/docs/data-entry/date-range-picker.tsx +0 -175
- package/docs/data-entry/month-picker.tsx +0 -101
- package/docs/data-entry/month-range-picker.tsx +0 -115
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import {
|
|
3
|
+
Badge,
|
|
4
|
+
Card,
|
|
5
|
+
CardContent,
|
|
6
|
+
CardDescription,
|
|
7
|
+
CardHeader,
|
|
8
|
+
CardTitle,
|
|
9
|
+
Descriptions,
|
|
10
|
+
EmptyState,
|
|
11
|
+
ScrollArea,
|
|
12
|
+
Tree,
|
|
13
|
+
type TreeNodeProp,
|
|
14
|
+
} from "@godxjp/ui/data-display";
|
|
15
|
+
import { Text } from "@godxjp/ui/general";
|
|
16
|
+
import { Flex, PageContainer, Separator } from "@godxjp/ui/layout";
|
|
17
|
+
import { Building2, FolderTree, ShieldCheck } from "lucide-react";
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Tree — the standalone WAI-ARIA "Tree View" on a page.
|
|
21
|
+
*
|
|
22
|
+
* The screen is a real one: an access-control settings page whose left column is the permission
|
|
23
|
+
* tree the administrator ticks, and whose right column reads back exactly what that means. Every
|
|
24
|
+
* card below is an independent pattern with its own data and its own state, and every prop the
|
|
25
|
+
* component declares is exercised somewhere on the page, at rest, without clicking.
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
// ── card 1 · the permission tree ────────────────────────────────────────────────────────────
|
|
29
|
+
const permissions: TreeNodeProp[] = [
|
|
30
|
+
{
|
|
31
|
+
value: "billing",
|
|
32
|
+
label: "請求管理",
|
|
33
|
+
children: [
|
|
34
|
+
{ value: "billing.invoice.read", label: "請求書を閲覧" },
|
|
35
|
+
{ value: "billing.invoice.write", label: "請求書を発行" },
|
|
36
|
+
{ value: "billing.refund", label: "返金を実行", disableCheckbox: true },
|
|
37
|
+
],
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
value: "people",
|
|
41
|
+
label: "人事",
|
|
42
|
+
children: [
|
|
43
|
+
{ value: "people.read", label: "プロフィールを閲覧" },
|
|
44
|
+
{ value: "people.write", label: "プロフィールを編集" },
|
|
45
|
+
{
|
|
46
|
+
value: "people.payroll",
|
|
47
|
+
label: "給与",
|
|
48
|
+
children: [
|
|
49
|
+
{ value: "people.payroll.read", label: "給与明細を閲覧" },
|
|
50
|
+
{ value: "people.payroll.approve", label: "給与を承認", disabled: true },
|
|
51
|
+
],
|
|
52
|
+
},
|
|
53
|
+
],
|
|
54
|
+
},
|
|
55
|
+
{ value: "audit", label: "監査ログ", isLeaf: true },
|
|
56
|
+
];
|
|
57
|
+
|
|
58
|
+
const permissionLabels = new Map<string, string>([
|
|
59
|
+
["billing", "請求管理"],
|
|
60
|
+
["billing.invoice.read", "請求書を閲覧"],
|
|
61
|
+
["billing.invoice.write", "請求書を発行"],
|
|
62
|
+
["billing.refund", "返金を実行"],
|
|
63
|
+
["people", "人事"],
|
|
64
|
+
["people.read", "プロフィールを閲覧"],
|
|
65
|
+
["people.write", "プロフィールを編集"],
|
|
66
|
+
["people.payroll", "給与"],
|
|
67
|
+
["people.payroll.read", "給与明細を閲覧"],
|
|
68
|
+
["people.payroll.approve", "給与を承認"],
|
|
69
|
+
["audit", "監査ログ"],
|
|
70
|
+
]);
|
|
71
|
+
|
|
72
|
+
// ── card 2 · the directory browser ──────────────────────────────────────────────────────────
|
|
73
|
+
const repository: TreeNodeProp[] = [
|
|
74
|
+
{
|
|
75
|
+
value: "src",
|
|
76
|
+
label: "src",
|
|
77
|
+
children: [
|
|
78
|
+
{
|
|
79
|
+
value: "src/components",
|
|
80
|
+
label: "components",
|
|
81
|
+
children: [
|
|
82
|
+
{ value: "src/components/tree.tsx", label: "tree.tsx", isLeaf: true },
|
|
83
|
+
{ value: "src/components/tree-list.tsx", label: "tree-list.tsx", isLeaf: true },
|
|
84
|
+
],
|
|
85
|
+
},
|
|
86
|
+
{ value: "src/index.ts", label: "index.ts", isLeaf: true },
|
|
87
|
+
],
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
value: "docs",
|
|
91
|
+
label: "docs",
|
|
92
|
+
children: [{ value: "docs/tree.mdx", label: "tree.mdx", isLeaf: true }],
|
|
93
|
+
},
|
|
94
|
+
];
|
|
95
|
+
|
|
96
|
+
const fileDetails: Record<string, { size: string; changed: string }> = {
|
|
97
|
+
"src/components/tree.tsx": { size: "18.4 KB", changed: "2026-09-10" },
|
|
98
|
+
"src/components/tree-list.tsx": { size: "1.2 KB", changed: "2025-11-02" },
|
|
99
|
+
"src/index.ts": { size: "0.9 KB", changed: "2026-08-21" },
|
|
100
|
+
"docs/tree.mdx": { size: "4.1 KB", changed: "2026-09-10" },
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
// ── card 3 · async branches (fieldNames + loadData + titleRender) ────────────────────────────
|
|
104
|
+
type Department = { id: string; name: string; leaf?: boolean; units?: Department[] };
|
|
105
|
+
|
|
106
|
+
const initialDepartments: Department[] = [
|
|
107
|
+
{ id: "jp", name: "日本法人" },
|
|
108
|
+
{ id: "vn", name: "ベトナム法人" },
|
|
109
|
+
{ id: "sg", name: "シンガポール支店", leaf: true },
|
|
110
|
+
];
|
|
111
|
+
|
|
112
|
+
const departmentChildren: Record<string, Department[]> = {
|
|
113
|
+
jp: [
|
|
114
|
+
{ id: "jp-sales", name: "営業部", leaf: true },
|
|
115
|
+
{ id: "jp-dev", name: "開発部", leaf: true },
|
|
116
|
+
],
|
|
117
|
+
vn: [{ id: "vn-dev", name: "開発センター", leaf: true }],
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
function attachChildren(nodes: Department[], id: string, children: Department[]): Department[] {
|
|
121
|
+
return nodes.map((node) =>
|
|
122
|
+
node.id === id
|
|
123
|
+
? { ...node, units: children }
|
|
124
|
+
: { ...node, units: node.units ? attachChildren(node.units, id, children) : undefined },
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export default function Demo() {
|
|
129
|
+
// Card 1 — checks are controlled so the readout beside the tree can never disagree with it.
|
|
130
|
+
const [granted, setGranted] = React.useState<string[]>(["billing.invoice.read"]);
|
|
131
|
+
// Card 2 — selection is controlled and drives the detail pane.
|
|
132
|
+
const [openFile, setOpenFile] = React.useState<string | undefined>("src/components/tree.tsx");
|
|
133
|
+
// Card 3 — async children land in state, exactly as a real fetch would.
|
|
134
|
+
const [departments, setDepartments] = React.useState<Department[]>(initialDepartments);
|
|
135
|
+
// Card 5 — independent (strict) checks, and a multi-select tree.
|
|
136
|
+
const [strictChecks, setStrictChecks] = React.useState<string[]>(["people", "people.read"]);
|
|
137
|
+
const [picked, setPicked] = React.useState<string[]>(["billing", "audit"]);
|
|
138
|
+
|
|
139
|
+
const loadDepartment = async (node: TreeNodeProp) => {
|
|
140
|
+
// A real delay, so the Skeleton row and aria-busy are OBSERVABLE rather than theoretical.
|
|
141
|
+
await new Promise((resolve) => setTimeout(resolve, 1200));
|
|
142
|
+
const children = departmentChildren[node.value] ?? [];
|
|
143
|
+
setDepartments((current) => attachChildren(current, node.value, children));
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
return (
|
|
147
|
+
<PageContainer
|
|
148
|
+
title="Tree"
|
|
149
|
+
subtitle="アクセス権限の設定 · 展開・折りたたみ・キーボード操作のある階層はすべて Tree"
|
|
150
|
+
>
|
|
151
|
+
<Flex direction="col" gap="lg">
|
|
152
|
+
<Card>
|
|
153
|
+
<CardHeader>
|
|
154
|
+
<CardTitle level={2}>権限ツリー(checkable · 三状態)</CardTitle>
|
|
155
|
+
<CardDescription>
|
|
156
|
+
親をチェックすると配下すべてが入り、一部だけのときは親がダッシュ(indeterminate)
|
|
157
|
+
になります。「返金を実行」は disableCheckbox(チェックだけ不可)、「給与を承認」は
|
|
158
|
+
disabled。どちらも親の分母に入らないため、残りを全部入れれば親はチェック済みになります。
|
|
159
|
+
showLine で接続線、defaultExpandAll で最初から全展開。
|
|
160
|
+
</CardDescription>
|
|
161
|
+
</CardHeader>
|
|
162
|
+
<CardContent>
|
|
163
|
+
<Flex gap="lg" wrap>
|
|
164
|
+
<Tree
|
|
165
|
+
aria-label="権限ツリー"
|
|
166
|
+
treeData={permissions}
|
|
167
|
+
checkable
|
|
168
|
+
showLine
|
|
169
|
+
defaultExpandAll
|
|
170
|
+
checkedValues={granted}
|
|
171
|
+
onCheckedValuesChange={setGranted}
|
|
172
|
+
/>
|
|
173
|
+
<Separator orientation="vertical" />
|
|
174
|
+
<Flex direction="col" gap="sm">
|
|
175
|
+
<Text size="sm" tone="muted">
|
|
176
|
+
付与された権限({granted.length} 件)
|
|
177
|
+
</Text>
|
|
178
|
+
{granted.length === 0 ? (
|
|
179
|
+
<EmptyState
|
|
180
|
+
icon={ShieldCheck}
|
|
181
|
+
title="権限がありません"
|
|
182
|
+
description="ツリーから付与する権限を選んでください。"
|
|
183
|
+
/>
|
|
184
|
+
) : (
|
|
185
|
+
<Flex gap="xs" wrap>
|
|
186
|
+
{granted.map((value) => (
|
|
187
|
+
<Badge key={value} variant="secondary">
|
|
188
|
+
{permissionLabels.get(value) ?? value}
|
|
189
|
+
</Badge>
|
|
190
|
+
))}
|
|
191
|
+
</Flex>
|
|
192
|
+
)}
|
|
193
|
+
</Flex>
|
|
194
|
+
</Flex>
|
|
195
|
+
</CardContent>
|
|
196
|
+
</Card>
|
|
197
|
+
|
|
198
|
+
<Card>
|
|
199
|
+
<CardHeader>
|
|
200
|
+
<CardTitle level={2}>ファイルブラウザ(variant="directory")</CardTitle>
|
|
201
|
+
<CardDescription>
|
|
202
|
+
DirectoryTree 相当。showIcon でフォルダ/ファイルのグリフが出て、選択行は行全体が帯に
|
|
203
|
+
なります。選択は value / onValueChange
|
|
204
|
+
の制御コンポーネントで、右の詳細と常に一致します。 長いツリーは ScrollArea
|
|
205
|
+
で高さを止めます(v1 に仮想スクロールはありません)。
|
|
206
|
+
</CardDescription>
|
|
207
|
+
</CardHeader>
|
|
208
|
+
<CardContent>
|
|
209
|
+
<Flex gap="lg" wrap>
|
|
210
|
+
<ScrollArea className="max-h-64 w-72">
|
|
211
|
+
<Tree
|
|
212
|
+
aria-label="リポジトリ"
|
|
213
|
+
variant="directory"
|
|
214
|
+
showIcon
|
|
215
|
+
treeData={repository}
|
|
216
|
+
defaultExpandedValues={["src", "src/components"]}
|
|
217
|
+
value={openFile}
|
|
218
|
+
onValueChange={(next) => setOpenFile(next as string | undefined)}
|
|
219
|
+
/>
|
|
220
|
+
</ScrollArea>
|
|
221
|
+
<Flex direction="col" gap="sm">
|
|
222
|
+
{openFile && fileDetails[openFile] ? (
|
|
223
|
+
<Descriptions
|
|
224
|
+
items={[
|
|
225
|
+
{ label: "パス", children: openFile },
|
|
226
|
+
{ label: "サイズ", children: fileDetails[openFile].size },
|
|
227
|
+
{ label: "最終更新", children: fileDetails[openFile].changed },
|
|
228
|
+
]}
|
|
229
|
+
/>
|
|
230
|
+
) : (
|
|
231
|
+
<EmptyState
|
|
232
|
+
icon={FolderTree}
|
|
233
|
+
title="ファイルが選択されていません"
|
|
234
|
+
description="ツリーからファイルを選ぶと詳細が出ます。"
|
|
235
|
+
/>
|
|
236
|
+
)}
|
|
237
|
+
</Flex>
|
|
238
|
+
</Flex>
|
|
239
|
+
</CardContent>
|
|
240
|
+
</Card>
|
|
241
|
+
|
|
242
|
+
<Card>
|
|
243
|
+
<CardHeader>
|
|
244
|
+
<CardTitle level={2}>組織ツリー(loadData · fieldNames · titleRender)</CardTitle>
|
|
245
|
+
<CardDescription>
|
|
246
|
+
API のキーが id / name / units でも fieldNames で読み替えるだけ。子を持たない枝は
|
|
247
|
+
isLeaf: false 扱いで、初回展開時に loadData が一度だけ走り、その間は Skeleton 行と
|
|
248
|
+
aria-busy が出ます(1.2 秒の実待ち)。titleRender で行の見た目を差し替えています。
|
|
249
|
+
</CardDescription>
|
|
250
|
+
</CardHeader>
|
|
251
|
+
<CardContent>
|
|
252
|
+
<Tree
|
|
253
|
+
aria-label="組織ツリー"
|
|
254
|
+
size="lg"
|
|
255
|
+
showIcon
|
|
256
|
+
treeData={
|
|
257
|
+
departments.map((node) => ({
|
|
258
|
+
...node,
|
|
259
|
+
isLeaf: node.leaf ?? false,
|
|
260
|
+
icon: <Building2 />,
|
|
261
|
+
})) as unknown as TreeNodeProp[]
|
|
262
|
+
}
|
|
263
|
+
fieldNames={{ label: "name", value: "id", children: "units" }}
|
|
264
|
+
loadData={loadDepartment}
|
|
265
|
+
titleRender={(node) => (
|
|
266
|
+
<Text size="sm" weight="medium">
|
|
267
|
+
{node.label}
|
|
268
|
+
</Text>
|
|
269
|
+
)}
|
|
270
|
+
/>
|
|
271
|
+
</CardContent>
|
|
272
|
+
</Card>
|
|
273
|
+
|
|
274
|
+
<Card>
|
|
275
|
+
<CardHeader>
|
|
276
|
+
<CardTitle level={2}>checkStrictly と multiple(チェックと選択は別の軸)</CardTitle>
|
|
277
|
+
<CardDescription>
|
|
278
|
+
左は checkStrictly:親と子のチェックは独立で、カスケードも indeterminate
|
|
279
|
+
もありません。 右は multiple の選択(チェックボックスなし)。ひとつの Tree で value と
|
|
280
|
+
checkedValues が別々に動くことが分かるよう、読み出しを両方出しています。
|
|
281
|
+
</CardDescription>
|
|
282
|
+
</CardHeader>
|
|
283
|
+
<CardContent>
|
|
284
|
+
<Flex gap="lg" wrap>
|
|
285
|
+
<Flex direction="col" gap="sm">
|
|
286
|
+
<Text size="sm" tone="muted">
|
|
287
|
+
checkStrictly · チェック: {strictChecks.length} 件
|
|
288
|
+
</Text>
|
|
289
|
+
<Tree
|
|
290
|
+
aria-label="権限ツリー(独立チェック)"
|
|
291
|
+
treeData={permissions}
|
|
292
|
+
checkable
|
|
293
|
+
checkStrictly
|
|
294
|
+
defaultExpandedValues={["people"]}
|
|
295
|
+
checkedValues={strictChecks}
|
|
296
|
+
onCheckedValuesChange={setStrictChecks}
|
|
297
|
+
/>
|
|
298
|
+
</Flex>
|
|
299
|
+
<Separator orientation="vertical" />
|
|
300
|
+
<Flex direction="col" gap="sm">
|
|
301
|
+
<Text size="sm" tone="muted">
|
|
302
|
+
multiple · 選択:{" "}
|
|
303
|
+
{picked.map((value) => permissionLabels.get(value) ?? value).join(" / ")}
|
|
304
|
+
</Text>
|
|
305
|
+
<Tree
|
|
306
|
+
aria-label="権限ツリー(複数選択)"
|
|
307
|
+
treeData={permissions}
|
|
308
|
+
multiple
|
|
309
|
+
defaultExpandAll
|
|
310
|
+
value={picked}
|
|
311
|
+
onValueChange={(next) => setPicked((next ?? []) as string[])}
|
|
312
|
+
/>
|
|
313
|
+
</Flex>
|
|
314
|
+
</Flex>
|
|
315
|
+
</CardContent>
|
|
316
|
+
</Card>
|
|
317
|
+
|
|
318
|
+
<Card>
|
|
319
|
+
<CardHeader>
|
|
320
|
+
<CardTitle level={2}>size の全段階 · disabled · 空</CardTitle>
|
|
321
|
+
<CardDescription>
|
|
322
|
+
行の高さは --control-height の段(xs / sm / md / lg)から来るので、同じ行に並ぶ他の
|
|
323
|
+
コントロールと常に揃います。disabled
|
|
324
|
+
はツリー全体を固め(読めるまま、開閉も選択も不可)、 treeData が空なら
|
|
325
|
+
role="status" の空メッセージが出ます。
|
|
326
|
+
</CardDescription>
|
|
327
|
+
</CardHeader>
|
|
328
|
+
<CardContent>
|
|
329
|
+
<Flex gap="lg" wrap>
|
|
330
|
+
{(["xs", "sm", "md", "lg"] as const).map((step) => (
|
|
331
|
+
<Flex key={step} direction="col" gap="xs">
|
|
332
|
+
<Text size="sm" tone="muted">
|
|
333
|
+
size="{step}"
|
|
334
|
+
</Text>
|
|
335
|
+
<Tree
|
|
336
|
+
aria-label={`サイズ ${step}`}
|
|
337
|
+
size={step}
|
|
338
|
+
treeData={repository}
|
|
339
|
+
defaultExpandedValues={["src"]}
|
|
340
|
+
/>
|
|
341
|
+
</Flex>
|
|
342
|
+
))}
|
|
343
|
+
<Flex direction="col" gap="xs">
|
|
344
|
+
<Text size="sm" tone="muted">
|
|
345
|
+
disabled
|
|
346
|
+
</Text>
|
|
347
|
+
<Tree
|
|
348
|
+
aria-label="読み取り専用ツリー"
|
|
349
|
+
disabled
|
|
350
|
+
treeData={repository}
|
|
351
|
+
defaultExpandAll
|
|
352
|
+
defaultValue="src/index.ts"
|
|
353
|
+
/>
|
|
354
|
+
</Flex>
|
|
355
|
+
<Flex direction="col" gap="xs">
|
|
356
|
+
<Text size="sm" tone="muted">
|
|
357
|
+
空
|
|
358
|
+
</Text>
|
|
359
|
+
<Tree aria-label="空のツリー" treeData={[]} />
|
|
360
|
+
</Flex>
|
|
361
|
+
</Flex>
|
|
362
|
+
</CardContent>
|
|
363
|
+
</Card>
|
|
364
|
+
|
|
365
|
+
<Card>
|
|
366
|
+
<CardHeader>
|
|
367
|
+
<CardTitle level={2}>キーボード(WAI-ARIA APG)</CardTitle>
|
|
368
|
+
<CardDescription>
|
|
369
|
+
ツリーに Tab で入るとタブストップはひとつだけ(roving
|
|
370
|
+
tabindex)。あとは矢印で歩けます。 dir="rtl" では → と ←
|
|
371
|
+
の意味が入れ替わり、インデントも反転します。
|
|
372
|
+
</CardDescription>
|
|
373
|
+
</CardHeader>
|
|
374
|
+
<CardContent>
|
|
375
|
+
<Descriptions
|
|
376
|
+
items={[
|
|
377
|
+
{ label: "↓ / ↑", children: "表示されている次/前のノードへ" },
|
|
378
|
+
{ label: "→", children: "閉じた枝を開く。開いていれば最初の子へ" },
|
|
379
|
+
{ label: "←", children: "開いた枝を閉じる。閉じていれば親へ" },
|
|
380
|
+
{ label: "Home / End", children: "表示されている最初/最後のノードへ" },
|
|
381
|
+
{
|
|
382
|
+
label: "Enter / Space",
|
|
383
|
+
children: "選択(checkable のときはチェックを切り替え)",
|
|
384
|
+
},
|
|
385
|
+
{ label: "*", children: "同じ階層の兄弟をすべて展開" },
|
|
386
|
+
{ label: "文字キー", children: "先頭一致で次のノードへジャンプ(type-ahead)" },
|
|
387
|
+
]}
|
|
388
|
+
/>
|
|
389
|
+
</CardContent>
|
|
390
|
+
</Card>
|
|
391
|
+
</Flex>
|
|
392
|
+
</PageContainer>
|
|
393
|
+
);
|
|
394
|
+
}
|
|
@@ -20,7 +20,7 @@ import type { DateRange } from "react-day-picker";
|
|
|
20
20
|
/**
|
|
21
21
|
* Calendar — styled react-day-picker grid for single, multiple, or range
|
|
22
22
|
* selection. Embed inside a Popover for picker UX; use DatePicker /
|
|
23
|
-
*
|
|
23
|
+
* `DatePicker range` for form-submittable inputs instead. Composed only from
|
|
24
24
|
* real @godxjp/ui components.
|
|
25
25
|
*/
|
|
26
26
|
export default function Demo() {
|
|
@@ -71,7 +71,7 @@ export default function Demo() {
|
|
|
71
71
|
<CardHeader>
|
|
72
72
|
<CardTitle level={2}>範囲選択 · Popover 内</CardTitle>
|
|
73
73
|
<CardDescription>
|
|
74
|
-
mode="range" でポップオーバー内に配置。
|
|
74
|
+
mode="range" でポップオーバー内に配置。DatePicker range
|
|
75
75
|
はこのパターンにフォーム送信を加えた上位コンポーネント。
|
|
76
76
|
</CardDescription>
|
|
77
77
|
</CardHeader>
|