ghost-portal/packages/react-components/src/Popup/utils.ts
MiZiet b6c827a908
Remove sui popup (#5924)
* Add custom popup

* Render popup window with react portal

* Handle scroll

* Handle pointer scroll

* Refactor types

* Add useOutsideClick

* Restore button styles

* Update types

* Add tests

* Set multiple refs

* Cleanup

* Cleanup

* Move offset const to the utils

* Add useCallback in useScroll

* Remove empty lines in useElementPosition

* Change styled components to functional

* Make sure popup window stays in view

* Highlight trigger button when popup is open

* Add uesPopupWindow hook

* Make triangle larger

* Use full trigger height

* Apply new lint rules

Co-authored-by: Jaco Greeff <jacogr@gmail.com>
2021-08-31 09:35:33 +02:00

77 lines
2.6 KiB
TypeScript

// Copyright 2017-2021 @polkadot/react-components authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { ElementPosition } from '@polkadot/react-hooks/useElementPosition';
import { WindowSize } from '@polkadot/react-hooks/useWindowSize';
import { HorizontalPosition, VerticalPosition } from './types';
// 0.8rem
const POINTER_OFFSET = 14 * 0.8;
// we don't want our popup window to cover apps menu
const MENU_BAR_HEIGHT = 56;
// adds 1rem margin between browsers window and popup
const FIXED_VERTICAL_OFFSET_MARGIN = 14;
export function getPosition (
triggerPosition: ElementPosition,
positionX: HorizontalPosition,
positionY: VerticalPosition,
windowPosition: ElementPosition,
scrollY: number,
windowSize: WindowSize
): {x: number, y: number} {
const globalX = triggerPosition.x + (triggerPosition.width / 2);
const globalY = triggerPosition.y + scrollY + (triggerPosition.height / 2);
return {
x: globalX - getHorizontalOffset(windowPosition.width, positionX),
y: fitsInView(positionY, triggerPosition, windowPosition.height, windowSize, scrollY)
? globalY + getVerticalOffset(triggerPosition.height, positionY, windowPosition.height)
: getFixedVerticalPosition(scrollY, positionY, windowSize, windowPosition.height)
};
}
function getHorizontalOffset (popupWindowWidth: number, position: HorizontalPosition): number {
if (position === 'left') {
return popupWindowWidth - POINTER_OFFSET;
}
if (position === 'right') {
return POINTER_OFFSET;
}
return (popupWindowWidth / 2);
}
function fitsInView (positionY: VerticalPosition, trigger: ElementPosition, popupWindowHeight: number, windowSize: WindowSize, scrollY: number): boolean {
const { height: triggerHeight, y: triggerY } = trigger;
if (positionY === 'bottom') {
return windowSize.height - triggerHeight - triggerY - FIXED_VERTICAL_OFFSET_MARGIN > popupWindowHeight;
}
return scrollY < MENU_BAR_HEIGHT
? triggerY - (MENU_BAR_HEIGHT - scrollY) > popupWindowHeight
: triggerY > popupWindowHeight;
}
function getVerticalOffset (triggerHeight: number, position: VerticalPosition, windowHeight: number): number {
if (position === 'bottom') {
return triggerHeight / 2;
}
return (triggerHeight / 2 + windowHeight + POINTER_OFFSET) * -1;
}
function getFixedVerticalPosition (scrollY: number, position: VerticalPosition, windowSize: WindowSize, popupWindowHeight: number): number {
if (position === 'bottom') {
return scrollY + windowSize.height - popupWindowHeight - FIXED_VERTICAL_OFFSET_MARGIN;
}
return scrollY < MENU_BAR_HEIGHT
? MENU_BAR_HEIGHT
: scrollY;
}