UNPKG

lightswind

Version:

A collection of beautifully crafted React Components, Blocks & Templates for Modern Developers. Create stunning web applications effortlessly by using our 160+ professional and animated react components.

45 lines (44 loc) 3.21 kB
// @ts-nocheck "use client"; import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { useEffect, useState, useRef } from "react"; import { motion, useAnimationControls } from "framer-motion"; import { cn } from "../../lib/utils"; export function LoopingWords({ words, className }) { const controls = useAnimationControls(); const wordsRef = useRef([]); const [selectorWidth, setSelectorWidth] = useState(0); // Duplicate the words array to create a seamless infinite loop const duplicatedWords = [...words, ...words]; const totalOriginal = words.length; useEffect(() => { // Initial width setup updateWidth(1); let index = 0; const interval = setInterval(async () => { index++; updateWidth((index % totalOriginal) + 1); await controls.start({ y: `-${(index * 100) / duplicatedWords.length}%`, transition: { duration: 1.2, ease: [0.175, 0.885, 0.32, 1.15] }, }); // If we've scrolled past the first full set, snap back to the start seamlessly if (index === totalOriginal) { index = 0; controls.set({ y: "0%" }); } }, 2200); return () => clearInterval(interval); }, [controls, totalOriginal, duplicatedWords.length]); const updateWidth = (index) => { const el = wordsRef.current[index]; if (el) { setSelectorWidth(el.offsetWidth); } }; return (_jsx("div", { className: cn("flex items-center justify-center", className), children: _jsxs("div", { className: "relative h-[2.7em] px-[0.2em] text-[11vw] md:text-[6vw] leading-[0.9] font-bold uppercase whitespace-nowrap overflow-hidden", children: [_jsx(motion.ul, { className: "flex flex-col items-center m-0 p-0 list-none", animate: controls, initial: { y: "0%" }, children: duplicatedWords.map((word, i) => (_jsx("li", { ref: (el) => { wordsRef.current[i] = el; }, className: "text-foreground tracking-tight", children: _jsx("p", { className: "m-0", children: word }) }, i))) }), _jsx("div", { className: "pointer-events-none absolute inset-0 z-10", style: { backgroundImage: "linear-gradient(180deg, hsl(var(--background)) 5%, transparent 40%, transparent 60%, hsl(var(--background)) 95%)", } }), _jsxs(motion.div, { className: "absolute left-1/2 top-1/2 h-[0.9em] -translate-x-1/2 -translate-y-1/2 pointer-events-none z-20", animate: { width: selectorWidth }, transition: { duration: 0.5, ease: "easeOut" }, children: [_jsx("div", { className: "absolute top-0 left-0 w-[0.125em] h-[0.125em] border-t-[0.035em] border-l-[0.035em] border-primarylw" }), _jsx("div", { className: "absolute top-0 right-0 w-[0.125em] h-[0.125em] border-t-[0.035em] border-r-[0.035em] border-primarylw" }), _jsx("div", { className: "absolute bottom-0 left-0 w-[0.125em] h-[0.125em] border-b-[0.035em] border-l-[0.035em] border-primarylw" }), _jsx("div", { className: "absolute bottom-0 right-0 w-[0.125em] h-[0.125em] border-b-[0.035em] border-r-[0.035em] border-primarylw" })] })] }) })); }