{
  "$schema": "https://ui.shadcn.com/schema/registry.json",
  "name": "saastro",
  "homepage": "https://ui.saastro.io",
  "items": [
    {
      "name": "hero-01",
      "type": "registry:block",
      "title": "Hero — Centered",
      "description": "Centered hero with badge, heading, description, and dual CTA buttons. Zero-JS Astro component.",
      "registryDependencies": [],
      "files": [
        {
          "path": "registry/default/blocks/hero-01.astro",
          "type": "registry:component",
          "target": "@components/blocks/hero-01.astro"
        }
      ],
      "categories": [
        "hero",
        "landing"
      ],
      "author": "SAASTRO <https://saastro.io>",
      "docs": "Astro component — zero JS, no React required. Default import: `import Hero01 from '@/components/blocks/hero-01.astro'` and render statically. Props: badge?, title, description, primaryCta {label, href}, secondaryCta?, class?.",
      "meta": {
        "group": "Hero",
        "iframeHeight": "760px"
      }
    },
    {
      "name": "hero-02",
      "type": "registry:block",
      "title": "Hero — Split with Image",
      "description": "Split hero with content on the left and image or screenshot on the right. Zero-JS Astro component.",
      "registryDependencies": [],
      "files": [
        {
          "path": "registry/default/blocks/hero-02.astro",
          "type": "registry:component",
          "target": "@components/blocks/hero-02.astro"
        }
      ],
      "categories": [
        "hero",
        "landing"
      ],
      "author": "SAASTRO <https://saastro.io>",
      "docs": "Astro component — zero JS, no React required. Default import: `import Hero02 from '@/components/blocks/hero-02.astro'`. Props: badge?, title, description, primaryCta, secondaryCta?, imageSrc?, imageAlt?, class?.",
      "meta": {
        "group": "Hero",
        "iframeHeight": "760px"
      }
    },
    {
      "name": "hero-03",
      "type": "registry:block",
      "title": "Hero — Gradient",
      "description": "Hero with gradient background, floating badge, and a single prominent CTA. Zero-JS Astro component.",
      "registryDependencies": [],
      "files": [
        {
          "path": "registry/default/blocks/hero-03.astro",
          "type": "registry:component",
          "target": "@components/blocks/hero-03.astro"
        }
      ],
      "categories": [
        "hero",
        "landing"
      ],
      "author": "SAASTRO <https://saastro.io>",
      "docs": "Astro component — zero JS, no React required. Default import: `import Hero03 from '@/components/blocks/hero-03.astro'`. Props: badge?, title, description, cta {label, href}, class?.",
      "meta": {
        "group": "Hero",
        "iframeHeight": "700px"
      }
    },
    {
      "name": "features-01",
      "type": "registry:block",
      "title": "Features — Icon Grid",
      "description": "3-column feature grid with icons, titles, and descriptions in cards. Zero-JS Astro component.",
      "registryDependencies": [],
      "files": [
        {
          "path": "registry/default/blocks/features-01.astro",
          "type": "registry:component",
          "target": "@components/blocks/features-01.astro"
        }
      ],
      "categories": [
        "features",
        "landing"
      ],
      "author": "SAASTRO <https://saastro.io>",
      "docs": "Astro component — zero JS, no React required. Default import: `import Features01 from '@/components/blocks/features-01.astro'`. Props: title?, description?, features [{icon: 'zap'|'shield'|'code'|'sparkles'|'globe'|'lock', title, description}], class?. Icons are built-in inline SVGs keyed by name — props stay serializable.",
      "meta": {
        "group": "Features",
        "iframeHeight": "820px"
      }
    },
    {
      "name": "features-02",
      "type": "registry:block",
      "title": "Features — Alternating",
      "description": "Alternating image and text sections to showcase features. Zero-JS Astro component.",
      "registryDependencies": [],
      "files": [
        {
          "path": "registry/default/blocks/features-02.astro",
          "type": "registry:component",
          "target": "@components/blocks/features-02.astro"
        }
      ],
      "categories": [
        "features",
        "landing"
      ],
      "author": "SAASTRO <https://saastro.io>",
      "docs": "Astro component — zero JS, no React required. Default import: `import Features02 from '@/components/blocks/features-02.astro'`. Props: title?, description?, features [{badge?, title, description, imageSrc?, imageAlt?}], class?.",
      "meta": {
        "group": "Features",
        "iframeHeight": "1150px"
      }
    },
    {
      "name": "steps-01",
      "type": "registry:block",
      "title": "Steps — Numbered How-It-Works",
      "description": "Numbered steps for a how-it-works section, with optional eyebrow and description. Zero-JS Astro component.",
      "registryDependencies": [],
      "files": [
        {
          "path": "registry/default/blocks/steps-01.astro",
          "type": "registry:component",
          "target": "@components/blocks/steps-01.astro"
        }
      ],
      "categories": [
        "features",
        "landing"
      ],
      "author": "SAASTRO <https://saastro.io>",
      "docs": "Astro component — zero JS, no React required. Default import: `import Steps01 from '@/components/blocks/steps-01.astro'`. Props: steps[{title, description}], eyebrow?, title?, description?, class?. Los pasos se numeran solos por su orden: no metas el número en el texto. La cabecera entera es opcional — sin eyebrow/title/description el bloque pinta solo los pasos, que es lo que necesita un adaptador que quiera su cabecera editable.",
      "meta": {
        "group": "Features",
        "iframeHeight": "620px"
      }
    },
    {
      "name": "pricing-01",
      "type": "registry:block",
      "title": "Pricing — 3 Tiers",
      "description": "Three-tier pricing cards with monthly/annual toggle and feature lists.",
      "registryDependencies": [
        "@saastro/button",
        "@saastro/card",
        "@saastro/badge",
        "@saastro/separator"
      ],
      "files": [
        {
          "path": "registry/default/blocks/pricing-01.tsx",
          "type": "registry:component",
          "target": "@components/blocks/pricing-01.tsx"
        }
      ],
      "categories": [
        "pricing",
        "landing"
      ],
      "author": "SAASTRO <https://saastro.io>",
      "docs": "Import: `import { Pricing01 } from '@/components/blocks/pricing-01'`. Props: title?, description?, plans [{name, description, monthlyPrice, annualPrice, features[], popular?, cta {label, href}}], className?. Interactive (billing toggle) — in Astro hydrate with client:visible.",
      "meta": {
        "group": "Pricing",
        "iframeHeight": "1050px"
      }
    },
    {
      "name": "compare-01",
      "type": "registry:block",
      "title": "Compare — Two-column table",
      "description": "Two-column comparison of paired statements, with column labels and check/cross marks. Zero-JS Astro component.",
      "registryDependencies": [],
      "files": [
        {
          "path": "registry/default/blocks/compare-01.astro",
          "type": "registry:component",
          "target": "@components/blocks/compare-01.astro"
        }
      ],
      "categories": [
        "landing"
      ],
      "author": "SAASTRO <https://saastro.io>",
      "docs": "Astro component — zero JS, no React required. Default import: `import Compare01 from '@/components/blocks/compare-01.astro'`. Props: labels{left,right}, rows[{left,right}], eyebrow?, title?, description?, class?. La columna derecha es la destacada por convenio; las dos se quedan lado a lado también en móvil, porque apilarlas rompe la comparación.",
      "meta": {
        "group": "Landing",
        "iframeHeight": "820px"
      }
    },
    {
      "name": "cta-01",
      "type": "registry:block",
      "title": "CTA — Gradient Banner",
      "description": "Full-width CTA banner with gradient background, heading, and action buttons. Zero-JS Astro component.",
      "registryDependencies": [],
      "files": [
        {
          "path": "registry/default/blocks/cta-01.astro",
          "type": "registry:component",
          "target": "@components/blocks/cta-01.astro"
        }
      ],
      "categories": [
        "cta",
        "landing"
      ],
      "author": "SAASTRO <https://saastro.io>",
      "docs": "Astro component — zero JS, no React required. Default import: `import Cta01 from '@/components/blocks/cta-01.astro'`. Props: title, description, primaryCta, secondaryCta?, class?.",
      "meta": {
        "group": "CTA",
        "iframeHeight": "520px"
      }
    },
    {
      "name": "faq-01",
      "type": "registry:block",
      "title": "FAQ — Accordion",
      "description": "FAQ section with accordion for expandable questions and answers.",
      "registryDependencies": [
        "@saastro/accordion"
      ],
      "files": [
        {
          "path": "registry/default/blocks/faq-01.tsx",
          "type": "registry:component",
          "target": "@components/blocks/faq-01.tsx"
        }
      ],
      "categories": [
        "faq",
        "landing"
      ],
      "author": "SAASTRO <https://saastro.io>",
      "docs": "Import: `import { Faq01 } from '@/components/blocks/faq-01'`. Props: title?, description?, items [{question, answer}], className?. Interactive (accordion, Base UI) — in Astro hydrate with client:visible. Requires the base-nova (Base UI) accordion primitive.",
      "meta": {
        "group": "FAQ",
        "iframeHeight": "820px"
      }
    },
    {
      "name": "faq-02",
      "type": "registry:block",
      "title": "FAQ — sin JavaScript",
      "description": "FAQ con `<details>` nativo: cero JS, respuestas dentro del HTML servido e indexables. El hermano sin hidratar de faq-01.",
      "registryDependencies": [],
      "dependencies": [],
      "files": [
        {
          "path": "registry/default/blocks/faq-02.astro",
          "type": "registry:component",
          "target": "@components/blocks/faq-02.astro"
        }
      ],
      "categories": [
        "faq",
        "landing"
      ],
      "author": "SAASTRO <https://saastro.io>",
      "docs": "Import por defecto: `import Faq02 from '@/components/blocks/faq-02.astro'`. Props: title?, description?, items [{question, answer}], openFirst?, class?. Bloque Astro puro — NO lleva client:*, y no debe llevarlo: si lo hidratas pierdes lo único que lo distingue de faq-01. Elige faq-01 si necesitas animación de altura o un solo panel abierto a la vez.",
      "meta": {
        "group": "FAQ",
        "iframeHeight": "820px"
      }
    },
    {
      "name": "testimonials-01",
      "type": "registry:block",
      "title": "Testimonials — Card Grid",
      "description": "Testimonial grid with avatar, name, role, and quote cards. Zero-JS Astro component.",
      "registryDependencies": [],
      "files": [
        {
          "path": "registry/default/blocks/testimonials-01.astro",
          "type": "registry:component",
          "target": "@components/blocks/testimonials-01.astro"
        }
      ],
      "categories": [
        "testimonials",
        "landing"
      ],
      "author": "SAASTRO <https://saastro.io>",
      "docs": "Astro component — zero JS, no React required. Default import: `import Testimonials01 from '@/components/blocks/testimonials-01.astro'`. Props: title?, description?, testimonials [{quote, author, role, company?, avatarUrl?}], class?.",
      "meta": {
        "group": "Testimonials",
        "iframeHeight": "860px"
      }
    },
    {
      "name": "footer-01",
      "type": "registry:block",
      "title": "Footer — Multi-Column",
      "description": "Multi-column footer with navigation links, social icons, and copyright. Zero-JS Astro component.",
      "registryDependencies": [],
      "files": [
        {
          "path": "registry/default/blocks/footer-01.astro",
          "type": "registry:component",
          "target": "@components/blocks/footer-01.astro"
        }
      ],
      "categories": [
        "footer",
        "landing"
      ],
      "author": "SAASTRO <https://saastro.io>",
      "docs": "Astro component — zero JS, no React required. Default import: `import Footer01 from '@/components/blocks/footer-01.astro'`. Props: logo? (string), columns [{title, links}], copyright?, socialLinks? [{icon: 'github'|'x'|'linkedin', href, label}], class?.",
      "meta": {
        "group": "Navigation",
        "iframeHeight": "520px"
      }
    },
    {
      "name": "navbar-01",
      "type": "registry:block",
      "title": "Navbar — Responsive",
      "description": "Responsive navbar with desktop navigation and mobile hamburger menu.",
      "registryDependencies": [
        "@saastro/button",
        "@saastro/sheet"
      ],
      "files": [
        {
          "path": "registry/default/blocks/navbar-01.tsx",
          "type": "registry:component",
          "target": "@components/blocks/navbar-01.tsx"
        }
      ],
      "categories": [
        "navbar",
        "landing"
      ],
      "author": "SAASTRO <https://saastro.io>",
      "docs": "Import: `import { Navbar01 } from '@/components/blocks/navbar-01'`. Props: logo?, links [{label, href}], cta?, className?. Interactive (mobile Sheet, Base UI) — in Astro hydrate with client:load.",
      "meta": {
        "group": "Navigation",
        "iframeHeight": "480px"
      }
    },
    {
      "name": "blog-grid-01",
      "type": "registry:block",
      "title": "Blog — Post Grid",
      "description": "Responsive grid of blog post cards with image, title, excerpt, and metadata. Zero-JS Astro component.",
      "registryDependencies": [],
      "files": [
        {
          "path": "registry/default/blocks/blog-grid-01.astro",
          "type": "registry:component",
          "target": "@components/blocks/blog-grid-01.astro"
        }
      ],
      "categories": [
        "blog",
        "content"
      ],
      "author": "SAASTRO <https://saastro.io>",
      "docs": "Astro component — zero JS, no React required. Default import: `import BlogGrid01 from '@/components/blocks/blog-grid-01.astro'`. Props: title?, description?, posts [{title, excerpt, date, category?, imageUrl?, href}], class?.",
      "meta": {
        "group": "Content",
        "iframeHeight": "940px"
      }
    },
    {
      "name": "newsletter-01",
      "type": "registry:block",
      "title": "Newsletter — Signup",
      "description": "Email newsletter signup section with input and submit button. Zero-JS Astro component.",
      "registryDependencies": [],
      "files": [
        {
          "path": "registry/default/blocks/newsletter-01.astro",
          "type": "registry:component",
          "target": "@components/blocks/newsletter-01.astro"
        }
      ],
      "categories": [
        "newsletter",
        "cta"
      ],
      "author": "SAASTRO <https://saastro.io>",
      "docs": "Astro component — zero JS, NATIVE form submit (works without JavaScript). Default import: `import Newsletter01 from '@/components/blocks/newsletter-01.astro'`. Props: title?, description?, placeholder?, buttonText?, action? (submit endpoint), method?, class?.",
      "meta": {
        "group": "CTA",
        "iframeHeight": "480px"
      }
    },
    {
      "name": "stats-01",
      "type": "registry:block",
      "title": "Stats — Counter Row",
      "description": "Row of key statistics with large numbers and labels. Zero-JS Astro component.",
      "registryDependencies": [],
      "files": [
        {
          "path": "registry/default/blocks/stats-01.astro",
          "type": "registry:component",
          "target": "@components/blocks/stats-01.astro"
        }
      ],
      "categories": [
        "stats",
        "landing"
      ],
      "author": "SAASTRO <https://saastro.io>",
      "docs": "Astro component — zero JS, no React required. Default import: `import Stats01 from '@/components/blocks/stats-01.astro'`. Props: title?, stats [{value, label, prefix?, suffix?}], class?.",
      "meta": {
        "group": "Social Proof",
        "iframeHeight": "420px"
      }
    },
    {
      "name": "logos-01",
      "type": "registry:block",
      "title": "Logos — Trusted By",
      "description": "\"Trusted by\" logo cloud section with grayscale hover effect. Zero-JS Astro component.",
      "registryDependencies": [],
      "files": [
        {
          "path": "registry/default/blocks/logos-01.astro",
          "type": "registry:component",
          "target": "@components/blocks/logos-01.astro"
        }
      ],
      "categories": [
        "logos",
        "landing"
      ],
      "author": "SAASTRO <https://saastro.io>",
      "docs": "Astro component — zero JS, no React required. Default import: `import Logos01 from '@/components/blocks/logos-01.astro'`. Props: title?, logos [{name, imageUrl?}], class?.",
      "meta": {
        "group": "Social Proof",
        "iframeHeight": "420px"
      }
    },
    {
      "name": "button-pro",
      "type": "registry:ui",
      "title": "Button Pro",
      "description": "Enhanced button with CVA variants, icon effects, shine, gooey, underline, and gradient animations.",
      "registryDependencies": [],
      "dependencies": [
        "@base-ui/react",
        "class-variance-authority"
      ],
      "files": [
        {
          "path": "registry/default/ui/button-pro.tsx",
          "type": "registry:ui",
          "target": "@ui/button-pro.tsx"
        }
      ],
      "categories": [
        "ui",
        "buttons"
      ],
      "author": "SAASTRO <https://saastro.io>",
      "docs": "Import: `import { ButtonPro } from '@/components/ui/button-pro'`. Built on Base UI useRender/mergeProps: use render={<a/>} instead of asChild. Variants: variant, size, rounded, effect (shine, gooeyRight, underline, gradientSlideShow…), iconfx.",
      "meta": {
        "group": "Buttons",
        "iframeHeight": "640px"
      }
    },
    {
      "name": "button",
      "type": "registry:ui",
      "title": "Button",
      "description": "El botón base sobre Base UI. Variantes CVA (variant, size) y `render` en vez de `asChild`.",
      "registryDependencies": [],
      "dependencies": [
        "@base-ui/react",
        "class-variance-authority"
      ],
      "files": [
        {
          "path": "registry/default/ui/button.tsx",
          "type": "registry:ui",
          "target": "@ui/button.tsx"
        }
      ],
      "categories": [
        "ui",
        "buttons"
      ],
      "author": "SAASTRO <https://saastro.io>",
      "docs": "Primitivo sobre Base UI. En Base UI se usa `render={<a/>}`, no `asChild`. OJO: `render` NO funciona dentro de un fichero .astro — ahí usa las clases sobre el elemento nativo.",
      "meta": {
        "group": "Buttons",
        "iframeHeight": "480px"
      }
    },
    {
      "name": "badge",
      "type": "registry:ui",
      "title": "Badge",
      "description": "Etiqueta compacta con variantes CVA.",
      "registryDependencies": [],
      "dependencies": [
        "@base-ui/react",
        "class-variance-authority"
      ],
      "files": [
        {
          "path": "registry/default/ui/badge.tsx",
          "type": "registry:ui",
          "target": "@ui/badge.tsx"
        }
      ],
      "categories": [
        "ui"
      ],
      "author": "SAASTRO <https://saastro.io>",
      "docs": "Primitivo sobre Base UI. En Base UI se usa `render={<a/>}`, no `asChild`. OJO: `render` NO funciona dentro de un fichero .astro — ahí usa las clases sobre el elemento nativo.",
      "meta": {
        "group": "Display",
        "iframeHeight": "480px"
      }
    },
    {
      "name": "separator",
      "type": "registry:ui",
      "title": "Separator",
      "description": "Separador horizontal o vertical, accesible.",
      "registryDependencies": [],
      "dependencies": [
        "@base-ui/react"
      ],
      "files": [
        {
          "path": "registry/default/ui/separator.tsx",
          "type": "registry:ui",
          "target": "@ui/separator.tsx"
        }
      ],
      "categories": [
        "ui"
      ],
      "author": "SAASTRO <https://saastro.io>",
      "docs": "Primitivo sobre Base UI. En Base UI se usa `render={<a/>}`, no `asChild`. OJO: `render` NO funciona dentro de un fichero .astro — ahí usa las clases sobre el elemento nativo.",
      "meta": {
        "group": "Display",
        "iframeHeight": "480px"
      }
    },
    {
      "name": "card",
      "type": "registry:ui",
      "title": "Card",
      "description": "Tarjeta y sus partes (header, title, description, content, footer). Markup puro, sin dependencias.",
      "registryDependencies": [],
      "dependencies": [],
      "files": [
        {
          "path": "registry/default/ui/card.tsx",
          "type": "registry:ui",
          "target": "@ui/card.tsx"
        }
      ],
      "categories": [
        "ui"
      ],
      "author": "SAASTRO <https://saastro.io>",
      "docs": "Markup puro: no lleva primitivo externo. No usa Base UI, así que `render` no aplica aquí. Se instala y se edita como cualquier otro fichero copy-in.",
      "meta": {
        "group": "Display",
        "iframeHeight": "480px"
      }
    },
    {
      "name": "accordion",
      "type": "registry:ui",
      "title": "Accordion",
      "description": "Acordeón sobre Base UI, con animación de altura por CSS.",
      "registryDependencies": [],
      "dependencies": [
        "@base-ui/react",
        "lucide-react"
      ],
      "files": [
        {
          "path": "registry/default/ui/accordion.tsx",
          "type": "registry:ui",
          "target": "@ui/accordion.tsx"
        }
      ],
      "categories": [
        "ui"
      ],
      "author": "SAASTRO <https://saastro.io>",
      "docs": "Primitivo sobre Base UI. En Base UI se usa `render={<a/>}`, no `asChild`. OJO: `render` NO funciona dentro de un fichero .astro — ahí usa las clases sobre el elemento nativo.",
      "meta": {
        "group": "Disclosure",
        "iframeHeight": "480px"
      }
    },
    {
      "name": "sheet",
      "type": "registry:ui",
      "title": "Sheet",
      "description": "Panel lateral (drawer) sobre Base UI Dialog, con los cuatro lados.",
      "registryDependencies": [
        "@saastro/button"
      ],
      "dependencies": [
        "@base-ui/react",
        "lucide-react"
      ],
      "files": [
        {
          "path": "registry/default/ui/sheet.tsx",
          "type": "registry:ui",
          "target": "@ui/sheet.tsx"
        }
      ],
      "categories": [
        "ui",
        "overlays"
      ],
      "author": "SAASTRO <https://saastro.io>",
      "docs": "Primitivo sobre Base UI. En Base UI se usa `render={<a/>}`, no `asChild`. OJO: `render` NO funciona dentro de un fichero .astro — ahí usa las clases sobre el elemento nativo.",
      "meta": {
        "group": "Overlays",
        "iframeHeight": "420px"
      }
    },
    {
      "name": "input",
      "type": "registry:ui",
      "title": "Input",
      "description": "Campo de texto sobre Base UI, con los estados de foco e invalidez del sistema.",
      "registryDependencies": [],
      "dependencies": [
        "@base-ui/react"
      ],
      "files": [
        {
          "path": "registry/default/ui/input.tsx",
          "type": "registry:ui",
          "target": "@ui/input.tsx"
        }
      ],
      "categories": [
        "ui",
        "forms"
      ],
      "author": "SAASTRO <https://saastro.io>",
      "docs": "Primitivo sobre Base UI. Se usa `render={<a/>}`, no `asChild`. OJO: `render` NO funciona dentro de un .astro — un formulario con validación va en isla con @saastro/forms, nunca en .astro.",
      "meta": {
        "group": "Forms",
        "iframeHeight": "480px"
      }
    },
    {
      "name": "label",
      "type": "registry:ui",
      "title": "Label",
      "description": "Etiqueta de campo. La necesita `field`, y es markup puro.",
      "registryDependencies": [],
      "dependencies": [],
      "files": [
        {
          "path": "registry/default/ui/label.tsx",
          "type": "registry:ui",
          "target": "@ui/label.tsx"
        }
      ],
      "categories": [
        "ui",
        "forms"
      ],
      "author": "SAASTRO <https://saastro.io>",
      "docs": "Markup puro: no lleva primitivo externo. No usa Base UI, así que `render` no aplica aquí. Se instala y se edita como cualquier otro fichero copy-in.",
      "meta": {
        "group": "Forms",
        "iframeHeight": "480px"
      }
    },
    {
      "name": "textarea",
      "type": "registry:ui",
      "title": "Textarea",
      "description": "Área de texto multilínea.",
      "registryDependencies": [],
      "dependencies": [],
      "files": [
        {
          "path": "registry/default/ui/textarea.tsx",
          "type": "registry:ui",
          "target": "@ui/textarea.tsx"
        }
      ],
      "categories": [
        "ui",
        "forms"
      ],
      "author": "SAASTRO <https://saastro.io>",
      "docs": "Markup puro: no lleva primitivo externo. No usa Base UI, así que `render` no aplica aquí. Se instala y se edita como cualquier otro fichero copy-in.",
      "meta": {
        "group": "Forms",
        "iframeHeight": "480px"
      }
    },
    {
      "name": "select",
      "type": "registry:ui",
      "title": "Select",
      "description": "Desplegable sobre Base UI. Pasa `items` al Root: sin eso el trigger pinta el value crudo en vez de la etiqueta.",
      "registryDependencies": [],
      "dependencies": [
        "@base-ui/react",
        "lucide-react"
      ],
      "files": [
        {
          "path": "registry/default/ui/select.tsx",
          "type": "registry:ui",
          "target": "@ui/select.tsx"
        }
      ],
      "categories": [
        "ui",
        "forms"
      ],
      "author": "SAASTRO <https://saastro.io>",
      "docs": "Primitivo sobre Base UI. Se usa `render={<a/>}`, no `asChild`. OJO: `render` NO funciona dentro de un .astro — un formulario con validación va en isla con @saastro/forms, nunca en .astro. `SelectLabel` EXIGE un `<SelectGroup>` alrededor: es `Select.GroupLabel` y sin grupo lanza «SelectGroupContext is missing» al desplegar (en Radix el Label era libre).",
      "meta": {
        "group": "Forms",
        "iframeHeight": "480px"
      }
    },
    {
      "name": "checkbox",
      "type": "registry:ui",
      "title": "Checkbox",
      "description": "Casilla sobre Base UI.",
      "registryDependencies": [],
      "dependencies": [
        "@base-ui/react",
        "lucide-react"
      ],
      "files": [
        {
          "path": "registry/default/ui/checkbox.tsx",
          "type": "registry:ui",
          "target": "@ui/checkbox.tsx"
        }
      ],
      "categories": [
        "ui",
        "forms"
      ],
      "author": "SAASTRO <https://saastro.io>",
      "docs": "Primitivo sobre Base UI. Se usa `render={<a/>}`, no `asChild`. OJO: `render` NO funciona dentro de un .astro — un formulario con validación va en isla con @saastro/forms, nunca en .astro.",
      "meta": {
        "group": "Forms",
        "iframeHeight": "480px"
      }
    },
    {
      "name": "radio-group",
      "type": "registry:ui",
      "title": "Radio Group",
      "description": "Grupo de opciones excluyentes sobre Base UI.",
      "registryDependencies": [],
      "dependencies": [
        "@base-ui/react"
      ],
      "files": [
        {
          "path": "registry/default/ui/radio-group.tsx",
          "type": "registry:ui",
          "target": "@ui/radio-group.tsx"
        }
      ],
      "categories": [
        "ui",
        "forms"
      ],
      "author": "SAASTRO <https://saastro.io>",
      "docs": "Primitivo sobre Base UI. Se usa `render={<a/>}`, no `asChild`. OJO: `render` NO funciona dentro de un .astro — un formulario con validación va en isla con @saastro/forms, nunca en .astro.",
      "meta": {
        "group": "Forms",
        "iframeHeight": "480px"
      }
    },
    {
      "name": "switch",
      "type": "registry:ui",
      "title": "Switch",
      "description": "Interruptor sobre Base UI.",
      "registryDependencies": [],
      "dependencies": [
        "@base-ui/react"
      ],
      "files": [
        {
          "path": "registry/default/ui/switch.tsx",
          "type": "registry:ui",
          "target": "@ui/switch.tsx"
        }
      ],
      "categories": [
        "ui",
        "forms"
      ],
      "author": "SAASTRO <https://saastro.io>",
      "docs": "Primitivo sobre Base UI. Se usa `render={<a/>}`, no `asChild`. OJO: `render` NO funciona dentro de un .astro — un formulario con validación va en isla con @saastro/forms, nunca en .astro.",
      "meta": {
        "group": "Forms",
        "iframeHeight": "480px"
      }
    },
    {
      "name": "field",
      "type": "registry:ui",
      "title": "Field",
      "description": "Envoltorio de campo: label, descripción y error. Es lo que consume @saastro/forms.",
      "registryDependencies": [
        "@saastro/label",
        "@saastro/separator"
      ],
      "dependencies": [
        "class-variance-authority"
      ],
      "files": [
        {
          "path": "registry/default/ui/field.tsx",
          "type": "registry:ui",
          "target": "@ui/field.tsx"
        }
      ],
      "categories": [
        "ui",
        "forms"
      ],
      "author": "SAASTRO <https://saastro.io>",
      "docs": "Markup puro: no lleva primitivo externo. No usa Base UI, así que `render` no aplica aquí. Se instala y se edita como cualquier otro fichero copy-in.",
      "meta": {
        "group": "Forms",
        "iframeHeight": "480px"
      }
    },
    {
      "name": "form",
      "type": "registry:ui",
      "title": "Form",
      "description": "Puente entre react-hook-form y los primitivos. FormField/FormControl.",
      "registryDependencies": [],
      "dependencies": [
        "@base-ui/react",
        "react-hook-form"
      ],
      "files": [
        {
          "path": "registry/default/ui/form.tsx",
          "type": "registry:ui",
          "target": "@ui/form.tsx"
        }
      ],
      "categories": [
        "ui",
        "forms"
      ],
      "author": "SAASTRO <https://saastro.io>",
      "docs": "Primitivo sobre Base UI. Se usa `render={<a/>}`, no `asChild`. OJO: `render` NO funciona dentro de un .astro — un formulario con validación va en isla con @saastro/forms, nunca en .astro.",
      "meta": {
        "group": "Forms",
        "iframeHeight": "480px"
      }
    },
    {
      "name": "dialog",
      "type": "registry:ui",
      "title": "Dialog",
      "description": "Modal sobre Base UI, con backdrop y cierre accesible.",
      "registryDependencies": [
        "@saastro/button"
      ],
      "dependencies": [
        "@base-ui/react",
        "lucide-react"
      ],
      "files": [
        {
          "path": "registry/default/ui/dialog.tsx",
          "type": "registry:ui",
          "target": "@ui/dialog.tsx"
        }
      ],
      "categories": [
        "ui",
        "overlays"
      ],
      "author": "SAASTRO <https://saastro.io>",
      "docs": "Primitivo sobre Base UI. Se usa `render={<a/>}`, no `asChild`. OJO: `render` NO funciona dentro de un fichero .astro.",
      "meta": {
        "group": "Overlays",
        "iframeHeight": "420px"
      }
    },
    {
      "name": "popover",
      "type": "registry:ui",
      "title": "Popover",
      "description": "Panel flotante anclado sobre Base UI.",
      "registryDependencies": [],
      "dependencies": [
        "@base-ui/react"
      ],
      "files": [
        {
          "path": "registry/default/ui/popover.tsx",
          "type": "registry:ui",
          "target": "@ui/popover.tsx"
        }
      ],
      "categories": [
        "ui",
        "overlays"
      ],
      "author": "SAASTRO <https://saastro.io>",
      "docs": "Primitivo sobre Base UI. Se usa `render={<a/>}`, no `asChild`. OJO: `render` NO funciona dentro de un fichero .astro.",
      "meta": {
        "group": "Overlays",
        "iframeHeight": "420px"
      }
    },
    {
      "name": "tooltip",
      "type": "registry:ui",
      "title": "Tooltip",
      "description": "Ayuda contextual sobre Base UI.",
      "registryDependencies": [],
      "dependencies": [
        "@base-ui/react"
      ],
      "files": [
        {
          "path": "registry/default/ui/tooltip.tsx",
          "type": "registry:ui",
          "target": "@ui/tooltip.tsx"
        }
      ],
      "categories": [
        "ui",
        "overlays"
      ],
      "author": "SAASTRO <https://saastro.io>",
      "docs": "Primitivo sobre Base UI. Se usa `render={<a/>}`, no `asChild`. OJO: `render` NO funciona dentro de un fichero .astro.",
      "meta": {
        "group": "Overlays",
        "iframeHeight": "420px"
      }
    },
    {
      "name": "scroll-area",
      "type": "registry:ui",
      "title": "Scroll Area",
      "description": "Área con scroll y barra propia.",
      "registryDependencies": [],
      "dependencies": [
        "@base-ui/react"
      ],
      "files": [
        {
          "path": "registry/default/ui/scroll-area.tsx",
          "type": "registry:ui",
          "target": "@ui/scroll-area.tsx"
        }
      ],
      "categories": [
        "ui"
      ],
      "author": "SAASTRO <https://saastro.io>",
      "docs": "Primitivo sobre Base UI. Se usa `render={<a/>}`, no `asChild`. OJO: `render` NO funciona dentro de un fichero .astro.",
      "meta": {
        "group": "Display",
        "iframeHeight": "480px"
      }
    },
    {
      "name": "navigation-menu",
      "type": "registry:ui",
      "title": "Navigation Menu",
      "description": "Menú de navegación con submenús, sobre Base UI.",
      "registryDependencies": [],
      "dependencies": [
        "@base-ui/react",
        "class-variance-authority",
        "lucide-react"
      ],
      "files": [
        {
          "path": "registry/default/ui/navigation-menu.tsx",
          "type": "registry:ui",
          "target": "@ui/navigation-menu.tsx"
        }
      ],
      "categories": [
        "ui",
        "navigation"
      ],
      "author": "SAASTRO <https://saastro.io>",
      "docs": "Primitivo sobre Base UI. Se usa `render={<a/>}`, no `asChild`. OJO: `render` NO funciona dentro de un fichero .astro.",
      "meta": {
        "group": "Navigation",
        "iframeHeight": "420px"
      }
    },
    {
      "name": "slider",
      "type": "registry:ui",
      "title": "Slider",
      "description": "Control de rango sobre Base UI. Con un thumb emite NÚMERO PLANO, no array.",
      "registryDependencies": [],
      "dependencies": [
        "@base-ui/react"
      ],
      "files": [
        {
          "path": "registry/default/ui/slider.tsx",
          "type": "registry:ui",
          "target": "@ui/slider.tsx"
        }
      ],
      "categories": [
        "ui",
        "forms"
      ],
      "author": "SAASTRO <https://saastro.io>",
      "docs": "Primitivo sobre Base UI. Se usa `render={<a/>}`, no `asChild`. OJO: `render` NO funciona dentro de un fichero .astro.",
      "meta": {
        "group": "Forms",
        "iframeHeight": "480px"
      }
    },
    {
      "name": "native-select",
      "type": "registry:ui",
      "title": "Native Select",
      "description": "`<select>` nativo estilado. La opción sin JS cuando no hace falta un desplegable rico.",
      "registryDependencies": [],
      "dependencies": [
        "lucide-react"
      ],
      "files": [
        {
          "path": "registry/default/ui/native-select.tsx",
          "type": "registry:ui",
          "target": "@ui/native-select.tsx"
        }
      ],
      "categories": [
        "ui",
        "forms"
      ],
      "author": "SAASTRO <https://saastro.io>",
      "docs": "Markup puro: no lleva primitivo externo. No usa Base UI, así que `render` no aplica aquí. Se instala y se edita como cualquier otro fichero copy-in.",
      "meta": {
        "group": "Forms",
        "iframeHeight": "480px"
      }
    },
    {
      "name": "input-group",
      "type": "registry:ui",
      "title": "Input Group",
      "description": "Input con addons (prefijo, sufijo, botón).",
      "registryDependencies": [
        "@saastro/button",
        "@saastro/input",
        "@saastro/textarea"
      ],
      "dependencies": [
        "class-variance-authority"
      ],
      "files": [
        {
          "path": "registry/default/ui/input-group.tsx",
          "type": "registry:ui",
          "target": "@ui/input-group.tsx"
        }
      ],
      "categories": [
        "ui",
        "forms"
      ],
      "author": "SAASTRO <https://saastro.io>",
      "docs": "Markup puro: no lleva primitivo externo. No usa Base UI, así que `render` no aplica aquí. Se instala y se edita como cualquier otro fichero copy-in.",
      "meta": {
        "group": "Forms",
        "iframeHeight": "480px"
      }
    },
    {
      "name": "input-otp",
      "type": "registry:ui",
      "title": "Input OTP",
      "description": "Campo de código de un solo uso.",
      "registryDependencies": [],
      "dependencies": [
        "input-otp",
        "lucide-react"
      ],
      "files": [
        {
          "path": "registry/default/ui/input-otp.tsx",
          "type": "registry:ui",
          "target": "@ui/input-otp.tsx"
        }
      ],
      "categories": [
        "ui",
        "forms"
      ],
      "author": "SAASTRO <https://saastro.io>",
      "docs": "Sobre `input-otp`. No usa Base UI, así que `render` no aplica aquí. Se instala y se edita como cualquier otro fichero copy-in.",
      "meta": {
        "group": "Forms",
        "iframeHeight": "480px"
      }
    },
    {
      "name": "calendar",
      "type": "registry:ui",
      "title": "Calendar",
      "description": "Calendario sobre react-day-picker, con la navegación y los estilos del sistema.",
      "registryDependencies": [
        "@saastro/button"
      ],
      "dependencies": [
        "react-day-picker",
        "lucide-react"
      ],
      "files": [
        {
          "path": "registry/default/ui/calendar.tsx",
          "type": "registry:ui",
          "target": "@ui/calendar.tsx"
        }
      ],
      "categories": [
        "ui",
        "forms"
      ],
      "author": "SAASTRO <https://saastro.io>",
      "docs": "Sobre `react-day-picker`. No usa Base UI, así que `render` no aplica aquí. Se instala y se edita como cualquier otro fichero copy-in.",
      "meta": {
        "group": "Forms",
        "iframeHeight": "560px"
      }
    },
    {
      "name": "avatar",
      "type": "registry:ui",
      "title": "Avatar",
      "description": "Imagen de persona con iniciales de reserva, sobre Base UI.",
      "registryDependencies": [],
      "dependencies": [
        "@base-ui/react"
      ],
      "files": [
        {
          "path": "registry/default/ui/avatar.tsx",
          "type": "registry:ui",
          "target": "@ui/avatar.tsx"
        }
      ],
      "categories": [
        "ui",
        "display"
      ],
      "author": "SAASTRO <https://saastro.io>",
      "docs": "Primitivo sobre Base UI. En Base UI se compone con `render={<a/>}`, no con `asChild`. OJO: `render` NO funciona dentro de un fichero .astro.",
      "meta": {
        "group": "Display",
        "iframeHeight": "240px"
      }
    },
    {
      "name": "skeleton",
      "type": "registry:ui",
      "title": "Skeleton",
      "description": "El hueco de lo que está cargando, con la forma que va a tener.",
      "registryDependencies": [],
      "dependencies": [],
      "files": [
        {
          "path": "registry/default/ui/skeleton.tsx",
          "type": "registry:ui",
          "target": "@ui/skeleton.tsx"
        }
      ],
      "categories": [
        "ui",
        "display"
      ],
      "author": "SAASTRO <https://saastro.io>",
      "docs": "Markup puro: no lleva primitivo externo. Se instala y se edita como cualquier otro fichero copy-in; en .astro se usa tal cual.",
      "meta": {
        "group": "Display",
        "iframeHeight": "240px"
      }
    },
    {
      "name": "progress",
      "type": "registry:ui",
      "title": "Progress",
      "description": "Barra de avance sobre Base UI. `value={null}` es indeterminado.",
      "registryDependencies": [],
      "dependencies": [
        "@base-ui/react"
      ],
      "files": [
        {
          "path": "registry/default/ui/progress.tsx",
          "type": "registry:ui",
          "target": "@ui/progress.tsx"
        }
      ],
      "categories": [
        "ui",
        "display"
      ],
      "author": "SAASTRO <https://saastro.io>",
      "docs": "Primitivo sobre Base UI. En Base UI se compone con `render={<a/>}`, no con `asChild`. OJO: `render` NO funciona dentro de un fichero .astro. OJO al SSR: `ProgressValue` formatea con `Intl`, así que **pasa `locale` explícito** — si no, el servidor (Node, en-US) escribe «64%», un navegador es-ES pinta «64 %» y React tira la hidratación con el error #418.",
      "meta": {
        "group": "Display",
        "iframeHeight": "240px"
      }
    },
    {
      "name": "alert",
      "type": "registry:ui",
      "title": "Alert",
      "description": "El aviso que ya está en la página, no el que interrumpe.",
      "registryDependencies": [],
      "dependencies": [
        "class-variance-authority"
      ],
      "files": [
        {
          "path": "registry/default/ui/alert.tsx",
          "type": "registry:ui",
          "target": "@ui/alert.tsx"
        }
      ],
      "categories": [
        "ui",
        "display"
      ],
      "author": "SAASTRO <https://saastro.io>",
      "docs": "Markup puro: no lleva primitivo externo. Se instala y se edita como cualquier otro fichero copy-in; en .astro se usa tal cual.",
      "meta": {
        "group": "Display",
        "iframeHeight": "320px"
      }
    },
    {
      "name": "table",
      "type": "registry:ui",
      "title": "Table",
      "description": "Tabla nativa con su propio scroll horizontal.",
      "registryDependencies": [],
      "dependencies": [],
      "files": [
        {
          "path": "registry/default/ui/table.tsx",
          "type": "registry:ui",
          "target": "@ui/table.tsx"
        }
      ],
      "categories": [
        "ui",
        "display"
      ],
      "author": "SAASTRO <https://saastro.io>",
      "docs": "Markup puro: no lleva primitivo externo. Se instala y se edita como cualquier otro fichero copy-in; en .astro se usa tal cual.",
      "meta": {
        "group": "Display",
        "iframeHeight": "380px"
      }
    },
    {
      "name": "tabs",
      "type": "registry:ui",
      "title": "Tabs",
      "description": "Pestañas sobre Base UI, con indicador deslizante.",
      "registryDependencies": [],
      "dependencies": [
        "@base-ui/react"
      ],
      "files": [
        {
          "path": "registry/default/ui/tabs.tsx",
          "type": "registry:ui",
          "target": "@ui/tabs.tsx"
        }
      ],
      "categories": [
        "ui",
        "navigation"
      ],
      "author": "SAASTRO <https://saastro.io>",
      "docs": "Primitivo sobre Base UI. En Base UI se compone con `render={<a/>}`, no con `asChild`. OJO: `render` NO funciona dentro de un fichero .astro.",
      "meta": {
        "group": "Navigation",
        "iframeHeight": "320px"
      }
    },
    {
      "name": "dropdown-menu",
      "type": "registry:ui",
      "title": "Dropdown Menu",
      "description": "Menú desplegable sobre Base UI: items, checkbox, radio y submenús.",
      "registryDependencies": [],
      "dependencies": [
        "@base-ui/react"
      ],
      "files": [
        {
          "path": "registry/default/ui/dropdown-menu.tsx",
          "type": "registry:ui",
          "target": "@ui/dropdown-menu.tsx"
        }
      ],
      "categories": [
        "ui",
        "overlays"
      ],
      "author": "SAASTRO <https://saastro.io>",
      "docs": "Primitivo sobre Base UI. En Base UI se compone con `render={<a/>}`, no con `asChild`. OJO: `render` NO funciona dentro de un fichero .astro. `DropdownMenuLabel` EXIGE un `<DropdownMenuGroup>` alrededor: es `Menu.GroupLabel` y sin grupo lanza «MenuGroupContext is missing» al abrir el menú (en Radix el Label era libre).",
      "meta": {
        "group": "Overlays",
        "iframeHeight": "420px"
      }
    },
    {
      "name": "context-menu",
      "type": "registry:ui",
      "title": "Context Menu",
      "description": "El menú del botón derecho, sobre Base UI.",
      "registryDependencies": [],
      "dependencies": [
        "@base-ui/react"
      ],
      "files": [
        {
          "path": "registry/default/ui/context-menu.tsx",
          "type": "registry:ui",
          "target": "@ui/context-menu.tsx"
        }
      ],
      "categories": [
        "ui",
        "overlays"
      ],
      "author": "SAASTRO <https://saastro.io>",
      "docs": "Primitivo sobre Base UI. En Base UI se compone con `render={<a/>}`, no con `asChild`. OJO: `render` NO funciona dentro de un fichero .astro. `ContextMenuLabel` EXIGE un `<ContextMenuGroup>` alrededor: es `Menu.GroupLabel` y sin grupo lanza «MenuGroupContext is missing» al abrir el menú (en Radix el Label era libre).",
      "meta": {
        "group": "Overlays",
        "iframeHeight": "420px"
      }
    },
    {
      "name": "alert-dialog",
      "type": "registry:ui",
      "title": "Alert Dialog",
      "description": "El diálogo que exige respuesta: no se cierra con Escape ni pinchando fuera.",
      "registryDependencies": [
        "@saastro/button"
      ],
      "dependencies": [
        "@base-ui/react"
      ],
      "files": [
        {
          "path": "registry/default/ui/alert-dialog.tsx",
          "type": "registry:ui",
          "target": "@ui/alert-dialog.tsx"
        }
      ],
      "categories": [
        "ui",
        "overlays"
      ],
      "author": "SAASTRO <https://saastro.io>",
      "docs": "Primitivo sobre Base UI. En Base UI se compone con `render={<a/>}`, no con `asChild`. OJO: `render` NO funciona dentro de un fichero .astro.",
      "meta": {
        "group": "Overlays",
        "iframeHeight": "420px"
      }
    }
  ],
  "description": "Landing page blocks for Astro sites, installable with the shadcn CLI."
}
