@neasg/design-system 0.4.132 → 0.4.133
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/dist/checklist.d.ts +3 -0
- package/dist/checklist.js +13 -6
- package/dist/dialog.d.ts +2 -2
- package/dist/dialog.js +3 -6
- package/dist/editable-table.js +1 -1
- package/dist/file-upload-list.d.ts +15 -0
- package/dist/file-upload-list.js +7 -0
- package/dist/file-upload-status-row.d.ts +3 -1
- package/dist/file-upload-status-row.js +2 -2
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/label-value-grid.d.ts +3 -1
- package/dist/label-value-grid.js +2 -2
- package/dist/routing-action-panel.js +1 -1
- package/package.json +1 -1
package/dist/checklist.d.ts
CHANGED
package/dist/checklist.js
CHANGED
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import * as CollapsiblePrimitive from "@radix-ui/react-collapsible";
|
|
5
|
-
import { Camera, ChevronDown, ClipboardList, LoaderCircle, MessageSquareText
|
|
5
|
+
import { Camera, ChevronDown, ClipboardList, LoaderCircle, MessageSquareText } from "lucide-react";
|
|
6
6
|
import { Button } from "./button";
|
|
7
|
+
import { FileUploadStatusRow } from "./file-upload-status-row";
|
|
7
8
|
import { Select } from "./select";
|
|
8
9
|
import { Textarea } from "./textarea";
|
|
9
10
|
import { Tooltip } from "./tooltip";
|
|
@@ -16,18 +17,24 @@ export function ChecklistSection({ title, progress, action, children, defaultOpe
|
|
|
16
17
|
}
|
|
17
18
|
export function ChecklistSelection({ title, description, typeOptions, subtypeOptions, type, subtype, onTypeChange, onSubtypeChange, disabled, loading, action }) {
|
|
18
19
|
const Icon = loading ? LoaderCircle : ClipboardList;
|
|
19
|
-
return _jsxs("div", { "data-slot": "checklist-selection", "aria-busy": loading, className: "flex flex-col items-center gap-4 rounded-lg bg-muted/30 p-6 text-center", children: [_jsx(Icon, { "aria-hidden": "true", className: cn("size-8", loading && "animate-spin") }), _jsxs("div", { className: "space-y-2", children: [_jsx("p", { className: "text-sm font-medium", children: title }), _jsx("p", { className: "text-sm text-muted-foreground", children: description })] }), _jsxs("div", { className: "grid w-full max-w-md grid-cols-1 gap-[var(--
|
|
20
|
+
return _jsxs("div", { "data-slot": "checklist-selection", "aria-busy": loading, className: "flex flex-col items-center gap-4 rounded-lg bg-muted/30 p-6 text-center", children: [_jsx(Icon, { "aria-hidden": "true", className: cn("size-8", loading && "animate-spin") }), _jsxs("div", { className: "space-y-2", children: [_jsx("p", { className: "text-sm font-medium", children: title }), _jsx("p", { className: "text-sm text-muted-foreground", children: description })] }), _jsxs("div", { className: "grid w-full max-w-md grid-cols-1 gap-[var(--space-2)] sm:grid-cols-2", children: [_jsx(Select, { label: "Type", hideLabel: true, placeholder: "Type", options: typeOptions, value: type, onValueChange: onTypeChange, disabled: disabled || loading }), _jsx(Select, { label: "Sub-Type", hideLabel: true, placeholder: "Sub-Type", options: subtypeOptions, value: subtype, onValueChange: onSubtypeChange, disabled: disabled || loading || !type })] }), action] });
|
|
20
21
|
}
|
|
21
22
|
export function ChecklistQuestion({ label, options, value, onValueChange, disabled, remarks, onRemarksChange, remarksLimit = 500, remarksMaxLength, remarksRequired = false, evidence, evidenceCount = 0 }) {
|
|
22
23
|
const name = React.useId();
|
|
23
|
-
const [
|
|
24
|
-
const [
|
|
24
|
+
const [remarksOpen, setRemarksOpen] = React.useState(null);
|
|
25
|
+
const [evidenceOpen, setEvidenceOpen] = React.useState(null);
|
|
26
|
+
React.useEffect(() => {
|
|
27
|
+
if (remarksRequired)
|
|
28
|
+
setRemarksOpen(true);
|
|
29
|
+
}, [remarksRequired]);
|
|
30
|
+
const showRemarks = remarksOpen !== null && remarksOpen !== void 0 ? remarksOpen : (remarksRequired || Boolean(remarks.trim()));
|
|
31
|
+
const showEvidence = evidenceOpen !== null && evidenceOpen !== void 0 ? evidenceOpen : evidenceCount > 0;
|
|
25
32
|
const remarksVisible = disabled ? Boolean(remarks.trim()) : showRemarks;
|
|
26
33
|
const evidenceVisible = disabled ? evidenceCount > 0 : showEvidence;
|
|
27
34
|
const remarksToggleLabel = showRemarks ? "Hide remarks" : "Show remarks";
|
|
28
35
|
const evidenceToggleLabel = showEvidence ? "Hide photos" : "Show photos";
|
|
29
|
-
return _jsxs("div", { "data-slot": "checklist-question", className: "space-y-4 rounded-xl border border-border bg-card p-4 shadow-xs", children: [_jsx("p", { id: `${name}-label`, className: "text-sm font-medium", children: label }), _jsxs("div", { className: "flex flex-wrap items-center gap-6", children: [_jsx("fieldset", { disabled: disabled, "aria-labelledby": `${name}-label`, className: cn("flex min-w-0 border-0 p-0", disabled && "opacity-50"), children: options.map((option, index) => _jsxs("label", { className: cn("relative cursor-pointer border border-input px-2.5 py-2 text-sm font-medium focus-within:z-10 focus-within:ring-2 focus-within:ring-ring", index > 0 && "-ml-px", index === 0 && "rounded-l-md", index === options.length - 1 && "rounded-r-md", disabled && "cursor-not-allowed", value === option.value ? option.tone === "negative" ? "bg-destructive/20" : option.tone === "positive" ? "bg-primary/20" : "bg-muted" : "bg-background"), children: [_jsx("input", { className: "absolute inset-0 size-full cursor-
|
|
36
|
+
return _jsxs("div", { "data-slot": "checklist-question", className: "space-y-4 rounded-xl border border-border bg-card p-4 shadow-xs", children: [_jsx("p", { id: `${name}-label`, className: "text-sm font-medium", children: label }), _jsxs("div", { className: "flex flex-wrap items-center gap-6", children: [_jsx("fieldset", { disabled: disabled, "aria-labelledby": `${name}-label`, className: cn("flex min-w-0 border-0 p-0", disabled && "opacity-50"), children: options.map((option, index) => _jsxs("label", { className: cn("relative cursor-pointer border border-input px-2.5 py-2 text-sm font-medium focus-within:z-10 focus-within:ring-2 focus-within:ring-ring", index > 0 && "-ml-px", index === 0 && "rounded-l-md", index === options.length - 1 && "rounded-r-md", disabled && "cursor-not-allowed", value === option.value ? option.tone === "negative" ? "bg-destructive/20" : option.tone === "positive" ? "bg-primary/20" : "bg-muted" : "bg-background"), children: [_jsx("input", { className: "absolute inset-0 size-full cursor-pointer opacity-0 disabled:cursor-not-allowed", type: "radio", name: name, value: option.value, checked: value === option.value, onChange: () => onValueChange(option.value) }), option.label] }, option.value)) }), !disabled ? _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Tooltip, { content: remarksToggleLabel, children: _jsx(Button, { type: "button", variant: "ghost", size: "compactIcon", "aria-label": remarksToggleLabel, "aria-expanded": showRemarks, "aria-controls": `${name}-remarks`, onClick: () => setRemarksOpen(!showRemarks), children: _jsx(MessageSquareText, { "aria-hidden": "true", size: 16 }) }) }), evidence ? _jsx(Tooltip, { content: `${evidenceToggleLabel}${evidenceCount > 0 ? ` (${evidenceCount})` : ""}`, children: _jsx(Button, { type: "button", variant: "ghost", size: "compactIcon", "aria-label": evidenceToggleLabel, "aria-expanded": showEvidence, "aria-controls": `${name}-evidence`, onClick: () => setEvidenceOpen(!showEvidence), children: _jsx(Camera, { "aria-hidden": "true", size: 16 }) }) }) : null] }) : null] }), evidenceVisible && evidence ? _jsx("div", { id: `${name}-evidence`, children: evidence }) : null, remarksVisible ? _jsx("div", { id: `${name}-remarks`, children: disabled ? _jsxs("div", { className: "space-y-1", children: [_jsx("p", { className: "text-sm font-medium", children: "Remarks" }), _jsx("p", { className: "whitespace-pre-wrap text-sm text-muted-foreground", children: remarks })] }) : _jsx(Textarea, { label: "Remarks", description: "Required when No or N/A is selected.", placeholder: "Type...", value: remarks, "aria-required": remarksRequired, rows: 5, onChange: (event) => { setRemarksOpen(true); onRemarksChange(event.target.value); }, maxWords: remarksMaxLength === undefined ? remarksLimit : undefined, maxLength: remarksMaxLength, showCount: remarksMaxLength !== undefined }) }) : null] });
|
|
30
37
|
}
|
|
31
38
|
export function ChecklistAttachments({ items, onRemove }) {
|
|
32
|
-
return _jsx("
|
|
39
|
+
return _jsx("ul", { className: "space-y-2", children: items.map((item) => _jsx(FileUploadStatusRow, { file: { name: item.name, type: item.type, size: item.sizeBytes || item.size, status: "complete" }, href: item.url, onRemove: onRemove ? () => onRemove(item.key) : undefined }, item.key)) });
|
|
33
40
|
}
|
package/dist/dialog.d.ts
CHANGED
|
@@ -9,10 +9,10 @@ export interface DialogAction extends Omit<ButtonProps, "children"> {
|
|
|
9
9
|
}
|
|
10
10
|
type DialogRenderable = React.ReactNode | ((helpers: DialogRenderHelpers) => React.ReactNode);
|
|
11
11
|
export interface DialogProps {
|
|
12
|
-
variant?: "default" | "confirmation"
|
|
12
|
+
variant?: "default" | "confirmation";
|
|
13
13
|
/** Standard dialogs are 512px wide; larger sizes are for complex editors. */
|
|
14
14
|
size?: "standard" | "large" | "extraLarge" | "full";
|
|
15
|
-
/**
|
|
15
|
+
/** Minimum height; defaults to 11.25rem (180px at the default root font size). */
|
|
16
16
|
minHeight?: React.CSSProperties["minHeight"];
|
|
17
17
|
open?: boolean;
|
|
18
18
|
defaultOpen?: boolean;
|
package/dist/dialog.js
CHANGED
|
@@ -32,7 +32,7 @@ function renderDialogAction({ action, close, defaultVariant, }) {
|
|
|
32
32
|
}
|
|
33
33
|
}, children: label }));
|
|
34
34
|
}
|
|
35
|
-
function Dialog({ variant = "default", size = "standard", minHeight, open, defaultOpen, onOpenChange, modal, trigger, title, description, children, footer, primaryAction, secondaryAction, contentClassName, bodyClassName, hideCloseButton = false, closeOnOutsideClick = false, }) {
|
|
35
|
+
function Dialog({ variant = "default", size = "standard", minHeight = "11.25rem", open, defaultOpen, onOpenChange, modal, trigger, title, description, children, footer, primaryAction, secondaryAction, contentClassName, bodyClassName, hideCloseButton = false, closeOnOutsideClick = false, }) {
|
|
36
36
|
const [isOpen, setIsOpen] = useControllableOpen({
|
|
37
37
|
open,
|
|
38
38
|
defaultOpen,
|
|
@@ -45,15 +45,12 @@ function Dialog({ variant = "default", size = "standard", minHeight, open, defau
|
|
|
45
45
|
const customFooter = resolveDialogRenderable(footer, helpers);
|
|
46
46
|
const hasFooter = Boolean(customFooter || primaryAction || secondaryAction);
|
|
47
47
|
const isCompactConfirmation = variant === "confirmation";
|
|
48
|
-
const isRoutingConfirmation = variant === "routingConfirmation";
|
|
49
48
|
return (_jsxs(DialogRoot, { open: isOpen, onOpenChange: setIsOpen, modal: modal, children: [trigger ? _jsx(DialogTrigger, { asChild: true, children: trigger }) : null, _jsxs(DialogSurface, { ...(!description ? { "aria-describedby": undefined } : {}), style: minHeight !== undefined ? { minHeight } : undefined, className: cn(isCompactConfirmation &&
|
|
50
|
-
"gap-0 overflow-hidden rounded-xl p-0",
|
|
51
|
-
"gap-0 rounded-overlay p-[var(--space-8)]", minHeight !== undefined && "flex flex-col", "w-[calc(100vw-32px)]", { standard: "max-w-[512px]", large: "max-w-3xl", extraLarge: "max-w-5xl", full: "max-w-[96rem]" }[size], contentClassName), hideCloseButton: hideCloseButton || isCompactConfirmation || isRoutingConfirmation, onPointerDownOutside: (event) => {
|
|
49
|
+
"gap-0 overflow-hidden rounded-xl p-0", minHeight !== undefined && "flex flex-col", "w-[calc(100vw-32px)]", { standard: "max-w-[512px]", large: "max-w-3xl", extraLarge: "max-w-5xl", full: "max-w-[96rem]" }[size], contentClassName), hideCloseButton: hideCloseButton || isCompactConfirmation, onPointerDownOutside: (event) => {
|
|
52
50
|
if (!closeOnOutsideClick) {
|
|
53
51
|
event.preventDefault();
|
|
54
52
|
}
|
|
55
|
-
}, children: [_jsxs("div", { className: cn(isCompactConfirmation && "flex items-start gap-4 p-4"), children: [isCompactConfirmation ? (_jsx("div", { className: "rounded-lg bg-muted p-2", children: _jsx(CircleAlert, { "aria-hidden": "true", className: "size-6" }) })) : null, _jsxs(DialogHeader, {
|
|
56
|
-
"text-base leading-6 text-foreground"), children: description })) : null] })] }), body ? (_jsx("div", { className: cn("grid gap-4", minHeight !== undefined && "flex-1", isRoutingConfirmation && "mt-3 gap-[var(--space-8)]", bodyClassName), children: body })) : null, hasFooter ? (_jsx(DialogFooter, { className: cn(isCompactConfirmation && "border-t bg-muted/30 p-4", isRoutingConfirmation && "mt-[var(--space-8)] gap-3", minHeight !== undefined && "mt-auto"), children: customFooter !== null && customFooter !== void 0 ? customFooter : (_jsxs(_Fragment, { children: [secondaryAction
|
|
53
|
+
}, children: [_jsxs("div", { className: cn(isCompactConfirmation && "flex items-start gap-4 p-4"), children: [isCompactConfirmation ? (_jsx("div", { className: "rounded-lg bg-muted p-2", children: _jsx(CircleAlert, { "aria-hidden": "true", className: "size-6" }) })) : null, _jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: title }), description ? (_jsx(DialogDescription, { children: description })) : null] })] }), body ? (_jsx("div", { className: cn("grid gap-4", minHeight !== undefined && "flex-1", bodyClassName), children: body })) : null, hasFooter ? (_jsx(DialogFooter, { className: cn(isCompactConfirmation && "border-t bg-muted/30 p-4", minHeight !== undefined && "mt-auto"), children: customFooter !== null && customFooter !== void 0 ? customFooter : (_jsxs(_Fragment, { children: [secondaryAction
|
|
57
54
|
? renderDialogAction({
|
|
58
55
|
action: secondaryAction,
|
|
59
56
|
close: helpers.close,
|
package/dist/editable-table.js
CHANGED
|
@@ -145,7 +145,7 @@ function EditableTable({ value, onChange, columns, isEditing = false, className,
|
|
|
145
145
|
insertRow: (nextRow, index = rowIndex + 1) => handleInsertRow(nextRow, index),
|
|
146
146
|
removeRow: () => handleDeleteRow(rowIndex),
|
|
147
147
|
})
|
|
148
|
-
: null, isEditing ? (_jsx(Button, { type: "button", variant: "
|
|
148
|
+
: null, isEditing ? (_jsx(Button, { type: "button", variant: "destructiveGhost", size: "compactIcon", onClick: () => handleDeleteRow(rowIndex), "aria-label": `Delete row ${rowIndex + 1}`, children: _jsx(TrashIcon, { size: 16 }) })) : null] }) })) : null] }, `row-${rowIndex}`)))) })] }) }), isEditing ? (_jsx(TableAddRow, { onClick: handleAddRow, children: addRowLabel })) : null] }));
|
|
149
149
|
}
|
|
150
150
|
EditableTable.displayName = "EditableTable";
|
|
151
151
|
export { EditableTable };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface UploadedFile {
|
|
2
|
+
id: string;
|
|
3
|
+
name: string;
|
|
4
|
+
type?: string;
|
|
5
|
+
size?: number | string;
|
|
6
|
+
href?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface FileUploadListProps {
|
|
9
|
+
files: UploadedFile[];
|
|
10
|
+
onRemove?: (id: string) => void;
|
|
11
|
+
disabled?: boolean;
|
|
12
|
+
label?: string;
|
|
13
|
+
}
|
|
14
|
+
/** Saved files, using the same rows as the uploader. */
|
|
15
|
+
export declare function FileUploadList({ files, onRemove, disabled, label }: FileUploadListProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { FileUploadStatusRow } from "./file-upload-status-row";
|
|
4
|
+
/** Saved files, using the same rows as the uploader. */
|
|
5
|
+
export function FileUploadList({ files, onRemove, disabled, label = "Uploaded files" }) {
|
|
6
|
+
return _jsx("ul", { "aria-label": label, className: "space-y-2", children: files.map(file => _jsx(FileUploadStatusRow, { file: { ...file, status: "complete" }, href: file.href, disabled: disabled, onRemove: onRemove ? () => onRemove(file.id) : undefined }, file.id)) });
|
|
7
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { FileUploadStatus } from "./use-file-upload";
|
|
2
|
-
export declare function FileUploadStatusRow({ file, onCancel, onRemove, disabled, }: {
|
|
2
|
+
export declare function FileUploadStatusRow({ file, href, onCancel, onRemove, disabled, }: {
|
|
3
3
|
file: {
|
|
4
4
|
name: string;
|
|
5
5
|
type?: string;
|
|
@@ -8,6 +8,8 @@ export declare function FileUploadStatusRow({ file, onCancel, onRemove, disabled
|
|
|
8
8
|
progress?: number;
|
|
9
9
|
error?: string;
|
|
10
10
|
};
|
|
11
|
+
/** Optional destination for an uploaded file name. */
|
|
12
|
+
href?: string;
|
|
11
13
|
onCancel?: () => void;
|
|
12
14
|
onRemove?: () => void;
|
|
13
15
|
disabled?: boolean;
|
|
@@ -27,7 +27,7 @@ function getStatusIcon(status, type) {
|
|
|
27
27
|
const Icon = (type === null || type === void 0 ? void 0 : type.startsWith("image/")) ? ImageIcon : type === "application/pdf" ? FileText : File;
|
|
28
28
|
return (_jsx(Icon, { "aria-hidden": "true", className: "size-5 text-muted-foreground" }));
|
|
29
29
|
}
|
|
30
|
-
export function FileUploadStatusRow({ file, onCancel, onRemove, disabled = false, }) {
|
|
30
|
+
export function FileUploadStatusRow({ file, href, onCancel, onRemove, disabled = false, }) {
|
|
31
31
|
var _a;
|
|
32
32
|
const isUploading = file.status === "uploading";
|
|
33
33
|
const isPending = file.status === "pending";
|
|
@@ -39,7 +39,7 @@ export function FileUploadStatusRow({ file, onCancel, onRemove, disabled = false
|
|
|
39
39
|
const action = canCancel ? "cancel" : canRemove ? "remove" : null;
|
|
40
40
|
return (_jsxs("li", { className: cn("rounded-control border bg-background px-2.5 py-2", isError && "border-destructive/80 bg-destructive/5"), children: [_jsxs("div", { className: cn("grid min-h-7 items-start gap-x-2", action
|
|
41
41
|
? "grid-cols-[1.5rem_minmax(0,1fr)_auto_1.75rem]"
|
|
42
|
-
: "grid-cols-[1.5rem_minmax(0,1fr)_auto]"), children: [_jsx("span", { className: "flex h-7 w-6 shrink-0 items-center justify-center", children: getStatusIcon(file.status, file.type) }), _jsxs("div", { className: "flex min-w-0 flex-col gap-1 py-1", children: [_jsx(Typography, { as: "p", variant: "label", className: cn("truncate", isComplete && "text-[hsl(var(--status-success-foreground))]"), title: file.name, children: file.name }), isError ? (_jsx(Typography, { as: "p", variant: "caption", className: "break-words text-xs leading-4 text-destructive", children: (_a = file.error) !== null && _a !== void 0 ? _a : "Upload failed" })) : null] }), sizeLabel ? (_jsx(Typography, { as: "span", variant: "bodySm", className: "col-start-3 mt-1.5 whitespace-nowrap text-xs leading-4 text-muted-foreground", children: sizeLabel })) : null, action ? (_jsx(Button, { type: "button", variant: "ghost", size: "compactIcon", className: "col-start-4 h-7 w-7 shrink-0", disabled: disabled, onClick: (event) => {
|
|
42
|
+
: "grid-cols-[1.5rem_minmax(0,1fr)_auto]"), children: [_jsx("span", { className: "flex h-7 w-6 shrink-0 items-center justify-center", children: getStatusIcon(file.status, file.type) }), _jsxs("div", { className: "flex min-w-0 flex-col gap-1 py-1", children: [href ? (_jsx("a", { href: href, target: "_blank", rel: "noreferrer", className: "min-w-0 truncate underline-offset-4 hover:underline", children: _jsx(Typography, { as: "span", variant: "label", className: cn("truncate", isComplete && "text-[hsl(var(--status-success-foreground))]"), title: file.name, children: file.name }) })) : (_jsx(Typography, { as: "p", variant: "label", className: cn("truncate", isComplete && "text-[hsl(var(--status-success-foreground))]"), title: file.name, children: file.name })), isError ? (_jsx(Typography, { as: "p", variant: "caption", className: "break-words text-xs leading-4 text-destructive", children: (_a = file.error) !== null && _a !== void 0 ? _a : "Upload failed" })) : null] }), sizeLabel ? (_jsx(Typography, { as: "span", variant: "bodySm", className: "col-start-3 mt-1.5 whitespace-nowrap text-xs leading-4 text-muted-foreground", children: sizeLabel })) : null, action ? (_jsx(Button, { type: "button", variant: action === "remove" ? "destructiveGhost" : "ghost", size: "compactIcon", className: "col-start-4 h-7 w-7 shrink-0", disabled: disabled, onClick: (event) => {
|
|
43
43
|
event.stopPropagation();
|
|
44
44
|
if (action === "cancel") {
|
|
45
45
|
onCancel === null || onCancel === void 0 ? void 0 : onCancel();
|
package/dist/index.d.ts
CHANGED
|
@@ -174,3 +174,5 @@ export type { ChecklistAttachmentsProps, ChecklistPanelProps, ChecklistSectionPr
|
|
|
174
174
|
export { TableAddRow, type TableAddRowProps } from "./table-add-row";
|
|
175
175
|
export { PopoverList, type PopoverListProps } from "./popover";
|
|
176
176
|
export { StatusBanner, type StatusBannerProps } from "./status-banner";
|
|
177
|
+
export { FileUploadList } from "./file-upload-list";
|
|
178
|
+
export type { FileUploadListProps, UploadedFile } from "./file-upload-list";
|
package/dist/index.js
CHANGED
|
@@ -93,3 +93,4 @@ export { ChecklistAttachments, ChecklistPanel, ChecklistSection, ChecklistSelect
|
|
|
93
93
|
export { TableAddRow } from "./table-add-row";
|
|
94
94
|
export { PopoverList } from "./popover";
|
|
95
95
|
export { StatusBanner } from "./status-banner";
|
|
96
|
+
export { FileUploadList } from "./file-upload-list";
|
|
@@ -7,11 +7,13 @@ export interface LabelValueGridProps extends React.HTMLAttributes<HTMLDivElement
|
|
|
7
7
|
items: LabelValueGridItem[];
|
|
8
8
|
columns?: 1 | 2 | 3 | 4 | 5 | 6;
|
|
9
9
|
density?: "default" | "compact";
|
|
10
|
+
/** Controls whether every grid row shares one height or sizes to its content. */
|
|
11
|
+
rowSizing?: "equal" | "natural";
|
|
10
12
|
itemClassName?: string;
|
|
11
13
|
minColumnWidth?: number;
|
|
12
14
|
hideIfEmpty?: boolean;
|
|
13
15
|
loading?: boolean;
|
|
14
16
|
loadingItems?: number;
|
|
15
17
|
}
|
|
16
|
-
declare function LabelValueGrid({ items, columns, density, className, itemClassName, minColumnWidth, hideIfEmpty, loading, loadingItems, style, ...props }: LabelValueGridProps): import("react/jsx-runtime").JSX.Element;
|
|
18
|
+
declare function LabelValueGrid({ items, columns, density, rowSizing, className, itemClassName, minColumnWidth, hideIfEmpty, loading, loadingItems, style, ...props }: LabelValueGridProps): import("react/jsx-runtime").JSX.Element;
|
|
17
19
|
export { LabelValueGrid };
|
package/dist/label-value-grid.js
CHANGED
|
@@ -11,7 +11,7 @@ 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, density = "default", className, itemClassName, minColumnWidth, hideIfEmpty = false, loading = false, loadingItems = 4, style, ...props }) {
|
|
14
|
+
function LabelValueGrid({ items, columns = 4, density = "default", rowSizing = "equal", className, itemClassName, minColumnWidth, hideIfEmpty = false, loading = false, loadingItems = 4, style, ...props }) {
|
|
15
15
|
const resolvedMinColumnWidth = minColumnWidth !== null && minColumnWidth !== void 0 ? minColumnWidth : (density === "compact" ? 140 : 192);
|
|
16
16
|
const resolvedItems = React.useMemo(() => {
|
|
17
17
|
if (!loading)
|
|
@@ -66,7 +66,7 @@ function LabelValueGrid({ items, columns = 4, density = "default", className, it
|
|
|
66
66
|
}, [columns, density, resolvedMinColumnWidth]);
|
|
67
67
|
return (_jsx("div", { ref: containerRef, className: cn("grid items-start", density === "compact"
|
|
68
68
|
? "auto-rows-auto gap-x-4 gap-y-3"
|
|
69
|
-
: resolvedColumns === 1
|
|
69
|
+
: resolvedColumns === 1 || rowSizing === "natural"
|
|
70
70
|
? "auto-rows-auto gap-x-6 gap-y-6"
|
|
71
71
|
: "auto-rows-fr gap-x-6 gap-y-6", className), style: {
|
|
72
72
|
...style,
|
|
@@ -16,6 +16,6 @@ import { Textarea } from "./textarea";
|
|
|
16
16
|
function RoutingActionPanel({ items, isLoading = false, loadingLabel = "Loading routing activity", emptyMessage = "No routing activity yet", emptyDescription = "Workflow routes will appear here.", routeOptions, routeValue, routePlaceholder = "Select Officer Role", routeDescription, routeDisabled = false, onRouteValueChange, supplementaryFields, context, remarks, remarksDescription, remarksPlaceholder = "Type remarks", remarksRequired = false, remarksRows = 2, validationMessages = [], onRemarksChange, submitLabel = "Route", submitDisabled = false, submitLoading = false, onSubmit, ...panelProps }) {
|
|
17
17
|
const RoutingEmptyState = context ? EmptyState : DashboardActionPanelEmptyState;
|
|
18
18
|
const footer = (_jsxs("div", { "data-slot": "routing-action-panel-form", className: "grid gap-[var(--space-4)]", children: [supplementaryFields, _jsx(Select, { label: "Route To", options: routeOptions, value: routeValue, placeholder: routePlaceholder, disabled: routeDisabled || submitLoading, description: routeDescription, onValueChange: onRouteValueChange }), _jsx(Textarea, { label: "Remarks", value: remarks, onChange: (event) => onRemarksChange(event.target.value), placeholder: remarksPlaceholder, description: remarksDescription, disabled: routeDisabled || submitLoading, required: remarksRequired, rows: remarksRows }), validationMessages.length > 0 ? (_jsxs("details", { className: "text-sm text-muted-foreground", children: [_jsxs("summary", { className: "cursor-pointer font-medium text-foreground", children: [validationMessages.length, " required ", validationMessages.length === 1 ? "item" : "items", " remaining \u2014 view details"] }), _jsx("ul", { className: "mt-2 max-h-40 list-disc space-y-1 overflow-y-auto pl-5", children: validationMessages.map((message, index) => _jsx("li", { children: message }, index)) })] })) : null, _jsx("div", { className: "flex justify-end", children: _jsxs(Button, { type: "button", size: "default", disabled: routeDisabled || submitDisabled || validationMessages.length > 0, loading: submitLoading, loadingText: submitLabel, onClick: onSubmit, children: [_jsx(Route, { "aria-hidden": "true", className: "size-4" }), submitLabel] }) })] }));
|
|
19
|
-
return (_jsx(DashboardActionPanel, { headerSpacing: "comfortable", ...panelProps, children: _jsxs(DashboardRightPanelBody, { spacing: "comfortable", topInset: "none", footerVariant: "separated", footer: footer, children: [context ? (_jsx("div", { "data-slot": "routing-action-panel-context", className: "mb-[var(--space-4)] grid min-w-0 gap-[var(--space-3)] whitespace-pre-wrap [overflow-wrap:anywhere]", children: context })) : null, isLoading ? (_jsx("div", { "data-slot": "routing-action-panel-loading", className: context ? "flex items-center justify-center py-[var(--space-4)]" : "absolute inset-0 flex items-center justify-center", children: _jsx(Spinner, { size: "md", label: loadingLabel }) })) : items.length === 0 ? (_jsx(RoutingEmptyState, { icon: Route, message: emptyMessage, description: emptyDescription })) : (_jsx(RoutingTimeline, { density: "compact", items: items }))] }) }));
|
|
19
|
+
return (_jsx(DashboardActionPanel, { headerSpacing: "comfortable", ...panelProps, children: _jsxs(DashboardRightPanelBody, { spacing: "comfortable", topInset: "none", footerVariant: "separated", footerClassName: "max-h-[50%] overflow-y-auto overscroll-contain", footer: footer, children: [context ? (_jsx("div", { "data-slot": "routing-action-panel-context", className: "mb-[var(--space-4)] grid min-w-0 gap-[var(--space-3)] whitespace-pre-wrap [overflow-wrap:anywhere]", children: context })) : null, isLoading ? (_jsx("div", { "data-slot": "routing-action-panel-loading", className: context ? "flex items-center justify-center py-[var(--space-4)]" : "absolute inset-0 flex items-center justify-center", children: _jsx(Spinner, { size: "md", label: loadingLabel }) })) : items.length === 0 ? (_jsx(RoutingEmptyState, { icon: Route, message: emptyMessage, description: emptyDescription })) : (_jsx(RoutingTimeline, { density: "compact", items: items }))] }) }));
|
|
20
20
|
}
|
|
21
21
|
export { RoutingActionPanel };
|