{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "cta-2",
  "title": "CTA 2: waitlist over light beams",
  "author": "Ballmac <https://ui.ballmac.com>",
  "description": "A waitlist or newsletter signup over rising light beams: heading, email field with validation, loading, success and error states.",
  "dependencies": [
    "lucide-react"
  ],
  "registryDependencies": [
    "utils",
    "https://ui.ballmac.com/r/beams-background.json",
    "https://ui.ballmac.com/r/button.json",
    "https://ui.ballmac.com/r/input.json"
  ],
  "files": [
    {
      "path": "registry/ballmac/components/blocks/cta-2/cta-2.tsx",
      "content": "// Ballmac UI: CTA 2. https://ui.ballmac.com/blocks/cta-2\n\"use client\"\n\nimport * as React from \"react\"\nimport { Check } from \"lucide-react\"\n\nimport { BeamsBackground } from \"@/components/ballmac/beams-background\"\nimport { Button } from \"@/components/ballmac/button\"\nimport { Input } from \"@/components/ballmac/input\"\nimport { cn } from \"@/lib/utils\"\n\ntype Cta2Props = Omit<React.ComponentProps<\"section\">, \"title\" | \"onSubmit\"> & {\n  /** Small label above the heading. */\n  eyebrow?: string\n  /** The heading. */\n  title?: string\n  /** One sentence under the heading. */\n  description?: string\n  /** Submit button text. */\n  buttonLabel?: string\n  /** Line under the form, e.g. social proof. */\n  note?: string\n  /** Message shown after a successful signup. */\n  successMessage?: string\n  /** Called with the email. Throw to show an error; resolve to show the success message. */\n  onSubmit?: (email: string) => void | Promise<void>\n}\n\nfunction Cta2({\n  eyebrow = \"Private beta\",\n  title = \"Join the waitlist.\",\n  description = \"We let new teams in every week. Leave your email and we'll save you a seat.\",\n  buttonLabel = \"Request access\",\n  note = \"No spam. One email when your seat is ready.\",\n  successMessage = \"You're on the list. We'll email you when your seat is ready.\",\n  onSubmit,\n  className,\n  ...props\n}: Cta2Props) {\n  const id = React.useId()\n  const [state, setState] = React.useState<\"idle\" | \"sending\" | \"done\" | \"error\">(\"idle\")\n  const submit = async (event: React.FormEvent<HTMLFormElement>) => {\n    event.preventDefault()\n    const email = String(new FormData(event.currentTarget).get(\"email\") ?? \"\")\n    setState(\"sending\")\n    try {\n      await onSubmit?.(email)\n      setState(\"done\")\n    } catch {\n      setState(\"error\")\n    }\n  }\n  return (\n    <section data-slot=\"cta-2\" className={cn(\"mx-auto max-w-6xl px-4 py-20 sm:px-6\", className)} {...props}>\n      <div className=\"relative isolate flex flex-col items-center overflow-hidden rounded-3xl border bg-background px-6 py-24 text-center sm:py-28\">\n        <BeamsBackground className=\"-z-10\" />\n        <div aria-hidden=\"true\" className=\"pointer-events-none absolute inset-0 -z-10 bg-[radial-gradient(ellipse_45%_45%_at_50%_50%,var(--background)_25%,transparent)]\" />\n        <p className=\"font-mono text-xs tracking-widest text-muted-foreground uppercase\">{eyebrow}</p>\n        <h2 className=\"mt-3 max-w-xl text-4xl font-semibold tracking-[-0.04em] text-balance sm:text-6xl\">{title}</h2>\n        <p className=\"mt-4 max-w-md text-pretty text-muted-foreground\">{description}</p>\n        {state === \"done\" ? (\n          <p role=\"status\" className=\"mt-8 inline-flex items-center gap-2 rounded-full border bg-background/80 px-4 py-2 text-sm font-medium backdrop-blur\">\n            <Check className=\"size-4 text-chart-2\" aria-hidden=\"true\" />\n            {successMessage}\n          </p>\n        ) : (\n          <form onSubmit={submit} className=\"mt-8 flex w-full max-w-md flex-col gap-2 sm:flex-row\">\n            <label htmlFor={`${id}-email`} className=\"sr-only\">\n              Email address\n            </label>\n            <Input\n              id={`${id}-email`}\n              name=\"email\"\n              type=\"email\"\n              required\n              autoComplete=\"email\"\n              placeholder=\"you@company.com\"\n              aria-invalid={state === \"error\" || undefined}\n              aria-describedby={state === \"error\" ? `${id}-error` : undefined}\n              className=\"h-10 bg-background/70 backdrop-blur\"\n            />\n            <Button type=\"submit\" loading={state === \"sending\"} className=\"h-10 shrink-0\">\n              {buttonLabel}\n            </Button>\n          </form>\n        )}\n        {state === \"error\" ? (\n          <p id={`${id}-error`} role=\"alert\" className=\"mt-3 text-sm text-destructive\">\n            Something went wrong. Please try again.\n          </p>\n        ) : (\n          state !== \"done\" && <p className=\"mt-4 text-xs text-muted-foreground\">{note}</p>\n        )}\n      </div>\n    </section>\n  )\n}\n\nexport { Cta2, type Cta2Props }\n",
      "type": "registry:component",
      "target": "@components/ballmac/blocks/cta-2/cta-2.tsx"
    }
  ],
  "meta": {
    "schema": 1,
    "tier": "free",
    "tags": [
      "cta",
      "waitlist",
      "newsletter",
      "signup",
      "beams"
    ],
    "version": "1.0.0",
    "updated": "2026-09-29",
    "ai": {
      "summary": "Email capture section. Wire `onSubmit(email)` to your API (throw on failure); the block handles loading, success and error states.",
      "whenToUse": [
        "Pre-launch waitlists",
        "Newsletter signup at the end of a page"
      ],
      "whenNotToUse": [
        "Collecting more than an email (use a form page)"
      ],
      "composesWith": [
        "hero-4",
        "features-3",
        "footer-1"
      ],
      "a11y": [],
      "customization": [
        "eyebrow, title, description, buttonLabel, note, successMessage",
        "onSubmit(email): Promise<void>"
      ]
    },
    "examples": [
      "cta-2-demo"
    ],
    "url": "https://ui.ballmac.com/components/cta-2"
  },
  "categories": [
    "blocks",
    "cta"
  ],
  "type": "registry:block"
}