@neasg/design-system 0.4.14 → 0.4.15
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/index.d.ts +4 -4
- package/dist/index.js +2 -2
- package/dist/message-item.js +13 -1
- package/dist/notification.d.ts +8 -1
- package/dist/notification.js +72 -4
- package/dist/popover.d.ts +6 -1
- package/dist/popover.js +4 -2
- package/dist/table-column-visibility.d.ts +2 -1
- package/dist/table-column-visibility.js +3 -2
- package/dist/table.d.ts +12 -1
- package/dist/table.js +118 -7
- package/dist/task-mode-shell.d.ts +5 -1
- package/dist/task-mode-shell.js +18 -4
- package/dist/toaster.js +33 -12
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -11,8 +11,8 @@ export type { CardGridProps, CardListItemProps, CardListProps, CardProps, CardSp
|
|
|
11
11
|
export type { BadgeProps } from "./badge";
|
|
12
12
|
export { MessageAttachmentRow, MessageItem, MessageNewDivider, MessageThread, formatMessageDate, } from "./message-item";
|
|
13
13
|
export type { MessageAttachmentRowProps, MessageItemAttachment, MessageItemData, MessageItemProps, MessageNewDividerProps, MessageThreadProps, } from "./message-item";
|
|
14
|
-
export { NotificationItem, NotificationList, NotificationPopover, NotificationTrigger, } from "./notification";
|
|
15
|
-
export type { NotificationAction, NotificationFilter, NotificationIcon, NotificationItemData, NotificationItemProps, NotificationKind, NotificationListProps, NotificationPopoverProps, NotificationTriggerProps, NotificationTone, } from "./notification";
|
|
14
|
+
export { formatNotificationTimestamp, NotificationItem, NotificationList, NotificationPopover, NotificationTrigger, } from "./notification";
|
|
15
|
+
export type { NotificationAction, NotificationFilter, NotificationIcon, NotificationItemData, NotificationItemProps, NotificationKind, NotificationListProps, NotificationPopoverProps, NotificationTimestamp, NotificationTriggerProps, NotificationTone, FormatNotificationTimestampOptions, } from "./notification";
|
|
16
16
|
export { RoutingTimeline } from "./routing-timeline";
|
|
17
17
|
export type { RoutingTimelineItem, RoutingTimelineItemKind, RoutingTimelineProps, } from "./routing-timeline";
|
|
18
18
|
export { RichTextEditor, formatFileSize, replaceTemplateVariables, sanitizeRichTextHtml, } from "./rich-text-editor";
|
|
@@ -78,7 +78,7 @@ export { RadioGroup } from "./radio-group";
|
|
|
78
78
|
export type { RadioGroupOption, RadioGroupProps } from "./radio-group";
|
|
79
79
|
export { ScrollHint } from "./scroll-hint";
|
|
80
80
|
export type { ScrollHintProps } from "./scroll-hint";
|
|
81
|
-
export { TaskModeShell } from "./task-mode-shell";
|
|
81
|
+
export { TaskModeShell, TASK_MODE_SHELL_ANIMATION_DURATION_MS, } from "./task-mode-shell";
|
|
82
82
|
export type { TaskModeShellProps } from "./task-mode-shell";
|
|
83
83
|
export { useFileUpload } from "./use-file-upload";
|
|
84
84
|
export type { FileUploadProgress, FileUploadResult, FileUploadStatus, UseFileUploadOptions, UseFileUploadReturn, } from "./use-file-upload";
|
|
@@ -132,7 +132,7 @@ export type { TableColumnVisibilityMenuProps } from "./table-column-visibility";
|
|
|
132
132
|
export { useTableSort } from "./use-table-sort";
|
|
133
133
|
export type { UseTableSortOptions, UseTableSortReturn, } from "./use-table-sort";
|
|
134
134
|
export { Table, TableRoot, TableContainer, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell, TableCaption, TableRowSkeleton, TABLE_SKELETON_PRESETS, } from "./table";
|
|
135
|
-
export type { TableColumn, TableColumnWidths, TableProps, TableRowTone, TableSortDirection, TableSortingProps, TableSkeletonConfig, TableRowSkeletonProps, } from "./table";
|
|
135
|
+
export type { TableColumn, TableColumnWidths, TableProps, TableResizeMode, TableRowTone, TableSortDirection, TableSortingProps, TableSkeletonConfig, TableRowSkeletonProps, } from "./table";
|
|
136
136
|
export { Tabs, TabsRoot, TabWithDropdown, type TabsItem, type TabsItemLabel, type TabsItemLabelProps, type TabsProps, TabsList, TabsTrigger, TabsContent, type TabWithDropdownProps, useTabsContext, type TabDropdownSection, } from "./tabs";
|
|
137
137
|
export { Tooltip, TooltipRoot, TooltipTrigger, TooltipContent, TooltipProvider, type TooltipProps, } from "./tooltip";
|
|
138
138
|
export { Toaster, toast } from "./toaster";
|
package/dist/index.js
CHANGED
|
@@ -5,7 +5,7 @@ export { Alert, AlertAction, AlertConsent, alertVariants } from "./alert";
|
|
|
5
5
|
export { Badge, badgeVariants } from "./badge";
|
|
6
6
|
export { Card, CardGrid, CardSplitGrid, CardList, CardListItem, } from "./card";
|
|
7
7
|
export { MessageAttachmentRow, MessageItem, MessageNewDivider, MessageThread, formatMessageDate, } from "./message-item";
|
|
8
|
-
export { NotificationItem, NotificationList, NotificationPopover, NotificationTrigger, } from "./notification";
|
|
8
|
+
export { formatNotificationTimestamp, NotificationItem, NotificationList, NotificationPopover, NotificationTrigger, } from "./notification";
|
|
9
9
|
export { RoutingTimeline } from "./routing-timeline";
|
|
10
10
|
export { RichTextEditor, formatFileSize, replaceTemplateVariables, sanitizeRichTextHtml, } from "./rich-text-editor";
|
|
11
11
|
export { Calendar, CalendarDayButton } from "./calendar";
|
|
@@ -40,7 +40,7 @@ export { FilterPopover, getFilterSelectionLabel } from "./filter-popover";
|
|
|
40
40
|
export { Progress } from "./progress";
|
|
41
41
|
export { RadioGroup } from "./radio-group";
|
|
42
42
|
export { ScrollHint } from "./scroll-hint";
|
|
43
|
-
export { TaskModeShell } from "./task-mode-shell";
|
|
43
|
+
export { TaskModeShell, TASK_MODE_SHELL_ANIMATION_DURATION_MS, } from "./task-mode-shell";
|
|
44
44
|
export { useFileUpload } from "./use-file-upload";
|
|
45
45
|
export { Popover } from "./popover";
|
|
46
46
|
export { PopoverMenuContent, PopoverMenuCheckboxItem, PopoverMenuHeader, PopoverMenuSection, PopoverMenuItem, PopoverMenuDivider, PopoverMenuFooter, PopoverMenuFooterAction, PopoverMenuFooterMeta, PopoverMenuGroup, PopoverMenuGroupLabel, PopoverMenuSearch, PopoverMenuScrollArea, PopoverMenuView, } from "./popover-menu";
|
package/dist/message-item.js
CHANGED
|
@@ -5,9 +5,11 @@ import { FileText } from "lucide-react";
|
|
|
5
5
|
import { DownloadIcon } from "./animated-icons";
|
|
6
6
|
import { AvatarProfile } from "./avatar";
|
|
7
7
|
import { Badge } from "./badge";
|
|
8
|
+
import { formatNotificationTimestamp } from "./notification";
|
|
8
9
|
import { Separator } from "./separator";
|
|
9
10
|
import { Typography } from "./typography";
|
|
10
11
|
import { cn } from "./lib/utils";
|
|
12
|
+
const MESSAGE_TIMESTAMP_REFRESH_MS = 60 * 1000;
|
|
11
13
|
export const formatMessageDate = (date) => {
|
|
12
14
|
const d = new Date(date);
|
|
13
15
|
const hours = d.getHours();
|
|
@@ -52,6 +54,7 @@ export function MessageItem({ message, caseId, showNewBadge = false, newMessageL
|
|
|
52
54
|
var _a;
|
|
53
55
|
const messageRef = React.useRef(null);
|
|
54
56
|
const [hasBeenViewed, setHasBeenViewed] = React.useState(message.isRead);
|
|
57
|
+
const [timestampNow, setTimestampNow] = React.useState(() => new Date());
|
|
55
58
|
const isVisibleEnoughRef = React.useRef(false);
|
|
56
59
|
const isOfficer = message.senderRole === "OFFICER";
|
|
57
60
|
const isApplicant = message.senderRole === "APPLICANT";
|
|
@@ -116,6 +119,13 @@ export function MessageItem({ message, caseId, showNewBadge = false, newMessageL
|
|
|
116
119
|
onMarkAsRead,
|
|
117
120
|
onMarkedAsRead,
|
|
118
121
|
]);
|
|
122
|
+
React.useEffect(() => {
|
|
123
|
+
if (formatTimestamp) {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
const intervalId = window.setInterval(() => setTimestampNow(new Date()), MESSAGE_TIMESTAMP_REFRESH_MS);
|
|
127
|
+
return () => window.clearInterval(intervalId);
|
|
128
|
+
}, [formatTimestamp]);
|
|
119
129
|
const senderName = isOfficer
|
|
120
130
|
? message.officerName || "Officer"
|
|
121
131
|
: isApplicant
|
|
@@ -136,7 +146,9 @@ export function MessageItem({ message, caseId, showNewBadge = false, newMessageL
|
|
|
136
146
|
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-primary [&_a]:underline [&_a:hover]:text-primary/80", "[&_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);
|
|
137
147
|
return (_jsxs(_Fragment, { children: [showUnreadDivider && (_jsx(MessageNewDivider, { children: newMessageLabel })), _jsxs("article", { ref: messageRef, className: cn("min-w-0", className), children: [_jsxs("div", { className: "flex min-w-0 items-start justify-between gap-x-3 gap-y-1", children: [_jsx(AvatarProfile, { fallback: getInitials(initialsName), name: senderName, nameAs: "h3", nameTrailing: 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]" }), _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
|
|
138
148
|
? formatTimestamp(messageDate, message)
|
|
139
|
-
:
|
|
149
|
+
: formatNotificationTimestamp(messageDate, {
|
|
150
|
+
now: timestampNow,
|
|
151
|
+
}) }) })] }), _jsxs("div", { className: "ml-[calc(2.25rem+var(--space-3))] pt-2", children: [_jsx(Typography, { as: "div", variant: "bodySm", color: "inherit", className: richContentClassName, dangerouslySetInnerHTML: { __html: contentHtml } }), attachments.length > 0 ? (_jsx("div", { className: "mt-3 space-y-2", children: attachments.map((attachment, idx) => (_jsx(MessageAttachmentRow, { attachment: attachment, downloadUrl: getAttachmentDownloadUrl === null || getAttachmentDownloadUrl === void 0 ? void 0 : getAttachmentDownloadUrl(attachment, message, downloadCaseId) }, `${attachment.name}-${idx}`))) })) : null] })] })] }));
|
|
140
152
|
}
|
|
141
153
|
export function MessageThread({ messages, caseId, showNewBadge = false, newMessageLabel = "New Message", onMarkAsRead, onMarkedAsRead, getAttachmentDownloadUrl, formatTimestamp, className, itemClassName, contentClassName, }) {
|
|
142
154
|
var _a;
|
package/dist/notification.d.ts
CHANGED
|
@@ -8,6 +8,11 @@ export type NotificationIcon = React.ComponentType<{
|
|
|
8
8
|
className?: string;
|
|
9
9
|
}>;
|
|
10
10
|
export type NotificationFilter = "all" | "unread";
|
|
11
|
+
export type NotificationTimestamp = string | number | Date;
|
|
12
|
+
export interface FormatNotificationTimestampOptions {
|
|
13
|
+
now?: NotificationTimestamp;
|
|
14
|
+
locale?: string | string[];
|
|
15
|
+
}
|
|
11
16
|
export interface NotificationAction {
|
|
12
17
|
id?: string;
|
|
13
18
|
label: React.ReactNode;
|
|
@@ -21,6 +26,7 @@ export interface NotificationItemData {
|
|
|
21
26
|
title: React.ReactNode;
|
|
22
27
|
description?: React.ReactNode;
|
|
23
28
|
meta?: React.ReactNode;
|
|
29
|
+
timestamp?: NotificationTimestamp;
|
|
24
30
|
dateTime?: string;
|
|
25
31
|
unread?: boolean;
|
|
26
32
|
kind?: NotificationKind;
|
|
@@ -75,8 +81,9 @@ export interface NotificationTriggerProps extends Omit<ButtonProps, "children">
|
|
|
75
81
|
label?: React.ReactNode;
|
|
76
82
|
triggerVariant?: "default" | "sidebar";
|
|
77
83
|
}
|
|
84
|
+
declare function formatNotificationTimestamp(timestamp: NotificationTimestamp, { now, locale }?: FormatNotificationTimestampOptions): string;
|
|
78
85
|
declare const NotificationTrigger: React.ForwardRefExoticComponent<NotificationTriggerProps & React.RefAttributes<HTMLButtonElement>>;
|
|
79
86
|
declare function NotificationItem({ notification, density, labelLines, descriptionLines, unreadLabel, className, onClick, onSelect, ...props }: NotificationItemProps): import("react/jsx-runtime").JSX.Element;
|
|
80
87
|
declare function NotificationList({ notifications, density, variant, labelLines, descriptionLines, unreadLabel, emptyState, itemClassName, className, onNotificationClick, ...props }: NotificationListProps): import("react/jsx-runtime").JSX.Element;
|
|
81
88
|
declare function NotificationPopover({ trigger, notifications, title, filter, defaultFilter, onFilterChange, showFilterTabs, height, minHeight, maxHeight, emptyState, listClassName, itemClassName, unreadLabel, markAllAsReadLabel, onNotificationClick, onMarkAllAsRead, contentClassName, align, ...popoverProps }: NotificationPopoverProps): import("react/jsx-runtime").JSX.Element;
|
|
82
|
-
export { NotificationItem, NotificationList, NotificationPopover, NotificationTrigger, };
|
|
89
|
+
export { formatNotificationTimestamp, NotificationItem, NotificationList, NotificationPopover, NotificationTrigger, };
|
package/dist/notification.js
CHANGED
|
@@ -32,6 +32,67 @@ const notificationToneClasses = {
|
|
|
32
32
|
success: "border-status-success-foreground/20 bg-status-success text-status-success-foreground",
|
|
33
33
|
warning: "border-status-warning-foreground/20 bg-status-warning text-status-warning-foreground",
|
|
34
34
|
};
|
|
35
|
+
const MINUTE_MS = 60 * 1000;
|
|
36
|
+
const HOUR_MS = 60 * MINUTE_MS;
|
|
37
|
+
const DAY_MS = 24 * HOUR_MS;
|
|
38
|
+
const WEEK_MS = 7 * DAY_MS;
|
|
39
|
+
const NOTIFICATION_TIMESTAMP_REFRESH_MS = MINUTE_MS;
|
|
40
|
+
function parseNotificationTimestamp(timestamp) {
|
|
41
|
+
if (timestamp === undefined) {
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
const date = timestamp instanceof Date
|
|
45
|
+
? timestamp
|
|
46
|
+
: typeof timestamp === "number"
|
|
47
|
+
? new Date(timestamp)
|
|
48
|
+
: new Date(timestamp);
|
|
49
|
+
return Number.isFinite(date.getTime()) ? date : undefined;
|
|
50
|
+
}
|
|
51
|
+
function formatNotificationTimestamp(timestamp, { now = new Date(), locale } = {}) {
|
|
52
|
+
const date = parseNotificationTimestamp(timestamp);
|
|
53
|
+
const nowDate = parseNotificationTimestamp(now);
|
|
54
|
+
if (!date || !nowDate) {
|
|
55
|
+
return "";
|
|
56
|
+
}
|
|
57
|
+
const elapsedMs = nowDate.getTime() - date.getTime();
|
|
58
|
+
const absoluteElapsedMs = Math.abs(elapsedMs);
|
|
59
|
+
const isPast = elapsedMs >= 0;
|
|
60
|
+
if (absoluteElapsedMs < MINUTE_MS) {
|
|
61
|
+
return "Just now";
|
|
62
|
+
}
|
|
63
|
+
const tense = isPast ? "ago" : "from now";
|
|
64
|
+
if (absoluteElapsedMs < HOUR_MS) {
|
|
65
|
+
const minutes = Math.round(absoluteElapsedMs / MINUTE_MS);
|
|
66
|
+
return `${minutes} min ${tense}`;
|
|
67
|
+
}
|
|
68
|
+
if (absoluteElapsedMs < DAY_MS) {
|
|
69
|
+
const hours = Math.round(absoluteElapsedMs / HOUR_MS);
|
|
70
|
+
return `${hours}h ${tense}`;
|
|
71
|
+
}
|
|
72
|
+
if (isPast && absoluteElapsedMs < 2 * DAY_MS) {
|
|
73
|
+
return "Yesterday";
|
|
74
|
+
}
|
|
75
|
+
if (absoluteElapsedMs < WEEK_MS) {
|
|
76
|
+
const days = Math.round(absoluteElapsedMs / DAY_MS);
|
|
77
|
+
return `${days} days ${tense}`;
|
|
78
|
+
}
|
|
79
|
+
return new Intl.DateTimeFormat(locale, {
|
|
80
|
+
day: "numeric",
|
|
81
|
+
month: "short",
|
|
82
|
+
...(date.getFullYear() === nowDate.getFullYear() ? {} : { year: "numeric" }),
|
|
83
|
+
}).format(date);
|
|
84
|
+
}
|
|
85
|
+
function useNotificationTimestampNow(timestamp) {
|
|
86
|
+
const [now, setNow] = React.useState(() => new Date());
|
|
87
|
+
React.useEffect(() => {
|
|
88
|
+
if (timestamp === undefined) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
const intervalId = window.setInterval(() => setNow(new Date()), NOTIFICATION_TIMESTAMP_REFRESH_MS);
|
|
92
|
+
return () => window.clearInterval(intervalId);
|
|
93
|
+
}, [timestamp]);
|
|
94
|
+
return now;
|
|
95
|
+
}
|
|
35
96
|
const NotificationTrigger = React.forwardRef(({ count = 0, countMax = 9, countSize = "md", hideCountWhenZero = true, isCollapsed = false, label = "Notifications", triggerVariant = "default", className, size, variant = "ghost", "aria-label": ariaLabel, ...props }, ref) => {
|
|
36
97
|
const resolvedAriaLabel = ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : (isCollapsed && typeof label === "string" ? label : undefined);
|
|
37
98
|
return (_jsxs(Button, { ref: ref, type: "button", variant: variant, size: size !== null && size !== void 0 ? size : (isCollapsed ? "icon" : "default"), "aria-label": resolvedAriaLabel, className: cn("relative", triggerVariant === "sidebar" &&
|
|
@@ -58,7 +119,7 @@ function getNotificationTone(notification) {
|
|
|
58
119
|
return ((_a = notification.tone) !== null && _a !== void 0 ? _a : notificationKindTones[(_b = notification.kind) !== null && _b !== void 0 ? _b : "system"]);
|
|
59
120
|
}
|
|
60
121
|
function NotificationItem({ notification, density = "default", labelLines = 2, descriptionLines = 2, unreadLabel = "Unread", className, onClick, onSelect, ...props }) {
|
|
61
|
-
var _a;
|
|
122
|
+
var _a, _b, _c;
|
|
62
123
|
const Icon = getNotificationIcon(notification);
|
|
63
124
|
const tone = getNotificationTone(notification);
|
|
64
125
|
const isUnread = Boolean(notification.unread);
|
|
@@ -66,14 +127,21 @@ function NotificationItem({ notification, density = "default", labelLines = 2, d
|
|
|
66
127
|
const hasActions = actions.length > 0;
|
|
67
128
|
const isInteractive = Boolean(!hasActions && (notification.href || onClick || onSelect));
|
|
68
129
|
const hasHoverSurface = isInteractive || hasActions;
|
|
69
|
-
const
|
|
130
|
+
const timestamp = notification.timestamp;
|
|
131
|
+
const now = useNotificationTimestampNow(timestamp);
|
|
132
|
+
const formattedTimestamp = timestamp !== undefined
|
|
133
|
+
? formatNotificationTimestamp(timestamp, { now })
|
|
134
|
+
: undefined;
|
|
135
|
+
const metaContent = (_b = notification.meta) !== null && _b !== void 0 ? _b : formattedTimestamp;
|
|
136
|
+
const timestampDateTime = (_c = parseNotificationTimestamp(timestamp)) === null || _c === void 0 ? void 0 : _c.toISOString();
|
|
137
|
+
const meta = metaContent ? (timestampDateTime || notification.dateTime ? (_jsx("time", { dateTime: timestampDateTime !== null && timestampDateTime !== void 0 ? timestampDateTime : notification.dateTime, children: metaContent })) : (_jsx("span", { children: metaContent }))) : null;
|
|
70
138
|
const handleClick = (event) => {
|
|
71
139
|
onClick === null || onClick === void 0 ? void 0 : onClick(event);
|
|
72
140
|
if (!event.defaultPrevented) {
|
|
73
141
|
onSelect === null || onSelect === void 0 ? void 0 : onSelect(notification);
|
|
74
142
|
}
|
|
75
143
|
};
|
|
76
|
-
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: "
|
|
144
|
+
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-muted-foreground/70", 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-muted-foreground", descriptionLineClasses[descriptionLines]), children: notification.description })) : null, hasActions ? (_jsx("span", { className: "mt-4 flex flex-wrap gap-2", children: actions.map((action, index) => {
|
|
77
145
|
var _a, _b;
|
|
78
146
|
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) => {
|
|
79
147
|
var _a;
|
|
@@ -118,4 +186,4 @@ function NotificationPopover({ trigger, notifications, title = "Notifications",
|
|
|
118
186
|
{ value: "unread", label: "Unread", content: null },
|
|
119
187
|
] })) : null] }), _jsx(PopoverMenuDivider, { className: "mx-0 my-0 shrink-0 bg-border/90" }), _jsx(PopoverMenuScrollArea, { maxHeight: "max-h-none", className: "scrollbar-none min-h-0 flex-1 space-y-0", children: _jsx(NotificationList, { notifications: visibleNotifications, variant: "plain", emptyState: resolvedEmptyState, itemClassName: cn("py-3", itemClassName), unreadLabel: unreadLabel, onNotificationClick: onNotificationClick, className: cn("gap-0", listClassName) }) }), onMarkAllAsRead ? (_jsx(PopoverMenuFooter, { inset: "flush", className: "border-border/80", children: _jsx(PopoverMenuFooterAction, { onClick: onMarkAllAsRead, disabled: resolvedUnreadCount === 0, children: markAllAsReadLabel }) })) : null] }));
|
|
120
188
|
}
|
|
121
|
-
export { NotificationItem, NotificationList, NotificationPopover, NotificationTrigger, };
|
|
189
|
+
export { formatNotificationTimestamp, NotificationItem, NotificationList, NotificationPopover, NotificationTrigger, };
|
package/dist/popover.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import * as PopoverPrimitive from "@radix-ui/react-popover";
|
|
3
|
+
import { type TooltipProps } from "./tooltip";
|
|
3
4
|
type PopoverRootProps = React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Root>;
|
|
4
5
|
type PopoverContentProps = React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>;
|
|
5
6
|
export interface PopoverProps extends Pick<PopoverRootProps, "defaultOpen" | "modal" | "onOpenChange" | "open">, Omit<PopoverContentProps, "children" | "className"> {
|
|
@@ -7,6 +8,10 @@ export interface PopoverProps extends Pick<PopoverRootProps, "defaultOpen" | "mo
|
|
|
7
8
|
children: React.ReactNode;
|
|
8
9
|
surface?: "panel" | "menu";
|
|
9
10
|
contentClassName?: string;
|
|
11
|
+
triggerTooltip?: React.ReactNode;
|
|
12
|
+
triggerTooltipSide?: TooltipProps["side"];
|
|
13
|
+
triggerTooltipSideOffset?: TooltipProps["sideOffset"];
|
|
14
|
+
triggerTooltipClassName?: TooltipProps["contentClassName"];
|
|
10
15
|
}
|
|
11
|
-
declare function Popover({ defaultOpen, modal, onOpenChange, open, trigger, children, surface, contentClassName, align, sideOffset, ...contentProps }: PopoverProps): import("react/jsx-runtime").JSX.Element;
|
|
16
|
+
declare function Popover({ defaultOpen, modal, onOpenChange, open, trigger, children, surface, contentClassName, triggerTooltip, triggerTooltipSide, triggerTooltipSideOffset, triggerTooltipClassName, align, sideOffset, ...contentProps }: PopoverProps): import("react/jsx-runtime").JSX.Element;
|
|
12
17
|
export { Popover };
|
package/dist/popover.js
CHANGED
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { cn } from "./lib/utils";
|
|
4
4
|
import { PopoverContent, PopoverRoot, PopoverTrigger, } from "./popover-primitive";
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
import { Tooltip } from "./tooltip";
|
|
6
|
+
function Popover({ defaultOpen, modal, onOpenChange, open, trigger, children, surface = "panel", contentClassName, triggerTooltip, triggerTooltipSide, triggerTooltipSideOffset, triggerTooltipClassName, align = "center", sideOffset = 4, ...contentProps }) {
|
|
7
|
+
const triggerElement = _jsx(PopoverTrigger, { asChild: true, children: trigger });
|
|
8
|
+
return (_jsxs(PopoverRoot, { defaultOpen: defaultOpen, modal: modal, onOpenChange: onOpenChange, open: open, children: [triggerTooltip ? (_jsx(Tooltip, { content: triggerTooltip, side: triggerTooltipSide, sideOffset: triggerTooltipSideOffset, contentClassName: triggerTooltipClassName, children: triggerElement })) : (triggerElement), _jsx(PopoverContent, { align: align, sideOffset: sideOffset, className: cn(surface === "menu" && "overflow-hidden p-1", contentClassName), ...contentProps, children: children })] }));
|
|
7
9
|
}
|
|
8
10
|
export { Popover };
|
|
@@ -11,6 +11,7 @@ export interface TableColumnVisibilityMenuProps<Row> extends PopoverPlacementPro
|
|
|
11
11
|
trigger?: React.ReactElement;
|
|
12
12
|
triggerLabel?: string;
|
|
13
13
|
triggerClassName?: string;
|
|
14
|
+
triggerTooltip?: React.ReactNode;
|
|
14
15
|
contentClassName?: string;
|
|
15
16
|
className?: string;
|
|
16
17
|
title?: React.ReactNode;
|
|
@@ -19,5 +20,5 @@ export interface TableColumnVisibilityMenuProps<Row> extends PopoverPlacementPro
|
|
|
19
20
|
emptyMessage?: React.ReactNode;
|
|
20
21
|
minVisibleColumns?: number;
|
|
21
22
|
}
|
|
22
|
-
declare function TableColumnVisibilityMenu<Row>({ columns, visibleColumnKeys, onVisibleColumnKeysChange, defaultVisibleColumnKeys, trigger, triggerLabel, triggerClassName, contentClassName, className, title, searchPlaceholder, restoreDefaultsLabel, emptyMessage, minVisibleColumns, align, sideOffset, side, }: TableColumnVisibilityMenuProps<Row>): import("react/jsx-runtime").JSX.Element;
|
|
23
|
+
declare function TableColumnVisibilityMenu<Row>({ columns, visibleColumnKeys, onVisibleColumnKeysChange, defaultVisibleColumnKeys, trigger, triggerLabel, triggerClassName, triggerTooltip, contentClassName, className, title, searchPlaceholder, restoreDefaultsLabel, emptyMessage, minVisibleColumns, align, sideOffset, side, }: TableColumnVisibilityMenuProps<Row>): import("react/jsx-runtime").JSX.Element;
|
|
23
24
|
export { TableColumnVisibilityMenu };
|
|
@@ -52,7 +52,8 @@ function SortableColumnOption({ columnKey, label, checked, disabled, onToggle, }
|
|
|
52
52
|
? "cursor-grab active:cursor-grabbing"
|
|
53
53
|
: "cursor-not-allowed opacity-40"), ...(checked ? { ...attributes, ...listeners } : {}), children: _jsx(GripVertical, { className: "h-4 w-4", "aria-hidden": "true" }) }), _jsx(Checkbox, { id: checkboxId, checked: checked, disabled: disabled, onChange: onToggle, "aria-label": label }), _jsx("label", { htmlFor: checkboxId, className: cn("min-w-0 flex-1 cursor-pointer truncate", disabled && "cursor-not-allowed text-muted-foreground"), children: label })] }));
|
|
54
54
|
}
|
|
55
|
-
function TableColumnVisibilityMenu({ columns, visibleColumnKeys, onVisibleColumnKeysChange, defaultVisibleColumnKeys, trigger, triggerLabel = "Customize columns", triggerClassName, contentClassName, className, title = "Customize columns", searchPlaceholder = "Search columns", restoreDefaultsLabel = "Restore defaults", emptyMessage = "No columns found", minVisibleColumns = 1, align = "end", sideOffset = 4, side, }) {
|
|
55
|
+
function TableColumnVisibilityMenu({ columns, visibleColumnKeys, onVisibleColumnKeysChange, defaultVisibleColumnKeys, trigger, triggerLabel = "Customize columns", triggerClassName, triggerTooltip, contentClassName, className, title = "Customize columns", searchPlaceholder = "Search columns", restoreDefaultsLabel = "Restore defaults", emptyMessage = "No columns found", minVisibleColumns = 1, align = "end", sideOffset = 4, side, }) {
|
|
56
|
+
const resolvedTriggerTooltip = triggerTooltip === undefined && !trigger ? triggerLabel : triggerTooltip;
|
|
56
57
|
const [query, setQuery] = React.useState("");
|
|
57
58
|
const sensors = useSensors(useSensor(PointerSensor, {
|
|
58
59
|
activationConstraint: {
|
|
@@ -111,7 +112,7 @@ function TableColumnVisibilityMenu({ columns, visibleColumnKeys, onVisibleColumn
|
|
|
111
112
|
commitVisibleColumnKeys(arrayMove(currentKeys, oldIndex, newIndex));
|
|
112
113
|
}, [commitVisibleColumnKeys, currentKeys]);
|
|
113
114
|
const defaultTrigger = (_jsx(Button, { type: "button", variant: "outline", size: "icon", "aria-label": triggerLabel, className: triggerClassName, children: _jsx(Columns3, { "aria-hidden": "true" }) }));
|
|
114
|
-
return (_jsx(Popover, { trigger: trigger !== null && trigger !== void 0 ? trigger : defaultTrigger, align: align, side: side, sideOffset: sideOffset, contentClassName: cn("w-80 p-0", contentClassName), "aria-labelledby": title ? titleId : undefined, children: _jsxs("div", { className: cn("flex max-h-96 flex-col", className), children: [_jsxs("div", { className: "border-b p-2", children: [_jsx("label", { htmlFor: searchInputId, className: "sr-only", children: searchPlaceholder }), _jsx(SearchInputShell, { children: _jsx(InputControl, { id: searchInputId, value: query, onChange: (event) => setQuery(event.target.value), placeholder: searchPlaceholder, className: "h-8 bg-background pl-8 pr-2" }) })] }), _jsxs("div", { className: "min-h-0 flex-1 overflow-y-auto p-1", children: [title ? (_jsx(PopoverMenuGroupLabel, { id: titleId, children: title })) : null, filteredColumns.length ? (_jsx(DndContext, { sensors: sensors, collisionDetection: closestCenter, onDragEnd: handleDragEnd, children: _jsx(SortableContext, { items: filteredColumns.map((column) => column.key), strategy: verticalListSortingStrategy, children: filteredColumns.map((column) => {
|
|
115
|
+
return (_jsx(Popover, { trigger: trigger !== null && trigger !== void 0 ? trigger : defaultTrigger, triggerTooltip: resolvedTriggerTooltip, align: align, side: side, sideOffset: sideOffset, contentClassName: cn("w-80 p-0", contentClassName), "aria-labelledby": title ? titleId : undefined, children: _jsxs("div", { className: cn("flex max-h-96 flex-col", className), children: [_jsxs("div", { className: "border-b p-2", children: [_jsx("label", { htmlFor: searchInputId, className: "sr-only", children: searchPlaceholder }), _jsx(SearchInputShell, { children: _jsx(InputControl, { id: searchInputId, value: query, onChange: (event) => setQuery(event.target.value), placeholder: searchPlaceholder, className: "h-8 bg-background pl-8 pr-2" }) })] }), _jsxs("div", { className: "min-h-0 flex-1 overflow-y-auto p-1", children: [title ? (_jsx(PopoverMenuGroupLabel, { id: titleId, children: title })) : null, filteredColumns.length ? (_jsx(DndContext, { sensors: sensors, collisionDetection: closestCenter, onDragEnd: handleDragEnd, children: _jsx(SortableContext, { items: filteredColumns.map((column) => column.key), strategy: verticalListSortingStrategy, children: filteredColumns.map((column) => {
|
|
115
116
|
const label = getColumnVisibilityLabel(column);
|
|
116
117
|
const checked = visibleColumnKeySet.has(column.key);
|
|
117
118
|
const disabled = checked && visibleColumnCount <= requiredVisibleColumns;
|
package/dist/table.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ interface TableContainerProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
|
8
8
|
}
|
|
9
9
|
declare const TableContainer: React.ForwardRefExoticComponent<TableContainerProps & React.RefAttributes<HTMLDivElement>>;
|
|
10
10
|
export type TableColumnWidths = Record<string, number>;
|
|
11
|
+
export type TableResizeMode = "pair" | "grow";
|
|
11
12
|
declare const TableHeader: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLTableSectionElement> & React.RefAttributes<HTMLTableSectionElement>>;
|
|
12
13
|
declare const TableBody: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLTableSectionElement> & React.RefAttributes<HTMLTableSectionElement>>;
|
|
13
14
|
declare const TableFooter: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLTableSectionElement> & React.RefAttributes<HTMLTableSectionElement>>;
|
|
@@ -130,6 +131,8 @@ export interface TableProps<Row> extends Omit<React.HTMLAttributes<HTMLDivElemen
|
|
|
130
131
|
rowTone?: TableRowTone | ((row: Row, index: number) => TableRowTone | undefined);
|
|
131
132
|
/** Constrains the table container height so the table body scrolls instead of the surrounding surface. */
|
|
132
133
|
maxHeight?: React.CSSProperties["maxHeight"];
|
|
134
|
+
/** Sets a minimum table container height. */
|
|
135
|
+
minHeight?: React.CSSProperties["minHeight"];
|
|
133
136
|
sorting?: TableSortingProps;
|
|
134
137
|
pagination?: Omit<PaginationProps, "className">;
|
|
135
138
|
loading?: boolean;
|
|
@@ -138,6 +141,8 @@ export interface TableProps<Row> extends Omit<React.HTMLAttributes<HTMLDivElemen
|
|
|
138
141
|
visibleColumnKeys?: readonly string[];
|
|
139
142
|
/** When true, every column is resizable unless its column config sets `resizable: false`. */
|
|
140
143
|
resizableColumns?: boolean;
|
|
144
|
+
/** `pair` preserves total table width; `grow` resizes one column and lets the table widen. */
|
|
145
|
+
columnResizeMode?: TableResizeMode;
|
|
141
146
|
/** Controlled pixel widths keyed by column key. */
|
|
142
147
|
columnWidths?: TableColumnWidths;
|
|
143
148
|
/** Initial pixel widths keyed by column key for uncontrolled resizing. */
|
|
@@ -146,10 +151,16 @@ export interface TableProps<Row> extends Omit<React.HTMLAttributes<HTMLDivElemen
|
|
|
146
151
|
onColumnWidthsChange?: (columnWidths: TableColumnWidths) => void;
|
|
147
152
|
/** Optional hook for decorating resize handles without replacing table sizing behavior. */
|
|
148
153
|
renderColumnResizeHandle?: (props: TableColumnResizeHandleRenderProps<Row>) => React.ReactNode;
|
|
154
|
+
/** Forces the browser table layout mode. Resizable tables always use fixed layout. */
|
|
155
|
+
tableLayout?: "auto" | "fixed";
|
|
156
|
+
/** Centers the empty state inside the table body when there are no rows. */
|
|
157
|
+
centerEmptyState?: boolean;
|
|
158
|
+
/** Minimum height for the centered empty-state area. */
|
|
159
|
+
emptyStateMinHeight?: React.CSSProperties["minHeight"];
|
|
149
160
|
/** When true, applies alternating row backgrounds for easier scanning. */
|
|
150
161
|
striped?: boolean;
|
|
151
162
|
/** When set, rows become interactive: cursor-pointer, hover highlight, and click handling. */
|
|
152
163
|
onRowClick?: (row: Row, index: number) => void;
|
|
153
164
|
}
|
|
154
|
-
declare function Table<Row>({ columns, rows, getRowKey, emptyState, toolbar, caption, className, containerClassName, tableClassName, rowClassName, rowTone, maxHeight, sorting, pagination, loading, loadingRows, visibleColumnKeys, resizableColumns, columnWidths, defaultColumnWidths, onColumnWidthsChange, renderColumnResizeHandle, striped, onRowClick, onScroll, style, ...props }: TableProps<Row>): import("react/jsx-runtime").JSX.Element;
|
|
165
|
+
declare function Table<Row>({ columns, rows, getRowKey, emptyState, toolbar, caption, className, containerClassName, tableClassName, rowClassName, rowTone, maxHeight, minHeight, sorting, pagination, loading, loadingRows, visibleColumnKeys, resizableColumns, columnResizeMode, columnWidths, defaultColumnWidths, onColumnWidthsChange, renderColumnResizeHandle, tableLayout, centerEmptyState, emptyStateMinHeight, striped, onRowClick, onScroll, style, ...props }: TableProps<Row>): import("react/jsx-runtime").JSX.Element;
|
|
155
166
|
export { Table, TableRoot, TableContainer, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell, TableCaption, SortableTableHead, TableRowSkeleton, };
|
package/dist/table.js
CHANGED
|
@@ -14,6 +14,9 @@ TableContainer.displayName = "TableContainer";
|
|
|
14
14
|
const DEFAULT_COLUMN_RESIZE_MIN_WIDTH = 64;
|
|
15
15
|
const DEFAULT_COLUMN_RESIZE_START_WIDTH = 160;
|
|
16
16
|
const COLUMN_RESIZE_KEYBOARD_STEP = 16;
|
|
17
|
+
const TABLE_MIN_WIDTH_CSS_VAR = "--table-min-width";
|
|
18
|
+
const DEFAULT_TABLE_MIN_HEIGHT = "var(--table-min-height, var(--app-table-min-height, 24rem))";
|
|
19
|
+
const DEFAULT_CENTERED_EMPTY_STATE_MIN_HEIGHT = "calc(var(--table-min-height, var(--app-table-min-height, 24rem)) - var(--table-empty-state-offset, var(--app-table-empty-state-offset, 5.75rem)))";
|
|
17
20
|
function getTableColumnSizingStyle({ style, width, minWidth, maxWidth, treatWidthAsMinWidth = true, }) {
|
|
18
21
|
const resolvedMinWidth = minWidth !== null && minWidth !== void 0 ? minWidth : (treatWidthAsMinWidth ? width : undefined);
|
|
19
22
|
return {
|
|
@@ -101,6 +104,28 @@ function getColumnResizeBaseWidth(column, columnWidths, elementWidth) {
|
|
|
101
104
|
var _a, _b, _c, _d;
|
|
102
105
|
return ((_d = (_c = (_b = (_a = columnWidths[column.key]) !== null && _a !== void 0 ? _a : parsePixelSize(column.width)) !== null && _b !== void 0 ? _b : (elementWidth && elementWidth > 0 ? elementWidth : undefined)) !== null && _c !== void 0 ? _c : parsePixelSize(column.minWidth)) !== null && _d !== void 0 ? _d : DEFAULT_COLUMN_RESIZE_START_WIDTH);
|
|
103
106
|
}
|
|
107
|
+
function hasColumnWidthOverrides(columnWidths) {
|
|
108
|
+
return Object.keys(columnWidths).length > 0;
|
|
109
|
+
}
|
|
110
|
+
function getMeasuredColumnWidths(resizeHandle, columns, fallbackColumnWidths) {
|
|
111
|
+
const table = resizeHandle.closest("table");
|
|
112
|
+
const headerCells = table === null || table === void 0 ? void 0 : table.querySelectorAll("thead th");
|
|
113
|
+
if (!(headerCells === null || headerCells === void 0 ? void 0 : headerCells.length)) {
|
|
114
|
+
return fallbackColumnWidths;
|
|
115
|
+
}
|
|
116
|
+
return columns.reduce((widths, column, index) => {
|
|
117
|
+
var _a;
|
|
118
|
+
const measuredWidth = (_a = headerCells.item(index)) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect().width;
|
|
119
|
+
widths[column.key] =
|
|
120
|
+
measuredWidth && Number.isFinite(measuredWidth) && measuredWidth > 0
|
|
121
|
+
? Math.round(measuredWidth)
|
|
122
|
+
: getColumnResizeBaseWidth(column, fallbackColumnWidths);
|
|
123
|
+
return widths;
|
|
124
|
+
}, {});
|
|
125
|
+
}
|
|
126
|
+
function getTableMinWidth(columns, columnWidths) {
|
|
127
|
+
return columns.reduce((total, column) => total + getColumnResizeBaseWidth(column, columnWidths), 0);
|
|
128
|
+
}
|
|
104
129
|
function getColumnResizeLabel(column) {
|
|
105
130
|
if (column.visibilityLabel) {
|
|
106
131
|
return column.visibilityLabel;
|
|
@@ -243,6 +268,26 @@ const TableColumnResizeHandle = React.forwardRef(function TableColumnResizeHandl
|
|
|
243
268
|
: COLUMN_RESIZE_KEYBOARD_STEP);
|
|
244
269
|
}, className: cn("group absolute right-0 top-0 z-[1] flex h-full w-4 cursor-col-resize touch-none items-center justify-center focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2", className), children: _jsx("span", { "aria-hidden": "true", className: "h-6 w-px rounded-full bg-[hsl(var(--table-border))] transition-colors group-hover:bg-primary group-focus-visible:bg-primary" }) }));
|
|
245
270
|
});
|
|
271
|
+
const TableColumnGrowResizeHandle = React.forwardRef(function TableColumnGrowResizeHandle({ column, currentWidth, minWidth, maxWidth, onResizeStart, onResizeByKeyboard, className, onClick, ...props }, ref) {
|
|
272
|
+
const label = getColumnResizeLabel(column);
|
|
273
|
+
return (_jsx("button", { ...props, ref: ref, type: "button", "aria-label": `Resize ${label} column`, title: `Resize ${label} column`, "aria-valuenow": currentWidth, "aria-valuemin": minWidth, "aria-valuemax": maxWidth, onPointerDown: (event) => onResizeStart(column, event), onClick: (event) => {
|
|
274
|
+
onClick === null || onClick === void 0 ? void 0 : onClick(event);
|
|
275
|
+
if (event.defaultPrevented) {
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
event.preventDefault();
|
|
279
|
+
event.stopPropagation();
|
|
280
|
+
}, onKeyDown: (event) => {
|
|
281
|
+
if (event.key !== "ArrowLeft" && event.key !== "ArrowRight") {
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
event.preventDefault();
|
|
285
|
+
event.stopPropagation();
|
|
286
|
+
onResizeByKeyboard(column, event.key === "ArrowLeft"
|
|
287
|
+
? -COLUMN_RESIZE_KEYBOARD_STEP
|
|
288
|
+
: COLUMN_RESIZE_KEYBOARD_STEP);
|
|
289
|
+
}, className: cn("group absolute right-0 top-0 z-[1] flex h-full w-4 cursor-col-resize touch-none items-center justify-center focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2", className), children: _jsx("span", { "aria-hidden": "true", className: "h-6 w-px rounded-full bg-[hsl(var(--table-border))] transition-colors group-hover:bg-primary group-focus-visible:bg-primary" }) }));
|
|
290
|
+
});
|
|
246
291
|
function getDefaultSkeleton(column) {
|
|
247
292
|
var _a, _b;
|
|
248
293
|
return {
|
|
@@ -282,15 +327,21 @@ function getVisibleColumns(columns, visibleColumnKeys) {
|
|
|
282
327
|
function isStickyResizeBoundary(column, nextColumn) {
|
|
283
328
|
return Boolean(column.sticky === "right" || nextColumn.sticky);
|
|
284
329
|
}
|
|
285
|
-
function Table({ columns, rows, getRowKey, emptyState = (_jsx(EmptyState, { message: "No data available", description: "There are no rows to display in this table yet.", className: "border-0 bg-transparent px-0 py-6" })), toolbar, caption, className, containerClassName, tableClassName, rowClassName, rowTone, maxHeight, sorting, pagination, loading = false, loadingRows = 5, visibleColumnKeys, resizableColumns = false, columnWidths, defaultColumnWidths, onColumnWidthsChange, renderColumnResizeHandle, striped = false, onRowClick, onScroll, style, ...props }) {
|
|
330
|
+
function Table({ columns, rows, getRowKey, emptyState = (_jsx(EmptyState, { message: "No data available", description: "There are no rows to display in this table yet.", className: "border-0 bg-transparent px-0 py-6" })), toolbar, caption, className, containerClassName, tableClassName, rowClassName, rowTone, maxHeight, minHeight, sorting, pagination, loading = false, loadingRows = 5, visibleColumnKeys, resizableColumns = false, columnResizeMode = "pair", columnWidths, defaultColumnWidths, onColumnWidthsChange, renderColumnResizeHandle, tableLayout, centerEmptyState = false, emptyStateMinHeight = DEFAULT_CENTERED_EMPTY_STATE_MIN_HEIGHT, striped = false, onRowClick, onScroll, style, ...props }) {
|
|
286
331
|
const visibleColumns = getVisibleColumns(columns, visibleColumnKeys);
|
|
332
|
+
const isGrowResizeMode = columnResizeMode === "grow";
|
|
287
333
|
const isColumnResizingEnabled = resizableColumns || visibleColumns.some((column) => column.resizable);
|
|
288
334
|
// Use auto layout by default so the browser can grow a column to contain its
|
|
289
335
|
// nowrap header. Resizable columns need fixed layout so neighbour columns do
|
|
290
336
|
// not redistribute width while a handle is dragged.
|
|
291
|
-
const shouldUseFixedLayout = isColumnResizingEnabled;
|
|
337
|
+
const shouldUseFixedLayout = tableLayout === "fixed" || isColumnResizingEnabled;
|
|
292
338
|
const [uncontrolledColumnWidths, setUncontrolledColumnWidths] = React.useState(() => ({ ...(defaultColumnWidths !== null && defaultColumnWidths !== void 0 ? defaultColumnWidths : {}) }));
|
|
293
339
|
const resolvedColumnWidths = columnWidths !== null && columnWidths !== void 0 ? columnWidths : uncontrolledColumnWidths;
|
|
340
|
+
const hasResolvedColumnWidths = hasColumnWidthOverrides(resolvedColumnWidths);
|
|
341
|
+
const growTableMinWidth = isGrowResizeMode
|
|
342
|
+
? getTableMinWidth(visibleColumns, resolvedColumnWidths)
|
|
343
|
+
: undefined;
|
|
344
|
+
const resolvedMinHeight = minHeight !== null && minHeight !== void 0 ? minHeight : (centerEmptyState ? DEFAULT_TABLE_MIN_HEIGHT : undefined);
|
|
294
345
|
const columnWidthsRef = React.useRef(resolvedColumnWidths);
|
|
295
346
|
const resizeCleanupRef = React.useRef(null);
|
|
296
347
|
const tableContainerRef = React.useRef(null);
|
|
@@ -355,6 +406,17 @@ function Table({ columns, rows, getRowKey, emptyState = (_jsx(EmptyState, { mess
|
|
|
355
406
|
const resizeColumnByKeyboard = React.useCallback((column, nextColumn, delta) => {
|
|
356
407
|
resizeColumnPairByDelta(column, nextColumn, delta);
|
|
357
408
|
}, [resizeColumnPairByDelta]);
|
|
409
|
+
const resizeGrowColumn = React.useCallback((column, width, baseColumnWidths = columnWidthsRef.current) => {
|
|
410
|
+
const nextWidth = clampColumnResizeWidth(column, width);
|
|
411
|
+
commitColumnWidths((currentColumnWidths) => ({
|
|
412
|
+
...currentColumnWidths,
|
|
413
|
+
...baseColumnWidths,
|
|
414
|
+
[column.key]: nextWidth,
|
|
415
|
+
}));
|
|
416
|
+
}, [commitColumnWidths]);
|
|
417
|
+
const resizeGrowColumnByKeyboard = React.useCallback((column, delta) => {
|
|
418
|
+
resizeGrowColumn(column, getColumnResizeBaseWidth(column, columnWidthsRef.current) + delta);
|
|
419
|
+
}, [resizeGrowColumn]);
|
|
358
420
|
const startColumnResize = React.useCallback((column, nextColumn, event) => {
|
|
359
421
|
var _a;
|
|
360
422
|
event.preventDefault();
|
|
@@ -375,13 +437,47 @@ function Table({ columns, rows, getRowKey, emptyState = (_jsx(EmptyState, { mess
|
|
|
375
437
|
const cleanup = () => {
|
|
376
438
|
ownerDocument.removeEventListener("pointermove", handlePointerMove);
|
|
377
439
|
ownerDocument.removeEventListener("pointerup", handlePointerUp);
|
|
440
|
+
ownerDocument.removeEventListener("pointercancel", handlePointerUp);
|
|
378
441
|
ownerDocument.documentElement.style.cursor = previousCursor;
|
|
379
442
|
resizeCleanupRef.current = null;
|
|
380
443
|
};
|
|
381
444
|
resizeCleanupRef.current = cleanup;
|
|
382
445
|
ownerDocument.addEventListener("pointermove", handlePointerMove);
|
|
383
446
|
ownerDocument.addEventListener("pointerup", handlePointerUp);
|
|
447
|
+
ownerDocument.addEventListener("pointercancel", handlePointerUp);
|
|
384
448
|
}, [resizeColumnPairByDelta]);
|
|
449
|
+
const startGrowColumnResize = React.useCallback((column, event) => {
|
|
450
|
+
var _a, _b;
|
|
451
|
+
event.preventDefault();
|
|
452
|
+
event.stopPropagation();
|
|
453
|
+
(_a = resizeCleanupRef.current) === null || _a === void 0 ? void 0 : _a.call(resizeCleanupRef);
|
|
454
|
+
const ownerDocument = event.currentTarget.ownerDocument;
|
|
455
|
+
const startX = event.clientX;
|
|
456
|
+
const startColumnWidths = hasColumnWidthOverrides(columnWidthsRef.current)
|
|
457
|
+
? columnWidthsRef.current
|
|
458
|
+
: getMeasuredColumnWidths(event.currentTarget, visibleColumns, columnWidthsRef.current);
|
|
459
|
+
const startWidth = (_b = startColumnWidths[column.key]) !== null && _b !== void 0 ? _b : getColumnResizeBaseWidth(column, startColumnWidths);
|
|
460
|
+
const previousCursor = ownerDocument.documentElement.style.cursor;
|
|
461
|
+
ownerDocument.documentElement.style.cursor = "col-resize";
|
|
462
|
+
const handlePointerMove = (pointerEvent) => {
|
|
463
|
+
resizeGrowColumn(column, startWidth + pointerEvent.clientX - startX, startColumnWidths);
|
|
464
|
+
};
|
|
465
|
+
const handlePointerUp = () => {
|
|
466
|
+
var _a;
|
|
467
|
+
(_a = resizeCleanupRef.current) === null || _a === void 0 ? void 0 : _a.call(resizeCleanupRef);
|
|
468
|
+
};
|
|
469
|
+
const cleanup = () => {
|
|
470
|
+
ownerDocument.removeEventListener("pointermove", handlePointerMove);
|
|
471
|
+
ownerDocument.removeEventListener("pointerup", handlePointerUp);
|
|
472
|
+
ownerDocument.removeEventListener("pointercancel", handlePointerUp);
|
|
473
|
+
ownerDocument.documentElement.style.cursor = previousCursor;
|
|
474
|
+
resizeCleanupRef.current = null;
|
|
475
|
+
};
|
|
476
|
+
resizeCleanupRef.current = cleanup;
|
|
477
|
+
ownerDocument.addEventListener("pointermove", handlePointerMove);
|
|
478
|
+
ownerDocument.addEventListener("pointerup", handlePointerUp);
|
|
479
|
+
ownerDocument.addEventListener("pointercancel", handlePointerUp);
|
|
480
|
+
}, [resizeGrowColumn, visibleColumns]);
|
|
385
481
|
const renderResizeHandle = React.useCallback((column, columnIndex) => {
|
|
386
482
|
var _a, _b;
|
|
387
483
|
const nextColumn = visibleColumns[columnIndex + 1];
|
|
@@ -394,18 +490,25 @@ function Table({ columns, rows, getRowKey, emptyState = (_jsx(EmptyState, { mess
|
|
|
394
490
|
if (stickyResizeBoundary) {
|
|
395
491
|
return null;
|
|
396
492
|
}
|
|
397
|
-
const
|
|
398
|
-
|
|
399
|
-
|
|
493
|
+
const currentWidth = isGrowResizeMode
|
|
494
|
+
? getColumnResizeBaseWidth(column, resolvedColumnWidths)
|
|
495
|
+
: getResolvedResizableColumnWidth(column, resolvedColumnWidths);
|
|
496
|
+
const maxWidth = Number.isFinite(getColumnResizeMaxWidth(column))
|
|
497
|
+
? getColumnResizeMaxWidth(column)
|
|
498
|
+
: undefined;
|
|
499
|
+
const handle = isGrowResizeMode ? (_jsx(TableColumnGrowResizeHandle, { column: column, currentWidth: currentWidth, minWidth: getColumnResizeMinWidth(column), maxWidth: maxWidth, onResizeStart: startGrowColumnResize, onResizeByKeyboard: resizeGrowColumnByKeyboard })) : (_jsx(TableColumnResizeHandle, { column: column, nextColumn: nextColumn, currentWidth: currentWidth, minWidth: getColumnResizeMinWidth(column), maxWidth: maxWidth, onResizeStart: startColumnResize, onResizeByKeyboard: resizeColumnByKeyboard }));
|
|
400
500
|
if (renderColumnResizeHandle) {
|
|
401
501
|
return renderColumnResizeHandle({ column, nextColumn, handle });
|
|
402
502
|
}
|
|
403
503
|
return handle;
|
|
404
504
|
}, [
|
|
505
|
+
isGrowResizeMode,
|
|
405
506
|
resizableColumns,
|
|
406
507
|
renderColumnResizeHandle,
|
|
508
|
+
resizeGrowColumnByKeyboard,
|
|
407
509
|
resizeColumnByKeyboard,
|
|
408
510
|
resolvedColumnWidths,
|
|
511
|
+
startGrowColumnResize,
|
|
409
512
|
startColumnResize,
|
|
410
513
|
visibleColumns,
|
|
411
514
|
]);
|
|
@@ -413,10 +516,18 @@ function Table({ columns, rows, getRowKey, emptyState = (_jsx(EmptyState, { mess
|
|
|
413
516
|
onScroll === null || onScroll === void 0 ? void 0 : onScroll(event);
|
|
414
517
|
updateStickyScrollState(event.currentTarget);
|
|
415
518
|
}, [onScroll, updateStickyScrollState]);
|
|
519
|
+
const resolvedEmptyState = centerEmptyState ? (_jsx("div", { "data-slot": "table-empty-state", className: "flex w-full min-w-0 items-center justify-center whitespace-normal text-center [&>*]:mx-auto", style: { minHeight: emptyStateMinHeight }, children: emptyState })) : (emptyState);
|
|
416
520
|
const container = (_jsx(TableContainer, { ref: tableContainerRef, onScroll: handleTableContainerScroll, className: cn("w-full", loading && "pointer-events-none select-none", className, containerClassName), style: {
|
|
417
521
|
...style,
|
|
522
|
+
...(growTableMinWidth !== undefined
|
|
523
|
+
? { [TABLE_MIN_WIDTH_CSS_VAR]: `${growTableMinWidth}px` }
|
|
524
|
+
: {}),
|
|
418
525
|
...(maxHeight !== undefined ? { maxHeight } : {}),
|
|
419
|
-
|
|
526
|
+
...(resolvedMinHeight !== undefined ? { minHeight: resolvedMinHeight } : {}),
|
|
527
|
+
}, ...props, children: _jsxs(TableRoot, { className: cn(shouldUseFixedLayout && "table-fixed", isGrowResizeMode &&
|
|
528
|
+
(hasResolvedColumnWidths
|
|
529
|
+
? "w-[var(--table-min-width)]"
|
|
530
|
+
: "min-w-[var(--table-min-width)]"), tableClassName), children: [caption ? _jsx(TableCaption, { children: caption }) : null, _jsx("colgroup", { children: visibleColumns.map((column) => (_jsx("col", { style: getTableColumnSizingStyle({
|
|
420
531
|
width: getRenderedColumnWidth({
|
|
421
532
|
column,
|
|
422
533
|
columnWidths: resolvedColumnWidths,
|
|
@@ -458,7 +569,7 @@ function Table({ columns, rows, getRowKey, emptyState = (_jsx(EmptyState, { mess
|
|
|
458
569
|
: null);
|
|
459
570
|
return (_jsx(TableCell, { width: columnWidth, minWidth: getRenderedColumnMinWidth(column, isColumnResizingEnabled), maxWidth: getRenderedColumnMaxWidth(column, isColumnResizingEnabled), wrap: column.wrap, treatWidthAsMinWidth: !isColumnResizingEnabled, containOverflow: isColumnResizingEnabled, className: cn(alignClassName(column.align), stickyClassName(column.sticky, "cell", getStickyShadowVisibility(column.sticky, stickyScrollState)), column.cellClassName), children: value }, column.key));
|
|
460
571
|
}) }, getRowKey(row, rowIndex)));
|
|
461
|
-
})) : (_jsx(TableRow, { className: "cursor-default hover:bg-card", children: _jsx(TableCell, { colSpan: Math.max(visibleColumns.length, 1), className: "p-6", children:
|
|
572
|
+
})) : (_jsx(TableRow, { className: "cursor-default hover:bg-card", children: _jsx(TableCell, { colSpan: Math.max(visibleColumns.length, 1), className: "p-6", children: resolvedEmptyState }) })) })] }) }));
|
|
462
573
|
if (!pagination) {
|
|
463
574
|
return (_jsxs("div", { className: "space-y-4", children: [toolbar, container] }));
|
|
464
575
|
}
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
+
import { type BackButtonProps } from "./back-button";
|
|
3
|
+
export declare const TASK_MODE_SHELL_ANIMATION_DURATION_MS = 250;
|
|
2
4
|
export interface TaskModeShellProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "children"> {
|
|
3
|
-
header
|
|
5
|
+
header?: React.ReactNode;
|
|
4
6
|
children: React.ReactNode;
|
|
5
7
|
loadingProgress?: number;
|
|
6
8
|
showLoadingBar?: boolean;
|
|
7
9
|
loadingLabel?: string;
|
|
8
10
|
ready?: boolean;
|
|
9
11
|
exiting?: boolean;
|
|
12
|
+
backButtonProps?: BackButtonProps;
|
|
10
13
|
headerClassName?: string;
|
|
14
|
+
headerContentClassName?: string;
|
|
11
15
|
contentOffsetClassName?: string;
|
|
12
16
|
bodyClassName?: string;
|
|
13
17
|
mainPanelClassName?: string;
|
package/dist/task-mode-shell.js
CHANGED
|
@@ -3,26 +3,39 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import { GripVertical } from "lucide-react";
|
|
5
5
|
import { cn } from "./lib/utils";
|
|
6
|
+
import { BackButton } from "./back-button";
|
|
6
7
|
import { rightPanelEdgeClassName, rightPanelEdgeClosedClassName, rightPanelEdgeDividerClassName, rightPanelEdgeOpenClassName, rightPanelResizeHandleSurfaceClassName, } from "./layout-right-panel-edge";
|
|
7
8
|
import { Progress } from "./progress";
|
|
8
9
|
const TASK_MODE_SIDE_PANEL_DEFAULT_SIZE = 50;
|
|
9
10
|
const TASK_MODE_SIDE_PANEL_MIN_SIZE = 28;
|
|
10
11
|
const TASK_MODE_SIDE_PANEL_MAX_SIZE = 72;
|
|
11
12
|
const TASK_MODE_SIDE_PANEL_SIZE_CSS_VAR = "--task-mode-side-panel-size";
|
|
13
|
+
export const TASK_MODE_SHELL_ANIMATION_DURATION_MS = 250;
|
|
12
14
|
function clampSidePanelSize(size, minSize, maxSize) {
|
|
13
15
|
return Math.min(Math.max(size, minSize), maxSize);
|
|
14
16
|
}
|
|
15
17
|
function getResizableSplitTemplate() {
|
|
16
18
|
return `minmax(0, calc(100% - var(${TASK_MODE_SIDE_PANEL_SIZE_CSS_VAR}))) minmax(0, var(${TASK_MODE_SIDE_PANEL_SIZE_CSS_VAR}))`;
|
|
17
19
|
}
|
|
18
|
-
export const TaskModeShell = React.forwardRef(({ className, header, children, loadingProgress = 0, showLoadingBar = false, loadingLabel = "Loading task", ready = true, exiting = false, headerClassName, contentOffsetClassName = "pt-16", bodyClassName, mainPanelClassName, sidePanel, sidePanelOpen = false, sidePanelClassName, sidePanelAriaLabel, sidePanelResizable = false, sidePanelDefaultSize = TASK_MODE_SIDE_PANEL_DEFAULT_SIZE, sidePanelMinSize = TASK_MODE_SIDE_PANEL_MIN_SIZE, sidePanelMaxSize = TASK_MODE_SIDE_PANEL_MAX_SIZE, splitDividerClassName, ...props }, ref) => {
|
|
20
|
+
export const TaskModeShell = React.forwardRef(({ className, header, children, loadingProgress = 0, showLoadingBar = false, loadingLabel = "Loading task", ready = true, exiting = false, backButtonProps, headerClassName, headerContentClassName, contentOffsetClassName = "pt-16", bodyClassName, mainPanelClassName, sidePanel, sidePanelOpen = false, sidePanelClassName, sidePanelAriaLabel, sidePanelResizable = false, sidePanelDefaultSize = TASK_MODE_SIDE_PANEL_DEFAULT_SIZE, sidePanelMinSize = TASK_MODE_SIDE_PANEL_MIN_SIZE, sidePanelMaxSize = TASK_MODE_SIDE_PANEL_MAX_SIZE, splitDividerClassName, ...props }, ref) => {
|
|
19
21
|
const hasSidePanel = sidePanel !== undefined && sidePanel !== null;
|
|
22
|
+
const hasHeaderContent = header !== undefined && header !== null;
|
|
20
23
|
const splitOpen = hasSidePanel && sidePanelOpen;
|
|
21
24
|
const splitContainerRef = React.useRef(null);
|
|
25
|
+
const [entered, setEntered] = React.useState(false);
|
|
22
26
|
const resolvedSidePanelMinSize = Math.min(sidePanelMinSize, sidePanelMaxSize);
|
|
23
27
|
const resolvedSidePanelMaxSize = Math.max(sidePanelMinSize, sidePanelMaxSize);
|
|
24
28
|
const [sidePanelSize, setSidePanelSize] = React.useState(() => clampSidePanelSize(sidePanelDefaultSize, resolvedSidePanelMinSize, resolvedSidePanelMaxSize));
|
|
25
29
|
const sidePanelSizeRef = React.useRef(sidePanelSize);
|
|
30
|
+
const taskModeVisible = entered && ready && !exiting;
|
|
31
|
+
const taskModeState = exiting
|
|
32
|
+
? "exiting"
|
|
33
|
+
: taskModeVisible
|
|
34
|
+
? "entered"
|
|
35
|
+
: "entering";
|
|
36
|
+
React.useEffect(() => {
|
|
37
|
+
setEntered(true);
|
|
38
|
+
}, []);
|
|
26
39
|
React.useEffect(() => {
|
|
27
40
|
sidePanelSizeRef.current = sidePanelSize;
|
|
28
41
|
}, [sidePanelSize]);
|
|
@@ -96,9 +109,10 @@ export const TaskModeShell = React.forwardRef(({ className, header, children, lo
|
|
|
96
109
|
sidePanelResizable,
|
|
97
110
|
splitOpen,
|
|
98
111
|
]);
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
112
|
+
const renderedHeader = backButtonProps ? (_jsxs("div", { className: cn("flex h-14 items-center justify-between gap-4 px-6", headerContentClassName), children: [_jsx(BackButton, { ...backButtonProps, className: cn("text-base", backButtonProps.className) }), hasHeaderContent ? (_jsx("div", { className: "flex min-w-0 items-center gap-2", children: header })) : null] })) : (header);
|
|
113
|
+
return (_jsxs("div", { ref: ref, className: cn("relative min-h-screen w-full bg-background text-foreground", className), ...props, children: [showLoadingBar || loadingProgress > 0 ? (_jsx(Progress, { value: loadingProgress, size: "xs", shape: "square", label: loadingLabel, className: cn("absolute left-0 top-0 z-50 transition-opacity duration-300 ease-out", showLoadingBar ? "opacity-100" : "pointer-events-none opacity-0"), trackClassName: "bg-transparent", indicatorClassName: "bg-emerald-600" })) : null, _jsxs("div", { "data-slot": "task-mode-shell-content", "data-state": taskModeState, className: cn("motion-safe:transition-[opacity,transform] motion-safe:[transition-duration:250ms] motion-safe:ease-out motion-reduce:transition-none", taskModeVisible
|
|
114
|
+
? "opacity-100 motion-safe:translate-y-0 motion-safe:scale-100"
|
|
115
|
+
: "pointer-events-none opacity-0 motion-safe:translate-y-3 motion-safe:scale-[0.99]"), children: [_jsx("header", { className: cn("fixed left-0 right-0 top-0 z-30 border-b bg-background", headerClassName), children: renderedHeader }), _jsx("main", { className: cn("w-full", contentOffsetClassName), children: hasSidePanel ? (_jsxs("div", { ref: splitContainerRef, className: cn("relative grid min-h-0 w-full overflow-hidden transition-[grid-template-columns] duration-300 ease-in-out", bodyClassName), style: splitStyle, children: [_jsx("section", { className: cn("min-h-0 min-w-0", mainPanelClassName), children: children }), _jsx("aside", { "aria-hidden": !splitOpen, "aria-label": sidePanelAriaLabel, className: cn("min-h-0 min-w-0 bg-[hsl(var(--layout-right-panel-background))] transition-[border-color,box-shadow,opacity] duration-300 ease-in-out", rightPanelEdgeClassName, sidePanelClassName, splitOpen
|
|
102
116
|
? ["opacity-100", rightPanelEdgeOpenClassName]
|
|
103
117
|
: [
|
|
104
118
|
"pointer-events-none overflow-hidden opacity-0",
|
package/dist/toaster.js
CHANGED
|
@@ -1,27 +1,48 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { CheckCircle2, CircleAlert, CircleX, Info } from "lucide-react";
|
|
3
4
|
import { Toaster as SonnerToaster, toast } from "sonner";
|
|
4
5
|
import { buttonVariants } from "./button";
|
|
5
6
|
import { XIcon } from "./animated-icons/x";
|
|
6
7
|
import { cn } from "./lib/utils";
|
|
7
8
|
import { typographyVariants } from "./typography";
|
|
9
|
+
const toastActionClassName = "!ml-0 !mr-0 !mt-0 !self-start !justify-self-start";
|
|
10
|
+
const toastLayoutStyle = {
|
|
11
|
+
display: "grid",
|
|
12
|
+
gridTemplateColumns: "auto var(--space-2) auto minmax(0, 1fr)",
|
|
13
|
+
alignItems: "start",
|
|
14
|
+
columnGap: "0",
|
|
15
|
+
rowGap: "var(--space-2)",
|
|
16
|
+
"--toast-button-margin-start": "0px",
|
|
17
|
+
"--toast-button-margin-end": "0px",
|
|
18
|
+
"--toast-icon-margin-start": "0px",
|
|
19
|
+
"--toast-icon-margin-end": "0px",
|
|
20
|
+
"--toast-svg-margin-start": "0px",
|
|
21
|
+
"--toast-svg-margin-end": "0px",
|
|
22
|
+
};
|
|
8
23
|
function Toaster({ position = "top-right", visibleToasts = 3, closeButton = true, duration = 4000, }) {
|
|
9
24
|
return (_jsx(SonnerToaster, { position: position, visibleToasts: visibleToasts, closeButton: closeButton, duration: duration, icons: {
|
|
25
|
+
success: _jsx(CheckCircle2, { "aria-hidden": "true", className: "h-4 w-4" }),
|
|
26
|
+
info: _jsx(Info, { "aria-hidden": "true", className: "h-4 w-4" }),
|
|
27
|
+
warning: _jsx(CircleAlert, { "aria-hidden": "true", className: "h-4 w-4" }),
|
|
28
|
+
error: _jsx(CircleX, { "aria-hidden": "true", className: "h-4 w-4" }),
|
|
10
29
|
close: _jsx(XIcon, { size: 14 }),
|
|
11
30
|
}, toastOptions: {
|
|
31
|
+
unstyled: true,
|
|
32
|
+
style: toastLayoutStyle,
|
|
12
33
|
classNames: {
|
|
13
|
-
toast: "group relative border border-border bg-
|
|
14
|
-
content: "min-w-0 flex-
|
|
15
|
-
title: cn(typographyVariants({ variant: "bodySm" }), "font-medium"),
|
|
16
|
-
description: cn(typographyVariants({ variant: "bodySm" }), "text-muted-foreground"),
|
|
17
|
-
icon: "
|
|
18
|
-
actionButton: cn(buttonVariants({ variant: "
|
|
19
|
-
cancelButton: cn(buttonVariants({ variant: "
|
|
20
|
-
closeButton: "!absolute !left-auto !right-2 !top-2 !h-6 !w-6 !translate-x-0 !translate-y-0 !rounded-control !border-0 !bg-transparent !text-muted-foreground hover:!bg-accent hover:!text-foreground",
|
|
21
|
-
success: "border-[hsl(var(--status-success-foreground))]/20 [&_[data-icon]]
|
|
22
|
-
error: "border-destructive/20 [&_[data-icon]]
|
|
23
|
-
warning: "border-[hsl(var(--status-warning-foreground))]/20 [&_[data-icon]]
|
|
24
|
-
info: "border-[hsl(var(--status-info-foreground))]/20 [&_[data-icon]]
|
|
34
|
+
toast: "group relative !grid w-[var(--width)] !grid-cols-[auto_var(--space-2)_auto_minmax(0,1fr)] !items-start !gap-x-0 !gap-y-2 !rounded-overlay !border !border-border/80 !bg-popover !p-3 !pr-10 !text-popover-foreground !shadow-overlay-strong [&_[data-action]]:col-start-1 [&_[data-button]]:row-start-2 [&_[data-button]]:!ml-0 [&_[data-button]]:!mr-0 [&_[data-cancel]]:col-start-1 [&_[data-content]]:col-span-full [&_[data-content]]:col-start-1 [&_[data-content]]:row-start-1 [&_[data-icon]]:col-start-1 [&_[data-icon]]:row-start-1 [&:has([data-cancel])_[data-action]]:col-start-3 [&:has([data-icon])]:!grid-cols-[auto_var(--space-3)_auto_var(--space-2)_auto_minmax(0,1fr)] [&:has([data-icon])_[data-action]]:col-start-3 [&:has([data-icon])_[data-cancel]]:col-start-3 [&:has([data-icon])_[data-content]]:col-start-3 [&:has([data-icon]):has([data-cancel])_[data-action]]:col-start-5",
|
|
35
|
+
content: "flex min-w-0 flex-col gap-1",
|
|
36
|
+
title: cn(typographyVariants({ variant: "bodySm" }), "!font-medium !text-popover-foreground"),
|
|
37
|
+
description: cn(typographyVariants({ variant: "bodySm" }), "!text-muted-foreground"),
|
|
38
|
+
icon: "!mx-0 flex !h-8 !w-8 shrink-0 !items-center !justify-center self-start rounded-control !border !border-border !bg-muted !text-muted-foreground [&>svg]:!m-0 [&>svg]:!h-4 [&>svg]:!w-4",
|
|
39
|
+
actionButton: cn(buttonVariants({ variant: "default", size: "compact" }), toastActionClassName, "!bg-primary !text-primary-foreground hover:!bg-primary/90"),
|
|
40
|
+
cancelButton: cn(buttonVariants({ variant: "outline", size: "compact" }), toastActionClassName, "!border-[hsl(var(--button-outline-border))] !bg-[hsl(var(--button-outline-background))] !text-foreground hover:!bg-[hsl(var(--button-outline-hover-background))]"),
|
|
41
|
+
closeButton: "!absolute !left-auto !right-2.5 !top-2.5 !flex !h-6 !w-6 !translate-x-0 !translate-y-0 !items-center !justify-center !rounded-control !border-0 !bg-transparent !text-muted-foreground hover:!bg-accent hover:!text-foreground",
|
|
42
|
+
success: "border-[hsl(var(--status-success-foreground))]/20 [&_[data-icon]]:!border-status-success-foreground/20 [&_[data-icon]]:!bg-status-success [&_[data-icon]]:!text-status-success-foreground",
|
|
43
|
+
error: "border-destructive/20 [&_[data-icon]]:!border-status-destructive-foreground/20 [&_[data-icon]]:!bg-status-destructive [&_[data-icon]]:!text-status-destructive-foreground",
|
|
44
|
+
warning: "border-[hsl(var(--status-warning-foreground))]/20 [&_[data-icon]]:!border-status-warning-foreground/20 [&_[data-icon]]:!bg-status-warning [&_[data-icon]]:!text-status-warning-foreground",
|
|
45
|
+
info: "border-[hsl(var(--status-info-foreground))]/20 [&_[data-icon]]:!border-status-info-foreground/20 [&_[data-icon]]:!bg-status-info [&_[data-icon]]:!text-status-info-foreground",
|
|
25
46
|
},
|
|
26
47
|
} }));
|
|
27
48
|
}
|