The useTransform()
hook is used to transform the vertical scroll (drag) distance to the small circle’s scale
and opacity
.
We have a scrollY
Motion value that we pass to the draggable div’s y
.
Now, this Motion value will update when you drag so that we can utilize useTransform()
to create two other Motion values that change the scale
and opacity
of the small circle.
const items = [0, 1, 2, 3, 4];
const height = 70;
const padding = 10;
const size = 150;
export function Example() {
const scrollY = useMotionValue(0);
const scale = useTransform(scrollY, [0, 100], [0, 1]);
const opacity = useTransform(scrollY, [0, 100], [0, 1]);
return (
<>
<motion.div
style={{
width: 40,
height: 40,
borderRadius: 20,
backgroundColor: "#fff",
position: "absolute",
top: "50%",
marginTop: -85,
left: "50%",
marginLeft: -20,
scale,
opacity
}}
/>
<motion.div
style={{
width: 150,
height: 150,
borderRadius: 30,
overflow: "hidden",
position: "relative",
transform: "translateZ(0)",
}}
>
<motion.div
style={{
width: 150,
height: getHeight(items),
y: scrollY
}}
drag="y"
dragConstraints={{
top: -getHeight(items) + size,
bottom: 0
}}
>
{items.map((index) => {
return (
<motion.div
style={{
width: 150,
height: height,
borderRadius: 20,
backgroundColor: "#fff",
marginBottom:
index !== items.length - 1 ? 10 : 0
}}
key={index}
/>
);
})}
</motion.div>
</motion.div>
</>
);
}
function getHeight(items) {
const totalHeight = items.length * height;
const totalPadding = (items.length - 1) * padding;
const totalScroll = totalHeight + totalPadding;
return totalScroll;
}