"use client";
import React, {
CSSProperties,
Suspense,
lazy,
useCallback,
useEffect,
useRef,
useState,
} from "react";
import { IGatsbyAnimation } from "../types";
const LottiePlayer = lazy(() => import("./LottiePlayer"));
function getSizerStyle({
width,
height,
layout,
}: IGatsbyAnimation): CSSProperties | undefined {
if (width && height) {
if (layout === "fullWidth") {
return { paddingTop: `${(height / width) * 100}%` };
}
if (layout === "constrained") {
return { maxWidth: width, display: `block` };
}
}
return undefined;
}
const Sizer: React.FC<{ animation: IGatsbyAnimation }> = ({ animation }) => {
const { width, height, layout } = animation;
const sizerStyle = getSizerStyle(animation);
if (layout === "fullWidth") {
return
;
}
if (layout === "constrained") {
return (
);
}
return null;
};
function calculateSizes({ width, height, layout }: IGatsbyAnimation): {
width: number | undefined;
height: number | undefined;
} {
if (width && height) {
const aspectRatio = width / height;
switch (layout) {
case "fixed":
return { width, height };
case "fullWidth":
return { width: 1, height: 1 / aspectRatio };
}
return { width, height };
}
return { width: undefined, height: undefined };
}
function getWrapperProps({ width, height, layout }: IGatsbyAnimation): {
className: string;
style: React.CSSProperties;
} {
let className = "gatsby-animation-wrapper";
const style: CSSProperties = {};
if (layout === "fixed") {
style.width = width;
style.height = height;
} else if (layout === "constrained") {
className = "gatsby-animation-wrapper gatsby-animation-wrapper-constrained";
}
return { className, style };
}
export type IGatsbyExtractedAnimation = Record;
export const GatsbyAnimation: React.FC<{
animation: IGatsbyExtractedAnimation;
objectFit?: CSSProperties["objectFit"];
objectPosition?: CSSProperties["objectPosition"];
className?: string;
style?: Omit;
loop?: boolean | null;
loopDelay?: number | null;
animationClassName?: string;
}> = allProps => {
const containerRef = useRef(null);
const {
animation,
objectFit,
objectPosition,
style,
className,
animationClassName,
loop = false,
loopDelay,
} = allProps;
const { width, height } = calculateSizes(
animation as unknown as IGatsbyAnimation,
);
const { style: wrapperStyle, className: wrapperClassName } = getWrapperProps(
animation as unknown as IGatsbyAnimation,
);
const [loadAnimation, setLoadAnimation] = useState(false);
const [containerVisible, setContainerVisible] = useState(false);
const [showPoster, setShowPoster] = useState(true);
const onPlay = useCallback(() => setShowPoster(false), []);
useEffect(() => {
const container = containerRef.current;
if (container) {
const io = new IntersectionObserver(entries => {
entries.forEach(entry => {
if (container === entry.target) {
if (entry.isIntersecting || entry.intersectionRatio > 0) {
setLoadAnimation(true);
setContainerVisible(true);
} else {
setContainerVisible(false);
}
}
});
});
io.observe(container);
return () => io.unobserve(container);
}
return undefined;
});
const posterSrc = (animation.encoded || animation.encodedUrl) as string;
return (
{showPoster && posterSrc && (

)}
{loadAnimation && (
)}
);
};