// Taxed from https://www.joshwcomeau.com/react/animated-sparkles-in-react/
import React, {
CSSProperties,
forwardRef,
HTMLAttributes,
PropsWithChildren,
useState,
} from "react";
import classNames from "classnames";
import random from "lodash.random";
import range from "lodash.range";
import { usePrefersReducedMotion, useRandomInterval } from "../../hooks";
import { bemHOF } from "../../utilities";
import { Box } from "../Box";
import { Svg } from "../Svg";
const cn = bemHOF("Sparkles");
const DEFAULT_COLOR = "#ffc700";
const generateSparkle = (color = DEFAULT_COLOR) => {
const sparkle = {
id: String(random(10000, 99999)),
createdAt: Date.now(),
color,
size: random(10, 20),
style: {
top: `${random(0, 100)}%`,
left: `${random(0, 100)}%`,
},
};
return sparkle;
};
interface SparkleProps {
size: number;
color: string;
style: CSSProperties;
}
const Sparkle = ({ size, color, style }: SparkleProps) => {
const path =
"M16 0c0 0 0.857 8.258 4.299 11.701s11.701 4.299 11.701 4.299-8.259 0.857-11.701 4.299c-3.442 3.442-4.299 11.701-4.299 11.701s-0.857-8.259-4.299-11.701c-3.442-3.442-11.701-4.299-11.701-4.299s8.258-0.857 11.701-4.299c3.442-3.442 4.299-11.701 4.299-11.701z";
return (
);
};
export type SparklesProps = PropsWithChildren>;
export const Sparkles = forwardRef(
({ children, color = DEFAULT_COLOR, className, ...rest }, ref) => {
const prefersReducedMotion = usePrefersReducedMotion();
const [sparkles, setSparkles] = useState(() => {
return range(3).map(() => generateSparkle(color));
});
useRandomInterval({
callback: () => {
const sparkle = generateSparkle(color);
const now = Date.now();
const nextSparkles = sparkles.filter((sp) => {
const delta = now - sp.createdAt;
return delta < 750;
});
nextSparkles.push(sparkle);
setSparkles(nextSparkles);
},
minDelay: prefersReducedMotion ? 0 : 50,
maxDelay: prefersReducedMotion ? 0 : 450,
});
return (
{sparkles.map((sparkle) => (
))}
{children}
);
},
);