UNPKG

pouncejs

Version:

A collection of UI components from Panther labs

205 lines (165 loc) 9.48 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); exports.__esModule = true; exports.useAlignment = exports.useAlignmentFunction = void 0; var _react = _interopRequireDefault(require("react")); var _rect = require("@reach/rect"); function getForcedDirection(triggerElementRect, floatingElementRect, alignment) { var collisions; var isHorizontalAlignment = alignment.startsWith('left') || alignment.startsWith('right'); var isCentralAlignment = alignment.endsWith('center'); if (isHorizontalAlignment) { collisions = { top: triggerElementRect.top + triggerElementRect.height < (isCentralAlignment ? floatingElementRect.height / 2 : floatingElementRect.height), right: window.innerWidth < triggerElementRect.right + floatingElementRect.width, bottom: window.innerHeight < triggerElementRect.top + (isCentralAlignment ? floatingElementRect.height / 2 : floatingElementRect.height), left: triggerElementRect.left < floatingElementRect.width }; } else { collisions = { top: triggerElementRect.top - floatingElementRect.height < 0, right: window.innerWidth < triggerElementRect.left + (isCentralAlignment ? floatingElementRect.width / 2 : floatingElementRect.width), bottom: window.innerHeight < triggerElementRect.bottom + floatingElementRect.height, left: triggerElementRect.left + triggerElementRect.width - (isCentralAlignment ? floatingElementRect.width / 2 : floatingElementRect.width) < 0 }; } return { forcedRightwards: !collisions.right && collisions.left, forcedLeftwards: !collisions.left && collisions.right, forcedUpwards: !collisions.top && collisions.bottom, forcedDownwards: !collisions.bottom && collisions.top }; } var leftAlignmentLeft = function leftAlignmentLeft(triggerElementRect, floatingElementRect, direction) { return direction.forcedRightwards ? triggerElementRect.right + window.pageXOffset + "px" : triggerElementRect.left + window.pageXOffset - floatingElementRect.width + "px"; }; var rightAlignmentLeft = function rightAlignmentLeft(triggerElementRect, floatingElementRect, direction) { return direction.forcedLeftwards ? triggerElementRect.left + window.pageXOffset - floatingElementRect.width + "px" : triggerElementRect.right + window.pageXOffset + "px"; }; var bottomAlignmentTop = function bottomAlignmentTop(triggerElementRect, floatingElementRect, direction) { return direction.forcedUpwards ? triggerElementRect.top - floatingElementRect.height + window.pageYOffset + "px" : triggerElementRect.top + triggerElementRect.height + window.pageYOffset + "px"; }; var topAlignmentTop = function topAlignmentTop(triggerElementRect, floatingElementRect, direction) { return direction.forcedDownwards ? triggerElementRect.top + triggerElementRect.height + window.pageYOffset + "px" : triggerElementRect.top - floatingElementRect.height + window.pageYOffset + "px"; }; var horizontalTopAlignmentTop = function horizontalTopAlignmentTop(triggerElementRect, floatingElementRect, direction) { return direction.forcedDownwards ? triggerElementRect.top + window.pageYOffset + "px" : triggerElementRect.bottom - floatingElementRect.height + window.pageYOffset + "px"; }; var horizontalBottomAlignmentTop = function horizontalBottomAlignmentTop(triggerElementRect, floatingElementRect, direction) { return direction.forcedUpwards ? triggerElementRect.bottom - floatingElementRect.height + window.pageYOffset + "px" : triggerElementRect.top + window.pageYOffset + "px"; }; var horizontalCenterAlignmentTop = function horizontalCenterAlignmentTop(triggerElementRect, floatingElementRect, direction) { if (direction.forcedUpwards) { return triggerElementRect.bottom - floatingElementRect.height + window.pageYOffset + "px"; } if (direction.forcedDownwards) { return triggerElementRect.top + window.pageYOffset + "px"; } return triggerElementRect.bottom - floatingElementRect.height / 2 - triggerElementRect.height / 2 + window.pageYOffset + "px"; }; var verticalLeftAlignmentLeft = function verticalLeftAlignmentLeft(triggerElementRect, floatingElementRect, direction) { return direction.forcedRightwards ? triggerElementRect.left + window.pageXOffset + "px" : triggerElementRect.right - floatingElementRect.width + window.pageXOffset + "px"; }; var verticalRightAlignmentLeft = function verticalRightAlignmentLeft(triggerElementRect, floatingElementRect, direction) { return direction.forcedLeftwards ? triggerElementRect.right - floatingElementRect.width + window.pageXOffset + "px" : triggerElementRect.left + window.pageXOffset + "px"; }; var verticalCenterAlignmentLeft = function verticalCenterAlignmentLeft(triggerElementRect, floatingElementRect, direction) { if (direction.forcedLeftwards) { return triggerElementRect.right - floatingElementRect.width + window.pageXOffset + "px"; } if (direction.forcedRightwards) { return triggerElementRect.right - triggerElementRect.width + window.pageXOffset + "px"; } return triggerElementRect.right - floatingElementRect.width / 2 - triggerElementRect.width / 2 + window.pageXOffset + "px"; }; /** * Αccepts an alignment and returns a function that when given 2 Rect instances, will return a set of positional CSS * properties that the floating element should receive in order for it to be correctly aligned with its trigger element * * ### * This function is only to be used by @reach/ui elements. The one that any element can use is the `useAlignment` one * ### */ var useAlignmentFunction = function useAlignmentFunction(alignment) { return _react.default.useCallback(function (triggerElementRect, floatingElementRect) { if (!triggerElementRect || !floatingElementRect) { return {}; } var direction = getForcedDirection(triggerElementRect, floatingElementRect, alignment); switch (alignment) { case 'left-bottom': return { left: leftAlignmentLeft(triggerElementRect, floatingElementRect, direction), top: horizontalBottomAlignmentTop(triggerElementRect, floatingElementRect, direction) }; case 'left-center': return { left: leftAlignmentLeft(triggerElementRect, floatingElementRect, direction), top: horizontalCenterAlignmentTop(triggerElementRect, floatingElementRect, direction) }; case 'left-top': return { left: leftAlignmentLeft(triggerElementRect, floatingElementRect, direction), top: horizontalTopAlignmentTop(triggerElementRect, floatingElementRect, direction) }; case 'top-left': return { left: verticalLeftAlignmentLeft(triggerElementRect, floatingElementRect, direction), top: topAlignmentTop(triggerElementRect, floatingElementRect, direction) }; case 'top-center': return { left: verticalCenterAlignmentLeft(triggerElementRect, floatingElementRect, direction), top: topAlignmentTop(triggerElementRect, floatingElementRect, direction) }; case 'top-right': return { left: verticalRightAlignmentLeft(triggerElementRect, floatingElementRect, direction), top: topAlignmentTop(triggerElementRect, floatingElementRect, direction) }; case 'right-bottom': return { left: rightAlignmentLeft(triggerElementRect, floatingElementRect, direction), top: horizontalBottomAlignmentTop(triggerElementRect, floatingElementRect, direction) }; case 'right-center': return { left: rightAlignmentLeft(triggerElementRect, floatingElementRect, direction), top: horizontalCenterAlignmentTop(triggerElementRect, floatingElementRect, direction) }; case 'right-top': return { left: rightAlignmentLeft(triggerElementRect, floatingElementRect, direction), top: horizontalTopAlignmentTop(triggerElementRect, floatingElementRect, direction) }; case 'bottom-left': return { left: verticalLeftAlignmentLeft(triggerElementRect, floatingElementRect, direction), top: bottomAlignmentTop(triggerElementRect, floatingElementRect, direction) }; case 'bottom-center': return { left: verticalCenterAlignmentLeft(triggerElementRect, floatingElementRect, direction), top: bottomAlignmentTop(triggerElementRect, floatingElementRect, direction) }; case 'bottom-right': default: return { left: verticalRightAlignmentLeft(triggerElementRect, floatingElementRect, direction), top: bottomAlignmentTop(triggerElementRect, floatingElementRect, direction) }; } }, [alignment]); }; /** * Αccepts a trigger reference, a floating element reference and an alignment and returns a set of positional CSS * properties that the floating element should receive in order for it to be correctly aligned with its trigger element */ exports.useAlignmentFunction = useAlignmentFunction; var useAlignment = function useAlignment(triggerElementRef, floatingElementRef, alignment) { var triggerElementRect = (0, _rect.useRect)(triggerElementRef); var floatingElementRect = (0, _rect.useRect)(floatingElementRef); var alignmentFunction = useAlignmentFunction(alignment); return alignmentFunction(triggerElementRect, floatingElementRect); }; exports.useAlignment = useAlignment;