toggle-corp/react-store

View on GitHub
components/View/Modal/index.js

Summary

Maintainability
A
0 mins
Test Coverage
import FocusTrap from 'react-focus-trap';
import PropTypes from 'prop-types';
import React from 'react';
import { _cs } from '@togglecorp/fujs';

import Haze from '../Haze';
import Portal from '../Portal';
import styles from './styles.scss';

const ESCAPE_KEY = 27;

const noop = () => {};

const propTypes = {
    children: PropTypes.oneOfType([
        PropTypes.arrayOf(PropTypes.element),
        PropTypes.element,
    ]).isRequired,
    className: PropTypes.string,
    closeOnEscape: PropTypes.bool,
    closeOnOutsideClick: PropTypes.bool,
    onClose: PropTypes.func,
};

const defaultProps = {
    className: '',
    closeOnEscape: false,
    closeOnOutsideClick: false,
    onClose: noop,
};

// eslint-disable-next-line react/no-multi-comp
export default class Modal extends React.PureComponent {
    static propTypes = propTypes;

    static defaultProps = defaultProps;

    constructor(props) {
        super(props);
        this.wrapperRef = React.createRef();
    }

    componentDidMount() {
        document.addEventListener('keydown', this.handleKeyPressed);
        document.addEventListener('mousedown', this.handleClickOutside);
    }

    componentWillUnmount() {
        document.removeEventListener('keydown', this.handleKeyPressed);
        document.removeEventListener('mousedown', this.handleClickOutside);
    }

    handleClickOutside = (event) => {
        const {
            closeOnOutsideClick,
            onClose,
        } = this.props;

        const { current: wrapper } = this.wrapperRef;

        if (closeOnOutsideClick && !wrapper.contains(event.target)) {
            onClose({ outsideClick: true });
        }
    }

    handleKeyPressed = (event) => {
        const {
            closeOnEscape,
            onClose,
        } = this.props;

        const { current: container } = this.wrapperRef;
        const isLastModal = container && container.dataset.lastModal === 'true';


        if (isLastModal && closeOnEscape && event.keyCode === ESCAPE_KEY) {
            onClose({ escape: true });
        }
    }

    render() {
        const {
            children,
            className: classNameFromProps,
        } = this.props;

        const className = _cs(
            classNameFromProps,
            styles.modal,
            'modal',
        );

        return (
            <Portal>
                <FocusTrap>
                    <Haze>
                        <div
                            ref={this.wrapperRef}
                            className={className}
                        >
                            { children }
                        </div>
                    </Haze>
                </FocusTrap>
            </Portal>
        );
    }
}