@neasg/design-system 0.4.118 → 0.4.132

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/alert.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import * as React from "react";
3
+ import { CircleAlert } from "lucide-react";
3
4
  import { cva } from "class-variance-authority";
4
5
  import { Button } from "./button";
5
6
  import { Checkbox } from "./checkbox";
@@ -20,7 +21,8 @@ const alertVariants = cva("relative flex w-full items-start gap-2 rounded-surfac
20
21
  });
21
22
  const AlertAction = React.forwardRef(({ className, type = "button", ...props }, ref) => (_jsx(Button, { ref: ref, type: type, variant: "link", size: "compact", className: cn("h-auto min-h-6 px-0 text-inherit hover:text-inherit", className), ...props })));
22
23
  AlertAction.displayName = "AlertAction";
23
- const Alert = React.forwardRef(({ variant, title, description, icon: Icon, action, className, children, role = "alert", ...props }, ref) => {
24
+ const Alert = React.forwardRef(({ variant, title, description, icon, action, className, children, role = "alert", ...props }, ref) => {
25
+ const Icon = icon !== null && icon !== void 0 ? icon : (variant === "destructive" ? CircleAlert : undefined);
24
26
  const body = description !== null && description !== void 0 ? description : children;
25
27
  const hasStackedContent = Boolean(title);
26
28
  return (_jsxs("div", { ref: ref, role: role, className: cn(alertVariants({ variant }), !hasStackedContent && "items-center", className), ...props, children: [Icon ? (_jsx(Icon, { className: cn("h-4 w-4 shrink-0", hasStackedContent && "mt-0.5") })) : null, _jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-1", children: [title ? (_jsx(Typography, { as: "p", variant: "bodySm", color: "inherit", className: "font-bold", children: title })) : null, body ? (_jsx(Typography, { as: "div", variant: "caption", color: "inherit", className: "opacity-95", children: body })) : null] }), action ? (_jsx("div", { className: cn("shrink-0 text-inherit [&_a]:text-inherit [&_button]:text-inherit [&_button:hover]:text-inherit", hasStackedContent ? "self-start" : "self-center"), children: action })) : null] }));
package/dist/button.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as React from "react";
2
2
  import { type VariantProps } from "class-variance-authority";
3
3
  declare const buttonVariants: (props?: ({
4
- variant?: "link" | "default" | "warning" | "destructive" | "outline" | "secondary" | "ghost" | null | undefined;
4
+ variant?: "link" | "default" | "warning" | "destructive" | "outline" | "secondary" | "ghost" | "destructiveGhost" | null | undefined;
5
5
  size?: "default" | "sm" | "compact" | "comfortable" | "icon" | "compactIcon" | null | undefined;
6
6
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
7
7
  export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {
@@ -12,6 +12,8 @@ export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElemen
12
12
  asChild?: boolean;
13
13
  /** Allow the label to wrap within its container and the button to grow in height. */
14
14
  wrap?: boolean;
15
+ /** Align the button content within its available width. */
16
+ contentAlign?: "center" | "start";
15
17
  /**
16
18
  * Shows a loading indicator, disables interaction, and sets `aria-busy`.
17
19
  * When used with `asChild`, the component also prevents click handling and sets `aria-disabled`.
package/dist/button.js CHANGED
@@ -12,6 +12,7 @@ const buttonVariants = cva("inline-flex cursor-pointer items-center justify-cent
12
12
  outline: "border border-[hsl(var(--button-outline-border))] bg-[hsl(var(--button-outline-background))] text-foreground hover:bg-[hsl(var(--button-outline-hover-background))] hover:text-accent-foreground",
13
13
  secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
14
14
  ghost: "hover:bg-accent hover:text-accent-foreground",
15
+ destructiveGhost: "text-destructive hover:bg-destructive/10 hover:text-destructive focus-visible:ring-destructive",
15
16
  link: "text-interactive underline-offset-4 hover:text-interactive hover:underline",
16
17
  },
17
18
  size: {
@@ -102,7 +103,7 @@ function attachAnimatedIconRefs(node, refs) {
102
103
  }
103
104
  return node;
104
105
  }
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
+ const Button = React.forwardRef(({ className, variant, size, asChild = false, wrap = false, contentAlign = "center", loading = false, loadingText, loadingIndicator, disabled, children, onClick, onMouseEnter, onMouseLeave, onFocus, onBlur, tabIndex, ...props }, ref) => {
106
107
  const Comp = asChild ? Slot : "button";
107
108
  const isDisabled = disabled || loading;
108
109
  const loadingLabel = loadingText !== null && loadingText !== void 0 ? loadingText : children;
@@ -112,7 +113,7 @@ const Button = React.forwardRef(({ className, variant, size, asChild = false, wr
112
113
  hasTextLikeContent(children)) {
113
114
  throw new Error('NEA Button `size="icon"` and `size="compactIcon"` only accepts icon components or SVG content. Do not pass text or emoji.');
114
115
  }
115
- const content = loading ? (loadingLabel ? (_jsxs("span", { className: "inline-flex items-center gap-2", children: [loadingIndicator !== null && loadingIndicator !== void 0 ? loadingIndicator : _jsx(DefaultLoadingIndicator, {}), _jsx("span", { children: attachAnimatedIconRefs(loadingLabel, animatedIconRefs) })] })) : (loadingIndicator !== null && loadingIndicator !== void 0 ? loadingIndicator : _jsx(DefaultLoadingIndicator, {}))) : (attachAnimatedIconRefs(children, animatedIconRefs));
116
+ const content = loading ? (loadingLabel ? (_jsxs("span", { className: "inline-flex items-center gap-2", children: [loadingIndicator !== null && loadingIndicator !== void 0 ? loadingIndicator : _jsx(DefaultLoadingIndicator, {}), _jsx("span", { className: "inline-flex items-center gap-2", children: attachAnimatedIconRefs(loadingLabel, animatedIconRefs) })] })) : (loadingIndicator !== null && loadingIndicator !== void 0 ? loadingIndicator : _jsx(DefaultLoadingIndicator, {}))) : (attachAnimatedIconRefs(children, animatedIconRefs));
116
117
  const startAnimatedIcons = () => {
117
118
  animatedIconRefs.current.forEach((icon) => { var _a; return (_a = icon.startAnimation) === null || _a === void 0 ? void 0 : _a.call(icon); });
118
119
  };
@@ -149,7 +150,7 @@ const Button = React.forwardRef(({ className, variant, size, asChild = false, wr
149
150
  };
150
151
  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
152
  ? "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 }));
153
+ : size === "comfortable" ? "min-h-[46px]" : "min-h-control"), contentAlign === "start" && "justify-start text-left", 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 }));
153
154
  });
154
155
  Button.displayName = "Button";
155
156
  export { Button, buttonVariants };
package/dist/checkbox.js CHANGED
@@ -24,9 +24,9 @@ const Checkbox = React.forwardRef(({ className, indeterminate = false, size = "m
24
24
  innerRef.current.indeterminate = indeterminate;
25
25
  }
26
26
  }, [indeterminate]);
27
- const box = (_jsxs("span", { className: cn("relative inline-block shrink-0 rounded-sm border bg-background align-middle text-primary-foreground transition-colors", sizeClasses[size], (checked || indeterminate) && !disabled
27
+ const box = (_jsxs("span", { className: cn("relative inline-flex shrink-0 items-center justify-center rounded-sm border bg-background align-middle text-primary-foreground transition-colors", sizeClasses[size], (checked || indeterminate) && !disabled
28
28
  ? "border-primary bg-primary"
29
- : "border-input", disabled && "cursor-not-allowed opacity-50", label && alignToStart && startAlignedOffsetClasses[size], !label && className), children: [_jsx("input", { ref: innerRef, type: "checkbox", id: inputId, checked: checked, disabled: disabled, className: "absolute inset-0 h-full w-full cursor-pointer appearance-none opacity-0 disabled:cursor-not-allowed", ...props }), indeterminate ? (_jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "3", strokeLinecap: "round", className: "pointer-events-none absolute inset-0 m-auto h-3 w-3", "aria-hidden": "true", children: _jsx("line", { x1: "5", y1: "12", x2: "19", y2: "12" }) })) : checked ? (_jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "3", strokeLinecap: "round", strokeLinejoin: "round", className: "pointer-events-none absolute inset-0 m-auto h-3 w-3", "aria-hidden": "true", children: _jsx("polyline", { points: "20 6 9 17 4 12" }) })) : null] }));
29
+ : "border-input", disabled && "cursor-not-allowed opacity-50", label && alignToStart && startAlignedOffsetClasses[size], !label && className), children: [_jsx("input", { ref: innerRef, type: "checkbox", id: inputId, checked: checked, disabled: disabled, className: "absolute inset-0 h-full w-full cursor-pointer appearance-none opacity-0 disabled:cursor-not-allowed", ...props }), indeterminate ? (_jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "3", strokeLinecap: "round", className: "pointer-events-none h-3 w-3", "aria-hidden": "true", children: _jsx("line", { x1: "5", y1: "12", x2: "19", y2: "12" }) })) : checked ? (_jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "3", strokeLinecap: "round", strokeLinejoin: "round", className: "pointer-events-none h-3 w-3", "aria-hidden": "true", children: _jsx("polyline", { points: "20 6 9 17 4 12" }) })) : null] }));
30
30
  if (!label)
31
31
  return box;
32
32
  return (_jsxs("label", { htmlFor: inputId, className: cn("inline-flex cursor-pointer gap-2 text-sm", alignToStart ? "items-start" : "items-center", disabled && "cursor-not-allowed opacity-50", className), children: [box, _jsxs("div", { className: "flex min-w-0 flex-col gap-0.5 select-none", children: [_jsx(Typography, { as: "span", variant: "bodySm", children: label }), description ? (_jsx(Typography, { as: "p", variant: "caption", color: "muted", children: description })) : null] })] }));
package/dist/checklist.js CHANGED
@@ -16,15 +16,17 @@ export function ChecklistSection({ title, progress, action, children, defaultOpe
16
16
  }
17
17
  export function ChecklistSelection({ title, description, typeOptions, subtypeOptions, type, subtype, onTypeChange, onSubtypeChange, disabled, loading, action }) {
18
18
  const Icon = loading ? LoaderCircle : ClipboardList;
19
- return _jsxs("div", { "data-slot": "checklist-selection", "aria-busy": loading, className: "flex flex-col items-center gap-4 rounded-lg bg-muted/30 p-6 text-center", children: [_jsx(Icon, { "aria-hidden": "true", className: cn("size-8", loading && "animate-spin") }), _jsxs("div", { className: "space-y-2", children: [_jsx("p", { className: "text-sm font-medium", children: title }), _jsx("p", { className: "text-sm text-muted-foreground", children: description })] }), _jsxs("div", { className: "flex flex-wrap items-center justify-center gap-4", children: [_jsx(Select, { className: "w-auto", triggerClassName: "w-auto min-w-0", label: "Type", hideLabel: true, placeholder: "Type", options: typeOptions, value: type, onValueChange: onTypeChange, disabled: disabled || loading }), _jsx(Select, { className: "w-auto", triggerClassName: "w-auto min-w-0", label: "Sub-Type", hideLabel: true, placeholder: "Sub-Type", options: subtypeOptions, value: subtype, onValueChange: onSubtypeChange, disabled: disabled || loading || !type }), action] })] });
19
+ return _jsxs("div", { "data-slot": "checklist-selection", "aria-busy": loading, className: "flex flex-col items-center gap-4 rounded-lg bg-muted/30 p-6 text-center", children: [_jsx(Icon, { "aria-hidden": "true", className: cn("size-8", loading && "animate-spin") }), _jsxs("div", { className: "space-y-2", children: [_jsx("p", { className: "text-sm font-medium", children: title }), _jsx("p", { className: "text-sm text-muted-foreground", children: description })] }), _jsxs("div", { className: "grid w-full max-w-md grid-cols-1 gap-[var(--layout-page-control-gap)] sm:grid-cols-2", children: [_jsx(Select, { label: "Type", hideLabel: true, placeholder: "Type", options: typeOptions, value: type, onValueChange: onTypeChange, disabled: disabled || loading }), _jsx(Select, { label: "Sub-Type", hideLabel: true, placeholder: "Sub-Type", options: subtypeOptions, value: subtype, onValueChange: onSubtypeChange, disabled: disabled || loading || !type })] }), action] });
20
20
  }
21
21
  export function ChecklistQuestion({ label, options, value, onValueChange, disabled, remarks, onRemarksChange, remarksLimit = 500, remarksMaxLength, remarksRequired = false, evidence, evidenceCount = 0 }) {
22
22
  const name = React.useId();
23
23
  const [showRemarks, setShowRemarks] = React.useState(false);
24
24
  const [showEvidence, setShowEvidence] = React.useState(false);
25
+ const remarksVisible = disabled ? Boolean(remarks.trim()) : showRemarks;
26
+ const evidenceVisible = disabled ? evidenceCount > 0 : showEvidence;
25
27
  const remarksToggleLabel = showRemarks ? "Hide remarks" : "Show remarks";
26
28
  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] });
29
+ 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)) }), !disabled ? _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] }) : null] }), evidenceVisible && evidence ? _jsx("div", { id: `${name}-evidence`, children: evidence }) : null, remarksVisible ? _jsx("div", { id: `${name}-remarks`, children: disabled ? _jsxs("div", { className: "space-y-1", children: [_jsx("p", { className: "text-sm font-medium", children: "Remarks" }), _jsx("p", { className: "whitespace-pre-wrap text-sm text-muted-foreground", children: remarks })] }) : _jsx(Textarea, { label: "Remarks", hideLabel: true, placeholder: "Type...", value: remarks, "aria-required": remarksRequired, rows: 5, onChange: (event) => onRemarksChange(event.target.value), maxWords: remarksMaxLength === undefined ? remarksLimit : undefined, maxLength: remarksMaxLength, showCount: remarksMaxLength !== undefined }) }) : null] });
28
30
  }
29
31
  export function ChecklistAttachments({ items, onRemove }) {
30
32
  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
@@ -10,6 +10,10 @@ 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 512px wide; larger sizes are for complex editors. */
14
+ size?: "standard" | "large" | "extraLarge" | "full";
15
+ /** Optional minimum height for dialogs whose content changes between steps. */
16
+ minHeight?: React.CSSProperties["minHeight"];
13
17
  open?: boolean;
14
18
  defaultOpen?: boolean;
15
19
  onOpenChange?: (open: boolean) => void;
@@ -27,5 +31,5 @@ export interface DialogProps {
27
31
  /** Whether a pointer interaction outside the dialog closes it. */
28
32
  closeOnOutsideClick?: boolean;
29
33
  }
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;
34
+ declare function Dialog({ variant, size, minHeight, open, defaultOpen, onOpenChange, modal, trigger, title, description, children, footer, primaryAction, secondaryAction, contentClassName, bodyClassName, hideCloseButton, closeOnOutsideClick, }: DialogProps): import("react/jsx-runtime").JSX.Element;
31
35
  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", minHeight, 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,
@@ -46,14 +46,14 @@ function Dialog({ variant = "default", open, defaultOpen, onOpenChange, modal, t
46
46
  const hasFooter = Boolean(customFooter || primaryAction || secondaryAction);
47
47
  const isCompactConfirmation = variant === "confirmation";
48
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) => {
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 } : {}), style: minHeight !== undefined ? { minHeight } : undefined, className: cn(isCompactConfirmation &&
50
+ "gap-0 overflow-hidden rounded-xl p-0", isRoutingConfirmation &&
51
+ "gap-0 rounded-overlay p-[var(--space-8)]", minHeight !== undefined && "flex flex-col", "w-[calc(100vw-32px)]", { standard: "max-w-[512px]", 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
  }
55
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
56
+ "text-base leading-6 text-foreground"), children: description })) : null] })] }), body ? (_jsx("div", { className: cn("grid gap-4", minHeight !== undefined && "flex-1", 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", minHeight !== undefined && "mt-auto"), children: customFooter !== null && customFooter !== void 0 ? customFooter : (_jsxs(_Fragment, { children: [secondaryAction
57
57
  ? renderDialogAction({
58
58
  action: secondaryAction,
59
59
  close: helpers.close,
@@ -12,6 +12,7 @@ const splitButtonDividerClassNames = {
12
12
  outline: "before:bg-[hsl(var(--button-outline-border))]",
13
13
  secondary: "before:bg-secondary-foreground/20",
14
14
  ghost: "before:bg-border",
15
+ destructiveGhost: "before:bg-destructive/30",
15
16
  link: "before:bg-interactive/25",
16
17
  };
17
18
  function DropdownButton({ label, leadingIcon, children, className, contentClassName, dropdownAriaLabel, menuWidth = "trigger", align = "end", alignOffset, avoidCollisions, collisionPadding, defaultOpen, disabled, hideWhenDetached, loading, loadingIndicator, loadingText, modal, onClick, onOpenChange, open, side, sideOffset = 4, split: splitProp, sticky, type = "button", variant, size, ...buttonProps }) {
@@ -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,53 @@
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: cn("grid min-h-7 items-start gap-x-2", action
41
+ ? "grid-cols-[1.5rem_minmax(0,1fr)_auto_1.75rem]"
42
+ : "grid-cols-[1.5rem_minmax(0,1fr)_auto]"), 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) => {
43
+ event.stopPropagation();
44
+ if (action === "cancel") {
45
+ onCancel === null || onCancel === void 0 ? void 0 : onCancel();
46
+ }
47
+ else {
48
+ onRemove === null || onRemove === void 0 ? void 0 : onRemove();
49
+ }
50
+ }, "aria-label": action === "cancel"
51
+ ? `Cancel upload for ${file.name}`
52
+ : `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] }));
53
+ }
@@ -17,6 +17,8 @@ export interface FileUploadStatusToastProps {
17
17
  className?: string;
18
18
  onCancel?: (file: FileUploadStatusToastFile) => void;
19
19
  onRemove?: (file: FileUploadStatusToastFile) => void;
20
+ /** Show remove actions when onRemove is provided. Does not hide cancel. */
21
+ showRemoveButton?: boolean;
20
22
  onDismiss?: () => void;
21
23
  }
22
24
  export interface ShowFileUploadStatusToastOptions extends FileUploadStatusToastProps {
@@ -24,5 +26,5 @@ export interface ShowFileUploadStatusToastOptions extends FileUploadStatusToastP
24
26
  duration?: number;
25
27
  dismissible?: boolean;
26
28
  }
27
- export declare function FileUploadStatusToast({ files, uploadProgress, title, description, className, onCancel, onRemove, onDismiss, }: FileUploadStatusToastProps): import("react/jsx-runtime").JSX.Element;
29
+ export declare function FileUploadStatusToast({ files, uploadProgress, title, description, className, onCancel, onRemove, showRemoveButton, onDismiss, }: FileUploadStatusToastProps): import("react/jsx-runtime").JSX.Element;
28
30
  export declare function showFileUploadStatusToast({ id, duration, dismissible, onDismiss, ...props }: ShowFileUploadStatusToastOptions): string | number;
@@ -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
- export function FileUploadStatusToast({ files, uploadProgress, title, description, className, onCancel, onRemove, onDismiss, }) {
64
+ export function FileUploadStatusToast({ files, uploadProgress, title, description, className, onCancel, onRemove, showRemoveButton = true, 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: showRemoveButton && 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 }) {
@@ -6,7 +6,9 @@ export interface FileUploadProps {
6
6
  onFilesChange: (files: File[]) => void;
7
7
  value?: File[];
8
8
  disabled?: boolean;
9
+ /** Show the remove action on file rows. */
10
+ showRemoveButton?: boolean;
9
11
  className?: string;
10
12
  uploadProgress?: Map<string, FileUploadProgress>;
11
13
  }
12
- export declare function FileUpload({ accept, maxSize, maxFiles, onFilesChange, value, disabled, className, uploadProgress, }: FileUploadProps): import("react/jsx-runtime").JSX.Element;
14
+ export declare function FileUpload({ accept, maxSize, maxFiles, onFilesChange, value, disabled, showRemoveButton, className, uploadProgress, }: FileUploadProps): import("react/jsx-runtime").JSX.Element;
@@ -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,16 +15,7 @@ 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
- export function FileUpload({ accept, maxSize = DEFAULT_MAX_FILE_SIZE, maxFiles = 10, onFilesChange, value = [], disabled = false, className, uploadProgress, }) {
18
+ export function FileUpload({ accept, maxSize = DEFAULT_MAX_FILE_SIZE, maxFiles = 10, onFilesChange, value = [], disabled = false, showRemoveButton = true, className, uploadProgress, }) {
33
19
  const [isDragOver, setIsDragOver] = useState(false);
34
20
  const [error, setError] = useState(null);
35
21
  const inputRef = React.useRef(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: showRemoveButton ? () => removeFile(index) : undefined }, `${file.name}-${file.size}-${index}`));
106
91
  }) })) : null] }));
107
92
  }
package/dist/index.d.ts CHANGED
@@ -3,6 +3,7 @@ export type { AvatarProps, AvatarSize, AvatarProfileProps, AvatarRootProps, } fr
3
3
  export { AvatarProfilePopover, AvatarProfilePopoverContent, AvatarProfilePopoverHeader, AvatarProfilePopoverSection, AvatarProfilePopoverFooter, AvatarProfilePopoverFooterAction, } from "./avatar-profile-popover";
4
4
  export type { AvatarProfilePopoverProps, AvatarProfilePopoverContentProps, AvatarProfilePopoverHeaderProps, AvatarProfilePopoverSectionProps, AvatarProfilePopoverFooterProps, AvatarProfilePopoverFooterActionProps, } from "./avatar-profile-popover";
5
5
  export * from "./animated-icons";
6
+ export { Inline } from "./inline";
6
7
  export { Alert, AlertAction, AlertConsent, alertVariants, } from "./alert";
7
8
  export type { AlertActionProps, AlertConsentProps, AlertProps, } from "./alert";
8
9
  export { AlertStack } from "./alert-stack";
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  export { Avatar, AvatarProfile, AvatarRoot, AvatarImage, } from "./avatar";
2
2
  export { AvatarProfilePopover, AvatarProfilePopoverContent, AvatarProfilePopoverHeader, AvatarProfilePopoverSection, AvatarProfilePopoverFooter, AvatarProfilePopoverFooterAction, } from "./avatar-profile-popover";
3
3
  export * from "./animated-icons";
4
+ export { Inline } from "./inline";
4
5
  export { Alert, AlertAction, AlertConsent, alertVariants, } from "./alert";
5
6
  export { AlertStack } from "./alert-stack";
6
7
  export { ActivityCard, ActivityCardActor, ActivityCardContent, } from "./activity-card";
@@ -0,0 +1,3 @@
1
+ import * as React from "react";
2
+ /** A compact horizontal group with design-system spacing. */
3
+ export declare function Inline({ children, ...props }: Omit<React.HTMLAttributes<HTMLDivElement>, "className" | "style">): import("react/jsx-runtime").JSX.Element;
package/dist/inline.js ADDED
@@ -0,0 +1,5 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ /** A compact horizontal group with design-system spacing. */
3
+ export function Inline({ children, ...props }) {
4
+ return _jsx("div", { ...props, "data-slot": "inline", className: "flex items-center gap-[var(--space-2)]", children: children });
5
+ }
@@ -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
  }
@@ -122,7 +122,7 @@ export function replaceTemplateVariables(content, context) {
122
122
  return result;
123
123
  }
124
124
  function ToolbarIconButton({ active, label, onClick, children, }) {
125
- return (_jsx(Button, { type: "button", variant: "ghost", size: "icon", className: cn("h-8 w-8", active && "bg-muted"), onClick: onClick, "aria-label": label, title: label, children: children }));
125
+ return (_jsx(Button, { type: "button", variant: "ghost", size: "compactIcon", className: cn(active && "bg-muted"), onClick: onClick, "aria-label": label, title: label, children: children }));
126
126
  }
127
127
  function getTemplateCategory(template) {
128
128
  return template.category || DEFAULT_TEMPLATE_CATEGORY;
@@ -359,7 +359,7 @@ export function RichTextEditor({ variant = "default", placeholder = "Type messag
359
359
  void handleSend();
360
360
  }, children: [_jsx(SendIcon, { size: 16 }), isSending ? sendingLabel : sendLabel] }));
361
361
  if (variant === "message") {
362
- return (_jsxs("div", { "data-slot": "message-composer", ref: dropZoneRef, onDragEnter: handleDragEnter, onDragLeave: handleDragLeave, onDragOver: handleDragOver, onDrop: handleDrop, className: cn("box-border flex min-h-[164px] flex-col overflow-hidden rounded-[8px] border border-input bg-background transition-all focus-within:border-ring focus-within:ring-[3px] focus-within:ring-ring/50", !isExpanded && attachments.length === 0 && "h-[164px]", isDragging && "border-2 border-primary bg-primary/5", className), children: [header ? (_jsxs("div", { "data-slot": "message-composer-header", className: "flex min-h-[48px] items-center justify-between px-[10px] py-[8px] text-muted-foreground", children: [_jsxs("div", { className: "flex min-w-0 items-center gap-[8px]", children: [_jsx(Reply, { "aria-hidden": "true", className: "size-[16px] shrink-0" }), _jsx(Typography, { as: "span", variant: "caption", className: "min-w-0 truncate font-medium text-muted-foreground", "data-slot": "message-composer-header-label", children: header })] }), onExpandToggle ? (_jsx(Tooltip, { content: isExpanded ? "Collapse editor" : "Expand editor", side: "top", children: _jsx(Button, { type: "button", variant: "ghost", size: "compactIcon", className: "h-[28px] w-[28px] shrink-0", onClick: onExpandToggle, "aria-label": isExpanded ? "Collapse editor" : "Expand editor", children: _jsx(MaximizeIcon, { size: 16 }) }) })) : null] })) : null, _jsx("div", { "data-slot": "message-composer-editor", className: cn("min-h-[64px]", isExpanded && "min-h-[200px]"), children: _jsx(EditorContent, { editor: editor, className: cn("min-h-[64px] text-sm", isExpanded && "min-h-[200px]", "[&_.ProseMirror]:min-h-[64px] [&_.ProseMirror]:outline-none", isExpanded && "[&_.ProseMirror]:min-h-[200px]", "[&_.ProseMirror_p.is-editor-empty:first-child::before]:float-left", "[&_.ProseMirror_p.is-editor-empty:first-child::before]:h-0", "[&_.ProseMirror_p.is-editor-empty:first-child::before]:pointer-events-none", "[&_.ProseMirror_p.is-editor-empty:first-child::before]:text-muted-foreground", "[&_.ProseMirror_p.is-editor-empty:first-child::before]:content-[attr(data-placeholder)]") }) }), attachments.length > 0 ? (_jsx("div", { className: "space-y-[8px] px-[10px] pb-[8px]", children: attachments.map((attachment, index) => (_jsxs("div", { className: "flex w-full items-center gap-[8px] rounded-md border bg-muted px-[12px] py-[8px] text-sm", children: [_jsx(PaperclipIcon, { size: 14, className: "shrink-0 text-muted-foreground" }), _jsx("span", { className: "min-w-0 flex-1 truncate", children: attachment.name }), _jsx("span", { className: "shrink-0 text-xs text-muted-foreground", children: formatFileSize(attachment.size) }), _jsx("button", { type: "button", onClick: () => removeAttachment(index), className: "shrink-0 text-muted-foreground hover:text-foreground", "aria-label": `Remove ${attachment.name}`, children: _jsx(XIcon, { size: 14 }) })] }, `${attachment.name}-${attachment.size}-${index}`))) })) : null, _jsx("input", { ref: fileInputRef, type: "file", accept: acceptedFileTypes, multiple: true, onChange: handleFileSelect, className: "hidden" }), linkPopoverOpen &&
362
+ return (_jsxs("div", { "data-slot": "message-composer", ref: dropZoneRef, onDragEnter: handleDragEnter, onDragLeave: handleDragLeave, onDragOver: handleDragOver, onDrop: handleDrop, className: cn("box-border flex min-h-[148px] flex-col overflow-hidden rounded-[8px] border border-input bg-background transition-all focus-within:border-ring focus-within:ring-[3px] focus-within:ring-ring/50", !isExpanded && attachments.length === 0 && "h-[148px]", isDragging && "border-2 border-primary bg-primary/5", className), children: [header ? (_jsx("div", { "data-slot": "message-composer-header", className: "flex min-h-[32px] items-center px-[10px] py-[4px] text-muted-foreground", children: _jsxs("div", { className: "flex min-w-0 items-center gap-[8px]", children: [_jsx(Reply, { "aria-hidden": "true", className: "size-[16px] shrink-0" }), _jsx(Typography, { as: "span", variant: "caption", className: "min-w-0 truncate font-medium text-muted-foreground", "data-slot": "message-composer-header-label", children: header })] }) })) : null, _jsx("div", { "data-slot": "message-composer-editor", className: cn("min-h-[64px]", isExpanded && "min-h-[200px]"), children: _jsx(EditorContent, { editor: editor, className: cn("min-h-[64px] text-sm", isExpanded && "min-h-[200px]", "[&_.ProseMirror]:min-h-[64px] [&_.ProseMirror]:outline-none", isExpanded && "[&_.ProseMirror]:min-h-[200px]", "[&_.ProseMirror_p.is-editor-empty:first-child::before]:float-left", "[&_.ProseMirror_p.is-editor-empty:first-child::before]:h-0", "[&_.ProseMirror_p.is-editor-empty:first-child::before]:pointer-events-none", "[&_.ProseMirror_p.is-editor-empty:first-child::before]:text-muted-foreground", "[&_.ProseMirror_p.is-editor-empty:first-child::before]:content-[attr(data-placeholder)]") }) }), attachments.length > 0 ? (_jsx("div", { className: "space-y-[8px] px-[10px] pb-[8px]", children: attachments.map((attachment, index) => (_jsxs("div", { className: "flex w-full items-center gap-[8px] rounded-md border bg-muted px-[12px] py-[8px] text-sm", children: [_jsx(PaperclipIcon, { size: 14, className: "shrink-0 text-muted-foreground" }), _jsx("span", { className: "min-w-0 flex-1 truncate", children: attachment.name }), _jsx("span", { className: "shrink-0 text-xs text-muted-foreground", children: formatFileSize(attachment.size) }), _jsx("button", { type: "button", onClick: () => removeAttachment(index), className: "shrink-0 text-muted-foreground hover:text-foreground", "aria-label": `Remove ${attachment.name}`, children: _jsx(XIcon, { size: 14 }) })] }, `${attachment.name}-${attachment.size}-${index}`))) })) : null, _jsx("input", { ref: fileInputRef, type: "file", accept: acceptedFileTypes, multiple: true, onChange: handleFileSelect, className: "hidden" }), linkPopoverOpen &&
363
363
  linkMenuPosition &&
364
364
  typeof document !== "undefined" &&
365
365
  createPortal(_jsxs(_Fragment, { children: [_jsx("div", { className: "fixed inset-0 z-[99]", onClick: () => {
@@ -370,7 +370,7 @@ export function RichTextEditor({ variant = "default", placeholder = "Type messag
370
370
  } }), _jsx("div", { ref: linkMenuRef, className: "fixed z-[100] w-80 animate-in fade-in-0 zoom-in-95 rounded-md border bg-popover p-3 shadow-md", style: {
371
371
  top: linkMenuPosition.top,
372
372
  left: linkMenuPosition.left,
373
- }, children: _jsxs("div", { className: "flex items-end gap-2", children: [_jsx(Input, { ref: linkInputRef, label: "URL", id: "message-link-url", type: "url", placeholder: "https://example.com", value: linkUrl, onChange: (event) => setLinkUrl(event.target.value), onKeyDown: handleLinkKeyDown, inputClassName: "h-8 text-sm", autoFocus: true }), _jsx(Button, { type: "button", className: "h-8 px-3", onClick: handleLinkSubmit, disabled: !linkUrl.trim(), children: "Add" })] }) })] }), document.body), isFormattingOpen ? (_jsxs("div", { className: "flex flex-wrap items-center gap-[4px] border-t border-border px-[10px] py-[8px]", children: [_jsx(ToolbarIconButton, { label: "Bold", active: editor === null || editor === void 0 ? void 0 : editor.isActive("bold"), onClick: () => editor === null || editor === void 0 ? void 0 : editor.chain().focus().toggleBold().run(), children: _jsx(BoldIcon, { size: 14 }) }), _jsx(ToolbarIconButton, { label: "Italic", active: editor === null || editor === void 0 ? void 0 : editor.isActive("italic"), onClick: () => editor === null || editor === void 0 ? void 0 : editor.chain().focus().toggleItalic().run(), children: _jsx(ItalicIcon, { size: 14 }) }), _jsx(ToolbarIconButton, { label: "Underline", active: editor === null || editor === void 0 ? void 0 : editor.isActive("underline"), onClick: () => editor === null || editor === void 0 ? void 0 : editor.chain().focus().toggleUnderline().run(), children: _jsx(UnderlineIcon, { size: 14 }) }), _jsx(ToolbarIconButton, { label: "Bullet list", active: editor === null || editor === void 0 ? void 0 : editor.isActive("bulletList"), onClick: () => editor === null || editor === void 0 ? void 0 : editor.chain().focus().toggleBulletList().run(), children: _jsx(ListIcon, { size: 14 }) }), _jsx(ToolbarIconButton, { label: "Ordered list", active: editor === null || editor === void 0 ? void 0 : editor.isActive("orderedList"), onClick: () => editor === null || editor === void 0 ? void 0 : editor.chain().focus().toggleOrderedList().run(), children: _jsx(ListOrderedIcon, { size: 14 }) })] })) : null, _jsxs("div", { "data-slot": "message-composer-toolbar", className: "flex min-h-[52px] items-center justify-between px-[10px] py-[8px]", children: [_jsxs("div", { className: "flex items-center gap-[8px]", children: [_jsx(Tooltip, { content: `Attach files (max ${maxFileSizeLabel}) - ${acceptedFileTypesLabel}`, side: "top", contentClassName: "max-w-[240px] text-center", children: _jsx(Button, { type: "button", variant: "ghost", size: "compactIcon", className: "h-[28px] w-[28px]", onClick: () => { var _a; return (_a = fileInputRef.current) === null || _a === void 0 ? void 0 : _a.click(); }, "aria-label": "Attach files", children: _jsx(PaperclipIcon, { size: 16 }) }) }), _jsxs("div", { className: "inline-flex h-[32px] overflow-hidden rounded-control border border-input bg-background", children: [_jsx(Button, { type: "button", variant: "ghost", size: "compactIcon", className: "h-[32px] w-[32px] rounded-none border-r border-input", onClick: () => editor === null || editor === void 0 ? void 0 : editor.chain().focus().toggleBold().run(), "aria-pressed": (_a = editor === null || editor === void 0 ? void 0 : editor.isActive("bold")) !== null && _a !== void 0 ? _a : false, "aria-label": "Bold", children: _jsx(BoldIcon, { size: 16 }) }), _jsx(Button, { type: "button", variant: "ghost", size: "compactIcon", className: "h-[32px] w-[32px] rounded-none border-r border-input", onClick: openLinkMenu, "aria-label": "Add link", children: _jsx(LinkIcon, { size: 16 }) }), _jsx(Button, { type: "button", variant: "ghost", size: "compactIcon", className: "h-[32px] w-[32px] rounded-none", onClick: () => setIsFormattingOpen((open) => !open), "aria-expanded": isFormattingOpen, "aria-label": "Formatting options", children: _jsx(Baseline, { "aria-hidden": "true", className: "size-[16px]" }) })] })] }), _jsxs("div", { className: "flex items-center gap-[8px]", children: [showTemplates && (templates.length > 0 || templateCreateHref) ? (_jsxs(Popover, { open: templatePopoverOpen, onOpenChange: setTemplatePopoverOpen, align: "end", contentClassName: "w-96 p-0", trigger: _jsxs(Button, { type: "button", variant: "outline", size: "sm", children: ["Templates", _jsx(ChevronDownIcon, { size: 16 })] }), children: [_jsx("div", { className: "max-h-80 overflow-y-auto", children: templatesByCategory.map(({ category, templates }) => {
373
+ }, children: _jsxs("div", { className: "flex items-end gap-2", children: [_jsx(Input, { ref: linkInputRef, label: "URL", id: "message-link-url", type: "url", placeholder: "https://example.com", value: linkUrl, onChange: (event) => setLinkUrl(event.target.value), onKeyDown: handleLinkKeyDown, inputClassName: "h-8 text-sm", autoFocus: true }), _jsx(Button, { type: "button", className: "h-8 px-3", onClick: handleLinkSubmit, disabled: !linkUrl.trim(), children: "Add" })] }) })] }), document.body), isFormattingOpen ? (_jsxs("div", { className: "flex flex-wrap items-center gap-[4px] border-t border-border px-[10px] py-[8px]", children: [_jsx(ToolbarIconButton, { label: "Bold", active: editor === null || editor === void 0 ? void 0 : editor.isActive("bold"), onClick: () => editor === null || editor === void 0 ? void 0 : editor.chain().focus().toggleBold().run(), children: _jsx(BoldIcon, { size: 14 }) }), _jsx(ToolbarIconButton, { label: "Italic", active: editor === null || editor === void 0 ? void 0 : editor.isActive("italic"), onClick: () => editor === null || editor === void 0 ? void 0 : editor.chain().focus().toggleItalic().run(), children: _jsx(ItalicIcon, { size: 14 }) }), _jsx(ToolbarIconButton, { label: "Underline", active: editor === null || editor === void 0 ? void 0 : editor.isActive("underline"), onClick: () => editor === null || editor === void 0 ? void 0 : editor.chain().focus().toggleUnderline().run(), children: _jsx(UnderlineIcon, { size: 14 }) }), _jsx(ToolbarIconButton, { label: "Bullet list", active: editor === null || editor === void 0 ? void 0 : editor.isActive("bulletList"), onClick: () => editor === null || editor === void 0 ? void 0 : editor.chain().focus().toggleBulletList().run(), children: _jsx(ListIcon, { size: 14 }) }), _jsx(ToolbarIconButton, { label: "Ordered list", active: editor === null || editor === void 0 ? void 0 : editor.isActive("orderedList"), onClick: () => editor === null || editor === void 0 ? void 0 : editor.chain().focus().toggleOrderedList().run(), children: _jsx(ListOrderedIcon, { size: 14 }) })] })) : null, _jsxs("div", { "data-slot": "message-composer-toolbar", className: "flex min-h-[52px] items-center justify-between px-[10px] py-[8px]", children: [_jsxs("div", { className: "flex items-center gap-[8px]", children: [_jsx(Tooltip, { content: `Attach files (max ${maxFileSizeLabel}) - ${acceptedFileTypesLabel}`, side: "top", contentClassName: "max-w-[240px] text-center", children: _jsx(Button, { type: "button", variant: "ghost", size: "compactIcon", onClick: () => { var _a; return (_a = fileInputRef.current) === null || _a === void 0 ? void 0 : _a.click(); }, "aria-label": "Attach files", children: _jsx(PaperclipIcon, { size: 16 }) }) }), _jsxs("div", { className: "inline-flex h-[32px] overflow-hidden rounded-control border border-input bg-background", children: [_jsx(Button, { type: "button", variant: "ghost", size: "compactIcon", className: "rounded-none border-r border-input", onClick: () => editor === null || editor === void 0 ? void 0 : editor.chain().focus().toggleBold().run(), "aria-pressed": (_a = editor === null || editor === void 0 ? void 0 : editor.isActive("bold")) !== null && _a !== void 0 ? _a : false, "aria-label": "Bold", children: _jsx(BoldIcon, { size: 16 }) }), _jsx(Button, { type: "button", variant: "ghost", size: "compactIcon", className: "rounded-none border-r border-input", onClick: openLinkMenu, "aria-label": "Add link", children: _jsx(LinkIcon, { size: 16 }) }), _jsx(Button, { type: "button", variant: "ghost", size: "compactIcon", className: "rounded-none", onClick: () => setIsFormattingOpen((open) => !open), "aria-expanded": isFormattingOpen, "aria-label": "Formatting options", children: _jsx(Baseline, { "aria-hidden": "true", className: "size-[16px]" }) })] })] }), _jsxs("div", { className: "flex items-center gap-[8px]", children: [showTemplates && (templates.length > 0 || templateCreateHref) ? (_jsxs(Popover, { open: templatePopoverOpen, onOpenChange: setTemplatePopoverOpen, align: "end", contentClassName: "w-96 p-0", trigger: _jsxs(Button, { type: "button", variant: "outline", size: "sm", children: ["Templates", _jsx(ChevronDownIcon, { size: 16 })] }), children: [_jsx("div", { className: "max-h-80 overflow-y-auto", children: templatesByCategory.map(({ category, templates }) => {
374
374
  var _a;
375
375
  return (_jsxs("div", { children: [_jsx("div", { className: "sticky top-0 bg-muted px-3 py-2 text-sm font-semibold text-foreground", children: (_a = templateCategoryLabels[category]) !== null && _a !== void 0 ? _a : category }), templates.map((template) => (_jsxs("button", { type: "button", className: "w-full border-b border-border/50 px-3 py-2 text-left text-sm transition-colors last:border-0 hover:bg-muted", onClick: () => applyTemplate(template), children: [_jsx("div", { className: "truncate font-medium", children: template.name }), template.description ? (_jsx("div", { className: "mt-0.5 truncate text-xs text-muted-foreground", children: template.description })) : null] }, template.id)))] }, category));
376
376
  }) }), templateCreateHref ? (_jsx("div", { className: "border-t p-2", children: _jsxs("a", { href: templateCreateHref, target: "_blank", rel: "noopener noreferrer", className: "flex w-full items-center justify-center gap-1.5 rounded-md px-3 py-2 text-sm text-interactive transition-colors hover:bg-muted", children: [_jsx(PlusIcon, { size: 16 }), templateCreateLabel] }) })) : null] })) : null, renderSendAction({ compact: true })] })] })] }));
@@ -16,6 +16,8 @@ export interface RoutingActionPanelProps extends Omit<DashboardActionPanelProps,
16
16
  onRouteValueChange?: (value: string) => void;
17
17
  /** Workflow-specific fields rendered before the route target. */
18
18
  supplementaryFields?: React.ReactNode;
19
+ /** Read-only review context in the scrollable body, above routing activity. */
20
+ context?: React.ReactNode;
19
21
  remarks: string;
20
22
  remarksDescription?: React.ReactNode;
21
23
  remarksPlaceholder?: string;
@@ -34,5 +36,5 @@ export interface RoutingActionPanelProps extends Omit<DashboardActionPanelProps,
34
36
  * Consumers provide workflow data and actions; the component owns the complete
35
37
  * visual composition so different records render routing consistently.
36
38
  */
37
- declare function RoutingActionPanel({ items, isLoading, loadingLabel, emptyMessage, emptyDescription, routeOptions, routeValue, routePlaceholder, routeDescription, routeDisabled, onRouteValueChange, supplementaryFields, remarks, remarksDescription, remarksPlaceholder, remarksRequired, remarksRows, validationMessages, onRemarksChange, submitLabel, submitDisabled, submitLoading, onSubmit, ...panelProps }: RoutingActionPanelProps): import("react/jsx-runtime").JSX.Element;
39
+ declare function RoutingActionPanel({ items, isLoading, loadingLabel, emptyMessage, emptyDescription, routeOptions, routeValue, routePlaceholder, routeDescription, routeDisabled, onRouteValueChange, supplementaryFields, context, remarks, remarksDescription, remarksPlaceholder, remarksRequired, remarksRows, validationMessages, onRemarksChange, submitLabel, submitDisabled, submitLoading, onSubmit, ...panelProps }: RoutingActionPanelProps): import("react/jsx-runtime").JSX.Element;
38
40
  export { RoutingActionPanel };
@@ -2,6 +2,7 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { Route } from "lucide-react";
4
4
  import { Button } from "./button";
5
+ import { EmptyState } from "./empty-state";
5
6
  import { DashboardActionPanel, DashboardActionPanelEmptyState, DashboardRightPanelBody, } from "./layout";
6
7
  import { RoutingTimeline, } from "./routing-timeline";
7
8
  import { Select } from "./select";
@@ -12,8 +13,9 @@ import { Textarea } from "./textarea";
12
13
  * Consumers provide workflow data and actions; the component owns the complete
13
14
  * visual composition so different records render routing consistently.
14
15
  */
15
- function RoutingActionPanel({ items, isLoading = false, loadingLabel = "Loading routing activity", emptyMessage = "No routing activity yet", emptyDescription = "Workflow routes will appear here.", routeOptions, routeValue, routePlaceholder = "Select Officer Role", routeDescription, routeDisabled = false, onRouteValueChange, supplementaryFields, remarks, remarksDescription, remarksPlaceholder = "Type remarks", remarksRequired = false, remarksRows = 2, validationMessages = [], onRemarksChange, submitLabel = "Route", submitDisabled = false, submitLoading = false, onSubmit, ...panelProps }) {
16
- const footer = (_jsxs("div", { "data-slot": "routing-action-panel-form", className: "grid gap-[var(--space-4)]", children: [supplementaryFields, _jsx(Select, { label: "Route To", options: routeOptions, value: routeValue, placeholder: routePlaceholder, disabled: routeDisabled || submitLoading, description: routeDescription, onValueChange: onRouteValueChange }), _jsx(Textarea, { label: "Remarks", value: remarks, onChange: (event) => onRemarksChange(event.target.value), placeholder: remarksPlaceholder, description: remarksDescription, disabled: routeDisabled || submitLoading, required: remarksRequired, rows: remarksRows }), validationMessages.length > 0 ? (_jsxs("details", { className: "text-sm text-muted-foreground", children: [_jsxs("summary", { className: "cursor-pointer font-medium text-foreground", children: [validationMessages.length, " required ", validationMessages.length === 1 ? "item" : "items", " remaining \u2014 view details"] }), _jsx("ul", { className: "mt-2 max-h-40 list-disc space-y-1 overflow-y-auto pl-5", children: validationMessages.map((message, index) => _jsx("li", { children: message }, index)) })] })) : null, _jsx("div", { className: "flex justify-end", children: _jsxs(Button, { type: "button", disabled: routeDisabled || submitDisabled || validationMessages.length > 0, loading: submitLoading, onClick: onSubmit, children: [_jsx(Route, { "aria-hidden": "true", className: "size-4" }), submitLabel] }) })] }));
17
- return (_jsx(DashboardActionPanel, { headerSpacing: "comfortable", ...panelProps, children: _jsx(DashboardRightPanelBody, { spacing: "comfortable", topInset: "none", footerVariant: "separated", footer: footer, children: isLoading ? (_jsx("div", { "data-slot": "routing-action-panel-loading", className: "absolute inset-0 flex items-center justify-center", children: _jsx(Spinner, { size: "md", label: loadingLabel }) })) : items.length === 0 ? (_jsx(DashboardActionPanelEmptyState, { icon: Route, message: emptyMessage, description: emptyDescription })) : (_jsx(RoutingTimeline, { density: "compact", items: items })) }) }));
16
+ function RoutingActionPanel({ items, isLoading = false, loadingLabel = "Loading routing activity", emptyMessage = "No routing activity yet", emptyDescription = "Workflow routes will appear here.", routeOptions, routeValue, routePlaceholder = "Select Officer Role", routeDescription, routeDisabled = false, onRouteValueChange, supplementaryFields, context, remarks, remarksDescription, remarksPlaceholder = "Type remarks", remarksRequired = false, remarksRows = 2, validationMessages = [], onRemarksChange, submitLabel = "Route", submitDisabled = false, submitLoading = false, onSubmit, ...panelProps }) {
17
+ const RoutingEmptyState = context ? EmptyState : DashboardActionPanelEmptyState;
18
+ const footer = (_jsxs("div", { "data-slot": "routing-action-panel-form", className: "grid gap-[var(--space-4)]", children: [supplementaryFields, _jsx(Select, { label: "Route To", options: routeOptions, value: routeValue, placeholder: routePlaceholder, disabled: routeDisabled || submitLoading, description: routeDescription, onValueChange: onRouteValueChange }), _jsx(Textarea, { label: "Remarks", value: remarks, onChange: (event) => onRemarksChange(event.target.value), placeholder: remarksPlaceholder, description: remarksDescription, disabled: routeDisabled || submitLoading, required: remarksRequired, rows: remarksRows }), validationMessages.length > 0 ? (_jsxs("details", { className: "text-sm text-muted-foreground", children: [_jsxs("summary", { className: "cursor-pointer font-medium text-foreground", children: [validationMessages.length, " required ", validationMessages.length === 1 ? "item" : "items", " remaining \u2014 view details"] }), _jsx("ul", { className: "mt-2 max-h-40 list-disc space-y-1 overflow-y-auto pl-5", children: validationMessages.map((message, index) => _jsx("li", { children: message }, index)) })] })) : null, _jsx("div", { className: "flex justify-end", children: _jsxs(Button, { type: "button", size: "default", disabled: routeDisabled || submitDisabled || validationMessages.length > 0, loading: submitLoading, loadingText: submitLabel, onClick: onSubmit, children: [_jsx(Route, { "aria-hidden": "true", className: "size-4" }), submitLabel] }) })] }));
19
+ return (_jsx(DashboardActionPanel, { headerSpacing: "comfortable", ...panelProps, children: _jsxs(DashboardRightPanelBody, { spacing: "comfortable", topInset: "none", footerVariant: "separated", footer: footer, children: [context ? (_jsx("div", { "data-slot": "routing-action-panel-context", className: "mb-[var(--space-4)] grid min-w-0 gap-[var(--space-3)] whitespace-pre-wrap [overflow-wrap:anywhere]", children: context })) : null, isLoading ? (_jsx("div", { "data-slot": "routing-action-panel-loading", className: context ? "flex items-center justify-center py-[var(--space-4)]" : "absolute inset-0 flex items-center justify-center", children: _jsx(Spinner, { size: "md", label: loadingLabel }) })) : items.length === 0 ? (_jsx(RoutingEmptyState, { icon: Route, message: emptyMessage, description: emptyDescription })) : (_jsx(RoutingTimeline, { density: "compact", items: items }))] }) }));
18
20
  }
19
21
  export { RoutingActionPanel };
@@ -87,7 +87,7 @@ function RoutingTimeline({ items, emptyMessage = "No routing activity yet.", den
87
87
  ? "gap-[var(--space-3)]"
88
88
  : "gap-[24px]"), children: [item.from ? (_jsx(RoutingTimelineHandoffEndpoint, { value: item.from, label: item.fromLabel })) : null, item.from && item.to ? (_jsxs(_Fragment, { children: [_jsx("span", { className: "sr-only", children: "to" }), _jsx(ArrowRight, { "aria-hidden": "true", "data-slot": "routing-timeline-handoff-arrow", className: cn("shrink-0 text-foreground", density === "compact" ? "size-4" : "size-6") })] })) : null, item.to ? (_jsx(RoutingTimelineHandoffEndpoint, { value: item.to, label: item.toLabel })) : null] })) : null, remark ? (_jsxs("div", { "data-slot": "routing-timeline-remark", className: cn("bg-muted", density === "compact"
89
89
  ? "rounded-control p-[var(--space-2)]"
90
- : "rounded-md p-[12px]"), children: [detailLabel ? (_jsx(Typography, { as: "p", variant: "bodySm", className: "font-semibold text-instructional", children: detailLabel })) : null, _jsx(Typography, { as: "div", variant: "bodySm", className: cn(detailLabel &&
90
+ : "rounded-md p-[12px]"), children: [detailLabel ? (_jsx(Typography, { as: "p", variant: "bodySm", className: "font-semibold text-instructional", children: detailLabel })) : null, _jsx(Typography, { as: "div", variant: "bodySm", className: cn("whitespace-pre-wrap [overflow-wrap:anywhere]", detailLabel &&
91
91
  (density === "compact"
92
92
  ? "mt-[var(--space-1)]"
93
93
  : "mt-[4px]")), children: remark })] })) : null] })) : null }) }, item.id));
package/dist/table.d.ts CHANGED
@@ -29,6 +29,7 @@ declare const TableCell: React.ForwardRefExoticComponent<React.TdHTMLAttributes<
29
29
  wrap?: boolean;
30
30
  treatWidthAsMinWidth?: boolean;
31
31
  containOverflow?: boolean;
32
+ preserveButtonPadding?: boolean;
32
33
  } & React.RefAttributes<HTMLTableCellElement>>;
33
34
  declare const TableRowHeader: React.ForwardRefExoticComponent<React.ThHTMLAttributes<HTMLTableCellElement> & {
34
35
  width?: string;
@@ -93,6 +94,8 @@ export interface TableColumn<Row> {
93
94
  skeleton?: TableSkeletonConfig;
94
95
  headerClassName?: string;
95
96
  cellClassName?: string;
97
+ /** Keeps each design-system button's own horizontal padding in body cells. */
98
+ preserveButtonPadding?: boolean;
96
99
  /** Renders this column's body cells as semantic row headers. */
97
100
  rowHeader?: boolean;
98
101
  /** Pins the column to the left or right edge while the table scrolls horizontally. */
package/dist/table.js CHANGED
@@ -171,7 +171,8 @@ 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, preserveButtonPadding = false, ...props }, ref) => (_jsx("td", { ref: ref, className: cn("h-12 px-4 py-[4px] align-middle text-card-foreground [&:has([role=checkbox])]:pr-0", !preserveButtonPadding &&
175
+ "[&:not([data-slot=table-empty-cell])_[data-slot=button]]:px-0", wrap ? "whitespace-normal" : "whitespace-nowrap", overflowContainmentClassName({ containOverflow, wrap }), className), style: getTableColumnSizingStyle({
175
176
  style,
176
177
  width,
177
178
  minWidth,
@@ -742,11 +743,11 @@ function Table({ accessibleLabel, columns, rows, getRowKey, emptyState = (_jsx(T
742
743
  const Cell = column.rowHeader
743
744
  ? TableRowHeader
744
745
  : TableCell;
745
- return (_jsx(Cell, { width: columnWidth, minWidth: getRenderedColumnMinWidth(column, isColumnResizingEnabled), maxWidth: getRenderedColumnMaxWidth(column, isColumnResizingEnabled), wrap: column.wrap, treatWidthAsMinWidth: !isColumnResizingEnabled, containOverflow: isColumnResizingEnabled, className: cn(alignClassName(column.align), stickyClassName(column.sticky, "cell", getStickyShadowVisibility(column.sticky, stickyScrollState)), column.cellClassName), children: value }, column.key));
746
+ return (_jsx(Cell, { width: columnWidth, minWidth: getRenderedColumnMinWidth(column, isColumnResizingEnabled), maxWidth: getRenderedColumnMaxWidth(column, isColumnResizingEnabled), wrap: column.wrap, treatWidthAsMinWidth: !isColumnResizingEnabled, containOverflow: isColumnResizingEnabled, preserveButtonPadding: column.preserveButtonPadding, className: cn(alignClassName(column.align), stickyClassName(column.sticky, "cell", getStickyShadowVisibility(column.sticky, stickyScrollState)), column.cellClassName), children: value }, column.key));
746
747
  })] }), 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
748
  (hasRowIndicatorColumn ? 1 : 0) +
748
749
  (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 +
750
+ })) : (_jsx(TableRow, { className: "cursor-default hover:bg-card", children: _jsx(TableCell, { "data-slot": "table-empty-cell", colSpan: Math.max(visibleColumns.length +
750
751
  (hasRowIndicatorColumn ? 1 : 0) +
751
752
  (hasExpansionColumn ? 1 : 0), 1), className: "p-6", children: resolvedEmptyState }) })) })] }), _jsx("div", { role: "status", className: "sr-only", children: loading ? loadingLabel : null })] }));
752
753
  const reorderableContainer = reorderableColumns ? (_jsx(DndContext, { sensors: columnReorderSensors, collisionDetection: closestCenter, onDragEnd: handleColumnDragEnd, children: _jsx(SortableContext, { items: reorderableColumnIds, strategy: horizontalListSortingStrategy, children: container }) })) : (container);
@@ -7,7 +7,7 @@ export interface TypographyProps extends React.HTMLAttributes<HTMLElement>, Vari
7
7
  as?: keyof React.JSX.IntrinsicElements;
8
8
  asChild?: boolean;
9
9
  /** Override the built-in text colour. Use "inherit" to inherit from a parent container. */
10
- color?: "inherit" | "foreground" | "muted";
10
+ color?: "inherit" | "foreground" | "muted" | "primary";
11
11
  }
12
12
  declare const Typography: React.ForwardRefExoticComponent<TypographyProps & React.RefAttributes<HTMLElement>>;
13
13
  export { Typography, typographyVariants };
@@ -39,9 +39,11 @@ const Typography = React.forwardRef(({ as, asChild = false, className, variant,
39
39
  ? "text-inherit"
40
40
  : color === "foreground"
41
41
  ? "text-foreground"
42
- : color === "muted"
43
- ? "text-instructional"
44
- : undefined;
42
+ : color === "primary"
43
+ ? "text-primary"
44
+ : color === "muted"
45
+ ? "text-instructional"
46
+ : undefined;
45
47
  return (_jsx(Comp, { ref: ref, className: cn(typographyVariants({ variant: resolvedVariant }), colorClass, className), ...props }));
46
48
  });
47
49
  Typography.displayName = "Typography";
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.132",
4
4
  "description": "NEA shared design system primitives, theme tokens, and Storybook docs.",
5
5
  "repository": {
6
6
  "type": "git",