UNPKG

xlibs-components

Version:

Modern React component library with Aceternity, MagicUI, and ShadCN components for building beautiful web applications

115 lines (114 loc) 4.69 kB
"use client"; import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { cn } from '../../lib/utils.js'; import { useRef, useState, useEffect } from "react"; import { motion, useMotionValue, useSpring, useTransform, animate, useVelocity, useAnimationControls, } from "framer-motion"; export const DraggableCardBody = ({ className, children, }) => { const mouseX = useMotionValue(0); const mouseY = useMotionValue(0); const cardRef = useRef(null); const controls = useAnimationControls(); const [constraints, setConstraints] = useState({ top: 0, left: 0, right: 0, bottom: 0, }); // physics biatch const velocityX = useVelocity(mouseX); const velocityY = useVelocity(mouseY); const springConfig = { stiffness: 100, damping: 20, mass: 0.5, }; const rotateX = useSpring(useTransform(mouseY, [-300, 300], [25, -25]), springConfig); const rotateY = useSpring(useTransform(mouseX, [-300, 300], [-25, 25]), springConfig); const opacity = useSpring(useTransform(mouseX, [-300, 0, 300], [0.8, 1, 0.8]), springConfig); const glareOpacity = useSpring(useTransform(mouseX, [-300, 0, 300], [0.2, 0, 0.2]), springConfig); useEffect(() => { // Update constraints when component mounts or window resizes const updateConstraints = () => { if (typeof window !== "undefined") { setConstraints({ top: -window.innerHeight / 2, left: -window.innerWidth / 2, right: window.innerWidth / 2, bottom: window.innerHeight / 2, }); } }; updateConstraints(); // Add resize listener window.addEventListener("resize", updateConstraints); // Clean up return () => { window.removeEventListener("resize", updateConstraints); }; }, []); const handleMouseMove = (e) => { const { clientX, clientY } = e; const { width, height, left, top } = cardRef.current?.getBoundingClientRect() ?? { width: 0, height: 0, left: 0, top: 0, }; const centerX = left + width / 2; const centerY = top + height / 2; const deltaX = clientX - centerX; const deltaY = clientY - centerY; mouseX.set(deltaX); mouseY.set(deltaY); }; const handleMouseLeave = () => { mouseX.set(0); mouseY.set(0); }; return (_jsxs(motion.div, { ref: cardRef, drag: true, dragConstraints: constraints, onDragStart: () => { document.body.style.cursor = "grabbing"; }, onDragEnd: (event, info) => { document.body.style.cursor = "default"; controls.start({ rotateX: 0, rotateY: 0, transition: { type: "spring", ...springConfig, }, }); const currentVelocityX = velocityX.get(); const currentVelocityY = velocityY.get(); const velocityMagnitude = Math.sqrt(currentVelocityX * currentVelocityX + currentVelocityY * currentVelocityY); const bounce = Math.min(0.8, velocityMagnitude / 1000); animate(info.point.x, info.point.x + currentVelocityX * 0.3, { duration: 0.8, ease: [0.2, 0, 0, 1], bounce, type: "spring", stiffness: 50, damping: 15, mass: 0.8, }); animate(info.point.y, info.point.y + currentVelocityY * 0.3, { duration: 0.8, ease: [0.2, 0, 0, 1], bounce, type: "spring", stiffness: 50, damping: 15, mass: 0.8, }); }, style: { rotateX, rotateY, opacity, willChange: "transform", }, animate: controls, whileHover: { scale: 1.02 }, onMouseMove: handleMouseMove, onMouseLeave: handleMouseLeave, className: cn("relative min-h-96 w-80 overflow-hidden rounded-md bg-neutral-100 p-6 shadow-2xl transform-3d dark:bg-neutral-900", className), children: [children, _jsx(motion.div, { style: { opacity: glareOpacity, }, className: "pointer-events-none absolute inset-0 bg-white select-none" })] })); }; export const DraggableCardContainer = ({ className, children, }) => { return (_jsx("div", { className: cn("[perspective:3000px]", className), children: children })); };