UNPKG

@zohodesk/components

Version:

In this Package, we Provide Some Basic Components to Build Web App

374 lines (359 loc) • 14.3 kB
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 };