diff --git a/app/docs/infinite-slider/page.mdx b/app/docs/infinite-slider/page.mdx index ad42c490..2faec2fe 100644 --- a/app/docs/infinite-slider/page.mdx +++ b/app/docs/infinite-slider/page.mdx @@ -80,3 +80,4 @@ Infinite scrolling slider component that smoothly loops through its children. It | direction | 'horizontal' \| 'vertical' | 'horizontal' | The direction of the slider movement. | | reverse | boolean | false | Whether to reverse the direction of the slider movement. | | className | string | undefined | Optional CSS class for styling the component. | +| fillElements | boolean | false | This controll to fill children with respect to container's width | diff --git a/components/core/infinite-slider.tsx b/components/core/infinite-slider.tsx index 87d851ec..0d1f3a81 100644 --- a/components/core/infinite-slider.tsx +++ b/components/core/infinite-slider.tsx @@ -1,7 +1,7 @@ 'use client'; import { cn } from '@/lib/utils'; import { useMotionValue, animate, motion } from 'motion/react'; -import { useState, useEffect } from 'react'; +import React, { useState, useEffect } from 'react'; import useMeasure from 'react-use-measure'; export type InfiniteSliderProps = { @@ -11,6 +11,7 @@ export type InfiniteSliderProps = { speedOnHover?: number; direction?: 'horizontal' | 'vertical'; reverse?: boolean; + fillElements?: boolean; className?: string; }; @@ -22,39 +23,40 @@ export function InfiniteSlider({ direction = 'horizontal', reverse = false, className, + fillElements = true, }: InfiniteSliderProps) { const [currentSpeed, setCurrentSpeed] = useState(speed); - const [ref, { width, height }] = useMeasure(); + const [containerRef, { width: containerWidth, height }] = useMeasure(); + const [contentRef, { width: contentWidth, height: contentHeight }] = + useMeasure(); const translation = useMotionValue(0); const [isTransitioning, setIsTransitioning] = useState(false); const [key, setKey] = useState(0); useEffect(() => { let controls; - const size = direction === 'horizontal' ? width : height; - const contentSize = size + gap; - const from = reverse ? -contentSize / 2 : 0; - const to = reverse ? 0 : -contentSize / 2; + const contentSize = + (direction === 'horizontal' ? contentWidth : contentHeight) + gap; + const from = reverse ? -contentSize : 0; + const to = reverse ? 0 : -contentSize; - const distanceToTravel = Math.abs(to - from); - const duration = distanceToTravel / currentSpeed; + const duration = Math.abs(contentSize) / currentSpeed; if (isTransitioning) { - const remainingDistance = Math.abs(translation.get() - to); - const transitionDuration = remainingDistance / currentSpeed; - - controls = animate(translation, [translation.get(), to], { + const current = translation.get(); + controls = animate(translation, [current, to], { ease: 'linear', - duration: transitionDuration, + duration: Math.abs(to - current) / currentSpeed, onComplete: () => { setIsTransitioning(false); - setKey((prevKey) => prevKey + 1); + translation.set(from); + setKey((prev) => prev + 1); }, }); } else { controls = animate(translation, [from, to], { ease: 'linear', - duration: duration, + duration, repeat: Infinity, repeatType: 'loop', repeatDelay: 0, @@ -64,13 +66,13 @@ export function InfiniteSlider({ }); } - return controls?.stop; + return () => controls?.stop(); }, [ key, translation, currentSpeed, - width, - height, + contentWidth, + contentHeight, gap, isTransitioning, direction, @@ -91,22 +93,79 @@ export function InfiniteSlider({ : {}; return ( -