mirror of
https://github.com/chinchang/web-maker.git
synced 2025-07-28 17:20:13 +02:00
82 lines
2.1 KiB
JavaScript
82 lines
2.1 KiB
JavaScript
import { h, Component } from 'preact';
|
|
import Portal from 'preact-portal';
|
|
|
|
export default class Modal extends Component {
|
|
componentDidMount() {
|
|
window.addEventListener('keydown', this.onKeyDownHandler.bind(this));
|
|
}
|
|
componentWillUnmount() {
|
|
window.removeEventListener('keydown', this.onKeyDownHandler.bind(this));
|
|
if (this.focusGrabber) {
|
|
this.focusGrabber.remove();
|
|
this.focusGrabber = null;
|
|
}
|
|
}
|
|
onKeyDownHandler(e) {
|
|
if (e.keyCode === 27) {
|
|
this.props.closeHandler();
|
|
}
|
|
}
|
|
onOverlayClick(e) {
|
|
if (e.target === this.overlayEl) {
|
|
this.props.closeHandler();
|
|
}
|
|
}
|
|
componentDidUpdate(prevProps) {
|
|
if (this.props.show !== prevProps.show) {
|
|
document.body.classList[this.props.show ? 'add' : 'remove'](
|
|
'overlay-visible'
|
|
);
|
|
if (this.props.show) {
|
|
// HACK: refs will evaluate on next tick due to portals
|
|
setTimeout(() => {
|
|
this.overlayEl.querySelector('.js-modal__close-btn').focus();
|
|
}, 0);
|
|
|
|
/* We insert a dummy hidden input which will take focus as soon as focus
|
|
escapes the modal, instead of focus going outside modal because modal
|
|
is last focusable element. */
|
|
this.focusGrabber = document.createElement('input');
|
|
this.focusGrabber.setAttribute(
|
|
'style',
|
|
'height:0;opacity:0;overflow:hidden;width:0;'
|
|
);
|
|
setTimeout(() => {
|
|
document.body.appendChild(this.focusGrabber);
|
|
}, 10);
|
|
} else {
|
|
this.focusGrabber.remove();
|
|
this.focusGrabber = null;
|
|
}
|
|
}
|
|
}
|
|
render() {
|
|
if (!this.props.show) return null;
|
|
|
|
return (
|
|
<Portal into="body">
|
|
<div
|
|
class={`${this.props.extraClasses || ''} modal is-modal-visible ${
|
|
this.props.small ? 'modal--small' : ''
|
|
}`}
|
|
ref={el => (this.overlayEl = el)}
|
|
onClick={this.onOverlayClick.bind(this)}
|
|
>
|
|
<div class="modal__content">
|
|
<button
|
|
type="button"
|
|
onClick={this.props.closeHandler}
|
|
aria-label="Close modal"
|
|
title="Close"
|
|
class="js-modal__close-btn modal__close-btn"
|
|
>
|
|
Close
|
|
</button>
|
|
{this.props.children}
|
|
</div>
|
|
</div>
|
|
</Portal>
|
|
);
|
|
}
|
|
}
|