UNPKG

@arco-design/web-vue

Version:

Arco Design Vue 2.0: A Vue.js 3 UI Library

380 lines (379 loc) 11.4 kB
import { isArray } from "../_utils/is.js"; import { getDocumentSize } from "../_utils/dom.js"; const getViewPortSize = () => { const { height, width } = getDocumentSize(); return { width: Math.min(width, window.innerWidth), height: Math.min(height, window.innerHeight) }; }; const getElementScrollRect = (element, containerRect) => { var _a, _b; const rect = element.getBoundingClientRect(); return { top: rect.top, bottom: rect.bottom, left: rect.left, right: rect.right, scrollTop: rect.top - containerRect.top, scrollBottom: rect.bottom - containerRect.top, scrollLeft: rect.left - containerRect.left, scrollRight: rect.right - containerRect.left, width: (_a = element.offsetWidth) != null ? _a : element.clientWidth, height: (_b = element.offsetHeight) != null ? _b : element.clientHeight }; }; const getBoundaryPosition = (position) => { switch (position) { case "top": case "tl": case "tr": return "top"; case "bottom": case "bl": case "br": return "bottom"; case "left": case "lt": case "lb": return "left"; case "right": case "rt": case "rb": return "right"; default: return "top"; } }; const changePosition = (position, direction) => { switch (direction) { case "top": switch (position) { case "bottom": return "top"; case "bl": return "tl"; case "br": return "tr"; default: return position; } case "bottom": switch (position) { case "top": return "bottom"; case "tl": return "bl"; case "tr": return "br"; default: return position; } case "left": switch (position) { case "right": return "left"; case "rt": return "lt"; case "rb": return "lb"; default: return position; } case "right": switch (position) { case "left": return "right"; case "lt": return "rt"; case "lb": return "rb"; default: return position; } default: return position; } }; const getFitPosition = (position, popupPosition, { containerRect, triggerRect, popupRect, offset, translate }) => { const direction = getBoundaryPosition(position); const viewPortSize = getViewPortSize(); const viewPortBoundary = { top: containerRect.top + popupPosition.top, bottom: viewPortSize.height - (containerRect.top + popupPosition.top + popupRect.height), left: containerRect.left + popupPosition.left, right: viewPortSize.width - (containerRect.left + popupPosition.left + popupRect.width) }; let finalPosition = position; if (direction === "top" && viewPortBoundary.top < 0) { if (triggerRect.top > popupRect.height) { popupPosition.top = -containerRect.top; } else { const fitPosition = getPopupOffset("bottom", triggerRect, popupRect, { offset, translate }); if (viewPortSize.height - (containerRect.top + fitPosition.top + popupRect.height) > 0) { finalPosition = changePosition(position, "bottom"); popupPosition.top = fitPosition.top; } } } if (direction === "bottom" && viewPortBoundary.bottom < 0) { if (viewPortSize.height - triggerRect.bottom > popupRect.height) { popupPosition.top = -containerRect.top + (viewPortSize.height - popupRect.height); } else { const fitPosition = getPopupOffset("top", triggerRect, popupRect, { offset, translate }); if (containerRect.top + fitPosition.top > 0) { finalPosition = changePosition(position, "top"); popupPosition.top = fitPosition.top; } } } if (direction === "left" && viewPortBoundary.left < 0) { if (triggerRect.left > popupRect.width) { popupPosition.left = -containerRect.left; } else { const fitPosition = getPopupOffset("right", triggerRect, popupRect, { offset, translate }); if (viewPortSize.width - (containerRect.left + fitPosition.left + popupRect.width) > 0) { finalPosition = changePosition(position, "right"); popupPosition.left = fitPosition.left; } } } if (direction === "right" && viewPortBoundary.right < 0) { if (viewPortSize.width - triggerRect.right > popupRect.width) { popupPosition.left = -containerRect.left + (viewPortSize.width - popupRect.width); } else { const fitPosition = getPopupOffset("left", triggerRect, popupRect, { offset, translate }); if (containerRect.left + fitPosition.left > 0) { finalPosition = changePosition(position, "left"); popupPosition.left = fitPosition.left; } } } if (direction === "top" || direction === "bottom") { if (viewPortBoundary.left < 0) { popupPosition.left = -containerRect.left; } else if (viewPortBoundary.right < 0) { popupPosition.left = -containerRect.left + (viewPortSize.width - popupRect.width); } } if (direction === "left" || direction === "right") { if (viewPortBoundary.top < 0) { popupPosition.top = -containerRect.top; } else if (viewPortBoundary.bottom < 0) { popupPosition.top = -containerRect.top + (viewPortSize.height - popupRect.height); } } return { popupPosition, position: finalPosition }; }; const getPopupOffset = (position, triggerRect, popupRect, { offset = 0, translate = [0, 0] } = {}) => { var _a; const _translate = (_a = isArray(translate) ? translate : translate[position]) != null ? _a : [0, 0]; switch (position) { case "top": return { left: triggerRect.scrollLeft + Math.round(triggerRect.width / 2) - Math.round(popupRect.width / 2) + _translate[0], top: triggerRect.scrollTop - popupRect.height - offset + _translate[1] }; case "tl": return { left: triggerRect.scrollLeft + _translate[0], top: triggerRect.scrollTop - popupRect.height - offset + _translate[1] }; case "tr": return { left: triggerRect.scrollRight - popupRect.width + _translate[0], top: triggerRect.scrollTop - popupRect.height - offset + _translate[1] }; case "bottom": return { left: triggerRect.scrollLeft + Math.round(triggerRect.width / 2) - Math.round(popupRect.width / 2) + _translate[0], top: triggerRect.scrollBottom + offset + _translate[1] }; case "bl": return { left: triggerRect.scrollLeft + _translate[0], top: triggerRect.scrollBottom + offset + _translate[1] }; case "br": return { left: triggerRect.scrollRight - popupRect.width + _translate[0], top: triggerRect.scrollBottom + offset + _translate[1] }; case "left": return { left: triggerRect.scrollLeft - popupRect.width - offset + _translate[0], top: triggerRect.scrollTop + Math.round(triggerRect.height / 2) - Math.round(popupRect.height / 2) + _translate[1] }; case "lt": return { left: triggerRect.scrollLeft - popupRect.width - offset + _translate[0], top: triggerRect.scrollTop + _translate[1] }; case "lb": return { left: triggerRect.scrollLeft - popupRect.width - offset + _translate[0], top: triggerRect.scrollBottom - popupRect.height + _translate[1] }; case "right": return { left: triggerRect.scrollRight + offset + _translate[0], top: triggerRect.scrollTop + Math.round(triggerRect.height / 2) - Math.round(popupRect.height / 2) + _translate[1] }; case "rt": return { left: triggerRect.scrollRight + offset + _translate[0], top: triggerRect.scrollTop + _translate[1] }; case "rb": return { left: triggerRect.scrollRight + offset + _translate[0], top: triggerRect.scrollBottom - popupRect.height + _translate[1] }; default: return { left: 0, top: 0 }; } }; const getTransformOrigin = (position) => { let originX = "0"; if (["top", "bottom"].includes(position)) { originX = "50%"; } else if (["left", "lt", "lb", "tr", "br"].includes(position)) { originX = "100%"; } let originY = "0"; if (["left", "right"].includes(position)) { originY = "50%"; } else if (["top", "tl", "tr", "lb", "rb"].includes(position)) { originY = "100%"; } return `${originX} ${originY}`; }; const getPopupStyle = (position, containerRect, triggerRect, popupRect, { offset = 0, translate = [0, 0], customStyle = {}, autoFitPosition = false } = {}) => { let finalPosition = position; let popupPosition = getPopupOffset(position, triggerRect, popupRect, { offset, translate }); if (autoFitPosition) { const result = getFitPosition(position, popupPosition, { containerRect, popupRect, triggerRect, offset, translate }); popupPosition = result.popupPosition; finalPosition = result.position; } const style = { left: `${popupPosition.left}px`, top: `${popupPosition.top}px`, ...customStyle }; return { style, position: finalPosition }; }; const getArrowStyle = (position, triggerRect, popupRect, { customStyle = {} }) => { if (["top", "tl", "tr", "bottom", "bl", "br"].includes(position)) { let offsetLeft = Math.abs( triggerRect.scrollLeft + triggerRect.width / 2 - popupRect.scrollLeft ); if (offsetLeft > popupRect.width - 8) { if (triggerRect.width > popupRect.width) { offsetLeft = popupRect.width / 2; } else { offsetLeft = popupRect.width - 8; } } if (["top", "tl", "tr"].includes(position)) { return { left: `${offsetLeft}px`, bottom: "0", transform: "translate(-50%,50%) rotate(45deg)", ...customStyle }; } return { left: `${offsetLeft}px`, top: "0", transform: "translate(-50%,-50%) rotate(45deg)", ...customStyle }; } let offsetTop = Math.abs( triggerRect.scrollTop + triggerRect.height / 2 - popupRect.scrollTop ); if (offsetTop > popupRect.height - 8) { if (triggerRect.height > popupRect.height) { offsetTop = popupRect.height / 2; } else { offsetTop = popupRect.height - 8; } } if (["left", "lt", "lb"].includes(position)) { return { top: `${offsetTop}px`, right: "0", transform: "translate(50%,-50%) rotate(45deg)", ...customStyle }; } return { top: `${offsetTop}px`, left: "0", transform: "translate(-50%,-50%) rotate(45deg)", ...customStyle }; }; const isScrollElement = (element) => { return element.scrollHeight > element.offsetHeight || element.scrollWidth > element.offsetWidth; }; const getScrollElements = (container) => { var _a; const scrollElements = []; let element = container; while (element && element !== document.documentElement) { if (isScrollElement(element)) { scrollElements.push(element); } element = (_a = element.parentElement) != null ? _a : void 0; } return scrollElements; }; export { getArrowStyle, getElementScrollRect, getPopupStyle, getScrollElements, getTransformOrigin, isScrollElement };