Files
kolaytercih/src/components/scroll-flow.tsx

78 lines
2.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use client";
import { type ReactNode } from "react";
import { ReactLenis } from "lenis/react";
import {
motion,
useReducedMotion,
useScroll,
useSpring,
useTransform,
useVelocity,
} from "motion/react";
/**
* Vitrin sayfalarının akışkan scroll efekti: Lenis ile lerp'li (yavaşlatılmış,
* momentumlu) kaydırma + scroll hızına bağlı içerik bükülmesi (skew).
* Hızlı kaydırdıkça sayfa hafifçe yana yatar, durunca yayla yerine oturur.
*
* Sohbet ve liste gibi iç scroll alanı olan uygulama sayfalarında KULLANMA —
* Lenis tekerlek olayını sayfaya yönlendirdiği için iç scroll'u bozar,
* transform da `fixed` konumlu çocukları koparır.
*
* Hareket azaltılmışsa hem yumuşatma hem bükülme tamamen kapalıdır.
*/
export function ScrollFlow({
children,
className,
maxSkew = 3,
}: {
children: ReactNode;
className?: string;
/** Derece cinsinden en fazla bükülme açısı. */
maxSkew?: number;
}) {
const reduceMotion = useReducedMotion();
const { scrollY } = useScroll();
const velocity = useVelocity(scrollY);
// Önce hızı kesintisiz bir hedef açıya dönüştür, sonra doğrudan görünen
// açıyı yumuşat. Böylece eşik/clamp kaynaklı ani hız değişimleri yaya girmez.
const targetSkew = useTransform(velocity, (v) => {
const RESPONSE = 1800;
return Math.tanh(v / RESPONSE) * maxSkew;
});
const smoothSkew = useSpring(targetSkew, {
stiffness: 240,
damping: 26,
mass: 0.7,
restDelta: 0.005,
restSpeed: 0.01,
});
// Yuvarlama görsel basamaklanma üretir. Tam hassasiyetle çiz; yalnızca açı
// algılanamayacak kadar küçüldüğünde transform'u kaldırarak dev sayfa
// katmanının GPU belleğinde boşuna tutulmasını önle.
const transform = useTransform(smoothSkew, (v) => {
if (Math.abs(v) < 0.01) return "none";
return `skewY(${v}deg)`;
});
// Hareket azaltılmışsa da AYNI ağaç render edilir (server/client farklı
// ağaç hydration uyumsuzluğu yaratıyordu); efektler koşullu kapatılır:
// Lenis tekerlek yumuşatması kapalı, skew transform'u hiç bağlanmaz.
return (
<ReactLenis
root
options={{ lerp: 0.09, anchors: true, smoothWheel: !reduceMotion }}
>
<motion.div
className={className}
style={reduceMotion ? undefined : { transform }}
>
{children}
</motion.div>
</ReactLenis>
);
}