@zohodesk/hooks
Version:
Unified Component Library - Hooks
210 lines (206 loc) • 9.11 kB
JavaScript
import getViewPortEle from "./getViewPortEle";
import frameRelativeRects from "./frameRelativeRects";
export default function possibilities(el, relativeBox, customFrame) {
let {
needArrow,
isAbsolute
} = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
if (!el) {
return;
}
const elViewPortEle = getViewPortEle(el);
const elRects = frameRelativeRects(el, customFrame, elViewPortEle);
const {
rect
} = elRects;
const relativeBoxViewPortEle = getViewPortEle(relativeBox);
const relativeBoxRects = frameRelativeRects(relativeBox, customFrame, relativeBoxViewPortEle);
const {
rectGap: relativeBoxGap,
rect: relativeBoxRect
} = relativeBoxRects;
const relativeBoxDocumentRects = frameRelativeRects(relativeBox, customFrame);
const {
rectGap: documentGap
} = relativeBoxDocumentRects; // rect => PopOverContainer, relativeBoxGap => PopOverTarget
// Horizontal ~ ----- X axis
// Vertical ~ ||||||| Y axis
const paddingSpace = 5; // space between target and relative element
const arrowSize = needArrow ? 10 : 0;
rect.height += needArrow ? arrowSize : paddingSpace;
rect.width += needArrow ? arrowSize : paddingSpace;
const arrowHorizontalBalancePx = !isAbsolute && needArrow ? 30 : 0;
const arrowVerticalBalancePx = !isAbsolute && needArrow ? 27 : 0;
const bottomOverFlow = rect.height > relativeBoxGap.bottom;
const topOverFlow = rect.height > relativeBoxGap.top;
const rightOverFlow = rect.width > relativeBoxGap.right;
const leftOverFlow = rect.width > relativeBoxGap.left;
const horizontalCenterOverFlow = rect.width / 2 > relativeBoxGap.center.right || rect.width / 2 > relativeBoxGap.center.left;
const verticalCenterOverFlow = rect.height / 2 > relativeBoxGap.center.top || rect.height / 2 > relativeBoxGap.center.bottom;
const horizontalLeftToRightOverFlow = rect.width > relativeBoxRect.width + relativeBoxGap.right;
const horizontalCenterToRightOverFlow = rect.width > relativeBoxGap.center.right || arrowHorizontalBalancePx > relativeBoxGap.center.left;
const horizontalRightToLeft = rect.width > relativeBoxRect.width + relativeBoxGap.left;
const horizontalCenterToLeft = rect.width > relativeBoxGap.center.left || arrowHorizontalBalancePx > relativeBoxGap.center.right;
const verticalTopToBottomOverFlow = rect.height > relativeBoxRect.height + relativeBoxGap.bottom;
const verticalCenterToBottomOverFlow = rect.height > relativeBoxGap.center.bottom || arrowVerticalBalancePx > relativeBoxGap.center.top;
const verticalBottomToTopOverFlow = rect.height > relativeBoxRect.height + relativeBoxGap.top;
const verticalCenterToTopOverFlow = rect.height > relativeBoxGap.center.top || arrowVerticalBalancePx > relativeBoxGap.center.bottom;
const 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)
};
const horizontalCenter = relativeBoxGap.left + relativeBoxRect.width / 2;
const horizontalLeft = relativeBoxGap.left;
const horizontalRight = relativeBoxGap.left + relativeBoxRect.width;
const verticalBottom = relativeBoxGap.top + relativeBoxRect.height;
const verticalTop = relativeBoxGap.top;
const verticalCenter = relativeBoxGap.top + relativeBoxRect.height / 2;
const horizontalTop = documentGap.bottom + relativeBoxRect.height;
const verticalCenterToTop = documentGap.bottom + relativeBoxRect.height / 2;
const 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
};
}