DocDoeAI / src /components /reactbits /SpotlightCard.tsx
asnannp's picture
deploy: sync backend to Space root (learn-lesson HF cache fix)
65d68f5
Raw History Blame Contribute Delete
1.83 kB
"use client";
import {
useRef,
type CSSProperties,
type PointerEvent,
type ReactNode,
} from "react";
import { motion, useReducedMotion, type HTMLMotionProps } from "framer-motion";
import "./SpotlightCard.css";
type SpotlightCardProps = Omit<
HTMLMotionProps<"article">,
"children" | "onMouseLeave" | "onPointerMove" | "onPointerLeave" | "style"
> & {
children: ReactNode;
className?: string;
spotlightColor?: string;
style?: CSSProperties;
};
export default function SpotlightCard({
children,
className = "",
spotlightColor = "rgba(255, 255, 255, 0.095)",
style,
...props
}: SpotlightCardProps) {
const cardRef = useRef<HTMLElement | null>(null);
const shouldReduceMotion = useReducedMotion();
function handlePointerMove(event: PointerEvent<HTMLElement>) {
if (shouldReduceMotion || event.pointerType === "touch") return;
const card = cardRef.current;
if (!card) return;
const bounds = card.getBoundingClientRect();
card.style.setProperty("--spotlight-x", `${event.clientX - bounds.left}px`);
card.style.setProperty("--spotlight-y", `${event.clientY - bounds.top}px`);
card.style.setProperty("--spotlight-visible", "1");
}
function handlePointerLeave() {
cardRef.current?.style.setProperty("--spotlight-visible", "0");
}
return (
<motion.article
ref={cardRef}
className={`reactbits-spotlight-card ${className}`.trim()}
onPointerMove={handlePointerMove}
onPointerLeave={handlePointerLeave}
onMouseLeave={handlePointerLeave}
style={
{
...style,
"--reactbits-spotlight-color": spotlightColor,
} as CSSProperties
}
{...props}
>
<span className="reactbits-spotlight-card__glow" aria-hidden="true" />
{children}
</motion.article>
);
}