xlibs-components
Version:
Modern React component library with Aceternity, MagicUI, and ShadCN components for building beautiful web applications
55 lines (54 loc) • 2.9 kB
JavaScript
"use client";
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
import { motion, useAnimationFrame, useMotionValue, useScroll, useSpring, useTransform, useVelocity, } from "motion/react";
import React, { useEffect, useRef, useState } from "react";
import { cn } from '../../lib/utils.js';
export const wrap = (min, max, v) => {
const rangeSize = max - min;
return ((((v - min) % rangeSize) + rangeSize) % rangeSize) + min;
};
function ParallaxText({ children, baseVelocity = 100, ...props }) {
const baseX = useMotionValue(0);
const { scrollY } = useScroll();
const scrollVelocity = useVelocity(scrollY);
const smoothVelocity = useSpring(scrollVelocity, {
damping: 50,
stiffness: 400,
});
const velocityFactor = useTransform(smoothVelocity, [0, 1000], [0, 5], {
clamp: false,
});
const [repetitions, setRepetitions] = useState(1);
const containerRef = useRef(null);
const textRef = useRef(null);
useEffect(() => {
const calculateRepetitions = () => {
if (containerRef.current && textRef.current) {
const containerWidth = containerRef.current.offsetWidth;
const textWidth = textRef.current.offsetWidth;
const newRepetitions = Math.ceil(containerWidth / textWidth) + 2;
setRepetitions(newRepetitions);
}
};
calculateRepetitions();
window.addEventListener("resize", calculateRepetitions);
return () => window.removeEventListener("resize", calculateRepetitions);
}, [children]);
const x = useTransform(baseX, (v) => `${wrap(-100 / repetitions, 0, v)}%`);
const directionFactor = React.useRef(1);
useAnimationFrame((t, delta) => {
let moveBy = directionFactor.current * baseVelocity * (delta / 1000);
if (velocityFactor.get() < 0) {
directionFactor.current = -1;
}
else if (velocityFactor.get() > 0) {
directionFactor.current = 1;
}
moveBy += directionFactor.current * moveBy * velocityFactor.get();
baseX.set(baseX.get() + moveBy);
});
return (_jsx("div", { ref: containerRef, className: "w-full overflow-hidden whitespace-nowrap", ...props, children: _jsx(motion.div, { className: "inline-block", style: { x }, children: Array.from({ length: repetitions }).map((_, i) => (_jsxs("span", { ref: i === 0 ? textRef : null, children: [children, " "] }, i))) }) }));
}
export function VelocityScroll({ defaultVelocity = 5, numRows = 2, children, className, ...props }) {
return (_jsx("div", { className: cn("relative w-full text-4xl font-bold tracking-[-0.02em] md:text-7xl md:leading-[5rem]", className), ...props, children: Array.from({ length: numRows }).map((_, i) => (_jsx(ParallaxText, { baseVelocity: defaultVelocity * (i % 2 === 0 ? 1 : -1), children: children }, i))) }));
}