pouncejs
Version:
A collection of UI components from Panther labs
205 lines (165 loc) • 9.48 kB
JavaScript
;
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;