@zohodesk/components
Version:
In this Package, we Provide Some Basic Components to Build Web App
374 lines (359 loc) • 14.3 kB
JavaScript
const defaultOrder = ['bottomCenter', 'bottomLeftToRight', 'bottomCenterToRight', 'bottomRightToLeft', 'bottomCenterToLeft', 'topCenter', 'topLeftToRight', 'topCenterToRight', 'topRightToLeft', 'topCenterToLeft', 'rightTopToBottom', 'rightCenterToBottom', 'rightCenter', 'rightBottomToTop', 'rightCenterToTop', 'leftTopToBottom', 'leftCenterToBottom', 'leftCenter', 'leftBottomToTop', 'leftCenterToTop', 'bottomRight', 'bottomLeft', 'topRight', 'topLeft', 'rightBottom', 'rightTop', 'leftBottom', 'leftTop'];
let viewPort = {
frameRelativeRects: (el, customFrame, documentEle) => {
if (!el) {
return;
}
let rectTemp = el.getBoundingClientRect();
let rect = {
height: rectTemp.height || el.clientHeight,
width: rectTemp.width || el.clientWidth,
top: rectTemp.top,
bottom: rectTemp.bottom,
left: rectTemp.left,
right: rectTemp.right,
x: rectTemp.x,
y: rectTemp.y
};
documentEle = documentEle ? documentEle : document.documentElement;
let 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 newRect = {
top: rect.top - customFrameRect.top,
left: rect.left - customFrameRect.left,
height: rect.height,
width: rect.width
};
newRect.bottom = newRect.top + newRect.height;
newRect.right = newRect.left + newRect.width;
newRect.x = newRect.left;
newRect.y = newRect.top;
let rectGap = {
top: newRect.top,
left: newRect.left,
bottom: customFrameRect.height - newRect.bottom,
right: customFrameRect.width - newRect.right
};
rectGap.center = {
top: rectGap.top + newRect.height / 2,
left: rectGap.left + newRect.width / 2,
bottom: rectGap.bottom + newRect.height / 2,
right: rectGap.right + newRect.width / 2
};
return {
frameRect: customFrameRect,
rect: newRect,
rectGap
};
},
isInViewPort: (el, customFrame) => {
if (!el) {
return;
}
let elRects = viewPort.frameRelativeRects(el, customFrame);
let {
rect
} = elRects;
let {
frameRect
} = elRects;
return rect.top >= 0 && rect.left >= 0 && rect.bottom <= frameRect.height && rect.right <= frameRect.width;
},
getViewPortEle: el => {
return el.closest('[data-viewport-container=true]') ? el.closest('[data-viewport-container=true]') : document.documentElement;
},
possibilities: function (el, relativeBox, customFrame) {
let {
needArrow,
isAbsolute
} = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
if (!el) {
return;
}
let elViewPortEle = viewPort.getViewPortEle(el);
let elRects = viewPort.frameRelativeRects(el, customFrame, elViewPortEle);
let {
rect
} = elRects;
let relativeBoxViewPortEle = viewPort.getViewPortEle(relativeBox);
let relativeBoxRects = viewPort.frameRelativeRects(relativeBox, customFrame, relativeBoxViewPortEle);
let {
rectGap: relativeBoxGap,
rect: relativeBoxRect
} = relativeBoxRects;
let relativeBoxDocumentRects = viewPort.frameRelativeRects(relativeBox, customFrame);
let {
rectGap: documentGap
} = relativeBoxDocumentRects; //rect => PopOverContainer, relativeBoxGap => PopOverTarget
//Horizontal ~ ----- X axis
//Vertical ~ ||||||| Y axis
let paddingSpace = 5; // space between target and relative element
let arrowSize = needArrow ? 10 : 0;
rect.height = rect.height + (needArrow ? arrowSize : paddingSpace);
rect.width = rect.width + (needArrow ? arrowSize : paddingSpace);
let arrowHorizontalBalancePx = !isAbsolute && needArrow ? 30 : 0;
let arrowVerticalBalancePx = !isAbsolute && needArrow ? 27 : 0;
let bottomOverFlow = rect.height > relativeBoxGap.bottom;
let topOverFlow = rect.height > relativeBoxGap.top;
let rightOverFlow = rect.width > relativeBoxGap.right;
let leftOverFlow = rect.width > relativeBoxGap.left;
let horizontalCenterOverFlow = rect.width / 2 > relativeBoxGap.center.right || rect.width / 2 > relativeBoxGap.center.left;
let verticalCenterOverFlow = rect.height / 2 > relativeBoxGap.center.top || rect.height / 2 > relativeBoxGap.center.bottom;
let horizontalLeftToRightOverFlow = rect.width > relativeBoxRect.width + relativeBoxGap.right;
let horizontalCenterToRightOverFlow = rect.width > relativeBoxGap.center.right || arrowHorizontalBalancePx > relativeBoxGap.center.left;
let horizontalRightToLeft = rect.width > relativeBoxRect.width + relativeBoxGap.left;
let horizontalCenterToLeft = rect.width > relativeBoxGap.center.left || arrowHorizontalBalancePx > relativeBoxGap.center.right;
let verticalTopToBottomOverFlow = rect.height > relativeBoxRect.height + relativeBoxGap.bottom;
let verticalCenterToBottomOverFlow = rect.height > relativeBoxGap.center.bottom || arrowVerticalBalancePx > relativeBoxGap.center.top;
let verticalBottomToTopOverFlow = rect.height > relativeBoxRect.height + relativeBoxGap.top;
let verticalCenterToTopOverFlow = rect.height > relativeBoxGap.center.top || arrowVerticalBalancePx > relativeBoxGap.center.bottom;
let views = {
bottomCenter: !(bottomOverFlow || horizontalCenterOverFlow),
bottomLeftToRight: !(bottomOverFlow || horizontalLeftToRightOverFlow),
bottomCenterToRight: !(bottomOverFlow || horizontalCenterToRightOverFlow),
bottomRight: !(bottomOverFlow || rightOverFlow || arrowHorizontalBalancePx > relativeBoxRect.right),
bottomRightToLeft: !(bottomOverFlow || horizontalRightToLeft),
bottomCenterToLeft: !(bottomOverFlow || horizontalCenterToLeft),
bottomLeft: !(bottomOverFlow || leftOverFlow || arrowHorizontalBalancePx > relativeBoxGap.right + relativeBoxRect.width),
topCenter: !(topOverFlow || horizontalCenterOverFlow),
topLeftToRight: !(topOverFlow || horizontalLeftToRightOverFlow),
topCenterToRight: !(topOverFlow || horizontalCenterToRightOverFlow),
topRight: !(topOverFlow || rightOverFlow || arrowHorizontalBalancePx > relativeBoxRect.right),
topRightToLeft: !(topOverFlow || horizontalRightToLeft),
topCenterToLeft: !(topOverFlow || horizontalCenterToLeft),
topLeft: !(topOverFlow || leftOverFlow || arrowHorizontalBalancePx > relativeBoxGap.right + relativeBoxRect.width),
rightCenter: !(rightOverFlow || verticalCenterOverFlow),
rightTopToBottom: !(rightOverFlow || verticalTopToBottomOverFlow),
rightCenterToBottom: !(rightOverFlow || verticalCenterToBottomOverFlow),
rightBottom: !(rightOverFlow || bottomOverFlow || arrowVerticalBalancePx > relativeBoxRect.bottom),
rightBottomToTop: !(rightOverFlow || verticalBottomToTopOverFlow),
rightCenterToTop: !(rightOverFlow || verticalCenterToTopOverFlow),
rightTop: !(rightOverFlow || topOverFlow || arrowVerticalBalancePx > relativeBoxGap.bottom + relativeBoxRect.height),
leftCenter: !(leftOverFlow || verticalCenterOverFlow),
leftTopToBottom: !(leftOverFlow || verticalTopToBottomOverFlow),
leftCenterToBottom: !(leftOverFlow || verticalCenterToBottomOverFlow),
leftBottom: !(leftOverFlow || bottomOverFlow || arrowVerticalBalancePx > relativeBoxRect.bottom),
leftBottomToTop: !(leftOverFlow || verticalBottomToTopOverFlow),
leftCenterToTop: !(leftOverFlow || verticalCenterToTopOverFlow),
leftTop: !(leftOverFlow || topOverFlow || arrowVerticalBalancePx > relativeBoxGap.bottom + relativeBoxRect.height)
};
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 verticalCenterToTop = documentGap.bottom + relativeBoxRect.height / 2;
let viewsOffset = {
bottomCenter: {
left: horizontalCenter - rect.width / 2,
top: verticalBottom + arrowSize
},
bottomLeftToRight: {
left: horizontalLeft,
top: verticalBottom + arrowSize
},
bottomCenterToRight: {
left: horizontalCenter - arrowHorizontalBalancePx,
top: verticalBottom + arrowSize
},
bottomRight: {
left: horizontalRight - arrowHorizontalBalancePx,
top: verticalBottom + arrowSize
},
bottomRightToLeft: {
left: horizontalRight - rect.width,
top: verticalBottom + arrowSize
},
bottomCenterToLeft: {
left: horizontalCenter - rect.width + arrowHorizontalBalancePx,
top: verticalBottom + arrowSize
},
bottomLeft: {
left: horizontalLeft - rect.width + arrowHorizontalBalancePx,
top: verticalBottom + arrowSize
},
topCenter: {
left: horizontalCenter - rect.width / 2,
bottom: horizontalTop + arrowSize
},
topLeftToRight: {
left: horizontalLeft,
bottom: horizontalTop + arrowSize
},
topCenterToRight: {
left: horizontalCenter - arrowHorizontalBalancePx,
bottom: horizontalTop + arrowSize
},
topRight: {
left: horizontalRight - arrowHorizontalBalancePx,
bottom: horizontalTop + arrowSize
},
topRightToLeft: {
left: horizontalRight - rect.width,
bottom: horizontalTop + arrowSize
},
topCenterToLeft: {
left: horizontalCenter - rect.width + arrowHorizontalBalancePx,
bottom: horizontalTop + arrowSize
},
topLeft: {
left: horizontalLeft - rect.width + arrowHorizontalBalancePx,
top: verticalTop - (rect.height + arrowSize)
},
rightCenter: {
left: horizontalRight + arrowSize,
top: verticalCenter - rect.height / 2
},
rightTopToBottom: {
left: horizontalRight + arrowSize,
top: verticalTop
},
rightCenterToBottom: {
left: horizontalRight + arrowSize,
top: verticalCenter - arrowVerticalBalancePx
},
rightBottom: {
left: horizontalRight + arrowSize,
top: verticalBottom - arrowVerticalBalancePx
},
rightBottomToTop: {
left: horizontalRight + arrowSize,
bottom: documentGap.bottom
},
rightCenterToTop: {
left: horizontalRight + arrowSize,
bottom: verticalCenterToTop - arrowVerticalBalancePx
},
rightTop: {
left: horizontalRight + arrowSize,
bottom: horizontalTop - arrowVerticalBalancePx
},
leftCenter: {
left: horizontalLeft - (rect.width + arrowSize),
top: verticalCenter - rect.height / 2
},
leftTopToBottom: {
left: horizontalLeft - (rect.width + arrowSize),
top: verticalTop
},
leftCenterToBottom: {
left: horizontalLeft - (rect.width + arrowSize),
top: verticalCenter - arrowVerticalBalancePx
},
leftBottom: {
left: horizontalLeft - (rect.width + arrowSize),
top: verticalBottom - arrowVerticalBalancePx
},
leftBottomToTop: {
left: horizontalLeft - (rect.width + arrowSize),
bottom: documentGap.bottom
},
leftCenterToTop: {
left: horizontalLeft - (rect.width + arrowSize),
bottom: verticalCenterToTop - arrowVerticalBalancePx
},
leftTop: {
left: horizontalLeft - (rect.width + arrowSize),
bottom: horizontalTop - arrowVerticalBalancePx
}
};
return {
views,
viewsOffset,
targetOffset: relativeBoxRect,
popupOffset: rect
};
},
getArrowAdjustments: (el, relativeBox, customFrame) => {
if (!el) {
return;
}
let elRects = viewPort.frameRelativeRects(el, customFrame);
let {
rectGap
} = elRects;
let relativeBoxRects = viewPort.frameRelativeRects(relativeBox, customFrame);
let relativeBoxGap = relativeBoxRects.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: function (popup, relativeBox) {
let defaultView = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : '';
let customFrame = arguments.length > 3 ? arguments[3] : undefined;
let {
needArrow,
isAbsolute,
customOrder = []
} = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {};
let customScrollFrame = isAbsolute ? customFrame : '';
let viewPortPossibilities = viewPort.possibilities(popup, relativeBox, customScrollFrame, {
needArrow,
isAbsolute
});
if (!viewPortPossibilities) {
return;
}
let {
views,
viewsOffset,
targetOffset,
popupOffset
} = viewPortPossibilities;
let view = null;
let isViewFound = false;
if (!isViewFound && defaultView && views[defaultView]) {
view = defaultView;
isViewFound = true;
}
if (!isViewFound) {
if (customOrder.length > 0) {
isViewFound = customOrder.some(position => {
if (views[position]) {
view = position;
return true;
}
});
} else {
isViewFound = defaultOrder.some(position => {
if (views[position]) {
view = position;
return true;
}
});
}
}
if (!isViewFound) {
view = defaultView;
}
return {
view,
views,
viewsOffset,
targetOffset,
popupOffset
};
}
};
export default {
betterView: viewPort.betterView,
frameRelativeRects: viewPort.frameRelativeRects,
getArrowAdjustments: viewPort.getArrowAdjustments,
isInViewPort: viewPort.isInViewPort
};