{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "torch-grid",
  "type": "registry:component",
  "title": "Torch Grid",
  "description": "One soft light follows your pointer across a grid of cards, washing over the one you're on and catching the rims of its neighbours across the gaps.",
  "categories": [
    "motion",
    "Cursor"
  ],
  "dependencies": [],
  "registryDependencies": [
    "utils"
  ],
  "files": [
    {
      "path": "registry/devl/torch-grid.tsx",
      "type": "registry:component",
      "content": "\"use client\";\n\nimport { type ComponentProps, type CSSProperties, type PointerEvent, useRef } from \"react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface TorchGridProps extends ComponentProps<\"div\"> {\n  radius?: number;\n}\n\nexport function TorchGrid({\n  radius = 260,\n  className,\n  style,\n  onPointerEnter,\n  onPointerMove,\n  onPointerLeave,\n  ...props\n}: TorchGridProps) {\n  const ref = useRef<HTMLDivElement>(null);\n\n  const measure = () => {\n    const grid = ref.current;\n    if (!grid) return;\n    const g = grid.getBoundingClientRect();\n    for (const card of grid.querySelectorAll<HTMLElement>(\"[data-spotlight-card]\")) {\n      const c = card.getBoundingClientRect();\n      card.style.setProperty(\"--card-x\", `${c.left - g.left}px`);\n      card.style.setProperty(\"--card-y\", `${c.top - g.top}px`);\n    }\n  };\n\n  const track = (event: PointerEvent<HTMLDivElement>) => {\n    const grid = ref.current;\n    if (!grid) return;\n    const g = grid.getBoundingClientRect();\n    grid.style.setProperty(\"--spot-x\", `${event.clientX - g.left}px`);\n    grid.style.setProperty(\"--spot-y\", `${event.clientY - g.top}px`);\n  };\n\n  return (\n    <div\n      className={cn(\"group/spotlight relative\", className)}\n      data-spotlight-grid=\"\"\n      onPointerEnter={(e) => {\n        onPointerEnter?.(e);\n        if (e.pointerType !== \"mouse\") return;\n        measure();\n        track(e);\n        ref.current?.setAttribute(\"data-lit\", \"\");\n      }}\n      onPointerLeave={(e) => {\n        onPointerLeave?.(e);\n        ref.current?.removeAttribute(\"data-lit\");\n      }}\n      onPointerMove={(e) => {\n        onPointerMove?.(e);\n        if (e.pointerType === \"mouse\") track(e);\n      }}\n      ref={ref}\n      style={{ \"--spot-r\": `${radius}px`, ...style } as CSSProperties}\n      {...props}\n    />\n  );\n}\n\nexport type TorchCardProps = ComponentProps<\"div\">;\n\nconst atX = \"(var(--spot-x, -999px) - var(--card-x, 0px))\";\nconst atY = \"(var(--spot-y, -999px) - var(--card-y, 0px))\";\n\nexport function TorchCard({ className, children, ...props }: TorchCardProps) {\n  return (\n    <div\n      className={cn(\"relative isolate rounded-2xl border bg-card shadow-xs/5\", className)}\n      data-spotlight-card=\"\"\n      {...props}\n    >\n      <span\n        aria-hidden\n        className=\"pointer-events-none absolute inset-0 -z-10 rounded-[inherit] opacity-0 transition-opacity duration-300 ease-out group-data-lit/spotlight:opacity-100 [--spot-fill:color-mix(in_srgb,var(--color-foreground)_5%,transparent)] dark:[--spot-fill:color-mix(in_srgb,var(--color-foreground)_9%,transparent)]\"\n        style={{ background: `radial-gradient(var(--spot-r) circle at calc${atX} calc${atY}, var(--spot-fill), transparent 70%)` }}\n      />\n      <span\n        aria-hidden\n        className=\"pointer-events-none absolute -inset-px z-10 rounded-[inherit] border border-transparent opacity-0 transition-opacity duration-300 ease-out group-data-lit/spotlight:opacity-100 [--spot-rim:color-mix(in_srgb,var(--color-foreground)_32%,transparent)] dark:[--spot-rim:color-mix(in_srgb,var(--color-foreground)_44%,transparent)]\"\n        style={{\n          background: `radial-gradient(calc(var(--spot-r) * 0.7) circle at calc(${atX} + 1px) calc(${atY} + 1px), var(--spot-rim), transparent 70%) border-box`,\n          mask: \"linear-gradient(#000 0 0) padding-box exclude, linear-gradient(#000 0 0) border-box\",\n        }}\n      />\n      {children}\n    </div>\n  );\n}\n"
    }
  ]
}