chore: improve animation of blurred overlay

This commit is contained in:
Mahyar Khanbolooki
2025-07-12 23:09:22 +03:30
parent 3ac533956e
commit 817af6e2e0
6 changed files with 67 additions and 40 deletions
+2 -2
View File
@@ -234,7 +234,7 @@ const MenuIndex = () => {
</VerticalScrollView>
</section>
<AnimatedBottomSheet title="فیلتر ها" visible={filterModal} changeDelay="150" onClick={toggleFilterModal}>
<AnimatedBottomSheet title="فیلتر ها" visible={filterModal} outDelay={150} onClick={toggleFilterModal}>
<div className="ps-8.5 pe-[31px] mt-[89px]">
<SearchComboBox
title="محتویات"
@@ -277,7 +277,7 @@ const MenuIndex = () => {
</div>
</AnimatedBottomSheet>
<AnimatedBottomSheet title="مرتب کردن بر اساس" visible={sortingModal} changeDelay="150" onClick={toggleSortingModal}>
<AnimatedBottomSheet title="مرتب کردن بر اساس" visible={sortingModal} inDelay={150} onClick={toggleSortingModal}>
<div className="px-8.5 py-10 justify-between">
{sortings.map((v, i) => {
return (
@@ -9,7 +9,7 @@ type Props = {
const AnimatedBottomSheet = (props: Props) => {
return (
<BlurredOverlayContainer {...props} changeDelay="150">
<BlurredOverlayContainer {...props} inDelay={150}>
<div
data-visible={props.visible}
className={clsx(
+1 -1
View File
@@ -76,7 +76,7 @@ function SideMenu({ menuState, toggleMenuState, nightModeState, togglenightModeS
return (
<div className='w-full h-dvh'>
<BlurredOverlayContainer bgOpacity='40' visible={menuStateMemo} onClick={toggleMenuState} changeDelay='300'>
<BlurredOverlayContainer bgOpacity={40} visible={menuStateMemo} onClick={toggleMenuState} outDelay={150}>
<div
data-isvisible={menuStateMemo}
onClick={(e) => { e.stopPropagation(); }}
@@ -1,20 +1,26 @@
'use client'
import React, { useEffect, useState } from 'react'
import React, { ReactNode, useEffect, useState } from 'react'
import { motion, Variants } from "framer-motion";
import clsx from 'clsx';
export type BlurredOverlayContainerProps = {
visible: boolean
bgOpacity?: string
changeDelay?: string
effectdelay?: string
} & React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
bgOpacity?: number
inDelay?: number
outDelay?: number
transitionDelay?: number
children: ReactNode
} & React.ComponentProps<typeof motion.div>
const BlurredOverlayContainer = ({
visible = true,
bgOpacity = '30',
changeDelay = '0',
effectdelay = '0',
bgOpacity = 30,
inDelay = 0,
outDelay = 0,
transitionDelay: transitionDelay = 0,
children,
className,
onClick,
...props
}: BlurredOverlayContainerProps) => {
@@ -23,34 +29,55 @@ const BlurredOverlayContainer = ({
useEffect(() => {
if (visible) {
// Show immediately or after delay
const timeout = setTimeout(() => setLoaded(true), +changeDelay)
const timeout = setTimeout(() => setLoaded(true), inDelay)
return () => clearTimeout(timeout)
} else {
// Hide with delay (matches opacity transition duration)
const timeout = setTimeout(() => setLoaded(false), +changeDelay) // 300ms matches Tailwind transition
const timeout = setTimeout(() => setLoaded(false), outDelay) // 300ms matches Tailwind transition
return () => clearTimeout(timeout)
}
}, [visible, changeDelay])
}, [visible, inDelay, outDelay])
const zClass =
visible || loaded ? 'z-50' : !visible && !loaded ? '-z-50' : 'z-0'
const variants: Variants = {
hidden: {
opacity: 0,
transition: {
delay: transitionDelay / 1000,
duration: 0.3,
ease: 'easeInOut',
},
},
visible: {
opacity: 1,
transition: {
delay: transitionDelay / 1000,
duration: 0.3,
ease: 'easeInOut',
},
},
};
return (
<div
<motion.div
data-visible={visible}
data-loaded={loaded}
className={props.className + `
fixed inset-0 flex items-center justify-center h-dvh w-full
backdrop-blur-sm
opacity-0 transition-opacity duration-300 ease-in-out delay-${effectdelay}
${zClass}
${visible ? 'opacity-100' : 'opacity-0'}`}
style={{ backgroundColor: `rgba(0, 0, 0, ${+bgOpacity / 100})` }}
className={clsx(
className,
visible || loaded ? 'z-50' : !visible && !loaded ? '-z-50' : 'z-0',
'fixed inset-0 flex items-center justify-center h-dvh 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}
</div>
</motion.div>
)
}