reactbits-mcp-server
Version:
MCP Server for React Bits - Access 99+ React components with animations, backgrounds, and UI elements
95 lines (82 loc) • 2.98 kB
JSX
import { useEffect, useRef } from 'react';
import { gsap } from 'gsap';
import './GridMotion.css';
const GridMotion = ({ items = [], gradientColor = 'black' }) => {
const gridRef = useRef(null);
const rowRefs = useRef([]);
const mouseXRef = useRef(window.innerWidth / 2);
const totalItems = 28;
const defaultItems = Array.from({ length: totalItems }, (_, index) => `Item ${index + 1}`);
const combinedItems = items.length > 0 ? items.slice(0, totalItems) : defaultItems;
useEffect(() => {
gsap.ticker.lagSmoothing(0);
const handleMouseMove = (e) => {
mouseXRef.current = e.clientX;
};
const updateMotion = () => {
const maxMoveAmount = 300;
const baseDuration = 0.8;
const inertiaFactors = [0.6, 0.4, 0.3, 0.2];
rowRefs.current.forEach((row, index) => {
if (row) {
const direction = index % 2 === 0 ? 1 : -1;
const moveAmount = ((mouseXRef.current / window.innerWidth) * maxMoveAmount - maxMoveAmount / 2) * direction;
gsap.to(row, {
x: moveAmount,
duration: baseDuration + inertiaFactors[index % inertiaFactors.length],
ease: 'power3.out',
overwrite: 'auto',
});
}
});
};
const removeAnimationLoop = gsap.ticker.add(updateMotion);
window.addEventListener('mousemove', handleMouseMove);
return () => {
window.removeEventListener('mousemove', handleMouseMove);
removeAnimationLoop();
};
}, []);
return (
<div className="noscroll loading" ref={gridRef}>
<section
className="intro"
style={{
background: `radial-gradient(circle, ${gradientColor} 0%, transparent 100%)`,
}}
>
<div className="gridMotion-container">
{[...Array(4)].map((_, rowIndex) => (
<div
key={rowIndex}
className="row"
ref={(el) => (rowRefs.current[rowIndex] = el)}
>
{[...Array(7)].map((_, itemIndex) => {
const content = combinedItems[rowIndex * 7 + itemIndex];
return (
<div key={itemIndex} className="row__item">
<div className="row__item-inner" style={{ backgroundColor: '#111' }}>
{typeof content === 'string' && content.startsWith('http') ? (
<div
className="row__item-img"
style={{
backgroundImage: `url(${content})`,
}}
></div>
) : (
<div className="row__item-content">{content}</div>
)}
</div>
</div>
);
})}
</div>
))}
</div>
<div className="fullview"></div>
</section>
</div>
);
};
export default GridMotion;