UNPKG

@zohodesk/popups

Version:

popups popupover modal dialog alert notifications popup handling for whole app

257 lines (218 loc) 8.33 kB
function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } import React from 'react'; import ReactDOM from 'react-dom'; import hoistStatics from 'hoist-non-react-statics'; import viewPort from '../ViewPort'; let popups = {}; const closeGroupPopups = function () { let groupName = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'global'; let groupPopups = popups[groupName] || []; groupPopups.forEach(popup => { popup.state.isPopupOpen && resetPopupState(popup); }); }; const resetPopupState = popup => { popup.setState({ isPopupOpen: false, isPopupReady: false, position: 'bottom' }); }; const resetAllPopupState = (popup, filterGroupName) => { Object.keys(popups).forEach(closeGroupPopups); }; const Popup = function (Component) { let group = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'global'; let customStyles = arguments.length > 2 ? arguments[2] : undefined; const popupStyles = Object.assign({}, customStyles); group = group || 'global'; class Popup extends React.Component { constructor(props) { super(props); this.state = { isPopupOpen: props.isPopupOpen || false, isPopupReady: props.isPopupReady || false, position: props.position || 'bottom', fixedPosition: {} }; this.popupGroup = props.group || group; this.childGroup = props.childGroup; this.stopCloseEvent = this.stopCloseEvent.bind(this); this.documentKeyupHandler = this.documentKeyupHandler.bind(this); this.documentClickHandler = this.documentClickHandler.bind(this); this.togglePopup = this.togglePopup.bind(this); this.openPopupOnly = this.openPopupOnly.bind(this); this.closePopupOnly = this.closePopupOnly.bind(this); this.setRef = this.setRef.bind(this); //this.popupName = popupName; } setRef(el) { this.elementRef = el; } UNSAFE_componentWillReceiveProps(nextProps) { let state = null; if (typeof nextProps.isPopupOpen !== "undefined" && nextProps.isPopupOpen !== this.state.isPopupOpen) { state = state || {}; state.isPopupOpen = nextProps.isPopupOpen; } if (typeof nextProps.isPopupReady !== "undefined" && nextProps.isPopupReady !== this.state.isPopupReady) { state = state || {}; state.isPopupReady = nextProps.isPopupReady; } if (typeof nextProps.position !== "undefined" && nextProps.position !== this.state.position) { state = state || {}; state.position = nextProps.position; } if (state) { this.setState(state); } } componentDidMount() { let groupPopups = popups[this.popupGroup] || []; groupPopups.push(this); popups[this.popupGroup] = groupPopups; if (groupPopups.length == 1) { global.document.addEventListener('click', this.documentClickHandler, false); global.document.addEventListener('keyup', this.documentKeyupHandler, false); } } componentWillUnmount() { popups = Object.keys(popups).reduce((res, groupName) => { if (groupName == this.popupGroup) { let groupPopups = popups[this.popupGroup]; let newGroupPopups = groupPopups.filter(popup => { return popup !== this; }); res[this.popupGroup] = newGroupPopups; } return res; }, popups); if (popups.length == 0) { global.document.removeEventListener('click', this.documentClickHandler); global.document.removeEventListener('keyup', this.documentKeyupHandler); } } togglePopup(e, dropElement, placeHoldeEl, isPopupOpen) { this.stopCloseEvent(e); //Close the all other opes let groupPopups = popups[this.popupGroup]; groupPopups.forEach(popup => { if (popup != this) { popup.state.isPopupOpen && popup.setState({ isPopupOpen: false, position: 'bottom' }); } }); this.setState({ isPopupOpen: isPopupOpen ? isPopupOpen : !this.state.isPopupOpen, isPopupReady: false, position: 'bottom' }, () => { if (!dropElement || !placeHoldeEl) { return; } ; requestAnimationFrame(() => { var frame = this.props.frameId ? document.getElementById(this.props.frameId) : document.getElementById("container"); let defaultPosition = this.props.defaultPosition || "bottom"; let betterPosition = viewPort.betterView(dropElement, placeHoldeEl, defaultPosition, frame); //Auto predict views if (betterPosition.view) { this.setState({ isPopupReady: true, position: betterPosition.view, fixedPosition: betterPosition.fixedPosition }); } else { this.setState({ isPopupReady: true, position: 'bottom' }); } }); }); } openPopupOnly(e, dropElement, placeHoldeEl) { this.togglePopup(e, dropElement, placeHoldeEl, true); /*this.stopCloseEvent(e); let groupPopups = popups[this.popupGroup]; groupPopups.forEach(popup => { if (popup != this) { popup.state.isPopupOpen && popup.setState({ isPopupOpen: false, position: 'bottom' }); } }); this.setState({ isPopupOpen: true , isPopupReady : false , position: 'bottom' },()=>{ if( !dropElement || !placeHoldeEl ){ return; }; requestAnimationFrame(()=>{ var frame = this.props.frameId ? document.getElementById(this.props.frameId) : document.getElementById("container"); let defaultPosition = this.props.defaultPosition || "bottomCenter"; let betterPosition = viewPort.betterView( dropElement , placeHoldeEl , defaultPosition , frame); //Auto predict views if( betterPosition.view ) { this.setState({ isPopupReady : true , position: betterPosition.view }); }else{ this.setState({ isPopupReady : true , position: defaultPosition }); } }) });*/ } closePopupOnly(e) { this.stopCloseEvent(e); resetPopupState(this); } documentClickHandler(e) { try { resetAllPopupState(); } catch (e) { console.error('error', e); } } documentKeyupHandler(e) { try { if (e.keyCode == 27) { resetAllPopupState(); } } catch (e) { console.log('error', e); } } stopCloseEvent(e) { e.stopPropagation && e.stopPropagation(); e.nativeEvent && e.nativeEvent.stopImmediatePropagation && e.nativeEvent.stopImmediatePropagation(); if (this.childGroup) { closeGroupPopups(this.childGroup); } } render() { let { position, isPopupOpen, isPopupReady } = this.state; let positionStyle = position ? popupStyles[position] || '' : ''; let arrowStyle = `${popupStyles.arrow} ${positionStyle}`; let popupOpenStyle = isPopupOpen ? `${popupStyles.isOpen} ${positionStyle}` : `${popupStyles.isHide}`; let popupReadyStyle = isPopupReady ? `${popupStyles.isReady}` : ''; let contentStyle = `${popupStyles.content} ${popupOpenStyle} ${popupReadyStyle}`; return /*#__PURE__*/React.createElement(Component, _extends({ ref: this.setRef }, this.props, this.state, { openPopupOnly: this.openPopupOnly, closePopupOnly: this.closePopupOnly, togglePopup: this.togglePopup, isPopupOpen: this.state.isPopupOpen, removeClose: this.stopCloseEvent, popupStyle: { arrow: arrowStyle, content: contentStyle }, popupStyles: popupStyles })); } } return hoistStatics(Popup, Component); }; export default Popup; export { closeGroupPopups };