-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy pathsparkles.tsx
42 lines (35 loc) · 1.3 KB
/
sparkles.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
'use client'
import { ReactNode, useState } from 'react'
import { range } from '@/utils'
import { generateSparkle } from '@/utils/generateSparkle'
import { usePrefersReducedMotion } from '@/hooks/use-prefers-reduced-motion'
import { useRandomInterval } from '@/hooks/use-random-interval'
import { SparkleItem } from '@/components/sparkle-item'
export function Sparkles({ color, children }: { color: string; children: ReactNode }) {
const [sparkles, setSparkles] = useState(() => {
return range({ start: 4, step: 1 }).map(() => generateSparkle({ color }))
})
const prefersReducedMotion = usePrefersReducedMotion()
useRandomInterval({
callback: () => {
const sparkle = generateSparkle({ color })
const now = Date.now()
const nextSparkles = sparkles.filter((sp) => {
const delta = now - sp.createdAt
return delta < 700
})
nextSparkles.push(sparkle)
setSparkles(nextSparkles)
},
minDelay: prefersReducedMotion ? null : 80,
maxDelay: prefersReducedMotion ? null : 1100
})
return (
<span className='relative inline-block'>
{sparkles.map(({ id, color, size, style }) => (
<SparkleItem key={id} color={color} size={size} style={style} />
))}
<strong className='relative z-[1px]'>{children}</strong>
</span>
)
}