'use client';
import * as React from 'react';
import { motion, type HTMLMotionProps } from 'motion/react';
import {
useIsInView,
type UseIsInViewOptions,
} from '@/hooks/use-is-in-view';
import { Slot, type WithAsChild } from '@/components/animate-ui/primitives/animate/slot';
type ZoomProps = WithAsChild<
{
children?: React.ReactNode;
delay?: number;
initialScale?: number;
scale?: number;
ref?: React.Ref<HTMLElement>;
} & UseIsInViewOptions &
HTMLMotionProps<'div'>
>;
function Zoom({
ref,
transition = { type: 'spring', stiffness: 200, damping: 20 },
delay = 0,
inView = false,
inViewMargin = '0px',
inViewOnce = true,
initialScale = 0.5,
scale = 1,
asChild = false,
...props
}: ZoomProps) {
const { ref: localRef, isInView } = useIsInView(
ref as React.Ref<HTMLElement>,
{
inView,
inViewOnce,
inViewMargin,
},
);
const Component = asChild ? Slot : motion.div;
return (
<Component
ref={localRef as React.Ref<HTMLDivElement>}
initial="hidden"
animate={isInView ? 'visible' : 'hidden'}
exit="hidden"
variants={{
hidden: { scale: initialScale },
visible: { scale },
}}
transition={{
...transition,
delay: (transition?.delay ?? 0) + delay / 1000,
}}
{...props}
/>
);
}
type ZoomListProps = Omit<ZoomProps, 'children'> & {
children: React.ReactElement | React.ReactElement[];
holdDelay?: number;
};
function Zooms({
children,
delay = 0,
holdDelay = 0,
...props
}: ZoomListProps) {
const array = React.Children.toArray(children) as React.ReactElement[];
return (
<>
{array.map((child, index) => (
<Zoom
key={child.key ?? index}
delay={delay + index * holdDelay}
{...props}
>
{child}
</Zoom>
))}
</>
);
}
export { Zoom, Zooms, type ZoomProps, type ZoomListProps };