@neasg/design-system 0.4.21 → 0.4.23
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 +9 -0
- package/dist/badge.js +1 -1
- package/dist/button.js +2 -2
- package/dist/calendar.js +4 -4
- package/dist/card.js +2 -1
- package/dist/command-search.js +1 -1
- package/dist/count-badge.js +2 -2
- package/dist/date-input.js +1 -1
- package/dist/dropdown-button.js +2 -2
- package/dist/file-upload.js +1 -1
- package/dist/filter-popover.js +4 -2
- package/dist/filter-toggle.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/input-control.d.ts +1 -1
- package/dist/input-control.js +1 -1
- package/dist/link.js +2 -2
- package/dist/message-item.js +2 -2
- package/dist/multi-select.js +22 -34
- package/dist/page-header.d.ts +3 -1
- package/dist/page-header.js +2 -2
- package/dist/pagination.d.ts +7 -1
- package/dist/pagination.js +4 -3
- package/dist/popover-focus.d.ts +14 -0
- package/dist/popover-focus.js +64 -0
- package/dist/popover-menu.js +29 -7
- package/dist/popover.d.ts +4 -1
- package/dist/popover.js +31 -3
- package/dist/rich-text-editor.js +1 -1
- package/dist/select-primitive.js +1 -1
- package/dist/select.js +28 -11
- package/dist/spinner.js +1 -1
- package/dist/styles.css +18 -0
- package/dist/table.d.ts +17 -5
- package/dist/table.js +136 -86
- package/dist/tailwind-preset.js +15 -0
- package/dist/theme.d.ts +45 -0
- package/dist/theme.js +36 -0
- package/dist/toaster.js +1 -1
- package/dist/typography.js +3 -3
- package/dist/use-search-highlight.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -146,6 +146,15 @@ const darkThemeTokenMapping = {
|
|
|
146
146
|
"--tooltip-foreground": "var(--nea-dark-neutral-50)",
|
|
147
147
|
"--primary": "148 30% 38%",
|
|
148
148
|
"--primary-foreground": "var(--nea-dark-neutral-50)",
|
|
149
|
+
"--interactive-foreground": "143 44% 67%",
|
|
150
|
+
"--highlight-background": "148 20% 18%",
|
|
151
|
+
"--highlight-foreground": "143 44% 67%",
|
|
152
|
+
"--button-primary-background": "148 30% 38%",
|
|
153
|
+
"--button-primary-hover-background": "148 30% 39%",
|
|
154
|
+
"--button-primary-foreground": "0 0% 100%",
|
|
155
|
+
"--count-badge-background": "144 66% 40%",
|
|
156
|
+
"--count-badge-foreground": "var(--nea-dark-neutral-800)",
|
|
157
|
+
"--instructional-foreground": "var(--nea-dark-neutral-200)",
|
|
149
158
|
"--secondary": "var(--nea-dark-neutral-500)",
|
|
150
159
|
"--secondary-foreground": "var(--nea-dark-neutral-100)",
|
|
151
160
|
"--muted": "var(--nea-dark-neutral-500)",
|
package/dist/badge.js
CHANGED
|
@@ -7,7 +7,7 @@ const badgeVariants = cva("inline-flex items-center justify-center text-center r
|
|
|
7
7
|
variants: {
|
|
8
8
|
variant: {
|
|
9
9
|
secondary: "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
10
|
-
muted: "border-transparent bg-muted text-
|
|
10
|
+
muted: "border-transparent bg-muted text-instructional",
|
|
11
11
|
destructive: "border-transparent bg-[hsl(var(--status-destructive))] text-[hsl(var(--status-destructive-foreground))]",
|
|
12
12
|
outline: "text-foreground",
|
|
13
13
|
success: "border-transparent bg-[hsl(var(--status-success))] text-[hsl(var(--status-success-foreground))]",
|
package/dist/button.js
CHANGED
|
@@ -6,12 +6,12 @@ import { cn } from "./lib/utils";
|
|
|
6
6
|
const buttonVariants = cva("inline-flex cursor-pointer items-center justify-center gap-1.5 whitespace-nowrap rounded-control text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 disabled:pointer-events-none [&_svg]:h-4 [&_svg]:min-h-4 [&_svg]:w-4 [&_svg]:min-w-4 [&_svg]:pointer-events-none [&_svg]:shrink-0", {
|
|
7
7
|
variants: {
|
|
8
8
|
variant: {
|
|
9
|
-
default: "bg-primary text-primary-foreground hover:bg-primary
|
|
9
|
+
default: "bg-button-primary text-button-primary-foreground hover:bg-button-primary-hover",
|
|
10
10
|
destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
|
|
11
11
|
outline: "border border-[hsl(var(--button-outline-border))] bg-[hsl(var(--button-outline-background))] text-foreground hover:bg-[hsl(var(--button-outline-hover-background))] hover:text-accent-foreground",
|
|
12
12
|
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
13
13
|
ghost: "hover:bg-accent hover:text-accent-foreground",
|
|
14
|
-
link: "text-
|
|
14
|
+
link: "text-interactive underline-offset-4 hover:text-interactive hover:underline",
|
|
15
15
|
},
|
|
16
16
|
size: {
|
|
17
17
|
sm: "h-8 px-2.5 text-sm",
|
package/dist/calendar.js
CHANGED
|
@@ -16,7 +16,7 @@ function CalendarDayButton({ className, day, modifiers, children, disabled, onCl
|
|
|
16
16
|
return (_jsx("button", { ref: ref, type: type, disabled: disabled, onClick: onClick, onFocus: onFocus, onBlur: onBlur, onKeyDown: onKeyDown, onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, tabIndex: tabIndex, "aria-label": ariaLabel, "aria-pressed": ariaPressed, "aria-selected": ariaSelected, "data-day": day.date.toLocaleDateString(), "data-selected-single": modifiers.selected &&
|
|
17
17
|
!modifiers.range_start &&
|
|
18
18
|
!modifiers.range_end &&
|
|
19
|
-
!modifiers.range_middle, "data-range-start": modifiers.range_start, "data-range-end": modifiers.range_end, "data-range-middle": modifiers.range_middle, className: cn("inline-flex cursor-pointer items-center justify-center rounded-control outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50", "data-[selected-single=true]:bg-primary data-[selected-single=true]:text-primary-foreground data-[range-middle=true]:bg-
|
|
19
|
+
!modifiers.range_middle, "data-range-start": modifiers.range_start, "data-range-end": modifiers.range_end, "data-range-middle": modifiers.range_middle, className: cn("inline-flex cursor-pointer items-center justify-center rounded-control outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50", "data-[selected-single=true]:bg-button-primary data-[selected-single=true]:text-button-primary-foreground data-[range-middle=true]:bg-highlight data-[range-middle=true]:text-highlight-foreground data-[range-start=true]:bg-button-primary data-[range-start=true]:text-button-primary-foreground data-[range-end=true]:bg-button-primary data-[range-end=true]:text-button-primary-foreground group-data-[focused=true]/day:border-ring group-data-[focused=true]/day:ring-ring/50 aspect-square w-full min-w-[--cell-size] data-[range-end=true]:rounded-control data-[range-middle=true]:rounded-none data-[range-start=true]:rounded-control group-data-[focused=true]/day:relative group-data-[focused=true]/day:z-10 group-data-[focused=true]/day:ring-[3px]", defaultClassNames.day, className), children: _jsx(Typography, { as: "span", variant: "bodySm", color: "inherit", children: children }) }));
|
|
20
20
|
}
|
|
21
21
|
function Calendar({ className, classNames, showOutsideDays = true, fixedWeeks = true, captionLayout = "label", buttonVariant = "ghost", formatters, components, ...props }) {
|
|
22
22
|
const defaultClassNames = getDefaultClassNames();
|
|
@@ -44,9 +44,9 @@ function Calendar({ className, classNames, showOutsideDays = true, fixedWeeks =
|
|
|
44
44
|
week_number_header: cn("w-[--cell-size] select-none", defaultClassNames.week_number_header),
|
|
45
45
|
week_number: cn("text-muted-foreground select-none text-[0.8rem]", defaultClassNames.week_number),
|
|
46
46
|
day: cn("group/day relative aspect-square h-full w-full select-none p-0 text-center [&:first-child[data-selected=true]_button]:rounded-l-[var(--radius-control)] [&:last-child[data-selected=true]_button]:rounded-r-[var(--radius-control)]", defaultClassNames.day),
|
|
47
|
-
range_start: cn("bg-
|
|
48
|
-
range_middle: cn("bg-
|
|
49
|
-
range_end: cn("bg-
|
|
47
|
+
range_start: cn("bg-highlight rounded-l-[var(--radius-control)]", defaultClassNames.range_start),
|
|
48
|
+
range_middle: cn("bg-highlight rounded-none", defaultClassNames.range_middle),
|
|
49
|
+
range_end: cn("bg-highlight rounded-r-[var(--radius-control)]", defaultClassNames.range_end),
|
|
50
50
|
today: cn("bg-accent text-accent-foreground rounded-control data-[selected=true]:rounded-none", defaultClassNames.today),
|
|
51
51
|
outside: cn("text-muted-foreground aria-selected:text-muted-foreground", defaultClassNames.outside),
|
|
52
52
|
disabled: cn("text-muted-foreground opacity-50", defaultClassNames.disabled),
|
package/dist/card.js
CHANGED
|
@@ -109,7 +109,8 @@ const Card = React.forwardRef(({ title, description, variant = "default", size =
|
|
|
109
109
|
return (_jsxs("div", { ref: ref, onClick: onClick, onKeyDown: handleKeyDown, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, onFocus: handleFocus, onBlur: handleBlur, role: role !== null && role !== void 0 ? role : (interactive ? "button" : undefined), tabIndex: tabIndex !== null && tabIndex !== void 0 ? tabIndex : (interactive ? 0 : undefined), "aria-pressed": ariaPressed !== null && ariaPressed !== void 0 ? ariaPressed : (interactive && active !== undefined ? Boolean(active) : undefined), className: cn("group/card rounded-surface border border-[hsl(var(--card-border))] text-card-foreground", variant === "default" && "bg-card", variant === "elevated" && "bg-card shadow-sm", variant === "gradient" &&
|
|
110
110
|
"border-[hsl(var(--card-gradient-border))]/30 bg-gradient-to-br from-[hsl(var(--card-gradient-from))] to-[hsl(var(--card-gradient-to))] text-[hsl(var(--card-gradient-foreground))]", active && "border-primary bg-primary/[0.04] ring-1 ring-primary/20", accent === "primary" &&
|
|
111
111
|
"border-[hsl(var(--card-border))] shadow-[inset_4px_0_0_0_hsl(var(--primary))]", interactive &&
|
|
112
|
-
"cursor-pointer transition-[border-color,background-color,box-shadow,transform] duration-150 ease-out hover:border-primary/50 hover:bg-primary/5 hover:shadow-md motion-safe:hover:-translate-y-0.5 motion-safe:active:translate-y-0 motion-safe:active:scale-[0.99] focus-visible:border-primary/50 focus-visible:bg-primary/5 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background", className), ...props, children: [_jsxs("div", { className: cn("relative flex flex-col gap-2", size === "default" && "p-4", size === "compact" && "p-3", showIcon && size === "default" && "pr-12", showIcon && size === "compact" && "pr-10"), children: [showIcon ? (_jsx("span", { "aria-hidden": "true", "data-slot": "card-icon", className: cn("pointer-events-none absolute right-3 top-3 inline-flex size-7 items-center justify-center rounded-control border border-[hsl(var(--card-border))] bg-background/80 text-muted-foreground shadow-sm transition-[background-color,color,transform] duration-150 ease-out group-hover/card:scale-105 group-hover/card:bg-
|
|
112
|
+
"cursor-pointer transition-[border-color,background-color,box-shadow,transform] duration-150 ease-out hover:border-primary/50 hover:bg-primary/5 hover:shadow-md motion-safe:hover:-translate-y-0.5 motion-safe:active:translate-y-0 motion-safe:active:scale-[0.99] focus-visible:border-primary/50 focus-visible:bg-primary/5 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background", className), ...props, children: [_jsxs("div", { className: cn("relative flex flex-col gap-2", size === "default" && "p-4", size === "compact" && "p-3", showIcon && size === "default" && "pr-12", showIcon && size === "compact" && "pr-10"), children: [showIcon ? (_jsx("span", { "aria-hidden": "true", "data-slot": "card-icon", className: cn("pointer-events-none absolute right-3 top-3 inline-flex size-7 items-center justify-center rounded-control border border-[hsl(var(--card-border))] bg-background/80 text-muted-foreground shadow-sm transition-[background-color,color,transform] duration-150 ease-out group-hover/card:scale-105 group-hover/card:bg-highlight group-hover/card:text-highlight-foreground group-focus-visible/card:bg-highlight group-focus-visible/card:text-highlight-foreground motion-reduce:transition-colors [&_svg]:size-3.5", size === "compact" && "right-2.5 top-2.5 size-6 [&_svg]:size-3", active &&
|
|
113
|
+
"border-primary/30 bg-highlight text-highlight-foreground", variant === "gradient" &&
|
|
113
114
|
"border-white/25 bg-white/10 text-current group-hover/card:bg-white/20 group-hover/card:text-current group-focus-visible/card:bg-white/20 group-focus-visible/card:text-current"), children: renderedIcon })) : null, loading ? (_jsx(Skeleton, { className: "h-3.5 w-24" })) : (renderedTitle), loading
|
|
114
115
|
? description != null && _jsx(Skeleton, { className: "h-5 w-40" })
|
|
115
116
|
: renderedDescription, loading ? (stat !== undefined && _jsx(Skeleton, { className: "h-8 w-20" })) : stat ? (_jsx(Typography, { as: "p", variant: "title", color: variant === "gradient" ? "inherit" : undefined, children: stat })) : null, loading ? (subMetric !== undefined && _jsx(Skeleton, { className: "h-5 w-28" })) : subMetric ? (_jsx(Typography, { as: "p", variant: "caption", color: variant === "gradient" ? "inherit" : undefined, className: variant === "gradient" ? "opacity-80" : undefined, children: subMetric })) : null] }), children ? (_jsx("div", { className: cn(size === "default" && "p-4 pt-0", size === "compact" && "p-3 pt-0"), children: children })) : null, footer ? (_jsx("div", { className: cn("flex items-center", size === "default" && "p-4 pt-0", size === "compact" && "p-3 pt-0"), children: footer })) : null] }));
|
package/dist/command-search.js
CHANGED
|
@@ -241,7 +241,7 @@ function CommandSearch({ value, onValueChange, sections, children, className, is
|
|
|
241
241
|
if (((_c = section.action) === null || _c === void 0 ? void 0 : _c.closeOnSelect) !== false) {
|
|
242
242
|
setIsOpen(false);
|
|
243
243
|
}
|
|
244
|
-
}), children: _jsx(Button, { asChild: true, variant: "link", size: "compact", className: "w-full justify-start text-left font-medium group-data-[selected=true]:underline", children: _jsxs("span", { children: [_jsx("span", { className: "min-w-0 truncate", children: section.action.label }), _jsxs("span", { className: "inline-flex shrink-0 items-center justify-center text-
|
|
244
|
+
}), children: _jsx(Button, { asChild: true, variant: "link", size: "compact", className: "w-full justify-start text-left font-medium group-data-[selected=true]:underline", children: _jsxs("span", { children: [_jsx("span", { className: "min-w-0 truncate", children: section.action.label }), _jsxs("span", { className: "inline-flex shrink-0 items-center justify-center text-interactive", children: [(_a = section.action.affordance) !== null && _a !== void 0 ? _a : (_jsx(ArrowRight, { className: "size-[var(--space-4)]", "aria-hidden": "true" })), _jsx("span", { className: "sr-only", children: (_b = section.action.affordanceLabel) !== null && _b !== void 0 ? _b : "Show all results in group" })] })] }) }) }, `${section.key}-action`)) : null] })] }, section.key));
|
|
245
245
|
})) : (_jsx(CommandSearchEmptyState, { query: value, resultsMinHeight: resultsMinHeight }))) : (_jsx(CommandSearchEmptyState, { query: value, resultsMinHeight: resultsMinHeight })) }), shouldShowAllResults ? (_jsx(PopoverMenuFooter, { inset: "flush", children: _jsxs(PopoverMenuFooterAction, { className: "group", onClick: () => {
|
|
246
246
|
onShowAllResults === null || onShowAllResults === void 0 ? void 0 : onShowAllResults(normalizedValue);
|
|
247
247
|
setIsOpen(false);
|
package/dist/count-badge.js
CHANGED
|
@@ -17,7 +17,7 @@ function CountBadge({ count, variant = "default", size = "md", max, pulse = fals
|
|
|
17
17
|
const variantClasses = {
|
|
18
18
|
default: {
|
|
19
19
|
badgeVariant: "secondary",
|
|
20
|
-
className: "border-transparent bg-
|
|
20
|
+
className: "border-transparent bg-count-badge text-count-badge-foreground",
|
|
21
21
|
},
|
|
22
22
|
danger: {
|
|
23
23
|
badgeVariant: "destructive",
|
|
@@ -29,7 +29,7 @@ function CountBadge({ count, variant = "default", size = "md", max, pulse = fals
|
|
|
29
29
|
},
|
|
30
30
|
};
|
|
31
31
|
const pulseColor = {
|
|
32
|
-
default: "bg-
|
|
32
|
+
default: "bg-count-badge/75",
|
|
33
33
|
danger: "bg-[hsl(var(--status-destructive))]/70",
|
|
34
34
|
muted: "bg-muted-foreground/50",
|
|
35
35
|
};
|
package/dist/date-input.js
CHANGED
|
@@ -166,7 +166,7 @@ const DateInput = React.forwardRef((props, ref) => {
|
|
|
166
166
|
const disabledDays = (date) => isDateOutsideBounds(date, minDate, maxDate);
|
|
167
167
|
const calendarContent = (_jsx(_Fragment, { children: props.mode === "range" ? (_jsx(Calendar, { mode: "range", selected: selectedRange, onSelect: handleRangeSelect, disabled: disabledDays, defaultMonth: (_b = selectedRange === null || selectedRange === void 0 ? void 0 : selectedRange.from) !== null && _b !== void 0 ? _b : selectedRange === null || selectedRange === void 0 ? void 0 : selectedRange.to, numberOfMonths: (_c = props.numberOfMonths) !== null && _c !== void 0 ? _c : 2, showOutsideDays: false, autoFocus: true })) : (_jsx(Calendar, { mode: "single", selected: selectedDate, onSelect: handleSelect, disabled: disabledDays, defaultMonth: selectedDate, autoFocus: true })) }));
|
|
168
168
|
if (appearance === "inline") {
|
|
169
|
-
return (_jsxs("span", { className: cn("inline-flex", className), "data-disabled": disabled ? "true" : undefined, "data-invalid": isInvalid ? "true" : undefined, children: [_jsx(Popover, { open: open, onOpenChange: handleOpenChange, align: "start", title: popoverTitle, surface: popoverTitle ? "menu" : "panel", contentClassName: "w-auto p-0", trigger: _jsxs("button", { ref: ref, type: "button", id: inputId, disabled: disabled, "aria-invalid": isInvalid ? "true" : undefined, "aria-describedby": [descriptionId, errorId].filter(Boolean).join(" ") || undefined, className: cn("inline-flex cursor-pointer items-baseline rounded-sm border-0 bg-transparent p-0 font-medium text-
|
|
169
|
+
return (_jsxs("span", { className: cn("inline-flex", className), "data-disabled": disabled ? "true" : undefined, "data-invalid": isInvalid ? "true" : undefined, children: [_jsx(Popover, { open: open, onOpenChange: handleOpenChange, align: "start", title: popoverTitle, surface: popoverTitle ? "menu" : "panel", contentClassName: "w-auto p-0", trigger: _jsxs("button", { ref: ref, type: "button", id: inputId, disabled: disabled, "aria-invalid": isInvalid ? "true" : undefined, "aria-describedby": [descriptionId, errorId].filter(Boolean).join(" ") || undefined, className: cn("inline-flex cursor-pointer items-baseline rounded-sm border-0 bg-transparent p-0 font-medium text-interactive underline decoration-interactive/40 underline-offset-4 transition-colors hover:decoration-interactive focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50", !displayValue && "text-muted-foreground decoration-border", isInvalid && "text-destructive decoration-destructive", triggerClassName), children: [_jsxs("span", { className: "sr-only", children: [label, ": "] }), _jsx("span", { children: displayValue !== null && displayValue !== void 0 ? displayValue : placeholder })] }), children: calendarContent }), showDescription ? (_jsx("span", { id: descriptionId, className: "sr-only", children: description })) : null, error ? (_jsx("span", { id: errorId, role: "alert", className: "sr-only", children: error })) : null] }));
|
|
170
170
|
}
|
|
171
171
|
return (_jsxs(Field, { className: className, "data-disabled": disabled ? "true" : undefined, "data-invalid": isInvalid ? "true" : undefined, children: [_jsx(FieldLabel, { htmlFor: inputId, className: cn(hideLabel && "sr-only", labelClassName), children: label }), _jsxs("div", { className: "relative", children: [_jsx(Popover, { open: open, onOpenChange: handleOpenChange, align: "start", title: popoverTitle, surface: popoverTitle ? "menu" : "panel", contentClassName: "w-auto p-0", trigger: _jsx("button", { ref: ref, type: "button", id: inputId, disabled: disabled, "aria-invalid": isInvalid ? "true" : undefined, "aria-describedby": [descriptionId, errorId].filter(Boolean).join(" ") || undefined, className: cn(inputControlClassName, "relative cursor-pointer pr-9 text-left", showClearButton && "pr-16", !displayValue && "text-muted-foreground", isInvalid && "border-destructive focus-visible:ring-destructive", triggerClassName), children: _jsx("span", { className: "block truncate", children: displayValue !== null && displayValue !== void 0 ? displayValue : placeholder }) }), children: calendarContent }), _jsxs("span", { "aria-hidden": showClearButton ? undefined : true, className: "pointer-events-none absolute inset-y-0 right-3 flex items-center gap-2 text-muted-foreground", children: [showClearButton ? (_jsx("button", { type: "button", "aria-label": resolvedClearLabel, onClick: handleClear, className: "pointer-events-auto inline-flex h-4 w-4 cursor-pointer items-center justify-center rounded-sm text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:cursor-not-allowed", children: _jsx(XIcon, { size: 14, className: "flex items-center justify-center" }) })) : null, _jsx(CalendarIcon, { "aria-hidden": "true", className: "h-4 w-4 shrink-0", strokeWidth: 2 })] })] }), showDescription ? (_jsx(FieldDescription, { id: descriptionId, className: descriptionClassName, children: description })) : null, _jsx(FieldError, { id: errorId, className: errorClassName, children: error })] }));
|
|
172
172
|
});
|
package/dist/dropdown-button.js
CHANGED
|
@@ -6,12 +6,12 @@ import { Popover } from "./popover";
|
|
|
6
6
|
import { PopoverAnchor, PopoverContent, PopoverRoot, PopoverTrigger, } from "./popover-primitive";
|
|
7
7
|
import { cn } from "./lib/utils";
|
|
8
8
|
const splitButtonDividerClassNames = {
|
|
9
|
-
default: "before:bg-primary-foreground/30",
|
|
9
|
+
default: "before:bg-button-primary-foreground/30",
|
|
10
10
|
destructive: "before:bg-destructive-foreground/30",
|
|
11
11
|
outline: "before:bg-[hsl(var(--button-outline-border))]",
|
|
12
12
|
secondary: "before:bg-secondary-foreground/20",
|
|
13
13
|
ghost: "before:bg-border",
|
|
14
|
-
link: "before:bg-
|
|
14
|
+
link: "before:bg-interactive/25",
|
|
15
15
|
};
|
|
16
16
|
function DropdownButton({ label, leadingIcon, children, className, contentClassName, dropdownAriaLabel, menuWidth = "trigger", align = "end", alignOffset, avoidCollisions, collisionPadding, defaultOpen, disabled, hideWhenDetached, loading, loadingIndicator, loadingText, modal, onClick, onOpenChange, open, side, sideOffset = 4, split: splitProp, sticky, type = "button", variant, size, ...buttonProps }) {
|
|
17
17
|
const menuContentClassName = cn("shadow-overlay-strong border-border/80 bg-popover ring-1 ring-border/50", menuWidth === "trigger" &&
|
package/dist/file-upload.js
CHANGED
|
@@ -92,7 +92,7 @@ export function FileUpload({ accept, maxSize = DEFAULT_MAX_FILE_SIZE, maxFiles =
|
|
|
92
92
|
const fileInput = (_jsx("input", { ref: inputRef, type: "file", accept: accept, multiple: maxFiles > 1, onChange: handleInputChange, disabled: disabled, className: "hidden" }));
|
|
93
93
|
return (_jsxs("div", { className: cn("space-y-2", className), children: [fileInput, _jsxs("div", { onDrop: handleDrop, onDragOver: handleDragOver, onDragLeave: handleDragLeave, onClick: openFilePicker, className: cn("relative flex cursor-pointer flex-col items-center justify-center gap-1.5 rounded-surface border border-dashed p-4 transition-colors", isDragOver && !disabled
|
|
94
94
|
? "border-primary bg-primary/5"
|
|
95
|
-
: "border-muted-foreground/25 hover:border-muted-foreground/50", disabled && "cursor-not-allowed opacity-50"), children: [_jsx(UploadIcon, { className: cn(isDragOver ? "text-
|
|
95
|
+
: "border-muted-foreground/25 hover:border-muted-foreground/50", disabled && "cursor-not-allowed opacity-50"), children: [_jsx(UploadIcon, { className: cn(isDragOver ? "text-interactive" : "text-muted-foreground"), size: 28 }), _jsxs("div", { className: "text-center", children: [_jsx(Typography, { as: "p", variant: "label", children: isDragOver ? "Drop files here" : "Drag & drop files here" }), _jsxs(Typography, { as: "p", variant: "caption", className: "mt-1", children: ["or click to browse (max ", formatFileSize(maxSize), " each)"] })] })] }), error ? (_jsx(Typography, { as: "p", variant: "bodySm", className: "text-destructive", children: error })) : null, value.length > 0 ? (_jsx("div", { className: "space-y-2", children: value.map((file, index) => {
|
|
96
96
|
var _a;
|
|
97
97
|
const progress = uploadProgress === null || uploadProgress === void 0 ? void 0 : uploadProgress.get(file.name);
|
|
98
98
|
const isUploading = (progress === null || progress === void 0 ? void 0 : progress.status) === "uploading";
|
package/dist/filter-popover.js
CHANGED
|
@@ -7,7 +7,7 @@ import { Button } from "./button";
|
|
|
7
7
|
import { CountBadge } from "./count-badge";
|
|
8
8
|
import { cn } from "./lib/utils";
|
|
9
9
|
import { Popover } from "./popover";
|
|
10
|
-
import { PopoverMenuFooter, PopoverMenuFooterAction, PopoverMenuGroup, PopoverMenuGroupLabel, PopoverMenuItem, PopoverMenuScrollArea, PopoverMenuSearch, PopoverMenuSection, PopoverMenuView, popoverMenuItemFocusClassName, } from "./popover-menu";
|
|
10
|
+
import { PopoverMenuFooter, PopoverMenuFooterAction, PopoverMenuCheckboxItem, PopoverMenuGroup, PopoverMenuGroupLabel, PopoverMenuItem, PopoverMenuScrollArea, PopoverMenuSearch, PopoverMenuSection, PopoverMenuView, popoverMenuItemFocusClassName, } from "./popover-menu";
|
|
11
11
|
import { Typography } from "./typography";
|
|
12
12
|
function getText(value) {
|
|
13
13
|
if (typeof value === "string" || typeof value === "number") {
|
|
@@ -72,7 +72,9 @@ function FilterPopover({ align = "start", ariaLabel, contentClassName, defaultOp
|
|
|
72
72
|
onOpenChange === null || onOpenChange === void 0 ? void 0 : onOpenChange(nextOpen);
|
|
73
73
|
};
|
|
74
74
|
const resolvedTitle = (_c = title !== null && title !== void 0 ? title : directGroup === null || directGroup === void 0 ? void 0 : directGroup.label) !== null && _c !== void 0 ? _c : (!activeGroup ? triggerLabel : undefined);
|
|
75
|
-
return (_jsxs(Popover, { align: align, contentClassName: cn("w-[360px]", contentClassName), defaultOpen: defaultOpen, modal: modal, onOpenChange: handleOpenChange, open: open, side: side, surface: "menu", trigger: trigger !== null && trigger !== void 0 ? trigger : defaultTrigger, title: resolvedTitle, "aria-label": (_e = (_d = ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : getText(resolvedTitle)) !== null && _d !== void 0 ? _d : getText(triggerLabel)) !== null && _e !== void 0 ? _e : "Filters", children: [_jsx(PopoverMenuView, { className: cn("-mx-1 -mt-1 px-1 pt-1", viewClassName), direction: transitionDirection, viewKey: activeGroup ? `group-${activeGroup.id}` : "filter-groups", children: activeGroup ? (_jsxs(_Fragment, { children: [!directGroup ? (_jsx("div", { className: "-mx-1 -mt-1 border-b p-1", children: _jsxs(Button, { type: "button", variant: "ghost", size: "sm", className: cn("w-full justify-start", popoverMenuItemFocusClassName), onClick: showFilterGroups, children: [_jsx(ChevronLeft, { className: "h-4 w-4" }), activeGroup.label] }) })) : null, activeGroup.searchable ? (_jsx(PopoverMenuSearch, { value: query, onChange: (event) => setQuery(event.target.value), placeholder: (_f = activeGroup.searchPlaceholder) !== null && _f !== void 0 ? _f : `Search ${getGroupLabel(activeGroup).toLowerCase()}...`, "aria-label": (_g = activeGroup.searchPlaceholder) !== null && _g !== void 0 ? _g : `Search ${getGroupLabel(activeGroup).toLowerCase()}` })) : null, _jsx(PopoverMenuScrollArea, { maxHeight: maxHeight, children: _jsx(PopoverMenuSection, { children: filteredOptions.length ? (filteredOptions.map((option) => (_jsx(
|
|
75
|
+
return (_jsxs(Popover, { align: align, contentClassName: cn("w-[360px]", contentClassName), defaultOpen: defaultOpen, modal: modal, onOpenChange: handleOpenChange, open: open, side: side, surface: "menu", tabBehavior: "close-at-boundary", trigger: trigger !== null && trigger !== void 0 ? trigger : defaultTrigger, title: resolvedTitle, "aria-label": (_e = (_d = ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : getText(resolvedTitle)) !== null && _d !== void 0 ? _d : getText(triggerLabel)) !== null && _e !== void 0 ? _e : "Filters", children: [_jsx(PopoverMenuView, { className: cn("-mx-1 -mt-1 px-1 pt-1", viewClassName), direction: transitionDirection, viewKey: activeGroup ? `group-${activeGroup.id}` : "filter-groups", children: activeGroup ? (_jsxs(_Fragment, { children: [!directGroup ? (_jsx("div", { className: "-mx-1 -mt-1 border-b p-1", children: _jsxs(Button, { type: "button", variant: "ghost", size: "sm", className: cn("w-full justify-start", popoverMenuItemFocusClassName), onClick: showFilterGroups, children: [_jsx(ChevronLeft, { className: "h-4 w-4" }), activeGroup.label] }) })) : null, activeGroup.searchable ? (_jsx(PopoverMenuSearch, { value: query, onChange: (event) => setQuery(event.target.value), placeholder: (_f = activeGroup.searchPlaceholder) !== null && _f !== void 0 ? _f : `Search ${getGroupLabel(activeGroup).toLowerCase()}...`, "aria-label": (_g = activeGroup.searchPlaceholder) !== null && _g !== void 0 ? _g : `Search ${getGroupLabel(activeGroup).toLowerCase()}` })) : null, _jsx(PopoverMenuScrollArea, { maxHeight: maxHeight, children: _jsx(PopoverMenuSection, { children: filteredOptions.length ? (filteredOptions.map((option) => (_jsx(PopoverMenuCheckboxItem, { "aria-label": option.ariaLabel, checked: Boolean(option.selected), disabled: option.disabled, onChange: option.onSelect
|
|
76
|
+
? () => { var _a; return (_a = option.onSelect) === null || _a === void 0 ? void 0 : _a.call(option); }
|
|
77
|
+
: undefined, children: option.label }, option.id)))) : (_jsx(Typography, { as: "p", variant: "caption", className: "px-2 py-2", children: (_h = activeGroup.emptyLabel) !== null && _h !== void 0 ? _h : emptyLabel })) }) })] })) : (_jsx(PopoverMenuScrollArea, { maxHeight: maxHeight, children: _jsxs(PopoverMenuGroup, { children: [!resolvedTitle ? (_jsx(PopoverMenuGroupLabel, { children: groupListLabel })) : null, _jsx(PopoverMenuSection, { children: groups.map((group) => {
|
|
76
78
|
var _a;
|
|
77
79
|
const groupSelectedCount = getGroupSelectedCount(group);
|
|
78
80
|
const selectionLabel = (_a = group.selectionLabel) !== null && _a !== void 0 ? _a : getFilterSelectionLabel(groupSelectedCount);
|
package/dist/filter-toggle.js
CHANGED
|
@@ -9,7 +9,7 @@ const filterToggleVariants = cva("inline-flex shrink-0 cursor-pointer select-non
|
|
|
9
9
|
muted: "",
|
|
10
10
|
},
|
|
11
11
|
selected: {
|
|
12
|
-
true: "border-transparent bg-
|
|
12
|
+
true: "border-transparent bg-highlight text-highlight-foreground hover:bg-highlight/80 focus-visible:bg-highlight/80",
|
|
13
13
|
false: "border-transparent bg-muted text-muted-foreground hover:bg-muted/80",
|
|
14
14
|
},
|
|
15
15
|
},
|
package/dist/index.d.ts
CHANGED
|
@@ -131,7 +131,7 @@ export { TableColumnVisibilityMenu } from "./table-column-visibility";
|
|
|
131
131
|
export type { TableColumnVisibilityMenuProps } from "./table-column-visibility";
|
|
132
132
|
export { useTableSort } from "./use-table-sort";
|
|
133
133
|
export type { UseTableSortOptions, UseTableSortReturn, } from "./use-table-sort";
|
|
134
|
-
export { Table, TableRoot, TableContainer, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell, TableCaption, TableRowSkeleton, TABLE_SKELETON_PRESETS, } from "./table";
|
|
134
|
+
export { Table, TableRoot, TableContainer, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell, TableRowHeader, TableCaption, TableRowSkeleton, TABLE_SKELETON_PRESETS, } from "./table";
|
|
135
135
|
export type { TableColumn, TableColumnWidths, TableProps, TableResizeMode, TableRowExpansionProps, TableRowTone, TableSortDirection, TableSortingProps, TableSkeletonConfig, TableRowSkeletonProps, } from "./table";
|
|
136
136
|
export type { TableColumnFilter, TableColumnFilterOption, TableDateColumnFilter, TableOptionsColumnFilter, TableTextColumnFilter, } from "./table-column-filter";
|
|
137
137
|
export { Tabs, SubTabs, TabsRoot, TabWithDropdown, type TabsItem, type TabsItemLabel, type TabsItemLabelProps, type TabsProps, type SubTabsItem, type SubTabsProps, TabsList, TabsTrigger, TabsContent, type TabWithDropdownProps, useTabsContext, type TabDropdownSection, } from "./tabs";
|
package/dist/index.js
CHANGED
|
@@ -68,7 +68,7 @@ export { Pagination } from "./pagination";
|
|
|
68
68
|
export { TableToolbar } from "./table-toolbar";
|
|
69
69
|
export { TableColumnVisibilityMenu } from "./table-column-visibility";
|
|
70
70
|
export { useTableSort } from "./use-table-sort";
|
|
71
|
-
export { Table, TableRoot, TableContainer, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell, TableCaption, TableRowSkeleton, TABLE_SKELETON_PRESETS, } from "./table";
|
|
71
|
+
export { Table, TableRoot, TableContainer, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell, TableRowHeader, TableCaption, TableRowSkeleton, TABLE_SKELETON_PRESETS, } from "./table";
|
|
72
72
|
export { Tabs, SubTabs, TabsRoot, TabWithDropdown, TabsList, TabsTrigger, TabsContent, useTabsContext, } from "./tabs";
|
|
73
73
|
export { Tooltip, TooltipRoot, TooltipTrigger, TooltipContent, TooltipProvider, } from "./tooltip";
|
|
74
74
|
export { Toaster, toast } from "./toaster";
|
package/dist/input-control.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
declare const inputControlPaddingClassName = "px-3 py-2";
|
|
3
|
-
declare const inputControlClassName = "h-control w-full min-w-0 rounded-control border border-input bg-transparent px-3 py-2 text-sm transition-[color,box-shadow] outline-none selection:bg-
|
|
3
|
+
declare const inputControlClassName = "h-control w-full min-w-0 rounded-control border border-input bg-transparent px-3 py-2 text-sm transition-[color,box-shadow] outline-none selection:bg-highlight selection:text-highlight-foreground file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 aria-[invalid=true]:border-destructive aria-[invalid=true]:ring-destructive/20";
|
|
4
4
|
declare const InputControl: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>, "ref"> & React.RefAttributes<HTMLInputElement>>;
|
|
5
5
|
export { InputControl, inputControlClassName, inputControlPaddingClassName };
|
package/dist/input-control.js
CHANGED
|
@@ -2,7 +2,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import * as React from "react";
|
|
3
3
|
import { cn } from "./lib/utils";
|
|
4
4
|
const inputControlPaddingClassName = "px-3 py-2";
|
|
5
|
-
const inputControlClassName = `h-control w-full min-w-0 rounded-control border border-input bg-transparent ${inputControlPaddingClassName} text-sm transition-[color,box-shadow] outline-none selection:bg-
|
|
5
|
+
const inputControlClassName = `h-control w-full min-w-0 rounded-control border border-input bg-transparent ${inputControlPaddingClassName} text-sm transition-[color,box-shadow] outline-none selection:bg-highlight selection:text-highlight-foreground file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 aria-[invalid=true]:border-destructive aria-[invalid=true]:ring-destructive/20`;
|
|
6
6
|
const InputControl = React.forwardRef(({ className, type = "text", ...props }, ref) => (_jsx("input", { ref: ref, type: type, "data-slot": "input", className: cn(inputControlClassName, className), ...props })));
|
|
7
7
|
InputControl.displayName = "InputControl";
|
|
8
8
|
export { InputControl, inputControlClassName, inputControlPaddingClassName };
|
package/dist/link.js
CHANGED
|
@@ -5,8 +5,8 @@ import { cn } from "./lib/utils";
|
|
|
5
5
|
const linkVariants = cva("rounded-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2", {
|
|
6
6
|
variants: {
|
|
7
7
|
variant: {
|
|
8
|
-
default: "text-
|
|
9
|
-
subtle: "text-foreground underline-offset-4 hover:text-
|
|
8
|
+
default: "text-interactive underline-offset-4 hover:text-interactive hover:underline",
|
|
9
|
+
subtle: "text-foreground underline-offset-4 hover:text-interactive hover:underline",
|
|
10
10
|
inherit: "text-inherit no-underline hover:no-underline",
|
|
11
11
|
},
|
|
12
12
|
},
|
package/dist/message-item.js
CHANGED
|
@@ -43,7 +43,7 @@ export function MessageNewDivider({ children = "New Message", className, }) {
|
|
|
43
43
|
}
|
|
44
44
|
export function MessageAttachmentRow({ attachment, downloadUrl, downloadLabel = `Download ${attachment.name}`, className, ...props }) {
|
|
45
45
|
const renderContent = (isInteractive) => (_jsxs(_Fragment, { children: [_jsx("span", { className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-md bg-muted text-muted-foreground", children: _jsx(FileText, { className: "h-4 w-4" }) }), _jsxs("div", { className: "min-w-0 pr-1", children: [_jsx(Typography, { as: "p", variant: "bodySm", className: "line-clamp-2 font-medium", children: attachment.name }), attachment.size ? (_jsx(Typography, { as: "p", variant: "caption", children: attachment.size })) : null] }), _jsx("span", { "aria-hidden": "true", className: cn("flex h-8 w-8 shrink-0 items-center justify-center rounded-control border border-border bg-background text-muted-foreground transition-colors", isInteractive
|
|
46
|
-
? "group-hover:border-primary/40 group-hover:bg-
|
|
46
|
+
? "group-hover:border-primary/40 group-hover:bg-highlight group-hover:text-highlight-foreground group-focus-visible:border-primary/40 group-focus-visible:bg-highlight group-focus-visible:text-highlight-foreground"
|
|
47
47
|
: "opacity-60"), children: _jsx(DownloadIcon, { size: 14 }) })] }));
|
|
48
48
|
if (downloadUrl) {
|
|
49
49
|
return (_jsx("a", { className: cn("group grid min-w-0 cursor-pointer grid-cols-[auto_minmax(0,1fr)_2.75rem] items-center gap-3 rounded-lg border border-border bg-card px-3 py-2 text-foreground no-underline shadow-sm transition hover:border-primary/50 hover:bg-primary/5 hover:no-underline hover:shadow-md focus-visible:border-primary/50 focus-visible:bg-primary/5 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background", className), href: downloadUrl, target: "_blank", rel: "noopener noreferrer", download: attachment.name, "aria-label": downloadLabel, title: downloadLabel, ...props, children: renderContent(true) }));
|
|
@@ -143,7 +143,7 @@ export function MessageItem({ message, caseId, showNewBadge = false, newMessageL
|
|
|
143
143
|
const messageDate = (_a = message.sentAt) !== null && _a !== void 0 ? _a : message.createdAt;
|
|
144
144
|
const downloadCaseId = caseId !== null && caseId !== void 0 ? caseId : message.caseId;
|
|
145
145
|
const contentHtml = toHtmlContent(message.content);
|
|
146
|
-
const richContentClassName = cn("break-words leading-6", "[&_p]:my-0 [&_p+p]:mt-2", "[&_ul]:my-2 [&_ul]:list-disc [&_ul]:pl-5", "[&_ol]:my-2 [&_ol]:list-decimal [&_ol]:pl-5", "[&_li]:my-1", "[&_a]:text-
|
|
146
|
+
const richContentClassName = cn("break-words leading-6", "[&_p]:my-0 [&_p+p]:mt-2", "[&_ul]:my-2 [&_ul]:list-disc [&_ul]:pl-5", "[&_ol]:my-2 [&_ol]:list-decimal [&_ol]:pl-5", "[&_li]:my-1", "[&_a]:text-interactive [&_a]:underline [&_a:hover]:text-interactive", "[&_h1]:mb-2 [&_h1]:mt-3 [&_h1]:text-xl [&_h1]:font-semibold", "[&_h2]:mb-2 [&_h2]:mt-3 [&_h2]:text-lg [&_h2]:font-semibold", "[&_h3]:mb-1.5 [&_h3]:mt-3 [&_h3]:text-base [&_h3]:font-semibold", "[&_h4]:mb-1.5 [&_h4]:mt-3 [&_h4]:font-semibold", "[&_h5]:mb-1.5 [&_h5]:mt-3 [&_h5]:font-semibold", "[&_h6]:mb-1.5 [&_h6]:mt-3 [&_h6]:font-semibold", "[&_blockquote]:my-2 [&_blockquote]:border-l-2 [&_blockquote]:border-border [&_blockquote]:pl-3 [&_blockquote]:text-muted-foreground", "[&_table]:my-2 [&_table]:w-full [&_table]:border-collapse", "[&_td]:border [&_td]:border-border [&_td]:p-2", "[&_th]:border [&_th]:border-border [&_th]:bg-[hsl(var(--table-header-background))] [&_th]:p-2 [&_th]:font-semibold", "[&_pre]:my-2 [&_pre]:overflow-x-auto [&_pre]:rounded-md [&_pre]:bg-muted [&_pre]:p-3 [&_pre]:font-mono [&_pre]:text-[0.85em]", "[&_code]:rounded [&_code]:bg-muted [&_code]:px-1 [&_code]:py-0.5 [&_code]:font-mono [&_code]:text-[0.85em]", "[&_pre_code]:bg-transparent [&_pre_code]:p-0", "[&_mark]:rounded-sm [&_mark]:bg-[hsl(var(--status-warning))] [&_mark]:px-0.5 [&_mark]:text-[hsl(var(--status-warning-foreground))]", "[&_img]:h-auto [&_img]:max-w-full", contentClassName);
|
|
147
147
|
return (_jsxs(_Fragment, { children: [showUnreadDivider && (_jsx(MessageNewDivider, { children: newMessageLabel })), _jsxs("article", { ref: messageRef, className: cn("min-w-0", className), children: [_jsxs("div", { className: "flex min-w-0 items-start justify-between gap-x-3 gap-y-1", children: [_jsx(AvatarProfile, { fallback: getInitials(initialsName), name: senderName, nameAs: "h3", nameTrailing: isApplicant ? (_jsx(Badge, { variant: "warning", bordered: true, children: "Applicant" })) : undefined, role: hasSenderProfileRole ? (_jsx("span", { "data-slot": "message-author-role", children: senderProfileRole })) : undefined, rolePlacement: "below", className: "min-w-0 flex-1 [column-gap:var(--space-3)]", avatarClassName: "h-9 w-9 shrink-0", fallbackClassName: "text-xs font-medium", nameClassName: "max-w-full whitespace-normal break-words [overflow-wrap:anywhere]" }), _jsx("time", { className: "shrink-0 whitespace-nowrap pt-0.5", dateTime: messageDate.toISOString(), children: _jsx(Typography, { as: "span", variant: "caption", className: "text-muted-foreground/60", children: formatTimestamp
|
|
148
148
|
? formatTimestamp(messageDate, message)
|
|
149
149
|
: formatNotificationTimestamp(messageDate, {
|
package/dist/multi-select.js
CHANGED
|
@@ -6,9 +6,11 @@ import { XIcon } from "./animated-icons/x";
|
|
|
6
6
|
import { Badge } from "./badge";
|
|
7
7
|
import { Field, FieldDescription, FieldError, FieldLabel } from "./field";
|
|
8
8
|
import { Checkbox } from "./checkbox";
|
|
9
|
-
import { InputControl } from "./input-control";
|
|
10
9
|
import { cn } from "./lib/utils";
|
|
10
|
+
import { Popover } from "./popover";
|
|
11
|
+
import { PopoverMenuSearch } from "./popover-menu";
|
|
11
12
|
import { Typography } from "./typography";
|
|
13
|
+
import { SearchHighlight } from "./use-search-highlight";
|
|
12
14
|
function MultiSelect({ label, options, value, onValueChange, placeholder = "Select options", description, error, invalid = false, disabled = false, hideLabel = false, searchable = false, searchPlaceholder = "Search...", maxVisibleTags = 2, className, triggerClassName, labelClassName, descriptionClassName, errorClassName, id, }) {
|
|
13
15
|
const generatedId = React.useId();
|
|
14
16
|
const selectId = id !== null && id !== void 0 ? id : `multi-select-${generatedId}`;
|
|
@@ -20,7 +22,6 @@ function MultiSelect({ label, options, value, onValueChange, placeholder = "Sele
|
|
|
20
22
|
const isInvalid = invalid || Boolean(error);
|
|
21
23
|
const [open, setOpen] = React.useState(false);
|
|
22
24
|
const [searchQuery, setSearchQuery] = React.useState("");
|
|
23
|
-
const containerRef = React.useRef(null);
|
|
24
25
|
const triggerRef = React.useRef(null);
|
|
25
26
|
const searchInputRef = React.useRef(null);
|
|
26
27
|
const listboxRef = React.useRef(null);
|
|
@@ -67,6 +68,14 @@ function MultiSelect({ label, options, value, onValueChange, placeholder = "Sele
|
|
|
67
68
|
const removeOption = React.useCallback((optionValue) => {
|
|
68
69
|
onValueChange(value.filter((v) => v !== optionValue));
|
|
69
70
|
}, [value, onValueChange]);
|
|
71
|
+
const handleOpenChange = React.useCallback((nextOpen) => {
|
|
72
|
+
if (disabled)
|
|
73
|
+
return;
|
|
74
|
+
if (nextOpen) {
|
|
75
|
+
openFocusTargetRef.current = searchable ? "search" : "first";
|
|
76
|
+
}
|
|
77
|
+
setOpen(nextOpen);
|
|
78
|
+
}, [disabled, searchable]);
|
|
70
79
|
React.useEffect(() => {
|
|
71
80
|
if (!open) {
|
|
72
81
|
setSearchQuery("");
|
|
@@ -82,18 +91,6 @@ function MultiSelect({ label, options, value, onValueChange, placeholder = "Sele
|
|
|
82
91
|
});
|
|
83
92
|
return () => window.cancelAnimationFrame(frame);
|
|
84
93
|
}, [focusBoundaryOption, open, searchable]);
|
|
85
|
-
React.useEffect(() => {
|
|
86
|
-
const handleClickOutside = (event) => {
|
|
87
|
-
if (containerRef.current &&
|
|
88
|
-
!containerRef.current.contains(event.target)) {
|
|
89
|
-
setOpen(false);
|
|
90
|
-
}
|
|
91
|
-
};
|
|
92
|
-
if (open) {
|
|
93
|
-
document.addEventListener("mousedown", handleClickOutside);
|
|
94
|
-
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
95
|
-
}
|
|
96
|
-
}, [open]);
|
|
97
94
|
const handleTriggerKeyDown = React.useCallback((event) => {
|
|
98
95
|
if (disabled)
|
|
99
96
|
return;
|
|
@@ -165,25 +162,16 @@ function MultiSelect({ label, options, value, onValueChange, placeholder = "Sele
|
|
|
165
162
|
var _a;
|
|
166
163
|
event.preventDefault();
|
|
167
164
|
(_a = triggerRef.current) === null || _a === void 0 ? void 0 : _a.focus();
|
|
168
|
-
}, children: label }), _jsxs("
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
removeOption(opt.value);
|
|
180
|
-
}, "aria-label": `Remove ${opt.label}`, children: _jsx(XIcon, { size: 12 }) })] }, opt.value))), selectedLabels.length > maxVisibleTags ? (_jsxs(Badge, { variant: "secondary", className: "shrink-0 text-sm font-medium", title: selectedLabels
|
|
181
|
-
.slice(maxVisibleTags)
|
|
182
|
-
.map((o) => o.label)
|
|
183
|
-
.join(", "), children: ["+", selectedLabels.length - maxVisibleTags] })) : null] })) : (_jsx("span", { className: "text-muted-foreground", children: placeholder })), _jsx(ChevronDownIcon, { "aria-hidden": "true", size: 16, className: cn("pointer-events-none absolute right-2.5 top-1/2 -translate-y-1/2 shrink-0 text-muted-foreground transition-transform duration-150", open && "rotate-180") })] }), open ? (_jsxs("div", { className: "absolute z-50 mt-1 w-full rounded-overlay border bg-popover shadow-md", children: [searchable ? (_jsx("div", { className: "border-b p-1", children: _jsx(InputControl, { ref: searchInputRef, value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), placeholder: searchPlaceholder, className: "h-control border-0 bg-transparent px-2 py-0 text-sm shadow-none", onKeyDown: handleSearchKeyDown }) })) : null, _jsx("div", { ref: listboxRef, id: listboxId, role: "listbox", "aria-label": typeof label === "string" ? label : "Options", "aria-multiselectable": "true", className: "max-h-64 overflow-y-auto p-1", onKeyDown: handleListboxKeyDown, children: filteredOptions.length > 0 ? (filteredOptions.map((option) => {
|
|
184
|
-
const isSelected = value.includes(option.value);
|
|
185
|
-
return (_jsxs("button", { type: "button", role: "option", "aria-selected": isSelected, disabled: option.disabled, tabIndex: -1, onClick: () => toggleOption(option.value), className: cn("flex min-h-8 w-full cursor-pointer items-center gap-1.5 rounded-sm px-2 py-1.5 text-left text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground disabled:pointer-events-none disabled:opacity-50", isSelected &&
|
|
186
|
-
"bg-primary/10 text-primary hover:bg-primary/20 hover:text-primary focus:bg-primary/20 focus:text-primary"), children: [_jsx(Checkbox, { checked: isSelected, disabled: option.disabled, tabIndex: -1, readOnly: true, "aria-hidden": "true", className: "mt-0.5" }), _jsxs("div", { className: "flex flex-col gap-0.5", children: [_jsx("span", { children: option.label }), option.description ? (_jsx(Typography, { as: "span", variant: "caption", children: option.description })) : null] })] }, option.value));
|
|
187
|
-
})) : (_jsx("div", { className: "px-2.5 py-1.5 text-center text-sm text-muted-foreground", children: "No options found." })) })] })) : null] }), showDescription ? (_jsx(FieldDescription, { id: descriptionId, className: descriptionClassName, children: description })) : null, _jsx(FieldError, { id: errorId, className: errorClassName, children: error })] }));
|
|
165
|
+
}, children: label }), _jsxs(Popover, { open: disabled ? false : open, onOpenChange: handleOpenChange, align: "start", sideOffset: 4, collisionPadding: 16, surface: "menu", tabBehavior: "close", contentClassName: "flex max-h-[var(--radix-popover-content-available-height)] w-[var(--radix-popover-trigger-width)] min-w-[var(--radix-popover-trigger-width)] flex-col overflow-hidden", onOpenAutoFocus: (event) => event.preventDefault(), trigger: _jsxs("div", { ref: triggerRef, role: "combobox", id: selectId, tabIndex: disabled ? -1 : 0, onKeyDown: handleTriggerKeyDown, "aria-expanded": open, "aria-controls": open ? listboxId : undefined, "aria-haspopup": "listbox", "aria-invalid": isInvalid ? "true" : undefined, "aria-disabled": disabled ? "true" : undefined, "aria-labelledby": labelId, "aria-describedby": [descriptionId, errorId].filter(Boolean).join(" ") || undefined, className: cn("relative flex h-control w-full cursor-pointer items-center gap-1.5 overflow-hidden rounded-control border border-input bg-background px-2.5 py-1.5 pr-8 text-sm ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2", isInvalid ? "border-destructive" : "border-input", disabled && "cursor-not-allowed opacity-50", triggerClassName), children: [selectedLabels.length > 0 ? (_jsxs(_Fragment, { children: [selectedLabels.slice(0, maxVisibleTags).map((opt) => (_jsxs(Badge, { variant: "secondary", className: "max-w-[10rem] shrink-0 justify-start gap-1 overflow-visible text-sm font-medium", children: [_jsx("span", { className: "min-w-0 truncate", children: opt.label }), _jsx("button", { type: "button", className: "inline-flex cursor-pointer items-center justify-center rounded-sm text-muted-foreground hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", onClick: (event) => {
|
|
166
|
+
event.stopPropagation();
|
|
167
|
+
removeOption(opt.value);
|
|
168
|
+
}, "aria-label": `Remove ${opt.label}`, children: _jsx(XIcon, { size: 12 }) })] }, opt.value))), selectedLabels.length > maxVisibleTags ? (_jsxs(Badge, { variant: "secondary", className: "shrink-0 text-sm font-medium", title: selectedLabels
|
|
169
|
+
.slice(maxVisibleTags)
|
|
170
|
+
.map((option) => option.label)
|
|
171
|
+
.join(", "), children: ["+", selectedLabels.length - maxVisibleTags] })) : null] })) : (_jsx("span", { className: "text-muted-foreground", children: placeholder })), _jsx(ChevronDownIcon, { "aria-hidden": "true", size: 16, className: cn("pointer-events-none absolute right-2.5 top-1/2 -translate-y-1/2 shrink-0 text-muted-foreground transition-transform duration-150", open && "rotate-180") })] }), children: [searchable ? (_jsx(PopoverMenuSearch, { ref: searchInputRef, value: searchQuery, onChange: (event) => setSearchQuery(event.target.value), onKeyDown: handleSearchKeyDown, placeholder: searchPlaceholder, "aria-label": searchPlaceholder, className: "h-control border-0 bg-transparent px-2 py-0 text-sm shadow-none" })) : null, _jsx("div", { ref: listboxRef, id: listboxId, role: "listbox", "aria-label": typeof label === "string" ? label : "Options", "aria-multiselectable": "true", className: "max-h-64 overflow-y-auto", onKeyDown: handleListboxKeyDown, children: filteredOptions.length > 0 ? (filteredOptions.map((option) => {
|
|
172
|
+
const isSelected = value.includes(option.value);
|
|
173
|
+
return (_jsxs("button", { type: "button", role: "option", "aria-selected": isSelected, disabled: option.disabled, tabIndex: -1, onClick: () => toggleOption(option.value), className: cn("flex min-h-8 w-full cursor-pointer items-center gap-1.5 rounded-sm px-2 py-1.5 text-left text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground disabled:pointer-events-none disabled:opacity-50", isSelected &&
|
|
174
|
+
"bg-highlight text-highlight-foreground hover:bg-highlight/80 hover:text-highlight-foreground focus:bg-highlight/80 focus:text-highlight-foreground"), children: [_jsx(Checkbox, { checked: isSelected, disabled: option.disabled, tabIndex: -1, readOnly: true, "aria-hidden": "true", className: "mt-0.5" }), _jsxs("div", { className: "flex flex-col gap-0.5", children: [_jsx(SearchHighlight, { text: option.label, query: searchQuery }), option.description ? (_jsx(Typography, { as: "span", variant: "caption", children: _jsx(SearchHighlight, { text: option.description, query: searchQuery }) })) : null] })] }, option.value));
|
|
175
|
+
})) : (_jsx("div", { className: "px-2.5 py-1.5 text-center text-sm text-muted-foreground", children: "No options found." })) })] }), showDescription ? (_jsx(FieldDescription, { id: descriptionId, className: descriptionClassName, children: description })) : null, _jsx(FieldError, { id: errorId, className: errorClassName, children: error })] }));
|
|
188
176
|
}
|
|
189
177
|
export { MultiSelect };
|
package/dist/page-header.d.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
export interface PageHeaderProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "title"> {
|
|
3
3
|
title: React.ReactNode;
|
|
4
|
+
/** Semantic heading level for the page title. Use 1 for top-level routed pages. */
|
|
5
|
+
headingLevel?: 1 | 2;
|
|
4
6
|
subtitle?: React.ReactNode;
|
|
5
7
|
breadcrumbs?: React.ReactNode;
|
|
6
8
|
children?: React.ReactNode;
|
|
7
9
|
}
|
|
8
|
-
declare function PageHeader({ title, subtitle, breadcrumbs, children, className, ...props }: PageHeaderProps): import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
declare function PageHeader({ title, headingLevel, subtitle, breadcrumbs, children, className, ...props }: PageHeaderProps): import("react/jsx-runtime").JSX.Element;
|
|
9
11
|
export { PageHeader };
|
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
|
-
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-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] }) }));
|
|
3
|
+
function PageHeader({ title, headingLevel = 2, subtitle, breadcrumbs, children, className, ...props }) {
|
|
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: headingLevel === 1 ? "h1" : "h2", variant: "title", children: title }) }), subtitle ? (_jsx(Typography, { as: "p", variant: "caption", children: subtitle })) : null] }), children] }) }));
|
|
5
5
|
}
|
|
6
6
|
export { PageHeader };
|
package/dist/pagination.d.ts
CHANGED
|
@@ -7,6 +7,12 @@ export interface PaginationProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
|
7
7
|
onPageChange: (page: number) => void;
|
|
8
8
|
onItemsPerPageChange?: (itemsPerPage: number) => void;
|
|
9
9
|
itemsPerPageOptions?: number[];
|
|
10
|
+
/** Accessible name for the page-navigation landmark. */
|
|
11
|
+
navigationLabel?: string;
|
|
12
|
+
/** Visible label for the page-size control. */
|
|
13
|
+
itemsPerPageLabel?: string;
|
|
14
|
+
/** Accessible name for the page-size control. Defaults to `itemsPerPageLabel`. */
|
|
15
|
+
itemsPerPageAriaLabel?: string;
|
|
10
16
|
}
|
|
11
|
-
declare function Pagination({ currentPage, totalPages, totalItems, itemsPerPage, onPageChange, onItemsPerPageChange, itemsPerPageOptions, className, ...props }: PaginationProps): import("react/jsx-runtime").JSX.Element;
|
|
17
|
+
declare function Pagination({ currentPage, totalPages, totalItems, itemsPerPage, onPageChange, onItemsPerPageChange, itemsPerPageOptions, navigationLabel, itemsPerPageLabel, itemsPerPageAriaLabel, className, ...props }: PaginationProps): import("react/jsx-runtime").JSX.Element;
|
|
12
18
|
export { Pagination };
|
package/dist/pagination.js
CHANGED
|
@@ -13,13 +13,14 @@ const PaginationContent = React.forwardRef(({ className, ...props }, ref) => (_j
|
|
|
13
13
|
PaginationContent.displayName = "PaginationContent";
|
|
14
14
|
const PaginationItem = React.forwardRef(({ className, ...props }, ref) => (_jsx("li", { ref: ref, className: cn("", className), ...props })));
|
|
15
15
|
PaginationItem.displayName = "PaginationItem";
|
|
16
|
-
function Pagination({ currentPage, totalPages, totalItems, itemsPerPage = 5, onPageChange, onItemsPerPageChange, itemsPerPageOptions = [5, 10, 20, 50, 100], className, ...props }) {
|
|
16
|
+
function Pagination({ currentPage, totalPages, totalItems, itemsPerPage = 5, onPageChange, onItemsPerPageChange, itemsPerPageOptions = [5, 10, 20, 50, 100], navigationLabel = "Pagination", itemsPerPageLabel = "Rows per page", itemsPerPageAriaLabel, className, ...props }) {
|
|
17
|
+
const itemsPerPageLabelId = React.useId();
|
|
17
18
|
const normalizedTotalPages = totalPages || 1;
|
|
18
19
|
const startItem = totalItems === 0 ? 0 : (currentPage - 1) * itemsPerPage + 1;
|
|
19
20
|
const endItem = Math.min(currentPage * itemsPerPage, totalItems);
|
|
20
|
-
return (_jsxs("div", { className: cn("flex items-center justify-between gap-4", className), ...props, children: [_jsxs("div", { className: "text-sm text-
|
|
21
|
+
return (_jsxs("div", { "data-slot": "pagination", className: cn("flex flex-col items-start gap-3 sm:flex-row sm:items-center sm:justify-between sm:gap-4", className), ...props, children: [_jsxs("div", { className: "text-sm text-instructional", children: ["Showing ", startItem, "-", endItem, " out of ", totalItems] }), _jsxs("div", { "data-slot": "pagination-controls", className: "flex w-full flex-wrap items-center justify-between gap-x-4 gap-y-2 sm:w-auto sm:flex-nowrap sm:justify-start", children: [onItemsPerPageChange ? (_jsxs("div", { className: "flex items-center gap-1.5", children: [_jsx(Typography, { id: itemsPerPageLabelId, as: "span", variant: "caption", children: itemsPerPageLabel }), _jsxs(SelectRoot, { value: itemsPerPage.toString(), onValueChange: (value) => {
|
|
21
22
|
onItemsPerPageChange(Number(value));
|
|
22
23
|
onPageChange(1);
|
|
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-
|
|
24
|
+
}, children: [_jsx(SelectTrigger, { "aria-label": itemsPerPageAriaLabel, "aria-labelledby": itemsPerPageAriaLabel ? undefined : itemsPerPageLabelId, 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-instructional", children: ["Page ", currentPage, " of ", normalizedTotalPages] }), _jsx(PaginationNav, { "aria-label": navigationLabel, 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
25
|
}
|
|
25
26
|
export { Pagination };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
type PopoverTabBehavior = "contain" | "close" | "close-at-boundary";
|
|
3
|
+
interface UsePopoverTabExitOptions<TTrigger extends HTMLElement, TContent extends HTMLElement> {
|
|
4
|
+
behavior: PopoverTabBehavior;
|
|
5
|
+
triggerRef: React.RefObject<TTrigger>;
|
|
6
|
+
contentRef: React.RefObject<TContent>;
|
|
7
|
+
onExit: () => void;
|
|
8
|
+
}
|
|
9
|
+
declare function usePopoverTabExit<TTrigger extends HTMLElement, TContent extends HTMLElement>({ behavior, triggerRef, contentRef, onExit, }: UsePopoverTabExitOptions<TTrigger, TContent>): {
|
|
10
|
+
handleCloseAutoFocus: (event: Event) => void;
|
|
11
|
+
handleTabKeyDown: (event: React.KeyboardEvent<HTMLElement>) => boolean;
|
|
12
|
+
};
|
|
13
|
+
export { usePopoverTabExit };
|
|
14
|
+
export type { PopoverTabBehavior };
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
const tabbableSelector = 'a[href], button:not(:disabled), input:not(:disabled):not([type="hidden"]), select:not(:disabled), textarea:not(:disabled), [tabindex]:not([tabindex="-1"])';
|
|
4
|
+
function usePopoverTabExit({ behavior, triggerRef, contentRef, onExit, }) {
|
|
5
|
+
const tabExitPendingRef = React.useRef(false);
|
|
6
|
+
const focusFrameRef = React.useRef(null);
|
|
7
|
+
React.useEffect(() => () => {
|
|
8
|
+
if (focusFrameRef.current !== null) {
|
|
9
|
+
window.cancelAnimationFrame(focusFrameRef.current);
|
|
10
|
+
}
|
|
11
|
+
}, []);
|
|
12
|
+
const handleTabKeyDown = React.useCallback((event) => {
|
|
13
|
+
if (behavior === "contain" ||
|
|
14
|
+
event.defaultPrevented ||
|
|
15
|
+
event.key !== "Tab") {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
const trigger = triggerRef.current;
|
|
19
|
+
const content = contentRef.current;
|
|
20
|
+
if (!trigger) {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
if (behavior === "close-at-boundary" && content) {
|
|
24
|
+
const contentControls = Array.from(content.querySelectorAll(tabbableSelector)).filter((candidate) => !candidate.closest('[hidden], [aria-hidden="true"], [inert]'));
|
|
25
|
+
const boundaryControl = event.shiftKey
|
|
26
|
+
? contentControls[0]
|
|
27
|
+
: contentControls[contentControls.length - 1];
|
|
28
|
+
if (document.activeElement !== boundaryControl) {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
const candidates = Array.from(document.querySelectorAll(tabbableSelector)).filter((candidate) => {
|
|
33
|
+
const hiddenAncestor = candidate.closest('[hidden], [aria-hidden="true"], [inert]');
|
|
34
|
+
const isHidden = hiddenAncestor &&
|
|
35
|
+
!hiddenAncestor.hasAttribute("data-aria-hidden");
|
|
36
|
+
return (!candidate.hasAttribute("data-radix-focus-guard") &&
|
|
37
|
+
!isHidden &&
|
|
38
|
+
(candidate === trigger ||
|
|
39
|
+
(!trigger.contains(candidate) && !(content === null || content === void 0 ? void 0 : content.contains(candidate)))));
|
|
40
|
+
});
|
|
41
|
+
const triggerIndex = candidates.indexOf(trigger);
|
|
42
|
+
const target = triggerIndex >= 0
|
|
43
|
+
? candidates[triggerIndex + (event.shiftKey ? -1 : 1)]
|
|
44
|
+
: undefined;
|
|
45
|
+
event.preventDefault();
|
|
46
|
+
event.stopPropagation();
|
|
47
|
+
tabExitPendingRef.current = true;
|
|
48
|
+
onExit();
|
|
49
|
+
focusFrameRef.current = window.requestAnimationFrame(() => {
|
|
50
|
+
(target !== null && target !== void 0 ? target : trigger).focus({ preventScroll: true });
|
|
51
|
+
focusFrameRef.current = null;
|
|
52
|
+
});
|
|
53
|
+
return true;
|
|
54
|
+
}, [behavior, contentRef, onExit, triggerRef]);
|
|
55
|
+
const handleCloseAutoFocus = React.useCallback((event) => {
|
|
56
|
+
if (!tabExitPendingRef.current) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
event.preventDefault();
|
|
60
|
+
tabExitPendingRef.current = false;
|
|
61
|
+
}, []);
|
|
62
|
+
return { handleCloseAutoFocus, handleTabKeyDown };
|
|
63
|
+
}
|
|
64
|
+
export { usePopoverTabExit };
|