@neasg/design-system 0.4.35 → 0.4.113

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/README.md +9 -0
  2. package/dist/activity-card.d.ts +31 -0
  3. package/dist/activity-card.js +65 -0
  4. package/dist/alert.d.ts +1 -1
  5. package/dist/autocomplete.d.ts +84 -0
  6. package/dist/autocomplete.js +267 -0
  7. package/dist/avatar.d.ts +3 -1
  8. package/dist/avatar.js +27 -10
  9. package/dist/badge.d.ts +1 -1
  10. package/dist/badge.js +1 -1
  11. package/dist/button.d.ts +2 -2
  12. package/dist/button.js +3 -1
  13. package/dist/calendar.js +1 -1
  14. package/dist/card.d.ts +1 -1
  15. package/dist/card.js +1 -1
  16. package/dist/changelog-action-panel.d.ts +17 -0
  17. package/dist/changelog-action-panel.js +14 -0
  18. package/dist/checklist.d.ts +63 -0
  19. package/dist/checklist.js +30 -0
  20. package/dist/compound-search-input.d.ts +10 -0
  21. package/dist/compound-search-input.js +19 -0
  22. package/dist/date-input.js +3 -3
  23. package/dist/dialog.d.ts +4 -1
  24. package/dist/dialog.js +7 -2
  25. package/dist/draggable-tabs.js +9 -8
  26. package/dist/dropdown-button.js +1 -0
  27. package/dist/editable-table.js +2 -2
  28. package/dist/field-counter.d.ts +7 -0
  29. package/dist/field-counter.js +5 -0
  30. package/dist/index.d.ts +22 -4
  31. package/dist/index.js +12 -2
  32. package/dist/input.d.ts +2 -0
  33. package/dist/input.js +11 -3
  34. package/dist/label-value-grid.js +6 -4
  35. package/dist/layout.d.ts +39 -6
  36. package/dist/layout.js +118 -42
  37. package/dist/lib/utils.js +1 -0
  38. package/dist/message-action-panel.d.ts +12 -0
  39. package/dist/message-action-panel.js +11 -0
  40. package/dist/message-item.d.ts +23 -3
  41. package/dist/message-item.js +115 -16
  42. package/dist/notification.d.ts +14 -3
  43. package/dist/notification.js +36 -7
  44. package/dist/page-section.d.ts +2 -1
  45. package/dist/page-section.js +2 -2
  46. package/dist/popover-menu.d.ts +4 -2
  47. package/dist/popover-menu.js +65 -5
  48. package/dist/popover.d.ts +10 -2
  49. package/dist/popover.js +7 -3
  50. package/dist/rich-text-editor.d.ts +2 -1
  51. package/dist/rich-text-editor.js +29 -6
  52. package/dist/routing-action-panel.d.ts +38 -0
  53. package/dist/routing-action-panel.js +19 -0
  54. package/dist/routing-timeline.d.ts +7 -2
  55. package/dist/routing-timeline.js +67 -29
  56. package/dist/search-input.d.ts +6 -0
  57. package/dist/search-input.js +6 -4
  58. package/dist/select-primitive.js +1 -1
  59. package/dist/select.d.ts +3 -1
  60. package/dist/select.js +9 -4
  61. package/dist/status-dot.d.ts +13 -0
  62. package/dist/status-dot.js +19 -0
  63. package/dist/styles.css +0 -19
  64. package/dist/table-add-row.d.ts +8 -0
  65. package/dist/table-add-row.js +7 -0
  66. package/dist/table-column-filter.js +7 -5
  67. package/dist/table.d.ts +9 -1
  68. package/dist/table.js +25 -11
  69. package/dist/tabs.d.ts +1 -1
  70. package/dist/tabs.js +6 -4
  71. package/dist/tailwind-preset.js +10 -0
  72. package/dist/textarea.d.ts +5 -0
  73. package/dist/textarea.js +18 -3
  74. package/dist/theme-switcher.d.ts +3 -1
  75. package/dist/theme-switcher.js +8 -2
  76. package/package.json +1 -1
package/dist/card.d.ts CHANGED
@@ -2,7 +2,7 @@ import * as React from "react";
2
2
  export interface CardProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "title"> {
3
3
  title: React.ReactNode;
4
4
  description?: React.ReactNode;
5
- variant?: "default" | "elevated" | "gradient";
5
+ variant?: "default" | "subtle" | "elevated" | "gradient";
6
6
  size?: "default" | "compact";
7
7
  /** Large value displayed above the title — use for stat/metric cards. */
8
8
  stat?: React.ReactNode;
package/dist/card.js CHANGED
@@ -106,7 +106,7 @@ const Card = React.forwardRef(({ title, description, variant = "default", size =
106
106
  };
107
107
  const renderedTitle = React.isValidElement(title) ? (title) : (_jsx(Typography, { as: "p", variant: hasStat ? "caption" : "body", color: variant === "gradient" ? "inherit" : hasStat ? "muted" : "foreground", className: cn(hasStat && "font-medium", !hasStat && "font-semibold", variant === "gradient" && "opacity-80"), children: title }));
108
108
  const renderedDescription = description == null ? null : React.isValidElement(description) ? (description) : (_jsx(Typography, { as: "p", variant: "caption", color: variant === "gradient" ? "inherit" : undefined, className: variant === "gradient" ? "opacity-70" : undefined, children: description }));
109
- return (_jsxs("div", { ref: ref, onClick: onClick, onKeyDown: handleKeyDown, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, onFocus: handleFocus, onBlur: handleBlur, role: role !== null && role !== void 0 ? role : (interactive ? "button" : props["aria-label"] || props["aria-labelledby"] ? "region" : undefined), tabIndex: tabIndex !== null && tabIndex !== void 0 ? tabIndex : (interactive ? 0 : undefined), "aria-pressed": ariaPressed !== null && ariaPressed !== void 0 ? ariaPressed : (interactive && active !== undefined ? Boolean(active) : undefined), className: cn("group/card rounded-surface border border-[hsl(var(--card-border))] text-card-foreground", variant === "default" && "bg-card", variant === "elevated" && "bg-card shadow-sm", variant === "gradient" &&
109
+ return (_jsxs("div", { ref: ref, onClick: onClick, onKeyDown: handleKeyDown, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, onFocus: handleFocus, onBlur: handleBlur, role: role !== null && role !== void 0 ? role : (interactive ? "button" : props["aria-label"] || props["aria-labelledby"] ? "region" : undefined), tabIndex: tabIndex !== null && tabIndex !== void 0 ? tabIndex : (interactive ? 0 : undefined), "aria-pressed": ariaPressed !== null && ariaPressed !== void 0 ? ariaPressed : (interactive && active !== undefined ? Boolean(active) : undefined), className: cn("group/card rounded-surface border border-[hsl(var(--card-border))] text-card-foreground", variant === "default" && "bg-card", variant === "subtle" && "bg-muted/40", variant === "elevated" && "bg-card shadow-sm", variant === "gradient" &&
110
110
  "border-[hsl(var(--card-gradient-border))]/30 bg-gradient-to-br from-[hsl(var(--card-gradient-from))] to-[hsl(var(--card-gradient-to))] text-[hsl(var(--card-gradient-foreground))]", active && "border-primary bg-primary/[0.04] ring-1 ring-primary/20", accent === "primary" &&
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 &&
@@ -0,0 +1,17 @@
1
+ import * as React from "react";
2
+ import { type DashboardActionPanelProps } from "./layout";
3
+ import { type NotificationItemData } from "./notification";
4
+ export interface ChangelogActionPanelProps extends Omit<DashboardActionPanelProps, "children" | "headerSpacing" | "title"> {
5
+ title?: React.ReactNode;
6
+ notifications: NotificationItemData[];
7
+ isLoading?: boolean;
8
+ loadingLabel?: string;
9
+ emptyMessage?: React.ReactNode;
10
+ emptyDescription?: React.ReactNode;
11
+ }
12
+ /**
13
+ * Shared change-log panel. Consumers map their domain events to notification
14
+ * items; this component owns the complete list, loading, and empty-state UI.
15
+ */
16
+ declare function ChangelogActionPanel({ title, subtitle, notifications, isLoading, loadingLabel, emptyMessage, emptyDescription, ...panelProps }: ChangelogActionPanelProps): import("react/jsx-runtime").JSX.Element;
17
+ export { ChangelogActionPanel };
@@ -0,0 +1,14 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { History } from "lucide-react";
4
+ import { DashboardActionPanel, DashboardActionPanelEmptyState, DashboardRightPanelBody, } from "./layout";
5
+ import { NotificationList, } from "./notification";
6
+ import { Spinner } from "./spinner";
7
+ /**
8
+ * Shared change-log panel. Consumers map their domain events to notification
9
+ * items; this component owns the complete list, loading, and empty-state UI.
10
+ */
11
+ function ChangelogActionPanel({ title = "Change log", subtitle = "Review all activity recorded here.", notifications, isLoading = false, loadingLabel = "Loading change log", emptyMessage = "No change log entries yet", emptyDescription = "Changes will be recorded here.", ...panelProps }) {
12
+ return (_jsx(DashboardActionPanel, { headerSpacing: "comfortable", title: title, subtitle: subtitle, ...panelProps, children: _jsx(DashboardRightPanelBody, { spacing: "comfortable", topInset: "none", children: isLoading ? (_jsx("div", { "data-slot": "changelog-action-panel-loading", className: "absolute inset-0 flex items-center justify-center", children: _jsx(Spinner, { size: "md", label: loadingLabel }) })) : notifications.length === 0 ? (_jsx(DashboardActionPanelEmptyState, { icon: History, message: emptyMessage, description: emptyDescription })) : (_jsx(NotificationList, { density: "compact", notifications: notifications, descriptionLines: 3, emptyState: null, variant: "bordered" })) }) }));
13
+ }
14
+ export { ChangelogActionPanel };
@@ -0,0 +1,63 @@
1
+ import * as React from "react";
2
+ import { type SelectOption } from "./select";
3
+ export interface ChecklistPanelProps {
4
+ title: React.ReactNode;
5
+ action?: React.ReactNode;
6
+ children: React.ReactNode;
7
+ }
8
+ export declare function ChecklistPanel({ title, action, children }: ChecklistPanelProps): import("react/jsx-runtime").JSX.Element;
9
+ export interface ChecklistSectionProps {
10
+ title: string;
11
+ progress?: string;
12
+ /** Independent control displayed beside the section chevron. */
13
+ action?: React.ReactNode;
14
+ children: React.ReactNode;
15
+ defaultOpen?: boolean;
16
+ open?: boolean;
17
+ onOpenChange?: (open: boolean) => void;
18
+ }
19
+ export declare function ChecklistSection({ title, progress, action, children, defaultOpen, open, onOpenChange }: ChecklistSectionProps): import("react/jsx-runtime").JSX.Element;
20
+ export interface ChecklistSelectionProps {
21
+ title: string;
22
+ description: string;
23
+ typeOptions: SelectOption[];
24
+ subtypeOptions: SelectOption[];
25
+ type: string;
26
+ subtype: string;
27
+ onTypeChange: (value: string) => void;
28
+ onSubtypeChange: (value: string) => void;
29
+ disabled?: boolean;
30
+ loading?: boolean;
31
+ action?: React.ReactNode;
32
+ }
33
+ export declare function ChecklistSelection({ title, description, typeOptions, subtypeOptions, type, subtype, onTypeChange, onSubtypeChange, disabled, loading, action }: ChecklistSelectionProps): import("react/jsx-runtime").JSX.Element;
34
+ export interface ChecklistQuestionOption {
35
+ value: string;
36
+ label: string;
37
+ tone?: "positive" | "negative" | "neutral";
38
+ }
39
+ export interface ChecklistQuestionProps {
40
+ label: string;
41
+ options: ChecklistQuestionOption[];
42
+ value: string;
43
+ onValueChange: (value: string) => void;
44
+ disabled?: boolean;
45
+ remarks: string;
46
+ onRemarksChange: (value: string) => void;
47
+ remarksLimit?: number;
48
+ /** Count and limit characters instead of words when supplied. */
49
+ remarksMaxLength?: number;
50
+ remarksRequired?: boolean;
51
+ evidence?: React.ReactNode;
52
+ evidenceCount?: number;
53
+ }
54
+ export declare function ChecklistQuestion({ label, options, value, onValueChange, disabled, remarks, onRemarksChange, remarksLimit, remarksMaxLength, remarksRequired, evidence, evidenceCount }: ChecklistQuestionProps): import("react/jsx-runtime").JSX.Element;
55
+ export interface ChecklistAttachmentsProps {
56
+ items: {
57
+ key: string;
58
+ name: string;
59
+ url: string;
60
+ }[];
61
+ onRemove?: (key: string) => void;
62
+ }
63
+ export declare function ChecklistAttachments({ items, onRemove }: ChecklistAttachmentsProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,30 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import * as CollapsiblePrimitive from "@radix-ui/react-collapsible";
5
+ import { Camera, ChevronDown, ClipboardList, LoaderCircle, MessageSquareText, Trash2 } from "lucide-react";
6
+ import { Button } from "./button";
7
+ import { Select } from "./select";
8
+ import { Textarea } from "./textarea";
9
+ import { cn } from "./lib/utils";
10
+ export function ChecklistPanel({ title, action, children }) {
11
+ 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] });
12
+ }
13
+ export function ChecklistSection({ title, progress, action, children, defaultOpen = false, open, onOpenChange }) {
14
+ return _jsxs(CollapsiblePrimitive.Root, { open: open, onOpenChange: onOpenChange, defaultOpen: defaultOpen, className: "border-b border-border last:border-0", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsxs(CollapsiblePrimitive.Trigger, { className: "group flex min-w-0 flex-1 items-center gap-1.5 py-3 text-left focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", children: [_jsx("span", { className: "text-base font-medium", children: title }), progress ? _jsx("span", { className: "text-sm text-muted-foreground", children: progress }) : null, !action ? _jsx(ChevronDown, { "aria-hidden": "true", className: "ml-auto size-4 shrink-0 text-muted-foreground transition-transform group-data-[state=open]:rotate-180" }) : null] }), action ? _jsxs(_Fragment, { children: [_jsx("div", { "data-slot": "checklist-section-action", className: "shrink-0", children: action }), _jsx(CollapsiblePrimitive.Trigger, { "aria-label": `Toggle ${title}`, className: "group py-3 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", children: _jsx(ChevronDown, { "aria-hidden": "true", className: "size-4 shrink-0 text-muted-foreground transition-transform group-data-[state=open]:rotate-180" }) })] }) : null] }), _jsx(CollapsiblePrimitive.Content, { className: "overflow-hidden data-[state=open]:animate-collapsible-down data-[state=closed]:animate-collapsible-up motion-reduce:data-[state=open]:animate-none motion-reduce:data-[state=closed]:animate-none", children: _jsx("div", { className: "flex flex-col gap-4 pb-4", children: children }) })] });
15
+ }
16
+ export function ChecklistSelection({ title, description, typeOptions, subtypeOptions, type, subtype, onTypeChange, onSubtypeChange, disabled, loading, action }) {
17
+ const Icon = loading ? LoaderCircle : ClipboardList;
18
+ 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
+ }
20
+ export function ChecklistQuestion({ label, options, value, onValueChange, disabled, remarks, onRemarksChange, remarksLimit = 500, remarksMaxLength, remarksRequired = false, evidence, evidenceCount = 0 }) {
21
+ const name = React.useId();
22
+ React.useEffect(() => { if (remarksRequired)
23
+ setShowRemarks(true); }, [remarksRequired, value]);
24
+ const [showRemarks, setShowRemarks] = React.useState(Boolean(remarks));
25
+ const [showEvidence, setShowEvidence] = React.useState(false);
26
+ return _jsxs("div", { "data-slot": "checklist-question", className: "rounded-xl border border-border bg-card p-4 shadow-xs", children: [_jsx("p", { id: `${name}-label`, className: "mb-4 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(Button, { variant: "ghost", size: "compactIcon", "aria-label": "Add remarks", disabled: disabled, onClick: () => setShowRemarks(true), children: _jsx(MessageSquareText, { "aria-hidden": "true", size: 16 }) }), _jsx(Button, { variant: "ghost", size: "compactIcon", "aria-label": "Add photos", disabled: disabled, onClick: () => setShowEvidence((open) => !open), children: _jsx(Camera, { "aria-hidden": "true", size: 16 }) })] })] }), showRemarks || remarks ? _jsx("div", { className: "mt-2 space-y-2", children: _jsxs("div", { className: "flex items-start gap-2", children: [_jsx("div", { className: "min-w-0 flex-1", children: _jsx(Textarea, { label: "Remarks", hideLabel: true, placeholder: "Type...", value: remarks, disabled: disabled, rows: 2, onChange: (event) => onRemarksChange(event.target.value), maxWords: remarksMaxLength === undefined ? remarksLimit : undefined, maxLength: remarksMaxLength, showCount: remarksMaxLength !== undefined }) }), _jsx(Button, { variant: "ghost", size: "compactIcon", "aria-label": "Remove remarks", disabled: disabled, onClick: () => { onRemarksChange(""); setShowRemarks(false); }, children: _jsx(Trash2, { "aria-hidden": "true", size: 16 }) })] }) }) : null, (showEvidence || evidenceCount > 0) && evidence ? _jsx("div", { className: "mt-2", children: evidence }) : null] });
27
+ }
28
+ export function ChecklistAttachments({ items, onRemove }) {
29
+ 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)) });
30
+ }
@@ -0,0 +1,10 @@
1
+ import * as React from "react";
2
+ export interface CompoundSearchInputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, "size"> {
3
+ /** Display a character counter when maxLength is set. */
4
+ showCount?: boolean;
5
+ actions?: React.ReactNode;
6
+ criteria?: React.ReactNode;
7
+ selected?: boolean;
8
+ }
9
+ declare const CompoundSearchInput: React.ForwardRefExoticComponent<CompoundSearchInputProps & React.RefAttributes<HTMLInputElement>>;
10
+ export { CompoundSearchInput };
@@ -0,0 +1,19 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import * as React from "react";
3
+ import { SearchIcon } from "lucide-react";
4
+ import { FieldCounter } from "./field-counter";
5
+ import { cn } from "./lib/utils";
6
+ const CompoundSearchInput = React.forwardRef(({ actions, showCount = false, value, defaultValue, onChange, "aria-invalid": ariaInvalid, className, criteria, selected = false, ...props }, ref) => {
7
+ const [uncontrolledValue, setUncontrolledValue] = React.useState(defaultValue !== null && defaultValue !== void 0 ? defaultValue : "");
8
+ const generatedId = React.useId();
9
+ const limitId = showCount && props.maxLength !== undefined ? `search-limit-${generatedId}` : undefined;
10
+ return (_jsxs("div", { className: "grid gap-2", children: [_jsxs("div", { "data-slot": "compound-search-input", "data-selected": selected ? "true" : "false", className: cn("flex min-h-12 w-full min-w-0 flex-wrap items-center gap-1.5 rounded-control border border-input bg-background p-1.5 transition-[border-color,box-shadow] focus-within:border-ring focus-within:ring-[3px] focus-within:ring-ring/50 data-[selected=true]:border-interactive data-[selected=true]:bg-highlight data-[selected=true]:ring-[3px] data-[selected=true]:ring-interactive/20", ariaInvalid === true || ariaInvalid === "true"
11
+ ? "border-destructive ring-destructive/20"
12
+ : undefined), children: [_jsx(SearchIcon, { "aria-hidden": "true", className: "ml-1.5 h-4 w-4 shrink-0 text-muted-foreground" }), criteria, _jsx("input", { ref: ref, "aria-invalid": ariaInvalid, className: cn("h-8 min-w-44 basis-52 flex-1 bg-transparent px-1.5 text-sm outline-none placeholder:text-muted-foreground", className), ...props, "aria-describedby": [props["aria-describedby"], limitId].filter(Boolean).join(" ") || undefined, value: value, defaultValue: defaultValue, onChange: (event) => {
13
+ if (value === undefined)
14
+ setUncontrolledValue(event.target.value);
15
+ onChange === null || onChange === void 0 ? void 0 : onChange(event);
16
+ } }), actions ? (_jsx("span", { className: "ml-auto inline-flex h-8 shrink-0 items-center gap-1 text-muted-foreground", children: actions })) : null] }), limitId && _jsx(FieldCounter, { id: limitId, count: String(value !== null && value !== void 0 ? value : uncontrolledValue).length, limit: props.maxLength })] }));
17
+ });
18
+ CompoundSearchInput.displayName = "CompoundSearchInput";
19
+ export { CompoundSearchInput };
@@ -164,11 +164,11 @@ const DateInput = React.forwardRef((props, ref) => {
164
164
  }
165
165
  };
166
166
  const disabledDays = (date) => isDateOutsideBounds(date, minDate, maxDate);
167
- const calendarContent = (_jsx(_Fragment, { children: props.mode === "range" ? (_jsx(Calendar, { mode: "range", selected: selectedRange, onSelect: handleRangeSelect, disabled: disabledDays, defaultMonth: (_b = selectedRange === null || selectedRange === void 0 ? void 0 : selectedRange.from) !== null && _b !== void 0 ? _b : selectedRange === null || selectedRange === void 0 ? void 0 : selectedRange.to, numberOfMonths: (_c = props.numberOfMonths) !== null && _c !== void 0 ? _c : 2, showOutsideDays: false, autoFocus: true })) : (_jsx(Calendar, { mode: "single", selected: selectedDate, onSelect: handleSelect, disabled: disabledDays, defaultMonth: selectedDate, autoFocus: true })) }));
167
+ const calendarContent = (_jsx(_Fragment, { children: props.mode === "range" ? (_jsx(Calendar, { mode: "range", selected: selectedRange, onSelect: handleRangeSelect, disabled: disabledDays, defaultMonth: (_b = selectedRange === null || selectedRange === void 0 ? void 0 : selectedRange.from) !== null && _b !== void 0 ? _b : selectedRange === null || selectedRange === void 0 ? void 0 : selectedRange.to, numberOfMonths: (_c = props.numberOfMonths) !== null && _c !== void 0 ? _c : 2, showOutsideDays: false, className: "[&_.rdp-month:not(:first-of-type)]:hidden sm:[&_.rdp-month:not(:first-of-type)]:flex", autoFocus: true })) : (_jsx(Calendar, { mode: "single", selected: selectedDate, onSelect: handleSelect, disabled: disabledDays, defaultMonth: selectedDate, autoFocus: true })) }));
168
168
  if (appearance === "inline") {
169
- return (_jsxs("span", { className: cn("inline-flex", className), "data-disabled": disabled ? "true" : undefined, "data-invalid": isInvalid ? "true" : undefined, children: [_jsx(Popover, { open: open, onOpenChange: handleOpenChange, align: "start", title: popoverTitle, surface: popoverTitle ? "menu" : "panel", contentClassName: "w-auto p-0", trigger: _jsxs("button", { ref: ref, type: "button", id: inputId, disabled: disabled, "aria-invalid": isInvalid ? "true" : undefined, "aria-describedby": [descriptionId, errorId].filter(Boolean).join(" ") || undefined, className: cn("inline-flex cursor-pointer items-baseline rounded-sm border-0 bg-transparent p-0 font-medium text-interactive underline decoration-interactive/40 underline-offset-4 transition-colors hover:decoration-interactive focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50", !displayValue && "text-muted-foreground decoration-border", isInvalid && "text-destructive decoration-destructive", triggerClassName), children: [_jsxs("span", { className: "sr-only", children: [label, ": "] }), _jsx("span", { children: displayValue !== null && displayValue !== void 0 ? displayValue : placeholder })] }), children: calendarContent }), showDescription ? (_jsx("span", { id: descriptionId, className: "sr-only", children: description })) : null, error ? (_jsx("span", { id: errorId, role: "alert", className: "sr-only", children: error })) : null] }));
169
+ return (_jsxs("span", { className: cn("inline-flex", className), "data-disabled": disabled ? "true" : undefined, "data-invalid": isInvalid ? "true" : undefined, children: [_jsx(Popover, { open: open, onOpenChange: handleOpenChange, align: "start", title: popoverTitle, surface: popoverTitle ? "menu" : "panel", collisionPadding: 8, contentClassName: "max-h-[var(--radix-popover-content-available-height)] w-auto overflow-auto p-0 [&_[data-slot=popover-title]]:p-3", trigger: _jsxs("button", { ref: ref, type: "button", id: inputId, disabled: disabled, "aria-invalid": isInvalid ? "true" : undefined, "aria-describedby": [descriptionId, errorId].filter(Boolean).join(" ") || undefined, className: cn("inline-flex cursor-pointer items-baseline rounded-sm border-0 bg-transparent p-0 font-medium text-interactive underline decoration-interactive/40 underline-offset-4 transition-colors hover:decoration-interactive focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50", !displayValue && "text-muted-foreground decoration-border", isInvalid && "text-destructive decoration-destructive", triggerClassName), children: [_jsxs("span", { className: "sr-only", children: [label, ": "] }), _jsx("span", { children: displayValue !== null && displayValue !== void 0 ? displayValue : placeholder })] }), children: calendarContent }), showDescription ? (_jsx("span", { id: descriptionId, className: "sr-only", children: description })) : null, error ? (_jsx("span", { id: errorId, role: "alert", className: "sr-only", children: error })) : null] }));
170
170
  }
171
- return (_jsxs(Field, { className: className, "data-disabled": disabled ? "true" : undefined, "data-invalid": isInvalid ? "true" : undefined, children: [_jsx(FieldLabel, { htmlFor: inputId, className: cn(hideLabel && "sr-only", labelClassName), children: label }), _jsxs("div", { className: "relative", children: [_jsx(Popover, { open: open, onOpenChange: handleOpenChange, align: "start", title: popoverTitle, surface: popoverTitle ? "menu" : "panel", contentClassName: "w-auto p-0", trigger: _jsx("button", { ref: ref, type: "button", id: inputId, disabled: disabled, "aria-invalid": isInvalid ? "true" : undefined, "aria-describedby": [descriptionId, errorId].filter(Boolean).join(" ") || undefined, className: cn(inputControlClassName, "relative cursor-pointer pr-9 text-left", showClearButton && "pr-16", !displayValue && "text-muted-foreground", isInvalid && "border-destructive focus-visible:ring-destructive", triggerClassName), children: _jsx("span", { className: "block truncate", children: displayValue !== null && displayValue !== void 0 ? displayValue : placeholder }) }), children: calendarContent }), _jsxs("span", { "aria-hidden": showClearButton ? undefined : true, className: "pointer-events-none absolute inset-y-0 right-3 flex items-center gap-2 text-muted-foreground", children: [showClearButton ? (_jsx("button", { type: "button", "aria-label": resolvedClearLabel, onClick: handleClear, className: "pointer-events-auto inline-flex h-4 w-4 cursor-pointer items-center justify-center rounded-sm text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:cursor-not-allowed", children: _jsx(XIcon, { size: 14, className: "flex items-center justify-center" }) })) : null, _jsx(CalendarIcon, { "aria-hidden": "true", className: "h-4 w-4 shrink-0", strokeWidth: 2 })] })] }), showDescription ? (_jsx(FieldDescription, { id: descriptionId, className: descriptionClassName, children: description })) : null, _jsx(FieldError, { id: errorId, className: errorClassName, children: error })] }));
171
+ return (_jsxs(Field, { className: className, "data-disabled": disabled ? "true" : undefined, "data-invalid": isInvalid ? "true" : undefined, children: [_jsx(FieldLabel, { htmlFor: inputId, className: cn(hideLabel && "sr-only", labelClassName), children: label }), _jsxs("div", { className: "relative", children: [_jsx(Popover, { open: open, onOpenChange: handleOpenChange, align: "start", title: popoverTitle, surface: popoverTitle ? "menu" : "panel", collisionPadding: 8, contentClassName: "max-h-[var(--radix-popover-content-available-height)] w-auto overflow-auto p-0 [&_[data-slot=popover-title]]:p-3", trigger: _jsx("button", { ref: ref, type: "button", id: inputId, disabled: disabled, "aria-invalid": isInvalid ? "true" : undefined, "aria-describedby": [descriptionId, errorId].filter(Boolean).join(" ") || undefined, className: cn(inputControlClassName, "relative cursor-pointer pr-9 text-left", showClearButton && "pr-16", !displayValue && "text-muted-foreground", isInvalid && "border-destructive focus-visible:ring-destructive", triggerClassName), children: _jsx("span", { className: "block truncate", children: displayValue !== null && displayValue !== void 0 ? displayValue : placeholder }) }), children: calendarContent }), _jsxs("span", { "aria-hidden": showClearButton ? undefined : true, className: "pointer-events-none absolute inset-y-0 right-3 flex items-center gap-2 text-muted-foreground", children: [showClearButton ? (_jsx("button", { type: "button", "aria-label": resolvedClearLabel, onClick: handleClear, className: "pointer-events-auto inline-flex h-4 w-4 cursor-pointer items-center justify-center rounded-sm text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:cursor-not-allowed", children: _jsx(XIcon, { size: 14, className: "flex items-center justify-center" }) })) : null, _jsx(CalendarIcon, { "aria-hidden": "true", className: "h-4 w-4 shrink-0", strokeWidth: 2 })] })] }), showDescription ? (_jsx(FieldDescription, { id: descriptionId, className: descriptionClassName, children: description })) : null, _jsx(FieldError, { id: errorId, className: errorClassName, children: error })] }));
172
172
  });
173
173
  DateInput.displayName = "DateInput";
174
174
  export { DateInput };
package/dist/dialog.d.ts CHANGED
@@ -9,6 +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
13
  open?: boolean;
13
14
  defaultOpen?: boolean;
14
15
  onOpenChange?: (open: boolean) => void;
@@ -23,6 +24,8 @@ export interface DialogProps {
23
24
  contentClassName?: string;
24
25
  bodyClassName?: string;
25
26
  hideCloseButton?: boolean;
27
+ /** Whether a pointer interaction outside the dialog closes it. */
28
+ closeOnOutsideClick?: boolean;
26
29
  }
27
- declare function Dialog({ open, defaultOpen, onOpenChange, modal, trigger, title, description, children, footer, primaryAction, secondaryAction, contentClassName, bodyClassName, hideCloseButton, }: DialogProps): import("react/jsx-runtime").JSX.Element;
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;
28
31
  export { Dialog };
package/dist/dialog.js CHANGED
@@ -3,6 +3,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
3
3
  import * as React from "react";
4
4
  import { Button } from "./button";
5
5
  import { DialogDescription, DialogFooter, DialogHeader, DialogRoot, DialogSurface, DialogTitle, DialogTrigger, } from "./dialog-primitive";
6
+ import { CircleAlert } from "lucide-react";
6
7
  import { cn } from "./lib/utils";
7
8
  function useControllableOpen({ open, defaultOpen, onOpenChange, }) {
8
9
  const [internalOpen, setInternalOpen] = React.useState(defaultOpen !== null && defaultOpen !== void 0 ? defaultOpen : false);
@@ -31,7 +32,7 @@ function renderDialogAction({ action, close, defaultVariant, }) {
31
32
  }
32
33
  }, children: label }));
33
34
  }
34
- function Dialog({ open, defaultOpen, onOpenChange, modal, trigger, title, description, children, footer, primaryAction, secondaryAction, contentClassName, bodyClassName, hideCloseButton, }) {
35
+ function Dialog({ variant = "default", open, defaultOpen, onOpenChange, modal, trigger, title, description, children, footer, primaryAction, secondaryAction, contentClassName, bodyClassName, hideCloseButton = false, closeOnOutsideClick = false, }) {
35
36
  const [isOpen, setIsOpen] = useControllableOpen({
36
37
  open,
37
38
  defaultOpen,
@@ -43,7 +44,11 @@ function Dialog({ open, defaultOpen, onOpenChange, modal, trigger, title, descri
43
44
  const body = resolveDialogRenderable(children, helpers);
44
45
  const customFooter = resolveDialogRenderable(footer, helpers);
45
46
  const hasFooter = Boolean(customFooter || primaryAction || secondaryAction);
46
- return (_jsxs(DialogRoot, { open: isOpen, onOpenChange: setIsOpen, modal: modal, children: [trigger ? _jsx(DialogTrigger, { asChild: true, children: trigger }) : null, _jsxs(DialogSurface, { className: contentClassName, hideCloseButton: hideCloseButton, children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: title }), description ? (_jsx(DialogDescription, { children: description })) : null] }), body ? _jsx("div", { className: cn("grid gap-4", bodyClassName), children: body }) : null, hasFooter ? (_jsx(DialogFooter, { children: customFooter !== null && customFooter !== void 0 ? customFooter : (_jsxs(_Fragment, { children: [secondaryAction
47
+ 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(variant === "confirmation" && "max-w-sm gap-0 overflow-hidden rounded-xl p-0", contentClassName), hideCloseButton: hideCloseButton || variant === "confirmation", onPointerDownOutside: (event) => {
48
+ if (!closeOnOutsideClick) {
49
+ event.preventDefault();
50
+ }
51
+ }, children: [_jsxs("div", { className: cn(variant === "confirmation" && "flex items-start gap-4 p-4"), children: [variant === "confirmation" ? _jsx("div", { className: "rounded-lg bg-muted p-2", children: _jsx(CircleAlert, { "aria-hidden": "true", className: "size-6" }) }) : null, _jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: title }), description ? _jsx(DialogDescription, { children: description }) : null] })] }), body ? _jsx("div", { className: cn("grid gap-4", bodyClassName), children: body }) : null, hasFooter ? (_jsx(DialogFooter, { className: variant === "confirmation" ? "border-t bg-muted/30 p-4" : undefined, children: customFooter !== null && customFooter !== void 0 ? customFooter : (_jsxs(_Fragment, { children: [secondaryAction
47
52
  ? renderDialogAction({
48
53
  action: secondaryAction,
49
54
  close: helpers.close,
@@ -3,12 +3,13 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { DndContext, closestCenter, KeyboardSensor, PointerSensor, useSensor, useSensors, } from "@dnd-kit/core";
4
4
  import { SortableContext, horizontalListSortingStrategy, sortableKeyboardCoordinates, useSortable, } from "@dnd-kit/sortable";
5
5
  import { CSS } from "@dnd-kit/utilities";
6
+ import { GripVertical } from "lucide-react";
6
7
  import { XIcon } from "./animated-icons/x";
7
8
  import { Badge } from "./badge";
8
9
  import { GuidanceTip } from "./guidance-tip";
9
10
  import { cn } from "./lib/utils";
10
11
  import { Tooltip } from "./tooltip";
11
- function TabButton({ item, dragHandleProps, }) {
12
+ function TabButton({ item, dragHandleProps, showDivider = false, }) {
12
13
  var _a, _b, _c;
13
14
  const isDraggable = Boolean(dragHandleProps);
14
15
  const labelClassName = item.labelClassName
@@ -16,17 +17,17 @@ function TabButton({ item, dragHandleProps, }) {
16
17
  : item.active
17
18
  ? "text-foreground"
18
19
  : "text-muted-foreground hover:text-foreground";
19
- const content = (_jsxs("div", { className: cn("group flex items-center gap-1.5 border-b-2 px-2.5 transition-colors select-none", item.disabled
20
+ const content = (_jsxs("div", { className: cn("group/draggable-tab relative -mb-px flex items-center gap-1.5 border-b-[3px] px-2.5 transition-colors select-none", item.disabled
20
21
  ? "cursor-not-allowed opacity-50"
21
22
  : isDraggable
22
23
  ? "cursor-grab active:cursor-grabbing"
23
24
  : "cursor-pointer", item.active
24
25
  ? (_a = item.activeClassName) !== null && _a !== void 0 ? _a : "border-[hsl(var(--tab-indicator))] bg-transparent hover:bg-transparent"
25
- : (_b = item.inactiveClassName) !== null && _b !== void 0 ? _b : "border-transparent hover:bg-[hsl(var(--tab-trigger-hover-background))]", item.className), ...dragHandleProps, children: [_jsxs("button", { type: "button", onClick: item.disabled ? undefined : item.onSelect, disabled: item.disabled, className: cn("flex cursor-pointer items-center gap-1.5 py-2 pr-1 text-sm font-medium whitespace-nowrap disabled:cursor-not-allowed", labelClassName), children: [item.badge ? (_jsx(Badge, { variant: item.badge.variant, bordered: item.badge.bordered, size: "icon", children: item.badge.label })) : null, item.leading, item.label, item.trailing] }), item.onClose ? (_jsx("button", { type: "button", onClick: (event) => {
26
+ : (_b = item.inactiveClassName) !== null && _b !== void 0 ? _b : "border-transparent hover:bg-[hsl(var(--tab-trigger-hover-background))]", item.className), ...dragHandleProps, children: [isDraggable ? (_jsx("span", { "data-slot": "draggable-tab-grip", "aria-hidden": "true", className: "pointer-events-none absolute left-0 top-1/2 z-10 inline-flex h-5 w-4 -translate-x-1/2 -translate-y-1/2 items-center justify-center rounded border border-border bg-background text-muted-foreground opacity-0 shadow-sm transition-opacity group-hover/draggable-tab:opacity-100 group-has-[:focus-visible]/draggable-tab:opacity-100", children: _jsx(GripVertical, { className: "h-3 w-3" }) })) : null, _jsxs("button", { type: "button", onClick: item.disabled ? undefined : item.onSelect, disabled: item.disabled, className: cn("flex cursor-pointer items-center gap-1.5 py-2 pr-1 text-sm font-medium whitespace-nowrap disabled:cursor-not-allowed", labelClassName), children: [item.badge ? (_jsx(Badge, { variant: item.badge.variant, bordered: item.badge.bordered, size: "icon", children: item.badge.label })) : null, item.leading, item.label, item.trailing] }), item.onClose ? (_jsx("button", { type: "button", onClick: (event) => {
26
27
  var _a;
27
28
  event.stopPropagation();
28
29
  (_a = item.onClose) === null || _a === void 0 ? void 0 : _a.call(item);
29
- }, className: cn("cursor-pointer rounded p-1 text-muted-foreground hover:text-foreground", item.closeButtonClassName), "aria-label": "Close tab", children: _jsx(XIcon, { size: 12 }) })) : null] }));
30
+ }, className: cn("cursor-pointer rounded p-1 text-muted-foreground hover:text-foreground", item.closeButtonClassName), "aria-label": "Close tab", children: _jsx(XIcon, { size: 12 }) })) : null, showDivider ? (_jsx("span", { "data-slot": "draggable-tab-divider", "aria-hidden": "true", className: "pointer-events-none absolute -right-0.5 top-1/2 h-4 w-px -translate-y-1/2 bg-[hsl(var(--layout-surface-border))]" })) : null] }));
30
31
  if (item.guidance) {
31
32
  return _jsx(GuidanceTip, { ...item.guidance, trigger: content });
32
33
  }
@@ -35,13 +36,13 @@ function TabButton({ item, dragHandleProps, }) {
35
36
  }
36
37
  return (_jsx(Tooltip, { content: item.tooltip, side: (_c = item.tooltipSide) !== null && _c !== void 0 ? _c : "bottom", contentClassName: item.tooltipContentClassName, children: content }));
37
38
  }
38
- function SortableTab({ item }) {
39
- const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({ id: item.id });
39
+ function SortableTab({ item, showDivider, }) {
40
+ const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({ id: item.id, disabled: item.disabled });
40
41
  return (_jsx("div", { ref: setNodeRef, style: {
41
42
  transform: CSS.Transform.toString(transform),
42
43
  transition,
43
44
  zIndex: isDragging ? 50 : undefined,
44
- }, className: cn(isDragging && "opacity-50 shadow-lg"), children: _jsx(TabButton, { item: item, dragHandleProps: { ...attributes, ...listeners } }) }));
45
+ }, className: cn(isDragging && "opacity-50 shadow-lg"), children: _jsx(TabButton, { item: item, showDivider: showDivider, dragHandleProps: item.disabled ? undefined : { ...attributes, ...listeners } }) }));
45
46
  }
46
47
  function DraggableTabs({ staticTabs = [], tabs, onReorder, className, ...props }) {
47
48
  const sensors = useSensors(useSensor(PointerSensor, {
@@ -61,6 +62,6 @@ function DraggableTabs({ staticTabs = [], tabs, onReorder, className, ...props }
61
62
  onReorder(oldIndex, newIndex);
62
63
  }
63
64
  };
64
- return (_jsxs("div", { "data-slot": "draggable-tabs", className: cn("flex items-end gap-1 border-b overflow-x-auto overflow-y-hidden bg-transparent", "border-[hsl(var(--layout-surface-border))]", className), ...props, children: [staticTabs.map((tab) => (_jsx(TabButton, { item: tab }, tab.id))), _jsx(DndContext, { sensors: sensors, collisionDetection: closestCenter, onDragEnd: handleDragEnd, children: _jsx(SortableContext, { items: tabs.map((tab) => tab.id), strategy: horizontalListSortingStrategy, children: tabs.map((tab) => (_jsx(SortableTab, { item: tab }, tab.id))) }) })] }));
65
+ return (_jsxs("div", { "data-slot": "draggable-tabs", className: cn("flex items-end gap-1 border-b overflow-x-auto overflow-y-hidden bg-transparent", "border-[hsl(var(--layout-surface-border))]", className), ...props, children: [staticTabs.map((tab, index) => (_jsx(TabButton, { item: tab, showDivider: index < staticTabs.length - 1 || tabs.length > 0 }, tab.id))), _jsx(DndContext, { sensors: sensors, collisionDetection: closestCenter, onDragEnd: handleDragEnd, children: _jsx(SortableContext, { items: tabs.map((tab) => tab.id), strategy: horizontalListSortingStrategy, children: tabs.map((tab, index) => (_jsx(SortableTab, { item: tab, showDivider: index < tabs.length - 1 }, tab.id))) }) })] }));
65
66
  }
66
67
  export { DraggableTabs };
@@ -8,6 +8,7 @@ import { cn } from "./lib/utils";
8
8
  const splitButtonDividerClassNames = {
9
9
  default: "before:bg-button-primary-foreground/30",
10
10
  destructive: "before:bg-destructive-foreground/30",
11
+ warning: "before:bg-[hsl(var(--status-warning-foreground))]/30",
11
12
  outline: "before:bg-[hsl(var(--button-outline-border))]",
12
13
  secondary: "before:bg-secondary-foreground/20",
13
14
  ghost: "before:bg-border",
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import * as React from "react";
3
3
  import { Button } from "./button";
4
- import { PlusIcon } from "./animated-icons/plus";
4
+ import { TableAddRow } from "./table-add-row";
5
5
  import { TrashIcon } from "./animated-icons/trash";
6
6
  import { Checkbox } from "./checkbox";
7
7
  import { EmptyState } from "./empty-state";
@@ -145,7 +145,7 @@ function EditableTable({ value, onChange, columns, isEditing = false, className,
145
145
  insertRow: (nextRow, index = rowIndex + 1) => handleInsertRow(nextRow, index),
146
146
  removeRow: () => handleDeleteRow(rowIndex),
147
147
  })
148
- : null, isEditing ? (_jsx(Button, { type: "button", variant: "ghost", size: "compactIcon", className: "text-muted-foreground hover:bg-destructive/10 hover:text-destructive focus-visible:text-destructive", onClick: () => handleDeleteRow(rowIndex), "aria-label": `Delete row ${rowIndex + 1}`, children: _jsx(TrashIcon, { size: 16 }) })) : null] }) })) : null] }, `row-${rowIndex}`)))) })] }) }), isEditing ? (_jsxs(Button, { type: "button", variant: "outline", onClick: handleAddRow, className: "w-full justify-center", children: [_jsx(PlusIcon, { size: 16 }), addRowLabel] })) : null] }));
148
+ : null, isEditing ? (_jsx(Button, { type: "button", variant: "ghost", size: "compactIcon", className: "text-muted-foreground hover:bg-destructive/10 hover:text-destructive focus-visible:text-destructive", onClick: () => handleDeleteRow(rowIndex), "aria-label": `Delete row ${rowIndex + 1}`, children: _jsx(TrashIcon, { size: 16 }) })) : null] }) })) : null] }, `row-${rowIndex}`)))) })] }) }), isEditing ? (_jsx(TableAddRow, { onClick: handleAddRow, children: addRowLabel })) : null] }));
149
149
  }
150
150
  EditableTable.displayName = "EditableTable";
151
151
  export { EditableTable };
@@ -0,0 +1,7 @@
1
+ /** Internal shared presentation for field length counters. */
2
+ export declare function FieldCounter({ id, count, limit, unit }: {
3
+ id?: string;
4
+ count: number;
5
+ limit: number;
6
+ unit?: "words" | "characters";
7
+ }): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,5 @@
1
+ import { jsxs as _jsxs } from "react/jsx-runtime";
2
+ /** Internal shared presentation for field length counters. */
3
+ export function FieldCounter({ id, count, limit, unit = "characters" }) {
4
+ return (_jsxs("div", { "data-slot": "field-counter", className: "flex items-start justify-between gap-3 text-sm text-muted-foreground", children: [_jsxs("span", { id: id, className: "sr-only", children: ["Maximum ", limit, " ", unit] }), _jsxs("span", { className: "ml-auto shrink-0 tabular-nums", "aria-live": "polite", "aria-atomic": "true", "aria-label": `${count} of ${limit} ${unit}`, children: [count, " / ", limit] })] }));
5
+ }
package/dist/index.d.ts CHANGED
@@ -7,16 +7,24 @@ export { Alert, AlertAction, AlertConsent, alertVariants, } from "./alert";
7
7
  export type { AlertActionProps, AlertConsentProps, AlertProps, } from "./alert";
8
8
  export { AlertStack } from "./alert-stack";
9
9
  export type { AlertStackProps } from "./alert-stack";
10
+ export { ActivityCard, ActivityCardActor, ActivityCardContent, } from "./activity-card";
11
+ export type { ActivityCardActorProps, ActivityCardContentProps, ActivityCardDensity, ActivityCardIconTone, ActivityCardProps, } from "./activity-card";
12
+ export { ChangelogActionPanel } from "./changelog-action-panel";
13
+ export type { ChangelogActionPanelProps } from "./changelog-action-panel";
10
14
  export { Badge, badgeVariants } from "./badge";
11
15
  export { Card, CardGrid, CardSplitGrid, CardList, CardListItem, } from "./card";
12
16
  export type { CardGridProps, CardListItemProps, CardListProps, CardProps, CardSplitGridProps, } from "./card";
13
17
  export type { BadgeProps } from "./badge";
14
- export { MessageAttachmentRow, MessageItem, MessageNewDivider, MessageThread, formatMessageDate, } from "./message-item";
18
+ export { MessageAttachmentRow, MessageItem, MessageNewDivider, MessageThread, formatMessageCardTimestamp, formatMessageDate, } from "./message-item";
15
19
  export type { MessageAttachmentRowProps, MessageItemAttachment, MessageItemData, MessageItemProps, MessageNewDividerProps, MessageThreadProps, } from "./message-item";
20
+ export { MessageActionPanel } from "./message-action-panel";
21
+ export type { MessageActionPanelProps } from "./message-action-panel";
16
22
  export { formatNotificationTimestamp, NotificationItem, NotificationList, NotificationPopover, NotificationTrigger, } from "./notification";
17
23
  export type { NotificationAction, NotificationFilter, NotificationIcon, NotificationItemData, NotificationItemProps, NotificationKind, NotificationListProps, NotificationPopoverProps, NotificationTimestamp, NotificationTriggerProps, NotificationTone, FormatNotificationTimestampOptions, } from "./notification";
18
24
  export { RoutingTimeline } from "./routing-timeline";
19
25
  export type { RoutingTimelineItem, RoutingTimelineItemKind, RoutingTimelineProps, } from "./routing-timeline";
26
+ export { RoutingActionPanel } from "./routing-action-panel";
27
+ export type { RoutingActionPanelProps } from "./routing-action-panel";
20
28
  export { RichTextEditor, formatFileSize, replaceTemplateVariables, sanitizeRichTextHtml, } from "./rich-text-editor";
21
29
  export type { AttachmentFile, RichTextEditorColor, RichTextEditorProps, RichTextEditorSendAction, RichTextEditorSendMetadata, RichTextEditorTemplate, TemplateContext, } from "./rich-text-editor";
22
30
  export { Calendar, CalendarDayButton } from "./calendar";
@@ -30,6 +38,8 @@ export { DateInput } from "./date-input";
30
38
  export type { DateInputProps, DateInputRangeProps, DateInputSingleProps, DateRangeInputValue, } from "./date-input";
31
39
  export { CountBadge } from "./count-badge";
32
40
  export type { CountBadgeProps } from "./count-badge";
41
+ export { StatusDot } from "./status-dot";
42
+ export type { StatusDotProps, StatusDotSize, StatusDotVariant, } from "./status-dot";
33
43
  export { EmptyState } from "./empty-state";
34
44
  export type { EmptyStateProps } from "./empty-state";
35
45
  export { EditableTable } from "./editable-table";
@@ -90,6 +100,10 @@ export { PopoverMenuContent, PopoverMenuCheckboxItem, PopoverMenuHeader, Popover
90
100
  export type { PopoverMenuContentProps, PopoverMenuCheckboxItemProps, PopoverMenuHeaderProps, PopoverMenuSectionProps, PopoverMenuItemProps, PopoverMenuDividerProps, PopoverMenuFooterActionProps, PopoverMenuFooterMetaProps, PopoverMenuFooterProps, PopoverMenuGroupProps, PopoverMenuGroupLabelProps, PopoverMenuSearchProps, PopoverMenuScrollAreaProps, PopoverMenuViewProps, } from "./popover-menu";
91
101
  export { SearchInput } from "./search-input";
92
102
  export type { SearchInputProps } from "./search-input";
103
+ export { CompoundSearchInput } from "./compound-search-input";
104
+ export type { CompoundSearchInputProps } from "./compound-search-input";
105
+ export { Autocomplete, AutocompleteOptions, AutocompletePopover, useAutocompleteController, } from "./autocomplete";
106
+ export type { AutocompleteController, AutocompleteControllerOptions, AutocompleteOption, AutocompleteOptionGroup, AutocompleteOptionRenderState, AutocompleteOptionsProps, AutocompletePopoverProps, AutocompleteProps, AutocompleteStateContent, } from "./autocomplete";
93
107
  export { SectionNav } from "./section-nav";
94
108
  export type { SectionNavItem, SectionNavProps } from "./section-nav";
95
109
  export { GovtMasthead } from "./govt-masthead";
@@ -111,8 +125,8 @@ export type { TextareaProps } from "./textarea";
111
125
  export { DraggableTabs, type DraggableTabBadge, type DraggableTabGuidance, type DraggableTabItem, type DraggableTabsProps, } from "./draggable-tabs";
112
126
  export { Drawer, } from "./drawer";
113
127
  export type { DrawerAction, DrawerProps, DrawerSide } from "./drawer";
114
- export { DashboardContent, DashboardLayout, DashboardRightPanel, DashboardRightPanelBody, DashboardRightPanelHeader, DashboardRightPanelSection, DashboardRightPanelTabs, DashboardSidebar, DashboardSidebarProfile, DashboardSidebarProfilePopover, SidebarProvider, useSidebar, } from "./layout";
115
- export type { DashboardContentProps, DashboardLayoutProps, DashboardRightPanelBodyProps, DashboardRightPanelHeaderProps, DashboardRightPanelMode, DashboardRightPanelProps, DashboardRightPanelSectionProps, DashboardRightPanelTabsProps, DashboardSidebarNavDropdownItem, DashboardSidebarNavGroup, DashboardSidebarNavItem, DashboardSidebarNavLinkItem, DashboardSidebarProfileProps, DashboardSidebarProfilePopoverProps, } from "./layout";
128
+ export { DashboardActionPanel, DashboardActionPanelEmptyState, DashboardContent, DashboardLayout, DashboardRightPanel, DashboardRightPanelBody, DashboardRightPanelHeader, DashboardRightPanelSection, DashboardRightPanelTabs, DashboardSidebar, DashboardSidebarProfile, DashboardSidebarProfilePopover, SidebarProvider, useSidebar, } from "./layout";
129
+ export type { DashboardActionPanelProps, DashboardActionPanelEmptyStateProps, DashboardContentProps, DashboardLayoutProps, DashboardRightPanelBodyProps, DashboardRightPanelHeaderProps, DashboardRightPanelMode, DashboardRightPanelProps, DashboardRightPanelSectionProps, DashboardRightPanelTabsProps, DashboardSidebarNavDropdownItem, DashboardSidebarNavGroup, DashboardSidebarNavItem, DashboardSidebarNavLinkItem, DashboardSidebarProfileProps, DashboardSidebarProfilePopoverProps, } from "./layout";
116
130
  export { PageHeader } from "./page-header";
117
131
  export { PageLayout, PageLayoutContext, PageLayoutControls, PageLayoutHeader, PageLayoutSection, PageLayoutStack, PageLayoutTitle, pageLayoutGapClassNames, pageLayoutStackGapClassNames, } from "./page-layout";
118
132
  export type { PageLayoutGap, PageLayoutProps, PageLayoutStackGap, PageLayoutStackProps, PageLayoutTitleProps, } from "./page-layout";
@@ -134,7 +148,7 @@ export type { TableColumnVisibilityMenuProps } from "./table-column-visibility";
134
148
  export { useTableSort } from "./use-table-sort";
135
149
  export type { UseTableSortOptions, UseTableSortReturn, } from "./use-table-sort";
136
150
  export { Table, TableRoot, TableContainer, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell, TableRowHeader, TableCaption, TableRowSkeleton, TABLE_SKELETON_PRESETS, } from "./table";
137
- export type { TableColumn, TableColumnWidths, TableProps, TableResizeMode, TableRowExpansionProps, TableRowTone, TableSortDirection, TableSortingProps, TableSkeletonConfig, TableRowSkeletonProps, } from "./table";
151
+ export type { TableColumn, TableColumnWidths, TableProps, TableResizeMode, TableRowExpansionProps, TableRowIndicatorProps, TableRowTone, TableSortDirection, TableSortingProps, TableSkeletonConfig, TableRowSkeletonProps, } from "./table";
138
152
  export type { TableColumnFilter, TableColumnFilterOption, TableDateColumnFilter, TableDateRangeColumnFilter, TableOptionsColumnFilter, TableTextColumnFilter, } from "./table-column-filter";
139
153
  export { Tabs, SubTabs, TabsRoot, TabWithDropdown, type TabsItem, type TabsItemLabel, type TabsItemLabelProps, type TabsProps, type SubTabsItem, type SubTabsProps, TabsList, TabsTrigger, TabsContent, type TabWithDropdownProps, useTabsContext, type TabDropdownSection, } from "./tabs";
140
154
  export { Tooltip, TooltipRoot, TooltipTrigger, TooltipContent, TooltipProvider, type TooltipProps, } from "./tooltip";
@@ -153,3 +167,7 @@ export type { CollapsibleProps } from "./collapsible";
153
167
  export { cn } from "./lib/utils";
154
168
  export { parseDateTime, formatDateTime } from "./lib/date-utils";
155
169
  export type { ParseDateTimeOptions } from "./lib/date-utils";
170
+ export { ChecklistAttachments, ChecklistPanel, ChecklistSection, ChecklistSelection, ChecklistQuestion } from "./checklist";
171
+ export type { ChecklistAttachmentsProps, ChecklistPanelProps, ChecklistSectionProps, ChecklistSelectionProps, ChecklistQuestionProps, ChecklistQuestionOption } from "./checklist";
172
+ export { TableAddRow, type TableAddRowProps } from "./table-add-row";
173
+ export { PopoverList, type PopoverListProps } from "./popover";
package/dist/index.js CHANGED
@@ -3,11 +3,15 @@ export { AvatarProfilePopover, AvatarProfilePopoverContent, AvatarProfilePopover
3
3
  export * from "./animated-icons";
4
4
  export { Alert, AlertAction, AlertConsent, alertVariants, } from "./alert";
5
5
  export { AlertStack } from "./alert-stack";
6
+ export { ActivityCard, ActivityCardActor, ActivityCardContent, } from "./activity-card";
7
+ export { ChangelogActionPanel } from "./changelog-action-panel";
6
8
  export { Badge, badgeVariants } from "./badge";
7
9
  export { Card, CardGrid, CardSplitGrid, CardList, CardListItem, } from "./card";
8
- export { MessageAttachmentRow, MessageItem, MessageNewDivider, MessageThread, formatMessageDate, } from "./message-item";
10
+ export { MessageAttachmentRow, MessageItem, MessageNewDivider, MessageThread, formatMessageCardTimestamp, formatMessageDate, } from "./message-item";
11
+ export { MessageActionPanel } from "./message-action-panel";
9
12
  export { formatNotificationTimestamp, NotificationItem, NotificationList, NotificationPopover, NotificationTrigger, } from "./notification";
10
13
  export { RoutingTimeline } from "./routing-timeline";
14
+ export { RoutingActionPanel } from "./routing-action-panel";
11
15
  export { RichTextEditor, formatFileSize, replaceTemplateVariables, sanitizeRichTextHtml, } from "./rich-text-editor";
12
16
  export { Calendar, CalendarDayButton } from "./calendar";
13
17
  export { Checkbox } from "./checkbox";
@@ -15,6 +19,7 @@ export { Switch } from "./switch";
15
19
  export { ThemeSwitcher } from "./theme-switcher";
16
20
  export { DateInput } from "./date-input";
17
21
  export { CountBadge } from "./count-badge";
22
+ export { StatusDot } from "./status-dot";
18
23
  export { EmptyState } from "./empty-state";
19
24
  export { EditableTable } from "./editable-table";
20
25
  export { EditButton } from "./edit-button";
@@ -46,6 +51,8 @@ export { useFileUpload } from "./use-file-upload";
46
51
  export { Popover, PopoverTitle } from "./popover";
47
52
  export { PopoverMenuContent, PopoverMenuCheckboxItem, PopoverMenuHeader, PopoverMenuSection, PopoverMenuItem, PopoverMenuDivider, PopoverMenuFooter, PopoverMenuFooterAction, PopoverMenuFooterMeta, PopoverMenuGroup, PopoverMenuGroupLabel, PopoverMenuSearch, PopoverMenuScrollArea, PopoverMenuView, } from "./popover-menu";
48
53
  export { SearchInput } from "./search-input";
54
+ export { CompoundSearchInput } from "./compound-search-input";
55
+ export { Autocomplete, AutocompleteOptions, AutocompletePopover, useAutocompleteController, } from "./autocomplete";
49
56
  export { SectionNav } from "./section-nav";
50
57
  export { GovtMasthead } from "./govt-masthead";
51
58
  export { GuidanceTip } from "./guidance-tip";
@@ -57,7 +64,7 @@ export { useViewportThreshold } from "./use-viewport-threshold";
57
64
  export { Textarea } from "./textarea";
58
65
  export { DraggableTabs, } from "./draggable-tabs";
59
66
  export { Drawer, } from "./drawer";
60
- export { DashboardContent, DashboardLayout, DashboardRightPanel, DashboardRightPanelBody, DashboardRightPanelHeader, DashboardRightPanelSection, DashboardRightPanelTabs, DashboardSidebar, DashboardSidebarProfile, DashboardSidebarProfilePopover, SidebarProvider, useSidebar, } from "./layout";
67
+ export { DashboardActionPanel, DashboardActionPanelEmptyState, DashboardContent, DashboardLayout, DashboardRightPanel, DashboardRightPanelBody, DashboardRightPanelHeader, DashboardRightPanelSection, DashboardRightPanelTabs, DashboardSidebar, DashboardSidebarProfile, DashboardSidebarProfilePopover, SidebarProvider, useSidebar, } from "./layout";
61
68
  export { PageHeader } from "./page-header";
62
69
  export { PageLayout, PageLayoutContext, PageLayoutControls, PageLayoutHeader, PageLayoutSection, PageLayoutStack, PageLayoutTitle, pageLayoutGapClassNames, pageLayoutStackGapClassNames, } from "./page-layout";
63
70
  export { WorkspaceHeader } from "./workspace-header";
@@ -80,3 +87,6 @@ export { Spinner, PageLoader, FullPageLoader } from "./spinner";
80
87
  export { Collapsible, CollapsibleSection } from "./collapsible";
81
88
  export { cn } from "./lib/utils";
82
89
  export { parseDateTime, formatDateTime } from "./lib/date-utils";
90
+ export { ChecklistAttachments, ChecklistPanel, ChecklistSection, ChecklistSelection, ChecklistQuestion } from "./checklist";
91
+ export { TableAddRow } from "./table-add-row";
92
+ export { PopoverList } from "./popover";
package/dist/input.d.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  import * as React from "react";
2
2
  import { InputControl } from "./input-control";
3
3
  export interface InputProps extends Omit<React.ComponentProps<typeof InputControl>, "className"> {
4
+ /** Display a character counter when maxLength is set. */
5
+ showCount?: boolean;
4
6
  label: React.ReactNode;
5
7
  description?: React.ReactNode;
6
8
  error?: React.ReactNode;
package/dist/input.js CHANGED
@@ -2,10 +2,14 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import * as React from "react";
3
3
  import { Field, FieldDescription, FieldError, FieldLabel } from "./field";
4
4
  import { InputControl } from "./input-control";
5
+ import { FieldCounter } from "./field-counter";
5
6
  import { cn } from "./lib/utils";
6
- const Input = React.forwardRef(({ label, description, error, invalid = false, hideLabel = false, className, inputClassName, labelClassName, descriptionClassName, errorClassName, id, disabled, "aria-invalid": ariaInvalid, "aria-describedby": ariaDescribedBy, required, ...props }, ref) => {
7
+ const Input = React.forwardRef(({ label, showCount = false, value, defaultValue, onChange, description, error, invalid = false, hideLabel = false, className, inputClassName, labelClassName, descriptionClassName, errorClassName, id, disabled, "aria-invalid": ariaInvalid, "aria-describedby": ariaDescribedBy, required, ...props }, ref) => {
8
+ const [uncontrolledValue, setUncontrolledValue] = React.useState(defaultValue !== null && defaultValue !== void 0 ? defaultValue : "");
9
+ const count = String(value !== null && value !== void 0 ? value : uncontrolledValue).length;
7
10
  const generatedId = React.useId();
8
11
  const inputId = id !== null && id !== void 0 ? id : `input-${generatedId}`;
12
+ const limitId = showCount && props.maxLength !== undefined ? `${inputId}-limit` : undefined;
9
13
  const errorId = error ? `${inputId}-error` : undefined;
10
14
  const showDescription = Boolean(description) && !error;
11
15
  const descriptionId = showDescription ? `${inputId}-description` : undefined;
@@ -13,10 +17,14 @@ const Input = React.forwardRef(({ label, description, error, invalid = false, hi
13
17
  ariaInvalid === true ||
14
18
  ariaInvalid === "true" ||
15
19
  Boolean(error);
16
- const describedBy = [ariaDescribedBy, descriptionId, errorId]
20
+ const describedBy = [ariaDescribedBy, descriptionId, errorId, limitId]
17
21
  .filter(Boolean)
18
22
  .join(" ") || undefined;
19
- return (_jsxs(Field, { className: className, "data-disabled": disabled ? "true" : undefined, "data-invalid": isInvalid ? "true" : undefined, children: [_jsx(FieldLabel, { htmlFor: inputId, required: required, className: cn(hideLabel && "sr-only", labelClassName), children: label }), _jsx(InputControl, { ref: ref, id: inputId, disabled: disabled, required: required, "aria-invalid": isInvalid ? "true" : undefined, "aria-describedby": describedBy, className: inputClassName, ...props }), showDescription ? (_jsx(FieldDescription, { id: descriptionId, className: descriptionClassName, children: description })) : null, _jsx(FieldError, { id: errorId, className: errorClassName, children: error })] }));
23
+ return (_jsxs(Field, { className: className, "data-disabled": disabled ? "true" : undefined, "data-invalid": isInvalid ? "true" : undefined, children: [_jsx(FieldLabel, { htmlFor: inputId, required: required, className: cn(hideLabel && "sr-only", labelClassName), children: label }), _jsx(InputControl, { ref: ref, id: inputId, disabled: disabled, required: required, "aria-invalid": isInvalid ? "true" : undefined, "aria-describedby": describedBy, className: inputClassName, ...props, value: value, defaultValue: defaultValue, onChange: (event) => {
24
+ if (value === undefined)
25
+ setUncontrolledValue(event.target.value);
26
+ onChange === null || onChange === void 0 ? void 0 : onChange(event);
27
+ } }), showDescription ? (_jsx(FieldDescription, { id: descriptionId, className: descriptionClassName, children: description })) : null, limitId && _jsx(FieldCounter, { id: limitId, count: count, limit: props.maxLength }), _jsx(FieldError, { id: errorId, className: errorClassName, children: error })] }));
20
28
  });
21
29
  Input.displayName = "Input";
22
30
  export { Input };