@neasg/design-system 0.4.35 → 0.4.113
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/activity-card.d.ts +31 -0
- package/dist/activity-card.js +65 -0
- package/dist/alert.d.ts +1 -1
- 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.d.ts +1 -1
- package/dist/badge.js +1 -1
- package/dist/button.d.ts +2 -2
- package/dist/button.js +3 -1
- package/dist/calendar.js +1 -1
- package/dist/card.d.ts +1 -1
- package/dist/card.js +1 -1
- package/dist/changelog-action-panel.d.ts +17 -0
- package/dist/changelog-action-panel.js +14 -0
- package/dist/checklist.d.ts +63 -0
- package/dist/checklist.js +30 -0
- package/dist/compound-search-input.d.ts +10 -0
- package/dist/compound-search-input.js +19 -0
- package/dist/date-input.js +3 -3
- package/dist/dialog.d.ts +4 -1
- package/dist/dialog.js +7 -2
- package/dist/draggable-tabs.js +9 -8
- package/dist/dropdown-button.js +1 -0
- package/dist/editable-table.js +2 -2
- package/dist/field-counter.d.ts +7 -0
- package/dist/field-counter.js +5 -0
- package/dist/index.d.ts +22 -4
- package/dist/index.js +12 -2
- package/dist/input.d.ts +2 -0
- package/dist/input.js +11 -3
- 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-action-panel.d.ts +12 -0
- package/dist/message-action-panel.js +11 -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 +36 -7
- package/dist/page-section.d.ts +2 -1
- package/dist/page-section.js +2 -2
- package/dist/popover-menu.d.ts +4 -2
- package/dist/popover-menu.js +65 -5
- package/dist/popover.d.ts +10 -2
- package/dist/popover.js +7 -3
- package/dist/rich-text-editor.d.ts +2 -1
- package/dist/rich-text-editor.js +29 -6
- package/dist/routing-action-panel.d.ts +38 -0
- package/dist/routing-action-panel.js +19 -0
- package/dist/routing-timeline.d.ts +7 -2
- package/dist/routing-timeline.js +67 -29
- package/dist/search-input.d.ts +6 -0
- package/dist/search-input.js +6 -4
- 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-add-row.d.ts +8 -0
- package/dist/table-add-row.js +7 -0
- 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/tailwind-preset.js +10 -0
- package/dist/textarea.d.ts +5 -0
- package/dist/textarea.js +18 -3
- package/dist/theme-switcher.d.ts +3 -1
- package/dist/theme-switcher.js +8 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -331,3 +331,12 @@ GitHub Actions builds Storybook with `npm run build-storybook` to verify that
|
|
|
331
331
|
the stories compile. The Chromatic publishing step is temporarily commented
|
|
332
332
|
out in `.github/workflows/ci.yml` and can be uncommented when snapshot
|
|
333
333
|
publishing is needed again.
|
|
334
|
+
|
|
335
|
+
### Text length counters
|
|
336
|
+
|
|
337
|
+
Use `showCount` with `maxLength` on `Input`, `SearchInput`, `CompoundSearchInput`, or `Textarea` for a character counter. Use `maxWords` on `Textarea` for a word counter; it takes precedence if both limits are supplied. Counters appear below the field, aligned right, as `count / limit`. The unit is available to screen readers without repeating a visible maximum-length hint. Native character limits remain enforced; word limits report validation errors without truncating text.
|
|
338
|
+
|
|
339
|
+
```tsx
|
|
340
|
+
const [reference, setReference] = React.useState("");
|
|
341
|
+
<Input label="Reference" value={reference} onChange={(event) => setReference(event.target.value)} maxLength={50} showCount />
|
|
342
|
+
```
|
|
@@ -0,0 +1,31 @@
|
|
|
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
|
+
/** Optional supporting content rendered inside the card header. */
|
|
13
|
+
headerContent?: React.ReactNode;
|
|
14
|
+
trailing?: React.ReactNode;
|
|
15
|
+
href?: string;
|
|
16
|
+
type?: "button" | "submit" | "reset";
|
|
17
|
+
"data-slot"?: string;
|
|
18
|
+
}
|
|
19
|
+
export interface ActivityCardContentProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
20
|
+
density?: ActivityCardDensity;
|
|
21
|
+
}
|
|
22
|
+
export interface ActivityCardActorProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "children"> {
|
|
23
|
+
actor: React.ReactNode;
|
|
24
|
+
label?: React.ReactNode;
|
|
25
|
+
avatarSrc?: string | null;
|
|
26
|
+
avatarFallback?: React.ReactNode;
|
|
27
|
+
}
|
|
28
|
+
declare const ActivityCard: React.ForwardRefExoticComponent<ActivityCardProps & React.RefAttributes<HTMLElement>>;
|
|
29
|
+
declare const ActivityCardContent: React.ForwardRefExoticComponent<ActivityCardContentProps & React.RefAttributes<HTMLDivElement>>;
|
|
30
|
+
declare const ActivityCardActor: React.ForwardRefExoticComponent<ActivityCardActorProps & React.RefAttributes<HTMLDivElement>>;
|
|
31
|
+
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, headerContent, 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, headerContent ? (_jsx("div", { "data-slot": "activity-card-header-content", className: "mt-[var(--space-2)]", children: headerContent })) : 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 };
|
package/dist/alert.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { type VariantProps } from "class-variance-authority";
|
|
|
3
3
|
import { type ButtonProps } from "./button";
|
|
4
4
|
import { type CheckboxProps } from "./checkbox";
|
|
5
5
|
declare const alertVariants: (props?: ({
|
|
6
|
-
variant?: "
|
|
6
|
+
variant?: "warning" | "destructive" | "info" | "success" | null | undefined;
|
|
7
7
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
8
8
|
export interface AlertProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "title">, VariantProps<typeof alertVariants> {
|
|
9
9
|
title?: React.ReactNode;
|
|
@@ -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.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { type VariantProps } from "class-variance-authority";
|
|
3
3
|
declare const badgeVariants: (props?: ({
|
|
4
|
-
variant?: "accent" | "muted" | "destructive" | "outline" | "secondary" | "info" | "success" |
|
|
4
|
+
variant?: "accent" | "muted" | "warning" | "destructive" | "outline" | "secondary" | "info" | "success" | null | undefined;
|
|
5
5
|
size?: "default" | "icon" | null | undefined;
|
|
6
6
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
7
7
|
/**
|
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
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { type VariantProps } from "class-variance-authority";
|
|
3
3
|
declare const buttonVariants: (props?: ({
|
|
4
|
-
variant?: "link" | "default" | "destructive" | "outline" | "secondary" | "ghost" | null | undefined;
|
|
5
|
-
size?: "default" | "sm" | "compact" | "icon" | "compactIcon" | null | undefined;
|
|
4
|
+
variant?: "link" | "default" | "warning" | "destructive" | "outline" | "secondary" | "ghost" | 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
|
@@ -7,6 +7,7 @@ const buttonVariants = cva("inline-flex cursor-pointer items-center justify-cent
|
|
|
7
7
|
variants: {
|
|
8
8
|
variant: {
|
|
9
9
|
default: "bg-button-primary text-button-primary-foreground hover:bg-button-primary-hover",
|
|
10
|
+
warning: "border border-[hsl(var(--status-warning-foreground))]/30 bg-[hsl(var(--status-warning))] text-[hsl(var(--status-warning-foreground))] hover:bg-[hsl(var(--status-warning))]/80 focus-visible:ring-[hsl(var(--status-warning-foreground))]",
|
|
10
11
|
destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
|
|
11
12
|
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
13
|
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
@@ -16,6 +17,7 @@ const buttonVariants = cva("inline-flex cursor-pointer items-center justify-cent
|
|
|
16
17
|
size: {
|
|
17
18
|
sm: "h-8 px-2.5 text-sm",
|
|
18
19
|
compact: "h-8 gap-1 px-2 text-sm",
|
|
20
|
+
comfortable: "h-[46px] px-[12px] py-[11px] text-[16px] [&_svg]:h-[24px] [&_svg]:min-h-[24px] [&_svg]:w-[24px] [&_svg]:min-w-[24px]",
|
|
19
21
|
default: "h-control px-3 py-1.5",
|
|
20
22
|
icon: "h-control w-control",
|
|
21
23
|
compactIcon: "h-8 w-8",
|
|
@@ -145,7 +147,7 @@ const Button = React.forwardRef(({ className, variant, size, asChild = false, lo
|
|
|
145
147
|
stopAnimatedIcons();
|
|
146
148
|
onBlur === null || onBlur === void 0 ? void 0 : onBlur(event);
|
|
147
149
|
};
|
|
148
|
-
return (_jsx(Comp, { className: cn(buttonVariants({ variant, size, className })), ref: ref, "aria-busy": loading || undefined, "aria-disabled": isDisabled || undefined, "data-loading": loading ? "" : undefined, "data-disabled": isDisabled ? "" : undefined, onClick: handleClick, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, onFocus: handleFocus, onBlur: handleBlur, tabIndex: isDisabled && asChild ? -1 : tabIndex, disabled: !asChild ? isDisabled : undefined, ...props, children: content }));
|
|
150
|
+
return (_jsx(Comp, { "data-slot": "button", className: cn(buttonVariants({ variant, size, className })), ref: ref, "aria-busy": loading || undefined, "aria-disabled": isDisabled || undefined, "data-loading": loading ? "" : undefined, "data-disabled": isDisabled ? "" : undefined, onClick: handleClick, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, onFocus: handleFocus, onBlur: handleBlur, tabIndex: isDisabled && asChild ? -1 : tabIndex, disabled: !asChild ? isDisabled : undefined, ...props, children: content }));
|
|
149
151
|
});
|
|
150
152
|
Button.displayName = "Button";
|
|
151
153
|
export { Button, buttonVariants };
|
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),
|