89 lines
2.2 KiB
TypeScript
89 lines
2.2 KiB
TypeScript
'use client'
|
|
|
|
import React, { ReactNode, useEffect, useState } from 'react'
|
|
import { motion, Variants } from "framer-motion";
|
|
import clsx from 'clsx';
|
|
|
|
export type BlurredOverlayContainerProps = {
|
|
visible: boolean
|
|
bgOpacity?: number
|
|
inDelay?: number
|
|
outDelay?: number
|
|
transitionDelay?: number
|
|
children: ReactNode
|
|
} & React.ComponentProps<typeof motion.div>
|
|
|
|
const BlurredOverlayContainer = ({
|
|
visible = true,
|
|
bgOpacity = 30,
|
|
inDelay = 0,
|
|
outDelay = 0,
|
|
transitionDelay: transitionDelay = 0,
|
|
children,
|
|
className,
|
|
onClick,
|
|
...props
|
|
}: BlurredOverlayContainerProps) => {
|
|
const [loaded, setLoaded] = useState(visible)
|
|
|
|
useEffect(() => {
|
|
if (visible) {
|
|
// Show immediately or after delay
|
|
const timeout = setTimeout(() => setLoaded(true), inDelay)
|
|
return () => clearTimeout(timeout)
|
|
} else {
|
|
// Hide with delay (matches opacity transition duration)
|
|
const timeout = setTimeout(() => setLoaded(false), outDelay) // 300ms matches Tailwind transition
|
|
return () => clearTimeout(timeout)
|
|
}
|
|
}, [visible, inDelay, outDelay])
|
|
|
|
const variants: Variants = {
|
|
hidden: {
|
|
opacity: 0,
|
|
visibility: 'hidden',
|
|
display: 'none',
|
|
transition: {
|
|
delay: transitionDelay / 1000,
|
|
duration: 0.3,
|
|
ease: 'easeInOut',
|
|
},
|
|
},
|
|
visible: {
|
|
opacity: 1,
|
|
visibility: 'visible',
|
|
display: 'block',
|
|
transition: {
|
|
delay: transitionDelay / 1000,
|
|
duration: 0.3,
|
|
ease: 'easeInOut',
|
|
},
|
|
},
|
|
};
|
|
|
|
return (
|
|
<motion.div
|
|
data-visible={visible}
|
|
data-loaded={loaded}
|
|
className={clsx(
|
|
className,
|
|
visible || loaded ? 'z-50' : !visible && !loaded ? '-z-50' : 'z-0',
|
|
'absolute inset-0 flex items-center justify-center h-full w-full backdrop-blur-sm',
|
|
)}
|
|
style={{
|
|
backgroundColor: `rgba(0, 0, 0, ${bgOpacity / 100})`,
|
|
}}
|
|
|
|
initial={visible ? 'visible' : 'hidden'}
|
|
animate={visible ? 'visible' : 'hidden'}
|
|
variants={variants}
|
|
{...props}
|
|
>
|
|
<div className='w-full h-dvh overflow-hidden' onClick={onClick}></div>
|
|
{children}
|
|
</motion.div>
|
|
)
|
|
}
|
|
|
|
export default BlurredOverlayContainer
|