Skip to content

Commit a9127eb

Browse files
committed
Improve the AnimatedElement entry threshold
1 parent 25a6320 commit a9127eb

File tree

1 file changed

+56
-92
lines changed

1 file changed

+56
-92
lines changed
Lines changed: 56 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -1,124 +1,88 @@
1-
"use client";
2-
3-
import { motion } from "framer-motion";
4-
import React from "react";
1+
import { motion, MotionProps, Variants } from "framer-motion";
2+
import {
3+
ComponentPropsWithoutRef,
4+
ComponentType,
5+
ElementType,
6+
ReactNode,
7+
useMemo,
8+
} from "react";
59
import { useInView } from "react-intersection-observer";
610

711
import {
812
fadeIn,
9-
fadeInUp,
1013
fadeInDown,
1114
fadeInLeft,
1215
fadeInRight,
16+
fadeInUp,
1317
scaleAnimation,
1418
} from "./AnimationUtils";
1519

16-
interface AnimatedElementProps {
17-
children: React.ReactNode;
18-
className?: string;
19-
animationType?: "fade" | "fadeUp" | "fadeDown" | "fadeLeft" | "fadeRight" | "scale";
20+
type AnimationType = "fade" | "fadeUp" | "fadeDown" | "fadeLeft" | "fadeRight" | "scale";
21+
22+
const getAnimationVariant = (animationType: AnimationType): Variants => {
23+
switch (animationType) {
24+
case "fadeUp":
25+
return fadeInUp;
26+
case "fadeDown":
27+
return fadeInDown;
28+
case "fadeLeft":
29+
return fadeInLeft;
30+
case "fadeRight":
31+
return fadeInRight;
32+
case "scale":
33+
return scaleAnimation;
34+
default:
35+
return fadeIn;
36+
}
37+
};
38+
39+
type AnimatedElementProps<T extends ElementType> = {
40+
children: ReactNode;
41+
animationType?: AnimationType;
2042
delay?: number;
2143
threshold?: number;
2244
rootMargin?: string;
2345
triggerOnce?: boolean;
24-
as?: keyof JSX.IntrinsicElements;
2546
interactive?: boolean;
26-
[key: string]: unknown;
27-
}
47+
as?: T;
48+
} & MotionProps &
49+
Omit<ComponentPropsWithoutRef<T>, keyof MotionProps>;
2850

29-
const AnimatedElement: React.FC<AnimatedElementProps> = ({
51+
const AnimatedElement = <T extends ElementType = "div">({
3052
children,
31-
className = "",
3253
animationType = "fade",
3354
delay = 0,
34-
threshold = 0.1,
35-
rootMargin = "0px 0px -100px 0px",
55+
threshold = 0.05,
56+
rootMargin = "0px 0px -20px 0px", // próg wejscia animacji, -20 powoduje ze animacja wchodzi od razu i nie buguje sie
3657
triggerOnce = false,
37-
as = "div",
3858
interactive = false,
39-
...props
40-
}) => {
59+
as,
60+
...restProps
61+
}: AnimatedElementProps<T>) => {
4162
const { ref, inView } = useInView({
4263
triggerOnce,
4364
threshold,
4465
rootMargin,
4566
});
4667

47-
const getAnimationVariant = () => {
48-
switch (animationType) {
49-
case "fadeUp":
50-
return fadeInUp;
51-
case "fadeDown":
52-
return fadeInDown;
53-
case "fadeLeft":
54-
return fadeInLeft;
55-
case "fadeRight":
56-
return fadeInRight;
57-
case "scale":
58-
return scaleAnimation;
59-
default:
60-
return fadeIn;
61-
}
62-
};
63-
64-
const animationVariant = getAnimationVariant();
68+
const variants = getAnimationVariant(animationType);
6569

66-
const filteredProps = props;
70+
const Component = useMemo(() => motion(as || "div"), [as]) as ComponentType<any>;
6771

68-
const commonProps = {
69-
ref,
70-
className,
71-
variants: animationVariant,
72-
initial: interactive ? "initial" : "hidden",
73-
animate: inView ? (interactive ? "initial" : "visible") : interactive ? "initial" : "hidden",
74-
whileHover: interactive ? "hover" : undefined,
75-
whileTap: interactive ? "tap" : undefined,
76-
transition: { delay },
77-
...filteredProps,
78-
};
79-
80-
switch (as) {
81-
case "div":
82-
return <motion.div {...commonProps}>{children}</motion.div>;
83-
case "section":
84-
return <motion.section {...commonProps}>{children}</motion.section>;
85-
case "article":
86-
return <motion.article {...commonProps}>{children}</motion.article>;
87-
case "main":
88-
return <motion.main {...commonProps}>{children}</motion.main>;
89-
case "header":
90-
return <motion.header {...commonProps}>{children}</motion.header>;
91-
case "footer":
92-
return <motion.footer {...commonProps}>{children}</motion.footer>;
93-
case "nav":
94-
return <motion.nav {...commonProps}>{children}</motion.nav>;
95-
case "aside":
96-
return <motion.aside {...commonProps}>{children}</motion.aside>;
97-
case "span":
98-
return <motion.span {...commonProps}>{children}</motion.span>;
99-
case "p":
100-
return <motion.p {...commonProps}>{children}</motion.p>;
101-
case "h1":
102-
return <motion.h1 {...commonProps}>{children}</motion.h1>;
103-
case "h2":
104-
return <motion.h2 {...commonProps}>{children}</motion.h2>;
105-
case "h3":
106-
return <motion.h3 {...commonProps}>{children}</motion.h3>;
107-
case "h4":
108-
return <motion.h4 {...commonProps}>{children}</motion.h4>;
109-
case "h5":
110-
return <motion.h5 {...commonProps}>{children}</motion.h5>;
111-
case "h6":
112-
return <motion.h6 {...commonProps}>{children}</motion.h6>;
113-
case "ul":
114-
return <motion.ul {...commonProps}>{children}</motion.ul>;
115-
case "ol":
116-
return <motion.ol {...commonProps}>{children}</motion.ol>;
117-
case "li":
118-
return <motion.li {...commonProps}>{children}</motion.li>;
119-
default:
120-
return <motion.div {...commonProps}>{children}</motion.div>;
121-
}
72+
return (
73+
<Component
74+
ref={ref}
75+
variants={variants}
76+
initial={interactive ? "initial" : "hidden"}
77+
animate={interactive ? "initial" : inView ? "visible" : "hidden"}
78+
whileHover={interactive ? "hover" : undefined}
79+
whileTap={interactive ? "tap" : undefined}
80+
transition={{ delay }}
81+
{...restProps}
82+
>
83+
{children}
84+
</Component>
85+
);
12286
};
12387

12488
export default AnimatedElement;

0 commit comments

Comments
 (0)