import * as React from "react"; import { useState } from "react"; import { motion, AnimatePresence } from "framer-motion"; import { wrap } from "popmotion"; const variants = { enter: (direction) => { return { x: direction > 0 ? 1000 : -1000, opacity: 0, }; }, center: { zIndex: 1, x: 0, opacity: 1, }, exit: (direction) => { return { zIndex: 0, x: direction < 0 ? 1000 : -1000, opacity: 0, }; }, }; /** * Experimenting with distilling swipe offset and velocity into a single variable, so the * less distance a user has swiped, the more velocity they need to register as a swipe. * Should accomodate longer swipes and short flicks without having binary checks on * just distance thresholds and velocity > 0. */ const swipeConfidenceThreshold = 10000; const swipePower = (offset, velocity) => { return Math.abs(offset) * velocity; }; export const Carousel = ({ items }) => { const [[page, direction], setPage] = useState([0, 0]); // We only have 3 items, but we paginate them absolutely (ie 1, 2, 3, 4, 5...) and // then wrap that within 0-2 to find our image ID in the array below. By passing an // absolute page index as the `motion` component's `key` prop, `AnimatePresence` will // detect it as an entirely new image. So you can infinitely paginate as few as 1 item. const itemIndex = wrap(0, items.length, page); const paginate = (newDirection) => { setPage([page + newDirection, newDirection]); }; return ( <> { const swipe = swipePower(offset.x, velocity.x); if (swipe < -swipeConfidenceThreshold) { paginate(1); } else if (swipe > swipeConfidenceThreshold) { paginate(-1); } }} > {items[itemIndex]}
paginate(1)}> {"‣"}
paginate(-1)}> {"‣"}
); };