@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,322 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { FileIcon, ImagePlus, Plus, X } from "lucide-react";
|
|
5
|
+
import { useTranslation } from "../../i18n/use-translation.js";
|
|
6
|
+
import { formatBytes } from "../../lib/format.js";
|
|
7
|
+
import { cn } from "../../lib/utils.js";
|
|
8
|
+
import { Button } from "../general/button.js";
|
|
9
|
+
import { Text } from "../general/typography.js";
|
|
10
|
+
import { Progress } from "../data-display/progress.js";
|
|
11
|
+
import { createUploadItem } from "./upload-types.js";
|
|
12
|
+
import { readDroppedFiles } from "./upload-files.js";
|
|
13
|
+
const AttachmentContext = React.createContext({ disabled: false });
|
|
14
|
+
function toAttachmentItem(item) {
|
|
15
|
+
const status = item.status === "uploading" ? "uploading" : item.status === "done" ? "done" : item.status === "error" ? "error" : item.status === "removed" ? "removed" : void 0;
|
|
16
|
+
return {
|
|
17
|
+
uid: item.uid,
|
|
18
|
+
name: item.name,
|
|
19
|
+
size: item.size,
|
|
20
|
+
status,
|
|
21
|
+
percent: item.percent,
|
|
22
|
+
url: item.url,
|
|
23
|
+
thumbUrl: item.previewUrl,
|
|
24
|
+
originFileObj: item.file,
|
|
25
|
+
response: item.response,
|
|
26
|
+
error: item.error
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
function resolvePlaceholder(placeholder, type) {
|
|
30
|
+
if (!placeholder) return {};
|
|
31
|
+
return typeof placeholder === "function" ? placeholder(type) : placeholder;
|
|
32
|
+
}
|
|
33
|
+
function fileMatchesAccept(file, accept) {
|
|
34
|
+
if (!accept) return true;
|
|
35
|
+
return accept.split(",").some((rule) => {
|
|
36
|
+
const trimmed = rule.trim().toLowerCase();
|
|
37
|
+
if (trimmed.endsWith("/*")) return file.type.toLowerCase().startsWith(trimmed.slice(0, -1));
|
|
38
|
+
return file.type.toLowerCase() === trimmed || trimmed.startsWith(".") && file.name.toLowerCase().endsWith(trimmed);
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
function PlaceholderUploader({
|
|
42
|
+
type,
|
|
43
|
+
placeholder,
|
|
44
|
+
onOpen,
|
|
45
|
+
onFiles,
|
|
46
|
+
className,
|
|
47
|
+
style,
|
|
48
|
+
hidden
|
|
49
|
+
}) {
|
|
50
|
+
const { t } = useTranslation();
|
|
51
|
+
const { disabled } = React.useContext(AttachmentContext);
|
|
52
|
+
const [dragActive, setDragActive] = React.useState(false);
|
|
53
|
+
if (hidden) return null;
|
|
54
|
+
const title = placeholder.title ?? t("dataEntry.attachments.placeholderTitle");
|
|
55
|
+
const description = placeholder.description ?? t("dataEntry.attachments.placeholderDescription");
|
|
56
|
+
const icon = placeholder.icon ?? /* @__PURE__ */ jsx(ImagePlus, { "aria-hidden": "true" });
|
|
57
|
+
return /* @__PURE__ */ jsxs(
|
|
58
|
+
"div",
|
|
59
|
+
{
|
|
60
|
+
className: cn("ui-attachments-placeholder", className),
|
|
61
|
+
style,
|
|
62
|
+
"data-drag-active": dragActive ? "true" : void 0,
|
|
63
|
+
"aria-hidden": disabled ? true : void 0,
|
|
64
|
+
onDragEnter: (event) => {
|
|
65
|
+
event.preventDefault();
|
|
66
|
+
if (!disabled) setDragActive(true);
|
|
67
|
+
},
|
|
68
|
+
onDragOver: (event) => event.preventDefault(),
|
|
69
|
+
onDragLeave: (event) => {
|
|
70
|
+
if (!event.currentTarget.contains(event.relatedTarget)) setDragActive(false);
|
|
71
|
+
},
|
|
72
|
+
onDrop: async (event) => {
|
|
73
|
+
event.preventDefault();
|
|
74
|
+
setDragActive(false);
|
|
75
|
+
if (disabled) return;
|
|
76
|
+
const files = await readDroppedFiles(event.dataTransfer, false);
|
|
77
|
+
if (files.length) onFiles(files);
|
|
78
|
+
},
|
|
79
|
+
onClick: () => {
|
|
80
|
+
if (!disabled) onOpen();
|
|
81
|
+
},
|
|
82
|
+
onKeyDown: (event) => {
|
|
83
|
+
if (disabled) return;
|
|
84
|
+
if (event.key === "Enter" || event.key === " ") {
|
|
85
|
+
event.preventDefault();
|
|
86
|
+
onOpen();
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
role: "button",
|
|
90
|
+
tabIndex: disabled ? -1 : 0,
|
|
91
|
+
"aria-label": String(title),
|
|
92
|
+
children: [
|
|
93
|
+
/* @__PURE__ */ jsx("span", { className: "ui-attachments-placeholder-icon", children: icon }),
|
|
94
|
+
title ? /* @__PURE__ */ jsx("span", { className: "ui-attachments-placeholder-title", children: title }) : null,
|
|
95
|
+
description ? /* @__PURE__ */ jsx("span", { className: "ui-attachments-placeholder-description", children: description }) : null,
|
|
96
|
+
/* @__PURE__ */ jsx("span", { className: "sr-only", children: t("dataEntry.attachments.dropLabel", { type }) })
|
|
97
|
+
]
|
|
98
|
+
}
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
function AttachmentCard({
|
|
102
|
+
item,
|
|
103
|
+
description,
|
|
104
|
+
onRemove,
|
|
105
|
+
classNames
|
|
106
|
+
}) {
|
|
107
|
+
const { t } = useTranslation();
|
|
108
|
+
const { disabled } = React.useContext(AttachmentContext);
|
|
109
|
+
const preview = item.thumbUrl ?? item.url;
|
|
110
|
+
const desc = description ?? item.description ?? (item.status === "uploading" ? `${item.percent ?? 0}%` : item.status === "error" ? typeof item.response === "string" ? item.response : t("dataEntry.attachments.error") : item.size ? formatBytes(item.size) : "");
|
|
111
|
+
return /* @__PURE__ */ jsxs("li", { className: cn("ui-attachments-card", classNames?.card, classNames?.file), children: [
|
|
112
|
+
preview ? /* @__PURE__ */ jsx("img", { src: preview, alt: "", className: "ui-attachments-card-preview", "aria-hidden": "true" }) : /* @__PURE__ */ jsx("span", { className: "ui-attachments-card-placeholder", "aria-hidden": "true", children: /* @__PURE__ */ jsx(FileIcon, {}) }),
|
|
113
|
+
(item.status === "uploading" || item.status === "error") && /* @__PURE__ */ jsx("div", { className: "ui-attachments-card-overlay", children: item.status === "uploading" && item.percent != null ? /* @__PURE__ */ jsx(Progress, { value: item.percent, "aria-label": t("dataEntry.attachments.uploading") }) : /* @__PURE__ */ jsx(Text, { size: "xs", children: String(desc) }) }),
|
|
114
|
+
desc && item.status !== "uploading" && item.status !== "error" ? /* @__PURE__ */ jsx("div", { className: "ui-attachments-card-meta", children: desc }) : null,
|
|
115
|
+
!disabled && onRemove ? /* @__PURE__ */ jsx(
|
|
116
|
+
Button,
|
|
117
|
+
{
|
|
118
|
+
type: "button",
|
|
119
|
+
variant: "ghost",
|
|
120
|
+
size: "icon-xs",
|
|
121
|
+
className: "ui-attachments-card-remove",
|
|
122
|
+
"aria-label": t("dataEntry.attachments.remove", { name: item.name }),
|
|
123
|
+
onClick: (event) => {
|
|
124
|
+
event.stopPropagation();
|
|
125
|
+
onRemove();
|
|
126
|
+
},
|
|
127
|
+
children: /* @__PURE__ */ jsx(X, { "aria-hidden": "true" })
|
|
128
|
+
}
|
|
129
|
+
) : null
|
|
130
|
+
] });
|
|
131
|
+
}
|
|
132
|
+
const Attachments = React.forwardRef(
|
|
133
|
+
({
|
|
134
|
+
className,
|
|
135
|
+
rootClassName,
|
|
136
|
+
classNames = {},
|
|
137
|
+
styles = {},
|
|
138
|
+
items: controlledItems,
|
|
139
|
+
onChange,
|
|
140
|
+
onRemove,
|
|
141
|
+
overflow,
|
|
142
|
+
placeholder,
|
|
143
|
+
getDropContainer,
|
|
144
|
+
disabled = false,
|
|
145
|
+
maxCount,
|
|
146
|
+
accept,
|
|
147
|
+
multiple,
|
|
148
|
+
children
|
|
149
|
+
}, ref) => {
|
|
150
|
+
const { t } = useTranslation();
|
|
151
|
+
const containerRef = React.useRef(null);
|
|
152
|
+
const inputRef = React.useRef(null);
|
|
153
|
+
const [internalItems, setInternalItems] = React.useState([]);
|
|
154
|
+
const items = controlledItems ?? internalItems;
|
|
155
|
+
const setItems = React.useCallback(
|
|
156
|
+
(next, file) => {
|
|
157
|
+
if (controlledItems === void 0) setInternalItems(next);
|
|
158
|
+
onChange?.({ file, fileList: next });
|
|
159
|
+
},
|
|
160
|
+
[controlledItems, onChange]
|
|
161
|
+
);
|
|
162
|
+
const openPicker = React.useCallback(() => {
|
|
163
|
+
inputRef.current?.click();
|
|
164
|
+
}, []);
|
|
165
|
+
const dispatchFiles = React.useCallback(
|
|
166
|
+
(files) => {
|
|
167
|
+
const accepted = files.filter((file) => fileMatchesAccept(file, accept));
|
|
168
|
+
if (!accepted.length) return;
|
|
169
|
+
const room = maxCount == null ? accepted.length : Math.max(0, maxCount - items.length);
|
|
170
|
+
const picked = accepted.slice(0, room);
|
|
171
|
+
const next = [
|
|
172
|
+
...items,
|
|
173
|
+
...picked.map((file) => {
|
|
174
|
+
const uploadItem = createUploadItem(file);
|
|
175
|
+
return toAttachmentItem(uploadItem);
|
|
176
|
+
})
|
|
177
|
+
];
|
|
178
|
+
const last = next[next.length - 1];
|
|
179
|
+
if (last) setItems(next, last);
|
|
180
|
+
},
|
|
181
|
+
[accept, items, maxCount, setItems]
|
|
182
|
+
);
|
|
183
|
+
React.useImperativeHandle(ref, () => ({
|
|
184
|
+
nativeElement: containerRef.current,
|
|
185
|
+
fileNativeElement: inputRef.current,
|
|
186
|
+
upload: (file) => dispatchFiles([file]),
|
|
187
|
+
select: (options) => {
|
|
188
|
+
const input = inputRef.current;
|
|
189
|
+
if (!input) return;
|
|
190
|
+
input.multiple = options?.multiple ?? false;
|
|
191
|
+
input.accept = options?.accept ?? accept ?? "";
|
|
192
|
+
input.click();
|
|
193
|
+
}
|
|
194
|
+
}));
|
|
195
|
+
const handleRemove = async (item) => {
|
|
196
|
+
const ret = await Promise.resolve(typeof onRemove === "function" ? onRemove(item) : onRemove);
|
|
197
|
+
if (ret === false) return;
|
|
198
|
+
const next = items.filter((entry) => entry.uid !== item.uid);
|
|
199
|
+
setItems(next, { ...item, status: "removed" });
|
|
200
|
+
};
|
|
201
|
+
const showExtension = !disabled && (maxCount == null || maxCount > items.length) && items.length > 0;
|
|
202
|
+
const inlinePlaceholder = resolvePlaceholder(placeholder, "inline");
|
|
203
|
+
const dropPlaceholder = resolvePlaceholder(placeholder, "drop");
|
|
204
|
+
const hasFiles = items.length > 0;
|
|
205
|
+
const fileInput = /* @__PURE__ */ jsx(
|
|
206
|
+
"input",
|
|
207
|
+
{
|
|
208
|
+
ref: inputRef,
|
|
209
|
+
type: "file",
|
|
210
|
+
className: "ui-attachments-input",
|
|
211
|
+
accept,
|
|
212
|
+
multiple: multiple ?? (maxCount == null || maxCount > 1),
|
|
213
|
+
disabled,
|
|
214
|
+
"aria-label": t("dataEntry.attachments.inputLabel"),
|
|
215
|
+
onChange: (event) => {
|
|
216
|
+
const files = event.target.files ? Array.from(event.target.files) : [];
|
|
217
|
+
event.target.value = "";
|
|
218
|
+
dispatchFiles(files);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
);
|
|
222
|
+
if (children) {
|
|
223
|
+
return /* @__PURE__ */ jsxs(AttachmentContext.Provider, { value: { disabled }, children: [
|
|
224
|
+
fileInput,
|
|
225
|
+
/* @__PURE__ */ jsx(
|
|
226
|
+
"div",
|
|
227
|
+
{
|
|
228
|
+
ref: containerRef,
|
|
229
|
+
className: cn("ui-attachments", rootClassName, classNames.root),
|
|
230
|
+
style: styles.root,
|
|
231
|
+
children
|
|
232
|
+
}
|
|
233
|
+
),
|
|
234
|
+
/* @__PURE__ */ jsx(
|
|
235
|
+
PlaceholderUploader,
|
|
236
|
+
{
|
|
237
|
+
type: "drop",
|
|
238
|
+
placeholder: dropPlaceholder,
|
|
239
|
+
onOpen: openPicker,
|
|
240
|
+
onFiles: dispatchFiles,
|
|
241
|
+
className: classNames.placeholder,
|
|
242
|
+
style: styles.placeholder
|
|
243
|
+
}
|
|
244
|
+
)
|
|
245
|
+
] });
|
|
246
|
+
}
|
|
247
|
+
const dropHost = getDropContainer?.() ?? containerRef.current;
|
|
248
|
+
return /* @__PURE__ */ jsx(AttachmentContext.Provider, { value: { disabled }, children: /* @__PURE__ */ jsxs(
|
|
249
|
+
"div",
|
|
250
|
+
{
|
|
251
|
+
ref: containerRef,
|
|
252
|
+
className: cn("ui-attachments", className, rootClassName, classNames.root),
|
|
253
|
+
style: styles.root,
|
|
254
|
+
dir: "auto",
|
|
255
|
+
children: [
|
|
256
|
+
fileInput,
|
|
257
|
+
hasFiles ? /* @__PURE__ */ jsxs(
|
|
258
|
+
"ul",
|
|
259
|
+
{
|
|
260
|
+
className: cn("ui-attachments-list", classNames.list),
|
|
261
|
+
style: styles.list,
|
|
262
|
+
"data-overflow": overflow ?? "wrap",
|
|
263
|
+
children: [
|
|
264
|
+
items.map((item) => /* @__PURE__ */ jsx(
|
|
265
|
+
AttachmentCard,
|
|
266
|
+
{
|
|
267
|
+
item,
|
|
268
|
+
onRemove: () => handleRemove(item),
|
|
269
|
+
classNames
|
|
270
|
+
},
|
|
271
|
+
item.uid
|
|
272
|
+
)),
|
|
273
|
+
showExtension ? /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
|
|
274
|
+
"button",
|
|
275
|
+
{
|
|
276
|
+
type: "button",
|
|
277
|
+
className: cn("ui-attachments-upload-btn", classNames.upload),
|
|
278
|
+
style: styles.upload,
|
|
279
|
+
disabled,
|
|
280
|
+
"aria-label": t("dataEntry.attachments.add"),
|
|
281
|
+
onClick: openPicker,
|
|
282
|
+
children: /* @__PURE__ */ jsx(Plus, { "aria-hidden": "true" })
|
|
283
|
+
}
|
|
284
|
+
) }) : null
|
|
285
|
+
]
|
|
286
|
+
}
|
|
287
|
+
) : null,
|
|
288
|
+
/* @__PURE__ */ jsx(
|
|
289
|
+
PlaceholderUploader,
|
|
290
|
+
{
|
|
291
|
+
type: "inline",
|
|
292
|
+
placeholder: inlinePlaceholder,
|
|
293
|
+
onOpen: openPicker,
|
|
294
|
+
onFiles: dispatchFiles,
|
|
295
|
+
className: classNames.placeholder,
|
|
296
|
+
style: hasFiles ? { display: "none" } : styles.placeholder,
|
|
297
|
+
hidden: hasFiles
|
|
298
|
+
}
|
|
299
|
+
),
|
|
300
|
+
dropHost ? /* @__PURE__ */ jsx(
|
|
301
|
+
"div",
|
|
302
|
+
{
|
|
303
|
+
className: "ui-attachments-drop-layer",
|
|
304
|
+
"data-active": void 0,
|
|
305
|
+
"aria-hidden": "true",
|
|
306
|
+
onDragOver: (event) => event.preventDefault(),
|
|
307
|
+
onDrop: async (event) => {
|
|
308
|
+
event.preventDefault();
|
|
309
|
+
const files = await readDroppedFiles(event.dataTransfer, false);
|
|
310
|
+
dispatchFiles(files);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
) : null
|
|
314
|
+
]
|
|
315
|
+
}
|
|
316
|
+
) });
|
|
317
|
+
}
|
|
318
|
+
);
|
|
319
|
+
Attachments.displayName = "Attachments";
|
|
320
|
+
export {
|
|
321
|
+
Attachments
|
|
322
|
+
};
|
|
@@ -69,3 +69,5 @@ export { TimeRangePicker } from "./time-range-picker.js";
|
|
|
69
69
|
export type { TimeRangePickerProps } from "./time-range-picker.js";
|
|
70
70
|
export type { UploadRequestContext, UploadResult, UploadRejection } from "./upload-types.js";
|
|
71
71
|
export type { UploadItemActions } from "./upload-types.js";
|
|
72
|
+
export { Attachments } from "./attachments.js";
|
|
73
|
+
export type { AttachmentsProp, AttachmentsProps, AttachmentsItemProp, AttachmentsPlaceholderProp, AttachmentsOverflowProp, AttachmentsRefProp, } from "./attachments.js";
|
|
@@ -59,7 +59,9 @@ import { TagInput } from "./tag-input.js";
|
|
|
59
59
|
import { Segmented } from "./segmented.js";
|
|
60
60
|
import { BranchScopePicker } from "./branch-scope-picker.js";
|
|
61
61
|
import { TimeRangePicker } from "./time-range-picker.js";
|
|
62
|
+
import { Attachments } from "./attachments.js";
|
|
62
63
|
export {
|
|
64
|
+
Attachments,
|
|
63
65
|
BranchScopePicker,
|
|
64
66
|
Calendar,
|
|
65
67
|
Cascader,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import type { ToneProp } from "../../props/vocabulary/index.js";
|
|
3
|
-
import type { AlertDialogProp } from "../../props/components/feedback.prop.js";
|
|
4
|
-
export type { AlertDialogProp, AlertDialogProp as AlertDialogProps, } from "../../props/components/feedback.prop.js";
|
|
3
|
+
import type { AlertDialogProp, DialogContentProp, DialogProp } from "../../props/components/feedback.prop.js";
|
|
4
|
+
export type { AlertDialogProp, AlertDialogProp as AlertDialogProps, DialogProp, DialogProp as DialogProps, DialogContentProp, DialogContentProp as DialogContentProps, } from "../../props/components/feedback.prop.js";
|
|
5
5
|
interface OverlayOpenProps {
|
|
6
6
|
/** Trạng thái mở, có kiểm soát. */
|
|
7
7
|
open?: boolean;
|
|
@@ -10,7 +10,7 @@ interface OverlayOpenProps {
|
|
|
10
10
|
/** Gọi khi trạng thái mở đổi. */
|
|
11
11
|
onOpenChange?: (open: boolean) => void;
|
|
12
12
|
}
|
|
13
|
-
interface DialogRootProps extends OverlayOpenProps {
|
|
13
|
+
interface DialogRootProps extends OverlayOpenProps, Pick<DialogProp, "variant"> {
|
|
14
14
|
/**
|
|
15
15
|
* Giữ tên prop của Radix. RAC không có kiểu overlay không-modal: `Modal` LUÔN khoá cuộn và ẩn
|
|
16
16
|
* nền khỏi trình đọc màn hình, nên `modal={false}` không còn tắt được điều đó.
|
|
@@ -19,7 +19,7 @@ interface DialogRootProps extends OverlayOpenProps {
|
|
|
19
19
|
children?: React.ReactNode;
|
|
20
20
|
}
|
|
21
21
|
/** `data-slot="dialog"` cũ nằm trên Root của Radix, thứ không dựng thẻ nào — nó chưa từng ra DOM. */
|
|
22
|
-
declare function DialogRoot({ children, modal: _modal, ...openProps }: DialogRootProps): React.JSX.Element;
|
|
22
|
+
declare function DialogRoot({ children, modal: _modal, variant, ...openProps }: DialogRootProps): React.JSX.Element;
|
|
23
23
|
interface DialogTriggerProps extends React.ComponentPropsWithRef<"button"> {
|
|
24
24
|
/** Mượn thẻ của con thay vì dựng `<button>` riêng. */
|
|
25
25
|
asChild?: boolean;
|
|
@@ -48,7 +48,7 @@ declare function DialogOverlay(_props: DialogOverlayProps): null;
|
|
|
48
48
|
declare namespace DialogOverlay {
|
|
49
49
|
var displayName: string;
|
|
50
50
|
}
|
|
51
|
-
interface DialogContentProps extends Omit<React.ComponentPropsWithRef<"section">, "role"> {
|
|
51
|
+
interface DialogContentProps extends Omit<React.ComponentPropsWithRef<"section">, "role">, Pick<DialogContentProp, "variant"> {
|
|
52
52
|
showClose?: boolean;
|
|
53
53
|
showCloseButton?: boolean;
|
|
54
54
|
overlayClassName?: string;
|
|
@@ -57,7 +57,7 @@ interface DialogContentProps extends Omit<React.ComponentPropsWithRef<"section">
|
|
|
57
57
|
/** Giữ tên prop của Radix — xem `useCloseAutoFocus`. */
|
|
58
58
|
onCloseAutoFocus?: (event: Event) => void;
|
|
59
59
|
}
|
|
60
|
-
declare function DialogContent({ className, children, showClose, showCloseButton: showCloseButtonProp, overlayClassName, forceMount: _forceMount, ...props }: DialogContentProps): React.JSX.Element;
|
|
60
|
+
declare function DialogContent({ className, children, showClose, showCloseButton: showCloseButtonProp, overlayClassName, variant: variantProp, forceMount: _forceMount, ...props }: DialogContentProps): React.JSX.Element;
|
|
61
61
|
declare namespace DialogContent {
|
|
62
62
|
var displayName: string;
|
|
63
63
|
}
|
|
@@ -125,7 +125,10 @@ interface DialogActionProps extends React.ComponentPropsWithRef<"button"> {
|
|
|
125
125
|
/** Mượn thẻ của con thay vì dựng `<button>` riêng. */
|
|
126
126
|
asChild?: boolean;
|
|
127
127
|
}
|
|
128
|
-
/**
|
|
128
|
+
/**
|
|
129
|
+
* Confirm mode — primary action (maps to Radix AlertDialogAction). Nhấn mạnh đọc từ `variant` của
|
|
130
|
+
* hộp thoại: đây là phần thứ ba của một-prop-ba-việc ở đầu tệp, và là chỗ antd đặt `okType`.
|
|
131
|
+
*/
|
|
129
132
|
declare function DialogAction({ asChild, className, onClick, ...props }: DialogActionProps): React.JSX.Element;
|
|
130
133
|
declare namespace DialogAction {
|
|
131
134
|
var displayName: string;
|
|
@@ -40,6 +40,7 @@ function useDialogOpenState(component) {
|
|
|
40
40
|
return state;
|
|
41
41
|
}
|
|
42
42
|
const DialogLabelContext = React.createContext(null);
|
|
43
|
+
const DialogVariantContext = React.createContext("default");
|
|
43
44
|
const OVERLAY_CLASS = "ui-dialog-overlay data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:animate-in data-[state=open]:fade-in-0";
|
|
44
45
|
const CONTENT_CLASS = "data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 duration-200 outline-none";
|
|
45
46
|
function DialogShell({
|
|
@@ -89,9 +90,14 @@ function DialogShell({
|
|
|
89
90
|
}
|
|
90
91
|
);
|
|
91
92
|
}
|
|
92
|
-
function DialogRoot({
|
|
93
|
+
function DialogRoot({
|
|
94
|
+
children,
|
|
95
|
+
modal: _modal,
|
|
96
|
+
variant = "default",
|
|
97
|
+
...openProps
|
|
98
|
+
}) {
|
|
93
99
|
const state = useOverlayOpenState(openProps);
|
|
94
|
-
return /* @__PURE__ */ jsx(DialogOpenContext.Provider, { value: state, children });
|
|
100
|
+
return /* @__PURE__ */ jsx(DialogOpenContext.Provider, { value: state, children: /* @__PURE__ */ jsx(DialogVariantContext.Provider, { value: variant, children }) });
|
|
95
101
|
}
|
|
96
102
|
function DialogTrigger({ asChild, onClick, ...props }) {
|
|
97
103
|
const state = useDialogOpenState("DialogTrigger");
|
|
@@ -139,24 +145,39 @@ function DialogContent({
|
|
|
139
145
|
showClose,
|
|
140
146
|
showCloseButton: showCloseButtonProp,
|
|
141
147
|
overlayClassName,
|
|
148
|
+
variant: variantProp,
|
|
142
149
|
forceMount: _forceMount,
|
|
143
150
|
...props
|
|
144
151
|
}) {
|
|
145
152
|
const { t } = useTranslation();
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
153
|
+
const inheritedVariant = React.useContext(DialogVariantContext);
|
|
154
|
+
const variant = variantProp ?? inheritedVariant;
|
|
155
|
+
const isDestructive = variant === "destructive";
|
|
156
|
+
const showCloseButton = showCloseButtonProp ?? showClose ?? !isDestructive;
|
|
157
|
+
return /* @__PURE__ */ jsx(DialogVariantContext.Provider, { value: variant, children: /* @__PURE__ */ jsxs(
|
|
158
|
+
DialogShell,
|
|
159
|
+
{
|
|
160
|
+
role: isDestructive ? "alertdialog" : "dialog",
|
|
161
|
+
isDismissable: !isDestructive,
|
|
162
|
+
"data-variant": variant,
|
|
163
|
+
className,
|
|
164
|
+
overlayClassName,
|
|
165
|
+
...props,
|
|
166
|
+
children: [
|
|
167
|
+
children,
|
|
168
|
+
showCloseButton ? /* @__PURE__ */ jsxs(
|
|
169
|
+
DialogClose,
|
|
170
|
+
{
|
|
171
|
+
className: "ui-focus-ring transition-opacity disabled:pointer-events-none",
|
|
172
|
+
children: [
|
|
173
|
+
/* @__PURE__ */ jsx(X, { className: "ui-dialog-close-icon", "aria-hidden": "true" }),
|
|
174
|
+
/* @__PURE__ */ jsx("span", { className: "sr-only", children: t("feedback.alert.dismiss") })
|
|
175
|
+
]
|
|
176
|
+
}
|
|
177
|
+
) : null
|
|
178
|
+
]
|
|
179
|
+
}
|
|
180
|
+
) });
|
|
160
181
|
}
|
|
161
182
|
DialogContent.displayName = "DialogContent";
|
|
162
183
|
const DialogHeader = ({
|
|
@@ -312,12 +333,14 @@ const AlertDialogTitle = DialogTitle;
|
|
|
312
333
|
const AlertDialogDescription = DialogDescription;
|
|
313
334
|
function DialogAction({ asChild, className, onClick, ...props }) {
|
|
314
335
|
const state = useDialogOpenState("DialogAction");
|
|
336
|
+
const variant = React.useContext(DialogVariantContext);
|
|
315
337
|
const Comp = asChild ? Slot : "button";
|
|
316
338
|
return /* @__PURE__ */ jsx(
|
|
317
339
|
Comp,
|
|
318
340
|
{
|
|
319
341
|
type: "button",
|
|
320
|
-
|
|
342
|
+
"data-variant": asChild ? void 0 : variant,
|
|
343
|
+
className: cn(buttonVariants({ variant }), className),
|
|
321
344
|
...props,
|
|
322
345
|
onClick: chain(onClick, () => {
|
|
323
346
|
state.setOpen(false);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { Dialog, DialogClose, DialogContent, DialogDescription, DialogBody, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DialogAction, DialogCancel, AlertDialogRoot, AlertDialogTrigger, AlertDialogPortal, AlertDialogOverlay, AlertDialogContent, AlertDialogHeader, AlertDialogFooter, AlertDialogTitle, AlertDialogDescription, AlertDialogAction, AlertDialogCancel, AlertDialog, } from "./dialog.js";
|
|
2
|
-
export type { AlertDialogProp, AlertDialogProps } from "./dialog.js";
|
|
2
|
+
export type { AlertDialogProp, AlertDialogProps, DialogProp, DialogProps, DialogContentProp, DialogContentProps, } from "./dialog.js";
|
|
3
3
|
export { Sheet, SheetBody, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger, useSheetResponsiveMode, } from "./sheet.js";
|
|
4
4
|
export type { SheetContentProps, SheetPresentation, SheetResponsiveProp } from "./sheet.js";
|
|
5
5
|
export { TwoFactorSetup } from "./two-factor-setup.js";
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import type { ActionsCopyProp, ActionsFeedbackProp, ActionsItemProp, ActionsProp } from "../../props/components/general.prop.js";
|
|
3
|
+
export type { ActionsProp, ActionsProp as ActionsProps, ActionsItemsProp, ActionsItemProp, ActionsItemProp as ActionsItemProps, ActionsCopyProp, ActionsCopyProp as ActionsCopyProps, ActionsFeedbackProp, ActionsFeedbackProp as ActionsFeedbackProps, ActionsVariantProp, ActionsStatusProp, ActionsFeedbackValueProp, } from "../../props/components/general.prop.js";
|
|
4
|
+
/**
|
|
5
|
+
* Actions — the strip of actions under an assistant message (Ant Design X `Actions`).
|
|
6
|
+
*
|
|
7
|
+
* ## What Ant X ships, measured
|
|
8
|
+
*
|
|
9
|
+
* `@ant-design/x@2.9.0`, `es/actions/Item.js`: each action is
|
|
10
|
+
* `<div className="…-item" onClick>` wrapping `<div className="…-icon">{item.icon}</div>`, with
|
|
11
|
+
* the label supplied only as a `Tooltip` title. Three consequences, all of them defects rather
|
|
12
|
+
* than choices: the strip cannot be reached by keyboard at all, the actions have no accessible
|
|
13
|
+
* name, and on a touch device — where `useMobile()` drops the Tooltip entirely — they have no
|
|
14
|
+
* visible name either.
|
|
15
|
+
*
|
|
16
|
+
* ## What this port does about it, while keeping the API
|
|
17
|
+
*
|
|
18
|
+
* `items`, `onClick({ item, key, keyPath, domEvent })`, `onItemClick` winning over `onClick`,
|
|
19
|
+
* `danger`, `subItems`, `actionRender`, `variant`, `fadeIn` / `fadeInLeft` — all Ant's, with Ant's
|
|
20
|
+
* semantics. What changes is what they render onto: a real `Button` per action carrying `label` as
|
|
21
|
+
* its accessible name AND its tooltip, inside a WAI-ARIA APG **Toolbar** — one tab stop for the
|
|
22
|
+
* whole strip, the logical arrows moving between the actions, `Home` / `End` at its ends. That is
|
|
23
|
+
* the same trade `Conversations` makes and for the same reason: a strip of eight actions under
|
|
24
|
+
* every message would otherwise be eight tab stops between the reader and the next message.
|
|
25
|
+
*/
|
|
26
|
+
export declare const Actions: React.ForwardRefExoticComponent<ActionsProp & React.RefAttributes<HTMLDivElement>>;
|
|
27
|
+
/**
|
|
28
|
+
* ActionsItem — one status-aware action (Ant Design X `Actions.Item`).
|
|
29
|
+
*
|
|
30
|
+
* It is a NAMED export rather than `Actions.Item`, because this library has no compound-static
|
|
31
|
+
* convention: `CardHeader`, `TabsList` and `DropdownMenuItem` are all separate exports, and one
|
|
32
|
+
* component attaching statics would be the only one of its kind.
|
|
33
|
+
*
|
|
34
|
+
* The status table is Ant's, from `es/actions/ActionsItem.js`: `loading` and `error` bring their
|
|
35
|
+
* own glyph, `running` takes `runningIcon`, anything else takes `defaultIcon`. What is added is
|
|
36
|
+
* that the status is ANNOUNCED — `aria-busy` while loading, and the state in the accessible name —
|
|
37
|
+
* because a glyph swap is a colour-and-shape-only signal (WCAG 1.4.1).
|
|
38
|
+
*/
|
|
39
|
+
export declare const ActionsItem: React.ForwardRefExoticComponent<ActionsItemProp & React.RefAttributes<HTMLButtonElement>>;
|
|
40
|
+
/**
|
|
41
|
+
* ActionsCopy — copy the message to the clipboard (Ant Design X `Actions.Copy`).
|
|
42
|
+
*
|
|
43
|
+
* Ant X hands this to antd's `Typography copyable`, which swaps the glyph to a tick for 3s. The
|
|
44
|
+
* tick is reproduced at the same 3s, and the change is also SPOKEN through a polite status region:
|
|
45
|
+
* a glyph that only changes shape tells a screen-reader user nothing about whether the copy
|
|
46
|
+
* worked, which is the one thing this control exists to report.
|
|
47
|
+
*/
|
|
48
|
+
export declare const ActionsCopy: React.ForwardRefExoticComponent<ActionsCopyProp & React.RefAttributes<HTMLButtonElement>>;
|
|
49
|
+
/**
|
|
50
|
+
* ActionsFeedback — the like / dislike pair (Ant Design X `Actions.Feedback`).
|
|
51
|
+
*
|
|
52
|
+
* `value` / `onChange` and the clear-on-second-click behaviour are Ant's, byte for byte. ONE
|
|
53
|
+
* rendering difference, and it is deliberate: Ant hides the opposite button once an opinion is
|
|
54
|
+
* recorded (`[default, like].includes(value) && likeNode`), so a reader who mis-clicked "dislike"
|
|
55
|
+
* finds no "like" button on the screen at all and has to guess that clicking dislike again brings
|
|
56
|
+
* it back. Both buttons stay here, and the recorded opinion is carried by `aria-pressed` — the APG
|
|
57
|
+
* toggle-button pattern, which states the value instead of removing its alternative.
|
|
58
|
+
*/
|
|
59
|
+
export declare const ActionsFeedback: React.ForwardRefExoticComponent<ActionsFeedbackProp & React.RefAttributes<HTMLDivElement>>;
|