@neasg/design-system 0.4.137 → 0.4.143
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/assignee-popover.d.ts +15 -1
- package/dist/assignee-popover.js +18 -9
- package/dist/checklist.d.ts +2 -1
- package/dist/checklist.js +2 -2
- package/dist/index.d.ts +2 -4
- package/dist/index.js +1 -2
- package/dist/layout.js +1 -1
- package/dist/message-action-panel.d.ts +9 -2
- package/dist/message-action-panel.js +9 -2
- package/dist/message-item.js +4 -3
- package/dist/multi-select.d.ts +3 -1
- package/dist/multi-select.js +3 -3
- package/dist/notification.js +2 -2
- package/dist/rich-text-editor.js +4 -3
- package/dist/select-primitive.js +1 -1
- package/dist/select.d.ts +1 -1
- package/dist/select.js +2 -2
- package/dist/textarea.js +2 -2
- package/package.json +1 -1
- package/dist/routing-action-panel.d.ts +0 -33
- package/dist/routing-action-panel.js +0 -16
|
@@ -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;
|
package/dist/assignee-popover.js
CHANGED
|
@@ -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 [
|
|
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
|
-
|
|
42
|
-
|
|
53
|
+
if (closeOnSelect)
|
|
54
|
+
changeOpen(false);
|
|
43
55
|
};
|
|
44
|
-
return _jsxs(Popover, { open: open && !disabled, onOpenChange: (
|
|
45
|
-
|
|
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
|
}
|
package/dist/checklist.d.ts
CHANGED
|
@@ -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:
|
|
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";
|
package/dist/layout.js
CHANGED
|
@@ -648,7 +648,7 @@ function DashboardContent({ className, hasSidebar = true, rightPanel, rightPanel
|
|
|
648
648
|
rightPanelAutoCollapseSidebarBreakpoint,
|
|
649
649
|
]);
|
|
650
650
|
const handleContentClick = React.useCallback(() => {
|
|
651
|
-
if (!isCollapsed
|
|
651
|
+
if (!isCollapsed) {
|
|
652
652
|
collapse();
|
|
653
653
|
}
|
|
654
654
|
}, [collapse, isCollapsed]);
|
|
@@ -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
|
-
|
|
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
|
-
|
|
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 };
|
package/dist/message-item.js
CHANGED
|
@@ -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 {
|
|
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
|
|
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
|
|
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
|
package/dist/multi-select.d.ts
CHANGED
|
@@ -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 };
|
package/dist/multi-select.js
CHANGED
|
@@ -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
|
|
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 };
|
package/dist/notification.js
CHANGED
|
@@ -166,7 +166,7 @@ function NotificationItem({ notification, density = "default", variant = "row",
|
|
|
166
166
|
const unreadIndicator = isUnread && unreadLabel !== null ? (_jsx("span", { "data-slot": "notification-unread-indicator", className: "block size-2.5 rounded-full bg-primary ring-2 ring-background", children: _jsx("span", { className: "sr-only", children: unreadLabel }) })) : null;
|
|
167
167
|
const cardTrailing = notification.badge || unreadIndicator ? (_jsxs("span", { className: "flex items-center gap-[var(--space-2)]", children: [notification.badge, unreadIndicator] })) : null;
|
|
168
168
|
return (_jsx(ActivityCard, { as: activityElement, "data-slot": "notification-item", "data-unread": isUnread ? "" : undefined, density: activityDensity, icon: _jsx(Icon, { className: activityDensity === "compact" ? "size-3.5" : "size-[24px]" }), iconTone: notification.iconAppearance === "plain" ? undefined : tone, title: notification.title, titleLines: labelLines, meta: meta, headerContent: actorBelongsInHeader ? (_jsx(ActivityCardActor, { actor: notification.actor, label: actorLabel })) : undefined, trailing: cardTrailing, href: notification.href, className: cn("group relative w-full text-left outline-none transition-colors", isUnread && "bg-primary/[0.045]", hasHoverSurface && "hover:bg-accent/70", isInteractive &&
|
|
169
|
-
"cursor-pointer focus-visible:z-10 focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-inset", className), onClick: isInteractive ? handleClick : undefined, ...props, children: hasCardContent ? (_jsxs(ActivityCardContent, { density: activityDensity, children: [hasDescription ? (_jsx(Typography, { as: "div", variant: "bodySm", className: cn("text-left", isUnread ? "text-foreground/75" : "text-instructional", descriptionLineClasses[descriptionLines]), children: notification.description })) : null, hasDetail ? (_jsxs("div", { "data-slot": "notification-item-detail", className: "text-left", children: [notification.detailLabel !== undefined ? (_jsx(Typography, { as: "div", variant: "caption", className: "font-semibold text-foreground", children: notification.detailLabel })) : null, _jsx(Typography, { as: "div", variant: "bodySm", className: "whitespace-pre-wrap text-instructional [overflow-wrap:anywhere]", children: notification.detail })] })) : null, notification.actor !== undefined && !actorBelongsInHeader ? (_jsx(ActivityCardActor, { actor: notification.actor, label: actorLabel })) : null, hasActions ? (_jsx("div", { className: "flex flex-wrap gap-2", children: actions.map((action, index) => {
|
|
169
|
+
"cursor-pointer focus-visible:z-10 focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-inset", className), onClick: isInteractive ? handleClick : undefined, ...props, children: hasCardContent ? (_jsxs(ActivityCardContent, { density: activityDensity, children: [hasDescription ? (_jsx(Typography, { as: "div", variant: "bodySm", className: cn("text-left", isUnread ? "text-foreground/75" : "text-instructional", descriptionLineClasses[descriptionLines]), children: notification.description })) : null, hasDetail ? (_jsxs("div", { "data-slot": "notification-item-detail", className: "space-y-0.5 rounded-control bg-muted px-3 py-2 text-left", children: [notification.detailLabel !== undefined ? (_jsx(Typography, { as: "div", variant: "caption", className: "font-semibold text-foreground", children: notification.detailLabel })) : null, _jsx(Typography, { as: "div", variant: "bodySm", className: "whitespace-pre-wrap text-instructional [overflow-wrap:anywhere]", children: notification.detail })] })) : null, notification.actor !== undefined && !actorBelongsInHeader ? (_jsx(ActivityCardActor, { actor: notification.actor, label: actorLabel })) : null, hasActions ? (_jsx("div", { className: "flex flex-wrap gap-2", children: actions.map((action, index) => {
|
|
170
170
|
var _a, _b;
|
|
171
171
|
return (_jsx(Button, { type: "button", variant: (_a = action.variant) !== null && _a !== void 0 ? _a : (index === 0 ? "outline" : "default"), size: "sm", disabled: action.disabled, className: cn("min-w-24", action.className), onClick: (event) => {
|
|
172
172
|
var _a;
|
|
@@ -175,7 +175,7 @@ function NotificationItem({ notification, density = "default", variant = "row",
|
|
|
175
175
|
}, children: action.label }, (_b = action.id) !== null && _b !== void 0 ? _b : index));
|
|
176
176
|
}) })) : null] })) : null }));
|
|
177
177
|
}
|
|
178
|
-
const content = (_jsxs(_Fragment, { children: [_jsx("span", { "aria-hidden": "true", className: cn("mt-0.5 flex shrink-0 items-center justify-center rounded-control border", density === "compact" ? "h-7 w-7" : "h-8 w-8", notificationToneClasses[tone]), children: _jsx(Icon, { className: density === "compact" ? "h-3.5 w-3.5" : "h-4 w-4" }) }), _jsxs("span", { className: "min-w-0 flex-1", children: [_jsxs("span", { className: "grid min-w-0 grid-cols-[minmax(0,1fr)_auto] items-start gap-3", children: [_jsx(Typography, { as: "span", variant: "bodySm", className: cn("min-w-0 text-left text-foreground", isUnread ? "font-semibold" : "font-medium", labelLineClasses[labelLines]), children: notification.title }), meta || (isUnread && unreadLabel !== null) ? (_jsxs("span", { className: "flex min-w-0 shrink-0 items-center justify-end gap-1.5 text-right", children: [meta ? (_jsx(Typography, { as: "span", variant: "caption", className: "shrink-0 whitespace-nowrap text-instructional", children: meta })) : null, isUnread && unreadLabel !== null ? (_jsx("span", { "data-slot": "notification-unread-indicator", className: "mt-1 h-2.5 w-2.5 shrink-0 rounded-full bg-primary ring-2 ring-background", children: _jsx("span", { className: "sr-only", children: unreadLabel }) })) : null] })) : null] }), notification.description !== undefined ? (_jsx(Typography, { as: "span", variant: "caption", className: cn("mt-1.5 block text-left", isUnread ? "text-foreground/75" : "text-instructional", descriptionLineClasses[descriptionLines]), children: notification.description })) : null, hasDetail ? (_jsxs("span", { "data-slot": "notification-item-detail", className: "mt-2 block text-left", children: [notification.detailLabel !== undefined ? (_jsx(Typography, { as: "span", variant: "caption", className: "block font-semibold text-foreground", children: notification.detailLabel })) : null, _jsx(Typography, { as: "span", variant: "caption", className: "block whitespace-pre-wrap text-instructional [overflow-wrap:anywhere]", children: notification.detail })] })) : null, notification.actor !== undefined ? (_jsxs(Typography, { as: "span", variant: "bodySm", className: "mt-2 block text-left font-semibold text-foreground", children: [actorLabel, " ", notification.actor] })) : null, hasActions ? (_jsx("span", { className: "mt-4 flex flex-wrap gap-2", children: actions.map((action, index) => {
|
|
178
|
+
const content = (_jsxs(_Fragment, { children: [_jsx("span", { "aria-hidden": "true", className: cn("mt-0.5 flex shrink-0 items-center justify-center rounded-control border", density === "compact" ? "h-7 w-7" : "h-8 w-8", notificationToneClasses[tone]), children: _jsx(Icon, { className: density === "compact" ? "h-3.5 w-3.5" : "h-4 w-4" }) }), _jsxs("span", { className: "min-w-0 flex-1", children: [_jsxs("span", { className: "grid min-w-0 grid-cols-[minmax(0,1fr)_auto] items-start gap-3", children: [_jsx(Typography, { as: "span", variant: "bodySm", className: cn("min-w-0 text-left text-foreground", isUnread ? "font-semibold" : "font-medium", labelLineClasses[labelLines]), children: notification.title }), meta || (isUnread && unreadLabel !== null) ? (_jsxs("span", { className: "flex min-w-0 shrink-0 items-center justify-end gap-1.5 text-right", children: [meta ? (_jsx(Typography, { as: "span", variant: "caption", className: "shrink-0 whitespace-nowrap text-instructional", children: meta })) : null, isUnread && unreadLabel !== null ? (_jsx("span", { "data-slot": "notification-unread-indicator", className: "mt-1 h-2.5 w-2.5 shrink-0 rounded-full bg-primary ring-2 ring-background", children: _jsx("span", { className: "sr-only", children: unreadLabel }) })) : null] })) : null] }), notification.description !== undefined ? (_jsx(Typography, { as: "span", variant: "caption", className: cn("mt-1.5 block text-left", isUnread ? "text-foreground/75" : "text-instructional", descriptionLineClasses[descriptionLines]), children: notification.description })) : null, hasDetail ? (_jsxs("span", { "data-slot": "notification-item-detail", className: "mt-2 block space-y-0.5 rounded-control bg-muted px-3 py-2 text-left", children: [notification.detailLabel !== undefined ? (_jsx(Typography, { as: "span", variant: "caption", className: "block font-semibold text-foreground", children: notification.detailLabel })) : null, _jsx(Typography, { as: "span", variant: "caption", className: "block whitespace-pre-wrap text-instructional [overflow-wrap:anywhere]", children: notification.detail })] })) : null, notification.actor !== undefined ? (_jsxs(Typography, { as: "span", variant: "bodySm", className: "mt-2 block text-left font-semibold text-foreground", children: [actorLabel, " ", notification.actor] })) : null, hasActions ? (_jsx("span", { className: "mt-4 flex flex-wrap gap-2", children: actions.map((action, index) => {
|
|
179
179
|
var _a, _b;
|
|
180
180
|
return (_jsx(Button, { type: "button", variant: (_a = action.variant) !== null && _a !== void 0 ? _a : (index === 0 ? "outline" : "default"), size: "sm", disabled: action.disabled, className: cn("min-w-24", action.className), onClick: (event) => {
|
|
181
181
|
var _a;
|
package/dist/rich-text-editor.js
CHANGED
|
@@ -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
|
|
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
|
|
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 })] })] })] }));
|
package/dist/select-primitive.js
CHANGED
|
@@ -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,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 };
|