michaelpeskov/components/ParallaxLayer.tsx

61 lines
1.2 KiB
TypeScript

'use client'
import { useEffect, useRef } from 'react'
import { gsap } from 'gsap'
import { ScrollTrigger } from 'gsap/ScrollTrigger'
if (typeof window !== 'undefined') {
gsap.registerPlugin(ScrollTrigger)
}
interface ParallaxLayerProps {
depth?: number
children: React.ReactNode
className?: string
speed?: number
}
export default function ParallaxLayer({
depth = 1,
children,
className = '',
speed = 0.5
}: ParallaxLayerProps) {
const ref = useRef<HTMLDivElement>(null)
useEffect(() => {
const element = ref.current
if (!element) return
// Check for reduced motion
const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches
if (prefersReducedMotion) return
const yMovement = -100 * depth * speed
const tl = gsap.to(element, {
yPercent: yMovement,
ease: 'none',
scrollTrigger: {
trigger: element,
start: 'top bottom',
end: 'bottom top',
scrub: true,
invalidateOnRefresh: true
}
})
return () => {
tl.kill()
}
}, [depth, speed])
return (
<div
ref={ref}
className={`will-change-transform ${className}`}
style={{ willChange: 'transform' }}
>
{children}
</div>
)
}