"use client"; import React, { createContext, useContext, useRef } from "react"; import { useScroll, useTransform, motion, MotionValue } from "framer-motion"; import { cn } from "./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; range: number[]; }; type WordType = { children: React.ReactNode; progress: MotionValue; range: number[]; }; type CharType = { children: React.ReactNode; progress: MotionValue; range: number[]; }; type TextGradientScrollContextType = { textOpacity?: TextOpacityEnum; type?: ViewTypeEnum; }; const TextGradientScrollContext = createContext( {} ); function useGradientScroll() { const context = useContext(TextGradientScrollContext); return context; } export default function TextGradientScroll({ text, className, type = "letter", textOpacity = "soft", }: TextGradientScrollType) { const ref = useRef(null); const { scrollYProgress } = useScroll({ target: ref, offset: ["start center", "end center"], }); const words = text.split(" "); return (

{words.map((word, i) => { const start = i / words.length; const end = start + 1 / words.length; return type === "word" ? ( {word} ) : ( {word} ); })}

); } const Word = ({ children, progress, range }: WordType) => { const opacity = useTransform(progress, range, [0, 1]); return ( {children} {children} ); }; const Letter = ({ children, progress, range }: LetterType) => { if (typeof children === "string") { const amount = range[1] - range[0]; const step = amount / children.length; return ( {children.split("").map((char: string, i: number) => { const start = range[0] + i * step; const end = range[0] + (i + 1) * step; return ( {char} ); })} ); } }; const Char = ({ children, progress, range }: CharType) => { const opacity = useTransform(progress, range, [0, 1]); const { textOpacity } = useGradientScroll(); return ( {children} {children} ); };