@neasg/design-system 0.4.7 → 0.4.9
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/README.md +121 -0
- package/dist/alert.d.ts +21 -2
- package/dist/alert.js +10 -3
- package/dist/avatar.d.ts +5 -2
- package/dist/avatar.js +76 -8
- package/dist/back-button.d.ts +2 -0
- package/dist/back-button.js +1 -1
- package/dist/badge.d.ts +3 -2
- package/dist/badge.js +9 -3
- package/dist/breadcrumb.js +2 -1
- package/dist/button.d.ts +1 -1
- package/dist/button.js +13 -10
- package/dist/calendar.js +10 -9
- package/dist/card.d.ts +29 -1
- package/dist/card.js +61 -7
- package/dist/checkbox.d.ts +2 -0
- package/dist/checkbox.js +2 -2
- package/dist/close-button.d.ts +6 -0
- package/dist/close-button.js +8 -0
- package/dist/collapsible.d.ts +7 -1
- package/dist/collapsible.js +2 -2
- package/dist/command-search.d.ts +16 -1
- package/dist/command-search.js +42 -16
- package/dist/command.js +3 -3
- package/dist/copy-button.d.ts +3 -1
- package/dist/copy-button.js +4 -2
- package/dist/count-badge.d.ts +3 -1
- package/dist/count-badge.js +10 -5
- package/dist/date-input.d.ts +18 -3
- package/dist/date-input.js +94 -21
- package/dist/dialog-primitive.js +4 -3
- package/dist/draggable-tabs.d.ts +7 -0
- package/dist/draggable-tabs.js +6 -5
- package/dist/drawer.js +2 -2
- package/dist/dropdown-button.d.ts +18 -0
- package/dist/dropdown-button.js +31 -0
- package/dist/edit-button.d.ts +10 -0
- package/dist/edit-button.js +7 -0
- package/dist/editable-table.d.ts +3 -1
- package/dist/editable-table.js +25 -12
- package/dist/field.d.ts +2 -2
- package/dist/field.js +4 -3
- package/dist/file-upload-status-toast.d.ts +28 -0
- package/dist/file-upload-status-toast.js +136 -0
- package/dist/file-upload.js +8 -7
- package/dist/filter-popover.d.ts +37 -0
- package/dist/filter-popover.js +73 -0
- package/dist/filter-toggle.js +2 -2
- package/dist/index.d.ts +45 -14
- package/dist/index.js +19 -4
- package/dist/input-control.d.ts +3 -2
- package/dist/input-control.js +3 -2
- package/dist/label-value-grid.d.ts +4 -2
- package/dist/label-value-grid.js +7 -6
- package/dist/label-value.js +3 -1
- package/dist/layout-right-panel-edge.d.ts +6 -0
- package/dist/layout-right-panel-edge.js +6 -0
- package/dist/layout.d.ts +77 -5
- package/dist/layout.js +439 -35
- package/dist/lib/date-utils.d.ts +10 -2
- package/dist/lib/date-utils.js +91 -11
- package/dist/lib/utils.js +8 -1
- package/dist/link.js +2 -2
- package/dist/message-item.d.ts +62 -0
- package/dist/message-item.js +148 -0
- package/dist/multi-select.js +31 -5
- package/dist/notification.d.ts +82 -0
- package/dist/notification.js +121 -0
- package/dist/otp-input.js +1 -1
- package/dist/page-header.js +1 -1
- package/dist/page-section.d.ts +2 -1
- package/dist/page-section.js +4 -3
- package/dist/pagination.js +2 -2
- package/dist/popover-menu.d.ts +23 -1
- package/dist/popover-menu.js +75 -5
- package/dist/popover-primitive.js +1 -1
- package/dist/progress.d.ts +5 -2
- package/dist/progress.js +6 -3
- package/dist/radio-group.d.ts +21 -0
- package/dist/radio-group.js +41 -0
- package/dist/rich-text-editor.d.ts +56 -0
- package/dist/rich-text-editor.js +394 -0
- package/dist/routing-timeline.d.ts +22 -0
- package/dist/routing-timeline.js +58 -0
- package/dist/scroll-hint.d.ts +8 -0
- package/dist/scroll-hint.js +7 -0
- package/dist/search-input-shell.js +1 -1
- package/dist/search-input.js +2 -2
- package/dist/section-nav.js +4 -4
- package/dist/select-primitive.js +3 -3
- package/dist/select.js +1 -1
- package/dist/skeleton.js +1 -1
- package/dist/styles.css +235 -57
- package/dist/table-column-visibility.d.ts +21 -0
- package/dist/table-column-visibility.js +74 -0
- package/dist/table-toolbar.js +1 -1
- package/dist/table.d.ts +12 -1
- package/dist/table.js +67 -33
- package/dist/tabs.d.ts +14 -3
- package/dist/tabs.js +60 -6
- package/dist/tailwind-preset.js +46 -0
- package/dist/task-mode-shell.d.ts +24 -0
- package/dist/task-mode-shell.js +110 -0
- package/dist/textarea.js +2 -1
- package/dist/theme-switcher.d.ts +28 -0
- package/dist/theme-switcher.js +27 -0
- package/dist/theme.d.ts +167 -0
- package/dist/theme.js +112 -0
- package/dist/toaster.js +5 -4
- package/dist/tooltip.js +1 -1
- package/dist/typography.d.ts +1 -1
- package/dist/typography.js +5 -5
- package/dist/workspace-header.d.ts +13 -0
- package/dist/workspace-header.js +11 -0
- package/package.json +15 -1
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { Bell, ClipboardCheck, FileText, MessageSquare, UserCheck, } from "lucide-react";
|
|
5
|
+
import { Button } from "./button";
|
|
6
|
+
import { CountBadge } from "./count-badge";
|
|
7
|
+
import { EmptyState } from "./empty-state";
|
|
8
|
+
import { cn } from "./lib/utils";
|
|
9
|
+
import { Popover } from "./popover";
|
|
10
|
+
import { PopoverMenuDivider, PopoverMenuFooter, PopoverMenuFooterAction, PopoverMenuScrollArea, } from "./popover-menu";
|
|
11
|
+
import { Tabs } from "./tabs";
|
|
12
|
+
import { Typography } from "./typography";
|
|
13
|
+
const notificationKindIcons = {
|
|
14
|
+
assignment: ClipboardCheck,
|
|
15
|
+
message: MessageSquare,
|
|
16
|
+
request: UserCheck,
|
|
17
|
+
review: FileText,
|
|
18
|
+
system: Bell,
|
|
19
|
+
};
|
|
20
|
+
const notificationKindTones = {
|
|
21
|
+
assignment: "info",
|
|
22
|
+
message: "accent",
|
|
23
|
+
request: "warning",
|
|
24
|
+
review: "success",
|
|
25
|
+
system: "muted",
|
|
26
|
+
};
|
|
27
|
+
const notificationToneClasses = {
|
|
28
|
+
accent: "border-status-accent-foreground/20 bg-status-accent text-status-accent-foreground",
|
|
29
|
+
destructive: "border-status-destructive-foreground/20 bg-status-destructive text-status-destructive-foreground",
|
|
30
|
+
info: "border-status-info-foreground/20 bg-status-info text-status-info-foreground",
|
|
31
|
+
muted: "border-border bg-muted text-muted-foreground",
|
|
32
|
+
success: "border-status-success-foreground/20 bg-status-success text-status-success-foreground",
|
|
33
|
+
warning: "border-status-warning-foreground/20 bg-status-warning text-status-warning-foreground",
|
|
34
|
+
};
|
|
35
|
+
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
|
+
const resolvedAriaLabel = ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : (isCollapsed && typeof label === "string" ? label : undefined);
|
|
37
|
+
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" &&
|
|
38
|
+
(isCollapsed
|
|
39
|
+
? "border-none bg-transparent text-muted-foreground shadow-none hover:bg-card hover:text-foreground"
|
|
40
|
+
: "h-control w-full justify-start gap-2.5 px-3 text-sm font-medium text-muted-foreground shadow-none hover:bg-card hover:text-foreground"), className), ...props, children: [_jsx(Bell, { "aria-hidden": "true", className: "h-4 w-4 shrink-0" }), isCollapsed ? (_jsx(CountBadge, { count: count, max: countMax, size: "sm", hideWhenZero: hideCountWhenZero, className: "pointer-events-none absolute -right-1 -top-1" })) : (_jsxs(_Fragment, { children: [_jsx("span", { className: "flex-1 truncate text-left", children: label }), _jsx(CountBadge, { count: count, size: countSize, hideWhenZero: hideCountWhenZero })] }))] }));
|
|
41
|
+
});
|
|
42
|
+
NotificationTrigger.displayName = "NotificationTrigger";
|
|
43
|
+
const labelLineClasses = {
|
|
44
|
+
1: "truncate",
|
|
45
|
+
2: "line-clamp-2",
|
|
46
|
+
};
|
|
47
|
+
const descriptionLineClasses = {
|
|
48
|
+
1: "truncate",
|
|
49
|
+
2: "line-clamp-2",
|
|
50
|
+
3: "line-clamp-3",
|
|
51
|
+
};
|
|
52
|
+
function getNotificationIcon(notification) {
|
|
53
|
+
var _a, _b;
|
|
54
|
+
return ((_a = notification.icon) !== null && _a !== void 0 ? _a : notificationKindIcons[(_b = notification.kind) !== null && _b !== void 0 ? _b : "system"]);
|
|
55
|
+
}
|
|
56
|
+
function getNotificationTone(notification) {
|
|
57
|
+
var _a, _b;
|
|
58
|
+
return ((_a = notification.tone) !== null && _a !== void 0 ? _a : notificationKindTones[(_b = notification.kind) !== null && _b !== void 0 ? _b : "system"]);
|
|
59
|
+
}
|
|
60
|
+
function NotificationItem({ notification, density = "default", labelLines = 2, descriptionLines = 2, unreadLabel = "Unread", className, onClick, onSelect, ...props }) {
|
|
61
|
+
var _a;
|
|
62
|
+
const Icon = getNotificationIcon(notification);
|
|
63
|
+
const tone = getNotificationTone(notification);
|
|
64
|
+
const isUnread = Boolean(notification.unread);
|
|
65
|
+
const actions = (_a = notification.actions) !== null && _a !== void 0 ? _a : [];
|
|
66
|
+
const hasActions = actions.length > 0;
|
|
67
|
+
const isInteractive = Boolean(!hasActions && (notification.href || onClick || onSelect));
|
|
68
|
+
const hasHoverSurface = isInteractive || hasActions;
|
|
69
|
+
const meta = notification.meta ? (notification.dateTime ? (_jsx("time", { dateTime: notification.dateTime, children: notification.meta })) : (_jsx("span", { children: notification.meta }))) : null;
|
|
70
|
+
const handleClick = (event) => {
|
|
71
|
+
onClick === null || onClick === void 0 ? void 0 : onClick(event);
|
|
72
|
+
if (!event.defaultPrevented) {
|
|
73
|
+
onSelect === null || onSelect === void 0 ? void 0 : onSelect(notification);
|
|
74
|
+
}
|
|
75
|
+
};
|
|
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: "min-w-0 max-w-24 truncate whitespace-nowrap text-muted-foreground", 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
|
+
var _a, _b;
|
|
78
|
+
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
|
+
var _a;
|
|
80
|
+
event.stopPropagation();
|
|
81
|
+
(_a = action.onClick) === null || _a === void 0 ? void 0 : _a.call(action, notification, event);
|
|
82
|
+
}, children: action.label }, (_b = action.id) !== null && _b !== void 0 ? _b : index));
|
|
83
|
+
}) })) : null] })] }));
|
|
84
|
+
const itemClassName = cn("group relative flex w-full min-w-0 items-start gap-3 overflow-hidden border-b border-border/70 bg-card text-left text-card-foreground outline-none transition-colors last:border-b-0", density === "compact" ? "px-3 py-3" : "px-4 py-4", isUnread && "bg-primary/[0.045]", hasHoverSurface && "hover:bg-accent/70", isInteractive &&
|
|
85
|
+
"cursor-pointer focus-visible:z-10 focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-inset", className);
|
|
86
|
+
if (notification.href && !hasActions) {
|
|
87
|
+
return (_jsx("a", { href: notification.href, "data-slot": "notification-item", "data-unread": isUnread ? "" : undefined, className: itemClassName, onClick: handleClick, ...props, children: content }));
|
|
88
|
+
}
|
|
89
|
+
if (isInteractive) {
|
|
90
|
+
return (_jsx("button", { type: "button", "data-slot": "notification-item", "data-unread": isUnread ? "" : undefined, className: itemClassName, onClick: handleClick, ...props, children: content }));
|
|
91
|
+
}
|
|
92
|
+
return (_jsx("div", { "data-slot": "notification-item", "data-unread": isUnread ? "" : undefined, className: itemClassName, ...props, children: content }));
|
|
93
|
+
}
|
|
94
|
+
function NotificationList({ notifications, density = "default", variant = "bordered", labelLines = 2, descriptionLines = 2, unreadLabel = "Unread", emptyState, itemClassName, className, onNotificationClick, ...props }) {
|
|
95
|
+
const hasNotifications = notifications.length > 0;
|
|
96
|
+
const resolvedEmptyState = emptyState !== null && emptyState !== void 0 ? emptyState : (_jsx(EmptyState, { message: "No notifications", description: "New updates will appear here.", icon: Bell }));
|
|
97
|
+
return (_jsx("div", { "data-slot": "notification-list", className: cn("min-w-0 overflow-hidden bg-card text-card-foreground", !hasNotifications && "flex min-h-full flex-col", variant === "bordered" && "rounded-surface border border-border/70", className), ...props, children: hasNotifications
|
|
98
|
+
? notifications.map((notification) => (_jsx(NotificationItem, { notification: notification, density: density, labelLines: labelLines, descriptionLines: descriptionLines, unreadLabel: unreadLabel, className: itemClassName, onSelect: onNotificationClick }, notification.id)))
|
|
99
|
+
: (_jsx("div", { className: "flex min-h-0 flex-1 flex-col justify-center", children: resolvedEmptyState })) }));
|
|
100
|
+
}
|
|
101
|
+
function NotificationPopover({ trigger, notifications, title = "Notifications", filter, defaultFilter = "all", onFilterChange, showFilterTabs = true, height = "h-[36rem]", minHeight = "min-h-[36rem]", maxHeight = "max-h-[36rem]", emptyState, listClassName, itemClassName, unreadLabel = "Unread", markAllAsReadLabel = "Mark all as read", onNotificationClick, onMarkAllAsRead, contentClassName, align = "end", ...popoverProps }) {
|
|
102
|
+
const [uncontrolledFilter, setUncontrolledFilter] = React.useState(defaultFilter);
|
|
103
|
+
const activeFilter = filter !== null && filter !== void 0 ? filter : uncontrolledFilter;
|
|
104
|
+
const setActiveFilter = (nextFilter) => {
|
|
105
|
+
const resolvedFilter = nextFilter;
|
|
106
|
+
if (filter === undefined) {
|
|
107
|
+
setUncontrolledFilter(resolvedFilter);
|
|
108
|
+
}
|
|
109
|
+
onFilterChange === null || onFilterChange === void 0 ? void 0 : onFilterChange(resolvedFilter);
|
|
110
|
+
};
|
|
111
|
+
const resolvedUnreadCount = notifications.filter((notification) => notification.unread).length;
|
|
112
|
+
const visibleNotifications = activeFilter === "unread"
|
|
113
|
+
? notifications.filter((notification) => notification.unread)
|
|
114
|
+
: notifications;
|
|
115
|
+
const resolvedEmptyState = activeFilter === "unread" && emptyState === undefined ? (_jsx(EmptyState, { message: "No unread notifications", description: "You're all caught up.", icon: Bell })) : (emptyState);
|
|
116
|
+
return (_jsxs(Popover, { surface: "menu", trigger: trigger, align: align, contentClassName: cn("flex w-[32rem] max-w-[calc(100vw-2rem)] flex-col overflow-hidden border-border/80 p-0 ring-1 ring-border/40", height, minHeight, maxHeight, contentClassName), ...popoverProps, children: [_jsxs("div", { className: "flex items-center justify-between gap-4 px-4 py-3", children: [_jsx(Typography, { as: "h3", variant: "label", children: title }), showFilterTabs ? (_jsx(Tabs, { value: activeFilter, onValueChange: setActiveFilter, size: "compact", renderPanels: false, className: "shrink-0 space-y-0", items: [
|
|
117
|
+
{ value: "all", label: "All", content: null },
|
|
118
|
+
{ value: "unread", label: "Unread", content: null },
|
|
119
|
+
] })) : 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
|
+
}
|
|
121
|
+
export { NotificationItem, NotificationList, NotificationPopover, NotificationTrigger, };
|
package/dist/otp-input.js
CHANGED
|
@@ -7,7 +7,7 @@ import { validateOtp } from "./input-validation";
|
|
|
7
7
|
import { cn } from "./lib/utils";
|
|
8
8
|
function OtpSlot({ slot, invalid, className, }) {
|
|
9
9
|
var _a, _b;
|
|
10
|
-
return (_jsxs("div", { "data-slot": "otp-slot", className: cn("relative flex size-10 items-center justify-center rounded-
|
|
10
|
+
return (_jsxs("div", { "data-slot": "otp-slot", className: cn("relative flex size-10 items-center justify-center rounded-control border bg-transparent text-sm font-medium transition-[border-color,box-shadow,color] outline-none group-data-[disabled=true]/field:cursor-not-allowed group-data-[disabled=true]/field:bg-muted/30 group-data-[disabled=true]/field:text-muted-foreground group-data-[disabled=true]/field:opacity-50", invalid ? "border-destructive" : "border-input", slot.isActive &&
|
|
11
11
|
(invalid
|
|
12
12
|
? "border-destructive ring-[3px] ring-destructive/20"
|
|
13
13
|
: "border-ring ring-[3px] ring-ring/50"), className), children: [_jsx("span", { className: cn("pointer-events-none", !slot.char && slot.placeholderChar ? "text-muted-foreground" : ""), children: (_b = (_a = slot.char) !== null && _a !== void 0 ? _a : slot.placeholderChar) !== null && _b !== void 0 ? _b : "" }), slot.hasFakeCaret ? (_jsx("span", { "aria-hidden": "true", className: "pointer-events-none absolute inset-0 flex items-center justify-center", children: _jsx("span", { className: "h-4 w-px animate-pulse bg-foreground" }) })) : null] }));
|
package/dist/page-header.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Typography } from "./typography";
|
|
3
3
|
function PageHeader({ title, subtitle, breadcrumbs, children, className, ...props }) {
|
|
4
|
-
return (_jsx("div", { className: className, ...props, children: _jsxs("div", { className: "flex items-center justify-between gap-
|
|
4
|
+
return (_jsx("div", { className: className, ...props, children: _jsxs("div", { className: "flex items-center justify-between gap-3", children: [_jsxs("div", { className: "flex min-w-0 flex-col gap-1", children: [breadcrumbs ? _jsx("div", { children: breadcrumbs }) : null, _jsx("div", { className: "flex items-center gap-2", children: _jsx(Typography, { as: "h2", variant: "title", children: title }) }), subtitle ? (_jsx(Typography, { as: "p", variant: "caption", children: subtitle })) : null] }), children] }) }));
|
|
5
5
|
}
|
|
6
6
|
export { PageHeader };
|
package/dist/page-section.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
export interface PageSectionGroupProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
3
|
+
variant?: "divided" | "cards";
|
|
3
4
|
}
|
|
4
|
-
declare function PageSectionGroup({ className, ...props }: PageSectionGroupProps): import("react/jsx-runtime").JSX.Element;
|
|
5
|
+
declare function PageSectionGroup({ variant, className, ...props }: PageSectionGroupProps): import("react/jsx-runtime").JSX.Element;
|
|
5
6
|
export interface PageSectionProps extends Omit<React.HTMLAttributes<HTMLElement>, "title"> {
|
|
6
7
|
title: React.ReactNode;
|
|
7
8
|
description?: React.ReactNode;
|
package/dist/page-section.js
CHANGED
|
@@ -2,12 +2,13 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import * as React from "react";
|
|
3
3
|
import { cn } from "./lib/utils";
|
|
4
4
|
import { Typography } from "./typography";
|
|
5
|
-
function PageSectionGroup({ className, ...props }) {
|
|
6
|
-
return _jsx("div", { className: cn("divide-y divide-border",
|
|
5
|
+
function PageSectionGroup({ variant = "divided", className, ...props }) {
|
|
6
|
+
return (_jsx("div", { className: cn(variant === "divided" && "divide-y divide-border", variant === "cards" &&
|
|
7
|
+
"space-y-4 [&>[data-slot=page-section]]:rounded-surface [&>[data-slot=page-section]]:border [&>[data-slot=page-section]]:border-border/70 [&>[data-slot=page-section]]:bg-card [&>[data-slot=page-section]]:p-5", className), ...props }));
|
|
7
8
|
}
|
|
8
9
|
function PageSection({ title, description, headerAction, titleAdornment, className, headerClassName, contentClassName, children, ...props }) {
|
|
9
10
|
const renderedTitle = React.isValidElement(title) ? (title) : (_jsx(Typography, { as: "h3", variant: "subheading", children: title }));
|
|
10
11
|
const renderedDescription = description == null ? null : React.isValidElement(description) ? (description) : (_jsx(Typography, { as: "p", variant: "caption", children: description }));
|
|
11
|
-
return (_jsxs("section", { className: cn("py-6", className), ...props, children: [_jsxs("div", { className: cn("flex flex-col gap-
|
|
12
|
+
return (_jsxs("section", { "data-slot": "page-section", className: cn("py-6", className), ...props, children: [_jsxs("div", { className: cn("flex flex-col gap-2 sm:flex-row sm:items-start sm:justify-between", headerClassName), children: [_jsxs("div", { className: "min-w-0 space-y-1", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-1.5", children: [renderedTitle, titleAdornment] }), renderedDescription] }), headerAction ? (_jsx("div", { className: "flex flex-wrap items-center justify-end gap-1.5 sm:shrink-0", children: headerAction })) : null] }), children ? (_jsx("div", { className: cn("pt-4", contentClassName), children: children })) : null] }));
|
|
12
13
|
}
|
|
13
14
|
export { PageSection, PageSectionGroup };
|
package/dist/pagination.js
CHANGED
|
@@ -17,9 +17,9 @@ function Pagination({ currentPage, totalPages, totalItems, itemsPerPage = 5, onP
|
|
|
17
17
|
const normalizedTotalPages = totalPages || 1;
|
|
18
18
|
const startItem = totalItems === 0 ? 0 : (currentPage - 1) * itemsPerPage + 1;
|
|
19
19
|
const endItem = Math.min(currentPage * itemsPerPage, totalItems);
|
|
20
|
-
return (_jsxs("div", { className: cn("flex items-center justify-between gap-
|
|
20
|
+
return (_jsxs("div", { className: cn("flex items-center justify-between gap-4", className), ...props, children: [_jsxs("div", { className: "text-sm text-muted-foreground", children: ["Showing ", startItem, "-", endItem, " out of ", totalItems] }), _jsxs("div", { className: "flex items-center gap-4", children: [onItemsPerPageChange ? (_jsxs("div", { className: "flex items-center gap-1.5", children: [_jsx(Typography, { as: "span", variant: "caption", children: "Rows per page" }), _jsxs(SelectRoot, { value: itemsPerPage.toString(), onValueChange: (value) => {
|
|
21
21
|
onItemsPerPageChange(Number(value));
|
|
22
22
|
onPageChange(1);
|
|
23
|
-
}, children: [_jsx(SelectTrigger, { className: "w-[
|
|
23
|
+
}, children: [_jsx(SelectTrigger, { className: "w-[64px] text-sm", children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: itemsPerPageOptions.map((option) => (_jsx(SelectItem, { value: option.toString(), children: option }, option))) })] })] })) : null, _jsxs("div", { className: "text-sm text-muted-foreground", children: ["Page ", currentPage, " of ", normalizedTotalPages] }), _jsx(PaginationNav, { className: "mx-0 w-auto justify-start", children: _jsxs(PaginationContent, { children: [_jsx(PaginationItem, { children: _jsx(Button, { type: "button", variant: "outline", size: "icon", onClick: () => onPageChange(1), disabled: currentPage === 1, "aria-label": "Go to first page", children: _jsx(ChevronsLeft, { className: "h-4 w-4" }) }) }), _jsx(PaginationItem, { children: _jsx(Button, { type: "button", variant: "outline", size: "icon", onClick: () => onPageChange(Math.max(1, currentPage - 1)), disabled: currentPage === 1, "aria-label": "Go to previous page", children: _jsx(ChevronLeftIcon, { size: 16 }) }) }), _jsx(PaginationItem, { children: _jsx(Button, { type: "button", variant: "outline", size: "icon", onClick: () => onPageChange(Math.min(normalizedTotalPages, currentPage + 1)), disabled: currentPage === normalizedTotalPages || totalPages === 0, "aria-label": "Go to next page", children: _jsx(ChevronRightIcon, { size: 16 }) }) }), _jsx(PaginationItem, { children: _jsx(Button, { type: "button", variant: "outline", size: "icon", onClick: () => onPageChange(normalizedTotalPages), disabled: currentPage === normalizedTotalPages || totalPages === 0, "aria-label": "Go to last page", children: _jsx(ChevronsRight, { className: "h-4 w-4" }) }) })] }) })] })] }));
|
|
24
24
|
}
|
|
25
25
|
export { Pagination };
|
package/dist/popover-menu.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
+
import { type ButtonProps } from "./button";
|
|
3
|
+
import { type CheckboxProps } from "./checkbox";
|
|
2
4
|
import { InputControl } from "./input-control";
|
|
3
5
|
import { PopoverContent } from "./popover-primitive";
|
|
4
6
|
import { Typography } from "./typography";
|
|
@@ -15,9 +17,24 @@ export interface PopoverMenuItemProps extends React.ButtonHTMLAttributes<HTMLBut
|
|
|
15
17
|
active?: boolean;
|
|
16
18
|
}
|
|
17
19
|
declare function PopoverMenuItem({ className, children, active, type, ...props }: PopoverMenuItemProps): import("react/jsx-runtime").JSX.Element;
|
|
20
|
+
export interface PopoverMenuCheckboxItemProps extends Omit<CheckboxProps, "className" | "label"> {
|
|
21
|
+
description?: React.ReactNode;
|
|
22
|
+
className?: string;
|
|
23
|
+
}
|
|
24
|
+
declare function PopoverMenuCheckboxItem({ className, children, checked, description, disabled, onChange, readOnly, ...props }: PopoverMenuCheckboxItemProps): import("react/jsx-runtime").JSX.Element;
|
|
18
25
|
export interface PopoverMenuDividerProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
19
26
|
}
|
|
20
27
|
declare function PopoverMenuDivider({ className, ...props }: PopoverMenuDividerProps): import("react/jsx-runtime").JSX.Element;
|
|
28
|
+
export interface PopoverMenuFooterProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
29
|
+
inset?: "menu" | "flush";
|
|
30
|
+
}
|
|
31
|
+
declare function PopoverMenuFooter({ className, children, inset, ...props }: PopoverMenuFooterProps): import("react/jsx-runtime").JSX.Element;
|
|
32
|
+
export interface PopoverMenuFooterActionProps extends Omit<ButtonProps, "variant" | "size"> {
|
|
33
|
+
}
|
|
34
|
+
declare function PopoverMenuFooterAction({ className, type, ...props }: PopoverMenuFooterActionProps): import("react/jsx-runtime").JSX.Element;
|
|
35
|
+
export interface PopoverMenuFooterMetaProps extends Omit<React.ComponentPropsWithoutRef<typeof Typography>, "as" | "asChild" | "variant" | "color"> {
|
|
36
|
+
}
|
|
37
|
+
declare function PopoverMenuFooterMeta({ className, children, ...props }: PopoverMenuFooterMetaProps): import("react/jsx-runtime").JSX.Element;
|
|
21
38
|
export interface PopoverMenuGroupProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
22
39
|
}
|
|
23
40
|
declare function PopoverMenuGroup({ className, children, ...props }: PopoverMenuGroupProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -32,4 +49,9 @@ export interface PopoverMenuScrollAreaProps extends React.HTMLAttributes<HTMLDiv
|
|
|
32
49
|
maxHeight?: string;
|
|
33
50
|
}
|
|
34
51
|
declare function PopoverMenuScrollArea({ className, children, maxHeight, ...props }: PopoverMenuScrollAreaProps): import("react/jsx-runtime").JSX.Element;
|
|
35
|
-
export
|
|
52
|
+
export interface PopoverMenuViewProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
53
|
+
direction?: "forward" | "backward" | "none";
|
|
54
|
+
viewKey?: React.Key;
|
|
55
|
+
}
|
|
56
|
+
declare function PopoverMenuView({ children, className, direction, viewKey, ...props }: PopoverMenuViewProps): import("react/jsx-runtime").JSX.Element;
|
|
57
|
+
export { PopoverMenuContent, PopoverMenuHeader, PopoverMenuSection, PopoverMenuItem, PopoverMenuCheckboxItem, PopoverMenuDivider, PopoverMenuFooter, PopoverMenuFooterAction, PopoverMenuFooterMeta, PopoverMenuGroup, PopoverMenuGroupLabel, PopoverMenuSearch, PopoverMenuScrollArea, PopoverMenuView, };
|
package/dist/popover-menu.js
CHANGED
|
@@ -3,10 +3,13 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import { Check } from "lucide-react";
|
|
5
5
|
import { Button } from "./button";
|
|
6
|
+
import { Checkbox } from "./checkbox";
|
|
6
7
|
import { cn } from "./lib/utils";
|
|
7
8
|
import { InputControl } from "./input-control";
|
|
8
9
|
import { PopoverContent } from "./popover-primitive";
|
|
9
10
|
import { Typography } from "./typography";
|
|
11
|
+
const POPOVER_MENU_VIEW_TRANSITION_MS = 300;
|
|
12
|
+
const useIsomorphicLayoutEffect = typeof window === "undefined" ? React.useEffect : React.useLayoutEffect;
|
|
10
13
|
const PopoverMenuContent = React.forwardRef(({ className, ...props }, ref) => (_jsx(PopoverContent, { ref: ref, className: cn("overflow-hidden p-1", className), ...props })));
|
|
11
14
|
PopoverMenuContent.displayName = "PopoverMenuContent";
|
|
12
15
|
function PopoverMenuHeader({ className, children, ...props }) {
|
|
@@ -16,21 +19,88 @@ function PopoverMenuSection({ className, children, ...props }) {
|
|
|
16
19
|
return (_jsx("div", { className: cn("space-y-0", className), ...props, children: children }));
|
|
17
20
|
}
|
|
18
21
|
function PopoverMenuItem({ className, children, active, type = "button", ...props }) {
|
|
19
|
-
return (_jsxs(Button, { type: type, variant: "ghost", className: cn("w-full justify-start rounded-sm text-left font-normal whitespace-normal", active &&
|
|
22
|
+
return (_jsxs(Button, { type: type, variant: "ghost", className: cn("h-auto min-h-8 w-full justify-start gap-2 rounded-sm px-2 py-2 text-left font-normal whitespace-normal", active &&
|
|
20
23
|
"bg-accent text-accent-foreground hover:bg-accent hover:text-accent-foreground", className), ...props, children: [children, active ? _jsx(Check, { "aria-hidden": "true", className: "ml-auto h-4 w-4 shrink-0" }) : null] }));
|
|
21
24
|
}
|
|
25
|
+
function PopoverMenuCheckboxItem({ className, children, checked = false, description, disabled, onChange, readOnly, ...props }) {
|
|
26
|
+
return (_jsxs("label", { className: cn("flex h-auto min-h-8 w-full cursor-pointer items-start gap-1.5 rounded-sm px-2 py-2 text-left text-popover-foreground outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus-within:bg-accent focus-within:text-accent-foreground", checked && "bg-accent text-accent-foreground", disabled &&
|
|
27
|
+
"cursor-not-allowed opacity-50 hover:bg-transparent hover:text-inherit", className), children: [_jsx(Checkbox, { ...props, checked: checked, disabled: disabled, readOnly: readOnly !== null && readOnly !== void 0 ? readOnly : !onChange, onChange: onChange, className: "mt-0.5" }), _jsxs("span", { className: "min-w-0 flex-1", children: [_jsx(Typography, { as: "span", variant: "bodySm", className: "block", children: children }), description ? (_jsx(Typography, { as: "span", variant: "caption", className: "mt-0.5 block", children: description })) : null] })] }));
|
|
28
|
+
}
|
|
22
29
|
function PopoverMenuDivider({ className, ...props }) {
|
|
23
30
|
return _jsx("div", { className: cn("-mx-1 my-1 h-px bg-border", className), ...props });
|
|
24
31
|
}
|
|
32
|
+
function PopoverMenuFooter({ className, children, inset = "menu", ...props }) {
|
|
33
|
+
return (_jsx("div", { className: cn("flex items-center gap-2 border-t p-1.5", inset === "menu" && "-mx-1 -mb-1", inset === "flush" && "m-0", className), ...props, children: children }));
|
|
34
|
+
}
|
|
35
|
+
function PopoverMenuFooterAction({ className, type = "button", ...props }) {
|
|
36
|
+
return (_jsx(Button, { type: type, variant: "ghost", size: "sm", className: cn("h-auto min-h-8 w-full justify-start px-2 py-1.5 text-left whitespace-normal", className), ...props }));
|
|
37
|
+
}
|
|
38
|
+
function PopoverMenuFooterMeta({ className, children, ...props }) {
|
|
39
|
+
return (_jsx(Typography, { as: "span", variant: "bodySm", color: "muted", className: cn("shrink-0 px-2 font-medium", className), ...props, children: children }));
|
|
40
|
+
}
|
|
25
41
|
function PopoverMenuGroup({ className, children, ...props }) {
|
|
26
42
|
return (_jsx("div", { className: cn("space-y-1", className), ...props, children: children }));
|
|
27
43
|
}
|
|
28
44
|
function PopoverMenuGroupLabel({ className, children, ...props }) {
|
|
29
|
-
return (_jsx(Typography, { as: "p", variant: "
|
|
45
|
+
return (_jsx(Typography, { as: "p", variant: "caption", color: "muted", className: cn("px-2 py-1.5", className), ...props, children: children }));
|
|
30
46
|
}
|
|
31
|
-
const PopoverMenuSearch = React.forwardRef(({ className, containerClassName, ...props }, ref) => (_jsx("div", { className: cn("-mx-1 -mt-1 mb-1
|
|
47
|
+
const PopoverMenuSearch = React.forwardRef(({ className, containerClassName, ...props }, ref) => (_jsx("div", { className: cn("relative -mx-1 -mt-1 mb-1 px-2 py-1 after:absolute after:inset-x-0 after:bottom-0 after:h-px after:bg-border after:content-['']", containerClassName), children: _jsx(InputControl, { ref: ref, className: cn("h-8 border-0 bg-transparent px-2 py-0 text-sm shadow-none focus-visible:ring-0", className), ...props }) })));
|
|
32
48
|
PopoverMenuSearch.displayName = "PopoverMenuSearch";
|
|
33
49
|
function PopoverMenuScrollArea({ className, children, maxHeight = "max-h-64", ...props }) {
|
|
34
|
-
return (_jsx("div", { className: cn(maxHeight, "space-y-1 overflow-y-auto", className), ...props, children: children }));
|
|
50
|
+
return (_jsx("div", { className: cn(maxHeight, "space-y-1 overflow-y-auto overflow-x-hidden", className), ...props, children: children }));
|
|
51
|
+
}
|
|
52
|
+
function PopoverMenuView({ children, className, direction = "forward", viewKey = "default", ...props }) {
|
|
53
|
+
const [activeViewKey, setActiveViewKey] = React.useState(viewKey);
|
|
54
|
+
const [exitingView, setExitingView] = React.useState(null);
|
|
55
|
+
const activeViewRef = React.useRef({
|
|
56
|
+
key: viewKey,
|
|
57
|
+
children,
|
|
58
|
+
});
|
|
59
|
+
const exitTimeoutRef = React.useRef(null);
|
|
60
|
+
if (Object.is(viewKey, activeViewKey)) {
|
|
61
|
+
activeViewRef.current = { key: viewKey, children };
|
|
62
|
+
}
|
|
63
|
+
useIsomorphicLayoutEffect(() => {
|
|
64
|
+
const previousView = activeViewRef.current;
|
|
65
|
+
if (Object.is(viewKey, previousView.key)) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
if (exitTimeoutRef.current) {
|
|
69
|
+
window.clearTimeout(exitTimeoutRef.current);
|
|
70
|
+
exitTimeoutRef.current = null;
|
|
71
|
+
}
|
|
72
|
+
if (direction === "none") {
|
|
73
|
+
setExitingView(null);
|
|
74
|
+
activeViewRef.current = { key: viewKey, children };
|
|
75
|
+
setActiveViewKey(viewKey);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
setExitingView({
|
|
79
|
+
key: previousView.key,
|
|
80
|
+
children: previousView.children,
|
|
81
|
+
direction,
|
|
82
|
+
});
|
|
83
|
+
activeViewRef.current = { key: viewKey, children };
|
|
84
|
+
setActiveViewKey(viewKey);
|
|
85
|
+
exitTimeoutRef.current = window.setTimeout(() => {
|
|
86
|
+
setExitingView((current) => (current === null || current === void 0 ? void 0 : current.key) === previousView.key ? null : current);
|
|
87
|
+
exitTimeoutRef.current = null;
|
|
88
|
+
}, POPOVER_MENU_VIEW_TRANSITION_MS);
|
|
89
|
+
return () => {
|
|
90
|
+
if (exitTimeoutRef.current) {
|
|
91
|
+
window.clearTimeout(exitTimeoutRef.current);
|
|
92
|
+
exitTimeoutRef.current = null;
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
}, [direction, viewKey]);
|
|
96
|
+
const activeDirection = exitingView === null || exitingView === void 0 ? void 0 : exitingView.direction;
|
|
97
|
+
const shouldAnimateActive = Boolean(activeDirection);
|
|
98
|
+
return (_jsxs("div", { className: cn("grid min-w-0 overflow-hidden", className), ...props, children: [exitingView ? (_jsx("div", { "aria-hidden": "true", className: cn("pointer-events-none col-start-1 row-start-1 min-w-0", exitingView.direction !== "none" &&
|
|
99
|
+
"motion-safe:animate-out motion-safe:fade-out-0 motion-safe:duration-300 motion-reduce:animate-none", exitingView.direction === "forward" &&
|
|
100
|
+
"motion-safe:slide-out-to-left-full", exitingView.direction === "backward" &&
|
|
101
|
+
"motion-safe:slide-out-to-right-full"), children: exitingView.children }, `leaving-${exitingView.key}`)) : null, _jsx("div", { className: cn("col-start-1 row-start-1 min-w-0", shouldAnimateActive &&
|
|
102
|
+
"motion-safe:animate-in motion-safe:fade-in-0 motion-safe:duration-300 motion-reduce:animate-none", activeDirection === "forward" &&
|
|
103
|
+
"motion-safe:slide-in-from-right-full", activeDirection === "backward" &&
|
|
104
|
+
"motion-safe:slide-in-from-left-full"), children: children }, viewKey)] }));
|
|
35
105
|
}
|
|
36
|
-
export { PopoverMenuContent, PopoverMenuHeader, PopoverMenuSection, PopoverMenuItem, PopoverMenuDivider, PopoverMenuGroup, PopoverMenuGroupLabel, PopoverMenuSearch, PopoverMenuScrollArea, };
|
|
106
|
+
export { PopoverMenuContent, PopoverMenuHeader, PopoverMenuSection, PopoverMenuItem, PopoverMenuCheckboxItem, PopoverMenuDivider, PopoverMenuFooter, PopoverMenuFooterAction, PopoverMenuFooterMeta, PopoverMenuGroup, PopoverMenuGroupLabel, PopoverMenuSearch, PopoverMenuScrollArea, PopoverMenuView, };
|
|
@@ -6,6 +6,6 @@ import { cn } from "./lib/utils";
|
|
|
6
6
|
const PopoverRoot = PopoverPrimitive.Root;
|
|
7
7
|
const PopoverTrigger = PopoverPrimitive.Trigger;
|
|
8
8
|
const PopoverAnchor = PopoverPrimitive.Anchor;
|
|
9
|
-
const PopoverContent = React.forwardRef(({ className, align = "center", sideOffset = 4, ...props }, ref) => (_jsx(PopoverPrimitive.Portal, { children: _jsx(PopoverPrimitive.Content, { ref: ref, align: align, sideOffset: sideOffset, className: cn("z-50 w-72 rounded-
|
|
9
|
+
const PopoverContent = React.forwardRef(({ className, align = "center", sideOffset = 4, ...props }, ref) => (_jsx(PopoverPrimitive.Portal, { children: _jsx(PopoverPrimitive.Content, { ref: ref, align: align, sideOffset: sideOffset, className: cn("shadow-overlay-strong z-50 w-72 rounded-overlay border bg-popover p-4 text-popover-foreground outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", className), ...props }) })));
|
|
10
10
|
PopoverContent.displayName = PopoverPrimitive.Content.displayName;
|
|
11
11
|
export { PopoverAnchor, PopoverContent, PopoverRoot, PopoverTrigger };
|
package/dist/progress.d.ts
CHANGED
|
@@ -3,8 +3,11 @@ export interface ProgressProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
|
3
3
|
value?: number;
|
|
4
4
|
max?: number;
|
|
5
5
|
showValue?: boolean;
|
|
6
|
-
size?: "sm" | "md" | "lg";
|
|
6
|
+
size?: "xs" | "sm" | "md" | "lg";
|
|
7
7
|
variant?: "default" | "success" | "error";
|
|
8
8
|
label?: string;
|
|
9
|
+
shape?: "rounded" | "square";
|
|
10
|
+
trackClassName?: string;
|
|
11
|
+
indicatorClassName?: string;
|
|
9
12
|
}
|
|
10
|
-
export declare function Progress({ value, max, showValue, size, variant, label, className, ...props }: ProgressProps): import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
export declare function Progress({ value, max, showValue, size, variant, label, shape, className, trackClassName, indicatorClassName, ...props }: ProgressProps): import("react/jsx-runtime").JSX.Element;
|
package/dist/progress.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { cn } from "./lib/utils";
|
|
4
4
|
const sizeClasses = {
|
|
5
|
+
xs: "h-[3px]",
|
|
5
6
|
sm: "h-1",
|
|
6
7
|
md: "h-2",
|
|
7
8
|
lg: "h-3",
|
|
@@ -11,7 +12,9 @@ const variantClasses = {
|
|
|
11
12
|
success: "bg-green-500",
|
|
12
13
|
error: "bg-destructive",
|
|
13
14
|
};
|
|
14
|
-
export function Progress({ value = 0, max = 100, showValue = false, size = "md", variant = "default", label = "Progress", className, ...props }) {
|
|
15
|
-
const
|
|
16
|
-
|
|
15
|
+
export function Progress({ value = 0, max = 100, showValue = false, size = "md", variant = "default", label = "Progress", shape = "rounded", className, trackClassName, indicatorClassName, ...props }) {
|
|
16
|
+
const safeMax = max > 0 ? max : 100;
|
|
17
|
+
const clampedValue = Math.min(Math.max(value, 0), safeMax);
|
|
18
|
+
const percentage = Math.min(Math.max((clampedValue / safeMax) * 100, 0), 100);
|
|
19
|
+
return (_jsxs("div", { className: cn("w-full", className), ...props, children: [_jsx("div", { className: cn("w-full overflow-hidden bg-secondary", shape === "rounded" ? "rounded-full" : "rounded-none", sizeClasses[size], trackClassName), role: "progressbar", "aria-valuenow": clampedValue, "aria-valuemin": 0, "aria-valuemax": safeMax, "aria-label": label, children: _jsx("div", { className: cn("h-full transition-all duration-300 ease-out", shape === "rounded" ? "rounded-full" : "rounded-none", variantClasses[variant], indicatorClassName), style: { width: `${percentage}%` } }) }), showValue && (_jsxs("p", { className: "mt-1 text-right text-xs text-muted-foreground", children: [Math.round(percentage), "%"] }))] }));
|
|
17
20
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export interface RadioGroupOption {
|
|
3
|
+
value: string;
|
|
4
|
+
label: React.ReactNode;
|
|
5
|
+
description?: React.ReactNode;
|
|
6
|
+
disabled?: boolean;
|
|
7
|
+
}
|
|
8
|
+
export interface RadioGroupProps extends Omit<React.FieldsetHTMLAttributes<HTMLFieldSetElement>, "defaultValue" | "onChange"> {
|
|
9
|
+
options: RadioGroupOption[];
|
|
10
|
+
value?: string;
|
|
11
|
+
defaultValue?: string;
|
|
12
|
+
onValueChange?: (value: string) => void;
|
|
13
|
+
name?: string;
|
|
14
|
+
label?: React.ReactNode;
|
|
15
|
+
hideLabel?: boolean;
|
|
16
|
+
description?: React.ReactNode;
|
|
17
|
+
orientation?: "horizontal" | "vertical";
|
|
18
|
+
groupClassName?: string;
|
|
19
|
+
optionClassName?: string;
|
|
20
|
+
}
|
|
21
|
+
export declare const RadioGroup: React.ForwardRefExoticComponent<RadioGroupProps & React.RefAttributes<HTMLFieldSetElement>>;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { cn } from "./lib/utils";
|
|
5
|
+
import { Typography } from "./typography";
|
|
6
|
+
function useControllableValue({ value, defaultValue, onValueChange, }) {
|
|
7
|
+
const [uncontrolledValue, setUncontrolledValue] = React.useState(defaultValue);
|
|
8
|
+
const isControlled = value !== undefined;
|
|
9
|
+
const currentValue = isControlled ? value : uncontrolledValue;
|
|
10
|
+
const setValue = React.useCallback((nextValue) => {
|
|
11
|
+
if (!isControlled) {
|
|
12
|
+
setUncontrolledValue(nextValue);
|
|
13
|
+
}
|
|
14
|
+
onValueChange === null || onValueChange === void 0 ? void 0 : onValueChange(nextValue);
|
|
15
|
+
}, [isControlled, onValueChange]);
|
|
16
|
+
return [currentValue, setValue];
|
|
17
|
+
}
|
|
18
|
+
export const RadioGroup = React.forwardRef(({ className, optionClassName, options, value, defaultValue, onValueChange, name, label, hideLabel = false, description, orientation = "horizontal", groupClassName, disabled, "aria-labelledby": ariaLabelledBy, "aria-describedby": ariaDescribedBy, ...props }, ref) => {
|
|
19
|
+
const generatedId = React.useId();
|
|
20
|
+
const groupName = name !== null && name !== void 0 ? name : `radio-group-${generatedId.replace(/:/g, "")}`;
|
|
21
|
+
const labelId = label ? `${groupName}-label` : undefined;
|
|
22
|
+
const descriptionId = description ? `${groupName}-description` : undefined;
|
|
23
|
+
const [currentValue, setCurrentValue] = useControllableValue({
|
|
24
|
+
value,
|
|
25
|
+
defaultValue,
|
|
26
|
+
onValueChange,
|
|
27
|
+
});
|
|
28
|
+
return (_jsxs("fieldset", { ref: ref, disabled: disabled, className: cn("min-w-0 border-0 p-0", className), ...props, children: [label ? (_jsx("legend", { id: labelId, className: cn("mb-2 text-sm font-medium text-foreground", hideLabel && "sr-only"), children: label })) : null, description ? (_jsx(Typography, { as: "p", id: descriptionId, variant: "caption", color: "muted", className: cn("mb-2", hideLabel && "sr-only"), children: description })) : null, _jsx("div", { role: "radiogroup", "aria-orientation": orientation, "aria-labelledby": labelId !== null && labelId !== void 0 ? labelId : ariaLabelledBy, "aria-describedby": descriptionId !== null && descriptionId !== void 0 ? descriptionId : ariaDescribedBy, className: cn(orientation === "horizontal"
|
|
29
|
+
? "flex flex-wrap items-center gap-4"
|
|
30
|
+
: "grid gap-2", groupClassName), children: options.map((option, optionIndex) => {
|
|
31
|
+
const optionId = `${groupName}-option-${optionIndex}`;
|
|
32
|
+
const checked = currentValue === option.value;
|
|
33
|
+
const optionDisabled = disabled || option.disabled;
|
|
34
|
+
return (_jsxs("label", { htmlFor: optionId, className: cn("inline-flex min-w-0 cursor-pointer items-start gap-2 text-sm text-foreground", optionDisabled && "cursor-not-allowed opacity-50", optionClassName), children: [_jsxs("span", { className: cn("relative mt-0.5 inline-flex size-3.5 shrink-0 items-center justify-center rounded-full border bg-background transition-colors focus-within:ring-2 focus-within:ring-ring focus-within:ring-offset-2", checked ? "border-primary" : "border-input"), children: [_jsx("span", { className: cn("size-2 rounded-full bg-primary transition-transform", checked ? "scale-100" : "scale-0") }), _jsx("input", { id: optionId, type: "radio", name: groupName, value: option.value, checked: checked, disabled: optionDisabled, onChange: (event) => {
|
|
35
|
+
if (event.target.checked) {
|
|
36
|
+
setCurrentValue(option.value);
|
|
37
|
+
}
|
|
38
|
+
}, className: "absolute inset-0 cursor-pointer opacity-0 disabled:cursor-not-allowed" })] }), _jsxs("span", { className: "min-w-0", children: [_jsx(Typography, { as: "span", variant: "bodySm", children: option.label }), option.description ? (_jsx(Typography, { as: "p", variant: "caption", color: "muted", children: option.description })) : null] })] }, option.value));
|
|
39
|
+
}) })] }));
|
|
40
|
+
});
|
|
41
|
+
RadioGroup.displayName = "RadioGroup";
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export interface AttachmentFile {
|
|
3
|
+
name: string;
|
|
4
|
+
size: number;
|
|
5
|
+
type: string;
|
|
6
|
+
file: File;
|
|
7
|
+
}
|
|
8
|
+
export type TemplateContext = Record<string, string | null | undefined>;
|
|
9
|
+
export interface RichTextEditorTemplate {
|
|
10
|
+
id: string;
|
|
11
|
+
name: string;
|
|
12
|
+
content: string;
|
|
13
|
+
category?: string | null;
|
|
14
|
+
description?: string | null;
|
|
15
|
+
}
|
|
16
|
+
export interface RichTextEditorColor {
|
|
17
|
+
name: string;
|
|
18
|
+
value: string;
|
|
19
|
+
}
|
|
20
|
+
export type RichTextEditorSendMetadata = Record<string, unknown>;
|
|
21
|
+
export interface RichTextEditorSendAction {
|
|
22
|
+
id: string;
|
|
23
|
+
label: React.ReactNode;
|
|
24
|
+
metadata?: RichTextEditorSendMetadata;
|
|
25
|
+
disabled?: boolean;
|
|
26
|
+
}
|
|
27
|
+
export interface RichTextEditorProps {
|
|
28
|
+
placeholder?: string;
|
|
29
|
+
editorAriaLabel?: string;
|
|
30
|
+
header?: React.ReactNode;
|
|
31
|
+
isExpanded?: boolean;
|
|
32
|
+
onExpandToggle?: () => void;
|
|
33
|
+
onSend?: (content: string, attachments?: AttachmentFile[], metadata?: RichTextEditorSendMetadata) => Promise<boolean> | boolean | void;
|
|
34
|
+
className?: string;
|
|
35
|
+
maxFileSize?: number;
|
|
36
|
+
maxFileSizeLabel?: string;
|
|
37
|
+
acceptedFileTypes?: string;
|
|
38
|
+
acceptedFileTypesLabel?: string;
|
|
39
|
+
isSending?: boolean;
|
|
40
|
+
showTemplates?: boolean;
|
|
41
|
+
templates?: RichTextEditorTemplate[];
|
|
42
|
+
templateContext?: TemplateContext;
|
|
43
|
+
templateCategoryLabels?: Record<string, string>;
|
|
44
|
+
templateCategoryOrder?: string[];
|
|
45
|
+
templateCreateHref?: string;
|
|
46
|
+
templateCreateLabel?: string;
|
|
47
|
+
onFileRejected?: (message: string) => void;
|
|
48
|
+
colorPalette?: RichTextEditorColor[];
|
|
49
|
+
sendLabel?: string;
|
|
50
|
+
sendingLabel?: string;
|
|
51
|
+
sendActions?: RichTextEditorSendAction[];
|
|
52
|
+
}
|
|
53
|
+
export declare function formatFileSize(bytes: number): string;
|
|
54
|
+
export declare function sanitizeRichTextHtml(html: string): string;
|
|
55
|
+
export declare function replaceTemplateVariables(content: string, context: TemplateContext): string;
|
|
56
|
+
export declare function RichTextEditor({ placeholder, editorAriaLabel, header, isExpanded, onExpandToggle, onSend, className, maxFileSize, maxFileSizeLabel, acceptedFileTypes, acceptedFileTypesLabel, isSending, showTemplates, templates, templateContext, templateCategoryLabels, templateCategoryOrder, templateCreateHref, templateCreateLabel, onFileRejected, colorPalette, sendLabel, sendingLabel, sendActions, }: RichTextEditorProps): import("react/jsx-runtime").JSX.Element;
|