react-widget-popup
Version:
``` npm install --save react-widget-popup ```
258 lines (257 loc) • 11 kB
JavaScript
import React, { Fragment } from "react";
import { findDOMNode } from "react-dom";
import classnames from "classnames";
import TransitionGroupContext from "react-transition-group/TransitionGroupContext";
import Transition, { EXITED } from "react-transition-group/Transition";
import CSSTransition from "react-transition-group/CSSTransition";
export const version = "%VERSION%";
export class Popup extends React.Component {
constructor() {
super(...arguments);
this.transitionStatus = EXITED;
this.inTransition = false;
this.inMaskTransition = false;
this.refHandlers = {
root: (node) => (this.rootInstance = node),
popup: (node) => (this.popupInstance = node),
mask: (node) => (this.maskInstance = node),
};
this.addEndListener = (_, cb) => {
const transition = this.props.transition;
transition?.addEndListener?.(findDOMNode(this.popupInstance), cb);
};
}
getRootDOM() {
return findDOMNode(this.rootInstance);
}
getPopupDOM() {
return findDOMNode(this.popupInstance);
}
getMaskDOM() {
return findDOMNode(this.maskInstance);
}
shouldComponentUpdate(nextProps) {
return nextProps.forceRender || !(EXITED === this.transitionStatus && !nextProps.visible);
}
componentDidMount() {
const { lazy, visible, mask } = this.props;
const rootElement = findDOMNode(this.rootInstance);
const popupElement = findDOMNode(this.popupInstance);
const maskElement = findDOMNode(this.maskInstance);
if (!visible && !lazy) {
if (rootElement) {
rootElement.style.display = "none";
// @ts-ignore
rootElement.__popupHide = true;
}
if (popupElement) {
popupElement.style.display = "none";
// @ts-ignore
popupElement.__popupHide = true;
}
if (maskElement) {
maskElement.style.display = "none";
// @ts-ignore
maskElement.__popupHide = true;
}
}
if (visible && !mask) {
if (maskElement) {
maskElement.style.display = "none";
// @ts-ignore
maskElement.__popupHide = true;
}
}
}
onEnter({ onEnter }, isMask, node, appearing) {
const { getPosition } = this.props;
const rootElement = findDOMNode(this.rootInstance);
const popupElement = findDOMNode(this.popupInstance);
const maskElement = findDOMNode(this.maskInstance);
if (isMask) {
this.inMaskTransition = true;
}
else {
this.inTransition = true;
}
// if (!destroyOnClose) {
//@ts-ignore
if (rootElement && rootElement.__popupHide) {
rootElement.style.display = "";
//@ts-ignore
delete rootElement.__popupHide;
}
//@ts-ignore
if (!isMask && popupElement && popupElement.__popupHide) {
popupElement.style.display = "";
//@ts-ignore
delete popupElement.__popupHide;
}
//@ts-ignore
if (isMask && maskElement && maskElement.__popupHide) {
maskElement.style.display = "";
//@ts-ignore
delete maskElement.__popupHide;
}
// }
if (!isMask && getPosition) {
const pos = getPosition(node);
const transform = (v) => (typeof v === "number" ? `${v}px` : v);
if (pos) {
if ("left" in pos) {
node.style.left = transform(pos.left);
}
if ("top" in pos) {
node.style.top = transform(pos.top);
}
if ("right" in pos) {
node.style.right = transform(pos.right);
}
if ("bottom" in pos) {
node.style.bottom = transform(pos.bottom);
}
}
}
if (onEnter) {
onEnter(node, appearing);
}
}
onEntered({ onEntered }, isMask, node, appearing) {
if (isMask) {
this.inMaskTransition = false;
}
else {
this.inTransition = false;
}
if (onEntered) {
onEntered(node, appearing);
}
}
onExit({ onExit }, isMask, node) {
if (isMask) {
this.inMaskTransition = true;
}
else {
this.inTransition = true;
}
if (onExit) {
onExit(node);
}
}
onExited({ onExited }, isMask, node) {
const { destroyOnClose, visible } = this.props;
const rootElement = findDOMNode(this.rootInstance);
const popupElement = findDOMNode(this.popupInstance);
const maskElement = findDOMNode(this.maskInstance);
if (isMask) {
this.inMaskTransition = false;
}
else {
this.inTransition = false;
}
if (!destroyOnClose) {
if (!visible && !this.inMaskTransition && !this.inTransition && rootElement) {
rootElement.style.display = "none";
// @ts-ignore
rootElement.__popupHide = true;
}
if (!isMask && popupElement) {
popupElement.style.display = "none";
// @ts-ignore
popupElement.__popupHide = true;
}
if (isMask && maskElement) {
maskElement.style.display = "none";
// @ts-ignore
maskElement.__popupHide = true;
}
}
if (onExited) {
onExited(node);
}
}
renderPopupMask() {
const { prefixCls, visible, mask, maskProps, maskStyle, maskClassName, maskTransition, lazy, destroyOnClose, fixed, maskComponent, } = this.props;
const MaskComponent = maskComponent;
const classes = classnames({
[`${prefixCls}-mask`]: true,
[`${prefixCls}-mask-fixed`]: fixed,
}, maskProps.className, maskClassName);
const TransitionComponent = maskTransition.classNames ? CSSTransition : Transition;
return (React.createElement(TransitionComponent, Object.assign({ enter: true, exit: true, appear: true, addEndListener: (_, cb) => maskTransition.timeout == null && cb() }, maskTransition, { in: mask && visible, onEnter: this.onEnter.bind(this, maskTransition, true), onEntered: this.onEntered.bind(this, maskTransition, true), onExit: this.onExit.bind(this, maskTransition, true), onExited: this.onExited.bind(this, maskTransition, true), unmountOnExit: destroyOnClose, mountOnEnter: lazy }),
React.createElement(MaskComponent, Object.assign({}, maskProps, { ref: this.refHandlers.mask, style: {
...maskStyle,
...maskProps.style,
}, className: classes }))));
}
render() {
const { style, prefixCls, className, fixed, visible, children, lazy, destroyOnClose, rootClassName, rootStyle, rootProps, rootComponent, component, transition, wrapContent, disableMask, ...childProps } = this.props;
const RootComponent = rootComponent;
const Component = component;
delete childProps.mask;
delete childProps.maskProps;
delete childProps.maskStyle;
delete childProps.maskClassName;
delete childProps.maskComponent;
delete childProps.maskTransition;
delete childProps.getPosition;
delete childProps.forceRender;
let rootComponentProps = {
...rootProps,
className: classnames(`${prefixCls}-root`, rootClassName, rootProps.className),
style: {
...rootStyle,
...rootProps.style,
},
};
if (RootComponent === Fragment) {
rootComponentProps = {};
}
const classes = classnames(prefixCls, {
[`${prefixCls}-fixed`]: fixed,
}, className);
const TransitionComponent = transition.classNames ? CSSTransition : Transition;
const popup = (React.createElement(RootComponent, Object.assign({}, rootComponentProps, { ref: this.refHandlers.root }),
!disableMask && this.renderPopupMask(),
wrapContent(React.createElement(TransitionComponent, Object.assign({ enter: true, exit: true, appear: true, addEndListener: (_, cb) => transition.timeout == null && cb() }, transition, { in: visible, onEnter: this.onEnter.bind(this, transition, false), onEntered: this.onEntered.bind(this, transition, false), onExit: this.onExit.bind(this, transition, false), onExited: this.onExited.bind(this, transition, false), unmountOnExit: destroyOnClose, mountOnEnter: lazy }), (status) => {
this.transitionStatus = status;
return (React.createElement(Component, Object.assign({}, childProps, { ref: this.refHandlers.popup, style: style, className: classes }), typeof children === "function" ? children(status) : children));
}))));
return (React.createElement(TransitionGroupContext.Provider, { value: null },
React.createElement(Transition, { enter: true, exit: true, appear: true, addEndListener: transition.addEndListener ? this.addEndListener : undefined, timeout: transition.timeout, in: visible, unmountOnExit: destroyOnClose, mountOnEnter: lazy }, () => popup)));
}
}
Popup.defaultProps = {
prefixCls: "rw-popup",
style: {},
className: "",
rootClassName: "",
rootStyle: {},
rootProps: {},
visible: false,
fixed: false,
//初始未显示的情况下不渲染组件,作用同react-transition-group的mountOnEnter
lazy: true,
//当destroyOnClose=false时,visible=false的情况下也会刷新组件
forceRender: false,
//popup动画配置参数参考react-transition-group
//http://reactcommunity.org/react-transition-group/css-transition
transition: {},
//visible=false时移除组件,作用同react-transition-group的unmountOnExit
destroyOnClose: true,
disableMask: false,
mask: false,
maskStyle: {},
maskProps: {},
maskClassName: "",
//popupMask动画配置参数参考react-transition-group
//http://reactcommunity.org/react-transition-group/css-transition
maskTransition: {},
component: "div",
maskComponent: "div",
rootComponent: "div",
wrapContent: (node) => {
return node;
},
};
export default Popup;