@neasg/design-system 0.4.35 → 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 +25 -11
- 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 +1 -1
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export type ActivityCardDensity = "default" | "compact";
|
|
3
|
+
export type ActivityCardIconTone = "accent" | "destructive" | "info" | "muted" | "success" | "warning";
|
|
4
|
+
export interface ActivityCardProps extends Omit<React.HTMLAttributes<HTMLElement>, "title"> {
|
|
5
|
+
as?: "article" | "div" | "a" | "button";
|
|
6
|
+
density?: ActivityCardDensity;
|
|
7
|
+
icon?: React.ReactNode;
|
|
8
|
+
iconTone?: ActivityCardIconTone;
|
|
9
|
+
title: React.ReactNode;
|
|
10
|
+
titleLines?: 1 | 2;
|
|
11
|
+
meta?: React.ReactNode;
|
|
12
|
+
trailing?: React.ReactNode;
|
|
13
|
+
href?: string;
|
|
14
|
+
type?: "button" | "submit" | "reset";
|
|
15
|
+
"data-slot"?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface ActivityCardContentProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
18
|
+
density?: ActivityCardDensity;
|
|
19
|
+
}
|
|
20
|
+
export interface ActivityCardActorProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "children"> {
|
|
21
|
+
actor: React.ReactNode;
|
|
22
|
+
label?: React.ReactNode;
|
|
23
|
+
avatarSrc?: string | null;
|
|
24
|
+
avatarFallback?: React.ReactNode;
|
|
25
|
+
}
|
|
26
|
+
declare const ActivityCard: React.ForwardRefExoticComponent<ActivityCardProps & React.RefAttributes<HTMLElement>>;
|
|
27
|
+
declare const ActivityCardContent: React.ForwardRefExoticComponent<ActivityCardContentProps & React.RefAttributes<HTMLDivElement>>;
|
|
28
|
+
declare const ActivityCardActor: React.ForwardRefExoticComponent<ActivityCardActorProps & React.RefAttributes<HTMLDivElement>>;
|
|
29
|
+
export { ActivityCard, ActivityCardActor, ActivityCardContent };
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { AvatarProfile } from "./avatar";
|
|
4
|
+
import { cn } from "./lib/utils";
|
|
5
|
+
import { Typography } from "./typography";
|
|
6
|
+
const activityCardIconToneClasses = {
|
|
7
|
+
accent: "border-status-accent-foreground/20 bg-status-accent text-status-accent-foreground",
|
|
8
|
+
destructive: "border-status-destructive-foreground/20 bg-status-destructive text-status-destructive-foreground",
|
|
9
|
+
info: "border-status-info-foreground/20 bg-status-info text-status-info-foreground",
|
|
10
|
+
muted: "border-border bg-muted text-muted-foreground",
|
|
11
|
+
success: "border-status-success-foreground/20 bg-status-success text-status-success-foreground",
|
|
12
|
+
warning: "border-status-warning-foreground/20 bg-status-warning text-status-warning-foreground",
|
|
13
|
+
};
|
|
14
|
+
const activityCardTitleLineClasses = {
|
|
15
|
+
1: "truncate",
|
|
16
|
+
2: "line-clamp-2",
|
|
17
|
+
};
|
|
18
|
+
function getActivityActorText(value) {
|
|
19
|
+
if (value === null || value === undefined || typeof value === "boolean") {
|
|
20
|
+
return "";
|
|
21
|
+
}
|
|
22
|
+
if (typeof value === "string" || typeof value === "number") {
|
|
23
|
+
return String(value);
|
|
24
|
+
}
|
|
25
|
+
if (Array.isArray(value)) {
|
|
26
|
+
return value.map(getActivityActorText).join(" ").trim();
|
|
27
|
+
}
|
|
28
|
+
if (React.isValidElement(value)) {
|
|
29
|
+
return getActivityActorText(value.props.children);
|
|
30
|
+
}
|
|
31
|
+
return "";
|
|
32
|
+
}
|
|
33
|
+
function getActivityActorInitials(value) {
|
|
34
|
+
return getActivityActorText(value)
|
|
35
|
+
.split(/\s+/)
|
|
36
|
+
.filter(Boolean)
|
|
37
|
+
.slice(0, 2)
|
|
38
|
+
.map((part) => part.charAt(0).toUpperCase())
|
|
39
|
+
.join("");
|
|
40
|
+
}
|
|
41
|
+
const ActivityCard = React.forwardRef(({ as = "article", density = "default", icon, iconTone, title, titleLines = 2, meta, trailing, href, type, className, children, "data-slot": dataSlot, ...props }, ref) => {
|
|
42
|
+
const Comp = as;
|
|
43
|
+
return (_jsxs(Comp, { ref: ref, "data-slot": dataSlot !== null && dataSlot !== void 0 ? dataSlot : "activity-card", "data-activity-card": "", "data-density": density, href: as === "a" ? href : undefined, type: as === "button" ? (type !== null && type !== void 0 ? type : "button") : undefined, className: cn("min-w-0 overflow-hidden rounded-surface border border-border bg-card text-card-foreground shadow-sm", className), ...props, children: [_jsxs("header", { "data-slot": "activity-card-header", className: cn("flex items-center", density === "compact"
|
|
44
|
+
? "min-h-[var(--space-12)] p-[var(--space-3)]"
|
|
45
|
+
: "min-h-[80px] p-[16px]"), children: [icon ? (_jsx("span", { "data-slot": "activity-card-icon", "aria-hidden": "true", className: cn("flex shrink-0 items-center justify-center", iconTone
|
|
46
|
+
? cn("rounded-control border", density === "compact" ? "size-7" : "size-8", activityCardIconToneClasses[iconTone])
|
|
47
|
+
: cn("text-foreground", density === "compact" ? "size-4" : "size-[24px]")), children: icon })) : null, _jsxs("div", { className: cn("min-w-0 flex-1", icon &&
|
|
48
|
+
(density === "compact"
|
|
49
|
+
? "pl-[var(--space-3)]"
|
|
50
|
+
: "pl-[16px]"), trailing &&
|
|
51
|
+
(density === "compact"
|
|
52
|
+
? "pr-[var(--space-3)]"
|
|
53
|
+
: "pr-[32px]")), children: [_jsx(Typography, { as: "h3", variant: "label", className: cn("font-semibold", activityCardTitleLineClasses[titleLines]), children: title }), meta ? (_jsx(Typography, { as: "div", variant: "caption", className: "font-medium text-instructional", children: meta })) : null] }), trailing ? (_jsx("div", { "data-slot": "activity-card-trailing", className: "max-w-full shrink-0", children: trailing })) : null] }), children] }));
|
|
54
|
+
});
|
|
55
|
+
ActivityCard.displayName = "ActivityCard";
|
|
56
|
+
const ActivityCardContent = React.forwardRef(({ density = "default", className, ...props }, ref) => (_jsx("div", { ref: ref, "data-slot": "activity-card-content", "data-density": density, className: cn("border-t border-border", density === "compact"
|
|
57
|
+
? "space-y-[var(--space-3)] px-[var(--space-4)] py-[var(--space-3)]"
|
|
58
|
+
: "space-y-[24px] px-[32px] pb-[24px] pt-[16px]", className), ...props })));
|
|
59
|
+
ActivityCardContent.displayName = "ActivityCardContent";
|
|
60
|
+
const ActivityCardActor = React.forwardRef(({ actor, label = "By", avatarSrc, avatarFallback, className, ...props }, ref) => {
|
|
61
|
+
const actorText = getActivityActorText(actor);
|
|
62
|
+
return (_jsx("div", { ref: ref, "data-slot": "activity-card-actor", className: cn("min-w-0 text-left", className), ...props, children: _jsx(AvatarProfile, { size: "xs", src: avatarSrc, alt: actorText, fallback: avatarFallback !== null && avatarFallback !== void 0 ? avatarFallback : (getActivityActorInitials(actor) || "?"), name: _jsxs(_Fragment, { children: [label, " ", actor] }), wrapName: true, nameClassName: "font-semibold" }) }));
|
|
63
|
+
});
|
|
64
|
+
ActivityCardActor.displayName = "ActivityCardActor";
|
|
65
|
+
export { ActivityCard, ActivityCardActor, ActivityCardContent };
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { type EmptyStateProps } from "./empty-state";
|
|
3
|
+
import { type PopoverProps } from "./popover";
|
|
4
|
+
import { type PopoverMenuScrollAreaProps } from "./popover-menu";
|
|
5
|
+
import { type SearchInputProps } from "./search-input";
|
|
6
|
+
export interface AutocompleteControllerOptions {
|
|
7
|
+
listboxId: string;
|
|
8
|
+
onDismiss: () => void;
|
|
9
|
+
onSelect: (index: number) => void;
|
|
10
|
+
open: boolean;
|
|
11
|
+
optionCount: number;
|
|
12
|
+
isOptionDisabled?: (index: number) => boolean;
|
|
13
|
+
}
|
|
14
|
+
export interface AutocompleteController {
|
|
15
|
+
activeIndex: number;
|
|
16
|
+
getInputProps: () => {
|
|
17
|
+
"aria-activedescendant": string | undefined;
|
|
18
|
+
"aria-autocomplete": "list";
|
|
19
|
+
"aria-controls": string | undefined;
|
|
20
|
+
"aria-expanded": boolean;
|
|
21
|
+
"aria-haspopup": "listbox";
|
|
22
|
+
role: "combobox";
|
|
23
|
+
};
|
|
24
|
+
getOptionProps: (index: number) => Pick<React.ButtonHTMLAttributes<HTMLButtonElement>, "aria-selected" | "disabled" | "id" | "onClick" | "onMouseEnter" | "role" | "tabIndex">;
|
|
25
|
+
handleInputKeyDown: (event: React.KeyboardEvent<HTMLInputElement>) => boolean;
|
|
26
|
+
resetActiveIndex: () => void;
|
|
27
|
+
}
|
|
28
|
+
declare function useAutocompleteController({ listboxId, onDismiss, onSelect, open, optionCount, isOptionDisabled, }: AutocompleteControllerOptions): AutocompleteController;
|
|
29
|
+
export interface AutocompletePopoverProps extends Omit<PopoverProps, "surface"> {
|
|
30
|
+
}
|
|
31
|
+
/** Menu popover that preserves focus in its autocomplete input. */
|
|
32
|
+
declare function AutocompletePopover({ contentClassName, onCloseAutoFocus, onMouseDown, onOpenAutoFocus, ...props }: AutocompletePopoverProps): import("react/jsx-runtime").JSX.Element;
|
|
33
|
+
export interface AutocompleteOptionsProps extends PopoverMenuScrollAreaProps {
|
|
34
|
+
}
|
|
35
|
+
/** Scrollable option area that also works inside a modal dialog. */
|
|
36
|
+
declare function AutocompleteOptions({ className, onWheel, ...props }: AutocompleteOptionsProps): import("react/jsx-runtime").JSX.Element;
|
|
37
|
+
export interface AutocompleteOption {
|
|
38
|
+
value: string;
|
|
39
|
+
label: string;
|
|
40
|
+
description?: React.ReactNode;
|
|
41
|
+
disabled?: boolean;
|
|
42
|
+
}
|
|
43
|
+
export interface AutocompleteOptionGroup {
|
|
44
|
+
id: string;
|
|
45
|
+
label?: React.ReactNode;
|
|
46
|
+
options: readonly AutocompleteOption[];
|
|
47
|
+
}
|
|
48
|
+
export interface AutocompleteOptionRenderState {
|
|
49
|
+
active: boolean;
|
|
50
|
+
query: string;
|
|
51
|
+
}
|
|
52
|
+
export interface AutocompleteStateContent extends Pick<EmptyStateProps, "description" | "icon" | "message"> {
|
|
53
|
+
}
|
|
54
|
+
interface AutocompleteBaseProps extends Omit<SearchInputProps, "onKeyDown" | "onSearch" | "onValueChange" | "searchOnChange" | "searchOnEnter" | "value"> {
|
|
55
|
+
value: string;
|
|
56
|
+
onValueChange: (value: string) => void;
|
|
57
|
+
onOptionSelect: (option: AutocompleteOption) => void;
|
|
58
|
+
/** Minimum trimmed query length required before the menu can open. */
|
|
59
|
+
minLength?: number;
|
|
60
|
+
loading?: boolean;
|
|
61
|
+
open?: boolean;
|
|
62
|
+
defaultOpen?: boolean;
|
|
63
|
+
onOpenChange?: (open: boolean) => void;
|
|
64
|
+
/** Filters supplied options by label in the browser. Keep false for remote or fuzzy search results. */
|
|
65
|
+
filterOptions?: boolean;
|
|
66
|
+
emptyState?: AutocompleteStateContent;
|
|
67
|
+
loadingState?: AutocompleteStateContent;
|
|
68
|
+
renderOption?: (option: AutocompleteOption, state: AutocompleteOptionRenderState) => React.ReactNode;
|
|
69
|
+
listboxLabel?: string;
|
|
70
|
+
contentClassName?: string;
|
|
71
|
+
optionClassName?: string;
|
|
72
|
+
maxHeight?: string;
|
|
73
|
+
onKeyDown?: React.KeyboardEventHandler<HTMLInputElement>;
|
|
74
|
+
}
|
|
75
|
+
type AutocompleteOptionSource = {
|
|
76
|
+
options: readonly AutocompleteOption[];
|
|
77
|
+
groups?: never;
|
|
78
|
+
} | {
|
|
79
|
+
options?: never;
|
|
80
|
+
groups: readonly AutocompleteOptionGroup[];
|
|
81
|
+
};
|
|
82
|
+
export type AutocompleteProps = AutocompleteBaseProps & AutocompleteOptionSource;
|
|
83
|
+
declare function Autocomplete({ value, onValueChange, onOptionSelect, options, groups, minLength, loading, open, defaultOpen, onOpenChange, filterOptions, emptyState, loadingState, renderOption, listboxLabel, contentClassName, optionClassName, maxHeight, onKeyDown, label, hideLabel, disabled, id, onFocus, ...inputProps }: AutocompleteProps): import("react/jsx-runtime").JSX.Element;
|
|
84
|
+
export { Autocomplete, AutocompleteOptions, AutocompletePopover, useAutocompleteController, };
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { LoaderPinwheelIcon, SearchIcon } from "./animated-icons";
|
|
5
|
+
import { EmptyState } from "./empty-state";
|
|
6
|
+
import { cn } from "./lib/utils";
|
|
7
|
+
import { Popover } from "./popover";
|
|
8
|
+
import { PopoverMenuDivider, PopoverMenuGroup, PopoverMenuGroupLabel, PopoverMenuItem, PopoverMenuScrollArea, } from "./popover-menu";
|
|
9
|
+
import { SearchInput } from "./search-input";
|
|
10
|
+
import { Typography } from "./typography";
|
|
11
|
+
import { SearchHighlight } from "./use-search-highlight";
|
|
12
|
+
function getNextEnabledOptionIndex({ currentIndex, direction, isOptionDisabled, optionCount, }) {
|
|
13
|
+
if (optionCount <= 0) {
|
|
14
|
+
return -1;
|
|
15
|
+
}
|
|
16
|
+
const startIndex = direction === "previous" && currentIndex < 0 ? 0 : currentIndex;
|
|
17
|
+
const offset = direction === "previous" ? -1 : 1;
|
|
18
|
+
for (let step = 1; step <= optionCount; step += 1) {
|
|
19
|
+
const index = (startIndex + offset * step + optionCount * 2) % optionCount;
|
|
20
|
+
if (!isOptionDisabled(index)) {
|
|
21
|
+
return index;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return -1;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Shared active-descendant navigation for autocomplete inputs whose focus must
|
|
28
|
+
* remain in the search field. Prefer `Autocomplete` unless the result rows need
|
|
29
|
+
* a custom composition.
|
|
30
|
+
*/
|
|
31
|
+
const autocompleteOptionIsEnabled = () => false;
|
|
32
|
+
function useAutocompleteController({ listboxId, onDismiss, onSelect, open, optionCount, isOptionDisabled = autocompleteOptionIsEnabled, }) {
|
|
33
|
+
const [activeIndex, setActiveIndex] = React.useState(-1);
|
|
34
|
+
React.useEffect(() => {
|
|
35
|
+
if (!open ||
|
|
36
|
+
activeIndex >= optionCount ||
|
|
37
|
+
(activeIndex >= 0 && isOptionDisabled(activeIndex))) {
|
|
38
|
+
setActiveIndex(-1);
|
|
39
|
+
}
|
|
40
|
+
}, [activeIndex, isOptionDisabled, open, optionCount]);
|
|
41
|
+
React.useEffect(() => {
|
|
42
|
+
var _a, _b;
|
|
43
|
+
if (!open || activeIndex < 0) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
(_b = (_a = document
|
|
47
|
+
.getElementById(`${listboxId}-option-${activeIndex}`)) === null || _a === void 0 ? void 0 : _a.scrollIntoView) === null || _b === void 0 ? void 0 : _b.call(_a, { block: "nearest" });
|
|
48
|
+
}, [activeIndex, listboxId, open]);
|
|
49
|
+
const resetActiveIndex = React.useCallback(() => setActiveIndex(-1), []);
|
|
50
|
+
const handleInputKeyDown = React.useCallback((event) => {
|
|
51
|
+
if (event.nativeEvent.isComposing || !open) {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
let direction;
|
|
55
|
+
if (event.key === "ArrowDown")
|
|
56
|
+
direction = "next";
|
|
57
|
+
if (event.key === "ArrowUp")
|
|
58
|
+
direction = "previous";
|
|
59
|
+
if (direction && optionCount > 0) {
|
|
60
|
+
event.preventDefault();
|
|
61
|
+
setActiveIndex((currentIndex) => getNextEnabledOptionIndex({
|
|
62
|
+
currentIndex,
|
|
63
|
+
direction,
|
|
64
|
+
isOptionDisabled,
|
|
65
|
+
optionCount,
|
|
66
|
+
}));
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
if (event.key === "Enter" && activeIndex >= 0) {
|
|
70
|
+
event.preventDefault();
|
|
71
|
+
onSelect(activeIndex);
|
|
72
|
+
setActiveIndex(-1);
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
if (event.key === "Escape") {
|
|
76
|
+
event.preventDefault();
|
|
77
|
+
event.stopPropagation();
|
|
78
|
+
setActiveIndex(-1);
|
|
79
|
+
onDismiss();
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
return false;
|
|
83
|
+
}, [activeIndex, isOptionDisabled, onDismiss, onSelect, open, optionCount]);
|
|
84
|
+
const getInputProps = React.useCallback(() => ({
|
|
85
|
+
"aria-activedescendant": open && activeIndex >= 0 && activeIndex < optionCount
|
|
86
|
+
? `${listboxId}-option-${activeIndex}`
|
|
87
|
+
: undefined,
|
|
88
|
+
"aria-autocomplete": "list",
|
|
89
|
+
"aria-controls": open ? listboxId : undefined,
|
|
90
|
+
"aria-expanded": open,
|
|
91
|
+
"aria-haspopup": "listbox",
|
|
92
|
+
role: "combobox",
|
|
93
|
+
}), [activeIndex, listboxId, open, optionCount]);
|
|
94
|
+
const getOptionProps = React.useCallback((index) => {
|
|
95
|
+
const disabled = isOptionDisabled(index);
|
|
96
|
+
return {
|
|
97
|
+
id: `${listboxId}-option-${index}`,
|
|
98
|
+
role: "option",
|
|
99
|
+
tabIndex: -1,
|
|
100
|
+
"aria-selected": activeIndex === index,
|
|
101
|
+
disabled,
|
|
102
|
+
onMouseEnter: () => {
|
|
103
|
+
if (!disabled)
|
|
104
|
+
setActiveIndex(index);
|
|
105
|
+
},
|
|
106
|
+
onClick: () => {
|
|
107
|
+
if (disabled)
|
|
108
|
+
return;
|
|
109
|
+
onSelect(index);
|
|
110
|
+
setActiveIndex(-1);
|
|
111
|
+
},
|
|
112
|
+
};
|
|
113
|
+
}, [activeIndex, isOptionDisabled, listboxId, onSelect]);
|
|
114
|
+
return {
|
|
115
|
+
activeIndex,
|
|
116
|
+
getInputProps,
|
|
117
|
+
getOptionProps,
|
|
118
|
+
handleInputKeyDown,
|
|
119
|
+
resetActiveIndex,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
/** Menu popover that preserves focus in its autocomplete input. */
|
|
123
|
+
function AutocompletePopover({ contentClassName, onCloseAutoFocus, onMouseDown, onOpenAutoFocus, ...props }) {
|
|
124
|
+
return (_jsx(Popover, { ...props, surface: "menu", contentClassName: cn("[&_[data-slot=popover-menu-item]]:min-h-8 [&_[data-slot=popover-menu-item]]:px-1.5 [&_[data-slot=popover-menu-item]]:py-1.5", contentClassName), onMouseDown: (event) => {
|
|
125
|
+
onMouseDown === null || onMouseDown === void 0 ? void 0 : onMouseDown(event);
|
|
126
|
+
if (!event.defaultPrevented)
|
|
127
|
+
event.preventDefault();
|
|
128
|
+
}, onOpenAutoFocus: (event) => {
|
|
129
|
+
onOpenAutoFocus === null || onOpenAutoFocus === void 0 ? void 0 : onOpenAutoFocus(event);
|
|
130
|
+
if (!event.defaultPrevented)
|
|
131
|
+
event.preventDefault();
|
|
132
|
+
}, onCloseAutoFocus: (event) => {
|
|
133
|
+
onCloseAutoFocus === null || onCloseAutoFocus === void 0 ? void 0 : onCloseAutoFocus(event);
|
|
134
|
+
if (!event.defaultPrevented)
|
|
135
|
+
event.preventDefault();
|
|
136
|
+
} }));
|
|
137
|
+
}
|
|
138
|
+
/** Scrollable option area that also works inside a modal dialog. */
|
|
139
|
+
function AutocompleteOptions({ className, onWheel, ...props }) {
|
|
140
|
+
const handleWheel = (event) => {
|
|
141
|
+
onWheel === null || onWheel === void 0 ? void 0 : onWheel(event);
|
|
142
|
+
if (event.defaultPrevented)
|
|
143
|
+
return;
|
|
144
|
+
const optionList = event.currentTarget;
|
|
145
|
+
const maxScrollTop = optionList.scrollHeight - optionList.clientHeight;
|
|
146
|
+
if (maxScrollTop <= 0)
|
|
147
|
+
return;
|
|
148
|
+
const deltaMultiplier = event.deltaMode === WheelEvent.DOM_DELTA_LINE
|
|
149
|
+
? 16
|
|
150
|
+
: event.deltaMode === WheelEvent.DOM_DELTA_PAGE
|
|
151
|
+
? optionList.clientHeight
|
|
152
|
+
: 1;
|
|
153
|
+
const nextScrollTop = Math.min(maxScrollTop, Math.max(0, optionList.scrollTop + event.deltaY * deltaMultiplier));
|
|
154
|
+
if (nextScrollTop === optionList.scrollTop)
|
|
155
|
+
return;
|
|
156
|
+
optionList.scrollTop = nextScrollTop;
|
|
157
|
+
event.preventDefault();
|
|
158
|
+
event.stopPropagation();
|
|
159
|
+
};
|
|
160
|
+
return (_jsx(PopoverMenuScrollArea, { ...props, "data-slot": "autocomplete-options", className: cn("min-h-0 touch-pan-y space-y-0 overscroll-contain", className), onWheel: handleWheel }));
|
|
161
|
+
}
|
|
162
|
+
const defaultEmptyState = {
|
|
163
|
+
icon: SearchIcon,
|
|
164
|
+
message: "No matches found",
|
|
165
|
+
description: "Try a different search term.",
|
|
166
|
+
};
|
|
167
|
+
function AutocompleteLoadingIcon({ className }) {
|
|
168
|
+
return _jsx(LoaderPinwheelIcon, { className: cn("animate-spin", className) });
|
|
169
|
+
}
|
|
170
|
+
const defaultLoadingState = {
|
|
171
|
+
icon: AutocompleteLoadingIcon,
|
|
172
|
+
message: "Finding matching options",
|
|
173
|
+
description: "Search results will appear here.",
|
|
174
|
+
};
|
|
175
|
+
function Autocomplete({ value, onValueChange, onOptionSelect, options, groups, minLength = 0, loading = false, open, defaultOpen = false, onOpenChange, filterOptions = false, emptyState = defaultEmptyState, loadingState = defaultLoadingState, renderOption, listboxLabel, contentClassName, optionClassName, maxHeight, onKeyDown, label = "Search", hideLabel = false, disabled, id, onFocus, ...inputProps }) {
|
|
176
|
+
const inputRef = React.useRef(null);
|
|
177
|
+
const generatedId = React.useId().replace(/:/g, "");
|
|
178
|
+
const inputId = id !== null && id !== void 0 ? id : `autocomplete-${generatedId}`;
|
|
179
|
+
const listboxId = `${inputId}-listbox`;
|
|
180
|
+
const [internalOpen, setInternalOpen] = React.useState(defaultOpen);
|
|
181
|
+
const isControlled = open !== undefined;
|
|
182
|
+
const requestedOpen = isControlled ? open : internalOpen;
|
|
183
|
+
const meetsMinimumLength = value.trim().length >= minLength;
|
|
184
|
+
const canOpen = !disabled && meetsMinimumLength;
|
|
185
|
+
const currentOpen = Boolean(requestedOpen && canOpen);
|
|
186
|
+
const requestOpen = React.useCallback((nextOpen) => {
|
|
187
|
+
const resolvedOpen = Boolean(nextOpen && canOpen);
|
|
188
|
+
if (!isControlled)
|
|
189
|
+
setInternalOpen(resolvedOpen);
|
|
190
|
+
onOpenChange === null || onOpenChange === void 0 ? void 0 : onOpenChange(resolvedOpen);
|
|
191
|
+
}, [canOpen, isControlled, onOpenChange]);
|
|
192
|
+
React.useEffect(() => {
|
|
193
|
+
if (requestedOpen && !canOpen)
|
|
194
|
+
requestOpen(false);
|
|
195
|
+
}, [canOpen, requestOpen, requestedOpen]);
|
|
196
|
+
const sourceGroups = React.useMemo(() => groups !== null && groups !== void 0 ? groups : [
|
|
197
|
+
{
|
|
198
|
+
id: "options",
|
|
199
|
+
options: options !== null && options !== void 0 ? options : [],
|
|
200
|
+
},
|
|
201
|
+
], [groups, options]);
|
|
202
|
+
const visibleGroups = React.useMemo(() => {
|
|
203
|
+
if (!filterOptions)
|
|
204
|
+
return sourceGroups;
|
|
205
|
+
const normalizedQuery = value.trim().toLocaleLowerCase();
|
|
206
|
+
return sourceGroups
|
|
207
|
+
.map((group) => ({
|
|
208
|
+
...group,
|
|
209
|
+
options: group.options.filter((option) => option.label.toLocaleLowerCase().includes(normalizedQuery)),
|
|
210
|
+
}))
|
|
211
|
+
.filter((group) => group.options.length > 0);
|
|
212
|
+
}, [filterOptions, sourceGroups, value]);
|
|
213
|
+
const visibleOptions = React.useMemo(() => visibleGroups.flatMap((group) => group.options), [visibleGroups]);
|
|
214
|
+
const visibleOptionIdentity = visibleOptions
|
|
215
|
+
.map((option) => option.value)
|
|
216
|
+
.join("\u0000");
|
|
217
|
+
const isOptionDisabled = React.useCallback((index) => { var _a; return Boolean((_a = visibleOptions[index]) === null || _a === void 0 ? void 0 : _a.disabled); }, [visibleOptions]);
|
|
218
|
+
const selectOption = React.useCallback((index) => {
|
|
219
|
+
const option = visibleOptions[index];
|
|
220
|
+
if (!option || option.disabled)
|
|
221
|
+
return;
|
|
222
|
+
onOptionSelect(option);
|
|
223
|
+
requestOpen(false);
|
|
224
|
+
}, [onOptionSelect, requestOpen, visibleOptions]);
|
|
225
|
+
const controller = useAutocompleteController({
|
|
226
|
+
listboxId,
|
|
227
|
+
onDismiss: () => requestOpen(false),
|
|
228
|
+
onSelect: selectOption,
|
|
229
|
+
open: currentOpen,
|
|
230
|
+
optionCount: visibleOptions.length,
|
|
231
|
+
isOptionDisabled,
|
|
232
|
+
});
|
|
233
|
+
React.useEffect(() => {
|
|
234
|
+
controller.resetActiveIndex();
|
|
235
|
+
}, [controller.resetActiveIndex, value, visibleOptionIdentity]);
|
|
236
|
+
const handleValueChange = React.useCallback((nextValue) => {
|
|
237
|
+
onValueChange(nextValue);
|
|
238
|
+
const nextCanOpen = !disabled && nextValue.trim().length >= minLength;
|
|
239
|
+
if (!isControlled)
|
|
240
|
+
setInternalOpen(nextCanOpen);
|
|
241
|
+
onOpenChange === null || onOpenChange === void 0 ? void 0 : onOpenChange(nextCanOpen);
|
|
242
|
+
}, [disabled, isControlled, minLength, onOpenChange, onValueChange]);
|
|
243
|
+
const handleKeyDown = React.useCallback((event) => {
|
|
244
|
+
onKeyDown === null || onKeyDown === void 0 ? void 0 : onKeyDown(event);
|
|
245
|
+
if (!event.defaultPrevented)
|
|
246
|
+
controller.handleInputKeyDown(event);
|
|
247
|
+
}, [controller, onKeyDown]);
|
|
248
|
+
const resolvedListboxLabel = listboxLabel !== null && listboxLabel !== void 0 ? listboxLabel : (typeof label === "string" ? `${label} options` : "Autocomplete options");
|
|
249
|
+
let optionIndex = -1;
|
|
250
|
+
return (_jsx(AutocompletePopover, { open: currentOpen, onOpenChange: requestOpen, virtualAnchorRef: inputRef, align: "start", contentClassName: cn("flex max-h-[var(--radix-popover-content-available-height)] w-[var(--radix-popover-trigger-width)] flex-col", contentClassName), id: listboxId, role: "listbox", "aria-label": resolvedListboxLabel, "aria-busy": loading || undefined, trigger: _jsx("div", { "data-slot": "autocomplete", className: "w-full", onClick: (event) => {
|
|
251
|
+
if (currentOpen)
|
|
252
|
+
event.preventDefault();
|
|
253
|
+
}, children: _jsx(SearchInput, { ref: inputRef, ...inputProps, ...controller.getInputProps(), id: inputId, label: label, hideLabel: hideLabel, value: value, onValueChange: handleValueChange, onFocus: (event) => {
|
|
254
|
+
onFocus === null || onFocus === void 0 ? void 0 : onFocus(event);
|
|
255
|
+
if (!event.defaultPrevented && canOpen)
|
|
256
|
+
requestOpen(true);
|
|
257
|
+
}, onKeyDown: handleKeyDown, disabled: disabled, searchOnChange: false, searchOnEnter: false }) }), children: _jsx(AutocompleteOptions, { maxHeight: maxHeight, children: loading ? (_jsx(EmptyState, { ...loadingState, className: "min-h-40", role: "status" })) : visibleOptions.length === 0 ? (_jsx(EmptyState, { ...emptyState, className: "min-h-40", role: "status" })) : (visibleGroups.map((group, groupIndex) => {
|
|
258
|
+
const groupLabelId = `${listboxId}-group-${group.id}`;
|
|
259
|
+
return (_jsxs(React.Fragment, { children: [_jsxs(PopoverMenuGroup, { role: group.label ? "group" : undefined, "aria-labelledby": group.label ? groupLabelId : undefined, className: "space-y-0", children: [group.label ? (_jsx(PopoverMenuGroupLabel, { id: groupLabelId, children: group.label })) : null, group.options.map((option) => {
|
|
260
|
+
optionIndex += 1;
|
|
261
|
+
const currentIndex = optionIndex;
|
|
262
|
+
const active = controller.activeIndex === currentIndex;
|
|
263
|
+
return (_jsx(PopoverMenuItem, { type: "button", className: optionClassName, ...controller.getOptionProps(currentIndex), children: renderOption ? (renderOption(option, { active, query: value })) : (_jsxs("span", { className: "min-w-0 flex-1", children: [_jsx(Typography, { as: "span", variant: "bodySm", className: "block truncate", children: _jsx(SearchHighlight, { text: option.label, query: value }) }), option.description ? (_jsx(Typography, { as: "span", variant: "caption", className: "mt-0.5 block", children: option.description })) : null] })) }, option.value));
|
|
264
|
+
})] }), groupIndex < visibleGroups.length - 1 ? (_jsx(PopoverMenuDivider, { "data-slot": "autocomplete-group-separator" })) : null] }, group.id));
|
|
265
|
+
})) }) }));
|
|
266
|
+
}
|
|
267
|
+
export { Autocomplete, AutocompleteOptions, AutocompletePopover, useAutocompleteController, };
|
package/dist/avatar.d.ts
CHANGED
|
@@ -22,6 +22,8 @@ interface AvatarProfileProps extends Omit<React.HTMLAttributes<HTMLDivElement>,
|
|
|
22
22
|
name?: React.ReactNode;
|
|
23
23
|
nameAs?: React.ElementType;
|
|
24
24
|
nameTrailing?: React.ReactNode;
|
|
25
|
+
wrapName?: boolean;
|
|
26
|
+
wrapInfo?: boolean;
|
|
25
27
|
role?: React.ReactNode;
|
|
26
28
|
rolePlacement?: "above" | "below";
|
|
27
29
|
topInfo?: React.ReactNode;
|
|
@@ -38,7 +40,7 @@ interface AvatarProfileProps extends Omit<React.HTMLAttributes<HTMLDivElement>,
|
|
|
38
40
|
avatarOverlay?: React.ReactNode;
|
|
39
41
|
}
|
|
40
42
|
declare function Avatar({ src, alt, fallback, size, loading, className, imageClassName, fallbackClassName, ...props }: AvatarProps): import("react/jsx-runtime").JSX.Element;
|
|
41
|
-
declare function AvatarProfile({ src, alt, fallback, size, loading, name, nameAs: NameElement, nameTrailing, role, rolePlacement, topInfo, bottomInfo, className, avatarClassName, imageClassName, fallbackClassName, contentClassName, nameRowClassName, nameClassName, roleClassName, topInfoClassName, bottomInfoClassName, avatarOverlay, ...props }: AvatarProfileProps): import("react/jsx-runtime").JSX.Element;
|
|
43
|
+
declare function AvatarProfile({ src, alt, fallback, size, loading, name, nameAs: NameElement, nameTrailing, wrapName, wrapInfo, role, rolePlacement, topInfo, bottomInfo, className, avatarClassName, imageClassName, fallbackClassName, contentClassName, nameRowClassName, nameClassName, roleClassName, topInfoClassName, bottomInfoClassName, avatarOverlay, ...props }: AvatarProfileProps): import("react/jsx-runtime").JSX.Element;
|
|
42
44
|
export { Avatar, AvatarProfile, AvatarRoot, AvatarImage, AvatarFallback };
|
|
43
45
|
export type AvatarRootProps = React.ComponentPropsWithoutRef<typeof AvatarRoot>;
|
|
44
46
|
export type { AvatarProps, AvatarProfileProps };
|
package/dist/avatar.js
CHANGED
|
@@ -21,9 +21,19 @@ const avatarProfileGapClasses = {
|
|
|
21
21
|
md: "gap-2.5",
|
|
22
22
|
};
|
|
23
23
|
const avatarProfileNameClasses = {
|
|
24
|
-
xs: "text-xs
|
|
25
|
-
sm: "text-sm
|
|
26
|
-
md: "text-sm
|
|
24
|
+
xs: "text-xs",
|
|
25
|
+
sm: "text-sm",
|
|
26
|
+
md: "text-sm",
|
|
27
|
+
};
|
|
28
|
+
const avatarProfileNameCompactLeadingClasses = {
|
|
29
|
+
xs: "leading-4",
|
|
30
|
+
sm: "leading-5",
|
|
31
|
+
md: "leading-5",
|
|
32
|
+
};
|
|
33
|
+
const avatarProfileContentMinHeightClasses = {
|
|
34
|
+
xs: "min-h-[24px]",
|
|
35
|
+
sm: "min-h-[32px]",
|
|
36
|
+
md: "min-h-[40px]",
|
|
27
37
|
};
|
|
28
38
|
const avatarProfileInfoClasses = {
|
|
29
39
|
xs: "text-[11px] leading-3",
|
|
@@ -80,27 +90,34 @@ function Avatar({ src, alt = "", fallback, size = "sm", loading = false, classNa
|
|
|
80
90
|
"--avatar-fallback-background": fallbackTone.background,
|
|
81
91
|
"--avatar-fallback-foreground": fallbackTone.foreground,
|
|
82
92
|
};
|
|
83
|
-
return (_jsxs(AvatarRoot, { className: cn(avatarSizeClasses[size], className), ...props, children: [src ? (_jsx(AvatarImage, { src: src, alt: alt, className: imageClassName })) : null, _jsx(AvatarFallback, { style: fallbackStyle, className: cn("bg-[hsl(var(--avatar-fallback-background))] font-medium text-[hsl(var(--avatar-fallback-foreground))]", fallbackClassName), children: fallback })] }));
|
|
93
|
+
return (_jsxs(AvatarRoot, { "data-slot": "avatar", className: cn(avatarSizeClasses[size], className), ...props, children: [src ? (_jsx(AvatarImage, { src: src, alt: alt, className: imageClassName })) : null, _jsx(AvatarFallback, { style: fallbackStyle, className: cn("bg-[hsl(var(--avatar-fallback-background))] font-medium text-[hsl(var(--avatar-fallback-foreground))]", fallbackClassName), children: fallback })] }));
|
|
84
94
|
}
|
|
85
|
-
function AvatarProfile({ src, alt = "", fallback, size = "sm", loading = false, name, nameAs: NameElement = "span", nameTrailing, role, rolePlacement = "below", topInfo, bottomInfo, className, avatarClassName, imageClassName, fallbackClassName, contentClassName, nameRowClassName, nameClassName, roleClassName, topInfoClassName, bottomInfoClassName, avatarOverlay, ...props }) {
|
|
95
|
+
function AvatarProfile({ src, alt = "", fallback, size = "sm", loading = false, name, nameAs: NameElement = "span", nameTrailing, wrapName = false, wrapInfo = false, role, rolePlacement = "below", topInfo, bottomInfo, className, avatarClassName, imageClassName, fallbackClassName, contentClassName, nameRowClassName, nameClassName, roleClassName, topInfoClassName, bottomInfoClassName, avatarOverlay, ...props }) {
|
|
86
96
|
const resolvedTop = topInfo !== null && topInfo !== void 0 ? topInfo : (rolePlacement === "above" ? role : undefined);
|
|
87
97
|
const resolvedBottom = bottomInfo !== null && bottomInfo !== void 0 ? bottomInfo : (rolePlacement === "below" ? role : undefined);
|
|
88
98
|
const hasSupportingInfo = (resolvedTop !== undefined && resolvedTop !== null) ||
|
|
89
99
|
(resolvedBottom !== undefined && resolvedBottom !== null);
|
|
90
|
-
const alignmentClassName = hasSupportingInfo ? "items-start" : "items-center";
|
|
100
|
+
const alignmentClassName = hasSupportingInfo || wrapName ? "items-start" : "items-center";
|
|
91
101
|
const avatarOffsetClassName = hasSupportingInfo ? "mt-0.5" : undefined;
|
|
102
|
+
const wrappedNameContentClassName = wrapName && !hasSupportingInfo
|
|
103
|
+
? cn(avatarProfileContentMinHeightClasses[size], "justify-center")
|
|
104
|
+
: undefined;
|
|
92
105
|
if (loading) {
|
|
93
|
-
return (_jsxs("div", { className: cn("flex min-w-0 max-w-full", alignmentClassName, avatarProfileGapClasses[size], className), "aria-busy": "true", ...props, children: [_jsx(Skeleton, { className: cn("shrink-0 rounded-full", avatarSizeClasses[size], avatarOffsetClassName, avatarClassName) }), _jsxs("div", { className: cn("flex min-w-0 flex-1 flex-col", avatarProfileContentGapClass, contentClassName), children: [resolvedTop !== undefined ? (_jsx(Skeleton, { className: "h-3 w-20" })) : null, _jsx(Skeleton, { className: "h-4 w-32" }), resolvedBottom !== undefined ? (_jsx(Skeleton, { className: "h-3 w-20" })) : null] })] }));
|
|
106
|
+
return (_jsxs("div", { className: cn("flex min-w-0 max-w-full", alignmentClassName, avatarProfileGapClasses[size], className), "aria-busy": "true", ...props, children: [_jsx(Skeleton, { className: cn("shrink-0 rounded-full", avatarSizeClasses[size], avatarOffsetClassName, avatarClassName) }), _jsxs("div", { className: cn("flex min-w-0 flex-1 flex-col", avatarProfileContentGapClass, wrappedNameContentClassName, contentClassName), children: [resolvedTop !== undefined ? (_jsx(Skeleton, { className: "h-3 w-20" })) : null, _jsx(Skeleton, { className: "h-4 w-32" }), resolvedBottom !== undefined ? (_jsx(Skeleton, { className: "h-3 w-20" })) : null] })] }));
|
|
94
107
|
}
|
|
95
108
|
const hasMeta = name !== undefined ||
|
|
96
109
|
nameTrailing !== undefined ||
|
|
97
110
|
resolvedTop !== undefined ||
|
|
98
111
|
resolvedBottom !== undefined;
|
|
99
|
-
const infoBaseClass = cn("min-w-0
|
|
112
|
+
const infoBaseClass = cn("min-w-0", wrapInfo
|
|
113
|
+
? "whitespace-normal break-words [overflow-wrap:anywhere]"
|
|
114
|
+
: "truncate", "text-muted-foreground", avatarProfileInfoClasses[size]);
|
|
100
115
|
const topNode = resolvedTop !== undefined && resolvedTop !== null ? (_jsx("span", { className: cn(infoBaseClass, topInfo !== undefined ? topInfoClassName : roleClassName), children: resolvedTop })) : null;
|
|
101
116
|
const bottomNode = resolvedBottom !== undefined && resolvedBottom !== null ? (_jsx("span", { className: cn(infoBaseClass, bottomInfo !== undefined ? bottomInfoClassName : roleClassName), children: resolvedBottom })) : null;
|
|
102
|
-
const nameTextNode = name !== undefined && name !== null ? (_jsx(NameElement, { className: cn("min-w-0
|
|
117
|
+
const nameTextNode = name !== undefined && name !== null ? (_jsx(NameElement, { className: cn("min-w-0 font-medium text-foreground", wrapName
|
|
118
|
+
? "whitespace-normal break-words [overflow-wrap:anywhere]"
|
|
119
|
+
: "truncate", avatarProfileNameClasses[size], wrapName ? undefined : avatarProfileNameCompactLeadingClasses[size], nameClassName), children: name })) : null;
|
|
103
120
|
const nameNode = nameTrailing !== undefined && nameTrailing !== null ? (_jsxs("div", { className: cn("flex min-w-0 flex-wrap items-center gap-x-2 gap-y-1", nameRowClassName), children: [nameTextNode, nameTrailing] })) : (nameTextNode);
|
|
104
|
-
return (_jsxs("div", { className: cn("flex min-w-0 max-w-full", alignmentClassName, avatarProfileGapClasses[size], className), ...props, children: [_jsxs("div", { className: "relative shrink-0", children: [_jsx(Avatar, { src: src, alt: alt, fallback: fallback, size: size, className: cn(avatarOffsetClassName, avatarClassName), imageClassName: imageClassName, fallbackClassName: fallbackClassName }), avatarOverlay] }), hasMeta ? (_jsxs("div", { className: cn("flex min-w-0 flex-1 flex-col", avatarProfileContentGapClass, contentClassName), children: [topNode, nameNode, bottomNode] })) : null] }));
|
|
121
|
+
return (_jsxs("div", { className: cn("flex min-w-0 max-w-full", alignmentClassName, avatarProfileGapClasses[size], className), ...props, children: [_jsxs("div", { className: "relative shrink-0", children: [_jsx(Avatar, { src: src, alt: alt, fallback: fallback, size: size, className: cn(avatarOffsetClassName, avatarClassName), imageClassName: imageClassName, fallbackClassName: fallbackClassName }), avatarOverlay] }), hasMeta ? (_jsxs("div", { className: cn("flex min-w-0 flex-1 flex-col", avatarProfileContentGapClass, wrappedNameContentClassName, contentClassName), children: [topNode, nameNode, bottomNode] })) : null] }));
|
|
105
122
|
}
|
|
106
123
|
export { Avatar, AvatarProfile, AvatarRoot, AvatarImage, AvatarFallback };
|
package/dist/badge.js
CHANGED
|
@@ -3,7 +3,7 @@ import * as React from "react";
|
|
|
3
3
|
import { cva } from "class-variance-authority";
|
|
4
4
|
import { cn } from "./lib/utils";
|
|
5
5
|
import { Typography } from "./typography";
|
|
6
|
-
const badgeVariants = cva("inline-flex items-center justify-center text-center rounded-md border transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 truncate", {
|
|
6
|
+
const badgeVariants = cva("inline-flex items-center justify-center text-center rounded-md border transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 truncate [&>span]:text-[10px] [&_svg]:size-3 [&_svg]:shrink-0", {
|
|
7
7
|
variants: {
|
|
8
8
|
variant: {
|
|
9
9
|
secondary: "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
package/dist/button.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import * as React from "react";
|
|
|
2
2
|
import { type VariantProps } from "class-variance-authority";
|
|
3
3
|
declare const buttonVariants: (props?: ({
|
|
4
4
|
variant?: "link" | "default" | "destructive" | "outline" | "secondary" | "ghost" | null | undefined;
|
|
5
|
-
size?: "default" | "sm" | "compact" | "icon" | "compactIcon" | null | undefined;
|
|
5
|
+
size?: "default" | "sm" | "compact" | "comfortable" | "icon" | "compactIcon" | null | undefined;
|
|
6
6
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
7
7
|
export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {
|
|
8
8
|
/**
|
package/dist/button.js
CHANGED
|
@@ -16,6 +16,7 @@ const buttonVariants = cva("inline-flex cursor-pointer items-center justify-cent
|
|
|
16
16
|
size: {
|
|
17
17
|
sm: "h-8 px-2.5 text-sm",
|
|
18
18
|
compact: "h-8 gap-1 px-2 text-sm",
|
|
19
|
+
comfortable: "h-[46px] px-[12px] py-[11px] text-[16px] [&_svg]:h-[24px] [&_svg]:min-h-[24px] [&_svg]:w-[24px] [&_svg]:min-w-[24px]",
|
|
19
20
|
default: "h-control px-3 py-1.5",
|
|
20
21
|
icon: "h-control w-control",
|
|
21
22
|
compactIcon: "h-8 w-8",
|
package/dist/calendar.js
CHANGED
|
@@ -25,7 +25,7 @@ function Calendar({ className, classNames, showOutsideDays = true, fixedWeeks =
|
|
|
25
25
|
...formatters,
|
|
26
26
|
}, classNames: {
|
|
27
27
|
root: cn("w-fit", defaultClassNames.root),
|
|
28
|
-
months: cn("relative flex flex-col gap-4
|
|
28
|
+
months: cn("relative flex flex-col gap-4 sm:flex-row", defaultClassNames.months),
|
|
29
29
|
month: cn("flex w-full flex-col gap-4", defaultClassNames.month),
|
|
30
30
|
nav: cn("absolute inset-x-0 top-0 flex w-full items-center justify-between gap-1", defaultClassNames.nav),
|
|
31
31
|
button_previous: cn(buttonVariants({ variant: buttonVariant }), "h-[--cell-size] w-[--cell-size] select-none p-0 aria-disabled:opacity-50", defaultClassNames.button_previous),
|
package/dist/card.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import * as React from "react";
|
|
|
2
2
|
export interface CardProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "title"> {
|
|
3
3
|
title: React.ReactNode;
|
|
4
4
|
description?: React.ReactNode;
|
|
5
|
-
variant?: "default" | "elevated" | "gradient";
|
|
5
|
+
variant?: "default" | "subtle" | "elevated" | "gradient";
|
|
6
6
|
size?: "default" | "compact";
|
|
7
7
|
/** Large value displayed above the title — use for stat/metric cards. */
|
|
8
8
|
stat?: React.ReactNode;
|
package/dist/card.js
CHANGED
|
@@ -106,7 +106,7 @@ const Card = React.forwardRef(({ title, description, variant = "default", size =
|
|
|
106
106
|
};
|
|
107
107
|
const renderedTitle = React.isValidElement(title) ? (title) : (_jsx(Typography, { as: "p", variant: hasStat ? "caption" : "body", color: variant === "gradient" ? "inherit" : hasStat ? "muted" : "foreground", className: cn(hasStat && "font-medium", !hasStat && "font-semibold", variant === "gradient" && "opacity-80"), children: title }));
|
|
108
108
|
const renderedDescription = description == null ? null : React.isValidElement(description) ? (description) : (_jsx(Typography, { as: "p", variant: "caption", color: variant === "gradient" ? "inherit" : undefined, className: variant === "gradient" ? "opacity-70" : undefined, children: description }));
|
|
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" : props["aria-label"] || props["aria-labelledby"] ? "region" : 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" &&
|
|
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" : props["aria-label"] || props["aria-labelledby"] ? "region" : 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 === "subtle" && "bg-muted/40", 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
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 &&
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export interface CompoundSearchInputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, "size"> {
|
|
3
|
+
actions?: React.ReactNode;
|
|
4
|
+
criteria?: React.ReactNode;
|
|
5
|
+
selected?: boolean;
|
|
6
|
+
}
|
|
7
|
+
declare const CompoundSearchInput: React.ForwardRefExoticComponent<CompoundSearchInputProps & React.RefAttributes<HTMLInputElement>>;
|
|
8
|
+
export { CompoundSearchInput };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { SearchIcon } from "lucide-react";
|
|
4
|
+
import { cn } from "./lib/utils";
|
|
5
|
+
const CompoundSearchInput = React.forwardRef(({ actions, "aria-invalid": ariaInvalid, className, criteria, selected = false, ...props }, ref) => (_jsxs("div", { "data-slot": "compound-search-input", "data-selected": selected ? "true" : "false", className: cn("flex min-h-12 w-full min-w-0 flex-wrap items-center gap-1.5 rounded-control border border-input bg-background p-1.5 transition-[border-color,box-shadow] focus-within:border-ring focus-within:ring-[3px] focus-within:ring-ring/50 data-[selected=true]:border-interactive data-[selected=true]:bg-highlight data-[selected=true]:ring-[3px] data-[selected=true]:ring-interactive/20", ariaInvalid === true || ariaInvalid === "true"
|
|
6
|
+
? "border-destructive ring-destructive/20"
|
|
7
|
+
: undefined), children: [_jsx(SearchIcon, { "aria-hidden": "true", className: "ml-1.5 h-4 w-4 shrink-0 text-muted-foreground" }), criteria, _jsx("input", { ref: ref, "aria-invalid": ariaInvalid, className: cn("h-8 min-w-44 basis-52 flex-1 bg-transparent px-1.5 text-sm outline-none placeholder:text-muted-foreground", className), ...props }), actions ? (_jsx("span", { className: "ml-auto inline-flex h-8 shrink-0 items-center gap-1 text-muted-foreground", children: actions })) : null] })));
|
|
8
|
+
CompoundSearchInput.displayName = "CompoundSearchInput";
|
|
9
|
+
export { CompoundSearchInput };
|