{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "grid",
  "title": "Grid & Bento",
  "description": "Responsive grid and a 12-column bento with spanning items.",
  "dependencies": [],
  "registryDependencies": [
    "@hjconsult/lib"
  ],
  "files": [
    {
      "path": "src/components/grid/index.tsx",
      "content": "import type { ComponentPropsWithoutRef, Ref } from 'react'\nimport { cn } from '../../lib'\n\nexport type GridColumns = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12\nexport type Breakpoint = 'base' | 'sm' | 'md' | 'lg' | 'xl'\nexport type Responsive<T> = T | Partial<Record<Breakpoint, T>>\nexport type GridGap = 'none' | 'sm' | 'md' | 'lg' | 'xl'\n\n/*\n * Class lookups are spelled out so Tailwind's scanner sees every utility.\n */\nconst cols: Record<Breakpoint, Record<GridColumns, string>> = {\n  base: {\n    1: 'grid-cols-1',\n    2: 'grid-cols-2',\n    3: 'grid-cols-3',\n    4: 'grid-cols-4',\n    5: 'grid-cols-5',\n    6: 'grid-cols-6',\n    7: 'grid-cols-7',\n    8: 'grid-cols-8',\n    9: 'grid-cols-9',\n    10: 'grid-cols-10',\n    11: 'grid-cols-11',\n    12: 'grid-cols-12',\n  },\n  sm: {\n    1: 'sm:grid-cols-1',\n    2: 'sm:grid-cols-2',\n    3: 'sm:grid-cols-3',\n    4: 'sm:grid-cols-4',\n    5: 'sm:grid-cols-5',\n    6: 'sm:grid-cols-6',\n    7: 'sm:grid-cols-7',\n    8: 'sm:grid-cols-8',\n    9: 'sm:grid-cols-9',\n    10: 'sm:grid-cols-10',\n    11: 'sm:grid-cols-11',\n    12: 'sm:grid-cols-12',\n  },\n  md: {\n    1: 'md:grid-cols-1',\n    2: 'md:grid-cols-2',\n    3: 'md:grid-cols-3',\n    4: 'md:grid-cols-4',\n    5: 'md:grid-cols-5',\n    6: 'md:grid-cols-6',\n    7: 'md:grid-cols-7',\n    8: 'md:grid-cols-8',\n    9: 'md:grid-cols-9',\n    10: 'md:grid-cols-10',\n    11: 'md:grid-cols-11',\n    12: 'md:grid-cols-12',\n  },\n  lg: {\n    1: 'lg:grid-cols-1',\n    2: 'lg:grid-cols-2',\n    3: 'lg:grid-cols-3',\n    4: 'lg:grid-cols-4',\n    5: 'lg:grid-cols-5',\n    6: 'lg:grid-cols-6',\n    7: 'lg:grid-cols-7',\n    8: 'lg:grid-cols-8',\n    9: 'lg:grid-cols-9',\n    10: 'lg:grid-cols-10',\n    11: 'lg:grid-cols-11',\n    12: 'lg:grid-cols-12',\n  },\n  xl: {\n    1: 'xl:grid-cols-1',\n    2: 'xl:grid-cols-2',\n    3: 'xl:grid-cols-3',\n    4: 'xl:grid-cols-4',\n    5: 'xl:grid-cols-5',\n    6: 'xl:grid-cols-6',\n    7: 'xl:grid-cols-7',\n    8: 'xl:grid-cols-8',\n    9: 'xl:grid-cols-9',\n    10: 'xl:grid-cols-10',\n    11: 'xl:grid-cols-11',\n    12: 'xl:grid-cols-12',\n  },\n}\n\nconst colSpans: Record<Breakpoint, Record<GridColumns | 'full', string>> = {\n  base: {\n    1: 'col-span-1',\n    2: 'col-span-2',\n    3: 'col-span-3',\n    4: 'col-span-4',\n    5: 'col-span-5',\n    6: 'col-span-6',\n    7: 'col-span-7',\n    8: 'col-span-8',\n    9: 'col-span-9',\n    10: 'col-span-10',\n    11: 'col-span-11',\n    12: 'col-span-12',\n    full: 'col-span-full',\n  },\n  sm: {\n    1: 'sm:col-span-1',\n    2: 'sm:col-span-2',\n    3: 'sm:col-span-3',\n    4: 'sm:col-span-4',\n    5: 'sm:col-span-5',\n    6: 'sm:col-span-6',\n    7: 'sm:col-span-7',\n    8: 'sm:col-span-8',\n    9: 'sm:col-span-9',\n    10: 'sm:col-span-10',\n    11: 'sm:col-span-11',\n    12: 'sm:col-span-12',\n    full: 'sm:col-span-full',\n  },\n  md: {\n    1: 'md:col-span-1',\n    2: 'md:col-span-2',\n    3: 'md:col-span-3',\n    4: 'md:col-span-4',\n    5: 'md:col-span-5',\n    6: 'md:col-span-6',\n    7: 'md:col-span-7',\n    8: 'md:col-span-8',\n    9: 'md:col-span-9',\n    10: 'md:col-span-10',\n    11: 'md:col-span-11',\n    12: 'md:col-span-12',\n    full: 'md:col-span-full',\n  },\n  lg: {\n    1: 'lg:col-span-1',\n    2: 'lg:col-span-2',\n    3: 'lg:col-span-3',\n    4: 'lg:col-span-4',\n    5: 'lg:col-span-5',\n    6: 'lg:col-span-6',\n    7: 'lg:col-span-7',\n    8: 'lg:col-span-8',\n    9: 'lg:col-span-9',\n    10: 'lg:col-span-10',\n    11: 'lg:col-span-11',\n    12: 'lg:col-span-12',\n    full: 'lg:col-span-full',\n  },\n  xl: {\n    1: 'xl:col-span-1',\n    2: 'xl:col-span-2',\n    3: 'xl:col-span-3',\n    4: 'xl:col-span-4',\n    5: 'xl:col-span-5',\n    6: 'xl:col-span-6',\n    7: 'xl:col-span-7',\n    8: 'xl:col-span-8',\n    9: 'xl:col-span-9',\n    10: 'xl:col-span-10',\n    11: 'xl:col-span-11',\n    12: 'xl:col-span-12',\n    full: 'xl:col-span-full',\n  },\n}\n\nexport type RowSpan = 1 | 2 | 3 | 4 | 5 | 6\nconst rowSpans: Record<Breakpoint, Record<RowSpan, string>> = {\n  base: {\n    1: 'row-span-1',\n    2: 'row-span-2',\n    3: 'row-span-3',\n    4: 'row-span-4',\n    5: 'row-span-5',\n    6: 'row-span-6',\n  },\n  sm: {\n    1: 'sm:row-span-1',\n    2: 'sm:row-span-2',\n    3: 'sm:row-span-3',\n    4: 'sm:row-span-4',\n    5: 'sm:row-span-5',\n    6: 'sm:row-span-6',\n  },\n  md: {\n    1: 'md:row-span-1',\n    2: 'md:row-span-2',\n    3: 'md:row-span-3',\n    4: 'md:row-span-4',\n    5: 'md:row-span-5',\n    6: 'md:row-span-6',\n  },\n  lg: {\n    1: 'lg:row-span-1',\n    2: 'lg:row-span-2',\n    3: 'lg:row-span-3',\n    4: 'lg:row-span-4',\n    5: 'lg:row-span-5',\n    6: 'lg:row-span-6',\n  },\n  xl: {\n    1: 'xl:row-span-1',\n    2: 'xl:row-span-2',\n    3: 'xl:row-span-3',\n    4: 'xl:row-span-4',\n    5: 'xl:row-span-5',\n    6: 'xl:row-span-6',\n  },\n}\n\nconst gaps: Record<GridGap, string> = {\n  none: 'gap-0',\n  sm: 'gap-3',\n  md: 'gap-5',\n  lg: 'gap-8',\n  xl: 'gap-12',\n}\n\nconst BREAKPOINTS: Breakpoint[] = ['base', 'sm', 'md', 'lg', 'xl']\n\nfunction responsiveClasses<T extends string | number>(\n  value: Responsive<T> | undefined,\n  lookup: Record<Breakpoint, Partial<Record<T, string>>>,\n): string[] {\n  if (value === undefined) return []\n  if (typeof value !== 'object') return [lookup.base[value] ?? '']\n  return BREAKPOINTS.flatMap((bp) => {\n    const v = value[bp]\n    return v === undefined ? [] : [lookup[bp][v] ?? '']\n  })\n}\n\nexport interface GridProps extends ComponentPropsWithoutRef<'div'> {\n  as?: 'div' | 'ul' | 'ol' | 'section'\n  /** Column count, optionally per breakpoint: `{ base: 1, md: 2, lg: 3 }`. */\n  columns?: Responsive<GridColumns>\n  gap?: GridGap\n  /** `dense` back-fills holes left by spanning items. */\n  flow?: 'row' | 'dense'\n  ref?: Ref<HTMLDivElement>\n}\n\nexport function Grid({\n  as = 'div',\n  columns = { base: 1, md: 2, lg: 3 },\n  gap = 'md',\n  flow = 'row',\n  className,\n  ...props\n}: GridProps) {\n  const Tag = as as 'div'\n  return (\n    <Tag\n      className={cn(\n        'grid',\n        responsiveClasses(columns, cols),\n        gaps[gap],\n        flow === 'dense' && 'grid-flow-dense',\n        className,\n      )}\n      {...props}\n    />\n  )\n}\n\n/* -------------------------------------------------------------------------------------------------\n * Bento\n * -----------------------------------------------------------------------------------------------*/\n\nexport interface BentoItemProps extends ComponentPropsWithoutRef<'div'> {\n  as?: 'div' | 'li' | 'article' | 'section'\n  /** Column span, optionally per breakpoint. `'full'` spans every column. */\n  span?: Responsive<GridColumns | 'full'>\n  rowSpan?: Responsive<RowSpan>\n  ref?: Ref<HTMLDivElement>\n}\n\nfunction BentoItem({ as = 'div', span, rowSpan, className, ...props }: BentoItemProps) {\n  const Tag = as as 'div'\n  return (\n    <Tag\n      className={cn(\n        'min-w-0',\n        responsiveClasses(span, colSpans),\n        responsiveClasses(rowSpan, rowSpans),\n        className,\n      )}\n      {...props}\n    />\n  )\n}\n\nexport type BentoProps = GridProps\n\n/**\n * Editorial grid: 1 column on phones, 6 on tablets, 12 on desktop. Compose cells with\n * `Bento.Item span={{ base: 'full', md: 3, lg: 4 }}`.\n */\nfunction BentoRoot({ columns = { base: 1, md: 6, lg: 12 }, flow = 'dense', ...props }: BentoProps) {\n  return <Grid columns={columns} flow={flow} {...props} />\n}\n\nexport const Bento = Object.assign(BentoRoot, { Item: BentoItem })\nexport { BentoItem }\n",
      "type": "registry:ui",
      "target": "hj/components/grid/index.tsx"
    }
  ],
  "cssVars": {},
  "type": "registry:ui"
}