landing-page/app/components/FadeIn.tsx

113 lines
2.1 KiB
TypeScript

"use client";
import { motion } from "framer-motion";
import { ReactNode } from "react";
interface FadeInProps {
children: ReactNode;
delay?: number;
duration?: number;
direction?: "up" | "down" | "left" | "right" | "none";
distance?: number;
className?: string;
once?: boolean;
}
export default function FadeIn({
children,
delay = 0,
duration = 0.6,
direction = "up",
distance = 30,
className = "",
once = true,
}: FadeInProps) {
const directions = {
up: { y: distance, x: 0 },
down: { y: -distance, x: 0 },
left: { x: distance, y: 0 },
right: { x: -distance, y: 0 },
none: { x: 0, y: 0 },
};
return (
<motion.div
initial={{
opacity: 0,
...directions[direction],
}}
whileInView={{
opacity: 1,
x: 0,
y: 0,
}}
viewport={{ once, margin: "-50px" }}
transition={{
duration,
delay,
ease: [0.16, 1, 0.3, 1],
}}
className={className}
>
{children}
</motion.div>
);
}
interface StaggerContainerProps {
children: ReactNode;
className?: string;
staggerDelay?: number;
}
export function StaggerContainer({
children,
className = "",
staggerDelay = 0.1,
}: StaggerContainerProps) {
return (
<motion.div
initial="hidden"
whileInView="visible"
viewport={{ once: true, margin: "-50px" }}
variants={{
hidden: {},
visible: {
transition: {
staggerChildren: staggerDelay,
},
},
}}
className={className}
>
{children}
</motion.div>
);
}
interface StaggerItemProps {
children: ReactNode;
className?: string;
}
export function StaggerItem({ children, className = "" }: StaggerItemProps) {
return (
<motion.div
variants={{
hidden: { opacity: 0, y: 30 },
visible: {
opacity: 1,
y: 0,
transition: {
duration: 0.6,
ease: [0.16, 1, 0.3, 1],
},
},
}}
className={className}
>
{children}
</motion.div>
);
}