UNPKG

@sms-frontend/components

Version:

SMS Design React UI Library.

319 lines (318 loc) 14.6 kB
var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; import { isServerRendering } from '../_util/dom'; import { isArray } from '../_util/is'; // get element's position relative to root element function getElementPosition(element, elementRect, root) { if (!root || !element || isServerRendering) { return { left: 0, width: 0, height: 0, top: 0 }; } // safari and chrome var bodyScroll = function (direction) { return document.documentElement[direction] || document.body[direction]; }; var pageScrollTop = root === document.body ? bodyScroll('scrollTop') : root.scrollTop; var pageScrollLeft = root === document.body ? bodyScroll('scrollLeft') : root.scrollLeft; var left = elementRect.left, top = elementRect.top, width = elementRect.width, height = elementRect.height; // custom container var rootLeft = root === document.body ? 0 : root.getBoundingClientRect().left; var rootTop = root === document.body ? 0 : root.getBoundingClientRect().top; var pTop = top + pageScrollTop - rootTop; var pLeft = left + pageScrollLeft - rootLeft; return { left: pLeft, top: pTop, width: width, height: height, }; } var getInsideValue = function (min, max, value) { if (value < min) { return min; } if (value > max) { return max; } return value; }; var getPopupAlign = function (propsPopupAlign, showArrow) { var horizontalOffset = 0; var verticalOffset = 0; var resultPopupAlign = {}; if (!showArrow) { resultPopupAlign = __assign({}, propsPopupAlign); } else { resultPopupAlign = __assign({ left: 12, right: 12, top: 12, bottom: 12 }, propsPopupAlign); } for (var key in resultPopupAlign) { if (isArray(resultPopupAlign[key])) { var index = 0; // top,bottom 时候,第二个参数是纵向偏移量 if (['top', 'bottom'].indexOf(key) > -1) { index = 1; horizontalOffset = resultPopupAlign[key][0]; } else { verticalOffset = resultPopupAlign[key][1]; } resultPopupAlign[key] = resultPopupAlign[key][index]; } } return __assign(__assign({}, resultPopupAlign), { horizontalOffset: horizontalOffset, verticalOffset: verticalOffset }); }; var getChildRect = function (child, mouseLocation) { return mouseLocation ? { left: mouseLocation.clientX, top: mouseLocation.clientY, width: 0, height: 0, right: mouseLocation.clientX, bottom: mouseLocation.clientY, } : child.getBoundingClientRect(); }; export default (function (props, content, child, mountContainer, mouseLocation) { var autoAlignPopupWidth = props.autoAlignPopupWidth, autoAlignPopupMinWidth = props.autoAlignPopupMinWidth, alignPoint = props.alignPoint, propsStyle = props.style; if (!child || !content || !mountContainer) { return {}; } var style = {}; // 如果跟随鼠标,相当于鼠标位置作为 child var childRect = getChildRect(child, alignPoint && mouseLocation); var _a = getElementPosition(child, childRect, mountContainer), left = _a.left, top = _a.top, width = _a.width, height = _a.height; var popupAlign = getPopupAlign(props.popupAlign, props.showArrow); var alignLeft = popupAlign.left || 0; var alignRight = popupAlign.right || 0; var alignTop = popupAlign.top || 0; var alignBottom = popupAlign.bottom || 0; // 通过props.style 传递的width优先级更高 if (autoAlignPopupWidth && (propsStyle === null || propsStyle === void 0 ? void 0 : propsStyle.width) === undefined) { content.style.width = child.offsetWidth + "px"; } if (autoAlignPopupMinWidth) { content.style.minWidth = child.offsetWidth + "px"; } var realPosition = props.position; var arrowStyle = {}; var autoPosition = function (direction) { var _a, _b; if (!props.autoFitPosition) { return; } // document.documentElement?.clientHeight 是为了排除横向滚动条的高度影响。 var windowHeight = ((_a = document.documentElement) === null || _a === void 0 ? void 0 : _a.clientHeight) || window.innerHeight; var windowWidth = ((_b = document.documentElement) === null || _b === void 0 ? void 0 : _b.clientWidth) || window.innerWidth; var result = false; // 是否进行了位置调整 // 视口左侧/顶部到 popupcontainer 的距离 var boundnary = { left: left - childRect.left, top: top - childRect.top, }; var _c = style.top, styleTop = _c === void 0 ? 0 : _c, _d = style.left, styleLeft = _d === void 0 ? 0 : _d; // 水平方向微调 if (direction === 'top' || direction === 'bottom') { if (boundnary.left > styleLeft && childRect.right > 12) { // 左边被遮挡 style.left = Math.max(boundnary.left, left - content.clientWidth); style.left = Math.max(style.left, left - content.clientWidth + 24); } else if (styleLeft - boundnary.left + content.clientWidth > windowWidth && windowWidth - childRect.left > 12) { // 右侧被遮挡,右侧贴边。如果child在可视区内的宽度小于12,不进行位置调整 style.left = Math.max(boundnary.left, boundnary.left + windowWidth - content.clientWidth); style.left = Math.max(style.left, left - content.clientWidth + 24); } } // 垂直方向微调 if (direction === 'left' || direction === 'right') { if (boundnary.top > styleTop && childRect.bottom > 12) { // 上面 style.top = boundnary.top; style.top = Math.max(style.top, top - content.clientHeight + childRect.height / 2); } else if (styleTop - boundnary.top + content.clientHeight > windowHeight && windowHeight - childRect.top > 12) { // 向上微调位置,如果child在可视区内的高度小于12,不进行位置调整 style.top = Math.max(boundnary.top, boundnary.top + windowHeight - content.clientHeight); style.top = Math.max(style.top, top - content.clientHeight + childRect.height / 2); } } if (direction === 'top' && boundnary.top > styleTop) { // 上面被遮挡 if (childRect.top < windowHeight - childRect.bottom) { // 放到下面 style.top = Math.min(top + height + (alignTop || 0), boundnary.top + windowHeight - content.clientHeight); result = true; } else { // 贴顶部边界 style.top = boundnary.top; } } if (direction === 'bottom' && styleTop - boundnary.top + content.clientHeight > windowHeight) { // 下部分被遮挡 if (windowHeight - childRect.bottom < childRect.top) { // 放到上面 style.top = Math.max(top - content.clientHeight - (alignBottom || 0), boundnary.top); result = true; } else { // 贴底边界 style.top = boundnary.top + windowHeight - content.clientHeight; } } if (direction === 'left' && boundnary.left > styleLeft) { // 左边被遮挡 if (childRect.left < windowWidth - childRect.right) { // 放到右边 style.left = Math.min(width + left + alignRight, boundnary.left + windowWidth - content.clientWidth); result = true; } else { style.left = boundnary.left; } } if (direction === 'right' && styleLeft - boundnary.left + content.clientWidth > windowWidth) { // 右边被遮挡 if (windowWidth - childRect.right < childRect.left) { // 放到左边 style.left = Math.max(left - content.clientWidth - alignLeft, boundnary.left); result = true; } else { // 贴左边界 style.left = boundnary.left + windowWidth - content.clientWidth; } } // 限制在popupContainer中,左侧最小为 0px if (style.left < 0) { style.left = 0; } else { // 限制在popupContainer中,左侧最大为 mountContainer.scrollWidth - content.clientWidth,保证弹出层在container内部 var maxLeft = mountContainer.scrollWidth - content.clientWidth; style.left = Math.min(maxLeft, style.left); } return result; }; var horizontalOffset = popupAlign.horizontalOffset || 0; var verticalOffset = popupAlign.verticalOffset || 0; switch (props.position) { case 'top': { style.top = top - content.clientHeight - alignTop; style.left = left + width / 2 - content.clientWidth / 2; autoPosition('top') && (realPosition = 'bottom'); style.left += horizontalOffset; var arrowLeft_1 = left - Number(style.left) + width / 2; arrowStyle.left = getInsideValue(12, content.clientWidth - 12, arrowLeft_1); break; } case 'tl': style.top = top - content.clientHeight - alignTop; style.left = left; autoPosition('top') && (realPosition = 'bl'); style.left += horizontalOffset; var arrowLeft = left - Number(style.left) + Math.min(width / 2, 50); arrowStyle.left = getInsideValue(12, content.clientWidth - 12, arrowLeft); break; case 'tr': style.top = -content.clientHeight + top - alignTop; style.left = left + width - content.clientWidth; autoPosition('top') && (realPosition = 'br'); style.left += horizontalOffset; arrowLeft = left - Number(style.left) + Math.max(width / 2, width - 50); arrowStyle.left = getInsideValue(12, content.clientWidth - 12, arrowLeft); break; case 'bottom': { style.top = height + top + alignBottom; style.left = left + width / 2 - content.clientWidth / 2; autoPosition('bottom') && (realPosition = 'top'); style.left += horizontalOffset; var arrowLeft_2 = left - Number(style.left) + width / 2; arrowStyle.left = getInsideValue(12, content.clientWidth - 12, arrowLeft_2); break; } case 'bl': style.top = height + top + alignBottom; style.left = left; autoPosition('bottom') && (realPosition = 'tl'); style.left += horizontalOffset; arrowLeft = left - Number(style.left) + Math.min(width / 2, 50); arrowStyle.left = getInsideValue(12, content.clientWidth - 12, arrowLeft); break; case 'br': style.top = height + top + alignBottom; style.left = left + width - content.clientWidth; autoPosition('bottom') && (realPosition = 'tr'); style.left += horizontalOffset; arrowLeft = left - Number(style.left) + Math.max(width / 2, width - 50); arrowStyle.left = getInsideValue(12, content.clientWidth - 12, arrowLeft); break; case 'left': { style.top = top + height / 2 - content.clientHeight / 2; style.left = left - content.clientWidth - alignLeft; autoPosition('left') && (realPosition = 'right'); style.top += verticalOffset; var arrowTop_1 = top - Number(style.top) + height / 2; arrowStyle.top = getInsideValue(12, content.clientHeight - 12, arrowTop_1); break; } case 'lt': style.top = top; style.left = left - content.clientWidth - alignLeft; autoPosition('left') && (realPosition = 'rt'); style.top += verticalOffset; var arrowTop = top - Number(style.top) + Math.min(height / 2, 50); arrowStyle.top = getInsideValue(12, content.clientHeight - 12, arrowTop); break; case 'lb': style.top = top + height - content.clientHeight; style.left = left - content.clientWidth - alignLeft; autoPosition('left') && (realPosition = 'rb'); style.top += verticalOffset; arrowTop = top - Number(style.top) + Math.max(height / 2, height - 50); arrowStyle.top = getInsideValue(12, content.clientHeight - 12, arrowTop); break; case 'right': { style.top = top + height / 2 - content.clientHeight / 2; style.left = width + left + alignRight; autoPosition('right') && (realPosition = 'left'); style.top += verticalOffset; var arrowTop_2 = top - Number(style.top) + height / 2; arrowStyle.top = getInsideValue(12, content.clientHeight - 12, arrowTop_2); break; } case 'rt': style.top = top; style.left = width + left + alignRight; autoPosition('right') && (realPosition = 'lt'); style.top += verticalOffset; arrowTop = top - Number(style.top) + Math.min(height / 2, 50); arrowStyle.top = getInsideValue(12, content.clientHeight - 12, arrowTop); break; case 'rb': style.top = top + height - content.clientHeight; style.left = width + left + alignRight; autoPosition('right') && (realPosition = 'lb'); style.top += verticalOffset; arrowTop = top - Number(style.top) + Math.max(height / 2, height - 50); arrowStyle.top = getInsideValue(12, content.clientHeight - 12, arrowTop); break; default: break; } return { style: style, arrowStyle: arrowStyle, realPosition: realPosition, }; });