@neasg/design-system 0.3.0 → 0.4.3
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 +13 -4
- package/dist/avatar.js +24 -7
- package/dist/back-button.d.ts +6 -0
- package/dist/back-button.js +8 -0
- package/dist/badge.d.ts +1 -1
- package/dist/breadcrumb.js +2 -2
- package/dist/button.d.ts +2 -2
- package/dist/button.js +3 -4
- package/dist/card.d.ts +3 -0
- package/dist/card.js +9 -2
- 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 +2 -2
- package/dist/command.d.ts +1 -1
- package/dist/copy-button.d.ts +19 -0
- package/dist/copy-button.js +31 -0
- package/dist/date-input.js +2 -2
- 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 +47 -6
- package/dist/index.js +25 -4
- 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 +4 -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 +3 -1
- package/dist/multi-select.js +12 -11
- package/dist/page-section.d.ts +14 -0
- package/dist/page-section.js +13 -0
- package/dist/pagination.js +1 -1
- 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 +10 -5
- package/dist/popover.js +6 -9
- 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.js +2 -2
- package/dist/select.js +2 -2
- 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.js +19 -10
- package/dist/typography.d.ts +1 -1
- 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 +32 -6
- package/dist/tab-with-dropdown.d.ts +0 -18
- package/dist/tab-with-dropdown.js +0 -70
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,11 +1,17 @@
|
|
|
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";
|
|
5
7
|
export { Card } from "./card";
|
|
6
8
|
export type { CardProps } from "./card";
|
|
7
9
|
export type { BadgeProps } from "./badge";
|
|
8
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";
|
|
9
15
|
export { DateInput } from "./date-input";
|
|
10
16
|
export type { DateInputProps } from "./date-input";
|
|
11
17
|
export { CountBadge } from "./count-badge";
|
|
@@ -32,26 +38,50 @@ export { LabelValueGrid } from "./label-value-grid";
|
|
|
32
38
|
export type { LabelValueGridItem, LabelValueGridProps, } from "./label-value-grid";
|
|
33
39
|
export { Breadcrumb, BreadcrumbNav, BreadcrumbList, BreadcrumbItem, BreadcrumbLink, BreadcrumbPage, BreadcrumbSeparator, BreadcrumbEllipsis, } from "./breadcrumb";
|
|
34
40
|
export type { BreadcrumbEntry, BreadcrumbProps } from "./breadcrumb";
|
|
41
|
+
export { BackButton } from "./back-button";
|
|
42
|
+
export type { BackButtonProps } from "./back-button";
|
|
35
43
|
export { Button, buttonVariants } from "./button";
|
|
36
44
|
export type { ButtonProps } from "./button";
|
|
45
|
+
export { Link, linkVariants } from "./link";
|
|
46
|
+
export type { LinkProps } from "./link";
|
|
37
47
|
export { Dialog } from "./dialog";
|
|
38
48
|
export type { DialogAction, DialogProps } from "./dialog";
|
|
39
49
|
export { Command, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem, CommandSeparator, CommandShortcut, } from "./command";
|
|
40
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";
|
|
41
61
|
export { SearchInput } from "./search-input";
|
|
42
62
|
export type { SearchInputProps } from "./search-input";
|
|
63
|
+
export { SectionNav } from "./section-nav";
|
|
64
|
+
export type { SectionNavItem, SectionNavProps } from "./section-nav";
|
|
43
65
|
export { GovtMasthead } from "./govt-masthead";
|
|
44
66
|
export type { GovtMastheadProps } from "./govt-masthead";
|
|
45
67
|
export { SearchHighlight, useSearchHighlight, } from "./use-search-highlight";
|
|
46
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";
|
|
47
75
|
export { Textarea } from "./textarea";
|
|
48
76
|
export type { TextareaProps } from "./textarea";
|
|
49
77
|
export { DraggableTabs, type DraggableTabItem, type DraggableTabsProps, } from "./draggable-tabs";
|
|
50
78
|
export { Drawer, } from "./drawer";
|
|
51
79
|
export type { DrawerAction, DrawerProps, DrawerSide } from "./drawer";
|
|
52
|
-
export { DashboardLayout, DashboardSidebar,
|
|
53
|
-
export type { DashboardSidebarNavGroup, DashboardSidebarNavItem, } from "./layout";
|
|
80
|
+
export { DashboardLayout, DashboardSidebar, useSidebar, } from "./layout";
|
|
81
|
+
export type { DashboardLayoutProps, DashboardSidebarNavGroup, DashboardSidebarNavItem, } from "./layout";
|
|
54
82
|
export { PageHeader } from "./page-header";
|
|
83
|
+
export { PageSection, PageSectionGroup } from "./page-section";
|
|
84
|
+
export type { PageSectionGroupProps, PageSectionProps } from "./page-section";
|
|
55
85
|
export { Typography, typographyVariants } from "./typography";
|
|
56
86
|
export type { TypographyProps } from "./typography";
|
|
57
87
|
export { neaPalette, semanticColorTokens, typographyTokens, radiusTokens, spacingTokens, layoutTokens, } from "./theme";
|
|
@@ -60,12 +90,23 @@ export { Pagination } from "./pagination";
|
|
|
60
90
|
export type { PaginationProps } from "./pagination";
|
|
61
91
|
export { TableToolbar } from "./table-toolbar";
|
|
62
92
|
export type { TableToolbarProps } from "./table-toolbar";
|
|
93
|
+
export { useTableSort } from "./use-table-sort";
|
|
94
|
+
export type { UseTableSortOptions, UseTableSortReturn, } from "./use-table-sort";
|
|
63
95
|
export { Table, TableRoot, TableContainer, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell, TableCaption, TableRowSkeleton, TABLE_SKELETON_PRESETS, } from "./table";
|
|
64
96
|
export type { TableColumn, TableProps, TableSortDirection, TableSortingProps, TableSkeletonConfig, TableRowSkeletonProps, } from "./table";
|
|
65
|
-
export { Tabs, TabsRoot, type TabsItem, type TabsProps, TabsList, TabsTrigger, TabsContent, useTabsContext, } from "./tabs";
|
|
66
|
-
export { TabWithDropdown } from "./tab-with-dropdown";
|
|
67
|
-
export type { TabWithDropdownProps, TabDropdownSection } from "./tab-with-dropdown";
|
|
97
|
+
export { Tabs, TabsRoot, TabWithDropdown, type TabsItem, type TabsProps, TabsList, TabsTrigger, TabsContent, type TabWithDropdownProps, useTabsContext, type TabDropdownSection, } from "./tabs";
|
|
68
98
|
export { Tooltip, TooltipRoot, TooltipTrigger, TooltipContent, TooltipProvider, type TooltipProps, } from "./tooltip";
|
|
69
99
|
export { Toaster, toast } from "./toaster";
|
|
70
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";
|
|
71
111
|
export { cn } from "./lib/utils";
|
|
112
|
+
export { parseDateTime, formatDateTime } from "./lib/date-utils";
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
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";
|
|
4
5
|
export { Card } from "./card";
|
|
5
6
|
export { Calendar, CalendarDayButton } from "./calendar";
|
|
7
|
+
export { Checkbox } from "./checkbox";
|
|
8
|
+
export { Switch } from "./switch";
|
|
6
9
|
export { DateInput } from "./date-input";
|
|
7
10
|
export { CountBadge } from "./count-badge";
|
|
8
11
|
export { EmptyState } from "./empty-state";
|
|
@@ -16,26 +19,44 @@ export { OtpInput } from "./otp-input";
|
|
|
16
19
|
export { LabelValue, isEmptyValue, } from "./label-value";
|
|
17
20
|
export { LabelValueGrid } from "./label-value-grid";
|
|
18
21
|
export { Breadcrumb, BreadcrumbNav, BreadcrumbList, BreadcrumbItem, BreadcrumbLink, BreadcrumbPage, BreadcrumbSeparator, BreadcrumbEllipsis, } from "./breadcrumb";
|
|
22
|
+
export { BackButton } from "./back-button";
|
|
19
23
|
export { Button, buttonVariants } from "./button";
|
|
24
|
+
export { Link, linkVariants } from "./link";
|
|
20
25
|
export { Dialog } from "./dialog";
|
|
21
26
|
export { Command, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem, CommandSeparator, CommandShortcut, } from "./command";
|
|
22
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";
|
|
23
33
|
export { SearchInput } from "./search-input";
|
|
34
|
+
export { SectionNav } from "./section-nav";
|
|
24
35
|
export { GovtMasthead } from "./govt-masthead";
|
|
25
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";
|
|
26
40
|
export { Textarea } from "./textarea";
|
|
27
41
|
export { DraggableTabs, } from "./draggable-tabs";
|
|
28
42
|
export { Drawer, } from "./drawer";
|
|
29
|
-
export { DashboardLayout, DashboardSidebar,
|
|
43
|
+
export { DashboardLayout, DashboardSidebar, useSidebar, } from "./layout";
|
|
30
44
|
export { PageHeader } from "./page-header";
|
|
45
|
+
export { PageSection, PageSectionGroup } from "./page-section";
|
|
31
46
|
export { Typography, typographyVariants } from "./typography";
|
|
32
47
|
export { neaPalette, semanticColorTokens, typographyTokens, radiusTokens, spacingTokens, layoutTokens, } from "./theme";
|
|
33
48
|
export { neaDesignSystemContent, neaTailwindPreset, } from "./tailwind-preset";
|
|
34
49
|
export { Pagination } from "./pagination";
|
|
35
50
|
export { TableToolbar } from "./table-toolbar";
|
|
51
|
+
export { useTableSort } from "./use-table-sort";
|
|
36
52
|
export { Table, TableRoot, TableContainer, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell, TableCaption, TableRowSkeleton, TABLE_SKELETON_PRESETS, } from "./table";
|
|
37
|
-
export { Tabs, TabsRoot, TabsList, TabsTrigger, TabsContent, useTabsContext, } from "./tabs";
|
|
38
|
-
export { TabWithDropdown } from "./tab-with-dropdown";
|
|
53
|
+
export { Tabs, TabsRoot, TabWithDropdown, TabsList, TabsTrigger, TabsContent, useTabsContext, } from "./tabs";
|
|
39
54
|
export { Tooltip, TooltipRoot, TooltipTrigger, TooltipContent, TooltipProvider, } from "./tooltip";
|
|
40
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";
|
|
41
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,6 @@
|
|
|
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";
|
|
3
4
|
import { Typography } from "./typography";
|
|
4
5
|
export function isEmptyValue(value) {
|
|
5
6
|
if (value === null || value === undefined || value === "")
|
|
@@ -10,11 +11,11 @@ export function isEmptyValue(value) {
|
|
|
10
11
|
}
|
|
11
12
|
return false;
|
|
12
13
|
}
|
|
13
|
-
function LabelValue({ label, value, className, labelClassName, hideIfEmpty = false, }) {
|
|
14
|
+
function LabelValue({ label, value, className, labelClassName, hideIfEmpty = false, hideLabel = false, loading = false, required = false, }) {
|
|
14
15
|
const empty = isEmptyValue(value);
|
|
15
|
-
if (hideIfEmpty && empty) {
|
|
16
|
+
if (!loading && hideIfEmpty && empty) {
|
|
16
17
|
return null;
|
|
17
18
|
}
|
|
18
|
-
return (_jsxs("div", { className: cn("min-w-0 h-full space-y-1", className), children: [_jsx(Typography, { as: "p", variant: "label", className: labelClassName, children: label }), _jsx("div", { className: cn("min-w-0 break-words text-sm text-foreground", empty && "italic text-muted-foreground/60"), children: empty ? "-" : value })] }));
|
|
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: cn("leading-tight", 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 }))] }));
|
|
19
20
|
}
|
|
20
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;
|
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: "sticky top-0 z-40 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?: "inherit" | "default" | "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 };
|
package/dist/multi-select.d.ts
CHANGED
|
@@ -18,6 +18,8 @@ export interface MultiSelectProps {
|
|
|
18
18
|
hideLabel?: boolean;
|
|
19
19
|
searchable?: boolean;
|
|
20
20
|
searchPlaceholder?: string;
|
|
21
|
+
/** Cap how many selected tags render in the trigger; the rest collapse into a `+N` badge. */
|
|
22
|
+
maxVisibleTags?: number;
|
|
21
23
|
className?: string;
|
|
22
24
|
triggerClassName?: string;
|
|
23
25
|
labelClassName?: string;
|
|
@@ -25,5 +27,5 @@ export interface MultiSelectProps {
|
|
|
25
27
|
errorClassName?: string;
|
|
26
28
|
id?: string;
|
|
27
29
|
}
|
|
28
|
-
declare function MultiSelect({ label, options, value, onValueChange, placeholder, description, error, invalid, disabled, hideLabel, searchable, searchPlaceholder, className, triggerClassName, labelClassName, descriptionClassName, errorClassName, id, }: MultiSelectProps): import("react/jsx-runtime").JSX.Element;
|
|
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;
|
|
29
31
|
export { MultiSelect };
|