{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "buttons-stroke",
  "title": "Stroke buttons",
  "description": "Styled buttons: the Stroke set. 5 decorative buttons variations (RotateStrokeButton, BeamButton, GradientStrokeButton, CornersButton, GrowRingButton) on the ai2 token system, powered by framer-motion, reduced-motion aware and sized sm to xl. Part of the free styled layer.",
  "dependencies": [
    "motion@^12.42.2"
  ],
  "registryDependencies": [
    "@ai2/tokens"
  ],
  "files": [
    {
      "path": "registry/ai2/styled/buttons-stroke.tsx",
      "content": "\"use client\"\n\nimport type * as React from \"react\"\nimport { motion, useReducedMotion, type HTMLMotionProps } from \"motion/react\"\n\nimport { cn } from \"@/lib/utils\"\n\n/* Stroke button family: 5 variations on edges and frames. All are sized, use framer-motion, take colour ONLY from semantic tokens and are reduced-motion safe. The rotating rings derive from two layers: the outer one a gradient or conic, the inner one covering the middle with bg. */\n\nexport type StyledSize = \"sm\" | \"md\" | \"lg\" | \"xl\"\n\n/* Ring structure (Rotate/Beam/Gradient): outer height plus inner fill and radius. */\nconst ring: Record<StyledSize, string> = {\n  sm: \"h-8 rounded-md\",\n  md: \"h-9 rounded-lg\",\n  lg: \"h-10 rounded-lg\",\n  xl: \"h-12 rounded-xl\",\n}\nconst ringInner: Record<StyledSize, string> = {\n  sm: \"gap-1.5 rounded-[5px] px-3 text-sm\",\n  md: \"gap-2 rounded-[7px] px-4 text-sm\",\n  lg: \"gap-2 rounded-[7px] px-5 text-sm\",\n  xl: \"gap-2.5 rounded-[11px] px-6 text-base\",\n}\n\n/* Duz yapi (Corners/Grow). */\nconst flat: Record<StyledSize, string> = {\n  sm: \"h-8 gap-1.5 rounded-md px-3 text-sm\",\n  md: \"h-9 gap-2 rounded-lg px-4 text-sm\",\n  lg: \"h-10 gap-2 rounded-lg px-5 text-sm\",\n  xl: \"h-12 gap-2.5 rounded-xl px-6 text-base\",\n}\n\nconst ringBase =\n  \"group relative inline-flex shrink-0 select-none items-center justify-center overflow-hidden p-px text-sm font-medium whitespace-nowrap outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50\"\nconst ringInnerBase =\n  \"relative inline-flex h-full w-full items-center justify-center bg-background text-foreground [&_svg]:size-4 [&_svg]:shrink-0 [&_i]:text-base\"\nconst flatBase =\n  \"group relative inline-flex shrink-0 select-none items-center justify-center font-medium whitespace-nowrap text-foreground outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 [&_i]:text-base [&_i]:leading-none\"\n\ntype Props = HTMLMotionProps<\"button\"> & { size?: StyledSize }\n\n/* Rotate: buton cevresinde donen genis konik token yay. */\nexport function RotateStrokeButton({ className, size = \"md\", children, ...props }: Props) {\n  const reduce = useReducedMotion()\n  return (\n    <motion.button\n      data-slot=\"styled-button\"\n      whileTap={reduce ? undefined : { scale: 0.97 }}\n      transition={{ type: \"spring\", stiffness: 400, damping: 20 }}\n      className={cn(ringBase, ring[size], \"bg-border\", className)}\n      {...props}\n    >\n      <motion.span\n        aria-hidden=\"true\"\n        className=\"absolute inset-[-150%] motion-reduce:hidden\"\n        style={{ background: \"conic-gradient(from 0deg, transparent 0deg, var(--info) 70deg, transparent 140deg)\" }}\n        animate={reduce ? undefined : { rotate: 360 }}\n        transition={reduce ? undefined : { duration: 4, ease: \"linear\", repeat: Infinity }}\n      />\n      <span className={cn(ringInnerBase, ringInner[size])}>{children as React.ReactNode}</span>\n    </motion.button>\n  )\n}\n\n/* Beam: dar ve parlak tek isik yayi kenar boyunca hizli doner. */\nexport function BeamButton({ className, size = \"md\", children, ...props }: Props) {\n  const reduce = useReducedMotion()\n  return (\n    <motion.button\n      data-slot=\"styled-button\"\n      whileTap={reduce ? undefined : { scale: 0.97 }}\n      transition={{ type: \"spring\", stiffness: 400, damping: 20 }}\n      className={cn(ringBase, ring[size], \"bg-border\", className)}\n      {...props}\n    >\n      <motion.span\n        aria-hidden=\"true\"\n        className=\"absolute inset-[-150%] motion-reduce:hidden\"\n        style={{ background: \"conic-gradient(from 0deg, transparent 0deg, var(--brand) 18deg, color-mix(in_oklab,var(--brand)_50%,transparent) 30deg, transparent 42deg)\" }}\n        animate={reduce ? undefined : { rotate: 360 }}\n        transition={reduce ? undefined : { duration: 2.4, ease: \"linear\", repeat: Infinity }}\n      />\n      <span className={cn(ringInnerBase, ringInner[size], \"bg-card\")}>{children as React.ReactNode}</span>\n    </motion.button>\n  )\n}\n\n/* Gradient: statik cok tonlu token gradyan kenar. */\nexport function GradientStrokeButton({ className, size = \"md\", children, ...props }: Props) {\n  const reduce = useReducedMotion()\n  return (\n    <motion.button\n      data-slot=\"styled-button\"\n      whileHover={reduce ? undefined : { scale: 1.03 }}\n      whileTap={reduce ? undefined : { scale: 0.97 }}\n      transition={{ type: \"spring\", stiffness: 400, damping: 20 }}\n      className={cn(ringBase, ring[size], \"[background-image:linear-gradient(120deg,var(--info),var(--brand),var(--success))]\", className)}\n      {...props}\n    >\n      <span className={cn(ringInnerBase, ringInner[size])}>{children as React.ReactNode}</span>\n    </motion.button>\n  )\n}\n\n/* Corners: the four corner brackets extend on hover (token border). */\nexport function CornersButton({ className, size = \"md\", children, ...props }: Props) {\n  const reduce = useReducedMotion()\n  return (\n    <motion.button\n      data-slot=\"styled-button\"\n      whileTap={reduce ? undefined : { scale: 0.97 }}\n      transition={{ type: \"spring\", stiffness: 400, damping: 20 }}\n      className={cn(flatBase, flat[size], \"border border-border/60\", className)}\n      {...props}\n    >\n      <span aria-hidden=\"true\" className=\"pointer-events-none absolute left-0 top-0 h-2 w-2 rounded-tl-md border-l-2 border-t-2 border-primary transition-all duration-(--motion-base) group-hover:h-4 group-hover:w-4\" />\n      <span aria-hidden=\"true\" className=\"pointer-events-none absolute bottom-0 right-0 h-2 w-2 rounded-br-md border-b-2 border-r-2 border-primary transition-all duration-(--motion-base) group-hover:h-4 group-hover:w-4\" />\n      <span className=\"relative flex items-center gap-2\">{children as React.ReactNode}</span>\n    </motion.button>\n  )\n}\n\n/* Grow: a token ring growing from zero on hover. */\nexport function GrowRingButton({ className, size = \"md\", children, ...props }: Props) {\n  const reduce = useReducedMotion()\n  return (\n    <motion.button\n      data-slot=\"styled-button\"\n      whileTap={reduce ? undefined : { scale: 0.97 }}\n      transition={{ type: \"spring\", stiffness: 400, damping: 20 }}\n      className={cn(\n        flatBase,\n        flat[size],\n        \"border border-border ring-0 ring-primary/50 ring-offset-2 ring-offset-background transition-[box-shadow] duration-(--motion-base) hover:ring-2\",\n        className\n      )}\n      {...props}\n    >\n      <span className=\"relative flex items-center gap-2\">{children as React.ReactNode}</span>\n    </motion.button>\n  )\n}\n",
      "type": "registry:component",
      "target": "components/ui/buttons-stroke.tsx"
    }
  ],
  "categories": [
    "styled",
    "buttons"
  ],
  "type": "registry:component"
}