|
<!DOCTYPE html> |
|
<html> |
|
<head> |
|
<title>React Popup</title> |
|
<link rel='stylesheet' href='https://use.fontawesome.com/releases/v6.7.2/css/all.css'> |
|
<script src="https://unpkg.com/react@18/umd/react.development.js"></script> |
|
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script> |
|
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script> |
|
<style> |
|
body { |
|
font-family: sans-serif; |
|
text-align: center; |
|
} |
|
button { |
|
cursor: pointer; |
|
} |
|
|
|
.popup { |
|
position: fixed; |
|
inset: 0; |
|
z-index: 10; |
|
display: flex; |
|
align-items: center; |
|
justify-content: center; |
|
visibility: hidden; |
|
transition: 0.35s cubic-bezier(0.22, 1, 0.36, 1); |
|
} |
|
.popup.show { |
|
visibility: visible; |
|
background: rgb(0, 0, 0, 0.5); |
|
backdrop-filter: blur(5px); |
|
} |
|
|
|
.popup .popup-content { |
|
position: relative; |
|
background: white; |
|
padding: 1rem; |
|
border-radius: 1rem; |
|
scale: 0.95; |
|
opacity: 0; |
|
transform: translateY(1rem); |
|
will-change: scale, opacity, transform; |
|
transition: 0.35s cubic-bezier(0.22, 1, 0.36, 1); |
|
} |
|
.popup.show .popup-content { |
|
transform: translateY(0); |
|
opacity: 1; |
|
scale: 1; |
|
} |
|
|
|
.popup .close { |
|
color: red; |
|
cursor: pointer; |
|
position: absolute; |
|
top: 0.5rem; |
|
right: 0.5rem; |
|
transition: 0.2s; |
|
will-change: rotate; |
|
} |
|
.popup .close:hover { |
|
rotate: 90deg; |
|
} |
|
</style> |
|
</head> |
|
|
|
<body> |
|
<div id="root"></div> |
|
|
|
<script type="text/babel"> |
|
const Popup = ({ |
|
onClose, children, |
|
closeButton=true, |
|
closeOnOutsideClick=true |
|
}) => { |
|
const [show, setShow] = React.useState(false) |
|
React.useEffect(_=>{ |
|
setTimeout(_=>setShow(true), 0) |
|
}, []) |
|
const BeforeClose = _=>{ |
|
if (show){ |
|
setShow(false) |
|
setTimeout(_=>{ onClose && onClose() }, 350) |
|
} |
|
} |
|
return ( |
|
<div className={`popup ${show && "show"}`} |
|
onClick={closeOnOutsideClick && ( |
|
e=>e.target.classList.contains("popup") && BeforeClose() |
|
)} |
|
> |
|
<div className="popup-content"> |
|
{closeButton && ( |
|
<i className="close fa-solid fa-circle-xmark" onClick={_=>BeforeClose()}></i> |
|
)} |
|
{typeof children === "function" ? children({ close: BeforeClose }) : children} |
|
</div> |
|
</div> |
|
) |
|
} |
|
|
|
const App = () => { |
|
const [renderPopup, setRenderPopup] = React.useState(false) |
|
const onClose = _=>{ |
|
console.log("closed") |
|
setRenderPopup(false) |
|
} |
|
return ( |
|
<> |
|
<button onClick={_=>setRenderPopup(true)}>Show popup</button> |
|
{renderPopup && ( |
|
<Popup onClose={onClose}> |
|
{({ close }) => ( |
|
<> |
|
<h3>Hello world!</h3> |
|
<button onClick={close}>OK</button> |
|
</> |
|
)} |
|
</Popup> |
|
)} |
|
</> |
|
) |
|
} |
|
const root = ReactDOM.createRoot(document.getElementById("root")) |
|
root.render(<App/>) |
|
</script> |
|
</body> |
|
</html> |