@neasg/design-system 0.4.21 → 0.4.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -0
- package/dist/badge.js +1 -1
- package/dist/button.js +2 -2
- package/dist/calendar.js +4 -4
- package/dist/card.js +2 -1
- package/dist/command-search.js +1 -1
- package/dist/count-badge.js +2 -2
- package/dist/date-input.js +1 -1
- package/dist/dropdown-button.js +2 -2
- package/dist/file-upload.js +1 -1
- package/dist/filter-popover.js +4 -2
- package/dist/filter-toggle.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/input-control.d.ts +1 -1
- package/dist/input-control.js +1 -1
- package/dist/link.js +2 -2
- package/dist/message-item.js +2 -2
- package/dist/multi-select.js +22 -34
- package/dist/page-header.d.ts +3 -1
- package/dist/page-header.js +2 -2
- package/dist/pagination.d.ts +7 -1
- package/dist/pagination.js +4 -3
- package/dist/popover-focus.d.ts +14 -0
- package/dist/popover-focus.js +64 -0
- package/dist/popover-menu.js +29 -7
- package/dist/popover.d.ts +4 -1
- package/dist/popover.js +31 -3
- package/dist/rich-text-editor.js +1 -1
- package/dist/select-primitive.js +1 -1
- package/dist/select.js +28 -11
- package/dist/spinner.js +1 -1
- package/dist/styles.css +18 -0
- package/dist/table.d.ts +17 -5
- package/dist/table.js +136 -86
- package/dist/tailwind-preset.js +15 -0
- package/dist/theme.d.ts +45 -0
- package/dist/theme.js +36 -0
- package/dist/toaster.js +1 -1
- package/dist/typography.js +3 -3
- package/dist/use-search-highlight.js +1 -1
- package/package.json +1 -1
package/dist/popover-menu.js
CHANGED
|
@@ -21,13 +21,13 @@ function PopoverMenuSection({ className, children, ...props }) {
|
|
|
21
21
|
return (_jsx("div", { className: cn("space-y-0", className), ...props, children: children }));
|
|
22
22
|
}
|
|
23
23
|
function PopoverMenuItem({ className, children, active, type = "button", ...props }) {
|
|
24
|
-
return (_jsxs(Button, { type: type, variant: "ghost", "data-slot": "popover-menu-item", className: cn("h-auto min-h-8 w-full justify-start gap-2 px-2 py-2 text-left font-normal whitespace-normal", popoverMenuItemFocusClassName, active &&
|
|
25
|
-
"bg-
|
|
24
|
+
return (_jsxs(Button, { type: type, variant: "ghost", "data-slot": "popover-menu-item", className: cn("h-auto min-h-8 w-full justify-start gap-2 px-2 py-2 text-left font-normal whitespace-normal aria-[selected=true]:bg-highlight aria-[selected=true]:text-highlight-foreground aria-[selected=true]:[--muted-foreground:var(--instructional-foreground)] aria-[selected=true]:hover:bg-highlight/80 aria-[selected=true]:hover:text-highlight-foreground aria-[selected=true]:focus-visible:bg-highlight/80 aria-[selected=true]:focus-visible:text-highlight-foreground", popoverMenuItemFocusClassName, active &&
|
|
25
|
+
"bg-highlight text-highlight-foreground [--muted-foreground:var(--instructional-foreground)] hover:bg-highlight/80 hover:text-highlight-foreground focus-visible:bg-highlight/80 focus-visible:text-highlight-foreground", className), ...props, children: [children, active ? _jsx(Check, { "aria-hidden": "true", className: "ml-auto h-4 w-4 shrink-0" }) : null] }));
|
|
26
26
|
}
|
|
27
27
|
function PopoverMenuCheckboxItem({ className, children, checked = false, description, disabled, onChange, readOnly, ...props }) {
|
|
28
28
|
return (_jsxs("label", { className: cn("flex h-auto min-h-8 w-full cursor-pointer items-start gap-1.5 rounded-sm px-2 py-2 text-left text-popover-foreground outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus-within:bg-accent focus-within:text-accent-foreground", popoverMenuItemFocusWithinClassName, checked &&
|
|
29
|
-
"bg-
|
|
30
|
-
"cursor-not-allowed opacity-50 hover:bg-transparent hover:text-inherit", className), children: [_jsx(Checkbox, { ...props, checked: checked, disabled: disabled, readOnly: readOnly !== null && readOnly !== void 0 ? readOnly : !onChange, onChange: onChange, className: "mt-0.5" }), _jsxs("span", { className: "min-w-0 flex-1", children: [_jsx(Typography, { as: "span", variant: "bodySm", className: "block", children: children }), description ? (_jsx(Typography, { as: "span", variant: "caption", className: "mt-0.5 block", children: description })) : null] })] }));
|
|
29
|
+
"bg-highlight text-highlight-foreground hover:bg-highlight/80 hover:text-highlight-foreground focus-within:bg-highlight/80 focus-within:text-highlight-foreground", disabled &&
|
|
30
|
+
"cursor-not-allowed opacity-50 hover:bg-transparent hover:text-inherit", className), children: [_jsx(Checkbox, { ...props, "data-slot": "popover-menu-item", checked: checked, disabled: disabled, readOnly: readOnly !== null && readOnly !== void 0 ? readOnly : !onChange, onChange: onChange, className: "mt-0.5" }), _jsxs("span", { className: "min-w-0 flex-1", children: [_jsx(Typography, { as: "span", variant: "bodySm", className: "block", children: children }), description ? (_jsx(Typography, { as: "span", variant: "caption", className: "mt-0.5 block", children: description })) : null] })] }));
|
|
31
31
|
}
|
|
32
32
|
function PopoverMenuDivider({ className, ...props }) {
|
|
33
33
|
return _jsx("div", { className: cn("-mx-1 my-1 h-px bg-border", className), ...props });
|
|
@@ -49,7 +49,7 @@ function PopoverMenuGroupLabel({ className, children, ...props }) {
|
|
|
49
49
|
}
|
|
50
50
|
const PopoverMenuSearch = React.forwardRef(({ "aria-label": ariaLabel, className, containerClassName, label, placeholder, ...props }, ref) => {
|
|
51
51
|
var _a, _b;
|
|
52
|
-
return (_jsx("div", { className: cn("relative -mx-1 -mt-1 mb-1 px-
|
|
52
|
+
return (_jsx("div", { className: cn("relative -mx-1 -mt-1 mb-1 px-1 py-1 after:absolute after:inset-x-0 after:bottom-0 after:h-px after:bg-border after:content-['']", containerClassName), children: _jsx(Input, { ref: ref, "data-popover-menu-search": "true", label: (_b = (_a = label !== null && label !== void 0 ? label : ariaLabel) !== null && _a !== void 0 ? _a : placeholder) !== null && _b !== void 0 ? _b : "Search", hideLabel: true, className: "gap-0", inputClassName: className, "aria-label": ariaLabel, placeholder: placeholder, ...props }) }));
|
|
53
53
|
});
|
|
54
54
|
PopoverMenuSearch.displayName = "PopoverMenuSearch";
|
|
55
55
|
function PopoverMenuScrollArea({ className, children, maxHeight = "max-h-64", ...props }) {
|
|
@@ -62,6 +62,8 @@ function PopoverMenuView({ children, className, direction = "forward", viewKey =
|
|
|
62
62
|
key: viewKey,
|
|
63
63
|
children,
|
|
64
64
|
});
|
|
65
|
+
const activeViewElementRef = React.useRef(null);
|
|
66
|
+
const previousViewKeyRef = React.useRef(viewKey);
|
|
65
67
|
const exitTimeoutRef = React.useRef(null);
|
|
66
68
|
if (Object.is(viewKey, activeViewKey)) {
|
|
67
69
|
activeViewRef.current = { key: viewKey, children };
|
|
@@ -99,12 +101,32 @@ function PopoverMenuView({ children, className, direction = "forward", viewKey =
|
|
|
99
101
|
}
|
|
100
102
|
};
|
|
101
103
|
}, [direction, viewKey]);
|
|
104
|
+
useIsomorphicLayoutEffect(() => {
|
|
105
|
+
var _a;
|
|
106
|
+
if (Object.is(previousViewKeyRef.current, viewKey)) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
previousViewKeyRef.current = viewKey;
|
|
110
|
+
const firstControl = (_a = activeViewElementRef.current) === null || _a === void 0 ? void 0 : _a.querySelector('button:not(:disabled), input:not(:disabled):not([type="hidden"]), select:not(:disabled), textarea:not(:disabled), [tabindex]:not([tabindex="-1"])');
|
|
111
|
+
firstControl === null || firstControl === void 0 ? void 0 : firstControl.focus({ preventScroll: true });
|
|
112
|
+
}, [viewKey]);
|
|
102
113
|
const activeDirection = exitingView === null || exitingView === void 0 ? void 0 : exitingView.direction;
|
|
103
114
|
const shouldAnimateActive = Boolean(activeDirection);
|
|
104
|
-
|
|
115
|
+
const setExitingViewElement = React.useCallback((element) => {
|
|
116
|
+
if (!element) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
element.inert = true;
|
|
120
|
+
element
|
|
121
|
+
.querySelectorAll('a[href], button, input, select, textarea, [contenteditable="true"], [tabindex]')
|
|
122
|
+
.forEach((control) => {
|
|
123
|
+
control.tabIndex = -1;
|
|
124
|
+
});
|
|
125
|
+
}, []);
|
|
126
|
+
return (_jsxs("div", { className: cn("grid min-w-0 overflow-hidden", className), ...props, children: [exitingView ? (_jsx("div", { ref: setExitingViewElement, "aria-hidden": "true", inert: "", "data-popover-menu-view": "exiting", className: cn("pointer-events-none col-start-1 row-start-1 min-w-0", exitingView.direction !== "none" &&
|
|
105
127
|
"motion-safe:animate-out motion-safe:fade-out-0 motion-safe:duration-300 motion-reduce:animate-none", exitingView.direction === "forward" &&
|
|
106
128
|
"motion-safe:slide-out-to-left-full", exitingView.direction === "backward" &&
|
|
107
|
-
"motion-safe:slide-out-to-right-full"), children: exitingView.children }, `leaving-${exitingView.key}`)) : null, _jsx("div", { className: cn("col-start-1 row-start-1 min-w-0", shouldAnimateActive &&
|
|
129
|
+
"motion-safe:slide-out-to-right-full"), children: exitingView.children }, `leaving-${exitingView.key}`)) : null, _jsx("div", { ref: activeViewElementRef, "data-popover-menu-view": "active", className: cn("col-start-1 row-start-1 min-w-0", shouldAnimateActive &&
|
|
108
130
|
"motion-safe:animate-in motion-safe:fade-in-0 motion-safe:duration-300 motion-reduce:animate-none", activeDirection === "forward" &&
|
|
109
131
|
"motion-safe:slide-in-from-right-full", activeDirection === "backward" &&
|
|
110
132
|
"motion-safe:slide-in-from-left-full"), children: children }, viewKey)] }));
|
package/dist/popover.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import * as PopoverPrimitive from "@radix-ui/react-popover";
|
|
3
|
+
import { type PopoverTabBehavior } from "./popover-focus";
|
|
3
4
|
import { type TooltipProps } from "./tooltip";
|
|
4
5
|
import { Typography } from "./typography";
|
|
5
6
|
type PopoverRootProps = React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Root>;
|
|
@@ -10,13 +11,15 @@ export interface PopoverProps extends Pick<PopoverRootProps, "defaultOpen" | "mo
|
|
|
10
11
|
/** Visible popover heading. Also labels the popover for assistive technology. */
|
|
11
12
|
title?: React.ReactNode;
|
|
12
13
|
surface?: "panel" | "menu";
|
|
14
|
+
/** Controls whether Tab stays within the popover or closes it and continues in the page Tab order. */
|
|
15
|
+
tabBehavior?: PopoverTabBehavior;
|
|
13
16
|
contentClassName?: string;
|
|
14
17
|
triggerTooltip?: React.ReactNode;
|
|
15
18
|
triggerTooltipSide?: TooltipProps["side"];
|
|
16
19
|
triggerTooltipSideOffset?: TooltipProps["sideOffset"];
|
|
17
20
|
triggerTooltipClassName?: TooltipProps["contentClassName"];
|
|
18
21
|
}
|
|
19
|
-
declare function Popover({ defaultOpen, modal, onOpenChange, open, trigger, children, title, surface, contentClassName, triggerTooltip, triggerTooltipSide, triggerTooltipSideOffset, triggerTooltipClassName, align, sideOffset, ...contentProps }: PopoverProps): import("react/jsx-runtime").JSX.Element;
|
|
22
|
+
declare function Popover({ defaultOpen, modal, onOpenChange, open, trigger, children, title, surface, tabBehavior, contentClassName, triggerTooltip, triggerTooltipSide, triggerTooltipSideOffset, triggerTooltipClassName, align, sideOffset, ...contentProps }: PopoverProps): import("react/jsx-runtime").JSX.Element;
|
|
20
23
|
export interface PopoverTitleProps extends Omit<React.ComponentPropsWithoutRef<typeof Typography>, "as" | "asChild" | "variant" | "color"> {
|
|
21
24
|
}
|
|
22
25
|
declare function PopoverTitle({ className, children, ...props }: PopoverTitleProps): import("react/jsx-runtime").JSX.Element;
|
package/dist/popover.js
CHANGED
|
@@ -3,13 +3,33 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import { cn } from "./lib/utils";
|
|
5
5
|
import { PopoverContent, PopoverRoot, PopoverTrigger, } from "./popover-primitive";
|
|
6
|
+
import { usePopoverTabExit, } from "./popover-focus";
|
|
6
7
|
import { Tooltip } from "./tooltip";
|
|
7
8
|
import { Typography } from "./typography";
|
|
8
|
-
function Popover({ defaultOpen, modal, onOpenChange, open, trigger, children, title, surface = "panel", contentClassName, triggerTooltip, triggerTooltipSide, triggerTooltipSideOffset, triggerTooltipClassName, align = "center", sideOffset = 4, ...contentProps }) {
|
|
9
|
+
function Popover({ defaultOpen, modal, onOpenChange, open, trigger, children, title, surface = "panel", tabBehavior = "contain", contentClassName, triggerTooltip, triggerTooltipSide, triggerTooltipSideOffset, triggerTooltipClassName, align = "center", sideOffset = 4, ...contentProps }) {
|
|
9
10
|
const generatedTitleId = React.useId();
|
|
10
11
|
const titleId = title ? `popover-title-${generatedTitleId}` : undefined;
|
|
11
|
-
const
|
|
12
|
+
const [internalOpen, setInternalOpen] = React.useState(defaultOpen !== null && defaultOpen !== void 0 ? defaultOpen : false);
|
|
13
|
+
const isControlled = open !== undefined;
|
|
14
|
+
const currentOpen = isControlled ? open : internalOpen;
|
|
15
|
+
const triggerRef = React.useRef(null);
|
|
16
|
+
const contentRef = React.useRef(null);
|
|
17
|
+
const setOpen = React.useCallback((nextOpen) => {
|
|
18
|
+
if (!isControlled) {
|
|
19
|
+
setInternalOpen(nextOpen);
|
|
20
|
+
}
|
|
21
|
+
onOpenChange === null || onOpenChange === void 0 ? void 0 : onOpenChange(nextOpen);
|
|
22
|
+
}, [isControlled, onOpenChange]);
|
|
23
|
+
const { handleCloseAutoFocus, handleTabKeyDown } = usePopoverTabExit({
|
|
24
|
+
behavior: tabBehavior,
|
|
25
|
+
triggerRef,
|
|
26
|
+
contentRef,
|
|
27
|
+
onExit: () => setOpen(false),
|
|
28
|
+
});
|
|
29
|
+
const triggerElement = (_jsx(PopoverTrigger, { ref: triggerRef, asChild: true, children: trigger }));
|
|
12
30
|
const contentOnKeyDown = contentProps.onKeyDown;
|
|
31
|
+
const contentOnKeyDownCapture = contentProps.onKeyDownCapture;
|
|
32
|
+
const contentOnCloseAutoFocus = contentProps.onCloseAutoFocus;
|
|
13
33
|
const handleContentKeyDown = React.useCallback((event) => {
|
|
14
34
|
contentOnKeyDown === null || contentOnKeyDown === void 0 ? void 0 : contentOnKeyDown(event);
|
|
15
35
|
if (event.defaultPrevented ||
|
|
@@ -51,7 +71,15 @@ function Popover({ defaultOpen, modal, onOpenChange, open, trigger, children, ti
|
|
|
51
71
|
event.preventDefault();
|
|
52
72
|
focusTarget.focus({ preventScroll: true });
|
|
53
73
|
}, [contentOnKeyDown]);
|
|
54
|
-
|
|
74
|
+
const handleContentKeyDownCapture = React.useCallback((event) => {
|
|
75
|
+
contentOnKeyDownCapture === null || contentOnKeyDownCapture === void 0 ? void 0 : contentOnKeyDownCapture(event);
|
|
76
|
+
handleTabKeyDown(event);
|
|
77
|
+
}, [contentOnKeyDownCapture, handleTabKeyDown]);
|
|
78
|
+
const handleContentCloseAutoFocus = React.useCallback((event) => {
|
|
79
|
+
contentOnCloseAutoFocus === null || contentOnCloseAutoFocus === void 0 ? void 0 : contentOnCloseAutoFocus(event);
|
|
80
|
+
handleCloseAutoFocus(event);
|
|
81
|
+
}, [contentOnCloseAutoFocus, handleCloseAutoFocus]);
|
|
82
|
+
return (_jsxs(PopoverRoot, { modal: modal, onOpenChange: setOpen, open: currentOpen, children: [triggerTooltip ? (_jsx(Tooltip, { content: triggerTooltip, side: triggerTooltipSide, sideOffset: triggerTooltipSideOffset, contentClassName: triggerTooltipClassName, children: triggerElement })) : (triggerElement), _jsxs(PopoverContent, { ref: contentRef, align: align, sideOffset: sideOffset, "aria-labelledby": titleId !== null && titleId !== void 0 ? titleId : contentProps["aria-labelledby"], className: cn(surface === "menu" && "overflow-hidden p-1", contentClassName), ...contentProps, onCloseAutoFocus: handleContentCloseAutoFocus, onKeyDown: handleContentKeyDown, onKeyDownCapture: handleContentKeyDownCapture, children: [title ? (_jsx(PopoverTitle, { id: titleId, className: cn(surface === "menu"
|
|
55
83
|
? "px-2 py-1.5"
|
|
56
84
|
: "-mx-4 -mt-4 mb-4 border-b px-4 py-3"), children: title })) : null, children] })] }));
|
|
57
85
|
}
|
package/dist/rich-text-editor.js
CHANGED
|
@@ -390,5 +390,5 @@ export function RichTextEditor({ placeholder = "Type message here...", editorAri
|
|
|
390
390
|
}, children: color.value === "" && (_jsx("span", { className: "text-xs text-muted-foreground", children: "A" })) }, `bg-${color.name}`))) }) }), _jsx(ToolbarIconButton, { label: "Bullet list", active: editor === null || editor === void 0 ? void 0 : editor.isActive("bulletList"), onClick: () => editor === null || editor === void 0 ? void 0 : editor.chain().focus().toggleBulletList().run(), children: _jsx(ListIcon, { size: 14 }) }), _jsx(ToolbarIconButton, { label: "Ordered list", active: editor === null || editor === void 0 ? void 0 : editor.isActive("orderedList"), onClick: () => editor === null || editor === void 0 ? void 0 : editor.chain().focus().toggleOrderedList().run(), children: _jsx(ListOrderedIcon, { size: 14 }) }), _jsx(Tooltip, { content: `Attach files (max ${maxFileSizeLabel}) - ${acceptedFileTypesLabel}`, side: "top", contentClassName: "max-w-[240px] text-center", children: _jsx(Button, { type: "button", variant: "ghost", size: "icon", className: "h-8 w-8", onClick: () => { var _a; return (_a = fileInputRef.current) === null || _a === void 0 ? void 0 : _a.click(); }, "aria-label": "Attach files", children: _jsx(PaperclipIcon, { size: 14 }) }) }), _jsx(ToolbarIconButton, { label: "Add link", active: editor === null || editor === void 0 ? void 0 : editor.isActive("link"), onClick: openLinkMenu, children: _jsx(LinkIcon, { size: 14 }) }), showTemplates && templates.length > 0 && (_jsx(_Fragment, { children: _jsxs(Popover, { open: templatePopoverOpen, onOpenChange: setTemplatePopoverOpen, align: "end", contentClassName: "w-96 p-0", trigger: _jsxs(Button, { type: "button", variant: "ghost", className: "h-8 gap-1 text-muted-foreground", children: ["Template", _jsx(ChevronDownIcon, { size: 14 })] }), children: [_jsx("div", { className: "max-h-80 overflow-y-auto", children: templatesByCategory.map(({ category, templates }) => {
|
|
391
391
|
var _a;
|
|
392
392
|
return (_jsxs("div", { children: [_jsx("div", { className: "sticky top-0 bg-muted px-3 py-2 text-sm font-semibold text-foreground", children: (_a = templateCategoryLabels[category]) !== null && _a !== void 0 ? _a : category }), templates.map((template) => (_jsxs("button", { type: "button", className: "w-full border-b border-border/50 px-3 py-2 text-left text-sm transition-colors last:border-0 hover:bg-muted", onClick: () => applyTemplate(template), children: [_jsx("div", { className: "truncate font-medium", children: template.name }), template.description && (_jsx("div", { className: "mt-0.5 truncate text-xs text-muted-foreground", children: template.description }))] }, template.id)))] }, category));
|
|
393
|
-
}) }), templateCreateHref && (_jsx("div", { className: "border-t p-2", children: _jsxs("a", { href: templateCreateHref, target: "_blank", rel: "noopener noreferrer", className: "flex w-full items-center justify-center gap-1.5 rounded-md px-3 py-2 text-sm text-
|
|
393
|
+
}) }), templateCreateHref && (_jsx("div", { className: "border-t p-2", children: _jsxs("a", { href: templateCreateHref, target: "_blank", rel: "noopener noreferrer", className: "flex w-full items-center justify-center gap-1.5 rounded-md px-3 py-2 text-sm text-interactive transition-colors hover:bg-muted", children: [_jsx(PlusIcon, { size: 16 }), templateCreateLabel] }) }))] }) }))] }) }), _jsx("div", { className: "bg-muted px-3 pb-2 pt-1 dark:bg-background", children: sendAction })] }));
|
|
394
394
|
}
|
package/dist/select-primitive.js
CHANGED
|
@@ -27,7 +27,7 @@ const SelectContent = React.forwardRef(({ className, children, header, position
|
|
|
27
27
|
SelectContent.displayName = SelectPrimitive.Content.displayName;
|
|
28
28
|
const SelectLabel = React.forwardRef(({ className, ...props }, ref) => (_jsx(SelectPrimitive.Label, { ref: ref, "data-slot": "select-label", className: cn("px-2 py-1.5 text-xs text-muted-foreground", className), ...props })));
|
|
29
29
|
SelectLabel.displayName = SelectPrimitive.Label.displayName;
|
|
30
|
-
const SelectItem = React.forwardRef(({ className, children, description, ...props }, ref) => (_jsxs(SelectPrimitive.Item, { ref: ref, "data-slot": "select-item", className: cn("relative flex min-h-8 w-full cursor-pointer select-none items-center gap-1.5 rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground data-[state=checked]:bg-
|
|
30
|
+
const SelectItem = React.forwardRef(({ className, children, description, ...props }, ref) => (_jsxs(SelectPrimitive.Item, { ref: ref, "data-slot": "select-item", className: cn("relative flex min-h-8 w-full cursor-pointer select-none items-center gap-1.5 rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground data-[state=checked]:bg-highlight data-[state=checked]:text-highlight-foreground data-[state=checked]:hover:bg-highlight/80 data-[state=checked]:hover:text-highlight-foreground data-[state=checked]:focus:bg-highlight/80 data-[state=checked]:focus:text-highlight-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50", className), ...props, children: [_jsx("span", { "data-slot": "select-item-indicator", className: "absolute right-2 flex h-3.5 w-3.5 items-center justify-center", children: _jsx(SelectPrimitive.ItemIndicator, { children: _jsx(Check, { className: "h-4 w-4" }) }) }), _jsxs("div", { className: "flex flex-col gap-0.5", children: [_jsx(SelectPrimitive.ItemText, { className: "break-words font-normal", children: children }), description ? (_jsx(Typography, { as: "span", variant: "caption", children: description })) : null] })] })));
|
|
31
31
|
SelectItem.displayName = SelectPrimitive.Item.displayName;
|
|
32
32
|
const SelectSeparator = React.forwardRef(({ className, ...props }, ref) => (_jsx(SelectPrimitive.Separator, { ref: ref, "data-slot": "select-separator", className: cn("-mx-1 my-1 h-px bg-border", className), ...props })));
|
|
33
33
|
SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
|
package/dist/select.js
CHANGED
|
@@ -4,6 +4,7 @@ import * as React from "react";
|
|
|
4
4
|
import { Field, FieldDescription, FieldError, FieldLabel } from "./field";
|
|
5
5
|
import { InputControl } from "./input-control";
|
|
6
6
|
import { cn } from "./lib/utils";
|
|
7
|
+
import { usePopoverTabExit } from "./popover-focus";
|
|
7
8
|
import { SearchHighlight } from "./use-search-highlight";
|
|
8
9
|
import { SelectContent, SelectGroup, SelectItem, SelectLabel, SelectRoot, SelectSeparator, SelectTrigger, SelectValue, } from "./select-primitive";
|
|
9
10
|
function groupOptions(options) {
|
|
@@ -42,6 +43,7 @@ function renderHighlightedLabel(label, query) {
|
|
|
42
43
|
function Select({ label, options, placeholder = "Select an option", description, error, invalid = false, hideLabel = false, searchable = false, searchPlaceholder = "Search options...", searchEmptyMessage = "No options found.", searchInputAriaLabel = "Search options", className, triggerClassName, contentClassName, labelClassName, descriptionClassName, errorClassName, id, disabled, open, onOpenChange, ...props }) {
|
|
43
44
|
const generatedId = React.useId();
|
|
44
45
|
const selectId = id !== null && id !== void 0 ? id : `select-${generatedId}`;
|
|
46
|
+
const triggerRef = React.useRef(null);
|
|
45
47
|
const searchInputRef = React.useRef(null);
|
|
46
48
|
const contentRef = React.useRef(null);
|
|
47
49
|
const [uncontrolledOpen, setUncontrolledOpen] = React.useState(false);
|
|
@@ -63,6 +65,22 @@ function Select({ label, options, placeholder = "Select an option", description,
|
|
|
63
65
|
: options;
|
|
64
66
|
const optionGroups = groupOptions(filteredOptions);
|
|
65
67
|
const hasVisibleOptions = filteredOptions.length > 0;
|
|
68
|
+
const handleOpenChange = React.useCallback((nextOpen) => {
|
|
69
|
+
if (open === undefined) {
|
|
70
|
+
setUncontrolledOpen(nextOpen);
|
|
71
|
+
}
|
|
72
|
+
if (!nextOpen) {
|
|
73
|
+
setSearchQuery("");
|
|
74
|
+
}
|
|
75
|
+
onOpenChange === null || onOpenChange === void 0 ? void 0 : onOpenChange(nextOpen);
|
|
76
|
+
}, [onOpenChange, open]);
|
|
77
|
+
const closeForTab = React.useCallback(() => handleOpenChange(false), [handleOpenChange]);
|
|
78
|
+
const { handleCloseAutoFocus, handleTabKeyDown } = usePopoverTabExit({
|
|
79
|
+
behavior: "close",
|
|
80
|
+
triggerRef,
|
|
81
|
+
contentRef,
|
|
82
|
+
onExit: closeForTab,
|
|
83
|
+
});
|
|
66
84
|
const focusSearchInput = React.useCallback(() => {
|
|
67
85
|
const input = searchInputRef.current;
|
|
68
86
|
if (!input || document.activeElement === input) {
|
|
@@ -82,6 +100,9 @@ function Select({ label, options, placeholder = "Select an option", description,
|
|
|
82
100
|
option === null || option === void 0 ? void 0 : option.focus({ preventScroll: true });
|
|
83
101
|
}, [getEnabledOptionElements]);
|
|
84
102
|
const handleContentKeyDownCapture = React.useCallback((event) => {
|
|
103
|
+
if (handleTabKeyDown(event)) {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
85
106
|
if (event.key !== "ArrowUp") {
|
|
86
107
|
return;
|
|
87
108
|
}
|
|
@@ -94,7 +115,12 @@ function Select({ label, options, placeholder = "Select an option", description,
|
|
|
94
115
|
if (searchable) {
|
|
95
116
|
focusSearchInput();
|
|
96
117
|
}
|
|
97
|
-
}, [
|
|
118
|
+
}, [
|
|
119
|
+
focusSearchInput,
|
|
120
|
+
getEnabledOptionElements,
|
|
121
|
+
handleTabKeyDown,
|
|
122
|
+
searchable,
|
|
123
|
+
]);
|
|
98
124
|
React.useEffect(() => {
|
|
99
125
|
if (!isOpen) {
|
|
100
126
|
setSearchQuery("");
|
|
@@ -127,16 +153,7 @@ function Select({ label, options, placeholder = "Select an option", description,
|
|
|
127
153
|
searchable,
|
|
128
154
|
searchQuery,
|
|
129
155
|
]);
|
|
130
|
-
|
|
131
|
-
if (open === undefined) {
|
|
132
|
-
setUncontrolledOpen(nextOpen);
|
|
133
|
-
}
|
|
134
|
-
if (!nextOpen) {
|
|
135
|
-
setSearchQuery("");
|
|
136
|
-
}
|
|
137
|
-
onOpenChange === null || onOpenChange === void 0 ? void 0 : onOpenChange(nextOpen);
|
|
138
|
-
}, [onOpenChange, open]);
|
|
139
|
-
return (_jsxs(Field, { className: className, "data-disabled": disabled ? "true" : undefined, "data-invalid": isInvalid ? "true" : undefined, children: [_jsx(FieldLabel, { htmlFor: selectId, className: cn(hideLabel && "sr-only", labelClassName), children: label }), _jsxs(SelectRoot, { disabled: disabled, open: open, onOpenChange: handleOpenChange, ...props, children: [_jsx(SelectTrigger, { id: selectId, className: triggerClassName, "aria-invalid": isInvalid ? "true" : undefined, "aria-describedby": [descriptionId, errorId].filter(Boolean).join(" ") || undefined, children: _jsx(SelectValue, { placeholder: placeholder }) }), _jsx(SelectContent, { ref: contentRef, className: contentClassName, onKeyDownCapture: handleContentKeyDownCapture, header: searchable ? (_jsx(InputControl, { ref: searchInputRef, value: searchQuery, onChange: (event) => setSearchQuery(event.target.value), placeholder: searchPlaceholder, "aria-label": searchInputAriaLabel, autoComplete: "off", className: "h-control border-0 bg-transparent px-2 py-0 text-sm shadow-none", onKeyDown: (event) => {
|
|
156
|
+
return (_jsxs(Field, { className: className, "data-disabled": disabled ? "true" : undefined, "data-invalid": isInvalid ? "true" : undefined, children: [_jsx(FieldLabel, { htmlFor: selectId, className: cn(hideLabel && "sr-only", labelClassName), children: label }), _jsxs(SelectRoot, { disabled: disabled, open: isOpen, onOpenChange: handleOpenChange, ...props, children: [_jsx(SelectTrigger, { ref: triggerRef, id: selectId, className: triggerClassName, "aria-invalid": isInvalid ? "true" : undefined, "aria-describedby": [descriptionId, errorId].filter(Boolean).join(" ") || undefined, children: _jsx(SelectValue, { placeholder: placeholder }) }), _jsx(SelectContent, { ref: contentRef, className: contentClassName, onCloseAutoFocus: handleCloseAutoFocus, onKeyDownCapture: handleContentKeyDownCapture, header: searchable ? (_jsx(InputControl, { ref: searchInputRef, value: searchQuery, onChange: (event) => setSearchQuery(event.target.value), placeholder: searchPlaceholder, "aria-label": searchInputAriaLabel, autoComplete: "off", className: "h-control border-0 bg-transparent px-2 py-0 text-sm shadow-none", onKeyDown: (event) => {
|
|
140
157
|
if (event.key === "ArrowDown" ||
|
|
141
158
|
event.key === "ArrowUp") {
|
|
142
159
|
event.preventDefault();
|
package/dist/spinner.js
CHANGED
|
@@ -8,7 +8,7 @@ const SIZE_CLASS = {
|
|
|
8
8
|
lg: "h-10 w-10 border-[3px]",
|
|
9
9
|
};
|
|
10
10
|
function Spinner({ size = "md", label = "Loading", className, ...props }) {
|
|
11
|
-
return (_jsxs("div", { role: "status", "aria-live": "polite", className: cn("inline-flex items-center justify-center", className), ...props, children: [_jsx("span", { "aria-hidden": "true", className: cn("shrink-0 animate-spin rounded-full border-current border-t-transparent text-
|
|
11
|
+
return (_jsxs("div", { role: "status", "aria-live": "polite", className: cn("inline-flex items-center justify-center", className), ...props, children: [_jsx("span", { "aria-hidden": "true", className: cn("shrink-0 animate-spin rounded-full border-current border-t-transparent text-interactive", SIZE_CLASS[size]) }), _jsx("span", { className: "sr-only", children: label })] }));
|
|
12
12
|
}
|
|
13
13
|
function LoaderStack({ size, label, message, description, }) {
|
|
14
14
|
return (_jsxs(_Fragment, { children: [_jsx("div", { className: "mb-4", children: _jsx(Spinner, { size: size, label: label }) }), message || description ? (_jsxs("div", { className: "space-y-1.5", children: [message ? (_jsx(Typography, { as: "p", variant: "bodySm", className: "font-semibold", children: message })) : null, description ? (_jsx(Typography, { as: "p", variant: "caption", className: "max-w-md", children: description })) : null] })) : null] }));
|
package/dist/styles.css
CHANGED
|
@@ -171,6 +171,15 @@
|
|
|
171
171
|
|
|
172
172
|
--primary: var(--nea-green-700);
|
|
173
173
|
--primary-foreground: var(--nea-neutral-0);
|
|
174
|
+
--interactive-foreground: var(--nea-green-800);
|
|
175
|
+
--highlight-background: var(--nea-green-100);
|
|
176
|
+
--highlight-foreground: var(--nea-green-900);
|
|
177
|
+
--button-primary-background: var(--nea-green-800);
|
|
178
|
+
--button-primary-hover-background: var(--nea-green-900);
|
|
179
|
+
--button-primary-foreground: var(--nea-neutral-0);
|
|
180
|
+
--count-badge-background: var(--nea-green-800);
|
|
181
|
+
--count-badge-foreground: var(--nea-neutral-0);
|
|
182
|
+
--instructional-foreground: 215 16% 40%;
|
|
174
183
|
|
|
175
184
|
--secondary: var(--nea-neutral-100);
|
|
176
185
|
--secondary-foreground: var(--nea-neutral-900);
|
|
@@ -296,6 +305,15 @@
|
|
|
296
305
|
|
|
297
306
|
--primary: 148 30% 38%;
|
|
298
307
|
--primary-foreground: var(--nea-dark-neutral-50);
|
|
308
|
+
--interactive-foreground: 143 44% 67%;
|
|
309
|
+
--highlight-background: 148 20% 18%;
|
|
310
|
+
--highlight-foreground: 143 44% 67%;
|
|
311
|
+
--button-primary-background: 148 30% 38%;
|
|
312
|
+
--button-primary-hover-background: 148 30% 39%;
|
|
313
|
+
--button-primary-foreground: 0 0% 100%;
|
|
314
|
+
--count-badge-background: 148 24% 24%;
|
|
315
|
+
--count-badge-foreground: 143 44% 67%;
|
|
316
|
+
--instructional-foreground: var(--nea-dark-neutral-200);
|
|
299
317
|
|
|
300
318
|
--secondary: var(--nea-dark-neutral-500);
|
|
301
319
|
--secondary-foreground: var(--nea-dark-neutral-100);
|
package/dist/table.d.ts
CHANGED
|
@@ -30,6 +30,14 @@ declare const TableCell: React.ForwardRefExoticComponent<React.TdHTMLAttributes<
|
|
|
30
30
|
treatWidthAsMinWidth?: boolean;
|
|
31
31
|
containOverflow?: boolean;
|
|
32
32
|
} & React.RefAttributes<HTMLTableCellElement>>;
|
|
33
|
+
declare const TableRowHeader: React.ForwardRefExoticComponent<React.ThHTMLAttributes<HTMLTableCellElement> & {
|
|
34
|
+
width?: string;
|
|
35
|
+
minWidth?: string;
|
|
36
|
+
maxWidth?: string;
|
|
37
|
+
wrap?: boolean;
|
|
38
|
+
treatWidthAsMinWidth?: boolean;
|
|
39
|
+
containOverflow?: boolean;
|
|
40
|
+
} & React.RefAttributes<HTMLTableCellElement>>;
|
|
33
41
|
declare const TableCaption: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLTableCaptionElement> & React.RefAttributes<HTMLTableCaptionElement>>;
|
|
34
42
|
type TableAlign = "left" | "center" | "right";
|
|
35
43
|
export type TableRowTone = "default" | "muted" | "warning";
|
|
@@ -85,13 +93,15 @@ export interface TableColumn<Row> {
|
|
|
85
93
|
skeleton?: TableSkeletonConfig;
|
|
86
94
|
headerClassName?: string;
|
|
87
95
|
cellClassName?: string;
|
|
96
|
+
/** Renders this column's body cells as semantic row headers. */
|
|
97
|
+
rowHeader?: boolean;
|
|
88
98
|
/** Pins the column to the left or right edge while the table scrolls horizontally. */
|
|
89
99
|
sticky?: "left" | "right";
|
|
90
100
|
/** Enables a resize handle for this column. Use `resizableColumns` on Table to opt every column in by default. */
|
|
91
101
|
resizable?: boolean;
|
|
92
102
|
/** Minimum pixel width while resizing. Defaults to `minWidth`, then 64. */
|
|
93
103
|
resizeMinWidth?: number;
|
|
94
|
-
/** Maximum pixel width while resizing.
|
|
104
|
+
/** Maximum pixel width while resizing. Defaults to 1200. */
|
|
95
105
|
resizeMaxWidth?: number;
|
|
96
106
|
}
|
|
97
107
|
export interface TableSortingProps {
|
|
@@ -137,6 +147,8 @@ export interface TableColumnResizeHandleRenderProps<Row> {
|
|
|
137
147
|
handle: React.ReactElement;
|
|
138
148
|
}
|
|
139
149
|
export interface TableProps<Row> extends Omit<React.HTMLAttributes<HTMLDivElement>, "children"> {
|
|
150
|
+
/** Accessible name used as a visually hidden caption when `caption` is omitted. */
|
|
151
|
+
accessibleLabel: string;
|
|
140
152
|
columns: TableColumn<Row>[];
|
|
141
153
|
rows: Row[];
|
|
142
154
|
getRowKey: (row: Row, index: number) => string;
|
|
@@ -155,6 +167,8 @@ export interface TableProps<Row> extends Omit<React.HTMLAttributes<HTMLDivElemen
|
|
|
155
167
|
sorting?: TableSortingProps;
|
|
156
168
|
pagination?: Omit<PaginationProps, "className">;
|
|
157
169
|
loading?: boolean;
|
|
170
|
+
/** Status announced while loading. */
|
|
171
|
+
loadingLabel?: string;
|
|
158
172
|
loadingRows?: number;
|
|
159
173
|
/** Optional controlled ordered list of visible column keys. Omit to render every column in config order. */
|
|
160
174
|
visibleColumnKeys?: readonly string[];
|
|
@@ -180,8 +194,6 @@ export interface TableProps<Row> extends Omit<React.HTMLAttributes<HTMLDivElemen
|
|
|
180
194
|
striped?: boolean;
|
|
181
195
|
/** Adds a disclosure column and full-width expandable content for nested tables or row details. */
|
|
182
196
|
rowExpansion?: TableRowExpansionProps<Row>;
|
|
183
|
-
/** When set, rows become interactive: cursor-pointer, hover highlight, and click handling. */
|
|
184
|
-
onRowClick?: (row: Row, index: number) => void;
|
|
185
197
|
}
|
|
186
|
-
declare function Table<Row>({ columns, rows, getRowKey, emptyState, toolbar, caption, className, containerClassName, tableClassName, rowClassName, rowTone, maxHeight, minHeight, sorting, pagination, loading, loadingRows, visibleColumnKeys, resizableColumns, columnResizeMode, columnWidths, defaultColumnWidths, onColumnWidthsChange, renderColumnResizeHandle, tableLayout, centerEmptyState, emptyStateMinHeight, striped, rowExpansion,
|
|
187
|
-
export { Table, TableRoot, TableContainer, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell, TableCaption, SortableTableHead, TableRowSkeleton, };
|
|
198
|
+
declare function Table<Row>({ accessibleLabel, columns, rows, getRowKey, emptyState, toolbar, caption, className, containerClassName, tableClassName, rowClassName, rowTone, maxHeight, minHeight, sorting, pagination, loading, loadingLabel, loadingRows, visibleColumnKeys, resizableColumns, columnResizeMode, columnWidths, defaultColumnWidths, onColumnWidthsChange, renderColumnResizeHandle, tableLayout, centerEmptyState, emptyStateMinHeight, striped, rowExpansion, onScroll, style, ...props }: TableProps<Row>): import("react/jsx-runtime").JSX.Element;
|
|
199
|
+
export { Table, TableRoot, TableContainer, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell, TableRowHeader, TableCaption, SortableTableHead, TableRowSkeleton, };
|