"use client"; import React from "react"; import { AnimationType, AnimationWrapperProps, DEFAULT_BUTTON_ANIMATION_TYPE, } from "./types"; import { motion, useReducedMotion } from "framer-motion"; interface AnimationPreset { whileHover: Record; whileTap?: Record; transition: Record; } const ANIMATION_PRESETS: Record = { scale: { whileHover: { scale: 1.02 }, whileTap: { scale: 0.98 }, transition: { duration: 0.3 }, }, shadow: { whileHover: { boxShadow: "0 10px 25px rgba(0,0,0,0.15)" }, transition: { duration: 0.3 }, }, lift: { whileHover: { y: -5 }, whileTap: { y: 0 }, transition: { type: "spring", stiffness: 300, damping: 20 }, }, opacity: { whileHover: { opacity: 0.8 }, transition: { duration: 0.2 }, }, grow: { whileHover: { scale: 1.1 }, whileTap: { scale: 0.95 }, transition: { type: "spring", stiffness: 300, damping: 20 }, }, pop: { whileHover: { scale: 1.05 }, whileTap: { scale: 0.95 }, transition: { duration: 0.15 }, }, }; function mergePresets(animationType?: AnimationType | AnimationType[]) { if (!animationType) return undefined; const types = Array.isArray(animationType) ? animationType : [animationType]; if (types.length === 0) return undefined; return types.reduce( (merged, type) => { const preset = ANIMATION_PRESETS[type]; return { whileHover: { ...merged.whileHover, ...preset.whileHover }, ...(merged.whileTap || preset.whileTap ? { whileTap: { ...merged.whileTap, ...preset.whileTap }, } : {}), transition: { ...merged.transition, ...preset.transition }, }; }, { whileHover: {}, transition: {} } ); } export function AnimationWrapper({ children, animationType = DEFAULT_BUTTON_ANIMATION_TYPE, // default to true for backward compatibility disableAnimation = true, whileHover, whileTap, transition, ...motionProps }: AnimationWrapperProps) { const prefersReducedMotion = useReducedMotion(); const child = React.Children.only(children) as React.ReactElement< Record >; if (disableAnimation || prefersReducedMotion) { return child; } // Use the provided animationType, falling back to the centralized default. const preset = mergePresets(animationType); const mergedWhileHover = preset ? { ...preset.whileHover, ...(whileHover as Record) } : whileHover; const mergedWhileTap = preset?.whileTap || whileTap ? { ...preset?.whileTap, ...(whileTap as Record) } : undefined; const mergedTransition = preset ? { ...preset.transition, ...(transition as Record) } : transition; const isIntrinsicElement = typeof child.type === "string"; if (isIntrinsicElement) { const MotionComponent = motion[ child.type as keyof typeof motion ] as React.ComponentType>; return ( ); } return ( {child} ); } AnimationWrapper.displayName = "AnimationWrapper"; export { DEFAULT_BUTTON_ANIMATION_TYPE }; export type { AnimationWrapperProps, AnimationType };