@neasg/design-system 0.4.113 → 0.4.118
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/button.d.ts +2 -0
- package/dist/button.js +4 -2
- package/dist/card.d.ts +2 -0
- package/dist/card.js +2 -2
- package/dist/checklist.js +5 -4
- package/dist/dialog.d.ts +1 -1
- package/dist/dialog.js +7 -2
- package/dist/editable-table.js +2 -2
- package/dist/empty-state.d.ts +3 -1
- package/dist/empty-state.js +2 -2
- package/dist/file-upload.js +3 -3
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/status-banner.d.ts +15 -0
- package/dist/status-banner.js +6 -0
- package/dist/table-empty-state.d.ts +3 -0
- package/dist/table-empty-state.js +7 -0
- package/dist/table.js +2 -2
- package/package.json +1 -1
package/dist/button.d.ts
CHANGED
|
@@ -10,6 +10,8 @@ export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElemen
|
|
|
10
10
|
* Use this for links or custom interactive elements that should look like a button.
|
|
11
11
|
*/
|
|
12
12
|
asChild?: boolean;
|
|
13
|
+
/** Allow the label to wrap within its container and the button to grow in height. */
|
|
14
|
+
wrap?: boolean;
|
|
13
15
|
/**
|
|
14
16
|
* Shows a loading indicator, disables interaction, and sets `aria-busy`.
|
|
15
17
|
* When used with `asChild`, the component also prevents click handling and sets `aria-disabled`.
|
package/dist/button.js
CHANGED
|
@@ -102,7 +102,7 @@ function attachAnimatedIconRefs(node, refs) {
|
|
|
102
102
|
}
|
|
103
103
|
return node;
|
|
104
104
|
}
|
|
105
|
-
const Button = React.forwardRef(({ className, variant, size, asChild = false, loading = false, loadingText, loadingIndicator, disabled, children, onClick, onMouseEnter, onMouseLeave, onFocus, onBlur, tabIndex, ...props }, ref) => {
|
|
105
|
+
const Button = React.forwardRef(({ className, variant, size, asChild = false, wrap = false, loading = false, loadingText, loadingIndicator, disabled, children, onClick, onMouseEnter, onMouseLeave, onFocus, onBlur, tabIndex, ...props }, ref) => {
|
|
106
106
|
const Comp = asChild ? Slot : "button";
|
|
107
107
|
const isDisabled = disabled || loading;
|
|
108
108
|
const loadingLabel = loadingText !== null && loadingText !== void 0 ? loadingText : children;
|
|
@@ -147,7 +147,9 @@ const Button = React.forwardRef(({ className, variant, size, asChild = false, lo
|
|
|
147
147
|
stopAnimatedIcons();
|
|
148
148
|
onBlur === null || onBlur === void 0 ? void 0 : onBlur(event);
|
|
149
149
|
};
|
|
150
|
-
return (_jsx(Comp, { "data-slot": "button", className: cn(buttonVariants({ variant, size
|
|
150
|
+
return (_jsx(Comp, { "data-slot": "button", className: cn(buttonVariants({ variant, size }), wrap && "h-auto max-w-full whitespace-normal break-words py-1.5", wrap && (size === "sm" || size === "compact" || size === "compactIcon"
|
|
151
|
+
? "min-h-8"
|
|
152
|
+
: size === "comfortable" ? "min-h-[46px]" : "min-h-control"), className), ref: ref, "aria-busy": loading || undefined, "aria-disabled": isDisabled || undefined, "data-loading": loading ? "" : undefined, "data-disabled": isDisabled ? "" : undefined, onClick: handleClick, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, onFocus: handleFocus, onBlur: handleBlur, tabIndex: isDisabled && asChild ? -1 : tabIndex, disabled: !asChild ? isDisabled : undefined, ...props, children: content }));
|
|
151
153
|
});
|
|
152
154
|
Button.displayName = "Button";
|
|
153
155
|
export { Button, buttonVariants };
|
package/dist/card.d.ts
CHANGED
|
@@ -13,6 +13,8 @@ export interface CardProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "t
|
|
|
13
13
|
accent?: "primary";
|
|
14
14
|
/** Optional visual affordance shown in the top-right corner, such as a filter icon. */
|
|
15
15
|
icon?: React.ReactNode;
|
|
16
|
+
/** Interactive action beside the card title. */
|
|
17
|
+
headerAction?: React.ReactNode;
|
|
16
18
|
/** Replaces title/stat/subMetric with skeleton placeholders while data is loading. */
|
|
17
19
|
loading?: boolean;
|
|
18
20
|
}
|
package/dist/card.js
CHANGED
|
@@ -55,7 +55,7 @@ function attachCardIconRef(node, ref) {
|
|
|
55
55
|
ref: mergeRefs(node.ref, refCallback),
|
|
56
56
|
});
|
|
57
57
|
}
|
|
58
|
-
const Card = React.forwardRef(({ title, description, variant = "default", size = "default", stat, subMetric, footer, active, accent, icon, loading = false, children, className, onClick, onKeyDown, onMouseEnter, onMouseLeave, onFocus, onBlur, role, tabIndex, "aria-pressed": ariaPressed, ...props }, ref) => {
|
|
58
|
+
const Card = React.forwardRef(({ title, description, variant = "default", size = "default", stat, subMetric, footer, active, accent, icon, headerAction, loading = false, children, className, onClick, onKeyDown, onMouseEnter, onMouseLeave, onFocus, onBlur, role, tabIndex, "aria-pressed": ariaPressed, ...props }, ref) => {
|
|
59
59
|
const interactive = Boolean(onClick);
|
|
60
60
|
const hasStat = stat !== undefined;
|
|
61
61
|
const iconRef = React.useRef(null);
|
|
@@ -111,7 +111,7 @@ const Card = React.forwardRef(({ title, description, variant = "default", size =
|
|
|
111
111
|
"border-[hsl(var(--card-border))] shadow-[inset_4px_0_0_0_hsl(var(--primary))]", interactive &&
|
|
112
112
|
"cursor-pointer transition-[border-color,background-color,box-shadow,transform] duration-150 ease-out hover:border-primary/50 hover:bg-primary/5 hover:shadow-md motion-safe:hover:-translate-y-0.5 motion-safe:active:translate-y-0 motion-safe:active:scale-[0.99] focus-visible:border-primary/50 focus-visible:bg-primary/5 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background", className), ...props, children: [_jsxs("div", { className: cn("relative flex flex-col gap-2", size === "default" && "p-4", size === "compact" && "p-3", showIcon && size === "default" && "pr-12", showIcon && size === "compact" && "pr-10"), children: [showIcon ? (_jsx("span", { "aria-hidden": "true", "data-slot": "card-icon", className: cn("pointer-events-none absolute right-3 top-3 inline-flex size-7 items-center justify-center rounded-control border border-[hsl(var(--card-border))] bg-background/80 text-muted-foreground shadow-sm transition-[background-color,color,transform] duration-150 ease-out group-hover/card:scale-105 group-hover/card:bg-highlight group-hover/card:text-highlight-foreground group-focus-visible/card:bg-highlight group-focus-visible/card:text-highlight-foreground motion-reduce:transition-colors [&_svg]:size-3.5", size === "compact" && "right-2.5 top-2.5 size-6 [&_svg]:size-3", active &&
|
|
113
113
|
"border-primary/30 bg-highlight text-highlight-foreground", variant === "gradient" &&
|
|
114
|
-
"border-white/25 bg-white/10 text-current group-hover/card:bg-white/20 group-hover/card:text-current group-focus-visible/card:bg-white/20 group-focus-visible/card:text-current"), children: renderedIcon })) : null, loading ? (_jsx(Skeleton, { className: "h-3.5 w-24" })) : (renderedTitle), loading
|
|
114
|
+
"border-white/25 bg-white/10 text-current group-hover/card:bg-white/20 group-hover/card:text-current group-focus-visible/card:bg-white/20 group-focus-visible/card:text-current"), children: renderedIcon })) : null, loading ? (_jsx(Skeleton, { className: "h-3.5 w-24" })) : (headerAction ? (_jsxs("div", { className: "flex items-start justify-between gap-3", children: [renderedTitle, _jsx("div", { className: "shrink-0", children: headerAction })] })) : renderedTitle), loading
|
|
115
115
|
? description != null && _jsx(Skeleton, { className: "h-5 w-40" })
|
|
116
116
|
: renderedDescription, loading ? (stat !== undefined && _jsx(Skeleton, { className: "h-8 w-20" })) : stat ? (_jsx(Typography, { as: "p", variant: "title", color: variant === "gradient" ? "inherit" : undefined, children: stat })) : null, loading ? (subMetric !== undefined && _jsx(Skeleton, { className: "h-5 w-28" })) : subMetric ? (_jsx(Typography, { as: "p", variant: "caption", color: variant === "gradient" ? "inherit" : undefined, className: variant === "gradient" ? "opacity-80" : undefined, children: subMetric })) : null] }), children ? (_jsx("div", { className: cn(size === "default" && "p-4 pt-0", size === "compact" && "p-3 pt-0"), children: children })) : null, footer ? (_jsx("div", { className: cn("flex items-center", size === "default" && "p-4 pt-0", size === "compact" && "p-3 pt-0"), children: footer })) : null] }));
|
|
117
117
|
});
|
package/dist/checklist.js
CHANGED
|
@@ -6,6 +6,7 @@ import { Camera, ChevronDown, ClipboardList, LoaderCircle, MessageSquareText, Tr
|
|
|
6
6
|
import { Button } from "./button";
|
|
7
7
|
import { Select } from "./select";
|
|
8
8
|
import { Textarea } from "./textarea";
|
|
9
|
+
import { Tooltip } from "./tooltip";
|
|
9
10
|
import { cn } from "./lib/utils";
|
|
10
11
|
export function ChecklistPanel({ title, action, children }) {
|
|
11
12
|
return _jsxs("div", { "data-slot": "checklist-panel", className: "rounded-xl border border-border bg-card p-4 shadow-xs", children: [_jsxs("div", { className: "mb-4 flex items-center justify-between gap-4", children: [_jsx("h3", { className: "text-base font-medium text-card-foreground", children: title }), action] }), children] });
|
|
@@ -19,11 +20,11 @@ export function ChecklistSelection({ title, description, typeOptions, subtypeOpt
|
|
|
19
20
|
}
|
|
20
21
|
export function ChecklistQuestion({ label, options, value, onValueChange, disabled, remarks, onRemarksChange, remarksLimit = 500, remarksMaxLength, remarksRequired = false, evidence, evidenceCount = 0 }) {
|
|
21
22
|
const name = React.useId();
|
|
22
|
-
|
|
23
|
-
setShowRemarks(true); }, [remarksRequired, value]);
|
|
24
|
-
const [showRemarks, setShowRemarks] = React.useState(Boolean(remarks));
|
|
23
|
+
const [showRemarks, setShowRemarks] = React.useState(false);
|
|
25
24
|
const [showEvidence, setShowEvidence] = React.useState(false);
|
|
26
|
-
|
|
25
|
+
const remarksToggleLabel = showRemarks ? "Hide remarks" : "Show remarks";
|
|
26
|
+
const evidenceToggleLabel = showEvidence ? "Hide photos" : "Show photos";
|
|
27
|
+
return _jsxs("div", { "data-slot": "checklist-question", className: "space-y-4 rounded-xl border border-border bg-card p-4 shadow-xs", children: [_jsx("p", { id: `${name}-label`, className: "text-sm font-medium", children: label }), _jsxs("div", { className: "flex flex-wrap items-center gap-6", children: [_jsx("fieldset", { disabled: disabled, "aria-labelledby": `${name}-label`, className: cn("flex min-w-0 border-0 p-0", disabled && "opacity-50"), children: options.map((option, index) => _jsxs("label", { className: cn("relative cursor-pointer border border-input px-2.5 py-2 text-sm font-medium focus-within:z-10 focus-within:ring-2 focus-within:ring-ring", index > 0 && "-ml-px", index === 0 && "rounded-l-md", index === options.length - 1 && "rounded-r-md", disabled && "cursor-not-allowed", value === option.value ? option.tone === "negative" ? "bg-destructive/20" : option.tone === "positive" ? "bg-primary/20" : "bg-muted" : "bg-background"), children: [_jsx("input", { className: "absolute inset-0 size-full cursor-inherit opacity-0", type: "radio", name: name, value: option.value, checked: value === option.value, onChange: () => onValueChange(option.value) }), option.label] }, option.value)) }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Tooltip, { content: remarksToggleLabel, children: _jsx(Button, { type: "button", variant: "ghost", size: "compactIcon", "aria-label": remarksToggleLabel, "aria-expanded": showRemarks, "aria-controls": `${name}-remarks`, onClick: () => setShowRemarks((open) => !open), children: _jsx(MessageSquareText, { "aria-hidden": "true", size: 16 }) }) }), evidence ? _jsx(Tooltip, { content: `${evidenceToggleLabel}${evidenceCount > 0 ? ` (${evidenceCount})` : ""}`, children: _jsx(Button, { type: "button", variant: "ghost", size: "compactIcon", "aria-label": evidenceToggleLabel, "aria-expanded": showEvidence, "aria-controls": `${name}-evidence`, onClick: () => setShowEvidence((open) => !open), children: _jsx(Camera, { "aria-hidden": "true", size: 16 }) }) }) : null] })] }), showEvidence && evidence ? _jsx("div", { id: `${name}-evidence`, children: evidence }) : null, showRemarks ? _jsx("div", { id: `${name}-remarks`, children: _jsx(Textarea, { label: "Remarks", hideLabel: true, placeholder: "Type...", value: remarks, disabled: disabled, "aria-required": remarksRequired, rows: 5, onChange: (event) => onRemarksChange(event.target.value), maxWords: remarksMaxLength === undefined ? remarksLimit : undefined, maxLength: remarksMaxLength, showCount: remarksMaxLength !== undefined }) }) : null] });
|
|
27
28
|
}
|
|
28
29
|
export function ChecklistAttachments({ items, onRemove }) {
|
|
29
30
|
return _jsx("div", { className: "flex flex-wrap gap-2", children: items.map((item) => _jsxs("div", { className: "relative", children: [_jsx("a", { href: item.url, target: "_blank", rel: "noreferrer", children: _jsx("img", { src: item.url, alt: item.name, className: "size-20 rounded-md border border-border object-cover" }) }), onRemove ? _jsx(Button, { variant: "outline", size: "compactIcon", "aria-label": `Remove ${item.name}`, onClick: () => onRemove(item.key), children: _jsx(Trash2, { "aria-hidden": "true", size: 16 }) }) : null] }, item.key)) });
|
package/dist/dialog.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ export interface DialogAction extends Omit<ButtonProps, "children"> {
|
|
|
9
9
|
}
|
|
10
10
|
type DialogRenderable = React.ReactNode | ((helpers: DialogRenderHelpers) => React.ReactNode);
|
|
11
11
|
export interface DialogProps {
|
|
12
|
-
variant?: "default" | "confirmation";
|
|
12
|
+
variant?: "default" | "confirmation" | "routingConfirmation";
|
|
13
13
|
open?: boolean;
|
|
14
14
|
defaultOpen?: boolean;
|
|
15
15
|
onOpenChange?: (open: boolean) => void;
|
package/dist/dialog.js
CHANGED
|
@@ -44,11 +44,16 @@ function Dialog({ variant = "default", open, defaultOpen, onOpenChange, modal, t
|
|
|
44
44
|
const body = resolveDialogRenderable(children, helpers);
|
|
45
45
|
const customFooter = resolveDialogRenderable(footer, helpers);
|
|
46
46
|
const hasFooter = Boolean(customFooter || primaryAction || secondaryAction);
|
|
47
|
-
|
|
47
|
+
const isCompactConfirmation = variant === "confirmation";
|
|
48
|
+
const isRoutingConfirmation = variant === "routingConfirmation";
|
|
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) => {
|
|
48
52
|
if (!closeOnOutsideClick) {
|
|
49
53
|
event.preventDefault();
|
|
50
54
|
}
|
|
51
|
-
}, children: [_jsxs("div", { className: cn(
|
|
55
|
+
}, children: [_jsxs("div", { className: cn(isCompactConfirmation && "flex items-start gap-4 p-4"), children: [isCompactConfirmation ? (_jsx("div", { className: "rounded-lg bg-muted p-2", children: _jsx(CircleAlert, { "aria-hidden": "true", className: "size-6" }) })) : null, _jsxs(DialogHeader, { className: cn(isRoutingConfirmation && "gap-3 space-y-0"), children: [_jsx(DialogTitle, { className: cn(isRoutingConfirmation && "text-2xl leading-8"), children: title }), description ? (_jsx(DialogDescription, { className: cn(isRoutingConfirmation &&
|
|
56
|
+
"text-base leading-6 text-foreground"), children: description })) : null] })] }), body ? (_jsx("div", { className: cn("grid gap-4", isRoutingConfirmation && "mt-3 gap-[var(--space-8)]", bodyClassName), children: body })) : null, hasFooter ? (_jsx(DialogFooter, { className: cn(isCompactConfirmation && "border-t bg-muted/30 p-4", isRoutingConfirmation && "mt-[var(--space-8)] gap-3"), children: customFooter !== null && customFooter !== void 0 ? customFooter : (_jsxs(_Fragment, { children: [secondaryAction
|
|
52
57
|
? renderDialogAction({
|
|
53
58
|
action: secondaryAction,
|
|
54
59
|
close: helpers.close,
|
package/dist/editable-table.js
CHANGED
|
@@ -4,7 +4,7 @@ import { Button } from "./button";
|
|
|
4
4
|
import { TableAddRow } from "./table-add-row";
|
|
5
5
|
import { TrashIcon } from "./animated-icons/trash";
|
|
6
6
|
import { Checkbox } from "./checkbox";
|
|
7
|
-
import {
|
|
7
|
+
import { TableEmptyState } from "./table-empty-state";
|
|
8
8
|
import { InputControl } from "./input-control";
|
|
9
9
|
import { TableRoot as Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "./table";
|
|
10
10
|
import { cn } from "./lib/utils";
|
|
@@ -121,7 +121,7 @@ function EditableTable({ value, onChange, columns, isEditing = false, className,
|
|
|
121
121
|
const checkableColumnWidth = checkableHeader ? "9rem" : "48px";
|
|
122
122
|
return (_jsxs("div", { className: cn("space-y-2", className), children: [_jsx("div", { className: "overflow-x-auto rounded-surface border", children: _jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [checkable ? (_jsx(TableHead, { width: checkableColumnWidth, minWidth: checkableColumnWidth, children: checkableHeader })) : null, columns.map((column, index) => (_jsx(TableHead, { width: column.width, minWidth: getColumnMinWidth(column), children: _jsx("div", { className: "whitespace-nowrap", children: column.header }) }, `header-${index}`))), hasActionsColumn ? (_jsx(TableHead, { width: renderRowActions ? undefined : "72px", minWidth: renderRowActions ? "120px" : "72px" })) : null] }) }), _jsx(TableBody, { children: value.length === 0 ? (_jsx(TableRow, { children: _jsx(TableCell, { colSpan: columns.length +
|
|
123
123
|
(checkable ? 1 : 0) +
|
|
124
|
-
(hasActionsColumn ? 1 : 0), className: "p-0", children: _jsx(
|
|
124
|
+
(hasActionsColumn ? 1 : 0), className: "p-0", children: _jsx(TableEmptyState, {}) }) })) : (value.map((row, rowIndex) => (_jsxs(TableRow, { className: rowIndex % 2 === 0
|
|
125
125
|
? "bg-[hsl(var(--table-row-striped-background))]"
|
|
126
126
|
: undefined, children: [checkable ? (_jsx(TableCell, { width: checkableColumnWidth, minWidth: checkableColumnWidth, children: _jsx("div", { className: "flex items-center", onClick: (event) => event.stopPropagation(), children: _jsx(Checkbox, { checked: Boolean(row[activeField]), disabled: !isEditing, onChange: isEditing
|
|
127
127
|
? (event) => handleToggleRow(rowIndex, event.currentTarget.checked)
|
package/dist/empty-state.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
export interface EmptyStateProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
3
|
+
/** Muted panel treatment for section empty states. */
|
|
4
|
+
variant?: "default" | "muted";
|
|
3
5
|
message: React.ReactNode;
|
|
4
6
|
description?: React.ReactNode;
|
|
5
7
|
icon?: React.ComponentType<{
|
|
@@ -7,5 +9,5 @@ export interface EmptyStateProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
|
7
9
|
}>;
|
|
8
10
|
action?: React.ReactNode;
|
|
9
11
|
}
|
|
10
|
-
declare function EmptyState({ message, description, icon: Icon, action, className, ...props }: EmptyStateProps): import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
declare function EmptyState({ variant, message, description, icon: Icon, action, className, ...props }: EmptyStateProps): import("react/jsx-runtime").JSX.Element;
|
|
11
13
|
export { EmptyState };
|
package/dist/empty-state.js
CHANGED
|
@@ -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({ message, description, icon: Icon, action, className, ...props }) {
|
|
5
|
-
return (_jsxs("div", { className: cn("flex flex-col items-center justify-center px-6 py-10 text-center", className), ...props, children: [Icon ? (_jsx(Icon, { className: "mb-4 h-10 w-10 stroke-[1.5] text-muted-foreground/70" })) : null, _jsxs("div", { className: "space-y-1.5", children: [_jsx(Typography, { as: "p", variant: "bodySm", className: "font-semibold", children: message }), description ? (_jsx(Typography, { as: "p", variant: "caption", className: "max-w-md", children: description })) : null] }), action ? _jsx("div", { className: "pt-6", children: action }) : null] }));
|
|
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] }));
|
|
6
6
|
}
|
|
7
7
|
export { EmptyState };
|
package/dist/file-upload.js
CHANGED
|
@@ -22,12 +22,12 @@ function formatFileSize(bytes) {
|
|
|
22
22
|
}
|
|
23
23
|
function getFileIcon(file) {
|
|
24
24
|
if (file.type.startsWith("image/")) {
|
|
25
|
-
return _jsx(ImageIcon, { className: "
|
|
25
|
+
return _jsx(ImageIcon, { className: "size-6 shrink-0 text-muted-foreground" });
|
|
26
26
|
}
|
|
27
27
|
if (file.type === "application/pdf") {
|
|
28
|
-
return _jsx(FileTextIcon, { className: "text-muted-foreground", size:
|
|
28
|
+
return _jsx(FileTextIcon, { className: "shrink-0 text-muted-foreground", size: 24 });
|
|
29
29
|
}
|
|
30
|
-
return _jsx(FileIcon, { className: "
|
|
30
|
+
return _jsx(FileIcon, { className: "size-6 shrink-0 text-muted-foreground" });
|
|
31
31
|
}
|
|
32
32
|
export function FileUpload({ accept, maxSize = DEFAULT_MAX_FILE_SIZE, maxFiles = 10, onFilesChange, value = [], disabled = false, className, uploadProgress, }) {
|
|
33
33
|
const [isDragOver, setIsDragOver] = useState(false);
|
package/dist/index.d.ts
CHANGED
|
@@ -40,6 +40,7 @@ export { CountBadge } from "./count-badge";
|
|
|
40
40
|
export type { CountBadgeProps } from "./count-badge";
|
|
41
41
|
export { StatusDot } from "./status-dot";
|
|
42
42
|
export type { StatusDotProps, StatusDotSize, StatusDotVariant, } from "./status-dot";
|
|
43
|
+
export { TableEmptyState } from "./table-empty-state";
|
|
43
44
|
export { EmptyState } from "./empty-state";
|
|
44
45
|
export type { EmptyStateProps } from "./empty-state";
|
|
45
46
|
export { EditableTable } from "./editable-table";
|
|
@@ -171,3 +172,4 @@ export { ChecklistAttachments, ChecklistPanel, ChecklistSection, ChecklistSelect
|
|
|
171
172
|
export type { ChecklistAttachmentsProps, ChecklistPanelProps, ChecklistSectionProps, ChecklistSelectionProps, ChecklistQuestionProps, ChecklistQuestionOption } from "./checklist";
|
|
172
173
|
export { TableAddRow, type TableAddRowProps } from "./table-add-row";
|
|
173
174
|
export { PopoverList, type PopoverListProps } from "./popover";
|
|
175
|
+
export { StatusBanner, type StatusBannerProps } from "./status-banner";
|
package/dist/index.js
CHANGED
|
@@ -20,6 +20,7 @@ export { ThemeSwitcher } from "./theme-switcher";
|
|
|
20
20
|
export { DateInput } from "./date-input";
|
|
21
21
|
export { CountBadge } from "./count-badge";
|
|
22
22
|
export { StatusDot } from "./status-dot";
|
|
23
|
+
export { TableEmptyState } from "./table-empty-state";
|
|
23
24
|
export { EmptyState } from "./empty-state";
|
|
24
25
|
export { EditableTable } from "./editable-table";
|
|
25
26
|
export { EditButton } from "./edit-button";
|
|
@@ -90,3 +91,4 @@ export { parseDateTime, formatDateTime } from "./lib/date-utils";
|
|
|
90
91
|
export { ChecklistAttachments, ChecklistPanel, ChecklistSection, ChecklistSelection, ChecklistQuestion } from "./checklist";
|
|
91
92
|
export { TableAddRow } from "./table-add-row";
|
|
92
93
|
export { PopoverList } from "./popover";
|
|
94
|
+
export { StatusBanner } from "./status-banner";
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export interface StatusBannerProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
3
|
+
label: string;
|
|
4
|
+
detail?: React.ReactNode;
|
|
5
|
+
icon?: React.ComponentType<{
|
|
6
|
+
className?: string;
|
|
7
|
+
"aria-hidden"?: React.AriaAttributes["aria-hidden"];
|
|
8
|
+
}>;
|
|
9
|
+
trailingIcon?: React.ComponentType<{
|
|
10
|
+
className?: string;
|
|
11
|
+
"aria-hidden"?: React.AriaAttributes["aria-hidden"];
|
|
12
|
+
}>;
|
|
13
|
+
}
|
|
14
|
+
/** Compact primary-colour status strip for an ongoing activity. */
|
|
15
|
+
export declare function StatusBanner({ label, detail, icon: Icon, trailingIcon: TrailingIcon, className, ...props }: StatusBannerProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from "./lib/utils";
|
|
3
|
+
/** Compact primary-colour status strip for an ongoing activity. */
|
|
4
|
+
export function StatusBanner({ label, detail, icon: Icon, trailingIcon: TrailingIcon, className, ...props }) {
|
|
5
|
+
return (_jsxs("div", { ...props, className: cn("flex w-full items-center justify-center gap-2 rounded-none border border-border bg-primary px-4 py-1.5 text-sm text-primary-foreground shadow-sm", className), children: [Icon ? _jsx(Icon, { className: "h-4 w-4 shrink-0", "aria-hidden": true }) : null, _jsx("span", { className: "font-medium", children: label }), detail, TrailingIcon ? (_jsx(TrailingIcon, { className: "h-4 w-4 shrink-0 opacity-50", "aria-hidden": true })) : null] }));
|
|
6
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { type EmptyStateProps } from "./empty-state";
|
|
2
|
+
/** Shared empty-table presentation, with an icon and explanatory copy by default. */
|
|
3
|
+
export declare function TableEmptyState({ message, description, icon, ...props }: Partial<EmptyStateProps>): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Inbox } from "lucide-react";
|
|
3
|
+
import { EmptyState } from "./empty-state";
|
|
4
|
+
/** Shared empty-table presentation, with an icon and explanatory copy by default. */
|
|
5
|
+
export function TableEmptyState({ message = "No data available", description = "There are no rows to display in this table yet.", icon = Inbox, ...props }) {
|
|
6
|
+
return _jsx(EmptyState, { ...props, message: message, description: description, icon: icon });
|
|
7
|
+
}
|
package/dist/table.js
CHANGED
|
@@ -6,7 +6,7 @@ import { CSS } from "@dnd-kit/utilities";
|
|
|
6
6
|
import { ArrowUpDown, ChevronRight } from "lucide-react";
|
|
7
7
|
import { ArrowDownIcon } from "./animated-icons/arrow-down";
|
|
8
8
|
import { ArrowUpIcon } from "./animated-icons/arrow-up";
|
|
9
|
-
import {
|
|
9
|
+
import { TableEmptyState } from "./table-empty-state";
|
|
10
10
|
import { Pagination } from "./pagination";
|
|
11
11
|
import { Skeleton } from "./skeleton";
|
|
12
12
|
import { TableColumnFilterControl, } from "./table-column-filter";
|
|
@@ -399,7 +399,7 @@ function getColumnPairResizeRange(column, nextColumn, columnWidths) {
|
|
|
399
399
|
maxWidth: Math.round(currentWidth + maxDelta),
|
|
400
400
|
};
|
|
401
401
|
}
|
|
402
|
-
function Table({ accessibleLabel, columns, rows, getRowKey, emptyState = (_jsx(
|
|
402
|
+
function Table({ accessibleLabel, columns, rows, getRowKey, emptyState = (_jsx(TableEmptyState, {})), toolbar, caption, className, containerClassName, tableClassName, rowClassName, rowTone, maxHeight, minHeight, sorting, pagination, loading = false, loadingLabel = "Loading table data", loadingRows = 5, visibleColumnKeys, resizableColumns = false, columnResizeMode = "pair", columnWidths, defaultColumnWidths, onColumnWidthsChange, renderColumnResizeHandle, tableLayout, centerEmptyState = false, emptyStateMinHeight = DEFAULT_CENTERED_EMPTY_STATE_MIN_HEIGHT, striped = false, rowIndicator, rowExpansion, reorderableColumns = false, onColumnOrderChange, onScroll, style, ...props }) {
|
|
403
403
|
var _a;
|
|
404
404
|
const visibleColumns = getVisibleColumns(columns, visibleColumnKeys);
|
|
405
405
|
const hasRowIndicatorColumn = Boolean(rowIndicator);
|