@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
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { format, parse } from "date-fns";
|
|
5
|
+
import { Calendar } from "./calendar";
|
|
6
|
+
import { inputControlClassName } from "./input-control";
|
|
7
|
+
import { Field, FieldDescription, FieldError, FieldLabel } from "./field";
|
|
8
|
+
import { PopoverContent, PopoverRoot, PopoverTrigger } from "./popover-primitive";
|
|
9
|
+
import { cn } from "./lib/utils";
|
|
10
|
+
function parseDateString(dateStr) {
|
|
11
|
+
if (!(dateStr === null || dateStr === void 0 ? void 0 : dateStr.trim()))
|
|
12
|
+
return undefined;
|
|
13
|
+
try {
|
|
14
|
+
const nativeDate = new Date(dateStr);
|
|
15
|
+
if (!isNaN(nativeDate.getTime()))
|
|
16
|
+
return nativeDate;
|
|
17
|
+
const ddmmyyyyMatch = dateStr.match(/^(\d{1,2})\/(\d{1,2})\/(\d{4})/);
|
|
18
|
+
if (ddmmyyyyMatch) {
|
|
19
|
+
const [, day, month, year] = ddmmyyyyMatch;
|
|
20
|
+
const date = new Date(parseInt(year), parseInt(month) - 1, parseInt(day));
|
|
21
|
+
if (!isNaN(date.getTime()))
|
|
22
|
+
return date;
|
|
23
|
+
}
|
|
24
|
+
const date = parse(dateStr, "yyyy-MM-dd", new Date());
|
|
25
|
+
if (!isNaN(date.getTime()))
|
|
26
|
+
return date;
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function formatISODate(date) {
|
|
34
|
+
return format(date, "yyyy-MM-dd");
|
|
35
|
+
}
|
|
36
|
+
const DateInput = React.forwardRef(({ label, value, onValueChange, description, error, invalid = false, hideLabel = false, placeholder = "Pick a date", disabled = false, minDate, maxDate, className, triggerClassName, labelClassName, descriptionClassName, errorClassName, id, }, ref) => {
|
|
37
|
+
const [open, setOpen] = React.useState(false);
|
|
38
|
+
const generatedId = React.useId();
|
|
39
|
+
const inputId = id !== null && id !== void 0 ? id : `date-input-${generatedId}`;
|
|
40
|
+
const errorId = error ? `${inputId}-error` : undefined;
|
|
41
|
+
const showDescription = Boolean(description) && !error;
|
|
42
|
+
const descriptionId = showDescription ? `${inputId}-description` : undefined;
|
|
43
|
+
const isInvalid = invalid || Boolean(error);
|
|
44
|
+
const selectedDate = React.useMemo(() => parseDateString(value), [value]);
|
|
45
|
+
const displayValue = selectedDate
|
|
46
|
+
? format(selectedDate, "d MMM yyyy")
|
|
47
|
+
: undefined;
|
|
48
|
+
const handleSelect = (date) => {
|
|
49
|
+
onValueChange(date ? formatISODate(date) : "");
|
|
50
|
+
setOpen(false);
|
|
51
|
+
};
|
|
52
|
+
return (_jsxs(Field, { className: className, "data-disabled": disabled ? "true" : undefined, "data-invalid": isInvalid ? "true" : undefined, children: [_jsx(FieldLabel, { htmlFor: inputId, className: cn(hideLabel && "sr-only", labelClassName), children: label }), _jsxs(PopoverRoot, { open: open, onOpenChange: setOpen, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs("div", { className: "relative w-full", children: [_jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground", style: { width: 14, height: 14 }, "aria-hidden": "true", children: [_jsx("rect", { width: "18", height: "18", x: "3", y: "4", rx: "2", ry: "2" }), _jsx("line", { x1: "16", x2: "16", y1: "2", y2: "6" }), _jsx("line", { x1: "8", x2: "8", y1: "2", y2: "6" }), _jsx("line", { x1: "3", x2: "21", y1: "10", y2: "10" })] }), _jsx("button", { ref: ref, type: "button", id: inputId, disabled: disabled, "aria-invalid": isInvalid ? "true" : undefined, "aria-describedby": [descriptionId, errorId].filter(Boolean).join(" ") || undefined, className: cn(inputControlClassName, "cursor-pointer pl-9 text-left", !selectedDate && "text-muted-foreground", isInvalid && "border-destructive focus-visible:ring-destructive", triggerClassName), children: displayValue !== null && displayValue !== void 0 ? displayValue : _jsx("span", { children: placeholder }) })] }) }), _jsx(PopoverContent, { className: "w-auto p-0", align: "start", children: _jsx(Calendar, { mode: "single", selected: selectedDate, onSelect: handleSelect, disabled: (date) => {
|
|
53
|
+
if (minDate && date < minDate)
|
|
54
|
+
return true;
|
|
55
|
+
if (maxDate && date > maxDate)
|
|
56
|
+
return true;
|
|
57
|
+
return false;
|
|
58
|
+
}, defaultMonth: selectedDate, autoFocus: true }) })] }), showDescription ? (_jsx(FieldDescription, { id: descriptionId, className: descriptionClassName, children: description })) : null, _jsx(FieldError, { id: errorId, className: errorClassName, children: error })] }));
|
|
59
|
+
});
|
|
60
|
+
DateInput.displayName = "DateInput";
|
|
61
|
+
export { DateInput };
|
package/dist/dialog-primitive.js
CHANGED
|
@@ -10,7 +10,7 @@ const DialogPortal = DialogPrimitive.Portal;
|
|
|
10
10
|
const DialogClose = DialogPrimitive.Close;
|
|
11
11
|
const DialogOverlay = React.forwardRef(({ className, ...props }, ref) => (_jsx(DialogPrimitive.Overlay, { ref: ref, className: cn("fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0", className), ...props })));
|
|
12
12
|
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
|
|
13
|
-
const DialogSurface = React.forwardRef(({ className, children, hideCloseButton, ...props }, ref) => (_jsxs(DialogPortal, { children: [_jsx(DialogOverlay, {}), _jsxs(DialogPrimitive.Content, { ref: ref, className: cn("fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 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-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg", className), ...props, children: [children, !hideCloseButton ? (_jsxs(DialogPrimitive.Close, { className: "absolute right-
|
|
13
|
+
const DialogSurface = React.forwardRef(({ className, children, hideCloseButton, ...props }, ref) => (_jsxs(DialogPortal, { children: [_jsx(DialogOverlay, {}), _jsxs(DialogPrimitive.Content, { ref: ref, className: cn("fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 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-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg", className), ...props, children: [children, !hideCloseButton ? (_jsxs(DialogPrimitive.Close, { className: "absolute right-2 top-2 flex h-6 w-6 cursor-pointer items-center justify-center rounded-md text-muted-foreground ring-offset-background transition-colors hover:bg-accent hover:text-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none", children: [_jsx(XIcon, { size: 16 }), _jsx("span", { className: "sr-only", children: "Close" })] })) : null] })] })));
|
|
14
14
|
DialogSurface.displayName = DialogPrimitive.Content.displayName;
|
|
15
15
|
const DialogHeader = ({ className, ...props }) => (_jsx("div", { className: cn("flex flex-col space-y-1.5 text-center sm:text-left", className), ...props }));
|
|
16
16
|
DialogHeader.displayName = "DialogHeader";
|
package/dist/draggable-tabs.js
CHANGED
|
@@ -19,7 +19,7 @@ function TabButton({ item, dragHandleProps, }) {
|
|
|
19
19
|
: isDraggable
|
|
20
20
|
? "cursor-grab active:cursor-grabbing"
|
|
21
21
|
: "cursor-pointer", item.active
|
|
22
|
-
? (_a = item.activeClassName) !== null && _a !== void 0 ? _a : "border-green-500"
|
|
22
|
+
? (_a = item.activeClassName) !== null && _a !== void 0 ? _a : "border-green-500 hover:bg-muted"
|
|
23
23
|
: (_b = item.inactiveClassName) !== null && _b !== void 0 ? _b : "border-transparent hover:bg-muted", item.className), ...dragHandleProps, children: [_jsxs("button", { type: "button", onClick: item.disabled ? undefined : item.onSelect, disabled: item.disabled, className: cn("flex cursor-pointer items-center gap-2 py-3 pr-1 text-sm font-medium whitespace-nowrap disabled:cursor-not-allowed", labelClassName), children: [item.leading, item.label, item.trailing] }), item.onClose ? (_jsx("button", { type: "button", onClick: (event) => {
|
|
24
24
|
var _a;
|
|
25
25
|
event.stopPropagation();
|
package/dist/drawer.js
CHANGED
|
@@ -46,7 +46,7 @@ const drawerSurfaceVariants = cva("fixed z-50 flex flex-col gap-4 overflow-y-aut
|
|
|
46
46
|
},
|
|
47
47
|
});
|
|
48
48
|
function DrawerSurface({ side, className, children, hideCloseButton, ...props }) {
|
|
49
|
-
return (_jsxs(DialogPortal, { children: [_jsx(DialogOverlay, {}), _jsxs(DialogPrimitive.Content, { className: cn(drawerSurfaceVariants({ side }), className), ...props, children: [children, !hideCloseButton ? (_jsxs(DialogPrimitive.Close, { className: "absolute right-
|
|
49
|
+
return (_jsxs(DialogPortal, { children: [_jsx(DialogOverlay, {}), _jsxs(DialogPrimitive.Content, { className: cn(drawerSurfaceVariants({ side }), className), ...props, children: [children, !hideCloseButton ? (_jsxs(DialogPrimitive.Close, { className: "absolute right-2 top-2 flex h-6 w-6 cursor-pointer items-center justify-center rounded-md text-muted-foreground ring-offset-background transition-colors hover:bg-accent hover:text-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none", children: [_jsx(XIcon, { size: 16 }), _jsx("span", { className: "sr-only", children: "Close" })] })) : null] })] }));
|
|
50
50
|
}
|
|
51
51
|
function Drawer({ open, defaultOpen, onOpenChange, modal, trigger, title, description, children, footer, primaryAction, secondaryAction, side = "right", contentClassName, bodyClassName, hideCloseButton, }) {
|
|
52
52
|
const [isOpen, setIsOpen] = useControllableOpen({
|
package/dist/editable-table.js
CHANGED
|
@@ -97,11 +97,11 @@ function EditableTable({ value, onChange, columns, isEditing = false, className,
|
|
|
97
97
|
return String(cellValue);
|
|
98
98
|
};
|
|
99
99
|
const hasActionsColumn = isEditing || Boolean(renderRowActions);
|
|
100
|
-
return (_jsxs("div", { className: cn("space-y-2", className), children: [_jsx("div", { className: "rounded-md border", children: _jsxs(Table, { className: "table-fixed", children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [columns.map((column, index) => (_jsx(TableHead, { width: column.width, minWidth: getColumnMinWidth(column), children: _jsx("div", { className: "whitespace-nowrap", children: column.header }) }, `header-${index}`))), hasActionsColumn ? (_jsx(TableHead, { width: renderRowActions ? undefined : "
|
|
100
|
+
return (_jsxs("div", { className: cn("space-y-2", className), children: [_jsx("div", { className: "rounded-md border", children: _jsxs(Table, { className: "table-fixed", children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [columns.map((column, index) => (_jsx(TableHead, { width: column.width, minWidth: getColumnMinWidth(column), children: _jsx("div", { className: "whitespace-nowrap", children: column.header }) }, `header-${index}`))), hasActionsColumn ? (_jsx(TableHead, { width: renderRowActions ? undefined : "72px", minWidth: renderRowActions ? "120px" : "72px" })) : null] }) }), _jsx(TableBody, { children: value.length === 0 ? (_jsx(TableRow, { children: _jsx(TableCell, { colSpan: columns.length + (hasActionsColumn ? 1 : 0), className: "py-8 text-center text-muted-foreground", children: "No data available" }) })) : (value.map((row, rowIndex) => (_jsxs(TableRow, { className: rowIndex % 2 === 0 ? "bg-muted/30" : undefined, children: [columns.map((column, columnIndex) => {
|
|
101
101
|
const cellValue = getNestedValue(row, column.path);
|
|
102
102
|
const isEditingCell = (editingCell === null || editingCell === void 0 ? void 0 : editingCell.rowIndex) === rowIndex &&
|
|
103
103
|
(editingCell === null || editingCell === void 0 ? void 0 : editingCell.colPath) === column.path;
|
|
104
|
-
return (_jsx(TableCell, { className: cn("whitespace-normal", isEditing && "cursor-pointer hover:bg-muted/50"), minWidth: getColumnMinWidth(column), onClick: () => handleCellClick(rowIndex, column.path), children: isEditingCell ? (_jsx(InputControl, { ref: inputRef, value: editValue, onChange: (event) => setEditValue(event.target.value), onBlur: commitEdit, onKeyDown: handleKeyDown, className: "h-
|
|
104
|
+
return (_jsx(TableCell, { className: cn("whitespace-normal", isEditing && "cursor-pointer hover:bg-muted/50"), minWidth: getColumnMinWidth(column), onClick: () => handleCellClick(rowIndex, column.path), children: isEditingCell ? (_jsx(InputControl, { ref: inputRef, value: editValue, onChange: (event) => setEditValue(event.target.value), onBlur: commitEdit, onKeyDown: handleKeyDown, className: "h-control w-full text-sm" })) : (_jsx("span", { className: cn("block whitespace-normal break-words", cellValue === null ||
|
|
105
105
|
cellValue === undefined ||
|
|
106
106
|
cellValue === ""
|
|
107
107
|
? "text-muted-foreground"
|
package/dist/empty-state.js
CHANGED
|
@@ -2,6 +2,6 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { cn } from "./lib/utils";
|
|
3
3
|
import { Typography } from "./typography";
|
|
4
4
|
function EmptyState({ message, description, icon: Icon, action, className, ...props }) {
|
|
5
|
-
return (_jsxs("div", { className: cn("flex flex-col items-center justify-center px-6 py-10 text-center", className), ...props, children: [Icon ? (_jsx(Icon, { className: "mb-4 h-
|
|
5
|
+
return (_jsxs("div", { className: cn("flex flex-col items-center justify-center px-6 py-10 text-center", className), ...props, children: [Icon ? (_jsx(Icon, { className: "mb-4 h-10 w-10 stroke-[1.5] text-muted-foreground/70" })) : null, _jsxs("div", { className: "space-y-1.5", children: [_jsx(Typography, { as: "p", variant: "bodySm", className: "font-semibold", children: message }), description ? (_jsx(Typography, { as: "p", variant: "caption", className: "max-w-md", children: description })) : null] }), action ? _jsx("div", { className: "pt-6", children: action }) : null] }));
|
|
6
6
|
}
|
|
7
7
|
export { EmptyState };
|
package/dist/field.d.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
declare function Field({ className, ...props }: React.ComponentProps<"div">): import("react/jsx-runtime").JSX.Element;
|
|
3
|
-
|
|
3
|
+
interface FieldLabelProps extends React.ComponentProps<"label"> {
|
|
4
|
+
required?: boolean;
|
|
5
|
+
}
|
|
6
|
+
declare function FieldLabel({ className, required, children, ...props }: FieldLabelProps): import("react/jsx-runtime").JSX.Element;
|
|
4
7
|
declare function FieldDescription({ className, ...props }: React.ComponentProps<"p">): import("react/jsx-runtime").JSX.Element;
|
|
5
8
|
declare function FieldError({ className, ...props }: React.ComponentProps<"p">): import("react/jsx-runtime").JSX.Element | null;
|
|
6
9
|
export { Field, FieldDescription, FieldError, FieldLabel };
|
package/dist/field.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { cn } from "./lib/utils";
|
|
3
3
|
function Field({ className, ...props }) {
|
|
4
4
|
return (_jsx("div", { "data-slot": "field", className: cn("group/field flex w-full flex-col gap-2", className), ...props }));
|
|
5
5
|
}
|
|
6
|
-
function FieldLabel({ className, ...props }) {
|
|
7
|
-
return (
|
|
6
|
+
function FieldLabel({ className, required, children, ...props }) {
|
|
7
|
+
return (_jsxs("label", { "data-slot": "field-label", className: cn("text-sm font-medium leading-none group-data-[disabled=true]/field:cursor-not-allowed group-data-[disabled=true]/field:opacity-50 group-data-[invalid=true]/field:text-destructive", className), ...props, children: [children, required ? (_jsx("span", { "aria-hidden": "true", className: "ml-0.5 text-destructive", children: "*" })) : null] }));
|
|
8
8
|
}
|
|
9
9
|
function FieldDescription({ className, ...props }) {
|
|
10
10
|
return (_jsx("p", { "data-slot": "field-description", className: cn("text-sm leading-normal text-muted-foreground", className), ...props }));
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { FileUploadProgress } from "./use-file-upload";
|
|
2
|
+
export interface FileUploadProps {
|
|
3
|
+
accept?: string;
|
|
4
|
+
maxSize?: number;
|
|
5
|
+
maxFiles?: number;
|
|
6
|
+
onFilesChange: (files: File[]) => void;
|
|
7
|
+
value?: File[];
|
|
8
|
+
disabled?: boolean;
|
|
9
|
+
className?: string;
|
|
10
|
+
uploadProgress?: Map<string, FileUploadProgress>;
|
|
11
|
+
}
|
|
12
|
+
export declare function FileUpload({ accept, maxSize, maxFiles, onFilesChange, value, disabled, className, uploadProgress, }: FileUploadProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { useCallback, useState } from "react";
|
|
5
|
+
import { File, ImageIcon } from "lucide-react";
|
|
6
|
+
import { CheckIcon } from "./animated-icons/check";
|
|
7
|
+
import { FileTextIcon } from "./animated-icons/file-text";
|
|
8
|
+
import { UploadIcon } from "./animated-icons/upload";
|
|
9
|
+
import { XIcon } from "./animated-icons/x";
|
|
10
|
+
import { Button } from "./button";
|
|
11
|
+
import { cn } from "./lib/utils";
|
|
12
|
+
import { Progress } from "./progress";
|
|
13
|
+
const DEFAULT_MAX_FILE_SIZE = 10 * 1024 * 1024;
|
|
14
|
+
function formatFileSize(bytes) {
|
|
15
|
+
if (bytes === 0)
|
|
16
|
+
return "0 B";
|
|
17
|
+
const k = 1024;
|
|
18
|
+
const sizes = ["B", "KB", "MB", "GB"];
|
|
19
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
20
|
+
return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + " " + sizes[i];
|
|
21
|
+
}
|
|
22
|
+
function getFileIcon(file) {
|
|
23
|
+
if (file.type.startsWith("image/")) {
|
|
24
|
+
return _jsx(ImageIcon, { className: "h-4 w-4 text-blue-500" });
|
|
25
|
+
}
|
|
26
|
+
if (file.type === "application/pdf") {
|
|
27
|
+
return _jsx(FileTextIcon, { className: "text-red-500", size: 16 });
|
|
28
|
+
}
|
|
29
|
+
return _jsx(File, { className: "h-4 w-4 text-muted-foreground" });
|
|
30
|
+
}
|
|
31
|
+
export function FileUpload({ accept, maxSize = DEFAULT_MAX_FILE_SIZE, maxFiles = 10, onFilesChange, value = [], disabled = false, className, uploadProgress, }) {
|
|
32
|
+
const [isDragOver, setIsDragOver] = useState(false);
|
|
33
|
+
const [error, setError] = useState(null);
|
|
34
|
+
const inputRef = React.useRef(null);
|
|
35
|
+
const validateFiles = useCallback((files) => {
|
|
36
|
+
const validFiles = [];
|
|
37
|
+
const fileArray = Array.from(files);
|
|
38
|
+
for (const file of fileArray) {
|
|
39
|
+
if (value.length + validFiles.length >= maxFiles) {
|
|
40
|
+
setError(`Maximum ${maxFiles} files allowed`);
|
|
41
|
+
break;
|
|
42
|
+
}
|
|
43
|
+
if (file.size > maxSize) {
|
|
44
|
+
setError(`File "${file.name}" exceeds ${formatFileSize(maxSize)} limit`);
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
if (value.some((f) => f.name === file.name && f.size === file.size)) {
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
validFiles.push(file);
|
|
51
|
+
}
|
|
52
|
+
return validFiles;
|
|
53
|
+
}, [maxFiles, maxSize, value]);
|
|
54
|
+
const handleFiles = useCallback((files) => {
|
|
55
|
+
setError(null);
|
|
56
|
+
const validFiles = validateFiles(files);
|
|
57
|
+
if (validFiles.length > 0) {
|
|
58
|
+
onFilesChange([...value, ...validFiles]);
|
|
59
|
+
}
|
|
60
|
+
}, [validateFiles, value, onFilesChange]);
|
|
61
|
+
const handleDrop = useCallback((e) => {
|
|
62
|
+
e.preventDefault();
|
|
63
|
+
setIsDragOver(false);
|
|
64
|
+
if (disabled)
|
|
65
|
+
return;
|
|
66
|
+
handleFiles(e.dataTransfer.files);
|
|
67
|
+
}, [disabled, handleFiles]);
|
|
68
|
+
const handleDragOver = useCallback((e) => {
|
|
69
|
+
e.preventDefault();
|
|
70
|
+
setIsDragOver(true);
|
|
71
|
+
}, []);
|
|
72
|
+
const handleDragLeave = useCallback((e) => {
|
|
73
|
+
e.preventDefault();
|
|
74
|
+
setIsDragOver(false);
|
|
75
|
+
}, []);
|
|
76
|
+
const handleInputChange = useCallback((e) => {
|
|
77
|
+
if (e.target.files) {
|
|
78
|
+
handleFiles(e.target.files);
|
|
79
|
+
}
|
|
80
|
+
e.target.value = "";
|
|
81
|
+
}, [handleFiles]);
|
|
82
|
+
const removeFile = useCallback((index) => {
|
|
83
|
+
const newFiles = value.filter((_, i) => i !== index);
|
|
84
|
+
onFilesChange(newFiles);
|
|
85
|
+
setError(null);
|
|
86
|
+
}, [value, onFilesChange]);
|
|
87
|
+
const openFilePicker = useCallback(() => {
|
|
88
|
+
var _a;
|
|
89
|
+
(_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.click();
|
|
90
|
+
}, []);
|
|
91
|
+
const fileInput = (_jsx("input", { ref: inputRef, type: "file", accept: accept, multiple: maxFiles > 1, onChange: handleInputChange, disabled: disabled, className: "hidden" }));
|
|
92
|
+
return (_jsxs("div", { className: cn("space-y-3", className), children: [fileInput, _jsxs("div", { onDrop: handleDrop, onDragOver: handleDragOver, onDragLeave: handleDragLeave, onClick: openFilePicker, className: cn("relative flex cursor-pointer flex-col items-center justify-center gap-2 rounded-lg border border-dashed p-6 transition-colors", isDragOver && !disabled
|
|
93
|
+
? "border-primary bg-primary/5"
|
|
94
|
+
: "border-muted-foreground/25 hover:border-muted-foreground/50", disabled && "cursor-not-allowed opacity-50"), children: [_jsx(UploadIcon, { className: cn(isDragOver ? "text-primary" : "text-muted-foreground"), size: 32 }), _jsxs("div", { className: "text-center", children: [_jsx("p", { className: "text-sm font-medium", children: isDragOver ? "Drop files here" : "Drag & drop files here" }), _jsxs("p", { className: "mt-1 text-xs text-muted-foreground", children: ["or click to browse (max ", formatFileSize(maxSize), " each)"] })] })] }), error ? _jsx("p", { className: "text-sm text-destructive", children: error }) : null, value.length > 0 ? (_jsx("div", { className: "space-y-2", children: value.map((file, index) => {
|
|
95
|
+
var _a;
|
|
96
|
+
const progress = uploadProgress === null || uploadProgress === void 0 ? void 0 : uploadProgress.get(file.name);
|
|
97
|
+
const isUploading = (progress === null || progress === void 0 ? void 0 : progress.status) === "uploading";
|
|
98
|
+
const isComplete = (progress === null || progress === void 0 ? void 0 : progress.status) === "complete";
|
|
99
|
+
const isError = (progress === null || progress === void 0 ? void 0 : progress.status) === "error";
|
|
100
|
+
return (_jsxs("div", { className: "rounded-md border bg-muted/30 px-3 py-2", children: [_jsxs("div", { className: "flex items-center gap-3", children: [getFileIcon(file), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("p", { className: "truncate text-sm font-medium", children: file.name }), _jsxs("p", { className: "text-xs text-muted-foreground", children: [formatFileSize(file.size), isUploading && ` • ${progress === null || progress === void 0 ? void 0 : progress.progress}%`, isComplete && " • Complete", isError && ` • ${(progress === null || progress === void 0 ? void 0 : progress.error) || "Error"}`] })] }), isComplete ? (_jsx("div", { className: "flex h-6 w-6 shrink-0 items-center justify-center text-green-500", children: _jsx(CheckIcon, { size: 16 }) })) : (_jsx(Button, { type: "button", variant: "ghost", size: "icon", className: "h-6 w-6 shrink-0", onClick: (e) => {
|
|
101
|
+
e.stopPropagation();
|
|
102
|
+
removeFile(index);
|
|
103
|
+
}, disabled: disabled || isUploading, "aria-label": `Remove ${file.name}`, children: _jsx(XIcon, { size: 16 }) }))] }), (isUploading ||
|
|
104
|
+
(progress && progress.status === "pending")) && (_jsx("div", { className: "mt-2", children: _jsx(Progress, { value: (_a = progress === null || progress === void 0 ? void 0 : progress.progress) !== null && _a !== void 0 ? _a : 0, size: "sm", variant: isError ? "error" : "default", label: `Uploading ${file.name}` }) }))] }, `${file.name}-${file.size}-${index}`));
|
|
105
|
+
}) })) : null] }));
|
|
106
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,19 @@
|
|
|
1
|
-
export { Avatar, AvatarProfile, AvatarRoot, AvatarImage,
|
|
1
|
+
export { Avatar, AvatarProfile, AvatarRoot, AvatarImage, } from "./avatar";
|
|
2
2
|
export type { AvatarProps, AvatarProfileProps, AvatarRootProps, } from "./avatar";
|
|
3
3
|
export * from "./animated-icons";
|
|
4
|
+
export { Alert, alertVariants } from "./alert";
|
|
5
|
+
export type { AlertProps } from "./alert";
|
|
4
6
|
export { Badge, badgeVariants } from "./badge";
|
|
7
|
+
export { Card } from "./card";
|
|
8
|
+
export type { CardProps } from "./card";
|
|
5
9
|
export type { BadgeProps } from "./badge";
|
|
10
|
+
export { Calendar, CalendarDayButton } from "./calendar";
|
|
11
|
+
export { Checkbox } from "./checkbox";
|
|
12
|
+
export type { CheckboxProps } from "./checkbox";
|
|
13
|
+
export { Switch } from "./switch";
|
|
14
|
+
export type { SwitchProps } from "./switch";
|
|
15
|
+
export { DateInput } from "./date-input";
|
|
16
|
+
export type { DateInputProps } from "./date-input";
|
|
6
17
|
export { CountBadge } from "./count-badge";
|
|
7
18
|
export type { CountBadgeProps } from "./count-badge";
|
|
8
19
|
export { EmptyState } from "./empty-state";
|
|
@@ -15,6 +26,8 @@ export { Input } from "./input";
|
|
|
15
26
|
export type { InputProps } from "./input";
|
|
16
27
|
export { Select } from "./select";
|
|
17
28
|
export type { SelectOption, SelectProps } from "./select";
|
|
29
|
+
export { MultiSelect } from "./multi-select";
|
|
30
|
+
export type { MultiSelectOption, MultiSelectProps } from "./multi-select";
|
|
18
31
|
export { DEFAULT_COUNTRY_CODES, PhoneInput, } from "./phone-input";
|
|
19
32
|
export type { CountryCode, PhoneInputProps, } from "./phone-input";
|
|
20
33
|
export { OtpInput } from "./otp-input";
|
|
@@ -25,26 +38,50 @@ export { LabelValueGrid } from "./label-value-grid";
|
|
|
25
38
|
export type { LabelValueGridItem, LabelValueGridProps, } from "./label-value-grid";
|
|
26
39
|
export { Breadcrumb, BreadcrumbNav, BreadcrumbList, BreadcrumbItem, BreadcrumbLink, BreadcrumbPage, BreadcrumbSeparator, BreadcrumbEllipsis, } from "./breadcrumb";
|
|
27
40
|
export type { BreadcrumbEntry, BreadcrumbProps } from "./breadcrumb";
|
|
41
|
+
export { BackButton } from "./back-button";
|
|
42
|
+
export type { BackButtonProps } from "./back-button";
|
|
28
43
|
export { Button, buttonVariants } from "./button";
|
|
29
44
|
export type { ButtonProps } from "./button";
|
|
45
|
+
export { Link, linkVariants } from "./link";
|
|
46
|
+
export type { LinkProps } from "./link";
|
|
30
47
|
export { Dialog } from "./dialog";
|
|
31
48
|
export type { DialogAction, DialogProps } from "./dialog";
|
|
32
49
|
export { Command, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem, CommandSeparator, CommandShortcut, } from "./command";
|
|
33
50
|
export { CommandSearch, type CommandSearchFilter, type CommandSearchItem, type CommandSearchProps, type CommandSearchSection, } from "./command-search";
|
|
51
|
+
export { FileUpload } from "./file-upload";
|
|
52
|
+
export type { FileUploadProps } from "./file-upload";
|
|
53
|
+
export { Progress } from "./progress";
|
|
54
|
+
export type { ProgressProps } from "./progress";
|
|
55
|
+
export { useFileUpload } from "./use-file-upload";
|
|
56
|
+
export type { FileUploadProgress, FileUploadResult, FileUploadStatus, UseFileUploadOptions, UseFileUploadReturn, } from "./use-file-upload";
|
|
57
|
+
export { Popover } from "./popover";
|
|
58
|
+
export type { PopoverProps } from "./popover";
|
|
59
|
+
export { PopoverMenuContent, PopoverMenuHeader, PopoverMenuSection, PopoverMenuItem, PopoverMenuDivider, PopoverMenuGroup, PopoverMenuGroupLabel, PopoverMenuSearch, PopoverMenuScrollArea, } from "./popover-menu";
|
|
60
|
+
export type { PopoverMenuContentProps, PopoverMenuHeaderProps, PopoverMenuSectionProps, PopoverMenuItemProps, PopoverMenuDividerProps, PopoverMenuGroupProps, PopoverMenuGroupLabelProps, PopoverMenuSearchProps, PopoverMenuScrollAreaProps, } from "./popover-menu";
|
|
34
61
|
export { SearchInput } from "./search-input";
|
|
35
62
|
export type { SearchInputProps } from "./search-input";
|
|
63
|
+
export { SectionNav } from "./section-nav";
|
|
64
|
+
export type { SectionNavItem, SectionNavProps } from "./section-nav";
|
|
36
65
|
export { GovtMasthead } from "./govt-masthead";
|
|
37
66
|
export type { GovtMastheadProps } from "./govt-masthead";
|
|
38
67
|
export { SearchHighlight, useSearchHighlight, } from "./use-search-highlight";
|
|
39
68
|
export type { SearchHighlightProps, SearchHighlightSegment, } from "./use-search-highlight";
|
|
69
|
+
export { useErrorShake } from "./use-error-shake";
|
|
70
|
+
export type { UseErrorShakeOptions } from "./use-error-shake";
|
|
71
|
+
export { useStickySentinel } from "./use-sticky-sentinel";
|
|
72
|
+
export type { UseStickySentinelOptions, UseStickySentinelReturn, } from "./use-sticky-sentinel";
|
|
73
|
+
export { useViewportThreshold } from "./use-viewport-threshold";
|
|
74
|
+
export type { UseViewportThresholdOptions, UseViewportThresholdReturn, } from "./use-viewport-threshold";
|
|
40
75
|
export { Textarea } from "./textarea";
|
|
41
76
|
export type { TextareaProps } from "./textarea";
|
|
42
77
|
export { DraggableTabs, type DraggableTabItem, type DraggableTabsProps, } from "./draggable-tabs";
|
|
43
78
|
export { Drawer, } from "./drawer";
|
|
44
79
|
export type { DrawerAction, DrawerProps, DrawerSide } from "./drawer";
|
|
45
|
-
export { DashboardLayout, DashboardSidebar,
|
|
46
|
-
export type { DashboardSidebarNavGroup, DashboardSidebarNavItem, } from "./layout";
|
|
80
|
+
export { DashboardLayout, DashboardSidebar, useSidebar, } from "./layout";
|
|
81
|
+
export type { DashboardLayoutProps, DashboardSidebarNavGroup, DashboardSidebarNavItem, } from "./layout";
|
|
47
82
|
export { PageHeader } from "./page-header";
|
|
83
|
+
export { PageSection, PageSectionGroup } from "./page-section";
|
|
84
|
+
export type { PageSectionGroupProps, PageSectionProps } from "./page-section";
|
|
48
85
|
export { Typography, typographyVariants } from "./typography";
|
|
49
86
|
export type { TypographyProps } from "./typography";
|
|
50
87
|
export { neaPalette, semanticColorTokens, typographyTokens, radiusTokens, spacingTokens, layoutTokens, } from "./theme";
|
|
@@ -53,8 +90,23 @@ export { Pagination } from "./pagination";
|
|
|
53
90
|
export type { PaginationProps } from "./pagination";
|
|
54
91
|
export { TableToolbar } from "./table-toolbar";
|
|
55
92
|
export type { TableToolbarProps } from "./table-toolbar";
|
|
93
|
+
export { useTableSort } from "./use-table-sort";
|
|
94
|
+
export type { UseTableSortOptions, UseTableSortReturn, } from "./use-table-sort";
|
|
56
95
|
export { Table, TableRoot, TableContainer, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell, TableCaption, TableRowSkeleton, TABLE_SKELETON_PRESETS, } from "./table";
|
|
57
96
|
export type { TableColumn, TableProps, TableSortDirection, TableSortingProps, TableSkeletonConfig, TableRowSkeletonProps, } from "./table";
|
|
58
|
-
export { Tabs, TabsRoot, type TabsItem, type TabsProps, TabsList, TabsTrigger, TabsContent, useTabsContext, } from "./tabs";
|
|
97
|
+
export { Tabs, TabsRoot, TabWithDropdown, type TabsItem, type TabsProps, TabsList, TabsTrigger, TabsContent, type TabWithDropdownProps, useTabsContext, type TabDropdownSection, } from "./tabs";
|
|
59
98
|
export { Tooltip, TooltipRoot, TooltipTrigger, TooltipContent, TooltipProvider, type TooltipProps, } from "./tooltip";
|
|
99
|
+
export { Toaster, toast } from "./toaster";
|
|
100
|
+
export type { ToasterProps } from "./toaster";
|
|
101
|
+
export { Separator } from "./separator";
|
|
102
|
+
export type { SeparatorProps } from "./separator";
|
|
103
|
+
export { Skeleton } from "./skeleton";
|
|
104
|
+
export type { SkeletonProps } from "./skeleton";
|
|
105
|
+
export { CopyButton } from "./copy-button";
|
|
106
|
+
export type { CopyButtonProps } from "./copy-button";
|
|
107
|
+
export { Spinner, PageLoader, FullPageLoader } from "./spinner";
|
|
108
|
+
export type { SpinnerProps, PageLoaderProps, FullPageLoaderProps, } from "./spinner";
|
|
109
|
+
export { Collapsible, CollapsibleSection } from "./collapsible";
|
|
110
|
+
export type { CollapsibleProps } from "./collapsible";
|
|
60
111
|
export { cn } from "./lib/utils";
|
|
112
|
+
export { parseDateTime, formatDateTime } from "./lib/date-utils";
|
package/dist/index.js
CHANGED
|
@@ -1,35 +1,62 @@
|
|
|
1
|
-
export { Avatar, AvatarProfile, AvatarRoot, AvatarImage,
|
|
1
|
+
export { Avatar, AvatarProfile, AvatarRoot, AvatarImage, } from "./avatar";
|
|
2
2
|
export * from "./animated-icons";
|
|
3
|
+
export { Alert, alertVariants } from "./alert";
|
|
3
4
|
export { Badge, badgeVariants } from "./badge";
|
|
5
|
+
export { Card } from "./card";
|
|
6
|
+
export { Calendar, CalendarDayButton } from "./calendar";
|
|
7
|
+
export { Checkbox } from "./checkbox";
|
|
8
|
+
export { Switch } from "./switch";
|
|
9
|
+
export { DateInput } from "./date-input";
|
|
4
10
|
export { CountBadge } from "./count-badge";
|
|
5
11
|
export { EmptyState } from "./empty-state";
|
|
6
12
|
export { EditableTable } from "./editable-table";
|
|
7
13
|
export { EmailInput } from "./email-input";
|
|
8
14
|
export { Input } from "./input";
|
|
9
15
|
export { Select } from "./select";
|
|
16
|
+
export { MultiSelect } from "./multi-select";
|
|
10
17
|
export { DEFAULT_COUNTRY_CODES, PhoneInput, } from "./phone-input";
|
|
11
18
|
export { OtpInput } from "./otp-input";
|
|
12
19
|
export { LabelValue, isEmptyValue, } from "./label-value";
|
|
13
20
|
export { LabelValueGrid } from "./label-value-grid";
|
|
14
21
|
export { Breadcrumb, BreadcrumbNav, BreadcrumbList, BreadcrumbItem, BreadcrumbLink, BreadcrumbPage, BreadcrumbSeparator, BreadcrumbEllipsis, } from "./breadcrumb";
|
|
22
|
+
export { BackButton } from "./back-button";
|
|
15
23
|
export { Button, buttonVariants } from "./button";
|
|
24
|
+
export { Link, linkVariants } from "./link";
|
|
16
25
|
export { Dialog } from "./dialog";
|
|
17
26
|
export { Command, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem, CommandSeparator, CommandShortcut, } from "./command";
|
|
18
27
|
export { CommandSearch, } from "./command-search";
|
|
28
|
+
export { FileUpload } from "./file-upload";
|
|
29
|
+
export { Progress } from "./progress";
|
|
30
|
+
export { useFileUpload } from "./use-file-upload";
|
|
31
|
+
export { Popover } from "./popover";
|
|
32
|
+
export { PopoverMenuContent, PopoverMenuHeader, PopoverMenuSection, PopoverMenuItem, PopoverMenuDivider, PopoverMenuGroup, PopoverMenuGroupLabel, PopoverMenuSearch, PopoverMenuScrollArea, } from "./popover-menu";
|
|
19
33
|
export { SearchInput } from "./search-input";
|
|
34
|
+
export { SectionNav } from "./section-nav";
|
|
20
35
|
export { GovtMasthead } from "./govt-masthead";
|
|
21
36
|
export { SearchHighlight, useSearchHighlight, } from "./use-search-highlight";
|
|
37
|
+
export { useErrorShake } from "./use-error-shake";
|
|
38
|
+
export { useStickySentinel } from "./use-sticky-sentinel";
|
|
39
|
+
export { useViewportThreshold } from "./use-viewport-threshold";
|
|
22
40
|
export { Textarea } from "./textarea";
|
|
23
41
|
export { DraggableTabs, } from "./draggable-tabs";
|
|
24
42
|
export { Drawer, } from "./drawer";
|
|
25
|
-
export { DashboardLayout, DashboardSidebar,
|
|
43
|
+
export { DashboardLayout, DashboardSidebar, useSidebar, } from "./layout";
|
|
26
44
|
export { PageHeader } from "./page-header";
|
|
45
|
+
export { PageSection, PageSectionGroup } from "./page-section";
|
|
27
46
|
export { Typography, typographyVariants } from "./typography";
|
|
28
47
|
export { neaPalette, semanticColorTokens, typographyTokens, radiusTokens, spacingTokens, layoutTokens, } from "./theme";
|
|
29
48
|
export { neaDesignSystemContent, neaTailwindPreset, } from "./tailwind-preset";
|
|
30
49
|
export { Pagination } from "./pagination";
|
|
31
50
|
export { TableToolbar } from "./table-toolbar";
|
|
51
|
+
export { useTableSort } from "./use-table-sort";
|
|
32
52
|
export { Table, TableRoot, TableContainer, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell, TableCaption, TableRowSkeleton, TABLE_SKELETON_PRESETS, } from "./table";
|
|
33
|
-
export { Tabs, TabsRoot, TabsList, TabsTrigger, TabsContent, useTabsContext, } from "./tabs";
|
|
53
|
+
export { Tabs, TabsRoot, TabWithDropdown, TabsList, TabsTrigger, TabsContent, useTabsContext, } from "./tabs";
|
|
34
54
|
export { Tooltip, TooltipRoot, TooltipTrigger, TooltipContent, TooltipProvider, } from "./tooltip";
|
|
55
|
+
export { Toaster, toast } from "./toaster";
|
|
56
|
+
export { Separator } from "./separator";
|
|
57
|
+
export { Skeleton } from "./skeleton";
|
|
58
|
+
export { CopyButton } from "./copy-button";
|
|
59
|
+
export { Spinner, PageLoader, FullPageLoader } from "./spinner";
|
|
60
|
+
export { Collapsible, CollapsibleSection } from "./collapsible";
|
|
35
61
|
export { cn } from "./lib/utils";
|
|
62
|
+
export { parseDateTime, formatDateTime } from "./lib/date-utils";
|
package/dist/input-control.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
declare const inputControlClassName = "h-
|
|
2
|
+
declare const inputControlClassName = "h-control w-full min-w-0 rounded-md border border-input bg-transparent px-3 py-1 text-sm transition-[color,box-shadow] outline-none selection:bg-primary selection:text-primary-foreground file:inline-flex file:h-8 file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 aria-[invalid=true]:border-destructive aria-[invalid=true]:ring-destructive/20";
|
|
3
3
|
declare const InputControl: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>, "ref"> & React.RefAttributes<HTMLInputElement>>;
|
|
4
4
|
export { InputControl, inputControlClassName };
|
package/dist/input-control.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import * as React from "react";
|
|
3
3
|
import { cn } from "./lib/utils";
|
|
4
|
-
const inputControlClassName = "h-
|
|
4
|
+
const inputControlClassName = "h-control w-full min-w-0 rounded-md border border-input bg-transparent px-3 py-1 text-sm transition-[color,box-shadow] outline-none selection:bg-primary selection:text-primary-foreground file:inline-flex file:h-8 file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 aria-[invalid=true]:border-destructive aria-[invalid=true]:ring-destructive/20";
|
|
5
5
|
const InputControl = React.forwardRef(({ className, type = "text", ...props }, ref) => (_jsx("input", { ref: ref, type: type, "data-slot": "input", className: cn(inputControlClassName, className), ...props })));
|
|
6
6
|
InputControl.displayName = "InputControl";
|
|
7
7
|
export { InputControl, inputControlClassName };
|
package/dist/input.js
CHANGED
|
@@ -3,7 +3,7 @@ import * as React from "react";
|
|
|
3
3
|
import { Field, FieldDescription, FieldError, FieldLabel } from "./field";
|
|
4
4
|
import { InputControl } from "./input-control";
|
|
5
5
|
import { cn } from "./lib/utils";
|
|
6
|
-
const Input = React.forwardRef(({ label, description, error, invalid = false, hideLabel = false, className, inputClassName, labelClassName, descriptionClassName, errorClassName, id, disabled, "aria-invalid": ariaInvalid, "aria-describedby": ariaDescribedBy, ...props }, ref) => {
|
|
6
|
+
const Input = React.forwardRef(({ label, description, error, invalid = false, hideLabel = false, className, inputClassName, labelClassName, descriptionClassName, errorClassName, id, disabled, "aria-invalid": ariaInvalid, "aria-describedby": ariaDescribedBy, required, ...props }, ref) => {
|
|
7
7
|
const generatedId = React.useId();
|
|
8
8
|
const inputId = id !== null && id !== void 0 ? id : `input-${generatedId}`;
|
|
9
9
|
const errorId = error ? `${inputId}-error` : undefined;
|
|
@@ -16,7 +16,7 @@ const Input = React.forwardRef(({ label, description, error, invalid = false, hi
|
|
|
16
16
|
const describedBy = [ariaDescribedBy, descriptionId, errorId]
|
|
17
17
|
.filter(Boolean)
|
|
18
18
|
.join(" ") || undefined;
|
|
19
|
-
return (_jsxs(Field, { className: className, "data-disabled": disabled ? "true" : undefined, "data-invalid": isInvalid ? "true" : undefined, children: [_jsx(FieldLabel, { htmlFor: inputId, className: cn(hideLabel && "sr-only", labelClassName), children: label }), _jsx(InputControl, { ref: ref, id: inputId, disabled: disabled, "aria-invalid": isInvalid ? "true" : undefined, "aria-describedby": describedBy, className: inputClassName, ...props }), showDescription ? (_jsx(FieldDescription, { id: descriptionId, className: descriptionClassName, children: description })) : null, _jsx(FieldError, { id: errorId, className: errorClassName, children: error })] }));
|
|
19
|
+
return (_jsxs(Field, { className: className, "data-disabled": disabled ? "true" : undefined, "data-invalid": isInvalid ? "true" : undefined, children: [_jsx(FieldLabel, { htmlFor: inputId, required: required, className: cn(hideLabel && "sr-only", labelClassName), children: label }), _jsx(InputControl, { ref: ref, id: inputId, disabled: disabled, required: required, "aria-invalid": isInvalid ? "true" : undefined, "aria-describedby": describedBy, className: inputClassName, ...props }), showDescription ? (_jsx(FieldDescription, { id: descriptionId, className: descriptionClassName, children: description })) : null, _jsx(FieldError, { id: errorId, className: errorClassName, children: error })] }));
|
|
20
20
|
});
|
|
21
21
|
Input.displayName = "Input";
|
|
22
22
|
export { Input };
|
|
@@ -8,6 +8,8 @@ export interface LabelValueGridProps extends React.HTMLAttributes<HTMLDivElement
|
|
|
8
8
|
columns?: 1 | 2 | 3 | 4;
|
|
9
9
|
itemClassName?: string;
|
|
10
10
|
minColumnWidth?: number;
|
|
11
|
+
loading?: boolean;
|
|
12
|
+
loadingItems?: number;
|
|
11
13
|
}
|
|
12
|
-
declare function LabelValueGrid({ items, columns, className, itemClassName, minColumnWidth, style, ...props }: LabelValueGridProps): import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
declare function LabelValueGrid({ items, columns, className, itemClassName, minColumnWidth, loading, loadingItems, style, ...props }: LabelValueGridProps): import("react/jsx-runtime").JSX.Element;
|
|
13
15
|
export { LabelValueGrid };
|
package/dist/label-value-grid.js
CHANGED
|
@@ -11,7 +11,20 @@ function getAvailableWidth(element) {
|
|
|
11
11
|
var _a, _b, _c, _d, _e, _f;
|
|
12
12
|
return Math.max(element.getBoundingClientRect().width, element.clientWidth, element.offsetWidth, (_b = (_a = element.parentElement) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect().width) !== null && _b !== void 0 ? _b : 0, (_d = (_c = element.parentElement) === null || _c === void 0 ? void 0 : _c.clientWidth) !== null && _d !== void 0 ? _d : 0, (_f = (_e = element.parentElement) === null || _e === void 0 ? void 0 : _e.offsetWidth) !== null && _f !== void 0 ? _f : 0);
|
|
13
13
|
}
|
|
14
|
-
function LabelValueGrid({ items, columns = 4, className, itemClassName, minColumnWidth = 192, style, ...props }) {
|
|
14
|
+
function LabelValueGrid({ items, columns = 4, className, itemClassName, minColumnWidth = 192, loading = false, loadingItems = 4, style, ...props }) {
|
|
15
|
+
const resolvedItems = React.useMemo(() => {
|
|
16
|
+
if (!loading)
|
|
17
|
+
return items;
|
|
18
|
+
if (items.length > 0) {
|
|
19
|
+
return items.map((item) => ({ ...item, loading: true }));
|
|
20
|
+
}
|
|
21
|
+
return Array.from({ length: loadingItems }).map((_, index) => ({
|
|
22
|
+
id: `skeleton-${index}`,
|
|
23
|
+
label: "",
|
|
24
|
+
value: null,
|
|
25
|
+
loading: true,
|
|
26
|
+
}));
|
|
27
|
+
}, [items, loading, loadingItems]);
|
|
15
28
|
const containerRef = React.useRef(null);
|
|
16
29
|
const [resolvedColumns, setResolvedColumns] = React.useState(columns);
|
|
17
30
|
React.useLayoutEffect(() => {
|
|
@@ -53,7 +66,7 @@ function LabelValueGrid({ items, columns = 4, className, itemClassName, minColum
|
|
|
53
66
|
return (_jsx("div", { ref: containerRef, className: cn("grid auto-rows-fr items-start gap-x-6 gap-y-3", className), style: {
|
|
54
67
|
...style,
|
|
55
68
|
gridTemplateColumns: `repeat(${resolvedColumns}, minmax(0, 1fr))`,
|
|
56
|
-
}, ...props, children:
|
|
69
|
+
}, ...props, children: resolvedItems.map((item, index) => {
|
|
57
70
|
var _a;
|
|
58
71
|
return (_jsx(LabelValue, { ...item, className: cn("min-w-0", itemClassName, item.className) }, (_a = item.id) !== null && _a !== void 0 ? _a : `${item.label}-${index}`));
|
|
59
72
|
}) }));
|
package/dist/label-value.d.ts
CHANGED
|
@@ -5,7 +5,10 @@ export interface LabelValueProps {
|
|
|
5
5
|
className?: string;
|
|
6
6
|
labelClassName?: string;
|
|
7
7
|
hideIfEmpty?: boolean;
|
|
8
|
+
hideLabel?: boolean;
|
|
9
|
+
loading?: boolean;
|
|
10
|
+
required?: boolean;
|
|
8
11
|
}
|
|
9
12
|
export declare function isEmptyValue(value: React.ReactNode): boolean;
|
|
10
|
-
declare function LabelValue({ label, value, className, labelClassName, hideIfEmpty, }: LabelValueProps): import("react/jsx-runtime").JSX.Element | null;
|
|
13
|
+
declare function LabelValue({ label, value, className, labelClassName, hideIfEmpty, hideLabel, loading, required, }: LabelValueProps): import("react/jsx-runtime").JSX.Element | null;
|
|
11
14
|
export { LabelValue };
|
package/dist/label-value.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { cn } from "./lib/utils";
|
|
3
|
+
import { Skeleton } from "./skeleton";
|
|
4
|
+
import { Typography } from "./typography";
|
|
3
5
|
export function isEmptyValue(value) {
|
|
4
6
|
if (value === null || value === undefined || value === "")
|
|
5
7
|
return true;
|
|
@@ -9,11 +11,11 @@ export function isEmptyValue(value) {
|
|
|
9
11
|
}
|
|
10
12
|
return false;
|
|
11
13
|
}
|
|
12
|
-
function LabelValue({ label, value, className, labelClassName, hideIfEmpty = false, }) {
|
|
14
|
+
function LabelValue({ label, value, className, labelClassName, hideIfEmpty = false, hideLabel = false, loading = false, required = false, }) {
|
|
13
15
|
const empty = isEmptyValue(value);
|
|
14
|
-
if (hideIfEmpty && empty) {
|
|
16
|
+
if (!loading && hideIfEmpty && empty) {
|
|
15
17
|
return null;
|
|
16
18
|
}
|
|
17
|
-
return (_jsxs("div", { className: cn("min-w-0 h-full space-y-1", className), children: [_jsx("
|
|
19
|
+
return (_jsxs("div", { className: cn("min-w-0 h-full space-y-1", className), children: [!hideLabel && (loading ? (_jsx(Skeleton, { className: "h-3.5 w-20" })) : (_jsxs(Typography, { as: "p", variant: "label", className: labelClassName, children: [label, required ? (_jsx("span", { "aria-hidden": "true", className: "ml-0.5 text-destructive", children: "*" })) : null] }))), loading ? (_jsx(Skeleton, { className: "h-4 w-32" })) : (_jsx("div", { className: cn("min-w-0 break-words text-sm text-foreground", empty && "italic text-muted-foreground/60"), children: empty ? "-" : value }))] }));
|
|
18
20
|
}
|
|
19
21
|
export { LabelValue };
|
package/dist/layout.d.ts
CHANGED
|
@@ -11,8 +11,14 @@ export declare function useSidebar(): SidebarContextType;
|
|
|
11
11
|
export interface DashboardLayoutProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
12
12
|
masthead?: React.ReactNode;
|
|
13
13
|
prototypeBanner?: React.ReactNode;
|
|
14
|
+
/** Sidebar element, typically a <DashboardSidebar />. */
|
|
15
|
+
sidebar?: React.ReactNode;
|
|
16
|
+
/** Class names applied to the inner content surface (the rounded card around children). */
|
|
17
|
+
surfaceClassName?: string;
|
|
18
|
+
/** Class names applied to the content `<main>` wrapper. */
|
|
19
|
+
contentClassName?: string;
|
|
14
20
|
}
|
|
15
|
-
declare function DashboardLayout({ className, masthead, prototypeBanner, children, style, ...props }: DashboardLayoutProps): import("react/jsx-runtime").JSX.Element;
|
|
21
|
+
declare function DashboardLayout({ className, masthead, prototypeBanner, sidebar, surfaceClassName, contentClassName, children, style, ...props }: DashboardLayoutProps): import("react/jsx-runtime").JSX.Element;
|
|
16
22
|
export interface DashboardSidebarProps extends React.HTMLAttributes<HTMLElement> {
|
|
17
23
|
logo?: React.ReactNode | ((context: {
|
|
18
24
|
isCollapsed: boolean;
|