{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "link-square-02",
  "title": "link-square-02",
  "description": "Animated link square icon",
  "dependencies": [
    "motion"
  ],
  "files": [
    {
      "path": "icons/link-square-02.tsx",
      "content": "'use client';\n\nimport type { Variants } from 'motion/react';\nimport { motion, useAnimation } from 'motion/react';\nimport type { HTMLAttributes } from 'react';\nimport { forwardRef } from 'react';\nimport { useIconAnimation } from '@/lib/use-icon-animation';\nimport { cn } from '@/lib/utils';\n\nexport interface LinkSquare02IconHandle {\n  startAnimation: () => void;\n  stopAnimation: () => void;\n}\n\ninterface LinkSquare02IconProps extends HTMLAttributes<HTMLDivElement> {\n  size?: number;\n}\n\nconst pathVariants: Variants = {\n  normal: { pathLength: 1, visibility: 'visible', transform: 'translate(0, 0)' },\n  animate: (i: number) =>\n    i === 0\n      ? {\n          transform: ['scale(1)', 'scale(0.95)', 'scale(1.025)', 'scale(1)'],\n          pathLength: [1, 0.72, 1, 1],\n          transition: { duration: 0.58, ease: [0.23, 1, 0.32, 1] },\n        }\n      : {\n          transform: [\n            'translate(0, 0)',\n            'translate(-0.7px, 0.7px)',\n            'translate(2.8px, -2.8px)',\n            'translate(-0.35px, 0.35px)',\n            'translate(0, 0)',\n          ],\n          transition: { duration: 0.6, ease: [0.23, 1, 0.32, 1] },\n        },\n};\n\nconst LinkSquare02Icon = forwardRef<LinkSquare02IconHandle, LinkSquare02IconProps>(\n  ({ onMouseEnter, onMouseLeave, className, size = 28, ...props }, ref) => {\n    const controls = useAnimation();\n    const { handleMouseEnter, handleMouseLeave } = useIconAnimation({\n      controls,\n      onMouseEnter,\n      onMouseLeave,\n      ref,\n    });\n\n    return (\n      <div\n        className={cn(className)}\n        onMouseEnter={handleMouseEnter}\n        onMouseLeave={handleMouseLeave}\n        {...props}\n      >\n        <svg\n          xmlns=\"http://www.w3.org/2000/svg\"\n          width={size}\n          height={size}\n          viewBox=\"0 0 24 24\"\n          fill=\"none\"\n          overflow=\"visible\"\n        >\n        <motion.path\n          d=\"M11.0991 3.00012C7.45013 3.00669 5.53932 3.09629 4.31817 4.31764C3.00034 5.63568 3.00034 7.75704 3.00034 11.9997C3.00034 16.2424 3.00034 18.3638 4.31817 19.6818C5.63599 20.9999 7.75701 20.9999 11.9991 20.9999C16.241 20.9999 18.3621 20.9999 19.6799 19.6818C20.901 18.4605 20.9906 16.5493 20.9972 12.8998\" stroke=\"currentColor\" strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth=\"1.5\"\n          variants={pathVariants}\n          custom={0}\n          animate={controls}\n          initial=\"normal\"\n        />\n        <motion.path\n          d=\"M20.556 3.49612L11.0487 13.0586M20.556 3.49612C20.062 3.00151 16.7343 3.04761 16.0308 3.05762M20.556 3.49612C21.05 3.99074 21.0039 7.32273 20.9939 8.02714\" stroke=\"currentColor\" strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth=\"1.5\"\n          variants={pathVariants}\n          custom={1}\n          animate={controls}\n          initial=\"normal\"\n        />\n        </svg>\n      </div>\n    );\n  }\n);\n\nLinkSquare02Icon.displayName = 'LinkSquare02Icon';\n\nexport { LinkSquare02Icon };\n",
      "type": "registry:ui"
    },
    {
      "path": "lib/use-icon-animation.ts",
      "content": "'use client';\n\nimport type { LegacyAnimationControls } from 'motion/react';\nimport { useReducedMotion } from 'motion/react';\nimport type {\n  ForwardedRef,\n  MouseEventHandler,\n} from 'react';\nimport { useCallback, useImperativeHandle, useRef } from 'react';\n\nexport interface AnimatedIconHandle {\n  startAnimation: () => void;\n  stopAnimation: () => void;\n}\n\ninterface UseIconAnimationOptions {\n  controls: LegacyAnimationControls;\n  loops?: boolean;\n  onMouseEnter?: MouseEventHandler<HTMLDivElement>;\n  onMouseLeave?: MouseEventHandler<HTMLDivElement>;\n  ref: ForwardedRef<AnimatedIconHandle>;\n}\n\nexport function useIconAnimation({\n  controls,\n  loops = false,\n  onMouseEnter,\n  onMouseLeave,\n  ref,\n}: UseIconAnimationOptions) {\n  const shouldReduceMotion = useReducedMotion();\n  const isControlledRef = useRef(false);\n  const isPlayingRef = useRef(false);\n  const runRef = useRef(0);\n\n  const startAnimation = useCallback(() => {\n    if (shouldReduceMotion || isPlayingRef.current) return;\n\n    isPlayingRef.current = true;\n    const run = ++runRef.current;\n    controls.set('normal');\n    void controls.start('animate').then(() => {\n      if (runRef.current === run) isPlayingRef.current = false;\n    });\n  }, [controls, shouldReduceMotion]);\n\n  const stopAnimation = useCallback(() => {\n    if (!loops) return;\n\n    runRef.current++;\n    isPlayingRef.current = false;\n    void controls.start('normal');\n  }, [controls, loops]);\n\n  useImperativeHandle(\n    ref,\n    () => {\n      isControlledRef.current = true;\n      return { startAnimation, stopAnimation };\n    },\n    [startAnimation, stopAnimation]\n  );\n\n  const handleMouseEnter = useCallback<MouseEventHandler<HTMLDivElement>>(\n    (event) => {\n      onMouseEnter?.(event);\n      if (!isControlledRef.current) startAnimation();\n    },\n    [onMouseEnter, startAnimation]\n  );\n\n  const handleMouseLeave = useCallback<MouseEventHandler<HTMLDivElement>>(\n    (event) => {\n      onMouseLeave?.(event);\n      if (!isControlledRef.current) stopAnimation();\n    },\n    [onMouseLeave, stopAnimation]\n  );\n\n  return { handleMouseEnter, handleMouseLeave };\n}\n",
      "type": "registry:lib"
    }
  ],
  "type": "registry:ui"
}