A progressive-blur component from Motion Primitives.
1'use client';
2import { cn } from '@/lib/utils';
3import { HTMLMotionProps, motion } from 'motion/react';
4
5export const GRADIENT_ANGLES = {
6 top: 0,
7 right: 90,
8 bottom: 180,
9 left: 270,
10};
11
12export type ProgressiveBlurProps = {
13 direction?: keyof typeof GRADIENT_ANGLES;
14 blurLayers?: number;
15 className?: string;
16 blurIntensity?: number;
17} & HTMLMotionProps<'div'>;
18
19export function ProgressiveBlur({
20 direction = 'bottom',
21 blurLayers = 8,
22 className,
23 blurIntensity = 0.25,
24 ...props
25}: ProgressiveBlurProps) {
26 const layers = Math.max(blurLayers, 2);
27 const segmentSize = 1 / (blurLayers + 1);
28
29 return (
30 <div className={cn('relative', className)}>
31 {Array.from({ length: layers }).map((_, index) => {
32 const angle = GRADIENT_ANGLES[direction];
33 const gradientStops = [
34 index * segmentSize,
35 (index + 1) * segmentSize,
36 (index + 2) * segmentSize,
37 (index + 3) * segmentSize,
38 ].map(
39 (pos, posIndex) =>
40 `rgba(255, 255, 255, ${posIndex === 1 || posIndex === 2 ? 1 : 0}) ${pos * 100}%`
41 );
42
43 const gradient = `linear-gradient(${angle}deg, ${gradientStops.join(
44 ', '
45 )})`;
46
47 return (
48 <motion.div
49 key={index}
50 className='pointer-events-none absolute inset-0 rounded-[inherit]'
51 style={{
52 maskImage: gradient,
53 WebkitMaskImage: gradient,
54 backdropFilter: `blur(${index * blurIntensity}px)`,
55 WebkitBackdropFilter: `blur(${index * blurIntensity}px)`,
56 }}
57 {...props}
58 />
59 );
60 })}
61 </div>
62 );
63}
64