2019-10-01 12:50:56 +00:00
|
|
|
import React from "react";
|
|
|
|
import PropTypes from "prop-types";
|
2021-02-09 08:56:15 +00:00
|
|
|
|
2019-10-01 12:50:56 +00:00
|
|
|
import Backdrop from "../backdrop";
|
2019-12-20 11:35:53 +00:00
|
|
|
import Aside from "../aside";
|
2019-12-09 11:47:36 +00:00
|
|
|
import Heading from "../heading";
|
2021-10-04 16:37:01 +00:00
|
|
|
import { getModalType } from "../utils/device";
|
2019-10-01 12:50:56 +00:00
|
|
|
import throttle from "lodash/throttle";
|
2020-09-09 18:49:25 +00:00
|
|
|
import Box from "../box";
|
2021-02-09 08:56:15 +00:00
|
|
|
import {
|
|
|
|
CloseButton,
|
|
|
|
StyledHeader,
|
|
|
|
Content,
|
|
|
|
Dialog,
|
|
|
|
BodyBox,
|
|
|
|
} from "./styled-modal-dialog";
|
2021-05-06 09:49:53 +00:00
|
|
|
import Portal from "../portal";
|
2021-06-30 07:23:49 +00:00
|
|
|
import Loaders from "@appserver/common/components/Loaders";
|
2021-05-06 09:49:53 +00:00
|
|
|
|
2020-09-09 18:49:25 +00:00
|
|
|
function Header() {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
Header.displayName = "DialogHeader";
|
|
|
|
|
|
|
|
function Body() {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
Body.displayName = "DialogBody";
|
|
|
|
|
|
|
|
function Footer() {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
Footer.displayName = "DialogFooter";
|
2019-06-27 12:47:32 +00:00
|
|
|
|
2019-10-01 12:50:56 +00:00
|
|
|
class ModalDialog extends React.Component {
|
2020-09-09 18:49:25 +00:00
|
|
|
static Header = Header;
|
|
|
|
static Body = Body;
|
2019-10-01 12:50:56 +00:00
|
|
|
constructor(props) {
|
|
|
|
super(props);
|
|
|
|
|
|
|
|
this.state = { displayType: this.getTypeByWidth() };
|
|
|
|
|
|
|
|
this.getTypeByWidth = this.getTypeByWidth.bind(this);
|
|
|
|
this.resize = this.resize.bind(this);
|
|
|
|
this.popstate = this.popstate.bind(this);
|
|
|
|
this.throttledResize = throttle(this.resize, 300);
|
|
|
|
}
|
|
|
|
|
|
|
|
getTypeByWidth() {
|
|
|
|
if (this.props.displayType !== "auto") return this.props.displayType;
|
|
|
|
|
2021-10-04 16:37:01 +00:00
|
|
|
return getModalType();
|
2019-10-01 12:50:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
resize() {
|
|
|
|
if (this.props.displayType !== "auto") return;
|
|
|
|
|
|
|
|
const type = this.getTypeByWidth();
|
|
|
|
if (type === this.state.displayType) return;
|
2019-06-27 12:47:32 +00:00
|
|
|
|
2021-08-19 15:35:04 +00:00
|
|
|
this.setState({ displayType: type });
|
2021-10-04 16:37:01 +00:00
|
|
|
|
|
|
|
this.props.onResize && this.props.onResize(type);
|
2019-10-01 12:50:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
popstate() {
|
|
|
|
window.removeEventListener("popstate", this.popstate, false);
|
|
|
|
this.props.onClose();
|
|
|
|
window.history.go(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
componentDidUpdate(prevProps) {
|
|
|
|
if (this.props.displayType !== prevProps.displayType) {
|
|
|
|
this.setState({ displayType: this.getTypeByWidth() });
|
|
|
|
}
|
|
|
|
if (this.props.visible && this.state.displayType === "aside") {
|
|
|
|
window.addEventListener("popstate", this.popstate, false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
componentDidMount() {
|
|
|
|
window.addEventListener("resize", this.throttledResize);
|
2019-12-25 14:38:32 +00:00
|
|
|
window.addEventListener("keyup", this.onKeyPress);
|
2019-10-01 12:50:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
componentWillUnmount() {
|
|
|
|
window.removeEventListener("resize", this.throttledResize);
|
2019-12-25 14:38:32 +00:00
|
|
|
window.removeEventListener("keyup", this.onKeyPress);
|
2019-10-01 12:50:56 +00:00
|
|
|
}
|
|
|
|
|
2020-10-16 13:16:01 +00:00
|
|
|
onKeyPress = (event) => {
|
2019-12-25 14:38:32 +00:00
|
|
|
if (event.key === "Esc" || event.key === "Escape") {
|
|
|
|
this.props.onClose();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-10-01 12:50:56 +00:00
|
|
|
render() {
|
|
|
|
const {
|
|
|
|
visible,
|
|
|
|
scale,
|
2019-10-02 07:23:58 +00:00
|
|
|
onClose,
|
2020-07-20 07:37:23 +00:00
|
|
|
zIndex,
|
2021-11-15 09:54:10 +00:00
|
|
|
asideBodyPadding,
|
|
|
|
modalBodyPadding,
|
2020-09-15 19:29:14 +00:00
|
|
|
contentHeight,
|
|
|
|
contentWidth,
|
2020-09-14 19:04:40 +00:00
|
|
|
className,
|
|
|
|
id,
|
|
|
|
style,
|
2020-10-16 13:16:01 +00:00
|
|
|
children,
|
2021-06-30 07:23:49 +00:00
|
|
|
isLoading,
|
2021-07-30 11:18:11 +00:00
|
|
|
contentPaddingBottom,
|
|
|
|
removeScroll,
|
2021-11-22 07:15:24 +00:00
|
|
|
modalLoaderBodyHeight,
|
2022-03-02 13:33:02 +00:00
|
|
|
withoutCloseButton,
|
2019-10-01 12:50:56 +00:00
|
|
|
} = this.props;
|
|
|
|
|
2020-09-09 18:49:25 +00:00
|
|
|
let header = null;
|
|
|
|
let body = null;
|
|
|
|
let footer = null;
|
|
|
|
|
2020-10-16 13:16:01 +00:00
|
|
|
React.Children.forEach(children, (child) => {
|
2020-09-09 18:49:25 +00:00
|
|
|
const childType =
|
|
|
|
child && child.type && (child.type.displayName || child.type.name);
|
|
|
|
|
|
|
|
switch (childType) {
|
|
|
|
case Header.displayName:
|
|
|
|
header = child;
|
|
|
|
break;
|
|
|
|
case Body.displayName:
|
|
|
|
body = child;
|
|
|
|
break;
|
|
|
|
case Footer.displayName:
|
|
|
|
footer = child;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2021-05-06 09:49:53 +00:00
|
|
|
const renderModal = () => {
|
|
|
|
return this.state.displayType === "modal" ? (
|
2020-12-10 17:09:16 +00:00
|
|
|
<Backdrop
|
|
|
|
visible={visible}
|
2020-09-09 18:49:25 +00:00
|
|
|
zIndex={zIndex}
|
2021-05-06 09:49:53 +00:00
|
|
|
withBackground={true}
|
|
|
|
isModalDialog
|
2019-11-25 07:51:53 +00:00
|
|
|
>
|
2021-05-06 09:49:53 +00:00
|
|
|
<Dialog
|
|
|
|
className={`${className} not-selectable`}
|
|
|
|
id={id}
|
|
|
|
style={style}
|
|
|
|
>
|
2021-11-15 09:54:10 +00:00
|
|
|
<Content
|
|
|
|
contentHeight={contentHeight}
|
|
|
|
contentWidth={contentWidth}
|
|
|
|
displayType={this.state.displayType}
|
|
|
|
>
|
2021-06-30 07:23:49 +00:00
|
|
|
{isLoading ? (
|
2021-11-22 07:15:24 +00:00
|
|
|
<Loaders.DialogLoader bodyHeight={modalLoaderBodyHeight} />
|
2021-06-30 07:23:49 +00:00
|
|
|
) : (
|
|
|
|
<>
|
|
|
|
<StyledHeader>
|
|
|
|
<Heading className="heading" size="medium" truncate={true}>
|
|
|
|
{header ? header.props.children : null}
|
|
|
|
</Heading>
|
2022-03-02 13:33:02 +00:00
|
|
|
{!withoutCloseButton && (
|
|
|
|
<CloseButton
|
|
|
|
className="modal-dialog-button_close"
|
|
|
|
onClick={onClose}
|
|
|
|
></CloseButton>
|
|
|
|
)}
|
2021-06-30 07:23:49 +00:00
|
|
|
</StyledHeader>
|
2021-11-15 09:54:10 +00:00
|
|
|
<BodyBox paddingProp={modalBodyPadding}>
|
2021-06-30 07:23:49 +00:00
|
|
|
{body ? body.props.children : null}
|
|
|
|
</BodyBox>
|
|
|
|
<Box>{footer ? footer.props.children : null}</Box>
|
|
|
|
</>
|
|
|
|
)}
|
2021-05-06 09:49:53 +00:00
|
|
|
</Content>
|
|
|
|
</Dialog>
|
|
|
|
</Backdrop>
|
|
|
|
) : (
|
|
|
|
<Box className={className} id={id} style={style}>
|
|
|
|
<Backdrop
|
|
|
|
visible={visible}
|
|
|
|
onClick={onClose}
|
|
|
|
zIndex={zIndex}
|
|
|
|
isAside={true}
|
|
|
|
/>
|
|
|
|
<Aside
|
|
|
|
visible={visible}
|
|
|
|
scale={scale}
|
|
|
|
zIndex={zIndex}
|
2021-07-30 11:18:11 +00:00
|
|
|
contentPaddingBottom={contentPaddingBottom}
|
2021-05-06 09:49:53 +00:00
|
|
|
className="modal-dialog-aside not-selectable"
|
2021-11-17 06:59:40 +00:00
|
|
|
withoutBodyScroll={removeScroll}
|
2021-05-06 09:49:53 +00:00
|
|
|
>
|
2021-07-30 11:18:11 +00:00
|
|
|
<Content
|
|
|
|
contentHeight={contentHeight}
|
|
|
|
contentWidth={contentWidth}
|
|
|
|
removeScroll={removeScroll}
|
2021-11-15 09:54:10 +00:00
|
|
|
displayType={this.state.displayType}
|
2021-07-30 11:18:11 +00:00
|
|
|
>
|
2021-06-30 07:23:49 +00:00
|
|
|
{isLoading ? (
|
2021-07-02 09:25:36 +00:00
|
|
|
<Loaders.DialogAsideLoader withoutAside />
|
2021-06-30 07:23:49 +00:00
|
|
|
) : (
|
|
|
|
<>
|
|
|
|
<StyledHeader className="modal-dialog-aside-header">
|
|
|
|
<Heading className="heading" size="medium" truncate={true}>
|
|
|
|
{header ? header.props.children : null}
|
|
|
|
</Heading>
|
|
|
|
{scale ? <CloseButton onClick={onClose}></CloseButton> : ""}
|
|
|
|
</StyledHeader>
|
|
|
|
<BodyBox
|
|
|
|
className="modal-dialog-aside-body"
|
2021-11-15 09:54:10 +00:00
|
|
|
paddingProp={asideBodyPadding}
|
2021-07-30 11:18:11 +00:00
|
|
|
removeScroll={removeScroll}
|
2021-06-30 07:23:49 +00:00
|
|
|
>
|
|
|
|
{body ? body.props.children : null}
|
|
|
|
</BodyBox>
|
|
|
|
<Box className="modal-dialog-aside-footer">
|
|
|
|
{footer ? footer.props.children : null}
|
|
|
|
</Box>
|
|
|
|
</>
|
|
|
|
)}
|
2021-05-06 09:49:53 +00:00
|
|
|
</Content>
|
|
|
|
</Aside>
|
|
|
|
</Box>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
const modalDialog = renderModal();
|
|
|
|
|
|
|
|
return <Portal element={modalDialog} />;
|
2019-10-01 12:50:56 +00:00
|
|
|
}
|
|
|
|
}
|
2019-06-27 12:47:32 +00:00
|
|
|
|
|
|
|
ModalDialog.propTypes = {
|
2020-09-09 18:49:25 +00:00
|
|
|
children: PropTypes.any,
|
2021-03-08 20:18:45 +00:00
|
|
|
/** Display dialog or not */
|
2019-07-11 15:02:48 +00:00
|
|
|
visible: PropTypes.bool,
|
2021-03-08 20:18:45 +00:00
|
|
|
/** Display type */
|
2019-10-01 12:50:56 +00:00
|
|
|
displayType: PropTypes.oneOf(["auto", "modal", "aside"]),
|
2021-03-08 20:18:45 +00:00
|
|
|
/** Indicates the side panel has scale */
|
2019-10-01 12:50:56 +00:00
|
|
|
scale: PropTypes.bool,
|
2021-03-08 20:18:45 +00:00
|
|
|
/** Will be triggered when a close button is clicked */
|
2019-10-02 07:23:58 +00:00
|
|
|
onClose: PropTypes.func,
|
2021-10-04 16:37:01 +00:00
|
|
|
onResize: PropTypes.func,
|
2022-03-02 13:33:02 +00:00
|
|
|
/**Display close button or not */
|
|
|
|
withoutCloseButton: PropTypes.bool,
|
2021-03-08 20:18:45 +00:00
|
|
|
/** CSS z-index */
|
2019-11-25 07:51:53 +00:00
|
|
|
zIndex: PropTypes.number,
|
2021-03-08 20:18:45 +00:00
|
|
|
/** CSS padding props for body section */
|
2021-11-15 09:54:10 +00:00
|
|
|
asideBodyPadding: PropTypes.string,
|
|
|
|
modalBodyPadding: PropTypes.string,
|
2020-09-15 19:29:14 +00:00
|
|
|
contentHeight: PropTypes.string,
|
|
|
|
contentWidth: PropTypes.string,
|
2021-06-30 07:23:49 +00:00
|
|
|
isLoading: PropTypes.bool,
|
2021-07-30 11:18:11 +00:00
|
|
|
removeScroll: PropTypes.bool,
|
2019-11-25 07:51:53 +00:00
|
|
|
className: PropTypes.string,
|
|
|
|
id: PropTypes.string,
|
2020-10-16 13:16:01 +00:00
|
|
|
style: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
|
2021-07-30 11:18:11 +00:00
|
|
|
contentPaddingBottom: PropTypes.string,
|
2021-11-15 09:54:10 +00:00
|
|
|
modalLoaderBodyHeight: PropTypes.string,
|
2019-10-01 12:50:56 +00:00
|
|
|
};
|
2019-09-13 14:02:56 +00:00
|
|
|
|
|
|
|
ModalDialog.defaultProps = {
|
2019-10-02 07:23:58 +00:00
|
|
|
displayType: "auto",
|
2020-07-20 07:37:23 +00:00
|
|
|
zIndex: 310,
|
2021-11-15 09:54:10 +00:00
|
|
|
asideBodyPadding: "16px 0",
|
|
|
|
modalBodyPadding: "12px 0",
|
2020-10-16 13:16:01 +00:00
|
|
|
contentWidth: "100%",
|
2022-03-02 13:33:02 +00:00
|
|
|
withoutCloseButton: false,
|
2019-10-01 12:50:56 +00:00
|
|
|
};
|
2019-06-27 12:47:32 +00:00
|
|
|
|
2020-09-09 18:49:25 +00:00
|
|
|
ModalDialog.Header = Header;
|
|
|
|
ModalDialog.Body = Body;
|
|
|
|
ModalDialog.Footer = Footer;
|
|
|
|
|
2019-10-01 12:50:56 +00:00
|
|
|
export default ModalDialog;
|