@neasg/design-system 0.4.139 → 0.4.144

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
@@ -25,7 +25,7 @@ const Alert = React.forwardRef(({ variant, title, description, icon, action, cla
25
25
  const Icon = icon !== null && icon !== void 0 ? icon : (variant === "destructive" ? CircleAlert : undefined);
26
26
  const body = description !== null && description !== void 0 ? description : children;
27
27
  const hasStackedContent = Boolean(title);
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] }));
28
+ return (_jsxs("div", { ref: ref, role: role, className: cn(alertVariants({ variant }), className), ...props, children: [Icon ? (_jsx(Icon, { className: "mt-0.5 h-4 w-4 shrink-0" })) : 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] }));
29
29
  });
30
30
  Alert.displayName = "Alert";
31
31
  const AlertConsent = React.forwardRef(({ variant = "success", checked, defaultChecked, disabled, required, name, value, checkboxId, checkboxClassName, label, description, onCheckedChange, role = "status", className, ...props }, ref) => (_jsx(Alert, { ref: ref, variant: variant, role: role, className: cn("items-start", className), description: _jsx(Checkbox, { id: checkboxId, name: name, value: value, checked: checked, defaultChecked: defaultChecked, disabled: disabled, required: required, onChange: (event) => onCheckedChange === null || onCheckedChange === void 0 ? void 0 : onCheckedChange(event.target.checked), className: cn("[&>span:first-child]:mt-0.5", checkboxClassName), labelAlign: "start", label: label, description: description }), ...props })));
@@ -1,3 +1,4 @@
1
+ import * as React from "react";
1
2
  export interface AssigneeOption {
2
3
  value: string;
3
4
  label: string;
@@ -24,5 +25,18 @@ export interface AssigneePopoverProps {
24
25
  groupLabel?: string;
25
26
  searchPlaceholder?: string;
26
27
  emptyMessage?: string;
28
+ trigger?: React.ReactElement;
29
+ open?: boolean;
30
+ onOpenChange?: (open: boolean) => void;
31
+ align?: "start" | "center" | "end";
32
+ /** Keep the menu open while the consumer completes an asynchronous assignment. */
33
+ closeOnSelect?: boolean;
34
+ showSearch?: boolean;
35
+ actions?: Array<{
36
+ label: string;
37
+ icon?: React.ReactNode;
38
+ onSelect: () => void;
39
+ disabled?: boolean;
40
+ }>;
27
41
  }
28
- export declare function AssigneePopover({ options, value, onValueChange, currentUserValue, disabled, placeholder, highlightQuery, triggerAriaLabel, menuLabel, selfOptionLabel, groupLabel, searchPlaceholder, emptyMessage, }: AssigneePopoverProps): import("react/jsx-runtime").JSX.Element;
42
+ export declare function AssigneePopover({ options, value, onValueChange, currentUserValue, disabled, placeholder, highlightQuery, triggerAriaLabel, menuLabel, selfOptionLabel, groupLabel, searchPlaceholder, emptyMessage, trigger, open: controlledOpen, onOpenChange, align, closeOnSelect, showSearch, actions, }: AssigneePopoverProps): import("react/jsx-runtime").JSX.Element;
@@ -12,10 +12,22 @@ function Profile({ option, label = option.label, query = "" }) {
12
12
  var _a;
13
13
  return _jsx(AvatarProfile, { size: "xs", src: option.avatarSrc, alt: option.label, fallback: (_a = option.initials) !== null && _a !== void 0 ? _a : option.label.trim().split(/\s+/).slice(0, 2).map((word) => { var _a; return (_a = word[0]) === null || _a === void 0 ? void 0 : _a.toUpperCase(); }).join(""), name: _jsx(SearchHighlight, { text: label, query: query }), role: option.role, rolePlacement: "below", className: "min-w-0 max-w-full" });
14
14
  }
15
- export function AssigneePopover({ options, value, onValueChange, currentUserValue, disabled = false, placeholder = "Unassigned", highlightQuery, triggerAriaLabel, menuLabel = "Assign to", selfOptionLabel = "Assign to myself", groupLabel = "People", searchPlaceholder = "Search people...", emptyMessage = "No matching people", }) {
15
+ export function AssigneePopover({ options, value, onValueChange, currentUserValue, disabled = false, placeholder = "Unassigned", highlightQuery, triggerAriaLabel, menuLabel = "Assign to", selfOptionLabel = "Assign to myself", groupLabel = "People", searchPlaceholder = "Search people...", emptyMessage = "No matching people", trigger, open: controlledOpen, onOpenChange, align = "start", closeOnSelect = true, showSearch = true, actions = [], }) {
16
16
  var _a;
17
- const [open, setOpen] = React.useState(false);
17
+ const [internalOpen, setInternalOpen] = React.useState(false);
18
+ const open = controlledOpen !== null && controlledOpen !== void 0 ? controlledOpen : internalOpen;
18
19
  const [search, setSearch] = React.useState("");
20
+ const changeOpen = (nextOpen) => {
21
+ if (controlledOpen === undefined)
22
+ setInternalOpen(nextOpen);
23
+ if (!nextOpen)
24
+ setSearch("");
25
+ onOpenChange === null || onOpenChange === void 0 ? void 0 : onOpenChange(nextOpen);
26
+ };
27
+ React.useEffect(() => {
28
+ if (!open)
29
+ setSearch("");
30
+ }, [open]);
19
31
  const selected = (_a = options.find((option) => option.value === value)) !== null && _a !== void 0 ? _a : { value, label: value || placeholder };
20
32
  const currentUser = options.find((option) => option.value === currentUserValue);
21
33
  const query = search.trim().toLowerCase();
@@ -38,12 +50,9 @@ export function AssigneePopover({ options, value, onValueChange, currentUserValu
38
50
  if (disabled || option.disabled)
39
51
  return;
40
52
  onValueChange(option.value);
41
- setOpen(false);
42
- setSearch("");
53
+ if (closeOnSelect)
54
+ changeOpen(false);
43
55
  };
44
- return _jsxs(Popover, { open: open && !disabled, onOpenChange: (nextOpen) => {
45
- setOpen(nextOpen);
46
- if (!nextOpen)
47
- setSearch("");
48
- }, surface: "menu", align: "start", contentClassName: "w-72", trigger: _jsx(Button, { type: "button", variant: "ghost", size: "default", disabled: disabled, className: "flex h-auto min-w-0 max-w-full justify-start whitespace-normal text-left leading-none", "aria-label": triggerAriaLabel !== null && triggerAriaLabel !== void 0 ? triggerAriaLabel : `Change assignee: ${selected.label}`, onClick: (event) => event.stopPropagation(), children: _jsx(Profile, { option: selected, query: highlightQuery }) }), children: [_jsxs(PopoverMenuGroup, { children: [_jsx(PopoverMenuGroupLabel, { children: menuLabel }), currentUser ? _jsx(PopoverMenuSection, { children: _jsxs(PopoverMenuItem, { active: value === currentUser.value, disabled: currentUser.disabled, onClick: () => select(currentUser), children: [_jsx(UserPlus, { "aria-hidden": "true", className: "size-4" }), _jsx("span", { children: selfOptionLabel })] }) }) : null] }), _jsx(PopoverMenuDivider, {}), _jsx(PopoverMenuSearch, { value: search, onChange: (event) => setSearch(event.target.value), placeholder: searchPlaceholder, "aria-label": searchPlaceholder, className: "h-control border-0 bg-transparent px-2 py-0 text-sm shadow-none", autoFocus: true }), _jsxs(PopoverMenuScrollArea, { children: [groups.map((group) => _jsxs(PopoverMenuGroup, { children: [_jsx(PopoverMenuGroupLabel, { children: group.label }), _jsx(PopoverMenuSection, { children: group.options.map((option) => _jsx(PopoverMenuItem, { active: value === option.value, disabled: option.disabled, onClick: () => select(option), children: _jsx(Profile, { option: option, query: search }) }, option.value)) })] }, group.label)), filtered.length === 0 ? _jsx(Typography, { as: "p", variant: "bodySm", className: "px-2 py-3 text-muted-foreground", role: "status", children: emptyMessage }) : null] })] });
56
+ return _jsxs(Popover, { open: open && !disabled, onOpenChange: changeOpen, surface: "menu", align: align, contentClassName: "w-72", trigger: trigger !== null && trigger !== void 0 ? trigger : (_jsx(Button, { type: "button", variant: "ghost", size: "default", disabled: disabled, className: "flex h-auto min-w-0 max-w-full justify-start whitespace-normal text-left leading-none", "aria-label": triggerAriaLabel !== null && triggerAriaLabel !== void 0 ? triggerAriaLabel : `Change assignee: ${selected.label}`, onClick: (event) => event.stopPropagation(), children: _jsx(Profile, { option: selected, query: highlightQuery }) })), children: [(currentUser || actions.length > 0) ? _jsxs(PopoverMenuGroup, { children: [_jsx(PopoverMenuGroupLabel, { children: menuLabel }), _jsxs(PopoverMenuSection, { children: [currentUser ?
57
+ _jsxs(PopoverMenuItem, { active: value === currentUser.value, disabled: currentUser.disabled, onClick: () => select(currentUser), children: [_jsx(UserPlus, { "aria-hidden": "true", className: "size-4" }), _jsx("span", { children: selfOptionLabel })] }) : null, actions.map((action) => _jsxs(PopoverMenuItem, { disabled: action.disabled, onClick: action.onSelect, children: [action.icon, action.label] }, action.label))] })] }) : null, (currentUser || actions.length > 0) && (showSearch || options.length > 0) ? _jsx(PopoverMenuDivider, {}) : null, showSearch ? _jsx(PopoverMenuSearch, { value: search, onChange: (event) => setSearch(event.target.value), placeholder: searchPlaceholder, "aria-label": searchPlaceholder, className: "h-control border-0 bg-transparent px-2 py-0 text-sm shadow-none", autoFocus: true }) : null, (showSearch || options.length > 0) ? _jsxs(PopoverMenuScrollArea, { children: [groups.map((group) => _jsxs(PopoverMenuGroup, { children: [_jsx(PopoverMenuGroupLabel, { children: group.label }), _jsx(PopoverMenuSection, { children: group.options.map((option) => _jsx(PopoverMenuItem, { active: value === option.value, disabled: option.disabled, onClick: () => select(option), children: _jsx(Profile, { option: option, query: search }) }, option.value)) })] }, group.label)), filtered.length === 0 ? _jsx(Typography, { as: "p", variant: "bodySm", className: "px-2 py-3 text-muted-foreground", role: "status", children: emptyMessage }) : null] }) : null] });
49
58
  }
@@ -49,12 +49,13 @@ export interface ChecklistQuestionProps {
49
49
  remarksMaxLength?: number;
50
50
  remarksRequired?: boolean;
51
51
  remarksDescription?: React.ReactNode;
52
+ remarksPlaceholder?: string;
52
53
  remarksOpen?: boolean;
53
54
  onRemarksOpenChange?: (open: boolean) => void;
54
55
  evidence?: React.ReactNode;
55
56
  evidenceCount?: number;
56
57
  }
57
- export declare function ChecklistQuestion({ label, options, value, onValueChange, disabled, remarks, onRemarksChange, remarksLimit, remarksMaxLength, remarksRequired, remarksDescription, remarksOpen, onRemarksOpenChange, evidence, evidenceCount }: ChecklistQuestionProps): import("react/jsx-runtime").JSX.Element;
58
+ export declare function ChecklistQuestion({ label, options, value, onValueChange, disabled, remarks, onRemarksChange, remarksLimit, remarksMaxLength, remarksRequired, remarksDescription, remarksPlaceholder, remarksOpen, onRemarksOpenChange, evidence, evidenceCount }: ChecklistQuestionProps): import("react/jsx-runtime").JSX.Element;
58
59
  export interface ChecklistAttachmentsProps {
59
60
  items: {
60
61
  key: string;
package/dist/checklist.js CHANGED
@@ -19,7 +19,7 @@ export function ChecklistSelection({ title, description, typeOptions, subtypeOpt
19
19
  const Icon = loading ? LoaderCircle : ClipboardList;
20
20
  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(--space-2)] 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] });
21
21
  }
22
- export function ChecklistQuestion({ label, options, value, onValueChange, disabled, remarks, onRemarksChange, remarksLimit = 500, remarksMaxLength, remarksRequired = false, remarksDescription, remarksOpen, onRemarksOpenChange, evidence, evidenceCount = 0 }) {
22
+ export function ChecklistQuestion({ label, options, value, onValueChange, disabled, remarks, onRemarksChange, remarksLimit = 500, remarksMaxLength, remarksRequired = false, remarksDescription, remarksPlaceholder = "Type...", remarksOpen, onRemarksOpenChange, evidence, evidenceCount = 0 }) {
23
23
  var _a;
24
24
  const name = React.useId();
25
25
  const [internalRemarksOpen, setInternalRemarksOpen] = React.useState(null);
@@ -35,7 +35,7 @@ export function ChecklistQuestion({ label, options, value, onValueChange, disabl
35
35
  const evidenceVisible = disabled ? evidenceCount > 0 : showEvidence;
36
36
  const remarksToggleLabel = showRemarks ? "Hide remarks" : "Show remarks";
37
37
  const evidenceToggleLabel = showEvidence ? "Hide photos" : "Show photos";
38
- 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-pointer opacity-0 disabled:cursor-not-allowed", 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: () => setRemarksOpen(!showRemarks), 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: () => setEvidenceOpen(!showEvidence), 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", description: remarksDescription, placeholder: "Type...", value: remarks, "aria-required": remarksRequired, rows: 5, onChange: (event) => { setRemarksOpen(true); onRemarksChange(event.target.value); }, maxWords: remarksMaxLength === undefined ? remarksLimit : undefined, maxLength: remarksMaxLength, showCount: remarksMaxLength !== undefined }) }) : null] });
38
+ 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-pointer opacity-0 disabled:cursor-not-allowed", 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: () => setRemarksOpen(!showRemarks), 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: () => setEvidenceOpen(!showEvidence), 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", description: remarksDescription, placeholder: remarksPlaceholder, value: remarks, "aria-required": remarksRequired, rows: 5, onChange: (event) => { setRemarksOpen(true); onRemarksChange(event.target.value); }, maxWords: remarksMaxLength === undefined ? remarksLimit : undefined, maxLength: remarksMaxLength, showCount: remarksMaxLength !== undefined }) }) : null] });
39
39
  }
40
40
  export function ChecklistAttachments({ items, onRemove }) {
41
41
  return _jsx("ul", { className: "space-y-2", children: items.map((item) => _jsx(FileUploadStatusRow, { file: { name: item.name, type: item.type, size: item.sizeBytes || item.size, status: "complete" }, href: item.url, onRemove: onRemove ? () => onRemove(item.key) : undefined }, item.key)) });
package/dist/index.d.ts CHANGED
@@ -18,12 +18,10 @@ export type { CardGridProps, CardListItemProps, CardListProps, CardProps, CardSp
18
18
  export type { BadgeProps } from "./badge";
19
19
  export { MessageAttachmentRow, MessageItem, MessageNewDivider, MessageThread, formatMessageCardTimestamp, formatMessageDate, } from "./message-item";
20
20
  export type { MessageAttachmentRowProps, MessageItemAttachment, MessageItemData, MessageItemProps, MessageNewDividerProps, MessageThreadProps, } from "./message-item";
21
- export { MessageActionPanel } from "./message-action-panel";
22
- export type { MessageActionPanelProps } from "./message-action-panel";
21
+ export { MessageActionPanel, MessageActionPanelContent, } from "./message-action-panel";
22
+ export type { MessageActionPanelContentProps, MessageActionPanelProps, } from "./message-action-panel";
23
23
  export { formatNotificationTimestamp, NotificationItem, NotificationList, NotificationPopover, NotificationTrigger, } from "./notification";
24
24
  export type { NotificationAction, NotificationFilter, NotificationIcon, NotificationItemData, NotificationItemProps, NotificationKind, NotificationListProps, NotificationPopoverProps, NotificationTimestamp, NotificationTriggerProps, NotificationTone, FormatNotificationTimestampOptions, } from "./notification";
25
- export { RoutingActionPanel } from "./routing-action-panel";
26
- export type { RoutingActionPanelProps } from "./routing-action-panel";
27
25
  export { RichTextEditor, formatFileSize, replaceTemplateVariables, sanitizeRichTextHtml, } from "./rich-text-editor";
28
26
  export type { AttachmentFile, RichTextEditorColor, RichTextEditorProps, RichTextEditorSendAction, RichTextEditorSendMetadata, RichTextEditorTemplate, TemplateContext, } from "./rich-text-editor";
29
27
  export { Calendar, CalendarDayButton } from "./calendar";
package/dist/index.js CHANGED
@@ -9,9 +9,8 @@ export { ChangelogActionPanel } from "./changelog-action-panel";
9
9
  export { Badge, badgeVariants } from "./badge";
10
10
  export { Card, CardGrid, CardSplitGrid, CardList, CardListItem, } from "./card";
11
11
  export { MessageAttachmentRow, MessageItem, MessageNewDivider, MessageThread, formatMessageCardTimestamp, formatMessageDate, } from "./message-item";
12
- export { MessageActionPanel } from "./message-action-panel";
12
+ export { MessageActionPanel, MessageActionPanelContent, } from "./message-action-panel";
13
13
  export { formatNotificationTimestamp, NotificationItem, NotificationList, NotificationPopover, NotificationTrigger, } from "./notification";
14
- export { RoutingActionPanel } from "./routing-action-panel";
15
14
  export { RichTextEditor, formatFileSize, replaceTemplateVariables, sanitizeRichTextHtml, } from "./rich-text-editor";
16
15
  export { Calendar, CalendarDayButton } from "./calendar";
17
16
  export { Checkbox } from "./checkbox";
@@ -1,12 +1,19 @@
1
1
  import * as React from "react";
2
- import { type DashboardActionPanelProps } from "./layout";
2
+ import { type DashboardActionPanelProps, type DashboardRightPanelBodyProps } from "./layout";
3
3
  export interface MessageActionPanelProps extends Omit<DashboardActionPanelProps, "children" | "headerSpacing" | "title"> {
4
4
  title?: React.ReactNode;
5
5
  children: React.ReactNode;
6
6
  }
7
+ export interface MessageActionPanelContentProps extends Omit<DashboardRightPanelBodyProps, "footerVariant" | "spacing" | "topInset"> {
8
+ }
7
9
  /**
8
10
  * Shared message-panel frame. Message data and composer behaviour remain with
9
11
  * the consuming application while this component keeps the panel UI stable.
10
12
  */
11
13
  declare function MessageActionPanel({ title, subtitle, children, ...panelProps }: MessageActionPanelProps): import("react/jsx-runtime").JSX.Element;
12
- export { MessageActionPanel };
14
+ /**
15
+ * Canonical message-panel body. It owns the scrolling content and separated
16
+ * composer footer so Case and Inspection do not reconstruct panel spacing.
17
+ */
18
+ declare function MessageActionPanelContent({ children, ...bodyProps }: MessageActionPanelContentProps): import("react/jsx-runtime").JSX.Element;
19
+ export { MessageActionPanel, MessageActionPanelContent };
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
  import { jsx as _jsx } from "react/jsx-runtime";
3
- import { DashboardActionPanel, } from "./layout";
3
+ import { DashboardActionPanel, DashboardRightPanelBody, } from "./layout";
4
4
  /**
5
5
  * Shared message-panel frame. Message data and composer behaviour remain with
6
6
  * the consuming application while this component keeps the panel UI stable.
@@ -8,4 +8,11 @@ import { DashboardActionPanel, } from "./layout";
8
8
  function MessageActionPanel({ title = "Messages", subtitle = "Find all correspondence here.", children, ...panelProps }) {
9
9
  return (_jsx(DashboardActionPanel, { headerSpacing: "comfortable", title: title, subtitle: subtitle, ...panelProps, children: children }));
10
10
  }
11
- export { MessageActionPanel };
11
+ /**
12
+ * Canonical message-panel body. It owns the scrolling content and separated
13
+ * composer footer so Case and Inspection do not reconstruct panel spacing.
14
+ */
15
+ function MessageActionPanelContent({ children, ...bodyProps }) {
16
+ return (_jsx(DashboardRightPanelBody, { spacing: "comfortable", topInset: "none", footerVariant: "separated", ...bodyProps, children: children }));
17
+ }
18
+ export { MessageActionPanel, MessageActionPanelContent };
@@ -3,7 +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 { FileText, Laptop, Paperclip } from "lucide-react";
5
5
  import { DownloadIcon } from "./animated-icons";
6
- import { Avatar, AvatarProfile } from "./avatar";
6
+ import { AvatarProfile } from "./avatar";
7
7
  import { Badge } from "./badge";
8
8
  import { formatNotificationTimestamp } from "./notification";
9
9
  import { Separator } from "./separator";
@@ -204,7 +204,7 @@ export function MessageItem({ message, caseId, showNewBadge = false, newMessageL
204
204
  const messageDate = (_a = message.sentAt) !== null && _a !== void 0 ? _a : message.createdAt;
205
205
  const downloadCaseId = caseId !== null && caseId !== void 0 ? caseId : message.caseId;
206
206
  const contentHtml = toHtmlContent(message.content);
207
- const richContentClassName = cn("break-words", variant === "default" && "leading-6", "[&_p]:my-0 [&_p+p]:mt-2", "[&_ul]:my-2 [&_ul]:list-disc [&_ul]:pl-5", "[&_ol]:my-2 [&_ol]:list-decimal [&_ol]:pl-5", "[&_li]:my-1", "[&_a]:text-interactive [&_a]:underline [&_a:hover]:text-interactive", "[&_h1]:mb-2 [&_h1]:mt-3 [&_h1]:text-xl [&_h1]:font-semibold", "[&_h2]:mb-2 [&_h2]:mt-3 [&_h2]:text-lg [&_h2]:font-semibold", "[&_h3]:mb-1.5 [&_h3]:mt-3 [&_h3]:text-base [&_h3]:font-semibold", "[&_h4]:mb-1.5 [&_h4]:mt-3 [&_h4]:font-semibold", "[&_h5]:mb-1.5 [&_h5]:mt-3 [&_h5]:font-semibold", "[&_h6]:mb-1.5 [&_h6]:mt-3 [&_h6]:font-semibold", "[&_blockquote]:my-2 [&_blockquote]:border-l-2 [&_blockquote]:border-border [&_blockquote]:pl-3 [&_blockquote]:text-muted-foreground", "[&_table]:my-2 [&_table]:w-full [&_table]:border-collapse", "[&_td]:border [&_td]:border-border [&_td]:p-2", "[&_th]:border [&_th]:border-border [&_th]:bg-[hsl(var(--table-header-background))] [&_th]:p-2 [&_th]:font-semibold", "[&_pre]:my-2 [&_pre]:overflow-x-auto [&_pre]:rounded-md [&_pre]:bg-muted [&_pre]:p-3 [&_pre]:font-mono [&_pre]:text-[0.85em]", "[&_code]:rounded [&_code]:bg-muted [&_code]:px-1 [&_code]:py-0.5 [&_code]:font-mono [&_code]:text-[0.85em]", "[&_pre_code]:bg-transparent [&_pre_code]:p-0", "[&_mark]:rounded-sm [&_mark]:bg-[hsl(var(--status-warning))] [&_mark]:px-0.5 [&_mark]:text-[hsl(var(--status-warning-foreground))]", "[&_img]:h-auto [&_img]:max-w-full", contentClassName);
207
+ const richContentClassName = cn("break-words leading-6", "[&_p]:my-0 [&_p+p]:mt-2", "[&_ul]:my-2 [&_ul]:list-disc [&_ul]:pl-5", "[&_ol]:my-2 [&_ol]:list-decimal [&_ol]:pl-5", "[&_li]:my-1", "[&_a]:text-interactive [&_a]:underline [&_a:hover]:text-interactive", "[&_h1]:mb-2 [&_h1]:mt-3 [&_h1]:text-xl [&_h1]:font-semibold", "[&_h2]:mb-2 [&_h2]:mt-3 [&_h2]:text-lg [&_h2]:font-semibold", "[&_h3]:mb-1.5 [&_h3]:mt-3 [&_h3]:text-base [&_h3]:font-semibold", "[&_h4]:mb-1.5 [&_h4]:mt-3 [&_h4]:font-semibold", "[&_h5]:mb-1.5 [&_h5]:mt-3 [&_h5]:font-semibold", "[&_h6]:mb-1.5 [&_h6]:mt-3 [&_h6]:font-semibold", "[&_blockquote]:my-2 [&_blockquote]:border-l-2 [&_blockquote]:border-border [&_blockquote]:pl-3 [&_blockquote]:text-muted-foreground", "[&_table]:my-2 [&_table]:w-full [&_table]:border-collapse", "[&_td]:border [&_td]:border-border [&_td]:p-2", "[&_th]:border [&_th]:border-border [&_th]:bg-[hsl(var(--table-header-background))] [&_th]:p-2 [&_th]:font-semibold", "[&_pre]:my-2 [&_pre]:overflow-x-auto [&_pre]:rounded-md [&_pre]:bg-muted [&_pre]:p-3 [&_pre]:font-mono [&_pre]:text-[0.85em]", "[&_code]:rounded [&_code]:bg-muted [&_code]:px-1 [&_code]:py-0.5 [&_code]:font-mono [&_code]:text-[0.85em]", "[&_pre_code]:bg-transparent [&_pre_code]:p-0", "[&_mark]:rounded-sm [&_mark]:bg-[hsl(var(--status-warning))] [&_mark]:px-0.5 [&_mark]:text-[hsl(var(--status-warning-foreground))]", "[&_img]:h-auto [&_img]:max-w-full", contentClassName);
208
208
  const cardSenderName = message.senderRole === "SYSTEM"
209
209
  ? "System (Auto-generated)"
210
210
  : senderName;
@@ -213,7 +213,8 @@ export function MessageItem({ message, caseId, showNewBadge = false, newMessageL
213
213
  : isApplicant
214
214
  ? "Applicant"
215
215
  : message.systemLabel || "Automated message";
216
- const sender = variant === "card" ? (_jsxs("div", { className: "flex min-w-0 flex-1 items-center gap-[8px]", children: [isOfficer ? (_jsx(Avatar, { src: message.avatarUrl, alt: cardSenderName, fallback: getInitials(initialsName), size: "sm", className: "shrink-0" })) : message.senderRole === "SYSTEM" ? (_jsx("span", { className: "flex size-[24px] shrink-0 items-center justify-center", children: _jsx(Laptop, { "aria-hidden": "true", className: "size-[24px]" }) })) : null, _jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("div", { className: "flex min-w-0 flex-wrap items-center gap-[4px]", children: [_jsx(Typography, { as: "h3", variant: "label", className: "min-w-0", children: cardSenderName }), message.senderBadgeLabel ? (_jsx(Badge, { variant: "muted", className: "h-5 rounded-full px-2 py-0 [&_span]:normal-case", children: message.senderBadgeLabel })) : null, showUnreadBadge ? (_jsx(Badge, { variant: "success", className: "h-5 rounded-full px-2 py-0 [&_span]:normal-case", children: newMessageLabel })) : null] }), cardSenderRole ? (_jsx(Typography, { as: "p", variant: "caption", className: "truncate text-muted-foreground", "data-slot": "message-author-role", children: cardSenderRole })) : null] })] })) : (_jsx(AvatarProfile, { fallback: getInitials(initialsName), name: senderName, nameAs: "h3", nameTrailing: variant === "default" && isApplicant ? (_jsx(Badge, { variant: "warning", bordered: true, children: "Applicant" })) : undefined, role: hasSenderProfileRole ? (_jsx("span", { "data-slot": "message-author-role", children: senderProfileRole })) : undefined, rolePlacement: "below", className: "min-w-0 flex-1 [column-gap:var(--space-3)]", avatarClassName: "h-9 w-9 shrink-0", fallbackClassName: "text-xs font-medium", nameClassName: "max-w-full whitespace-normal break-words [overflow-wrap:anywhere]" }));
216
+ const cardSenderTrailing = message.senderBadgeLabel || showUnreadBadge ? (_jsxs(_Fragment, { children: [message.senderBadgeLabel ? (_jsx(Badge, { variant: "muted", className: "h-5 rounded-full px-2 py-0 [&_span]:normal-case", children: message.senderBadgeLabel })) : null, showUnreadBadge ? (_jsx(Badge, { variant: "success", className: "h-5 rounded-full px-2 py-0 [&_span]:normal-case", children: newMessageLabel })) : null] })) : undefined;
217
+ const sender = variant === "card" ? (_jsx(AvatarProfile, { src: isOfficer ? message.avatarUrl : undefined, alt: cardSenderName, fallback: message.senderRole === "SYSTEM" ? (_jsx(Laptop, { "aria-hidden": "true", className: "size-[14px]" })) : (getInitials(initialsName)), size: "xs", name: cardSenderName, nameAs: "h3", nameTrailing: cardSenderTrailing, role: cardSenderRole ? (_jsx("span", { "data-slot": "message-author-role", children: cardSenderRole })) : undefined, rolePlacement: "below", className: "min-w-0 flex-1", nameClassName: "max-w-full whitespace-normal break-words [overflow-wrap:anywhere]" })) : (_jsx(AvatarProfile, { fallback: getInitials(initialsName), name: senderName, nameAs: "h3", nameTrailing: variant === "default" && isApplicant ? (_jsx(Badge, { variant: "warning", bordered: true, children: "Applicant" })) : undefined, role: hasSenderProfileRole ? (_jsx("span", { "data-slot": "message-author-role", children: senderProfileRole })) : undefined, rolePlacement: "below", className: "min-w-0 flex-1 [column-gap:var(--space-3)]", avatarClassName: "h-9 w-9 shrink-0", fallbackClassName: "text-xs font-medium", nameClassName: "max-w-full whitespace-normal break-words [overflow-wrap:anywhere]" }));
217
218
  const header = variant === "card" ? (_jsxs("div", { className: "flex min-w-0 items-start justify-between gap-[8px]", children: [sender, _jsx("time", { className: "shrink-0 whitespace-nowrap", dateTime: messageDate.toISOString(), children: _jsx(Typography, { as: "span", variant: "caption", className: "text-muted-foreground", children: formatTimestamp
218
219
  ? formatTimestamp(messageDate, message)
219
220
  : formatMessageCardTimestamp(messageDate, timestampNow) }) })] })) : (_jsxs("div", { className: "flex min-w-0 items-start justify-between gap-x-3 gap-y-1", children: [sender, _jsx("time", { className: "shrink-0 whitespace-nowrap pt-0.5", dateTime: messageDate.toISOString(), children: _jsx(Typography, { as: "span", variant: "caption", className: "text-muted-foreground/60", children: formatTimestamp
@@ -18,6 +18,8 @@ export interface MultiSelectProps {
18
18
  hideLabel?: boolean;
19
19
  searchable?: boolean;
20
20
  searchPlaceholder?: string;
21
+ /** Render supplementary content at the end of each dropdown option. */
22
+ renderOptionTrailing?: (option: MultiSelectOption) => React.ReactNode;
21
23
  /** Cap how many selected tags render in the trigger; the rest collapse into a `+N` badge. */
22
24
  maxVisibleTags?: number;
23
25
  /** Show a "Clear" button in the dropdown footer when items are selected. */
@@ -29,5 +31,5 @@ export interface MultiSelectProps {
29
31
  errorClassName?: string;
30
32
  id?: string;
31
33
  }
32
- declare function MultiSelect({ label, options, value, onValueChange, placeholder, description, error, invalid, disabled, hideLabel, searchable, searchPlaceholder, maxVisibleTags, clearable, className, triggerClassName, labelClassName, descriptionClassName, errorClassName, id, }: MultiSelectProps): import("react/jsx-runtime").JSX.Element;
34
+ declare function MultiSelect({ label, options, value, onValueChange, placeholder, description, error, invalid, disabled, hideLabel, searchable, searchPlaceholder, renderOptionTrailing, maxVisibleTags, clearable, className, triggerClassName, labelClassName, descriptionClassName, errorClassName, id, }: MultiSelectProps): import("react/jsx-runtime").JSX.Element;
33
35
  export { MultiSelect };
@@ -11,7 +11,7 @@ import { Popover } from "./popover";
11
11
  import { PopoverMenuFooter, PopoverMenuFooterAction, PopoverMenuSearch } from "./popover-menu";
12
12
  import { Typography } from "./typography";
13
13
  import { SearchHighlight } from "./use-search-highlight";
14
- function MultiSelect({ label, options, value, onValueChange, placeholder = "Select options", description, error, invalid = false, disabled = false, hideLabel = false, searchable = false, searchPlaceholder = "Search...", maxVisibleTags = 2, clearable = false, className, triggerClassName, labelClassName, descriptionClassName, errorClassName, id, }) {
14
+ function MultiSelect({ label, options, value, onValueChange, placeholder = "Select options", description, error, invalid = false, disabled = false, hideLabel = false, searchable = false, searchPlaceholder = "Search...", renderOptionTrailing, maxVisibleTags = 2, clearable = false, className, triggerClassName, labelClassName, descriptionClassName, errorClassName, id, }) {
15
15
  const generatedId = React.useId();
16
16
  const selectId = id !== null && id !== void 0 ? id : `multi-select-${generatedId}`;
17
17
  const labelId = `${selectId}-label`;
@@ -169,7 +169,7 @@ function MultiSelect({ label, options, value, onValueChange, placeholder = "Sele
169
169
  var _a;
170
170
  event.preventDefault();
171
171
  (_a = triggerRef.current) === null || _a === void 0 ? void 0 : _a.focus();
172
- }, children: label }), _jsxs(Popover, { open: disabled ? false : open, onOpenChange: handleOpenChange, align: "start", sideOffset: 4, collisionPadding: 16, surface: "menu", tabBehavior: "close", contentClassName: "flex max-h-[var(--radix-popover-content-available-height)] w-[var(--radix-popover-trigger-width)] min-w-[var(--radix-popover-trigger-width)] flex-col overflow-hidden", onOpenAutoFocus: (event) => event.preventDefault(), trigger: _jsxs("div", { ref: triggerRef, role: "combobox", id: selectId, tabIndex: disabled ? -1 : 0, onKeyDown: handleTriggerKeyDown, "aria-expanded": open, "aria-controls": open ? listboxId : undefined, "aria-haspopup": "listbox", "aria-invalid": isInvalid ? "true" : undefined, "aria-disabled": disabled ? "true" : undefined, "aria-labelledby": labelId, "aria-describedby": [descriptionId, errorId].filter(Boolean).join(" ") || undefined, className: cn("relative flex h-control w-full cursor-pointer items-center gap-1.5 overflow-hidden rounded-control border border-input bg-background px-2.5 py-1.5 pr-8 text-sm ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2", isInvalid ? "border-destructive" : "border-input", disabled && "cursor-not-allowed opacity-50", triggerClassName), children: [selectedLabels.length > 0 ? (_jsxs(_Fragment, { children: [selectedLabels.slice(0, maxVisibleTags).map((opt) => (_jsxs(Badge, { variant: "secondary", className: "max-w-[10rem] shrink-0 justify-start gap-1 overflow-visible text-sm font-medium", children: [_jsx("span", { className: "min-w-0 truncate", children: opt.label }), _jsx("button", { type: "button", className: "inline-flex cursor-pointer items-center justify-center rounded-sm text-muted-foreground hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", onClick: (event) => {
172
+ }, children: label }), _jsxs(Popover, { open: disabled ? false : open, onOpenChange: handleOpenChange, align: "start", sideOffset: 4, collisionPadding: 16, surface: "menu", tabBehavior: "close", contentClassName: "flex max-h-[var(--radix-popover-content-available-height)] w-[var(--radix-popover-trigger-width)] min-w-[var(--radix-popover-trigger-width)] flex-col overflow-hidden", onOpenAutoFocus: (event) => event.preventDefault(), trigger: _jsxs("div", { ref: triggerRef, role: "combobox", id: selectId, tabIndex: disabled ? -1 : 0, onKeyDown: handleTriggerKeyDown, "aria-expanded": open, "aria-controls": open ? listboxId : undefined, "aria-haspopup": "listbox", "aria-invalid": isInvalid ? "true" : undefined, "aria-disabled": disabled ? "true" : undefined, "aria-labelledby": labelId, "aria-describedby": [descriptionId, errorId].filter(Boolean).join(" ") || undefined, className: cn("relative flex h-control w-full cursor-pointer items-center gap-1.5 overflow-hidden rounded-control border border-input bg-background px-2.5 py-1.5 pr-8 text-sm outline-none transition-[color,box-shadow] focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50", isInvalid ? "border-destructive" : "border-input", open && "ring-[3px]", open && (isInvalid ? "ring-destructive/20" : "border-ring ring-ring/50"), disabled && "cursor-not-allowed opacity-50", triggerClassName), children: [selectedLabels.length > 0 ? (_jsxs(_Fragment, { children: [selectedLabels.slice(0, maxVisibleTags).map((opt) => (_jsxs(Badge, { variant: "secondary", className: "max-w-[10rem] shrink-0 justify-start gap-1 overflow-visible text-sm font-medium", children: [_jsx("span", { className: "min-w-0 truncate", children: opt.label }), _jsx("button", { type: "button", className: "inline-flex cursor-pointer items-center justify-center rounded-sm text-muted-foreground hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", onClick: (event) => {
173
173
  event.stopPropagation();
174
174
  removeOption(opt.value);
175
175
  }, "aria-label": `Remove ${opt.label}`, children: _jsx(XIcon, { size: 12 }) })] }, opt.value))), selectedLabels.length > maxVisibleTags ? (_jsxs(Badge, { variant: "secondary", className: "shrink-0 text-sm font-medium", title: selectedLabels
@@ -178,7 +178,7 @@ function MultiSelect({ label, options, value, onValueChange, placeholder = "Sele
178
178
  .join(", "), children: ["+", selectedLabels.length - maxVisibleTags] })) : null] })) : (_jsx("span", { className: "text-muted-foreground", children: placeholder })), _jsx(ChevronDownIcon, { "aria-hidden": "true", size: 16, className: cn("pointer-events-none absolute right-2.5 top-1/2 -translate-y-1/2 shrink-0 text-muted-foreground transition-transform duration-150", open && "rotate-180") })] }), children: [searchable ? (_jsx(PopoverMenuSearch, { ref: searchInputRef, value: searchQuery, onChange: (event) => setSearchQuery(event.target.value), onKeyDown: handleSearchKeyDown, placeholder: searchPlaceholder, "aria-label": searchPlaceholder, className: "h-control border-0 bg-transparent px-2 py-0 text-sm shadow-none" })) : null, _jsx("div", { ref: listboxRef, id: listboxId, role: "listbox", "aria-label": typeof label === "string" ? label : "Options", "aria-multiselectable": "true", className: "max-h-64 overflow-y-auto", onKeyDown: handleListboxKeyDown, children: filteredOptions.length > 0 ? (filteredOptions.map((option) => {
179
179
  const isSelected = value.includes(option.value);
180
180
  return (_jsxs("button", { type: "button", role: "option", "aria-selected": isSelected, disabled: option.disabled, tabIndex: -1, onClick: () => toggleOption(option.value), className: cn("flex min-h-8 w-full cursor-pointer items-center gap-1.5 rounded-sm px-2 py-1.5 text-left text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground disabled:pointer-events-none disabled:opacity-50", isSelected &&
181
- "bg-highlight text-highlight-foreground hover:bg-highlight/80 hover:text-highlight-foreground focus:bg-highlight/80 focus:text-highlight-foreground"), children: [_jsx(Checkbox, { checked: isSelected, disabled: option.disabled, tabIndex: -1, readOnly: true, "aria-hidden": "true", className: "mt-0.5" }), _jsxs("div", { className: "flex flex-col gap-0.5", children: [_jsx(SearchHighlight, { text: option.label, query: searchQuery }), option.description ? (_jsx(Typography, { as: "span", variant: "caption", children: _jsx(SearchHighlight, { text: option.description, query: searchQuery }) })) : null] })] }, option.value));
181
+ "bg-highlight text-highlight-foreground hover:bg-highlight/80 hover:text-highlight-foreground focus:bg-highlight/80 focus:text-highlight-foreground"), children: [_jsx(Checkbox, { checked: isSelected, disabled: option.disabled, tabIndex: -1, readOnly: true, "aria-hidden": "true", className: "mt-0.5" }), _jsxs("div", { className: "flex flex-col gap-0.5", children: [_jsx(SearchHighlight, { text: option.label, query: searchQuery }), option.description ? (_jsx(Typography, { as: "span", variant: "caption", children: _jsx(SearchHighlight, { text: option.description, query: searchQuery }) })) : null] }), renderOptionTrailing ? (_jsx("span", { className: "ml-auto shrink-0", children: renderOptionTrailing(option) })) : null] }, option.value));
182
182
  })) : (_jsx("div", { className: "px-2.5 py-1.5 text-center text-sm text-muted-foreground", children: "No options found." })) }), clearable && value.length > 0 ? (_jsx(PopoverMenuFooter, { children: _jsx(PopoverMenuFooterAction, { onClick: () => onValueChange([]), children: "Clear" }) })) : null] }), showDescription ? (_jsx(FieldDescription, { id: descriptionId, className: descriptionClassName, children: description })) : null, _jsx(FieldError, { id: errorId, className: errorClassName, children: error })] }));
183
183
  }
184
184
  export { MultiSelect };
@@ -351,11 +351,12 @@ export function RichTextEditor({ variant = "default", placeholder = "Type messag
351
351
  setTemplatePopoverOpen(false);
352
352
  };
353
353
  const hasSendActions = Boolean(sendActions === null || sendActions === void 0 ? void 0 : sendActions.length);
354
- const renderSendAction = ({ compact = false, fullWidth = false, } = {}) => hasSendActions ? (_jsx(DropdownButton, { className: fullWidth ? "w-full" : undefined, align: "end", disabled: sendDisabled, label: isSending ? sendingLabel : sendLabel, leadingIcon: _jsx(SendIcon, { size: 16 }), size: compact ? "sm" : undefined, split: true, onClick: () => {
354
+ const renderSendAction = ({ compact = false, fullWidth = false, } = {}) => hasSendActions ? (_jsx(DropdownButton, { className: cn(fullWidth && "w-full", compact &&
355
+ "[&_button]:h-[32px] [&_button:last-child]:w-[32px]"), align: "end", disabled: sendDisabled, label: isSending ? sendingLabel : sendLabel, leadingIcon: _jsx(SendIcon, { size: 16 }), size: compact ? "sm" : undefined, split: true, onClick: () => {
355
356
  void handleSend();
356
357
  }, children: _jsx(PopoverMenuSection, { children: sendActions === null || sendActions === void 0 ? void 0 : sendActions.map((action) => (_jsx(PopoverMenuItem, { disabled: sendDisabled || action.disabled, onClick: () => {
357
358
  void handleSend(action.metadata);
358
- }, children: action.label }, action.id))) }) })) : (_jsxs(Button, { type: "button", className: fullWidth ? "w-full" : undefined, size: compact ? "sm" : undefined, disabled: sendDisabled, "aria-label": isSending ? sendingLabel : sendLabel, onClick: () => {
359
+ }, children: action.label }, action.id))) }) })) : (_jsxs(Button, { type: "button", className: cn(fullWidth && "w-full", compact && "h-[32px]"), size: compact ? "sm" : undefined, disabled: sendDisabled, "aria-label": isSending ? sendingLabel : sendLabel, onClick: () => {
359
360
  void handleSend();
360
361
  }, children: [_jsx(SendIcon, { size: 16 }), isSending ? sendingLabel : sendLabel] }));
361
362
  if (variant === "message") {
@@ -370,7 +371,7 @@ export function RichTextEditor({ variant = "default", placeholder = "Type messag
370
371
  } }), _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
372
  top: linkMenuPosition.top,
372
373
  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", 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
+ }, 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-[32px] w-[32px]", 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", className: "h-[32px] px-[10px]", children: ["Templates", _jsx(ChevronDownIcon, { size: 16 })] }), children: [_jsx("div", { className: "max-h-80 overflow-y-auto", children: templatesByCategory.map(({ category, templates }) => {
374
375
  var _a;
375
376
  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
377
  }) }), 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 })] })] })] }));
@@ -15,7 +15,7 @@ function SelectGroup(props) {
15
15
  function SelectValue(props) {
16
16
  return _jsx(SelectPrimitive.Value, { "data-slot": "select-value", ...props });
17
17
  }
18
- const SelectTrigger = React.forwardRef(({ className, children, ...props }, ref) => (_jsxs(SelectPrimitive.Trigger, { ref: ref, "data-slot": "select-trigger", className: cn("flex h-control w-full cursor-pointer items-center justify-between gap-1.5 whitespace-nowrap rounded-control border border-input bg-background px-2.5 py-1.5 text-sm transition-[color,box-shadow] outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-[invalid=true]:border-destructive aria-[invalid=true]:ring-destructive/20 data-[placeholder]:text-muted-foreground [&>span]:line-clamp-1 [&_svg]:pointer-events-none [&_svg]:shrink-0", className), ...props, children: [children, _jsx(SelectPrimitive.Icon, { asChild: true, children: _jsx(ChevronDownIcon, { size: 16, className: "shrink-0 text-muted-foreground transition-transform duration-150 [[data-state=open]>&]:rotate-180" }) })] })));
18
+ const SelectTrigger = React.forwardRef(({ className, children, ...props }, ref) => (_jsxs(SelectPrimitive.Trigger, { ref: ref, "data-slot": "select-trigger", className: cn("flex h-control w-full cursor-pointer items-center justify-between gap-1.5 whitespace-nowrap rounded-control border border-input bg-background px-2.5 py-1.5 text-sm transition-[color,box-shadow] outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 data-[state=open]:border-ring data-[state=open]:ring-[3px] data-[state=open]:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-[invalid=true]:border-destructive aria-[invalid=true]:ring-destructive/20 aria-[invalid=true]:data-[state=open]:border-destructive aria-[invalid=true]:data-[state=open]:ring-destructive/20 data-[placeholder]:text-muted-foreground [&>span]:line-clamp-1 [&_svg]:pointer-events-none [&_svg]:shrink-0", className), ...props, children: [children, _jsx(SelectPrimitive.Icon, { asChild: true, children: _jsx(ChevronDownIcon, { size: 16, className: "shrink-0 text-muted-foreground transition-transform duration-150 [[data-state=open]>&]:rotate-180" }) })] })));
19
19
  SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
20
20
  const SelectScrollUpButton = React.forwardRef(({ className, ...props }, ref) => (_jsx(SelectPrimitive.ScrollUpButton, { ref: ref, "data-slot": "select-scroll-up-button", className: cn("flex cursor-pointer items-center justify-center py-1", className), ...props, children: _jsx(ChevronUp, { className: "h-4 w-4" }) })));
21
21
  SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
package/dist/select.d.ts CHANGED
@@ -30,5 +30,5 @@ export interface SelectProps extends Pick<React.ComponentProps<typeof SelectRoot
30
30
  errorClassName?: string;
31
31
  id?: string;
32
32
  }
33
- declare function Select({ label, options, placeholder, size, description, error, invalid, hideLabel, searchable, searchPlaceholder, searchEmptyMessage, searchInputAriaLabel, className, triggerClassName, contentClassName, labelClassName, descriptionClassName, errorClassName, id, disabled, open, onOpenChange, ...props }: SelectProps): import("react/jsx-runtime").JSX.Element;
33
+ declare function Select({ label, options, placeholder, size, description, error, invalid, hideLabel, searchable, searchPlaceholder, searchEmptyMessage, searchInputAriaLabel, className, triggerClassName, contentClassName, labelClassName, descriptionClassName, errorClassName, id, disabled, required, open, onOpenChange, ...props }: SelectProps): import("react/jsx-runtime").JSX.Element;
34
34
  export { Select };
package/dist/select.js CHANGED
@@ -41,7 +41,7 @@ function renderHighlightedLabel(label, query) {
41
41
  }
42
42
  return label;
43
43
  }
44
- function Select({ label, options, placeholder = "Select an option", size = "default", description, error, invalid = false, hideLabel = false, searchable = false, searchPlaceholder = "Search options...", searchEmptyMessage = "No options found.", searchInputAriaLabel = "Search options", className, triggerClassName, contentClassName, labelClassName, descriptionClassName, errorClassName, id, disabled, open, onOpenChange, ...props }) {
44
+ function Select({ label, options, placeholder = "Select an option", size = "default", description, error, invalid = false, hideLabel = false, searchable = false, searchPlaceholder = "Search options...", searchEmptyMessage = "No options found.", searchInputAriaLabel = "Search options", className, triggerClassName, contentClassName, labelClassName, descriptionClassName, errorClassName, id, disabled, required, open, onOpenChange, ...props }) {
45
45
  const generatedId = React.useId();
46
46
  const selectId = id !== null && id !== void 0 ? id : `select-${generatedId}`;
47
47
  const triggerRef = React.useRef(null);
@@ -154,7 +154,7 @@ function Select({ label, options, placeholder = "Select an option", size = "defa
154
154
  searchable,
155
155
  searchQuery,
156
156
  ]);
157
- return (_jsxs(Field, { className: cn(size === "comfortable" && "gap-[8px]", className), "data-disabled": disabled ? "true" : undefined, "data-invalid": isInvalid ? "true" : undefined, children: [_jsx(FieldLabel, { htmlFor: selectId, className: cn(size === "comfortable" && "text-[16px] leading-[24px]", hideLabel && "sr-only", labelClassName), children: label }), _jsxs(SelectRoot, { disabled: disabled, open: isOpen, onOpenChange: handleOpenChange, ...props, children: [_jsx(SelectTrigger, { ref: triggerRef, id: selectId, className: cn(size === "comfortable" &&
157
+ return (_jsxs(Field, { className: cn(size === "comfortable" && "gap-[8px]", className), "data-disabled": disabled ? "true" : undefined, "data-invalid": isInvalid ? "true" : undefined, children: [_jsx(FieldLabel, { htmlFor: selectId, required: required, className: cn(size === "comfortable" && "text-[16px] leading-[24px]", hideLabel && "sr-only", labelClassName), children: label }), _jsxs(SelectRoot, { disabled: disabled, required: required, open: isOpen, onOpenChange: handleOpenChange, ...props, children: [_jsx(SelectTrigger, { ref: triggerRef, id: selectId, className: cn(size === "comfortable" &&
158
158
  "h-[46px] px-[16px] py-[11px] text-[16px] leading-[24px]", triggerClassName), "aria-invalid": isInvalid ? "true" : undefined, "aria-describedby": [descriptionId, errorId].filter(Boolean).join(" ") || undefined, children: _jsx(SelectValue, { placeholder: placeholder }) }), _jsx(SelectContent, { ref: contentRef, className: contentClassName, onCloseAutoFocus: handleCloseAutoFocus, onKeyDownCapture: handleContentKeyDownCapture, header: searchable ? (_jsx(InputControl, { ref: searchInputRef, value: searchQuery, onChange: (event) => setSearchQuery(event.target.value), placeholder: searchPlaceholder, "aria-label": searchInputAriaLabel, autoComplete: "off", className: "h-control border-0 bg-transparent px-2 py-0 text-sm shadow-none", onKeyDown: (event) => {
159
159
  if (event.key === "ArrowDown" ||
160
160
  event.key === "ArrowUp") {
package/dist/textarea.js CHANGED
@@ -6,7 +6,7 @@ import { FieldCounter } from "./field-counter";
6
6
  import { cn } from "./lib/utils";
7
7
  const TextareaControl = React.forwardRef(({ className, ...props }, ref) => (_jsx("textarea", { ref: ref, "data-slot": "textarea", className: cn("flex min-h-16 w-full rounded-control border border-input bg-background text-sm transition-[color,box-shadow] outline-none placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-[invalid=true]:border-destructive aria-[invalid=true]:ring-destructive/20", inputControlPaddingClassName, className), ...props })));
8
8
  TextareaControl.displayName = "TextareaControl";
9
- const Textarea = React.forwardRef(({ label, size = "default", description, maxWords, showCount = false, value, defaultValue, onChange, error: suppliedError, invalid = false, hideLabel = false, className, textareaClassName, labelClassName, descriptionClassName, errorClassName, id, disabled, "aria-invalid": ariaInvalid, "aria-describedby": ariaDescribedBy, ...props }, ref) => {
9
+ const Textarea = React.forwardRef(({ label, size = "default", description, maxWords, showCount = false, value, defaultValue, onChange, error: suppliedError, invalid = false, hideLabel = false, className, textareaClassName, labelClassName, descriptionClassName, errorClassName, id, disabled, required, "aria-invalid": ariaInvalid, "aria-describedby": ariaDescribedBy, ...props }, ref) => {
10
10
  const [uncontrolledValue, setUncontrolledValue] = React.useState(defaultValue !== null && defaultValue !== void 0 ? defaultValue : "");
11
11
  const text = String(value !== null && value !== void 0 ? value : uncontrolledValue);
12
12
  const words = text.trim() ? text.trim().split(/\s+/).length : 0;
@@ -28,7 +28,7 @@ const Textarea = React.forwardRef(({ label, size = "default", description, maxWo
28
28
  const describedBy = [ariaDescribedBy, descriptionId, errorId, wordLimitId]
29
29
  .filter(Boolean)
30
30
  .join(" ") || undefined;
31
- return (_jsxs(Field, { className: cn(size === "comfortable" && "gap-[8px]", className), "data-disabled": disabled ? "true" : undefined, "data-invalid": isInvalid ? "true" : undefined, children: [_jsx(FieldLabel, { htmlFor: textareaId, className: cn(size === "comfortable" && "text-[16px] leading-[24px]", hideLabel && "sr-only", labelClassName), children: label }), _jsx(TextareaControl, { ref: ref, id: textareaId, disabled: disabled, "aria-invalid": isInvalid ? "true" : undefined, "aria-describedby": describedBy, className: cn(size === "comfortable" &&
31
+ return (_jsxs(Field, { className: cn(size === "comfortable" && "gap-[8px]", className), "data-disabled": disabled ? "true" : undefined, "data-invalid": isInvalid ? "true" : undefined, children: [_jsx(FieldLabel, { htmlFor: textareaId, required: required, className: cn(size === "comfortable" && "text-[16px] leading-[24px]", hideLabel && "sr-only", labelClassName), children: label }), _jsx(TextareaControl, { ref: ref, id: textareaId, disabled: disabled, required: required, "aria-invalid": isInvalid ? "true" : undefined, "aria-describedby": describedBy, className: cn(size === "comfortable" &&
32
32
  "min-h-[76px] px-[16px] py-[12px] text-[16px] leading-[24px]", textareaClassName), ...props, value: value, defaultValue: defaultValue, onChange: (event) => {
33
33
  if (value === undefined)
34
34
  setUncontrolledValue(event.target.value);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neasg/design-system",
3
- "version": "0.4.139",
3
+ "version": "0.4.144",
4
4
  "description": "NEA shared design system primitives, theme tokens, and Storybook docs.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -1,33 +0,0 @@
1
- import * as React from "react";
2
- import { type DashboardActionPanelProps } from "./layout";
3
- import { type SelectOption } from "./select";
4
- export interface RoutingActionPanelProps extends Omit<DashboardActionPanelProps, "children"> {
5
- routeOptions: SelectOption[];
6
- routeValue?: string;
7
- routePlaceholder?: string;
8
- routeDescription?: React.ReactNode;
9
- routeDisabled?: boolean;
10
- onRouteValueChange?: (value: string) => void;
11
- /** Workflow-specific fields rendered before the route target. */
12
- supplementaryFields?: React.ReactNode;
13
- /** Read-only review context in the scrollable body, above the routing form. */
14
- context?: React.ReactNode;
15
- remarks: string;
16
- remarksDescription?: React.ReactNode;
17
- remarksPlaceholder?: string;
18
- remarksRequired?: boolean;
19
- remarksRows?: number;
20
- /** Blocking validation messages, collapsed above the submit action. */
21
- validationMessages?: readonly string[];
22
- onRemarksChange: (value: string) => void;
23
- submitLabel?: React.ReactNode;
24
- submitDisabled?: boolean;
25
- submitLoading?: boolean;
26
- onSubmit: () => void;
27
- }
28
- /**
29
- * Shared action-only routing surface for constrained dashboard popovers and
30
- * right panels. Historical routing events belong in the change log.
31
- */
32
- declare function RoutingActionPanel({ 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;
33
- export { RoutingActionPanel };
@@ -1,16 +0,0 @@
1
- "use client";
2
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { Route } from "lucide-react";
4
- import { Button } from "./button";
5
- import { DashboardActionPanel, DashboardRightPanelBody, } from "./layout";
6
- import { Select } from "./select";
7
- import { Textarea } from "./textarea";
8
- /**
9
- * Shared action-only routing surface for constrained dashboard popovers and
10
- * right panels. Historical routing events belong in the change log.
11
- */
12
- function RoutingActionPanel({ 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 }) {
13
- const form = (_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] }) })] }));
14
- return (_jsx(DashboardActionPanel, { headerSpacing: "comfortable", ...panelProps, children: _jsxs(DashboardRightPanelBody, { spacing: "comfortable", topInset: "none", children: [context ? (_jsx("div", { "data-slot": "routing-action-panel-context", className: "grid min-w-0 gap-[var(--space-3)] whitespace-pre-wrap [overflow-wrap:anywhere]", children: context })) : null, form] }) }));
15
- }
16
- export { RoutingActionPanel };