/** * Reusable Animated Components Library * * Collection of common animated components following Apple/Jon Ive design principles. * Copy individual components as needed. */ import { motion, useMotionValue, useSpring, useReducedMotion } from "motion/react" import { useRef, MouseEvent, ReactNode } from "react" // ============================================================================ // 1. FADE UP (Entrance Animation) // ============================================================================ interface FadeUpProps { children: ReactNode delay?: number } export function FadeUp({ children, delay = 0 }: FadeUpProps) { const shouldReduceMotion = useReducedMotion() return ( {children} ) } // ============================================================================ // 2. SCROLL REVEAL // ============================================================================ interface ScrollRevealProps { children: ReactNode direction?: "up" | "down" | "left" | "right" delay?: number } export function ScrollReveal({ children, direction = "up", delay = 0 }: ScrollRevealProps) { const directions = { up: { y: 50 }, down: { y: -50 }, left: { x: 50 }, right: { x: -50 }, } return ( {children} ) } // ============================================================================ // 3. HOVER CARD (Interactive Card) // ============================================================================ interface HoverCardProps { children: ReactNode className?: string } export function HoverCard({ children, className = "" }: HoverCardProps) { return ( {children} ) } // ============================================================================ // 4. MAGNETIC BUTTON (Cursor Following) // ============================================================================ interface MagneticButtonProps { children: ReactNode className?: string onClick?: () => void } export function MagneticButton({ children, className = "", onClick }: MagneticButtonProps) { const ref = useRef(null) const x = useMotionValue(0) const y = useMotionValue(0) const springX = useSpring(x, { stiffness: 300, damping: 20 }) const springY = useSpring(y, { stiffness: 300, damping: 20 }) const handleMouseMove = (e: MouseEvent) => { if (!ref.current) return const rect = ref.current.getBoundingClientRect() const centerX = rect.left + rect.width / 2 const centerY = rect.top + rect.height / 2 const distanceX = e.clientX - centerX const distanceY = e.clientY - centerY x.set(distanceX * 0.3) y.set(distanceY * 0.3) } const handleMouseLeave = () => { x.set(0) y.set(0) } return ( {children} ) } // ============================================================================ // 5. STAGGERED LIST // ============================================================================ interface StaggeredListProps { items: ReactNode[] className?: string } export function StaggeredList({ items, className = "" }: StaggeredListProps) { const containerVariants = { hidden: { opacity: 0 }, visible: { opacity: 1, transition: { staggerChildren: 0.1, }, }, } const itemVariants = { hidden: { opacity: 0, y: 20 }, visible: { opacity: 1, y: 0, transition: { duration: 0.5 }, }, } return ( {items.map((item, i) => ( {item} ))} ) } // ============================================================================ // 6. SCALE BUTTON (Simple Hover/Tap) // ============================================================================ interface ScaleButtonProps { children: ReactNode className?: string onClick?: () => void } export function ScaleButton({ children, className = "", onClick }: ScaleButtonProps) { return ( {children} ) } // ============================================================================ // 7. ACCORDION (Expand/Collapse) // ============================================================================ interface AccordionProps { title: string children: ReactNode isOpen: boolean onToggle: () => void } export function Accordion({ title, children, isOpen, onToggle }: AccordionProps) { return (
{title} ▼
{children}
) } // ============================================================================ // 8. MODAL (With Backdrop) // ============================================================================ interface ModalProps { isOpen: boolean onClose: () => void children: ReactNode } export function Modal({ isOpen, onClose, children }: ModalProps) { if (!isOpen) return null return ( <> {/* Backdrop */} {/* Modal */}
{children}
) } // ============================================================================ // 9. LOADING SPINNER (Spring Animation) // ============================================================================ export function LoadingSpinner() { return ( ) } // ============================================================================ // 10. TOGGLE SWITCH // ============================================================================ interface ToggleSwitchProps { isOn: boolean onToggle: () => void } export function ToggleSwitch({ isOn, onToggle }: ToggleSwitchProps) { return ( ) } // ============================================================================ // USAGE EXAMPLE // ============================================================================ /* import { FadeUp, ScrollReveal, HoverCard, MagneticButton, ScaleButton, Accordion, Modal, LoadingSpinner, ToggleSwitch, } from "./component-library" export default function Example() { return ( <>

Hello World

Feature Card

console.log("Clicked!")}> Magnetic Button setIsOn(!isOn)} /> ) } */