SurfSense/surfsense_web/components/ui/tilt.tsx

90 lines
1.8 KiB
TypeScript
Raw Normal View History

2025-07-27 10:05:37 -07:00
"use client";
2025-04-07 23:47:06 -07:00
import {
2025-07-27 10:41:15 -07:00
type MotionStyle,
2025-07-27 10:05:37 -07:00
motion,
2025-07-27 10:41:15 -07:00
type SpringOptions,
2025-07-27 10:05:37 -07:00
useMotionTemplate,
useMotionValue,
useSpring,
useTransform,
} from "motion/react";
2025-07-27 10:41:15 -07:00
import type React from "react";
import { useRef } from "react";
2025-04-07 23:47:06 -07:00
type TiltProps = {
2025-07-27 10:05:37 -07:00
children: React.ReactNode;
className?: string;
style?: MotionStyle;
rotationFactor?: number;
isRevese?: boolean;
springOptions?: SpringOptions;
2025-04-07 23:47:06 -07:00
};
export function Tilt({
2025-07-27 10:05:37 -07:00
children,
className,
style,
rotationFactor = 15,
isRevese = false,
springOptions,
2025-04-07 23:47:06 -07:00
}: TiltProps) {
2025-07-27 10:05:37 -07:00
const ref = useRef<HTMLDivElement>(null);
2025-04-07 23:47:06 -07:00
2025-07-27 10:05:37 -07:00
const x = useMotionValue(0);
const y = useMotionValue(0);
2025-04-07 23:47:06 -07:00
2025-07-27 10:05:37 -07:00
const xSpring = useSpring(x, springOptions);
const ySpring = useSpring(y, springOptions);
2025-04-07 23:47:06 -07:00
2025-07-27 10:05:37 -07:00
const rotateX = useTransform(
ySpring,
[-0.5, 0.5],
isRevese ? [rotationFactor, -rotationFactor] : [-rotationFactor, rotationFactor]
);
const rotateY = useTransform(
xSpring,
[-0.5, 0.5],
isRevese ? [-rotationFactor, rotationFactor] : [rotationFactor, -rotationFactor]
);
2025-04-07 23:47:06 -07:00
2025-07-27 10:05:37 -07:00
const transform = useMotionTemplate`perspective(1000px) rotateX(${rotateX}deg) rotateY(${rotateY}deg)`;
2025-04-07 23:47:06 -07:00
2025-07-27 10:05:37 -07:00
const handleMouseMove = (e: React.MouseEvent<HTMLDivElement>) => {
if (!ref.current) return;
2025-04-07 23:47:06 -07:00
2025-07-27 10:05:37 -07:00
const rect = ref.current.getBoundingClientRect();
const width = rect.width;
const height = rect.height;
const mouseX = e.clientX - rect.left;
const mouseY = e.clientY - rect.top;
2025-04-07 23:47:06 -07:00
2025-07-27 10:05:37 -07:00
const xPos = mouseX / width - 0.5;
const yPos = mouseY / height - 0.5;
2025-04-07 23:47:06 -07:00
2025-07-27 10:05:37 -07:00
x.set(xPos);
y.set(yPos);
};
2025-04-07 23:47:06 -07:00
2025-07-27 10:05:37 -07:00
const handleMouseLeave = () => {
x.set(0);
y.set(0);
};
2025-04-07 23:47:06 -07:00
2025-07-27 10:05:37 -07:00
return (
<motion.div
ref={ref}
className={className}
style={{
transformStyle: "preserve-3d",
...style,
transform,
}}
onMouseMove={handleMouseMove}
onMouseLeave={handleMouseLeave}
>
{children}
</motion.div>
);
2025-04-07 23:47:06 -07:00
}