Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
Size: Mime:
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import AriaModal from 'react-aria-modal';

export const modalVariants = ['transparent', 'blue', 'ink'];
export const defaultModalVariant = 'transparent';

class Modal extends Component {
  static propTypes = {
    /** Modal contents displayed over underlay, no styling/wrapper provided */
    children: PropTypes.any.isRequired,
    /** Control whether to show the modal: this allows internal entering/exiting logic for transitions */
    show: PropTypes.bool.isRequired,
    /** If provided, it is invoked for escape key or underlay click interactions. If omitted, the modal dialog does not respond to these interactions: you have to provide a way of closing it from the modal dialog content (an interaction that will toggle the `show` prop) . */
    onExit: PropTypes.func,
    /** If provided, it is invoked as soon as the modal is in entered/opened state */
    onEnter: PropTypes.func,
    /** A11y-enabled modal title */
    title: PropTypes.string.isRequired,

    verticalBottomDialogOffset: PropTypes.string,
    verticalDialogOffset: PropTypes.string,
    verticalAlign: PropTypes.string,

    /** color variant of the underlay */
    variant: PropTypes.oneOf(modalVariants),
  };
  static defaultProps = {
    variant: defaultModalVariant,
    onExit: undefined,
    onEnter: () => {},
    verticalAlign: 'middle',
    verticalDialogOffset: null,
    verticalBottomDialogOffset: null,
  };

  constructor(props) {
    super(props);

    this.state = {
      modalActive: props.show,
      modalHasEntered: false,
      show: this.props.show,
    };
  }

  static getDerivedStateFromProps(nextProps, prevState) {
    if (nextProps.show !== prevState.show) return { show: nextProps.show };
    return null;
  }

  componentDidUpdate(prevProps, prevState) {
    if (!this.props.show && prevState.show) {
      this.onModalExit();
    }
    if (this.props.show && !prevState.show) {
      // #TODO: remove sideEffect
      // eslint-disable-next-line react/no-did-update-set-state
      this.setState({ modalActive: true });
    }
  }

  onModalExit = () => {
    this.setState(
      {
        modalHasEntered: false,
      },
      () => {
        setTimeout(() => {
          this.setState({
            modalActive: false,
          });
        }, 200);
      }
    );
  };

  onModalEnter = () => {
    const { onEnter } = this.props;
    onEnter();
    this.setState({ modalHasEntered: true });
  };

  render() {
    const {
      children,
      onExit,
      title,
      variant,
      verticalAlign,
      verticalDialogOffset,
      verticalBottomDialogOffset,
      ...props
    } = this.props;
    const { modalActive, modalHasEntered } = this.state;
    return (
      <AriaModal
        titleText={title}
        verticallyCenter
        {...props}
        onEnter={this.onModalEnter}
        onExit={onExit}
        mounted={modalActive}
        underlayClass={`Modal-underlay Modal--${variant} ${modalHasEntered ? 'has-entered' : ''}`}
        dialogClass={`Modal ${modalHasEntered ? 'has-entered' : ''}`}
        dialogStyle={{ marginTop: verticalDialogOffset, marginBottom: verticalBottomDialogOffset, verticalAlign }}
        underlayColor={false}
      >
        {children}
      </AriaModal>
    );
  }
}

export default Modal;