import * as React from "react";
/**
* EmptyState — three-part empty state: visual → headline → explanation → one CTA.
*
* Variants:
* - first-use : encouraging headline + create CTA.
* - no-results: echoes the query + a "Clear search" action.
* - error : neutral message + retry; announced via role="status".
*
* SaglitzDesign: exactly one primary action, >=44px CTA, visible focus,
* only transform/opacity animate (ease-out enter).
*/
type BaseProps = {
icon?: React.ReactNode; // decorative; wrapped with aria-hidden
headline: string;
description: string;
className?: string;
};
function Shell({
icon,
headline,
description,
children,
live,
className = "",
}: BaseProps & { children: React.ReactNode; live?: boolean }) {
const headingId = React.useId();
return (
{icon && (
{icon}
)}
{headline}
{description}
{children}
{/* keyframes; motion-reduce users skip the animation via motion-safe above */}
);
}
const primaryBtn =
"inline-flex min-h-11 items-center justify-center rounded-lg bg-indigo-600 px-5 text-sm font-medium text-white " +
"hover:bg-indigo-700 active:bg-indigo-800 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-indigo-600 " +
"focus-visible:ring-offset-2 dark:focus-visible:ring-indigo-400 dark:focus-visible:ring-offset-neutral-950 " +
"disabled:opacity-60 disabled:cursor-not-allowed";
const secondaryBtn =
"inline-flex min-h-11 items-center justify-center rounded-lg px-4 text-sm font-medium text-neutral-700 " +
"hover:bg-neutral-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-indigo-600 " +
"dark:text-neutral-200 dark:hover:bg-neutral-800";
/* --- first-use ------------------------------------------------------------ */
export function EmptyStateFirstUse({
icon,
headline = "Create your first project",
description = "Projects keep your work organized. Start with one and invite your team later.",
ctaLabel = "New project",
onCreate,
}: Partial & { ctaLabel?: string; onCreate: () => void }) {
return (
);
}
/* --- no-results ----------------------------------------------------------- */
export function EmptyStateNoResults({
icon,
query,
onClear,
}: Partial & { query: string; onClear: () => void }) {
return (
);
}
/* --- error ---------------------------------------------------------------- */
export function EmptyStateError({
icon,
description = "Something went wrong loading this. Check your connection and try again.",
onRetry,
loading = false,
}: Partial & { onRetry: () => void; loading?: boolean }) {
return (
);
}
/* -------------------------------------------------------------------------- */
/* Usage */
/* -------------------------------------------------------------------------- */
const FolderIcon = (
);
export function EmptyStateExamples() {
return (
{}} />
{}} />
{}} />
);
}