UNPKG

quasar-framework

Version:

Build responsive SPA, SSR, PWA, Hybrid Mobile Apps and Electron apps, all simultaneously using the same codebase

171 lines (145 loc) 4.74 kB
import { position as eventPosition } from './event.js' export function getAnchorPosition (el, offset) { let {top, left, right, bottom} = el.getBoundingClientRect(), a = { top, left, width: el.offsetWidth, height: el.offsetHeight } if (offset) { a.top -= offset[1] a.left -= offset[0] if (bottom) { bottom += offset[1] } if (right) { right += offset[0] } a.width += offset[0] a.height += offset[1] } a.right = right || a.left + a.width a.bottom = bottom || a.top + a.height a.middle = a.left + ((a.right - a.left) / 2) a.center = a.top + ((a.bottom - a.top) / 2) return a } export function getTargetPosition (el) { return { top: 0, center: el.offsetHeight / 2, bottom: el.offsetHeight, left: 0, middle: el.offsetWidth / 2, right: el.offsetWidth } } export function getPositions (anchor, target) { const a = Object.assign({}, anchor), t = Object.assign({}, target) const positions = { x: ['left', 'right'].filter(p => p !== t.horizontal), y: ['top', 'bottom'].filter(p => p !== t.vertical) } const overlapAuto = { x: [a.horizontal, t.horizontal].indexOf('middle') !== -1, y: [a.vertical, t.vertical].indexOf('center') !== -1 } positions.x.splice(overlapAuto.x ? 0 : 1, 0, 'middle') positions.y.splice(overlapAuto.y ? 0 : 1, 0, 'center') if (!overlapAuto.y) { a.vertical = a.vertical === 'top' ? 'bottom' : 'top' } if (!overlapAuto.x) { a.horizontal = a.horizontal === 'left' ? 'right' : 'left' } return { positions: positions, anchorPos: a } } export function repositionIfNeeded (anchor, target, selfOrigin, anchorOrigin, targetPosition) { const {positions, anchorPos} = getPositions(anchorOrigin, selfOrigin) if (targetPosition.top < 0 || targetPosition.top + target.bottom > window.innerHeight) { let newTop = anchor[anchorPos.vertical] - target[positions.y[0]] if (newTop + target.bottom <= window.innerHeight) { targetPosition.top = newTop } else { newTop = anchor[anchorPos.vertical] - target[positions.y[1]] if (newTop + target.bottom <= window.innerHeight) { targetPosition.top = newTop } } } if (targetPosition.left < 0 || targetPosition.left + target.right > window.innerWidth) { let newLeft = anchor[anchorPos.horizontal] - target[positions.x[0]] if (newLeft + target.right <= window.innerWidth) { targetPosition.left = newLeft } else { newLeft = anchor[anchorPos.horizontal] - target[positions.x[1]] if (newLeft + target.right <= window.innerWidth) { targetPosition.left = newLeft } } } return targetPosition } export function parseHorizTransformOrigin (pos) { return pos === 'middle' ? 'center' : pos } export function setPosition ({el, animate, anchorEl, anchorOrigin, selfOrigin, maxHeight, event, anchorClick, touchPosition, offset}) { let anchor el.style.maxHeight = maxHeight || '65vh' if (event && (!anchorClick || touchPosition)) { const {top, left} = eventPosition(event) anchor = {top, left, width: 1, height: 1, right: left + 1, center: top, middle: left, bottom: top + 1} } else { anchor = getAnchorPosition(anchorEl, offset) } let target = getTargetPosition(el) let targetPosition = { top: anchor[anchorOrigin.vertical] - target[selfOrigin.vertical], left: anchor[anchorOrigin.horizontal] - target[selfOrigin.horizontal] } targetPosition = repositionIfNeeded(anchor, target, selfOrigin, anchorOrigin, targetPosition) el.style.top = Math.max(0, targetPosition.top) + 'px' el.style.left = Math.max(0, targetPosition.left) + 'px' if (animate) { const directions = targetPosition.top < anchor.top ? ['up', 'down'] : ['down', 'up'] el.classList.add(`animate-popup-${directions[0]}`) el.classList.remove(`animate-popup-${directions[1]}`) } } export function positionValidator (pos) { let parts = pos.split(' ') if (parts.length !== 2) { return false } if (!['top', 'center', 'bottom'].includes(parts[0])) { console.error('Anchor/Self position must start with one of top/center/bottom') return false } if (!['left', 'middle', 'right'].includes(parts[1])) { console.error('Anchor/Self position must end with one of left/middle/right') return false } return true } export function offsetValidator (val) { if (!val) { return true } if (val.length !== 2) { return false } if (typeof val[0] !== 'number' || typeof val[1] !== 'number') { return false } return true } export function parsePosition (pos) { let parts = pos.split(' ') return {vertical: parts[0], horizontal: parts[1]} }