@neasg/design-system 0.4.33 → 0.4.95
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/activity-card.d.ts +29 -0
- package/dist/activity-card.js +65 -0
- package/dist/autocomplete.d.ts +84 -0
- package/dist/autocomplete.js +267 -0
- package/dist/avatar.d.ts +3 -1
- package/dist/avatar.js +27 -10
- package/dist/badge.js +1 -1
- package/dist/button.d.ts +1 -1
- package/dist/button.js +1 -0
- package/dist/calendar.js +1 -1
- package/dist/card.d.ts +1 -1
- package/dist/card.js +1 -1
- package/dist/compound-search-input.d.ts +8 -0
- package/dist/compound-search-input.js +9 -0
- package/dist/date-input.js +3 -3
- package/dist/dialog.d.ts +3 -1
- package/dist/dialog.js +6 -2
- package/dist/draggable-tabs.js +9 -8
- package/dist/index.d.ts +12 -4
- package/dist/index.js +6 -2
- package/dist/label-value-grid.js +6 -4
- package/dist/layout.d.ts +39 -6
- package/dist/layout.js +118 -42
- package/dist/lib/utils.js +1 -0
- package/dist/message-item.d.ts +23 -3
- package/dist/message-item.js +115 -16
- package/dist/notification.d.ts +14 -3
- package/dist/notification.js +32 -7
- package/dist/popover-menu.d.ts +4 -2
- package/dist/popover-menu.js +65 -5
- package/dist/popover.d.ts +5 -2
- package/dist/popover.js +3 -3
- package/dist/rich-text-editor.d.ts +2 -1
- package/dist/rich-text-editor.js +28 -3
- package/dist/routing-timeline.d.ts +7 -2
- package/dist/routing-timeline.js +67 -29
- package/dist/search-input.d.ts +4 -0
- package/dist/search-input.js +2 -2
- package/dist/select-primitive.js +1 -1
- package/dist/select.d.ts +3 -1
- package/dist/select.js +9 -4
- package/dist/status-dot.d.ts +13 -0
- package/dist/status-dot.js +19 -0
- package/dist/styles.css +0 -19
- package/dist/table-column-filter.js +7 -5
- package/dist/table.d.ts +9 -1
- package/dist/table.js +30 -12
- package/dist/tabs.d.ts +1 -1
- package/dist/tabs.js +6 -4
- package/dist/textarea.d.ts +1 -0
- package/dist/textarea.js +3 -2
- package/dist/theme-switcher.d.ts +3 -1
- package/dist/theme-switcher.js +8 -2
- package/package.json +5 -1
package/dist/routing-timeline.js
CHANGED
|
@@ -1,58 +1,96 @@
|
|
|
1
|
-
import { jsx as _jsx,
|
|
2
|
-
import {
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { ArrowRight, Mail, Route } from "lucide-react";
|
|
3
|
+
import { ActivityCard, ActivityCardContent } from "./activity-card";
|
|
4
|
+
import { AvatarProfile } from "./avatar";
|
|
3
5
|
import { Badge } from "./badge";
|
|
4
6
|
import { EmptyState } from "./empty-state";
|
|
5
7
|
import { cn } from "./lib/utils";
|
|
6
8
|
import { Typography } from "./typography";
|
|
7
9
|
const routingKindConfig = {
|
|
8
10
|
assigned: {
|
|
9
|
-
title: "Assigned
|
|
10
|
-
label: "
|
|
11
|
-
|
|
12
|
-
markerClassName: "border-[hsl(var(--status-info-foreground)/0.35)] bg-[hsl(var(--status-info))]",
|
|
11
|
+
title: "Assigned case",
|
|
12
|
+
label: "ASSIGNED",
|
|
13
|
+
icon: "route",
|
|
13
14
|
},
|
|
14
15
|
reassigned: {
|
|
15
|
-
title: "Reassigned
|
|
16
|
-
label: "
|
|
17
|
-
|
|
18
|
-
markerClassName: "border-[hsl(var(--status-accent-foreground)/0.35)] bg-[hsl(var(--status-accent))]",
|
|
16
|
+
title: "Reassigned case",
|
|
17
|
+
label: "REASSIGNED",
|
|
18
|
+
icon: "route",
|
|
19
19
|
},
|
|
20
20
|
returned: {
|
|
21
|
-
title: "
|
|
22
|
-
label: "
|
|
23
|
-
|
|
24
|
-
markerClassName: "border-[hsl(var(--status-warning-foreground)/0.35)] bg-[hsl(var(--status-warning))]",
|
|
21
|
+
title: "Case returned",
|
|
22
|
+
label: "RETURNED",
|
|
23
|
+
icon: "route",
|
|
25
24
|
},
|
|
26
25
|
routed: {
|
|
27
|
-
title: "Case
|
|
28
|
-
label: "
|
|
29
|
-
|
|
30
|
-
|
|
26
|
+
title: "Case routed",
|
|
27
|
+
label: "ROUTED",
|
|
28
|
+
icon: "route",
|
|
29
|
+
},
|
|
30
|
+
"message-received": {
|
|
31
|
+
title: "Received from applicant",
|
|
32
|
+
label: "RECEIVED",
|
|
33
|
+
detailLabel: "Response from applicant:",
|
|
34
|
+
icon: "mail",
|
|
35
|
+
},
|
|
36
|
+
"message-sent": {
|
|
37
|
+
title: "Sent to applicant",
|
|
38
|
+
label: "SENT",
|
|
39
|
+
detailLabel: "Officer sent a message:",
|
|
40
|
+
icon: "mail",
|
|
31
41
|
},
|
|
32
42
|
system: {
|
|
33
|
-
title: "System
|
|
34
|
-
label: "
|
|
35
|
-
|
|
36
|
-
markerClassName: "border-muted-foreground/30 bg-muted",
|
|
43
|
+
title: "System update",
|
|
44
|
+
label: "SYSTEM",
|
|
45
|
+
icon: "route",
|
|
37
46
|
},
|
|
38
47
|
};
|
|
39
|
-
function RoutingTimelineHandoffEndpoint({ value, }) {
|
|
48
|
+
function RoutingTimelineHandoffEndpoint({ value, label, }) {
|
|
40
49
|
const isTextValue = typeof value === "string" || typeof value === "number";
|
|
41
|
-
|
|
50
|
+
if (!isTextValue) {
|
|
51
|
+
return (_jsx("div", { "data-slot": "routing-timeline-profile", "data-avatar-size": "xs", className: "min-w-0", children: value }));
|
|
52
|
+
}
|
|
53
|
+
const name = String(value);
|
|
54
|
+
const fallback = name
|
|
55
|
+
.split(/\s+/)
|
|
56
|
+
.filter(Boolean)
|
|
57
|
+
.slice(0, 2)
|
|
58
|
+
.map((part) => part.charAt(0))
|
|
59
|
+
.join("")
|
|
60
|
+
.toUpperCase();
|
|
61
|
+
return (_jsx("div", { "data-slot": "routing-timeline-profile", "data-avatar-size": "xs", className: "min-w-0", children: _jsx(AvatarProfile, { size: "xs", fallback: fallback || "?", name: name, role: label, rolePlacement: "below" }) }));
|
|
62
|
+
}
|
|
63
|
+
function RoutingEventIcon({ icon, kind, density, }) {
|
|
64
|
+
if (icon)
|
|
65
|
+
return _jsx(_Fragment, { children: icon });
|
|
66
|
+
return routingKindConfig[kind].icon === "mail" ? (_jsx(Mail, { "aria-hidden": "true", className: density === "compact" ? "size-4" : "size-6" })) : (_jsx(Route, { "aria-hidden": "true", className: density === "compact" ? "size-4" : "size-6" }));
|
|
42
67
|
}
|
|
43
|
-
function RoutingTimeline({ items, emptyMessage = "No routing activity yet.", className, ...props }) {
|
|
68
|
+
function RoutingTimeline({ items, emptyMessage = "No routing activity yet.", density = "default", className, ...props }) {
|
|
44
69
|
if (items.length === 0) {
|
|
45
|
-
return (_jsx(EmptyState, { "data-slot": "routing-timeline", message: emptyMessage, className: cn("border-0 bg-transparent px-0
|
|
70
|
+
return (_jsx(EmptyState, { "data-slot": "routing-timeline", message: emptyMessage, className: cn("border-0 bg-transparent px-0", density === "compact"
|
|
71
|
+
? "py-[var(--space-4)]"
|
|
72
|
+
: "py-[var(--space-6)]", className), ...props }));
|
|
46
73
|
}
|
|
47
|
-
return (_jsx("div", { "data-slot": "routing-timeline", className: cn("min-w-0", className), ...props, children: _jsx("ol", { "data-slot": "routing-timeline-list", className:
|
|
48
|
-
var
|
|
74
|
+
return (_jsx("div", { "data-slot": "routing-timeline", "data-density": density, className: cn("min-w-0", className), ...props, children: _jsx("ol", { "data-slot": "routing-timeline-list", className: cn(density === "compact"
|
|
75
|
+
? "space-y-[var(--space-4)]"
|
|
76
|
+
: "space-y-[32px]"), children: items.map((item) => {
|
|
77
|
+
var _a, _b, _c, _d, _e;
|
|
49
78
|
const kind = (_a = item.kind) !== null && _a !== void 0 ? _a : "routed";
|
|
50
79
|
const config = routingKindConfig[kind];
|
|
51
80
|
const hasRouteEndpoints = Boolean(item.from || item.to);
|
|
52
81
|
const hasCompleteRoute = Boolean(item.from && item.to);
|
|
53
82
|
const title = (_b = item.title) !== null && _b !== void 0 ? _b : config.title;
|
|
54
83
|
const remark = (_c = item.remark) !== null && _c !== void 0 ? _c : item.description;
|
|
55
|
-
|
|
84
|
+
const detailLabel = (_d = item.detailLabel) !== null && _d !== void 0 ? _d : config.detailLabel;
|
|
85
|
+
const showDefaultBadge = item.badgeLabel !== null;
|
|
86
|
+
return (_jsx("li", { children: _jsx(ActivityCard, { "data-slot": "routing-timeline-event-card", density: density, icon: _jsx(RoutingEventIcon, { icon: item.icon, kind: kind, density: density }), title: title, meta: item.timestamp, trailing: item.badge ? (item.badge) : showDefaultBadge ? (_jsx(Badge, { variant: "outline", bordered: true, className: "max-w-full shrink-0", children: (_e = item.badgeLabel) !== null && _e !== void 0 ? _e : config.label })) : null, children: hasRouteEndpoints || remark ? (_jsxs(ActivityCardContent, { density: density, children: [hasRouteEndpoints ? (_jsxs("div", { "data-slot": "routing-timeline-handoff", "data-complete-route": hasCompleteRoute ? "true" : undefined, className: cn("flex min-w-0 items-center", density === "compact"
|
|
87
|
+
? "gap-[var(--space-3)]"
|
|
88
|
+
: "gap-[24px]"), children: [item.from ? (_jsx(RoutingTimelineHandoffEndpoint, { value: item.from, label: item.fromLabel })) : null, item.from && item.to ? (_jsxs(_Fragment, { children: [_jsx("span", { className: "sr-only", children: "to" }), _jsx(ArrowRight, { "aria-hidden": "true", "data-slot": "routing-timeline-handoff-arrow", className: cn("shrink-0 text-foreground", density === "compact" ? "size-4" : "size-6") })] })) : null, item.to ? (_jsx(RoutingTimelineHandoffEndpoint, { value: item.to, label: item.toLabel })) : null] })) : null, remark ? (_jsxs("div", { "data-slot": "routing-timeline-remark", className: cn("bg-muted", density === "compact"
|
|
89
|
+
? "rounded-control p-[var(--space-2)]"
|
|
90
|
+
: "rounded-md p-[12px]"), children: [detailLabel ? (_jsx(Typography, { as: "p", variant: "bodySm", className: "font-semibold text-instructional", children: detailLabel })) : null, _jsx(Typography, { as: "div", variant: "bodySm", className: cn(detailLabel &&
|
|
91
|
+
(density === "compact"
|
|
92
|
+
? "mt-[var(--space-1)]"
|
|
93
|
+
: "mt-[4px]")), children: remark })] })) : null] })) : null }) }, item.id));
|
|
56
94
|
}) }) }));
|
|
57
95
|
}
|
|
58
96
|
export { RoutingTimeline };
|
package/dist/search-input.d.ts
CHANGED
|
@@ -4,9 +4,13 @@ export interface SearchInputProps extends Omit<React.ComponentProps<typeof Input
|
|
|
4
4
|
value: string;
|
|
5
5
|
onValueChange: (value: string) => void;
|
|
6
6
|
label?: React.ReactNode;
|
|
7
|
+
/** Visually hides the label while keeping it available to assistive technology. */
|
|
8
|
+
hideLabel?: boolean;
|
|
7
9
|
description?: React.ReactNode;
|
|
8
10
|
error?: React.ReactNode;
|
|
9
11
|
invalid?: boolean;
|
|
12
|
+
/** Keeps the control visually marked after a search result is selected. */
|
|
13
|
+
selected?: boolean;
|
|
10
14
|
containerClassName?: string;
|
|
11
15
|
labelClassName?: string;
|
|
12
16
|
descriptionClassName?: string;
|
package/dist/search-input.js
CHANGED
|
@@ -6,7 +6,7 @@ import { Field, FieldDescription, FieldError, FieldLabel } from "./field";
|
|
|
6
6
|
import { InputControl } from "./input-control";
|
|
7
7
|
import { cn } from "./lib/utils";
|
|
8
8
|
import { SearchInputShell } from "./search-input-shell";
|
|
9
|
-
const SearchInput = React.forwardRef(({ value, onValueChange, label = "Search", description, error, invalid = false, placeholder = "Search...", containerClassName, labelClassName, descriptionClassName, errorClassName, onSearch, searchDelay = 300, searchOnChange = true, searchOnEnter = true, className, id, disabled, onKeyDown, "aria-invalid": ariaInvalid, "aria-describedby": ariaDescribedBy, ...props }, ref) => {
|
|
9
|
+
const SearchInput = React.forwardRef(({ value, onValueChange, label = "Search", hideLabel = true, description, error, invalid = false, selected = false, placeholder = "Search...", containerClassName, labelClassName, descriptionClassName, errorClassName, onSearch, searchDelay = 300, searchOnChange = true, searchOnEnter = true, className, id, disabled, onKeyDown, "aria-invalid": ariaInvalid, "aria-describedby": ariaDescribedBy, ...props }, ref) => {
|
|
10
10
|
const searchTimeoutRef = React.useRef();
|
|
11
11
|
React.useEffect(() => {
|
|
12
12
|
return () => {
|
|
@@ -64,7 +64,7 @@ const SearchInput = React.forwardRef(({ value, onValueChange, label = "Search",
|
|
|
64
64
|
}
|
|
65
65
|
onKeyDown === null || onKeyDown === void 0 ? void 0 : onKeyDown(event);
|
|
66
66
|
}, [onKeyDown, runSearch, searchOnEnter]);
|
|
67
|
-
return (_jsxs(Field, { className: containerClassName, "data-disabled": disabled ? "true" : undefined, "data-invalid": isInvalid ? "true" : undefined, children: [_jsx(FieldLabel, { htmlFor: inputId, className: cn("sr-only", labelClassName), children: label }), _jsxs(SearchInputShell, { children: [_jsx(InputControl, { ref: ref, id: inputId, type: "text", placeholder: placeholder, value: value, onChange: handleChange, onKeyDown: handleKeyDown, disabled: disabled, "aria-invalid": isInvalid ? "true" : undefined, "aria-describedby": describedBy, className: cn("bg-background pl-8 pr-7", className), ...props }), value ? (_jsx("button", { type: "button", onClick: () => {
|
|
67
|
+
return (_jsxs(Field, { className: containerClassName, "data-disabled": disabled ? "true" : undefined, "data-invalid": isInvalid ? "true" : undefined, children: [_jsx(FieldLabel, { htmlFor: inputId, className: cn(hideLabel && "sr-only", labelClassName), children: label }), _jsxs(SearchInputShell, { children: [_jsx(InputControl, { ref: ref, id: inputId, type: "text", placeholder: placeholder, value: value, onChange: handleChange, onKeyDown: handleKeyDown, disabled: disabled, "aria-invalid": isInvalid ? "true" : undefined, "aria-describedby": describedBy, "data-selected": selected ? "true" : undefined, className: cn("bg-background pl-8 pr-7 data-[selected=true]:border-interactive data-[selected=true]:bg-highlight data-[selected=true]:ring-[3px] data-[selected=true]:ring-interactive/20", className), ...props }), value ? (_jsx("button", { type: "button", onClick: () => {
|
|
68
68
|
onValueChange("");
|
|
69
69
|
runSearch("");
|
|
70
70
|
}, disabled: disabled, className: "absolute right-1.5 top-1/2 -translate-y-1/2 cursor-pointer rounded-sm p-0.5 text-muted-foreground hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-not-allowed disabled:pointer-events-none", "aria-label": "Clear search", children: _jsx(XIcon, { size: 14 }) })) : null] }), showDescription ? (_jsx(FieldDescription, { id: descriptionId, className: descriptionClassName, children: description })) : null, _jsx(FieldError, { id: errorId, className: errorClassName, children: error })] }));
|
package/dist/select-primitive.js
CHANGED
|
@@ -36,7 +36,7 @@ const SelectContent = React.forwardRef(({ className, children, header, position
|
|
|
36
36
|
SelectContent.displayName = SelectPrimitive.Content.displayName;
|
|
37
37
|
const SelectLabel = React.forwardRef(({ className, ...props }, ref) => (_jsx(SelectPrimitive.Label, { ref: ref, "data-slot": "select-label", className: cn("px-2 py-1.5 text-xs text-muted-foreground", className), ...props })));
|
|
38
38
|
SelectLabel.displayName = SelectPrimitive.Label.displayName;
|
|
39
|
-
const SelectItem = React.forwardRef(({ className, children, description, ...props }, ref) => (_jsxs(SelectPrimitive.Item, { ref: ref, "data-slot": "select-item", className: cn("relative flex min-h-8 w-full cursor-pointer select-none items-center gap-1.5 rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground data-[state=checked]:bg-highlight data-[state=checked]:text-highlight-foreground data-[state=checked]:hover:bg-highlight/80 data-[state=checked]:hover:text-highlight-foreground data-[state=checked]:focus:bg-highlight/80 data-[state=checked]:focus:text-highlight-foreground data-[disabled]:
|
|
39
|
+
const SelectItem = React.forwardRef(({ className, children, description, ...props }, ref) => (_jsxs(SelectPrimitive.Item, { ref: ref, "data-slot": "select-item", className: cn("relative flex min-h-8 w-full cursor-pointer select-none items-center gap-1.5 rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground data-[state=checked]:bg-highlight data-[state=checked]:text-highlight-foreground data-[state=checked]:hover:bg-highlight/80 data-[state=checked]:hover:text-highlight-foreground data-[state=checked]:focus:bg-highlight/80 data-[state=checked]:focus:text-highlight-foreground data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50 data-[disabled]:hover:bg-transparent data-[disabled]:hover:text-foreground", className), ...props, children: [_jsx("span", { "data-slot": "select-item-indicator", className: "absolute right-2 flex h-3.5 w-3.5 items-center justify-center", children: _jsx(SelectPrimitive.ItemIndicator, { children: _jsx(Check, { className: "h-4 w-4" }) }) }), _jsxs("div", { className: "flex flex-col gap-0.5", children: [_jsx(SelectPrimitive.ItemText, { className: "break-words font-normal", children: children }), description ? (_jsx(Typography, { as: "span", variant: "caption", children: description })) : null] })] })));
|
|
40
40
|
SelectItem.displayName = SelectPrimitive.Item.displayName;
|
|
41
41
|
const SelectSeparator = React.forwardRef(({ className, ...props }, ref) => (_jsx(SelectPrimitive.Separator, { ref: ref, "data-slot": "select-separator", className: cn("-mx-1 my-1 h-px bg-border", className), ...props })));
|
|
42
42
|
SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
|
package/dist/select.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ export interface SelectOption {
|
|
|
5
5
|
value: string;
|
|
6
6
|
description?: React.ReactNode;
|
|
7
7
|
disabled?: boolean;
|
|
8
|
+
disabledReason?: React.ReactNode;
|
|
8
9
|
group?: string;
|
|
9
10
|
textValue?: string;
|
|
10
11
|
}
|
|
@@ -12,6 +13,7 @@ export interface SelectProps extends Pick<React.ComponentProps<typeof SelectRoot
|
|
|
12
13
|
label: React.ReactNode;
|
|
13
14
|
options: SelectOption[];
|
|
14
15
|
placeholder?: string;
|
|
16
|
+
size?: "default" | "comfortable";
|
|
15
17
|
description?: React.ReactNode;
|
|
16
18
|
error?: React.ReactNode;
|
|
17
19
|
invalid?: boolean;
|
|
@@ -28,5 +30,5 @@ export interface SelectProps extends Pick<React.ComponentProps<typeof SelectRoot
|
|
|
28
30
|
errorClassName?: string;
|
|
29
31
|
id?: string;
|
|
30
32
|
}
|
|
31
|
-
declare function Select({ label, options, placeholder, description, error, invalid, hideLabel, searchable, searchPlaceholder, searchEmptyMessage, searchInputAriaLabel, className, triggerClassName, contentClassName, labelClassName, descriptionClassName, errorClassName, id, disabled, open, onOpenChange, ...props }: SelectProps): import("react/jsx-runtime").JSX.Element;
|
|
33
|
+
declare function Select({ label, options, placeholder, size, description, error, invalid, hideLabel, searchable, searchPlaceholder, searchEmptyMessage, searchInputAriaLabel, className, triggerClassName, contentClassName, labelClassName, descriptionClassName, errorClassName, id, disabled, open, onOpenChange, ...props }: SelectProps): import("react/jsx-runtime").JSX.Element;
|
|
32
34
|
export { Select };
|
package/dist/select.js
CHANGED
|
@@ -5,6 +5,7 @@ import { Field, FieldDescription, FieldError, FieldLabel } from "./field";
|
|
|
5
5
|
import { InputControl } from "./input-control";
|
|
6
6
|
import { cn } from "./lib/utils";
|
|
7
7
|
import { usePopoverTabExit } from "./popover-focus";
|
|
8
|
+
import { Tooltip } from "./tooltip";
|
|
8
9
|
import { SearchHighlight } from "./use-search-highlight";
|
|
9
10
|
import { SelectContent, SelectGroup, SelectItem, SelectLabel, SelectRoot, SelectSeparator, SelectTrigger, SelectValue, } from "./select-primitive";
|
|
10
11
|
function groupOptions(options) {
|
|
@@ -40,7 +41,7 @@ function renderHighlightedLabel(label, query) {
|
|
|
40
41
|
}
|
|
41
42
|
return label;
|
|
42
43
|
}
|
|
43
|
-
function Select({ label, options, placeholder = "Select an option", description, error, invalid = false, hideLabel = false, searchable = false, searchPlaceholder = "Search options...", searchEmptyMessage = "No options found.", searchInputAriaLabel = "Search options", className, triggerClassName, contentClassName, labelClassName, descriptionClassName, errorClassName, id, disabled, open, onOpenChange, ...props }) {
|
|
44
|
+
function Select({ label, options, placeholder = "Select an option", size = "default", description, error, invalid = false, hideLabel = false, searchable = false, searchPlaceholder = "Search options...", searchEmptyMessage = "No options found.", searchInputAriaLabel = "Search options", className, triggerClassName, contentClassName, labelClassName, descriptionClassName, errorClassName, id, disabled, open, onOpenChange, ...props }) {
|
|
44
45
|
const generatedId = React.useId();
|
|
45
46
|
const selectId = id !== null && id !== void 0 ? id : `select-${generatedId}`;
|
|
46
47
|
const triggerRef = React.useRef(null);
|
|
@@ -153,7 +154,8 @@ function Select({ label, options, placeholder = "Select an option", description,
|
|
|
153
154
|
searchable,
|
|
154
155
|
searchQuery,
|
|
155
156
|
]);
|
|
156
|
-
return (_jsxs(Field, { className: className, "data-disabled": disabled ? "true" : undefined, "data-invalid": isInvalid ? "true" : undefined, children: [_jsx(FieldLabel, { htmlFor: selectId, className: cn(hideLabel && "sr-only", labelClassName), children: label }), _jsxs(SelectRoot, { disabled: disabled, open: isOpen, onOpenChange: handleOpenChange, ...props, children: [_jsx(SelectTrigger, { ref: triggerRef, id: selectId, className:
|
|
157
|
+
return (_jsxs(Field, { className: cn(size === "comfortable" && "gap-[8px]", className), "data-disabled": disabled ? "true" : undefined, "data-invalid": isInvalid ? "true" : undefined, children: [_jsx(FieldLabel, { htmlFor: selectId, className: cn(size === "comfortable" && "text-[16px] leading-[24px]", hideLabel && "sr-only", labelClassName), children: label }), _jsxs(SelectRoot, { disabled: disabled, open: isOpen, onOpenChange: handleOpenChange, ...props, children: [_jsx(SelectTrigger, { ref: triggerRef, id: selectId, className: cn(size === "comfortable" &&
|
|
158
|
+
"h-[46px] px-[16px] py-[11px] text-[16px] leading-[24px]", triggerClassName), "aria-invalid": isInvalid ? "true" : undefined, "aria-describedby": [descriptionId, errorId].filter(Boolean).join(" ") || undefined, children: _jsx(SelectValue, { placeholder: placeholder }) }), _jsx(SelectContent, { ref: contentRef, className: contentClassName, onCloseAutoFocus: handleCloseAutoFocus, onKeyDownCapture: handleContentKeyDownCapture, header: searchable ? (_jsx(InputControl, { ref: searchInputRef, value: searchQuery, onChange: (event) => setSearchQuery(event.target.value), placeholder: searchPlaceholder, "aria-label": searchInputAriaLabel, autoComplete: "off", className: "h-control border-0 bg-transparent px-2 py-0 text-sm shadow-none", onKeyDown: (event) => {
|
|
157
159
|
if (event.key === "ArrowDown" ||
|
|
158
160
|
event.key === "ArrowUp") {
|
|
159
161
|
event.preventDefault();
|
|
@@ -167,7 +169,10 @@ function Select({ label, options, placeholder = "Select an option", description,
|
|
|
167
169
|
event.stopPropagation();
|
|
168
170
|
} })) : undefined, viewportClassName: searchable ? "max-h-64" : undefined, children: hasVisibleOptions ? (optionGroups.map((group, groupIndex) => {
|
|
169
171
|
var _a;
|
|
170
|
-
return (_jsxs(React.Fragment, { children: [_jsxs(SelectGroup, { children: [group.group ? (_jsx(SelectLabel, { children: _jsx(SearchHighlight, { text: group.group, query: searchQuery }) })) : null, group.options.map((option) =>
|
|
171
|
-
|
|
172
|
+
return (_jsxs(React.Fragment, { children: [_jsxs(SelectGroup, { children: [group.group ? (_jsx(SelectLabel, { children: _jsx(SearchHighlight, { text: group.group, query: searchQuery }) })) : null, group.options.map((option) => {
|
|
173
|
+
const optionItem = (_jsx(SelectItem, { value: option.value, disabled: option.disabled, textValue: getOptionTextValue(option), description: option.description, children: renderHighlightedLabel(option.label, searchQuery) }));
|
|
174
|
+
return option.disabled && option.disabledReason ? (_jsx(Tooltip, { content: option.disabledReason, side: "right", children: optionItem }, option.value)) : (_jsx(React.Fragment, { children: optionItem }, option.value));
|
|
175
|
+
})] }), groupIndex < optionGroups.length - 1 ? (_jsx(SelectSeparator, {})) : null] }, (_a = group.group) !== null && _a !== void 0 ? _a : `group-${groupIndex}`));
|
|
176
|
+
})) : (_jsx("div", { className: "px-2.5 py-1.5 text-sm text-muted-foreground", children: searchEmptyMessage })) })] }), showDescription ? (_jsx(FieldDescription, { id: descriptionId, className: cn(size === "comfortable" && "text-[14px] leading-[20px]", descriptionClassName), children: description })) : null, _jsx(FieldError, { id: errorId, className: errorClassName, children: error })] }));
|
|
172
177
|
}
|
|
173
178
|
export { Select };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export type StatusDotVariant = "default" | "muted" | "success" | "warning" | "info" | "destructive";
|
|
3
|
+
export type StatusDotSize = "sm" | "md" | "lg";
|
|
4
|
+
export interface StatusDotProps extends Omit<React.HTMLAttributes<HTMLSpanElement>, "children"> {
|
|
5
|
+
/** Semantic colour of the status. */
|
|
6
|
+
variant?: StatusDotVariant;
|
|
7
|
+
/** Diameter of the dot. */
|
|
8
|
+
size?: StatusDotSize;
|
|
9
|
+
/** Accessible name. Omit when nearby text already describes the status. */
|
|
10
|
+
label?: string;
|
|
11
|
+
}
|
|
12
|
+
declare const StatusDot: React.ForwardRefExoticComponent<StatusDotProps & React.RefAttributes<HTMLSpanElement>>;
|
|
13
|
+
export { StatusDot };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { cn } from "./lib/utils";
|
|
4
|
+
const sizeClasses = {
|
|
5
|
+
sm: "size-[6px]",
|
|
6
|
+
md: "size-[8px]",
|
|
7
|
+
lg: "size-[10px]",
|
|
8
|
+
};
|
|
9
|
+
const variantClasses = {
|
|
10
|
+
default: "bg-primary",
|
|
11
|
+
muted: "bg-muted-foreground",
|
|
12
|
+
success: "bg-[hsl(var(--nea-green-400))]",
|
|
13
|
+
warning: "bg-[hsl(var(--nea-amber-400))]",
|
|
14
|
+
info: "bg-[hsl(var(--nea-blue-400))]",
|
|
15
|
+
destructive: "bg-[hsl(var(--nea-red-400))]",
|
|
16
|
+
};
|
|
17
|
+
const StatusDot = React.forwardRef(({ variant = "default", size = "md", label, className, ...props }, ref) => (_jsx("span", { ref: ref, "data-slot": "status-dot", role: label ? "img" : undefined, "aria-label": label, "aria-hidden": label ? undefined : true, className: cn("inline-block shrink-0 rounded-full", sizeClasses[size], variantClasses[variant], className), ...props })));
|
|
18
|
+
StatusDot.displayName = "StatusDot";
|
|
19
|
+
export { StatusDot };
|
package/dist/styles.css
CHANGED
|
@@ -413,25 +413,6 @@
|
|
|
413
413
|
}
|
|
414
414
|
|
|
415
415
|
@layer components {
|
|
416
|
-
[data-slot="routing-timeline"] {
|
|
417
|
-
--routing-timeline-background: var(--layout-right-panel-background);
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
[data-slot="routing-timeline-list"]::before {
|
|
421
|
-
position: absolute;
|
|
422
|
-
top: var(--space-2);
|
|
423
|
-
bottom: var(--space-0);
|
|
424
|
-
left: calc(var(--space-3) / 2);
|
|
425
|
-
width: 1px;
|
|
426
|
-
content: "";
|
|
427
|
-
transform: translateX(-50%);
|
|
428
|
-
background: hsl(var(--border));
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
[data-slot="routing-timeline-marker"] {
|
|
432
|
-
box-shadow: 0 0 0 var(--space-1) hsl(var(--routing-timeline-background));
|
|
433
|
-
}
|
|
434
|
-
|
|
435
416
|
[data-slot="routing-timeline-event-card"] {
|
|
436
417
|
container-type: inline-size;
|
|
437
418
|
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import { FilterIcon } from "./animated-icons";
|
|
5
|
+
import { buttonVariants } from "./button";
|
|
5
6
|
import { DateInput } from "./date-input";
|
|
6
7
|
import { FilterPopover } from "./filter-popover";
|
|
7
8
|
import { FilterToggle, filterToggleVariants, } from "./filter-toggle";
|
|
@@ -29,7 +30,7 @@ function getOptionsFilterSummary(filter) {
|
|
|
29
30
|
}
|
|
30
31
|
return ((_c = (_b = filter.options.find((option) => option.value === filter.values[0])) === null || _b === void 0 ? void 0 : _b.label) !== null && _c !== void 0 ? _c : filter.values[0]);
|
|
31
32
|
}
|
|
32
|
-
const TableFilterTrigger = React.forwardRef(({ active, disabled, label, children, ...props }, ref) => (_jsx(FilterToggle, { ref: ref, type: "button", disabled: disabled, selected: active, "aria-label": `Filter by ${label}${active ? ", active" : ""}`, className: cn("h-
|
|
33
|
+
const TableFilterTrigger = React.forwardRef(({ active, disabled, label, children, ...props }, ref) => (_jsx(FilterToggle, { ref: ref, type: "button", disabled: disabled, selected: active, "aria-label": `Filter by ${label}${active ? ", active" : ""}`, className: cn("h-8 w-full min-w-0 justify-start overflow-hidden px-2 text-sm font-normal", !active &&
|
|
33
34
|
"bg-transparent text-muted-foreground hover:bg-accent hover:text-accent-foreground"), icon: _jsx(FilterIcon, { "aria-hidden": "true", className: "shrink-0", size: 16 }), ...props, children: _jsx("span", { className: "min-w-0 flex-1 truncate text-left", children: children }) })));
|
|
34
35
|
TableFilterTrigger.displayName = "TableFilterTrigger";
|
|
35
36
|
function TextColumnFilter({ filter, label, }) {
|
|
@@ -71,15 +72,16 @@ function DateColumnFilter({ filter, label, }) {
|
|
|
71
72
|
var _a, _b;
|
|
72
73
|
const active = isTableColumnFilterActive(filter);
|
|
73
74
|
const accessibleLabel = (_a = filter.label) !== null && _a !== void 0 ? _a : label;
|
|
74
|
-
return (_jsx(DateInput, { label: `Filter by ${accessibleLabel}${active ? ", active" : ""}`, hideLabel: true, value: filter.value, onValueChange: filter.onValueChange, placeholder: (_b = filter.placeholder) !== null && _b !== void 0 ? _b : "Pick a date", disabled: filter.disabled, minDate: filter.minDate, maxDate: filter.maxDate, clearable: true, clearLabel: `Clear ${accessibleLabel} filter`, className: "gap-0", triggerClassName: cn(
|
|
75
|
-
"border-
|
|
75
|
+
return (_jsx(DateInput, { label: `Filter by ${accessibleLabel}${active ? ", active" : ""}`, hideLabel: true, value: filter.value, onValueChange: filter.onValueChange, placeholder: (_b = filter.placeholder) !== null && _b !== void 0 ? _b : "Pick a date", popoverTitle: `Filter by ${accessibleLabel}`, disabled: filter.disabled, minDate: filter.minDate, maxDate: filter.maxDate, clearable: true, clearLabel: `Clear ${accessibleLabel} filter`, className: "gap-0", triggerClassName: cn(buttonVariants({ variant: "outline", size: "sm" }), "h-8 w-full min-w-0 justify-start font-normal shadow-none", active ? "pl-2 pr-16" : "pl-2 pr-9", active
|
|
76
|
+
? "border-transparent bg-highlight text-highlight-foreground hover:bg-highlight/80"
|
|
77
|
+
: "bg-transparent text-muted-foreground hover:bg-accent hover:text-accent-foreground") }));
|
|
76
78
|
}
|
|
77
79
|
function DateRangeColumnFilter({ filter, label, }) {
|
|
78
80
|
var _a, _b;
|
|
79
81
|
const active = isTableColumnFilterActive(filter);
|
|
80
82
|
const accessibleLabel = (_a = filter.label) !== null && _a !== void 0 ? _a : label;
|
|
81
|
-
return (_jsx(DateInput, { mode: "range", label: `Filter by ${accessibleLabel}${active ? ", active" : ""}`, hideLabel: true, value: filter.value, onValueChange: filter.onValueChange, placeholder: (_b = filter.placeholder) !== null && _b !== void 0 ? _b : "Pick date range", disabled: filter.disabled, minDate: filter.minDate, maxDate: filter.maxDate, clearable: true, clearLabel: `Clear ${accessibleLabel} filter`, className: "gap-0", triggerClassName: cn(filterToggleVariants({ selected: active }), "h-
|
|
82
|
-
"
|
|
83
|
+
return (_jsx(DateInput, { mode: "range", label: `Filter by ${accessibleLabel}${active ? ", active" : ""}`, hideLabel: true, value: filter.value, onValueChange: filter.onValueChange, placeholder: (_b = filter.placeholder) !== null && _b !== void 0 ? _b : "Pick date range", popoverTitle: `Filter by ${accessibleLabel}`, disabled: filter.disabled, minDate: filter.minDate, maxDate: filter.maxDate, clearable: true, clearLabel: `Clear ${accessibleLabel} filter`, className: "gap-0", triggerClassName: cn(filterToggleVariants({ selected: active }), "h-8 w-full min-w-0 justify-start border-0 text-sm font-normal shadow-none", active ? "pl-2 pr-16" : "pl-2 pr-9", !active &&
|
|
84
|
+
"bg-transparent text-muted-foreground hover:bg-accent hover:text-accent-foreground") }));
|
|
83
85
|
}
|
|
84
86
|
function TableColumnFilterControl({ filter, label, }) {
|
|
85
87
|
if (filter.type === "text") {
|
package/dist/table.d.ts
CHANGED
|
@@ -123,6 +123,12 @@ export interface TableRowExpansionProps<Row> {
|
|
|
123
123
|
/** Accessible label for a row's expansion toggle. */
|
|
124
124
|
getToggleLabel?: (row: Row, rowIndex: number, expanded: boolean) => string;
|
|
125
125
|
}
|
|
126
|
+
export interface TableRowIndicatorProps<Row> {
|
|
127
|
+
/** Renders a compact status marker in a fixed leading column for each row. */
|
|
128
|
+
render: (row: Row, rowIndex: number) => React.ReactNode;
|
|
129
|
+
/** Accessible name for the otherwise visually empty indicator column header. */
|
|
130
|
+
headerLabel?: string;
|
|
131
|
+
}
|
|
126
132
|
interface SortableTableHeadProps extends Omit<React.ThHTMLAttributes<HTMLTableCellElement>, "children" | "style"> {
|
|
127
133
|
field: string;
|
|
128
134
|
children: React.ReactNode;
|
|
@@ -194,6 +200,8 @@ export interface TableProps<Row> extends Omit<React.HTMLAttributes<HTMLDivElemen
|
|
|
194
200
|
emptyStateMinHeight?: React.CSSProperties["minHeight"];
|
|
195
201
|
/** When true, applies alternating row backgrounds for easier scanning. */
|
|
196
202
|
striped?: boolean;
|
|
203
|
+
/** Adds a compact, non-reorderable status column at the leading edge of every row. */
|
|
204
|
+
rowIndicator?: TableRowIndicatorProps<Row>;
|
|
197
205
|
/** Adds a disclosure column and full-width expandable content for nested tables or row details. */
|
|
198
206
|
rowExpansion?: TableRowExpansionProps<Row>;
|
|
199
207
|
/** When true, non-sticky header cells become draggable for column reordering. */
|
|
@@ -201,5 +209,5 @@ export interface TableProps<Row> extends Omit<React.HTMLAttributes<HTMLDivElemen
|
|
|
201
209
|
/** Called with the new ordered column key array after a drag-and-drop reorder. */
|
|
202
210
|
onColumnOrderChange?: (columnKeys: string[]) => void;
|
|
203
211
|
}
|
|
204
|
-
declare function Table<Row>({ accessibleLabel, columns, rows, getRowKey, emptyState, toolbar, caption, className, containerClassName, tableClassName, rowClassName, rowTone, maxHeight, minHeight, sorting, pagination, loading, loadingLabel, loadingRows, visibleColumnKeys, resizableColumns, columnResizeMode, columnWidths, defaultColumnWidths, onColumnWidthsChange, renderColumnResizeHandle, tableLayout, centerEmptyState, emptyStateMinHeight, striped, rowExpansion, reorderableColumns, onColumnOrderChange, onScroll, style, ...props }: TableProps<Row>): import("react/jsx-runtime").JSX.Element;
|
|
212
|
+
declare function Table<Row>({ accessibleLabel, columns, rows, getRowKey, emptyState, toolbar, caption, className, containerClassName, tableClassName, rowClassName, rowTone, maxHeight, minHeight, sorting, pagination, loading, loadingLabel, loadingRows, visibleColumnKeys, resizableColumns, columnResizeMode, columnWidths, defaultColumnWidths, onColumnWidthsChange, renderColumnResizeHandle, tableLayout, centerEmptyState, emptyStateMinHeight, striped, rowIndicator, rowExpansion, reorderableColumns, onColumnOrderChange, onScroll, style, ...props }: TableProps<Row>): import("react/jsx-runtime").JSX.Element;
|
|
205
213
|
export { Table, TableRoot, TableContainer, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell, TableRowHeader, TableCaption, SortableTableHead, TableRowSkeleton, };
|
package/dist/table.js
CHANGED
|
@@ -19,6 +19,7 @@ const DEFAULT_COLUMN_RESIZE_MIN_WIDTH = 64;
|
|
|
19
19
|
const DEFAULT_COLUMN_RESIZE_START_WIDTH = 160;
|
|
20
20
|
const DEFAULT_COLUMN_RESIZE_MAX_WIDTH = 1200;
|
|
21
21
|
const COLUMN_RESIZE_KEYBOARD_STEP = 16;
|
|
22
|
+
const TABLE_ROW_INDICATOR_COLUMN_WIDTH = 32;
|
|
22
23
|
const TABLE_EXPANSION_COLUMN_WIDTH = 48;
|
|
23
24
|
const TABLE_MIN_WIDTH_CSS_VAR = "--table-min-width";
|
|
24
25
|
const DEFAULT_TABLE_MIN_HEIGHT = "var(--table-min-height, var(--app-table-min-height, 24rem))";
|
|
@@ -159,7 +160,7 @@ const TableFooter = React.forwardRef(({ className, ...props }, ref) => (_jsx("tf
|
|
|
159
160
|
TableFooter.displayName = "TableFooter";
|
|
160
161
|
const TableRow = React.forwardRef(({ className, ...props }, ref) => (_jsx("tr", { ref: ref, className: cn("border-b border-[hsl(var(--table-border))] bg-card text-card-foreground transition-colors data-[state=selected]:bg-muted", className), ...props })));
|
|
161
162
|
TableRow.displayName = "TableRow";
|
|
162
|
-
const TableHead = React.forwardRef(({ className, style, width, minWidth, maxWidth, wrap = false, treatWidthAsMinWidth, containOverflow, ...props }, ref) => (_jsx("th", { ref: ref, className: cn("h-11 px-4 py-
|
|
163
|
+
const TableHead = React.forwardRef(({ className, style, width, minWidth, maxWidth, wrap = false, treatWidthAsMinWidth, containOverflow, ...props }, ref) => (_jsx("th", { ref: ref, className: cn("h-11 px-4 py-[4px] text-left align-middle font-medium text-instructional [&:has([role=checkbox])]:pr-0", wrap ? "whitespace-normal" : "whitespace-nowrap", overflowContainmentClassName({ containOverflow, wrap }), className), style: getTableColumnSizingStyle({
|
|
163
164
|
style: {
|
|
164
165
|
...style,
|
|
165
166
|
fontWeight: 500,
|
|
@@ -170,7 +171,7 @@ const TableHead = React.forwardRef(({ className, style, width, minWidth, maxWidt
|
|
|
170
171
|
treatWidthAsMinWidth,
|
|
171
172
|
}), ...props })));
|
|
172
173
|
TableHead.displayName = "TableHead";
|
|
173
|
-
const TableCell = React.forwardRef(({ className, style, width, minWidth, maxWidth, wrap = false, treatWidthAsMinWidth, containOverflow, ...props }, ref) => (_jsx("td", { ref: ref, className: cn("h-12 px-4 py-
|
|
174
|
+
const TableCell = React.forwardRef(({ className, style, width, minWidth, maxWidth, wrap = false, treatWidthAsMinWidth, containOverflow, ...props }, ref) => (_jsx("td", { ref: ref, className: cn("h-12 px-4 py-[4px] align-middle text-card-foreground [&:has([role=checkbox])]:pr-0", wrap ? "whitespace-normal" : "whitespace-nowrap", overflowContainmentClassName({ containOverflow, wrap }), className), style: getTableColumnSizingStyle({
|
|
174
175
|
style,
|
|
175
176
|
width,
|
|
176
177
|
minWidth,
|
|
@@ -178,7 +179,7 @@ const TableCell = React.forwardRef(({ className, style, width, minWidth, maxWidt
|
|
|
178
179
|
treatWidthAsMinWidth,
|
|
179
180
|
}), ...props })));
|
|
180
181
|
TableCell.displayName = "TableCell";
|
|
181
|
-
const TableRowHeader = React.forwardRef(({ className, style, width, minWidth, maxWidth, wrap = false, treatWidthAsMinWidth, containOverflow, scope = "row", ...props }, ref) => (_jsx("th", { ref: ref, scope: scope, className: cn("h-12 px-4 py-
|
|
182
|
+
const TableRowHeader = React.forwardRef(({ className, style, width, minWidth, maxWidth, wrap = false, treatWidthAsMinWidth, containOverflow, scope = "row", ...props }, ref) => (_jsx("th", { ref: ref, scope: scope, className: cn("h-12 px-4 py-[4px] text-left align-middle font-medium text-card-foreground [&:has([role=checkbox])]:pr-0", wrap ? "whitespace-normal" : "whitespace-nowrap", overflowContainmentClassName({ containOverflow, wrap }), className), style: getTableColumnSizingStyle({
|
|
182
183
|
style,
|
|
183
184
|
width,
|
|
184
185
|
minWidth,
|
|
@@ -198,7 +199,11 @@ function stickyClassName(sticky, kind, showShadow = false) {
|
|
|
198
199
|
? "shadow-[inset_-1px_0_0_0_hsl(var(--table-border)),_8px_0_12px_-10px_hsl(var(--foreground)_/_0.35)]"
|
|
199
200
|
: "shadow-[inset_1px_0_0_0_hsl(var(--table-border)),_-8px_0_12px_-10px_hsl(var(--foreground)_/_0.35)]"
|
|
200
201
|
: undefined;
|
|
201
|
-
const background = kind === "head"
|
|
202
|
+
const background = kind === "head"
|
|
203
|
+
? "bg-[hsl(var(--table-header-background))]"
|
|
204
|
+
: kind === "cell"
|
|
205
|
+
? "bg-inherit"
|
|
206
|
+
: "bg-card";
|
|
202
207
|
// Header and filter cells layer above sticky body cells on the other axis.
|
|
203
208
|
const z = kind === "cell" ? "z-10" : "z-20";
|
|
204
209
|
return cn("sticky", background, side, z, shadow);
|
|
@@ -236,7 +241,7 @@ function SkeletonCell({ config }) {
|
|
|
236
241
|
return (_jsx(TableCell, { children: _jsx(SkeletonBlock, { width: config.width, height: config.height, badge: config.badge }) }));
|
|
237
242
|
}
|
|
238
243
|
function TableRowSkeleton({ columns, rows = 1 }) {
|
|
239
|
-
return (_jsx(_Fragment, { children: Array.from({ length: rows }).map((_, rowIndex) => (_jsx(TableRow, { children: columns.map((config, columnIndex) => (_jsx(SkeletonCell, { config: config }, columnIndex))) }, rowIndex))) }));
|
|
244
|
+
return (_jsx(_Fragment, { children: Array.from({ length: rows }).map((_, rowIndex) => (_jsx(TableRow, { "data-slot": "table-skeleton-row", className: "h-12", children: columns.map((config, columnIndex) => (_jsx(SkeletonCell, { config: config }, columnIndex))) }, rowIndex))) }));
|
|
240
245
|
}
|
|
241
246
|
export const TABLE_SKELETON_PRESETS = {
|
|
242
247
|
text: (width = "8rem", height = "1rem") => ({
|
|
@@ -274,7 +279,7 @@ const SortableTableHead = React.forwardRef(function SortableTableHead({ field, c
|
|
|
274
279
|
? currentSortDirection === "asc"
|
|
275
280
|
? "ascending"
|
|
276
281
|
: "descending"
|
|
277
|
-
: undefined, className: cn(resizeHandle && "relative", alignClassName(align), className), style: style, wrap: allowWrap, width: width, minWidth: minWidth, maxWidth: maxWidth, treatWidthAsMinWidth: treatWidthAsMinWidth, containOverflow: containOverflow, ...rest, children: [gripIcon, _jsxs("button", { type: "button", onClick: () => onSort(field), className: cn("-ml-1.5 flex h-7 cursor-pointer items-center gap-1 rounded px-1.5 py-0 font-medium transition-colors hover:text-foreground", containOverflow && "max-w-full overflow-hidden", allowWrap
|
|
282
|
+
: undefined, className: cn(resizeHandle && "relative", alignClassName(align), className), style: style, wrap: allowWrap, width: width, minWidth: minWidth, maxWidth: maxWidth, treatWidthAsMinWidth: treatWidthAsMinWidth, containOverflow: containOverflow, ...rest, children: [gripIcon, _jsxs("button", { type: "button", onClick: () => onSort(field), className: cn("-ml-1.5 flex h-auto min-h-7 cursor-pointer items-center gap-1 rounded px-1.5 py-0 font-medium transition-colors hover:text-foreground", containOverflow && "max-w-full overflow-hidden", allowWrap
|
|
278
283
|
? "max-w-full whitespace-normal text-left"
|
|
279
284
|
: "whitespace-nowrap", align === "right" && "ml-auto justify-end", align === "center" && "mx-auto justify-center"), style: { font: "inherit", color: "inherit", fontWeight: 500 }, "aria-label": `Sort by ${resolvedSortLabel}`, children: [_jsx("span", { className: cn("min-w-0", containOverflow && !allowWrap && "truncate", containOverflow &&
|
|
280
285
|
allowWrap &&
|
|
@@ -394,8 +399,10 @@ function getColumnPairResizeRange(column, nextColumn, columnWidths) {
|
|
|
394
399
|
maxWidth: Math.round(currentWidth + maxDelta),
|
|
395
400
|
};
|
|
396
401
|
}
|
|
397
|
-
function Table({ accessibleLabel, 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, loadingLabel = "Loading table data", loadingRows = 5, visibleColumnKeys, resizableColumns = false, columnResizeMode = "pair", columnWidths, defaultColumnWidths, onColumnWidthsChange, renderColumnResizeHandle, tableLayout, centerEmptyState = false, emptyStateMinHeight = DEFAULT_CENTERED_EMPTY_STATE_MIN_HEIGHT, striped = false, rowExpansion, reorderableColumns = false, onColumnOrderChange, onScroll, style, ...props }) {
|
|
402
|
+
function Table({ accessibleLabel, 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, loadingLabel = "Loading table data", loadingRows = 5, visibleColumnKeys, resizableColumns = false, columnResizeMode = "pair", columnWidths, defaultColumnWidths, onColumnWidthsChange, renderColumnResizeHandle, tableLayout, centerEmptyState = false, emptyStateMinHeight = DEFAULT_CENTERED_EMPTY_STATE_MIN_HEIGHT, striped = false, rowIndicator, rowExpansion, reorderableColumns = false, onColumnOrderChange, onScroll, style, ...props }) {
|
|
403
|
+
var _a;
|
|
398
404
|
const visibleColumns = getVisibleColumns(columns, visibleColumnKeys);
|
|
405
|
+
const hasRowIndicatorColumn = Boolean(rowIndicator);
|
|
399
406
|
const hasExpansionColumn = Boolean(rowExpansion);
|
|
400
407
|
const hasColumnFilters = visibleColumns.some((column) => column.filter);
|
|
401
408
|
const isGrowResizeMode = columnResizeMode === "grow";
|
|
@@ -409,6 +416,7 @@ function Table({ accessibleLabel, columns, rows, getRowKey, emptyState = (_jsx(E
|
|
|
409
416
|
const hasResolvedColumnWidths = hasColumnWidthOverrides(resolvedColumnWidths);
|
|
410
417
|
const growTableMinWidth = isGrowResizeMode
|
|
411
418
|
? getTableMinWidth(visibleColumns, resolvedColumnWidths) +
|
|
419
|
+
(hasRowIndicatorColumn ? TABLE_ROW_INDICATOR_COLUMN_WIDTH : 0) +
|
|
412
420
|
(hasExpansionColumn ? TABLE_EXPANSION_COLUMN_WIDTH : 0)
|
|
413
421
|
: undefined;
|
|
414
422
|
const resolvedMinHeight = minHeight !== null && minHeight !== void 0 ? minHeight : (centerEmptyState ? DEFAULT_TABLE_MIN_HEIGHT : undefined);
|
|
@@ -669,7 +677,11 @@ function Table({ accessibleLabel, columns, rows, getRowKey, emptyState = (_jsx(E
|
|
|
669
677
|
}, ...props, children: [_jsxs(TableRoot, { "aria-busy": loading, className: cn(shouldUseFixedLayout && "table-fixed", isGrowResizeMode &&
|
|
670
678
|
(hasResolvedColumnWidths
|
|
671
679
|
? "w-[var(--table-min-width)]"
|
|
672
|
-
: "min-w-[var(--table-min-width)]"), tableClassName), children: [_jsx(TableCaption, { className: caption ? undefined : "sr-only !m-0", children: caption !== null && caption !== void 0 ? caption : accessibleLabel }), _jsxs("colgroup", { children: [
|
|
680
|
+
: "min-w-[var(--table-min-width)]"), tableClassName), children: [_jsx(TableCaption, { className: caption ? undefined : "sr-only !m-0", children: caption !== null && caption !== void 0 ? caption : accessibleLabel }), _jsxs("colgroup", { children: [hasRowIndicatorColumn ? (_jsx("col", { style: {
|
|
681
|
+
width: `${TABLE_ROW_INDICATOR_COLUMN_WIDTH}px`,
|
|
682
|
+
minWidth: `${TABLE_ROW_INDICATOR_COLUMN_WIDTH}px`,
|
|
683
|
+
maxWidth: `${TABLE_ROW_INDICATOR_COLUMN_WIDTH}px`,
|
|
684
|
+
} })) : null, hasExpansionColumn ? (_jsx("col", { style: {
|
|
673
685
|
width: `${TABLE_EXPANSION_COLUMN_WIDTH}px`,
|
|
674
686
|
minWidth: `${TABLE_EXPANSION_COLUMN_WIDTH}px`,
|
|
675
687
|
maxWidth: `${TABLE_EXPANSION_COLUMN_WIDTH}px`,
|
|
@@ -682,14 +694,17 @@ function Table({ accessibleLabel, columns, rows, getRowKey, emptyState = (_jsx(E
|
|
|
682
694
|
minWidth: getRenderedColumnMinWidth(column, isColumnResizingEnabled),
|
|
683
695
|
maxWidth: getRenderedColumnMaxWidth(column, isColumnResizingEnabled),
|
|
684
696
|
treatWidthAsMinWidth: !isColumnResizingEnabled,
|
|
685
|
-
}) }, column.key)))] }), _jsxs(TableHeader, { children: [_jsxs(TableRow, { children: [hasExpansionColumn ? (_jsx(TableHead, { "data-slot": "table-expansion-head", "aria-label": "Expand rows", scope: "col", className: "w-12 px-2" })) : null, renderColumnHeaders(visibleColumns)] }), hasColumnFilters ? (_jsxs(TableRow, { "data-slot": "table-filter-row", className: "!bg-card", children: [hasExpansionColumn ? (_jsx(TableCell, { "data-slot": "table-expansion-filter-cell", "aria-hidden": "true", className: "w-12 px-2" })) : null, visibleColumns.map((column) => {
|
|
697
|
+
}) }, column.key)))] }), _jsxs(TableHeader, { children: [_jsxs(TableRow, { children: [hasRowIndicatorColumn ? (_jsx(TableHead, { "data-slot": "table-row-indicator-head", "aria-label": (_a = rowIndicator === null || rowIndicator === void 0 ? void 0 : rowIndicator.headerLabel) !== null && _a !== void 0 ? _a : "Row status", scope: "col", className: "w-8 px-2" })) : null, hasExpansionColumn ? (_jsx(TableHead, { "data-slot": "table-expansion-head", "aria-label": "Expand rows", scope: "col", className: "w-12 px-2" })) : null, renderColumnHeaders(visibleColumns)] }), hasColumnFilters ? (_jsxs(TableRow, { "data-slot": "table-filter-row", className: "!bg-card", children: [hasRowIndicatorColumn ? (_jsx(TableCell, { "data-slot": "table-row-indicator-filter-cell", "aria-hidden": "true", className: "h-11 w-8 px-2 py-[4px]" })) : null, hasExpansionColumn ? (_jsx(TableCell, { "data-slot": "table-expansion-filter-cell", "aria-hidden": "true", className: "h-11 w-12 px-2 py-[4px]" })) : null, visibleColumns.map((column) => {
|
|
686
698
|
const columnWidth = getRenderedColumnWidth({
|
|
687
699
|
column,
|
|
688
700
|
columnWidths: resolvedColumnWidths,
|
|
689
701
|
resizing: isColumnResizingEnabled,
|
|
690
702
|
});
|
|
691
|
-
return (_jsx(TableCell, { "data-slot": "table-filter-cell", width: columnWidth, minWidth: getRenderedColumnMinWidth(column, isColumnResizingEnabled), maxWidth: getRenderedColumnMaxWidth(column, isColumnResizingEnabled), treatWidthAsMinWidth: !isColumnResizingEnabled, containOverflow: isColumnResizingEnabled, className: cn("relative h-11 px-2 py-
|
|
703
|
+
return (_jsx(TableCell, { "data-slot": "table-filter-cell", width: columnWidth, minWidth: getRenderedColumnMinWidth(column, isColumnResizingEnabled), maxWidth: getRenderedColumnMaxWidth(column, isColumnResizingEnabled), treatWidthAsMinWidth: !isColumnResizingEnabled, containOverflow: isColumnResizingEnabled, className: cn("relative h-11 px-2 py-[4px] font-normal", stickyClassName(column.sticky, "filter", getStickyShadowVisibility(column.sticky, stickyScrollState)), column.filterClassName), children: column.filter ? (_jsx("div", { "data-slot": "table-filter-control", className: "absolute inset-x-2 inset-y-[4px] min-w-0", children: _jsx(TableColumnFilterControl, { filter: column.filter, label: getColumnResizeLabel(column) }) })) : null }, column.key));
|
|
692
704
|
})] })) : null] }), _jsx(TableBody, { "aria-hidden": loading ? "true" : undefined, children: loading ? (_jsx(TableRowSkeleton, { rows: loadingRows, columns: [
|
|
705
|
+
...(hasRowIndicatorColumn
|
|
706
|
+
? [{ width: "0.5rem", height: "0.5rem", badge: true }]
|
|
707
|
+
: []),
|
|
693
708
|
...(hasExpansionColumn
|
|
694
709
|
? [{ width: "1rem", height: "1rem" }]
|
|
695
710
|
: []),
|
|
@@ -711,7 +726,7 @@ function Table({ accessibleLabel, columns, rows, getRowKey, emptyState = (_jsx(E
|
|
|
711
726
|
!resolvedTone &&
|
|
712
727
|
"bg-[hsl(var(--table-row-striped-background))]", tableRowToneClassName(resolvedTone), typeof rowClassName === "function"
|
|
713
728
|
? rowClassName(row, rowIndex)
|
|
714
|
-
: rowClassName), children: [hasExpansionColumn ? (_jsx(TableCell, { className: "w-12 px-2 text-center", children: isRowExpandable ? (_jsx("button", { type: "button", "aria-expanded": isExpanded, "aria-controls": isExpanded ? expandedContentId : undefined, "aria-label": (_d = (_c = rowExpansion === null || rowExpansion === void 0 ? void 0 : rowExpansion.getToggleLabel) === null || _c === void 0 ? void 0 : _c.call(rowExpansion, row, rowIndex, isExpanded)) !== null && _d !== void 0 ? _d : `${isExpanded ? "Collapse" : "Expand"} row ${rowIndex + 1}`, onClick: (event) => {
|
|
729
|
+
: rowClassName), children: [hasRowIndicatorColumn ? (_jsx(TableCell, { "data-slot": "table-row-indicator-cell", className: "w-8 px-2 text-center", children: rowIndicator === null || rowIndicator === void 0 ? void 0 : rowIndicator.render(row, rowIndex) })) : null, hasExpansionColumn ? (_jsx(TableCell, { className: "w-12 px-2 text-center", children: isRowExpandable ? (_jsx("button", { type: "button", "aria-expanded": isExpanded, "aria-controls": isExpanded ? expandedContentId : undefined, "aria-label": (_d = (_c = rowExpansion === null || rowExpansion === void 0 ? void 0 : rowExpansion.getToggleLabel) === null || _c === void 0 ? void 0 : _c.call(rowExpansion, row, rowIndex, isExpanded)) !== null && _d !== void 0 ? _d : `${isExpanded ? "Collapse" : "Expand"} row ${rowIndex + 1}`, onClick: (event) => {
|
|
715
730
|
event.stopPropagation();
|
|
716
731
|
toggleExpandedRow(rowKey);
|
|
717
732
|
}, className: "inline-flex h-8 w-8 cursor-pointer items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-muted hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2", children: _jsx(ChevronRight, { "aria-hidden": "true", className: cn("h-4 w-4 transition-transform duration-150", isExpanded && "rotate-90") }) })) : null })) : null, visibleColumns.map((column) => {
|
|
@@ -729,8 +744,11 @@ function Table({ accessibleLabel, columns, rows, getRowKey, emptyState = (_jsx(E
|
|
|
729
744
|
: TableCell;
|
|
730
745
|
return (_jsx(Cell, { 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));
|
|
731
746
|
})] }), isExpanded ? (_jsx(TableRow, { id: expandedContentId, "data-slot": "table-expanded-row", className: "bg-[hsl(var(--table-row-striped-background))] hover:bg-[hsl(var(--table-row-striped-background))]", children: _jsx(TableCell, { colSpan: Math.max(visibleColumns.length +
|
|
747
|
+
(hasRowIndicatorColumn ? 1 : 0) +
|
|
732
748
|
(hasExpansionColumn ? 1 : 0), 1), className: "h-auto whitespace-normal p-4", children: rowExpansion === null || rowExpansion === void 0 ? void 0 : rowExpansion.renderExpandedContent(row, rowIndex) }) })) : null] }, rowKey));
|
|
733
|
-
})) : (_jsx(TableRow, { className: "cursor-default hover:bg-card", children: _jsx(TableCell, { colSpan: Math.max(visibleColumns.length +
|
|
749
|
+
})) : (_jsx(TableRow, { className: "cursor-default hover:bg-card", children: _jsx(TableCell, { colSpan: Math.max(visibleColumns.length +
|
|
750
|
+
(hasRowIndicatorColumn ? 1 : 0) +
|
|
751
|
+
(hasExpansionColumn ? 1 : 0), 1), className: "p-6", children: resolvedEmptyState }) })) })] }), _jsx("div", { role: "status", className: "sr-only", children: loading ? loadingLabel : null })] }));
|
|
734
752
|
const reorderableContainer = reorderableColumns ? (_jsx(DndContext, { sensors: columnReorderSensors, collisionDetection: closestCenter, onDragEnd: handleColumnDragEnd, children: _jsx(SortableContext, { items: reorderableColumnIds, strategy: horizontalListSortingStrategy, children: container }) })) : (container);
|
|
735
753
|
if (!pagination) {
|
|
736
754
|
return (_jsxs("div", { className: "space-y-4", children: [toolbar, reorderableContainer] }));
|
package/dist/tabs.d.ts
CHANGED
|
@@ -65,7 +65,7 @@ export interface TabsProps extends Omit<React.ComponentPropsWithoutRef<typeof Ta
|
|
|
65
65
|
defaultValue?: string;
|
|
66
66
|
value?: string;
|
|
67
67
|
onValueChange?: (value: string) => void;
|
|
68
|
-
size?: "default" | "compact";
|
|
68
|
+
size?: "default" | "compact" | "comfortable";
|
|
69
69
|
renderPanels?: boolean;
|
|
70
70
|
listWrapperClassName?: string;
|
|
71
71
|
listClassName?: string;
|
package/dist/tabs.js
CHANGED
|
@@ -144,13 +144,15 @@ function Tabs({ items, defaultValue, value, onValueChange, size = "default", ren
|
|
|
144
144
|
if (!items.length) {
|
|
145
145
|
return null;
|
|
146
146
|
}
|
|
147
|
-
return (_jsxs(TabsRoot, { defaultValue: fallbackValue, value: value, onValueChange: handleValueChange, className: cn("space-y-4", className), ...props, children: [_jsx("div", { ref: listWrapperRef, className: listWrapperClassName, children: _jsx(TabsList, { className: cn(size === "compact" && "p-0.5", listClassName), children: items.map((item) => item.sections && item.sections.length > 0 ? (_jsx(TabTriggerWithDropdown, { item: item, suppressAriaControls: !renderPanels, triggerClassName: cn(size === "compact" &&
|
|
148
|
-
"min-h-7 px-2.5 py-0.5 data-[state=active]:shadow-sm",
|
|
149
|
-
"min-h-
|
|
147
|
+
return (_jsxs(TabsRoot, { defaultValue: fallbackValue, value: value, onValueChange: handleValueChange, className: cn("space-y-4", className), ...props, children: [_jsx("div", { ref: listWrapperRef, className: listWrapperClassName, children: _jsx(TabsList, { className: cn(size === "compact" && "p-0.5", size === "comfortable" && "rounded-[10px]", listClassName), children: items.map((item) => item.sections && item.sections.length > 0 ? (_jsx(TabTriggerWithDropdown, { item: item, suppressAriaControls: !renderPanels, triggerClassName: cn(size === "compact" &&
|
|
148
|
+
"min-h-7 px-2.5 py-0.5 data-[state=active]:shadow-sm", size === "comfortable" &&
|
|
149
|
+
"min-h-[40px] rounded-md px-[12px] py-[8px] text-[16px]", triggerClassName) }, item.value)) : (_jsx(TabTriggerItem, { item: item, suppressAriaControls: !renderPanels, triggerClassName: cn(size === "compact" &&
|
|
150
|
+
"min-h-7 px-2.5 py-0.5 data-[state=active]:shadow-sm", size === "comfortable" &&
|
|
151
|
+
"min-h-[40px] rounded-md px-[12px] py-[8px] text-[16px]", triggerClassName) }, item.value))) }) }), renderPanels
|
|
150
152
|
? items.map((item) => (_jsx(TabsContent, { value: item.value, className: cn("pt-4", panelClassName), children: item.content }, item.value)))
|
|
151
153
|
: null] }));
|
|
152
154
|
}
|
|
153
155
|
function SubTabs({ className, listWrapperClassName, listClassName, triggerClassName, panelClassName, ...props }) {
|
|
154
|
-
return (_jsx(Tabs, { className: cn("space-y-0", className), listWrapperClassName: cn("min-w-0 overflow-x-auto", listWrapperClassName), listClassName: cn("w-full min-w-max justify-start overflow-visible rounded-none border-0 border-b border-[hsl(var(--tab-list-border))] bg-transparent p-0", listClassName), triggerClassName: cn("min-h-9 rounded-none border-b-
|
|
156
|
+
return (_jsx(Tabs, { className: cn("space-y-0", className), listWrapperClassName: cn("min-w-0 overflow-x-auto", listWrapperClassName), listClassName: cn("w-full min-w-max justify-start overflow-visible rounded-none border-0 border-b border-[hsl(var(--tab-list-border))] bg-transparent p-0", listClassName), triggerClassName: cn("min-h-9 rounded-none border-b-[3px] border-transparent bg-transparent px-3 py-2 text-[hsl(var(--tab-trigger-foreground))] shadow-none focus-visible:ring-inset focus-visible:ring-offset-0 data-[state=inactive]:hover:bg-[hsl(var(--tab-trigger-hover-background))] data-[state=active]:border-[hsl(var(--tab-indicator))] data-[state=active]:bg-transparent data-[state=active]:text-[hsl(var(--tab-trigger-active-foreground))] data-[state=active]:shadow-none", triggerClassName), panelClassName: cn("pt-4", panelClassName), ...props }));
|
|
155
157
|
}
|
|
156
158
|
export { Tabs, SubTabs, TabsRoot, TabsList, TabsTrigger, TabsContent, TabWithDropdown, };
|