UNPKG

@shakthillc/components

Version:

React generic components for shakthi products

268 lines (241 loc) 8.23 kB
/**** Libraries ****/ import React from "react"; import hoistStatics from "hoist-non-react-statics"; /**** Methods ****/ import viewPort from "./viewPort"; let lastOpenedGroup = []; let popups = {}; global.closeGroupPopups = function (groupName) { let groupPopups = popups[groupName] || []; groupPopups.forEach((popup) => { popup.state.isPopupOpen && popup.setState({ isPopupOpen: false, isPopupReady: false }); }); }; /* eslint-disable react/no-deprecated */ /* eslint-disable react/prop-types */ let Popup = function (Component, group = "global", needResizeHandling = true) { class Popup extends React.Component { constructor(props) { super(props); this.state = { isPopupOpen: props.isPopupOpen || false, position: "bottomCenter", height: "0px", isPopupReady: props.isPopupOpen || false, adjustments: {} }; this.togglePopup = this.togglePopup.bind(this); this.documentClickHandler = this.documentClickHandler.bind(this); this.removeClose = this.removeClose.bind(this); this.documentKeyupHandler = this.documentKeyupHandler.bind(this); this.openPopupOnly = this.openPopupOnly.bind(this); this.closePopupOnly = this.closePopupOnly.bind(this); this.getTargetRef = this.getTargetRef.bind(this); this.getContainerRef = this.getContainerRef.bind(this); this.handlePopupPosition = this.handlePopupPosition.bind(this); this.size = null; } componentDidMount() { let group = this.getGroup(); let groupPopups = popups[group] || []; groupPopups.push(this); popups[group] = groupPopups; if (Object.keys(popups).length === 1 && groupPopups.length === 1) { document.addEventListener("click", this.documentClickHandler, false); document.addEventListener("keyup", this.documentKeyupHandler, false); } } componentWillReceiveProps(nextProps) { let { isPopupOpen } = this.state; if ( typeof nextProps.isPopupOpen !== "undefined" && nextProps.isPopupOpen !== isPopupOpen ) { this.setState({ isPopupOpen: nextProps.isPopupOpen }); } } componentWillUnmount() { let group = this.getGroup(); popups = Object.keys(popups).reduce((res, groupName) => { if (groupName === group) { let groupPopups = popups[group]; let newGroupPopups = groupPopups.filter((popup) => popup !== this); newGroupPopups.length === 0 && lastOpenedGroup.indexOf(group) >= 0 && lastOpenedGroup.splice(lastOpenedGroup.indexOf(group), 1); res[group] = newGroupPopups; } return res; }, popups); let noPopups = true; for (let i in popups) { if (popups[i].length >= 1) { noPopups = false; break; } } if (noPopups) { document.removeEventListener("click", this.documentClickHandler); document.removeEventListener("keyup", this.documentKeyupHandler); } } getGroup() { let { popupGroup } = this.props; return popupGroup || group; } togglePopup(e, defaultPosition) { let group = this.getGroup(); this.removeClose(e); let { isPopupOpen } = this.state; let groupPopups = popups[group]; lastOpenedGroup = !isPopupOpen && lastOpenedGroup.indexOf(group) === -1 ? [group, ...lastOpenedGroup] : lastOpenedGroup; isPopupOpen && lastOpenedGroup.splice(0, 1); groupPopups.forEach((popup) => { if (popup !== this && popup.state.isPopupOpen) { popup.setState({ isPopupOpen: false, isPopupReady: false }); } }); if (isPopupOpen) { this.setState({ isPopupOpen: false, isPopupReady: false }); } else { this.handlePopupPosition(defaultPosition); } } openPopupOnly(e, defaultPosition) { let group = this.getGroup(); this.removeClose(e); lastOpenedGroup = lastOpenedGroup.indexOf(group) === -1 ? [group, ...lastOpenedGroup] : lastOpenedGroup; this.handlePopupPosition(defaultPosition); } closePopupOnly(e) { this.removeClose(e); lastOpenedGroup.splice(0, 1); let { isPopupOpen } = this.state; if (isPopupOpen) { this.setState({ isPopupOpen: false, isPopupReady: false }); } } documentClickHandler() { try { Object.keys(popups).forEach((groupName) => { let groupPopups = popups[groupName]; groupPopups.forEach((popup) => { popup.state.isPopupOpen && (!popup.props.checkBeforeClose || (popup.props.checkBeforeClose && popup.props.checkBeforeClose())) && popup.setState({ isPopupOpen: false, isPopupReady: false }); }); }); lastOpenedGroup = []; } catch (e) { // eslint-disable-next-line no-console //console.error('popup component not unmounted properly', e); } } documentKeyupHandler(e) { try { if (e.keyCode === 27) { let groupPopups = lastOpenedGroup.length ? popups[lastOpenedGroup[0]] : []; lastOpenedGroup.splice(0, 1); groupPopups.forEach((popup) => { popup.state.isPopupOpen && popup.setState({ isPopupOpen: false, isPopupReady: false }); }); } } catch (e) { // eslint-disable-next-line no-console //console.log('error', e); } } removeClose(e) { e && e.stopPropagation && e.stopPropagation(); e && e.nativeEvent && e.nativeEvent.stopImmediatePropagation && e.nativeEvent.stopImmediatePropagation(); } handlePopupPosition(defaultPosition = "bottomCenter", isResizeHandling) { // isResizeHandling --->>> Window resize and dropBox resize let { placeHolderElement, dropElement } = this; if (!placeHolderElement && !dropElement) { this.setState({ isPopupOpen: true, isPopupReady: true }); return; } let setPosition = () => { requestAnimationFrame(() => { let { placeHolderElement, dropElement } = this; let { position, isPopupReady } = this.state; let scrollContainer = placeHolderElement.closest("[data-scroll=true]") || document.body; let betterPosition = viewPort.betterView( dropElement, placeHolderElement, defaultPosition, scrollContainer ); let { view, adjustments } = betterPosition || {}; if (position !== view || !isPopupReady) { this.setState({ isPopupReady: true, position: view, adjustments }); } }); }; if (isResizeHandling) { setPosition(); } else { this.defaultPosition = defaultPosition; this.setState( { isPopupOpen: true, isPopupReady: false }, setPosition ); } } getTargetRef(el) { this.placeHolderElement = el; } getContainerRef(el) { this.dropElement = el; } render() { return ( <Component {...this.props} {...this.state} openPopupOnly={this.openPopupOnly} closePopupOnly={this.closePopupOnly} togglePopup={this.togglePopup} removeClose={this.removeClose} getTargetRef={this.getTargetRef} getContainerRef={this.getContainerRef} /> ); } } Popup.displayName = Component.displayName || Component.name || Popup.name; return hoistStatics(Popup, Component); }; export default Popup;