/* * https://github.com/morethanwords/tweb * Copyright (C) 2019-2021 Eduard Kuzmenko * https://github.com/morethanwords/tweb/blob/master/LICENSE */ import mediaSizes from "./mediaSizes"; export type MenuPositionPadding = { top?: number, right?: number, bottom?: number, left?: number }; const PADDING_TOP = 8; const PADDING_BOTTOM = PADDING_TOP; const PADDING_LEFT = 8; const PADDING_RIGHT = PADDING_LEFT; export default function positionMenu({pageX, pageY}: MouseEvent | Touch, elem: HTMLElement, side?: 'left' | 'right' | 'center', additionalPadding?: MenuPositionPadding) { //let {clientX, clientY} = e; // * side mean the OPEN side const getScrollWidthFromElement = (Array.from(elem.children) as HTMLElement[]).find((element) => element.classList.contains('btn-menu-item') && !element.classList.contains('hide')) || elem; let {scrollWidth: menuWidth} = getScrollWidthFromElement; let {scrollHeight: menuHeight} = elem; //let {innerWidth: windowWidth, innerHeight: windowHeight} = window; const rect = document.body.getBoundingClientRect(); const windowWidth = rect.width; const windowHeight = rect.height; let paddingTop = PADDING_TOP, paddingRight = PADDING_RIGHT, paddingBottom = PADDING_BOTTOM, paddingLeft = PADDING_LEFT; if(additionalPadding) { if(additionalPadding.top) paddingTop += additionalPadding.top; if(additionalPadding.right) paddingRight += additionalPadding.right; if(additionalPadding.bottom) paddingBottom += additionalPadding.bottom; if(additionalPadding.left) paddingLeft += additionalPadding.left; } side = mediaSizes.isMobile ? 'right' : 'left'; let verticalSide: 'top' /* | 'bottom' */ | 'center' = 'top'; const maxTop = windowHeight - menuHeight - paddingBottom; const maxLeft = windowWidth - menuWidth - paddingRight; const minTop = paddingTop; const minLeft = paddingLeft; const getSides = () => { return { x: { left: pageX, right: Math.min(maxLeft, pageX - menuWidth) }, intermediateX: side === 'right' ? minLeft : maxLeft, //intermediateX: clientX < windowWidth / 2 ? PADDING_LEFT : windowWidth - menuWidth - PADDING_LEFT, y: { top: pageY, bottom: pageY - menuHeight }, //intermediateY: verticalSide === 'top' ? paddingTop : windowHeight - menuHeight - paddingTop, // intermediateY: pageY < (windowHeight / 2) ? paddingTop : windowHeight - menuHeight - paddingBottom, intermediateY: maxTop, }; }; const sides = getSides(); const possibleSides = { x: { left: (sides.x.left + menuWidth + paddingRight) <= windowWidth, right: sides.x.right >= paddingLeft }, y: { top: (sides.y.top + menuHeight + paddingBottom) <= windowHeight, bottom: (sides.y.bottom - paddingBottom) >= paddingBottom } }; /* if(side === undefined) { if((clientX + menuWidth + PADDING_LEFT) > windowWidth) { side = 'right'; } } */ { /* const x = sides.x; const s = Object.keys(x) as (keyof typeof possibleSides.x)[]; if(side) { s.findAndSplice((s) => s === side); s.unshift(side); } const possibleSide = s.find((s) => possibleSides.x[s]); */ let left: number; /* if(possibleSide) { left = x[possibleSide]; side = possibleSide; } else { left = sides.intermediateX; side = undefined; } */ left = possibleSides.x[side] ? sides.x[side] : (side = 'center', sides.intermediateX); elem.style.left = left + 'px'; } /* if((clientY + menuHeight + PADDING_TOP) > windowHeight) { elem.style.top = clamp(clientY - menuHeight, PADDING_TOP, windowHeight - menuHeight - PADDING_TOP) + 'px'; // elem.style.top = (innerHeight - scrollHeight - PADDING_TOP) + 'px'; verticalSide = 'bottom'; } else { elem.style.top = Math.max(PADDING_TOP, clientY) + 'px'; verticalSide = 'top'; } */ { let top: number; top = possibleSides.y[verticalSide] ? sides.y[verticalSide] : (verticalSide = 'center', sides.intermediateY); elem.style.top = top + 'px'; } elem.className = elem.className.replace(/(top|center|bottom)-(left|center|right)/g, ''); elem.classList.add( //(verticalSide === 'center' ? verticalSide : (verticalSide === 'bottom' ? 'top' : 'bottom')) + (verticalSide === 'center' ? verticalSide : 'bottom') + '-' + (side === 'center' ? side : (side === 'left' ? 'right' : 'left'))); return { width: menuWidth, height: menuHeight }; }