Skip to content

Instantly share code, notes, and snippets.

@yinkakun
Created January 25, 2024 15:23
Show Gist options
  • Save yinkakun/7a4a79397ddb5e1df5818c8ccd08988e to your computer and use it in GitHub Desktop.
Save yinkakun/7a4a79397ddb5e1df5818c8ccd08988e to your computer and use it in GitHub Desktop.
A slider that adapts to it's children
import React from "react";
import type { Variants } from "framer-motion";
import { motion, AnimatePresence } from "framer-motion";
const slideVariants: Variants = {
enter: {
x: "60%",
opacity: 0,
scale: 0.85,
},
active: {
x: 0,
scale: 1,
zIndex: 1,
opacity: 1,
},
exit: {
x: "-60%",
opacity: 0,
scale: 0.85,
},
};
interface SliderActions {
goToPrevSlide: () => void;
goToNextSlide: () => void;
}
const SliderContext = React.createContext<SliderActions | undefined>(undefined);
interface SliderProps {
children?: React.ReactNode;
}
export const Slider: React.FC<SliderProps> = ({ children }) => {
const sliderLength = React.Children.count(children);
const [slideIndex, setSlideIndex] = React.useState(0);
const goToNextSlide = () => {
if (slideIndex < sliderLength - 1) {
setSlideIndex((prev) => prev + 1);
}
};
const goToPrevSlide = () => {
if (slideIndex > 0) {
setSlideIndex((prev) => prev - 1);
}
};
return (
<SliderContext.Provider
value={{
goToPrevSlide,
goToNextSlide,
}}
>
<AnimatePresence mode="wait">
{React.Children.map(children, (child, index) => {
if (index === slideIndex) {
return (
<motion.div
layout
key={index}
exit="exit"
initial="enter"
animate="active"
variants={slideVariants}
transition={{
duration: 0.25,
x: { type: "spring", stiffness: 300, damping: 30 },
}}
>
{child}
</motion.div>
);
}
})}
</AnimatePresence>
</SliderContext.Provider>
);
};
export const useSlider = () => {
const context = React.useContext(SliderContext);
if (context === undefined) {
throw new Error("useSlider must be used within a Slider");
}
return {
prevSlide: context.goToPrevSlide,
nextSlide: context.goToNextSlide,
};
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment