@godxjp/ui 23.3.0 → 23.4.1
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 +87 -1
- package/dist/components/data-display/card.js +88 -15
- package/dist/components/data-display/index.d.ts +5 -1
- package/dist/components/data-display/index.js +5 -0
- package/dist/components/data-display/thought-chain.d.ts +42 -0
- package/dist/components/data-display/thought-chain.js +177 -0
- package/dist/components/data-display/welcome.d.ts +26 -0
- package/dist/components/data-display/welcome.js +37 -0
- package/dist/components/data-entry/attachments.d.ts +19 -0
- package/dist/components/data-entry/attachments.js +322 -0
- package/dist/components/data-entry/index.d.ts +2 -0
- package/dist/components/data-entry/index.js +2 -0
- package/dist/components/feedback/dialog.d.ts +10 -7
- package/dist/components/feedback/dialog.js +40 -17
- package/dist/components/feedback/index.d.ts +1 -1
- package/dist/components/general/actions.d.ts +59 -0
- package/dist/components/general/actions.js +253 -0
- package/dist/components/general/activity.js +1 -0
- package/dist/components/general/float-button.d.ts +41 -0
- package/dist/components/general/float-button.js +336 -0
- package/dist/components/general/index.d.ts +6 -2
- package/dist/components/general/index.js +12 -1
- package/dist/components/general/typography.d.ts +79 -4
- package/dist/components/general/typography.js +598 -54
- package/dist/components/layout/draggable-panel.d.ts +18 -0
- package/dist/components/layout/draggable-panel.js +189 -0
- package/dist/components/layout/index.d.ts +2 -0
- package/dist/components/layout/index.js +2 -0
- package/dist/components/navigation/conversations.d.ts +39 -0
- package/dist/components/navigation/conversations.js +371 -0
- package/dist/components/navigation/index.d.ts +2 -0
- package/dist/components/navigation/index.js +2 -0
- package/dist/components/ui/card.js +1 -0
- package/dist/i18n/messages/en.json +53 -0
- package/dist/i18n/messages/ja.json +53 -0
- package/dist/i18n/messages/vi.json +53 -0
- package/dist/props/components/data-display.prop.d.ts +143 -1
- package/dist/props/components/data-entry.prop.d.ts +76 -0
- package/dist/props/components/feedback.prop.d.ts +34 -1
- package/dist/props/components/general.prop.d.ts +440 -3
- package/dist/props/components/index.d.ts +2 -2
- package/dist/props/components/layout.prop.d.ts +63 -1
- package/dist/props/components/navigation.prop.d.ts +150 -0
- package/dist/props/registry.d.ts +426 -0
- package/dist/props/registry.js +546 -0
- package/dist/props/vocabulary/index.d.ts +1 -1
- package/dist/props/vocabulary/interaction.prop.d.ts +113 -0
- package/dist/styles/card-layout.css +30 -0
- package/dist/styles/core.css +1 -0
- package/dist/styles/data-display-layout.css +236 -0
- package/dist/styles/float-button-layout.css +168 -0
- package/dist/styles/index.css +1 -0
- package/dist/styles/layout.css +196 -0
- package/dist/styles/navigation-layout.css +139 -0
- package/dist/styles/text-layout.css +156 -0
- package/dist/tokens/base.css +7 -0
- package/dist/tokens/components/actions.css +14 -0
- package/dist/tokens/components/attachments.css +15 -0
- package/dist/tokens/components/conversations.css +28 -0
- package/dist/tokens/components/draggable-panel.css +25 -0
- package/dist/tokens/components/float-button.css +39 -0
- package/dist/tokens/components/text.css +13 -0
- package/dist/tokens/components/thought-chain.css +31 -0
- package/dist/tokens/components/welcome.css +19 -0
- package/dist/tokens/foundation.css +2 -0
- package/docs/DESIGN-AUTHORITY.md +89 -0
- package/docs/FRAME-COVERAGE-REPORT.md +5 -2
- package/docs/data-display/card/examples/tab-list.tsx +97 -0
- package/docs/data-display/thought-chain.tsx +176 -0
- package/docs/data-display/welcome.tsx +115 -0
- package/docs/data-entry/attachments.tsx +160 -0
- package/docs/feedback/dialog.tsx +50 -0
- package/docs/general/actions.tsx +175 -0
- package/docs/general/float-button.tsx +133 -0
- package/docs/general/typography.tsx +63 -1
- package/docs/layout/draggable-panel.tsx +127 -0
- package/docs/navigation/conversations.tsx +176 -0
- package/docs/roadmap/parity-audit-layout-navigation-general.md +17 -16
- package/package.json +3 -3
- package/scripts/ui-audit.mjs +66 -2
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { useState } from "react";
|
|
2
|
+
|
|
3
|
+
import { Attachments, type AttachmentsItemProp } from "@godxjp/ui/data-entry";
|
|
4
|
+
import { Text } from "@godxjp/ui/general";
|
|
5
|
+
import {
|
|
6
|
+
AppShell,
|
|
7
|
+
Flex,
|
|
8
|
+
PageContainer,
|
|
9
|
+
Sidebar,
|
|
10
|
+
type SidebarSectionProp,
|
|
11
|
+
Topbar,
|
|
12
|
+
} from "@godxjp/ui/layout";
|
|
13
|
+
import { Bot, MessageSquare, Paperclip, Settings, Users } from "lucide-react";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Attachments — the file collection that rides a chat surface (Ant Design X `Attachments`).
|
|
17
|
+
*
|
|
18
|
+
* Last of the #559 series. Every slot on this page is one Ant X axis at rest: the empty
|
|
19
|
+
* placeholder, a settled list, the three `overflow` modes, an upload in flight, a failed upload,
|
|
20
|
+
* and the disabled strip.
|
|
21
|
+
*
|
|
22
|
+
* The field names are antd's (`uid`, `name`, `size`, `status`, `percent`, `thumbUrl`,
|
|
23
|
+
* `originFileObj`) so an Ant X call site compiles here unchanged.
|
|
24
|
+
*
|
|
25
|
+
* Composed only from real @godxjp/ui components.
|
|
26
|
+
*/
|
|
27
|
+
const sections: SidebarSectionProp[] = [
|
|
28
|
+
{
|
|
29
|
+
label: "アシスタント",
|
|
30
|
+
items: [
|
|
31
|
+
{ id: "chat", label: "チャット", icon: MessageSquare },
|
|
32
|
+
{ id: "agents", label: "エージェント", icon: Bot },
|
|
33
|
+
{ id: "members", label: "メンバー", icon: Users },
|
|
34
|
+
],
|
|
35
|
+
},
|
|
36
|
+
{ label: "管理", items: [{ id: "settings", label: "設定", icon: Settings }] },
|
|
37
|
+
];
|
|
38
|
+
|
|
39
|
+
const settled: AttachmentsItemProp[] = [
|
|
40
|
+
{ uid: "1", name: "請求書_2026-03.pdf", size: 182_400, status: "done" },
|
|
41
|
+
{ uid: "2", name: "経費明細.xlsx", size: 44_120, status: "done" },
|
|
42
|
+
];
|
|
43
|
+
|
|
44
|
+
const inFlight: AttachmentsItemProp[] = [
|
|
45
|
+
{ uid: "3", name: "会議録画.mp4", size: 78_300_000, status: "uploading", percent: 42 },
|
|
46
|
+
];
|
|
47
|
+
|
|
48
|
+
const failed: AttachmentsItemProp[] = [
|
|
49
|
+
{ uid: "4", name: "契約書_原本.pdf", size: 2_400_000, status: "error" },
|
|
50
|
+
];
|
|
51
|
+
|
|
52
|
+
const many: AttachmentsItemProp[] = Array.from({ length: 6 }, (_, i) => ({
|
|
53
|
+
uid: `m${i}`,
|
|
54
|
+
name: `添付_${i + 1}.pdf`,
|
|
55
|
+
size: 12_000 * (i + 1),
|
|
56
|
+
status: "done" as const,
|
|
57
|
+
}));
|
|
58
|
+
|
|
59
|
+
export default function AttachmentsDoc() {
|
|
60
|
+
const [items, setItems] = useState<AttachmentsItemProp[]>(settled);
|
|
61
|
+
|
|
62
|
+
return (
|
|
63
|
+
<AppShell
|
|
64
|
+
sidebar={
|
|
65
|
+
<Sidebar
|
|
66
|
+
activeId="chat"
|
|
67
|
+
sections={sections}
|
|
68
|
+
onSelect={() => {}}
|
|
69
|
+
product={{ name: "CoreDesk", role: "アシスタント", color: "hsl(var(--primary))" }}
|
|
70
|
+
/>
|
|
71
|
+
}
|
|
72
|
+
topbar={<Topbar />}
|
|
73
|
+
>
|
|
74
|
+
<PageContainer
|
|
75
|
+
title="添付ファイル"
|
|
76
|
+
subtitle="Attachments · チャットに載せるファイルの束(Ant Design X)"
|
|
77
|
+
>
|
|
78
|
+
{/* EMPTY. The placeholder is the whole control when there is nothing yet: one button,
|
|
79
|
+
one accessible name, and a drop target that is the same box. */}
|
|
80
|
+
<Flex direction="col" gap="sm">
|
|
81
|
+
<Text size="sm" weight="medium">
|
|
82
|
+
空のとき · placeholder
|
|
83
|
+
</Text>
|
|
84
|
+
<Attachments items={[]} />
|
|
85
|
+
</Flex>
|
|
86
|
+
|
|
87
|
+
{/* THE CONTROLLED LIST. `onChange` carries antd's `{ file, fileList }`, so the removed
|
|
88
|
+
row arrives as `file` with status "removed" and `fileList` is what remains. */}
|
|
89
|
+
<Flex direction="col" gap="sm">
|
|
90
|
+
<Text size="sm" weight="medium">
|
|
91
|
+
items · onChange · onRemove
|
|
92
|
+
</Text>
|
|
93
|
+
<Attachments
|
|
94
|
+
items={items}
|
|
95
|
+
onRemove={() => true}
|
|
96
|
+
onChange={({ fileList }) => setItems(fileList)}
|
|
97
|
+
/>
|
|
98
|
+
<Text size="xs" tone="muted">
|
|
99
|
+
残り {items.length} 件。× を押すと `onChange` が `{"{ file, fileList }"}` で届く。
|
|
100
|
+
</Text>
|
|
101
|
+
</Flex>
|
|
102
|
+
|
|
103
|
+
{/* STATUS. Uploading carries a determinate Progress; error states the failure in words,
|
|
104
|
+
not only in tint. */}
|
|
105
|
+
<Flex direction="col" gap="sm">
|
|
106
|
+
<Text size="sm" weight="medium">
|
|
107
|
+
status · uploading と error
|
|
108
|
+
</Text>
|
|
109
|
+
<Attachments items={inFlight} />
|
|
110
|
+
<Attachments items={failed} />
|
|
111
|
+
</Flex>
|
|
112
|
+
|
|
113
|
+
{/* OVERFLOW. Three modes, same six items — what happens when the row runs out of box. */}
|
|
114
|
+
<Flex direction="col" gap="sm">
|
|
115
|
+
<Text size="sm" weight="medium">
|
|
116
|
+
overflow · wrap
|
|
117
|
+
</Text>
|
|
118
|
+
<Attachments items={many} overflow="wrap" />
|
|
119
|
+
</Flex>
|
|
120
|
+
|
|
121
|
+
<Flex direction="col" gap="sm">
|
|
122
|
+
<Text size="sm" weight="medium">
|
|
123
|
+
overflow · scrollX
|
|
124
|
+
</Text>
|
|
125
|
+
<Attachments items={many} overflow="scrollX" />
|
|
126
|
+
</Flex>
|
|
127
|
+
|
|
128
|
+
<Flex direction="col" gap="sm">
|
|
129
|
+
<Text size="sm" weight="medium">
|
|
130
|
+
overflow · scrollY
|
|
131
|
+
</Text>
|
|
132
|
+
<Attachments items={many} overflow="scrollY" />
|
|
133
|
+
</Flex>
|
|
134
|
+
|
|
135
|
+
{/* PLACEHOLDER, OVERRIDDEN. An object, or a function of "inline" | "drop". */}
|
|
136
|
+
<Flex direction="col" gap="sm">
|
|
137
|
+
<Text size="sm" weight="medium">
|
|
138
|
+
placeholder · 自分の文言
|
|
139
|
+
</Text>
|
|
140
|
+
<Attachments
|
|
141
|
+
items={[]}
|
|
142
|
+
placeholder={{
|
|
143
|
+
icon: <Paperclip />,
|
|
144
|
+
title: "証憑を添付",
|
|
145
|
+
description: "領収書・請求書・契約書。PDF と画像に対応します。",
|
|
146
|
+
}}
|
|
147
|
+
/>
|
|
148
|
+
</Flex>
|
|
149
|
+
|
|
150
|
+
{/* DISABLED. The strip stays readable; nothing in it is reachable. */}
|
|
151
|
+
<Flex direction="col" gap="sm">
|
|
152
|
+
<Text size="sm" weight="medium">
|
|
153
|
+
disabled
|
|
154
|
+
</Text>
|
|
155
|
+
<Attachments items={settled} disabled />
|
|
156
|
+
</Flex>
|
|
157
|
+
</PageContainer>
|
|
158
|
+
</AppShell>
|
|
159
|
+
);
|
|
160
|
+
}
|
package/docs/feedback/dialog.tsx
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { useState } from "react";
|
|
2
2
|
import {
|
|
3
3
|
Dialog,
|
|
4
|
+
DialogAction,
|
|
5
|
+
DialogCancel,
|
|
4
6
|
DialogContent,
|
|
5
7
|
DialogDescription,
|
|
6
8
|
DialogFooter,
|
|
@@ -8,6 +10,7 @@ import {
|
|
|
8
10
|
DialogTitle,
|
|
9
11
|
DialogTrigger,
|
|
10
12
|
} from "@godxjp/ui/feedback";
|
|
13
|
+
import { FormField, Textarea } from "@godxjp/ui/data-entry";
|
|
11
14
|
import {
|
|
12
15
|
Badge,
|
|
13
16
|
Card,
|
|
@@ -40,6 +43,8 @@ export default function Demo() {
|
|
|
40
43
|
const [detailOpen, setDetailOpen] = useState(false);
|
|
41
44
|
const [toneOpen, setToneOpen] = useState(false);
|
|
42
45
|
const [headerTone, setHeaderTone] = useState<(typeof headerTones)[number]>("default");
|
|
46
|
+
const [terminateOpen, setTerminateOpen] = useState(false);
|
|
47
|
+
const [reason, setReason] = useState("");
|
|
43
48
|
|
|
44
49
|
return (
|
|
45
50
|
<PageContainer
|
|
@@ -187,6 +192,51 @@ export default function Demo() {
|
|
|
187
192
|
</Flex>
|
|
188
193
|
</CardContent>
|
|
189
194
|
</Card>
|
|
195
|
+
|
|
196
|
+
<Card>
|
|
197
|
+
<CardHeader>
|
|
198
|
+
<CardTitle level={2}>Destructive confirmation with a required field</CardTitle>
|
|
199
|
+
<CardDescription>
|
|
200
|
+
variant is the one prop that decides three things that always travel together: the
|
|
201
|
+
ARIA role, whether an outside click dismisses, and the primary action emphasis.
|
|
202
|
+
variant="destructive" renders role="alertdialog", ignores an
|
|
203
|
+
outside click and tints DialogAction, while the surface stays a plain Dialog, so a
|
|
204
|
+
required input can sit inside it. That combination used to need a rewrite: Dialog had
|
|
205
|
+
the form but lost the role, AlertDialog had the role but its parts assume a two-button
|
|
206
|
+
body. Escape still closes, exactly as the AlertDialog family already does.
|
|
207
|
+
</CardDescription>
|
|
208
|
+
</CardHeader>
|
|
209
|
+
<CardContent>
|
|
210
|
+
<Dialog open={terminateOpen} onOpenChange={setTerminateOpen} variant="destructive">
|
|
211
|
+
<DialogTrigger asChild>
|
|
212
|
+
<Button variant="destructive" size="sm">
|
|
213
|
+
提携を終了
|
|
214
|
+
</Button>
|
|
215
|
+
</DialogTrigger>
|
|
216
|
+
<DialogContent className="max-w-md">
|
|
217
|
+
<DialogHeader
|
|
218
|
+
tone="destructive"
|
|
219
|
+
title="提携を終了しますか?"
|
|
220
|
+
subtitle="この操作は元に戻せません。終了理由は監査ログに残ります。"
|
|
221
|
+
/>
|
|
222
|
+
<FormField id="termination-reason" label="終了理由" required>
|
|
223
|
+
<Textarea
|
|
224
|
+
id="termination-reason"
|
|
225
|
+
value={reason}
|
|
226
|
+
onChange={(event) => setReason(event.target.value)}
|
|
227
|
+
placeholder="契約違反の内容を記載してください"
|
|
228
|
+
/>
|
|
229
|
+
</FormField>
|
|
230
|
+
<DialogFooter>
|
|
231
|
+
<DialogCancel asChild>
|
|
232
|
+
<Button variant="ghost">キャンセル</Button>
|
|
233
|
+
</DialogCancel>
|
|
234
|
+
<DialogAction disabled={reason.trim().length === 0}>終了する</DialogAction>
|
|
235
|
+
</DialogFooter>
|
|
236
|
+
</DialogContent>
|
|
237
|
+
</Dialog>
|
|
238
|
+
</CardContent>
|
|
239
|
+
</Card>
|
|
190
240
|
</Flex>
|
|
191
241
|
</PageContainer>
|
|
192
242
|
);
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { useState } from "react";
|
|
2
|
+
|
|
3
|
+
import { ChatBubble } from "@godxjp/ui/data-display";
|
|
4
|
+
import {
|
|
5
|
+
Actions,
|
|
6
|
+
ActionsCopy,
|
|
7
|
+
ActionsFeedback,
|
|
8
|
+
ActionsItem,
|
|
9
|
+
type ActionsFeedbackValueProp,
|
|
10
|
+
Text,
|
|
11
|
+
} from "@godxjp/ui/general";
|
|
12
|
+
import {
|
|
13
|
+
AppShell,
|
|
14
|
+
Flex,
|
|
15
|
+
PageContainer,
|
|
16
|
+
Sidebar,
|
|
17
|
+
type SidebarSectionProp,
|
|
18
|
+
Topbar,
|
|
19
|
+
} from "@godxjp/ui/layout";
|
|
20
|
+
import {
|
|
21
|
+
Bot,
|
|
22
|
+
Flag,
|
|
23
|
+
MessageSquare,
|
|
24
|
+
RefreshCw,
|
|
25
|
+
Settings,
|
|
26
|
+
Share2,
|
|
27
|
+
Users,
|
|
28
|
+
Volume2,
|
|
29
|
+
} from "lucide-react";
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Actions — the strip of actions under an assistant message (Ant Design X `Actions`).
|
|
33
|
+
*
|
|
34
|
+
* Every card is one axis at rest. The first shows the strip where it belongs, under a real
|
|
35
|
+
* `ChatBubble`; the rest are the three variants, the `subItems` menu, the four `ActionsItem`
|
|
36
|
+
* statuses, and the two ready-made actions (`ActionsCopy`, `ActionsFeedback`).
|
|
37
|
+
*
|
|
38
|
+
* The strip is a WAI-ARIA toolbar: one Tab reaches it, the arrows move inside it. Ant X's own
|
|
39
|
+
* strip is a row of `<div onClick>` and cannot be reached from the keyboard at all.
|
|
40
|
+
*
|
|
41
|
+
* Composed only from real @godxjp/ui components.
|
|
42
|
+
*/
|
|
43
|
+
const sections: SidebarSectionProp[] = [
|
|
44
|
+
{
|
|
45
|
+
label: "アシスタント",
|
|
46
|
+
items: [
|
|
47
|
+
{ id: "chat", label: "チャット", icon: MessageSquare },
|
|
48
|
+
{ id: "agents", label: "エージェント", icon: Bot },
|
|
49
|
+
{ id: "members", label: "メンバー", icon: Users },
|
|
50
|
+
],
|
|
51
|
+
},
|
|
52
|
+
{ label: "管理", items: [{ id: "settings", label: "設定", icon: Settings }] },
|
|
53
|
+
];
|
|
54
|
+
|
|
55
|
+
const ANSWER = "差分は3件でした。金額、支払期日、宛名のうちどれから直しますか。";
|
|
56
|
+
|
|
57
|
+
export default function ActionsDoc() {
|
|
58
|
+
const [vote, setVote] = useState<ActionsFeedbackValueProp>("default");
|
|
59
|
+
const [log, setLog] = useState("まだ何も押されていません。");
|
|
60
|
+
|
|
61
|
+
return (
|
|
62
|
+
<AppShell
|
|
63
|
+
sidebar={
|
|
64
|
+
<Sidebar
|
|
65
|
+
activeId="chat"
|
|
66
|
+
sections={sections}
|
|
67
|
+
onSelect={() => {}}
|
|
68
|
+
product={{ name: "CoreDesk", role: "アシスタント", color: "hsl(var(--primary))" }}
|
|
69
|
+
/>
|
|
70
|
+
}
|
|
71
|
+
topbar={<Topbar />}
|
|
72
|
+
>
|
|
73
|
+
<PageContainer
|
|
74
|
+
title="回答の操作"
|
|
75
|
+
subtitle="Actions · 一つの回答にぶら下がる操作の帯。Tab は一回、中は矢印キー。"
|
|
76
|
+
>
|
|
77
|
+
{/* WHERE IT BELONGS: under the answer it acts on. */}
|
|
78
|
+
<Flex direction="col" gap="sm">
|
|
79
|
+
<Text size="sm" weight="medium">
|
|
80
|
+
in place · 回答の下
|
|
81
|
+
</Text>
|
|
82
|
+
<ChatBubble placement="start" variant="filled">
|
|
83
|
+
{ANSWER}
|
|
84
|
+
</ChatBubble>
|
|
85
|
+
<Actions
|
|
86
|
+
label="回答の操作"
|
|
87
|
+
items={[
|
|
88
|
+
{ key: "retry", label: "やり直す", icon: <RefreshCw /> },
|
|
89
|
+
{ key: "copy", actionRender: <ActionsCopy text={ANSWER} /> },
|
|
90
|
+
{
|
|
91
|
+
key: "feedback",
|
|
92
|
+
actionRender: <ActionsFeedback value={vote} onChange={setVote} />,
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
key: "more",
|
|
96
|
+
label: "その他",
|
|
97
|
+
subItems: [
|
|
98
|
+
{ key: "share", label: "共有", icon: <Share2 /> },
|
|
99
|
+
{ key: "report", label: "報告", icon: <Flag />, danger: true },
|
|
100
|
+
],
|
|
101
|
+
},
|
|
102
|
+
]}
|
|
103
|
+
onClick={({ key, keyPath }) => setLog(`${key} — keyPath: ${keyPath.join(" ← ")}`)}
|
|
104
|
+
/>
|
|
105
|
+
<Text size="xs" tone="muted">
|
|
106
|
+
{log}
|
|
107
|
+
</Text>
|
|
108
|
+
</Flex>
|
|
109
|
+
|
|
110
|
+
{/* THE THREE VARIANTS. */}
|
|
111
|
+
<Flex direction="col" gap="sm">
|
|
112
|
+
<Text size="sm" weight="medium">
|
|
113
|
+
variant · borderless · filled · outlined
|
|
114
|
+
</Text>
|
|
115
|
+
<Actions
|
|
116
|
+
label="borderless の例"
|
|
117
|
+
variant="borderless"
|
|
118
|
+
items={[
|
|
119
|
+
{ key: "a", label: "やり直す", icon: <RefreshCw /> },
|
|
120
|
+
{ key: "b", label: "共有", icon: <Share2 /> },
|
|
121
|
+
]}
|
|
122
|
+
/>
|
|
123
|
+
<Actions
|
|
124
|
+
label="filled の例"
|
|
125
|
+
variant="filled"
|
|
126
|
+
items={[
|
|
127
|
+
{ key: "a", label: "やり直す", icon: <RefreshCw /> },
|
|
128
|
+
{ key: "b", label: "共有", icon: <Share2 /> },
|
|
129
|
+
]}
|
|
130
|
+
/>
|
|
131
|
+
<Actions
|
|
132
|
+
label="outlined の例"
|
|
133
|
+
variant="outlined"
|
|
134
|
+
items={[
|
|
135
|
+
{ key: "a", label: "やり直す", icon: <RefreshCw /> },
|
|
136
|
+
{ key: "b", label: "共有", icon: <Share2 /> },
|
|
137
|
+
]}
|
|
138
|
+
/>
|
|
139
|
+
</Flex>
|
|
140
|
+
|
|
141
|
+
{/* ACTIONSITEM — the four statuses, side by side. */}
|
|
142
|
+
<Flex direction="col" gap="sm">
|
|
143
|
+
<Text size="sm" weight="medium">
|
|
144
|
+
ActionsItem · status
|
|
145
|
+
</Text>
|
|
146
|
+
<Text size="xs" tone="muted">
|
|
147
|
+
状態は字にもなる。読み上げのボタン名に「実行中」「失敗」が入るので、
|
|
148
|
+
アイコンの差し替えだけに頼らない。
|
|
149
|
+
</Text>
|
|
150
|
+
<Flex gap="sm">
|
|
151
|
+
<ActionsItem defaultIcon={<Volume2 />} label="読み上げ" />
|
|
152
|
+
<ActionsItem defaultIcon={<Volume2 />} label="読み上げ" status="running" />
|
|
153
|
+
<ActionsItem defaultIcon={<Volume2 />} label="読み上げ" status="loading" />
|
|
154
|
+
<ActionsItem defaultIcon={<Volume2 />} label="読み上げ" status="error" />
|
|
155
|
+
</Flex>
|
|
156
|
+
</Flex>
|
|
157
|
+
|
|
158
|
+
{/* THE TWO READY-MADE ACTIONS, alone. */}
|
|
159
|
+
<Flex direction="col" gap="sm">
|
|
160
|
+
<Text size="sm" weight="medium">
|
|
161
|
+
ActionsCopy · ActionsFeedback
|
|
162
|
+
</Text>
|
|
163
|
+
<Text size="xs" tone="muted">
|
|
164
|
+
どちらも両方のボタンが画面に残る。押した側は aria-pressed
|
|
165
|
+
で示され、押していない側が消えることはない。
|
|
166
|
+
</Text>
|
|
167
|
+
<Flex gap="sm">
|
|
168
|
+
<ActionsCopy text={ANSWER} />
|
|
169
|
+
<ActionsFeedback value={vote} onChange={setVote} />
|
|
170
|
+
</Flex>
|
|
171
|
+
</Flex>
|
|
172
|
+
</PageContainer>
|
|
173
|
+
</AppShell>
|
|
174
|
+
);
|
|
175
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import type { CSSProperties } from "react";
|
|
2
|
+
|
|
3
|
+
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@godxjp/ui/data-display";
|
|
4
|
+
import { FloatButton, Text } from "@godxjp/ui/general";
|
|
5
|
+
import { Flex, PageContainer } from "@godxjp/ui/layout";
|
|
6
|
+
import { MessageCircle, Printer, Share2 } from "lucide-react";
|
|
7
|
+
|
|
8
|
+
/** One row up from the corner: the control's own height plus one stack step, both tokens. */
|
|
9
|
+
const STEP_UP = "calc(var(--space-stack-xl) + var(--control-height-lg) + var(--space-stack-md))";
|
|
10
|
+
/** Two rows up. */
|
|
11
|
+
const STEP_UP_TWICE =
|
|
12
|
+
"calc(var(--space-stack-xl) + (var(--control-height-lg) + var(--space-stack-md)) * 2)";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* FloatButton — Ant Design のコーナーアクションを 100% 移植したもの(antd 6.6.3)。
|
|
16
|
+
*
|
|
17
|
+
* ページの内容ではないが常に手の届く場所にあるべき道具のための、ビューポートに固定された操作子。
|
|
18
|
+
* `Button` はレイアウトの流れの中にあるので、隅に留めるには呼び出し側が `position: fixed` を書く
|
|
19
|
+
* しかなく、それは `ui-audit` が止める(gh#558)。`Popover` はパネルの位置を決めるもので、
|
|
20
|
+
* トリガーの位置は決めない。`Banner` は全幅の帯であって隅の印ではない。
|
|
21
|
+
*
|
|
22
|
+
* 隅までの距離は `--float-button-offset-block-end` / `--float-button-offset-inline-end`。
|
|
23
|
+
* 下部に固定バーがあるサービスは、メディアクエリではなくトークン 1 つで印を動かす。
|
|
24
|
+
*
|
|
25
|
+
* このフレームは実際に固定表示される要素を含むため、画面の右下に印が重なって見える。
|
|
26
|
+
* それが正しい姿で、そこが FloatButton の唯一の居場所である。
|
|
27
|
+
*/
|
|
28
|
+
export default function Demo() {
|
|
29
|
+
return (
|
|
30
|
+
<PageContainer
|
|
31
|
+
title="FloatButton"
|
|
32
|
+
subtitle="ビューポートの隅に固定される操作子 · Group と BackTop つき"
|
|
33
|
+
>
|
|
34
|
+
<Flex direction="col" gap="lg">
|
|
35
|
+
<Card>
|
|
36
|
+
<CardHeader>
|
|
37
|
+
<CardTitle level={2}>単体のボタン</CardTitle>
|
|
38
|
+
<CardDescription>
|
|
39
|
+
画面右下に丸い印が 1 つ出ている。`tooltip` を文字列で渡すと、それがアクセシブル名にも
|
|
40
|
+
なる —— アイコンだけの操作子に名前がないのは WCAG 4.1.2 違反であり、ツールチップは
|
|
41
|
+
タッチの利用者には決して届かないため。
|
|
42
|
+
</CardDescription>
|
|
43
|
+
</CardHeader>
|
|
44
|
+
<CardContent>
|
|
45
|
+
<Flex direction="col" gap="sm">
|
|
46
|
+
<Text size="sm" tone="muted">
|
|
47
|
+
type="primary" はブランド塗り、type="default" は面とヘアライン。
|
|
48
|
+
antd の語をそのまま使っている(この Library の他の場所では variant と呼ぶもの)。
|
|
49
|
+
</Text>
|
|
50
|
+
<Text size="sm" tone="muted">
|
|
51
|
+
badge は count / dot / overflowCount / showZero を取る。count が overflowCount を
|
|
52
|
+
超えると "99+" になる。
|
|
53
|
+
</Text>
|
|
54
|
+
</Flex>
|
|
55
|
+
</CardContent>
|
|
56
|
+
</Card>
|
|
57
|
+
|
|
58
|
+
<Card>
|
|
59
|
+
<CardHeader>
|
|
60
|
+
<CardTitle level={2}>Group · 積み重ねか、1 つのトリガーの後ろか</CardTitle>
|
|
61
|
+
<CardDescription>
|
|
62
|
+
`trigger` がその切り替えスイッチ。渡さなければ全部のボタンが見えたままの素の積み重ね、
|
|
63
|
+
渡せば子はトリガーの後ろに畳まれ、click か hover で開く。`placement` は top / left /
|
|
64
|
+
right / bottom。left と right は `inset-inline-*` で解決されるので、
|
|
65
|
+
dir="rtl" では画面上の向きが正しく反転する。
|
|
66
|
+
</CardDescription>
|
|
67
|
+
</CardHeader>
|
|
68
|
+
<CardContent>
|
|
69
|
+
<Text size="sm" tone="muted">
|
|
70
|
+
Group のルート要素は `pointer-events: none`、ボタンだけが `auto`。タッチ画面で、
|
|
71
|
+
ボタンとボタンの隙間に落ちたスワイプがページのスクロールを殺さないため。
|
|
72
|
+
</Text>
|
|
73
|
+
</CardContent>
|
|
74
|
+
</Card>
|
|
75
|
+
|
|
76
|
+
<Card>
|
|
77
|
+
<CardHeader>
|
|
78
|
+
<CardTitle level={2}>BackTop</CardTitle>
|
|
79
|
+
<CardDescription>
|
|
80
|
+
`visibilityHeight`(既定 400px)だけ下ったところで現れ、`duration`(既定 450ms)で
|
|
81
|
+
上まで戻す。`prefers-reduced-motion` では瞬時に移動する(WCAG 2.3.3)。 `target`
|
|
82
|
+
に「その要素を返す関数」を渡せば、document ではなくその要素を見張る —— 自前の
|
|
83
|
+
スクロール領域を持つシェルの中でも使えるのはこのため。
|
|
84
|
+
</CardDescription>
|
|
85
|
+
</CardHeader>
|
|
86
|
+
<CardContent>
|
|
87
|
+
<Text size="sm" tone="muted">
|
|
88
|
+
`showProgress` を付けると、どこまで読んだかをリングで描く。1 フレームごとに変わる値は
|
|
89
|
+
カスタムプロパティ 1 つだけで、呼び出し側に数値は 1 つも出てこない。
|
|
90
|
+
</Text>
|
|
91
|
+
</CardContent>
|
|
92
|
+
</Card>
|
|
93
|
+
</Flex>
|
|
94
|
+
|
|
95
|
+
{/*
|
|
96
|
+
実運用の画面に浮くボタンは 1 つである。このフレームは 3 つの形を同時に見せるため、
|
|
97
|
+
2 つ目と 3 つ目を 1 段ずつ上にずらしてある —— そして、そのずらし方こそが gh#558 の求めた
|
|
98
|
+
ものである: メディアクエリでも呼び出し側の px でもなく、トークンを 1 つ上書きするだけ。
|
|
99
|
+
段の高さはボタンの高さ + 段間で、どちらもトークンなので密度を変えても崩れない。
|
|
100
|
+
*/}
|
|
101
|
+
<FloatButton
|
|
102
|
+
tooltip="アシスタントに聞く"
|
|
103
|
+
type="primary"
|
|
104
|
+
icon={<MessageCircle />}
|
|
105
|
+
badge={{ count: 3 }}
|
|
106
|
+
/>
|
|
107
|
+
|
|
108
|
+
<FloatButton.Group
|
|
109
|
+
trigger="hover"
|
|
110
|
+
placement="left"
|
|
111
|
+
aria-label="その他の操作"
|
|
112
|
+
style={
|
|
113
|
+
{
|
|
114
|
+
"--float-button-offset-block-end": STEP_UP,
|
|
115
|
+
} as CSSProperties
|
|
116
|
+
}
|
|
117
|
+
>
|
|
118
|
+
<FloatButton tooltip="共有" icon={<Share2 />} />
|
|
119
|
+
<FloatButton tooltip="印刷" icon={<Printer />} />
|
|
120
|
+
</FloatButton.Group>
|
|
121
|
+
|
|
122
|
+
<FloatButton.BackTop
|
|
123
|
+
visibilityHeight={0}
|
|
124
|
+
showProgress
|
|
125
|
+
style={
|
|
126
|
+
{
|
|
127
|
+
"--float-button-offset-block-end": STEP_UP_TWICE,
|
|
128
|
+
} as CSSProperties
|
|
129
|
+
}
|
|
130
|
+
/>
|
|
131
|
+
</PageContainer>
|
|
132
|
+
);
|
|
133
|
+
}
|
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
import { useTranslation } from "@godxjp/ui/i18n";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
Button,
|
|
4
|
+
Heading,
|
|
5
|
+
Link,
|
|
6
|
+
Paragraph,
|
|
7
|
+
Text,
|
|
8
|
+
Title,
|
|
9
|
+
Typography,
|
|
10
|
+
VisuallyHidden,
|
|
11
|
+
} from "@godxjp/ui/general";
|
|
3
12
|
import {
|
|
4
13
|
Card,
|
|
5
14
|
CardContent,
|
|
@@ -231,6 +240,59 @@ export default function Demo() {
|
|
|
231
240
|
</Flex>
|
|
232
241
|
</CardContent>
|
|
233
242
|
</Card>
|
|
243
|
+
<Card>
|
|
244
|
+
<CardHeader>
|
|
245
|
+
<CardTitle level={2}>antd Typography · Title / Paragraph / Link</CardTitle>
|
|
246
|
+
<CardDescription>
|
|
247
|
+
antd の Typography をそのまま移植したもの。Text と Heading は変わらず、Title は 5
|
|
248
|
+
段階、Paragraph は rows 付きの ellipsis、Link は target="_blank" に rel
|
|
249
|
+
を自動で付けます。
|
|
250
|
+
</CardDescription>
|
|
251
|
+
</CardHeader>
|
|
252
|
+
<CardContent>
|
|
253
|
+
<Flex direction="col" gap="md">
|
|
254
|
+
<Typography>
|
|
255
|
+
<Title level={3}>請求サマリー</Title>
|
|
256
|
+
<Paragraph>今月の請求は 3 件です。明細は各行のリンクから確認できます。</Paragraph>
|
|
257
|
+
<Link href="#typography">変更履歴を見る</Link>
|
|
258
|
+
</Typography>
|
|
259
|
+
|
|
260
|
+
<Title level={5}>内訳(level 5 · Heading にはない段)</Title>
|
|
261
|
+
|
|
262
|
+
<Paragraph ellipsis={{ rows: 2, expandable: true }}>
|
|
263
|
+
ログイン画面の余白が狭く、パスワード再設定リンクが本文と重なって見えます。
|
|
264
|
+
発生条件は 390px 幅の端末で、日本語ロケールのときのみです。
|
|
265
|
+
再現手順とスクリーンショットは添付の通りです。
|
|
266
|
+
</Paragraph>
|
|
267
|
+
</Flex>
|
|
268
|
+
</CardContent>
|
|
269
|
+
</Card>
|
|
270
|
+
<Card>
|
|
271
|
+
<CardHeader>
|
|
272
|
+
<CardTitle level={2}>copyable · editable · 装飾</CardTitle>
|
|
273
|
+
<CardDescription>
|
|
274
|
+
antd の copyable / editable と、7 つの装飾フラグ。装飾は本物の要素を包むので、意味が
|
|
275
|
+
スクリーンリーダーにも届きます。
|
|
276
|
+
</CardDescription>
|
|
277
|
+
</CardHeader>
|
|
278
|
+
<CardContent>
|
|
279
|
+
<Flex direction="col" gap="sm">
|
|
280
|
+
<Text mono copyable>
|
|
281
|
+
RC-204881
|
|
282
|
+
</Text>
|
|
283
|
+
<Text editable>案件名をここで直接編集できます</Text>
|
|
284
|
+
<Text type="secondary">
|
|
285
|
+
type="secondary"(tone="muted" と同じ軸)
|
|
286
|
+
</Text>
|
|
287
|
+
<Text disabled>disabled · 使えないことを示します</Text>
|
|
288
|
+
<Text>
|
|
289
|
+
<Text code>npm run build</Text> と <Text keyboard>Ctrl</Text> +{" "}
|
|
290
|
+
<Text keyboard>S</Text>、<Text mark>強調</Text>、<Text delete>取り消し</Text>、
|
|
291
|
+
<Text strong>強い</Text>、<Text italic>斜体</Text>
|
|
292
|
+
</Text>
|
|
293
|
+
</Flex>
|
|
294
|
+
</CardContent>
|
|
295
|
+
</Card>
|
|
234
296
|
<Card>
|
|
235
297
|
<CardHeader>
|
|
236
298
|
<CardTitle level={2}>{t("textExamples.preservedText")}</CardTitle>
|