Text Gradient Scroll
Text Gradient Scroll é um componente de texto para React e Tailwind CSS, da biblioteca Bund UI, com licença MIT. Copia e cola no teu projeto.
Bund UI
MIT
text
O que é
Text Gradient Scroll é um componente de texto para React e Tailwind CSS, da biblioteca Bund UI, com licença MIT. Copia e cola no teu projeto.
Como usar
Abre o componente no catálogo, carrega em copiar, e cola no teu projeto. O prompt copiado leva o código e as regras para o teu agente o reproduzir sem alterar nada.
Cinco cópias grátis por mês. Sem cartão.
Precisa de
npm i lenis motion lucide-react
Licença
Este componente vem de Bund UI e é redistribuído sob a licença MIT, que permite uso comercial. O aviso de copyright viaja com o código.
Text Gradient Scroll
"use client";
import TextGradientScroll from "./text-gradient-scroll";
import { type LenisRef, ReactLenis } from "lenis/react";
import { useEffect, useRef } from "react";
import { cancelFrame, frame } from "motion/react";
import { ChevronDown, ChevronUp } from "lucide-react";
export default function TextGradientScrollExample() {
const lenisRef = useRef<LenisRef>(null);
useEffect(() => {
function update(data: { timestamp: number }) {
const time = data.timestamp;
lenisRef.current?.lenis?.raf(time);
}
frame.update(update, true);
return () => cancelFrame(update);
}, []);
return (
<>
<ReactLenis root options={{ autoRaf: false }} ref={lenisRef} />
<div>
<div className="flex h-screen items-center justify-center">
Scroll Down <ChevronDown className="text-muted-foreground ms-1 size-4" />
</div>
<div className="flex flex-col gap-10">
<TextGradientScroll
className="text-xl"
text="The text gradient scroll component is designed to enhance user interaction by providing a visually dynamic effect as the user scrolls through the text. Unlike static text, this effect offers a more engaging visual experience with smooth color transitions that change as the text is scrolled. The text gradient scroll component is designed to enhance user interaction by providing a visually dynamic effect as the user scrolls through the text. Unlike static text, this effect offers a more engaging visual experience with smooth color transitions that change as the text is scrolled."
/>
<TextGradientScroll
className="text-xl text-green-500"
text="The text gradient scroll component is designed to enhance user interaction by providing a visually dynamic effect as the user scrolls through the text. Unlike static text, this effect offers a more engaging visual experience with smooth color transitions that change as the text is scrolled."
/>
</div>
<div className="flex h-screen items-center justify-center">
Scroll Up <ChevronUp className="text-muted-foreground ms-1 size-4" />
</div>
</div>
</>
);
}
"use client";
import React, { createContext, useContext, useRef } from "react";
import { motion, MotionValue, useScroll, useTransform } from "motion/react";
import { cn } from "@/lib/utils";
type TextOpacityEnum = "none" | "soft" | "medium";
type ViewTypeEnum = "word" | "letter";
type TextGradientScrollType = {
text: string;
type?: ViewTypeEnum;
className?: string;
textOpacity?: TextOpacityEnum;
};
type LetterType = {
children: React.ReactNode | string;
progress: MotionValue<number>;
range: number[];
};
type WordType = {
children: React.ReactNode;
progress: MotionValue<number>;
range: number[];
};
type CharType = {
children: React.ReactNode;
progress: MotionValue<number>;
range: number[];
};
type TextGradientScrollContextType = {
textOpacity?: TextOpacityEnum;
type?: ViewTypeEnum;
};
const TextGradientScrollContext = createContext<TextGradientScrollContextType>({});
function useGradientScroll() {
return useContext(TextGradientScrollContext);
}
export default function TextGradientScroll({
text,
className,
type = "letter",
textOpacity = "soft"
}: TextGradientScrollType) {
const ref = useRef<HTMLParagraphElement>(null);
const { scrollYProgress } = useScroll({
target: ref,
offset: ["start center", "end center"]
});
const words = text.split(" ");
return (
<TextGradientScrollContext.Provider value={{ textOpacity, type }}>
<p ref={ref} className={cn("relative m-0 flex flex-wrap", className)}>
{words.map((word, i) => {
const start = i / words.length;
const end = start + 1 / words.length;
return type === "word" ? (
<Word key={i} progress={scrollYProgress} range={[start, end]}>
{word}
</Word>
) : (
<Letter key={i} progress={scrollYProgress} range={[start, end]}>
{word}
</Letter>
);
})}
</p>
</TextGradientScrollContext.Provider>
);
}
const Word = ({ children, progress, range }: WordType) => {
const opacity = useTransform(progress, range, [0, 1]);
return (
<span className="relative me-2 mt-2">
<span style={{ position: "absolute", opacity: 0.1 }}>{children}</span>
<motion.span style={{ transition: "all .5s", opacity: opacity }}>{children}</motion.span>
</span>
);
};
const Letter = ({ children, progress, range }: LetterType) => {
if (typeof children === "string") {
const amount = range[1] - range[0];
const step = amount / children.length;
return (
<span className="relative me-2 mt-2">
{children.split("").map((char: string, i: number) => {
const start = range[0] + i * step;
const end = range[0] + (i + 1) * step;
return (
<Char key={`c_${i}`} progress={progress} range={[start, end]}>
{char}
</Char>
);
})}
</span>
);
}
};
const Char = ({ children, progress, range }: CharType) => {
const opacity = useTransform(progress, range, [0, 1]);
const { textOpacity } = useGradientScroll();
return (
<span>
<span
className={cn("absolute", {
"opacity-0": textOpacity == "none",
"opacity-10": textOpacity == "soft",
"opacity-30": textOpacity == "medium"
})}>
{children}
</span>
<motion.span
style={{
transition: "all .5s",
opacity: opacity
}}>
{children}
</motion.span>
</span>
);
};