100 lines
2.4 KiB
JavaScript
100 lines
2.4 KiB
JavaScript
'use client'
|
|
|
|
import React, { useEffect } from 'react'
|
|
import Icons from './Icons'
|
|
|
|
const Modal = props => {
|
|
//? Porps
|
|
const { isShow, onClose, effect, children } = props
|
|
|
|
//? Re-Renders
|
|
useEffect(() => {
|
|
if (isShow) document.body.style.overflow = 'hidden'
|
|
else document.body.style.overflow = 'unset'
|
|
}, [isShow])
|
|
|
|
//? Styles
|
|
const effectClasses =
|
|
effect === 'bottom-to-top'
|
|
? `
|
|
${isShow ? 'bottom-0 lg:mt-20' : '-bottom-full lg:mt-60'} w-full h-full lg:h-auto lg:max-w-3xl
|
|
transition-all duration-700 mx-auto relative`
|
|
: effect === 'ease-out'
|
|
? `
|
|
${isShow ? 'top-40 transform scale-100' : 'top-40 transform scale-50 '} max-w-3xl
|
|
fixed transition-all duration-700 left-0 right-0 mx-auto relative`
|
|
: effect === 'buttom-to-fit'
|
|
? `
|
|
${isShow ? 'bottom-0' : '-bottom-full'} w-full h-fit lg:max-w-3xl
|
|
fixed transition-all duration-700 left-0 right-0 mx-auto relative`
|
|
: ''
|
|
|
|
//? Render(s)
|
|
return (
|
|
<div
|
|
className={`${
|
|
isShow ? 'opacity-100 visible' : 'opacity-0 invisible '
|
|
} transition-all duration-500 fixed inset-0 left-0 right-0 bottom-0 top-0 z-50 overflow-y-auto`}
|
|
>
|
|
<div
|
|
className="w-screen h-screen bg-gray-400/20 fixed inset-0 left-0 right-0 bottom-0 top-0"
|
|
onClick={onClose}
|
|
/>
|
|
<div className={effectClasses}>
|
|
{React.Children.map(children, child => {
|
|
if (React.isValidElement(child)) {
|
|
return React.cloneElement(child, { onClose })
|
|
}
|
|
|
|
return child
|
|
})}
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
const Content = props => {
|
|
//? Props
|
|
const { onClose, children, ...restProps } = props
|
|
|
|
//? Render(s)
|
|
return (
|
|
<div {...restProps}>
|
|
{React.Children.map(children, child => {
|
|
if (React.isValidElement(child)) {
|
|
return React.cloneElement(child, { onClose })
|
|
}
|
|
|
|
return child
|
|
})}
|
|
</div>
|
|
)
|
|
}
|
|
|
|
const Header = props => {
|
|
//? Props
|
|
const { onClose, children } = props
|
|
|
|
//? Render(s)
|
|
return (
|
|
<div className="flex items-center justify-between pb-2 border-b-2 border-gray-200">
|
|
<span className="text-sm">{children}</span>
|
|
<button onClick={onClose} className="p-1">
|
|
<Icons.Close className="icon" />
|
|
</button>
|
|
</div>
|
|
)
|
|
}
|
|
const Body = ({ children }) => {
|
|
return <>{children}</>
|
|
}
|
|
|
|
const _default = Object.assign(Modal, {
|
|
Modal,
|
|
Content,
|
|
Header,
|
|
Body,
|
|
})
|
|
|
|
export default _default
|