@zohodesk/popups
Version:
popups popupover modal dialog alert notifications popup handling for whole app
334 lines (293 loc) • 11.7 kB
JavaScript
let viewPort = {
frameRelativeRects: (el, customFrame) => {
if (!el) {
return;
}
var rect = el.getBoundingClientRect(); //Target Element
let documentEle = document.documentElement; //Body&HTML
var customFrameRect = {
top: 0,
left: 0,
right: documentEle.clientWidth,
bottom: documentEle.clientHeight,
height: documentEle.clientHeight,
width: documentEle.clientWidth,
x: 0,
y: 0
};
if (customFrame) {
customFrameRect = customFrame.getBoundingClientRect();
}
let newReact = {
top: rect.top - customFrameRect.top,
left: rect.left - customFrameRect.left,
height: rect.height,
width: rect.width
};
newReact.bottom = newReact.top + newReact.height;
newReact.right = newReact.left + newReact.width;
newReact.x = newReact.left;
newReact.y = newReact.top;
let rectGap = {
top: newReact.top,
left: newReact.left,
bottom: customFrameRect.height - newReact.bottom,
right: customFrameRect.width - newReact.right
};
rectGap.center = {
top: rectGap.top + newReact.height / 2,
left: rectGap.left + newReact.width / 2,
bottom: rectGap.bottom + newReact.height / 2,
right: rectGap.right + newReact.width / 2
};
let adjustments = {};
if (newReact.top < 0) {
adjustments.top = Math.abs(newReact.top);
}
if (newReact.left < 0) {
adjustments.left = Math.abs(newReact.left);
}
if (newReact.bottom > customFrameRect.height) {
adjustments.bottom = newReact.bottom - customFrameRect.height;
}
if (newReact.right > customFrameRect.width) {
adjustments.right = newReact.right - customFrameRect.width;
}
return {
frameRect: customFrameRect,
rect: newReact,
rectGap,
adjustments
};
},
isInViewPort: (el, customFrame) => {
if (!el) {
return;
}
let elRects = viewPort.frameRelativeRects(el, customFrame);
let react = elRects.rect;
let frameReact = elRects.frameRect;
return rect.top >= 0 && rect.left >= 0 && rect.bottom <= frameReact.height && rect.right <= frameReact.width;
},
possibilities: (el, relativeBox, customFrame) => {
if (!el) {
return;
}
let elRects = viewPort.frameRelativeRects(el, customFrame);
let rect = elRects.rect;
let adjustments = elRects.adjustments;
let relativeBoxReacts = viewPort.frameRelativeRects(relativeBox, customFrame);
let relativeBoxRect = relativeBoxReacts.rect;
let relativeBoxGap = relativeBoxReacts.rectGap;
let relativeBoxDocumentRects = viewPort.frameRelativeRects(relativeBox, customFrame);
let {
rectGap: documentGap
} = relativeBoxDocumentRects;
adjustments.left ? adjustments.left = adjustments.left + relativeBoxReacts.rect.width * 2 / 3 : null;
adjustments.right ? adjustments.right = adjustments.right + relativeBoxReacts.rect.width * 2 / 3 : null;
adjustments.top ? adjustments.top = adjustments.top + relativeBoxReacts.rect.width * 2 / 3 : null;
adjustments.bottom ? adjustments.bottom = adjustments.bottom + relativeBoxReacts.rect.width * 2 / 3 : null;
let views = {}; //bottomCenter
let bottomOverFlow = rect.height >= relativeBoxGap.bottom;
let bottomRightOverFlow = rect.width / 2 >= relativeBoxGap.center.right;
let bottomLeftOverFlow = rect.width / 2 >= relativeBoxGap.center.left; //bottomRight
let bottomLeftOnlyOverFlow = rect.width >= relativeBoxGap.center.left;
views.bottomRight = !(bottomOverFlow || bottomLeftOnlyOverFlow); //bottomLeft
let bottomRightOnlyOverFlow = rect.width >= relativeBoxGap.center.right;
views.bottomLeft = !(bottomOverFlow || bottomRightOnlyOverFlow);
views.bottomCenter = !(bottomOverFlow || bottomRightOverFlow || bottomLeftOverFlow); //topCenter
let topOverFlow = rect.height >= relativeBoxGap.top;
let topRightOverFlow = rect.width / 2 >= relativeBoxGap.center.right;
let topLeftOverFlow = rect.width / 2 >= relativeBoxGap.center.left; //topRight
let topLeftOnlyOverFlow = rect.width >= relativeBoxGap.center.left;
views.topRight = !(topOverFlow || topLeftOnlyOverFlow); //topLeft
let topRightOnlyOverFlow = rect.width >= relativeBoxGap.center.right;
views.topLeft = !(topOverFlow || topRightOnlyOverFlow);
views.topCenter = !(topOverFlow || topRightOverFlow || topLeftOverFlow); //|| topLeftOnlyOverFlow || topRightOnlyOverFlow);
//leftCenter
let leftOverFlow = rect.width >= relativeBoxGap.left;
let leftTopOverFlow = rect.height / 2 >= relativeBoxGap.center.top;
let leftBottomOverFlow = rect.height / 2 >= relativeBoxGap.center.bottom; //leftTop
let leftTopOnlyOverFlow = rect.height >= relativeBoxGap.center.bottom;
views.leftTop = !(leftOverFlow || leftTopOnlyOverFlow); //leftBottom
let leftBottomOnlyOverFlow = rect.height >= relativeBoxGap.center.top;
views.leftBottom = !(leftOverFlow || leftBottomOnlyOverFlow);
views.leftCenter = !(leftOverFlow || leftTopOverFlow || leftBottomOverFlow); // || leftTopOnlyOverFlow || leftBottomOnlyOverFlow);
//rightCenter
let rightOverFlow = rect.width >= relativeBoxGap.right;
let rightTopOverFlow = rect.height / 2 >= relativeBoxGap.center.top;
let rightBottomOverFlow = rect.height / 2 >= relativeBoxGap.center.bottom; //rightTop
let rightTopOnlyOverFlow = rect.height >= relativeBoxGap.center.bottom;
views.rightTop = !(rightOverFlow || rightTopOnlyOverFlow); //rightBottom
let rightBottomOnlyOverFlow = rect.height >= relativeBoxGap.center.top;
views.rightBottom = !(rightOverFlow || rightBottomOnlyOverFlow);
views.rightCenter = !(rightOverFlow || rightTopOverFlow || rightBottomOverFlow); // || rightTopOnlyOverFlow || rightBottomOnlyOverFlow);
let horizontalCenter = relativeBoxGap.left + relativeBoxRect.width / 2;
let horizontalLeft = relativeBoxGap.left;
let horizontalRight = relativeBoxGap.left + relativeBoxRect.width;
let verticalBottom = relativeBoxGap.top + relativeBoxRect.height;
let verticalTop = relativeBoxGap.top;
let verticalCenter = relativeBoxGap.top + relativeBoxRect.height / 2;
let horizontalTop = documentGap.bottom + relativeBoxRect.height;
let needArrow = false;
let paddingSpace = 5; // space between target and relative element
let arrowSize = needArrow ? 10 : 5;
rect.height = rect.height + (needArrow ? arrowSize : paddingSpace);
rect.width = rect.width + (needArrow ? arrowSize : paddingSpace);
let viewsOffset = {
// Code Copy frm DOT ViewPort.js qa
bottomCenter: {
left: horizontalCenter - rect.width / 2,
top: verticalBottom + arrowSize
},
bottomRight: {
left: horizontalRight - rect.width,
top: verticalBottom + arrowSize
},
bottomLeft: {
left: horizontalLeft,
top: verticalBottom + arrowSize
},
topCenter: {
left: horizontalCenter - rect.width / 2,
bottom: horizontalTop + arrowSize
},
topRight: {
left: horizontalRight - rect.width,
bottom: horizontalTop + arrowSize
},
topLeft: {
left: horizontalLeft,
bottom: horizontalTop + arrowSize
},
rightCenter: {
left: horizontalRight + arrowSize,
top: verticalCenter - rect.height / 2
},
rightBottom: {
left: horizontalRight + arrowSize,
bottom: documentGap.bottom
},
rightTop: {
left: horizontalRight + arrowSize,
top: verticalTop
},
leftCenter: {
left: horizontalLeft - (rect.width + arrowSize),
top: verticalCenter - rect.height / 2
},
leftTop: {
left: horizontalLeft - (rect.width + arrowSize),
top: verticalTop
},
leftBottom: {
left: horizontalLeft - (rect.width + arrowSize),
bottom: documentGap.bottom
}
};
return {
views,
adjustments,
positionOffset: viewsOffset
};
},
getArrowAdjustments: (el, relativeBox, customFrame) => {
if (!el) {
return;
}
let elRects = viewPort.frameRelativeRects(el, customFrame);
let rect = elRects.rect;
let rectGap = elRects.rectGap;
let adjustments = elRects.adjustments;
let relativeBoxReacts = viewPort.frameRelativeRects(relativeBox, customFrame);
let relativeBoxReact = relativeBoxReacts.rect;
let relativeBoxGap = relativeBoxReacts.rectGap;
return {
left: relativeBoxGap.center.left - rectGap.left,
right: relativeBoxGap.center.right - rectGap.right,
top: relativeBoxGap.center.top - rectGap.top,
bottom: relativeBoxGap.center.bottom - rectGap.bottom
};
},
betterView: (popup, relativeBox, defaultView, customFrame) => {
let viewPortPossibilities = viewPort.possibilities(popup, relativeBox, customFrame);
if (!viewPortPossibilities) {
return;
}
let views = viewPortPossibilities.views;
let adjustments = viewPortPossibilities.adjustments;
let viewKeys = Object.keys(views);
let isViewFound = false;
let positionOffset = viewPortPossibilities.positionOffset;
for (let i = 0; i < viewKeys.length; i++) {
let viewKey = viewKeys[i];
if (views[viewKey]) {
isViewFound = true;
break;
}
}
if (!isViewFound) {
return {
view: null,
adjustments,
fixedPosition: {}
};
}
if (views[defaultView]) {
return {
view: defaultView,
adjustments,
fixedPosition: positionOffset[defaultView]
};
}
let defaultPosition = defaultView.replace(/Center|Bottom|Top|Left|Right$/, '');
let viewTypes = {
top: ['Center', 'Right', 'Left'],
left: ['Center', 'Top', 'Bottom']
};
viewTypes.bottom = viewTypes.top;
viewTypes.right = viewTypes.left;
let defaultPositions = viewTypes[defaultPosition];
for (let i = 0, len = defaultPositions.length; i < len; i++) {
let viewKey = defaultPosition + defaultPositions[i];
if (views[viewKey]) {
return {
view: viewKey,
adjustments,
fixedPosition: positionOffset[viewKey]
};
}
}
let oppositePositionsOrder = {
bottom: ['top', 'right', 'left'],
top: ['bottom', 'right', 'left'],
left: ['bottom', 'right', 'top'],
right: ['bottom', 'top', 'left']
};
let oppositeViews = oppositePositionsOrder[defaultPosition];
for (let i = 0, len = oppositeViews.length; i < len; i++) {
let oppositeView = oppositeViews[i];
let positions = viewTypes[oppositeView];
for (let j = 0, lenx = positions.length; j < lenx; j++) {
let viewKey = oppositeView + positions[j];
if (views[viewKey]) {
return {
view: viewKey,
adjustments,
fixedPosition: positionOffset[viewKey]
};
}
}
}
return {
view: null,
adjustments,
fixedPosition: {}
};
}
};
export default {
betterView: viewPort.betterView,
frameRelativeRects: viewPort.frameRelativeRects,
getArrowAdjustments: viewPort.getArrowAdjustments
};