{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "background-pattern",
  "title": "Background Pattern",
  "description": "The nx-ui Background Pattern component.",
  "registryDependencies": [
    "@nx-ui/utils"
  ],
  "files": [
    {
      "path": "components/ui/background-pattern.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\n\n/**\n * BackgroundPattern — the Untitled UI decorative SVG backdrops that sit *behind*\n * a featured icon in empty states, modals and hero sections, radially masked so\n * they fade out toward the edges.\n *\n * Four patterns — concentric `circle` rings, a ruled `grid`, a filled-cell\n * `grid-check` checker, and `dots` — each in three sizes. All are pure SVG,\n * coloured with `currentColor` off the theme's `text-border-secondary` /\n * `bg-secondary` tokens, so they flip correctly in dark mode (unlike UUI's\n * grid-check, which hard-codes hexes — here the fill uses tokens).\n *\n * Paint-behind contract (shared with `glow` and `css-background-pattern`):\n * the svg is `pointer-events-none` and `-z-10`, so it stacks behind content\n * with no z-index needed on the content. `-z-10` resolves against the nearest\n * ancestor stacking context, so the consumer must make sure that ancestor\n * (give it `isolate`) BOTH contains every element the pattern may visually\n * overlap AND has no opaque background / intermediate stacking context in\n * between — otherwise the pattern paints over that content (an `isolate`\n * wrapper is itself painted in the positioned layer, above sibling text) or\n * vanishes behind an ancestor background. In practice:\n *\n * - Pattern clipped inside its box (thumbnails, card backdrops):\n *   `relative isolate overflow-hidden` on the wrapper.\n * - Flare bleeding behind following content (empty states, error pages):\n *   keep the positioning wrapper a plain `relative`, put `isolate` on the\n *   section root that wraps all of that content (e.g. the page `main`), and\n *   clip with `overflow-hidden` at the visual boundary.\n *\n * @example\n * <main className=\"relative isolate overflow-hidden\">\n *   …\n *   <div className=\"relative flex items-center justify-center\">\n *     <BackgroundPattern pattern=\"circle\" className=\"absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2\" />\n *     <FeaturedIcon … />\n *   </div>\n *   <h1>…</h1>\n * </main>\n */\n\ntype PatternName = \"circle\" | \"grid\" | \"grid-check\" | \"dots\"\ntype PatternSize = \"sm\" | \"md\" | \"lg\"\n\n/** viewBox side length + a divisor-friendly grid pitch, per size. */\nconst DIMS: Record<PatternSize, { box: number; pitch: number }> = {\n  sm: { box: 336, pitch: 24 },\n  md: { box: 480, pitch: 32 },\n  lg: { box: 768, pitch: 48 },\n}\n\n/** Concentric-ring radii per size (mirrors UUI's ~pitch-stepped rings). */\nconst RING_RADII: Record<PatternSize, number[]> = {\n  sm: [47.5, 71.5, 95.5, 119.5, 143.5, 167.5],\n  md: [47.5, 79.5, 111.5, 143.5, 175.5, 207.5, 239.5],\n  lg: [47.5, 95.5, 143.5, 191.5, 239.5, 287.5, 335.5, 383.5],\n}\n\nfunction RadialMask({\n  id,\n  box,\n  children,\n}: {\n  id: string\n  box: number\n  children: React.ReactNode\n}) {\n  const c = box / 2\n  return (\n    <>\n      <mask\n        id={id}\n        style={{ maskType: \"alpha\" }}\n        maskUnits=\"userSpaceOnUse\"\n        x=\"0\"\n        y=\"0\"\n        width={box}\n        height={box}\n      >\n        <rect width={box} height={box} fill={`url(#${id}-grad)`} />\n      </mask>\n      <defs>\n        <radialGradient\n          id={`${id}-grad`}\n          cx=\"0\"\n          cy=\"0\"\n          r=\"1\"\n          gradientUnits=\"userSpaceOnUse\"\n          gradientTransform={`translate(${c} ${c}) rotate(90) scale(${c} ${c})`}\n        >\n          <stop />\n          <stop offset=\"1\" stopOpacity=\"0\" />\n        </radialGradient>\n      </defs>\n      <g mask={`url(#${id})`}>{children}</g>\n    </>\n  )\n}\n\nfunction Circle({ size, maskId }: { size: PatternSize; maskId: string }) {\n  const { box } = DIMS[size]\n  const c = box / 2\n  return (\n    <RadialMask id={maskId} box={box}>\n      {RING_RADII[size].map((r) => (\n        <circle key={r} cx={c} cy={c} r={r} stroke=\"currentColor\" fill=\"none\" />\n      ))}\n    </RadialMask>\n  )\n}\n\nfunction Grid({ size, maskId }: { size: PatternSize; maskId: string }) {\n  const { box, pitch } = DIMS[size]\n  const lines: number[] = []\n  for (let x = 0.5; x < box; x += pitch) lines.push(x)\n  return (\n    <RadialMask id={maskId} box={box}>\n      {lines.map((x) => (\n        <line key={`v${x}`} x1={x} y1={0} x2={x} y2={box} stroke=\"currentColor\" />\n      ))}\n      {lines.map((y) => (\n        <line key={`h${y}`} x1={0} y1={y} x2={box} y2={y} stroke=\"currentColor\" />\n      ))}\n    </RadialMask>\n  )\n}\n\nfunction GridCheck({ size, maskId }: { size: PatternSize; maskId: string }) {\n  const { box, pitch } = DIMS[size]\n  const cells: { x: number; y: number }[] = []\n  const n = Math.ceil(box / pitch)\n  // A stable checker: fill cells where (row + col) is even, a subset of them,\n  // so the texture reads like UUI's grid-check without hard-coded hexes.\n  for (let row = 0; row < n; row++) {\n    for (let col = 0; col < n; col++) {\n      if ((row + col) % 3 === 0) cells.push({ x: col * pitch, y: row * pitch })\n    }\n  }\n  const lines: number[] = []\n  for (let x = 0.5; x < box; x += pitch) lines.push(x)\n  return (\n    <RadialMask id={maskId} box={box}>\n      {cells.map(({ x, y }) => (\n        <rect\n          key={`c${x}-${y}`}\n          x={x}\n          y={y}\n          width={pitch}\n          height={pitch}\n          className=\"fill-bg-secondary\"\n        />\n      ))}\n      {lines.map((x) => (\n        <line key={`v${x}`} x1={x} y1={0} x2={x} y2={box} stroke=\"currentColor\" />\n      ))}\n      {lines.map((y) => (\n        <line key={`h${y}`} x1={0} y1={y} x2={box} y2={y} stroke=\"currentColor\" />\n      ))}\n    </RadialMask>\n  )\n}\n\nfunction Dots({ size, maskId }: { size: PatternSize; maskId: string }) {\n  const { box, pitch } = DIMS[size]\n  const dots: { x: number; y: number }[] = []\n  for (let y = pitch / 2; y < box; y += pitch) {\n    for (let x = pitch / 2; x < box; x += pitch) {\n      dots.push({ x, y })\n    }\n  }\n  return (\n    <RadialMask id={maskId} box={box}>\n      {dots.map(({ x, y }) => (\n        <circle key={`d${x}-${y}`} cx={x} cy={y} r={1.5} fill=\"currentColor\" />\n      ))}\n    </RadialMask>\n  )\n}\n\nconst patterns = {\n  circle: Circle,\n  grid: Grid,\n  \"grid-check\": GridCheck,\n  dots: Dots,\n} as const\n\nfunction BackgroundPattern({\n  pattern = \"circle\",\n  size = \"md\",\n  className,\n  ...props\n}: React.ComponentProps<\"svg\"> & {\n  pattern?: PatternName\n  size?: PatternSize\n}) {\n  const uid = React.useId().replace(/[:]/g, \"\")\n  const maskId = `bgp-${uid}`\n  const { box } = DIMS[size]\n  const Pattern = patterns[pattern]\n\n  return (\n    <svg\n      data-slot=\"background-pattern\"\n      data-pattern={pattern}\n      width={box}\n      height={box}\n      viewBox={`0 0 ${box} ${box}`}\n      fill=\"none\"\n      aria-hidden=\"true\"\n      className={cn(\"pointer-events-none -z-10 text-border-secondary\", className)}\n      {...props}\n    >\n      <Pattern size={size} maskId={maskId} />\n    </svg>\n  )\n}\n\nexport { BackgroundPattern }\nexport type { PatternName, PatternSize }\n",
      "type": "registry:ui"
    }
  ],
  "type": "registry:ui"
}