Files
dmenu-plus-front/src/components/overlays/BlurredOverlayContainer.tsx
T
2025-07-13 02:28:52 +03:30

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