{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "bento-grid",
  "title": "Bento Grid",
  "description": "A modular bento layout of mixed-size cards that stagger in on scroll and lift with a spotlight on hover.",
  "dependencies": ["framer-motion"],
  "registryDependencies": ["@godui/godui-theme"],
  "files": [
    {
      "path": "packages/components/src/bento-grid/bento-grid.tsx",
      "content": "\"use client\";\n\nimport { motion, type Variants } from \"framer-motion\";\nimport * as React from \"react\";\n\nexport type BentoGridProps = React.HTMLAttributes<HTMLDivElement> & {\n  /** Number of columns on large screens. */\n  columns?: 2 | 3 | 4;\n};\n\nexport type BentoCardProps = React.HTMLAttributes<HTMLDivElement> & {\n  /** Columns the card spans on large screens. */\n  colSpan?: 1 | 2 | 3;\n  /** Rows the card spans on large screens. */\n  rowSpan?: 1 | 2;\n  /** Optional leading icon / media. */\n  icon?: React.ReactNode;\n  /** Card heading. */\n  title?: React.ReactNode;\n  /** Supporting copy under the title. */\n  description?: React.ReactNode;\n  /** Call-to-action rendered at the bottom of the card. */\n  cta?: React.ReactNode;\n};\n\n// Static class maps — the Tailwind scanner can't see interpolated class names.\nconst GRID_COLS: Record<NonNullable<BentoGridProps[\"columns\"]>, string> = {\n  2: \"md:grid-cols-2\",\n  3: \"md:grid-cols-3\",\n  4: \"md:grid-cols-4\",\n};\n\nconst COL_SPAN: Record<NonNullable<BentoCardProps[\"colSpan\"]>, string> = {\n  1: \"md:col-span-1\",\n  2: \"md:col-span-2\",\n  3: \"md:col-span-3\",\n};\n\nconst ROW_SPAN: Record<NonNullable<BentoCardProps[\"rowSpan\"]>, string> = {\n  1: \"md:row-span-1\",\n  2: \"md:row-span-2\",\n};\n\nconst containerVariants: Variants = {\n  hidden: {},\n  visible: { transition: { staggerChildren: 0.08 } },\n};\n\nconst itemVariants: Variants = {\n  hidden: { opacity: 0, y: 20 },\n  visible: {\n    opacity: 1,\n    y: 0,\n    transition: { type: \"spring\", damping: 32, stiffness: 320, mass: 0.9 },\n  },\n};\n\nconst CARD_BASE =\n  \"group relative flex flex-col overflow-hidden rounded-xl border border-border bg-card p-6 text-card-foreground shadow-sm [transition:translate_300ms_cubic-bezier(0.3,0.7,0.4,1),box-shadow_300ms_ease] hover:-translate-y-1 hover:shadow-lg motion-reduce:[transition:none] motion-reduce:hover:translate-y-0\";\n\nconst CARD_GLOW =\n  \"pointer-events-none absolute inset-0 opacity-0 [transition:opacity_400ms_ease] group-hover:opacity-100 motion-reduce:[transition:none] [background:radial-gradient(280px_circle_at_var(--x,50%)_var(--y,50%),color-mix(in_oklch,var(--primary)_18%,transparent),transparent_70%)]\";\n\nconst BentoGrid = React.forwardRef<HTMLDivElement, BentoGridProps>(\n  ({ columns = 3, className, children, ...props }, ref) => (\n    <motion.div\n      ref={ref}\n      data-slot=\"bento-grid\"\n      className={`grid auto-rows-[minmax(11rem,auto)] grid-cols-1 gap-4 ${GRID_COLS[columns]} ${className ?? \"\"}`}\n      variants={containerVariants}\n      initial=\"hidden\"\n      whileInView=\"visible\"\n      viewport={{ once: true, amount: 0.15 }}\n      {...(props as React.ComponentProps<typeof motion.div>)}\n    >\n      {children}\n    </motion.div>\n  ),\n);\nBentoGrid.displayName = \"BentoGrid\";\n\nconst BentoCard = React.forwardRef<HTMLDivElement, BentoCardProps>(\n  (\n    {\n      colSpan = 1,\n      rowSpan = 1,\n      icon,\n      title,\n      description,\n      cta,\n      className,\n      children,\n      onPointerMove,\n      ...props\n    },\n    forwardedRef,\n  ) => {\n    const ref = React.useRef<HTMLDivElement>(null);\n    React.useImperativeHandle(\n      forwardedRef,\n      () => ref.current as HTMLDivElement,\n    );\n\n    const handlePointerMove = (e: React.PointerEvent<HTMLDivElement>) => {\n      const el = ref.current;\n      if (el) {\n        const rect = el.getBoundingClientRect();\n        el.style.setProperty(\"--x\", `${e.clientX - rect.left}px`);\n        el.style.setProperty(\"--y\", `${e.clientY - rect.top}px`);\n      }\n      onPointerMove?.(e);\n    };\n\n    return (\n      <motion.div\n        ref={ref}\n        data-slot=\"bento-card\"\n        variants={itemVariants}\n        onPointerMove={handlePointerMove}\n        className={`${CARD_BASE} ${COL_SPAN[colSpan]} ${ROW_SPAN[rowSpan]} ${className ?? \"\"}`}\n        {...(props as React.ComponentProps<typeof motion.div>)}\n      >\n        <div aria-hidden className={CARD_GLOW} />\n        <div className=\"relative z-raised flex h-full flex-col\">\n          {icon ? (\n            <div className=\"mb-4 inline-flex size-10 items-center justify-center rounded-lg bg-muted text-foreground\">\n              {icon}\n            </div>\n          ) : null}\n          {title ? (\n            <h3 className=\"text-base font-semibold text-foreground\">{title}</h3>\n          ) : null}\n          {description ? (\n            <p className=\"mt-1 text-sm text-muted-foreground\">{description}</p>\n          ) : null}\n          {children}\n          {cta ? <div className=\"mt-auto pt-4\">{cta}</div> : null}\n        </div>\n      </motion.div>\n    );\n  },\n);\nBentoCard.displayName = \"BentoCard\";\n\nexport { BentoCard, BentoGrid };\n",
      "type": "registry:ui",
      "target": "components/godui/bento-grid.tsx"
    }
  ],
  "type": "registry:ui"
}
