{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "empty-state",
  "type": "registry:ui",
  "title": "Empty State",
  "description": "Empty State is a zero-content placeholder with title, description, and optional recovery actions for collections, search, or first-use flows.",
  "author": "Skrewww",
  "dependencies": [],
  "registryDependencies": [
    "@skrewww/button",
    "@skrewww/link",
    "@skrewww/foundation"
  ],
  "docs": "Host requirements (assumed already present, not installed by this command): react, react-dom.",
  "files": [
    {
      "path": "components/ui/EmptyState.tsx",
      "content": "/** @skrewww-component empty-state */\n\"use client\";\n\nimport { useId, type ReactNode } from \"react\";\nimport { Button } from \"@/components/ui/Button\";\nimport { Link } from \"@/components/ui/Link\";\nimport { cn } from \"@/lib/cn\";\nimport styles from \"@/components/ui/empty-state.module.css\";\n\nexport type EmptyStateAction = {\n  label: string;\n  href?: string;\n  onClick?: () => void;\n};\n\nexport type EmptyStateProps = {\n  title: string;\n  description?: ReactNode;\n  icon?: ReactNode;\n  illustration?: ReactNode;\n  illustrationAlt?: string;\n  primaryAction?: EmptyStateAction;\n  secondaryAction?: EmptyStateAction;\n  className?: string;\n};\n\nfunction EmptyStateActionControl({\n  action,\n  variant,\n}: {\n  action: EmptyStateAction;\n  variant: \"primary\" | \"secondary\";\n}) {\n  if (action.href) {\n    return (\n      <Link href={action.href} className={variant === \"primary\" ? styles.primaryLink : styles.secondaryLink}>\n        {action.label}\n      </Link>\n    );\n  }\n\n  return (\n    <Button type=\"button\" variant={variant === \"primary\" ? \"primary\" : \"secondary\"} onClick={action.onClick}>\n      {action.label}\n    </Button>\n  );\n}\n\nexport function EmptyState({\n  title,\n  description,\n  icon,\n  illustration,\n  illustrationAlt,\n  primaryAction,\n  secondaryAction,\n  className,\n}: EmptyStateProps) {\n  const titleId = useId();\n  const hasIllustration = Boolean(illustration);\n  const informativeIllustration = hasIllustration && Boolean(illustrationAlt?.trim());\n\n  return (\n    <section className={cn(styles.root, className)} aria-labelledby={titleId}>\n      {icon ? (\n        <div className={styles.icon} aria-hidden=\"true\">\n          {icon}\n        </div>\n      ) : null}\n      {hasIllustration ? (\n        informativeIllustration ? (\n          <div className={styles.illustration}>{illustration}</div>\n        ) : (\n          <div className={styles.illustration} aria-hidden=\"true\">\n            {illustration}\n          </div>\n        )\n      ) : null}\n      <h2 id={titleId} className={styles.title}>\n        {title}\n      </h2>\n      {description ? <p className={styles.description}>{description}</p> : null}\n      {primaryAction || secondaryAction ? (\n        <div className={styles.actions}>\n          {primaryAction ? (\n            <EmptyStateActionControl action={primaryAction} variant=\"primary\" />\n          ) : null}\n          {secondaryAction ? (\n            <EmptyStateActionControl action={secondaryAction} variant=\"secondary\" />\n          ) : null}\n        </div>\n      ) : null}\n    </section>\n  );\n}\n",
      "type": "registry:ui",
      "target": "~/components/ui/EmptyState.tsx"
    },
    {
      "path": "components/ui/empty-state.module.css",
      "content": ".root {\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  max-width: var(--empty-state-max-width);\n  margin-inline: auto;\n  padding: var(--empty-state-padding-y) var(--empty-state-padding-x);\n  border: 0;\n  background-color: var(--component-card-surface);\n  background-image: var(--component-surface-gradient-overlay);\n  box-shadow: none;\n  backdrop-filter: var(--component-surface-backdrop-filter);\n  text-align: center;\n}\n\n.icon {\n  display: inline-flex;\n  margin-bottom: var(--empty-state-content-gap);\n  color: var(--component-surface-content-muted);\n}\n\n.icon :global(svg) {\n  width: var(--empty-state-icon-size);\n  height: var(--empty-state-icon-size);\n}\n\n.illustration {\n  display: inline-flex;\n  margin-bottom: var(--empty-state-content-gap);\n  max-width: var(--empty-state-illustration-size);\n}\n\n.title {\n  margin: 0;\n  font-size: 1.125rem;\n  font-weight: 600;\n  line-height: 1.35;\n  color: var(--semantic-text-primary);\n}\n\n.description {\n  margin: 0.5rem 0 0;\n  font-size: 0.9375rem;\n  line-height: 1.5;\n  color: var(--empty-state-description-text);\n}\n\n.actions {\n  display: flex;\n  flex-wrap: wrap;\n  justify-content: center;\n  gap: var(--empty-state-action-gap);\n  margin-top: var(--empty-state-content-gap);\n}\n\n.primaryLink,\n.secondaryLink {\n  display: inline-flex;\n}\n",
      "type": "registry:ui",
      "target": "~/components/ui/empty-state.module.css"
    },
    {
      "path": "lib/cn.ts",
      "content": "export function cn(...classes: Array<string | false | null | undefined>): string {\n  return classes.filter(Boolean).join(\" \");\n}\n",
      "type": "registry:lib",
      "target": "~/lib/cn.ts"
    }
  ]
}
