{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "masonry-grid",
  "type": "registry:ui",
  "title": "Masonry grid",
  "description": "A masonry layout for React that keeps source order: a CSS grid with measured row spans, so keyboard and screen reader order match the visual flow.",
  "dependencies": [],
  "registryDependencies": [
    "utils"
  ],
  "files": [
    {
      "path": "registry/ui/masonry-grid.tsx",
      "type": "registry:ui",
      "target": "components/ui/masonry-grid.tsx",
      "content": "\"use client\"\nimport * as React from \"react\"\nimport { cn } from \"@/lib/utils\"\n\n/**\n * A masonry layout that keeps source order: a CSS grid with tiny rows where\n * each item spans as many rows as its measured height. Items flow left to\n * right, so keyboard and screen reader order match what you see, and the\n * column count follows the container width.\n */\ntype MasonryGridProps = {\n  children?: React.ReactNode\n  /** Minimum column width in pixels. */\n  minColumnWidth?: number\n  gap?: number\n  className?: string\n}\n\nconst ROW = 4\nconst DEMO = [180, 260, 140, 320, 200, 240, 160, 300, 220, 180, 280, 150]\n\nfunction Item({ children, gap }: { children: React.ReactNode; gap: number }) {\n  const ref = React.useRef<HTMLDivElement>(null)\n  const [span, setSpan] = React.useState(1)\n  React.useLayoutEffect(() => {\n    const el = ref.current?.firstElementChild as HTMLElement | null\n    if (!el) return\n    const fit = () => setSpan(Math.ceil((el.getBoundingClientRect().height + gap) / (ROW + gap)))\n    fit()\n    const ro = new ResizeObserver(fit)\n    ro.observe(el)\n    return () => ro.disconnect()\n  }, [gap])\n  return (\n    <div ref={ref} style={{ gridRowEnd: `span ${span}` }}>\n      {children}\n    </div>\n  )\n}\n\nfunction MasonryGrid({ children, minColumnWidth = 180, gap = 12, className }: MasonryGridProps) {\n  const items = React.Children.toArray(\n    children ??\n      DEMO.map((h, i) => (\n        <div key={i} className=\"grid place-items-center rounded-xl border border-border text-xs text-fg-subtle shadow-raised\" style={{ height: h, background: `color-mix(in oklch, var(--accent) ${6 + (i % 4) * 5}%, var(--surface))` }}>\n          {i + 1}\n        </div>\n      )),\n  )\n  return (\n    <div\n      data-slot=\"masonry-grid\"\n      className={cn(\"grid w-full items-start\", className)}\n      style={{ gridTemplateColumns: `repeat(auto-fill, minmax(min(${minColumnWidth}px, 100%), 1fr))`, gridAutoRows: ROW, columnGap: gap, rowGap: gap }}\n    >\n      {items.map((it, i) => (\n        <Item key={i} gap={gap}>\n          {it}\n        </Item>\n      ))}\n    </div>\n  )\n}\n\nexport { MasonryGrid }\nexport type { MasonryGridProps }\n"
    }
  ]
}
