Repository URL to install this package:
|
Version:
8.0.0 ▾
|
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;