{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "empty-styled",
  "title": "Empty essentials",
  "description": "Styled empty: the essentials set. 5 decorative empty variations (SimpleEmpty, IconEmpty, IllustrationEmpty, ActionEmpty, CardEmpty) on the ai2 token system, driven by CSS token transitions and sized sm to xl. Part of the free styled layer.",
  "dependencies": [
    "lucide-react@^1.23.0"
  ],
  "registryDependencies": [
    "@ai2/tokens"
  ],
  "files": [
    {
      "path": "registry/ai2/styled/empty-styled.tsx",
      "content": "\"use client\"\n\nimport type * as React from \"react\"\nimport { FileX, FolderOpen, Inbox, Plus, Search } from \"lucide-react\"\n\nimport { cn } from \"@/lib/utils\"\n\n/* Styled empty family: 5 opt-in empty-state placeholders. Each is a centred column: an icon or illustration plus title plus description plus an optional action. Colour comes ONLY from semantic tokens (transparency via color-mix), size = the padding plus icon and text scale. Renders without props too: the title, description and a default token icon come filled in. */\n\nexport type StyledSize = \"sm\" | \"md\" | \"lg\" | \"xl\"\n\ntype Scale = {\n  root: string\n  icon: string\n  badge: string\n  title: string\n  description: string\n}\n\nconst scales: Record<StyledSize, Scale> = {\n  sm: {\n    root: \"gap-2 p-6\",\n    icon: \"size-6\",\n    badge: \"size-12\",\n    title: \"text-sm\",\n    description: \"text-xs\",\n  },\n  md: {\n    root: \"gap-3 p-8\",\n    icon: \"size-8\",\n    badge: \"size-16\",\n    title: \"text-base\",\n    description: \"text-sm\",\n  },\n  lg: {\n    root: \"gap-3.5 p-10\",\n    icon: \"size-10\",\n    badge: \"size-20\",\n    title: \"text-lg\",\n    description: \"text-sm\",\n  },\n  xl: {\n    root: \"gap-4 p-12\",\n    icon: \"size-12\",\n    badge: \"size-24\",\n    title: \"text-xl\",\n    description: \"text-base\",\n  },\n}\n\ntype EmptyProps = {\n  className?: string\n  size?: StyledSize\n  icon?: React.ReactNode\n  title?: React.ReactNode\n  description?: React.ReactNode\n  action?: React.ReactNode\n}\n\n/* SimpleEmpty: a plain token icon + title + description, with no frame at all. */\nexport function SimpleEmpty({\n  className,\n  size = \"md\",\n  icon,\n  title = \"No results found\",\n  description = \"Try adjusting your search or filters to find what you are looking for.\",\n  action,\n}: EmptyProps) {\n  const s = scales[size]\n  return (\n    <div\n      data-slot=\"styled-empty\"\n      className={cn(\n        \"flex flex-col items-center justify-center text-center\",\n        s.root,\n        className\n      )}\n    >\n      <span\n        aria-hidden=\"true\"\n        className={cn(\n          \"text-muted-foreground [&_i]:leading-none [&_svg]:size-full\",\n          s.icon\n        )}\n      >\n        {icon ?? <Search />}\n      </span>\n      <p className={cn(\"font-semibold text-foreground\", s.title)}>{title}</p>\n      {description ? (\n        <p className={cn(\"max-w-prose text-muted-foreground\", s.description)}>\n          {description}\n        </p>\n      ) : null}\n      {action ? <div className=\"mt-2\">{action}</div> : null}\n    </div>\n  )\n}\n\n/* IconEmpty: token ikon, metnin ustunde yumusak token daire rozet icinde. */\nexport function IconEmpty({\n  className,\n  size = \"md\",\n  icon,\n  title = \"Your inbox is empty\",\n  description = \"New messages will show up here as soon as they arrive.\",\n  action,\n}: EmptyProps) {\n  const s = scales[size]\n  return (\n    <div\n      data-slot=\"styled-empty\"\n      className={cn(\n        \"flex flex-col items-center justify-center text-center\",\n        s.root,\n        className\n      )}\n    >\n      <span\n        aria-hidden=\"true\"\n        className={cn(\n          \"flex items-center justify-center rounded-full border border-border text-muted-foreground [background:color-mix(in_oklab,var(--color-foreground)_6%,transparent)]\",\n          s.badge\n        )}\n      >\n        <span className={cn(\"[&_i]:leading-none [&_svg]:size-full\", s.icon)}>\n          {icon ?? <Inbox />}\n        </span>\n      </span>\n      <p className={cn(\"font-semibold text-foreground\", s.title)}>{title}</p>\n      {description ? (\n        <p className={cn(\"max-w-prose text-muted-foreground\", s.description)}>\n          {description}\n        </p>\n      ) : null}\n      {action ? <div className=\"mt-2\">{action}</div> : null}\n    </div>\n  )\n}\n\n/* IllustrationEmpty: a geometric blob illustration built from token divs and SVG shapes above the text. When an icon prop is given it sits in the centre of the blob. */\nexport function IllustrationEmpty({\n  className,\n  size = \"md\",\n  icon,\n  title = \"Nothing here yet\",\n  description = \"This space is ready for your first item. Create one to get started.\",\n  action,\n}: EmptyProps) {\n  const s = scales[size]\n  return (\n    <div\n      data-slot=\"styled-empty\"\n      className={cn(\n        \"flex flex-col items-center justify-center text-center\",\n        s.root,\n        className\n      )}\n    >\n      <div aria-hidden=\"true\" className={cn(\"relative\", s.badge)}>\n        <div className=\"absolute inset-0 rounded-[42%_58%_58%_42%/48%_42%_58%_52%] [background:color-mix(in_oklab,var(--color-primary)_16%,transparent)]\" />\n        <div className=\"absolute inset-[18%] rounded-[58%_42%_45%_55%/52%_55%_45%_48%] [background:color-mix(in_oklab,var(--color-foreground)_8%,transparent)]\" />\n        <div className=\"absolute inset-0 grid place-items-center\">\n          <span\n            className={cn(\n              \"text-foreground/70 [&_i]:leading-none [&_svg]:size-full\",\n              s.icon\n            )}\n          >\n            {icon ?? <FolderOpen />}\n          </span>\n        </div>\n      </div>\n      <p className={cn(\"font-semibold text-foreground\", s.title)}>{title}</p>\n      {description ? (\n        <p className={cn(\"max-w-prose text-muted-foreground\", s.description)}>\n          {description}\n        </p>\n      ) : null}\n      {action ? <div className=\"mt-2\">{action}</div> : null}\n    </div>\n  )\n}\n\n/* ActionEmpty: title plus description plus a token primary action button (\"Create new\"). When no action prop is given the default button renders. */\nexport function ActionEmpty({\n  className,\n  size = \"md\",\n  icon,\n  title = \"No projects yet\",\n  description = \"Get started by creating your first project.\",\n  action,\n}: EmptyProps) {\n  const s = scales[size]\n  return (\n    <div\n      data-slot=\"styled-empty\"\n      className={cn(\n        \"flex flex-col items-center justify-center text-center\",\n        s.root,\n        className\n      )}\n    >\n      <span\n        aria-hidden=\"true\"\n        className={cn(\n          \"text-muted-foreground [&_i]:leading-none [&_svg]:size-full\",\n          s.icon\n        )}\n      >\n        {icon ?? <FileX />}\n      </span>\n      <p className={cn(\"font-semibold text-foreground\", s.title)}>{title}</p>\n      {description ? (\n        <p className={cn(\"max-w-prose text-muted-foreground\", s.description)}>\n          {description}\n        </p>\n      ) : null}\n      <div className=\"mt-2\">\n        {action ?? (\n          <button\n            type=\"button\"\n            data-slot=\"styled-empty-action\"\n            className=\"inline-flex h-9 items-center justify-center gap-2 rounded-md bg-primary px-4 text-sm font-medium text-primary-foreground transition-colors duration-(--motion-base) ease-(--motion-ease) hover:bg-primary/90 focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50 motion-reduce:transition-none [&_i]:text-base [&_i]:leading-none [&_svg]:size-4\"\n          >\n            <Plus />\n            Create new\n          </button>\n        )}\n      </div>\n    </div>\n  )\n}\n\n/* CardEmpty: the empty state sits inside a card surface with a dashed token\n   border. */\nexport function CardEmpty({\n  className,\n  size = \"md\",\n  icon,\n  title = \"No files uploaded\",\n  description = \"Drag and drop files here, or use the button to add your first one.\",\n  action,\n}: EmptyProps) {\n  const s = scales[size]\n  return (\n    <div\n      data-slot=\"styled-empty\"\n      className={cn(\n        \"flex flex-col items-center justify-center rounded-xl border border-dashed border-border bg-card text-center text-card-foreground [background:color-mix(in_oklab,var(--color-foreground)_3%,var(--color-card))]\",\n        s.root,\n        className\n      )}\n    >\n      <span\n        aria-hidden=\"true\"\n        className={cn(\n          \"text-muted-foreground [&_i]:leading-none [&_svg]:size-full\",\n          s.icon\n        )}\n      >\n        {icon ?? <Inbox />}\n      </span>\n      <p className={cn(\"font-semibold text-foreground\", s.title)}>{title}</p>\n      {description ? (\n        <p className={cn(\"max-w-prose text-muted-foreground\", s.description)}>\n          {description}\n        </p>\n      ) : null}\n      {action ? <div className=\"mt-2\">{action}</div> : null}\n    </div>\n  )\n}\n",
      "type": "registry:component",
      "target": "components/ui/empty-styled.tsx"
    }
  ],
  "categories": [
    "styled",
    "empty"
  ],
  "type": "registry:component"
}