import { motion, useReducedMotion } from "motion/react"; import { useEffect, useState, type ComponentPropsWithoutRef, type ElementType, type MouseEvent, type ReactNode } from "react"; import { cn } from "@/lib/utils"; type Direction = "TOP" | "LEFT" | "BOTTOM" | "RIGHT"; type HoverBorderGradientProps = { as?: T; containerClassName?: string; className?: string; duration?: number; clockwise?: boolean; children?: ReactNode; } & Omit, "as" | "children">; const movingMap: Record = { TOP: "radial-gradient(20.7% 50% at 50% 0%, color-mix(in srgb, var(--user-ink) 38%, transparent) 0%, transparent 100%)", LEFT: "radial-gradient(16.6% 43.1% at 0% 50%, color-mix(in srgb, var(--user-ink) 38%, transparent) 0%, transparent 100%)", BOTTOM: "radial-gradient(20.7% 50% at 50% 100%, color-mix(in srgb, var(--user-ink) 38%, transparent) 0%, transparent 100%)", RIGHT: "radial-gradient(16.2% 41.2% at 100% 50%, color-mix(in srgb, var(--user-ink) 38%, transparent) 0%, transparent 100%)", }; const highlight = "radial-gradient(75% 181% at 50% 50%, color-mix(in srgb, var(--user-ink) 22%, transparent) 0%, transparent 100%)"; function rotateDirection(current: Direction, clockwise: boolean): Direction { const directions: Direction[] = clockwise ? ["TOP", "LEFT", "BOTTOM", "RIGHT"] : ["TOP", "RIGHT", "BOTTOM", "LEFT"]; const index = directions.indexOf(current); return directions[(index - 1 + directions.length) % directions.length]; } // Aceternity Hover Border Gradient:中性墨色描边,不用彩色高光。 export function HoverBorderGradient({ children, containerClassName, className, as, duration = 1, clockwise = true, onMouseEnter, onMouseLeave, ...props }: HoverBorderGradientProps) { const Tag = (as || "button") as any; const reducedMotion = useReducedMotion(); const [hovered, setHovered] = useState(false); const [direction, setDirection] = useState("TOP"); useEffect(() => { if (reducedMotion || hovered) return; const interval = window.setInterval(() => { setDirection((current) => rotateDirection(current, clockwise)); }, duration * 1000); return () => window.clearInterval(interval); }, [clockwise, duration, hovered, reducedMotion]); return ( ) => { setHovered(true); (onMouseEnter as any)?.(event); }} onMouseLeave={(event: MouseEvent) => { setHovered(false); (onMouseLeave as any)?.(event); }} >
{children}
{reducedMotion ? null : ( )}
); }