infinite-slider
efferd-/infinite-sliderFreeComponent
Infinite slider component.
Install it
npx shadcn@latest add http://efferd.com/r/infinite-slider.jsonSource
1"use client";2import { cn } from "@/lib/utils";3import { animate, motion, useMotionValue } from "motion/react";4import { useEffect, useState } from "react";5import useMeasure from "react-use-measure";67export type InfiniteSliderProps = {8 children: React.ReactNode;9 gap?: number;10 speed?: number;11 speedOnHover?: number;12 direction?: "horizontal" | "vertical";13 reverse?: boolean;14 className?: string;15};1617export function InfiniteSlider({18 children,19 gap = 16,20 speed = 100,21 speedOnHover,22 direction = "horizontal",23 reverse = false,24 className,25}: InfiniteSliderProps) {26 const [currentSpeed, setCurrentSpeed] = useState(speed);27 const [ref, { width, height }] = useMeasure();28 const translation = useMotionValue(0);29 const [isTransitioning, setIsTransitioning] = useState(false);3031 useEffect(() => {32 let controls: ReturnType<typeof animate> | undefined;33 const size = direction === "horizontal" ? width : height;34 const contentSize = size + gap;35 const from = reverse ? -contentSize / 2 : 0;36 const to = reverse ? 0 : -contentSize / 2;3738 const distanceToTravel = Math.abs(to - from);39 const duration = distanceToTravel / currentSpeed;4041 if (isTransitioning) {42 const remainingDistance = Math.abs(translation.get() - to);43 const transitionDuration = remainingDistance / currentSpeed;4445 controls = animate(translation, [translation.get(), to], {46 ease: "linear",47 duration: transitionDuration,48 onComplete: () => {49 setIsTransitioning(false);50 },51 });52 } else {53 controls = animate(translation, [from, to], {54 ease: "linear",55 duration,56 repeat: Number.POSITIVE_INFINITY,57 repeatType: "loop",58 repeatDelay: 0,59 onRepeat: () => {60 translation.set(from);61 },62 });63 }6465 return controls?.stop;66 }, [67 translation,68 currentSpeed,69 width,70 height,71 gap,72 isTransitioning,73 direction,74 reverse,75 ]);7677 const hoverProps = speedOnHover78 ? {79 onHoverStart: () => {80 setIsTransitioning(true);81 setCurrentSpeed(speedOnHover);82 },83 onHoverEnd: () => {84 setIsTransitioning(true);85 setCurrentSpeed(speed);86 },87 }88 : {};8990 return (91 <div className={cn("overflow-hidden", className)}>92 <motion.div93 className="flex w-max"94 ref={ref}95 style={{96 ...(direction === "horizontal"97 ? { x: translation }98 : { y: translation }),99 gap: `${gap}px`,100 flexDirection: direction === "horizontal" ? "row" : "column",101 }}102 {...hoverProps}103 >104 {children}105 {children}106// … truncated
What it pulls in
npm packages
Files it writes
More from efferd
All 201 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| apple-iconapple-icon | efferd | Components | Free | no deps | |
| auth-dividerauth-divider | efferd | Components | Free | no deps | |
| copy-buttoncopy-button | efferd | Components | Free | no deps | |
| decor-icondecor-icon | efferd | Components | Free | no deps | |
| discord-icondiscord-icon | efferd | Components | Free | no deps | |
| facebook-iconfacebook-icon | efferd | Components | Free | no deps | |
| figma-iconfigma-icon | efferd | Components | Free | no deps | |
| formaterformater | efferd | Components | Free | no deps |
