@neasg/design-system 0.2.1 → 0.4.2
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 +37 -1
- package/dist/alert.d.ts +15 -0
- package/dist/alert.js +24 -0
- package/dist/avatar.d.ts +5 -2
- package/dist/avatar.js +8 -4
- package/dist/back-button.d.ts +6 -0
- package/dist/back-button.js +8 -0
- package/dist/badge.d.ts +4 -2
- package/dist/badge.js +13 -2
- package/dist/breadcrumb.js +2 -2
- package/dist/button.d.ts +2 -2
- package/dist/button.js +3 -4
- package/dist/calendar.d.ts +8 -0
- package/dist/calendar.js +80 -0
- package/dist/card.d.ts +17 -0
- package/dist/card.js +16 -0
- package/dist/checkbox.d.ts +13 -0
- package/dist/checkbox.js +29 -0
- package/dist/collapsible.d.ts +19 -0
- package/dist/collapsible.js +20 -0
- package/dist/command-search.js +4 -3
- package/dist/copy-button.d.ts +19 -0
- package/dist/copy-button.js +31 -0
- package/dist/date-input.d.ts +22 -0
- package/dist/date-input.js +61 -0
- package/dist/dialog-primitive.js +1 -1
- package/dist/draggable-tabs.js +1 -1
- package/dist/drawer.js +1 -1
- package/dist/editable-table.js +2 -2
- package/dist/empty-state.js +1 -1
- package/dist/field.d.ts +4 -1
- package/dist/field.js +3 -3
- package/dist/file-upload.d.ts +12 -0
- package/dist/file-upload.js +106 -0
- package/dist/index.d.ts +56 -4
- package/dist/index.js +30 -3
- package/dist/input-control.d.ts +1 -1
- package/dist/input-control.js +1 -1
- package/dist/input.js +2 -2
- package/dist/label-value-grid.d.ts +3 -1
- package/dist/label-value-grid.js +15 -2
- package/dist/label-value.d.ts +4 -1
- package/dist/label-value.js +5 -3
- package/dist/layout.d.ts +7 -1
- package/dist/layout.js +3 -3
- package/dist/lib/date-utils.d.ts +9 -0
- package/dist/lib/date-utils.js +34 -0
- package/dist/link.d.ts +9 -0
- package/dist/link.js +19 -0
- package/dist/multi-select.d.ts +31 -0
- package/dist/multi-select.js +78 -0
- package/dist/otp-input.js +1 -1
- package/dist/page-section.d.ts +14 -0
- package/dist/page-section.js +13 -0
- package/dist/pagination.js +3 -2
- package/dist/popover-menu.d.ts +35 -0
- package/dist/popover-menu.js +36 -0
- package/dist/popover-primitive.d.ts +7 -0
- package/dist/popover-primitive.js +11 -0
- package/dist/popover.d.ts +12 -0
- package/dist/popover.js +8 -0
- package/dist/progress.d.ts +10 -0
- package/dist/progress.js +17 -0
- package/dist/search-input.js +1 -1
- package/dist/section-nav.d.ts +22 -0
- package/dist/section-nav.js +25 -0
- package/dist/select-primitive.d.ts +3 -1
- package/dist/select-primitive.js +3 -2
- package/dist/select.d.ts +1 -0
- package/dist/select.js +3 -3
- package/dist/separator.d.ts +6 -0
- package/dist/separator.js +6 -0
- package/dist/skeleton.d.ts +4 -0
- package/dist/skeleton.js +6 -0
- package/dist/spinner.d.ts +22 -0
- package/dist/spinner.js +24 -0
- package/dist/styles.css +42 -0
- package/dist/switch.d.ts +12 -0
- package/dist/switch.js +16 -0
- package/dist/table.d.ts +7 -1
- package/dist/table.js +26 -12
- package/dist/tabs.d.ts +24 -1
- package/dist/tabs.js +61 -3
- package/dist/tailwind-preset.js +9 -0
- package/dist/textarea.js +1 -1
- package/dist/toaster.d.ts +13 -0
- package/dist/toaster.js +27 -0
- package/dist/typography.d.ts +2 -0
- package/dist/typography.js +9 -2
- package/dist/use-error-shake.d.ts +7 -0
- package/dist/use-error-shake.js +36 -0
- package/dist/use-file-upload.d.ts +34 -0
- package/dist/use-file-upload.js +133 -0
- package/dist/use-sticky-sentinel.d.ts +16 -0
- package/dist/use-sticky-sentinel.js +62 -0
- package/dist/use-table-sort.d.ts +28 -0
- package/dist/use-table-sort.js +53 -0
- package/dist/use-viewport-threshold.d.ts +12 -0
- package/dist/use-viewport-threshold.js +43 -0
- package/package.json +36 -6
package/dist/layout.js
CHANGED
|
@@ -44,7 +44,7 @@ export function useSidebar() {
|
|
|
44
44
|
}
|
|
45
45
|
return context;
|
|
46
46
|
}
|
|
47
|
-
function DashboardLayout({ className, masthead, prototypeBanner, children, style, ...props }) {
|
|
47
|
+
function DashboardLayout({ className, masthead, prototypeBanner, sidebar, surfaceClassName, contentClassName, children, style, ...props }) {
|
|
48
48
|
const chromeRef = React.useRef(null);
|
|
49
49
|
const [topOffset, setTopOffset] = React.useState(0);
|
|
50
50
|
const layoutStyle = React.useMemo(() => ({
|
|
@@ -69,7 +69,7 @@ function DashboardLayout({ className, masthead, prototypeBanner, children, style
|
|
|
69
69
|
observer.observe(node);
|
|
70
70
|
return () => observer.disconnect();
|
|
71
71
|
}, [masthead, prototypeBanner]);
|
|
72
|
-
return (_jsxs("div", { className: cn("flex min-h-screen flex-col bg-[hsl(var(--layout-shell-background))]", className), style: layoutStyle, ...props, children: [masthead || prototypeBanner ? (_jsxs("div", { ref: chromeRef, className: "shrink-0", children: [masthead, prototypeBanner] })) : null,
|
|
72
|
+
return (_jsx(SidebarProvider, { children: _jsxs("div", { className: cn("flex min-h-screen flex-col bg-[hsl(var(--layout-shell-background))]", className), style: layoutStyle, ...props, children: [masthead || prototypeBanner ? (_jsxs("div", { ref: chromeRef, className: "sticky top-0 z-40 shrink-0", children: [masthead, prototypeBanner] })) : null, _jsxs("div", { className: "flex min-h-0 flex-1", children: [sidebar, _jsx(DashboardContent, { className: contentClassName, surfaceClassName: surfaceClassName, children: children })] })] }) }));
|
|
73
73
|
}
|
|
74
74
|
function SidebarShell({ isCollapsed, className, children, ...props }) {
|
|
75
75
|
return (_jsx("aside", { className: cn("fixed left-0 top-[var(--layout-top-offset)] z-30 flex h-[calc(100dvh-var(--layout-top-offset))] shrink-0 flex-col overflow-hidden bg-[hsl(var(--layout-shell-background))] pb-2 pl-[var(--layout-sidebar-padding-inline)] pt-[var(--layout-sidebar-padding-top)] transition-all duration-300 ease-in-out", isCollapsed
|
|
@@ -98,7 +98,7 @@ function SidebarMenuItem({ className, children, }) {
|
|
|
98
98
|
return _jsx("li", { className: className, children: children });
|
|
99
99
|
}
|
|
100
100
|
function SidebarMenuButton({ active = false, collapsed = false, disabled = false, className, asChild = false, children, ...props }) {
|
|
101
|
-
return (_jsx(Button, { asChild: asChild, variant: "ghost", disabled: disabled, className: cn("h-
|
|
101
|
+
return (_jsx(Button, { asChild: asChild, variant: "ghost", disabled: disabled, className: cn("h-control w-full justify-start gap-3 rounded-lg text-sm font-medium shadow-none", collapsed ? "justify-center px-3" : "px-3", disabled
|
|
102
102
|
? "text-muted-foreground/50 hover:bg-transparent hover:text-muted-foreground/50"
|
|
103
103
|
: active
|
|
104
104
|
? "bg-white text-foreground hover:bg-white hover:text-foreground"
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse a date string in DD/MM/YYYY HH:MM AM/PM format to a timestamp (ms).
|
|
3
|
+
*/
|
|
4
|
+
export declare function parseDateTime(dateStr: string): number;
|
|
5
|
+
/**
|
|
6
|
+
* Format a Date object or ISO string to DD/MM/YYYY HH:MM AM/PM format.
|
|
7
|
+
* Returns `"-"` for null/undefined/invalid input.
|
|
8
|
+
*/
|
|
9
|
+
export declare function formatDateTime(date: Date | string | null | undefined): string;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse a date string in DD/MM/YYYY HH:MM AM/PM format to a timestamp (ms).
|
|
3
|
+
*/
|
|
4
|
+
export function parseDateTime(dateStr) {
|
|
5
|
+
const [datePart, timePart, ampm] = dateStr.split(" ");
|
|
6
|
+
const [day, month, year] = datePart.split("/");
|
|
7
|
+
const [hours, minutes] = timePart.split(":");
|
|
8
|
+
let hour = parseInt(hours);
|
|
9
|
+
if (ampm === "PM" && hour !== 12)
|
|
10
|
+
hour += 12;
|
|
11
|
+
if (ampm === "AM" && hour === 12)
|
|
12
|
+
hour = 0;
|
|
13
|
+
return new Date(parseInt(year), parseInt(month) - 1, parseInt(day), hour, parseInt(minutes)).getTime();
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Format a Date object or ISO string to DD/MM/YYYY HH:MM AM/PM format.
|
|
17
|
+
* Returns `"-"` for null/undefined/invalid input.
|
|
18
|
+
*/
|
|
19
|
+
export function formatDateTime(date) {
|
|
20
|
+
if (!date)
|
|
21
|
+
return "-";
|
|
22
|
+
const dateObj = typeof date === "string" ? new Date(date) : date;
|
|
23
|
+
if (isNaN(dateObj.getTime()))
|
|
24
|
+
return "-";
|
|
25
|
+
const day = dateObj.getDate().toString().padStart(2, "0");
|
|
26
|
+
const month = (dateObj.getMonth() + 1).toString().padStart(2, "0");
|
|
27
|
+
const year = dateObj.getFullYear();
|
|
28
|
+
let hours = dateObj.getHours();
|
|
29
|
+
const minutes = dateObj.getMinutes().toString().padStart(2, "0");
|
|
30
|
+
const ampm = hours >= 12 ? "PM" : "AM";
|
|
31
|
+
hours = hours % 12;
|
|
32
|
+
hours = hours ? hours : 12;
|
|
33
|
+
return `${day}/${month}/${year} ${hours}:${minutes} ${ampm}`;
|
|
34
|
+
}
|
package/dist/link.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { type VariantProps } from "class-variance-authority";
|
|
3
|
+
declare const linkVariants: (props?: ({
|
|
4
|
+
variant?: "default" | "inherit" | "subtle" | null | undefined;
|
|
5
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
6
|
+
export interface LinkProps extends React.AnchorHTMLAttributes<HTMLAnchorElement>, VariantProps<typeof linkVariants> {
|
|
7
|
+
}
|
|
8
|
+
declare const Link: React.ForwardRefExoticComponent<LinkProps & React.RefAttributes<HTMLAnchorElement>>;
|
|
9
|
+
export { Link, linkVariants };
|
package/dist/link.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { cva } from "class-variance-authority";
|
|
4
|
+
import { cn } from "./lib/utils";
|
|
5
|
+
const linkVariants = cva("rounded-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2", {
|
|
6
|
+
variants: {
|
|
7
|
+
variant: {
|
|
8
|
+
default: "text-primary underline-offset-4 hover:underline",
|
|
9
|
+
subtle: "text-foreground underline-offset-4 hover:text-primary hover:underline",
|
|
10
|
+
inherit: "text-inherit no-underline hover:no-underline",
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
defaultVariants: {
|
|
14
|
+
variant: "default",
|
|
15
|
+
},
|
|
16
|
+
});
|
|
17
|
+
const Link = React.forwardRef(({ className, variant, ...props }, ref) => (_jsx("a", { ref: ref, className: cn(linkVariants({ variant }), className), ...props })));
|
|
18
|
+
Link.displayName = "Link";
|
|
19
|
+
export { Link, linkVariants };
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export interface MultiSelectOption {
|
|
3
|
+
label: string;
|
|
4
|
+
value: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
disabled?: boolean;
|
|
7
|
+
}
|
|
8
|
+
export interface MultiSelectProps {
|
|
9
|
+
label: React.ReactNode;
|
|
10
|
+
options: MultiSelectOption[];
|
|
11
|
+
value: string[];
|
|
12
|
+
onValueChange: (value: string[]) => void;
|
|
13
|
+
placeholder?: string;
|
|
14
|
+
description?: React.ReactNode;
|
|
15
|
+
error?: React.ReactNode;
|
|
16
|
+
invalid?: boolean;
|
|
17
|
+
disabled?: boolean;
|
|
18
|
+
hideLabel?: boolean;
|
|
19
|
+
searchable?: boolean;
|
|
20
|
+
searchPlaceholder?: string;
|
|
21
|
+
/** Cap how many selected tags render in the trigger; the rest collapse into a `+N` badge. */
|
|
22
|
+
maxVisibleTags?: number;
|
|
23
|
+
className?: string;
|
|
24
|
+
triggerClassName?: string;
|
|
25
|
+
labelClassName?: string;
|
|
26
|
+
descriptionClassName?: string;
|
|
27
|
+
errorClassName?: string;
|
|
28
|
+
id?: string;
|
|
29
|
+
}
|
|
30
|
+
declare function MultiSelect({ label, options, value, onValueChange, placeholder, description, error, invalid, disabled, hideLabel, searchable, searchPlaceholder, maxVisibleTags, className, triggerClassName, labelClassName, descriptionClassName, errorClassName, id, }: MultiSelectProps): import("react/jsx-runtime").JSX.Element;
|
|
31
|
+
export { MultiSelect };
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { XIcon } from "./animated-icons/x";
|
|
5
|
+
import { Badge } from "./badge";
|
|
6
|
+
import { Field, FieldDescription, FieldError, FieldLabel } from "./field";
|
|
7
|
+
import { Checkbox } from "./checkbox";
|
|
8
|
+
import { InputControl } from "./input-control";
|
|
9
|
+
import { cn } from "./lib/utils";
|
|
10
|
+
import { Typography } from "./typography";
|
|
11
|
+
function MultiSelect({ label, options, value, onValueChange, placeholder = "Select options", description, error, invalid = false, disabled = false, hideLabel = false, searchable = false, searchPlaceholder = "Search...", maxVisibleTags = 2, className, triggerClassName, labelClassName, descriptionClassName, errorClassName, id, }) {
|
|
12
|
+
const generatedId = React.useId();
|
|
13
|
+
const selectId = id !== null && id !== void 0 ? id : `multi-select-${generatedId}`;
|
|
14
|
+
const errorId = error ? `${selectId}-error` : undefined;
|
|
15
|
+
const showDescription = Boolean(description) && !error;
|
|
16
|
+
const descriptionId = showDescription ? `${selectId}-description` : undefined;
|
|
17
|
+
const isInvalid = invalid || Boolean(error);
|
|
18
|
+
const [open, setOpen] = React.useState(false);
|
|
19
|
+
const [searchQuery, setSearchQuery] = React.useState("");
|
|
20
|
+
const containerRef = React.useRef(null);
|
|
21
|
+
const searchInputRef = React.useRef(null);
|
|
22
|
+
const normalizedQuery = searchQuery.trim().toLowerCase();
|
|
23
|
+
const filteredOptions = searchable && normalizedQuery
|
|
24
|
+
? options.filter((opt) => {
|
|
25
|
+
var _a, _b;
|
|
26
|
+
return opt.label.toLowerCase().includes(normalizedQuery) ||
|
|
27
|
+
((_b = (_a = opt.description) === null || _a === void 0 ? void 0 : _a.toLowerCase().includes(normalizedQuery)) !== null && _b !== void 0 ? _b : false);
|
|
28
|
+
})
|
|
29
|
+
: options;
|
|
30
|
+
const selectedLabels = value
|
|
31
|
+
.map((v) => options.find((opt) => opt.value === v))
|
|
32
|
+
.filter(Boolean);
|
|
33
|
+
const toggleOption = React.useCallback((optionValue) => {
|
|
34
|
+
const next = value.includes(optionValue)
|
|
35
|
+
? value.filter((v) => v !== optionValue)
|
|
36
|
+
: [...value, optionValue];
|
|
37
|
+
onValueChange(next);
|
|
38
|
+
}, [value, onValueChange]);
|
|
39
|
+
const removeOption = React.useCallback((optionValue) => {
|
|
40
|
+
onValueChange(value.filter((v) => v !== optionValue));
|
|
41
|
+
}, [value, onValueChange]);
|
|
42
|
+
React.useEffect(() => {
|
|
43
|
+
if (!open) {
|
|
44
|
+
setSearchQuery("");
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
if (searchable) {
|
|
48
|
+
const frame = window.requestAnimationFrame(() => {
|
|
49
|
+
var _a;
|
|
50
|
+
(_a = searchInputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
|
|
51
|
+
});
|
|
52
|
+
return () => window.cancelAnimationFrame(frame);
|
|
53
|
+
}
|
|
54
|
+
}, [open, searchable]);
|
|
55
|
+
React.useEffect(() => {
|
|
56
|
+
const handleClickOutside = (event) => {
|
|
57
|
+
if (containerRef.current &&
|
|
58
|
+
!containerRef.current.contains(event.target)) {
|
|
59
|
+
setOpen(false);
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
if (open) {
|
|
63
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
64
|
+
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
65
|
+
}
|
|
66
|
+
}, [open]);
|
|
67
|
+
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("div", { ref: containerRef, className: "relative", children: [_jsx("button", { type: "button", id: selectId, disabled: disabled, onClick: () => setOpen((prev) => !prev), "aria-expanded": open, "aria-haspopup": "listbox", "aria-invalid": isInvalid ? "true" : undefined, "aria-describedby": [descriptionId, errorId].filter(Boolean).join(" ") || undefined, className: cn("flex h-control w-full items-center gap-1.5 overflow-hidden rounded-md border border-input bg-background px-3 py-1 text-sm ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50", isInvalid ? "border-destructive" : "border-input", triggerClassName), children: selectedLabels.length > 0 ? (_jsxs(_Fragment, { children: [selectedLabels.slice(0, maxVisibleTags).map((opt) => (_jsxs(Badge, { variant: "secondary", className: "max-w-[10rem] shrink-0 justify-start gap-1 overflow-visible text-sm font-medium normal-case", children: [_jsx("span", { className: "min-w-0 truncate", children: opt.label }), _jsx("button", { type: "button", className: "inline-flex cursor-pointer items-center justify-center rounded-sm text-muted-foreground hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", onClick: (e) => {
|
|
68
|
+
e.stopPropagation();
|
|
69
|
+
removeOption(opt.value);
|
|
70
|
+
}, "aria-label": `Remove ${opt.label}`, children: _jsx(XIcon, { size: 12 }) })] }, opt.value))), selectedLabels.length > maxVisibleTags ? (_jsxs(Badge, { variant: "secondary", className: "shrink-0 text-sm font-medium normal-case", title: selectedLabels
|
|
71
|
+
.slice(maxVisibleTags)
|
|
72
|
+
.map((o) => o.label)
|
|
73
|
+
.join(", "), children: ["+", selectedLabels.length - maxVisibleTags] })) : null] })) : (_jsx("span", { className: "text-muted-foreground", children: placeholder })) }), open ? (_jsxs("div", { className: "absolute z-50 mt-1 w-full rounded-md border bg-popover shadow-md", children: [searchable ? (_jsx("div", { className: "border-b px-2 py-1", children: _jsx(InputControl, { ref: searchInputRef, value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), placeholder: searchPlaceholder, className: "h-8 border-0 bg-transparent px-2 py-0 text-sm shadow-none focus-visible:ring-0", onKeyDown: (e) => e.stopPropagation() }) })) : null, _jsx("div", { role: "listbox", "aria-label": typeof label === "string" ? label : "Options", "aria-multiselectable": "true", className: "max-h-64 overflow-y-auto p-1", children: filteredOptions.length > 0 ? (filteredOptions.map((option) => {
|
|
74
|
+
const isSelected = value.includes(option.value);
|
|
75
|
+
return (_jsxs("button", { type: "button", role: "option", "aria-selected": isSelected, disabled: option.disabled, onClick: () => toggleOption(option.value), className: cn("flex min-h-control w-full cursor-pointer items-center gap-2 rounded-sm px-2 py-2 text-left text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground disabled:pointer-events-none disabled:opacity-50", isSelected && "bg-accent"), children: [_jsx(Checkbox, { checked: isSelected, disabled: option.disabled, tabIndex: -1, readOnly: true, "aria-hidden": "true", className: "mt-0.5" }), _jsxs("div", { className: "flex flex-col gap-0.5", children: [_jsx("span", { children: option.label }), option.description ? (_jsx(Typography, { as: "span", variant: "caption", children: option.description })) : null] })] }, option.value));
|
|
76
|
+
})) : (_jsx("div", { className: "px-3 py-2 text-center text-sm text-muted-foreground", children: "No options found." })) })] })) : null] }), showDescription ? (_jsx(FieldDescription, { id: descriptionId, className: descriptionClassName, children: description })) : null, _jsx(FieldError, { id: errorId, className: errorClassName, children: error })] }));
|
|
77
|
+
}
|
|
78
|
+
export { MultiSelect };
|
package/dist/otp-input.js
CHANGED
|
@@ -7,7 +7,7 @@ import { validateOtp } from "./input-validation";
|
|
|
7
7
|
import { cn } from "./lib/utils";
|
|
8
8
|
function OtpSlot({ slot, invalid, className, }) {
|
|
9
9
|
var _a, _b;
|
|
10
|
-
return (_jsxs("div", { "data-slot": "otp-slot", className: cn("relative flex size-10 items-center justify-center rounded-md border bg-transparent text-sm font-medium
|
|
10
|
+
return (_jsxs("div", { "data-slot": "otp-slot", className: cn("relative flex size-10 items-center justify-center rounded-md border bg-transparent text-sm font-medium transition-[border-color,box-shadow,color] outline-none group-data-[disabled=true]/field:cursor-not-allowed group-data-[disabled=true]/field:bg-muted/30 group-data-[disabled=true]/field:text-muted-foreground group-data-[disabled=true]/field:opacity-50", invalid ? "border-destructive" : "border-input", slot.isActive &&
|
|
11
11
|
(invalid
|
|
12
12
|
? "border-destructive ring-[3px] ring-destructive/20"
|
|
13
13
|
: "border-ring ring-[3px] ring-ring/50"), className), children: [_jsx("span", { className: cn("pointer-events-none", !slot.char && slot.placeholderChar ? "text-muted-foreground" : ""), children: (_b = (_a = slot.char) !== null && _a !== void 0 ? _a : slot.placeholderChar) !== null && _b !== void 0 ? _b : "" }), slot.hasFakeCaret ? (_jsx("span", { "aria-hidden": "true", className: "pointer-events-none absolute inset-0 flex items-center justify-center", children: _jsx("span", { className: "h-4 w-px animate-pulse bg-foreground" }) })) : null] }));
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export interface PageSectionGroupProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
3
|
+
}
|
|
4
|
+
declare function PageSectionGroup({ className, ...props }: PageSectionGroupProps): import("react/jsx-runtime").JSX.Element;
|
|
5
|
+
export interface PageSectionProps extends Omit<React.HTMLAttributes<HTMLElement>, "title"> {
|
|
6
|
+
title: React.ReactNode;
|
|
7
|
+
description?: React.ReactNode;
|
|
8
|
+
headerAction?: React.ReactNode;
|
|
9
|
+
titleAdornment?: React.ReactNode;
|
|
10
|
+
headerClassName?: string;
|
|
11
|
+
contentClassName?: string;
|
|
12
|
+
}
|
|
13
|
+
declare function PageSection({ title, description, headerAction, titleAdornment, className, headerClassName, contentClassName, children, ...props }: PageSectionProps): import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
export { PageSection, PageSectionGroup };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { cn } from "./lib/utils";
|
|
4
|
+
import { Typography } from "./typography";
|
|
5
|
+
function PageSectionGroup({ className, ...props }) {
|
|
6
|
+
return _jsx("div", { className: cn("divide-y divide-border", className), ...props });
|
|
7
|
+
}
|
|
8
|
+
function PageSection({ title, description, headerAction, titleAdornment, className, headerClassName, contentClassName, children, ...props }) {
|
|
9
|
+
const renderedTitle = React.isValidElement(title) ? (title) : (_jsx(Typography, { as: "h3", variant: "subheading", children: title }));
|
|
10
|
+
const renderedDescription = description == null ? null : React.isValidElement(description) ? (description) : (_jsx(Typography, { as: "p", variant: "caption", children: description }));
|
|
11
|
+
return (_jsxs("section", { className: cn("py-6", className), ...props, children: [_jsxs("div", { className: cn("flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between", headerClassName), children: [_jsxs("div", { className: "min-w-0 space-y-1", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [renderedTitle, titleAdornment] }), renderedDescription] }), headerAction ? (_jsx("div", { className: "flex items-center gap-2 sm:shrink-0", children: headerAction })) : null] }), children ? (_jsx("div", { className: cn("pt-5", contentClassName), children: children })) : null] }));
|
|
12
|
+
}
|
|
13
|
+
export { PageSection, PageSectionGroup };
|
package/dist/pagination.js
CHANGED
|
@@ -6,6 +6,7 @@ import { ChevronRightIcon } from "./animated-icons/chevron-right";
|
|
|
6
6
|
import { Button } from "./button";
|
|
7
7
|
import { SelectContent, SelectItem, SelectRoot, SelectTrigger, SelectValue, } from "./select-primitive";
|
|
8
8
|
import { cn } from "./lib/utils";
|
|
9
|
+
import { Typography } from "./typography";
|
|
9
10
|
const PaginationNav = React.forwardRef(({ className, ...props }, ref) => (_jsx("nav", { ref: ref, role: "navigation", "aria-label": "pagination", className: cn("flex w-full justify-center", className), ...props })));
|
|
10
11
|
PaginationNav.displayName = "PaginationNav";
|
|
11
12
|
const PaginationContent = React.forwardRef(({ className, ...props }, ref) => (_jsx("ul", { ref: ref, className: cn("flex flex-row items-center gap-1", className), ...props })));
|
|
@@ -16,9 +17,9 @@ function Pagination({ currentPage, totalPages, totalItems, itemsPerPage = 5, onP
|
|
|
16
17
|
const normalizedTotalPages = totalPages || 1;
|
|
17
18
|
const startItem = totalItems === 0 ? 0 : (currentPage - 1) * itemsPerPage + 1;
|
|
18
19
|
const endItem = Math.min(currentPage * itemsPerPage, totalItems);
|
|
19
|
-
return (_jsxs("div", { className: cn("flex items-center justify-between gap-6", className), ...props, children: [_jsxs("div", { className: "text-sm text-muted-foreground", children: ["Showing ", startItem, "-", endItem, " out of ", totalItems] }), _jsxs("div", { className: "flex items-center gap-6", children: [onItemsPerPageChange ? (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(
|
|
20
|
+
return (_jsxs("div", { className: cn("flex items-center justify-between gap-6", className), ...props, children: [_jsxs("div", { className: "text-sm text-muted-foreground", children: ["Showing ", startItem, "-", endItem, " out of ", totalItems] }), _jsxs("div", { className: "flex items-center gap-6", children: [onItemsPerPageChange ? (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Typography, { as: "span", variant: "caption", children: "Rows per page" }), _jsxs(SelectRoot, { value: itemsPerPage.toString(), onValueChange: (value) => {
|
|
20
21
|
onItemsPerPageChange(Number(value));
|
|
21
22
|
onPageChange(1);
|
|
22
|
-
}, children: [_jsx(SelectTrigger, { className: "
|
|
23
|
+
}, children: [_jsx(SelectTrigger, { className: "w-[70px] text-sm", children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: itemsPerPageOptions.map((option) => (_jsx(SelectItem, { value: option.toString(), children: option }, option))) })] })] })) : null, _jsxs("div", { className: "text-sm text-muted-foreground", children: ["Page ", currentPage, " of ", normalizedTotalPages] }), _jsx(PaginationNav, { className: "mx-0 w-auto justify-start", children: _jsxs(PaginationContent, { children: [_jsx(PaginationItem, { children: _jsx(Button, { type: "button", variant: "outline", size: "icon", onClick: () => onPageChange(1), disabled: currentPage === 1, "aria-label": "Go to first page", children: _jsx(ChevronsLeft, { className: "h-4 w-4" }) }) }), _jsx(PaginationItem, { children: _jsx(Button, { type: "button", variant: "outline", size: "icon", onClick: () => onPageChange(Math.max(1, currentPage - 1)), disabled: currentPage === 1, "aria-label": "Go to previous page", children: _jsx(ChevronLeftIcon, { size: 16 }) }) }), _jsx(PaginationItem, { children: _jsx(Button, { type: "button", variant: "outline", size: "icon", onClick: () => onPageChange(Math.min(normalizedTotalPages, currentPage + 1)), disabled: currentPage === normalizedTotalPages || totalPages === 0, "aria-label": "Go to next page", children: _jsx(ChevronRightIcon, { size: 16 }) }) }), _jsx(PaginationItem, { children: _jsx(Button, { type: "button", variant: "outline", size: "icon", onClick: () => onPageChange(normalizedTotalPages), disabled: currentPage === normalizedTotalPages || totalPages === 0, "aria-label": "Go to last page", children: _jsx(ChevronsRight, { className: "h-4 w-4" }) }) })] }) })] })] }));
|
|
23
24
|
}
|
|
24
25
|
export { Pagination };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { InputControl } from "./input-control";
|
|
3
|
+
import { PopoverContent } from "./popover-primitive";
|
|
4
|
+
import { Typography } from "./typography";
|
|
5
|
+
export interface PopoverMenuHeaderProps extends Omit<React.ComponentPropsWithoutRef<typeof Typography>, "as" | "asChild" | "variant" | "color"> {
|
|
6
|
+
}
|
|
7
|
+
export interface PopoverMenuContentProps extends React.ComponentPropsWithoutRef<typeof PopoverContent> {
|
|
8
|
+
}
|
|
9
|
+
declare const PopoverMenuContent: React.ForwardRefExoticComponent<PopoverMenuContentProps & React.RefAttributes<HTMLDivElement>>;
|
|
10
|
+
declare function PopoverMenuHeader({ className, children, ...props }: PopoverMenuHeaderProps): import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
export interface PopoverMenuSectionProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
12
|
+
}
|
|
13
|
+
declare function PopoverMenuSection({ className, children, ...props }: PopoverMenuSectionProps): import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
export interface PopoverMenuItemProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
15
|
+
active?: boolean;
|
|
16
|
+
}
|
|
17
|
+
declare function PopoverMenuItem({ className, children, active, type, ...props }: PopoverMenuItemProps): import("react/jsx-runtime").JSX.Element;
|
|
18
|
+
export interface PopoverMenuDividerProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
19
|
+
}
|
|
20
|
+
declare function PopoverMenuDivider({ className, ...props }: PopoverMenuDividerProps): import("react/jsx-runtime").JSX.Element;
|
|
21
|
+
export interface PopoverMenuGroupProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
22
|
+
}
|
|
23
|
+
declare function PopoverMenuGroup({ className, children, ...props }: PopoverMenuGroupProps): import("react/jsx-runtime").JSX.Element;
|
|
24
|
+
export interface PopoverMenuGroupLabelProps extends Omit<React.ComponentPropsWithoutRef<typeof Typography>, "as" | "asChild" | "variant" | "color"> {
|
|
25
|
+
}
|
|
26
|
+
declare function PopoverMenuGroupLabel({ className, children, ...props }: PopoverMenuGroupLabelProps): import("react/jsx-runtime").JSX.Element;
|
|
27
|
+
export interface PopoverMenuSearchProps extends React.ComponentPropsWithoutRef<typeof InputControl> {
|
|
28
|
+
containerClassName?: string;
|
|
29
|
+
}
|
|
30
|
+
declare const PopoverMenuSearch: React.ForwardRefExoticComponent<PopoverMenuSearchProps & React.RefAttributes<HTMLInputElement>>;
|
|
31
|
+
export interface PopoverMenuScrollAreaProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
32
|
+
maxHeight?: string;
|
|
33
|
+
}
|
|
34
|
+
declare function PopoverMenuScrollArea({ className, children, maxHeight, ...props }: PopoverMenuScrollAreaProps): import("react/jsx-runtime").JSX.Element;
|
|
35
|
+
export { PopoverMenuContent, PopoverMenuHeader, PopoverMenuSection, PopoverMenuItem, PopoverMenuDivider, PopoverMenuGroup, PopoverMenuGroupLabel, PopoverMenuSearch, PopoverMenuScrollArea, };
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { Check } from "lucide-react";
|
|
5
|
+
import { Button } from "./button";
|
|
6
|
+
import { cn } from "./lib/utils";
|
|
7
|
+
import { InputControl } from "./input-control";
|
|
8
|
+
import { PopoverContent } from "./popover-primitive";
|
|
9
|
+
import { Typography } from "./typography";
|
|
10
|
+
const PopoverMenuContent = React.forwardRef(({ className, ...props }, ref) => (_jsx(PopoverContent, { ref: ref, className: cn("overflow-hidden p-1", className), ...props })));
|
|
11
|
+
PopoverMenuContent.displayName = "PopoverMenuContent";
|
|
12
|
+
function PopoverMenuHeader({ className, children, ...props }) {
|
|
13
|
+
return (_jsx(Typography, { as: "p", variant: "label", className: cn("px-2 py-1.5", className), ...props, children: children }));
|
|
14
|
+
}
|
|
15
|
+
function PopoverMenuSection({ className, children, ...props }) {
|
|
16
|
+
return (_jsx("div", { className: cn("space-y-0", className), ...props, children: children }));
|
|
17
|
+
}
|
|
18
|
+
function PopoverMenuItem({ className, children, active, type = "button", ...props }) {
|
|
19
|
+
return (_jsxs(Button, { type: type, variant: "ghost", className: cn("w-full justify-start rounded-sm text-left font-normal whitespace-normal", active &&
|
|
20
|
+
"bg-accent text-accent-foreground hover:bg-accent hover:text-accent-foreground", className), ...props, children: [children, active ? _jsx(Check, { "aria-hidden": "true", className: "ml-auto h-4 w-4 shrink-0" }) : null] }));
|
|
21
|
+
}
|
|
22
|
+
function PopoverMenuDivider({ className, ...props }) {
|
|
23
|
+
return _jsx("div", { className: cn("-mx-1 my-1 h-px bg-border", className), ...props });
|
|
24
|
+
}
|
|
25
|
+
function PopoverMenuGroup({ className, children, ...props }) {
|
|
26
|
+
return (_jsx("div", { className: cn("space-y-1", className), ...props, children: children }));
|
|
27
|
+
}
|
|
28
|
+
function PopoverMenuGroupLabel({ className, children, ...props }) {
|
|
29
|
+
return (_jsx(Typography, { as: "p", variant: "eyebrow", color: "muted", className: cn("px-2 py-1.5 font-normal normal-case tracking-normal", className), ...props, children: children }));
|
|
30
|
+
}
|
|
31
|
+
const PopoverMenuSearch = React.forwardRef(({ className, containerClassName, ...props }, ref) => (_jsx("div", { className: cn("-mx-1 -mt-1 mb-1 border-b px-2 py-1", containerClassName), children: _jsx(InputControl, { ref: ref, className: cn("h-8 border-0 bg-transparent px-2 py-0 text-sm shadow-none focus-visible:ring-0", className), ...props }) })));
|
|
32
|
+
PopoverMenuSearch.displayName = "PopoverMenuSearch";
|
|
33
|
+
function PopoverMenuScrollArea({ className, children, maxHeight = "max-h-64", ...props }) {
|
|
34
|
+
return (_jsx("div", { className: cn(maxHeight, "space-y-1 overflow-y-auto", className), ...props, children: children }));
|
|
35
|
+
}
|
|
36
|
+
export { PopoverMenuContent, PopoverMenuHeader, PopoverMenuSection, PopoverMenuItem, PopoverMenuDivider, PopoverMenuGroup, PopoverMenuGroupLabel, PopoverMenuSearch, PopoverMenuScrollArea, };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import * as PopoverPrimitive from "@radix-ui/react-popover";
|
|
3
|
+
declare const PopoverRoot: React.FC<PopoverPrimitive.PopoverProps>;
|
|
4
|
+
declare const PopoverTrigger: React.ForwardRefExoticComponent<PopoverPrimitive.PopoverTriggerProps & React.RefAttributes<HTMLButtonElement>>;
|
|
5
|
+
declare const PopoverAnchor: React.ForwardRefExoticComponent<PopoverPrimitive.PopoverAnchorProps & React.RefAttributes<HTMLDivElement>>;
|
|
6
|
+
declare const PopoverContent: React.ForwardRefExoticComponent<Omit<PopoverPrimitive.PopoverContentProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
7
|
+
export { PopoverAnchor, PopoverContent, PopoverRoot, PopoverTrigger };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import * as PopoverPrimitive from "@radix-ui/react-popover";
|
|
5
|
+
import { cn } from "./lib/utils";
|
|
6
|
+
const PopoverRoot = PopoverPrimitive.Root;
|
|
7
|
+
const PopoverTrigger = PopoverPrimitive.Trigger;
|
|
8
|
+
const PopoverAnchor = PopoverPrimitive.Anchor;
|
|
9
|
+
const PopoverContent = React.forwardRef(({ className, align = "center", sideOffset = 4, ...props }, ref) => (_jsx(PopoverPrimitive.Portal, { children: _jsx(PopoverPrimitive.Content, { ref: ref, align: align, sideOffset: sideOffset, className: cn("z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", className), ...props }) })));
|
|
10
|
+
PopoverContent.displayName = PopoverPrimitive.Content.displayName;
|
|
11
|
+
export { PopoverAnchor, PopoverContent, PopoverRoot, PopoverTrigger };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import * as PopoverPrimitive from "@radix-ui/react-popover";
|
|
3
|
+
type PopoverRootProps = React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Root>;
|
|
4
|
+
type PopoverContentProps = React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>;
|
|
5
|
+
export interface PopoverProps extends Pick<PopoverRootProps, "defaultOpen" | "modal" | "onOpenChange" | "open">, Omit<PopoverContentProps, "children" | "className"> {
|
|
6
|
+
trigger: React.ReactElement;
|
|
7
|
+
children: React.ReactNode;
|
|
8
|
+
surface?: "panel" | "menu";
|
|
9
|
+
contentClassName?: string;
|
|
10
|
+
}
|
|
11
|
+
declare function Popover({ defaultOpen, modal, onOpenChange, open, trigger, children, surface, contentClassName, align, sideOffset, ...contentProps }: PopoverProps): import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
export { Popover };
|
package/dist/popover.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { cn } from "./lib/utils";
|
|
4
|
+
import { PopoverContent, PopoverRoot, PopoverTrigger, } from "./popover-primitive";
|
|
5
|
+
function Popover({ defaultOpen, modal, onOpenChange, open, trigger, children, surface = "panel", contentClassName, align = "center", sideOffset = 4, ...contentProps }) {
|
|
6
|
+
return (_jsxs(PopoverRoot, { defaultOpen: defaultOpen, modal: modal, onOpenChange: onOpenChange, open: open, children: [_jsx(PopoverTrigger, { asChild: true, children: trigger }), _jsx(PopoverContent, { align: align, sideOffset: sideOffset, className: cn(surface === "menu" && "overflow-hidden p-1", contentClassName), ...contentProps, children: children })] }));
|
|
7
|
+
}
|
|
8
|
+
export { Popover };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export interface ProgressProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
3
|
+
value?: number;
|
|
4
|
+
max?: number;
|
|
5
|
+
showValue?: boolean;
|
|
6
|
+
size?: "sm" | "md" | "lg";
|
|
7
|
+
variant?: "default" | "success" | "error";
|
|
8
|
+
label?: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function Progress({ value, max, showValue, size, variant, label, className, ...props }: ProgressProps): import("react/jsx-runtime").JSX.Element;
|
package/dist/progress.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { cn } from "./lib/utils";
|
|
4
|
+
const sizeClasses = {
|
|
5
|
+
sm: "h-1",
|
|
6
|
+
md: "h-2",
|
|
7
|
+
lg: "h-3",
|
|
8
|
+
};
|
|
9
|
+
const variantClasses = {
|
|
10
|
+
default: "bg-primary",
|
|
11
|
+
success: "bg-green-500",
|
|
12
|
+
error: "bg-destructive",
|
|
13
|
+
};
|
|
14
|
+
export function Progress({ value = 0, max = 100, showValue = false, size = "md", variant = "default", label = "Progress", className, ...props }) {
|
|
15
|
+
const percentage = Math.min(Math.max((value / max) * 100, 0), 100);
|
|
16
|
+
return (_jsxs("div", { className: cn("w-full", className), ...props, children: [_jsx("div", { className: cn("w-full overflow-hidden rounded-full bg-secondary", sizeClasses[size]), role: "progressbar", "aria-valuenow": value, "aria-valuemin": 0, "aria-valuemax": max, "aria-label": label, children: _jsx("div", { className: cn("h-full rounded-full transition-all duration-300 ease-out", variantClasses[variant]), style: { width: `${percentage}%` } }) }), showValue && (_jsxs("p", { className: "mt-1 text-right text-xs text-muted-foreground", children: [Math.round(percentage), "%"] }))] }));
|
|
17
|
+
}
|
package/dist/search-input.js
CHANGED
|
@@ -67,7 +67,7 @@ const SearchInput = React.forwardRef(({ value, onValueChange, label = "Search",
|
|
|
67
67
|
return (_jsxs(Field, { className: containerClassName, "data-disabled": disabled ? "true" : undefined, "data-invalid": isInvalid ? "true" : undefined, children: [_jsx(FieldLabel, { htmlFor: inputId, className: cn("sr-only", labelClassName), children: label }), _jsxs(SearchInputShell, { children: [_jsx(InputControl, { ref: ref, id: inputId, type: "text", placeholder: placeholder, value: value, onChange: handleChange, onKeyDown: handleKeyDown, disabled: disabled, "aria-invalid": isInvalid ? "true" : undefined, "aria-describedby": describedBy, className: cn("bg-background pl-9 pr-8", className), ...props }), value ? (_jsx("button", { type: "button", onClick: () => {
|
|
68
68
|
onValueChange("");
|
|
69
69
|
runSearch("");
|
|
70
|
-
}, disabled: disabled, className: "absolute right-2 top-1/2 -translate-y-1/2 rounded-sm p-0.5 text-muted-foreground hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none", "aria-label": "Clear search", children: _jsx(XIcon, { size: 14 }) })) : null] }), showDescription ? (_jsx(FieldDescription, { id: descriptionId, className: descriptionClassName, children: description })) : null, _jsx(FieldError, { id: errorId, className: errorClassName, children: error })] }));
|
|
70
|
+
}, disabled: disabled, className: "absolute right-2 top-1/2 -translate-y-1/2 cursor-pointer rounded-sm p-0.5 text-muted-foreground hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-not-allowed disabled:pointer-events-none", "aria-label": "Clear search", children: _jsx(XIcon, { size: 14 }) })) : null] }), showDescription ? (_jsx(FieldDescription, { id: descriptionId, className: descriptionClassName, children: description })) : null, _jsx(FieldError, { id: errorId, className: errorClassName, children: error })] }));
|
|
71
71
|
});
|
|
72
72
|
SearchInput.displayName = "SearchInput";
|
|
73
73
|
export { SearchInput };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
type SectionNavIcon = React.ComponentType<{
|
|
3
|
+
className?: string;
|
|
4
|
+
}>;
|
|
5
|
+
export interface SectionNavItem {
|
|
6
|
+
id: string;
|
|
7
|
+
label: React.ReactNode;
|
|
8
|
+
icon?: SectionNavIcon;
|
|
9
|
+
href?: string;
|
|
10
|
+
target?: string;
|
|
11
|
+
rel?: string;
|
|
12
|
+
active?: boolean;
|
|
13
|
+
disabled?: boolean;
|
|
14
|
+
trailing?: React.ReactNode;
|
|
15
|
+
onClick?: () => void;
|
|
16
|
+
}
|
|
17
|
+
export interface SectionNavProps extends Omit<React.HTMLAttributes<HTMLElement>, "title"> {
|
|
18
|
+
title?: React.ReactNode;
|
|
19
|
+
items: SectionNavItem[];
|
|
20
|
+
}
|
|
21
|
+
declare function SectionNav({ title, items, className, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, ...props }: SectionNavProps): import("react/jsx-runtime").JSX.Element;
|
|
22
|
+
export { SectionNav };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { Button } from "./button";
|
|
4
|
+
import { cn } from "./lib/utils";
|
|
5
|
+
import { Link } from "./link";
|
|
6
|
+
import { Typography } from "./typography";
|
|
7
|
+
function SectionNav({ title, items, className, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, ...props }) {
|
|
8
|
+
const titleId = React.useId();
|
|
9
|
+
const resolvedLabelledBy = ariaLabelledBy !== null && ariaLabelledBy !== void 0 ? ariaLabelledBy : (!ariaLabel && title != null && !React.isValidElement(title)
|
|
10
|
+
? titleId
|
|
11
|
+
: undefined);
|
|
12
|
+
const renderedTitle = title == null ? null : React.isValidElement(title) ? (title) : (_jsx(Typography, { id: titleId, as: "h2", variant: "bodySm", className: "font-medium text-muted-foreground", children: title }));
|
|
13
|
+
return (_jsxs("nav", { className: cn("w-full space-y-3 rounded-xl bg-muted/40 p-3", className), "aria-label": ariaLabel, "aria-labelledby": resolvedLabelledBy, ...props, children: [renderedTitle, _jsx("ul", { className: "space-y-1.5", children: items.map((item) => {
|
|
14
|
+
const Icon = item.icon;
|
|
15
|
+
const itemClasses = cn("w-full justify-start", item.active &&
|
|
16
|
+
!item.disabled &&
|
|
17
|
+
"bg-white hover:bg-white");
|
|
18
|
+
const content = (_jsxs(_Fragment, { children: [Icon ? _jsx(Icon, {}) : null, _jsx("span", { className: "min-w-0 flex-1 truncate text-left", children: item.label }), item.trailing ? (_jsx("span", { className: "shrink-0", children: item.trailing })) : null] }));
|
|
19
|
+
const isLink = Boolean(item.href) && !item.disabled;
|
|
20
|
+
return (_jsx("li", { children: _jsx(Button, { asChild: isLink, variant: "ghost", disabled: item.disabled, className: itemClasses, "aria-current": item.active ? "page" : undefined, ...(isLink
|
|
21
|
+
? {}
|
|
22
|
+
: { type: "button", onClick: item.onClick }), children: isLink ? (_jsx(Link, { variant: "inherit", href: item.href, target: item.target, rel: item.rel, onClick: item.onClick, children: content })) : (content) }) }, item.id));
|
|
23
|
+
}) })] }));
|
|
24
|
+
}
|
|
25
|
+
export { SectionNav };
|
|
@@ -12,6 +12,8 @@ interface SelectContentProps extends React.ComponentPropsWithoutRef<typeof Selec
|
|
|
12
12
|
}
|
|
13
13
|
declare const SelectContent: React.ForwardRefExoticComponent<SelectContentProps & React.RefAttributes<HTMLDivElement>>;
|
|
14
14
|
declare const SelectLabel: React.ForwardRefExoticComponent<Omit<SelectPrimitive.SelectLabelProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
15
|
-
declare const SelectItem: React.ForwardRefExoticComponent<Omit<SelectPrimitive.SelectItemProps & React.RefAttributes<HTMLDivElement>, "ref"> &
|
|
15
|
+
declare const SelectItem: React.ForwardRefExoticComponent<Omit<SelectPrimitive.SelectItemProps & React.RefAttributes<HTMLDivElement>, "ref"> & {
|
|
16
|
+
description?: React.ReactNode;
|
|
17
|
+
} & React.RefAttributes<HTMLDivElement>>;
|
|
16
18
|
declare const SelectSeparator: React.ForwardRefExoticComponent<Omit<SelectPrimitive.SelectSeparatorProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
17
19
|
export { SelectContent, SelectGroup, SelectItem, SelectLabel, SelectRoot, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, };
|
package/dist/select-primitive.js
CHANGED
|
@@ -4,6 +4,7 @@ import * as React from "react";
|
|
|
4
4
|
import * as SelectPrimitive from "@radix-ui/react-select";
|
|
5
5
|
import { Check, ChevronDown, ChevronUp } from "lucide-react";
|
|
6
6
|
import { cn } from "./lib/utils";
|
|
7
|
+
import { Typography } from "./typography";
|
|
7
8
|
function SelectRoot(props) {
|
|
8
9
|
return _jsx(SelectPrimitive.Root, { "data-slot": "select", ...props });
|
|
9
10
|
}
|
|
@@ -13,7 +14,7 @@ function SelectGroup(props) {
|
|
|
13
14
|
function SelectValue(props) {
|
|
14
15
|
return _jsx(SelectPrimitive.Value, { "data-slot": "select-value", ...props });
|
|
15
16
|
}
|
|
16
|
-
const SelectTrigger = React.forwardRef(({ className, children, ...props }, ref) => (_jsxs(SelectPrimitive.Trigger, { ref: ref, "data-slot": "select-trigger", className: cn("flex h-
|
|
17
|
+
const SelectTrigger = React.forwardRef(({ className, children, ...props }, ref) => (_jsxs(SelectPrimitive.Trigger, { ref: ref, "data-slot": "select-trigger", className: cn("flex h-control w-full cursor-pointer items-center justify-between gap-2 whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-sm transition-[color,box-shadow] outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-[invalid=true]:border-destructive aria-[invalid=true]:ring-destructive/20 data-[placeholder]:text-muted-foreground [&>span]:line-clamp-1 [&_svg]:pointer-events-none [&_svg]:shrink-0", className), ...props, children: [children, _jsx(SelectPrimitive.Icon, { asChild: true, children: _jsx(ChevronDown, { className: "h-4 w-4 shrink-0 opacity-50" }) })] })));
|
|
17
18
|
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
|
|
18
19
|
const SelectScrollUpButton = React.forwardRef(({ className, ...props }, ref) => (_jsx(SelectPrimitive.ScrollUpButton, { ref: ref, "data-slot": "select-scroll-up-button", className: cn("flex cursor-pointer items-center justify-center py-1", className), ...props, children: _jsx(ChevronUp, { className: "h-4 w-4" }) })));
|
|
19
20
|
SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
|
|
@@ -26,7 +27,7 @@ const SelectContent = React.forwardRef(({ className, children, header, position
|
|
|
26
27
|
SelectContent.displayName = SelectPrimitive.Content.displayName;
|
|
27
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 })));
|
|
28
29
|
SelectLabel.displayName = SelectPrimitive.Label.displayName;
|
|
29
|
-
const SelectItem = React.forwardRef(({ className, children, ...props }, ref) => (_jsxs(SelectPrimitive.Item, { ref: ref, "data-slot": "select-item", className: cn("relative flex w-full cursor-pointer select-none items-center gap-2 rounded-sm py-
|
|
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-control w-full cursor-pointer select-none items-center gap-2 rounded-sm py-2 pl-2 pr-8 text-sm outline-none focus:bg-accent focus:text-accent-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] })] })));
|
|
30
31
|
SelectItem.displayName = SelectPrimitive.Item.displayName;
|
|
31
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 })));
|
|
32
33
|
SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
|
package/dist/select.d.ts
CHANGED
package/dist/select.js
CHANGED
|
@@ -87,11 +87,11 @@ function Select({ label, options, placeholder = "Select an option", description,
|
|
|
87
87
|
}
|
|
88
88
|
onOpenChange === null || onOpenChange === void 0 ? void 0 : onOpenChange(nextOpen);
|
|
89
89
|
}, [onOpenChange, open]);
|
|
90
|
-
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, { className: contentClassName, header: searchable ? (_jsx(InputControl, { ref: searchInputRef, value: searchQuery, onChange: (event) => setSearchQuery(event.target.value), placeholder: searchPlaceholder, "aria-label": searchInputAriaLabel, autoComplete: "off", className: "h-
|
|
90
|
+
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, { className: contentClassName, 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 focus-visible:border-0 focus-visible:ring-0", onKeyDown: (event) => {
|
|
91
91
|
event.stopPropagation();
|
|
92
92
|
} })) : undefined, viewportClassName: searchable ? "max-h-64" : undefined, children: hasVisibleOptions ? (optionGroups.map((group, groupIndex) => {
|
|
93
93
|
var _a;
|
|
94
|
-
return (_jsxs(React.Fragment, { children: [_jsxs(SelectGroup, { children: [group.group ? (_jsx(SelectLabel, { children: _jsx(SearchHighlight, { text: group.group, query: searchQuery }) })) : null, group.options.map((option) => (_jsx(SelectItem, { value: option.value, disabled: option.disabled, textValue: getOptionTextValue(option), children: renderHighlightedLabel(option.label, searchQuery) }, option.value)))] }), groupIndex < optionGroups.length - 1 ? _jsx(SelectSeparator, {}) : null] }, (_a = group.group) !== null && _a !== void 0 ? _a : `group-${groupIndex}`));
|
|
95
|
-
})) : (_jsx("div", { className: "px-3 py-
|
|
94
|
+
return (_jsxs(React.Fragment, { children: [_jsxs(SelectGroup, { children: [group.group ? (_jsx(SelectLabel, { children: _jsx(SearchHighlight, { text: group.group, query: searchQuery }) })) : null, group.options.map((option) => (_jsx(SelectItem, { value: option.value, disabled: option.disabled, textValue: getOptionTextValue(option), description: option.description, children: renderHighlightedLabel(option.label, searchQuery) }, option.value)))] }), groupIndex < optionGroups.length - 1 ? _jsx(SelectSeparator, {}) : null] }, (_a = group.group) !== null && _a !== void 0 ? _a : `group-${groupIndex}`));
|
|
95
|
+
})) : (_jsx("div", { className: "px-3 py-2 text-sm text-muted-foreground", children: searchEmptyMessage })) })] }), showDescription ? (_jsx(FieldDescription, { id: descriptionId, className: descriptionClassName, children: description })) : null, _jsx(FieldError, { id: errorId, className: errorClassName, children: error })] }));
|
|
96
96
|
}
|
|
97
97
|
export { Select };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export interface SeparatorProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
3
|
+
orientation?: "horizontal" | "vertical";
|
|
4
|
+
}
|
|
5
|
+
declare const Separator: React.ForwardRefExoticComponent<SeparatorProps & React.RefAttributes<HTMLDivElement>>;
|
|
6
|
+
export { Separator };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { cn } from "./lib/utils";
|
|
4
|
+
const Separator = React.forwardRef(({ className, orientation = "horizontal", ...props }, ref) => (_jsx("div", { ref: ref, role: "separator", "aria-orientation": orientation, className: cn("shrink-0 bg-border", orientation === "horizontal" ? "h-[1px] w-full" : "h-full w-[1px]", className), ...props })));
|
|
5
|
+
Separator.displayName = "Separator";
|
|
6
|
+
export { Separator };
|