{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "auto-grid",
  "type": "registry:ui",
  "title": "Auto Grid",
  "description": "A responsive, intrinsically-wrapping grid of equal cells with no breakpoints. Children flow into as many columns as fit at a configurable minimum item width, then grow to share the leftover space — the card-grid recipe, built on CSS Grid's repeat(auto-fit, minmax()) (the RAM pattern). Pure CSS, zero JavaScript.",
  "registryDependencies": [
    "utils"
  ],
  "files": [
    {
      "path": "registry/ui/auto-grid.tsx",
      "type": "registry:ui",
      "target": "components/ui/auto-grid.tsx",
      "content": "/** @jsxImportSource hono/jsx */\nimport type { PropsWithChildren } from \"hono/jsx\"\nimport { cn, type ClassValue } from \"@/registry/lib/cn\"\n\n// Auto Grid — shadcn-htmx, htmx v4 + Tailwind v4.\n//\n// A responsive, intrinsically-wrapping grid of equal cells with NO media\n// queries: children flow into as many columns as fit at a configurable\n// minimum item width, then grow to share the leftover space. This is the\n// \"RAM\" pattern (Repeat, Auto, Minmax) — the card-grid recipe most people\n// reach for. Pure CSS Grid; zero JavaScript.\n//\n// Built on (read before editing):\n//   repos/web.dev/src/site/content/en/patterns/layout/repeat-auto-minmax/index.md\n//     — the canonical recipe: `grid-template-columns: repeat(auto-fit,\n//       minmax(150px, 1fr))`. auto-fit collapses empty tracks so filled\n//       tracks grow; auto-fill keeps empty tracks (their width reserved).\n//   repos/web.dev/src/site/content/en/learn/css/grid/index.md:295-389\n//     — `minmax(0, 1fr)` forces equal share minus gaps; the\n//       `auto-fill`/`auto-fit` keywords create \"as many tracks as will fit\"\n//       with no media queries; the subtle auto-fill vs auto-fit difference.\n//   repos/mdn/files/en-us/web/css/minmax/index.md (minmax function)\n//   repos/mdn/files/en-us/web/css/min/index.md\n//     — `min(var(--auto-grid-min), 100%)` guards the lower bound so a single\n//       wide item can never overflow a container narrower than the min.\n//\n// shadcn/ui has no Auto Grid (React libraries leave layout to the consumer),\n// so there is no class string to mirror — this is a layout primitive.\n//\n// API shape:\n//   - `min`  : the per-item minimum width (any CSS length). Drives how many\n//              columns fit. Default \"16rem\".\n//   - `gap`  : the Tailwind gap step (number → gap-<n>) or a class. Default 4.\n//   - `fill` : false (default) uses auto-fit — empty tracks collapse and\n//              real items stretch to fill the row. true uses auto-fill —\n//              empty tracks are kept, so a half-empty last row stays aligned\n//              to the column rhythm rather than stretching.\n//   - `as`   : the element/role. Default <div>. Use \"ul\"/\"ol\" for a list of\n//              cards (each child should then be an <li>), or \"section\".\n//\n// We publish `--auto-grid-min` on the root and read it in an arbitrary\n// `grid-template-columns` utility, exactly like RangeSlider publishes\n// `--range-min`/`--range-max`. No runtime; the browser does the layout.\n\nexport type AutoGridAs = \"div\" | \"ul\" | \"ol\" | \"section\"\n\n// repeat(auto-fit|auto-fill, minmax(min(var(--auto-grid-min), 100%), 1fr)).\n// The min() guard means: never demand more than the container width, so one\n// item in a too-narrow container shrinks instead of forcing a scrollbar.\nconst FIT_CLASS =\n  \"grid [grid-template-columns:repeat(auto-fit,minmax(min(var(--auto-grid-min,16rem),100%),1fr))]\"\nconst FILL_CLASS =\n  \"grid [grid-template-columns:repeat(auto-fill,minmax(min(var(--auto-grid-min,16rem),100%),1fr))]\"\n\n// Gap presets so callers can pass a plain number; any other value (string)\n// is treated as an explicit class and appended verbatim.\nconst GAP_CLASS: Record<number, string> = {\n  0: \"gap-0\",\n  1: \"gap-1\",\n  2: \"gap-2\",\n  3: \"gap-3\",\n  4: \"gap-4\",\n  5: \"gap-5\",\n  6: \"gap-6\",\n  8: \"gap-8\",\n  10: \"gap-10\",\n  12: \"gap-12\",\n}\n\ntype AutoGridProps = PropsWithChildren<{\n  // Minimum per-item width. Any CSS length (\"16rem\", \"200px\", \"20ch\").\n  min?: string\n  // Gap between cells: a number maps to gap-<n>; a string is used verbatim.\n  gap?: number | string\n  // auto-fill (keep empty tracks) instead of auto-fit (collapse them).\n  fill?: boolean\n  // Semantic element / role. \"ul\"/\"ol\" for a card list.\n  as?: AutoGridAs\n  ariaLabel?: string\n  ariaLabelledby?: string\n  class?: ClassValue\n  id?: string\n  [key: `hx-${string}`]: any\n  [key: `data-${string}`]: any\n  [key: `aria-${string}`]: any\n}>\n\nexport function AutoGrid(props: AutoGridProps) {\n  const {\n    min = \"16rem\",\n    gap = 4,\n    fill = false,\n    as = \"div\",\n    ariaLabel,\n    ariaLabelledby,\n    class: className,\n    children,\n    ...rest\n  } = props as any\n  const Tag: any = as\n  const gapClass = typeof gap === \"number\" ? (GAP_CLASS[gap] ?? \"gap-4\") : gap\n  return (\n    <Tag\n      data-slot=\"auto-grid\"\n      data-fill={fill ? \"true\" : undefined}\n      // Publish the per-item minimum; the grid-template-columns utility reads\n      // it. Keeping it a custom property means callers tune density without\n      // touching the (uncompilable-at-runtime) arbitrary class.\n      style={`--auto-grid-min:${min}`}\n      aria-label={ariaLabel}\n      aria-labelledby={ariaLabelledby}\n      class={cn(fill ? FILL_CLASS : FIT_CLASS, gapClass, className)}\n      {...rest}\n    >\n      {children}\n    </Tag>\n  )\n}\n"
    },
    {
      "path": "registry/jinja2/auto-grid.html",
      "type": "registry:file",
      "target": "templates/components/auto-grid.html",
      "content": "{# Auto Grid macro — shadcn-htmx, htmx v4 + Tailwind v4.\n   Mirrors registry/ui/auto-grid.tsx.\n\n   A responsive, intrinsically-wrapping grid of equal cells with no media\n   queries (the RAM pattern: repeat, auto-fit/auto-fill, minmax). Pure CSS.\n\n   Usage:\n     {% from \"components/auto-grid.html\" import auto_grid %}\n\n     {% call auto_grid() %}                      {# default: 16rem min, gap-4 #}\n       <div>…card…</div>\n     {% endcall %}\n\n     {% call auto_grid(min=\"20rem\", gap=\"gap-6\", fill=true, tag=\"ul\") %}\n       <li>…</li>\n     {% endcall %}\n\n   Args:\n     min       per-item minimum width (any CSS length). Default \"16rem\".\n     gap       a gap-* class (string). Default \"gap-4\".\n     fill      true → auto-fill (keep empty tracks); false → auto-fit. Default false.\n     tag       div | ul | ol | section. Default \"div\".\n     attrs     dict of extra attributes (hx-*, data-*, aria-*). #}\n\n{% macro auto_grid(\n    min=\"16rem\",\n    gap=\"gap-4\",\n    fill=false,\n    tag=\"div\",\n    aria_label=none,\n    aria_labelledby=none,\n    extra_class=\"\",\n    attrs={}\n) %}\n{%- set tracks -%}\n{% if fill %}repeat(auto-fill,minmax(min(var(--auto-grid-min,16rem),100%),1fr)){% else %}repeat(auto-fit,minmax(min(var(--auto-grid-min,16rem),100%),1fr)){% endif %}\n{%- endset -%}\n<{{ tag }}\n  data-slot=\"auto-grid\"\n  {%- if fill %} data-fill=\"true\"{% endif %}\n  style=\"--auto-grid-min:{{ min }}\"\n  {%- if aria_label %} aria-label=\"{{ aria_label }}\"{% endif %}\n  {%- if aria_labelledby %} aria-labelledby=\"{{ aria_labelledby }}\"{% endif %}\n  {%- for k, v in attrs.items() %} {{ k|replace('_','-') }}=\"{{ v }}\"{% endfor %}\n  class=\"grid [grid-template-columns:{{ tracks }}] {{ gap }} {{ extra_class }}\">\n  {{ caller() }}\n</{{ tag }}>\n{% endmacro %}\n"
    },
    {
      "path": "registry/go-templates/auto-grid.tmpl",
      "type": "registry:file",
      "target": "components/auto-grid.tmpl",
      "content": "{{/*\n  Auto Grid template — shadcn-htmx, htmx v4 + Tailwind v4.\n  Mirrors registry/ui/auto-grid.tsx.\n\n  A responsive, intrinsically-wrapping grid of equal cells with no media\n  queries (the RAM pattern: repeat, auto-fit/auto-fill, minmax). Pure CSS.\n\n      type AutoGridArgs struct {\n          Min   string // per-item minimum width (any CSS length); default \"16rem\"\n          Gap   string // a gap-* class; default \"gap-4\"\n          Fill  bool   // true = auto-fill (keep empty tracks); false = auto-fit\n          Tag   string // div | ul | ol | section; default \"div\"\n          Class string // extra classes appended to the root\n          Body  string // inner HTML (use htmlSafe)\n      }\n\n  Usage:\n      {{template \"auto-grid\" (dict \"Body\" (htmlSafe $cards))}}\n      {{template \"auto-grid\" (dict \"Min\" \"20rem\" \"Gap\" \"gap-6\" \"Fill\" true \"Tag\" \"ul\" \"Body\" (htmlSafe $items))}}\n*/}}\n\n{{define \"auto-grid\"}}\n{{- $min := or .Min \"16rem\" -}}\n{{- $gap := or .Gap \"gap-4\" -}}\n{{- $tag := or .Tag \"div\" -}}\n{{- $tracks := \"repeat(auto-fit,minmax(min(var(--auto-grid-min,16rem),100%),1fr))\" -}}\n{{- if .Fill}}{{- $tracks = \"repeat(auto-fill,minmax(min(var(--auto-grid-min,16rem),100%),1fr))\"}}{{end -}}\n<{{$tag}} data-slot=\"auto-grid\"{{if .Fill}} data-fill=\"true\"{{end}} style=\"--auto-grid-min:{{$min}}\"{{if .AriaLabel}} aria-label=\"{{.AriaLabel}}\"{{end}}{{if .AriaLabelledby}} aria-labelledby=\"{{.AriaLabelledby}}\"{{end}} class=\"grid [grid-template-columns:{{$tracks}}] {{$gap}}{{if .Class}} {{.Class}}{{end}}\">{{htmlSafe .Body}}</{{$tag}}>\n{{end}}\n"
    },
    {
      "path": "registry/phoenix/auto_grid.ex",
      "type": "registry:file",
      "target": "lib/my_app_web/components/auto_grid.ex",
      "content": "defmodule ShadcnHtmx.Components.AutoGrid do\n  @moduledoc \"\"\"\n  Auto Grid — shadcn-htmx, htmx v4 + Tailwind v4 for Phoenix.\n\n  Mirrors registry/ui/auto-grid.tsx.\n\n  A responsive, intrinsically-wrapping grid of equal cells with no media\n  queries — children flow into as many columns as fit at a configurable\n  minimum item width, then grow to share the leftover space. This is the\n  \"RAM\" pattern (Repeat, Auto, Minmax). Pure CSS Grid; zero JavaScript.\n\n    - `min`  — per-item minimum width (any CSS length). Default \"16rem\".\n    - `gap`  — a gap-* class. Default \"gap-4\".\n    - `fill` — true → auto-fill (keep empty tracks); false → auto-fit\n               (collapse them so real items stretch). Default false.\n    - `tag`  — div | ul | ol | section. Default \"div\".\n\n  ## Examples\n\n      <.auto_grid>\n        <div :for={item <- @items}>…</.auto_grid>\n\n      <.auto_grid min=\"20rem\" gap=\"gap-6\" fill tag=\"ul\">\n        <li :for={item <- @items}>…</li>\n      </.auto_grid>\n  \"\"\"\n\n  use Phoenix.Component\n\n  attr :min, :string, default: \"16rem\"\n  attr :gap, :string, default: \"gap-4\"\n  attr :fill, :boolean, default: false\n  attr :tag, :string, default: \"div\", values: ~w(div ul ol section)\n  attr :class, :string, default: nil\n  attr :rest, :global, include: ~w(aria-label aria-labelledby)\n  slot :inner_block, required: true\n\n  def auto_grid(assigns) do\n    tracks =\n      if assigns.fill do\n        \"repeat(auto-fill,minmax(min(var(--auto-grid-min,16rem),100%),1fr))\"\n      else\n        \"repeat(auto-fit,minmax(min(var(--auto-grid-min,16rem),100%),1fr))\"\n      end\n\n    assigns = assign(assigns, :tracks, tracks)\n\n    ~H\"\"\"\n    <.dynamic_tag\n      tag_name={@tag}\n      data-slot=\"auto-grid\"\n      data-fill={if @fill, do: \"true\"}\n      style={\"--auto-grid-min:#{@min}\"}\n      class={[\"grid\", \"[grid-template-columns:#{@tracks}]\", @gap, @class]}\n      {@rest}\n    >\n      {render_slot(@inner_block)}\n    </.dynamic_tag>\n    \"\"\"\n  end\nend\n"
    },
    {
      "path": "registry/html/auto-grid.html",
      "type": "registry:file",
      "target": "snippets/auto-grid.html",
      "content": "<!--\n  shadcn-htmx — raw HTML Auto Grid snippet.\n  Mirrors registry/ui/auto-grid.tsx.\n\n  A responsive, intrinsically-wrapping grid of equal cells with NO media\n  queries (the RAM pattern: repeat, auto-fit/auto-fill, minmax). Pure CSS;\n  no script. Relies only on theme tokens.\n\n  Tune density with the --auto-grid-min custom property in the inline style.\n  The grid-template-columns utility reads it:\n    repeat(auto-fit,  minmax(min(var(--auto-grid-min), 100%), 1fr))  → collapse empty tracks\n    repeat(auto-fill, minmax(min(var(--auto-grid-min), 100%), 1fr))  → keep empty tracks\n-->\n\n<!-- Default: 16rem minimum per item, gap-4, auto-fit (items stretch) -->\n<div data-slot=\"auto-grid\"\n     style=\"--auto-grid-min:16rem\"\n     class=\"grid [grid-template-columns:repeat(auto-fit,minmax(min(var(--auto-grid-min,16rem),100%),1fr))] gap-4\">\n  <div class=\"rounded-lg border bg-card p-4 text-card-foreground\">Item 1</div>\n  <div class=\"rounded-lg border bg-card p-4 text-card-foreground\">Item 2</div>\n  <div class=\"rounded-lg border bg-card p-4 text-card-foreground\">Item 3</div>\n  <div class=\"rounded-lg border bg-card p-4 text-card-foreground\">Item 4</div>\n</div>\n\n<!-- As a list of cards: <ul> root, <li> children, wider min, larger gap -->\n<ul data-slot=\"auto-grid\"\n    style=\"--auto-grid-min:20rem\"\n    class=\"grid [grid-template-columns:repeat(auto-fit,minmax(min(var(--auto-grid-min,16rem),100%),1fr))] gap-6\">\n  <li class=\"rounded-lg border bg-card p-4 text-card-foreground\">Card A</li>\n  <li class=\"rounded-lg border bg-card p-4 text-card-foreground\">Card B</li>\n  <li class=\"rounded-lg border bg-card p-4 text-card-foreground\">Card C</li>\n</ul>\n\n<!-- auto-fill: empty trailing tracks are kept so a half-empty row stays\n     aligned to the column rhythm instead of stretching -->\n<div data-slot=\"auto-grid\" data-fill=\"true\"\n     style=\"--auto-grid-min:12rem\"\n     class=\"grid [grid-template-columns:repeat(auto-fill,minmax(min(var(--auto-grid-min,16rem),100%),1fr))] gap-4\">\n  <div class=\"rounded-lg border bg-card p-4 text-card-foreground\">One</div>\n  <div class=\"rounded-lg border bg-card p-4 text-card-foreground\">Two</div>\n</div>\n"
    }
  ]
}
