"use client"; import type { HTMLAttributes, MouseEvent } from "react"; import { forwardRef, useCallback, useEffect, useImperativeHandle, useRef } from "react"; import { motion, useAnimation, useReducedMotion, type Variants } from "framer-motion"; import { cn } from "../../lib/utils"; export interface FilePenLineIconHandle { startAnimation: () => void; stopAnimation: () => void; } interface FilePenLineIconProps extends HTMLAttributes { size?: number; active?: boolean; } const PEN_VARIANTS: Variants = { normal: { rotate: 0, x: 0, y: 0 }, animate: { rotate: [-0.3, 0.2, -0.4], x: [0, -0.5, 1, 0], y: [0, 1, -0.5, 0], transition: { duration: 0.5, repeat: 1, ease: "easeInOut" } }, active: { rotate: [-0.3, 0.2, -0.4], x: [0, -0.5, 1, 0], y: [0, 1, -0.5, 0], transition: { duration: 0.5, repeat: Number.POSITIVE_INFINITY, repeatDelay: 0.75, ease: "easeInOut" } } }; const LINE_VARIANTS: Variants = { normal: { d: "M8 18h1" }, animate: { d: "M8 18h5", transition: { duration: 0.5 } }, active: { d: ["M8 18h1", "M8 18h5", "M8 18h1"], transition: { duration: 0.8, repeat: Number.POSITIVE_INFINITY, repeatDelay: 0.45, ease: "easeInOut" } } }; const FilePenLineIcon = forwardRef( ( { active = false, onMouseEnter, onMouseLeave, className, size = 28, ...props }, ref ) => { const controls = useAnimation(); const reduceMotion = useReducedMotion(); const isControlledRef = useRef(false); const startAnimation = useCallback(() => { if (reduceMotion) { return; } void controls.start(active ? "active" : "animate"); }, [active, controls, reduceMotion]); const stopAnimation = useCallback(() => { void controls.start("normal"); }, [controls]); useImperativeHandle(ref, () => { isControlledRef.current = true; return { startAnimation, stopAnimation }; }); useEffect(() => { if (active) { startAnimation(); return; } stopAnimation(); }, [active, startAnimation, stopAnimation]); const handleMouseEnter = useCallback( (event: MouseEvent) => { if (isControlledRef.current) { onMouseEnter?.(event); } else { startAnimation(); } }, [onMouseEnter, startAnimation] ); const handleMouseLeave = useCallback( (event: MouseEvent) => { if (isControlledRef.current) { onMouseLeave?.(event); } else { stopAnimation(); } }, [onMouseLeave, stopAnimation] ); return (
); } ); FilePenLineIcon.displayName = "FilePenLineIcon"; export { FilePenLineIcon };