UNPKG

react-widget-popup

Version:

``` npm install --save react-widget-popup ```

258 lines (257 loc) 11 kB
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;