Photo carousel

DEMO
PhotoCarousel.jsx

 // Inspired by https://www.framer.com/docs/examples/#exit-animations
import { AnimatePresence, motion } from "framer-motion";

const images = ["corgi", "husky", "samoyed", "pom", "retriever"];

const PhotoCarousel = () => {
  const [slide, setSlide] = useState(1);
  const [direction, setDirection] = useState(1);

  const navigateGallery = (diff) => {
    if (slide + diff >= 0 && slide + diff < images.length) {
      setDirection(diff > 0 ? 1 : -1);
      setSlide((slide) => slide + diff);
    }
  };

  return (
    <>
      <DemoCont>
        <GalleryWrapper>
          <NavBtn
            onClick={() => navigateGallery(-1)}
            isDisabled={slide === 0}
            whileTap={slide !== 0 && { scale: 0.7 }}
          >
            <MdNavigateBefore size="2.5em" />
          </NavBtn>
          <ImgWrapper>
            <AnimatePresence initial={false} custom={direction}>
              <Img
                id={slide}
                key={slide}
                custom={direction}
                variants={variants}
                initial="enter"
                animate="center"
                exit="exit"
                transition={{
                  x: { type: "spring", stiffness: 300, damping: 30 },
                  opacity: { duration: 0.2 },
                }}
                src={`/images/gallery/${images[slide]}.jpg`}
              />
            </AnimatePresence>
          </ImgWrapper>
          <NavBtn
            onClick={() => navigateGallery(1)}
            isDisabled={slide === images.length - 1}
            whileTap={slide !== images.length - 1 && { scale: 0.7 }}
          >
            <MdNavigateNext size="2.5em" />
          </NavBtn>
        </GalleryWrapper>
      </DemoCont>
    </>
  );
};

export default PhotoCarousel;

const variants = {
  enter: (direction) => ({
    x: direction > 0 ? 100 : -100,
    opacity: 0,
  }),
  center: {
    x: 0,
    opacity: 1,
    zIndex: 1,
  },
  exit: (direction) => ({
    x: direction < 0 ? 100 : -100,
    opacity: 0,
    zIndex: -1,
  }),
};

const GalleryWrapper = styled.div`
  display: flex;
  align-items: center;
  gap: 10px;
  height: 400px;
  width: 600px;
`;

const Img = styled(motion.img)`
  width: 100%;
  height: 100%;
  object-fit: cover;
  position: absolute;
  top: 0;
  left: 0;
  box-shadow: rgba(0, 0, 0, 0.35) 0px 5px 15px;
`;

const ImgWrapper = styled.div`
  height: 100%;
  width: 100%;
  position: relative;
`;

const NavBtn = styled(motion.button)`
  color: ${(p) => (p.isDisabled ? "grey" : "white")};
  cursor: ${(p) => (p.isDisabled ? "auto" : "pointer")};
  background: none;
  border: none;
`;

Note: Code snippets do not include styling details unless they are the focus of the exercise.

Copyright © 2022 Explore React