Hi @Rodrigo,
I hope you're having a great day!
Thanks for sharing this, I've tried to apply information i got from the blog you shared in many differnet ways but now i am out of ideas i really don't know what special i should do to make them pin and fade away on scroll!!
I hope you've seen the sandbox link for understanding about the collision between horizontal scroll functionality that i have and scrolltrigger function
import { useMediaQuery, useRect } from '@studio-freight/hamo'
import cn from 'clsx'
import gsap from 'gsap'
import ScrollTrigger from 'gsap/ScrollTrigger'
import { useScroll } from '@/hooks/use-scroll'
import { clamp, mapRange } from '@/lib/maths'
import { useEffect, useRef, useState } from 'react'
import { useWindowSize } from 'react-use'
import s from './Horizontal.module.scss'
gsap.registerPlugin(ScrollTrigger)
export const HorizontalSlides = ({ children }: { children: React.ReactNode }) => {
const elementRef = useRef<HTMLDivElement | null>(null);
const isMobile = useMediaQuery('(max-width: 800px)')
const [wrapperRectRef, wrapperRect] = useRect()
const [elementRectRef, elementRect] = useRect()
const { height: windowHeight } = useWindowSize()
const [windowWidth, setWindowWidth] = useState<number>(0);
useScroll(({ scroll }: { scroll: number }) => {
setWindowWidth(window.innerWidth);
if (!elementRect || !elementRef.current) return
const start = wrapperRect.top - windowHeight
const end = wrapperRect.top + wrapperRect.height - windowHeight
let progress = mapRange(start, end, scroll, 0, 1)
progress = clamp(0, progress, 1)
const x = progress * (elementRect.width - windowWidth)
const cards = Array.from(elementRef.current.children)
gsap.to(cards, {
x: -x,
stagger: 0.033,
ease: 'none',
duration: 0,
})
})
useEffect(() => {
if (!elementRef.current) return;
const onResize = () => {
setWindowWidth(Math.min(window.innerWidth, document.documentElement.offsetWidth));
};
window.addEventListener('resize', onResize, false);
onResize();
Array.from(elementRef.current.children).forEach((card, index) => {
let tl = gsap.timeline({
scrollTrigger: {
trigger: card,
start: "left center-=500",
end: "right center+=500",
scrub: true,
markers: true,
horizontal: true,
pin: true,
}
});
tl.to(card, {opacity: 0, duration: 1}, 0);
});
return () => {
window.removeEventListener('resize', onResize, false);
ScrollTrigger.getAll().forEach(st => st.kill());
};
}, [windowWidth]);
return (
<>
<div
className={s.wrapper}
ref={wrapperRectRef}
style={
elementRect && isMobile === false
? { height: elementRect.width + 'px' }
: {}
}
>
<div className={s.inner}>
{/* {isMobile === false ? ( */}
<div
ref={(node) => {
elementRef.current = node
elementRectRef(node)
}}
className={cn(s.overflow, 'hide-on-mobile')}
>
{children}
</div>
{/* ) : ( */}
<div className={cn(s.cards, 'hide-on-desktop')}>{children}</div>
{/* )} */}
</div>
</div>
</>
)
}