@shakthillc/components
Version:
React generic components for shakthi products
268 lines (241 loc) • 8.23 kB
JavaScript
/**** 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;