@neasg/design-system 0.4.118 → 0.4.121

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/dialog.d.ts CHANGED
@@ -10,6 +10,8 @@ export interface DialogAction extends Omit<ButtonProps, "children"> {
10
10
  type DialogRenderable = React.ReactNode | ((helpers: DialogRenderHelpers) => React.ReactNode);
11
11
  export interface DialogProps {
12
12
  variant?: "default" | "confirmation" | "routingConfirmation";
13
+ /** Standard dialogs are 32rem wide; larger sizes are for complex editors. */
14
+ size?: "standard" | "large" | "extraLarge" | "full";
13
15
  open?: boolean;
14
16
  defaultOpen?: boolean;
15
17
  onOpenChange?: (open: boolean) => void;
@@ -27,5 +29,5 @@ export interface DialogProps {
27
29
  /** Whether a pointer interaction outside the dialog closes it. */
28
30
  closeOnOutsideClick?: boolean;
29
31
  }
30
- declare function Dialog({ variant, open, defaultOpen, onOpenChange, modal, trigger, title, description, children, footer, primaryAction, secondaryAction, contentClassName, bodyClassName, hideCloseButton, closeOnOutsideClick, }: DialogProps): import("react/jsx-runtime").JSX.Element;
32
+ declare function Dialog({ variant, size, open, defaultOpen, onOpenChange, modal, trigger, title, description, children, footer, primaryAction, secondaryAction, contentClassName, bodyClassName, hideCloseButton, closeOnOutsideClick, }: DialogProps): import("react/jsx-runtime").JSX.Element;
31
33
  export { Dialog };
package/dist/dialog.js CHANGED
@@ -32,7 +32,7 @@ function renderDialogAction({ action, close, defaultVariant, }) {
32
32
  }
33
33
  }, children: label }));
34
34
  }
35
- function Dialog({ variant = "default", open, defaultOpen, onOpenChange, modal, trigger, title, description, children, footer, primaryAction, secondaryAction, contentClassName, bodyClassName, hideCloseButton = false, closeOnOutsideClick = false, }) {
35
+ function Dialog({ variant = "default", size = "standard", open, defaultOpen, onOpenChange, modal, trigger, title, description, children, footer, primaryAction, secondaryAction, contentClassName, bodyClassName, hideCloseButton = false, closeOnOutsideClick = false, }) {
36
36
  const [isOpen, setIsOpen] = useControllableOpen({
37
37
  open,
38
38
  defaultOpen,
@@ -47,8 +47,8 @@ function Dialog({ variant = "default", open, defaultOpen, onOpenChange, modal, t
47
47
  const isCompactConfirmation = variant === "confirmation";
48
48
  const isRoutingConfirmation = variant === "routingConfirmation";
49
49
  return (_jsxs(DialogRoot, { open: isOpen, onOpenChange: setIsOpen, modal: modal, children: [trigger ? _jsx(DialogTrigger, { asChild: true, children: trigger }) : null, _jsxs(DialogSurface, { ...(!description ? { "aria-describedby": undefined } : {}), className: cn(isCompactConfirmation &&
50
- "max-w-sm gap-0 overflow-hidden rounded-xl p-0", isRoutingConfirmation &&
51
- "max-w-[40rem] gap-0 rounded-overlay p-[var(--space-8)]", contentClassName), hideCloseButton: hideCloseButton || isCompactConfirmation || isRoutingConfirmation, onPointerDownOutside: (event) => {
50
+ "gap-0 overflow-hidden rounded-xl p-0", isRoutingConfirmation &&
51
+ "gap-0 rounded-overlay p-[var(--space-8)]", "w-[calc(100vw-2rem)]", { standard: "max-w-lg", large: "max-w-3xl", extraLarge: "max-w-5xl", full: "max-w-[96rem]" }[size], contentClassName), hideCloseButton: hideCloseButton || isCompactConfirmation || isRoutingConfirmation, onPointerDownOutside: (event) => {
52
52
  if (!closeOnOutsideClick) {
53
53
  event.preventDefault();
54
54
  }
@@ -2,6 +2,8 @@ import * as React from "react";
2
2
  export interface EmptyStateProps extends React.HTMLAttributes<HTMLDivElement> {
3
3
  /** Muted panel treatment for section empty states. */
4
4
  variant?: "default" | "muted";
5
+ /** Controls spacing between the icon, copy, and action. */
6
+ density?: "default" | "compact";
5
7
  message: React.ReactNode;
6
8
  description?: React.ReactNode;
7
9
  icon?: React.ComponentType<{
@@ -9,5 +11,5 @@ export interface EmptyStateProps extends React.HTMLAttributes<HTMLDivElement> {
9
11
  }>;
10
12
  action?: React.ReactNode;
11
13
  }
12
- declare function EmptyState({ variant, message, description, icon: Icon, action, className, ...props }: EmptyStateProps): import("react/jsx-runtime").JSX.Element;
14
+ declare function EmptyState({ variant, density, message, description, icon: Icon, action, className, ...props }: EmptyStateProps): import("react/jsx-runtime").JSX.Element;
13
15
  export { EmptyState };
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { cn } from "./lib/utils";
3
3
  import { Typography } from "./typography";
4
- function EmptyState({ variant = "default", message, description, icon: Icon, action, className, ...props }) {
5
- return (_jsxs("div", { className: cn("flex flex-col items-center justify-center whitespace-normal px-6 py-10 text-center", variant === "muted" && "rounded-lg bg-muted/30", className), ...props, children: [Icon ? (_jsx(Icon, { className: "mb-4 h-10 w-10 stroke-[1.5] text-muted-foreground/70" })) : null, _jsxs("div", { className: "max-w-full space-y-1.5", children: [_jsx(Typography, { as: "p", variant: "bodySm", className: "font-semibold", children: message }), description ? (_jsx(Typography, { as: "p", variant: "caption", className: "mx-auto max-w-md", children: description })) : null] }), action ? _jsx("div", { className: "pt-6", children: action }) : null] }));
4
+ function EmptyState({ variant = "default", density = "default", message, description, icon: Icon, action, className, ...props }) {
5
+ return (_jsxs("div", { className: cn("flex flex-col items-center justify-center whitespace-normal px-6 py-10 text-center", variant === "muted" && "rounded-lg bg-muted/30", className), ...props, children: [Icon ? (_jsx(Icon, { className: cn("h-10 w-10 stroke-[1.5] text-muted-foreground/70", density === "compact" ? "mb-2" : "mb-4") })) : null, _jsxs("div", { className: "max-w-full space-y-1.5", children: [_jsx(Typography, { as: "p", variant: "bodySm", className: "font-semibold", children: message }), description ? (_jsx(Typography, { as: "p", variant: "caption", className: "mx-auto max-w-md", children: description })) : null] }), action ? _jsx("div", { className: density === "compact" ? "pt-4" : "pt-6", children: action }) : null] }));
6
6
  }
7
7
  export { EmptyState };
@@ -0,0 +1,14 @@
1
+ import type { FileUploadStatus } from "./use-file-upload";
2
+ export declare function FileUploadStatusRow({ file, onCancel, onRemove, disabled, }: {
3
+ file: {
4
+ name: string;
5
+ type?: string;
6
+ size?: number | string;
7
+ status?: FileUploadStatus;
8
+ progress?: number;
9
+ error?: string;
10
+ };
11
+ onCancel?: () => void;
12
+ onRemove?: () => void;
13
+ disabled?: boolean;
14
+ }): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,51 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { AlertCircle, CheckCircle2, File, FileText, ImageIcon, Trash2, X } from "lucide-react";
4
+ import { Button } from "./button";
5
+ import { cn } from "./lib/utils";
6
+ import { Progress } from "./progress";
7
+ import { Typography } from "./typography";
8
+ function formatUploadFileSize(size) {
9
+ if (typeof size === "string")
10
+ return size;
11
+ if (typeof size !== "number")
12
+ return "";
13
+ if (size === 0)
14
+ return "0 B";
15
+ const k = 1024;
16
+ const sizes = ["B", "KB", "MB", "GB"];
17
+ const i = Math.min(Math.floor(Math.log(size) / Math.log(k)), sizes.length - 1);
18
+ return `${parseFloat((size / Math.pow(k, i)).toFixed(1))} ${sizes[i]}`;
19
+ }
20
+ function getStatusIcon(status, type) {
21
+ if (status === "complete") {
22
+ return (_jsx(CheckCircle2, { "aria-hidden": "true", className: "size-5 text-[hsl(var(--status-success-foreground))]" }));
23
+ }
24
+ if (status === "error") {
25
+ return (_jsx(AlertCircle, { "aria-hidden": "true", className: "size-5 text-[hsl(var(--status-destructive-foreground))]" }));
26
+ }
27
+ const Icon = (type === null || type === void 0 ? void 0 : type.startsWith("image/")) ? ImageIcon : type === "application/pdf" ? FileText : File;
28
+ return (_jsx(Icon, { "aria-hidden": "true", className: "size-5 text-muted-foreground" }));
29
+ }
30
+ export function FileUploadStatusRow({ file, onCancel, onRemove, disabled = false, }) {
31
+ var _a;
32
+ const isUploading = file.status === "uploading";
33
+ const isPending = file.status === "pending";
34
+ const isComplete = file.status === "complete";
35
+ const isError = file.status === "error";
36
+ const sizeLabel = formatUploadFileSize(file.size);
37
+ const canCancel = (isUploading || isPending) && onCancel;
38
+ const canRemove = !isUploading && onRemove;
39
+ const action = canCancel ? "cancel" : canRemove ? "remove" : null;
40
+ return (_jsxs("li", { className: cn("rounded-control border bg-background px-2.5 py-2", isError && "border-destructive/80 bg-destructive/5"), children: [_jsxs("div", { className: "grid grid-cols-[1.5rem_minmax(0,1fr)_auto_1.75rem] min-h-7 items-start gap-x-2", children: [_jsx("span", { className: "flex h-7 w-6 shrink-0 items-center justify-center", children: getStatusIcon(file.status, file.type) }), _jsxs("div", { className: "flex min-w-0 flex-col gap-1 py-1", children: [_jsx(Typography, { as: "p", variant: "label", className: cn("truncate", isComplete && "text-[hsl(var(--status-success-foreground))]"), title: file.name, children: file.name }), isError ? (_jsx(Typography, { as: "p", variant: "caption", className: "break-words text-xs leading-4 text-destructive", children: (_a = file.error) !== null && _a !== void 0 ? _a : "Upload failed" })) : null] }), sizeLabel ? (_jsx(Typography, { as: "span", variant: "bodySm", className: "col-start-3 mt-1.5 whitespace-nowrap text-xs leading-4 text-muted-foreground", children: sizeLabel })) : null, action ? (_jsx(Button, { type: "button", variant: "ghost", size: "compactIcon", className: "col-start-4 h-7 w-7 shrink-0", disabled: disabled, onClick: (event) => {
41
+ event.stopPropagation();
42
+ if (action === "cancel") {
43
+ onCancel === null || onCancel === void 0 ? void 0 : onCancel();
44
+ }
45
+ else {
46
+ onRemove === null || onRemove === void 0 ? void 0 : onRemove();
47
+ }
48
+ }, "aria-label": action === "cancel"
49
+ ? `Cancel upload for ${file.name}`
50
+ : `Remove ${file.name}`, children: action === "cancel" ? (_jsx(X, { "aria-hidden": "true" })) : (_jsx(Trash2, { "aria-hidden": "true" })) })) : null] }), (isUploading || isPending) ? (_jsx(Progress, { className: "mt-2", value: file.progress, size: "sm", label: `Uploading ${file.name}` })) : null] }));
51
+ }
@@ -1,24 +1,12 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { AlertCircle, CheckCircle2, Paperclip, Trash2, X, } from "lucide-react";
3
+ import { X } from "lucide-react";
4
+ import { FileUploadStatusRow } from "./file-upload-status-row";
4
5
  import { Button } from "./button";
5
6
  import { cn } from "./lib/utils";
6
- import { Progress } from "./progress";
7
7
  import { toast } from "./toaster";
8
8
  import { Typography } from "./typography";
9
9
  const DEFAULT_TOAST_ID = "file-upload-status";
10
- function formatUploadFileSize(size) {
11
- if (typeof size === "string")
12
- return size;
13
- if (typeof size !== "number")
14
- return "";
15
- if (size === 0)
16
- return "0 B";
17
- const k = 1024;
18
- const sizes = ["B", "KB", "MB", "GB"];
19
- const i = Math.min(Math.floor(Math.log(size) / Math.log(k)), sizes.length - 1);
20
- return `${parseFloat((size / Math.pow(k, i)).toFixed(1))} ${sizes[i]}`;
21
- }
22
10
  function getProgress(uploadProgress, fileName) {
23
11
  if (!uploadProgress)
24
12
  return undefined;
@@ -34,6 +22,7 @@ function normalizeFiles({ files, uploadProgress, }) {
34
22
  const result = (_a = progress === null || progress === void 0 ? void 0 : progress.result) !== null && _a !== void 0 ? _a : file.result;
35
23
  return {
36
24
  ...file,
25
+ name: file.name,
37
26
  progress: (_c = (_b = progress === null || progress === void 0 ? void 0 : progress.progress) !== null && _b !== void 0 ? _b : file.progress) !== null && _c !== void 0 ? _c : 0,
38
27
  status: (_e = (_d = progress === null || progress === void 0 ? void 0 : progress.status) !== null && _d !== void 0 ? _d : file.status) !== null && _e !== void 0 ? _e : "pending",
39
28
  error: (_f = progress === null || progress === void 0 ? void 0 : progress.error) !== null && _f !== void 0 ? _f : file.error,
@@ -72,43 +61,15 @@ function getDefaultDescription(files) {
72
61
  ].filter(Boolean);
73
62
  return parts.length > 0 ? parts.join(" / ") : undefined;
74
63
  }
75
- function getStatusIcon(status) {
76
- if (status === "complete") {
77
- return (_jsx(CheckCircle2, { "aria-hidden": "true", className: "h-4 w-4 text-[hsl(var(--status-success-foreground))]" }));
78
- }
79
- if (status === "error") {
80
- return (_jsx(AlertCircle, { "aria-hidden": "true", className: "h-4 w-4 text-[hsl(var(--status-destructive-foreground))]" }));
81
- }
82
- return (_jsx(Paperclip, { "aria-hidden": "true", className: "h-4 w-4 text-muted-foreground" }));
83
- }
84
- function FileUploadStatusRow({ file, onCancel, onRemove, }) {
85
- var _a;
86
- const isUploading = file.status === "uploading";
87
- const isPending = file.status === "pending";
88
- const isComplete = file.status === "complete";
89
- const isError = file.status === "error";
90
- const sizeLabel = formatUploadFileSize(file.size);
91
- const canCancel = (isUploading || isPending) && onCancel;
92
- const canRemove = (isComplete || isError) && onRemove;
93
- const action = canCancel ? "cancel" : canRemove ? "remove" : null;
94
- return (_jsxs("li", { className: cn("rounded-control border bg-background px-2.5 py-2", isError && "border-destructive/80 bg-destructive/5"), children: [_jsxs("div", { className: "flex items-start gap-2", children: [_jsx("span", { className: "mt-0.5 flex h-5 w-5 shrink-0 items-center justify-center", children: getStatusIcon(file.status) }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx(Typography, { as: "p", variant: "label", className: cn("truncate", isComplete && "text-[hsl(var(--status-success-foreground))]"), title: file.name, children: file.name }), isError ? (_jsx(Typography, { as: "p", variant: "bodySm", className: "mt-0.5 text-destructive", children: (_a = file.error) !== null && _a !== void 0 ? _a : "Upload failed" })) : null] }), sizeLabel ? (_jsx(Typography, { as: "span", variant: "bodySm", className: "shrink-0 text-muted-foreground", children: sizeLabel })) : null, action ? (_jsx(Button, { type: "button", variant: "ghost", size: "compactIcon", className: "h-7 w-7 shrink-0", onClick: () => {
95
- if (action === "cancel") {
96
- onCancel === null || onCancel === void 0 ? void 0 : onCancel(file);
97
- }
98
- else {
99
- onRemove === null || onRemove === void 0 ? void 0 : onRemove(file);
100
- }
101
- }, "aria-label": action === "cancel"
102
- ? `Cancel upload for ${file.name}`
103
- : `Remove ${file.name}`, children: action === "cancel" ? (_jsx(X, { "aria-hidden": "true" })) : (_jsx(Trash2, { "aria-hidden": "true" })) })) : null] }), (isUploading || isPending) ? (_jsx(Progress, { className: "mt-2", value: file.progress, size: "sm", label: `Uploading ${file.name}` })) : null] }));
104
- }
105
64
  export function FileUploadStatusToast({ files, uploadProgress, title, description, className, onCancel, onRemove, onDismiss, }) {
106
65
  const normalizedFiles = normalizeFiles({ files, uploadProgress });
107
66
  const resolvedTitle = title !== null && title !== void 0 ? title : getDefaultTitle(normalizedFiles);
108
67
  const resolvedDescription = description !== null && description !== void 0 ? description : getDefaultDescription(normalizedFiles);
109
- return (_jsxs("section", { className: cn("w-[min(40rem,calc(100vw-2rem))] overflow-hidden rounded-overlay border border-border bg-background text-foreground shadow-overlay", className), "aria-label": "File upload status", children: [_jsxs("div", { className: "flex items-start gap-3 border-b px-3 py-2.5", children: [_jsxs("div", { className: "min-w-0 flex-1", children: [_jsx(Typography, { as: "p", variant: "label", className: "truncate", children: resolvedTitle }), resolvedDescription ? (_jsx(Typography, { as: "p", variant: "caption", className: "mt-0.5", children: resolvedDescription })) : null] }), onDismiss ? (_jsx(Button, { type: "button", variant: "ghost", size: "compactIcon", className: "h-7 w-7 shrink-0", onClick: onDismiss, "aria-label": "Dismiss file upload status", children: _jsx(X, { "aria-hidden": "true" }) })) : null] }), _jsx("ul", { className: "max-h-80 space-y-2 overflow-y-auto p-2.5", children: normalizedFiles.map((file, index) => {
68
+ return (_jsxs("section", { className: cn("w-[min(40rem,calc(100vw-2rem))] overflow-hidden rounded-overlay border border-border bg-background text-foreground shadow-overlay", className), "aria-label": "File upload status", children: [_jsxs("div", { className: "flex items-start gap-3 border-b px-3 py-2.5", children: [_jsxs("div", { className: "min-w-0 flex-1", children: [_jsx(Typography, { as: "p", variant: "label", className: "truncate", children: resolvedTitle }), resolvedDescription ? (_jsx(Typography, { as: "p", variant: "caption", className: "mt-0.5 text-xs leading-4", children: resolvedDescription })) : null] }), onDismiss ? (_jsx(Button, { type: "button", variant: "ghost", size: "compactIcon", className: "h-7 w-7 shrink-0", onClick: onDismiss, "aria-label": "Dismiss file upload status", children: _jsx(X, { "aria-hidden": "true" }) })) : null] }), _jsx("ul", { className: "max-h-80 space-y-2 overflow-y-auto p-2.5", children: normalizedFiles.map((file, index) => {
110
69
  var _a;
111
- return (_jsx(FileUploadStatusRow, { file: file, onCancel: onCancel, onRemove: onRemove }, `${file.name}-${(_a = file.size) !== null && _a !== void 0 ? _a : "unknown"}-${index}`));
70
+ return (_jsx(FileUploadStatusRow, { file: file, onCancel: onCancel ? () => onCancel(file) : undefined, onRemove: onRemove && (file.status === "complete" || file.status === "error")
71
+ ? () => onRemove(file)
72
+ : undefined }, `${file.name}-${(_a = file.size) !== null && _a !== void 0 ? _a : "unknown"}-${index}`));
112
73
  }) })] }));
113
74
  }
114
75
  export function showFileUploadStatusToast({ id = DEFAULT_TOAST_ID, duration = Number.POSITIVE_INFINITY, dismissible = true, onDismiss, ...props }) {
@@ -2,14 +2,9 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
4
  import { useCallback, useState } from "react";
5
- import { File as FileIcon, ImageIcon } from "lucide-react";
6
- import { CheckIcon } from "./animated-icons/check";
7
- import { FileTextIcon } from "./animated-icons/file-text";
8
5
  import { UploadIcon } from "./animated-icons/upload";
9
- import { XIcon } from "./animated-icons/x";
10
- import { Button } from "./button";
11
6
  import { cn } from "./lib/utils";
12
- import { Progress } from "./progress";
7
+ import { FileUploadStatusRow } from "./file-upload-status-row";
13
8
  import { Typography } from "./typography";
14
9
  const DEFAULT_MAX_FILE_SIZE = 10 * 1024 * 1024;
15
10
  function formatFileSize(bytes) {
@@ -20,15 +15,6 @@ function formatFileSize(bytes) {
20
15
  const i = Math.floor(Math.log(bytes) / Math.log(k));
21
16
  return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + " " + sizes[i];
22
17
  }
23
- function getFileIcon(file) {
24
- if (file.type.startsWith("image/")) {
25
- return _jsx(ImageIcon, { className: "size-6 shrink-0 text-muted-foreground" });
26
- }
27
- if (file.type === "application/pdf") {
28
- return _jsx(FileTextIcon, { className: "shrink-0 text-muted-foreground", size: 24 });
29
- }
30
- return _jsx(FileIcon, { className: "size-6 shrink-0 text-muted-foreground" });
31
- }
32
18
  export function FileUpload({ accept, maxSize = DEFAULT_MAX_FILE_SIZE, maxFiles = 10, onFilesChange, value = [], disabled = false, className, uploadProgress, }) {
33
19
  const [isDragOver, setIsDragOver] = useState(false);
34
20
  const [error, setError] = useState(null);
@@ -92,16 +78,15 @@ export function FileUpload({ accept, maxSize = DEFAULT_MAX_FILE_SIZE, maxFiles =
92
78
  const fileInput = (_jsx("input", { ref: inputRef, type: "file", accept: accept, multiple: maxFiles > 1, onChange: handleInputChange, disabled: disabled, className: "hidden" }));
93
79
  return (_jsxs("div", { className: cn("space-y-2", className), children: [fileInput, _jsxs("div", { onDrop: handleDrop, onDragOver: handleDragOver, onDragLeave: handleDragLeave, onClick: openFilePicker, className: cn("relative flex cursor-pointer flex-col items-center justify-center gap-1.5 rounded-surface border border-dashed p-4 transition-colors", isDragOver && !disabled
94
80
  ? "border-primary bg-primary/5"
95
- : "border-muted-foreground/25 hover:border-muted-foreground/50", disabled && "cursor-not-allowed opacity-50"), children: [_jsx(UploadIcon, { className: cn(isDragOver ? "text-interactive" : "text-muted-foreground"), size: 28 }), _jsxs("div", { className: "text-center", children: [_jsx(Typography, { as: "p", variant: "label", children: isDragOver ? "Drop files here" : "Drag & drop files here" }), _jsxs(Typography, { as: "p", variant: "caption", className: "mt-1", children: ["or click to browse (max ", formatFileSize(maxSize), " each)"] })] })] }), error ? (_jsx(Typography, { as: "p", variant: "bodySm", className: "text-destructive", children: error })) : null, value.length > 0 ? (_jsx("div", { className: "space-y-2", children: value.map((file, index) => {
96
- var _a;
81
+ : "border-muted-foreground/25 hover:border-muted-foreground/50", disabled && "cursor-not-allowed opacity-50"), children: [_jsx(UploadIcon, { className: cn(isDragOver ? "text-interactive" : "text-muted-foreground"), size: 28 }), _jsxs("div", { className: "text-center", children: [_jsx(Typography, { as: "p", variant: "label", children: isDragOver ? "Drop files here" : "Drag & drop files here" }), _jsxs(Typography, { as: "p", variant: "caption", className: "mt-1", children: ["or click to browse (max ", formatFileSize(maxSize), " each)"] })] })] }), error ? (_jsx(Typography, { as: "p", variant: "bodySm", className: "text-destructive", children: error })) : null, value.length > 0 ? (_jsx("ul", { className: "space-y-2", children: value.map((file, index) => {
97
82
  const progress = uploadProgress === null || uploadProgress === void 0 ? void 0 : uploadProgress.get(file.name);
98
- const isUploading = (progress === null || progress === void 0 ? void 0 : progress.status) === "uploading";
99
- const isComplete = (progress === null || progress === void 0 ? void 0 : progress.status) === "complete";
100
- const isError = (progress === null || progress === void 0 ? void 0 : progress.status) === "error";
101
- return (_jsxs("div", { className: "rounded-control border bg-muted/30 px-2.5 py-1.5", children: [_jsxs("div", { className: "flex items-center gap-2", children: [getFileIcon(file), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx(Typography, { as: "p", variant: "label", className: "truncate", children: file.name }), _jsxs(Typography, { as: "p", variant: "caption", children: [formatFileSize(file.size), isUploading && ` • ${progress === null || progress === void 0 ? void 0 : progress.progress}%`, isComplete && " • Complete", isError && ` • ${(progress === null || progress === void 0 ? void 0 : progress.error) || "Error"}`] })] }), isComplete ? (_jsx("div", { className: "flex h-6 w-6 shrink-0 items-center justify-center text-[hsl(var(--status-success-foreground))]", children: _jsx(CheckIcon, { size: 16 }) })) : (_jsx(Button, { type: "button", variant: "ghost", size: "icon", className: "h-6 w-6 shrink-0", onClick: (e) => {
102
- e.stopPropagation();
103
- removeFile(index);
104
- }, disabled: disabled || isUploading, "aria-label": `Remove ${file.name}`, children: _jsx(XIcon, { size: 16 }) }))] }), (isUploading ||
105
- (progress && progress.status === "pending")) && (_jsx("div", { className: "mt-2", children: _jsx(Progress, { value: (_a = progress === null || progress === void 0 ? void 0 : progress.progress) !== null && _a !== void 0 ? _a : 0, size: "sm", variant: isError ? "error" : "default", label: `Uploading ${file.name}` }) }))] }, `${file.name}-${file.size}-${index}`));
83
+ return (_jsx(FileUploadStatusRow, { file: {
84
+ name: file.name,
85
+ type: file.type,
86
+ size: file.size,
87
+ status: progress === null || progress === void 0 ? void 0 : progress.status,
88
+ progress: progress === null || progress === void 0 ? void 0 : progress.progress,
89
+ error: progress === null || progress === void 0 ? void 0 : progress.error,
90
+ }, disabled: disabled, onRemove: () => removeFile(index) }, `${file.name}-${file.size}-${index}`));
106
91
  }) })) : null] }));
107
92
  }
@@ -66,7 +66,9 @@ function LabelValueGrid({ items, columns = 4, density = "default", className, it
66
66
  }, [columns, density, resolvedMinColumnWidth]);
67
67
  return (_jsx("div", { ref: containerRef, className: cn("grid items-start", density === "compact"
68
68
  ? "auto-rows-auto gap-x-4 gap-y-3"
69
- : "auto-rows-fr gap-x-6 gap-y-6", className), style: {
69
+ : resolvedColumns === 1
70
+ ? "auto-rows-auto gap-x-6 gap-y-6"
71
+ : "auto-rows-fr gap-x-6 gap-y-6", className), style: {
70
72
  ...style,
71
73
  gridTemplateColumns: `repeat(${resolvedColumns}, minmax(0, 1fr))`,
72
74
  }, ...props, children: resolvedItems.map((item, index) => {
package/dist/popover.d.ts CHANGED
@@ -13,7 +13,8 @@ export interface PopoverProps extends Pick<PopoverRootProps, "defaultOpen" | "mo
13
13
  children: React.ReactNode;
14
14
  /** Visible popover heading. Also labels the popover for assistive technology. */
15
15
  title?: React.ReactNode;
16
- surface?: "panel" | "menu" | "message";
16
+ /** List surfaces scroll at the overlay edge and stay within the available viewport height. */
17
+ surface?: "panel" | "menu" | "message" | "list";
17
18
  /** Controls whether Tab stays within the popover or closes it and continues in the page Tab order. */
18
19
  tabBehavior?: PopoverTabBehavior;
19
20
  contentClassName?: string;
package/dist/popover.js CHANGED
@@ -79,7 +79,7 @@ function Popover({ defaultOpen, modal, onOpenChange, open, trigger, virtualAncho
79
79
  contentOnCloseAutoFocus === null || contentOnCloseAutoFocus === void 0 ? void 0 : contentOnCloseAutoFocus(event);
80
80
  handleCloseAutoFocus(event);
81
81
  }, [contentOnCloseAutoFocus, handleCloseAutoFocus]);
82
- return (_jsxs(PopoverRoot, { modal: modal, onOpenChange: setOpen, open: currentOpen, children: [virtualAnchorRef ? (_jsx(PopoverAnchor, { virtualRef: virtualAnchorRef })) : null, triggerTooltip ? (_jsx(Tooltip, { content: triggerTooltip, side: triggerTooltipSide, sideOffset: triggerTooltipSideOffset, contentClassName: triggerTooltipClassName, children: triggerElement })) : (triggerElement), _jsxs(PopoverContent, { ref: contentRef, align: align, sideOffset: sideOffset, "aria-labelledby": titleId !== null && titleId !== void 0 ? titleId : contentProps["aria-labelledby"], className: cn(surface === "menu" && "overflow-hidden p-1", surface === "message" && "overflow-hidden p-0", contentClassName), style: style, ...contentProps, onCloseAutoFocus: handleContentCloseAutoFocus, onKeyDown: handleContentKeyDown, onKeyDownCapture: handleContentKeyDownCapture, children: [title ? (_jsx(PopoverTitle, { id: titleId, className: cn(surface === "menu"
82
+ return (_jsxs(PopoverRoot, { modal: modal, onOpenChange: setOpen, open: currentOpen, children: [virtualAnchorRef ? (_jsx(PopoverAnchor, { virtualRef: virtualAnchorRef })) : null, triggerTooltip ? (_jsx(Tooltip, { content: triggerTooltip, side: triggerTooltipSide, sideOffset: triggerTooltipSideOffset, contentClassName: triggerTooltipClassName, children: triggerElement })) : (triggerElement), _jsxs(PopoverContent, { ref: contentRef, align: align, sideOffset: sideOffset, "aria-labelledby": titleId !== null && titleId !== void 0 ? titleId : contentProps["aria-labelledby"], className: cn(surface === "menu" && "overflow-hidden p-1", surface === "message" && "overflow-hidden p-0", surface === "list" && "max-h-[min(18rem,var(--radix-popover-content-available-height))] overflow-y-auto overscroll-contain", contentClassName), style: style, ...contentProps, onCloseAutoFocus: handleContentCloseAutoFocus, onKeyDown: handleContentKeyDown, onKeyDownCapture: handleContentKeyDownCapture, children: [title ? (_jsx(PopoverTitle, { id: titleId, className: cn(surface === "menu"
83
83
  ? "px-2 py-1.5"
84
84
  : "-mx-4 -mt-4 mb-4 border-b px-4 py-3"), children: title })) : null, children] })] }));
85
85
  }
@@ -89,5 +89,5 @@ function PopoverTitle({ className, children, ...props }) {
89
89
  export { Popover, PopoverTitle };
90
90
  /** Read-only information rows for a popover, without implying menu actions. */
91
91
  export function PopoverList({ items }) {
92
- return (_jsx("ul", { "data-slot": "popover-list", className: "max-h-64 space-y-3 overflow-y-auto text-sm text-foreground", children: items.map((item, index) => (_jsxs("li", { className: "flex items-start gap-2", children: [_jsx("span", { "aria-hidden": "true", className: "mt-2 size-1 shrink-0 rounded-full bg-muted-foreground" }), _jsx("span", { className: "min-w-0 break-words", children: item })] }, index))) }));
92
+ return (_jsx("ul", { "data-slot": "popover-list", className: "space-y-3 text-sm text-foreground", children: items.map((item, index) => (_jsxs("li", { className: "flex items-start gap-2", children: [_jsx("span", { "aria-hidden": "true", className: "mt-2 size-1 shrink-0 rounded-full bg-muted-foreground" }), _jsx("span", { className: "min-w-0 break-words", children: item })] }, index))) }));
93
93
  }
package/dist/table.js CHANGED
@@ -171,7 +171,7 @@ const TableHead = React.forwardRef(({ className, style, width, minWidth, maxWidt
171
171
  treatWidthAsMinWidth,
172
172
  }), ...props })));
173
173
  TableHead.displayName = "TableHead";
174
- const TableCell = React.forwardRef(({ className, style, width, minWidth, maxWidth, wrap = false, treatWidthAsMinWidth, containOverflow, ...props }, ref) => (_jsx("td", { ref: ref, className: cn("h-12 px-4 py-[4px] align-middle text-card-foreground [&:has([role=checkbox])]:pr-0 [&_[data-slot=button]]:px-0", wrap ? "whitespace-normal" : "whitespace-nowrap", overflowContainmentClassName({ containOverflow, wrap }), className), style: getTableColumnSizingStyle({
174
+ const TableCell = React.forwardRef(({ className, style, width, minWidth, maxWidth, wrap = false, treatWidthAsMinWidth, containOverflow, ...props }, ref) => (_jsx("td", { ref: ref, className: cn("h-12 px-4 py-[4px] align-middle text-card-foreground [&:has([role=checkbox])]:pr-0 [&:not([data-slot=table-empty-cell])_[data-slot=button]]:px-0", wrap ? "whitespace-normal" : "whitespace-nowrap", overflowContainmentClassName({ containOverflow, wrap }), className), style: getTableColumnSizingStyle({
175
175
  style,
176
176
  width,
177
177
  minWidth,
@@ -746,7 +746,7 @@ function Table({ accessibleLabel, columns, rows, getRowKey, emptyState = (_jsx(T
746
746
  })] }), isExpanded ? (_jsx(TableRow, { id: expandedContentId, "data-slot": "table-expanded-row", className: "bg-[hsl(var(--table-row-striped-background))] hover:bg-[hsl(var(--table-row-striped-background))]", children: _jsx(TableCell, { colSpan: Math.max(visibleColumns.length +
747
747
  (hasRowIndicatorColumn ? 1 : 0) +
748
748
  (hasExpansionColumn ? 1 : 0), 1), className: "h-auto whitespace-normal p-4", children: rowExpansion === null || rowExpansion === void 0 ? void 0 : rowExpansion.renderExpandedContent(row, rowIndex) }) })) : null] }, rowKey));
749
- })) : (_jsx(TableRow, { className: "cursor-default hover:bg-card", children: _jsx(TableCell, { colSpan: Math.max(visibleColumns.length +
749
+ })) : (_jsx(TableRow, { className: "cursor-default hover:bg-card", children: _jsx(TableCell, { "data-slot": "table-empty-cell", colSpan: Math.max(visibleColumns.length +
750
750
  (hasRowIndicatorColumn ? 1 : 0) +
751
751
  (hasExpansionColumn ? 1 : 0), 1), className: "p-6", children: resolvedEmptyState }) })) })] }), _jsx("div", { role: "status", className: "sr-only", children: loading ? loadingLabel : null })] }));
752
752
  const reorderableContainer = reorderableColumns ? (_jsx(DndContext, { sensors: columnReorderSensors, collisionDetection: closestCenter, onDragEnd: handleColumnDragEnd, children: _jsx(SortableContext, { items: reorderableColumnIds, strategy: horizontalListSortingStrategy, children: container }) })) : (container);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neasg/design-system",
3
- "version": "0.4.118",
3
+ "version": "0.4.121",
4
4
  "description": "NEA shared design system primitives, theme tokens, and Storybook docs.",
5
5
  "repository": {
6
6
  "type": "git",