"use client"; import { useSyncExternalStore, type HTMLAttributes, type ReactNode, type CSSProperties, } from "react"; export type StatusTone = "neutral" | "success" | "warning" | "error"; export function Status({ children, tone = "neutral", className = "", ...props }: HTMLAttributes & { tone?: StatusTone }) { return ( ); } export function Alert({ title, children, tone = "neutral", action, className = "", ...props }: Omit, "title"> & { title: string; tone?: StatusTone; action?: ReactNode; }) { return (
{title} {children &&
{children}
} {action &&
{action}
}
); } export function Progress({ value, max = 100, label = "Progress", showValue = true, className = "", }: { value?: number; max?: number; label?: string; showValue?: boolean; className?: string; }) { const limit = Math.max(1, max), current = value === undefined ? undefined : Math.min(limit, Math.max(0, value)); return (
{label} {showValue && ( {current === undefined ? "In progress" : `${Math.round((current / limit) * 100)}%`} )}
); } export function Meter({ value, min = 0, max = 100, low, high, optimum, label, format, className = "", }: { value: number; min?: number; max?: number; low?: number; high?: number; optimum?: number; label: string; format?: (value: number) => string; className?: string; }) { const limit = Math.max(min + 1, max), current = Math.min(limit, Math.max(min, value)); return (
{label} {format ? format(current) : current}
); } export function Skeleton({ lines = 3, label = "Loading content", className = "", style, }: { lines?: number; label?: string; className?: string; style?: CSSProperties; }) { return (
{Array.from({ length: Math.min(20, Math.max(1, lines)) }, (_, i) => (
); } export function EmptyState({ title, children, action, icon, className = "", }: { title: string; children?: ReactNode; action?: ReactNode; icon?: ReactNode; className?: string; }) { return (
{icon && ( )}

{title}

{children &&
{children}
} {action &&
{action}
}
); } export function ErrorState({ title = "Something went wrong", children, onRetry, className = "", }: { title?: string; children?: ReactNode; onRetry?: () => void; className?: string; }) { return (

{title}

{children &&

{children}

} {onRetry && ( )}
); } const subscribeConnection = (callback: () => void) => { window.addEventListener("online", callback); window.addEventListener("offline", callback); return () => { window.removeEventListener("online", callback); window.removeEventListener("offline", callback); }; }; export function ConnectionStatus({ onlineLabel = "Connected", offlineLabel = "Offline — changes may not sync", className = "", }: { onlineLabel?: string; offlineLabel?: string; className?: string; }) { const online = useSyncExternalStore( subscribeConnection, () => navigator.onLine, () => true, ); return ( {online ? onlineLabel : offlineLabel} ); } export function SaveIndicator({ state, onRetry, className = "", }: { state: "saved" | "unsaved" | "saving" | "error"; onRetry?: () => void; className?: string; }) { const messages = { saved: "All changes saved", unsaved: "Unsaved changes", saving: "Saving changes…", error: "Changes could not be saved", }; return (
{messages[state]} {state === "error" && onRetry && ( )}
); } export function AsyncBoundary({ state, children, loading, empty, error, onRetry, }: { state: "loading" | "empty" | "error" | "ready"; children: ReactNode; loading?: ReactNode; empty?: ReactNode; error?: string; onRetry?: () => void; }) { if (state === "loading") return <>{loading ?? }; if (state === "empty") return <>{empty ?? }; if (state === "error") return ( {error ?? "The content could not be loaded."} ); return <>{children}; } export type TaskStep = { id: string; label: string; state: "queued" | "running" | "complete" | "error"; detail?: string; }; export function TaskProgress({ steps, label = "Task progress", onCancel, className = "", }: { steps: readonly TaskStep[]; label?: string; onCancel?: () => void; className?: string; }) { const done = steps.filter((s) => s.state === "complete").length; return (
    {steps.map((step) => (
  1. {step.label} {step.state} {step.detail && {step.detail}}
  2. ))}
{onCancel && steps.some((s) => s.state === "running") && ( )}
); }