{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "glow",
  "title": "Glow Button",
  "description": "A button with an animated conic-gradient glow layer behind it. Supports rotate, pulse, breathe, colorShift, flowHorizontal and static modes.",
  "dependencies": [
    "class-variance-authority",
    "motion"
  ],
  "registryDependencies": [
    "@unlumen-ui/button"
  ],
  "files": [
    {
      "path": "registry/components/buttons/glow/index.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\nimport { motion, type Transition } from \"motion/react\";\n\nimport { type VariantProps } from \"class-variance-authority\";\nimport { Button, buttonVariants } from \"@/components/ui/button\";\nimport { cn } from \"@/lib/utils\";\n\ntype ButtonProps = React.ComponentPropsWithoutRef<\"button\"> &\n  VariantProps<typeof buttonVariants> & { asChild?: boolean };\n\ntype GlowMode =\n  | \"rotate\"\n  | \"pulse\"\n  | \"breathe\"\n  | \"colorShift\"\n  | \"flowHorizontal\"\n  | \"static\";\n\ntype GlowBlur =\n  | number\n  | \"softest\"\n  | \"soft\"\n  | \"medium\"\n  | \"strong\"\n  | \"stronger\"\n  | \"strongest\"\n  | \"none\";\n\nconst BLUR_PRESETS: Record<string, string> = {\n  softest: \"blur-xs\",\n  soft: \"blur-sm\",\n  medium: \"blur-md\",\n  strong: \"blur-lg\",\n  stronger: \"blur-xl\",\n  strongest: \"blur-2xl\",\n  none: \"blur-none\",\n};\n\nfunction blurClass(blur: GlowBlur) {\n  if (typeof blur === \"number\") return `blur-[${blur}px]`;\n  return BLUR_PRESETS[blur] ?? \"blur-md\";\n}\n\ninterface GlowEffectInnerProps {\n  colors?: string[];\n  mode?: GlowMode;\n  blur?: GlowBlur;\n  scale?: number;\n  duration?: number;\n  transition?: Transition;\n  className?: string;\n}\n\nfunction GlowEffectLayer({\n  colors = [\"#FF5733\", \"#33FF57\", \"#3357FF\", \"#F1C40F\"],\n  mode = \"rotate\",\n  blur = \"strong\",\n  scale = 1,\n  duration = 5,\n  transition,\n  className,\n}: GlowEffectInnerProps) {\n  const base: Transition = { repeat: Infinity, duration, ease: \"linear\" };\n\n  const animations: Record<GlowMode, object> = {\n    rotate: {\n      background: [\n        `conic-gradient(from 0deg at 50% 50%, ${colors.join(\", \")})`,\n        `conic-gradient(from 360deg at 50% 50%, ${colors.join(\", \")})`,\n      ],\n      transition: transition ?? base,\n    },\n    pulse: {\n      background: colors.map(\n        (c) => `radial-gradient(circle at 50% 50%, ${c} 0%, transparent 100%)`,\n      ),\n      scale: [scale, scale * 1.1, scale],\n      opacity: [0.5, 0.8, 0.5],\n      transition: transition ?? { ...base, repeatType: \"mirror\" },\n    },\n    breathe: {\n      background: colors.map(\n        (c) => `radial-gradient(circle at 50% 50%, ${c} 0%, transparent 100%)`,\n      ),\n      scale: [scale, scale * 1.05, scale],\n      transition: transition ?? { ...base, repeatType: \"mirror\" },\n    },\n    colorShift: {\n      background: colors.map((c, i) => {\n        const next = colors[(i + 1) % colors.length];\n        return `conic-gradient(from 0deg at 50% 50%, ${c} 0%, ${next} 50%, ${c} 100%)`;\n      }),\n      transition: transition ?? { ...base, repeatType: \"mirror\" },\n    },\n    flowHorizontal: {\n      background: colors.map((c, i) => {\n        const next = colors[(i + 1) % colors.length];\n        return `linear-gradient(to right, ${c}, ${next})`;\n      }),\n      transition: transition ?? { ...base, repeatType: \"mirror\" },\n    },\n    static: {\n      background: `linear-gradient(to right, ${colors.join(\", \")})`,\n    },\n  };\n\n  return (\n    <motion.div\n      animate={animations[mode] as any}\n      style={\n        { \"--scale\": scale, willChange: \"transform\" } as React.CSSProperties\n      }\n      className={cn(\n        \"pointer-events-none absolute inset-0 h-full w-full\",\n        \"scale-[var(--scale)] transform-gpu\",\n        blurClass(blur),\n        className,\n      )}\n    />\n  );\n}\n\nexport interface GlowButtonProps extends ButtonProps {\n  /**\n   * Glow animation mode.\n   * @default \"rotate\"\n   */\n  mode?: GlowMode;\n  /**\n   * Glow colours (at least 2 for interesting effects).\n   * @default [\"#FF5733\", \"#33FF57\", \"#3357FF\", \"#F1C40F\"]\n   */\n  colors?: string[];\n  /**\n   * Blur strength of the glow layer.\n   * @default \"strong\"\n   */\n  blur?: GlowBlur;\n  /**\n   * Duration of one animation cycle in seconds.\n   * @default 5\n   */\n  duration?: number;\n  /**\n   * Scale of the glow layer relative to the button.\n   * Values > 1 spread the glow beyond the button edges.\n   * @default 1\n   */\n  glowScale?: number;\n  /** Extra classes applied to the outer wrapper. */\n  wrapperClassName?: string;\n}\n\nexport function GlowButton({\n  mode = \"rotate\",\n  colors = [\"#FF5733\", \"#33FF57\", \"#3357FF\", \"#F1C40F\"],\n  blur = \"strong\",\n  duration = 5,\n  glowScale = 1,\n  children,\n  className,\n  wrapperClassName,\n  disabled,\n  variant,\n  size,\n  asChild,\n  ...props\n}: GlowButtonProps) {\n  return (\n    <motion.div\n      className={cn(\n        \"relative inline-flex\",\n        disabled && \"pointer-events-none opacity-50\",\n        wrapperClassName,\n      )}\n      whileHover=\"hovered\"\n      initial=\"idle\"\n    >\n      <motion.div\n        className=\"absolute inset-0\"\n        variants={{\n          idle: { scale: glowScale },\n          hovered: { scale: glowScale * 1.05 },\n        }}\n        transition={{\n          type: \"spring\",\n          stiffness: 300,\n          damping: 20,\n        }}\n      >\n        <GlowEffectLayer\n          colors={colors}\n          mode={mode}\n          blur={blur}\n          duration={duration}\n          scale={1}\n        />\n      </motion.div>\n      <Button\n        variant={variant}\n        size={size}\n        asChild={asChild}\n        disabled={disabled}\n        className={cn(\"relative\", className)}\n        {...props}\n      >\n        {children}\n      </Button>\n    </motion.div>\n  );\n}\n",
      "type": "registry:ui",
      "target": "components/unlumen-ui/glow.tsx"
    }
  ],
  "type": "registry:ui"
}