@godxjp/ui 23.3.0 → 23.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/dist/components/data-display/card.d.ts +87 -1
  2. package/dist/components/data-display/card.js +88 -15
  3. package/dist/components/data-display/index.d.ts +5 -1
  4. package/dist/components/data-display/index.js +5 -0
  5. package/dist/components/data-display/thought-chain.d.ts +42 -0
  6. package/dist/components/data-display/thought-chain.js +177 -0
  7. package/dist/components/data-display/welcome.d.ts +26 -0
  8. package/dist/components/data-display/welcome.js +37 -0
  9. package/dist/components/data-entry/attachments.d.ts +19 -0
  10. package/dist/components/data-entry/attachments.js +322 -0
  11. package/dist/components/data-entry/index.d.ts +2 -0
  12. package/dist/components/data-entry/index.js +2 -0
  13. package/dist/components/feedback/dialog.d.ts +10 -7
  14. package/dist/components/feedback/dialog.js +40 -17
  15. package/dist/components/feedback/index.d.ts +1 -1
  16. package/dist/components/general/actions.d.ts +59 -0
  17. package/dist/components/general/actions.js +253 -0
  18. package/dist/components/general/activity.js +1 -0
  19. package/dist/components/general/float-button.d.ts +41 -0
  20. package/dist/components/general/float-button.js +336 -0
  21. package/dist/components/general/index.d.ts +6 -2
  22. package/dist/components/general/index.js +12 -1
  23. package/dist/components/general/typography.d.ts +79 -4
  24. package/dist/components/general/typography.js +598 -54
  25. package/dist/components/layout/draggable-panel.d.ts +18 -0
  26. package/dist/components/layout/draggable-panel.js +189 -0
  27. package/dist/components/layout/index.d.ts +2 -0
  28. package/dist/components/layout/index.js +2 -0
  29. package/dist/components/navigation/conversations.d.ts +39 -0
  30. package/dist/components/navigation/conversations.js +371 -0
  31. package/dist/components/navigation/index.d.ts +2 -0
  32. package/dist/components/navigation/index.js +2 -0
  33. package/dist/components/ui/card.js +1 -0
  34. package/dist/i18n/messages/en.json +53 -0
  35. package/dist/i18n/messages/ja.json +53 -0
  36. package/dist/i18n/messages/vi.json +53 -0
  37. package/dist/props/components/data-display.prop.d.ts +143 -1
  38. package/dist/props/components/data-entry.prop.d.ts +76 -0
  39. package/dist/props/components/feedback.prop.d.ts +34 -1
  40. package/dist/props/components/general.prop.d.ts +440 -3
  41. package/dist/props/components/index.d.ts +2 -2
  42. package/dist/props/components/layout.prop.d.ts +63 -1
  43. package/dist/props/components/navigation.prop.d.ts +150 -0
  44. package/dist/props/registry.d.ts +426 -0
  45. package/dist/props/registry.js +546 -0
  46. package/dist/props/vocabulary/index.d.ts +1 -1
  47. package/dist/props/vocabulary/interaction.prop.d.ts +113 -0
  48. package/dist/styles/card-layout.css +30 -0
  49. package/dist/styles/core.css +1 -0
  50. package/dist/styles/data-display-layout.css +236 -0
  51. package/dist/styles/float-button-layout.css +168 -0
  52. package/dist/styles/index.css +1 -0
  53. package/dist/styles/layout.css +196 -0
  54. package/dist/styles/navigation-layout.css +139 -0
  55. package/dist/styles/text-layout.css +156 -0
  56. package/dist/tokens/base.css +7 -0
  57. package/dist/tokens/components/actions.css +14 -0
  58. package/dist/tokens/components/attachments.css +15 -0
  59. package/dist/tokens/components/conversations.css +28 -0
  60. package/dist/tokens/components/draggable-panel.css +25 -0
  61. package/dist/tokens/components/float-button.css +39 -0
  62. package/dist/tokens/components/text.css +13 -0
  63. package/dist/tokens/components/thought-chain.css +31 -0
  64. package/dist/tokens/components/welcome.css +19 -0
  65. package/dist/tokens/foundation.css +2 -0
  66. package/docs/DESIGN-AUTHORITY.md +89 -0
  67. package/docs/FRAME-COVERAGE-REPORT.md +5 -2
  68. package/docs/data-display/card/examples/tab-list.tsx +97 -0
  69. package/docs/data-display/thought-chain.tsx +176 -0
  70. package/docs/data-display/welcome.tsx +115 -0
  71. package/docs/data-entry/attachments.tsx +160 -0
  72. package/docs/feedback/dialog.tsx +50 -0
  73. package/docs/general/actions.tsx +175 -0
  74. package/docs/general/float-button.tsx +133 -0
  75. package/docs/general/typography.tsx +63 -1
  76. package/docs/layout/draggable-panel.tsx +127 -0
  77. package/docs/navigation/conversations.tsx +176 -0
  78. package/docs/roadmap/parity-audit-layout-navigation-general.md +17 -16
  79. package/package.json +3 -3
@@ -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
- /** Confirm mode — primary action (maps to Radix AlertDialogAction). */
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({ children, modal: _modal, ...openProps }) {
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 showCloseButton = showCloseButtonProp ?? showClose ?? true;
147
- return /* @__PURE__ */ jsxs(DialogShell, { isDismissable: true, className, overlayClassName, ...props, children: [
148
- children,
149
- showCloseButton ? /* @__PURE__ */ jsxs(
150
- DialogClose,
151
- {
152
- className: "ui-focus-ring transition-opacity disabled:pointer-events-none",
153
- children: [
154
- /* @__PURE__ */ jsx(X, { className: "ui-dialog-close-icon", "aria-hidden": "true" }),
155
- /* @__PURE__ */ jsx("span", { className: "sr-only", children: t("feedback.alert.dismiss") })
156
- ]
157
- }
158
- ) : null
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
- className: cn(buttonVariants(), className),
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>>;