A in-view component from Motion Primitives.
1'use client';
2import { ReactNode, useRef, useState } from 'react';
3import {
4 motion,
5 useInView,
6 Variant,
7 Transition,
8 UseInViewOptions,
9} from 'motion/react';
10
11export type InViewProps = {
12 children: ReactNode;
13 variants?: {
14 hidden: Variant;
15 visible: Variant;
16 };
17 transition?: Transition;
18 viewOptions?: UseInViewOptions;
19 as?: React.ElementType;
20 once?: boolean
21};
22
23const defaultVariants = {
24 hidden: { opacity: 0 },
25 visible: { opacity: 1 },
26};
27
28export function InView({
29 children,
30 variants = defaultVariants,
31 transition,
32 viewOptions,
33 as = 'div',
34 once
35}: InViewProps) {
36 const ref = useRef(null);
37 const isInView = useInView(ref, viewOptions);
38
39 const [isViewed, setIsViewed] = useState(false)
40
41 const MotionComponent = motion[as as keyof typeof motion] as typeof as;
42
43 return (
44 <MotionComponent
45 ref={ref}
46 initial='hidden'
47 onAnimationComplete={() => {
48 if (once) setIsViewed(true)
49 }}
50 animate={(isInView || isViewed) ? "visible" : "hidden"}
51
52 variants={variants}
53 transition={transition}
54 >
55 {children}
56 </MotionComponent>
57 );
58}
59